summaryrefslogtreecommitdiff
path: root/lib/libcrypto/rsa
diff options
context:
space:
mode:
authorJoel Sing <jsing@cvs.openbsd.org>2019-10-31 13:56:30 +0000
committerJoel Sing <jsing@cvs.openbsd.org>2019-10-31 13:56:30 +0000
commit03077a655aaf94a688602d07365bfb0016d41dd2 (patch)
treefc7ae99bb208e4acf1900b288db097859e806749 /lib/libcrypto/rsa
parentbfc6803e10a381ffdf7313315a96f008ade380f5 (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.h64
-rw-r--r--lib/libcrypto/rsa/rsa_ameth.c120
-rw-r--r--lib/libcrypto/rsa/rsa_err.c7
-rw-r--r--lib/libcrypto/rsa/rsa_locl.h7
-rw-r--r--lib/libcrypto/rsa/rsa_pmeth.c237
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
+};
+