Path: blob/main/crypto/heimdal/lib/hx509/ks_p12.c
101161 views
/*1* Copyright (c) 2004 - 2007 Kungliga Tekniska Högskolan2* (Royal Institute of Technology, Stockholm, Sweden).3* All rights reserved.4*5* Redistribution and use in source and binary forms, with or without6* modification, are permitted provided that the following conditions7* are met:8*9* 1. Redistributions of source code must retain the above copyright10* notice, this list of conditions and the following disclaimer.11*12* 2. Redistributions in binary form must reproduce the above copyright13* notice, this list of conditions and the following disclaimer in the14* documentation and/or other materials provided with the distribution.15*16* 3. Neither the name of the Institute nor the names of its contributors17* may be used to endorse or promote products derived from this software18* without specific prior written permission.19*20* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND21* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE22* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE23* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE24* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL25* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS26* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)27* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT28* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY29* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF30* SUCH DAMAGE.31*/3233#include "hx_locl.h"3435struct ks_pkcs12 {36hx509_certs certs;37char *fn;38};3940typedef int (*collector_func)(hx509_context,41struct hx509_collector *,42const void *, size_t,43const PKCS12_Attributes *);4445struct type {46const heim_oid *oid;47collector_func func;48};4950static void51parse_pkcs12_type(hx509_context, struct hx509_collector *, const heim_oid *,52const void *, size_t, const PKCS12_Attributes *);535455static const PKCS12_Attribute *56find_attribute(const PKCS12_Attributes *attrs, const heim_oid *oid)57{58size_t i;59if (attrs == NULL)60return NULL;61for (i = 0; i < attrs->len; i++)62if (der_heim_oid_cmp(oid, &attrs->val[i].attrId) == 0)63return &attrs->val[i];64return NULL;65}6667static int68keyBag_parser(hx509_context context,69struct hx509_collector *c,70const void *data, size_t length,71const PKCS12_Attributes *attrs)72{73const PKCS12_Attribute *attr;74PKCS8PrivateKeyInfo ki;75const heim_octet_string *os = NULL;76int ret;7778attr = find_attribute(attrs, &asn1_oid_id_pkcs_9_at_localKeyId);79if (attr)80os = &attr->attrValues;8182ret = decode_PKCS8PrivateKeyInfo(data, length, &ki, NULL);83if (ret)84return ret;8586_hx509_collector_private_key_add(context,87c,88&ki.privateKeyAlgorithm,89NULL,90&ki.privateKey,91os);92free_PKCS8PrivateKeyInfo(&ki);93return 0;94}9596static int97ShroudedKeyBag_parser(hx509_context context,98struct hx509_collector *c,99const void *data, size_t length,100const PKCS12_Attributes *attrs)101{102PKCS8EncryptedPrivateKeyInfo pk;103heim_octet_string content;104int ret;105106memset(&pk, 0, sizeof(pk));107108ret = decode_PKCS8EncryptedPrivateKeyInfo(data, length, &pk, NULL);109if (ret)110return ret;111112ret = _hx509_pbe_decrypt(context,113_hx509_collector_get_lock(c),114&pk.encryptionAlgorithm,115&pk.encryptedData,116&content);117free_PKCS8EncryptedPrivateKeyInfo(&pk);118if (ret)119return ret;120121ret = keyBag_parser(context, c, content.data, content.length, attrs);122der_free_octet_string(&content);123return ret;124}125126static int127certBag_parser(hx509_context context,128struct hx509_collector *c,129const void *data, size_t length,130const PKCS12_Attributes *attrs)131{132heim_octet_string os;133hx509_cert cert;134PKCS12_CertBag cb;135int ret;136137ret = decode_PKCS12_CertBag(data, length, &cb, NULL);138if (ret)139return ret;140141if (der_heim_oid_cmp(&asn1_oid_id_pkcs_9_at_certTypes_x509, &cb.certType)) {142free_PKCS12_CertBag(&cb);143return 0;144}145146ret = decode_PKCS12_OctetString(cb.certValue.data,147cb.certValue.length,148&os,149NULL);150free_PKCS12_CertBag(&cb);151if (ret)152return ret;153154ret = hx509_cert_init_data(context, os.data, os.length, &cert);155der_free_octet_string(&os);156if (ret)157return ret;158159ret = _hx509_collector_certs_add(context, c, cert);160if (ret) {161hx509_cert_free(cert);162return ret;163}164165{166const PKCS12_Attribute *attr;167const heim_oid *oids[] = {168&asn1_oid_id_pkcs_9_at_localKeyId, &asn1_oid_id_pkcs_9_at_friendlyName169};170size_t i;171172for (i = 0; i < sizeof(oids)/sizeof(oids[0]); i++) {173const heim_oid *oid = oids[i];174attr = find_attribute(attrs, oid);175if (attr)176_hx509_set_cert_attribute(context, cert, oid,177&attr->attrValues);178}179}180181hx509_cert_free(cert);182183return 0;184}185186static int187parse_safe_content(hx509_context context,188struct hx509_collector *c,189const unsigned char *p, size_t len)190{191PKCS12_SafeContents sc;192int ret;193size_t i;194195memset(&sc, 0, sizeof(sc));196197ret = decode_PKCS12_SafeContents(p, len, &sc, NULL);198if (ret)199return ret;200201for (i = 0; i < sc.len ; i++)202parse_pkcs12_type(context,203c,204&sc.val[i].bagId,205sc.val[i].bagValue.data,206sc.val[i].bagValue.length,207sc.val[i].bagAttributes);208209free_PKCS12_SafeContents(&sc);210return 0;211}212213static int214safeContent_parser(hx509_context context,215struct hx509_collector *c,216const void *data, size_t length,217const PKCS12_Attributes *attrs)218{219heim_octet_string os;220int ret;221222ret = decode_PKCS12_OctetString(data, length, &os, NULL);223if (ret)224return ret;225ret = parse_safe_content(context, c, os.data, os.length);226der_free_octet_string(&os);227return ret;228}229230static int231encryptedData_parser(hx509_context context,232struct hx509_collector *c,233const void *data, size_t length,234const PKCS12_Attributes *attrs)235{236heim_octet_string content;237heim_oid contentType;238int ret;239240memset(&contentType, 0, sizeof(contentType));241242ret = hx509_cms_decrypt_encrypted(context,243_hx509_collector_get_lock(c),244data, length,245&contentType,246&content);247if (ret)248return ret;249250if (der_heim_oid_cmp(&contentType, &asn1_oid_id_pkcs7_data) == 0)251ret = parse_safe_content(context, c, content.data, content.length);252253der_free_octet_string(&content);254der_free_oid(&contentType);255return ret;256}257258static int259envelopedData_parser(hx509_context context,260struct hx509_collector *c,261const void *data, size_t length,262const PKCS12_Attributes *attrs)263{264heim_octet_string content;265heim_oid contentType;266hx509_lock lock;267int ret;268269memset(&contentType, 0, sizeof(contentType));270271lock = _hx509_collector_get_lock(c);272273ret = hx509_cms_unenvelope(context,274_hx509_lock_unlock_certs(lock),2750,276data, length,277NULL,2780,279&contentType,280&content);281if (ret) {282hx509_set_error_string(context, HX509_ERROR_APPEND, ret,283"PKCS12 failed to unenvelope");284return ret;285}286287if (der_heim_oid_cmp(&contentType, &asn1_oid_id_pkcs7_data) == 0)288ret = parse_safe_content(context, c, content.data, content.length);289290der_free_octet_string(&content);291der_free_oid(&contentType);292293return ret;294}295296297struct type bagtypes[] = {298{ &asn1_oid_id_pkcs12_keyBag, keyBag_parser },299{ &asn1_oid_id_pkcs12_pkcs8ShroudedKeyBag, ShroudedKeyBag_parser },300{ &asn1_oid_id_pkcs12_certBag, certBag_parser },301{ &asn1_oid_id_pkcs7_data, safeContent_parser },302{ &asn1_oid_id_pkcs7_encryptedData, encryptedData_parser },303{ &asn1_oid_id_pkcs7_envelopedData, envelopedData_parser }304};305306static void307parse_pkcs12_type(hx509_context context,308struct hx509_collector *c,309const heim_oid *oid,310const void *data, size_t length,311const PKCS12_Attributes *attrs)312{313size_t i;314315for (i = 0; i < sizeof(bagtypes)/sizeof(bagtypes[0]); i++)316if (der_heim_oid_cmp(bagtypes[i].oid, oid) == 0)317(*bagtypes[i].func)(context, c, data, length, attrs);318}319320static int321p12_init(hx509_context context,322hx509_certs certs, void **data, int flags,323const char *residue, hx509_lock lock)324{325struct ks_pkcs12 *p12;326size_t len;327void *buf;328PKCS12_PFX pfx;329PKCS12_AuthenticatedSafe as;330int ret;331size_t i;332struct hx509_collector *c;333334*data = NULL;335336if (lock == NULL)337lock = _hx509_empty_lock;338339ret = _hx509_collector_alloc(context, lock, &c);340if (ret)341return ret;342343p12 = calloc(1, sizeof(*p12));344if (p12 == NULL) {345ret = ENOMEM;346hx509_set_error_string(context, 0, ret, "out of memory");347goto out;348}349350p12->fn = strdup(residue);351if (p12->fn == NULL) {352ret = ENOMEM;353hx509_set_error_string(context, 0, ret, "out of memory");354goto out;355}356357if (flags & HX509_CERTS_CREATE) {358ret = hx509_certs_init(context, "MEMORY:ks-file-create",3590, lock, &p12->certs);360if (ret == 0)361*data = p12;362goto out;363}364365ret = rk_undumpdata(residue, &buf, &len);366if (ret) {367hx509_clear_error_string(context);368goto out;369}370371ret = decode_PKCS12_PFX(buf, len, &pfx, NULL);372rk_xfree(buf);373if (ret) {374hx509_set_error_string(context, 0, ret,375"Failed to decode the PFX in %s", residue);376goto out;377}378379if (der_heim_oid_cmp(&pfx.authSafe.contentType, &asn1_oid_id_pkcs7_data) != 0) {380free_PKCS12_PFX(&pfx);381ret = EINVAL;382hx509_set_error_string(context, 0, ret,383"PKCS PFX isn't a pkcs7-data container");384goto out;385}386387if (pfx.authSafe.content == NULL) {388free_PKCS12_PFX(&pfx);389ret = EINVAL;390hx509_set_error_string(context, 0, ret,391"PKCS PFX missing data");392goto out;393}394395{396heim_octet_string asdata;397398ret = decode_PKCS12_OctetString(pfx.authSafe.content->data,399pfx.authSafe.content->length,400&asdata,401NULL);402free_PKCS12_PFX(&pfx);403if (ret) {404hx509_clear_error_string(context);405goto out;406}407ret = decode_PKCS12_AuthenticatedSafe(asdata.data,408asdata.length,409&as,410NULL);411der_free_octet_string(&asdata);412if (ret) {413hx509_clear_error_string(context);414goto out;415}416}417418for (i = 0; i < as.len; i++)419parse_pkcs12_type(context,420c,421&as.val[i].contentType,422as.val[i].content->data,423as.val[i].content->length,424NULL);425426free_PKCS12_AuthenticatedSafe(&as);427428ret = _hx509_collector_collect_certs(context, c, &p12->certs);429if (ret == 0)430*data = p12;431432out:433_hx509_collector_free(c);434435if (ret && p12) {436if (p12->fn)437free(p12->fn);438if (p12->certs)439hx509_certs_free(&p12->certs);440free(p12);441}442443return ret;444}445446static int447addBag(hx509_context context,448PKCS12_AuthenticatedSafe *as,449const heim_oid *oid,450void *data,451size_t length)452{453void *ptr;454int ret;455456ptr = realloc(as->val, sizeof(as->val[0]) * (as->len + 1));457if (ptr == NULL) {458hx509_set_error_string(context, 0, ENOMEM, "out of memory");459return ENOMEM;460}461as->val = ptr;462463ret = der_copy_oid(oid, &as->val[as->len].contentType);464if (ret) {465hx509_set_error_string(context, 0, ret, "out of memory");466return ret;467}468469as->val[as->len].content = calloc(1, sizeof(*as->val[0].content));470if (as->val[as->len].content == NULL) {471der_free_oid(&as->val[as->len].contentType);472hx509_set_error_string(context, 0, ENOMEM, "malloc out of memory");473return ENOMEM;474}475476as->val[as->len].content->data = data;477as->val[as->len].content->length = length;478479as->len++;480481return 0;482}483484static int485store_func(hx509_context context, void *ctx, hx509_cert c)486{487PKCS12_AuthenticatedSafe *as = ctx;488PKCS12_OctetString os;489PKCS12_CertBag cb;490size_t size;491int ret;492493memset(&os, 0, sizeof(os));494memset(&cb, 0, sizeof(cb));495496os.data = NULL;497os.length = 0;498499ret = hx509_cert_binary(context, c, &os);500if (ret)501return ret;502503ASN1_MALLOC_ENCODE(PKCS12_OctetString,504cb.certValue.data,cb.certValue.length,505&os, &size, ret);506free(os.data);507if (ret)508goto out;509ret = der_copy_oid(&asn1_oid_id_pkcs_9_at_certTypes_x509, &cb.certType);510if (ret) {511free_PKCS12_CertBag(&cb);512goto out;513}514ASN1_MALLOC_ENCODE(PKCS12_CertBag, os.data, os.length,515&cb, &size, ret);516free_PKCS12_CertBag(&cb);517if (ret)518goto out;519520ret = addBag(context, as, &asn1_oid_id_pkcs12_certBag, os.data, os.length);521522if (_hx509_cert_private_key_exportable(c)) {523hx509_private_key key = _hx509_cert_private_key(c);524PKCS8PrivateKeyInfo pki;525526memset(&pki, 0, sizeof(pki));527528ret = der_parse_hex_heim_integer("00", &pki.version);529if (ret)530return ret;531ret = _hx509_private_key_oid(context, key,532&pki.privateKeyAlgorithm.algorithm);533if (ret) {534free_PKCS8PrivateKeyInfo(&pki);535return ret;536}537ret = _hx509_private_key_export(context,538_hx509_cert_private_key(c),539HX509_KEY_FORMAT_DER,540&pki.privateKey);541if (ret) {542free_PKCS8PrivateKeyInfo(&pki);543return ret;544}545/* set attribute, asn1_oid_id_pkcs_9_at_localKeyId */546547ASN1_MALLOC_ENCODE(PKCS8PrivateKeyInfo, os.data, os.length,548&pki, &size, ret);549free_PKCS8PrivateKeyInfo(&pki);550if (ret)551return ret;552553ret = addBag(context, as, &asn1_oid_id_pkcs12_keyBag, os.data, os.length);554if (ret)555return ret;556}557558out:559return ret;560}561562static int563p12_store(hx509_context context,564hx509_certs certs, void *data, int flags, hx509_lock lock)565{566struct ks_pkcs12 *p12 = data;567PKCS12_PFX pfx;568PKCS12_AuthenticatedSafe as;569PKCS12_OctetString asdata;570size_t size;571int ret;572573memset(&as, 0, sizeof(as));574memset(&pfx, 0, sizeof(pfx));575576ret = hx509_certs_iter_f(context, p12->certs, store_func, &as);577if (ret)578goto out;579580ASN1_MALLOC_ENCODE(PKCS12_AuthenticatedSafe, asdata.data, asdata.length,581&as, &size, ret);582free_PKCS12_AuthenticatedSafe(&as);583if (ret)584return ret;585586ret = der_parse_hex_heim_integer("03", &pfx.version);587if (ret) {588free(asdata.data);589goto out;590}591592pfx.authSafe.content = calloc(1, sizeof(*pfx.authSafe.content));593594ASN1_MALLOC_ENCODE(PKCS12_OctetString,595pfx.authSafe.content->data,596pfx.authSafe.content->length,597&asdata, &size, ret);598free(asdata.data);599if (ret)600goto out;601602ret = der_copy_oid(&asn1_oid_id_pkcs7_data, &pfx.authSafe.contentType);603if (ret)604goto out;605606ASN1_MALLOC_ENCODE(PKCS12_PFX, asdata.data, asdata.length,607&pfx, &size, ret);608if (ret)609goto out;610611#if 0612const struct _hx509_password *pw;613614pw = _hx509_lock_get_passwords(lock);615if (pw != NULL) {616pfx.macData = calloc(1, sizeof(*pfx.macData));617if (pfx.macData == NULL) {618ret = ENOMEM;619hx509_set_error_string(context, 0, ret, "malloc out of memory");620return ret;621}622if (pfx.macData == NULL) {623free(asdata.data);624goto out;625}626}627ret = calculate_hash(&aspath, pw, pfx.macData);628#endif629630rk_dumpdata(p12->fn, asdata.data, asdata.length);631free(asdata.data);632633out:634free_PKCS12_AuthenticatedSafe(&as);635free_PKCS12_PFX(&pfx);636637return ret;638}639640641static int642p12_free(hx509_certs certs, void *data)643{644struct ks_pkcs12 *p12 = data;645hx509_certs_free(&p12->certs);646free(p12->fn);647free(p12);648return 0;649}650651static int652p12_add(hx509_context context, hx509_certs certs, void *data, hx509_cert c)653{654struct ks_pkcs12 *p12 = data;655return hx509_certs_add(context, p12->certs, c);656}657658static int659p12_iter_start(hx509_context context,660hx509_certs certs,661void *data,662void **cursor)663{664struct ks_pkcs12 *p12 = data;665return hx509_certs_start_seq(context, p12->certs, cursor);666}667668static int669p12_iter(hx509_context context,670hx509_certs certs,671void *data,672void *cursor,673hx509_cert *cert)674{675struct ks_pkcs12 *p12 = data;676return hx509_certs_next_cert(context, p12->certs, cursor, cert);677}678679static int680p12_iter_end(hx509_context context,681hx509_certs certs,682void *data,683void *cursor)684{685struct ks_pkcs12 *p12 = data;686return hx509_certs_end_seq(context, p12->certs, cursor);687}688689static struct hx509_keyset_ops keyset_pkcs12 = {690"PKCS12",6910,692p12_init,693p12_store,694p12_free,695p12_add,696NULL,697p12_iter_start,698p12_iter,699p12_iter_end700};701702void703_hx509_ks_pkcs12_register(hx509_context context)704{705_hx509_ks_register(context, &keyset_pkcs12);706}707708709