RSA PSS verification support including certificates and certificate
authorDr. Stephen Henson <steve@openssl.org>
Mon, 8 Mar 2010 18:10:35 +0000 (18:10 +0000)
committerDr. Stephen Henson <steve@openssl.org>
Mon, 8 Mar 2010 18:10:35 +0000 (18:10 +0000)
requests. Add new ASN1 signature initialisation function to handle this
case.

CHANGES
crypto/asn1/a_verify.c
crypto/asn1/asn1.h
crypto/asn1/asn1_locl.h
crypto/ossl_typ.h
crypto/rsa/rsa.h
crypto/rsa/rsa_ameth.c
crypto/rsa/rsa_err.c
crypto/rsa/rsa_pmeth.c

diff --git a/CHANGES b/CHANGES
index b970097..674a2f1 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -4,7 +4,14 @@
 
  Changes between 1.0.0 and 1.1.0  [xx XXX xxxx]
 
-   *) Add signature printing for PSS. Add PSS OIDs.
+  *) Add new algorithm specific ASN1 verification initialisation function
+     to EVP_PKEY_ASN1_METHOD: this is not in EVP_PKEY_METHOD since the ASN1
+     handling will be the same no matter what EVP_PKEY_METHOD is used.
+     Add a PSS handler to support verification of PSS signatures: checked
+     against a number of sample certificates.
+     [Steve Henson]
+
+  *) Add signature printing for PSS. Add PSS OIDs.
      [Steve Henson, Martin Kaiser <lists@kaiser.cx>]
 
   *) Add algorithm specific signature printing. An individual ASN1 method
index a914425..432722e 100644 (file)
@@ -131,11 +131,10 @@ err:
 #endif
 
 
-int ASN1_item_verify(const ASN1_ITEM *it, X509_ALGOR *a, ASN1_BIT_STRING *signature,
-            void *asn, EVP_PKEY *pkey)
+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;
        unsigned char *buf_in=NULL;
        int ret= -1,inl;
 
@@ -149,25 +148,47 @@ 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)
+       if (mdnid == NID_undef)
                {
-               ASN1err(ASN1_F_ASN1_ITEM_VERIFY,ASN1_R_UNKNOWN_MESSAGE_DIGEST_ALGORITHM);
-               goto err;
+               if (!pkey->ameth || !pkey->ameth->item_verify)
+                       {
+                       ASN1err(ASN1_F_ASN1_ITEM_VERIFY,ASN1_R_UNKNOWN_SIGNATURE_ALGORITHM);
+                       goto err;
+                       }
+               ret = pkey->ameth->item_verify(&ctx, it, asn, a,
+                                                       signature, pkey);
+               /* Return value of 2 means carry on, anything else means we
+                * exit straight away: either a fatal error of the underlying
+                * verification routine handles all verification.
+                */
+               if (ret != 2)
+                       goto err;
+               ret = -1;
                }
-
-       /* Check public key OID matches public key type */
-       if (EVP_PKEY_type(pknid) != pkey->ameth->pkey_id)
+       else
                {
-               ASN1err(ASN1_F_ASN1_ITEM_VERIFY,ASN1_R_WRONG_PUBLIC_KEY_TYPE);
-               goto err;
-               }
+               const EVP_MD *type;
+               type=EVP_get_digestbynid(mdnid);
+               if (type == NULL)
+                       {
+                       ASN1err(ASN1_F_ASN1_ITEM_VERIFY,ASN1_R_UNKNOWN_MESSAGE_DIGEST_ALGORITHM);
+                       goto err;
+                       }
+
+               /* Check public key OID matches public key type */
+               if (EVP_PKEY_type(pknid) != pkey->ameth->pkey_id)
+                       {
+                       ASN1err(ASN1_F_ASN1_ITEM_VERIFY,ASN1_R_WRONG_PUBLIC_KEY_TYPE);
+                       goto err;
+                       }
+
+               if (!EVP_DigestVerifyInit(&ctx, NULL, type, NULL, pkey))
+                       {
+                       ASN1err(ASN1_F_ASN1_ITEM_VERIFY,ERR_R_EVP_LIB);
+                       ret=0;
+                       goto err;
+                       }
 
-       if (!EVP_DigestVerifyInit(&ctx, NULL, type, NULL, pkey))
-               {
-               ASN1err(ASN1_F_ASN1_ITEM_VERIFY,ERR_R_EVP_LIB);
-               ret=0;
-               goto err;
                }
 
        inl = ASN1_item_i2d(asn, &buf_in, it);
index 6c94696..a074318 100644 (file)
@@ -293,7 +293,6 @@ DECLARE_STACK_OF(ASN1_STRING_TABLE)
  * see asn1t.h
  */
 typedef struct ASN1_TEMPLATE_st ASN1_TEMPLATE;
-typedef struct ASN1_ITEM_st ASN1_ITEM;
 typedef struct ASN1_TLC_st ASN1_TLC;
 /* This is just an opaque pointer */
 typedef struct ASN1_VALUE_st ASN1_VALUE;
index 6f37810..ceb3b4e 100644 (file)
@@ -106,6 +106,7 @@ struct evp_pkey_asn1_method_st
                         const X509_ALGOR *sigalg, const ASN1_STRING *sig,
                                         int indent, ASN1_PCTX *pctx);
 
+
        void (*pkey_free)(EVP_PKEY *pkey);
        int (*pkey_ctrl)(EVP_PKEY *pkey, int op, long arg1, void *arg2);
 
@@ -114,6 +115,10 @@ struct evp_pkey_asn1_method_st
        int (*old_priv_decode)(EVP_PKEY *pkey,
                                const unsigned char **pder, int derlen);
        int (*old_priv_encode)(const EVP_PKEY *pkey, unsigned char **pder);
+       /* Custom ASN1 signature verification */
+       int (*item_verify)(EVP_MD_CTX *ctx, const ASN1_ITEM *it, void *asn,
+                               X509_ALGOR *a, ASN1_BIT_STRING *sig,
+                               EVP_PKEY *pkey);
 
        } /* EVP_PKEY_ASN1_METHOD */;
 
index 23447e8..ea9227f 100644 (file)
@@ -96,6 +96,7 @@ typedef int ASN1_BOOLEAN;
 typedef int ASN1_NULL;
 #endif
 
+typedef struct ASN1_ITEM_st ASN1_ITEM;
 typedef struct asn1_pctx_st ASN1_PCTX;
 
 #ifdef OPENSSL_SYS_WIN32
index 06cda22..8cb737d 100644 (file)
@@ -236,12 +236,16 @@ struct rsa_st
        EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, 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, -1, EVP_PKEY_OP_TYPE_SIG,  \
+                               EVP_PKEY_CTRL_RSA_MGF1_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)
 
 #define EVP_PKEY_CTRL_RSA_KEYGEN_BITS  (EVP_PKEY_ALG_CTRL + 3)
 #define EVP_PKEY_CTRL_RSA_KEYGEN_PUBEXP        (EVP_PKEY_ALG_CTRL + 4)
-#define EVP_PKEY_CTRL_MGF1_MD          (EVP_PKEY_ALG_CTRL + 5)
+#define EVP_PKEY_CTRL_RSA_MGF1_MD      (EVP_PKEY_ALG_CTRL + 5)
 
 #define RSA_PKCS1_PADDING      1
 #define RSA_SSLV23_PADDING     2
@@ -424,6 +428,7 @@ void ERR_load_RSA_strings(void);
 #define RSA_F_RSA_EAY_PUBLIC_DECRYPT                    103
 #define RSA_F_RSA_EAY_PUBLIC_ENCRYPT                    104
 #define RSA_F_RSA_GENERATE_KEY                          105
+#define RSA_F_RSA_ITEM_VERIFY                           148
 #define RSA_F_RSA_MEMORY_LOCK                           130
 #define RSA_F_RSA_NEW_METHOD                            106
 #define RSA_F_RSA_NULL                                  124
@@ -483,7 +488,9 @@ void ERR_load_RSA_strings(void);
 #define RSA_R_INVALID_MESSAGE_LENGTH                    131
 #define RSA_R_INVALID_PADDING                           138
 #define RSA_R_INVALID_PADDING_MODE                      141
+#define RSA_R_INVALID_PSS_PARAMETERS                    149
 #define RSA_R_INVALID_PSS_SALTLEN                       146
+#define RSA_R_INVALID_SALT_LENGTH                       150
 #define RSA_R_INVALID_TRAILER                           139
 #define RSA_R_INVALID_X931_DIGEST                       142
 #define RSA_R_IQMP_NOT_INVERSE_OF_Q                     126
@@ -504,7 +511,12 @@ 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_MASK_DIGEST                       151
 #define RSA_R_UNKNOWN_PADDING_TYPE                      118
+#define RSA_R_UNKNOWN_PSS_DIGEST                        152
+#define RSA_R_UNSUPPORTED_MASK_ALGORITHM                153
+#define RSA_R_UNSUPPORTED_MASK_PARAMETER                154
+#define RSA_R_UNSUPPORTED_SIGNATURE_TYPE                155
 #define RSA_R_VALUE_MISSING                             147
 #define RSA_R_WRONG_SIGNATURE_LENGTH                    119
 
index 2ec302c..4e1dcfb 100644 (file)
@@ -449,6 +449,109 @@ static int rsa_pkey_ctrl(EVP_PKEY *pkey, int op, long arg1, void *arg2)
 
        }
 
+/* Customised RSA item verification routine. This is called 
+ * when a signature is encountered requiring special handling. We 
+ * currently only handle PSS.
+ */
+
+
+static int rsa_item_verify(EVP_MD_CTX *ctx, const ASN1_ITEM *it, void *asn,
+                       X509_ALGOR *sigalg, ASN1_BIT_STRING *sig,
+                       EVP_PKEY *pkey)
+       {
+       int rv = -1;
+       int saltlen;
+       const EVP_MD *mgf1md = NULL, *md = NULL;
+       RSA_PSS_PARAMS *pss;
+       X509_ALGOR *maskHash;
+       EVP_PKEY_CTX *pkctx;
+       /* Sanity check: make sure it is PSS */
+       if (OBJ_obj2nid(sigalg->algorithm) != NID_rsassaPss)
+               {
+               RSAerr(RSA_F_RSA_ITEM_VERIFY, RSA_R_UNSUPPORTED_SIGNATURE_TYPE);
+               return -1;
+               }
+       /* Decode PSS parameters */
+       pss = rsa_pss_decode(sigalg, &maskHash);
+
+       if (pss == NULL)
+               {
+               RSAerr(RSA_F_RSA_ITEM_VERIFY, RSA_R_INVALID_PSS_PARAMETERS);
+               goto err;
+               }
+       /* Check mask and lookup mask hash algorithm */
+       if (pss->maskGenAlgorithm)
+               {
+               if (OBJ_obj2nid(pss->maskGenAlgorithm->algorithm) != NID_mgf1)
+                       {
+                       RSAerr(RSA_F_RSA_ITEM_VERIFY, RSA_R_UNSUPPORTED_MASK_ALGORITHM);
+                       goto err;
+                       }
+               if (!maskHash)
+                       {
+                       RSAerr(RSA_F_RSA_ITEM_VERIFY, RSA_R_UNSUPPORTED_MASK_PARAMETER);
+                       goto err;
+                       }
+               mgf1md = EVP_get_digestbyobj(maskHash->algorithm);
+               if (mgf1md == NULL)
+                       {
+                       RSAerr(RSA_F_RSA_ITEM_VERIFY, RSA_R_UNKNOWN_MASK_DIGEST);
+                       goto err;
+                       }
+               }
+       else
+               mgf1md = EVP_sha1();
+
+       if (pss->hashAlgorithm)
+               {
+               md = EVP_get_digestbyobj(maskHash->algorithm);
+               if (md == NULL)
+                       {
+                       RSAerr(RSA_F_RSA_ITEM_VERIFY, RSA_R_UNKNOWN_PSS_DIGEST);
+                       goto err;
+                       }
+               }
+       else
+               md = EVP_sha1();
+
+       if (pss->saltLength)
+               {
+               saltlen = ASN1_INTEGER_get(pss->saltLength);
+
+               /* Could perform more salt length sanity checks but the main
+                * RSA routines will trap other invalid values anyway.
+                */
+               if (saltlen < 0)
+                       {
+                       RSAerr(RSA_F_RSA_ITEM_VERIFY, RSA_R_INVALID_SALT_LENGTH);
+                       goto err;
+                       }
+               }
+       else
+               saltlen = 20;
+
+       /* We have all parameters now set up context */
+
+       if (!EVP_DigestVerifyInit(ctx, &pkctx, md, NULL, pkey))
+               goto err;
+
+       if (!EVP_PKEY_CTX_set_rsa_padding(pkctx, RSA_PKCS1_PSS_PADDING))
+               goto err;
+
+       if (!EVP_PKEY_CTX_set_rsa_pss_saltlen(pkctx, saltlen))
+               goto err;
+
+       if (!EVP_PKEY_CTX_set_rsa_mgf1_md(pkctx, mgf1md))
+               goto err;
+       /* Carry on */
+       rv = 2;
+
+       err:
+       RSA_PSS_PARAMS_free(pss);
+       if (maskHash)
+               X509_ALGOR_free(maskHash);
+       return rv;
+       }
 
 const EVP_PKEY_ASN1_METHOD rsa_asn1_meths[] = 
        {
@@ -478,7 +581,8 @@ const EVP_PKEY_ASN1_METHOD rsa_asn1_meths[] =
                int_rsa_free,
                rsa_pkey_ctrl,
                old_rsa_priv_decode,
-               old_rsa_priv_encode
+               old_rsa_priv_encode,
+               rsa_item_verify
                },
 
                {
index cf9f110..32f3560 100644 (file)
@@ -1,6 +1,6 @@
 /* crypto/rsa/rsa_err.c */
 /* ====================================================================
- * Copyright (c) 1999-2008 The OpenSSL Project.  All rights reserved.
+ * Copyright (c) 1999-2010 The OpenSSL Project.  All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -86,6 +86,7 @@ static ERR_STRING_DATA RSA_str_functs[]=
 {ERR_FUNC(RSA_F_RSA_EAY_PUBLIC_DECRYPT),       "RSA_EAY_PUBLIC_DECRYPT"},
 {ERR_FUNC(RSA_F_RSA_EAY_PUBLIC_ENCRYPT),       "RSA_EAY_PUBLIC_ENCRYPT"},
 {ERR_FUNC(RSA_F_RSA_GENERATE_KEY),     "RSA_generate_key"},
+{ERR_FUNC(RSA_F_RSA_ITEM_VERIFY),      "RSA_ITEM_VERIFY"},
 {ERR_FUNC(RSA_F_RSA_MEMORY_LOCK),      "RSA_memory_lock"},
 {ERR_FUNC(RSA_F_RSA_NEW_METHOD),       "RSA_new_method"},
 {ERR_FUNC(RSA_F_RSA_NULL),     "RSA_NULL"},
@@ -148,7 +149,9 @@ static ERR_STRING_DATA RSA_str_reasons[]=
 {ERR_REASON(RSA_R_INVALID_MESSAGE_LENGTH),"invalid message length"},
 {ERR_REASON(RSA_R_INVALID_PADDING)       ,"invalid padding"},
 {ERR_REASON(RSA_R_INVALID_PADDING_MODE)  ,"invalid padding mode"},
+{ERR_REASON(RSA_R_INVALID_PSS_PARAMETERS),"invalid pss parameters"},
 {ERR_REASON(RSA_R_INVALID_PSS_SALTLEN)   ,"invalid pss saltlen"},
+{ERR_REASON(RSA_R_INVALID_SALT_LENGTH)   ,"invalid salt length"},
 {ERR_REASON(RSA_R_INVALID_TRAILER)       ,"invalid trailer"},
 {ERR_REASON(RSA_R_INVALID_X931_DIGEST)   ,"invalid x931 digest"},
 {ERR_REASON(RSA_R_IQMP_NOT_INVERSE_OF_Q) ,"iqmp not inverse of q"},
@@ -169,7 +172,12 @@ 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_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"},
+{ERR_REASON(RSA_R_UNSUPPORTED_MASK_ALGORITHM),"unsupported mask algorithm"},
+{ERR_REASON(RSA_R_UNSUPPORTED_MASK_PARAMETER),"unsupported mask parameter"},
+{ERR_REASON(RSA_R_UNSUPPORTED_SIGNATURE_TYPE),"unsupported signature type"},
 {ERR_REASON(RSA_R_VALUE_MISSING)         ,"value missing"},
 {ERR_REASON(RSA_R_WRONG_SIGNATURE_LENGTH),"wrong signature length"},
 {0,NULL}
index 6bfacda..1c34e13 100644 (file)
@@ -444,7 +444,7 @@ static int pkey_rsa_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2)
                rctx->md = p2;
                return 1;
 
-               case EVP_PKEY_CTRL_MGF1_MD:
+               case EVP_PKEY_CTRL_RSA_MGF1_MD:
                rctx->mgf1md = p2;
                return 1;