// Copyright 2021 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // //////////////////////////////////////////////////////////////////////////////// package signature import ( "crypto" "crypto/rsa" "fmt" "hash" "github.com/google/tink/go/subtle" "github.com/google/tink/go/tink" ) const ( rsaMinModulusSizeInBits = 2048 rsaDefaultPublicExponent = 65537 ) // RSAValidModulusSizeInBits the size in bits for an RSA key. func RSAValidModulusSizeInBits(m int) error { if m < rsaMinModulusSizeInBits { return fmt.Errorf("modulus size too small, must be >= %d", rsaMinModulusSizeInBits) } return nil } // RSAValidPublicExponent validates a public RSA exponent. func RSAValidPublicExponent(e int) error { // crypto/rsa uses the following hardcoded public exponent value. if e != rsaDefaultPublicExponent { return fmt.Errorf("invalid public exponent") } return nil } // HashSafeForSignature checks whether a hash function is safe to use with digital signatures // that require collision resistance. func HashSafeForSignature(hashAlg string) error { switch hashAlg { case "SHA256", "SHA384", "SHA512": return nil default: return fmt.Errorf("hash function not safe for digital signatures: %q", hashAlg) } } const ( testMsg = "Tink and Wycheproof." signVerifyErrMsg = "signing with private key followed by verifying with public key failed, the key may be corrupted" ) // Validate_RSA_SSA_PKCS1 validates that the corresponding private key is valid by signing and verifying a message. func Validate_RSA_SSA_PKCS1(hashAlg string, privKey *rsa.PrivateKey) error { signer, err := New_RSA_SSA_PKCS1_Signer(hashAlg, privKey) if err != nil { return err } verifier, err := New_RSA_SSA_PKCS1_Verifier(hashAlg, &privKey.PublicKey) if err != nil { return err } if err := validateSignerVerifier(signer, verifier); err != nil { return fmt.Errorf("RSA-SSA-PKCS1: %q", signVerifyErrMsg) } return nil } // Validate_RSA_SSA_PSS validates that the corresponding private key is valid by signing and verifying a message. func Validate_RSA_SSA_PSS(hashAlg string, saltLen int, privKey *rsa.PrivateKey) error { signer, err := New_RSA_SSA_PSS_Signer(hashAlg, saltLen, privKey) if err != nil { return err } verifier, err := New_RSA_SSA_PSS_Verifier(hashAlg, saltLen, &privKey.PublicKey) if err != nil { return err } if err := validateSignerVerifier(signer, verifier); err != nil { return fmt.Errorf("RSA-SSA-PSS: %q", signVerifyErrMsg) } return nil } func validateSignerVerifier(signer tink.Signer, verifier tink.Verifier) error { signature, err := signer.Sign([]byte(testMsg)) if err != nil { return err } if err := verifier.Verify([]byte(signature), []byte(testMsg)); err != nil { return err } return nil } func validRSAPublicKey(publicKey *rsa.PublicKey) error { if err := RSAValidModulusSizeInBits(publicKey.N.BitLen()); err != nil { return err } return RSAValidPublicExponent(publicKey.E) } func hashID(hashAlg string) (crypto.Hash, error) { switch hashAlg { case "SHA256": return crypto.SHA256, nil case "SHA384": return crypto.SHA384, nil case "SHA512": return crypto.SHA512, nil default: return 0, fmt.Errorf("invalid hash function: %q", hashAlg) } } func rsaHashFunc(hashAlg string) (func() hash.Hash, crypto.Hash, error) { if err := HashSafeForSignature(hashAlg); err != nil { return nil, 0, err } hashFunc := subtle.GetHashFunc(hashAlg) if hashFunc == nil { return nil, 0, fmt.Errorf("invalid hash function: %q", hashAlg) } hashID, err := hashID(hashAlg) if err != nil { return nil, 0, err } return hashFunc, hashID, nil }