boringssl/ssl/test/runner/sign.go
Nick Harper 60edffd2a5 Change SignatureAndHashAlgorithm to SignatureScheme in Go.
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>
2016-07-06 20:19:07 +00:00

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)
}
}