Dear all, I'm working on support for X.509 certificates with RSASSA-PSS signatures according to PKCS1 #2.1 and RFC 4055. As I would like to come up with something that can be included in the main tree, I'm sending this mail to ask for your advice and to make sure I'm heading in the right direction.
My first step is to support verification of X.509 certificates with a PSS signature that uses the default PSS parameters. Low-level routines for PSS signatures have been present for a long time. The signature type (PKCS1.5 or PSS) can be set for an EVP_PKEY_CTX object. X.509 signature verification is based on EVP_MD_CTX. EVP_VerifyInit_ex(), EVP_VerifyUpdate() and EVP_VerifyFinal() are called on the EVP_MD_CTX. EVP_VerifyFinal() uses a local EVP_PKEY_CTX object that is configured according to the EVP_MD_CTX' flags. I thought of different approaches - add a new flag similar to EVP_MD_FLAG_PKEY_METHOD_SIGNATURE This would require a new sha1_md which in turn would require a new NID_sha1Pss (or so) to have a unique match in obj_xref.txt -> looks like this will end up in a mess - base the signature verification on EVP_PKEY_CTX rather than EVP_MD_CTX -> I understand that EVP_VerifyInit/Update/Final() is the most abstract API for this and should be used for X.509 signature verification - therefore, my proposal is to use the pctx field of EVP_MD_CTX to set up the PSS-related parameters in ASN1_item_verify(). EVP_VerifyFinal() is changed to set up the local EVP_PKEY_CTX only if the EVP_MD_CTX' pctx field is unset. I attach a simple patch against 1.0.0-beta2 that outlines the basic idea. It is far from ready (e.g. PSS parameters are not checked) but it should be sufficient for discussing the approach. I would very much appreciate your comments. Best regards, Martin
diff --git a/crypto/asn1/a_verify.c b/crypto/asn1/a_verify.c index cecdb13..9094937 100644 --- a/crypto/asn1/a_verify.c +++ b/crypto/asn1/a_verify.c @@ -72,6 +72,7 @@ #include <openssl/buffer.h> #include <openssl/evp.h> + #ifndef NO_ASN1_OLD int ASN1_verify(i2d_of_void *i2d, X509_ALGOR *a, ASN1_BIT_STRING *signature, @@ -150,6 +151,17 @@ int ASN1_item_verify(const ASN1_ITEM *it, X509_ALGOR *a, ASN1_BIT_STRING *signat ASN1err(ASN1_F_ASN1_ITEM_VERIFY,ASN1_R_UNKNOWN_MESSAGE_DIGEST_ALGORITHM); goto err; } + if (OBJ_obj2nid(a->algorithm) == NID_rsaSsaPss) + { + if ((ctx.pctx = EVP_PKEY_CTX_new(pkey, NULL)) == NULL) + goto err; + if (EVP_PKEY_verify_init(ctx.pctx) <= 0) + goto err; + if (EVP_PKEY_CTX_set_signature_md(ctx.pctx, ctx.digest) <= 0) + goto err; + if (EVP_PKEY_CTX_set_rsa_padding(ctx.pctx, RSA_PKCS1_PSS_PADDING) <= 0) + goto err; + } /* Check public key OID matches public key type */ if (EVP_PKEY_type(pknid) != pkey->ameth->pkey_id) diff --git a/crypto/evp/p_verify.c b/crypto/evp/p_verify.c index 8db4641..4e406e5 100644 --- a/crypto/evp/p_verify.c +++ b/crypto/evp/p_verify.c @@ -77,21 +77,30 @@ int EVP_VerifyFinal(EVP_MD_CTX *ctx, const unsigned char *sigbuf, if (ctx->digest->flags & EVP_MD_FLAG_PKEY_METHOD_SIGNATURE) { - EVP_PKEY_CTX *pkctx = NULL; - i = -1; - pkctx = EVP_PKEY_CTX_new(pkey, NULL); - if (!pkctx) - goto err; - if (EVP_PKEY_verify_init(pkctx) <= 0) - goto err; - if (EVP_PKEY_CTX_set_signature_md(pkctx, ctx->digest) <= 0) - goto err; - i = EVP_PKEY_verify(pkctx, sigbuf, siglen, m, m_len); - err: - EVP_PKEY_CTX_free(pkctx); - return i; - } - + if (!ctx->pctx) + { + EVP_PKEY_CTX *pkctx = NULL; + i = -1; + pkctx = EVP_PKEY_CTX_new(pkey, NULL); + if (!pkctx) + goto err; + if (EVP_PKEY_verify_init(pkctx) <= 0) + goto err; + if (EVP_PKEY_CTX_set_signature_md(pkctx, ctx->digest) <= 0) + goto err; + i = EVP_PKEY_verify(pkctx, sigbuf, siglen, m, m_len); + err: + EVP_PKEY_CTX_free(pkctx); + return i; + } + else + { + /* pctx must have been prepared completely before calling + * EVP_VerifyFinal() */ + i = EVP_PKEY_verify(ctx->pctx, sigbuf, siglen, m, m_len); + return i; + } + } for (i=0; i<4; i++) { v=ctx->digest->required_pkey_type[i]; diff --git a/crypto/objects/obj_xref.txt b/crypto/objects/obj_xref.txt index e45b3d3..ef6f48f 100644 --- a/crypto/objects/obj_xref.txt +++ b/crypto/objects/obj_xref.txt @@ -6,6 +6,7 @@ md2WithRSAEncryption md2 rsaEncryption md5WithRSAEncryption md5 rsaEncryption shaWithRSAEncryption sha rsaEncryption sha1WithRSAEncryption sha1 rsaEncryption +rsaSsaPss sha1 rsaEncryption md4WithRSAEncryption md4 rsaEncryption sha256WithRSAEncryption sha256 rsaEncryption sha384WithRSAEncryption sha384 rsaEncryption diff --git a/crypto/objects/objects.txt b/crypto/objects/objects.txt index 52ac0a6..82fa188 100644 --- a/crypto/objects/objects.txt +++ b/crypto/objects/objects.txt @@ -166,6 +166,8 @@ pkcs1 3 : RSA-MD4 : md4WithRSAEncryption pkcs1 4 : RSA-MD5 : md5WithRSAEncryption pkcs1 5 : RSA-SHA1 : sha1WithRSAEncryption # According to PKCS #1 version 2.1 +pkcs1 8 : MGF1 : mgf1 +pkcs1 10 : RSASSA-PSS : rsaSsaPss pkcs1 11 : RSA-SHA256 : sha256WithRSAEncryption pkcs1 12 : RSA-SHA384 : sha384WithRSAEncryption pkcs1 13 : RSA-SHA512 : sha512WithRSAEncryption