From cb0ae8e15d6ac0f3049db6777a8b0201afb2d829 Mon Sep 17 00:00:00 2001 From: Pierre Date: Fri, 23 Aug 2024 14:40:29 +0200 Subject: [PATCH] Fix JA4 number of cipher suites and extensions (#19) JA4 specification[^1] mentions that the numbers of cipher suites and of extensions should be limited to two characters and that if the values are over 99 we should output 99. That value should never be reached, but it may happen on the Internet. I discovered the bug while implementing stricter JA4 parsing in [IVRE](https://github.com/ivre/ivre)[^2] and parsing logs from fingerproxy. Turns out, at least one (testing) tool[^3] produces a wrong fingerprint with the current implementation: `t12d1120600_e33c72313a64_a1e935682795` (112 extensions) rather than `t12d990600_e33c72313a64_a1e935682795`. The JA4_a part of the wrong fingerprint is 11 characters and IVRE now fails to parse it. This simple patch fixes the issue. [^1]: See [technical details](https://github.com/FoxIO-LLC/ja4/blob/main/technical_details/JA4.md#number-of-ciphers). [^2]: Change: [ff696af5](https://github.com/ivre/ivre/commit/ff696af52d349e38b3bce67a3b4efa99b9a3b6c3#diff-f7cabf3913e3ffe5d6cb6b7b0b2832170b265d64c03cbad89f93c94c0286a076). [^3]: Namely [TLS tester](https://testssl.sh/dev/). --- pkg/ja4/types.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/ja4/types.go b/pkg/ja4/types.go index 028707e..a77d1c6 100644 --- a/pkg/ja4/types.go +++ b/pkg/ja4/types.go @@ -29,8 +29,8 @@ func (x tlsVersion) String() string { } return "00" } -func (x numberOfCipherSuites) String() string { return fmt.Sprintf("%02d", x) } -func (x numberOfExtensions) String() string { return fmt.Sprintf("%02d", x) } +func (x numberOfCipherSuites) String() string { return fmt.Sprintf("%02d", min(x, 99)) } +func (x numberOfExtensions) String() string { return fmt.Sprintf("%02d", min(x, 99)) } func (x cipherSuites) String() string { return joinUint16(x, cipherSuitesSeparator) } func (x extensions) String() string { return joinUint16(x, extensionsSeparator) } func (x signatureAlgorithms) String() string { return joinUint16(x, signatureAlgorithmSeparator) }