RSA PSS verification support including certificates and certificate

requests. Add new ASN1 signature initialisation function to handle this
case.
This commit is contained in:
Dr. Stephen Henson 2010-03-08 18:10:35 +00:00
parent a4d9c12f99
commit 31904ecdf3
9 changed files with 181 additions and 24 deletions

View File

@ -4,6 +4,13 @@
Changes between 1.0.0 and 1.1.0 [xx XXX xxxx] Changes between 1.0.0 and 1.1.0 [xx XXX xxxx]
*) 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. *) Add signature printing for PSS. Add PSS OIDs.
[Steve Henson, Martin Kaiser <lists@kaiser.cx>] [Steve Henson, Martin Kaiser <lists@kaiser.cx>]

View File

@ -131,11 +131,10 @@ err:
#endif #endif
int ASN1_item_verify(const ASN1_ITEM *it, X509_ALGOR *a, ASN1_BIT_STRING *signature, int ASN1_item_verify(const ASN1_ITEM *it, X509_ALGOR *a,
void *asn, EVP_PKEY *pkey) ASN1_BIT_STRING *signature, void *asn, EVP_PKEY *pkey)
{ {
EVP_MD_CTX ctx; EVP_MD_CTX ctx;
const EVP_MD *type = NULL;
unsigned char *buf_in=NULL; unsigned char *buf_in=NULL;
int ret= -1,inl; int ret= -1,inl;
@ -149,6 +148,26 @@ 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); ASN1err(ASN1_F_ASN1_ITEM_VERIFY,ASN1_R_UNKNOWN_SIGNATURE_ALGORITHM);
goto err; goto err;
} }
if (mdnid == NID_undef)
{
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;
}
else
{
const EVP_MD *type;
type=EVP_get_digestbynid(mdnid); type=EVP_get_digestbynid(mdnid);
if (type == NULL) if (type == NULL)
{ {
@ -170,6 +189,8 @@ int ASN1_item_verify(const ASN1_ITEM *it, X509_ALGOR *a, ASN1_BIT_STRING *signat
goto err; goto err;
} }
}
inl = ASN1_item_i2d(asn, &buf_in, it); inl = ASN1_item_i2d(asn, &buf_in, it);
if (buf_in == NULL) if (buf_in == NULL)

View File

@ -293,7 +293,6 @@ DECLARE_STACK_OF(ASN1_STRING_TABLE)
* see asn1t.h * see asn1t.h
*/ */
typedef struct ASN1_TEMPLATE_st ASN1_TEMPLATE; typedef struct ASN1_TEMPLATE_st ASN1_TEMPLATE;
typedef struct ASN1_ITEM_st ASN1_ITEM;
typedef struct ASN1_TLC_st ASN1_TLC; typedef struct ASN1_TLC_st ASN1_TLC;
/* This is just an opaque pointer */ /* This is just an opaque pointer */
typedef struct ASN1_VALUE_st ASN1_VALUE; typedef struct ASN1_VALUE_st ASN1_VALUE;

View File

@ -106,6 +106,7 @@ struct evp_pkey_asn1_method_st
const X509_ALGOR *sigalg, const ASN1_STRING *sig, const X509_ALGOR *sigalg, const ASN1_STRING *sig,
int indent, ASN1_PCTX *pctx); int indent, ASN1_PCTX *pctx);
void (*pkey_free)(EVP_PKEY *pkey); void (*pkey_free)(EVP_PKEY *pkey);
int (*pkey_ctrl)(EVP_PKEY *pkey, int op, long arg1, void *arg2); 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, int (*old_priv_decode)(EVP_PKEY *pkey,
const unsigned char **pder, int derlen); const unsigned char **pder, int derlen);
int (*old_priv_encode)(const EVP_PKEY *pkey, unsigned char **pder); 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 */; } /* EVP_PKEY_ASN1_METHOD */;

View File

@ -96,6 +96,7 @@ typedef int ASN1_BOOLEAN;
typedef int ASN1_NULL; typedef int ASN1_NULL;
#endif #endif
typedef struct ASN1_ITEM_st ASN1_ITEM;
typedef struct asn1_pctx_st ASN1_PCTX; typedef struct asn1_pctx_st ASN1_PCTX;
#ifdef OPENSSL_SYS_WIN32 #ifdef OPENSSL_SYS_WIN32

View File

@ -236,12 +236,16 @@ struct rsa_st
EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, EVP_PKEY_OP_KEYGEN, \ EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, EVP_PKEY_OP_KEYGEN, \
EVP_PKEY_CTRL_RSA_KEYGEN_PUBEXP, 0, pubexp) 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_PADDING (EVP_PKEY_ALG_CTRL + 1)
#define EVP_PKEY_CTRL_RSA_PSS_SALTLEN (EVP_PKEY_ALG_CTRL + 2) #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_BITS (EVP_PKEY_ALG_CTRL + 3)
#define EVP_PKEY_CTRL_RSA_KEYGEN_PUBEXP (EVP_PKEY_ALG_CTRL + 4) #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_PKCS1_PADDING 1
#define RSA_SSLV23_PADDING 2 #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_DECRYPT 103
#define RSA_F_RSA_EAY_PUBLIC_ENCRYPT 104 #define RSA_F_RSA_EAY_PUBLIC_ENCRYPT 104
#define RSA_F_RSA_GENERATE_KEY 105 #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_MEMORY_LOCK 130
#define RSA_F_RSA_NEW_METHOD 106 #define RSA_F_RSA_NEW_METHOD 106
#define RSA_F_RSA_NULL 124 #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_MESSAGE_LENGTH 131
#define RSA_R_INVALID_PADDING 138 #define RSA_R_INVALID_PADDING 138
#define RSA_R_INVALID_PADDING_MODE 141 #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_PSS_SALTLEN 146
#define RSA_R_INVALID_SALT_LENGTH 150
#define RSA_R_INVALID_TRAILER 139 #define RSA_R_INVALID_TRAILER 139
#define RSA_R_INVALID_X931_DIGEST 142 #define RSA_R_INVALID_X931_DIGEST 142
#define RSA_R_IQMP_NOT_INVERSE_OF_Q 126 #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_SSLV3_ROLLBACK_ATTACK 115
#define RSA_R_THE_ASN1_OBJECT_IDENTIFIER_IS_NOT_KNOWN_FOR_THIS_MD 116 #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_ALGORITHM_TYPE 117
#define RSA_R_UNKNOWN_MASK_DIGEST 151
#define RSA_R_UNKNOWN_PADDING_TYPE 118 #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_VALUE_MISSING 147
#define RSA_R_WRONG_SIGNATURE_LENGTH 119 #define RSA_R_WRONG_SIGNATURE_LENGTH 119

View 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[] = const EVP_PKEY_ASN1_METHOD rsa_asn1_meths[] =
{ {
@ -478,7 +581,8 @@ const EVP_PKEY_ASN1_METHOD rsa_asn1_meths[] =
int_rsa_free, int_rsa_free,
rsa_pkey_ctrl, rsa_pkey_ctrl,
old_rsa_priv_decode, old_rsa_priv_decode,
old_rsa_priv_encode old_rsa_priv_encode,
rsa_item_verify
}, },
{ {

View File

@ -1,6 +1,6 @@
/* crypto/rsa/rsa_err.c */ /* 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 * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions * 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_DECRYPT), "RSA_EAY_PUBLIC_DECRYPT"},
{ERR_FUNC(RSA_F_RSA_EAY_PUBLIC_ENCRYPT), "RSA_EAY_PUBLIC_ENCRYPT"}, {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_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_MEMORY_LOCK), "RSA_memory_lock"},
{ERR_FUNC(RSA_F_RSA_NEW_METHOD), "RSA_new_method"}, {ERR_FUNC(RSA_F_RSA_NEW_METHOD), "RSA_new_method"},
{ERR_FUNC(RSA_F_RSA_NULL), "RSA_NULL"}, {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_MESSAGE_LENGTH),"invalid message length"},
{ERR_REASON(RSA_R_INVALID_PADDING) ,"invalid padding"}, {ERR_REASON(RSA_R_INVALID_PADDING) ,"invalid padding"},
{ERR_REASON(RSA_R_INVALID_PADDING_MODE) ,"invalid padding mode"}, {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_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_TRAILER) ,"invalid trailer"},
{ERR_REASON(RSA_R_INVALID_X931_DIGEST) ,"invalid x931 digest"}, {ERR_REASON(RSA_R_INVALID_X931_DIGEST) ,"invalid x931 digest"},
{ERR_REASON(RSA_R_IQMP_NOT_INVERSE_OF_Q) ,"iqmp not inverse of q"}, {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_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_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_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_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_VALUE_MISSING) ,"value missing"},
{ERR_REASON(RSA_R_WRONG_SIGNATURE_LENGTH),"wrong signature length"}, {ERR_REASON(RSA_R_WRONG_SIGNATURE_LENGTH),"wrong signature length"},
{0,NULL} {0,NULL}

View File

@ -444,7 +444,7 @@ static int pkey_rsa_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2)
rctx->md = p2; rctx->md = p2;
return 1; return 1;
case EVP_PKEY_CTRL_MGF1_MD: case EVP_PKEY_CTRL_RSA_MGF1_MD:
rctx->mgf1md = p2; rctx->mgf1md = p2;
return 1; return 1;