Add crypto/rsa-level RSA-PSS functions.

This allows us to implement RSA-PSS in the FIPS module without pulling
in EVP_PKEY. It also allows people to use RSA-PSS on an RSA*.
Empirically folks seem to use the low-level padding functions a lot,
which is unfortunate.

This allows us to remove a now redundant length check in p_rsa.c.

Change-Id: I5270e01c6999d462d378865db2b858103c335485
Reviewed-on: https://boringssl-review.googlesource.com/15825
Reviewed-by: Adam Langley <agl@google.com>
This commit is contained in:
David Benjamin 2017-05-02 14:34:09 -04:00 committed by Adam Langley
parent 05821b0ee3
commit 79d18bc4dd
4 changed files with 119 additions and 44 deletions

View File

@ -136,7 +136,7 @@ Output = c09d402423cbf233d26cae21f954547bc43fe80fd41360a0336cfdbe9aedad05bef6fd2
Sign = RSA-2048
Digest = SHA1
Input = "0123456789ABCDEF12345"
Error = INVALID_DIGEST_LENGTH
Error = INVALID_MESSAGE_LENGTH
Verify = RSA-2048
Digest = SHA1
@ -148,7 +148,7 @@ Error = INVALID_MESSAGE_LENGTH
Sign = RSA-2048
Digest = SHA1
Input = "0123456789ABCDEF123"
Error = INVALID_DIGEST_LENGTH
Error = INVALID_MESSAGE_LENGTH
Verify = RSA-2048
Digest = SHA1
@ -254,7 +254,7 @@ PSSSaltLength = 0
Digest = SHA256
Input = "0123456789ABCDEF0123456789ABCDE"
Output = 4de433d5844043ef08d354da03cb29068780d52706d7d1e4d50efb7d58c9d547d83a747ddd0635a96b28f854e50145518482cb49e963054621b53c60c498d07c16e9c2789c893cf38d4d86900de71bde463bd2761d1271e358c7480a1ac0bab930ddf39602ad1bc165b5d7436b516b7a7858e8eb7ab1c420eeb482f4d207f0e462b1724959320a084e13848d11d10fb593e66bf680bf6d3f345fc3e9c3de60abbac37e1c6ec80a268c8d9fc49626c679097aa690bc1aa662b95eb8db70390861aa0898229f9349b4b5fdd030d4928c47084708a933144be23bd3c6e661b85b2c0ef9ed36d498d5b7320e8194d363d4ad478c059bae804181965e0b81b663158a
Error = INVALID_DIGEST_LENGTH
Error = INVALID_MESSAGE_LENGTH
# Digest too long
Verify = RSA-2048-SPKI
@ -263,7 +263,7 @@ PSSSaltLength = 0
Digest = SHA256
Input = "0123456789ABCDEF0123456789ABCDEF0"
Output = 4de433d5844043ef08d354da03cb29068780d52706d7d1e4d50efb7d58c9d547d83a747ddd0635a96b28f854e50145518482cb49e963054621b53c60c498d07c16e9c2789c893cf38d4d86900de71bde463bd2761d1271e358c7480a1ac0bab930ddf39602ad1bc165b5d7436b516b7a7858e8eb7ab1c420eeb482f4d207f0e462b1724959320a084e13848d11d10fb593e66bf680bf6d3f345fc3e9c3de60abbac37e1c6ec80a268c8d9fc49626c679097aa690bc1aa662b95eb8db70390861aa0898229f9349b4b5fdd030d4928c47084708a933144be23bd3c6e661b85b2c0ef9ed36d498d5b7320e8194d363d4ad478c059bae804181965e0b81b663158a
Error = INVALID_DIGEST_LENGTH
Error = INVALID_MESSAGE_LENGTH
# Wrong salt length
Verify = RSA-2048

View File

@ -180,18 +180,7 @@ static int pkey_rsa_sign(EVP_PKEY_CTX *ctx, uint8_t *sig, size_t *siglen,
}
if (rctx->md) {
unsigned int out_len;
if (tbslen != EVP_MD_size(rctx->md)) {
OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_DIGEST_LENGTH);
return 0;
}
if (EVP_MD_type(rctx->md) == NID_mdc2) {
OPENSSL_PUT_ERROR(EVP, EVP_R_NO_MDC2_SUPPORT);
return 0;
}
unsigned out_len;
switch (rctx->pad_mode) {
case RSA_PKCS1_PADDING:
if (!RSA_sign(EVP_MD_type(rctx->md), tbs, tbslen, sig, &out_len, rsa)) {
@ -201,14 +190,8 @@ static int pkey_rsa_sign(EVP_PKEY_CTX *ctx, uint8_t *sig, size_t *siglen,
return 1;
case RSA_PKCS1_PSS_PADDING:
if (!setup_tbuf(rctx, ctx) ||
!RSA_padding_add_PKCS1_PSS_mgf1(rsa, rctx->tbuf, tbs, rctx->md,
rctx->mgf1md, rctx->saltlen) ||
!RSA_sign_raw(rsa, siglen, sig, *siglen, rctx->tbuf, key_len,
RSA_NO_PADDING)) {
return 0;
}
return 1;
return RSA_sign_pss_mgf1(rsa, siglen, sig, *siglen, tbs, tbslen,
rctx->md, rctx->mgf1md, rctx->saltlen);
default:
return 0;
@ -223,8 +206,6 @@ static int pkey_rsa_verify(EVP_PKEY_CTX *ctx, const uint8_t *sig,
size_t tbslen) {
RSA_PKEY_CTX *rctx = ctx->data;
RSA *rsa = ctx->pkey->pkey.rsa;
size_t rslen;
const size_t key_len = EVP_PKEY_size(ctx->pkey);
if (rctx->md) {
switch (rctx->pad_mode) {
@ -232,25 +213,16 @@ static int pkey_rsa_verify(EVP_PKEY_CTX *ctx, const uint8_t *sig,
return RSA_verify(EVP_MD_type(rctx->md), tbs, tbslen, sig, siglen, rsa);
case RSA_PKCS1_PSS_PADDING:
if (tbslen != EVP_MD_size(rctx->md)) {
OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_DIGEST_LENGTH);
return 0;
}
if (!setup_tbuf(rctx, ctx) ||
!RSA_verify_raw(rsa, &rslen, rctx->tbuf, key_len, sig, siglen,
RSA_NO_PADDING) ||
!RSA_verify_PKCS1_PSS_mgf1(rsa, tbs, rctx->md, rctx->mgf1md,
rctx->tbuf, rctx->saltlen)) {
return 0;
}
return 1;
return RSA_verify_pss_mgf1(rsa, tbs, tbslen, rctx->md, rctx->mgf1md,
rctx->saltlen, sig, siglen);
default:
return 0;
}
}
size_t rslen;
const size_t key_len = EVP_PKEY_size(ctx->pkey);
if (!setup_tbuf(rctx, ctx) ||
!RSA_verify_raw(rsa, &rslen, rctx->tbuf, key_len, sig, siglen,
rctx->pad_mode) ||

View File

@ -60,6 +60,7 @@
#include <string.h>
#include <openssl/bn.h>
#include <openssl/digest.h>
#include <openssl/engine.h>
#include <openssl/err.h>
#include <openssl/ex_data.h>
@ -473,6 +474,29 @@ err:
return ret;
}
int RSA_sign_pss_mgf1(RSA *rsa, size_t *out_len, uint8_t *out, size_t max_out,
const uint8_t *in, size_t in_len, const EVP_MD *md,
const EVP_MD *mgf1_md, int salt_len) {
if (in_len != EVP_MD_size(md)) {
OPENSSL_PUT_ERROR(RSA, RSA_R_INVALID_MESSAGE_LENGTH);
return 0;
}
size_t padded_len = RSA_size(rsa);
uint8_t *padded = OPENSSL_malloc(padded_len);
if (padded == NULL) {
OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE);
return 0;
}
int ret =
RSA_padding_add_PKCS1_PSS_mgf1(rsa, padded, in, md, mgf1_md, salt_len) &&
RSA_sign_raw(rsa, out_len, out, max_out, padded, padded_len,
RSA_NO_PADDING);
OPENSSL_free(padded);
return ret;
}
int RSA_verify(int hash_nid, const uint8_t *msg, size_t msg_len,
const uint8_t *sig, size_t sig_len, RSA *rsa) {
if (rsa->n == NULL || rsa->e == NULL) {
@ -525,6 +549,38 @@ out:
return ret;
}
int RSA_verify_pss_mgf1(RSA *rsa, const uint8_t *msg, size_t msg_len,
const EVP_MD *md, const EVP_MD *mgf1_md, int salt_len,
const uint8_t *sig, size_t sig_len) {
if (msg_len != EVP_MD_size(md)) {
OPENSSL_PUT_ERROR(RSA, RSA_R_INVALID_MESSAGE_LENGTH);
return 0;
}
size_t em_len = RSA_size(rsa);
uint8_t *em = OPENSSL_malloc(em_len);
if (em == NULL) {
OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE);
return 0;
}
int ret = 0;
if (!RSA_verify_raw(rsa, &em_len, em, em_len, sig, sig_len, RSA_NO_PADDING)) {
goto err;
}
if (em_len != RSA_size(rsa)) {
OPENSSL_PUT_ERROR(RSA, ERR_R_INTERNAL_ERROR);
goto err;
}
ret = RSA_verify_PKCS1_PSS_mgf1(rsa, msg, md, mgf1_md, em, salt_len);
err:
OPENSSL_free(em);
return ret;
}
static void bn_free_and_null(BIGNUM **bn) {
BN_free(*bn);
*bn = NULL;

View File

@ -206,6 +206,24 @@ OPENSSL_EXPORT int RSA_sign(int hash_nid, const uint8_t *in,
unsigned int in_len, uint8_t *out,
unsigned int *out_len, RSA *rsa);
/* RSA_sign_pss_mgf1 signs |in_len| bytes from |in| with the public key from
* |rsa| using RSASSA-PSS with MGF1 as the mask generation function. It writes,
* at most, |max_out| bytes of signature data to |out|. The |max_out| argument
* must be, at least, |RSA_size| in order to ensure success. It returns 1 on
* success or zero on error.
*
* The |md| and |mgf1_md| arguments identify the hash used to calculate |msg|
* and the MGF1 hash, respectively. If |mgf1_md| is NULL, |md| is
* used.
*
* |salt_len| specifies the expected salt length in bytes. If |salt_len| is -1,
* then the salt length is the same as the hash length. If -2, then the salt
* length is maximal given the size of |rsa|. If unsure, use -1. */
OPENSSL_EXPORT int RSA_sign_pss_mgf1(RSA *rsa, size_t *out_len, uint8_t *out,
size_t max_out, const uint8_t *in,
size_t in_len, const EVP_MD *md,
const EVP_MD *mgf1_md, int salt_len);
/* RSA_sign_raw signs |in_len| bytes from |in| with the public key from |rsa|
* and writes, at most, |max_out| bytes of signature data to |out|. The
* |max_out| argument must be, at least, |RSA_size| in order to ensure success.
@ -222,7 +240,7 @@ OPENSSL_EXPORT int RSA_sign_raw(RSA *rsa, size_t *out_len, uint8_t *out,
/* RSA_verify verifies that |sig_len| bytes from |sig| are a valid,
* RSASSA-PKCS1-v1_5 signature of |msg_len| bytes at |msg| by |rsa|.
*
* The |hash_nid| argument identifies the hash function used to calculate |in|
* The |hash_nid| argument identifies the hash function used to calculate |msg|
* and is embedded in the resulting signature in order to prevent hash
* confusion attacks. For example, it might be |NID_sha256|.
*
@ -233,6 +251,23 @@ OPENSSL_EXPORT int RSA_sign_raw(RSA *rsa, size_t *out_len, uint8_t *out,
OPENSSL_EXPORT int RSA_verify(int hash_nid, const uint8_t *msg, size_t msg_len,
const uint8_t *sig, size_t sig_len, RSA *rsa);
/* RSA_verify_pss_mgf1 verifies that |sig_len| bytes from |sig| are a valid,
* RSASSA-PSS signature of |msg_len| bytes at |msg| by |rsa|. It returns one if
* the signature is valid and zero otherwise. MGF1 is used as the mask
* generation function.
*
* The |md| and |mgf1_md| arguments identify the hash used to calculate |msg|
* and the MGF1 hash, respectively. If |mgf1_md| is NULL, |md| is
* used. |salt_len| specifies the expected salt length in bytes.
*
* If |salt_len| is -1, then the salt length is the same as the hash length. If
* -2, then the salt length is recovered and all values accepted. If unsure, use
* -1. */
OPENSSL_EXPORT int RSA_verify_pss_mgf1(RSA *rsa, const uint8_t *msg,
size_t msg_len, const EVP_MD *md,
const EVP_MD *mgf1_md, int salt_len,
const uint8_t *sig, size_t sig_len);
/* RSA_verify_raw verifies |in_len| bytes of signature from |in| using the
* public key from |rsa| and writes, at most, |max_out| bytes of plaintext to
* |out|. The |max_out| argument must be, at least, |RSA_size| in order to
@ -318,7 +353,10 @@ OPENSSL_EXPORT int RSA_recover_crt_params(RSA *rsa);
*
* If unsure, use -1.
*
* It returns one on success or zero on error. */
* It returns one on success or zero on error.
*
* This function implements only the low-level padding logic. Use
* |RSA_verify_pss_mgf1| instead. */
OPENSSL_EXPORT int RSA_verify_PKCS1_PSS_mgf1(RSA *rsa, const uint8_t *mHash,
const EVP_MD *Hash,
const EVP_MD *mgf1Hash,
@ -332,7 +370,10 @@ OPENSSL_EXPORT int RSA_verify_PKCS1_PSS_mgf1(RSA *rsa, const uint8_t *mHash,
* the salt length is the same as the hash length. If -2, then the salt length
* is maximal given the space in |EM|.
*
* It returns one on success or zero on error. */
* It returns one on success or zero on error.
*
* This function implements only the low-level padding logic. Use
* |RSA_sign_pss_mgf1| instead. */
OPENSSL_EXPORT int RSA_padding_add_PKCS1_PSS_mgf1(RSA *rsa, uint8_t *EM,
const uint8_t *mHash,
const EVP_MD *Hash,
@ -497,13 +538,19 @@ OPENSSL_EXPORT RSA *d2i_RSAPrivateKey(RSA **out, const uint8_t **inp, long len);
OPENSSL_EXPORT int i2d_RSAPrivateKey(const RSA *in, uint8_t **outp);
/* RSA_padding_add_PKCS1_PSS acts like |RSA_padding_add_PKCS1_PSS_mgf1| but the
* |mgf1Hash| parameter of the latter is implicitly set to |Hash|. */
* |mgf1Hash| parameter of the latter is implicitly set to |Hash|.
*
* This function implements only the low-level padding logic. Use
* |RSA_sign_pss_mgf1| instead. */
OPENSSL_EXPORT int RSA_padding_add_PKCS1_PSS(RSA *rsa, uint8_t *EM,
const uint8_t *mHash,
const EVP_MD *Hash, int sLen);
/* RSA_verify_PKCS1_PSS acts like |RSA_verify_PKCS1_PSS_mgf1| but the
* |mgf1Hash| parameter of the latter is implicitly set to |Hash|. */
* |mgf1Hash| parameter of the latter is implicitly set to |Hash|.
*
* This function implements only the low-level padding logic. Use
* |RSA_verify_pss_mgf1| instead. */
OPENSSL_EXPORT int RSA_verify_PKCS1_PSS(RSA *rsa, const uint8_t *mHash,
const EVP_MD *Hash, const uint8_t *EM,
int sLen);