From e51574599662486e2e54fec03eb69003a8998fa5 Mon Sep 17 00:00:00 2001 From: Nicolas Williams Date: Fri, 6 Dec 2019 17:11:01 -0600 Subject: [PATCH] hx509: private key exclusion options Add two ways to exclude private keys when dealing with an hx509 certificate store. One as a load option (load no private keys, never add private keys), one as a store option (store no private keys). This is useful for CA code so it can have a single store with the issuer's credentials _and_ the chain for it, and copy those to a store with the issued certificate and _not_ accidentally include the issuer's private key. It would be much safer still to flip the default for this flag, but that could break out-of-tree libhx509 dependents. --- lib/hx509/cert.c | 20 +++++++++++ lib/hx509/hx509.h | 5 +++ lib/hx509/hxtool-commands.in | 10 ++++++ lib/hx509/hxtool.c | 29 +++++++++++----- lib/hx509/keyset.c | 29 +++++++++++++--- lib/hx509/ks_file.c | 67 +++++++++++++++++++----------------- lib/hx509/ks_keychain.c | 7 ++++ lib/hx509/ks_p11.c | 7 ++++ lib/hx509/ks_p12.c | 64 ++++++++++++++++++++++++---------- 9 files changed, 177 insertions(+), 61 deletions(-) diff --git a/lib/hx509/cert.c b/lib/hx509/cert.c index dc5444d0a..598549cea 100644 --- a/lib/hx509/cert.c +++ b/lib/hx509/cert.c @@ -300,6 +300,26 @@ hx509_cert_init(hx509_context context, const Certificate *c, heim_error_t *error return cert; } +/** + * Copy a certificate object, but drop any private key assignment. + * + * @param context A hx509 context. + * @param src Certificate object + * @param error + * + * @return Returns an hx509 certificate + * + * @ingroup hx509_cert + */ + +HX509_LIB_FUNCTION hx509_cert HX509_LIB_CALL +hx509_cert_copy_no_private_key(hx509_context context, + hx509_cert src, + heim_error_t *error) +{ + return hx509_cert_init(context, src->data, error); +} + /** * Allocate and init an hx509 certificate object containing only a private key * (but no Certificate). diff --git a/lib/hx509/hx509.h b/lib/hx509/hx509.h index e8158e4d7..778a02ba4 100644 --- a/lib/hx509/hx509.h +++ b/lib/hx509/hx509.h @@ -154,6 +154,11 @@ typedef enum { /* flags to hx509_certs_init */ #define HX509_CERTS_CREATE 0x01 #define HX509_CERTS_UNPROTECT_ALL 0x02 +#define HX509_CERTS_NO_PRIVATE_KEYS 0x04 + +/* flags to hx509_certs_store */ +#define HX509_CERTS_STORE_NO_PRIVATE_KEYS 0x04 + /* flags to hx509_set_error_string */ #define HX509_ERROR_APPEND 0x01 diff --git a/lib/hx509/hxtool-commands.in b/lib/hx509/hxtool-commands.in index a75d539c3..556b1888e 100644 --- a/lib/hx509/hxtool-commands.in +++ b/lib/hx509/hxtool-commands.in @@ -996,6 +996,16 @@ command = { argument = "datetime" help = "check that the certificate's notBefore is after the given time" } + option = { + long = "has-private-key" + type = "flag" + help = "check that the certificate has a private key" + } + option = { + long = "lacks-private-key" + type = "flag" + help = "check that the certificate does not have a private key" + } name = "acert" min_args = "1" max_args = "1" diff --git a/lib/hx509/hxtool.c b/lib/hx509/hxtool.c index d9c315c34..ac7ba0960 100644 --- a/lib/hx509/hxtool.c +++ b/lib/hx509/hxtool.c @@ -2677,6 +2677,7 @@ acert1_validity(struct acert_options *opt, hx509_cert cert) time_t not_after_eq = 0; time_t not_after_lt = 0; time_t not_after_gt = 0; + int ret = 0; if (opt->valid_now_flag) { time_t now = time(NULL); @@ -2684,12 +2685,12 @@ acert1_validity(struct acert_options *opt, hx509_cert cert) if (hx509_cert_get_notBefore(cert) > now) { if (opt->verbose_flag) fprintf(stderr, "Certificate not valid yet\n"); - return -1; + ret = -1; } if (hx509_cert_get_notAfter(cert) < now) { if (opt->verbose_flag) fprintf(stderr, "Certificate currently expired\n"); - return -1; + ret = -1; } } if (opt->valid_at_string) { @@ -2699,13 +2700,13 @@ acert1_validity(struct acert_options *opt, hx509_cert cert) if (opt->verbose_flag) fprintf(stderr, "Certificate not valid yet at %s\n", opt->valid_at_string); - return -1; + ret = -1; } if (hx509_cert_get_notAfter(cert) < at) { if (opt->verbose_flag) fprintf(stderr, "Certificate expired before %s\n", opt->valid_at_string); - return -1; + ret = -1; } } @@ -2727,17 +2728,29 @@ acert1_validity(struct acert_options *opt, hx509_cert cert) (not_before_gt && hx509_cert_get_notBefore(cert) <= not_before_gt)) { if (opt->verbose_flag) fprintf(stderr, "Certificate notBefore not as requested\n"); - return -1; + ret = -1; } if ((not_after_eq && hx509_cert_get_notAfter(cert) != not_after_eq) || (not_after_lt && hx509_cert_get_notAfter(cert) >= not_after_lt) || (not_after_gt && hx509_cert_get_notAfter(cert) <= not_after_gt)) { if (opt->verbose_flag) fprintf(stderr, "Certificate notAfter not as requested\n"); - return -1; + ret = -1; } - return 0; + if (opt->has_private_key_flag && !hx509_cert_have_private_key(cert)) { + if (opt->verbose_flag) + fprintf(stderr, "Certificate does not have a private key\n"); + ret = -1; + } + + if (opt->lacks_private_key_flag && hx509_cert_have_private_key(cert)) { + if (opt->verbose_flag) + fprintf(stderr, "Certificate does not have a private key\n"); + ret = -1; + } + + return ret; } static int @@ -2810,7 +2823,7 @@ acert1(struct acert_options *opt, size_t cert_num, hx509_cert cert, int *matched if (e == NULL) { if (wanted) return -1; - return acert1_validity(opt, cert);; + return acert1_validity(opt, cert); } for (i = 0; i < e->len; i++) { diff --git a/lib/hx509/keyset.c b/lib/hx509/keyset.c index f89dfbef3..0b852dc51 100644 --- a/lib/hx509/keyset.c +++ b/lib/hx509/keyset.c @@ -63,6 +63,7 @@ struct hx509_certs_data { unsigned int ref; struct hx509_keyset_ops *ops; void *ops_data; + int flags; }; static struct hx509_keyset_ops * @@ -103,6 +104,7 @@ _hx509_ks_register(hx509_context context, struct hx509_keyset_ops *ops) * @param flags list of flags: * - HX509_CERTS_CREATE create a new keystore of the specific TYPE. * - HX509_CERTS_UNPROTECT_ALL fails if any private key failed to be extracted. + * - HX509_CERTS_NO_PRIVATE_KEYS does not load or permit adding private keys * @param lock a lock that unlocks the certificates store, use NULL to * select no password/certifictes/prompt lock (see @ref page_lock). * @param certs return pointer, free with hx509_certs_free(). @@ -158,6 +160,7 @@ hx509_certs_init(hx509_context context, hx509_clear_error_string(context); return ENOMEM; } + c->flags = flags; c->ops = ops; c->ref = 1; @@ -201,9 +204,12 @@ hx509_certs_destroy(hx509_context context, /** * Write the certificate store to stable storage. * + * Use the HX509_CERTS_STORE_NO_PRIVATE_KEYS flag to ensure that no private + * keys are stored, even if added. + * * @param context A hx509 context. * @param certs a certificate store to store. - * @param flags currently unused, use 0. + * @param flags currently one flag is defined: HX509_CERTS_STORE_NO_PRIVATE_KEYS * @param lock a lock that unlocks the certificates store, use NULL to * select no password/certifictes/prompt lock (see @ref page_lock). * @@ -485,6 +491,9 @@ hx509_ci_print_names(hx509_context context, void *ctx, hx509_cert c) HX509_LIB_FUNCTION int HX509_LIB_CALL hx509_certs_add(hx509_context context, hx509_certs certs, hx509_cert cert) { + hx509_cert copy = NULL; + int ret; + if (certs->ops->add == NULL) { hx509_set_error_string(context, 0, ENOENT, "Keyset type %s doesn't support add operation", @@ -492,7 +501,20 @@ hx509_certs_add(hx509_context context, hx509_certs certs, hx509_cert cert) return ENOENT; } - return (*certs->ops->add)(context, certs, certs->ops_data, cert); + if ((certs->flags & HX509_CERTS_NO_PRIVATE_KEYS) && + hx509_cert_have_private_key(cert)) { + if ((copy = hx509_cert_copy_no_private_key(context, cert, + NULL)) == NULL) { + hx509_set_error_string(context, 0, ENOMEM, + "Could not add certificate to store"); + return ENOMEM; + } + cert = copy; + } + + ret = (*certs->ops->add)(context, certs, certs->ops_data, cert); + hx509_cert_free(copy); + return ret; } /** @@ -637,8 +659,7 @@ certs_merge_func(hx509_context context, void *ctx, hx509_cert c) } /** - * Merge a certificate store into another. The from store is keep - * intact. + * Merge one certificate store into another. The from store is kept intact. * * @param context a hx509 context. * @param to the store to merge into. diff --git a/lib/hx509/ks_file.c b/lib/hx509/ks_file.c index 886038eb9..d406946d8 100644 --- a/lib/hx509/ks_file.c +++ b/lib/hx509/ks_file.c @@ -49,7 +49,7 @@ struct ks_file { */ static int -parse_certificate(hx509_context context, const char *fn, +parse_certificate(hx509_context context, const char *fn, int flags, struct hx509_collector *c, const hx509_pem_header *headers, const void *data, size_t len, @@ -74,6 +74,7 @@ parse_certificate(hx509_context context, const char *fn, static int try_decrypt(hx509_context context, struct hx509_collector *collector, + int flags, const AlgorithmIdentifier *alg, const EVP_CIPHER *c, const void *ivdata, @@ -122,12 +123,9 @@ try_decrypt(hx509_context context, EVP_CIPHER_CTX_cleanup(&ctx); } - ret = _hx509_collector_private_key_add(context, - collector, - alg, - NULL, - &clear, - NULL); + if (!(flags & HX509_CERTS_NO_PRIVATE_KEYS)) + ret = _hx509_collector_private_key_add(context, collector, alg, NULL, + &clear, NULL); memset_s(clear.data, clear.length, 0, clear.length); free(clear.data); @@ -138,7 +136,7 @@ out: } static int -parse_pkcs8_private_key(hx509_context context, const char *fn, +parse_pkcs8_private_key(hx509_context context, const char *fn, int flags, struct hx509_collector *c, const hx509_pem_header *headers, const void *data, size_t length, @@ -146,28 +144,28 @@ parse_pkcs8_private_key(hx509_context context, const char *fn, { PKCS8PrivateKeyInfo ki; heim_octet_string keydata; - int ret; ret = decode_PKCS8PrivateKeyInfo(data, length, &ki, NULL); if (ret) return ret; - keydata.data = rk_UNCONST(data); - keydata.length = length; - - ret = _hx509_collector_private_key_add(context, - c, - &ki.privateKeyAlgorithm, - NULL, - &ki.privateKey, - &keydata); + if (!(flags & HX509_CERTS_NO_PRIVATE_KEYS)) { + keydata.data = rk_UNCONST(data); + keydata.length = length; + ret = _hx509_collector_private_key_add(context, + c, + &ki.privateKeyAlgorithm, + NULL, + &ki.privateKey, + &keydata); + } free_PKCS8PrivateKeyInfo(&ki); return ret; } static int -parse_pem_private_key(hx509_context context, const char *fn, +parse_pem_private_key(hx509_context context, const char *fn, int flags, struct hx509_collector *c, const hx509_pem_header *headers, const void *data, size_t len, @@ -271,7 +269,7 @@ parse_pem_private_key(hx509_context context, const char *fn, password = pw->val[i]; passwordlen = strlen(password); - ret = try_decrypt(context, c, ai, cipher, ivdata, + ret = try_decrypt(context, c, flags, ai, cipher, ivdata, password, passwordlen, data, len); if (ret == 0) { decrypted = 1; @@ -292,21 +290,21 @@ parse_pem_private_key(hx509_context context, const char *fn, ret = hx509_lock_prompt(lock, &prompt); if (ret == 0) - ret = try_decrypt(context, c, ai, cipher, ivdata, password, - strlen(password), data, len); + ret = try_decrypt(context, c, flags, ai, cipher, ivdata, + password, strlen(password), data, len); /* XXX add password to lock password collection ? */ memset_s(password, sizeof(password), 0, sizeof(password)); } free(ivdata); - } else { + } else if (!(flags & HX509_CERTS_NO_PRIVATE_KEYS)) { heim_octet_string keydata; keydata.data = rk_UNCONST(data); keydata.length = len; - ret = _hx509_collector_private_key_add(context, c, ai, NULL, - &keydata, NULL); + ret = _hx509_collector_private_key_add(context, c, ai, NULL, + &keydata, NULL); } return ret; @@ -315,7 +313,7 @@ parse_pem_private_key(hx509_context context, const char *fn, struct pem_formats { const char *name; - int (*func)(hx509_context, const char *, struct hx509_collector *, + int (*func)(hx509_context, const char *, int, struct hx509_collector *, const hx509_pem_header *, const void *, size_t, const AlgorithmIdentifier *); const AlgorithmIdentifier *(*ai)(void); @@ -347,11 +345,12 @@ pem_func(hx509_context context, const char *type, const char *q = formats[j].name; if (strcasecmp(type, q) == 0) { const AlgorithmIdentifier *ai = NULL; + if (formats[j].ai != NULL) ai = (*formats[j].ai)(); - ret = (*formats[j].func)(context, NULL, pem_ctx->c, - header, data, len, ai); + ret = (*formats[j].func)(context, NULL, pem_ctx->flags, pem_ctx->c, + header, data, len, ai); if (ret && (pem_ctx->flags & HX509_CERTS_UNPROTECT_ALL)) { hx509_set_error_string(context, HX509_ERROR_APPEND, ret, "Failed parseing PEM format %s", type); @@ -468,10 +467,12 @@ file_init_common(hx509_context context, for (i = 0; i < sizeof(formats)/sizeof(formats[0]); i++) { const AlgorithmIdentifier *ai = NULL; + if (formats[i].ai != NULL) ai = (*formats[i].ai)(); - ret = (*formats[i].func)(context, p, pem_ctx.c, NULL, ptr, length, ai); + ret = (*formats[i].func)(context, p, pem_ctx.flags, pem_ctx.c, + NULL, ptr, length, ai); if (ret == 0) break; } @@ -539,6 +540,7 @@ file_free(hx509_certs certs, void *data) struct store_ctx { FILE *f; outformat format; + int store_flags; }; static int HX509_LIB_CALL @@ -563,7 +565,8 @@ store_func(hx509_context context, void *ctx, hx509_cert c) if (data.data) { fwrite(data.data, data.length, 1, sc->f); free(data.data); - } else if (_hx509_cert_private_key_exportable(c)) { + } else if (_hx509_cert_private_key_exportable(c) && + !(sc->store_flags & HX509_CERTS_STORE_NO_PRIVATE_KEYS)) { hx509_private_key key = _hx509_cert_private_key(c); ret = _hx509_private_key_export(context, key, @@ -573,7 +576,8 @@ store_func(hx509_context context, void *ctx, hx509_cert c) } break; case USE_PEM: - if (_hx509_cert_private_key_exportable(c)) { + if (_hx509_cert_private_key_exportable(c) && + !(sc->store_flags & HX509_CERTS_STORE_NO_PRIVATE_KEYS)) { heim_octet_string priv_key; hx509_private_key key = _hx509_cert_private_key(c); @@ -658,6 +662,7 @@ file_store(hx509_context context, return ret; } rk_cloexec_file(sc.f); + sc.store_flags = flags; sc.format = ksf->format; ret = hx509_certs_iter_f(context, ksf->certs, store_func, &sc); diff --git a/lib/hx509/ks_keychain.c b/lib/hx509/ks_keychain.c index 44dca03a3..3243ee8b2 100644 --- a/lib/hx509/ks_keychain.c +++ b/lib/hx509/ks_keychain.c @@ -328,6 +328,13 @@ keychain_init(hx509_context context, { struct ks_keychain *ctx; + if (flags & HX509_CERTS_NO_PRIVATE_KEYS) { + hx509_set_error_string(context, 0, ENOTSUP, + "KEYCHAIN store does not support not reading " + "private keys"); + return ENOTSUP; + } + ctx = calloc(1, sizeof(*ctx)); if (ctx == NULL) { hx509_clear_error_string(context); diff --git a/lib/hx509/ks_p11.c b/lib/hx509/ks_p11.c index 1826282b2..289fb4ecc 100644 --- a/lib/hx509/ks_p11.c +++ b/lib/hx509/ks_p11.c @@ -820,6 +820,13 @@ p11_init(hx509_context context, *data = NULL; + if (flags & HX509_CERTS_NO_PRIVATE_KEYS) { + hx509_set_error_string(context, 0, ENOTSUP, + "PKCS#11 store does not support " + "HX509_CERTS_NO_PRIVATE_KEYS flag"); + return ENOTSUP; + } + if (residue == NULL || residue[0] == '\0') { hx509_set_error_string(context, 0, EINVAL, "PKCS#11 store not specified"); diff --git a/lib/hx509/ks_p12.c b/lib/hx509/ks_p12.c index 2838e8129..6fd7cd105 100644 --- a/lib/hx509/ks_p12.c +++ b/lib/hx509/ks_p12.c @@ -36,10 +36,12 @@ struct ks_pkcs12 { hx509_certs certs; char *fn; + unsigned int store_no_priv_keys; }; typedef int (*collector_func)(hx509_context, struct hx509_collector *, + int, const void *, size_t, const PKCS12_Attributes *); @@ -49,8 +51,9 @@ struct type { }; static void -parse_pkcs12_type(hx509_context, struct hx509_collector *, const heim_oid *, - const void *, size_t, const PKCS12_Attributes *); +parse_pkcs12_type(hx509_context, struct hx509_collector *, int, + const heim_oid *, const void *, size_t, + const PKCS12_Attributes *); static const PKCS12_Attribute * @@ -68,6 +71,7 @@ find_attribute(const PKCS12_Attributes *attrs, const heim_oid *oid) static int keyBag_parser(hx509_context context, struct hx509_collector *c, + int flags, const void *data, size_t length, const PKCS12_Attributes *attrs) { @@ -76,6 +80,9 @@ keyBag_parser(hx509_context context, const heim_octet_string *os = NULL; int ret; + if (flags & HX509_CERTS_NO_PRIVATE_KEYS) + return 0; + attr = find_attribute(attrs, &asn1_oid_id_pkcs_9_at_localKeyId); if (attr) os = &attr->attrValues; @@ -97,6 +104,7 @@ keyBag_parser(hx509_context context, static int ShroudedKeyBag_parser(hx509_context context, struct hx509_collector *c, + int flags, const void *data, size_t length, const PKCS12_Attributes *attrs) { @@ -119,7 +127,8 @@ ShroudedKeyBag_parser(hx509_context context, if (ret) return ret; - ret = keyBag_parser(context, c, content.data, content.length, attrs); + ret = keyBag_parser(context, c, flags, content.data, content.length, + attrs); der_free_octet_string(&content); return ret; } @@ -127,6 +136,7 @@ ShroudedKeyBag_parser(hx509_context context, static int certBag_parser(hx509_context context, struct hx509_collector *c, + int flags, const void *data, size_t length, const PKCS12_Attributes *attrs) { @@ -191,6 +201,7 @@ certBag_parser(hx509_context context, static int parse_safe_content(hx509_context context, struct hx509_collector *c, + int flags, const unsigned char *p, size_t len) { PKCS12_SafeContents sc; @@ -206,6 +217,7 @@ parse_safe_content(hx509_context context, for (i = 0; i < sc.len ; i++) parse_pkcs12_type(context, c, + flags, &sc.val[i].bagId, sc.val[i].bagValue.data, sc.val[i].bagValue.length, @@ -218,6 +230,7 @@ parse_safe_content(hx509_context context, static int safeContent_parser(hx509_context context, struct hx509_collector *c, + int flags, const void *data, size_t length, const PKCS12_Attributes *attrs) { @@ -227,7 +240,7 @@ safeContent_parser(hx509_context context, ret = decode_PKCS12_OctetString(data, length, &os, NULL); if (ret) return ret; - ret = parse_safe_content(context, c, os.data, os.length); + ret = parse_safe_content(context, c, flags, os.data, os.length); der_free_octet_string(&os); return ret; } @@ -235,6 +248,7 @@ safeContent_parser(hx509_context context, static int encryptedData_parser(hx509_context context, struct hx509_collector *c, + int flags, const void *data, size_t length, const PKCS12_Attributes *attrs) { @@ -253,7 +267,8 @@ encryptedData_parser(hx509_context context, return ret; if (der_heim_oid_cmp(&contentType, &asn1_oid_id_pkcs7_data) == 0) - ret = parse_safe_content(context, c, content.data, content.length); + ret = parse_safe_content(context, c, flags, + content.data, content.length); der_free_octet_string(&content); der_free_oid(&contentType); @@ -263,6 +278,7 @@ encryptedData_parser(hx509_context context, static int envelopedData_parser(hx509_context context, struct hx509_collector *c, + int flags, const void *data, size_t length, const PKCS12_Attributes *attrs) { @@ -290,7 +306,8 @@ envelopedData_parser(hx509_context context, } if (der_heim_oid_cmp(&contentType, &asn1_oid_id_pkcs7_data) == 0) - ret = parse_safe_content(context, c, content.data, content.length); + ret = parse_safe_content(context, c, flags, + content.data, content.length); der_free_octet_string(&content); der_free_oid(&contentType); @@ -311,6 +328,7 @@ struct type bagtypes[] = { static void parse_pkcs12_type(hx509_context context, struct hx509_collector *c, + int flags, const heim_oid *oid, const void *data, size_t length, const PKCS12_Attributes *attrs) @@ -319,7 +337,7 @@ parse_pkcs12_type(hx509_context context, for (i = 0; i < sizeof(bagtypes)/sizeof(bagtypes[0]); i++) if (der_heim_oid_cmp(bagtypes[i].oid, oid) == 0) - (*bagtypes[i].func)(context, c, data, length, attrs); + (*bagtypes[i].func)(context, c, flags, data, length, attrs); } static int @@ -429,6 +447,7 @@ p12_init(hx509_context context, for (i = 0; i < as.len; i++) parse_pkcs12_type(context, c, + flags, &as.val[i].contentType, as.val[i].content->data, as.val[i].content->length, @@ -492,10 +511,15 @@ addBag(hx509_context context, return 0; } +struct store_func_ctx { + PKCS12_AuthenticatedSafe as; + int store_flags; +}; + static int HX509_LIB_CALL -store_func(hx509_context context, void *ctx, hx509_cert c) +store_func(hx509_context context, void *d, hx509_cert c) { - PKCS12_AuthenticatedSafe *as = ctx; + struct store_func_ctx *ctx = d; PKCS12_OctetString os; PKCS12_CertBag cb; size_t size; @@ -528,9 +552,11 @@ store_func(hx509_context context, void *ctx, hx509_cert c) if (ret) goto out; - ret = addBag(context, as, &asn1_oid_id_pkcs12_certBag, os.data, os.length); + ret = addBag(context, &ctx->as, &asn1_oid_id_pkcs12_certBag, os.data, + os.length); - if (_hx509_cert_private_key_exportable(c)) { + if (_hx509_cert_private_key_exportable(c) && + !(ctx->store_flags & HX509_CERTS_STORE_NO_PRIVATE_KEYS)) { hx509_private_key key = _hx509_cert_private_key(c); PKCS8PrivateKeyInfo pki; @@ -561,7 +587,8 @@ store_func(hx509_context context, void *ctx, hx509_cert c) if (ret) return ret; - ret = addBag(context, as, &asn1_oid_id_pkcs12_keyBag, os.data, os.length); + ret = addBag(context, &ctx->as, &asn1_oid_id_pkcs12_keyBag, os.data, + os.length); if (ret) return ret; } @@ -576,21 +603,22 @@ p12_store(hx509_context context, { struct ks_pkcs12 *p12 = data; PKCS12_PFX pfx; - PKCS12_AuthenticatedSafe as; + struct store_func_ctx ctx; PKCS12_OctetString asdata; size_t size; int ret; - memset(&as, 0, sizeof(as)); + memset(&ctx, 0, sizeof(ctx)); memset(&pfx, 0, sizeof(pfx)); + ctx.store_flags = flags; - ret = hx509_certs_iter_f(context, p12->certs, store_func, &as); + ret = hx509_certs_iter_f(context, p12->certs, store_func, &ctx); if (ret) goto out; ASN1_MALLOC_ENCODE(PKCS12_AuthenticatedSafe, asdata.data, asdata.length, - &as, &size, ret); - free_PKCS12_AuthenticatedSafe(&as); + &ctx.as, &size, ret); + free_PKCS12_AuthenticatedSafe(&ctx.as); if (ret) return ret; @@ -642,7 +670,7 @@ p12_store(hx509_context context, free(asdata.data); out: - free_PKCS12_AuthenticatedSafe(&as); + free_PKCS12_AuthenticatedSafe(&ctx.as); free_PKCS12_PFX(&pfx); return ret;