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  }