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

Reply via email to