summaryrefslogtreecommitdiff
path: root/src/pkg/crypto/tls/handshake_server.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/pkg/crypto/tls/handshake_server.go')
-rw-r--r--src/pkg/crypto/tls/handshake_server.go121
1 files changed, 85 insertions, 36 deletions
diff --git a/src/pkg/crypto/tls/handshake_server.go b/src/pkg/crypto/tls/handshake_server.go
index 823730c60..c9ccf675c 100644
--- a/src/pkg/crypto/tls/handshake_server.go
+++ b/src/pkg/crypto/tls/handshake_server.go
@@ -6,9 +6,11 @@ package tls
import (
"crypto"
+ "crypto/ecdsa"
"crypto/rsa"
"crypto/subtle"
"crypto/x509"
+ "encoding/asn1"
"errors"
"io"
)
@@ -21,10 +23,12 @@ type serverHandshakeState struct {
hello *serverHelloMsg
suite *cipherSuite
ellipticOk bool
+ ecdsaOk bool
sessionState *sessionState
finishedHash finishedHash
masterSecret []byte
certsFromClient [][]byte
+ cert *Certificate
}
// serverHandshake performs a TLS handshake as a server.
@@ -98,7 +102,7 @@ func (hs *serverHandshakeState) readClientHello() (isResume bool, err error) {
if !ok {
return false, c.sendAlert(alertUnexpectedMessage)
}
- c.vers, ok = mutualVersion(hs.clientHello.vers)
+ c.vers, ok = config.mutualVersion(hs.clientHello.vers)
if !ok {
return false, c.sendAlert(alertProtocolVersion)
}
@@ -156,11 +160,25 @@ Curves:
if len(hs.clientHello.serverName) > 0 {
c.serverName = hs.clientHello.serverName
}
- if hs.clientHello.nextProtoNeg {
+ // Although sending an empty NPN extension is reasonable, Firefox has
+ // had a bug around this. Best to send nothing at all if
+ // config.NextProtos is empty. See
+ // https://code.google.com/p/go/issues/detail?id=5445.
+ if hs.clientHello.nextProtoNeg && len(config.NextProtos) > 0 {
hs.hello.nextProtoNeg = true
hs.hello.nextProtos = config.NextProtos
}
+ if len(config.Certificates) == 0 {
+ return false, c.sendAlert(alertInternalError)
+ }
+ hs.cert = &config.Certificates[0]
+ if len(hs.clientHello.serverName) > 0 {
+ hs.cert = config.getCertificateForName(hs.clientHello.serverName)
+ }
+
+ _, hs.ecdsaOk = hs.cert.PrivateKey.(*ecdsa.PrivateKey)
+
if hs.checkForResumption() {
return true, nil
}
@@ -175,7 +193,7 @@ Curves:
}
for _, id := range preferenceList {
- if hs.suite = c.tryCipherSuite(id, supportedList, hs.ellipticOk); hs.suite != nil {
+ if hs.suite = c.tryCipherSuite(id, supportedList, c.vers, hs.ellipticOk, hs.ecdsaOk); hs.suite != nil {
break
}
}
@@ -199,7 +217,7 @@ func (hs *serverHandshakeState) checkForResumption() bool {
if hs.sessionState.vers > hs.clientHello.vers {
return false
}
- if vers, ok := mutualVersion(hs.sessionState.vers); !ok || vers != hs.sessionState.vers {
+ if vers, ok := c.config.mutualVersion(hs.sessionState.vers); !ok || vers != hs.sessionState.vers {
return false
}
@@ -216,7 +234,7 @@ func (hs *serverHandshakeState) checkForResumption() bool {
}
// Check that we also support the ciphersuite from the session.
- hs.suite = c.tryCipherSuite(hs.sessionState.cipherSuite, c.config.cipherSuites(), hs.ellipticOk)
+ hs.suite = c.tryCipherSuite(hs.sessionState.cipherSuite, c.config.cipherSuites(), hs.sessionState.vers, hs.ellipticOk, hs.ecdsaOk)
if hs.suite == nil {
return false
}
@@ -258,15 +276,7 @@ func (hs *serverHandshakeState) doFullHandshake() error {
config := hs.c.config
c := hs.c
- if len(config.Certificates) == 0 {
- return c.sendAlert(alertInternalError)
- }
- cert := &config.Certificates[0]
- if len(hs.clientHello.serverName) > 0 {
- cert = config.getCertificateForName(hs.clientHello.serverName)
- }
-
- if hs.clientHello.ocspStapling && len(cert.OCSPStaple) > 0 {
+ if hs.clientHello.ocspStapling && len(hs.cert.OCSPStaple) > 0 {
hs.hello.ocspStapling = true
}
@@ -276,20 +286,20 @@ func (hs *serverHandshakeState) doFullHandshake() error {
c.writeRecord(recordTypeHandshake, hs.hello.marshal())
certMsg := new(certificateMsg)
- certMsg.certificates = cert.Certificate
+ certMsg.certificates = hs.cert.Certificate
hs.finishedHash.Write(certMsg.marshal())
c.writeRecord(recordTypeHandshake, certMsg.marshal())
if hs.hello.ocspStapling {
certStatus := new(certificateStatusMsg)
certStatus.statusType = statusTypeOCSP
- certStatus.response = cert.OCSPStaple
+ certStatus.response = hs.cert.OCSPStaple
hs.finishedHash.Write(certStatus.marshal())
c.writeRecord(recordTypeHandshake, certStatus.marshal())
}
- keyAgreement := hs.suite.ka()
- skx, err := keyAgreement.generateServerKeyExchange(config, cert, hs.clientHello, hs.hello)
+ keyAgreement := hs.suite.ka(c.vers)
+ skx, err := keyAgreement.generateServerKeyExchange(config, hs.cert, hs.clientHello, hs.hello)
if err != nil {
c.sendAlert(alertHandshakeFailure)
return err
@@ -302,7 +312,14 @@ func (hs *serverHandshakeState) doFullHandshake() error {
if config.ClientAuth >= RequestClientCert {
// Request a client certificate
certReq := new(certificateRequestMsg)
- certReq.certificateTypes = []byte{certTypeRSASign}
+ certReq.certificateTypes = []byte{
+ byte(certTypeRSASign),
+ byte(certTypeECDSASign),
+ }
+ if c.vers >= VersionTLS12 {
+ certReq.hasSignatureAndHash = true
+ certReq.signatureAndHashes = supportedClientCertSignatureAlgorithms
+ }
// An empty list of certificateAuthorities signals to
// the client that it may send any certificate in response
@@ -320,7 +337,7 @@ func (hs *serverHandshakeState) doFullHandshake() error {
hs.finishedHash.Write(helloDone.marshal())
c.writeRecord(recordTypeHandshake, helloDone.marshal())
- var pub *rsa.PublicKey // public key for client auth, if any
+ var pub crypto.PublicKey // public key for client auth, if any
msg, err := c.readHandshake()
if err != nil {
@@ -365,7 +382,7 @@ func (hs *serverHandshakeState) doFullHandshake() error {
// If we received a client cert in response to our certificate request message,
// the client will send us a certificateVerifyMsg immediately after the
- // clientKeyExchangeMsg. This message is a MD5SHA1 digest of all preceding
+ // clientKeyExchangeMsg. This message is a digest of all preceding
// handshake-layer messages that is signed using the private key corresponding
// to the client's certificate. This allows us to verify that the client is in
// possession of the private key of the certificate.
@@ -379,10 +396,25 @@ func (hs *serverHandshakeState) doFullHandshake() error {
return c.sendAlert(alertUnexpectedMessage)
}
- digest := make([]byte, 0, 36)
- digest = hs.finishedHash.serverMD5.Sum(digest)
- digest = hs.finishedHash.serverSHA1.Sum(digest)
- err = rsa.VerifyPKCS1v15(pub, crypto.MD5SHA1, digest, certVerify.signature)
+ switch key := pub.(type) {
+ case *ecdsa.PublicKey:
+ ecdsaSig := new(ecdsaSignature)
+ if _, err = asn1.Unmarshal(certVerify.signature, ecdsaSig); err != nil {
+ break
+ }
+ if ecdsaSig.R.Sign() <= 0 || ecdsaSig.S.Sign() <= 0 {
+ err = errors.New("ECDSA signature contained zero or negative values")
+ break
+ }
+ digest, _, _ := hs.finishedHash.hashForClientCertificate(signatureECDSA)
+ if !ecdsa.Verify(key, digest, ecdsaSig.R, ecdsaSig.S) {
+ err = errors.New("ECDSA verification failure")
+ break
+ }
+ case *rsa.PublicKey:
+ digest, hashFunc, _ := hs.finishedHash.hashForClientCertificate(signatureRSA)
+ err = rsa.VerifyPKCS1v15(key, hashFunc, digest, certVerify.signature)
+ }
if err != nil {
c.sendAlert(alertBadCertificate)
return errors.New("could not validate signature of connection nonces: " + err.Error())
@@ -391,7 +423,7 @@ func (hs *serverHandshakeState) doFullHandshake() error {
hs.finishedHash.Write(certVerify.marshal())
}
- preMasterSecret, err := keyAgreement.processClientKeyExchange(config, cert, ckx, c.vers)
+ preMasterSecret, err := keyAgreement.processClientKeyExchange(config, hs.cert, ckx, c.vers)
if err != nil {
c.sendAlert(alertHandshakeFailure)
return err
@@ -407,12 +439,20 @@ func (hs *serverHandshakeState) establishKeys() error {
clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV :=
keysFromMasterSecret(c.vers, hs.masterSecret, hs.clientHello.random, hs.hello.random, hs.suite.macLen, hs.suite.keyLen, hs.suite.ivLen)
- clientCipher := hs.suite.cipher(clientKey, clientIV, true /* for reading */)
- clientHash := hs.suite.mac(c.vers, clientMAC)
- c.in.prepareCipherSpec(c.vers, clientCipher, clientHash)
+ var clientCipher, serverCipher interface{}
+ var clientHash, serverHash macFunction
- serverCipher := hs.suite.cipher(serverKey, serverIV, false /* not for reading */)
- serverHash := hs.suite.mac(c.vers, serverMAC)
+ if hs.suite.aead == nil {
+ clientCipher = hs.suite.cipher(clientKey, clientIV, true /* for reading */)
+ clientHash = hs.suite.mac(c.vers, clientMAC)
+ serverCipher = hs.suite.cipher(serverKey, serverIV, false /* not for reading */)
+ serverHash = hs.suite.mac(c.vers, serverMAC)
+ } else {
+ clientCipher = hs.suite.aead(clientKey, clientIV)
+ serverCipher = hs.suite.aead(serverKey, serverIV)
+ }
+
+ c.in.prepareCipherSpec(c.vers, clientCipher, clientHash)
c.out.prepareCipherSpec(c.vers, serverCipher, serverHash)
return nil
@@ -502,7 +542,7 @@ func (hs *serverHandshakeState) sendFinished() error {
// processCertsFromClient takes a chain of client certificates either from a
// Certificates message or from a sessionState and verifies them. It returns
// the public key of the leaf certificate.
-func (hs *serverHandshakeState) processCertsFromClient(certificates [][]byte) (*rsa.PublicKey, error) {
+func (hs *serverHandshakeState) processCertsFromClient(certificates [][]byte) (crypto.PublicKey, error) {
c := hs.c
hs.certsFromClient = certificates
@@ -549,8 +589,11 @@ func (hs *serverHandshakeState) processCertsFromClient(certificates [][]byte) (*
}
if len(certs) > 0 {
- pub, ok := certs[0].PublicKey.(*rsa.PublicKey)
- if !ok {
+ var pub crypto.PublicKey
+ switch key := certs[0].PublicKey.(type) {
+ case *ecdsa.PublicKey, *rsa.PublicKey:
+ pub = key
+ default:
return nil, c.sendAlert(alertUnsupportedCertificate)
}
c.peerCertificates = certs
@@ -562,7 +605,7 @@ func (hs *serverHandshakeState) processCertsFromClient(certificates [][]byte) (*
// tryCipherSuite returns a cipherSuite with the given id if that cipher suite
// is acceptable to use.
-func (c *Conn) tryCipherSuite(id uint16, supportedCipherSuites []uint16, ellipticOk bool) *cipherSuite {
+func (c *Conn) tryCipherSuite(id uint16, supportedCipherSuites []uint16, version uint16, ellipticOk, ecdsaOk bool) *cipherSuite {
for _, supported := range supportedCipherSuites {
if id == supported {
var candidate *cipherSuite
@@ -578,7 +621,13 @@ func (c *Conn) tryCipherSuite(id uint16, supportedCipherSuites []uint16, ellipti
}
// Don't select a ciphersuite which we can't
// support for this client.
- if candidate.elliptic && !ellipticOk {
+ if (candidate.flags&suiteECDHE != 0) && !ellipticOk {
+ continue
+ }
+ if (candidate.flags&suiteECDSA != 0) != ecdsaOk {
+ continue
+ }
+ if version < VersionTLS12 && candidate.flags&suiteTLS12 != 0 {
continue
}
return candidate