1*e12df184Stb /* $OpenBSD: p12_crt.c,v 1.26 2024/08/22 12:22:42 tb Exp $ */ 2e6841c1dSdjm /* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL 34fcf65c5Sdjm * project. 47695d5a3Sbeck */ 57695d5a3Sbeck /* ==================================================================== 64fcf65c5Sdjm * Copyright (c) 1999-2002 The OpenSSL Project. All rights reserved. 77695d5a3Sbeck * 87695d5a3Sbeck * Redistribution and use in source and binary forms, with or without 97695d5a3Sbeck * modification, are permitted provided that the following conditions 107695d5a3Sbeck * are met: 117695d5a3Sbeck * 127695d5a3Sbeck * 1. Redistributions of source code must retain the above copyright 137695d5a3Sbeck * notice, this list of conditions and the following disclaimer. 147695d5a3Sbeck * 157695d5a3Sbeck * 2. Redistributions in binary form must reproduce the above copyright 167695d5a3Sbeck * notice, this list of conditions and the following disclaimer in 177695d5a3Sbeck * the documentation and/or other materials provided with the 187695d5a3Sbeck * distribution. 197695d5a3Sbeck * 207695d5a3Sbeck * 3. All advertising materials mentioning features or use of this 217695d5a3Sbeck * software must display the following acknowledgment: 227695d5a3Sbeck * "This product includes software developed by the OpenSSL Project 237695d5a3Sbeck * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" 247695d5a3Sbeck * 257695d5a3Sbeck * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to 267695d5a3Sbeck * endorse or promote products derived from this software without 277695d5a3Sbeck * prior written permission. For written permission, please contact 287695d5a3Sbeck * licensing@OpenSSL.org. 297695d5a3Sbeck * 307695d5a3Sbeck * 5. Products derived from this software may not be called "OpenSSL" 317695d5a3Sbeck * nor may "OpenSSL" appear in their names without prior written 327695d5a3Sbeck * permission of the OpenSSL Project. 337695d5a3Sbeck * 347695d5a3Sbeck * 6. Redistributions of any form whatsoever must retain the following 357695d5a3Sbeck * acknowledgment: 367695d5a3Sbeck * "This product includes software developed by the OpenSSL Project 377695d5a3Sbeck * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" 387695d5a3Sbeck * 397695d5a3Sbeck * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY 407695d5a3Sbeck * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 417695d5a3Sbeck * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 427695d5a3Sbeck * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR 437695d5a3Sbeck * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 447695d5a3Sbeck * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 457695d5a3Sbeck * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 467695d5a3Sbeck * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 477695d5a3Sbeck * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 487695d5a3Sbeck * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 497695d5a3Sbeck * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 507695d5a3Sbeck * OF THE POSSIBILITY OF SUCH DAMAGE. 517695d5a3Sbeck * ==================================================================== 527695d5a3Sbeck * 537695d5a3Sbeck * This product includes cryptographic software written by Eric Young 547695d5a3Sbeck * (eay@cryptsoft.com). This product includes software written by Tim 557695d5a3Sbeck * Hudson (tjh@cryptsoft.com). 567695d5a3Sbeck * 577695d5a3Sbeck */ 587695d5a3Sbeck 597695d5a3Sbeck #include <stdio.h> 607695d5a3Sbeck 61b6ab114eSjsing #include <openssl/err.h> 62b6ab114eSjsing #include <openssl/pkcs12.h> 639982db7bStb #include <openssl/x509.h> 644fcf65c5Sdjm 659982db7bStb #include "evp_local.h" 66e4978644Stb #include "pkcs12_local.h" 679982db7bStb #include "x509_local.h" 68e4978644Stb 69d2af6916Sjsing static int pkcs12_add_bag(STACK_OF(PKCS12_SAFEBAG) **pbags, 70d2af6916Sjsing PKCS12_SAFEBAG *bag); 714fcf65c5Sdjm 72d2af6916Sjsing PKCS12 * 73f3a98326Stb PKCS12_create(const char *pass, const char *name, EVP_PKEY *pkey, X509 *cert, 74f6e3f262Sbeck STACK_OF(X509) *ca, int nid_key, int nid_cert, int iter, int mac_iter, 757695d5a3Sbeck int keytype) 767695d5a3Sbeck { 774fcf65c5Sdjm PKCS12 *p12 = NULL; 784fcf65c5Sdjm STACK_OF(PKCS7) *safes = NULL; 794fcf65c5Sdjm STACK_OF(PKCS12_SAFEBAG) *bags = NULL; 804fcf65c5Sdjm PKCS12_SAFEBAG *bag = NULL; 817695d5a3Sbeck int i; 827695d5a3Sbeck unsigned char keyid[EVP_MAX_MD_SIZE]; 834fcf65c5Sdjm unsigned int keyidlen = 0; 847695d5a3Sbeck 857695d5a3Sbeck /* Set defaults */ 86d2af6916Sjsing if (!nid_cert) { 876d388760Sdjm nid_cert = NID_pbe_WithSHA1And40BitRC2_CBC; 8897222eddSmiod } 894fcf65c5Sdjm if (!nid_key) 904fcf65c5Sdjm nid_key = NID_pbe_WithSHA1And3_Key_TripleDES_CBC; 914fcf65c5Sdjm if (!iter) 924fcf65c5Sdjm iter = PKCS12_DEFAULT_ITER; 934fcf65c5Sdjm if (!mac_iter) 944fcf65c5Sdjm mac_iter = 1; 957695d5a3Sbeck 96d2af6916Sjsing if (!pkey && !cert && !ca) { 975067ae9fSbeck PKCS12error(PKCS12_R_INVALID_NULL_ARGUMENT); 987695d5a3Sbeck return NULL; 997695d5a3Sbeck } 1007695d5a3Sbeck 101d2af6916Sjsing if (pkey && cert) { 1024fcf65c5Sdjm if (!X509_check_private_key(cert, pkey)) 1037695d5a3Sbeck return NULL; 104a6ee4600Sjob if (!X509_digest(cert, EVP_sha1(), keyid, &keyidlen)) 105a6ee4600Sjob return NULL; 1067695d5a3Sbeck } 1077695d5a3Sbeck 108d2af6916Sjsing if (cert) { 1094fcf65c5Sdjm bag = PKCS12_add_cert(&bags, cert); 1104fcf65c5Sdjm if (name && !PKCS12_add_friendlyname(bag, name, -1)) 1114fcf65c5Sdjm goto err; 1124fcf65c5Sdjm if (keyidlen && !PKCS12_add_localkeyid(bag, keyid, keyidlen)) 1134fcf65c5Sdjm goto err; 1147695d5a3Sbeck } 1157695d5a3Sbeck 1167695d5a3Sbeck /* Add all other certificates */ 117d2af6916Sjsing for (i = 0; i < sk_X509_num(ca); i++) { 1184fcf65c5Sdjm if (!PKCS12_add_cert(&bags, sk_X509_value(ca, i))) 1194fcf65c5Sdjm goto err; 1207695d5a3Sbeck } 1217695d5a3Sbeck 1224fcf65c5Sdjm if (bags && !PKCS12_add_safe(&safes, bags, nid_cert, iter, pass)) 1234fcf65c5Sdjm goto err; 1244fcf65c5Sdjm 125c109e398Sbeck sk_PKCS12_SAFEBAG_pop_free(bags, PKCS12_SAFEBAG_free); 1264fcf65c5Sdjm bags = NULL; 1277695d5a3Sbeck 128d2af6916Sjsing if (pkey) { 1294fcf65c5Sdjm bag = PKCS12_add_key(&bags, pkey, keytype, iter, nid_key, pass); 1307695d5a3Sbeck 1314fcf65c5Sdjm if (!bag) 1324fcf65c5Sdjm goto err; 1334fcf65c5Sdjm 1344fcf65c5Sdjm if (name && !PKCS12_add_friendlyname(bag, name, -1)) 1354fcf65c5Sdjm goto err; 1364fcf65c5Sdjm if (keyidlen && !PKCS12_add_localkeyid(bag, keyid, keyidlen)) 1374fcf65c5Sdjm goto err; 1387695d5a3Sbeck } 1394fcf65c5Sdjm 1404fcf65c5Sdjm if (bags && !PKCS12_add_safe(&safes, bags, -1, 0, NULL)) 1414fcf65c5Sdjm goto err; 1424fcf65c5Sdjm 143c109e398Sbeck sk_PKCS12_SAFEBAG_pop_free(bags, PKCS12_SAFEBAG_free); 1444fcf65c5Sdjm bags = NULL; 1457695d5a3Sbeck 1464fcf65c5Sdjm p12 = PKCS12_add_safes(safes, 0); 1477695d5a3Sbeck 14850c17820Sdjm if (!p12) 14950c17820Sdjm goto err; 15050c17820Sdjm 151c109e398Sbeck sk_PKCS7_pop_free(safes, PKCS7_free); 1527695d5a3Sbeck 1534fcf65c5Sdjm safes = NULL; 1544fcf65c5Sdjm 1554fcf65c5Sdjm if ((mac_iter != -1) && 1564fcf65c5Sdjm !PKCS12_set_mac(p12, pass, -1, NULL, 0, mac_iter, NULL)) 1574fcf65c5Sdjm goto err; 1584fcf65c5Sdjm 1594fcf65c5Sdjm return p12; 1604fcf65c5Sdjm 1614fcf65c5Sdjm err: 1624fcf65c5Sdjm if (p12) 1634fcf65c5Sdjm PKCS12_free(p12); 1644fcf65c5Sdjm if (safes) 1654fcf65c5Sdjm sk_PKCS7_pop_free(safes, PKCS7_free); 1664fcf65c5Sdjm if (bags) 1674fcf65c5Sdjm sk_PKCS12_SAFEBAG_pop_free(bags, PKCS12_SAFEBAG_free); 1687695d5a3Sbeck return NULL; 1694fcf65c5Sdjm } 170cedac418Stb LCRYPTO_ALIAS(PKCS12_create); 1714fcf65c5Sdjm 172d2af6916Sjsing PKCS12_SAFEBAG * 173d2af6916Sjsing PKCS12_add_cert(STACK_OF(PKCS12_SAFEBAG) **pbags, X509 *cert) 1744fcf65c5Sdjm { 1754fcf65c5Sdjm PKCS12_SAFEBAG *bag = NULL; 1764fcf65c5Sdjm char *name; 1774fcf65c5Sdjm int namelen = -1; 1784fcf65c5Sdjm unsigned char *keyid; 1794fcf65c5Sdjm int keyidlen = -1; 1804fcf65c5Sdjm 1814fcf65c5Sdjm /* Add user certificate */ 1824fcf65c5Sdjm if (!(bag = PKCS12_x5092certbag(cert))) 1834fcf65c5Sdjm goto err; 1844fcf65c5Sdjm 1854fcf65c5Sdjm /* Use friendlyName and localKeyID in certificate. 1864fcf65c5Sdjm * (if present) 1874fcf65c5Sdjm */ 1884fcf65c5Sdjm name = (char *)X509_alias_get0(cert, &namelen); 1894fcf65c5Sdjm if (name && !PKCS12_add_friendlyname(bag, name, namelen)) 1904fcf65c5Sdjm goto err; 1914fcf65c5Sdjm 1924fcf65c5Sdjm keyid = X509_keyid_get0(cert, &keyidlen); 1934fcf65c5Sdjm 1944fcf65c5Sdjm if (keyid && !PKCS12_add_localkeyid(bag, keyid, keyidlen)) 1954fcf65c5Sdjm goto err; 1964fcf65c5Sdjm 1974fcf65c5Sdjm if (!pkcs12_add_bag(pbags, bag)) 1984fcf65c5Sdjm goto err; 1994fcf65c5Sdjm 2004fcf65c5Sdjm return bag; 2014fcf65c5Sdjm 2024fcf65c5Sdjm err: 2034fcf65c5Sdjm if (bag) 2044fcf65c5Sdjm PKCS12_SAFEBAG_free(bag); 2054fcf65c5Sdjm 2064fcf65c5Sdjm return NULL; 2074fcf65c5Sdjm } 2084fcf65c5Sdjm 209d2af6916Sjsing PKCS12_SAFEBAG * 210d2af6916Sjsing PKCS12_add_key(STACK_OF(PKCS12_SAFEBAG) **pbags, EVP_PKEY *key, int key_usage, 211f3a98326Stb int iter, int nid_key, const char *pass) 2124fcf65c5Sdjm { 2134fcf65c5Sdjm PKCS12_SAFEBAG *bag = NULL; 2144fcf65c5Sdjm PKCS8_PRIV_KEY_INFO *p8 = NULL; 2154fcf65c5Sdjm 2164fcf65c5Sdjm /* Make a PKCS#8 structure */ 2174fcf65c5Sdjm if (!(p8 = EVP_PKEY2PKCS8(key))) 2184fcf65c5Sdjm goto err; 2194fcf65c5Sdjm if (key_usage && !PKCS8_add_keyusage(p8, key_usage)) 2204fcf65c5Sdjm goto err; 221d2af6916Sjsing if (nid_key != -1) { 222b9c7d6b6Stb bag = PKCS12_SAFEBAG_create_pkcs8_encrypt(nid_key, pass, -1, 223b9c7d6b6Stb NULL, 0, iter, p8); 2244fcf65c5Sdjm PKCS8_PRIV_KEY_INFO_free(p8); 225212d4d23Smiod p8 = NULL; 226212d4d23Smiod } else { 227b9c7d6b6Stb bag = PKCS12_SAFEBAG_create0_p8inf(p8); 228212d4d23Smiod if (bag != NULL) 229212d4d23Smiod p8 = NULL; 230212d4d23Smiod } 2314fcf65c5Sdjm 2324fcf65c5Sdjm if (!bag) 2334fcf65c5Sdjm goto err; 2344fcf65c5Sdjm 2354fcf65c5Sdjm if (!pkcs12_add_bag(pbags, bag)) 2364fcf65c5Sdjm goto err; 2374fcf65c5Sdjm 2384fcf65c5Sdjm return bag; 2394fcf65c5Sdjm 2404fcf65c5Sdjm err: 2414fcf65c5Sdjm if (bag) 2424fcf65c5Sdjm PKCS12_SAFEBAG_free(bag); 243212d4d23Smiod if (p8) 244212d4d23Smiod PKCS8_PRIV_KEY_INFO_free(p8); 2454fcf65c5Sdjm 2464fcf65c5Sdjm return NULL; 2474fcf65c5Sdjm } 2484fcf65c5Sdjm 249d2af6916Sjsing int 250d2af6916Sjsing PKCS12_add_safe(STACK_OF(PKCS7) **psafes, STACK_OF(PKCS12_SAFEBAG) *bags, 251f3a98326Stb int nid_safe, int iter, const char *pass) 2524fcf65c5Sdjm { 2534fcf65c5Sdjm PKCS7 *p7 = NULL; 2544fcf65c5Sdjm int free_safes = 0; 2554fcf65c5Sdjm 256d2af6916Sjsing if (!*psafes) { 2574fcf65c5Sdjm *psafes = sk_PKCS7_new_null(); 2584fcf65c5Sdjm if (!*psafes) 2594fcf65c5Sdjm return 0; 2604fcf65c5Sdjm free_safes = 1; 261d2af6916Sjsing } else 2624fcf65c5Sdjm free_safes = 0; 2634fcf65c5Sdjm 2644fcf65c5Sdjm if (nid_safe == 0) 2654fcf65c5Sdjm nid_safe = NID_pbe_WithSHA1And40BitRC2_CBC; 2664fcf65c5Sdjm 2674fcf65c5Sdjm if (nid_safe == -1) 2684fcf65c5Sdjm p7 = PKCS12_pack_p7data(bags); 2694fcf65c5Sdjm else 2704fcf65c5Sdjm p7 = PKCS12_pack_p7encdata(nid_safe, pass, -1, NULL, 0, 2714fcf65c5Sdjm iter, bags); 2724fcf65c5Sdjm if (!p7) 2734fcf65c5Sdjm goto err; 2744fcf65c5Sdjm 2754fcf65c5Sdjm if (!sk_PKCS7_push(*psafes, p7)) 2764fcf65c5Sdjm goto err; 2774fcf65c5Sdjm 2784fcf65c5Sdjm return 1; 2794fcf65c5Sdjm 2804fcf65c5Sdjm err: 281d2af6916Sjsing if (free_safes) { 2824fcf65c5Sdjm sk_PKCS7_free(*psafes); 2834fcf65c5Sdjm *psafes = NULL; 2844fcf65c5Sdjm } 2854fcf65c5Sdjm 2864fcf65c5Sdjm if (p7) 2874fcf65c5Sdjm PKCS7_free(p7); 2884fcf65c5Sdjm 2894fcf65c5Sdjm return 0; 2904fcf65c5Sdjm } 2914fcf65c5Sdjm 292d2af6916Sjsing static int 293d2af6916Sjsing pkcs12_add_bag(STACK_OF(PKCS12_SAFEBAG) **pbags, PKCS12_SAFEBAG *bag) 2944fcf65c5Sdjm { 2954fcf65c5Sdjm int free_bags; 296d2af6916Sjsing 2974fcf65c5Sdjm if (!pbags) 2984fcf65c5Sdjm return 1; 299d2af6916Sjsing if (!*pbags) { 3004fcf65c5Sdjm *pbags = sk_PKCS12_SAFEBAG_new_null(); 3014fcf65c5Sdjm if (!*pbags) 3024fcf65c5Sdjm return 0; 3034fcf65c5Sdjm free_bags = 1; 304d2af6916Sjsing } else 3054fcf65c5Sdjm free_bags = 0; 3064fcf65c5Sdjm 307d2af6916Sjsing if (!sk_PKCS12_SAFEBAG_push(*pbags, bag)) { 308d2af6916Sjsing if (free_bags) { 3094fcf65c5Sdjm sk_PKCS12_SAFEBAG_free(*pbags); 3104fcf65c5Sdjm *pbags = NULL; 3114fcf65c5Sdjm } 3124fcf65c5Sdjm return 0; 3134fcf65c5Sdjm } 3144fcf65c5Sdjm 3154fcf65c5Sdjm return 1; 3164fcf65c5Sdjm } 3174fcf65c5Sdjm 318d2af6916Sjsing PKCS12 * 319d2af6916Sjsing PKCS12_add_safes(STACK_OF(PKCS7) *safes, int nid_p7) 3204fcf65c5Sdjm { 3214fcf65c5Sdjm PKCS12 *p12; 322d2af6916Sjsing 3234fcf65c5Sdjm if (nid_p7 <= 0) 3244fcf65c5Sdjm nid_p7 = NID_pkcs7_data; 3254fcf65c5Sdjm p12 = PKCS12_init(nid_p7); 3264fcf65c5Sdjm 3274fcf65c5Sdjm if (!p12) 3284fcf65c5Sdjm return NULL; 3294fcf65c5Sdjm 330d2af6916Sjsing if (!PKCS12_pack_authsafes(p12, safes)) { 3314fcf65c5Sdjm PKCS12_free(p12); 3324fcf65c5Sdjm return NULL; 3334fcf65c5Sdjm } 3344fcf65c5Sdjm 3357695d5a3Sbeck return p12; 3367695d5a3Sbeck } 337