]> Cypherpunks.ru repositories - gostls13.git/blob - src/crypto/tls/auth.go
crypto/tls: consolidate signatures handling in SKE and CV
[gostls13.git] / src / crypto / tls / auth.go
1 // Copyright 2017 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 package tls
6
7 import (
8         "crypto"
9         "crypto/ecdsa"
10         "crypto/rsa"
11         "encoding/asn1"
12         "errors"
13         "fmt"
14 )
15
16 // pickSignatureAlgorithm selects a signature algorithm that is compatible with
17 // the given public key and the list of algorithms from the peer and this side.
18 // The lists of signature algorithms (peerSigAlgs and ourSigAlgs) are ignored
19 // for tlsVersion < VersionTLS12.
20 //
21 // The returned SignatureScheme codepoint is only meaningful for TLS 1.2,
22 // previous TLS versions have a fixed hash function.
23 func pickSignatureAlgorithm(pubkey crypto.PublicKey, peerSigAlgs, ourSigAlgs []SignatureScheme, tlsVersion uint16) (sigAlg SignatureScheme, sigType uint8, hashFunc crypto.Hash, err error) {
24         if tlsVersion < VersionTLS12 || len(peerSigAlgs) == 0 {
25                 // For TLS 1.1 and before, the signature algorithm could not be
26                 // negotiated and the hash is fixed based on the signature type.
27                 // For TLS 1.2, if the client didn't send signature_algorithms
28                 // extension then we can assume that it supports SHA1. See
29                 // https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1
30                 switch pubkey.(type) {
31                 case *rsa.PublicKey:
32                         if tlsVersion < VersionTLS12 {
33                                 return 0, signatureRSA, crypto.MD5SHA1, nil
34                         } else {
35                                 return PKCS1WithSHA1, signatureRSA, crypto.SHA1, nil
36                         }
37                 case *ecdsa.PublicKey:
38                         return ECDSAWithSHA1, signatureECDSA, crypto.SHA1, nil
39                 default:
40                         return 0, 0, 0, fmt.Errorf("tls: unsupported public key: %T", pubkey)
41                 }
42         }
43         for _, sigAlg := range peerSigAlgs {
44                 if !isSupportedSignatureAlgorithm(sigAlg, ourSigAlgs) {
45                         continue
46                 }
47                 hashAlg, err := lookupTLSHash(sigAlg)
48                 if err != nil {
49                         panic("tls: supported signature algorithm has an unknown hash function")
50                 }
51                 sigType := signatureFromSignatureScheme(sigAlg)
52                 switch pubkey.(type) {
53                 case *rsa.PublicKey:
54                         if sigType == signatureRSA {
55                                 return sigAlg, sigType, hashAlg, nil
56                         }
57                 case *ecdsa.PublicKey:
58                         if sigType == signatureECDSA {
59                                 return sigAlg, sigType, hashAlg, nil
60                         }
61                 default:
62                         return 0, 0, 0, fmt.Errorf("tls: unsupported public key: %T", pubkey)
63                 }
64         }
65         return 0, 0, 0, errors.New("tls: peer doesn't support any common signature algorithms")
66 }
67
68 // verifyHandshakeSignature verifies a signature against pre-hashed handshake
69 // contents.
70 func verifyHandshakeSignature(sigType uint8, pubkey crypto.PublicKey, hashFunc crypto.Hash, digest, sig []byte) error {
71         switch sigType {
72         case signatureECDSA:
73                 pubKey, ok := pubkey.(*ecdsa.PublicKey)
74                 if !ok {
75                         return errors.New("tls: ECDSA signing requires a ECDSA public key")
76                 }
77                 ecdsaSig := new(ecdsaSignature)
78                 if _, err := asn1.Unmarshal(sig, ecdsaSig); err != nil {
79                         return err
80                 }
81                 if ecdsaSig.R.Sign() <= 0 || ecdsaSig.S.Sign() <= 0 {
82                         return errors.New("tls: ECDSA signature contained zero or negative values")
83                 }
84                 if !ecdsa.Verify(pubKey, digest, ecdsaSig.R, ecdsaSig.S) {
85                         return errors.New("tls: ECDSA verification failure")
86                 }
87         case signatureRSA:
88                 pubKey, ok := pubkey.(*rsa.PublicKey)
89                 if !ok {
90                         return errors.New("tls: RSA signing requires a RSA public key")
91                 }
92                 if err := rsa.VerifyPKCS1v15(pubKey, hashFunc, digest, sig); err != nil {
93                         return err
94                 }
95         default:
96                 return errors.New("tls: unknown signature algorithm")
97         }
98         return nil
99 }