60edffd2a5
TLS 1.3 defines a new SignatureScheme uint16 enum that is backwards compatible on the wire with TLS1.2's SignatureAndHashAlgorithm. This change updates the go testing code to use a single signatureAlgorithm enum (instead of 2 separate signature and hash enums) in preparation for TLS 1.3. It also unifies all the signing around this new scheme, effectively backporting the change to TLS 1.2. For now, it does not distinguish signature algorithms between 1.2 and 1.3 (RSA-PSS instead of RSA-PKCS1, ECDSA must match curve types). When the C code is ready make a similar change, the Go code will be updated to match. [Originally written by nharper, tweaked significantly by davidben.] Change-Id: If9a315c4670755089ac061e4ec254ef3457a00de Reviewed-on: https://boringssl-review.googlesource.com/8450 Reviewed-by: David Benjamin <davidben@google.com>
220 lines
5.9 KiB
Go
220 lines
5.9 KiB
Go
// Copyright 2016 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package runner
|
|
|
|
import (
|
|
"crypto"
|
|
"crypto/ecdsa"
|
|
"crypto/md5"
|
|
"crypto/rsa"
|
|
"crypto/sha1"
|
|
_ "crypto/sha256"
|
|
_ "crypto/sha512"
|
|
"encoding/asn1"
|
|
"errors"
|
|
"fmt"
|
|
"math/big"
|
|
)
|
|
|
|
type signer interface {
|
|
supportsKey(key crypto.PrivateKey) bool
|
|
signMessage(key crypto.PrivateKey, config *Config, msg []byte) ([]byte, error)
|
|
verifyMessage(key crypto.PublicKey, msg, sig []byte) error
|
|
}
|
|
|
|
func selectSignatureAlgorithm(version uint16, key crypto.PrivateKey, peerSigAlgs, ourSigAlgs []signatureAlgorithm) (signatureAlgorithm, error) {
|
|
// If the client didn't specify any signature_algorithms extension then
|
|
// we can assume that it supports SHA1. See
|
|
// http://tools.ietf.org/html/rfc5246#section-7.4.1.4.1
|
|
if len(peerSigAlgs) == 0 {
|
|
peerSigAlgs = []signatureAlgorithm{signatureRSAPKCS1WithSHA1, signatureECDSAWithSHA1}
|
|
}
|
|
|
|
for _, sigAlg := range ourSigAlgs {
|
|
if !isSupportedSignatureAlgorithm(sigAlg, peerSigAlgs) {
|
|
continue
|
|
}
|
|
|
|
signer, err := getSigner(version, key, sigAlg)
|
|
if err != nil {
|
|
continue
|
|
}
|
|
|
|
if signer.supportsKey(key) {
|
|
return sigAlg, nil
|
|
}
|
|
}
|
|
return 0, errors.New("tls: no common signature algorithms")
|
|
}
|
|
|
|
func signMessage(version uint16, key crypto.PrivateKey, config *Config, sigAlg signatureAlgorithm, msg []byte) ([]byte, error) {
|
|
signer, err := getSigner(version, key, sigAlg)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return signer.signMessage(key, config, msg)
|
|
}
|
|
|
|
func verifyMessage(version uint16, key crypto.PublicKey, sigAlg signatureAlgorithm, msg, sig []byte) error {
|
|
signer, err := getSigner(version, key, sigAlg)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return signer.verifyMessage(key, msg, sig)
|
|
}
|
|
|
|
type rsaPKCS1Signer struct {
|
|
hash crypto.Hash
|
|
}
|
|
|
|
func (r *rsaPKCS1Signer) computeHash(msg []byte) []byte {
|
|
if r.hash == crypto.MD5SHA1 {
|
|
// crypto.MD5SHA1 is not a real hash function.
|
|
hashMD5 := md5.New()
|
|
hashMD5.Write(msg)
|
|
hashSHA1 := sha1.New()
|
|
hashSHA1.Write(msg)
|
|
return hashSHA1.Sum(hashMD5.Sum(nil))
|
|
}
|
|
|
|
h := r.hash.New()
|
|
h.Write(msg)
|
|
return h.Sum(nil)
|
|
}
|
|
|
|
func (r *rsaPKCS1Signer) supportsKey(key crypto.PrivateKey) bool {
|
|
_, ok := key.(*rsa.PrivateKey)
|
|
return ok
|
|
}
|
|
|
|
func (r *rsaPKCS1Signer) signMessage(key crypto.PrivateKey, config *Config, msg []byte) ([]byte, error) {
|
|
rsaKey, ok := key.(*rsa.PrivateKey)
|
|
if !ok {
|
|
return nil, errors.New("invalid key type for RSA-PKCS1")
|
|
}
|
|
|
|
return rsa.SignPKCS1v15(config.rand(), rsaKey, r.hash, r.computeHash(msg))
|
|
}
|
|
|
|
func (r *rsaPKCS1Signer) verifyMessage(key crypto.PublicKey, msg, sig []byte) error {
|
|
rsaKey, ok := key.(*rsa.PublicKey)
|
|
if !ok {
|
|
return errors.New("invalid key type for RSA-PKCS1")
|
|
}
|
|
|
|
return rsa.VerifyPKCS1v15(rsaKey, r.hash, r.computeHash(msg), sig)
|
|
}
|
|
|
|
type ecdsaSigner struct {
|
|
// TODO(davidben): In TLS 1.3, ECDSA signatures must match curves as
|
|
// well. Pass in a curve to enforce in 1.3 alone.
|
|
hash crypto.Hash
|
|
}
|
|
|
|
func (e *ecdsaSigner) supportsKey(key crypto.PrivateKey) bool {
|
|
_, ok := key.(*ecdsa.PrivateKey)
|
|
return ok
|
|
}
|
|
|
|
func maybeCorruptECDSAValue(n *big.Int, typeOfCorruption BadValue, limit *big.Int) *big.Int {
|
|
switch typeOfCorruption {
|
|
case BadValueNone:
|
|
return n
|
|
case BadValueNegative:
|
|
return new(big.Int).Neg(n)
|
|
case BadValueZero:
|
|
return big.NewInt(0)
|
|
case BadValueLimit:
|
|
return limit
|
|
case BadValueLarge:
|
|
bad := new(big.Int).Set(limit)
|
|
return bad.Lsh(bad, 20)
|
|
default:
|
|
panic("unknown BadValue type")
|
|
}
|
|
}
|
|
|
|
func (e *ecdsaSigner) signMessage(key crypto.PrivateKey, config *Config, msg []byte) ([]byte, error) {
|
|
ecdsaKey, ok := key.(*ecdsa.PrivateKey)
|
|
if !ok {
|
|
return nil, errors.New("invalid key type for ECDSA")
|
|
}
|
|
|
|
h := e.hash.New()
|
|
h.Write(msg)
|
|
digest := h.Sum(nil)
|
|
|
|
r, s, err := ecdsa.Sign(config.rand(), ecdsaKey, digest)
|
|
if err != nil {
|
|
return nil, errors.New("failed to sign ECDHE parameters: " + err.Error())
|
|
}
|
|
order := ecdsaKey.Curve.Params().N
|
|
r = maybeCorruptECDSAValue(r, config.Bugs.BadECDSAR, order)
|
|
s = maybeCorruptECDSAValue(s, config.Bugs.BadECDSAS, order)
|
|
return asn1.Marshal(ecdsaSignature{r, s})
|
|
}
|
|
|
|
func (e *ecdsaSigner) verifyMessage(key crypto.PublicKey, msg, sig []byte) error {
|
|
ecdsaKey, ok := key.(*ecdsa.PublicKey)
|
|
if !ok {
|
|
return errors.New("invalid key type for ECDSA")
|
|
}
|
|
|
|
ecdsaSig := new(ecdsaSignature)
|
|
if _, err := asn1.Unmarshal(sig, ecdsaSig); err != nil {
|
|
return err
|
|
}
|
|
if ecdsaSig.R.Sign() <= 0 || ecdsaSig.S.Sign() <= 0 {
|
|
return errors.New("ECDSA signature contained zero or negative values")
|
|
}
|
|
|
|
h := e.hash.New()
|
|
h.Write(msg)
|
|
if !ecdsa.Verify(ecdsaKey, h.Sum(nil), ecdsaSig.R, ecdsaSig.S) {
|
|
return errors.New("ECDSA verification failure")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func getSigner(version uint16, key interface{}, sigAlg signatureAlgorithm) (signer, error) {
|
|
// TLS 1.1 and below use legacy signature algorithms.
|
|
if version < VersionTLS12 {
|
|
switch key.(type) {
|
|
case *rsa.PrivateKey, *rsa.PublicKey:
|
|
return &rsaPKCS1Signer{crypto.MD5SHA1}, nil
|
|
case *ecdsa.PrivateKey, *ecdsa.PublicKey:
|
|
return &ecdsaSigner{crypto.SHA1}, nil
|
|
default:
|
|
return nil, errors.New("unknown key type")
|
|
}
|
|
}
|
|
|
|
// TODO(davidben): Implement RSA-PSS for TLS 1.3.
|
|
switch sigAlg {
|
|
case signatureRSAPKCS1WithMD5:
|
|
return &rsaPKCS1Signer{crypto.MD5}, nil
|
|
case signatureRSAPKCS1WithSHA1:
|
|
return &rsaPKCS1Signer{crypto.SHA1}, nil
|
|
case signatureRSAPKCS1WithSHA256:
|
|
return &rsaPKCS1Signer{crypto.SHA256}, nil
|
|
case signatureRSAPKCS1WithSHA384:
|
|
return &rsaPKCS1Signer{crypto.SHA384}, nil
|
|
case signatureRSAPKCS1WithSHA512:
|
|
return &rsaPKCS1Signer{crypto.SHA512}, nil
|
|
case signatureECDSAWithSHA1:
|
|
return &ecdsaSigner{crypto.SHA1}, nil
|
|
case signatureECDSAWithP256AndSHA256:
|
|
return &ecdsaSigner{crypto.SHA256}, nil
|
|
case signatureECDSAWithP384AndSHA384:
|
|
return &ecdsaSigner{crypto.SHA384}, nil
|
|
case signatureECDSAWithP521AndSHA512:
|
|
return &ecdsaSigner{crypto.SHA512}, nil
|
|
default:
|
|
return nil, fmt.Errorf("unsupported signature algorithm %04x", sigAlg)
|
|
}
|
|
}
|