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