diff --git a/CHANGES b/CHANGES index b59f8621f..60551db8e 100644 --- a/CHANGES +++ b/CHANGES @@ -8,6 +8,8 @@ *) 修复CVE-2023-6237 + *) 修复CVE-2024-0727 + *) 增加SM2两方门限解密算法 *) 增加SM2两方门限签名算法 [with work originated from FullyRobert] diff --git a/apps/openssl.cnf b/apps/openssl.cnf index e58082c8a..05faefadf 100644 --- a/apps/openssl.cnf +++ b/apps/openssl.cnf @@ -399,3 +399,10 @@ oldcert = $insta::certout # insta.cert.pem # Certificate revocation cmd = rr oldcert = $insta::certout # insta.cert.pem + +[pkcs12] +certBagAttr = cb_attr + +# Uncomment this if you need Java compatible PKCS12 files +[cb_attr] +#jdkTrustedKeyUsage = anyExtendedKeyUsage diff --git a/apps/pkcs12.c b/apps/pkcs12.c index 8ad93d36a..257dda403 100644 --- a/apps/pkcs12.c +++ b/apps/pkcs12.c @@ -14,6 +14,8 @@ #include #include "apps.h" #include "progs.h" +#include +#include #include #include #include @@ -53,6 +55,7 @@ void hex_prin(BIO *out, unsigned char *buf, int len); static int alg_print(const X509_ALGOR *alg); int cert_load(BIO *in, STACK_OF(X509) *sk); static int set_pbe(int *ppbe, const char *str); +static int jdk_trust(PKCS12_SAFEBAG *bag, void *cbarg); typedef enum OPTION_choice { OPT_COMMON, @@ -512,6 +515,11 @@ int pkcs12_main(int argc, char **argv) EVP_MD *macmd = NULL; unsigned char *catmp = NULL; int i; + CONF *conf = NULL; + ASN1_OBJECT *obj = NULL; + STACK_OF(CONF_VALUE) *cb_sk = NULL; + const char *cb_attr = NULL; + const CONF_VALUE *val = NULL; if ((options & (NOCERTS | NOKEYS)) == (NOCERTS | NOKEYS)) { BIO_printf(bio_err, "Nothing to export due to -noout or -nocerts and -nokeys\n"); @@ -656,9 +664,30 @@ int pkcs12_main(int argc, char **argv) if (!twopass) OPENSSL_strlcpy(macpass, pass, sizeof(macpass)); - p12 = PKCS12_create_ex(cpass, name, key, ee_cert, certs, - key_pbe, cert_pbe, iter, -1, keytype, - app_get0_libctx(), app_get0_propq()); + /* Load the config file */ + if ((conf = app_load_config(default_config_file)) == NULL) + goto export_end; + if (!app_load_modules(conf)) + goto export_end; + /* Find the cert bag section */ + if ((cb_attr = NCONF_get_string(conf, "pkcs12", "certBagAttr")) != NULL) { + if ((cb_sk = NCONF_get_section(conf, cb_attr)) != NULL) { + for (i = 0; i < sk_CONF_VALUE_num(cb_sk); i++) { + val = sk_CONF_VALUE_value(cb_sk, i); + if (strcmp(val->name, "jdkTrustedKeyUsage") == 0) + obj = OBJ_txt2obj(val->value, 0); + } + } else { + ERR_clear_error(); + } + } else { + ERR_clear_error(); + } + + p12 = PKCS12_create_ex2(cpass, name, key, ee_cert, certs, + key_pbe, cert_pbe, iter, -1, keytype, + app_get0_libctx(), app_get0_propq(), + jdk_trust, (void*)obj); if (p12 == NULL) { BIO_printf(bio_err, "Error creating PKCS12 structure for %s\n", @@ -695,7 +724,8 @@ int pkcs12_main(int argc, char **argv) sk_X509_pop_free(certs, X509_free); sk_X509_pop_free(untrusted_certs, X509_free); X509_free(ee_cert); - + NCONF_free(conf); + ASN1_OBJECT_free(obj); ERR_print_errors(bio_err); goto end; @@ -825,6 +855,31 @@ int pkcs12_main(int argc, char **argv) return ret; } +static int jdk_trust(PKCS12_SAFEBAG *bag, void *cbarg) +{ + STACK_OF(X509_ATTRIBUTE) *attrs = NULL; + X509_ATTRIBUTE *attr = NULL; + + /* Nothing to do */ + if (cbarg == NULL) + return 1; + + /* Get the current attrs */ + attrs = (STACK_OF(X509_ATTRIBUTE)*)PKCS12_SAFEBAG_get0_attrs(bag); + + /* Create a new attr for the JDK Trusted Usage and add it */ + attr = X509_ATTRIBUTE_create(NID_oracle_jdk_trustedkeyusage, V_ASN1_OBJECT, (ASN1_OBJECT*)cbarg); + + /* Add the new attr, if attrs is NULL, it'll be initialised */ + X509at_add1_attr(&attrs, attr); + + /* Set the bag attrs */ + PKCS12_SAFEBAG_set0_attrs(bag, attrs); + + X509_ATTRIBUTE_free(attr); + return 1; +} + int dump_certs_keys_p12(BIO *out, const PKCS12 *p12, const char *pass, int passlen, int options, char *pempass, const EVP_CIPHER *enc) @@ -1124,6 +1179,8 @@ int cert_load(BIO *in, STACK_OF(X509) *sk) void print_attribute(BIO *out, const ASN1_TYPE *av) { char *value; + const char *ln; + char objbuf[80]; switch (av->type) { case V_ASN1_BMPSTRING: @@ -1150,6 +1207,15 @@ void print_attribute(BIO *out, const ASN1_TYPE *av) BIO_printf(out, "\n"); break; + case V_ASN1_OBJECT: + ln = OBJ_nid2ln(OBJ_obj2nid(av->value.object)); + if (!ln) + ln = ""; + OBJ_obj2txt(objbuf, sizeof(objbuf), av->value.object, 1); + BIO_printf(out, "%s (%s)", ln, objbuf); + BIO_printf(out, "\n"); + break; + default: BIO_printf(out, "\n", av->type); break; diff --git a/crypto/asn1/asn_pack.c b/crypto/asn1/asn_pack.c index 292e6d817..bdddc7ccb 100644 --- a/crypto/asn1/asn_pack.c +++ b/crypto/asn1/asn_pack.c @@ -60,3 +60,16 @@ void *ASN1_item_unpack(const ASN1_STRING *oct, const ASN1_ITEM *it) ERR_raise(ERR_LIB_ASN1, ASN1_R_DECODE_ERROR); return ret; } + +void *ASN1_item_unpack_ex(const ASN1_STRING *oct, const ASN1_ITEM *it, + OSSL_LIB_CTX *libctx, const char *propq) +{ + const unsigned char *p; + void *ret; + + p = oct->data; + if ((ret = ASN1_item_d2i_ex(NULL, &p, oct->length, it,\ + libctx, propq)) == NULL) + ERR_raise(ERR_LIB_ASN1, ASN1_R_DECODE_ERROR); + return ret; +} diff --git a/crypto/err/openssl.txt b/crypto/err/openssl.txt index bfe7a985e..bd9bd818d 100644 --- a/crypto/err/openssl.txt +++ b/crypto/err/openssl.txt @@ -888,6 +888,7 @@ PEM_R_UNSUPPORTED_CIPHER:113:unsupported cipher PEM_R_UNSUPPORTED_ENCRYPTION:114:unsupported encryption PEM_R_UNSUPPORTED_KEY_COMPONENTS:126:unsupported key components PEM_R_UNSUPPORTED_PUBLIC_KEY_TYPE:110:unsupported public key type +PKCS12_R_CALLBACK_FAILED:115:callback failed PKCS12_R_CANT_PACK_STRUCTURE:100:cant pack structure PKCS12_R_CONTENT_TYPE_NOT_DATA:121:content type not data PKCS12_R_DECODE_ERROR:101:decode error diff --git a/crypto/objects/obj_dat.h b/crypto/objects/obj_dat.h index 16bf5d227..0228fd0b7 100644 --- a/crypto/objects/obj_dat.h +++ b/crypto/objects/obj_dat.h @@ -2,7 +2,7 @@ * WARNING: do not edit! * Generated by crypto/objects/obj_dat.pl * - * Copyright 1995-2022 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2024 The OpenSSL Project Authors. All Rights Reserved. * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy * in the file LICENSE in the source distribution or at @@ -10,7 +10,7 @@ */ /* Serialized OID's */ -static const unsigned char so[6609] = { +static const unsigned char so[6628] = { 0x2A,0x86,0x48,0x86,0xF7,0x0D, /* [ 0] OBJ_rsadsi */ 0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01, /* [ 6] OBJ_pkcs */ 0x2A,0x86,0x48,0x86,0xF7,0x0D,0x02,0x05, /* [ 13] OBJ_md5 */ @@ -929,9 +929,11 @@ static const unsigned char so[6609] = { 0x2A,0x81,0x1C,0xCF,0x55,0x01,0x86,0x22, /* [ 6581] OBJ_zuc_128_eia3 */ 0x2B,0x06,0x01,0x04,0x01,0x82,0xDA,0x4B,0x2C, /* [ 6589] OBJ_delegation_usage */ 0x2A,0x81,0x1C,0xCF,0x55,0x01,0x83,0x11,0x03,0x01, /* [ 6598] OBJ_hmacWithSM3 */ + 0x60,0x86,0x48,0x01,0x86,0xF9,0x66, /* [ 6608] OBJ_oracle */ + 0x60,0x86,0x48,0x01,0x86,0xF9,0x66,0xAD,0xCA,0x7B,0x01,0x01, /* [ 6615] OBJ_oracle_jdk_trustedkeyusage */ }; -#define NUM_NID 1258 +#define NUM_NID 1260 static const ASN1_OBJECT nid_objs[NUM_NID] = { {"UNDEF", "undefined", NID_undef}, {"rsadsi", "RSA Data Security, Inc.", NID_rsadsi, 6, &so[0]}, @@ -2191,9 +2193,11 @@ static const ASN1_OBJECT nid_objs[NUM_NID] = { {"ZUC-128-EIA3", "zuc-128-eia3", NID_zuc_128_eia3, 8, &so[6581]}, {"delegationUsage", "X509v3 Delegation Usage", NID_delegation_usage, 9, &so[6589]}, {"hmacWithSM3", "hmacWithSM3", NID_hmacWithSM3, 10, &so[6598]}, + {"oracle-organization", "Oracle organization", NID_oracle, 7, &so[6608]}, + {"oracle-jdk-trustedkeyusage", "Trusted key usage (Oracle)", NID_oracle_jdk_trustedkeyusage, 12, &so[6615]}, }; -#define NUM_SN 1008 +#define NUM_SN 1010 static const unsigned int sn_objs[NUM_SN] = { 364, /* "AD_DVCS" */ 419, /* "AES-128-CBC" */ @@ -2883,6 +2887,8 @@ static const unsigned int sn_objs[NUM_SN] = { 139, /* "nsSGC" */ 77, /* "nsSslServerName" */ 681, /* "onBasis" */ + 1259, /* "oracle-jdk-trustedkeyusage" */ + 1258, /* "oracle-organization" */ 1089, /* "organizationIdentifier" */ 491, /* "organizationalStatus" */ 1141, /* "oscca" */ @@ -3205,7 +3211,7 @@ static const unsigned int sn_objs[NUM_SN] = { 1093, /* "x509ExtAdmission" */ }; -#define NUM_LN 1008 +#define NUM_LN 1010 static const unsigned int ln_objs[NUM_LN] = { 363, /* "AD Time Stamping" */ 405, /* "ANSI X9.62" */ @@ -3305,6 +3311,7 @@ static const unsigned int ln_objs[NUM_LN] = { 366, /* "OCSP Nonce" */ 371, /* "OCSP Service Locator" */ 180, /* "OCSP Signing" */ + 1258, /* "Oracle organization" */ 161, /* "PBES2" */ 69, /* "PBKDF2" */ 162, /* "PBMAC1" */ @@ -3348,6 +3355,7 @@ static const unsigned int ln_objs[NUM_LN] = { 129, /* "TLS Web Server Authentication" */ 133, /* "Time Stamping" */ 375, /* "Trust Root" */ + 1259, /* "Trusted key usage (Oracle)" */ 1034, /* "X25519" */ 1035, /* "X448" */ 12, /* "X509" */ @@ -4217,7 +4225,7 @@ static const unsigned int ln_objs[NUM_LN] = { 1255, /* "zuc-128-eia3" */ }; -#define NUM_OBJ 924 +#define NUM_OBJ 926 static const unsigned int obj_objs[NUM_OBJ] = { 0, /* OBJ_undef 0 */ 181, /* OBJ_iso 1 */ @@ -4591,6 +4599,7 @@ static const unsigned int obj_objs[NUM_OBJ] = { 507, /* OBJ_id_hex_partial_message 1 3 6 1 7 1 1 1 */ 508, /* OBJ_id_hex_multipart_message 1 3 6 1 7 1 1 2 */ 57, /* OBJ_netscape 2 16 840 1 113730 */ + 1258, /* OBJ_oracle 2 16 840 1 113894 */ 437, /* OBJ_pilot 0 9 2342 19200300 100 */ 1133, /* OBJ_sm4_ecb 1 2 156 10197 1 104 1 */ 1134, /* OBJ_sm4_cbc 1 2 156 10197 1 104 2 */ @@ -5132,6 +5141,7 @@ static const unsigned int obj_objs[NUM_OBJ] = { 955, /* OBJ_jurisdictionLocalityName 1 3 6 1 4 1 311 60 2 1 1 */ 956, /* OBJ_jurisdictionStateOrProvinceName 1 3 6 1 4 1 311 60 2 1 2 */ 957, /* OBJ_jurisdictionCountryName 1 3 6 1 4 1 311 60 2 1 3 */ + 1259, /* OBJ_oracle_jdk_trustedkeyusage 2 16 840 1 113894 746875 1 1 */ 1159, /* OBJ_dstu4145be 1 2 804 2 1 1 1 1 3 1 1 1 1 */ 1160, /* OBJ_uacurve0 1 2 804 2 1 1 1 1 3 1 1 2 0 */ 1161, /* OBJ_uacurve1 1 2 804 2 1 1 1 1 3 1 1 2 1 */ diff --git a/crypto/objects/obj_mac.num b/crypto/objects/obj_mac.num index d9aeee93a..5e222b3f7 100644 --- a/crypto/objects/obj_mac.num +++ b/crypto/objects/obj_mac.num @@ -1025,3 +1025,5 @@ auth_sm2 1254 zuc_128_eia3 1255 delegation_usage 1256 hmacWithSM3 1257 +oracle 1258 +oracle_jdk_trustedkeyusage 1259 diff --git a/crypto/objects/obj_xref.h b/crypto/objects/obj_xref.h index cb6c67986..468766a34 100644 --- a/crypto/objects/obj_xref.h +++ b/crypto/objects/obj_xref.h @@ -2,7 +2,7 @@ * WARNING: do not edit! * Generated by objxref.pl * - * Copyright 1998-2022 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1998-2024 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy diff --git a/crypto/objects/objects.txt b/crypto/objects/objects.txt index 4e461fb0f..9aede25bd 100644 --- a/crypto/objects/objects.txt +++ b/crypto/objects/objects.txt @@ -1410,3 +1410,9 @@ dstu4145le 2 9 : uacurve9 : DSTU curve 9 : AES-128-SIV : aes-128-siv : AES-192-SIV : aes-192-siv : AES-256-SIV : aes-256-siv + + +!Cname oracle +joint-iso-itu-t 16 840 1 113894 : oracle-organization : Oracle organization +# Jdk trustedKeyUsage attribute +oracle 746875 1 1 : oracle-jdk-trustedkeyusage : Trusted key usage (Oracle) diff --git a/crypto/pkcs12/p12_add.c b/crypto/pkcs12/p12_add.c index 6fd4184af..7ef5dca67 100644 --- a/crypto/pkcs12/p12_add.c +++ b/crypto/pkcs12/p12_add.c @@ -78,7 +78,15 @@ STACK_OF(PKCS12_SAFEBAG) *PKCS12_unpack_p7data(PKCS7 *p7) ERR_raise(ERR_LIB_PKCS12, PKCS12_R_CONTENT_TYPE_NOT_DATA); return NULL; } - return ASN1_item_unpack(p7->d.data, ASN1_ITEM_rptr(PKCS12_SAFEBAGS)); + + if (p7->d.data == NULL) { + ERR_raise(ERR_LIB_PKCS12, PKCS12_R_DECODE_ERROR); + return NULL; + } + + return ASN1_item_unpack_ex(p7->d.data, ASN1_ITEM_rptr(PKCS12_SAFEBAGS), + ossl_pkcs7_ctx_get0_libctx(&p7->ctx), + ossl_pkcs7_ctx_get0_propq(&p7->ctx)); } /* Turn a stack of SAFEBAGS into a PKCS#7 encrypted data ContentInfo */ @@ -150,6 +158,12 @@ STACK_OF(PKCS12_SAFEBAG) *PKCS12_unpack_p7encdata(PKCS7 *p7, const char *pass, { if (!PKCS7_type_is_encrypted(p7)) return NULL; + + if (p7->d.encrypted == NULL) { + ERR_raise(ERR_LIB_PKCS12, PKCS12_R_DECODE_ERROR); + return NULL; + } + return PKCS12_item_decrypt_d2i_ex(p7->d.encrypted->enc_data->algorithm, ASN1_ITEM_rptr(PKCS12_SAFEBAGS), pass, passlen, @@ -181,6 +195,7 @@ int PKCS12_pack_authsafes(PKCS12 *p12, STACK_OF(PKCS7) *safes) STACK_OF(PKCS7) *PKCS12_unpack_authsafes(const PKCS12 *p12) { STACK_OF(PKCS7) *p7s; + PKCS7_CTX *p7ctx; PKCS7 *p7; int i; @@ -188,8 +203,17 @@ STACK_OF(PKCS7) *PKCS12_unpack_authsafes(const PKCS12 *p12) ERR_raise(ERR_LIB_PKCS12, PKCS12_R_CONTENT_TYPE_NOT_DATA); return NULL; } - p7s = ASN1_item_unpack(p12->authsafes->d.data, - ASN1_ITEM_rptr(PKCS12_AUTHSAFES)); + + if (p12->authsafes->d.data == NULL) { + ERR_raise(ERR_LIB_PKCS12, PKCS12_R_DECODE_ERROR); + return NULL; + } + + p7ctx = &p12->authsafes->ctx; + p7s = ASN1_item_unpack_ex(p12->authsafes->d.data, + ASN1_ITEM_rptr(PKCS12_AUTHSAFES), + ossl_pkcs7_ctx_get0_libctx(p7ctx), + ossl_pkcs7_ctx_get0_propq(p7ctx)); if (p7s != NULL) { for (i = 0; i < sk_PKCS7_num(p7s); i++) { p7 = sk_PKCS7_value(p7s, i); diff --git a/crypto/pkcs12/p12_asn.c b/crypto/pkcs12/p12_asn.c index aabbd38ee..caae639f8 100644 --- a/crypto/pkcs12/p12_asn.c +++ b/crypto/pkcs12/p12_asn.c @@ -12,6 +12,7 @@ #include #include #include "p12_local.h" +#include "crypto/pkcs7.h" /* PKCS#12 ASN1 module */ @@ -21,7 +22,21 @@ ASN1_SEQUENCE(PKCS12) = { ASN1_OPT(PKCS12, mac, PKCS12_MAC_DATA) } ASN1_SEQUENCE_END(PKCS12) -IMPLEMENT_ASN1_FUNCTIONS(PKCS12) +IMPLEMENT_ASN1_ENCODE_FUNCTIONS_fname(PKCS12, PKCS12, PKCS12) + +PKCS12 *PKCS12_new(void) +{ + return (PKCS12 *)ASN1_item_new(ASN1_ITEM_rptr(PKCS12)); +} + +void PKCS12_free(PKCS12 *p12) +{ + if (p12 != NULL && p12->authsafes != NULL) { + OPENSSL_free(p12->authsafes->ctx.propq); + p12->authsafes->ctx.propq = NULL; + } + ASN1_item_free((ASN1_VALUE *)p12, ASN1_ITEM_rptr(PKCS12)); +} ASN1_SEQUENCE(PKCS12_MAC_DATA) = { ASN1_SIMPLE(PKCS12_MAC_DATA, dinfo, X509_SIG), diff --git a/crypto/pkcs12/p12_attr.c b/crypto/pkcs12/p12_attr.c index da228336e..991d6f445 100644 --- a/crypto/pkcs12/p12_attr.c +++ b/crypto/pkcs12/p12_attr.c @@ -119,3 +119,11 @@ PKCS12_SAFEBAG_get0_attrs(const PKCS12_SAFEBAG *bag) { return bag->attrib; } + +void PKCS12_SAFEBAG_set0_attrs(PKCS12_SAFEBAG *bag, const STACK_OF(X509_ATTRIBUTE) *attrs) +{ + if (bag->attrib != attrs) + sk_X509_ATTRIBUTE_free(bag->attrib); + + bag->attrib = (STACK_OF(X509_ATTRIBUTE*))attrs; +} diff --git a/crypto/pkcs12/p12_crt.c b/crypto/pkcs12/p12_crt.c index f0190761e..32ca3b1c4 100644 --- a/crypto/pkcs12/p12_crt.c +++ b/crypto/pkcs12/p12_crt.c @@ -14,6 +14,8 @@ static int pkcs12_add_bag(STACK_OF(PKCS12_SAFEBAG) **pbags, PKCS12_SAFEBAG *bag); +static int pkcs12_remove_bag(STACK_OF(PKCS12_SAFEBAG) **pbags, + PKCS12_SAFEBAG *bag); static int copy_bag_attr(PKCS12_SAFEBAG *bag, EVP_PKEY *pkey, int nid) { @@ -28,16 +30,17 @@ static int copy_bag_attr(PKCS12_SAFEBAG *bag, EVP_PKEY *pkey, int nid) return 1; } -PKCS12 *PKCS12_create_ex(const char *pass, const char *name, EVP_PKEY *pkey, - X509 *cert, STACK_OF(X509) *ca, int nid_key, int nid_cert, - int iter, int mac_iter, int keytype, - OSSL_LIB_CTX *ctx, const char *propq) +PKCS12 *PKCS12_create_ex2(const char *pass, const char *name, EVP_PKEY *pkey, + X509 *cert, STACK_OF(X509) *ca, int nid_key, int nid_cert, + int iter, int mac_iter, int keytype, + OSSL_LIB_CTX *ctx, const char *propq, + PKCS12_create_cb *cb, void *cbarg) { PKCS12 *p12 = NULL; STACK_OF(PKCS7) *safes = NULL; STACK_OF(PKCS12_SAFEBAG) *bags = NULL; PKCS12_SAFEBAG *bag = NULL; - int i; + int i, cbret; unsigned char keyid[EVP_MAX_MD_SIZE]; unsigned int keyidlen = 0; @@ -69,12 +72,30 @@ PKCS12 *PKCS12_create_ex(const char *pass, const char *name, EVP_PKEY *pkey, goto err; if (keyidlen && !PKCS12_add_localkeyid(bag, keyid, keyidlen)) goto err; + if (cb != NULL) { + cbret = cb(bag, cbarg); + if (cbret == -1) { + ERR_raise(ERR_LIB_PKCS12, PKCS12_R_CALLBACK_FAILED); + goto err; + } else if (cbret == 0) { + pkcs12_remove_bag(&bags, bag); + } + } } /* Add all other certificates */ for (i = 0; i < sk_X509_num(ca); i++) { - if (!PKCS12_add_cert(&bags, sk_X509_value(ca, i))) + if ((bag = PKCS12_add_cert(&bags, sk_X509_value(ca, i))) == NULL) goto err; + if (cb != NULL) { + cbret = cb(bag, cbarg); + if (cbret == -1) { + ERR_raise(ERR_LIB_PKCS12, PKCS12_R_CALLBACK_FAILED); + goto err; + } else if (cbret == 0) { + pkcs12_remove_bag(&bags, bag); + } + } } if (bags && !PKCS12_add_safe_ex(&safes, bags, nid_cert, iter, pass, @@ -100,6 +121,15 @@ PKCS12 *PKCS12_create_ex(const char *pass, const char *name, EVP_PKEY *pkey, goto err; if (keyidlen && !PKCS12_add_localkeyid(bag, keyid, keyidlen)) goto err; + if (cb != NULL) { + cbret = cb(bag, cbarg); + if (cbret == -1) { + ERR_raise(ERR_LIB_PKCS12, PKCS12_R_CALLBACK_FAILED); + goto err; + } else if (cbret == 0) { + pkcs12_remove_bag(&bags, bag); + } + } } if (bags && !PKCS12_add_safe(&safes, bags, -1, 0, NULL)) @@ -131,6 +161,16 @@ PKCS12 *PKCS12_create_ex(const char *pass, const char *name, EVP_PKEY *pkey, } +PKCS12 *PKCS12_create_ex(const char *pass, const char *name, EVP_PKEY *pkey, X509 *cert, + STACK_OF(X509) *ca, int nid_key, int nid_cert, int iter, + int mac_iter, int keytype, + OSSL_LIB_CTX *ctx, const char *propq) +{ + return PKCS12_create_ex2(pass, name, pkey, cert, ca, nid_key, nid_cert, + iter, mac_iter, keytype, ctx, propq, + NULL, NULL); +} + PKCS12 *PKCS12_create(const char *pass, const char *name, EVP_PKEY *pkey, X509 *cert, STACK_OF(X509) *ca, int nid_key, int nid_cert, int iter, int mac_iter, int keytype) @@ -281,6 +321,22 @@ int PKCS12_add_safe(STACK_OF(PKCS7) **psafes, STACK_OF(PKCS12_SAFEBAG) *bags, return PKCS12_add_safe_ex(psafes, bags, nid_safe, iter, pass, NULL, NULL); } + +static int pkcs12_remove_bag(STACK_OF(PKCS12_SAFEBAG) **pbags, + PKCS12_SAFEBAG *bag) +{ + PKCS12_SAFEBAG *tmp; + + if (pbags == NULL || bag == NULL) + return 1; + + if ((tmp = sk_PKCS12_SAFEBAG_delete_ptr(*pbags, bag)) == NULL) + return 0; + + PKCS12_SAFEBAG_free(tmp); + return 1; +} + static int pkcs12_add_bag(STACK_OF(PKCS12_SAFEBAG) **pbags, PKCS12_SAFEBAG *bag) { diff --git a/crypto/pkcs12/p12_init.c b/crypto/pkcs12/p12_init.c index 45aa2f915..366f9ec7d 100644 --- a/crypto/pkcs12/p12_init.c +++ b/crypto/pkcs12/p12_init.c @@ -56,3 +56,9 @@ PKCS12 *PKCS12_init(int mode) return PKCS12_init_ex(mode, NULL, NULL); } +const PKCS7_CTX *ossl_pkcs12_get0_pkcs7ctx(const PKCS12 *p12) +{ + if (p12 == NULL || p12->authsafes == NULL) + return NULL; + return &p12->authsafes->ctx; +} diff --git a/crypto/pkcs12/p12_kiss.c b/crypto/pkcs12/p12_kiss.c index 229b34cf6..a17a49e51 100644 --- a/crypto/pkcs12/p12_kiss.c +++ b/crypto/pkcs12/p12_kiss.c @@ -18,10 +18,12 @@ static int parse_pk12(PKCS12 *p12, const char *pass, int passlen, EVP_PKEY **pkey, STACK_OF(X509) *ocerts); static int parse_bags(const STACK_OF(PKCS12_SAFEBAG) *bags, const char *pass, - int passlen, EVP_PKEY **pkey, STACK_OF(X509) *ocerts); + int passlen, EVP_PKEY **pkey, STACK_OF(X509) *ocerts, + OSSL_LIB_CTX *libctx, const char *propq); static int parse_bag(PKCS12_SAFEBAG *bag, const char *pass, int passlen, - EVP_PKEY **pkey, STACK_OF(X509) *ocerts); + EVP_PKEY **pkey, STACK_OF(X509) *ocerts, + OSSL_LIB_CTX *libctx, const char *propq); /* * Parse and decrypt a PKCS#12 structure returning user key, user cert and @@ -49,27 +51,28 @@ int PKCS12_parse(PKCS12 *p12, const char *pass, EVP_PKEY **pkey, X509 **cert, } /* Check the mac */ - - /* - * If password is zero length or NULL then try verifying both cases to - * determine which password is correct. The reason for this is that under - * PKCS#12 password based encryption no password and a zero length - * password are two different things... - */ - - if (pass == NULL || *pass == '\0') { - if (!PKCS12_mac_present(p12) - || PKCS12_verify_mac(p12, NULL, 0)) - pass = NULL; - else if (PKCS12_verify_mac(p12, "", 0)) - pass = ""; - else { + if (PKCS12_mac_present(p12)) { + /* + * If password is zero length or NULL then try verifying both cases to + * determine which password is correct. The reason for this is that under + * PKCS#12 password based encryption no password and a zero length + * password are two different things... + */ + if (pass == NULL || *pass == '\0') { + if (PKCS12_verify_mac(p12, NULL, 0)) + pass = NULL; + else if (PKCS12_verify_mac(p12, "", 0)) + pass = ""; + else { + ERR_raise(ERR_LIB_PKCS12, PKCS12_R_MAC_VERIFY_FAILURE); + goto err; + } + } else if (!PKCS12_verify_mac(p12, pass, -1)) { ERR_raise(ERR_LIB_PKCS12, PKCS12_R_MAC_VERIFY_FAILURE); goto err; } - } else if (!PKCS12_verify_mac(p12, pass, -1)) { - ERR_raise(ERR_LIB_PKCS12, PKCS12_R_MAC_VERIFY_FAILURE); - goto err; + } else if (pass == NULL || *pass == '\0') { + pass = NULL; } /* If needed, allocate stack for other certificates */ @@ -156,7 +159,8 @@ static int parse_pk12(PKCS12 *p12, const char *pass, int passlen, sk_PKCS7_pop_free(asafes, PKCS7_free); return 0; } - if (!parse_bags(bags, pass, passlen, pkey, ocerts)) { + if (!parse_bags(bags, pass, passlen, pkey, ocerts, + p7->ctx.libctx, p7->ctx.propq)) { sk_PKCS12_SAFEBAG_pop_free(bags, PKCS12_SAFEBAG_free); sk_PKCS7_pop_free(asafes, PKCS7_free); return 0; @@ -169,12 +173,14 @@ static int parse_pk12(PKCS12 *p12, const char *pass, int passlen, /* pkey and/or ocerts may be NULL */ static int parse_bags(const STACK_OF(PKCS12_SAFEBAG) *bags, const char *pass, - int passlen, EVP_PKEY **pkey, STACK_OF(X509) *ocerts) + int passlen, EVP_PKEY **pkey, STACK_OF(X509) *ocerts, + OSSL_LIB_CTX *libctx, const char *propq) { int i; for (i = 0; i < sk_PKCS12_SAFEBAG_num(bags); i++) { if (!parse_bag(sk_PKCS12_SAFEBAG_value(bags, i), - pass, passlen, pkey, ocerts)) + pass, passlen, pkey, ocerts, + libctx, propq)) return 0; } return 1; @@ -182,7 +188,8 @@ static int parse_bags(const STACK_OF(PKCS12_SAFEBAG) *bags, const char *pass, /* pkey and/or ocerts may be NULL */ static int parse_bag(PKCS12_SAFEBAG *bag, const char *pass, int passlen, - EVP_PKEY **pkey, STACK_OF(X509) *ocerts) + EVP_PKEY **pkey, STACK_OF(X509) *ocerts, + OSSL_LIB_CTX *libctx, const char *propq) { PKCS8_PRIV_KEY_INFO *p8; X509 *x509; @@ -200,7 +207,8 @@ static int parse_bag(PKCS12_SAFEBAG *bag, const char *pass, int passlen, case NID_keyBag: if (pkey == NULL || *pkey != NULL) return 1; - *pkey = EVP_PKCS82PKEY(PKCS12_SAFEBAG_get0_p8inf(bag)); + *pkey = EVP_PKCS82PKEY_ex(PKCS12_SAFEBAG_get0_p8inf(bag), + libctx, propq); if (*pkey == NULL) return 0; break; @@ -208,9 +216,10 @@ static int parse_bag(PKCS12_SAFEBAG *bag, const char *pass, int passlen, case NID_pkcs8ShroudedKeyBag: if (pkey == NULL || *pkey != NULL) return 1; - if ((p8 = PKCS12_decrypt_skey(bag, pass, passlen)) == NULL) + if ((p8 = PKCS12_decrypt_skey_ex(bag, pass, passlen, + libctx, propq)) == NULL) return 0; - *pkey = EVP_PKCS82PKEY(p8); + *pkey = EVP_PKCS82PKEY_ex(p8, libctx, propq); PKCS8_PRIV_KEY_INFO_free(p8); if (!(*pkey)) return 0; @@ -220,7 +229,7 @@ static int parse_bag(PKCS12_SAFEBAG *bag, const char *pass, int passlen, if (ocerts == NULL || PKCS12_SAFEBAG_get_bag_nid(bag) != NID_x509Certificate) return 1; - if ((x509 = PKCS12_SAFEBAG_get1_cert(bag)) == NULL) + if ((x509 = PKCS12_SAFEBAG_get1_cert_ex(bag, libctx, propq)) == NULL) return 0; if (lkid && !X509_keyid_set1(x509, lkid->data, lkid->length)) { X509_free(x509); @@ -250,7 +259,7 @@ static int parse_bag(PKCS12_SAFEBAG *bag, const char *pass, int passlen, case NID_safeContentsBag: return parse_bags(PKCS12_SAFEBAG_get0_safes(bag), pass, passlen, pkey, - ocerts); + ocerts, libctx, propq); default: return 1; diff --git a/crypto/pkcs12/p12_local.h b/crypto/pkcs12/p12_local.h index acaa27b19..97697922b 100644 --- a/crypto/pkcs12/p12_local.h +++ b/crypto/pkcs12/p12_local.h @@ -41,3 +41,5 @@ struct pkcs12_bag_st { ASN1_TYPE *other; /* Secret or other bag */ } value; }; + +const PKCS7_CTX *ossl_pkcs12_get0_pkcs7ctx(const PKCS12 *p12); diff --git a/crypto/pkcs12/p12_mutl.c b/crypto/pkcs12/p12_mutl.c index 118d598ea..28cb210ea 100644 --- a/crypto/pkcs12/p12_mutl.c +++ b/crypto/pkcs12/p12_mutl.c @@ -75,6 +75,11 @@ static int pkcs12_gen_mac(PKCS12 *p12, const char *pass, int passlen, return 0; } + if (p12->authsafes->d.data == NULL) { + ERR_raise(ERR_LIB_PKCS12, PKCS12_R_DECODE_ERROR); + return 0; + } + salt = p12->mac->salt->data; saltlen = p12->mac->salt->length; if (p12->mac->iter == NULL) diff --git a/crypto/pkcs12/p12_npas.c b/crypto/pkcs12/p12_npas.c index 62230bc61..007b171dc 100644 --- a/crypto/pkcs12/p12_npas.c +++ b/crypto/pkcs12/p12_npas.c @@ -19,11 +19,13 @@ static int newpass_p12(PKCS12 *p12, const char *oldpass, const char *newpass); static int newpass_bags(STACK_OF(PKCS12_SAFEBAG) *bags, const char *oldpass, - const char *newpass); + const char *newpass, + OSSL_LIB_CTX *libctx, const char *propq); static int newpass_bag(PKCS12_SAFEBAG *bag, const char *oldpass, - const char *newpass); + const char *newpass, + OSSL_LIB_CTX *libctx, const char *propq); static int alg_get(const X509_ALGOR *alg, int *pnid, int *piter, - int *psaltlen); + int *psaltlen, int *cipherid); /* * Change the password on a PKCS#12 structure. @@ -39,12 +41,12 @@ int PKCS12_newpass(PKCS12 *p12, const char *oldpass, const char *newpass) } /* Check the mac */ - - if (!PKCS12_verify_mac(p12, oldpass, -1)) { - ERR_raise(ERR_LIB_PKCS12, PKCS12_R_MAC_VERIFY_FAILURE); - return 0; + if (p12->mac != NULL) { + if (!PKCS12_verify_mac(p12, oldpass, -1)) { + ERR_raise(ERR_LIB_PKCS12, PKCS12_R_MAC_VERIFY_FAILURE); + return 0; + } } - if (!newpass_p12(p12, oldpass, newpass)) { ERR_raise(ERR_LIB_PKCS12, PKCS12_R_PARSE_ERROR); return 0; @@ -59,7 +61,7 @@ static int newpass_p12(PKCS12 *p12, const char *oldpass, const char *newpass) { STACK_OF(PKCS7) *asafes = NULL, *newsafes = NULL; STACK_OF(PKCS12_SAFEBAG) *bags = NULL; - int i, bagnid, pbe_nid = 0, pbe_iter = 0, pbe_saltlen = 0; + int i, bagnid, pbe_nid = 0, pbe_iter = 0, pbe_saltlen = 0, cipherid = NID_undef; PKCS7 *p7, *p7new; ASN1_OCTET_STRING *p12_data_tmp = NULL, *macoct = NULL; unsigned char mac[EVP_MAX_MD_SIZE]; @@ -72,27 +74,31 @@ static int newpass_p12(PKCS12 *p12, const char *oldpass, const char *newpass) goto err; for (i = 0; i < sk_PKCS7_num(asafes); i++) { p7 = sk_PKCS7_value(asafes, i); + bagnid = OBJ_obj2nid(p7->type); if (bagnid == NID_pkcs7_data) { bags = PKCS12_unpack_p7data(p7); } else if (bagnid == NID_pkcs7_encrypted) { bags = PKCS12_unpack_p7encdata(p7, oldpass, -1); - if (!alg_get(p7->d.encrypted->enc_data->algorithm, - &pbe_nid, &pbe_iter, &pbe_saltlen)) + if (p7->d.encrypted == NULL + || !alg_get(p7->d.encrypted->enc_data->algorithm, + &pbe_nid, &pbe_iter, &pbe_saltlen, &cipherid)) goto err; } else { continue; } if (bags == NULL) goto err; - if (!newpass_bags(bags, oldpass, newpass)) + if (!newpass_bags(bags, oldpass, newpass, + p7->ctx.libctx, p7->ctx.propq)) goto err; /* Repack bag in same form with new password */ if (bagnid == NID_pkcs7_data) p7new = PKCS12_pack_p7data(bags); else - p7new = PKCS12_pack_p7encdata(pbe_nid, newpass, -1, NULL, - pbe_saltlen, pbe_iter, bags); + p7new = PKCS12_pack_p7encdata_ex(pbe_nid, newpass, -1, NULL, + pbe_saltlen, pbe_iter, bags, + p7->ctx.libctx, p7->ctx.propq); if (p7new == NULL || !sk_PKCS7_push(newsafes, p7new)) goto err; sk_PKCS12_SAFEBAG_pop_free(bags, PKCS12_SAFEBAG_free); @@ -107,11 +113,13 @@ static int newpass_p12(PKCS12 *p12, const char *oldpass, const char *newpass) if (!PKCS12_pack_authsafes(p12, newsafes)) goto err; - if (!PKCS12_gen_mac(p12, newpass, -1, mac, &maclen)) - goto err; - X509_SIG_getm(p12->mac->dinfo, NULL, &macoct); - if (!ASN1_OCTET_STRING_set(macoct, mac, maclen)) - goto err; + if (p12->mac != NULL) { + if (!PKCS12_gen_mac(p12, newpass, -1, mac, &maclen)) + goto err; + X509_SIG_getm(p12->mac->dinfo, NULL, &macoct); + if (!ASN1_OCTET_STRING_set(macoct, mac, maclen)) + goto err; + } rv = 1; @@ -130,11 +138,13 @@ static int newpass_p12(PKCS12 *p12, const char *oldpass, const char *newpass) } static int newpass_bags(STACK_OF(PKCS12_SAFEBAG) *bags, const char *oldpass, - const char *newpass) + const char *newpass, + OSSL_LIB_CTX *libctx, const char *propq) { int i; for (i = 0; i < sk_PKCS12_SAFEBAG_num(bags); i++) { - if (!newpass_bag(sk_PKCS12_SAFEBAG_value(bags, i), oldpass, newpass)) + if (!newpass_bag(sk_PKCS12_SAFEBAG_value(bags, i), oldpass, newpass, + libctx, propq)) return 0; } return 1; @@ -143,26 +153,37 @@ static int newpass_bags(STACK_OF(PKCS12_SAFEBAG) *bags, const char *oldpass, /* Change password of safebag: only needs handle shrouded keybags */ static int newpass_bag(PKCS12_SAFEBAG *bag, const char *oldpass, - const char *newpass) + const char *newpass, + OSSL_LIB_CTX *libctx, const char *propq) { + EVP_CIPHER *cipher = NULL; PKCS8_PRIV_KEY_INFO *p8; X509_SIG *p8new; - int p8_nid, p8_saltlen, p8_iter; + int p8_nid, p8_saltlen, p8_iter, cipherid = 0; const X509_ALGOR *shalg; if (PKCS12_SAFEBAG_get_nid(bag) != NID_pkcs8ShroudedKeyBag) return 1; - if ((p8 = PKCS8_decrypt(bag->value.shkeybag, oldpass, -1)) == NULL) + if ((p8 = PKCS8_decrypt_ex(bag->value.shkeybag, oldpass, -1, + libctx, propq)) == NULL) return 0; X509_SIG_get0(bag->value.shkeybag, &shalg, NULL); - if (!alg_get(shalg, &p8_nid, &p8_iter, &p8_saltlen)) { + if (!alg_get(shalg, &p8_nid, &p8_iter, &p8_saltlen, &cipherid)) { PKCS8_PRIV_KEY_INFO_free(p8); return 0; } - p8new = PKCS8_encrypt(p8_nid, NULL, newpass, -1, NULL, p8_saltlen, - p8_iter, p8); + if (cipherid != NID_undef) { + cipher = EVP_CIPHER_fetch(libctx, OBJ_nid2sn(cipherid), propq); + if (cipher == NULL) { + PKCS8_PRIV_KEY_INFO_free(p8); + return 0; + } + } + p8new = PKCS8_encrypt_ex(p8_nid, cipher, newpass, -1, NULL, p8_saltlen, + p8_iter, p8, libctx, propq); PKCS8_PRIV_KEY_INFO_free(p8); + EVP_CIPHER_free(cipher); if (p8new == NULL) return 0; X509_SIG_free(bag->value.shkeybag); @@ -171,16 +192,69 @@ static int newpass_bag(PKCS12_SAFEBAG *bag, const char *oldpass, } static int alg_get(const X509_ALGOR *alg, int *pnid, int *piter, - int *psaltlen) + int *psaltlen, int *cipherid) { - PBEPARAM *pbe; + int ret = 0, pbenid, aparamtype; + int encnid, prfnid; + const ASN1_OBJECT *aoid; + const void *aparam; + PBEPARAM *pbe = NULL; + PBE2PARAM *pbe2 = NULL; + PBKDF2PARAM *kdf = NULL; - pbe = ASN1_TYPE_unpack_sequence(ASN1_ITEM_rptr(PBEPARAM), alg->parameter); - if (pbe == NULL) - return 0; - *pnid = OBJ_obj2nid(alg->algorithm); - *piter = ASN1_INTEGER_get(pbe->iter); - *psaltlen = pbe->salt->length; - PBEPARAM_free(pbe); - return 1; + X509_ALGOR_get0(&aoid, &aparamtype, &aparam, alg); + pbenid = OBJ_obj2nid(aoid); + + switch (pbenid) { + case NID_pbes2: + if (aparamtype == V_ASN1_SEQUENCE) + pbe2 = ASN1_item_unpack(aparam, ASN1_ITEM_rptr(PBE2PARAM)); + if (pbe2 == NULL) + goto done; + + X509_ALGOR_get0(&aoid, &aparamtype, &aparam, pbe2->keyfunc); + pbenid = OBJ_obj2nid(aoid); + X509_ALGOR_get0(&aoid, NULL, NULL, pbe2->encryption); + encnid = OBJ_obj2nid(aoid); + + if (aparamtype == V_ASN1_SEQUENCE) + kdf = ASN1_item_unpack(aparam, ASN1_ITEM_rptr(PBKDF2PARAM)); + if (kdf == NULL) + goto done; + + /* Only OCTET_STRING is supported */ + if (kdf->salt->type != V_ASN1_OCTET_STRING) + goto done; + + if (kdf->prf == NULL) { + prfnid = NID_hmacWithSHA1; + } else { + X509_ALGOR_get0(&aoid, NULL, NULL, kdf->prf); + prfnid = OBJ_obj2nid(aoid); + } + *psaltlen = kdf->salt->value.octet_string->length; + *piter = ASN1_INTEGER_get(kdf->iter); + *pnid = prfnid; + *cipherid = encnid; + break; + default: + pbe = ASN1_TYPE_unpack_sequence(ASN1_ITEM_rptr(PBEPARAM), alg->parameter); + if (pbe == NULL) + goto done; + *pnid = OBJ_obj2nid(alg->algorithm); + *piter = ASN1_INTEGER_get(pbe->iter); + *psaltlen = pbe->salt->length; + *cipherid = NID_undef; + ret = 1; + break; + } + ret = 1; +done: + if (kdf != NULL) + PBKDF2PARAM_free(kdf); + if (pbe2 != NULL) + PBE2PARAM_free(pbe2); + if (pbe != NULL) + PBEPARAM_free(pbe); + return ret; } diff --git a/crypto/pkcs12/p12_sbag.c b/crypto/pkcs12/p12_sbag.c index 7574c5412..823c696ff 100644 --- a/crypto/pkcs12/p12_sbag.c +++ b/crypto/pkcs12/p12_sbag.c @@ -11,6 +11,7 @@ #include "internal/cryptlib.h" #include #include "p12_local.h" +#include "crypto/x509.h" #ifndef OPENSSL_NO_DEPRECATED_1_1_0 ASN1_TYPE *PKCS12_get_attr(const PKCS12_SAFEBAG *bag, int attr_nid) @@ -101,6 +102,42 @@ X509_CRL *PKCS12_SAFEBAG_get1_crl(const PKCS12_SAFEBAG *bag) ASN1_ITEM_rptr(X509_CRL)); } +X509 *PKCS12_SAFEBAG_get1_cert_ex(const PKCS12_SAFEBAG *bag, + OSSL_LIB_CTX *libctx, const char *propq) +{ + X509 *ret = NULL; + + if (PKCS12_SAFEBAG_get_nid(bag) != NID_certBag) + return NULL; + if (OBJ_obj2nid(bag->value.bag->type) != NID_x509Certificate) + return NULL; + ret = ASN1_item_unpack_ex(bag->value.bag->value.octet, + ASN1_ITEM_rptr(X509), libctx, propq); + if (!ossl_x509_set0_libctx(ret, libctx, propq)) { + X509_free(ret); + return NULL; + } + return ret; +} + +X509_CRL *PKCS12_SAFEBAG_get1_crl_ex(const PKCS12_SAFEBAG *bag, + OSSL_LIB_CTX *libctx, const char *propq) +{ + X509_CRL *ret = NULL; + + if (PKCS12_SAFEBAG_get_nid(bag) != NID_crlBag) + return NULL; + if (OBJ_obj2nid(bag->value.bag->type) != NID_x509Crl) + return NULL; + ret = ASN1_item_unpack_ex(bag->value.bag->value.octet, + ASN1_ITEM_rptr(X509_CRL), libctx, propq); + if (!ossl_x509_crl_set0_libctx(ret, libctx, propq)) { + X509_CRL_free(ret); + return NULL; + } + return ret; +} + PKCS12_SAFEBAG *PKCS12_SAFEBAG_create_cert(X509 *x509) { return PKCS12_item_pack_safebag(x509, ASN1_ITEM_rptr(X509), diff --git a/crypto/pkcs12/p12_utl.c b/crypto/pkcs12/p12_utl.c index 3afc8b2f1..2fa2cfdc3 100644 --- a/crypto/pkcs12/p12_utl.c +++ b/crypto/pkcs12/p12_utl.c @@ -10,6 +10,8 @@ #include #include "internal/cryptlib.h" #include +#include "p12_local.h" +#include "crypto/pkcs7/pk7_local.h" /* Cheap and nasty Unicode stuff */ @@ -238,12 +240,34 @@ int i2d_PKCS12_fp(FILE *fp, const PKCS12 *p12) PKCS12 *d2i_PKCS12_bio(BIO *bp, PKCS12 **p12) { - return ASN1_item_d2i_bio(ASN1_ITEM_rptr(PKCS12), bp, p12); + OSSL_LIB_CTX *libctx = NULL; + const char *propq = NULL; + const PKCS7_CTX *p7ctx = NULL; + + if (p12 != NULL) { + p7ctx = ossl_pkcs12_get0_pkcs7ctx(*p12); + if (p7ctx != NULL) { + libctx = ossl_pkcs7_ctx_get0_libctx(p7ctx); + propq = ossl_pkcs7_ctx_get0_propq(p7ctx); + } + } + return ASN1_item_d2i_bio_ex(ASN1_ITEM_rptr(PKCS12), bp, p12, libctx, propq); } #ifndef OPENSSL_NO_STDIO PKCS12 *d2i_PKCS12_fp(FILE *fp, PKCS12 **p12) { - return ASN1_item_d2i_fp(ASN1_ITEM_rptr(PKCS12), fp, p12); + OSSL_LIB_CTX *libctx = NULL; + const char *propq = NULL; + const PKCS7_CTX *p7ctx = NULL; + + if (p12 != NULL) { + p7ctx = ossl_pkcs12_get0_pkcs7ctx(*p12); + if (p7ctx != NULL) { + libctx = ossl_pkcs7_ctx_get0_libctx(p7ctx); + propq = ossl_pkcs7_ctx_get0_propq(p7ctx); + } + } + return ASN1_item_d2i_fp_ex(ASN1_ITEM_rptr(PKCS12), fp, p12, libctx, propq); } #endif diff --git a/crypto/pkcs12/pk12err.c b/crypto/pkcs12/pk12err.c index 6e3ec78cd..b53b0e0d0 100644 --- a/crypto/pkcs12/pk12err.c +++ b/crypto/pkcs12/pk12err.c @@ -1,6 +1,6 @@ /* * Generated by util/mkerr.pl DO NOT EDIT - * Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2022 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -15,6 +15,7 @@ #ifndef OPENSSL_NO_ERR static const ERR_STRING_DATA PKCS12_str_reasons[] = { + {ERR_PACK(ERR_LIB_PKCS12, 0, PKCS12_R_CALLBACK_FAILED), "callback failed"}, {ERR_PACK(ERR_LIB_PKCS12, 0, PKCS12_R_CANT_PACK_STRUCTURE), "cant pack structure"}, {ERR_PACK(ERR_LIB_PKCS12, 0, PKCS12_R_CONTENT_TYPE_NOT_DATA), diff --git a/crypto/pkcs7/pk7_mime.c b/crypto/pkcs7/pk7_mime.c index 49a0da5f8..8228315ee 100644 --- a/crypto/pkcs7/pk7_mime.c +++ b/crypto/pkcs7/pk7_mime.c @@ -33,10 +33,13 @@ int SMIME_write_PKCS7(BIO *bio, PKCS7 *p7, BIO *data, int flags) int ctype_nid = OBJ_obj2nid(p7->type); const PKCS7_CTX *ctx = ossl_pkcs7_get0_ctx(p7); - if (ctype_nid == NID_pkcs7_signed) + if (ctype_nid == NID_pkcs7_signed) { + if (p7->d.sign == NULL) + return 0; mdalgs = p7->d.sign->md_algs; - else + } else { mdalgs = NULL; + } flags ^= SMIME_OLDMIME; diff --git a/fuzz/oids.txt b/fuzz/oids.txt index 813a0dc9e..093446094 100644 --- a/fuzz/oids.txt +++ b/fuzz/oids.txt @@ -1,7 +1,7 @@ # WARNING: do not edit! # Generated by fuzz/mkfuzzoids.pl # -# Copyright 2020-2022 The OpenSSL Project Authors. All Rights Reserved. +# Copyright 2020-2024 The OpenSSL Project Authors. All Rights Reserved. # # Licensed under the Apache License 2.0 (the "License"). You may not use # this file except in compliance with the License. You can obtain a copy @@ -925,3 +925,5 @@ OBJ_sm4_ccm="\x2A\x81\x1C\xCF\x55\x01\x68\x09" OBJ_zuc_128_eia3="\x2A\x81\x1C\xCF\x55\x01\x86\x22" OBJ_delegation_usage="\x2B\x06\x01\x04\x01\x82\xDA\x4B\x2C" OBJ_hmacWithSM3="\x2A\x81\x1C\xCF\x55\x01\x83\x11\x03\x01" +OBJ_oracle="\x60\x86\x48\x01\x86\xF9\x66" +OBJ_oracle_jdk_trustedkeyusage="\x60\x86\x48\x01\x86\xF9\x66\xAD\xCA\x7B\x01\x01" diff --git a/include/crypto/pkcs12err.h b/include/crypto/pkcs12err.h index 662f412e9..114971c60 100644 --- a/include/crypto/pkcs12err.h +++ b/include/crypto/pkcs12err.h @@ -1,6 +1,6 @@ /* * Generated by util/mkerr.pl DO NOT EDIT - * Copyright 2020-2021 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2020-2022 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy diff --git a/include/openssl/asn1.h.in b/include/openssl/asn1.h.in index dcd3500f5..494a36391 100644 --- a/include/openssl/asn1.h.in +++ b/include/openssl/asn1.h.in @@ -840,6 +840,8 @@ int ASN1_TYPE_get_int_octetstring(const ASN1_TYPE *a, long *num, unsigned char *data, int max_len); void *ASN1_item_unpack(const ASN1_STRING *oct, const ASN1_ITEM *it); +void *ASN1_item_unpack_ex(const ASN1_STRING *oct, const ASN1_ITEM *it, + OSSL_LIB_CTX *libctx, const char *propq); ASN1_STRING *ASN1_item_pack(void *obj, const ASN1_ITEM *it, ASN1_OCTET_STRING **oct); diff --git a/include/openssl/obj_mac.h b/include/openssl/obj_mac.h index 1b89df7c4..242d7b933 100644 --- a/include/openssl/obj_mac.h +++ b/include/openssl/obj_mac.h @@ -2,7 +2,7 @@ * WARNING: do not edit! * Generated by crypto/objects/objects.pl * - * Copyright 2000-2022 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2000-2024 The OpenSSL Project Authors. All Rights Reserved. * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy * in the file LICENSE in the source distribution or at @@ -4401,4 +4401,14 @@ #define LN_aes_256_siv "aes-256-siv" #define NID_aes_256_siv 1200 +#define SN_oracle "oracle-organization" +#define LN_oracle "Oracle organization" +#define NID_oracle 1258 +#define OBJ_oracle OBJ_joint_iso_itu_t,16L,840L,1L,113894L + +#define SN_oracle_jdk_trustedkeyusage "oracle-jdk-trustedkeyusage" +#define LN_oracle_jdk_trustedkeyusage "Trusted key usage (Oracle)" +#define NID_oracle_jdk_trustedkeyusage 1259 +#define OBJ_oracle_jdk_trustedkeyusage OBJ_oracle,746875L,1L,1L + #endif /* OPENSSL_OBJ_MAC_H */ diff --git a/include/openssl/pkcs12.h.in b/include/openssl/pkcs12.h.in index c98eebfb3..b97b980ae 100644 --- a/include/openssl/pkcs12.h.in +++ b/include/openssl/pkcs12.h.in @@ -107,7 +107,9 @@ int PKCS12_SAFEBAG_get_bag_nid(const PKCS12_SAFEBAG *bag); const ASN1_TYPE *PKCS12_SAFEBAG_get0_bag_obj(const PKCS12_SAFEBAG *bag); const ASN1_OBJECT *PKCS12_SAFEBAG_get0_bag_type(const PKCS12_SAFEBAG *bag); +X509 *PKCS12_SAFEBAG_get1_cert_ex(const PKCS12_SAFEBAG *bag, OSSL_LIB_CTX *libctx, const char *propq); X509 *PKCS12_SAFEBAG_get1_cert(const PKCS12_SAFEBAG *bag); +X509_CRL *PKCS12_SAFEBAG_get1_crl_ex(const PKCS12_SAFEBAG *bag, OSSL_LIB_CTX *libctx, const char *propq); X509_CRL *PKCS12_SAFEBAG_get1_crl(const PKCS12_SAFEBAG *bag); const STACK_OF(PKCS12_SAFEBAG) * PKCS12_SAFEBAG_get0_safes(const PKCS12_SAFEBAG *bag); @@ -195,6 +197,7 @@ ASN1_TYPE *PKCS12_get_attr_gen(const STACK_OF(X509_ATTRIBUTE) *attrs, char *PKCS12_get_friendlyname(PKCS12_SAFEBAG *bag); const STACK_OF(X509_ATTRIBUTE) * PKCS12_SAFEBAG_get0_attrs(const PKCS12_SAFEBAG *bag); +void PKCS12_SAFEBAG_set0_attrs(PKCS12_SAFEBAG *bag, const STACK_OF(X509_ATTRIBUTE) *attrs); unsigned char *PKCS12_pbe_crypt(const X509_ALGOR *algor, const char *pass, int passlen, const unsigned char *in, int inlen, @@ -282,6 +285,7 @@ DECLARE_ASN1_ITEM(PKCS12_AUTHSAFES) void PKCS12_PBE_add(void); int PKCS12_parse(PKCS12 *p12, const char *pass, EVP_PKEY **pkey, X509 **cert, STACK_OF(X509) **ca); +typedef int PKCS12_create_cb(PKCS12_SAFEBAG *bag, void *cbarg); PKCS12 *PKCS12_create(const char *pass, const char *name, EVP_PKEY *pkey, X509 *cert, STACK_OF(X509) *ca, int nid_key, int nid_cert, int iter, int mac_iter, int keytype); @@ -289,6 +293,11 @@ PKCS12 *PKCS12_create_ex(const char *pass, const char *name, EVP_PKEY *pkey, X509 *cert, STACK_OF(X509) *ca, int nid_key, int nid_cert, int iter, int mac_iter, int keytype, OSSL_LIB_CTX *ctx, const char *propq); +PKCS12 *PKCS12_create_ex2(const char *pass, const char *name, EVP_PKEY *pkey, + X509 *cert, STACK_OF(X509) *ca, int nid_key, int nid_cert, + int iter, int mac_iter, int keytype, + OSSL_LIB_CTX *ctx, const char *propq, + PKCS12_create_cb *cb, void *cbarg); PKCS12_SAFEBAG *PKCS12_add_cert(STACK_OF(PKCS12_SAFEBAG) **pbags, X509 *cert); PKCS12_SAFEBAG *PKCS12_add_key(STACK_OF(PKCS12_SAFEBAG) **pbags, diff --git a/include/openssl/pkcs12err.h b/include/openssl/pkcs12err.h index 933c83299..abce37362 100644 --- a/include/openssl/pkcs12err.h +++ b/include/openssl/pkcs12err.h @@ -1,6 +1,6 @@ /* * Generated by util/mkerr.pl DO NOT EDIT - * Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2022 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -21,6 +21,7 @@ /* * PKCS12 reason codes. */ +# define PKCS12_R_CALLBACK_FAILED 115 # define PKCS12_R_CANT_PACK_STRUCTURE 100 # define PKCS12_R_CONTENT_TYPE_NOT_DATA 121 # define PKCS12_R_DECODE_ERROR 101 diff --git a/test/build.info b/test/build.info index b0b915caf..6d53ee12f 100644 --- a/test/build.info +++ b/test/build.info @@ -30,7 +30,7 @@ IF[{- !$disabled{tests} -}] PROGRAMS{noinst}= \ confdump \ versions \ - aborttest test_test pkcs12_format_test \ + aborttest test_test pkcs12_format_test pkcs12_api_test \ sanitytest rsa_complex exdatatest bntest \ ecstresstest gmdifftest pbelutest \ destest sha_test \ @@ -278,6 +278,10 @@ IF[{- !$disabled{tests} -}] INCLUDE[pkcs12_format_test]=../include ../apps/include DEPEND[pkcs12_format_test]=../libcrypto libtestutil.a + SOURCE[pkcs12_api_test]=pkcs12_api_test.c helpers/pkcs12.c + INCLUDE[pkcs12_api_test]=../include ../apps/include + DEPEND[pkcs12_api_test]=../libcrypto libtestutil.a + SOURCE[pkcs7_test]=pkcs7_test.c INCLUDE[pkcs7_test]=../include ../apps/include DEPEND[pkcs7_test]=../libcrypto libtestutil.a diff --git a/test/helpers/pkcs12.c b/test/helpers/pkcs12.c index a87683dc9..a5ea0d33e 100644 --- a/test/helpers/pkcs12.c +++ b/test/helpers/pkcs12.c @@ -338,13 +338,15 @@ static STACK_OF(PKCS12_SAFEBAG) *decode_contentinfo(STACK_OF(PKCS7) *safes, int * PKCS12 safeBag/attribute builder */ -static int add_attributes(PKCS12_SAFEBAG *bag, const PKCS12_ATTR *attrs) +static int add_attributes(PKCS12_SAFEBAG *bag, const PKCS12_ATTR *attr) { int ret = 0; int attr_nid; - const PKCS12_ATTR *p_attr = attrs; + const PKCS12_ATTR *p_attr = attr; + STACK_OF(X509_ATTRIBUTE)* attrs = NULL; + X509_ATTRIBUTE *x509_attr = NULL; - if (attrs == NULL) + if (attr == NULL) return 1; while (p_attr->oid != NULL) { @@ -358,6 +360,12 @@ static int add_attributes(PKCS12_SAFEBAG *bag, const PKCS12_ATTR *attrs) if (!TEST_true(PKCS12_add_localkeyid(bag, (unsigned char *)p_attr->value, strlen(p_attr->value)))) goto err; + } else if (attr_nid == NID_oracle_jdk_trustedkeyusage) { + attrs = (STACK_OF(X509_ATTRIBUTE)*)PKCS12_SAFEBAG_get0_attrs(bag); + x509_attr = X509_ATTRIBUTE_create(attr_nid, V_ASN1_OBJECT, OBJ_txt2obj(p_attr->value, 0)); + X509at_add1_attr(&attrs, x509_attr); + PKCS12_SAFEBAG_set0_attrs(bag, attrs); + X509_ATTRIBUTE_free(x509_attr); } else { /* Custom attribute values limited to ASCII in these tests */ if (!TEST_true(PKCS12_add1_attr_by_txt(bag, p_attr->oid, MBSTRING_ASC, diff --git a/test/helpers/pkcs12.h b/test/helpers/pkcs12.h index d1a3b93d3..f09013222 100644 --- a/test/helpers/pkcs12.h +++ b/test/helpers/pkcs12.h @@ -82,6 +82,7 @@ void add_keybag(PKCS12_BUILDER *pb, const unsigned char *bytes, int len, const PKCS12_ATTR *attrs, const PKCS12_ENC *enc); void add_secretbag(PKCS12_BUILDER *pb, int secret_nid, const char *secret, const PKCS12_ATTR *attrs); +void add_extra_attr(PKCS12_BUILDER *pb); /* Decode/check functions */ void start_check_pkcs12(PKCS12_BUILDER *pb); diff --git a/test/pkcs12_api_test.c b/test/pkcs12_api_test.c new file mode 100644 index 000000000..7f5fec030 --- /dev/null +++ b/test/pkcs12_api_test.c @@ -0,0 +1,302 @@ +/* + * Copyright 2022 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include +#include +#include + +#include "internal/nelem.h" + +#include +#include +#include +#include + +#include "testutil.h" +#include "helpers/pkcs12.h" + +static OSSL_LIB_CTX *testctx = NULL; +static OSSL_PROVIDER *nullprov = NULL; + +static int test_null_args(void) +{ + return TEST_false(PKCS12_parse(NULL, NULL, NULL, NULL, NULL)); +} + +static PKCS12 *PKCS12_load(const char *fpath) +{ + BIO *bio = NULL; + PKCS12 *p12 = NULL; + + bio = BIO_new_file(fpath, "rb"); + if (!TEST_ptr(bio)) + goto err; + + p12 = PKCS12_init_ex(NID_pkcs7_data, testctx, "provider=default"); + if (!TEST_ptr(p12)) + goto err; + + if (!TEST_true(p12 == d2i_PKCS12_bio(bio, &p12))) + goto err; + + BIO_free(bio); + + return p12; + +err: + BIO_free(bio); + PKCS12_free(p12); + return NULL; +} + +static const char *in_file = NULL; +static const char *in_pass = ""; +static int has_key = 0; +static int has_cert = 0; +static int has_ca = 0; + +static int changepass(PKCS12 *p12, EVP_PKEY *key, X509 *cert, STACK_OF(X509) *ca) +{ + int ret = 0; + PKCS12 *p12new = NULL; + EVP_PKEY *key2 = NULL; + X509 *cert2 = NULL; + STACK_OF(X509) *ca2 = NULL; + BIO *bio = NULL; + + if (!TEST_true(PKCS12_newpass(p12, in_pass, "NEWPASS"))) + goto err; + if (!TEST_ptr(bio = BIO_new(BIO_s_mem()))) + goto err; + if (!TEST_true(i2d_PKCS12_bio(bio, p12))) + goto err; + if (!TEST_ptr(p12new = PKCS12_init_ex(NID_pkcs7_data, testctx, "provider=default"))) + goto err; + if (!TEST_ptr(d2i_PKCS12_bio(bio, &p12new))) + goto err; + if (!TEST_true(PKCS12_parse(p12new, "NEWPASS", &key2, &cert2, &ca2))) + goto err; + if (has_key) { + if (!TEST_ptr(key2) || !TEST_int_eq(EVP_PKEY_eq(key, key2), 1)) + goto err; + } + if (has_cert) { + if (!TEST_ptr(cert2) || !TEST_int_eq(X509_cmp(cert, cert2), 0)) + goto err; + } + ret = 1; +err: + BIO_free(bio); + PKCS12_free(p12new); + EVP_PKEY_free(key2); + X509_free(cert2); + sk_X509_pop_free(ca2, X509_free); + return ret; +} + +static int pkcs12_parse_test(void) +{ + int ret = 0; + PKCS12 *p12 = NULL; + EVP_PKEY *key = NULL; + X509 *cert = NULL; + STACK_OF(X509) *ca = NULL; + + if (in_file != NULL) { + p12 = PKCS12_load(in_file); + if (!TEST_ptr(p12)) + goto err; + + if (!TEST_true(PKCS12_parse(p12, in_pass, &key, &cert, &ca))) + goto err; + + if ((has_key && !TEST_ptr(key)) || (!has_key && !TEST_ptr_null(key))) + goto err; + if ((has_cert && !TEST_ptr(cert)) || (!has_cert && !TEST_ptr_null(cert))) + goto err; + if ((has_ca && !TEST_ptr(ca)) || (!has_ca && !TEST_ptr_null(ca))) + goto err; + if (has_key && !changepass(p12, key, cert, ca)) + goto err; + } + ret = 1; +err: + PKCS12_free(p12); + EVP_PKEY_free(key); + X509_free(cert); + sk_X509_pop_free(ca, X509_free); + return TEST_true(ret); +} + +static int pkcs12_create_cb(PKCS12_SAFEBAG *bag, void *cbarg) +{ + int cb_ret = *((int*)cbarg); + return cb_ret; +} + +static PKCS12 *pkcs12_create_ex2_setup(EVP_PKEY **key, X509 **cert, STACK_OF(X509) **ca) +{ + PKCS12 *p12 = NULL; + p12 = PKCS12_load("out6.p12"); + if (!TEST_ptr(p12)) + goto err; + + if (!TEST_true(PKCS12_parse(p12, "", key, cert, ca))) + goto err; + + return p12; +err: + PKCS12_free(p12); + return NULL; +} + +static int pkcs12_create_ex2_test(int test) +{ + int ret = 0, cb_ret = 0; + PKCS12 *ptr = NULL, *p12 = NULL; + EVP_PKEY *key = NULL; + X509 *cert = NULL; + STACK_OF(X509) *ca = NULL; + + p12 = pkcs12_create_ex2_setup(&key, &cert, &ca); + if (!TEST_ptr(p12)) + goto err; + + if (test == 0) { + /* Confirm PKCS12_create_ex2 returns NULL */ + ptr = PKCS12_create_ex2(NULL, NULL, NULL, + NULL, NULL, NID_undef, NID_undef, + 0, 0, 0, + testctx, NULL, + NULL, NULL); + if (TEST_ptr(ptr)) + goto err; + + /* Can't proceed without a valid cert at least */ + if (!TEST_ptr(cert)) + goto err; + + /* Specified call back called - return success */ + cb_ret = 1; + ptr = PKCS12_create_ex2(NULL, NULL, NULL, + cert, NULL, NID_undef, NID_undef, + 0, 0, 0, + testctx, NULL, + pkcs12_create_cb, (void*)&cb_ret); + /* PKCS12 successfully created */ + if (!TEST_ptr(ptr)) + goto err; + } else if (test == 1) { + /* Specified call back called - return error*/ + cb_ret = -1; + ptr = PKCS12_create_ex2(NULL, NULL, NULL, + cert, NULL, NID_undef, NID_undef, + 0, 0, 0, + testctx, NULL, + pkcs12_create_cb, (void*)&cb_ret); + /* PKCS12 not created */ + if (TEST_ptr(ptr)) + goto err; + } else if (test == 2) { + /* Specified call back called - return failure */ + cb_ret = 0; + ptr = PKCS12_create_ex2(NULL, NULL, NULL, + cert, NULL, NID_undef, NID_undef, + 0, 0, 0, + testctx, NULL, + pkcs12_create_cb, (void*)&cb_ret); + /* PKCS12 successfully created */ + if (!TEST_ptr(ptr)) + goto err; + } + + ret = 1; +err: + PKCS12_free(p12); + PKCS12_free(ptr); + EVP_PKEY_free(key); + X509_free(cert); + sk_X509_pop_free(ca, X509_free); + return TEST_true(ret); +} + +typedef enum OPTION_choice { + OPT_ERR = -1, + OPT_EOF = 0, + OPT_IN_FILE, + OPT_IN_PASS, + OPT_IN_HAS_KEY, + OPT_IN_HAS_CERT, + OPT_IN_HAS_CA, + OPT_LEGACY, + OPT_TEST_ENUM +} OPTION_CHOICE; + +const OPTIONS *test_get_options(void) +{ + static const OPTIONS options[] = { + OPT_TEST_OPTIONS_DEFAULT_USAGE, + { "in", OPT_IN_FILE, '<', "PKCS12 input file" }, + { "pass", OPT_IN_PASS, 's', "PKCS12 input file password" }, + { "has-key", OPT_IN_HAS_KEY, 'n', "Whether the input file does contain an user key" }, + { "has-cert", OPT_IN_HAS_CERT, 'n', "Whether the input file does contain an user certificate" }, + { "has-ca", OPT_IN_HAS_CA, 'n', "Whether the input file does contain other certificate" }, + { "legacy", OPT_LEGACY, '-', "Test the legacy APIs" }, + { NULL } + }; + return options; +} + +int setup_tests(void) +{ + OPTION_CHOICE o; + + while ((o = opt_next()) != OPT_EOF) { + switch (o) { + case OPT_IN_FILE: + in_file = opt_arg(); + break; + case OPT_IN_PASS: + in_pass = opt_arg(); + break; + case OPT_LEGACY: + break; + case OPT_IN_HAS_KEY: + has_key = opt_int_arg(); + break; + case OPT_IN_HAS_CERT: + has_cert = opt_int_arg(); + break; + case OPT_IN_HAS_CA: + has_ca = opt_int_arg(); + break; + case OPT_TEST_CASES: + break; + default: + return 0; + } + } + + if (!test_get_libctx(&testctx, &nullprov, NULL, NULL, NULL)) { + OSSL_LIB_CTX_free(testctx); + testctx = NULL; + return 0; + } + + ADD_TEST(test_null_args); + ADD_TEST(pkcs12_parse_test); + ADD_ALL_TESTS(pkcs12_create_ex2_test, 3); + return 1; +} + +void cleanup_tests(void) +{ + OSSL_LIB_CTX_free(testctx); + OSSL_PROVIDER_unload(nullprov); +} diff --git a/test/pkcs12_format_test.c b/test/pkcs12_format_test.c index 7315b16b3..258a78d80 100644 --- a/test/pkcs12_format_test.c +++ b/test/pkcs12_format_test.c @@ -205,6 +205,19 @@ static const PKCS12_ATTR ATTRS2[] = { { NULL, NULL } }; +static const PKCS12_ATTR ATTRS3[] = { + { "friendlyName", "wildduk" }, + { "localKeyID", "1122334455" }, + { "oracle-jdk-trustedkeyusage", "anyExtendedKeyUsage" }, + { NULL, NULL } +}; + +static const PKCS12_ATTR ATTRS4[] = { + { "friendlyName", "wildduk" }, + { "localKeyID", "1122334455" }, + { NULL, NULL } +}; + static const PKCS12_ENC enc_default = { #ifndef OPENSSL_NO_DES NID_pbe_WithSHA1And3_Key_TripleDES_CBC, @@ -688,6 +701,84 @@ static int test_multiple_contents(void) return end_pkcs12_builder(pb); } +static int test_jdk_trusted_attr(void) +{ + PKCS12_BUILDER *pb = new_pkcs12_builder("jdk_trusted.p12"); + + /* Generate/encode */ + start_pkcs12(pb); + + start_contentinfo(pb); + + add_certbag(pb, CERT1, sizeof(CERT1), ATTRS3); + + end_contentinfo(pb); + + end_pkcs12_with_mac(pb, &mac_default); + + /* Read/decode */ + start_check_pkcs12_with_mac(pb, &mac_default); + + start_check_contentinfo(pb); + + check_certbag(pb, CERT1, sizeof(CERT1), ATTRS3); + + end_check_contentinfo(pb); + + end_check_pkcs12(pb); + + return end_pkcs12_builder(pb); +} + +static int test_set0_attrs(void) +{ + PKCS12_BUILDER *pb = new_pkcs12_builder("attrs.p12"); + PKCS12_SAFEBAG *bag = NULL; + STACK_OF(X509_ATTRIBUTE) *attrs = NULL; + X509_ATTRIBUTE *attr = NULL; + + start_pkcs12(pb); + + start_contentinfo(pb); + + /* Add cert and attrs (name/locakkey only) */ + add_certbag(pb, CERT1, sizeof(CERT1), ATTRS4); + + bag = sk_PKCS12_SAFEBAG_value(pb->bags, 0); + attrs = (STACK_OF(X509_ATTRIBUTE)*)PKCS12_SAFEBAG_get0_attrs(bag); + + /* Create new attr, add to list and confirm return attrs is not NULL */ + attr = X509_ATTRIBUTE_create(NID_oracle_jdk_trustedkeyusage, V_ASN1_OBJECT, OBJ_txt2obj("anyExtendedKeyUsage", 0)); + X509at_add1_attr(&attrs, attr); + PKCS12_SAFEBAG_set0_attrs(bag, attrs); + attrs = (STACK_OF(X509_ATTRIBUTE)*)PKCS12_SAFEBAG_get0_attrs(bag); + X509_ATTRIBUTE_free(attr); + if(!TEST_ptr(attrs)) { + goto err; + } + + end_contentinfo(pb); + + end_pkcs12(pb); + + /* Read/decode */ + start_check_pkcs12(pb); + + start_check_contentinfo(pb); + + /* Use existing check functionality to confirm cert bag attrs identical to ATTRS3 */ + check_certbag(pb, CERT1, sizeof(CERT1), ATTRS3); + + end_check_contentinfo(pb); + + end_check_pkcs12(pb); + + return end_pkcs12_builder(pb); + +err: + return 0; +} + #ifndef OPENSSL_NO_DES static int pkcs12_create_test(void) { @@ -863,6 +954,8 @@ int setup_tests(void) ADD_TEST(test_cert_key_encrypted_content); ADD_TEST(test_single_secret_encrypted_content); ADD_TEST(test_multiple_contents); + ADD_TEST(test_jdk_trusted_attr); + ADD_TEST(test_set0_attrs); return 1; } diff --git a/test/recipes/80-test_pkcs12.t b/test/recipes/80-test_pkcs12.t index 8afd61269..f95e69488 100644 --- a/test/recipes/80-test_pkcs12.t +++ b/test/recipes/80-test_pkcs12.t @@ -9,7 +9,7 @@ use strict; use warnings; -use OpenSSL::Test qw/:DEFAULT srctop_file/; +use OpenSSL::Test qw/:DEFAULT srctop_file with/; use OpenSSL::Test::Utils; use Encode; @@ -54,7 +54,7 @@ if (eval { require Win32::API; 1; }) { } $ENV{OPENSSL_WIN32_UTF8}=1; -plan tests => 12; +plan tests => 26; # Test different PKCS#12 formats ok(run(test(["pkcs12_format_test"])), "test pkcs12 formats"); @@ -72,9 +72,10 @@ ok(run(app(["openssl", "pkcs12", "-noout", my @path = qw(test certs); my $outfile1 = "out1.p12"; my $outfile2 = "out2.p12"; -my $outfile3 = "out3.p12"; my $outfile4 = "out4.p12"; my $outfile5 = "out5.p12"; +my $outfile6 = "out6.p12"; +my $outfile7 = "out7.p12"; # Test the -chain option with -untrusted ok(run(app(["openssl", "pkcs12", "-export", "-chain", @@ -127,7 +128,101 @@ my @pkcs12info = run(app(["openssl", "pkcs12", "-info", "-in", $outfile5, # Test that with one input certificate, we get one output certificate ok(grep(/subject=CN = server.example/, @pkcs12info) == 1, "test one cert in output"); + # Test that the expected friendly name is present in the output ok(grep(/testname/, @pkcs12info) == 1, "test friendly name in output"); +# Test there's no Oracle Trusted Key Usage bag attribute +ok(grep(/Trusted key usage (Oracle)/, @pkcs12info) == 0, + "test no oracle trusted key usage"); + +# Test export of PEM file with both cert and key, without password. +# -nomac necessary to avoid legacy provider requirement +{ + ok(run(app(["openssl", "pkcs12", "-export", + "-inkey", srctop_file(@path, "cert-key-cert.pem"), + "-in", srctop_file(@path, "cert-key-cert.pem"), + "-passout", "pass:", + "-nomac", "-out", $outfile6], stderr => "outerr6.txt")), + "test_export_pkcs12_cert_key_cert_no_pass"); + open DATA, "outerr6.txt"; + my @match = grep /:error:/, ; + close DATA; + ok(scalar @match > 0 ? 0 : 1, "test_export_pkcs12_outerr6_empty"); +} + +# Test some bad pkcs12 files +my $bad1 = srctop_file("test", "recipes", "80-test_pkcs12_data", "bad1.p12"); +my $bad2 = srctop_file("test", "recipes", "80-test_pkcs12_data", "bad2.p12"); +my $bad3 = srctop_file("test", "recipes", "80-test_pkcs12_data", "bad3.p12"); + +with({ exit_checker => sub { return shift == 1; } }, + sub { + ok(run(app(["openssl", "pkcs12", "-in", $bad1, "-password", "pass:"])), + "test bad pkcs12 file 1"); + + ok(run(app(["openssl", "pkcs12", "-in", $bad1, "-password", "pass:", + "-nomacver"])), + "test bad pkcs12 file 1 (nomacver)"); + + ok(run(app(["openssl", "pkcs12", "-in", $bad2, "-password", "pass:"])), + "test bad pkcs12 file 2"); + + ok(run(app(["openssl", "pkcs12", "-in", $bad3, "-password", "pass:"])), + "test bad pkcs12 file 3"); + }); + +# Test with Oracle Trusted Key Usage specified in openssl.cnf +{ + $ENV{OPENSSL_CONF} = srctop_file("test", "recipes", "80-test_pkcs12_data", "jdk_trusted.cnf"); + ok(run(app(["openssl", "pkcs12", "-export", "-out", $outfile7, + "-in", srctop_file(@path, "ee-cert.pem"), + "-nokeys", "-passout", "pass:", "-certpbe", "NONE"])), + "test nokeys single cert"); + + my @pkcs12info = run(app(["openssl", "pkcs12", "-info", "-in", $outfile7, + "-passin", "pass:"]), capture => 1); + ok(grep(/Trusted key usage \(Oracle\): Any Extended Key Usage \(2.5.29.37.0\)/, @pkcs12info) == 1, + "test oracle trusted key usage is set"); + + delete $ENV{OPENSSL_CONF} +} + +# Tests for pkcs12_parse +ok(run(test(["pkcs12_api_test", + "-in", $outfile1, + "-has-ca", 1, + ])), "Test pkcs12_parse()"); + +SKIP: { + skip "Skipping PKCS#12 parse test because DES is disabled in this build", 1 + if disabled("des"); + ok(run(test(["pkcs12_api_test", + "-in", $outfile2, + "-pass", "v3-certs", + "-has-ca", 1, + ])), "Test pkcs12_parse()"); +} + +ok(run(test(["pkcs12_api_test", + "-in", $outfile4, + "-pass", "v3-certs", + "-has-ca", 1, + "-has-key", 1, + "-has-cert", 1, + ])), "Test pkcs12_parse()"); + +ok(run(test(["pkcs12_api_test", + "-in", $outfile5, + "-has-ca", 1, + ])), "Test pkcs12_parse()"); + +ok(run(test(["pkcs12_api_test", + "-in", $outfile6, + "-pass", "", + "-has-ca", 1, + "-has-key", 1, + "-has-cert", 1, + ])), "Test pkcs12_parse()"); + SetConsoleOutputCP($savedcp) if (defined($savedcp)); diff --git a/test/recipes/80-test_pkcs12_data/bad1.p12 b/test/recipes/80-test_pkcs12_data/bad1.p12 new file mode 100644 index 000000000..8f3387c7e Binary files /dev/null and b/test/recipes/80-test_pkcs12_data/bad1.p12 differ diff --git a/test/recipes/80-test_pkcs12_data/bad2.p12 b/test/recipes/80-test_pkcs12_data/bad2.p12 new file mode 100644 index 000000000..113cb6f1c Binary files /dev/null and b/test/recipes/80-test_pkcs12_data/bad2.p12 differ diff --git a/test/recipes/80-test_pkcs12_data/bad3.p12 b/test/recipes/80-test_pkcs12_data/bad3.p12 new file mode 100644 index 000000000..ef86a1d86 Binary files /dev/null and b/test/recipes/80-test_pkcs12_data/bad3.p12 differ diff --git a/test/recipes/80-test_pkcs12_data/jdk_trusted.cnf b/test/recipes/80-test_pkcs12_data/jdk_trusted.cnf new file mode 100644 index 000000000..57d11fccf --- /dev/null +++ b/test/recipes/80-test_pkcs12_data/jdk_trusted.cnf @@ -0,0 +1,8 @@ +# +[pkcs12] +certBagAttr = cb_attr + +# Uncomment this if you need Java compatible PKCS12 files +[cb_attr] +jdkTrustedKeyUsage = anyExtendedKeyUsage + diff --git a/util/libcrypto.num b/util/libcrypto.num index 8a538ff70..68c6edbf5 100644 --- a/util/libcrypto.num +++ b/util/libcrypto.num @@ -5638,3 +5638,8 @@ SM2_THRESHOLD_sign3 5953 3_0_3 EXIST::FUNCTION:SM2_THRESHOLD SM2_THRESHOLD_decrypt1 5954 3_0_3 EXIST::FUNCTION:SM2_THRESHOLD SM2_THRESHOLD_decrypt2 5955 3_0_3 EXIST::FUNCTION:SM2_THRESHOLD SM2_THRESHOLD_decrypt3 5956 3_0_3 EXIST::FUNCTION:SM2_THRESHOLD +PKCS12_SAFEBAG_set0_attrs 5957 3_0_3 EXIST::FUNCTION: +PKCS12_create_ex2 5958 3_0_3 EXIST::FUNCTION: +ASN1_item_unpack_ex 5960 3_0_3 EXIST::FUNCTION: +PKCS12_SAFEBAG_get1_cert_ex 5961 3_0_3 EXIST::FUNCTION: +PKCS12_SAFEBAG_get1_crl_ex 5962 3_0_3 EXIST::FUNCTION: diff --git a/util/other.syms b/util/other.syms index 4eb499750..d643f5cad 100644 --- a/util/other.syms +++ b/util/other.syms @@ -137,6 +137,7 @@ custom_ext_free_cb datatype custom_ext_parse_cb datatype pem_password_cb datatype ssl_ct_validation_cb datatype +PKCS12_create_cb datatype # ASN1_BIT_STRING_digest define BIO_append_filename define