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,