]> Cypherpunks repositories - gostls13.git/commitdiff
crypto/tls: make use of crypto.Signer and crypto.Decrypter
authorJacob H. Haven <jacob@cloudflare.com>
Thu, 19 Mar 2015 11:01:57 +0000 (04:01 -0700)
committerAdam Langley <agl@golang.org>
Thu, 2 Apr 2015 23:19:57 +0000 (23:19 +0000)
This change replaces all direct ECDSA/RSA sign and decrypt operations
with calls through the crypto.Signer and crypto.Decrypter interfaces.

This is a follow-up to https://go-review.googlesource.com/#/c/3900/
which added crypto.Decrypter and implemented it for RSA.

Change-Id: Ie0f3928448b285f329efcd3a93ca3fd5e3b3e42d
Reviewed-on: https://go-review.googlesource.com/7804
Reviewed-by: Adam Langley <agl@golang.org>
src/crypto/tls/common.go
src/crypto/tls/handshake_server.go
src/crypto/tls/key_agreement.go

index 584a36155879598b721dcd519e5e46e9db94bae4..ec3e997c5d6b8e3774818a2f6d2193a463a81ad1 100644 (file)
@@ -489,10 +489,10 @@ func (c *Config) BuildNameToCertificate() {
 type Certificate struct {
        Certificate [][]byte
        // PrivateKey contains the private key corresponding to the public key
-       // in Leaf. For a server, this must be a *rsa.PrivateKey or
-       // *ecdsa.PrivateKey. For a client doing client authentication, this
-       // can be any type that implements crypto.Signer (which includes RSA
-       // and ECDSA private keys).
+       // in Leaf. For a server, this must implement either crypto.Decrypter
+       // (implemented by RSA private keys) or crypto.Signer (which includes
+       // RSA and ECDSA private keys). For a client doing client authentication,
+       // this can be any type that implements crypto.Signer.
        PrivateKey crypto.PrivateKey
        // OCSPStaple contains an optional OCSP response which will be served
        // to clients that request it.
index c7c1f1e1f52d255318967f37f6523afc15e482ae..8b31c7cf35b648bef586983f362979a8beb8e33e 100644 (file)
@@ -25,6 +25,9 @@ type serverHandshakeState struct {
        suite           *cipherSuite
        ellipticOk      bool
        ecdsaOk         bool
+       rsaOk           bool
+       signOk          bool
+       decryptOk       bool
        sessionState    *sessionState
        finishedHash    finishedHash
        masterSecret    []byte
@@ -197,7 +200,28 @@ Curves:
                }
        }
 
-       _, hs.ecdsaOk = hs.cert.PrivateKey.(*ecdsa.PrivateKey)
+       if priv, ok := hs.cert.PrivateKey.(crypto.Signer); ok {
+               hs.signOk = true
+               switch priv.Public().(type) {
+               case *ecdsa.PublicKey:
+                       hs.ecdsaOk = true
+               case *rsa.PublicKey:
+                       hs.rsaOk = true
+               default:
+                       c.sendAlert(alertInternalError)
+                       return false, fmt.Errorf("crypto/tls: unsupported signing key type (%T)", priv.Public())
+               }
+       }
+       if priv, ok := hs.cert.PrivateKey.(crypto.Decrypter); ok {
+               hs.decryptOk = true
+               switch priv.Public().(type) {
+               case *rsa.PublicKey:
+                       hs.rsaOk = true
+               default:
+                       c.sendAlert(alertInternalError)
+                       return false, fmt.Errorf("crypto/tls: unsupported decryption key type (%T)", priv.Public())
+               }
+       }
 
        if hs.checkForResumption() {
                return true, nil
@@ -213,7 +237,7 @@ Curves:
        }
 
        for _, id := range preferenceList {
-               if hs.suite = c.tryCipherSuite(id, supportedList, c.vers, hs.ellipticOk, hs.ecdsaOk); hs.suite != nil {
+               if hs.setCipherSuite(id, supportedList, c.vers) {
                        break
                }
        }
@@ -272,8 +296,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.sessionState.vers, hs.ellipticOk, hs.ecdsaOk)
-       if hs.suite == nil {
+       if !hs.setCipherSuite(hs.sessionState.cipherSuite, c.config.cipherSuites(), hs.sessionState.vers) {
                return false
        }
 
@@ -649,9 +672,10 @@ func (hs *serverHandshakeState) processCertsFromClient(certificates [][]byte) (c
        return nil, nil
 }
 
-// tryCipherSuite returns a cipherSuite with the given id if that cipher suite
-// is acceptable to use.
-func (c *Conn) tryCipherSuite(id uint16, supportedCipherSuites []uint16, version uint16, ellipticOk, ecdsaOk bool) *cipherSuite {
+// setCipherSuite sets a cipherSuite with the given id as the serverHandshakeState
+// suite if that cipher suite is acceptable to use.
+// It returns a bool indicating if the suite was set.
+func (hs *serverHandshakeState) setCipherSuite(id uint16, supportedCipherSuites []uint16, version uint16) bool {
        for _, supported := range supportedCipherSuites {
                if id == supported {
                        var candidate *cipherSuite
@@ -667,18 +691,26 @@ func (c *Conn) tryCipherSuite(id uint16, supportedCipherSuites []uint16, version
                        }
                        // Don't select a ciphersuite which we can't
                        // support for this client.
-                       if (candidate.flags&suiteECDHE != 0) && !ellipticOk {
-                               continue
-                       }
-                       if (candidate.flags&suiteECDSA != 0) != ecdsaOk {
+                       if candidate.flags&suiteECDHE != 0 {
+                               if !hs.ellipticOk || !hs.signOk {
+                                       continue
+                               }
+                               if candidate.flags&suiteECDSA != 0 {
+                                       if !hs.ecdsaOk {
+                                               continue
+                                       }
+                               } else if !hs.rsaOk {
+                                       continue
+                               }
+                       } else if !hs.decryptOk || !hs.rsaOk {
                                continue
                        }
                        if version < VersionTLS12 && candidate.flags&suiteTLS12 != 0 {
                                continue
                        }
-                       return candidate
+                       hs.suite = candidate
+                       return true
                }
        }
-
-       return nil
+       return false
 }
index 0974fc6e0f4add7a51627ea2bb1675d569a582c4..d57d93357d81885ea4c2717370ceb71c80975eb1 100644 (file)
@@ -31,12 +31,6 @@ func (ka rsaKeyAgreement) generateServerKeyExchange(config *Config, cert *Certif
 }
 
 func (ka rsaKeyAgreement) processClientKeyExchange(config *Config, cert *Certificate, ckx *clientKeyExchangeMsg, version uint16) ([]byte, error) {
-       preMasterSecret := make([]byte, 48)
-       _, err := io.ReadFull(config.rand(), preMasterSecret[2:])
-       if err != nil {
-               return nil, err
-       }
-
        if len(ckx.ciphertext) < 2 {
                return nil, errClientKeyExchange
        }
@@ -49,8 +43,12 @@ func (ka rsaKeyAgreement) processClientKeyExchange(config *Config, cert *Certifi
                }
                ciphertext = ckx.ciphertext[2:]
        }
-
-       err = rsa.DecryptPKCS1v15SessionKey(config.rand(), cert.PrivateKey.(*rsa.PrivateKey), ciphertext, preMasterSecret)
+       priv, ok := cert.PrivateKey.(crypto.Decrypter)
+       if !ok {
+               return nil, errors.New("tls: certificate private key does not implement crypto.Decrypter")
+       }
+       // Perform contant time RSA PKCS#1 v1.5 decryption
+       preMasterSecret, err := priv.Decrypt(config.rand(), ciphertext, &rsa.PKCS1v15DecryptOptions{SessionKeyLen: 48})
        if err != nil {
                return nil, err
        }
@@ -239,30 +237,30 @@ NextCandidate:
        if err != nil {
                return nil, err
        }
+
+       priv, ok := cert.PrivateKey.(crypto.Signer)
+       if !ok {
+               return nil, errors.New("tls: certificate private key does not implement crypto.Signer")
+       }
        var sig []byte
        switch ka.sigType {
        case signatureECDSA:
-               privKey, ok := cert.PrivateKey.(*ecdsa.PrivateKey)
+               _, ok := priv.Public().(*ecdsa.PublicKey)
                if !ok {
-                       return nil, errors.New("ECDHE ECDSA requires an ECDSA server private key")
-               }
-               r, s, err := ecdsa.Sign(config.rand(), privKey, digest)
-               if err != nil {
-                       return nil, errors.New("failed to sign ECDHE parameters: " + err.Error())
+                       return nil, errors.New("ECDHE ECDSA requires an ECDSA server key")
                }
-               sig, err = asn1.Marshal(ecdsaSignature{r, s})
        case signatureRSA:
-               privKey, ok := cert.PrivateKey.(*rsa.PrivateKey)
+               _, ok := priv.Public().(*rsa.PublicKey)
                if !ok {
-                       return nil, errors.New("ECDHE RSA requires a RSA server private key")
-               }
-               sig, err = rsa.SignPKCS1v15(config.rand(), privKey, hashFunc, digest)
-               if err != nil {
-                       return nil, errors.New("failed to sign ECDHE parameters: " + err.Error())
+                       return nil, errors.New("ECDHE RSA requires a RSA server key")
                }
        default:
                return nil, errors.New("unknown ECDHE signature algorithm")
        }
+       sig, err = priv.Sign(config.rand(), digest, hashFunc)
+       if err != nil {
+               return nil, errors.New("failed to sign ECDHE parameters: " + err.Error())
+       }
 
        skx := new(serverKeyExchangeMsg)
        sigAndHashLen := 0