1// Copyright 2021 Google LLC 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// 15//////////////////////////////////////////////////////////////////////////////// 16 17package signature 18 19import ( 20 "crypto" 21 "crypto/rsa" 22 "fmt" 23 "hash" 24 25 "github.com/google/tink/go/subtle" 26 "github.com/google/tink/go/tink" 27) 28 29const ( 30 rsaMinModulusSizeInBits = 2048 31 rsaDefaultPublicExponent = 65537 32) 33 34// RSAValidModulusSizeInBits the size in bits for an RSA key. 35func RSAValidModulusSizeInBits(m int) error { 36 if m < rsaMinModulusSizeInBits { 37 return fmt.Errorf("modulus size too small, must be >= %d", rsaMinModulusSizeInBits) 38 } 39 return nil 40} 41 42// RSAValidPublicExponent validates a public RSA exponent. 43func RSAValidPublicExponent(e int) error { 44 // crypto/rsa uses the following hardcoded public exponent value. 45 if e != rsaDefaultPublicExponent { 46 return fmt.Errorf("invalid public exponent") 47 } 48 return nil 49} 50 51// HashSafeForSignature checks whether a hash function is safe to use with digital signatures 52// that require collision resistance. 53func HashSafeForSignature(hashAlg string) error { 54 switch hashAlg { 55 case "SHA256", "SHA384", "SHA512": 56 return nil 57 default: 58 return fmt.Errorf("hash function not safe for digital signatures: %q", hashAlg) 59 } 60} 61 62const ( 63 testMsg = "Tink and Wycheproof." 64 signVerifyErrMsg = "signing with private key followed by verifying with public key failed, the key may be corrupted" 65) 66 67// Validate_RSA_SSA_PKCS1 validates that the corresponding private key is valid by signing and verifying a message. 68func Validate_RSA_SSA_PKCS1(hashAlg string, privKey *rsa.PrivateKey) error { 69 signer, err := New_RSA_SSA_PKCS1_Signer(hashAlg, privKey) 70 if err != nil { 71 return err 72 } 73 verifier, err := New_RSA_SSA_PKCS1_Verifier(hashAlg, &privKey.PublicKey) 74 if err != nil { 75 return err 76 } 77 if err := validateSignerVerifier(signer, verifier); err != nil { 78 return fmt.Errorf("RSA-SSA-PKCS1: %q", signVerifyErrMsg) 79 } 80 return nil 81} 82 83// Validate_RSA_SSA_PSS validates that the corresponding private key is valid by signing and verifying a message. 84func Validate_RSA_SSA_PSS(hashAlg string, saltLen int, privKey *rsa.PrivateKey) error { 85 signer, err := New_RSA_SSA_PSS_Signer(hashAlg, saltLen, privKey) 86 if err != nil { 87 return err 88 } 89 verifier, err := New_RSA_SSA_PSS_Verifier(hashAlg, saltLen, &privKey.PublicKey) 90 if err != nil { 91 return err 92 } 93 if err := validateSignerVerifier(signer, verifier); err != nil { 94 return fmt.Errorf("RSA-SSA-PSS: %q", signVerifyErrMsg) 95 } 96 return nil 97} 98 99func validateSignerVerifier(signer tink.Signer, verifier tink.Verifier) error { 100 signature, err := signer.Sign([]byte(testMsg)) 101 if err != nil { 102 return err 103 } 104 if err := verifier.Verify([]byte(signature), []byte(testMsg)); err != nil { 105 return err 106 } 107 return nil 108} 109 110func validRSAPublicKey(publicKey *rsa.PublicKey) error { 111 if err := RSAValidModulusSizeInBits(publicKey.N.BitLen()); err != nil { 112 return err 113 } 114 return RSAValidPublicExponent(publicKey.E) 115} 116 117func hashID(hashAlg string) (crypto.Hash, error) { 118 switch hashAlg { 119 case "SHA256": 120 return crypto.SHA256, nil 121 case "SHA384": 122 return crypto.SHA384, nil 123 case "SHA512": 124 return crypto.SHA512, nil 125 default: 126 return 0, fmt.Errorf("invalid hash function: %q", hashAlg) 127 } 128} 129 130func rsaHashFunc(hashAlg string) (func() hash.Hash, crypto.Hash, error) { 131 if err := HashSafeForSignature(hashAlg); err != nil { 132 return nil, 0, err 133 } 134 hashFunc := subtle.GetHashFunc(hashAlg) 135 if hashFunc == nil { 136 return nil, 0, fmt.Errorf("invalid hash function: %q", hashAlg) 137 } 138 hashID, err := hashID(hashAlg) 139 if err != nil { 140 return nil, 0, err 141 } 142 return hashFunc, hashID, nil 143} 144