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:
parent
1282c034fb
commit
14accaf7f3
@ -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.
|
||||||
|
@ -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
|
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user