xref: /aosp_15_r20/external/tink/go/internal/signature/rsa.go (revision e7b1675dde1b92d52ec075b0a92829627f2c52a5)
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