forked from golang/go
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
crypto/tls: consolidate signatures handling in SKE and CV
ServerKeyExchange and CertificateVerify can share the same logic for picking a signature algorithm (based on the certificate public key and advertised algorithms), selecting a hash algorithm (depending on TLS version) and signature verification. Refactor the code to achieve code reuse, have common error checking (especially for intersecting supported signature algorithms) and to prepare for addition of new signature algorithms. Code should be easier to read since version-dependent logic is concentrated at one place. Change-Id: I978dec3815d28e33c3cfbc85f0c704b1894c25a3
- Loading branch information
1 parent
5e423ed
commit 0cb90a5
Showing
5 changed files
with
139 additions
and
194 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
// 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 tls | ||
|
||
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 the peer and this side. | ||
// | ||
// The returned SignatureScheme codepoint is only meaningful for TLS 1.2, | ||
// 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, signatureRSA, crypto.MD5SHA1, nil | ||
} else { | ||
return PKCS1WithSHA1, signatureRSA, 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) | ||
switch pubkey.(type) { | ||
case *rsa.PublicKey: | ||
if sigType == signatureRSA { | ||
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 signatureRSA: | ||
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 | ||
} | ||
default: | ||
return errors.New("tls: unknown signature algorithm") | ||
} | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.