parser.go 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357
  1. // Copyright (c) 2018, Open Systems AG. All rights reserved.
  2. //
  3. // Use of this source code is governed by a BSD-style license
  4. // that can be found in the LICENSE file in the root of the source
  5. // tree.
  6. package ja3
  7. import (
  8. "encoding/binary"
  9. "strconv"
  10. )
  11. const (
  12. // Constants used for parsing
  13. recordLayerHeaderLen int = 5
  14. handshakeHeaderLen int = 6
  15. randomDataLen int = 32
  16. sessionIDHeaderLen int = 1
  17. cipherSuiteHeaderLen int = 2
  18. compressMethodHeaderLen int = 1
  19. extensionsHeaderLen int = 2
  20. extensionHeaderLen int = 4
  21. sniExtensionHeaderLen int = 5
  22. ecExtensionHeaderLen int = 2
  23. ecpfExtensionHeaderLen int = 1
  24. versionExtensionHeaderLen int = 1
  25. signatureAlgorithmsExtensionHeaderLen int = 2
  26. contentType uint8 = 22
  27. handshakeType uint8 = 1
  28. sniExtensionType uint16 = 0
  29. sniNameDNSHostnameType uint8 = 0
  30. ecExtensionType uint16 = 10
  31. ecpfExtensionType uint16 = 11
  32. versionExtensionType uint16 = 43
  33. signatureAlgorithmsExtensionType uint16 = 13
  34. // Versions
  35. // The bitmask covers the versions SSL3.0 to TLS1.2
  36. tlsVersionBitmask uint16 = 0xFFFC
  37. tls13 uint16 = 0x0304
  38. // GREASE values
  39. // The bitmask covers all GREASE values
  40. GreaseBitmask uint16 = 0x0F0F
  41. // Constants used for marshalling
  42. dashByte = byte(45)
  43. commaByte = byte(44)
  44. )
  45. // parseSegment to populate the corresponding ClientHello object or return an error
  46. func (j *ClientHello) parseSegment(segment []byte) error {
  47. // Check if we can decode the next fields
  48. if len(segment) < recordLayerHeaderLen {
  49. return &ParseError{LengthErr, 1}
  50. }
  51. // Check if we have "Content Type: Handshake (22)"
  52. contType := uint8(segment[0])
  53. if contType != contentType {
  54. return &ParseError{errType: ContentTypeErr}
  55. }
  56. // Check if TLS record layer version is supported
  57. tlsRecordVersion := uint16(segment[1])<<8 | uint16(segment[2])
  58. if tlsRecordVersion&tlsVersionBitmask != 0x0300 && tlsRecordVersion != tls13 {
  59. return &ParseError{VersionErr, 1}
  60. }
  61. // Check that the Handshake is as long as expected from the length field
  62. segmentLen := uint16(segment[3])<<8 | uint16(segment[4])
  63. if len(segment[recordLayerHeaderLen:]) < int(segmentLen) {
  64. return &ParseError{LengthErr, 2}
  65. }
  66. // Keep the Handshake messege, ignore any additional following record types
  67. hs := segment[recordLayerHeaderLen : recordLayerHeaderLen+int(segmentLen)]
  68. err := j.parseHandshake(hs)
  69. return err
  70. }
  71. // parseHandshake body
  72. func (j *ClientHello) parseHandshake(hs []byte) error {
  73. // Check if we can decode the next fields
  74. if len(hs) < handshakeHeaderLen+randomDataLen+sessionIDHeaderLen {
  75. return &ParseError{LengthErr, 3}
  76. }
  77. // Check if we have "Handshake Type: Client Hello (1)"
  78. handshType := uint8(hs[0])
  79. if handshType != handshakeType {
  80. return &ParseError{errType: HandshakeTypeErr}
  81. }
  82. // Check if actual length of handshake matches (this is a great exclusion criterion for false positives,
  83. // as these fields have to match the actual length of the rest of the segment)
  84. handshakeLen := uint32(hs[1])<<16 | uint32(hs[2])<<8 | uint32(hs[3])
  85. if len(hs[4:]) != int(handshakeLen) {
  86. return &ParseError{LengthErr, 4}
  87. }
  88. // Check if Client Hello version is supported
  89. tlsVersion := uint16(hs[4])<<8 | uint16(hs[5])
  90. if tlsVersion&tlsVersionBitmask != 0x0300 && tlsVersion != tls13 {
  91. return &ParseError{VersionErr, 2}
  92. }
  93. j.Version = tlsVersion
  94. // Check if we can decode the next fields
  95. sessionIDLen := uint8(hs[38])
  96. if len(hs) < handshakeHeaderLen+randomDataLen+sessionIDHeaderLen+int(sessionIDLen) {
  97. return &ParseError{LengthErr, 5}
  98. }
  99. // Cipher Suites
  100. cs := hs[handshakeHeaderLen+randomDataLen+sessionIDHeaderLen+int(sessionIDLen):]
  101. // Check if we can decode the next fields
  102. if len(cs) < cipherSuiteHeaderLen {
  103. return &ParseError{LengthErr, 6}
  104. }
  105. csLen := uint16(cs[0])<<8 | uint16(cs[1])
  106. numCiphers := int(csLen / 2)
  107. cipherSuites := make([]uint16, 0, numCiphers)
  108. // Check if we can decode the next fields
  109. if len(cs) < cipherSuiteHeaderLen+int(csLen)+compressMethodHeaderLen {
  110. return &ParseError{LengthErr, 7}
  111. }
  112. for i := 0; i < numCiphers; i++ {
  113. cipherSuite := uint16(cs[2+i<<1])<<8 | uint16(cs[3+i<<1])
  114. cipherSuites = append(cipherSuites, cipherSuite)
  115. }
  116. j.CipherSuites = cipherSuites
  117. // Check if we can decode the next fields
  118. compressMethodLen := uint16(cs[cipherSuiteHeaderLen+int(csLen)])
  119. if len(cs) < cipherSuiteHeaderLen+int(csLen)+compressMethodHeaderLen+int(compressMethodLen) {
  120. return &ParseError{LengthErr, 8}
  121. }
  122. // Extensions
  123. exs := cs[cipherSuiteHeaderLen+int(csLen)+compressMethodHeaderLen+int(compressMethodLen):]
  124. err := j.parseExtensions(exs)
  125. return err
  126. }
  127. // parseExtensions of the handshake
  128. func (j *ClientHello) parseExtensions(exs []byte) error {
  129. // Check for no extensions, this fields header is nonexistent if no body is used
  130. if len(exs) == 0 {
  131. return nil
  132. }
  133. // Check if we can decode the next fields
  134. if len(exs) < extensionsHeaderLen {
  135. return &ParseError{LengthErr, 9}
  136. }
  137. exsLen := uint16(exs[0])<<8 | uint16(exs[1])
  138. exs = exs[extensionsHeaderLen:]
  139. // Check if we can decode the next fields
  140. if len(exs) < int(exsLen) {
  141. return &ParseError{LengthErr, 10}
  142. }
  143. var sni []byte
  144. var extensions, ellipticCurves []uint16
  145. var ellipticCurvePF []uint8
  146. var versions []uint16
  147. var signatureAlgorithms []uint16
  148. for len(exs) > 0 {
  149. // Check if we can decode the next fields
  150. if len(exs) < extensionHeaderLen {
  151. return &ParseError{LengthErr, 11}
  152. }
  153. exType := uint16(exs[0])<<8 | uint16(exs[1])
  154. exLen := uint16(exs[2])<<8 | uint16(exs[3])
  155. // Ignore any GREASE extensions
  156. extensions = append(extensions, exType)
  157. // Check if we can decode the next fields
  158. if len(exs) < extensionHeaderLen+int(exLen) {
  159. return &ParseError{LengthErr, 12}
  160. }
  161. sex := exs[extensionHeaderLen : extensionHeaderLen+int(exLen)]
  162. switch exType {
  163. case sniExtensionType: // Extensions: server_name
  164. // Check if we can decode the next fields
  165. if len(sex) < sniExtensionHeaderLen {
  166. return &ParseError{LengthErr, 13}
  167. }
  168. sniType := uint8(sex[2])
  169. sniLen := uint16(sex[3])<<8 | uint16(sex[4])
  170. sex = sex[sniExtensionHeaderLen:]
  171. // Check if we can decode the next fields
  172. if len(sex) != int(sniLen) {
  173. return &ParseError{LengthErr, 14}
  174. }
  175. switch sniType {
  176. case sniNameDNSHostnameType:
  177. sni = sex
  178. default:
  179. return &ParseError{errType: SNITypeErr}
  180. }
  181. case ecExtensionType: // Extensions: supported_groups
  182. // Check if we can decode the next fields
  183. if len(sex) < ecExtensionHeaderLen {
  184. return &ParseError{LengthErr, 15}
  185. }
  186. ecsLen := uint16(sex[0])<<8 | uint16(sex[1])
  187. numCurves := int(ecsLen / 2)
  188. ellipticCurves = make([]uint16, 0, numCurves)
  189. sex = sex[ecExtensionHeaderLen:]
  190. // Check if we can decode the next fields
  191. if len(sex) != int(ecsLen) {
  192. return &ParseError{LengthErr, 16}
  193. }
  194. for i := 0; i < numCurves; i++ {
  195. ecType := uint16(sex[i*2])<<8 | uint16(sex[1+i*2])
  196. ellipticCurves = append(ellipticCurves, ecType)
  197. }
  198. case ecpfExtensionType: // Extensions: ec_point_formats
  199. // Check if we can decode the next fields
  200. if len(sex) < ecpfExtensionHeaderLen {
  201. return &ParseError{LengthErr, 17}
  202. }
  203. ecpfsLen := uint8(sex[0])
  204. numPF := int(ecpfsLen)
  205. ellipticCurvePF = make([]uint8, numPF)
  206. sex = sex[ecpfExtensionHeaderLen:]
  207. // Check if we can decode the next fields
  208. if len(sex) != numPF {
  209. return &ParseError{LengthErr, 18}
  210. }
  211. for i := 0; i < numPF; i++ {
  212. ellipticCurvePF[i] = uint8(sex[i])
  213. }
  214. case versionExtensionType:
  215. if len(sex) < versionExtensionHeaderLen {
  216. return &ParseError{LengthErr, 19}
  217. }
  218. versionsLen := int(sex[0])
  219. for i := 0; i < versionsLen; i += 2 {
  220. versions = append(versions, binary.BigEndian.Uint16(sex[1:][i:]))
  221. }
  222. case signatureAlgorithmsExtensionType:
  223. if len(sex) < signatureAlgorithmsExtensionHeaderLen {
  224. return &ParseError{LengthErr, 20}
  225. }
  226. ssaLen := binary.BigEndian.Uint16(sex)
  227. for i := 0; i < int(ssaLen); i += 2 {
  228. signatureAlgorithms = append(signatureAlgorithms, binary.BigEndian.Uint16(sex[2:][i:]))
  229. }
  230. }
  231. exs = exs[4+exLen:]
  232. }
  233. j.ServerName = string(sni)
  234. j.Extensions = extensions
  235. j.EllipticCurves = ellipticCurves
  236. j.EllipticCurvePF = ellipticCurvePF
  237. j.Versions = versions
  238. j.SignatureAlgorithms = signatureAlgorithms
  239. return nil
  240. }
  241. // marshalJA3 into a byte string
  242. func (j *ClientHello) marshalJA3() {
  243. // An uint16 can contain numbers with up to 5 digits and an uint8 can contain numbers with up to 3 digits, but we
  244. // also need a byte for each separating character, except at the end.
  245. byteStringLen := 6*(1+len(j.CipherSuites)+len(j.Extensions)+len(j.EllipticCurves)) + 4*len(j.EllipticCurvePF) - 1
  246. byteString := make([]byte, 0, byteStringLen)
  247. // Version
  248. byteString = strconv.AppendUint(byteString, uint64(j.Version), 10)
  249. byteString = append(byteString, commaByte)
  250. // Cipher Suites
  251. if len(j.CipherSuites) != 0 {
  252. for _, val := range j.CipherSuites {
  253. if val&GreaseBitmask != 0x0A0A {
  254. continue
  255. }
  256. byteString = strconv.AppendUint(byteString, uint64(val), 10)
  257. byteString = append(byteString, dashByte)
  258. }
  259. // Replace last dash with a comma
  260. byteString[len(byteString)-1] = commaByte
  261. } else {
  262. byteString = append(byteString, commaByte)
  263. }
  264. // Extensions
  265. if len(j.Extensions) != 0 {
  266. for _, val := range j.Extensions {
  267. if val&GreaseBitmask != 0x0A0A {
  268. continue
  269. }
  270. byteString = strconv.AppendUint(byteString, uint64(val), 10)
  271. byteString = append(byteString, dashByte)
  272. }
  273. // Replace last dash with a comma
  274. byteString[len(byteString)-1] = commaByte
  275. } else {
  276. byteString = append(byteString, commaByte)
  277. }
  278. // Elliptic curves
  279. if len(j.EllipticCurves) != 0 {
  280. for _, val := range j.EllipticCurves {
  281. if val&GreaseBitmask != 0x0A0A {
  282. continue
  283. }
  284. byteString = strconv.AppendUint(byteString, uint64(val), 10)
  285. byteString = append(byteString, dashByte)
  286. }
  287. // Replace last dash with a comma
  288. byteString[len(byteString)-1] = commaByte
  289. } else {
  290. byteString = append(byteString, commaByte)
  291. }
  292. // ECPF
  293. if len(j.EllipticCurvePF) != 0 {
  294. for _, val := range j.EllipticCurvePF {
  295. byteString = strconv.AppendUint(byteString, uint64(val), 10)
  296. byteString = append(byteString, dashByte)
  297. }
  298. // Remove last dash
  299. byteString = byteString[:len(byteString)-1]
  300. }
  301. j.ja3ByteString = byteString
  302. }