summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDr. Stephen Henson <steve@openssl.org>2010-03-08 18:10:35 +0000
committerDr. Stephen Henson <steve@openssl.org>2010-03-08 18:10:35 +0000
commit31904ecdf3f1c613d1377dfe79c0413672de7762 (patch)
tree077a3207b9061b294925cde3495c30534d2dd0b0
parenta4d9c12f998d2260bf637d9964b53c28a191b173 (diff)
RSA PSS verification support including certificates and certificate
requests. Add new ASN1 signature initialisation function to handle this case.
-rw-r--r--CHANGES9
-rw-r--r--crypto/asn1/a_verify.c57
-rw-r--r--crypto/asn1/asn1.h1
-rw-r--r--crypto/asn1/asn1_locl.h5
-rw-r--r--crypto/ossl_typ.h1
-rw-r--r--crypto/rsa/rsa.h14
-rw-r--r--crypto/rsa/rsa_ameth.c106
-rw-r--r--crypto/rsa/rsa_err.c10
-rw-r--r--crypto/rsa/rsa_pmeth.c2
9 files changed, 181 insertions, 24 deletions
diff --git a/CHANGES b/CHANGES
index b9700972a6..674a2f1849 100644
--- 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
diff --git a/crypto/asn1/a_verify.c b/crypto/asn1/a_verify.c
index a9144251d1..432722e409 100644
--- a/crypto/asn1/a_verify.c
+++ b/crypto/asn1/a_verify.c
@@ -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);
diff --git a/crypto/asn1/asn1.h b/crypto/asn1/asn1.h
index 6c94696ae8..a074318101 100644
--- a/crypto/asn1/asn1.h
+++ b/crypto/asn1/asn1.h
@@ -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;
diff --git a/crypto/asn1/asn1_locl.h b/crypto/asn1/asn1_locl.h
index 6f3781045d..ceb3b4ed84 100644
--- a/crypto/asn1/asn1_locl.h
+++ b/crypto/asn1/asn1_locl.h
@@ -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 */;
diff --git a/crypto/ossl_typ.h b/crypto/ossl_typ.h
index 23447e8284..ea9227f6f9 100644
--- a/crypto/ossl_typ.h
+++ b/crypto/ossl_typ.h
@@ -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
diff --git a/crypto/rsa/rsa.h b/crypto/rsa/rsa.h
index 06cda223c7..8cb737d4b1 100644
--- a/crypto/rsa/rsa.h
+++ b/crypto/rsa/rsa.h
@@ -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
diff --git a/crypto/rsa/rsa_ameth.c b/crypto/rsa/rsa_ameth.c
index 2ec302c560..4e1dcfb3c3 100644
--- a/crypto/rsa/rsa_ameth.c
+++ b/crypto/rsa/rsa_ameth.c
@@ -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
},
{
diff --git a/crypto/rsa/rsa_err.c b/crypto/rsa/rsa_err.c
index cf9f1106b0..32f356069f 100644
--- a/crypto/rsa/rsa_err.c
+++ b/crypto/rsa/rsa_err.c
@@ -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}
diff --git a/crypto/rsa/rsa_pmeth.c b/crypto/rsa/rsa_pmeth.c
index 6bfacdae0b..1c34e13f43 100644
--- a/crypto/rsa/rsa_pmeth.c
+++ b/crypto/rsa/rsa_pmeth.c
@@ -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;