| // Copyright 2018 The Go Authors. 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 ( |
| "bytes" |
| "context" |
| "crypto" |
| "crypto/hmac" |
| "crypto/rsa" |
| "errors" |
| "hash" |
| "io" |
| "sync/atomic" |
| "time" |
| ) |
| |
| // maxClientPSKIdentities is the number of client PSK identities the server will |
| // attempt to validate. It will ignore the rest not to let cheap ClientHello |
| // messages cause too much work in session ticket decryption attempts. |
| const maxClientPSKIdentities = 5 |
| |
| type serverHandshakeStateTLS13 struct { |
| c *Conn |
| ctx context.Context |
| clientHello *clientHelloMsg |
| hello *serverHelloMsg |
| sentDummyCCS bool |
| usingPSK bool |
| suite *cipherSuiteTLS13 |
| cert *Certificate |
| sigAlg SignatureScheme |
| earlySecret []byte |
| sharedKey []byte |
| handshakeSecret []byte |
| masterSecret []byte |
| trafficSecret []byte // client_application_traffic_secret_0 |
| transcript hash.Hash |
| clientFinished []byte |
| } |
| |
| func (hs *serverHandshakeStateTLS13) handshake() error { |
| c := hs.c |
| |
| if needFIPS() { |
| return errors.New("tls: internal error: TLS 1.3 reached in FIPS mode") |
| } |
| |
| // For an overview of the TLS 1.3 handshake, see RFC 8446, Section 2. |
| if err := hs.processClientHello(); err != nil { |
| return err |
| } |
| if err := hs.checkForResumption(); err != nil { |
| return err |
| } |
| if err := hs.pickCertificate(); err != nil { |
| return err |
| } |
| c.buffering = true |
| if err := hs.sendServerParameters(); err != nil { |
| return err |
| } |
| if err := hs.sendServerCertificate(); err != nil { |
| return err |
| } |
| if err := hs.sendServerFinished(); err != nil { |
| return err |
| } |
| // Note that at this point we could start sending application data without |
| // waiting for the client's second flight, but the application might not |
| // expect the lack of replay protection of the ClientHello parameters. |
| if _, err := c.flush(); err != nil { |
| return err |
| } |
| if err := hs.readClientCertificate(); err != nil { |
| return err |
| } |
| if err := hs.readClientFinished(); err != nil { |
| return err |
| } |
| |
| atomic.StoreUint32(&c.handshakeStatus, 1) |
| |
| return nil |
| } |
| |
| func (hs *serverHandshakeStateTLS13) processClientHello() error { |
| c := hs.c |
| |
| hs.hello = new(serverHelloMsg) |
| |
| // TLS 1.3 froze the ServerHello.legacy_version field, and uses |
| // supported_versions instead. See RFC 8446, sections 4.1.3 and 4.2.1. |
| hs.hello.vers = VersionTLS12 |
| hs.hello.supportedVersion = c.vers |
| |
| if len(hs.clientHello.supportedVersions) == 0 { |
| c.sendAlert(alertIllegalParameter) |
| return errors.New("tls: client used the legacy version field to negotiate TLS 1.3") |
| } |
| |
| // Abort if the client is doing a fallback and landing lower than what we |
| // support. See RFC 7507, which however does not specify the interaction |
| // with supported_versions. The only difference is that with |
| // supported_versions a client has a chance to attempt a [TLS 1.2, TLS 1.4] |
| // handshake in case TLS 1.3 is broken but 1.2 is not. Alas, in that case, |
| // it will have to drop the TLS_FALLBACK_SCSV protection if it falls back to |
| // TLS 1.2, because a TLS 1.3 server would abort here. The situation before |
| // supported_versions was not better because there was just no way to do a |
| // TLS 1.4 handshake without risking the server selecting TLS 1.3. |
| for _, id := range hs.clientHello.cipherSuites { |
| if id == TLS_FALLBACK_SCSV { |
| // Use c.vers instead of max(supported_versions) because an attacker |
| // could defeat this by adding an arbitrary high version otherwise. |
| if c.vers < c.config.maxSupportedVersion(roleServer) { |
| c.sendAlert(alertInappropriateFallback) |
| return errors.New("tls: client using inappropriate protocol fallback") |
| } |
| break |
| } |
| } |
| |
| if len(hs.clientHello.compressionMethods) != 1 || |
| hs.clientHello.compressionMethods[0] != compressionNone { |
| c.sendAlert(alertIllegalParameter) |
| return errors.New("tls: TLS 1.3 client supports illegal compression methods") |
| } |
| |
| hs.hello.random = make([]byte, 32) |
| if _, err := io.ReadFull(c.config.rand(), hs.hello.random); err != nil { |
| c.sendAlert(alertInternalError) |
| return err |
| } |
| |
| if len(hs.clientHello.secureRenegotiation) != 0 { |
| c.sendAlert(alertHandshakeFailure) |
| return errors.New("tls: initial handshake had non-empty renegotiation extension") |
| } |
| |
| if hs.clientHello.earlyData { |
| // See RFC 8446, Section 4.2.10 for the complicated behavior required |
| // here. The scenario is that a different server at our address offered |
| // to accept early data in the past, which we can't handle. For now, all |
| // 0-RTT enabled session tickets need to expire before a Go server can |
| // replace a server or join a pool. That's the same requirement that |
| // applies to mixing or replacing with any TLS 1.2 server. |
| c.sendAlert(alertUnsupportedExtension) |
| return errors.New("tls: client sent unexpected early data") |
| } |
| |
| hs.hello.sessionId = hs.clientHello.sessionId |
| hs.hello.compressionMethod = compressionNone |
| |
| preferenceList := defaultCipherSuitesTLS13 |
| if !hasAESGCMHardwareSupport || !aesgcmPreferred(hs.clientHello.cipherSuites) { |
| preferenceList = defaultCipherSuitesTLS13NoAES |
| } |
| for _, suiteID := range preferenceList { |
| hs.suite = mutualCipherSuiteTLS13(hs.clientHello.cipherSuites, suiteID) |
| if hs.suite != nil { |
| break |
| } |
| } |
| if hs.suite == nil { |
| c.sendAlert(alertHandshakeFailure) |
| return errors.New("tls: no cipher suite supported by both client and server") |
| } |
| c.cipherSuite = hs.suite.id |
| hs.hello.cipherSuite = hs.suite.id |
| hs.transcript = hs.suite.hash.New() |
| |
| // Pick the ECDHE group in server preference order, but give priority to |
| // groups with a key share, to avoid a HelloRetryRequest round-trip. |
| var selectedGroup CurveID |
| var clientKeyShare *keyShare |
| GroupSelection: |
| for _, preferredGroup := range c.config.curvePreferences() { |
| for _, ks := range hs.clientHello.keyShares { |
| if ks.group == preferredGroup { |
| selectedGroup = ks.group |
| clientKeyShare = &ks |
| break GroupSelection |
| } |
| } |
| if selectedGroup != 0 { |
| continue |
| } |
| for _, group := range hs.clientHello.supportedCurves { |
| if group == preferredGroup { |
| selectedGroup = group |
| break |
| } |
| } |
| } |
| if selectedGroup == 0 { |
| c.sendAlert(alertHandshakeFailure) |
| return errors.New("tls: no ECDHE curve supported by both client and server") |
| } |
| if clientKeyShare == nil { |
| if err := hs.doHelloRetryRequest(selectedGroup); err != nil { |
| return err |
| } |
| clientKeyShare = &hs.clientHello.keyShares[0] |
| } |
| |
| if _, ok := curveForCurveID(selectedGroup); selectedGroup != X25519 && !ok { |
| c.sendAlert(alertInternalError) |
| return errors.New("tls: CurvePreferences includes unsupported curve") |
| } |
| params, err := generateECDHEParameters(c.config.rand(), selectedGroup) |
| if err != nil { |
| c.sendAlert(alertInternalError) |
| return err |
| } |
| hs.hello.serverShare = keyShare{group: selectedGroup, data: params.PublicKey()} |
| hs.sharedKey = params.SharedKey(clientKeyShare.data) |
| if hs.sharedKey == nil { |
| c.sendAlert(alertIllegalParameter) |
| return errors.New("tls: invalid client key share") |
| } |
| |
| c.serverName = hs.clientHello.serverName |
| return nil |
| } |
| |
| func (hs *serverHandshakeStateTLS13) checkForResumption() error { |
| c := hs.c |
| |
| if c.config.SessionTicketsDisabled { |
| return nil |
| } |
| |
| modeOK := false |
| for _, mode := range hs.clientHello.pskModes { |
| if mode == pskModeDHE { |
| modeOK = true |
| break |
| } |
| } |
| if !modeOK { |
| return nil |
| } |
| |
| if len(hs.clientHello.pskIdentities) != len(hs.clientHello.pskBinders) { |
| c.sendAlert(alertIllegalParameter) |
| return errors.New("tls: invalid or missing PSK binders") |
| } |
| if len(hs.clientHello.pskIdentities) == 0 { |
| return nil |
| } |
| |
| for i, identity := range hs.clientHello.pskIdentities { |
| if i >= maxClientPSKIdentities { |
| break |
| } |
| |
| plaintext, _ := c.decryptTicket(identity.label) |
| if plaintext == nil { |
| continue |
| } |
| sessionState := new(sessionStateTLS13) |
| if ok := sessionState.unmarshal(plaintext); !ok { |
| continue |
| } |
| |
| createdAt := time.Unix(int64(sessionState.createdAt), 0) |
| if c.config.time().Sub(createdAt) > maxSessionTicketLifetime { |
| continue |
| } |
| |
| // We don't check the obfuscated ticket age because it's affected by |
| // clock skew and it's only a freshness signal useful for shrinking the |
| // window for replay attacks, which don't affect us as we don't do 0-RTT. |
| |
| pskSuite := cipherSuiteTLS13ByID(sessionState.cipherSuite) |
| if pskSuite == nil || pskSuite.hash != hs.suite.hash { |
| continue |
| } |
| |
| // PSK connections don't re-establish client certificates, but carry |
| // them over in the session ticket. Ensure the presence of client certs |
| // in the ticket is consistent with the configured requirements. |
| sessionHasClientCerts := len(sessionState.certificate.Certificate) != 0 |
| needClientCerts := requiresClientCert(c.config.ClientAuth) |
| if needClientCerts && !sessionHasClientCerts { |
| continue |
| } |
| if sessionHasClientCerts && c.config.ClientAuth == NoClientCert { |
| continue |
| } |
| |
| psk := hs.suite.expandLabel(sessionState.resumptionSecret, "resumption", |
| nil, hs.suite.hash.Size()) |
| hs.earlySecret = hs.suite.extract(psk, nil) |
| binderKey := hs.suite.deriveSecret(hs.earlySecret, resumptionBinderLabel, nil) |
| // Clone the transcript in case a HelloRetryRequest was recorded. |
| transcript := cloneHash(hs.transcript, hs.suite.hash) |
| if transcript == nil { |
| c.sendAlert(alertInternalError) |
| return errors.New("tls: internal error: failed to clone hash") |
| } |
| transcript.Write(hs.clientHello.marshalWithoutBinders()) |
| pskBinder := hs.suite.finishedHash(binderKey, transcript) |
| if !hmac.Equal(hs.clientHello.pskBinders[i], pskBinder) { |
| c.sendAlert(alertDecryptError) |
| return errors.New("tls: invalid PSK binder") |
| } |
| |
| c.didResume = true |
| if err := c.processCertsFromClient(sessionState.certificate); err != nil { |
| return err |
| } |
| |
| hs.hello.selectedIdentityPresent = true |
| hs.hello.selectedIdentity = uint16(i) |
| hs.usingPSK = true |
| return nil |
| } |
| |
| return nil |
| } |
| |
| // cloneHash uses the encoding.BinaryMarshaler and encoding.BinaryUnmarshaler |
| // interfaces implemented by standard library hashes to clone the state of in |
| // to a new instance of h. It returns nil if the operation fails. |
| func cloneHash(in hash.Hash, h crypto.Hash) hash.Hash { |
| // Recreate the interface to avoid importing encoding. |
| type binaryMarshaler interface { |
| MarshalBinary() (data []byte, err error) |
| UnmarshalBinary(data []byte) error |
| } |
| marshaler, ok := in.(binaryMarshaler) |
| if !ok { |
| return nil |
| } |
| state, err := marshaler.MarshalBinary() |
| if err != nil { |
| return nil |
| } |
| out := h.New() |
| unmarshaler, ok := out.(binaryMarshaler) |
| if !ok { |
| return nil |
| } |
| if err := unmarshaler.UnmarshalBinary(state); err != nil { |
| return nil |
| } |
| return out |
| } |
| |
| func (hs *serverHandshakeStateTLS13) pickCertificate() error { |
| c := hs.c |
| |
| // Only one of PSK and certificates are used at a time. |
| if hs.usingPSK { |
| return nil |
| } |
| |
| // signature_algorithms is required in TLS 1.3. See RFC 8446, Section 4.2.3. |
| if len(hs.clientHello.supportedSignatureAlgorithms) == 0 { |
| return c.sendAlert(alertMissingExtension) |
| } |
| |
| certificate, err := c.config.getCertificate(clientHelloInfo(hs.ctx, c, hs.clientHello)) |
| if err != nil { |
| if err == errNoCertificates { |
| c.sendAlert(alertUnrecognizedName) |
| } else { |
| c.sendAlert(alertInternalError) |
| } |
| return err |
| } |
| hs.sigAlg, err = selectSignatureScheme(c.vers, certificate, hs.clientHello.supportedSignatureAlgorithms) |
| if err != nil { |
| // getCertificate returned a certificate that is unsupported or |
| // incompatible with the client's signature algorithms. |
| c.sendAlert(alertHandshakeFailure) |
| return err |
| } |
| hs.cert = certificate |
| |
| return nil |
| } |
| |
| // sendDummyChangeCipherSpec sends a ChangeCipherSpec record for compatibility |
| // with middleboxes that didn't implement TLS correctly. See RFC 8446, Appendix D.4. |
| func (hs *serverHandshakeStateTLS13) sendDummyChangeCipherSpec() error { |
| if hs.sentDummyCCS { |
| return nil |
| } |
| hs.sentDummyCCS = true |
| |
| _, err := hs.c.writeRecord(recordTypeChangeCipherSpec, []byte{1}) |
| return err |
| } |
| |
| func (hs *serverHandshakeStateTLS13) doHelloRetryRequest(selectedGroup CurveID) error { |
| c := hs.c |
| |
| // The first ClientHello gets double-hashed into the transcript upon a |
| // HelloRetryRequest. See RFC 8446, Section 4.4.1. |
| hs.transcript.Write(hs.clientHello.marshal()) |
| chHash := hs.transcript.Sum(nil) |
| hs.transcript.Reset() |
| hs.transcript.Write([]byte{typeMessageHash, 0, 0, uint8(len(chHash))}) |
| hs.transcript.Write(chHash) |
| |
| helloRetryRequest := &serverHelloMsg{ |
| vers: hs.hello.vers, |
| random: helloRetryRequestRandom, |
| sessionId: hs.hello.sessionId, |
| cipherSuite: hs.hello.cipherSuite, |
| compressionMethod: hs.hello.compressionMethod, |
| supportedVersion: hs.hello.supportedVersion, |
| selectedGroup: selectedGroup, |
| } |
| |
| hs.transcript.Write(helloRetryRequest.marshal()) |
| if _, err := c.writeRecord(recordTypeHandshake, helloRetryRequest.marshal()); err != nil { |
| return err |
| } |
| |
| if err := hs.sendDummyChangeCipherSpec(); err != nil { |
| return err |
| } |
| |
| msg, err := c.readHandshake() |
| if err != nil { |
| return err |
| } |
| |
| clientHello, ok := msg.(*clientHelloMsg) |
| if !ok { |
| c.sendAlert(alertUnexpectedMessage) |
| return unexpectedMessageError(clientHello, msg) |
| } |
| |
| if len(clientHello.keyShares) != 1 || clientHello.keyShares[0].group != selectedGroup { |
| c.sendAlert(alertIllegalParameter) |
| return errors.New("tls: client sent invalid key share in second ClientHello") |
| } |
| |
| if clientHello.earlyData { |
| c.sendAlert(alertIllegalParameter) |
| return errors.New("tls: client indicated early data in second ClientHello") |
| } |
| |
| if illegalClientHelloChange(clientHello, hs.clientHello) { |
| c.sendAlert(alertIllegalParameter) |
| return errors.New("tls: client illegally modified second ClientHello") |
| } |
| |
| hs.clientHello = clientHello |
| return nil |
| } |
| |
| // illegalClientHelloChange reports whether the two ClientHello messages are |
| // different, with the exception of the changes allowed before and after a |
| // HelloRetryRequest. See RFC 8446, Section 4.1.2. |
| func illegalClientHelloChange(ch, ch1 *clientHelloMsg) bool { |
| if len(ch.supportedVersions) != len(ch1.supportedVersions) || |
| len(ch.cipherSuites) != len(ch1.cipherSuites) || |
| len(ch.supportedCurves) != len(ch1.supportedCurves) || |
| len(ch.supportedSignatureAlgorithms) != len(ch1.supportedSignatureAlgorithms) || |
| len(ch.supportedSignatureAlgorithmsCert) != len(ch1.supportedSignatureAlgorithmsCert) || |
| len(ch.alpnProtocols) != len(ch1.alpnProtocols) { |
| return true |
| } |
| for i := range ch.supportedVersions { |
| if ch.supportedVersions[i] != ch1.supportedVersions[i] { |
| return true |
| } |
| } |
| for i := range ch.cipherSuites { |
| if ch.cipherSuites[i] != ch1.cipherSuites[i] { |
| return true |
| } |
| } |
| for i := range ch.supportedCurves { |
| if ch.supportedCurves[i] != ch1.supportedCurves[i] { |
| return true |
| } |
| } |
| for i := range ch.supportedSignatureAlgorithms { |
| if ch.supportedSignatureAlgorithms[i] != ch1.supportedSignatureAlgorithms[i] { |
| return true |
| } |
| } |
| for i := range ch.supportedSignatureAlgorithmsCert { |
| if ch.supportedSignatureAlgorithmsCert[i] != ch1.supportedSignatureAlgorithmsCert[i] { |
| return true |
| } |
| } |
| for i := range ch.alpnProtocols { |
| if ch.alpnProtocols[i] != ch1.alpnProtocols[i] { |
| return true |
| } |
| } |
| return ch.vers != ch1.vers || |
| !bytes.Equal(ch.random, ch1.random) || |
| !bytes.Equal(ch.sessionId, ch1.sessionId) || |
| !bytes.Equal(ch.compressionMethods, ch1.compressionMethods) || |
| ch.serverName != ch1.serverName || |
| ch.ocspStapling != ch1.ocspStapling || |
| !bytes.Equal(ch.supportedPoints, ch1.supportedPoints) || |
| ch.ticketSupported != ch1.ticketSupported || |
| !bytes.Equal(ch.sessionTicket, ch1.sessionTicket) || |
| ch.secureRenegotiationSupported != ch1.secureRenegotiationSupported || |
| !bytes.Equal(ch.secureRenegotiation, ch1.secureRenegotiation) || |
| ch.scts != ch1.scts || |
| !bytes.Equal(ch.cookie, ch1.cookie) || |
| !bytes.Equal(ch.pskModes, ch1.pskModes) |
| } |
| |
| func (hs *serverHandshakeStateTLS13) sendServerParameters() error { |
| c := hs.c |
| |
| hs.transcript.Write(hs.clientHello.marshal()) |
| hs.transcript.Write(hs.hello.marshal()) |
| if _, err := c.writeRecord(recordTypeHandshake, hs.hello.marshal()); err != nil { |
| return err |
| } |
| |
| if err := hs.sendDummyChangeCipherSpec(); err != nil { |
| return err |
| } |
| |
| earlySecret := hs.earlySecret |
| if earlySecret == nil { |
| earlySecret = hs.suite.extract(nil, nil) |
| } |
| hs.handshakeSecret = hs.suite.extract(hs.sharedKey, |
| hs.suite.deriveSecret(earlySecret, "derived", nil)) |
| |
| clientSecret := hs.suite.deriveSecret(hs.handshakeSecret, |
| clientHandshakeTrafficLabel, hs.transcript) |
| c.in.setTrafficSecret(hs.suite, clientSecret) |
| serverSecret := hs.suite.deriveSecret(hs.handshakeSecret, |
| serverHandshakeTrafficLabel, hs.transcript) |
| c.out.setTrafficSecret(hs.suite, serverSecret) |
| |
| err := c.config.writeKeyLog(keyLogLabelClientHandshake, hs.clientHello.random, clientSecret) |
| if err != nil { |
| c.sendAlert(alertInternalError) |
| return err |
| } |
| err = c.config.writeKeyLog(keyLogLabelServerHandshake, hs.clientHello.random, serverSecret) |
| if err != nil { |
| c.sendAlert(alertInternalError) |
| return err |
| } |
| |
| encryptedExtensions := new(encryptedExtensionsMsg) |
| |
| selectedProto, err := negotiateALPN(c.config.NextProtos, hs.clientHello.alpnProtocols) |
| if err != nil { |
| c.sendAlert(alertNoApplicationProtocol) |
| return err |
| } |
| encryptedExtensions.alpnProtocol = selectedProto |
| c.clientProtocol = selectedProto |
| |
| hs.transcript.Write(encryptedExtensions.marshal()) |
| if _, err := c.writeRecord(recordTypeHandshake, encryptedExtensions.marshal()); err != nil { |
| return err |
| } |
| |
| return nil |
| } |
| |
| func (hs *serverHandshakeStateTLS13) requestClientCert() bool { |
| return hs.c.config.ClientAuth >= RequestClientCert && !hs.usingPSK |
| } |
| |
| func (hs *serverHandshakeStateTLS13) sendServerCertificate() error { |
| c := hs.c |
| |
| // Only one of PSK and certificates are used at a time. |
| if hs.usingPSK { |
| return nil |
| } |
| |
| if hs.requestClientCert() { |
| // Request a client certificate |
| certReq := new(certificateRequestMsgTLS13) |
| certReq.ocspStapling = true |
| certReq.scts = true |
| certReq.supportedSignatureAlgorithms = supportedSignatureAlgorithms() |
| if c.config.ClientCAs != nil { |
| certReq.certificateAuthorities = c.config.ClientCAs.Subjects() |
| } |
| |
| hs.transcript.Write(certReq.marshal()) |
| if _, err := c.writeRecord(recordTypeHandshake, certReq.marshal()); err != nil { |
| return err |
| } |
| } |
| |
| certMsg := new(certificateMsgTLS13) |
| |
| certMsg.certificate = *hs.cert |
| certMsg.scts = hs.clientHello.scts && len(hs.cert.SignedCertificateTimestamps) > 0 |
| certMsg.ocspStapling = hs.clientHello.ocspStapling && len(hs.cert.OCSPStaple) > 0 |
| |
| hs.transcript.Write(certMsg.marshal()) |
| if _, err := c.writeRecord(recordTypeHandshake, certMsg.marshal()); err != nil { |
| return err |
| } |
| |
| certVerifyMsg := new(certificateVerifyMsg) |
| certVerifyMsg.hasSignatureAlgorithm = true |
| certVerifyMsg.signatureAlgorithm = hs.sigAlg |
| |
| sigType, sigHash, err := typeAndHashFromSignatureScheme(hs.sigAlg) |
| if err != nil { |
| return c.sendAlert(alertInternalError) |
| } |
| |
| signed := signedMessage(sigHash, serverSignatureContext, hs.transcript) |
| signOpts := crypto.SignerOpts(sigHash) |
| if sigType == signatureRSAPSS { |
| signOpts = &rsa.PSSOptions{SaltLength: rsa.PSSSaltLengthEqualsHash, Hash: sigHash} |
| } |
| sig, err := hs.cert.PrivateKey.(crypto.Signer).Sign(c.config.rand(), signed, signOpts) |
| if err != nil { |
| public := hs.cert.PrivateKey.(crypto.Signer).Public() |
| if rsaKey, ok := public.(*rsa.PublicKey); ok && sigType == signatureRSAPSS && |
| rsaKey.N.BitLen()/8 < sigHash.Size()*2+2 { // key too small for RSA-PSS |
| c.sendAlert(alertHandshakeFailure) |
| } else { |
| c.sendAlert(alertInternalError) |
| } |
| return errors.New("tls: failed to sign handshake: " + err.Error()) |
| } |
| certVerifyMsg.signature = sig |
| |
| hs.transcript.Write(certVerifyMsg.marshal()) |
| if _, err := c.writeRecord(recordTypeHandshake, certVerifyMsg.marshal()); err != nil { |
| return err |
| } |
| |
| return nil |
| } |
| |
| func (hs *serverHandshakeStateTLS13) sendServerFinished() error { |
| c := hs.c |
| |
| finished := &finishedMsg{ |
| verifyData: hs.suite.finishedHash(c.out.trafficSecret, hs.transcript), |
| } |
| |
| hs.transcript.Write(finished.marshal()) |
| if _, err := c.writeRecord(recordTypeHandshake, finished.marshal()); err != nil { |
| return err |
| } |
| |
| // Derive secrets that take context through the server Finished. |
| |
| hs.masterSecret = hs.suite.extract(nil, |
| hs.suite.deriveSecret(hs.handshakeSecret, "derived", nil)) |
| |
| hs.trafficSecret = hs.suite.deriveSecret(hs.masterSecret, |
| clientApplicationTrafficLabel, hs.transcript) |
| serverSecret := hs.suite.deriveSecret(hs.masterSecret, |
| serverApplicationTrafficLabel, hs.transcript) |
| c.out.setTrafficSecret(hs.suite, serverSecret) |
| |
| err := c.config.writeKeyLog(keyLogLabelClientTraffic, hs.clientHello.random, hs.trafficSecret) |
| if err != nil { |
| c.sendAlert(alertInternalError) |
| return err |
| } |
| err = c.config.writeKeyLog(keyLogLabelServerTraffic, hs.clientHello.random, serverSecret) |
| if err != nil { |
| c.sendAlert(alertInternalError) |
| return err |
| } |
| |
| c.ekm = hs.suite.exportKeyingMaterial(hs.masterSecret, hs.transcript) |
| |
| // If we did not request client certificates, at this point we can |
| // precompute the client finished and roll the transcript forward to send |
| // session tickets in our first flight. |
| if !hs.requestClientCert() { |
| if err := hs.sendSessionTickets(); err != nil { |
| return err |
| } |
| } |
| |
| return nil |
| } |
| |
| func (hs *serverHandshakeStateTLS13) shouldSendSessionTickets() bool { |
| if hs.c.config.SessionTicketsDisabled { |
| return false |
| } |
| |
| // Don't send tickets the client wouldn't use. See RFC 8446, Section 4.2.9. |
| for _, pskMode := range hs.clientHello.pskModes { |
| if pskMode == pskModeDHE { |
| return true |
| } |
| } |
| return false |
| } |
| |
| func (hs *serverHandshakeStateTLS13) sendSessionTickets() error { |
| c := hs.c |
| |
| hs.clientFinished = hs.suite.finishedHash(c.in.trafficSecret, hs.transcript) |
| finishedMsg := &finishedMsg{ |
| verifyData: hs.clientFinished, |
| } |
| hs.transcript.Write(finishedMsg.marshal()) |
| |
| if !hs.shouldSendSessionTickets() { |
| return nil |
| } |
| |
| resumptionSecret := hs.suite.deriveSecret(hs.masterSecret, |
| resumptionLabel, hs.transcript) |
| |
| m := new(newSessionTicketMsgTLS13) |
| |
| var certsFromClient [][]byte |
| for _, cert := range c.peerCertificates { |
| certsFromClient = append(certsFromClient, cert.Raw) |
| } |
| state := sessionStateTLS13{ |
| cipherSuite: hs.suite.id, |
| createdAt: uint64(c.config.time().Unix()), |
| resumptionSecret: resumptionSecret, |
| certificate: Certificate{ |
| Certificate: certsFromClient, |
| OCSPStaple: c.ocspResponse, |
| SignedCertificateTimestamps: c.scts, |
| }, |
| } |
| var err error |
| m.label, err = c.encryptTicket(state.marshal()) |
| if err != nil { |
| return err |
| } |
| m.lifetime = uint32(maxSessionTicketLifetime / time.Second) |
| |
| if _, err := c.writeRecord(recordTypeHandshake, m.marshal()); err != nil { |
| return err |
| } |
| |
| return nil |
| } |
| |
| func (hs *serverHandshakeStateTLS13) readClientCertificate() error { |
| c := hs.c |
| |
| if !hs.requestClientCert() { |
| // Make sure the connection is still being verified whether or not |
| // the server requested a client certificate. |
| if c.config.VerifyConnection != nil { |
| if err := c.config.VerifyConnection(c.connectionStateLocked()); err != nil { |
| c.sendAlert(alertBadCertificate) |
| return err |
| } |
| } |
| return nil |
| } |
| |
| // If we requested a client certificate, then the client must send a |
| // certificate message. If it's empty, no CertificateVerify is sent. |
| |
| msg, err := c.readHandshake() |
| if err != nil { |
| return err |
| } |
| |
| certMsg, ok := msg.(*certificateMsgTLS13) |
| if !ok { |
| c.sendAlert(alertUnexpectedMessage) |
| return unexpectedMessageError(certMsg, msg) |
| } |
| hs.transcript.Write(certMsg.marshal()) |
| |
| if err := c.processCertsFromClient(certMsg.certificate); err != nil { |
| return err |
| } |
| |
| if c.config.VerifyConnection != nil { |
| if err := c.config.VerifyConnection(c.connectionStateLocked()); err != nil { |
| c.sendAlert(alertBadCertificate) |
| return err |
| } |
| } |
| |
| if len(certMsg.certificate.Certificate) != 0 { |
| msg, err = c.readHandshake() |
| if err != nil { |
| return err |
| } |
| |
| certVerify, ok := msg.(*certificateVerifyMsg) |
| if !ok { |
| c.sendAlert(alertUnexpectedMessage) |
| return unexpectedMessageError(certVerify, msg) |
| } |
| |
| // See RFC 8446, Section 4.4.3. |
| if !isSupportedSignatureAlgorithm(certVerify.signatureAlgorithm, supportedSignatureAlgorithms()) { |
| c.sendAlert(alertIllegalParameter) |
| return errors.New("tls: client certificate used with invalid signature algorithm") |
| } |
| sigType, sigHash, err := typeAndHashFromSignatureScheme(certVerify.signatureAlgorithm) |
| if err != nil { |
| return c.sendAlert(alertInternalError) |
| } |
| if sigType == signaturePKCS1v15 || sigHash == crypto.SHA1 { |
| c.sendAlert(alertIllegalParameter) |
| return errors.New("tls: client certificate used with invalid signature algorithm") |
| } |
| signed := signedMessage(sigHash, clientSignatureContext, hs.transcript) |
| if err := verifyHandshakeSignature(sigType, c.peerCertificates[0].PublicKey, |
| sigHash, signed, certVerify.signature); err != nil { |
| c.sendAlert(alertDecryptError) |
| return errors.New("tls: invalid signature by the client certificate: " + err.Error()) |
| } |
| |
| hs.transcript.Write(certVerify.marshal()) |
| } |
| |
| // If we waited until the client certificates to send session tickets, we |
| // are ready to do it now. |
| if err := hs.sendSessionTickets(); err != nil { |
| return err |
| } |
| |
| return nil |
| } |
| |
| func (hs *serverHandshakeStateTLS13) readClientFinished() error { |
| c := hs.c |
| |
| msg, err := c.readHandshake() |
| if err != nil { |
| return err |
| } |
| |
| finished, ok := msg.(*finishedMsg) |
| if !ok { |
| c.sendAlert(alertUnexpectedMessage) |
| return unexpectedMessageError(finished, msg) |
| } |
| |
| if !hmac.Equal(hs.clientFinished, finished.verifyData) { |
| c.sendAlert(alertDecryptError) |
| return errors.New("tls: invalid client finished hash") |
| } |
| |
| c.in.setTrafficSecret(hs.suite, hs.trafficSecret) |
| |
| return nil |
| } |