diff --git a/crypto/evp/evp_tests.txt b/crypto/evp/evp_tests.txt index 1c872654..0d6dfdf5 100644 --- a/crypto/evp/evp_tests.txt +++ b/crypto/evp/evp_tests.txt @@ -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 diff --git a/crypto/evp/p_rsa.c b/crypto/evp/p_rsa.c index fcfca4b0..b4598b65 100644 --- a/crypto/evp/p_rsa.c +++ b/crypto/evp/p_rsa.c @@ -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) || diff --git a/crypto/rsa/rsa.c b/crypto/rsa/rsa.c index e6cdce97..843e757d 100644 --- a/crypto/rsa/rsa.c +++ b/crypto/rsa/rsa.c @@ -60,6 +60,7 @@ #include #include +#include #include #include #include @@ -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; diff --git a/include/openssl/rsa.h b/include/openssl/rsa.h index ee1bddea..c5510c85 100644 --- a/include/openssl/rsa.h +++ b/include/openssl/rsa.h @@ -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);