1// Copyright 2016 Google LLC. All Rights Reserved. 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15package tls 16 17import ( 18 "crypto" 19 "crypto/dsa" 20 "crypto/ecdsa" 21 _ "crypto/md5" // For registration side-effect 22 "crypto/rand" 23 "crypto/rsa" 24 _ "crypto/sha1" // For registration side-effect 25 _ "crypto/sha256" // For registration side-effect 26 _ "crypto/sha512" // For registration side-effect 27 "errors" 28 "fmt" 29 "log" 30 "math/big" 31 32 "github.com/google/certificate-transparency-go/asn1" 33) 34 35type dsaSig struct { 36 R, S *big.Int 37} 38 39func generateHash(algo HashAlgorithm, data []byte) ([]byte, crypto.Hash, error) { 40 var hashType crypto.Hash 41 switch algo { 42 case MD5: 43 hashType = crypto.MD5 44 case SHA1: 45 hashType = crypto.SHA1 46 case SHA224: 47 hashType = crypto.SHA224 48 case SHA256: 49 hashType = crypto.SHA256 50 case SHA384: 51 hashType = crypto.SHA384 52 case SHA512: 53 hashType = crypto.SHA512 54 default: 55 return nil, hashType, fmt.Errorf("unsupported Algorithm.Hash in signature: %v", algo) 56 } 57 58 hasher := hashType.New() 59 if _, err := hasher.Write(data); err != nil { 60 return nil, hashType, fmt.Errorf("failed to write to hasher: %v", err) 61 } 62 return hasher.Sum([]byte{}), hashType, nil 63} 64 65// VerifySignature verifies that the passed in signature over data was created by the given PublicKey. 66func VerifySignature(pubKey crypto.PublicKey, data []byte, sig DigitallySigned) error { 67 hash, hashType, err := generateHash(sig.Algorithm.Hash, data) 68 if err != nil { 69 return err 70 } 71 72 switch sig.Algorithm.Signature { 73 case RSA: 74 rsaKey, ok := pubKey.(*rsa.PublicKey) 75 if !ok { 76 return fmt.Errorf("cannot verify RSA signature with %T key", pubKey) 77 } 78 if err := rsa.VerifyPKCS1v15(rsaKey, hashType, hash, sig.Signature); err != nil { 79 return fmt.Errorf("failed to verify rsa signature: %v", err) 80 } 81 case DSA: 82 dsaKey, ok := pubKey.(*dsa.PublicKey) 83 if !ok { 84 return fmt.Errorf("cannot verify DSA signature with %T key", pubKey) 85 } 86 var dsaSig dsaSig 87 rest, err := asn1.Unmarshal(sig.Signature, &dsaSig) 88 if err != nil { 89 return fmt.Errorf("failed to unmarshal DSA signature: %v", err) 90 } 91 if len(rest) != 0 { 92 log.Printf("Garbage following signature %v", rest) 93 } 94 if dsaSig.R.Sign() <= 0 || dsaSig.S.Sign() <= 0 { 95 return errors.New("DSA signature contained zero or negative values") 96 } 97 if !dsa.Verify(dsaKey, hash, dsaSig.R, dsaSig.S) { 98 return errors.New("failed to verify DSA signature") 99 } 100 case ECDSA: 101 ecdsaKey, ok := pubKey.(*ecdsa.PublicKey) 102 if !ok { 103 return fmt.Errorf("cannot verify ECDSA signature with %T key", pubKey) 104 } 105 var ecdsaSig dsaSig 106 rest, err := asn1.Unmarshal(sig.Signature, &ecdsaSig) 107 if err != nil { 108 return fmt.Errorf("failed to unmarshal ECDSA signature: %v", err) 109 } 110 if len(rest) != 0 { 111 log.Printf("Garbage following signature %v", rest) 112 } 113 if ecdsaSig.R.Sign() <= 0 || ecdsaSig.S.Sign() <= 0 { 114 return errors.New("ECDSA signature contained zero or negative values") 115 } 116 117 if !ecdsa.Verify(ecdsaKey, hash, ecdsaSig.R, ecdsaSig.S) { 118 return errors.New("failed to verify ECDSA signature") 119 } 120 default: 121 return fmt.Errorf("unsupported Algorithm.Signature in signature: %v", sig.Algorithm.Hash) 122 } 123 return nil 124} 125 126// CreateSignature builds a signature over the given data using the specified hash algorithm and private key. 127func CreateSignature(privKey crypto.PrivateKey, hashAlgo HashAlgorithm, data []byte) (DigitallySigned, error) { 128 var sig DigitallySigned 129 sig.Algorithm.Hash = hashAlgo 130 hash, hashType, err := generateHash(sig.Algorithm.Hash, data) 131 if err != nil { 132 return sig, err 133 } 134 135 switch privKey := privKey.(type) { 136 case rsa.PrivateKey: 137 sig.Algorithm.Signature = RSA 138 sig.Signature, err = rsa.SignPKCS1v15(rand.Reader, &privKey, hashType, hash) 139 return sig, err 140 case ecdsa.PrivateKey: 141 sig.Algorithm.Signature = ECDSA 142 var ecdsaSig dsaSig 143 ecdsaSig.R, ecdsaSig.S, err = ecdsa.Sign(rand.Reader, &privKey, hash) 144 if err != nil { 145 return sig, err 146 } 147 sig.Signature, err = asn1.Marshal(ecdsaSig) 148 return sig, err 149 default: 150 return sig, fmt.Errorf("unsupported private key type %T", privKey) 151 } 152} 153