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.
suite *cipherSuite
ellipticOk bool
ecdsaOk bool
+ rsaOk bool
+ signOk bool
+ decryptOk bool
sessionState *sessionState
finishedHash finishedHash
masterSecret []byte
}
}
- _, 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
}
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
}
}
}
// 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
}
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
}
// 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
}
}
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
}
}
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
}
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