refactor isGREASE8 and isGREASE16 into isGREASE

This commit is contained in:
nervuri 2023-09-26 10:07:32 +00:00
parent b1e820afcf
commit 763458fbf1
3 changed files with 37 additions and 49 deletions

View File

@ -18,33 +18,31 @@ import (
"golang.org/x/crypto/cryptobyte"
)
// Check if this is a 16-bit GREASE value (RFC 8701).
func isGREASE16(value uint16) bool {
// Check if this is a GREASE value (RFC 8701).
func isGREASE[N uint16 | uint8](val N) bool {
// Values for: cipher suites, ALPN,
// extensions, named groups, signature algorithms and TLS versions:
greaseValues := [16]uint16{
greaseValues16 := [16]uint16{
0x0a0a, 0x1a1a, 0x2a2a, 0x3a3a, 0x4a4a, 0x5a5a, 0x6a6a, 0x7a7a,
0x8a8a, 0x9a9a, 0xaaaa, 0xbaba, 0xcaca, 0xdada, 0xeaea, 0xfafa,
}
// Run the check
for _, greaseValue := range greaseValues {
if value == greaseValue {
return true
}
}
return false
}
// Check if this is an 8-bit GREASE value (PskKeyExchangeModes) (RFC 8701).
func isGREASE8(value uint8) bool {
// Values for PskKeyExchangeModes:
greaseValues := [8]uint8{
greaseValues8 := [8]uint8{
0x0B, 0x2A, 0x49, 0x68, 0x87, 0xA6, 0xC5, 0xE4,
}
// Run the check
for _, greaseValue := range greaseValues {
if value == greaseValue {
return true
switch any(val).(type) {
case uint16:
for _, greaseValue := range greaseValues16 {
if any(val).(uint16) == greaseValue {
return true
}
}
case uint8:
for _, greaseValue := range greaseValues8 {
if any(val).(uint8) == greaseValue {
return true
}
}
}
return false

View File

@ -12,28 +12,21 @@ import (
"strings"
)
func toString[N uint8 | uint16](val N) string {
func toString[N uint16 | uint8](val N) string {
return strconv.FormatUint(uint64(val), 10)
}
func deGREASE16(val uint16, greaseReplacement string) string {
if isGREASE16(val) {
if greaseReplacement == "" {
return ""
func deGREASE[N uint16 | uint8](val N, replace bool) string {
if isGREASE(val) {
if replace {
switch any(val).(type) {
case uint16:
return "2570-" // generic 16-bit GREASE code 0x0A0A (2570)
default: // uint8
return "11-" // generic 8-bit GREASE code 0x0B (11)
}
} else {
return greaseReplacement + "-"
}
} else {
return toString(val) + "-"
}
}
func deGREASE8(val uint8, greaseReplacement string) string {
if isGREASE8(val) {
if greaseReplacement == "" {
return ""
} else {
return greaseReplacement + "-"
}
} else {
return toString(val) + "-"
@ -44,14 +37,14 @@ func (m *ClientHelloMsg) ja3() {
var codeGroups [5]string
codeGroups[0] = toString(m.TLSVersion.(uint16))
for _, cs := range m.CipherSuites {
codeGroups[1] += deGREASE16(cs.(uint16), "")
codeGroups[1] += deGREASE(cs.(uint16), false)
}
for _, e := range m.Extensions {
codeGroups[2] += deGREASE16(e.Code, "")
codeGroups[2] += deGREASE(e.Code, false)
switch e.Code {
case extensionSupportedGroups:
for _, g := range e.Data.SupportedGroups {
codeGroups[3] += deGREASE16(g.(uint16), "")
codeGroups[3] += deGREASE(g.(uint16), false)
}
case extensionSupportedPointFormats:
for _, pf := range e.Data.SupportedPointFormats {
@ -69,15 +62,12 @@ func (m *ClientHelloMsg) ja3() {
func (m *ClientHelloMsg) nja3() {
const genericGREASECode16 = uint16(0x0a0a) // 2570
const genericGREASECode8 = uint8(0x0B) // 11
var genericGreaseString16 = toString(genericGREASECode16)
var genericGreaseString8 = toString(genericGREASECode8)
var codeGroups [10]string
var extCodes []uint16
codeGroups[0] = toString(m.RecordHeaderTLSVersion.(uint16))
codeGroups[1] = toString(m.TLSVersion.(uint16))
for _, cs := range m.CipherSuites {
codeGroups[2] += deGREASE16(cs.(uint16), genericGreaseString16)
codeGroups[2] += deGREASE(cs.(uint16), true)
}
for _, e := range m.Extensions {
// Ignore conditional extensions.
@ -92,14 +82,14 @@ func (m *ClientHelloMsg) nja3() {
e.Code == extensionChannelIDOld {
continue
}
if isGREASE16(e.Code) {
if isGREASE(e.Code) {
e.Code = genericGREASECode16
}
extCodes = append(extCodes, e.Code)
switch e.Code {
case extensionSupportedGroups:
for _, g := range e.Data.SupportedGroups {
codeGroups[4] += deGREASE16(g.(uint16), genericGreaseString16)
codeGroups[4] += deGREASE(g.(uint16), true)
}
case extensionSupportedPointFormats:
for _, pf := range e.Data.SupportedPointFormats {
@ -107,15 +97,15 @@ func (m *ClientHelloMsg) nja3() {
}
case extensionSupportedVersions:
for _, v := range e.Data.SupportedVersions {
codeGroups[6] += deGREASE16(v.(uint16), genericGreaseString16)
codeGroups[6] += deGREASE(v.(uint16), true)
}
case extensionSignatureAlgorithms:
for _, sa := range e.Data.SupportedSignatureAlgorithms {
codeGroups[7] += deGREASE16(sa.(uint16), genericGreaseString16)
codeGroups[7] += deGREASE(sa.(uint16), true)
}
case extensionPSKModes:
for _, mode := range e.Data.PSKModes {
codeGroups[8] += deGREASE8(mode.(uint8), genericGreaseString8)
codeGroups[8] += deGREASE(mode.(uint8), true)
}
case extensionCompressCertificate:
for _, algo := range e.Data.CertificateCompressionAlgos {
@ -127,7 +117,7 @@ func (m *ClientHelloMsg) nja3() {
sort.Slice(extCodes, func(i, j int) bool { return extCodes[i] < extCodes[j] })
// Add sorted extension codes to NJA3 string.
for _, code := range extCodes {
codeGroups[3] += deGREASE16(code, genericGreaseString16)
codeGroups[3] += deGREASE(code, true)
}
for i, cg := range codeGroups {
codeGroups[i] = strings.TrimSuffix(cg, "-")

View File

@ -125,7 +125,7 @@ func GetSignatureSchemeInfo(sigSchemeCode uint16, mustName bool) SignatureScheme
Code: sigSchemeCode,
HexCode: fmt.Sprintf("%04X", sigSchemeCode),
}
if isGREASE16(sigSchemeCode) {
if isGREASE(sigSchemeCode) {
// As of September 2023, the IANA signature scheme registry
// doesn't include GREASE values, so we need to check here.
info.Name = "GREASE"