// Copyright 2017 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 qtls import ( "crypto" "crypto/ecdsa" "crypto/rsa" "encoding/asn1" "errors" "fmt" ) // pickSignatureAlgorithm selects a signature algorithm that is compatible with // the given public key and the list of algorithms from both sides of connection. // The lists of signature algorithms (peerSigAlgs and ourSigAlgs) are ignored // for tlsVersion < VersionTLS12. // // The returned SignatureScheme codepoint is only meaningful for TLS 1.2 and newer // previous TLS versions have a fixed hash function. func pickSignatureAlgorithm(pubkey crypto.PublicKey, peerSigAlgs, ourSigAlgs []SignatureScheme, tlsVersion uint16) (SignatureScheme, uint8, crypto.Hash, error) { if tlsVersion < VersionTLS12 || len(peerSigAlgs) == 0 { // 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 switch pubkey.(type) { case *rsa.PublicKey: if tlsVersion < VersionTLS12 { return 0, signaturePKCS1v15, crypto.MD5SHA1, nil } else { return PKCS1WithSHA1, signaturePKCS1v15, crypto.SHA1, nil } case *ecdsa.PublicKey: return ECDSAWithSHA1, signatureECDSA, crypto.SHA1, nil default: return 0, 0, 0, fmt.Errorf("tls: unsupported public key: %T", pubkey) } } for _, sigAlg := range peerSigAlgs { if !isSupportedSignatureAlgorithm(sigAlg, ourSigAlgs) { continue } hashAlg, err := lookupTLSHash(sigAlg) if err != nil { panic("tls: supported signature algorithm has an unknown hash function") } sigType := signatureFromSignatureScheme(sigAlg) if (sigType == signaturePKCS1v15 || hashAlg == crypto.SHA1) && tlsVersion >= VersionTLS13 { // TLS 1.3 forbids RSASSA-PKCS1-v1_5 and SHA-1 for // handshake messages. continue } switch pubkey.(type) { case *rsa.PublicKey: if sigType == signaturePKCS1v15 || sigType == signatureRSAPSS { return sigAlg, sigType, hashAlg, nil } case *ecdsa.PublicKey: if sigType == signatureECDSA { return sigAlg, sigType, hashAlg, nil } } } return 0, 0, 0, errors.New("tls: peer doesn't support any common signature algorithms") } // verifyHandshakeSignature verifies a signature against pre-hashed handshake // contents. func verifyHandshakeSignature(sigType uint8, pubkey crypto.PublicKey, hashFunc crypto.Hash, digest, sig []byte) error { switch sigType { case signatureECDSA: pubKey, ok := pubkey.(*ecdsa.PublicKey) if !ok { return errors.New("tls: ECDSA signing requires a ECDSA public key") } 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("tls: ECDSA signature contained zero or negative values") } if !ecdsa.Verify(pubKey, digest, ecdsaSig.R, ecdsaSig.S) { return errors.New("tls: ECDSA verification failure") } case signaturePKCS1v15: pubKey, ok := pubkey.(*rsa.PublicKey) if !ok { return errors.New("tls: RSA signing requires a RSA public key") } if err := rsa.VerifyPKCS1v15(pubKey, hashFunc, digest, sig); err != nil { return err } case signatureRSAPSS: pubKey, ok := pubkey.(*rsa.PublicKey) if !ok { return errors.New("tls: RSA signing requires a RSA public key") } signOpts := &rsa.PSSOptions{SaltLength: rsa.PSSSaltLengthEqualsHash} if err := rsa.VerifyPSS(pubKey, hashFunc, digest, sig, signOpts); err != nil { return err } default: return errors.New("tls: unknown signature algorithm") } return nil }