crypto/tls: make use of crypto.Signer and crypto.Decrypter

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>
This commit is contained in:
Jacob H. Haven 2015-03-19 04:01:57 -07:00 committed by Adam Langley
parent 1282c034fb
commit 14accaf7f3
3 changed files with 69 additions and 39 deletions

View File

@ -489,10 +489,10 @@ func (c *Config) BuildNameToCertificate() {
type Certificate struct { type Certificate struct {
Certificate [][]byte Certificate [][]byte
// PrivateKey contains the private key corresponding to the public key // PrivateKey contains the private key corresponding to the public key
// in Leaf. For a server, this must be a *rsa.PrivateKey or // in Leaf. For a server, this must implement either crypto.Decrypter
// *ecdsa.PrivateKey. For a client doing client authentication, this // (implemented by RSA private keys) or crypto.Signer (which includes
// can be any type that implements crypto.Signer (which includes RSA // RSA and ECDSA private keys). For a client doing client authentication,
// and ECDSA private keys). // this can be any type that implements crypto.Signer.
PrivateKey crypto.PrivateKey PrivateKey crypto.PrivateKey
// OCSPStaple contains an optional OCSP response which will be served // OCSPStaple contains an optional OCSP response which will be served
// to clients that request it. // to clients that request it.

View File

@ -25,6 +25,9 @@ type serverHandshakeState struct {
suite *cipherSuite suite *cipherSuite
ellipticOk bool ellipticOk bool
ecdsaOk bool ecdsaOk bool
rsaOk bool
signOk bool
decryptOk bool
sessionState *sessionState sessionState *sessionState
finishedHash finishedHash finishedHash finishedHash
masterSecret []byte 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() { if hs.checkForResumption() {
return true, nil return true, nil
@ -213,7 +237,7 @@ Curves:
} }
for _, id := range preferenceList { 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 break
} }
} }
@ -272,8 +296,7 @@ func (hs *serverHandshakeState) checkForResumption() bool {
} }
// Check that we also support the ciphersuite from the session. // 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.setCipherSuite(hs.sessionState.cipherSuite, c.config.cipherSuites(), hs.sessionState.vers) {
if hs.suite == nil {
return false return false
} }
@ -649,9 +672,10 @@ func (hs *serverHandshakeState) processCertsFromClient(certificates [][]byte) (c
return nil, nil return nil, nil
} }
// tryCipherSuite returns a cipherSuite with the given id if that cipher suite // setCipherSuite sets a cipherSuite with the given id as the serverHandshakeState
// is acceptable to use. // suite if that cipher suite is acceptable to use.
func (c *Conn) tryCipherSuite(id uint16, supportedCipherSuites []uint16, version uint16, ellipticOk, ecdsaOk bool) *cipherSuite { // 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 { for _, supported := range supportedCipherSuites {
if id == supported { if id == supported {
var candidate *cipherSuite 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 // Don't select a ciphersuite which we can't
// support for this client. // support for this client.
if (candidate.flags&suiteECDHE != 0) && !ellipticOk { if candidate.flags&suiteECDHE != 0 {
if !hs.ellipticOk || !hs.signOk {
continue continue
} }
if (candidate.flags&suiteECDSA != 0) != ecdsaOk { if candidate.flags&suiteECDSA != 0 {
if !hs.ecdsaOk {
continue
}
} else if !hs.rsaOk {
continue
}
} else if !hs.decryptOk || !hs.rsaOk {
continue continue
} }
if version < VersionTLS12 && candidate.flags&suiteTLS12 != 0 { if version < VersionTLS12 && candidate.flags&suiteTLS12 != 0 {
continue continue
} }
return candidate hs.suite = candidate
return true
} }
} }
return false
return nil
} }

View 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) { 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 { if len(ckx.ciphertext) < 2 {
return nil, errClientKeyExchange return nil, errClientKeyExchange
} }
@ -49,8 +43,12 @@ func (ka rsaKeyAgreement) processClientKeyExchange(config *Config, cert *Certifi
} }
ciphertext = ckx.ciphertext[2:] ciphertext = ckx.ciphertext[2:]
} }
priv, ok := cert.PrivateKey.(crypto.Decrypter)
err = rsa.DecryptPKCS1v15SessionKey(config.rand(), cert.PrivateKey.(*rsa.PrivateKey), ciphertext, preMasterSecret) 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 { if err != nil {
return nil, err return nil, err
} }
@ -239,30 +237,30 @@ NextCandidate:
if err != nil { if err != nil {
return nil, err 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 var sig []byte
switch ka.sigType { switch ka.sigType {
case signatureECDSA: case signatureECDSA:
privKey, ok := cert.PrivateKey.(*ecdsa.PrivateKey) _, ok := priv.Public().(*ecdsa.PublicKey)
if !ok { if !ok {
return nil, errors.New("ECDHE ECDSA requires an ECDSA server private key") return nil, errors.New("ECDHE ECDSA requires an ECDSA server key")
} }
r, s, err := ecdsa.Sign(config.rand(), privKey, digest)
if err != nil {
return nil, errors.New("failed to sign ECDHE parameters: " + err.Error())
}
sig, err = asn1.Marshal(ecdsaSignature{r, s})
case signatureRSA: case signatureRSA:
privKey, ok := cert.PrivateKey.(*rsa.PrivateKey) _, ok := priv.Public().(*rsa.PublicKey)
if !ok { if !ok {
return nil, errors.New("ECDHE RSA requires a RSA server private key") return nil, errors.New("ECDHE RSA requires a RSA server key")
}
sig, err = rsa.SignPKCS1v15(config.rand(), privKey, hashFunc, digest)
if err != nil {
return nil, errors.New("failed to sign ECDHE parameters: " + err.Error())
} }
default: default:
return nil, errors.New("unknown ECDHE signature algorithm") 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) skx := new(serverKeyExchangeMsg)
sigAndHashLen := 0 sigAndHashLen := 0