diff options
author | Joel Sing <jsing@cvs.openbsd.org> | 2019-10-31 13:56:30 +0000 |
---|---|---|
committer | Joel Sing <jsing@cvs.openbsd.org> | 2019-10-31 13:56:30 +0000 |
commit | 03077a655aaf94a688602d07365bfb0016d41dd2 (patch) | |
tree | fc7ae99bb208e4acf1900b288db097859e806749 /lib/libcrypto/rsa | |
parent | bfc6803e10a381ffdf7313315a96f008ade380f5 (diff) |
Add support for RSA-PSS.
From OpenSSL 1.1.1d.
ok inoguchi@
Diffstat (limited to 'lib/libcrypto/rsa')
-rw-r--r-- | lib/libcrypto/rsa/rsa.h | 64 | ||||
-rw-r--r-- | lib/libcrypto/rsa/rsa_ameth.c | 120 | ||||
-rw-r--r-- | lib/libcrypto/rsa/rsa_err.c | 7 | ||||
-rw-r--r-- | lib/libcrypto/rsa/rsa_locl.h | 7 | ||||
-rw-r--r-- | lib/libcrypto/rsa/rsa_pmeth.c | 237 |
5 files changed, 370 insertions, 65 deletions
diff --git a/lib/libcrypto/rsa/rsa.h b/lib/libcrypto/rsa/rsa.h index d3f9bee3a59..48d6d64bd17 100644 --- a/lib/libcrypto/rsa/rsa.h +++ b/lib/libcrypto/rsa/rsa.h @@ -1,4 +1,4 @@ -/* $OpenBSD: rsa.h,v 1.44 2019/10/29 08:00:18 jsing Exp $ */ +/* $OpenBSD: rsa.h,v 1.45 2019/10/31 13:56:29 jsing Exp $ */ /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) * All rights reserved. * @@ -201,46 +201,55 @@ struct rsa_st { */ #define RSA_FLAG_NO_BLINDING 0x0080 +/* Salt length matches digest */ +#define RSA_PSS_SALTLEN_DIGEST -1 +/* Verify only: auto detect salt length */ +#define RSA_PSS_SALTLEN_AUTO -2 +/* Set salt length to maximum possible */ +#define RSA_PSS_SALTLEN_MAX -3 + #define EVP_PKEY_CTX_set_rsa_padding(ctx, pad) \ - EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, -1, EVP_PKEY_CTRL_RSA_PADDING, \ - pad, NULL) + RSA_pkey_ctx_ctrl(ctx, -1, EVP_PKEY_CTRL_RSA_PADDING, pad, NULL) #define EVP_PKEY_CTX_get_rsa_padding(ctx, ppad) \ - EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, -1, \ - EVP_PKEY_CTRL_GET_RSA_PADDING, 0, ppad) + RSA_pkey_ctx_ctrl(ctx, -1, EVP_PKEY_CTRL_GET_RSA_PADDING, 0, ppad) #define EVP_PKEY_CTX_set_rsa_pss_saltlen(ctx, len) \ - EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, \ - (EVP_PKEY_OP_SIGN|EVP_PKEY_OP_VERIFY), \ - EVP_PKEY_CTRL_RSA_PSS_SALTLEN, \ - len, NULL) + RSA_pkey_ctx_ctrl(ctx, (EVP_PKEY_OP_SIGN|EVP_PKEY_OP_VERIFY), \ + EVP_PKEY_CTRL_RSA_PSS_SALTLEN, len, NULL) + +#define EVP_PKEY_CTX_set_rsa_pss_keygen_saltlen(ctx, len) \ + EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA_PSS, EVP_PKEY_OP_KEYGEN, \ + EVP_PKEY_CTRL_RSA_PSS_SALTLEN, len, NULL) #define EVP_PKEY_CTX_get_rsa_pss_saltlen(ctx, plen) \ - EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, \ - (EVP_PKEY_OP_SIGN|EVP_PKEY_OP_VERIFY), \ - EVP_PKEY_CTRL_GET_RSA_PSS_SALTLEN, \ - 0, plen) + RSA_pkey_ctx_ctrl(ctx, (EVP_PKEY_OP_SIGN|EVP_PKEY_OP_VERIFY), \ + EVP_PKEY_CTRL_GET_RSA_PSS_SALTLEN, 0, plen) #define EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, bits) \ - EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, EVP_PKEY_OP_KEYGEN, \ - EVP_PKEY_CTRL_RSA_KEYGEN_BITS, bits, NULL) + RSA_pkey_ctx_ctrl(ctx, EVP_PKEY_OP_KEYGEN, \ + EVP_PKEY_CTRL_RSA_KEYGEN_BITS, bits, NULL) #define EVP_PKEY_CTX_set_rsa_keygen_pubexp(ctx, pubexp) \ - EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, EVP_PKEY_OP_KEYGEN, \ - EVP_PKEY_CTRL_RSA_KEYGEN_PUBEXP, 0, pubexp) + RSA_pkey_ctx_ctrl(ctx, EVP_PKEY_OP_KEYGEN, \ + EVP_PKEY_CTRL_RSA_KEYGEN_PUBEXP, 0, pubexp) -#define EVP_PKEY_CTX_set_rsa_mgf1_md(ctx, md) \ - EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, EVP_PKEY_OP_TYPE_SIG, \ - EVP_PKEY_CTRL_RSA_MGF1_MD, 0, (void *)md) +#define EVP_PKEY_CTX_set_rsa_mgf1_md(ctx, md) \ + RSA_pkey_ctx_ctrl(ctx, EVP_PKEY_OP_TYPE_SIG | EVP_PKEY_OP_TYPE_CRYPT, \ + EVP_PKEY_CTRL_RSA_MGF1_MD, 0, (void *)(md)) -#define EVP_PKEY_CTX_get_rsa_mgf1_md(ctx, pmd) \ - EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, EVP_PKEY_OP_TYPE_SIG, \ - EVP_PKEY_CTRL_GET_RSA_MGF1_MD, 0, (void *)pmd) +#define EVP_PKEY_CTX_set_rsa_pss_keygen_mgf1_md(ctx, md) \ + EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA_PSS, EVP_PKEY_OP_KEYGEN, \ + EVP_PKEY_CTRL_RSA_MGF1_MD, 0, (void *)(md)) #define EVP_PKEY_CTX_set_rsa_oaep_md(ctx, md) \ EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, EVP_PKEY_OP_TYPE_CRYPT, \ EVP_PKEY_CTRL_RSA_OAEP_MD, 0, (void *)(md)) +#define EVP_PKEY_CTX_get_rsa_mgf1_md(ctx, pmd) \ + RSA_pkey_ctx_ctrl(ctx, EVP_PKEY_OP_TYPE_SIG | EVP_PKEY_OP_TYPE_CRYPT, \ + EVP_PKEY_CTRL_GET_RSA_MGF1_MD, 0, (void *)(pmd)) + #define EVP_PKEY_CTX_get_rsa_oaep_md(ctx, pmd) \ EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, EVP_PKEY_OP_TYPE_CRYPT, \ EVP_PKEY_CTRL_GET_RSA_OAEP_MD, 0, (void *)(pmd)) @@ -253,6 +262,10 @@ struct rsa_st { EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, EVP_PKEY_OP_TYPE_CRYPT, \ EVP_PKEY_CTRL_GET_RSA_OAEP_LABEL, 0, (void *)(l)) +#define EVP_PKEY_CTX_set_rsa_pss_keygen_md(ctx, md) \ + EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA_PSS, \ + EVP_PKEY_OP_KEYGEN, EVP_PKEY_CTRL_MD, 0, (void *)(md)) + #define EVP_PKEY_CTRL_RSA_PADDING (EVP_PKEY_ALG_CTRL + 1) #define EVP_PKEY_CTRL_RSA_PSS_SALTLEN (EVP_PKEY_ALG_CTRL + 2) @@ -602,12 +615,14 @@ void ERR_load_RSA_strings(void); #define RSA_R_DATA_TOO_LARGE_FOR_MODULUS 132 #define RSA_R_DATA_TOO_SMALL 111 #define RSA_R_DATA_TOO_SMALL_FOR_KEY_SIZE 122 +#define RSA_R_DIGEST_NOT_ALLOWED 145 #define RSA_R_DIGEST_TOO_BIG_FOR_RSA_KEY 112 #define RSA_R_DMP1_NOT_CONGRUENT_TO_D 124 #define RSA_R_DMQ1_NOT_CONGRUENT_TO_D 125 #define RSA_R_D_E_NOT_CONGRUENT_TO_1 123 #define RSA_R_FIRST_OCTET_INVALID 133 #define RSA_R_ILLEGAL_OR_UNSUPPORTED_PADDING_MODE 144 +#define RSA_R_INVALID_DIGEST 157 #define RSA_R_INVALID_DIGEST_LENGTH 143 #define RSA_R_INVALID_HEADER 137 #define RSA_R_INVALID_KEYBITS 145 @@ -624,6 +639,7 @@ void ERR_load_RSA_strings(void); #define RSA_R_KEY_SIZE_TOO_SMALL 120 #define RSA_R_LAST_OCTET_INVALID 134 #define RSA_R_MODULUS_TOO_LARGE 105 +#define RSA_R_MGF1_DIGEST_NOT_ALLOWED 152 #define RSA_R_NON_FIPS_RSA_METHOD 157 #define RSA_R_NO_PUBLIC_EXPONENT 140 #define RSA_R_NULL_BEFORE_BLOCK_MISSING 113 @@ -632,6 +648,7 @@ void ERR_load_RSA_strings(void); #define RSA_R_OPERATION_NOT_ALLOWED_IN_FIPS_MODE 158 #define RSA_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE 148 #define RSA_R_PADDING_CHECK_FAILED 114 +#define RSA_R_PSS_SALTLEN_TOO_SMALL 164 #define RSA_R_P_NOT_PRIME 128 #define RSA_R_Q_NOT_PRIME 129 #define RSA_R_RSA_OPERATIONS_NOT_SUPPORTED 130 @@ -640,6 +657,7 @@ void ERR_load_RSA_strings(void); #define RSA_R_SSLV3_ROLLBACK_ATTACK 115 #define RSA_R_THE_ASN1_OBJECT_IDENTIFIER_IS_NOT_KNOWN_FOR_THIS_MD 116 #define RSA_R_UNKNOWN_ALGORITHM_TYPE 117 +#define RSA_R_UNKNOWN_DIGEST 166 #define RSA_R_UNKNOWN_MASK_DIGEST 151 #define RSA_R_UNKNOWN_PADDING_TYPE 118 #define RSA_R_UNKNOWN_PSS_DIGEST 152 diff --git a/lib/libcrypto/rsa/rsa_ameth.c b/lib/libcrypto/rsa/rsa_ameth.c index ce3e9b3509f..f71cee8ec1f 100644 --- a/lib/libcrypto/rsa/rsa_ameth.c +++ b/lib/libcrypto/rsa/rsa_ameth.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rsa_ameth.c,v 1.19 2018/08/24 20:22:15 tb Exp $ */ +/* $OpenBSD: rsa_ameth.c,v 1.20 2019/10/31 13:56:29 jsing Exp $ */ /* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL * project 2006. */ @@ -433,6 +433,124 @@ rsa_pkey_ctrl(EVP_PKEY *pkey, int op, long arg1, void *arg2) return 1; } +/* Allocate and set algorithm ID from EVP_MD, defaults to SHA1. */ +static int +rsa_md_to_algor(X509_ALGOR **palg, const EVP_MD *md) +{ + if (md == NULL || EVP_MD_type(md) == NID_sha1) + return 1; + *palg = X509_ALGOR_new(); + if (*palg == NULL) + return 0; + X509_ALGOR_set_md(*palg, md); + return 1; +} + +/* Allocate and set MGF1 algorithm ID from EVP_MD. */ +static int +rsa_md_to_mgf1(X509_ALGOR **palg, const EVP_MD *mgf1md) +{ + X509_ALGOR *algtmp = NULL; + ASN1_STRING *stmp = NULL; + + *palg = NULL; + if (mgf1md == NULL || EVP_MD_type(mgf1md) == NID_sha1) + return 1; + /* need to embed algorithm ID inside another */ + if (!rsa_md_to_algor(&algtmp, mgf1md)) + goto err; + if (ASN1_item_pack(algtmp, &X509_ALGOR_it, &stmp) == NULL) + goto err; + *palg = X509_ALGOR_new(); + if (*palg == NULL) + goto err; + X509_ALGOR_set0(*palg, OBJ_nid2obj(NID_mgf1), V_ASN1_SEQUENCE, stmp); + stmp = NULL; + err: + ASN1_STRING_free(stmp); + X509_ALGOR_free(algtmp); + if (*palg) + return 1; + return 0; +} + +/* Convert algorithm ID to EVP_MD, defaults to SHA1. */ +static const EVP_MD * +rsa_algor_to_md(X509_ALGOR *alg) +{ + const EVP_MD *md; + + if (!alg) + return EVP_sha1(); + md = EVP_get_digestbyobj(alg->algorithm); + if (md == NULL) + RSAerror(RSA_R_UNKNOWN_DIGEST); + return md; +} + +/* convert algorithm ID to EVP_MD, default SHA1 */ +RSA_PSS_PARAMS * +rsa_pss_params_create(const EVP_MD *sigmd, const EVP_MD *mgf1md, int saltlen) +{ + RSA_PSS_PARAMS *pss = RSA_PSS_PARAMS_new(); + + if (pss == NULL) + goto err; + if (saltlen != 20) { + pss->saltLength = ASN1_INTEGER_new(); + if (pss->saltLength == NULL) + goto err; + if (!ASN1_INTEGER_set(pss->saltLength, saltlen)) + goto err; + } + if (!rsa_md_to_algor(&pss->hashAlgorithm, sigmd)) + goto err; + if (mgf1md == NULL) + mgf1md = sigmd; + if (!rsa_md_to_mgf1(&pss->maskGenAlgorithm, mgf1md)) + goto err; + if (!rsa_md_to_algor(&pss->maskHash, mgf1md)) + goto err; + return pss; + err: + RSA_PSS_PARAMS_free(pss); + return NULL; +} + +int +rsa_pss_get_param(const RSA_PSS_PARAMS *pss, const EVP_MD **pmd, + const EVP_MD **pmgf1md, int *psaltlen) +{ + if (pss == NULL) + return 0; + *pmd = rsa_algor_to_md(pss->hashAlgorithm); + if (*pmd == NULL) + return 0; + *pmgf1md = rsa_algor_to_md(pss->maskHash); + if (*pmgf1md == NULL) + return 0; + if (pss->saltLength) { + *psaltlen = ASN1_INTEGER_get(pss->saltLength); + if (*psaltlen < 0) { + RSAerror(RSA_R_INVALID_SALT_LENGTH); + return 0; + } + } else { + *psaltlen = 20; + } + + /* + * low-level routines support only trailer field 0xbc (value 1) and + * PKCS#1 says we should reject any other value anyway. + */ + if (pss->trailerField && ASN1_INTEGER_get(pss->trailerField) != 1) { + RSAerror(RSA_R_INVALID_TRAILER); + return 0; + } + + return 1; +} + /* Customised RSA item verification routine. This is called * when a signature is encountered requiring special handling. We * currently only handle PSS. diff --git a/lib/libcrypto/rsa/rsa_err.c b/lib/libcrypto/rsa/rsa_err.c index c2b197c581d..91d74307f09 100644 --- a/lib/libcrypto/rsa/rsa_err.c +++ b/lib/libcrypto/rsa/rsa_err.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rsa_err.c,v 1.17 2017/01/29 17:49:23 beck Exp $ */ +/* $OpenBSD: rsa_err.c,v 1.18 2019/10/31 13:56:29 jsing Exp $ */ /* ==================================================================== * Copyright (c) 1999-2011 The OpenSSL Project. All rights reserved. * @@ -90,12 +90,14 @@ static ERR_STRING_DATA RSA_str_reasons[] = { {ERR_REASON(RSA_R_DATA_TOO_LARGE_FOR_MODULUS), "data too large for modulus"}, {ERR_REASON(RSA_R_DATA_TOO_SMALL) , "data too small"}, {ERR_REASON(RSA_R_DATA_TOO_SMALL_FOR_KEY_SIZE), "data too small for key size"}, + {ERR_REASON(RSA_R_DIGEST_NOT_ALLOWED) , "digest not allowed"}, {ERR_REASON(RSA_R_DIGEST_TOO_BIG_FOR_RSA_KEY), "digest too big for rsa key"}, {ERR_REASON(RSA_R_DMP1_NOT_CONGRUENT_TO_D), "dmp1 not congruent to d"}, {ERR_REASON(RSA_R_DMQ1_NOT_CONGRUENT_TO_D), "dmq1 not congruent to d"}, {ERR_REASON(RSA_R_D_E_NOT_CONGRUENT_TO_1), "d e not congruent to 1"}, {ERR_REASON(RSA_R_FIRST_OCTET_INVALID) , "first octet invalid"}, {ERR_REASON(RSA_R_ILLEGAL_OR_UNSUPPORTED_PADDING_MODE), "illegal or unsupported padding mode"}, + {ERR_REASON(RSA_R_INVALID_DIGEST) , "invalid digest"}, {ERR_REASON(RSA_R_INVALID_DIGEST_LENGTH) , "invalid digest length"}, {ERR_REASON(RSA_R_INVALID_HEADER) , "invalid header"}, {ERR_REASON(RSA_R_INVALID_KEYBITS) , "invalid keybits"}, @@ -111,6 +113,7 @@ static ERR_STRING_DATA RSA_str_reasons[] = { {ERR_REASON(RSA_R_IQMP_NOT_INVERSE_OF_Q) , "iqmp not inverse of q"}, {ERR_REASON(RSA_R_KEY_SIZE_TOO_SMALL) , "key size too small"}, {ERR_REASON(RSA_R_LAST_OCTET_INVALID) , "last octet invalid"}, + {ERR_REASON(RSA_R_MGF1_DIGEST_NOT_ALLOWED), "mgf1 digest not allowed"}, {ERR_REASON(RSA_R_MODULUS_TOO_LARGE) , "modulus too large"}, {ERR_REASON(RSA_R_NON_FIPS_RSA_METHOD) , "non fips rsa method"}, {ERR_REASON(RSA_R_NO_PUBLIC_EXPONENT) , "no public exponent"}, @@ -120,6 +123,7 @@ static ERR_STRING_DATA RSA_str_reasons[] = { {ERR_REASON(RSA_R_OPERATION_NOT_ALLOWED_IN_FIPS_MODE), "operation not allowed in fips mode"}, {ERR_REASON(RSA_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE), "operation not supported for this keytype"}, {ERR_REASON(RSA_R_PADDING_CHECK_FAILED) , "padding check failed"}, + {ERR_REASON(RSA_R_PSS_SALTLEN_TOO_SMALL) , "pss saltlen too small"}, {ERR_REASON(RSA_R_P_NOT_PRIME) , "p not prime"}, {ERR_REASON(RSA_R_Q_NOT_PRIME) , "q not prime"}, {ERR_REASON(RSA_R_RSA_OPERATIONS_NOT_SUPPORTED), "rsa operations not supported"}, @@ -128,6 +132,7 @@ static ERR_STRING_DATA RSA_str_reasons[] = { {ERR_REASON(RSA_R_SSLV3_ROLLBACK_ATTACK) , "sslv3 rollback attack"}, {ERR_REASON(RSA_R_THE_ASN1_OBJECT_IDENTIFIER_IS_NOT_KNOWN_FOR_THIS_MD), "the asn1 object identifier is not known for this md"}, {ERR_REASON(RSA_R_UNKNOWN_ALGORITHM_TYPE), "unknown algorithm type"}, + {ERR_REASON(RSA_R_UNKNOWN_DIGEST) , "unknown digest"}, {ERR_REASON(RSA_R_UNKNOWN_MASK_DIGEST) , "unknown mask digest"}, {ERR_REASON(RSA_R_UNKNOWN_PADDING_TYPE) , "unknown padding type"}, {ERR_REASON(RSA_R_UNKNOWN_PSS_DIGEST) , "unknown pss digest"}, diff --git a/lib/libcrypto/rsa/rsa_locl.h b/lib/libcrypto/rsa/rsa_locl.h index a10ea958b58..d69946f95c0 100644 --- a/lib/libcrypto/rsa/rsa_locl.h +++ b/lib/libcrypto/rsa/rsa_locl.h @@ -1,9 +1,14 @@ -/* $OpenBSD: rsa_locl.h,v 1.7 2019/10/31 13:10:40 jsing Exp $ */ +/* $OpenBSD: rsa_locl.h,v 1.8 2019/10/31 13:56:29 jsing Exp $ */ __BEGIN_HIDDEN_DECLS #define RSA_MIN_MODULUS_BITS 512 +RSA_PSS_PARAMS *rsa_pss_params_create(const EVP_MD *sigmd, const EVP_MD *mgf1md, + int saltlen); +int rsa_pss_get_param(const RSA_PSS_PARAMS *pss, const EVP_MD **pmd, + const EVP_MD **pmgf1md, int *psaltlen); + typedef struct rsa_oaep_params_st { X509_ALGOR *hashFunc; X509_ALGOR *maskGenFunc; diff --git a/lib/libcrypto/rsa/rsa_pmeth.c b/lib/libcrypto/rsa/rsa_pmeth.c index 1b6d1de35de..5fd63092982 100644 --- a/lib/libcrypto/rsa/rsa_pmeth.c +++ b/lib/libcrypto/rsa/rsa_pmeth.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rsa_pmeth.c,v 1.30 2019/10/31 13:10:40 jsing Exp $ */ +/* $OpenBSD: rsa_pmeth.c,v 1.31 2019/10/31 13:56:29 jsing Exp $ */ /* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL * project 2006. */ @@ -89,6 +89,8 @@ typedef struct { const EVP_MD *mgf1md; /* PSS salt length */ int saltlen; + /* Minimum salt length or -1 if no PSS parameter restriction */ + int min_saltlen; /* Temp buffer */ unsigned char *tbuf; /* OAEP label */ @@ -96,6 +98,9 @@ typedef struct { size_t oaep_labellen; } RSA_PKEY_CTX; +/* True if PSS parameters are restricted */ +#define rsa_pss_restricted(rctx) (rctx->min_saltlen != -1) + static int pkey_rsa_init(EVP_PKEY_CTX *ctx) { @@ -105,9 +110,15 @@ pkey_rsa_init(EVP_PKEY_CTX *ctx) return 0; rctx->nbits = 2048; - rctx->pad_mode = RSA_PKCS1_PADDING; - rctx->saltlen = -2; + if (ctx->pmeth->pkey_id == EVP_PKEY_RSA_PSS) + rctx->pad_mode = RSA_PKCS1_PSS_PADDING; + else + rctx->pad_mode = RSA_PKCS1_PADDING; + + /* Maximum for sign, auto for verify */ + rctx->saltlen = RSA_PSS_SALTLEN_AUTO; + rctx->min_saltlen = -1; ctx->data = rctx; ctx->keygen_info = rctx->gentmp; @@ -385,7 +396,7 @@ pkey_rsa_decrypt(EVP_PKEY_CTX *ctx, unsigned char *out, size_t *outlen, static int check_padding_md(const EVP_MD *md, int padding) { - if (!md) + if (md == NULL) return 1; if (padding == RSA_NO_PADDING) { @@ -398,7 +409,24 @@ check_padding_md(const EVP_MD *md, int padding) RSAerror(RSA_R_INVALID_X931_DIGEST); return 0; } - return 1; + } else { + /* List of all supported RSA digests. */ + switch(EVP_MD_type(md)) { + case NID_sha1: + case NID_sha224: + case NID_sha256: + case NID_sha384: + case NID_sha512: + case NID_md5: + case NID_md5_sha1: + case NID_md4: + case NID_ripemd160: + return 1; + + default: + RSAerror(RSA_R_INVALID_DIGEST); + return 0; + } } return 1; @@ -420,6 +448,8 @@ pkey_rsa_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2) goto bad_pad; if (!rctx->md) rctx->md = EVP_sha1(); + } else if (ctx->pmeth->pkey_id == EVP_PKEY_RSA_PSS) { + goto bad_pad; } if (p1 == RSA_PKCS1_OAEP_PADDING) { if (!(ctx->operation & EVP_PKEY_OP_TYPE_CRYPT)) @@ -447,8 +477,21 @@ pkey_rsa_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2) if (type == EVP_PKEY_CTRL_GET_RSA_PSS_SALTLEN) { *(int *)p2 = rctx->saltlen; } else { - if (p1 < -2) + if (p1 < RSA_PSS_SALTLEN_MAX) return -2; + if (rsa_pss_restricted(rctx)) { + if (p1 == RSA_PSS_SALTLEN_AUTO && + ctx->operation == EVP_PKEY_OP_VERIFY) { + RSAerror(RSA_R_INVALID_PSS_SALTLEN); + return -2; + } + if ((p1 == RSA_PSS_SALTLEN_DIGEST && + rctx->min_saltlen > EVP_MD_size(rctx->md)) || + (p1 >= 0 && p1 < rctx->min_saltlen)) { + RSAerror(RSA_R_PSS_SALTLEN_TOO_SMALL); + return 0; + } + } rctx->saltlen = p1; } return 1; @@ -486,6 +529,12 @@ pkey_rsa_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2) case EVP_PKEY_CTRL_MD: if (!check_padding_md(p2, rctx->pad_mode)) return 0; + if (rsa_pss_restricted(rctx)) { + if (EVP_MD_type(rctx->md) == EVP_MD_type(p2)) + return 1; + RSAerror(RSA_R_DIGEST_NOT_ALLOWED); + return 0; + } rctx->md = p2; return 1; @@ -505,8 +554,15 @@ pkey_rsa_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2) *(const EVP_MD **)p2 = rctx->mgf1md; else *(const EVP_MD **)p2 = rctx->md; - } else + } else { + if (rsa_pss_restricted(rctx)) { + if (EVP_MD_type(rctx->mgf1md) == EVP_MD_type(p2)) + return 1; + RSAerror(RSA_R_MGF1_DIGEST_NOT_ALLOWED); + return 0; + } rctx->mgf1md = p2; + } return 1; case EVP_PKEY_CTRL_RSA_OAEP_LABEL: @@ -533,25 +589,28 @@ pkey_rsa_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2) return rctx->oaep_labellen; case EVP_PKEY_CTRL_DIGESTINIT: - case EVP_PKEY_CTRL_PKCS7_ENCRYPT: - case EVP_PKEY_CTRL_PKCS7_DECRYPT: case EVP_PKEY_CTRL_PKCS7_SIGN: return 1; + + case EVP_PKEY_CTRL_PKCS7_ENCRYPT: + case EVP_PKEY_CTRL_PKCS7_DECRYPT: + if (ctx->pmeth->pkey_id != EVP_PKEY_RSA_PSS) + return 1; + + /* fall through */ case EVP_PKEY_CTRL_PEER_KEY: RSAerror(RSA_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); return -2; default: return -2; + } } static int pkey_rsa_ctrl_str(EVP_PKEY_CTX *ctx, const char *type, const char *value) { - long lval; - char *ep; - if (!value) { RSAerror(RSA_R_VALUE_MISSING); return 0; @@ -577,39 +636,29 @@ pkey_rsa_ctrl_str(EVP_PKEY_CTX *ctx, const char *type, const char *value) return EVP_PKEY_CTX_set_rsa_padding(ctx, pm); } - if (!strcmp(type, "rsa_pss_saltlen")) { + if (strcmp(type, "rsa_pss_saltlen") == 0) { int saltlen; - errno = 0; - lval = strtol(value, &ep, 10); - if (value[0] == '\0' || *ep != '\0') - goto not_a_number; - if ((errno == ERANGE && - (lval == LONG_MAX || lval == LONG_MIN)) || - (lval > INT_MAX || lval < INT_MIN)) - goto out_of_range; - saltlen = lval; + if (!strcmp(value, "digest")) + saltlen = RSA_PSS_SALTLEN_DIGEST; + else if (!strcmp(value, "max")) + saltlen = RSA_PSS_SALTLEN_MAX; + else if (!strcmp(value, "auto")) + saltlen = RSA_PSS_SALTLEN_AUTO; + else + saltlen = atoi(value); return EVP_PKEY_CTX_set_rsa_pss_saltlen(ctx, saltlen); } - if (!strcmp(type, "rsa_keygen_bits")) { - int nbits; - - errno = 0; - lval = strtol(value, &ep, 10); - if (value[0] == '\0' || *ep != '\0') - goto not_a_number; - if ((errno == ERANGE && - (lval == LONG_MAX || lval == LONG_MIN)) || - (lval > INT_MAX || lval < INT_MIN)) - goto out_of_range; - nbits = lval; + if (strcmp(type, "rsa_keygen_bits") == 0) { + int nbits = atoi(value); + return EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, nbits); } - if (!strcmp(type, "rsa_keygen_pubexp")) { - int ret; + if (strcmp(type, "rsa_keygen_pubexp") == 0) { BIGNUM *pubexp = NULL; + int ret; if (!BN_asc2bn(&pubexp, value)) return 0; @@ -624,6 +673,22 @@ pkey_rsa_ctrl_str(EVP_PKEY_CTX *ctx, const char *type, const char *value) EVP_PKEY_OP_TYPE_SIG | EVP_PKEY_OP_TYPE_CRYPT, EVP_PKEY_CTRL_RSA_MGF1_MD, value); + if (ctx->pmeth->pkey_id == EVP_PKEY_RSA_PSS) { + if (strcmp(type, "rsa_pss_keygen_mgf1_md") == 0) + return EVP_PKEY_CTX_md(ctx, EVP_PKEY_OP_KEYGEN, + EVP_PKEY_CTRL_RSA_MGF1_MD, value); + + if (strcmp(type, "rsa_pss_keygen_md") == 0) + return EVP_PKEY_CTX_md(ctx, EVP_PKEY_OP_KEYGEN, + EVP_PKEY_CTRL_MD, value); + + if (strcmp(type, "rsa_pss_keygen_saltlen") == 0) { + int saltlen = atoi(value); + + return EVP_PKEY_CTX_set_rsa_pss_keygen_saltlen(ctx, saltlen); + } + } + if (strcmp(type, "rsa_oaep_md") == 0) return EVP_PKEY_CTX_md(ctx, EVP_PKEY_OP_TYPE_CRYPT, EVP_PKEY_CTRL_RSA_OAEP_MD, value); @@ -642,11 +707,31 @@ pkey_rsa_ctrl_str(EVP_PKEY_CTX *ctx, const char *type, const char *value) return ret; } - not_a_number: - out_of_range: return -2; } +/* Set PSS parameters when generating a key, if necessary. */ +static int +rsa_set_pss_param(RSA *rsa, EVP_PKEY_CTX *ctx) +{ + RSA_PKEY_CTX *rctx = ctx->data; + + if (ctx->pmeth->pkey_id != EVP_PKEY_RSA_PSS) + return 1; + + /* If all parameters are default values then do not set PSS. */ + if (rctx->md == NULL && rctx->mgf1md == NULL && + rctx->saltlen == RSA_PSS_SALTLEN_AUTO) + return 1; + + rsa->pss = rsa_pss_params_create(rctx->md, rctx->mgf1md, + rctx->saltlen == RSA_PSS_SALTLEN_AUTO ? 0 : rctx->saltlen); + if (rsa->pss == NULL) + return 0; + + return 1; +} + static int pkey_rsa_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) { @@ -670,8 +755,12 @@ pkey_rsa_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) pcb = NULL; } ret = RSA_generate_key_ex(rsa, rctx->nbits, rctx->pub_exp, pcb); + if (ret > 0 && !rsa_set_pss_param(rsa, ctx)) { + RSA_free(rsa); + return 0; + } if (ret > 0) - EVP_PKEY_assign_RSA(pkey, rsa); + EVP_PKEY_assign(pkey, ctx->pmeth->pkey_id, rsa); else RSA_free(rsa); return ret; @@ -700,3 +789,73 @@ const EVP_PKEY_METHOD rsa_pkey_meth = { .ctrl = pkey_rsa_ctrl, .ctrl_str = pkey_rsa_ctrl_str }; + +/* + * Called for PSS sign or verify initialisation: checks PSS parameter + * sanity and sets any restrictions on key usage. + */ + +static int +pkey_pss_init(EVP_PKEY_CTX *ctx) +{ + RSA *rsa; + RSA_PKEY_CTX *rctx = ctx->data; + const EVP_MD *md; + const EVP_MD *mgf1md; + int min_saltlen, max_saltlen; + + /* Should never happen */ + if (ctx->pmeth->pkey_id != EVP_PKEY_RSA_PSS) + return 0; + rsa = ctx->pkey->pkey.rsa; + + /* If no restrictions just return */ + if (rsa->pss == NULL) + return 1; + + /* Get and check parameters */ + if (!rsa_pss_get_param(rsa->pss, &md, &mgf1md, &min_saltlen)) + return 0; + + /* See if minimum salt length exceeds maximum possible */ + max_saltlen = RSA_size(rsa) - EVP_MD_size(md); + if ((RSA_bits(rsa) & 0x7) == 1) + max_saltlen--; + if (min_saltlen > max_saltlen) { + RSAerror(RSA_R_INVALID_SALT_LENGTH); + return 0; + } + rctx->min_saltlen = min_saltlen; + + /* + * Set PSS restrictions as defaults: we can then block any attempt to + * use invalid values in pkey_rsa_ctrl + */ + + rctx->md = md; + rctx->mgf1md = mgf1md; + rctx->saltlen = min_saltlen; + + return 1; +} + +const EVP_PKEY_METHOD rsa_pss_pkey_meth = { + .pkey_id = EVP_PKEY_RSA_PSS, + .flags = EVP_PKEY_FLAG_AUTOARGLEN, + + .init = pkey_rsa_init, + .copy = pkey_rsa_copy, + .cleanup = pkey_rsa_cleanup, + + .keygen = pkey_rsa_keygen, + + .sign_init = pkey_pss_init, + .sign = pkey_rsa_sign, + + .verify_init = pkey_pss_init, + .verify = pkey_rsa_verify, + + .ctrl = pkey_rsa_ctrl, + .ctrl_str = pkey_rsa_ctrl_str +}; + |