tls: add pcap capturing

This commit is contained in:
soypat
2026-08-08 21:31:53 -07:00
parent 9758d48696
commit 91c646c636
9 changed files with 1525 additions and 9 deletions
+1
View File
@@ -106,6 +106,7 @@ const (
ExtMaxFragmentLength ExtensionType = 1 // max_fragment_length
ExtStatusRequest ExtensionType = 5 // status_request
ExtSupportedGroups ExtensionType = 10 // supported_groups
ExtECPointFormats ExtensionType = 11 // ec_point_formats
ExtSignatureAlgorithms ExtensionType = 13 // signature_algorithms
ExtALPN ExtensionType = 16 // application_layer_protocol_negotiation
ExtSignedCertificateTimestamp ExtensionType = 18 // signed_certificate_timestamp
+366
View File
@@ -0,0 +1,366 @@
// Code generated by "stringer -type=ContentType,HandshakeType,ExtensionType,AlertDescription,AlertLevel,NamedGroup,SignatureScheme,CipherSuite -linecomment -output stringers.go ."; DO NOT EDIT.
package tls
import "strconv"
func _() {
// An "invalid array index" compiler error signifies that the constant values have changed.
// Re-run the stringer command to generate them again.
var x [1]struct{}
_ = x[ContentTypeInvalid-0]
_ = x[ContentTypeChangeCipherSpec-20]
_ = x[ContentTypeAlert-21]
_ = x[ContentTypeHandshake-22]
_ = x[ContentTypeApplicationData-23]
}
const (
_ContentType_name_0 = "invalid"
_ContentType_name_1 = "change_cipher_specalerthandshakeapplication_data"
)
var (
_ContentType_index_1 = [...]uint8{0, 18, 23, 32, 48}
)
func (i ContentType) String() string {
switch {
case i == 0:
return _ContentType_name_0
case 20 <= i && i <= 23:
i -= 20
return _ContentType_name_1[_ContentType_index_1[i]:_ContentType_index_1[i+1]]
default:
return "ContentType(" + strconv.FormatInt(int64(i), 10) + ")"
}
}
func _() {
// An "invalid array index" compiler error signifies that the constant values have changed.
// Re-run the stringer command to generate them again.
var x [1]struct{}
_ = x[HandshakeTypeClientHello-1]
_ = x[HandshakeTypeServerHello-2]
_ = x[HandshakeTypeNewSessionTicket-4]
_ = x[HandshakeTypeEndOfEarlyData-5]
_ = x[HandshakeTypeEncryptedExtensions-8]
_ = x[HandshakeTypeCertificate-11]
_ = x[HandshakeTypeCertificateRequest-13]
_ = x[HandshakeTypeCertificateVerify-15]
_ = x[HandshakeTypeFinished-20]
_ = x[HandshakeTypeKeyUpdate-24]
_ = x[HandshakeTypeMessageHash-254]
}
const (
_HandshakeType_name_0 = "client_helloserver_hello"
_HandshakeType_name_1 = "new_session_ticketend_of_early_data"
_HandshakeType_name_2 = "encrypted_extensions"
_HandshakeType_name_3 = "certificate"
_HandshakeType_name_4 = "certificate_request"
_HandshakeType_name_5 = "certificate_verify"
_HandshakeType_name_6 = "finished"
_HandshakeType_name_7 = "key_update"
_HandshakeType_name_8 = "message_hash"
)
var (
_HandshakeType_index_0 = [...]uint8{0, 12, 24}
_HandshakeType_index_1 = [...]uint8{0, 18, 35}
)
func (i HandshakeType) String() string {
switch {
case 1 <= i && i <= 2:
i -= 1
return _HandshakeType_name_0[_HandshakeType_index_0[i]:_HandshakeType_index_0[i+1]]
case 4 <= i && i <= 5:
i -= 4
return _HandshakeType_name_1[_HandshakeType_index_1[i]:_HandshakeType_index_1[i+1]]
case i == 8:
return _HandshakeType_name_2
case i == 11:
return _HandshakeType_name_3
case i == 13:
return _HandshakeType_name_4
case i == 15:
return _HandshakeType_name_5
case i == 20:
return _HandshakeType_name_6
case i == 24:
return _HandshakeType_name_7
case i == 254:
return _HandshakeType_name_8
default:
return "HandshakeType(" + strconv.FormatInt(int64(i), 10) + ")"
}
}
func _() {
// An "invalid array index" compiler error signifies that the constant values have changed.
// Re-run the stringer command to generate them again.
var x [1]struct{}
_ = x[ExtServerName-0]
_ = x[ExtMaxFragmentLength-1]
_ = x[ExtStatusRequest-5]
_ = x[ExtSupportedGroups-10]
_ = x[ExtECPointFormats-11]
_ = x[ExtSignatureAlgorithms-13]
_ = x[ExtALPN-16]
_ = x[ExtSignedCertificateTimestamp-18]
_ = x[ExtPadding-21]
_ = x[ExtExtendedMasterSecret-23]
_ = x[ExtCompressCertificate-27]
_ = x[ExtRecordSizeLimit-28]
_ = x[ExtSessionTicket-35]
_ = x[ExtPreSharedKey-41]
_ = x[ExtEarlyData-42]
_ = x[ExtSupportedVersions-43]
_ = x[ExtCookie-44]
_ = x[ExtPSKKeyExchangeModes-45]
_ = x[ExtCertificateAuthorities-47]
_ = x[ExtSignatureAlgorithmsCert-50]
_ = x[ExtKeyShare-51]
_ = x[ExtApplicationSettings-17513]
_ = x[ExtEncryptedClientHello-65037]
_ = x[ExtRenegotiationInfo-65281]
}
const _ExtensionType_name = "server_namemax_fragment_lengthstatus_requestsupported_groupsec_point_formatssignature_algorithmsapplication_layer_protocol_negotiationsigned_certificate_timestamppaddingextended_master_secretcompress_certificaterecord_size_limitsession_ticketpre_shared_keyearly_datasupported_versionscookiepsk_key_exchange_modescertificate_authoritiessignature_algorithms_certkey_shareapplication_settingsencrypted_client_hellorenegotiation_info"
var _ExtensionType_map = map[ExtensionType]string{
0: _ExtensionType_name[0:11],
1: _ExtensionType_name[11:30],
5: _ExtensionType_name[30:44],
10: _ExtensionType_name[44:60],
11: _ExtensionType_name[60:76],
13: _ExtensionType_name[76:96],
16: _ExtensionType_name[96:134],
18: _ExtensionType_name[134:162],
21: _ExtensionType_name[162:169],
23: _ExtensionType_name[169:191],
27: _ExtensionType_name[191:211],
28: _ExtensionType_name[211:228],
35: _ExtensionType_name[228:242],
41: _ExtensionType_name[242:256],
42: _ExtensionType_name[256:266],
43: _ExtensionType_name[266:284],
44: _ExtensionType_name[284:290],
45: _ExtensionType_name[290:312],
47: _ExtensionType_name[312:335],
50: _ExtensionType_name[335:360],
51: _ExtensionType_name[360:369],
17513: _ExtensionType_name[369:389],
65037: _ExtensionType_name[389:411],
65281: _ExtensionType_name[411:429],
}
func (i ExtensionType) String() string {
if str, ok := _ExtensionType_map[i]; ok {
return str
}
return "ExtensionType(" + strconv.FormatInt(int64(i), 10) + ")"
}
func _() {
// An "invalid array index" compiler error signifies that the constant values have changed.
// Re-run the stringer command to generate them again.
var x [1]struct{}
_ = x[AlertCloseNotify-0]
_ = x[AlertUnexpectedMessage-10]
_ = x[AlertBadRecordMAC-20]
_ = x[AlertRecordOverflow-22]
_ = x[AlertHandshakeFailure-40]
_ = x[AlertBadCertificate-42]
_ = x[AlertUnsupportedCertificate-43]
_ = x[AlertCertificateRevoked-44]
_ = x[AlertCertificateExpired-45]
_ = x[AlertCertificateUnknown-46]
_ = x[AlertIllegalParameter-47]
_ = x[AlertUnknownCA-48]
_ = x[AlertAccessDenied-49]
_ = x[AlertDecodeError-50]
_ = x[AlertDecryptError-51]
_ = x[AlertProtocolVersion-70]
_ = x[AlertInsufficientSecurity-71]
_ = x[AlertInternalError-80]
_ = x[AlertInappropriateFallback-86]
_ = x[AlertUserCanceled-90]
_ = x[AlertMissingExtension-109]
_ = x[AlertUnsupportedExtension-110]
_ = x[AlertUnrecognizedName-112]
_ = x[AlertBadCertificateStatusResponse-113]
_ = x[AlertUnknownPSKIdentity-115]
_ = x[AlertCertificateRequired-116]
_ = x[AlertNoApplicationProtocol-120]
}
const _AlertDescription_name = "close_notifyunexpected_messagebad_record_macrecord_overflowhandshake_failurebad_certificateunsupported_certificatecertificate_revokedcertificate_expiredcertificate_unknownillegal_parameterunknown_caaccess_denieddecode_errordecrypt_errorprotocol_versioninsufficient_securityinternal_errorinappropriate_fallbackuser_canceledmissing_extensionunsupported_extensionunrecognized_namebad_certificate_status_responseunknown_psk_identitycertificate_requiredno_application_protocol"
var _AlertDescription_map = map[AlertDescription]string{
0: _AlertDescription_name[0:12],
10: _AlertDescription_name[12:30],
20: _AlertDescription_name[30:44],
22: _AlertDescription_name[44:59],
40: _AlertDescription_name[59:76],
42: _AlertDescription_name[76:91],
43: _AlertDescription_name[91:114],
44: _AlertDescription_name[114:133],
45: _AlertDescription_name[133:152],
46: _AlertDescription_name[152:171],
47: _AlertDescription_name[171:188],
48: _AlertDescription_name[188:198],
49: _AlertDescription_name[198:211],
50: _AlertDescription_name[211:223],
51: _AlertDescription_name[223:236],
70: _AlertDescription_name[236:252],
71: _AlertDescription_name[252:273],
80: _AlertDescription_name[273:287],
86: _AlertDescription_name[287:309],
90: _AlertDescription_name[309:322],
109: _AlertDescription_name[322:339],
110: _AlertDescription_name[339:360],
112: _AlertDescription_name[360:377],
113: _AlertDescription_name[377:408],
115: _AlertDescription_name[408:428],
116: _AlertDescription_name[428:448],
120: _AlertDescription_name[448:471],
}
func (i AlertDescription) String() string {
if str, ok := _AlertDescription_map[i]; ok {
return str
}
return "AlertDescription(" + strconv.FormatInt(int64(i), 10) + ")"
}
func _() {
// An "invalid array index" compiler error signifies that the constant values have changed.
// Re-run the stringer command to generate them again.
var x [1]struct{}
_ = x[AlertLevelWarning-1]
_ = x[AlertLevelFatal-2]
}
const _AlertLevel_name = "warningfatal"
var _AlertLevel_index = [...]uint8{0, 7, 12}
func (i AlertLevel) String() string {
i -= 1
if i >= AlertLevel(len(_AlertLevel_index)-1) {
return "AlertLevel(" + strconv.FormatInt(int64(i+1), 10) + ")"
}
return _AlertLevel_name[_AlertLevel_index[i]:_AlertLevel_index[i+1]]
}
func _() {
// An "invalid array index" compiler error signifies that the constant values have changed.
// Re-run the stringer command to generate them again.
var x [1]struct{}
_ = x[GroupSECP256R1-23]
_ = x[GroupSECP384R1-24]
_ = x[GroupSECP521R1-25]
_ = x[GroupX25519-29]
_ = x[GroupX448-30]
_ = x[GroupX25519MLKEM768-4588]
}
const (
_NamedGroup_name_0 = "secp256r1secp384r1secp521r1"
_NamedGroup_name_1 = "x25519x448"
_NamedGroup_name_2 = "x25519mlkem768"
)
var (
_NamedGroup_index_0 = [...]uint8{0, 9, 18, 27}
_NamedGroup_index_1 = [...]uint8{0, 6, 10}
)
func (i NamedGroup) String() string {
switch {
case 23 <= i && i <= 25:
i -= 23
return _NamedGroup_name_0[_NamedGroup_index_0[i]:_NamedGroup_index_0[i+1]]
case 29 <= i && i <= 30:
i -= 29
return _NamedGroup_name_1[_NamedGroup_index_1[i]:_NamedGroup_index_1[i+1]]
case i == 4588:
return _NamedGroup_name_2
default:
return "NamedGroup(" + strconv.FormatInt(int64(i), 10) + ")"
}
}
func _() {
// An "invalid array index" compiler error signifies that the constant values have changed.
// Re-run the stringer command to generate them again.
var x [1]struct{}
_ = x[SigRSAPKCS1SHA256-1025]
_ = x[SigRSAPKCS1SHA384-1281]
_ = x[SigRSAPKCS1SHA512-1537]
_ = x[SigECDSAP256SHA256-1027]
_ = x[SigECDSAP384SHA384-1283]
_ = x[SigECDSAP521SHA512-1539]
_ = x[SigRSAPSSRSAESHA256-2052]
_ = x[SigRSAPSSRSAESHA384-2053]
_ = x[SigRSAPSSRSAESHA512-2054]
_ = x[SigEd25519-2055]
_ = x[SigRSAPSSPSSSHA256-2057]
}
const (
_SignatureScheme_name_0 = "rsa_pkcs1_sha256"
_SignatureScheme_name_1 = "ecdsa_secp256r1_sha256"
_SignatureScheme_name_2 = "rsa_pkcs1_sha384"
_SignatureScheme_name_3 = "ecdsa_secp384r1_sha384"
_SignatureScheme_name_4 = "rsa_pkcs1_sha512"
_SignatureScheme_name_5 = "ecdsa_secp521r1_sha512"
_SignatureScheme_name_6 = "rsa_pss_rsae_sha256rsa_pss_rsae_sha384rsa_pss_rsae_sha512ed25519"
_SignatureScheme_name_7 = "rsa_pss_pss_sha256"
)
var (
_SignatureScheme_index_6 = [...]uint8{0, 19, 38, 57, 64}
)
func (i SignatureScheme) String() string {
switch {
case i == 1025:
return _SignatureScheme_name_0
case i == 1027:
return _SignatureScheme_name_1
case i == 1281:
return _SignatureScheme_name_2
case i == 1283:
return _SignatureScheme_name_3
case i == 1537:
return _SignatureScheme_name_4
case i == 1539:
return _SignatureScheme_name_5
case 2052 <= i && i <= 2055:
i -= 2052
return _SignatureScheme_name_6[_SignatureScheme_index_6[i]:_SignatureScheme_index_6[i+1]]
case i == 2057:
return _SignatureScheme_name_7
default:
return "SignatureScheme(" + strconv.FormatInt(int64(i), 10) + ")"
}
}
func _() {
// An "invalid array index" compiler error signifies that the constant values have changed.
// Re-run the stringer command to generate them again.
var x [1]struct{}
_ = x[SuiteAES128GCMSHA256-4865]
_ = x[SuiteAES256GCMSHA384-4866]
_ = x[SuiteChaCha20Poly1305SHA256-4867]
_ = x[SuiteAES128CCMSHA256-4868]
_ = x[SuiteAES128CCM8SHA256-4869]
}
const _CipherSuite_name = "TLS_AES_128_GCM_SHA256TLS_AES_256_GCM_SHA384TLS_CHACHA20_POLY1305_SHA256TLS_AES_128_CCM_SHA256TLS_AES_128_CCM_8_SHA256"
var _CipherSuite_index = [...]uint8{0, 22, 44, 72, 94, 118}
func (i CipherSuite) String() string {
i -= 4865
if i >= CipherSuite(len(_CipherSuite_index)-1) {
return "CipherSuite(" + strconv.FormatInt(int64(i+4865), 10) + ")"
}
return _CipherSuite_name[_CipherSuite_index[i]:_CipherSuite_index[i+1]]
}
+122
View File
@@ -0,0 +1,122 @@
package tls
// StringConst methods name values as String does but always return a
// compile-time constant, unlike String which formats an unrecognized value with
// strconv. Wire values are attacker controlled, so decoders and logs on
// embedded targets use StringConst and print the number alongside it.
const (
// nameGREASE names the reserved values of RFC 8701, which carry no meaning.
nameGREASE = "GREASE"
// nameUnknown names a value this package does not recognize. Other RFCs may
// well define it: this is TLS 1.3 only.
nameUnknown = "unknown"
)
// StringConst returns the content type's name, or "unknown".
func (v ContentType) StringConst() string {
switch v {
case ContentTypeInvalid, ContentTypeChangeCipherSpec, ContentTypeAlert,
ContentTypeHandshake, ContentTypeApplicationData:
return v.String()
}
return nameUnknown
}
// StringConst returns the handshake message type's name, or "unknown".
func (v HandshakeType) StringConst() string {
switch v {
case HandshakeTypeClientHello, HandshakeTypeServerHello, HandshakeTypeNewSessionTicket,
HandshakeTypeEndOfEarlyData, HandshakeTypeEncryptedExtensions, HandshakeTypeCertificate,
HandshakeTypeCertificateRequest, HandshakeTypeCertificateVerify, HandshakeTypeFinished,
HandshakeTypeKeyUpdate, HandshakeTypeMessageHash:
return v.String()
}
return nameUnknown
}
// StringConst returns the extension type's name, "GREASE" or "unknown".
func (v ExtensionType) StringConst() string {
switch v {
case ExtServerName, ExtMaxFragmentLength, ExtStatusRequest, ExtSupportedGroups,
ExtECPointFormats, ExtSignatureAlgorithms, ExtALPN, ExtSignedCertificateTimestamp,
ExtPadding, ExtExtendedMasterSecret, ExtCompressCertificate, ExtRecordSizeLimit,
ExtSessionTicket, ExtPreSharedKey, ExtEarlyData, ExtSupportedVersions, ExtCookie,
ExtPSKKeyExchangeModes, ExtCertificateAuthorities, ExtSignatureAlgorithmsCert,
ExtKeyShare, ExtApplicationSettings, ExtEncryptedClientHello, ExtRenegotiationInfo:
return v.String()
}
if IsGREASE(uint16(v)) {
return nameGREASE
}
return nameUnknown
}
// StringConst returns the alert level's name, or "unknown".
func (v AlertLevel) StringConst() string {
switch v {
case AlertLevelWarning, AlertLevelFatal:
return v.String()
}
return nameUnknown
}
// StringConst returns the alert description's name, or "unknown".
func (v AlertDescription) StringConst() string {
switch v {
case AlertCloseNotify, AlertUnexpectedMessage, AlertBadRecordMAC, AlertRecordOverflow,
AlertHandshakeFailure, AlertBadCertificate, AlertUnsupportedCertificate,
AlertCertificateRevoked, AlertCertificateExpired, AlertCertificateUnknown,
AlertIllegalParameter, AlertUnknownCA, AlertAccessDenied, AlertDecodeError,
AlertDecryptError, AlertProtocolVersion, AlertInsufficientSecurity,
AlertInternalError, AlertInappropriateFallback, AlertUserCanceled,
AlertMissingExtension, AlertUnsupportedExtension, AlertUnrecognizedName,
AlertBadCertificateStatusResponse, AlertUnknownPSKIdentity,
AlertCertificateRequired, AlertNoApplicationProtocol:
return v.String()
}
return nameUnknown
}
// StringConst returns the named group's name, "GREASE" or "unknown".
func (v NamedGroup) StringConst() string {
switch v {
case GroupSECP256R1, GroupSECP384R1, GroupSECP521R1,
GroupX25519, GroupX448, GroupX25519MLKEM768:
return v.String()
}
if IsGREASE(uint16(v)) {
return nameGREASE
}
return nameUnknown
}
// StringConst returns the signature scheme's name, "GREASE" or "unknown".
func (v SignatureScheme) StringConst() string {
switch v {
case SigRSAPKCS1SHA256, SigRSAPKCS1SHA384, SigRSAPKCS1SHA512,
SigECDSAP256SHA256, SigECDSAP384SHA384, SigECDSAP521SHA512,
SigRSAPSSRSAESHA256, SigRSAPSSRSAESHA384, SigRSAPSSRSAESHA512,
SigEd25519, SigRSAPSSPSSSHA256:
return v.String()
}
if IsGREASE(uint16(v)) {
return nameGREASE
}
return nameUnknown
}
// StringConst returns the cipher suite's name, "GREASE" or "unknown".
// Every TLS 1.2 suite a browser still offers is undefined here: this package
// implements TLS 1.3 only.
func (v CipherSuite) StringConst() string {
switch v {
case SuiteAES128GCMSHA256, SuiteAES256GCMSHA384, SuiteChaCha20Poly1305SHA256,
SuiteAES128CCMSHA256, SuiteAES128CCM8SHA256:
return v.String()
}
if IsGREASE(uint16(v)) {
return nameGREASE
}
return nameUnknown
}
+73
View File
@@ -0,0 +1,73 @@
package tls_test
import (
"strings"
"testing"
"github.com/soypat/lneto/x/tls"
)
// StringConst must name defined values as String does, GREASE values "GREASE"
// and everything else "unknown", over the whole range and without allocating.
// A constant added without extending a StringConst switch fails here.
func TestStringConst(t *testing.T) {
for _, tc := range []struct {
name string
n int
grease bool // type carries GREASE values
str func(int) string
cst func(int) string
}{
{"ContentType", 1 << 8, false,
func(i int) string { return tls.ContentType(i).String() },
func(i int) string { return tls.ContentType(i).StringConst() }},
{"HandshakeType", 1 << 8, false,
func(i int) string { return tls.HandshakeType(i).String() },
func(i int) string { return tls.HandshakeType(i).StringConst() }},
{"AlertLevel", 1 << 8, false,
func(i int) string { return tls.AlertLevel(i).String() },
func(i int) string { return tls.AlertLevel(i).StringConst() }},
{"AlertDescription", 1 << 8, false,
func(i int) string { return tls.AlertDescription(i).String() },
func(i int) string { return tls.AlertDescription(i).StringConst() }},
{"ExtensionType", 1 << 16, true,
func(i int) string { return tls.ExtensionType(i).String() },
func(i int) string { return tls.ExtensionType(i).StringConst() }},
{"NamedGroup", 1 << 16, true,
func(i int) string { return tls.NamedGroup(i).String() },
func(i int) string { return tls.NamedGroup(i).StringConst() }},
{"SignatureScheme", 1 << 16, true,
func(i int) string { return tls.SignatureScheme(i).String() },
func(i int) string { return tls.SignatureScheme(i).StringConst() }},
{"CipherSuite", 1 << 16, true,
func(i int) string { return tls.CipherSuite(i).String() },
func(i int) string { return tls.CipherSuite(i).StringConst() }},
} {
t.Run(tc.name, func(t *testing.T) {
for i := range tc.n {
str, cst := tc.str(i), tc.cst(i)
if !strings.ContainsRune(str, '(') { // stringer names undefined values "Type(9)".
if cst != str {
t.Fatalf("%s(%d)=%q want %q", tc.name, i, cst, str)
}
continue
}
want := "unknown"
if tc.grease && tls.IsGREASE(uint16(i)) {
want = "GREASE"
}
if cst != want {
t.Fatalf("%s(%d)=%q want %q", tc.name, i, cst, want)
}
}
allocs := testing.AllocsPerRun(1, func() {
for i := range tc.n {
_ = tc.cst(i)
}
})
if allocs != 0 {
t.Errorf("%s allocated %v times", tc.name, allocs)
}
})
}
}