| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604 |
- // Copyright 2017 Google Inc. All rights reserved.
- // Use of this source code is governed by a BSD-style
- // license that can be found in the LICENSE file.
- package tls
- import (
- "crypto"
- "crypto/x509"
- "hash"
- )
- // ClientHandshakeState includes both TLS 1.3-only and TLS 1.2-only states,
- // only one of them will be used, depending on negotiated version.
- //
- // ClientHandshakeState will be converted into and from either
- // - clientHandshakeState (TLS 1.2)
- // - clientHandshakeStateTLS13 (TLS 1.3)
- // uTLS will call .handshake() on one of these private internal states,
- // to perform TLS handshake using standard crypto/tls implementation.
- type ClientHandshakeState struct {
- C *Conn
- ServerHello *ServerHelloMsg
- Hello *ClientHelloMsg
- MasterSecret []byte
- Session *ClientSessionState
- State12 TLS12OnlyState
- State13 TLS13OnlyState
- }
- // TLS 1.3 only
- type TLS13OnlyState struct {
- Suite *CipherSuiteTLS13
- EcdheParams EcdheParameters
- EarlySecret []byte
- BinderKey []byte
- CertReq *CertificateRequestMsgTLS13
- UsingPSK bool
- SentDummyCCS bool
- Transcript hash.Hash
- TrafficSecret []byte // client_application_traffic_secret_0
- }
- // TLS 1.2 and before only
- type TLS12OnlyState struct {
- FinishedHash FinishedHash
- Suite CipherSuite
- }
- func (chs *ClientHandshakeState) toPrivate13() *clientHandshakeStateTLS13 {
- if chs == nil {
- return nil
- } else {
- return &clientHandshakeStateTLS13{
- c: chs.C,
- serverHello: chs.ServerHello.getPrivatePtr(),
- hello: chs.Hello.getPrivatePtr(),
- ecdheParams: chs.State13.EcdheParams,
- session: chs.Session,
- earlySecret: chs.State13.EarlySecret,
- binderKey: chs.State13.BinderKey,
- certReq: chs.State13.CertReq.toPrivate(),
- usingPSK: chs.State13.UsingPSK,
- sentDummyCCS: chs.State13.SentDummyCCS,
- suite: chs.State13.Suite.toPrivate(),
- transcript: chs.State13.Transcript,
- masterSecret: chs.MasterSecret,
- trafficSecret: chs.State13.TrafficSecret,
- }
- }
- }
- func (chs13 *clientHandshakeStateTLS13) toPublic13() *ClientHandshakeState {
- if chs13 == nil {
- return nil
- } else {
- tls13State := TLS13OnlyState{
- EcdheParams: chs13.ecdheParams,
- EarlySecret: chs13.earlySecret,
- BinderKey: chs13.binderKey,
- CertReq: chs13.certReq.toPublic(),
- UsingPSK: chs13.usingPSK,
- SentDummyCCS: chs13.sentDummyCCS,
- Suite: chs13.suite.toPublic(),
- TrafficSecret: chs13.trafficSecret,
- Transcript: chs13.transcript,
- }
- return &ClientHandshakeState{
- C: chs13.c,
- ServerHello: chs13.serverHello.getPublicPtr(),
- Hello: chs13.hello.getPublicPtr(),
- Session: chs13.session,
- MasterSecret: chs13.masterSecret,
- State13: tls13State,
- }
- }
- }
- func (chs *ClientHandshakeState) toPrivate12() *clientHandshakeState {
- if chs == nil {
- return nil
- } else {
- return &clientHandshakeState{
- c: chs.C,
- serverHello: chs.ServerHello.getPrivatePtr(),
- hello: chs.Hello.getPrivatePtr(),
- suite: chs.State12.Suite.getPrivatePtr(),
- session: chs.Session,
- masterSecret: chs.MasterSecret,
- finishedHash: *chs.State12.FinishedHash.getPrivatePtr(),
- }
- }
- }
- func (chs12 *clientHandshakeState) toPublic13() *ClientHandshakeState {
- if chs12 == nil {
- return nil
- } else {
- tls12State := TLS12OnlyState{
- Suite: *chs12.suite.getPublicPtr(),
- FinishedHash: *chs12.finishedHash.getPublicPtr(),
- }
- return &ClientHandshakeState{
- C: chs12.c,
- ServerHello: chs12.serverHello.getPublicPtr(),
- Hello: chs12.hello.getPublicPtr(),
- Session: chs12.session,
- MasterSecret: chs12.masterSecret,
- State12: tls12State,
- }
- }
- }
- type EcdheParameters interface {
- ecdheParameters
- }
- type CertificateRequestMsgTLS13 struct {
- Raw []byte
- OcspStapling bool
- Scts bool
- SupportedSignatureAlgorithms []SignatureScheme
- SupportedSignatureAlgorithmsCert []SignatureScheme
- CertificateAuthorities [][]byte
- }
- func (crm *certificateRequestMsgTLS13) toPublic() *CertificateRequestMsgTLS13 {
- if crm == nil {
- return nil
- } else {
- return &CertificateRequestMsgTLS13{
- Raw: crm.raw,
- OcspStapling: crm.ocspStapling,
- Scts: crm.scts,
- SupportedSignatureAlgorithms: crm.supportedSignatureAlgorithms,
- SupportedSignatureAlgorithmsCert: crm.supportedSignatureAlgorithmsCert,
- CertificateAuthorities: crm.certificateAuthorities,
- }
- }
- }
- func (crm *CertificateRequestMsgTLS13) toPrivate() *certificateRequestMsgTLS13 {
- if crm == nil {
- return nil
- } else {
- return &certificateRequestMsgTLS13{
- raw: crm.Raw,
- ocspStapling: crm.OcspStapling,
- scts: crm.Scts,
- supportedSignatureAlgorithms: crm.SupportedSignatureAlgorithms,
- supportedSignatureAlgorithmsCert: crm.SupportedSignatureAlgorithmsCert,
- certificateAuthorities: crm.CertificateAuthorities,
- }
- }
- }
- type CipherSuiteTLS13 struct {
- Id uint16
- KeyLen int
- Aead func(key, fixedNonce []byte) aead
- Hash crypto.Hash
- }
- func (c *cipherSuiteTLS13) toPublic() *CipherSuiteTLS13 {
- if c == nil {
- return nil
- } else {
- return &CipherSuiteTLS13{
- Id: c.id,
- KeyLen: c.keyLen,
- Aead: c.aead,
- Hash: c.hash,
- }
- }
- }
- func (c *CipherSuiteTLS13) toPrivate() *cipherSuiteTLS13 {
- if c == nil {
- return nil
- } else {
- return &cipherSuiteTLS13{
- id: c.Id,
- keyLen: c.KeyLen,
- aead: c.Aead,
- hash: c.Hash,
- }
- }
- }
- type ServerHelloMsg struct {
- Raw []byte
- Vers uint16
- Random []byte
- SessionId []byte
- CipherSuite uint16
- CompressionMethod uint8
- NextProtoNeg bool
- NextProtos []string
- OcspStapling bool
- Scts [][]byte
- Ems bool
- TicketSupported bool
- SecureRenegotiation []byte
- SecureRenegotiationSupported bool
- AlpnProtocol string
- // 1.3
- SupportedVersion uint16
- ServerShare keyShare
- SelectedIdentityPresent bool
- SelectedIdentity uint16
- Cookie []byte // HelloRetryRequest extension
- SelectedGroup CurveID // HelloRetryRequest extension
- }
- func (shm *ServerHelloMsg) getPrivatePtr() *serverHelloMsg {
- if shm == nil {
- return nil
- } else {
- return &serverHelloMsg{
- raw: shm.Raw,
- vers: shm.Vers,
- random: shm.Random,
- sessionId: shm.SessionId,
- cipherSuite: shm.CipherSuite,
- compressionMethod: shm.CompressionMethod,
- nextProtoNeg: shm.NextProtoNeg,
- nextProtos: shm.NextProtos,
- ocspStapling: shm.OcspStapling,
- scts: shm.Scts,
- ems: shm.Ems,
- ticketSupported: shm.TicketSupported,
- secureRenegotiation: shm.SecureRenegotiation,
- secureRenegotiationSupported: shm.SecureRenegotiationSupported,
- alpnProtocol: shm.AlpnProtocol,
- supportedVersion: shm.SupportedVersion,
- serverShare: shm.ServerShare,
- selectedIdentityPresent: shm.SelectedIdentityPresent,
- selectedIdentity: shm.SelectedIdentity,
- cookie: shm.Cookie,
- selectedGroup: shm.SelectedGroup,
- }
- }
- }
- func (shm *serverHelloMsg) getPublicPtr() *ServerHelloMsg {
- if shm == nil {
- return nil
- } else {
- return &ServerHelloMsg{
- Raw: shm.raw,
- Vers: shm.vers,
- Random: shm.random,
- SessionId: shm.sessionId,
- CipherSuite: shm.cipherSuite,
- CompressionMethod: shm.compressionMethod,
- NextProtoNeg: shm.nextProtoNeg,
- NextProtos: shm.nextProtos,
- OcspStapling: shm.ocspStapling,
- Scts: shm.scts,
- Ems: shm.ems,
- TicketSupported: shm.ticketSupported,
- SecureRenegotiation: shm.secureRenegotiation,
- SecureRenegotiationSupported: shm.secureRenegotiationSupported,
- AlpnProtocol: shm.alpnProtocol,
- SupportedVersion: shm.supportedVersion,
- ServerShare: shm.serverShare,
- SelectedIdentityPresent: shm.selectedIdentityPresent,
- SelectedIdentity: shm.selectedIdentity,
- Cookie: shm.cookie,
- SelectedGroup: shm.selectedGroup,
- }
- }
- }
- type ClientHelloMsg struct {
- Raw []byte
- Vers uint16
- Random []byte
- SessionId []byte
- CipherSuites []uint16
- CompressionMethods []uint8
- NextProtoNeg bool
- ServerName string
- OcspStapling bool
- Scts bool
- Ems bool // [UTLS] actually implemented due to its prevalence
- SupportedCurves []CurveID
- SupportedPoints []uint8
- TicketSupported bool
- SessionTicket []uint8
- SupportedSignatureAlgorithms []SignatureScheme
- SecureRenegotiation []byte
- SecureRenegotiationSupported bool
- AlpnProtocols []string
- // 1.3
- SupportedSignatureAlgorithmsCert []SignatureScheme
- SupportedVersions []uint16
- Cookie []byte
- KeyShares []KeyShare
- EarlyData bool
- PskModes []uint8
- PskIdentities []pskIdentity
- PskBinders [][]byte
- }
- func (chm *ClientHelloMsg) getPrivatePtr() *clientHelloMsg {
- if chm == nil {
- return nil
- } else {
- return &clientHelloMsg{
- raw: chm.Raw,
- vers: chm.Vers,
- random: chm.Random,
- sessionId: chm.SessionId,
- cipherSuites: chm.CipherSuites,
- compressionMethods: chm.CompressionMethods,
- nextProtoNeg: chm.NextProtoNeg,
- serverName: chm.ServerName,
- ocspStapling: chm.OcspStapling,
- scts: chm.Scts,
- ems: chm.Ems,
- supportedCurves: chm.SupportedCurves,
- supportedPoints: chm.SupportedPoints,
- ticketSupported: chm.TicketSupported,
- sessionTicket: chm.SessionTicket,
- supportedSignatureAlgorithms: chm.SupportedSignatureAlgorithms,
- secureRenegotiation: chm.SecureRenegotiation,
- secureRenegotiationSupported: chm.SecureRenegotiationSupported,
- alpnProtocols: chm.AlpnProtocols,
- supportedSignatureAlgorithmsCert: chm.SupportedSignatureAlgorithmsCert,
- supportedVersions: chm.SupportedVersions,
- cookie: chm.Cookie,
- keyShares: KeyShares(chm.KeyShares).ToPrivate(),
- earlyData: chm.EarlyData,
- pskModes: chm.PskModes,
- pskIdentities: chm.PskIdentities,
- pskBinders: chm.PskBinders,
- }
- }
- }
- func (chm *clientHelloMsg) getPublicPtr() *ClientHelloMsg {
- if chm == nil {
- return nil
- } else {
- return &ClientHelloMsg{
- Raw: chm.raw,
- Vers: chm.vers,
- Random: chm.random,
- SessionId: chm.sessionId,
- CipherSuites: chm.cipherSuites,
- CompressionMethods: chm.compressionMethods,
- NextProtoNeg: chm.nextProtoNeg,
- ServerName: chm.serverName,
- OcspStapling: chm.ocspStapling,
- Scts: chm.scts,
- Ems: chm.ems,
- SupportedCurves: chm.supportedCurves,
- SupportedPoints: chm.supportedPoints,
- TicketSupported: chm.ticketSupported,
- SessionTicket: chm.sessionTicket,
- SupportedSignatureAlgorithms: chm.supportedSignatureAlgorithms,
- SecureRenegotiation: chm.secureRenegotiation,
- SecureRenegotiationSupported: chm.secureRenegotiationSupported,
- AlpnProtocols: chm.alpnProtocols,
- SupportedSignatureAlgorithmsCert: chm.supportedSignatureAlgorithmsCert,
- SupportedVersions: chm.supportedVersions,
- Cookie: chm.cookie,
- KeyShares: keyShares(chm.keyShares).ToPublic(),
- EarlyData: chm.earlyData,
- PskModes: chm.pskModes,
- PskIdentities: chm.pskIdentities,
- PskBinders: chm.pskBinders,
- }
- }
- }
- // A CipherSuite is a specific combination of key agreement, cipher and MAC
- // function. All cipher suites currently assume RSA key agreement.
- type CipherSuite struct {
- Id uint16
- // the lengths, in bytes, of the key material needed for each component.
- KeyLen int
- MacLen int
- IvLen int
- Ka func(version uint16) keyAgreement
- // flags is a bitmask of the suite* values, above.
- Flags int
- Cipher func(key, iv []byte, isRead bool) interface{}
- Mac func(version uint16, macKey []byte) macFunction
- Aead func(key, fixedNonce []byte) aead
- }
- func (cs *CipherSuite) getPrivatePtr() *cipherSuite {
- if cs == nil {
- return nil
- } else {
- return &cipherSuite{
- id: cs.Id,
- keyLen: cs.KeyLen,
- macLen: cs.MacLen,
- ivLen: cs.IvLen,
- ka: cs.Ka,
- flags: cs.Flags,
- cipher: cs.Cipher,
- mac: cs.Mac,
- aead: cs.Aead,
- }
- }
- }
- func (cs *cipherSuite) getPublicPtr() *CipherSuite {
- if cs == nil {
- return nil
- } else {
- return &CipherSuite{
- Id: cs.id,
- KeyLen: cs.keyLen,
- MacLen: cs.macLen,
- IvLen: cs.ivLen,
- Ka: cs.ka,
- Flags: cs.flags,
- Cipher: cs.cipher,
- Mac: cs.mac,
- Aead: cs.aead,
- }
- }
- }
- // A FinishedHash calculates the hash of a set of handshake messages suitable
- // for including in a Finished message.
- type FinishedHash struct {
- Client hash.Hash
- Server hash.Hash
- // Prior to TLS 1.2, an additional MD5 hash is required.
- ClientMD5 hash.Hash
- ServerMD5 hash.Hash
- // In TLS 1.2, a full buffer is sadly required.
- Buffer []byte
- Version uint16
- Prf func(result, secret, label, seed []byte)
- }
- func (fh *FinishedHash) getPrivatePtr() *finishedHash {
- if fh == nil {
- return nil
- } else {
- return &finishedHash{
- client: fh.Client,
- server: fh.Server,
- clientMD5: fh.ClientMD5,
- serverMD5: fh.ServerMD5,
- buffer: fh.Buffer,
- version: fh.Version,
- prf: fh.Prf,
- }
- }
- }
- func (fh *finishedHash) getPublicPtr() *FinishedHash {
- if fh == nil {
- return nil
- } else {
- return &FinishedHash{
- Client: fh.client,
- Server: fh.server,
- ClientMD5: fh.clientMD5,
- ServerMD5: fh.serverMD5,
- Buffer: fh.buffer,
- Version: fh.version,
- Prf: fh.prf}
- }
- }
- // TLS 1.3 Key Share. See RFC 8446, Section 4.2.8.
- type KeyShare struct {
- Group CurveID
- Data []byte
- }
- type KeyShares []KeyShare
- type keyShares []keyShare
- func (kss keyShares) ToPublic() []KeyShare {
- var KSS []KeyShare
- for _, ks := range kss {
- KSS = append(KSS, KeyShare{Data: ks.data, Group: ks.group})
- }
- return KSS
- }
- func (KSS KeyShares) ToPrivate() []keyShare {
- var kss []keyShare
- for _, KS := range KSS {
- kss = append(kss, keyShare{data: KS.Data, group: KS.Group})
- }
- return kss
- }
- // ClientSessionState is public, but all its fields are private. Let's add setters, getters and constructor
- // ClientSessionState contains the state needed by clients to resume TLS sessions.
- func MakeClientSessionState(
- SessionTicket []uint8,
- Vers uint16,
- CipherSuite uint16,
- MasterSecret []byte,
- ServerCertificates []*x509.Certificate,
- VerifiedChains [][]*x509.Certificate) *ClientSessionState {
- css := ClientSessionState{sessionTicket: SessionTicket,
- vers: Vers,
- cipherSuite: CipherSuite,
- masterSecret: MasterSecret,
- serverCertificates: ServerCertificates,
- verifiedChains: VerifiedChains}
- return &css
- }
- // Encrypted ticket used for session resumption with server
- func (css *ClientSessionState) SessionTicket() []uint8 {
- return css.sessionTicket
- }
- // SSL/TLS version negotiated for the session
- func (css *ClientSessionState) Vers() uint16 {
- return css.vers
- }
- // Ciphersuite negotiated for the session
- func (css *ClientSessionState) CipherSuite() uint16 {
- return css.cipherSuite
- }
- // MasterSecret generated by client on a full handshake
- func (css *ClientSessionState) MasterSecret() []byte {
- return css.masterSecret
- }
- // Certificate chain presented by the server
- func (css *ClientSessionState) ServerCertificates() []*x509.Certificate {
- return css.serverCertificates
- }
- // Certificate chains we built for verification
- func (css *ClientSessionState) VerifiedChains() [][]*x509.Certificate {
- return css.verifiedChains
- }
- func (css *ClientSessionState) SetSessionTicket(SessionTicket []uint8) {
- css.sessionTicket = SessionTicket
- }
- func (css *ClientSessionState) SetVers(Vers uint16) {
- css.vers = Vers
- }
- func (css *ClientSessionState) SetCipherSuite(CipherSuite uint16) {
- css.cipherSuite = CipherSuite
- }
- func (css *ClientSessionState) SetMasterSecret(MasterSecret []byte) {
- css.masterSecret = MasterSecret
- }
- func (css *ClientSessionState) SetServerCertificates(ServerCertificates []*x509.Certificate) {
- css.serverCertificates = ServerCertificates
- }
- func (css *ClientSessionState) SetVerifiedChains(VerifiedChains [][]*x509.Certificate) {
- css.verifiedChains = VerifiedChains
- }
|