Hello Steve,

thanks for your feedback.

Thus wrote Stephen Henson via RT (r...@openssl.org):

> As has been indicated the PSS ASN1 module is incorrect. Does that
> actually verify PSS signatures correctly with non-default algorithms?
> I'd expect ASN1 parsing errors.

I got Francesco's point and corrected this. The certificates I used for
testing either had the parameters omitted or were generated by myself
using the same wrong definition, that's why I didn't spot the problem.

I'll update the sample certificates on my website shortly
(http://www.kaiser.cx/x509Pss.html)

> A quick look through (I'm not short of things to do at the moment
> alas...) suggests ctrl return codes aren't checked properly in a number
> of places.

Are you refering to this?

   if (type == NULL) 
      {
      if (EVP_PKEY_CTX_ctrl(ctx->pctx, -1, ctx->pctx->operation,
                            EVP_PKEY_CTRL_PARAM_SET_FROM_PKEY, 0, pkey)) 
         { 
         EVP_PKEY_CTX_ctrl(ctx->pctx, -1, ctx->pctx->operation, 
                           EVP_PKEY_CTRL_GET_DIGEST, 0, &type);
         }
      ....

I'll add a clean error checking.

> I also find the lack of any use of the PSS OID as rather strange. The
> specifications I've seen should require it is at least checked.

I've added a function
void EVP_MD_CTX_set_padmode_from_nid(EVP_MD_CTX *ctx, int nid)
that sets EVP_MD_CTX_FLAG_PAD_PSS when it sees the PSS nid. This ctx is
then passed into EVP_DigestVerifyInit.

pkey_rsa_verifyctx_init() converts the flag into RSA_PKEY_CTX' pad_mode
parameter. The pad_mode is checked when the ctrls set the pss
parameters.

Please see the attached patch (against 2010-02-07 snapshot) for a first
concept. Does this make sense to you or does it contradict your intended
use of the (yet unused) EVP_MD_CTX_FLAG_PAD_... flags?

Best regards,

   Martin

diff --git a/crypto/asn1/a_verify.c b/crypto/asn1/a_verify.c
index d9332ee..c5531de 100644
--- a/crypto/asn1/a_verify.c
+++ b/crypto/asn1/a_verify.c
@@ -134,14 +134,15 @@ err:
 int ASN1_item_verify(const ASN1_ITEM *it, X509_ALGOR *a, ASN1_BIT_STRING *signature,
 	     void *asn, EVP_PKEY *pkey)
 	{
-	EVP_MD_CTX ctx;
-	const EVP_MD *type = NULL;
+	EVP_MD_CTX mctx;
+	const EVP_MD *md = NULL;
+
 	unsigned char *buf_in=NULL;
 	int ret= -1,inl;
 
 	int mdnid, pknid;
 
-	EVP_MD_CTX_init(&ctx);
+	EVP_MD_CTX_init(&mctx);
 
 	/* Convert signature OID into digest and public key OIDs */
 	if (!OBJ_find_sigid_algs(OBJ_obj2nid(a->algorithm), &mdnid, &pknid))
@@ -149,12 +150,7 @@ int ASN1_item_verify(const ASN1_ITEM *it, X509_ALGOR *a, ASN1_BIT_STRING *signat
 		ASN1err(ASN1_F_ASN1_ITEM_VERIFY,ASN1_R_UNKNOWN_SIGNATURE_ALGORITHM);
 		goto err;
 		}
-	type=EVP_get_digestbynid(mdnid);
-	if (type == NULL)
-		{
-		ASN1err(ASN1_F_ASN1_ITEM_VERIFY,ASN1_R_UNKNOWN_MESSAGE_DIGEST_ALGORITHM);
-		goto err;
-		}
+	md=EVP_get_digestbynid(mdnid); /* md == NULL is no longer an error */
 
 	/* Check public key OID matches public key type */
 	if (EVP_PKEY_type(pknid) != pkey->ameth->pkey_id)
@@ -162,8 +158,41 @@ int ASN1_item_verify(const ASN1_ITEM *it, X509_ALGOR *a, ASN1_BIT_STRING *signat
 		ASN1err(ASN1_F_ASN1_ITEM_VERIFY,ASN1_R_WRONG_PUBLIC_KEY_TYPE);
 		goto err;
 		}
-
-	if (!EVP_VerifyInit_ex(&ctx,type, NULL))
+   if (pkey->ameth->param_decode && a)
+      {
+      int plen;
+
+      /* this is ok for a->parameter==NULL, result is plen=0 */
+      plen = i2d_ASN1_TYPE(a->parameter, NULL);
+      if (plen > 0)
+         {
+         const unsigned char *cp;
+         unsigned char *p;
+         unsigned char *pder=NULL;
+         int ok;
+
+         pder = (unsigned char *)OPENSSL_malloc(plen);
+         if (pder == NULL)
+            {
+		      ASN1err(ASN1_F_ASN1_ITEM_VERIFY,ERR_R_MALLOC_FAILURE);
+		      goto err;
+            }
+
+         /* call i2d_...() routines like in pem_pkey.c */
+         p = pder; 
+         plen = i2d_ASN1_TYPE(a->parameter, &p);
+         cp = pder;
+
+         ok = pkey->ameth->param_decode(pkey, &cp, plen);
+         OPENSSL_free(pder);
+         if (!ok)
+            goto err;
+         }
+      }
+
+   EVP_MD_CTX_set_padmode_from_nid(&mctx, OBJ_obj2nid(a->algorithm));
+
+	if (!EVP_DigestVerifyInit(&mctx, NULL,md, NULL, pkey))
 		{
 		ASN1err(ASN1_F_ASN1_ITEM_VERIFY,ERR_R_EVP_LIB);
 		ret=0;
@@ -178,7 +207,7 @@ int ASN1_item_verify(const ASN1_ITEM *it, X509_ALGOR *a, ASN1_BIT_STRING *signat
 		goto err;
 		}
 
-	if (!EVP_VerifyUpdate(&ctx,(unsigned char *)buf_in,inl))
+	if (!EVP_DigestVerifyUpdate(&mctx,(unsigned char *)buf_in,inl))
 		{
 		ASN1err(ASN1_F_ASN1_ITEM_VERIFY,ERR_R_EVP_LIB);
 		ret=0;
@@ -188,19 +217,19 @@ int ASN1_item_verify(const ASN1_ITEM *it, X509_ALGOR *a, ASN1_BIT_STRING *signat
 	OPENSSL_cleanse(buf_in,(unsigned int)inl);
 	OPENSSL_free(buf_in);
 
-	if (EVP_VerifyFinal(&ctx,(unsigned char *)signature->data,
-			(unsigned int)signature->length,pkey) <= 0)
+	if (EVP_DigestVerifyFinal(&mctx,(unsigned char *)signature->data,
+			(unsigned int)signature->length) <= 0)
 		{
 		ASN1err(ASN1_F_ASN1_ITEM_VERIFY,ERR_R_EVP_LIB);
 		ret=0;
 		goto err;
 		}
-	/* we don't need to zero the 'ctx' because we just checked
+	/* we don't need to zero the 'mctx' because we just checked
 	 * public information */
-	/* memset(&ctx,0,sizeof(ctx)); */
+	/* memset(&mctx,0,sizeof(ctx)); */
 	ret=1;
 err:
-	EVP_MD_CTX_cleanup(&ctx);
+	EVP_MD_CTX_cleanup(&mctx);
 	return(ret);
 	}
 
diff --git a/crypto/evp/evp.h b/crypto/evp/evp.h
index 9064164..fafcc47 100644
--- a/crypto/evp/evp.h
+++ b/crypto/evp/evp.h
@@ -502,6 +502,7 @@ __owur int     EVP_MD_CTX_copy_ex(EVP_MD_CTX *out,const EVP_MD_CTX *in);
 void	EVP_MD_CTX_set_flags(EVP_MD_CTX *ctx, int flags);
 void	EVP_MD_CTX_clear_flags(EVP_MD_CTX *ctx, int flags);
 int 	EVP_MD_CTX_test_flags(const EVP_MD_CTX *ctx,int flags);
+void EVP_MD_CTX_set_padmode_from_nid(EVP_MD_CTX *ctx, int nid);
 __owur int	EVP_DigestInit_ex(EVP_MD_CTX *ctx, const EVP_MD *type, ENGINE *impl);
 __owur int	EVP_DigestUpdate(EVP_MD_CTX *ctx,const void *d,
 			 size_t cnt);
@@ -1038,6 +1039,9 @@ void EVP_PKEY_asn1_set_ctrl(EVP_PKEY_ASN1_METHOD *ameth,
 #define EVP_PKEY_CTRL_CMS_DECRYPT	10
 #define EVP_PKEY_CTRL_CMS_SIGN		11
 
+#define EVP_PKEY_CTRL_PARAM_SET_FROM_PKEY   20
+#define EVP_PKEY_CTRL_GET_DIGEST            21
+
 #define EVP_PKEY_ALG_CTRL		0x1000
 
 
diff --git a/crypto/evp/evp_lib.c b/crypto/evp/evp_lib.c
index 40951a0..aa9467c 100644
--- a/crypto/evp/evp_lib.c
+++ b/crypto/evp/evp_lib.c
@@ -296,6 +296,16 @@ int EVP_MD_CTX_test_flags(const EVP_MD_CTX *ctx, int flags)
 	return (ctx->flags & flags);
 	}
 
+void EVP_MD_CTX_set_padmode_from_nid(EVP_MD_CTX *ctx, int nid)
+	{
+	if (nid == NID_rsassaPss)
+      EVP_MD_CTX_set_flags(ctx, EVP_MD_CTX_FLAG_PAD_PSS);
+   else
+      EVP_MD_CTX_set_flags(ctx, EVP_MD_CTX_FLAG_PAD_PKCS1);
+   /* TODO: what about X931? */
+	}
+
+
 void EVP_CIPHER_CTX_set_flags(EVP_CIPHER_CTX *ctx, int flags)
 	{
 	ctx->flags |= flags;
diff --git a/crypto/evp/m_sigver.c b/crypto/evp/m_sigver.c
index f0b7f95..bbe841e 100644
--- a/crypto/evp/m_sigver.c
+++ b/crypto/evp/m_sigver.c
@@ -72,19 +72,6 @@ static int do_sigver_init(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx,
 	if (ctx->pctx == NULL)
 		return 0;
 
-	if (type == NULL)
-		{
-		int def_nid;
-		if (EVP_PKEY_get_default_digest_nid(pkey, &def_nid) > 0)
-			type = EVP_get_digestbynid(def_nid);
-		}
-
-	if (type == NULL)
-		{
-		EVPerr(EVP_F_DO_SIGVER_INIT, EVP_R_NO_DEFAULT_DIGEST);
-		return 0;
-		}
-
 	if (ver)
 		{
 		if (ctx->pctx->pmeth->verifyctx_init)
@@ -107,6 +94,29 @@ static int do_sigver_init(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx,
 		else if (EVP_PKEY_sign_init(ctx->pctx) <= 0)
 			return 0;
 		}
+
+	if (type == NULL)
+		{
+      if (EVP_PKEY_CTX_ctrl(ctx->pctx, -1, ctx->pctx->operation,
+                            EVP_PKEY_CTRL_PARAM_SET_FROM_PKEY, 0, pkey))
+         {
+			/* in case of error, type remains NULL */
+			EVP_PKEY_CTX_ctrl(ctx->pctx, -1, ctx->pctx->operation,
+                           EVP_PKEY_CTRL_GET_DIGEST, 0, &type);
+         }
+      else
+      	{
+         int def_nid;
+         if (EVP_PKEY_get_default_digest_nid(pkey, &def_nid) > 0)
+            type = EVP_get_digestbynid(def_nid);
+         }
+		}
+	if (type == NULL)
+		{
+		EVPerr(EVP_F_DO_SIGVER_INIT, EVP_R_NO_DEFAULT_DIGEST);
+		return 0;
+		}
+
 	if (EVP_PKEY_CTX_set_signature_md(ctx->pctx, type) <= 0)
 		return 0;
 	if (pctx)
diff --git a/crypto/evp/pmeth_fn.c b/crypto/evp/pmeth_fn.c
index c4676f2..67bb32c 100644
--- a/crypto/evp/pmeth_fn.c
+++ b/crypto/evp/pmeth_fn.c
@@ -144,7 +144,8 @@ int EVP_PKEY_verify(EVP_PKEY_CTX *ctx,
 			EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
 		return -2;
 		}
-	if (ctx->operation != EVP_PKEY_OP_VERIFY)
+	if (ctx->operation != EVP_PKEY_OP_VERIFY &&
+		 ctx->operation != EVP_PKEY_OP_VERIFYCTX) /* temporary workaround */
 		{
 		EVPerr(EVP_F_EVP_PKEY_VERIFY, EVP_R_OPERATON_NOT_INITIALIZED);
 		return -1;
diff --git a/crypto/objects/o_names.c b/crypto/objects/o_names.c
index 84380a9..f96352f 100644
--- a/crypto/objects/o_names.c
+++ b/crypto/objects/o_names.c
@@ -159,6 +159,10 @@ const char *OBJ_NAME_get(const char *name, int type)
 
 	if (name == NULL) return(NULL);
 	if ((names_lh == NULL) && !OBJ_NAME_init()) return(NULL);
+	/* we have to treat the undef case specially because
+	   several digests (mainly from engines) register themselves with
+	   name==undef */
+	if (OBJ_sn2nid(name) == NID_undef) return(NULL);
 
 	alias=type&OBJ_NAME_ALIAS;
 	type&= ~OBJ_NAME_ALIAS;
diff --git a/crypto/objects/obj_dat.h b/crypto/objects/obj_dat.h
index cbccf5a..be5fd90 100644
--- a/crypto/objects/obj_dat.h
+++ b/crypto/objects/obj_dat.h
@@ -62,12 +62,12 @@
  * [including the GNU Public Licence.]
  */
 
-#define NUM_NID 894
-#define NUM_SN 887
-#define NUM_LN 887
-#define NUM_OBJ 841
+#define NUM_NID 896
+#define NUM_SN 889
+#define NUM_LN 889
+#define NUM_OBJ 843
 
-static const unsigned char lvalues[5835]={
+static const unsigned char lvalues[5853]={
 0x00,                                        /* [  0] OBJ_undef */
 0x2A,0x86,0x48,0x86,0xF7,0x0D,               /* [  1] OBJ_rsadsi */
 0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,          /* [  7] OBJ_pkcs */
@@ -909,6 +909,8 @@ static const unsigned char lvalues[5835]={
 0x55,0x04,0x35,                              /* [5817] OBJ_deltaRevocationList */
 0x55,0x04,0x36,                              /* [5820] OBJ_dmdName */
 0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x03,0x09,/* [5823] OBJ_id_alg_PWRI_KEK */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x08,/* [5834] OBJ_mgf1 */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0A,/* [5843] OBJ_rsassaPss */
 };
 
 static const ASN1_OBJECT nid_objs[NUM_NID]={
@@ -2354,6 +2356,8 @@ static const ASN1_OBJECT nid_objs[NUM_NID]={
 {"dmdName","dmdName",NID_dmdName,3,&(lvalues[5820]),0},
 {"id-alg-PWRI-KEK","id-alg-PWRI-KEK",NID_id_alg_PWRI_KEK,11,
 	&(lvalues[5823]),0},
+{"MGF1","mgf1",NID_mgf1,9,&(lvalues[5834]),0},
+{"RSASSA-PSS","rsassaPss",NID_rsassaPss,9,&(lvalues[5843]),0},
 };
 
 static const unsigned int sn_objs[NUM_SN]={
@@ -2454,6 +2458,7 @@ static const unsigned int sn_objs[NUM_SN]={
  4,	/* "MD5" */
 114,	/* "MD5-SHA1" */
 95,	/* "MDC2" */
+894,	/* "MGF1" */
 388,	/* "Mail" */
 393,	/* "NULL" */
 404,	/* "NULL" */
@@ -2510,6 +2515,7 @@ static const unsigned int sn_objs[NUM_SN]={
 668,	/* "RSA-SHA256" */
 669,	/* "RSA-SHA384" */
 670,	/* "RSA-SHA512" */
+895,	/* "RSASSA-PSS" */
 777,	/* "SEED-CBC" */
 779,	/* "SEED-CFB" */
 776,	/* "SEED-ECB" */
@@ -3811,6 +3817,7 @@ static const unsigned int ln_objs[NUM_LN]={
 602,	/* "merchant initiated auth" */
 514,	/* "message extensions" */
 51,	/* "messageDigest" */
+894,	/* "mgf1" */
 506,	/* "mime-mhs-bodies" */
 505,	/* "mime-mhs-headings" */
 488,	/* "mobileTelephoneNumber" */
@@ -3910,6 +3917,7 @@ static const unsigned int ln_objs[NUM_LN]={
  6,	/* "rsaEncryption" */
 644,	/* "rsaOAEPEncryptionSET" */
 377,	/* "rsaSignature" */
+895,	/* "rsassaPss" */
 124,	/* "run length compression" */
 482,	/* "sOARecord" */
 155,	/* "safeContentsBag" */
@@ -4725,6 +4733,8 @@ static const unsigned int obj_objs[NUM_OBJ]={
  8,	/* OBJ_md5WithRSAEncryption         1 2 840 113549 1 1 4 */
 65,	/* OBJ_sha1WithRSAEncryption        1 2 840 113549 1 1 5 */
 644,	/* OBJ_rsaOAEPEncryptionSET         1 2 840 113549 1 1 6 */
+894,	/* OBJ_mgf1                         1 2 840 113549 1 1 8 */
+895,	/* OBJ_rsassaPss                    1 2 840 113549 1 1 10 */
 668,	/* OBJ_sha256WithRSAEncryption      1 2 840 113549 1 1 11 */
 669,	/* OBJ_sha384WithRSAEncryption      1 2 840 113549 1 1 12 */
 670,	/* OBJ_sha512WithRSAEncryption      1 2 840 113549 1 1 13 */
diff --git a/crypto/objects/obj_mac.h b/crypto/objects/obj_mac.h
index a432663..13c8a96 100644
--- a/crypto/objects/obj_mac.h
+++ b/crypto/objects/obj_mac.h
@@ -580,6 +580,16 @@
 #define NID_sha1WithRSAEncryption		65
 #define OBJ_sha1WithRSAEncryption		OBJ_pkcs1,5L
 
+#define SN_mgf1		"MGF1"
+#define LN_mgf1		"mgf1"
+#define NID_mgf1		894
+#define OBJ_mgf1		OBJ_pkcs1,8L
+
+#define SN_rsassaPss		"RSASSA-PSS"
+#define LN_rsassaPss		"rsassaPss"
+#define NID_rsassaPss		895
+#define OBJ_rsassaPss		OBJ_pkcs1,10L
+
 #define SN_sha256WithRSAEncryption		"RSA-SHA256"
 #define LN_sha256WithRSAEncryption		"sha256WithRSAEncryption"
 #define NID_sha256WithRSAEncryption		668
diff --git a/crypto/objects/obj_mac.num b/crypto/objects/obj_mac.num
index 65ca66f..108fd4f 100644
--- a/crypto/objects/obj_mac.num
+++ b/crypto/objects/obj_mac.num
@@ -891,3 +891,5 @@ supportedAlgorithms		890
 deltaRevocationList		891
 dmdName		892
 id_alg_PWRI_KEK		893
+mgf1		894
+rsassaPss		895
diff --git a/crypto/objects/obj_xref.h b/crypto/objects/obj_xref.h
index d5b9b8e..e23938c 100644
--- a/crypto/objects/obj_xref.h
+++ b/crypto/objects/obj_xref.h
@@ -38,10 +38,12 @@ static const nid_triple sigoid_srt[] =
 	{NID_id_GostR3411_94_with_GostR3410_94, NID_id_GostR3411_94, NID_id_GostR3410_94},
 	{NID_id_GostR3411_94_with_GostR3410_94_cc, NID_id_GostR3411_94, NID_id_GostR3410_94_cc},
 	{NID_id_GostR3411_94_with_GostR3410_2001_cc, NID_id_GostR3411_94, NID_id_GostR3410_2001_cc},
+	{NID_rsassaPss, NID_undef, NID_rsaEncryption},
 	};
 
 static const nid_triple * const sigoid_srt_xref[] =
 	{
+	&sigoid_srt[29],
 	&sigoid_srt[17],
 	&sigoid_srt[18],
 	&sigoid_srt[0],
diff --git a/crypto/objects/obj_xref.txt b/crypto/objects/obj_xref.txt
index e45b3d3..ab69e79 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	undef	rsaEncryption
 md4WithRSAEncryption	md4	rsaEncryption
 sha256WithRSAEncryption sha256	rsaEncryption
 sha384WithRSAEncryption	sha384	rsaEncryption
diff --git a/crypto/objects/objects.txt b/crypto/objects/objects.txt
index 97be877..56e156e 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
diff --git a/crypto/rsa/rsa.h b/crypto/rsa/rsa.h
index cf74343..8395fb0 100644
--- a/crypto/rsa/rsa.h
+++ b/crypto/rsa/rsa.h
@@ -158,6 +158,10 @@ struct rsa_st
 	char *bignum_data;
 	BN_BLINDING *blinding;
 	BN_BLINDING *mt_blinding;
+
+   /* PSS parameters */
+   const EVP_MD *pssDigest;
+   int pssSaltlen;
 	};
 
 #ifndef OPENSSL_RSA_MAX_MODULUS_BITS
@@ -300,6 +304,17 @@ const RSA_METHOD *RSA_null_method(void);
 DECLARE_ASN1_ENCODE_FUNCTIONS_const(RSA, RSAPublicKey)
 DECLARE_ASN1_ENCODE_FUNCTIONS_const(RSA, RSAPrivateKey)
 
+typedef struct rsassaPssParams_st
+{
+   X509_ALGOR *hashAlgorithm;
+   X509_ALGOR *maskGenAlgorithm;
+   ASN1_INTEGER *saltLength;
+   ASN1_INTEGER *trailerField;
+} RSASSA_PSS_PARAMS;
+
+DECLARE_ASN1_FUNCTIONS(RSASSA_PSS_PARAMS)
+
+
 #ifndef OPENSSL_NO_FP_API
 int	RSA_print_fp(FILE *fp, const RSA *r,int offset);
 #endif
@@ -445,6 +460,7 @@ void ERR_load_RSA_strings(void);
 #define RSA_F_RSA_VERIFY				 119
 #define RSA_F_RSA_VERIFY_ASN1_OCTET_STRING		 120
 #define RSA_F_RSA_VERIFY_PKCS1_PSS			 126
+#define RSA_F_RSA_PARAM_DECODE			150
 
 /* Reason codes. */
 #define RSA_R_ALGORITHM_MISMATCH			 100
diff --git a/crypto/rsa/rsa_ameth.c b/crypto/rsa/rsa_ameth.c
index 8c32098..e47294f 100644
--- a/crypto/rsa/rsa_ameth.c
+++ b/crypto/rsa/rsa_ameth.c
@@ -170,6 +170,103 @@ static void int_rsa_free(EVP_PKEY *pkey)
 	RSA_free(pkey->pkey.rsa);
 	}
 
+static int rsa_param_decode(EVP_PKEY *pkey, const unsigned char **pder, int derlen)
+	{
+	int ret=0;
+   RSASSA_PSS_PARAMS *pss=NULL;
+   int pssHashNid;
+   X509_ALGOR *mgf1HashAlg=NULL;
+   ASN1_OBJECT *algObj;
+   int ptype;
+   void *pval;
+   ASN1_STRING *pseq;
+   const unsigned char *pm;
+
+   if (!pkey || pkey->type!=EVP_PKEY_RSA)
+		{
+		RSAerr(RSA_F_RSA_PARAM_DECODE, RSA_R_UNKNOWN_ALGORITHM_TYPE);
+      goto end;
+		}
+   if (!pder)
+      goto end;
+
+   pss = d2i_RSASSA_PSS_PARAMS(NULL, pder, derlen);
+   if (!pss)
+      {
+      /* no pss parameters present (this is not an error) */
+      pkey->pkey.rsa->pssDigest = NULL;
+      pkey->pkey.rsa->pssSaltlen = 0;
+      ret=1;
+      }
+   else 
+      {
+      if (pss->hashAlgorithm)
+         {
+         X509_ALGOR_get0(&algObj, &ptype, NULL, pss->hashAlgorithm);
+         pssHashNid = OBJ_obj2nid(algObj);
+         pkey->pkey.rsa->pssDigest = EVP_get_digestbynid(pssHashNid);
+         if (ptype != V_ASN1_NULL)
+            goto end;
+         }
+      else
+         {
+         pssHashNid = NID_sha1;
+         pkey->pkey.rsa->pssDigest = EVP_get_digestbynid(pssHashNid);
+         }
+
+      if (pss->maskGenAlgorithm)
+         {
+         X509_ALGOR_get0(&algObj, &ptype, &pval, pss->maskGenAlgorithm);
+         /* low-level routines support only MGF1 */
+         if (OBJ_obj2nid(algObj) != NID_mgf1)
+            goto end;
+
+         if (ptype == V_ASN1_SEQUENCE)
+            {
+            pseq = pval;
+            if (pseq == NULL)
+               goto end;
+            pm = pseq->data;
+            mgf1HashAlg = d2i_X509_ALGOR(NULL, &pm, pseq->length);
+            if (!mgf1HashAlg) goto end;
+            X509_ALGOR_get0(&algObj, &ptype, NULL, mgf1HashAlg);
+            /* low-level routines require pss hash algo == mgf1 hash algo */
+            if (pssHashNid != OBJ_obj2nid(algObj))
+               goto end;
+            if (ptype != V_ASN1_NULL) /* of mgf1HashAlg */
+               goto end;
+            }
+         else if (ptype != V_ASN1_NULL) /* of  pss->maskGenAlgorithm */
+            goto end;
+         }
+
+      if (pss->saltLength)
+         {
+         pkey->pkey.rsa->pssSaltlen = ASN1_INTEGER_get(pss->saltLength);
+         }
+      else
+         {
+         pkey->pkey.rsa->pssSaltlen = 20;
+         }
+
+      /* low-level routines support only trailer field 0xbc (value 1) */
+      if (pss->trailerField && ASN1_INTEGER_get(pss->trailerField) != 1)
+         goto end;
+
+      ret=1;
+      }
+end:
+   if (!ret && pkey && pkey->type==EVP_PKEY_RSA)
+      {
+      pkey->pkey.rsa->pssDigest = NULL;
+      pkey->pkey.rsa->pssSaltlen = 0;
+      }
+   if (pss)
+      RSASSA_PSS_PARAMS_free(pss);
+   if (mgf1HashAlg)
+      X509_ALGOR_free(mgf1HashAlg);
+   return(ret);
+	}
 
 static void update_buflen(const BIGNUM *b, size_t *pbuflen)
 	{
@@ -333,7 +430,8 @@ const EVP_PKEY_ASN1_METHOD rsa_asn1_meths[] =
 		int_rsa_size,
 		rsa_bits,
 
-		0,0,0,0,0,0,
+		rsa_param_decode,
+		0,0,0,0,0,
 
 		int_rsa_free,
 		rsa_pkey_ctrl,
diff --git a/crypto/rsa/rsa_asn1.c b/crypto/rsa/rsa_asn1.c
index 4efca8c..b9d8109 100644
--- a/crypto/rsa/rsa_asn1.c
+++ b/crypto/rsa/rsa_asn1.c
@@ -61,6 +61,7 @@
 #include <openssl/bn.h>
 #include <openssl/rsa.h>
 #include <openssl/asn1t.h>
+#include <openssl/x509.h>
 
 /* Override the default free and new methods */
 static int rsa_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it,
@@ -96,10 +97,20 @@ ASN1_SEQUENCE_cb(RSAPublicKey, rsa_cb) = {
 	ASN1_SIMPLE(RSA, e, BIGNUM),
 } ASN1_SEQUENCE_END_cb(RSA, RSAPublicKey)
 
+ASN1_SEQUENCE(RSASSA_PSS_PARAMS) = {
+	ASN1_EXP_OPT(RSASSA_PSS_PARAMS, hashAlgorithm, X509_ALGOR,0),
+	ASN1_EXP_OPT(RSASSA_PSS_PARAMS, maskGenAlgorithm, X509_ALGOR,1),
+	ASN1_EXP_OPT(RSASSA_PSS_PARAMS, saltLength, ASN1_INTEGER,2),
+	ASN1_EXP_OPT(RSASSA_PSS_PARAMS, trailerField, ASN1_INTEGER,3)
+} ASN1_SEQUENCE_END(RSASSA_PSS_PARAMS)
+
+
 IMPLEMENT_ASN1_ENCODE_FUNCTIONS_const_fname(RSA, RSAPrivateKey, RSAPrivateKey)
 
 IMPLEMENT_ASN1_ENCODE_FUNCTIONS_const_fname(RSA, RSAPublicKey, RSAPublicKey)
 
+IMPLEMENT_ASN1_FUNCTIONS(RSASSA_PSS_PARAMS)
+
 RSA *RSAPublicKey_dup(RSA *rsa)
 	{
 	return ASN1_item_dup(ASN1_ITEM_rptr(RSAPublicKey), rsa);
diff --git a/crypto/rsa/rsa_lib.c b/crypto/rsa/rsa_lib.c
index de45088..8810754 100644
--- a/crypto/rsa/rsa_lib.c
+++ b/crypto/rsa/rsa_lib.c
@@ -180,6 +180,8 @@ RSA *RSA_new_method(ENGINE *engine)
 	ret->_method_mod_q=NULL;
 	ret->blinding=NULL;
 	ret->mt_blinding=NULL;
+	ret->pssDigest=NULL;
+	ret->pssSaltlen=0;
 	ret->bignum_data=NULL;
 	ret->flags=ret->meth->flags;
 	if (!CRYPTO_new_ex_data(CRYPTO_EX_INDEX_RSA, ret, &ret->ex_data))
@@ -243,6 +245,7 @@ void RSA_free(RSA *r)
 	if (r->iqmp != NULL) BN_clear_free(r->iqmp);
 	if (r->blinding != NULL) BN_BLINDING_free(r->blinding);
 	if (r->mt_blinding != NULL) BN_BLINDING_free(r->mt_blinding);
+	/* no need to free pssDigest, it's just a reference */
 	if (r->bignum_data != NULL) OPENSSL_free_locked(r->bignum_data);
 	OPENSSL_free(r);
 	}
diff --git a/crypto/rsa/rsa_pmeth.c b/crypto/rsa/rsa_pmeth.c
index 297e17c..9b67723 100644
--- a/crypto/rsa/rsa_pmeth.c
+++ b/crypto/rsa/rsa_pmeth.c
@@ -313,6 +313,22 @@ static int pkey_rsa_verify(EVP_PKEY_CTX *ctx,
 			
 	}
 	
+static int pkey_rsa_verifyctx_init(EVP_PKEY_CTX *ctx, EVP_MD_CTX *mctx)
+	{
+	RSA_PKEY_CTX *rctx = ctx->data;
+
+   if (!rctx)
+      return 0;
+
+	if (EVP_MD_CTX_test_flags(mctx, EVP_MD_CTX_FLAG_PAD_PSS))
+      rctx->pad_mode = RSA_PKCS1_PSS_PADDING;
+   else
+      rctx->pad_mode = RSA_PKCS1_PADDING;
+   /* TODO: what about X931? */
+
+	return 1;
+	}
+
 
 static int pkey_rsa_encrypt(EVP_PKEY_CTX *ctx,
 					unsigned char *out, size_t *outlen,
@@ -381,7 +397,8 @@ static int pkey_rsa_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2)
 			if (p1 == RSA_PKCS1_PSS_PADDING) 
 				{
 				if (!(ctx->operation &
-				     (EVP_PKEY_OP_SIGN | EVP_PKEY_OP_VERIFY)))
+				     (EVP_PKEY_OP_SIGN | EVP_PKEY_OP_VERIFY |
+						EVP_PKEY_OP_SIGNCTX | EVP_PKEY_OP_VERIFYCTX)))
 					goto bad_pad;
 				if (!rctx->md)
 					rctx->md = EVP_sha1();
@@ -433,6 +450,38 @@ static int pkey_rsa_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2)
 		rctx->md = p2;
 		return 1;
 
+      case EVP_PKEY_CTRL_PARAM_SET_FROM_PKEY:
+		if (p2)
+			{
+			EVP_PKEY *pkey = (EVP_PKEY *)p2;
+			if (pkey->type!=EVP_PKEY_RSA)
+				return -2;
+         if (!rctx->pad_mode == RSA_PKCS1_PSS_PADDING)
+            return 0;
+			if (!pkey->pkey.rsa->pssDigest)
+				return 0;
+			rctx->md = pkey->pkey.rsa->pssDigest;
+			rctx->saltlen = pkey->pkey.rsa->pssSaltlen;
+			return 1;
+			}
+		else
+			return -2;
+
+		case EVP_PKEY_CTRL_GET_DIGEST:
+		if (p2)
+			{
+			EVP_MD **md = (EVP_MD **)p2;
+			if (rctx->pad_mode == RSA_PKCS1_PSS_PADDING && rctx->md)
+				{
+				*md = (EVP_MD *)rctx->md;
+				return 1;
+				}
+			else
+				return 0;
+			}
+			else
+				return -2;
+
 		case EVP_PKEY_CTRL_DIGESTINIT:
 		case EVP_PKEY_CTRL_PKCS7_ENCRYPT:
 		case EVP_PKEY_CTRL_PKCS7_DECRYPT:
@@ -567,8 +616,9 @@ const EVP_PKEY_METHOD rsa_pkey_meth =
 	0,
 	pkey_rsa_verifyrecover,
 
-
-	0,0,0,0,
+	0,0,
+	pkey_rsa_verifyctx_init,
+   0,
 
 	0,
 	pkey_rsa_encrypt,

Reply via email to