github.com/zmap/zcrypto@v0.0.0-20240512203510-0fef58d9a9db/tls/tls_handshake.go (about) 1 // Copyright 2015 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package tls 6 7 import ( 8 "bytes" 9 "encoding/hex" 10 "encoding/json" 11 "errors" 12 "fmt" 13 "strings" 14 15 jsonKeys "github.com/zmap/zcrypto/json" 16 "github.com/zmap/zcrypto/x509" 17 "github.com/zmap/zcrypto/x509/ct" 18 ) 19 20 var ErrUnimplementedCipher error = errors.New("unimplemented cipher suite") 21 var ErrNoMutualCipher error = errors.New("no mutual cipher suite") 22 23 type TLSVersion uint16 24 25 type CipherSuite uint16 26 27 type ClientHello struct { 28 Version TLSVersion `json:"version"` 29 Random []byte `json:"random"` 30 SessionID []byte `json:"session_id,omitempty"` 31 CipherSuites []CipherSuite `json:"cipher_suites"` 32 CompressionMethods []CompressionMethod `json:"compression_methods"` 33 OcspStapling bool `json:"ocsp_stapling"` 34 TicketSupported bool `json:"ticket"` 35 SecureRenegotiation bool `json:"secure_renegotiation"` 36 HeartbeatSupported bool `json:"heartbeat"` 37 ExtendedRandom []byte `json:"extended_random,omitempty"` 38 ExtendedMasterSecret bool `json:"extended_master_secret"` 39 NextProtoNeg bool `json:"next_protocol_negotiation"` 40 ServerName string `json:"server_name,omitempty"` 41 Scts bool `json:"scts"` 42 SupportedCurves []CurveID `json:"supported_curves,omitempty"` 43 SupportedPoints []PointFormat `json:"supported_point_formats,omitempty"` 44 SessionTicket *SessionTicket `json:"session_ticket,omitempty"` 45 SignatureAndHashes []SignatureAndHash `json:"signature_and_hashes,omitempty"` 46 SctEnabled bool `json:"sct_enabled"` 47 AlpnProtocols []string `json:"alpn_protocols,omitempty"` 48 UnknownExtensions [][]byte `json:"unknown_extensions,omitempty"` 49 } 50 51 type ParsedAndRawSCT struct { 52 Raw []byte `json:"raw,omitempty"` 53 Parsed *ct.SignedCertificateTimestamp `json:"parsed,omitempty"` 54 } 55 56 type ServerHello struct { 57 Version TLSVersion `json:"version"` 58 Random []byte `json:"random"` 59 SessionID []byte `json:"session_id"` 60 CipherSuite CipherSuite `json:"cipher_suite"` 61 CompressionMethod CompressionMethod `json:"compression_method"` 62 OcspStapling bool `json:"ocsp_stapling"` 63 TicketSupported bool `json:"ticket"` 64 SecureRenegotiation bool `json:"secure_renegotiation"` 65 HeartbeatSupported bool `json:"heartbeat"` 66 ExtendedRandom []byte `json:"extended_random,omitempty"` 67 ExtendedMasterSecret bool `json:"extended_master_secret"` 68 NextProtoNeg bool `json:"next_protocol_negotiation"` 69 SignedCertificateTimestamps []ParsedAndRawSCT `json:"scts,omitempty"` 70 AlpnProtocol string `json:"alpn_protocol,omitempty"` 71 UnknownExtensions [][]byte `json:"unknown_extensions,omitempty"` 72 } 73 74 // SimpleCertificate holds a *x509.Certificate and a []byte for the certificate 75 type SimpleCertificate struct { 76 Raw []byte `json:"raw,omitempty"` 77 Parsed *x509.Certificate `json:"parsed,omitempty"` 78 } 79 80 // Certificates represents a TLS certificates message in a format friendly to the golang JSON library. 81 // ValidationError should be non-nil whenever Valid is false. 82 type Certificates struct { 83 Certificate SimpleCertificate `json:"certificate,omitempty"` 84 Chain []SimpleCertificate `json:"chain,omitempty"` 85 Validation *x509.Validation `json:"validation,omitempty"` 86 } 87 88 // ServerKeyExchange represents the raw key data sent by the server in TLS key exchange message 89 type ServerKeyExchange struct { 90 Raw []byte `json:"-"` 91 RSAParams *jsonKeys.RSAPublicKey `json:"rsa_params,omitempty"` 92 DHParams *jsonKeys.DHParams `json:"dh_params,omitempty"` 93 ECDHParams *jsonKeys.ECDHParams `json:"ecdh_params,omitempty"` 94 Digest []byte `json:"digest,omitempty"` 95 Signature *DigitalSignature `json:"signature,omitempty"` 96 SignatureError string `json:"signature_error,omitempty"` 97 } 98 99 // ClientKeyExchange represents the raw key data sent by the client in TLS key exchange message 100 type ClientKeyExchange struct { 101 Raw []byte `json:"-"` 102 RSAParams *jsonKeys.RSAClientParams `json:"rsa_params,omitempty"` 103 DHParams *jsonKeys.DHParams `json:"dh_params,omitempty"` 104 ECDHParams *jsonKeys.ECDHParams `json:"ecdh_params,omitempty"` 105 } 106 107 // Finished represents a TLS Finished message 108 type Finished struct { 109 VerifyData []byte `json:"verify_data"` 110 } 111 112 // SessionTicket represents the new session ticket sent by the server to the 113 // client 114 type SessionTicket struct { 115 Value []uint8 `json:"value,omitempty"` 116 Length int `json:"length,omitempty"` 117 LifetimeHint uint32 `json:"lifetime_hint,omitempty"` 118 } 119 120 type MasterSecret struct { 121 Value []byte `json:"value,omitempty"` 122 Length int `json:"length,omitempty"` 123 } 124 125 type PreMasterSecret struct { 126 Value []byte `json:"value,omitempty"` 127 Length int `json:"length,omitempty"` 128 } 129 130 // KeyMaterial explicitly represent the cryptographic values negotiated by 131 // the client and server 132 type KeyMaterial struct { 133 MasterSecret *MasterSecret `json:"master_secret,omitempty"` 134 PreMasterSecret *PreMasterSecret `json:"pre_master_secret,omitempty"` 135 } 136 137 // ServerHandshake stores all of the messages sent by the server during a standard TLS Handshake. 138 // It implements zgrab.EventData interface 139 type ServerHandshake struct { 140 ClientHello *ClientHello `json:"client_hello,omitempty" zgrab:"debug"` 141 ServerHello *ServerHello `json:"server_hello,omitempty"` 142 ServerCertificates *Certificates `json:"server_certificates,omitempty"` 143 ServerKeyExchange *ServerKeyExchange `json:"server_key_exchange,omitempty"` 144 ClientKeyExchange *ClientKeyExchange `json:"client_key_exchange,omitempty"` 145 ClientFinished *Finished `json:"client_finished,omitempty"` 146 SessionTicket *SessionTicket `json:"session_ticket,omitempty"` 147 ServerFinished *Finished `json:"server_finished,omitempty"` 148 KeyMaterial *KeyMaterial `json:"key_material,omitempty"` 149 } 150 151 // MarshalJSON implements the json.Marshler interface 152 func (v *TLSVersion) MarshalJSON() ([]byte, error) { 153 aux := struct { 154 Name string `json:"name"` 155 Value int `json:"value"` 156 }{ 157 Name: v.String(), 158 Value: int(*v), 159 } 160 return json.Marshal(&aux) 161 } 162 163 // UnmarshalJSON implements the json.Unmarshaler interface 164 func (v *TLSVersion) UnmarshalJSON(b []byte) error { 165 aux := struct { 166 Name string `json:"name"` 167 Value int `json:"value"` 168 }{} 169 if err := json.Unmarshal(b, &aux); err != nil { 170 return err 171 } 172 *v = TLSVersion(aux.Value) 173 if expectedName := v.String(); expectedName != aux.Name { 174 return fmt.Errorf("mismatched tls version and name: version: %d, name: %s, expected name: %s", aux.Value, aux.Name, expectedName) 175 } 176 return nil 177 } 178 179 // MarshalJSON implements the json.Marshler interface 180 func (cs *CipherSuite) MarshalJSON() ([]byte, error) { 181 buf := make([]byte, 2) 182 buf[0] = byte(*cs >> 8) 183 buf[1] = byte(*cs) 184 enc := strings.ToUpper(hex.EncodeToString(buf)) 185 aux := struct { 186 Hex string `json:"hex"` 187 Name string `json:"name"` 188 Value int `json:"value"` 189 }{ 190 Hex: fmt.Sprintf("0x%s", enc), 191 Name: cs.String(), 192 Value: int(*cs), 193 } 194 return json.Marshal(&aux) 195 } 196 197 // UnmarshalJSON implements the json.Unmarshaler interface 198 func (cs *CipherSuite) UnmarshalJSON(b []byte) error { 199 aux := struct { 200 Hex string `json:"hex"` 201 Name string `json:"name"` 202 Value uint16 `json:"value"` 203 }{} 204 if err := json.Unmarshal(b, &aux); err != nil { 205 return err 206 } 207 if expectedName := nameForSuite(aux.Value); expectedName != aux.Name { 208 return fmt.Errorf("mismatched cipher suite and name, suite: %d, name: %s, expected name: %s", aux.Value, aux.Name, expectedName) 209 } 210 *cs = CipherSuite(aux.Value) 211 return nil 212 } 213 214 type CompressionMethod uint8 215 216 func (cm *CompressionMethod) MarshalJSON() ([]byte, error) { 217 buf := make([]byte, 1) 218 buf[0] = byte(*cm) 219 enc := strings.ToUpper(hex.EncodeToString(buf)) 220 aux := struct { 221 Hex string `json:"hex"` 222 Name string `json:"name"` 223 Value uint8 `json:"value"` 224 }{ 225 Hex: fmt.Sprintf("0x%s", enc), 226 Name: cm.String(), 227 Value: uint8(*cm), 228 } 229 230 return json.Marshal(aux) 231 } 232 233 func (cm *CompressionMethod) UnmarshalJSON(b []byte) error { 234 aux := struct { 235 Hex string `json:"hex"` 236 Name string `json:"name"` 237 Value uint8 `json:"value"` 238 }{} 239 if err := json.Unmarshal(b, &aux); err != nil { 240 return err 241 } 242 if expectedName := nameForCompressionMethod(aux.Value); expectedName != aux.Name { 243 return fmt.Errorf("mismatched compression method and name, compression method: %d, name: %s, expected name: %s", aux.Value, aux.Name, expectedName) 244 } 245 *cm = CompressionMethod(aux.Value) 246 return nil 247 } 248 249 func (c *Conn) GetHandshakeLog() *ServerHandshake { 250 return c.handshakeLog 251 } 252 253 func (c *Conn) InCipher() (cipher interface{}) { 254 return c.in.cipher 255 } 256 257 func (c *Conn) InSeq() []byte { 258 return c.in.seq[:] 259 } 260 261 func (c *Conn) OutCipher() (cipher interface{}) { 262 return c.out.cipher 263 } 264 265 func (c *Conn) OutSeq() []byte { 266 return c.out.seq[:] 267 } 268 269 func (m *clientHelloMsg) MakeLog() *ClientHello { 270 ch := new(ClientHello) 271 272 ch.Version = TLSVersion(m.vers) 273 274 ch.Random = make([]byte, len(m.random)) 275 copy(ch.Random, m.random) 276 277 ch.SessionID = make([]byte, len(m.sessionId)) 278 copy(ch.SessionID, m.sessionId) 279 280 ch.CipherSuites = make([]CipherSuite, len(m.cipherSuites)) 281 for i, aCipher := range m.cipherSuites { 282 ch.CipherSuites[i] = CipherSuite(aCipher) 283 } 284 285 ch.CompressionMethods = make([]CompressionMethod, len(m.compressionMethods)) 286 for i, aCompressMethod := range m.compressionMethods { 287 ch.CompressionMethods[i] = CompressionMethod(aCompressMethod) 288 } 289 290 ch.OcspStapling = m.ocspStapling 291 ch.TicketSupported = m.ticketSupported 292 ch.SecureRenegotiation = m.secureRenegotiation 293 ch.HeartbeatSupported = m.heartbeatEnabled 294 295 if len(m.extendedRandom) > 0 { 296 ch.ExtendedRandom = make([]byte, len(m.extendedRandom)) 297 copy(ch.ExtendedRandom, m.extendedRandom) 298 } 299 300 ch.NextProtoNeg = m.nextProtoNeg 301 ch.ServerName = m.serverName 302 ch.Scts = m.scts 303 304 ch.SupportedCurves = make([]CurveID, len(m.supportedCurves)) 305 copy(ch.SupportedCurves, m.supportedCurves) 306 307 ch.SupportedPoints = make([]PointFormat, len(m.supportedPoints)) 308 for i, aFormat := range m.supportedPoints { 309 ch.SupportedPoints[i] = PointFormat(aFormat) 310 } 311 312 if len(m.sessionTicket) > 0 { 313 ch.SessionTicket = new(SessionTicket) 314 copy(ch.SessionTicket.Value, m.sessionTicket) 315 ch.SessionTicket.Length = len(m.sessionTicket) 316 ch.SessionTicket.LifetimeHint = 0 // Clients don't send 317 } 318 319 ch.SignatureAndHashes = make([]SignatureAndHash, len(m.signatureAndHashes)) 320 for i, aGroup := range m.signatureAndHashes { 321 ch.SignatureAndHashes[i] = SignatureAndHash(aGroup) 322 } 323 324 ch.SctEnabled = m.sctEnabled 325 326 ch.AlpnProtocols = make([]string, len(m.alpnProtocols)) 327 copy(ch.AlpnProtocols, m.alpnProtocols) 328 329 ch.UnknownExtensions = make([][]byte, len(m.unknownExtensions)) 330 for i, extBytes := range m.unknownExtensions { 331 tempBytes := make([]byte, len(extBytes)) 332 copy(tempBytes, extBytes) 333 ch.UnknownExtensions[i] = tempBytes 334 } 335 return ch 336 } 337 338 func (m *serverHelloMsg) MakeLog() *ServerHello { 339 sh := new(ServerHello) 340 sh.Version = TLSVersion(m.vers) 341 sh.Random = make([]byte, len(m.random)) 342 copy(sh.Random, m.random) 343 sh.SessionID = make([]byte, len(m.sessionId)) 344 copy(sh.SessionID, m.sessionId) 345 sh.CipherSuite = CipherSuite(m.cipherSuite) 346 sh.CompressionMethod = CompressionMethod(m.compressionMethod) 347 sh.OcspStapling = m.ocspStapling 348 sh.TicketSupported = m.ticketSupported 349 sh.SecureRenegotiation = m.secureRenegotiation 350 sh.HeartbeatSupported = m.heartbeatEnabled 351 if len(m.extendedRandom) > 0 { 352 sh.ExtendedRandom = make([]byte, len(m.extendedRandom)) 353 copy(sh.ExtendedRandom, m.extendedRandom) 354 } 355 sh.NextProtoNeg = m.nextProtoNeg 356 if len(m.scts) > 0 { 357 for _, rawSCT := range m.scts { 358 var out ParsedAndRawSCT 359 out.Raw = make([]byte, len(rawSCT)) 360 copy(out.Raw, rawSCT) 361 sct, err := ct.DeserializeSCT(bytes.NewReader(rawSCT)) 362 if err == nil { 363 out.Parsed = sct 364 } 365 sh.SignedCertificateTimestamps = append(sh.SignedCertificateTimestamps, out) 366 } 367 } 368 sh.ExtendedMasterSecret = m.extendedMasterSecret 369 sh.AlpnProtocol = m.alpnProtocol 370 sh.UnknownExtensions = make([][]byte, len(m.unknownExtensions)) 371 for i, extBytes := range m.unknownExtensions { 372 tempBytes := make([]byte, len(extBytes)) 373 copy(tempBytes, extBytes) 374 sh.UnknownExtensions[i] = tempBytes 375 } 376 return sh 377 } 378 379 func (m *certificateMsg) MakeLog() *Certificates { 380 sc := new(Certificates) 381 if len(m.certificates) >= 1 { 382 cert := m.certificates[0] 383 sc.Certificate.Raw = make([]byte, len(cert)) 384 copy(sc.Certificate.Raw, cert) 385 } 386 if len(m.certificates) >= 2 { 387 chain := m.certificates[1:] 388 sc.Chain = make([]SimpleCertificate, len(chain)) 389 for idx, cert := range chain { 390 sc.Chain[idx].Raw = make([]byte, len(cert)) 391 copy(sc.Chain[idx].Raw, cert) 392 } 393 } 394 return sc 395 } 396 397 // addParsed sets the parsed certificates and the validation. It assumes the 398 // chain slice has already been allocated. 399 func (c *Certificates) addParsed(certs []*x509.Certificate, validation *x509.Validation) { 400 if len(certs) >= 1 { 401 c.Certificate.Parsed = certs[0] 402 } 403 if len(certs) >= 2 { 404 chain := certs[1:] 405 for idx, cert := range chain { 406 c.Chain[idx].Parsed = cert 407 } 408 } 409 c.Validation = validation 410 } 411 412 func (m *serverKeyExchangeMsg) MakeLog(ka keyAgreement) *ServerKeyExchange { 413 skx := new(ServerKeyExchange) 414 skx.Raw = make([]byte, len(m.key)) 415 var auth keyAgreementAuthentication 416 var errAuth error 417 copy(skx.Raw, m.key) 418 skx.Digest = append(make([]byte, 0), m.digest...) 419 420 // Write out parameters 421 switch ka := ka.(type) { 422 case *rsaKeyAgreement: 423 skx.RSAParams = ka.RSAParams() 424 auth = ka.auth 425 errAuth = ka.verifyError 426 case *dheKeyAgreement: 427 skx.DHParams = ka.DHParams() 428 auth = ka.auth 429 errAuth = ka.verifyError 430 case *ecdheKeyAgreement: 431 skx.ECDHParams = ka.ECDHParams() 432 auth = ka.auth 433 errAuth = ka.verifyError 434 default: 435 break 436 } 437 438 // Write out signature 439 switch auth := auth.(type) { 440 case *signedKeyAgreement: 441 skx.Signature = auth.Signature() 442 default: 443 break 444 } 445 446 // Write the signature validation error 447 if errAuth != nil { 448 skx.SignatureError = errAuth.Error() 449 } 450 451 return skx 452 } 453 454 func (m *finishedMsg) MakeLog() *Finished { 455 sf := new(Finished) 456 sf.VerifyData = make([]byte, len(m.verifyData)) 457 copy(sf.VerifyData, m.verifyData) 458 return sf 459 } 460 461 func (m *ClientSessionState) MakeLog() *SessionTicket { 462 st := new(SessionTicket) 463 st.Length = len(m.sessionTicket) 464 st.Value = make([]uint8, st.Length) 465 copy(st.Value, m.sessionTicket) 466 st.LifetimeHint = m.lifetimeHint 467 return st 468 } 469 470 func (m *clientHandshakeState) MakeLog() *KeyMaterial { 471 keymat := new(KeyMaterial) 472 473 keymat.MasterSecret = new(MasterSecret) 474 keymat.MasterSecret.Length = len(m.masterSecret) 475 keymat.MasterSecret.Value = make([]byte, len(m.masterSecret)) 476 copy(keymat.MasterSecret.Value, m.masterSecret) 477 478 keymat.PreMasterSecret = new(PreMasterSecret) 479 keymat.PreMasterSecret.Length = len(m.preMasterSecret) 480 keymat.PreMasterSecret.Value = make([]byte, len(m.preMasterSecret)) 481 copy(keymat.PreMasterSecret.Value, m.preMasterSecret) 482 483 return keymat 484 } 485 486 func (m *serverHandshakeState) MakeLog() *KeyMaterial { 487 keymat := new(KeyMaterial) 488 489 keymat.MasterSecret = new(MasterSecret) 490 keymat.MasterSecret.Length = len(m.masterSecret) 491 keymat.MasterSecret.Value = make([]byte, len(m.masterSecret)) 492 copy(keymat.MasterSecret.Value, m.masterSecret) 493 494 keymat.PreMasterSecret = new(PreMasterSecret) 495 keymat.PreMasterSecret.Length = len(m.preMasterSecret) 496 keymat.PreMasterSecret.Value = make([]byte, len(m.preMasterSecret)) 497 copy(keymat.PreMasterSecret.Value, m.preMasterSecret) 498 499 return keymat 500 } 501 502 func (m *clientKeyExchangeMsg) MakeLog(ka keyAgreement) *ClientKeyExchange { 503 ckx := new(ClientKeyExchange) 504 ckx.Raw = make([]byte, len(m.raw)) 505 copy(ckx.Raw, m.raw) 506 507 switch ka := ka.(type) { 508 case *rsaKeyAgreement: 509 ckx.RSAParams = new(jsonKeys.RSAClientParams) 510 ckx.RSAParams.Length = uint16(len(m.ciphertext) - 2) // First 2 bytes are length 511 ckx.RSAParams.EncryptedPMS = make([]byte, len(m.ciphertext)-2) 512 copy(ckx.RSAParams.EncryptedPMS, m.ciphertext[2:]) 513 // Premaster-Secret is available in KeyMaterial record 514 case *dheKeyAgreement: 515 ckx.DHParams = ka.ClientDHParams() 516 case *ecdheKeyAgreement: 517 ckx.ECDHParams = ka.ClientECDHParams() 518 default: 519 break 520 } 521 522 return ckx 523 }