blob: d90b640201cd57db304dcb18c5489d3e3ecb3ca6 [file] [log] [blame] [edit]
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package rsa
// This file implements signing and verification using PKCS #1 v1.5 signatures.
import (
"bytes"
"crypto/internal/fips140"
"errors"
)
// These are ASN1 DER structures:
//
// DigestInfo ::= SEQUENCE {
// digestAlgorithm AlgorithmIdentifier,
// digest OCTET STRING
// }
//
// For performance, we don't use the generic ASN1 encoder. Rather, we
// precompute a prefix of the digest value that makes a valid ASN1 DER string
// with the correct contents.
var hashPrefixes = map[string][]byte{
"MD5": {0x30, 0x20, 0x30, 0x0c, 0x06, 0x08, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x05, 0x05, 0x00, 0x04, 0x10},
"SHA-1": {0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14},
"SHA-224": {0x30, 0x2d, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04, 0x05, 0x00, 0x04, 0x1c},
"SHA-256": {0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20},
"SHA-384": {0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05, 0x00, 0x04, 0x30},
"SHA-512": {0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x00, 0x04, 0x40},
"SHA-512/224": {0x30, 0x2d, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x05, 0x05, 0x00, 0x04, 0x1C},
"SHA-512/256": {0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x06, 0x05, 0x00, 0x04, 0x20},
"SHA3-224": {0x30, 0x2d, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x07, 0x05, 0x00, 0x04, 0x1C},
"SHA3-256": {0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x08, 0x05, 0x00, 0x04, 0x20},
"SHA3-384": {0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x09, 0x05, 0x00, 0x04, 0x30},
"SHA3-512": {0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x0a, 0x05, 0x00, 0x04, 0x40},
"MD5+SHA1": {}, // A special TLS case which doesn't use an ASN1 prefix.
"RIPEMD-160": {0x30, 0x20, 0x30, 0x08, 0x06, 0x06, 0x28, 0xcf, 0x06, 0x03, 0x00, 0x31, 0x04, 0x14},
}
// SignPKCS1v15 calculates an RSASSA-PKCS1-v1.5 signature.
//
// hash is the name of the hash function as returned by [crypto.Hash.String]
// or the empty string to indicate that the message is signed directly.
func SignPKCS1v15(priv *PrivateKey, hash string, hashed []byte) ([]byte, error) {
fipsSelfTest()
fips140.RecordApproved()
checkApprovedHashName(hash)
return signPKCS1v15(priv, hash, hashed)
}
func signPKCS1v15(priv *PrivateKey, hash string, hashed []byte) ([]byte, error) {
em, err := pkcs1v15ConstructEM(&priv.pub, hash, hashed)
if err != nil {
return nil, err
}
return decrypt(priv, em, withCheck)
}
func pkcs1v15ConstructEM(pub *PublicKey, hash string, hashed []byte) ([]byte, error) {
// Special case: "" is used to indicate that the data is signed directly.
var prefix []byte
if hash != "" {
var ok bool
prefix, ok = hashPrefixes[hash]
if !ok {
return nil, errors.New("crypto/rsa: unsupported hash function")
}
}
// EM = 0x00 || 0x01 || PS || 0x00 || T
k := pub.Size()
if k < len(prefix)+len(hashed)+2+8+1 {
return nil, ErrMessageTooLong
}
em := make([]byte, k)
em[1] = 1
for i := 2; i < k-len(prefix)-len(hashed)-1; i++ {
em[i] = 0xff
}
copy(em[k-len(prefix)-len(hashed):], prefix)
copy(em[k-len(hashed):], hashed)
return em, nil
}
// VerifyPKCS1v15 verifies an RSASSA-PKCS1-v1.5 signature.
//
// hash is the name of the hash function as returned by [crypto.Hash.String]
// or the empty string to indicate that the message is signed directly.
func VerifyPKCS1v15(pub *PublicKey, hash string, hashed []byte, sig []byte) error {
fipsSelfTest()
fips140.RecordApproved()
checkApprovedHashName(hash)
return verifyPKCS1v15(pub, hash, hashed, sig)
}
func verifyPKCS1v15(pub *PublicKey, hash string, hashed []byte, sig []byte) error {
if fipsApproved, err := checkPublicKey(pub); err != nil {
return err
} else if !fipsApproved {
fips140.RecordNonApproved()
}
// RFC 8017 Section 8.2.2: If the length of the signature S is not k
// octets (where k is the length in octets of the RSA modulus n), output
// "invalid signature" and stop.
if pub.Size() != len(sig) {
return ErrVerification
}
em, err := encrypt(pub, sig)
if err != nil {
return ErrVerification
}
expected, err := pkcs1v15ConstructEM(pub, hash, hashed)
if err != nil {
return ErrVerification
}
if !bytes.Equal(em, expected) {
return ErrVerification
}
return nil
}
func checkApprovedHashName(hash string) {
switch hash {
case "SHA-224", "SHA-256", "SHA-384", "SHA-512", "SHA-512/224", "SHA-512/256",
"SHA3-224", "SHA3-256", "SHA3-384", "SHA3-512":
default:
fips140.RecordNonApproved()
}
}