1*e7c3ccd1Stb /* $OpenBSD: pkcs12.c,v 1.29 2024/12/26 14:10:48 tb Exp $ */ 2dab3f910Sjsing /* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL 3dab3f910Sjsing * project. 4dab3f910Sjsing */ 5dab3f910Sjsing /* ==================================================================== 6dab3f910Sjsing * Copyright (c) 1999-2006 The OpenSSL Project. All rights reserved. 7dab3f910Sjsing * 8dab3f910Sjsing * Redistribution and use in source and binary forms, with or without 9dab3f910Sjsing * modification, are permitted provided that the following conditions 10dab3f910Sjsing * are met: 11dab3f910Sjsing * 12dab3f910Sjsing * 1. Redistributions of source code must retain the above copyright 13dab3f910Sjsing * notice, this list of conditions and the following disclaimer. 14dab3f910Sjsing * 15dab3f910Sjsing * 2. Redistributions in binary form must reproduce the above copyright 16dab3f910Sjsing * notice, this list of conditions and the following disclaimer in 17dab3f910Sjsing * the documentation and/or other materials provided with the 18dab3f910Sjsing * distribution. 19dab3f910Sjsing * 20dab3f910Sjsing * 3. All advertising materials mentioning features or use of this 21dab3f910Sjsing * software must display the following acknowledgment: 22dab3f910Sjsing * "This product includes software developed by the OpenSSL Project 23dab3f910Sjsing * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" 24dab3f910Sjsing * 25dab3f910Sjsing * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to 26dab3f910Sjsing * endorse or promote products derived from this software without 27dab3f910Sjsing * prior written permission. For written permission, please contact 28dab3f910Sjsing * licensing@OpenSSL.org. 29dab3f910Sjsing * 30dab3f910Sjsing * 5. Products derived from this software may not be called "OpenSSL" 31dab3f910Sjsing * nor may "OpenSSL" appear in their names without prior written 32dab3f910Sjsing * permission of the OpenSSL Project. 33dab3f910Sjsing * 34dab3f910Sjsing * 6. Redistributions of any form whatsoever must retain the following 35dab3f910Sjsing * acknowledgment: 36dab3f910Sjsing * "This product includes software developed by the OpenSSL Project 37dab3f910Sjsing * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" 38dab3f910Sjsing * 39dab3f910Sjsing * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY 40dab3f910Sjsing * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 41dab3f910Sjsing * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 42dab3f910Sjsing * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR 43dab3f910Sjsing * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 44dab3f910Sjsing * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 45dab3f910Sjsing * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 46dab3f910Sjsing * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 47dab3f910Sjsing * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 48dab3f910Sjsing * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 49dab3f910Sjsing * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 50dab3f910Sjsing * OF THE POSSIBILITY OF SUCH DAMAGE. 51dab3f910Sjsing * ==================================================================== 52dab3f910Sjsing * 53dab3f910Sjsing * This product includes cryptographic software written by Eric Young 54dab3f910Sjsing * (eay@cryptsoft.com). This product includes software written by Tim 55dab3f910Sjsing * Hudson (tjh@cryptsoft.com). 56dab3f910Sjsing * 57dab3f910Sjsing */ 58dab3f910Sjsing 59dab3f910Sjsing #include <openssl/opensslconf.h> 60dab3f910Sjsing 61dab3f910Sjsing #if !defined(OPENSSL_NO_DES) && !defined(OPENSSL_NO_SHA1) 62dab3f910Sjsing 63dab3f910Sjsing #include <stdio.h> 64dab3f910Sjsing #include <stdlib.h> 65dab3f910Sjsing #include <string.h> 66dab3f910Sjsing 67dab3f910Sjsing #include "apps.h" 68dab3f910Sjsing 69dab3f910Sjsing #include <openssl/crypto.h> 70dab3f910Sjsing #include <openssl/err.h> 71dab3f910Sjsing #include <openssl/pem.h> 72dab3f910Sjsing #include <openssl/pkcs12.h> 73b4a69dbeStb #include <openssl/x509.h> 74dab3f910Sjsing 75dab3f910Sjsing #define NOKEYS 0x1 76dab3f910Sjsing #define NOCERTS 0x2 77dab3f910Sjsing #define INFO 0x4 78dab3f910Sjsing #define CLCERTS 0x8 79dab3f910Sjsing #define CACERTS 0x10 80dab3f910Sjsing 810892a407Sinoguchi static int get_cert_chain(X509 *cert, X509_STORE *store, 820892a407Sinoguchi STACK_OF(X509) **chain); 830892a407Sinoguchi static int dump_certs_keys_p12(BIO *out, PKCS12 *p12, char *pass, int passlen, 84dab3f910Sjsing int options, char *pempass); 85b81aa332Stb static int dump_certs_pkeys_bags(BIO *out, const STACK_OF(PKCS12_SAFEBAG) *bags, 860892a407Sinoguchi char *pass, int passlen, int options, char *pempass); 870892a407Sinoguchi static int dump_certs_pkeys_bag(BIO *out, PKCS12_SAFEBAG *bags, char *pass, 88dab3f910Sjsing int passlen, int options, char *pempass); 890892a407Sinoguchi static int print_attribs(BIO *out, const STACK_OF(X509_ATTRIBUTE) *attrlst, 9002e96206Sinoguchi const char *name); 910892a407Sinoguchi static void hex_prin(BIO *out, unsigned char *buf, int len); 920892a407Sinoguchi static int alg_print(BIO *x, const X509_ALGOR *alg); 93dab3f910Sjsing static int set_pbe(BIO *err, int *ppbe, const char *str); 94dab3f910Sjsing 953ff5c216Sinoguchi static struct { 963ff5c216Sinoguchi char *CAfile; 973ff5c216Sinoguchi STACK_OF(OPENSSL_STRING) *canames; 983ff5c216Sinoguchi char *CApath; 993ff5c216Sinoguchi int cert_pbe; 1003ff5c216Sinoguchi char *certfile; 1013ff5c216Sinoguchi int chain; 1023ff5c216Sinoguchi const EVP_CIPHER *enc; 1033ff5c216Sinoguchi int export_cert; 1043ff5c216Sinoguchi int key_pbe; 1053ff5c216Sinoguchi char *keyname; 1063ff5c216Sinoguchi int keytype; 1073ff5c216Sinoguchi char *infile; 1083ff5c216Sinoguchi int iter; 1093ff5c216Sinoguchi char *macalg; 1103ff5c216Sinoguchi int maciter; 1113ff5c216Sinoguchi int macver; 1123ff5c216Sinoguchi char *name; 1133ff5c216Sinoguchi int noprompt; 1143ff5c216Sinoguchi int options; 1153ff5c216Sinoguchi char *outfile; 1163ff5c216Sinoguchi char *passarg; 1173ff5c216Sinoguchi char *passargin; 1183ff5c216Sinoguchi char *passargout; 1193ff5c216Sinoguchi int twopass; 120e7718adaStb } cfg; 1213ff5c216Sinoguchi 122e21e78ebSinoguchi static int 123e21e78ebSinoguchi pkcs12_opt_canames(char *arg) 124e21e78ebSinoguchi { 125e7718adaStb if (cfg.canames == NULL && 126e7718adaStb (cfg.canames = sk_OPENSSL_STRING_new_null()) == NULL) 127e21e78ebSinoguchi return (1); 128e21e78ebSinoguchi 129e7718adaStb if (!sk_OPENSSL_STRING_push(cfg.canames, arg)) 130e21e78ebSinoguchi return (1); 131e21e78ebSinoguchi 132e21e78ebSinoguchi return (0); 133e21e78ebSinoguchi } 134e21e78ebSinoguchi 135e21e78ebSinoguchi static int 136e21e78ebSinoguchi pkcs12_opt_cert_pbe(char *arg) 137e21e78ebSinoguchi { 138e7718adaStb return (!set_pbe(bio_err, &cfg.cert_pbe, arg)); 139e21e78ebSinoguchi } 140e21e78ebSinoguchi 141e21e78ebSinoguchi static int 142e21e78ebSinoguchi pkcs12_opt_key_pbe(char *arg) 143e21e78ebSinoguchi { 144e7718adaStb return (!set_pbe(bio_err, &cfg.key_pbe, arg)); 145e21e78ebSinoguchi } 146e21e78ebSinoguchi 147e21e78ebSinoguchi static int 148e21e78ebSinoguchi pkcs12_opt_passarg(char *arg) 149e21e78ebSinoguchi { 150e7718adaStb cfg.passarg = arg; 151e7718adaStb cfg.noprompt = 1; 152e21e78ebSinoguchi return (0); 153e21e78ebSinoguchi } 154e21e78ebSinoguchi 155e21e78ebSinoguchi static const EVP_CIPHER *get_cipher_by_name(char *name) 156e21e78ebSinoguchi { 157e21e78ebSinoguchi if (name == NULL || strcmp(name, "") == 0) 158e21e78ebSinoguchi return (NULL); 159e21e78ebSinoguchi #ifndef OPENSSL_NO_AES 160e21e78ebSinoguchi else if (strcmp(name, "aes128") == 0) 161e21e78ebSinoguchi return EVP_aes_128_cbc(); 162e21e78ebSinoguchi else if (strcmp(name, "aes192") == 0) 163e21e78ebSinoguchi return EVP_aes_192_cbc(); 164e21e78ebSinoguchi else if (strcmp(name, "aes256") == 0) 165e21e78ebSinoguchi return EVP_aes_256_cbc(); 166e21e78ebSinoguchi #endif 167e21e78ebSinoguchi #ifndef OPENSSL_NO_CAMELLIA 168e21e78ebSinoguchi else if (strcmp(name, "camellia128") == 0) 169e21e78ebSinoguchi return EVP_camellia_128_cbc(); 170e21e78ebSinoguchi else if (strcmp(name, "camellia192") == 0) 171e21e78ebSinoguchi return EVP_camellia_192_cbc(); 172e21e78ebSinoguchi else if (strcmp(name, "camellia256") == 0) 173e21e78ebSinoguchi return EVP_camellia_256_cbc(); 174e21e78ebSinoguchi #endif 175e21e78ebSinoguchi #ifndef OPENSSL_NO_DES 176e21e78ebSinoguchi else if (strcmp(name, "des") == 0) 177e21e78ebSinoguchi return EVP_des_cbc(); 178e21e78ebSinoguchi else if (strcmp(name, "des3") == 0) 179e21e78ebSinoguchi return EVP_des_ede3_cbc(); 180e21e78ebSinoguchi #endif 181e21e78ebSinoguchi #ifndef OPENSSL_NO_IDEA 182e21e78ebSinoguchi else if (strcmp(name, "idea") == 0) 183e21e78ebSinoguchi return EVP_idea_cbc(); 184e21e78ebSinoguchi #endif 185e21e78ebSinoguchi else 186e21e78ebSinoguchi return (NULL); 187e21e78ebSinoguchi } 188e21e78ebSinoguchi 189e21e78ebSinoguchi static int 190e21e78ebSinoguchi pkcs12_opt_enc(int argc, char **argv, int *argsused) 191e21e78ebSinoguchi { 192e21e78ebSinoguchi char *name = argv[0]; 193e21e78ebSinoguchi 194e21e78ebSinoguchi if (*name++ != '-') 195e21e78ebSinoguchi return (1); 196e21e78ebSinoguchi 197e21e78ebSinoguchi if (strcmp(name, "nodes") == 0) 198e7718adaStb cfg.enc = NULL; 199e7718adaStb else if ((cfg.enc = get_cipher_by_name(name)) == NULL) 200e21e78ebSinoguchi return (1); 201e21e78ebSinoguchi 202e21e78ebSinoguchi *argsused = 1; 203e21e78ebSinoguchi return (0); 204e21e78ebSinoguchi } 205e21e78ebSinoguchi 206e21e78ebSinoguchi static const struct option pkcs12_options[] = { 207e21e78ebSinoguchi #ifndef OPENSSL_NO_AES 208e21e78ebSinoguchi { 209e21e78ebSinoguchi .name = "aes128", 210e21e78ebSinoguchi .desc = "Encrypt PEM output with CBC AES", 211e21e78ebSinoguchi .type = OPTION_ARGV_FUNC, 212e21e78ebSinoguchi .opt.argvfunc = pkcs12_opt_enc, 213e21e78ebSinoguchi }, 214e21e78ebSinoguchi { 215e21e78ebSinoguchi .name = "aes192", 216e21e78ebSinoguchi .desc = "Encrypt PEM output with CBC AES", 217e21e78ebSinoguchi .type = OPTION_ARGV_FUNC, 218e21e78ebSinoguchi .opt.argvfunc = pkcs12_opt_enc, 219e21e78ebSinoguchi }, 220e21e78ebSinoguchi { 221e21e78ebSinoguchi .name = "aes256", 222e21e78ebSinoguchi .desc = "Encrypt PEM output with CBC AES", 223e21e78ebSinoguchi .type = OPTION_ARGV_FUNC, 224e21e78ebSinoguchi .opt.argvfunc = pkcs12_opt_enc, 225e21e78ebSinoguchi }, 226e21e78ebSinoguchi #endif 227e21e78ebSinoguchi #ifndef OPENSSL_NO_CAMELLIA 228e21e78ebSinoguchi { 229e21e78ebSinoguchi .name = "camellia128", 230e21e78ebSinoguchi .desc = "Encrypt PEM output with CBC Camellia", 231e21e78ebSinoguchi .type = OPTION_ARGV_FUNC, 232e21e78ebSinoguchi .opt.argvfunc = pkcs12_opt_enc, 233e21e78ebSinoguchi }, 234e21e78ebSinoguchi { 235e21e78ebSinoguchi .name = "camellia192", 236e21e78ebSinoguchi .desc = "Encrypt PEM output with CBC Camellia", 237e21e78ebSinoguchi .type = OPTION_ARGV_FUNC, 238e21e78ebSinoguchi .opt.argvfunc = pkcs12_opt_enc, 239e21e78ebSinoguchi }, 240e21e78ebSinoguchi { 241e21e78ebSinoguchi .name = "camellia256", 242e21e78ebSinoguchi .desc = "Encrypt PEM output with CBC Camellia", 243e21e78ebSinoguchi .type = OPTION_ARGV_FUNC, 244e21e78ebSinoguchi .opt.argvfunc = pkcs12_opt_enc, 245e21e78ebSinoguchi }, 246e21e78ebSinoguchi #endif 247e21e78ebSinoguchi { 248e21e78ebSinoguchi .name = "des", 249e21e78ebSinoguchi .desc = "Encrypt private keys with DES", 250e21e78ebSinoguchi .type = OPTION_ARGV_FUNC, 251e21e78ebSinoguchi .opt.argvfunc = pkcs12_opt_enc, 252e21e78ebSinoguchi }, 253e21e78ebSinoguchi { 254e21e78ebSinoguchi .name = "des3", 255e21e78ebSinoguchi .desc = "Encrypt private keys with triple DES (default)", 256e21e78ebSinoguchi .type = OPTION_ARGV_FUNC, 257e21e78ebSinoguchi .opt.argvfunc = pkcs12_opt_enc, 258e21e78ebSinoguchi }, 259e21e78ebSinoguchi #ifndef OPENSSL_NO_IDEA 260e21e78ebSinoguchi { 261e21e78ebSinoguchi .name = "idea", 262e21e78ebSinoguchi .desc = "Encrypt private keys with IDEA", 263e21e78ebSinoguchi .type = OPTION_ARGV_FUNC, 264e21e78ebSinoguchi .opt.argvfunc = pkcs12_opt_enc, 265e21e78ebSinoguchi }, 266e21e78ebSinoguchi #endif 267e21e78ebSinoguchi { 268e21e78ebSinoguchi .name = "cacerts", 269e21e78ebSinoguchi .desc = "Only output CA certificates", 270e21e78ebSinoguchi .type = OPTION_VALUE_OR, 271e7718adaStb .opt.value = &cfg.options, 272e21e78ebSinoguchi .value = CACERTS, 273e21e78ebSinoguchi }, 274e21e78ebSinoguchi { 275e21e78ebSinoguchi .name = "CAfile", 276e21e78ebSinoguchi .argname = "file", 277e21e78ebSinoguchi .desc = "PEM format file of CA certificates", 278e21e78ebSinoguchi .type = OPTION_ARG, 279e7718adaStb .opt.arg = &cfg.CAfile, 280e21e78ebSinoguchi }, 281e21e78ebSinoguchi { 282e21e78ebSinoguchi .name = "caname", 283e21e78ebSinoguchi .argname = "name", 284e21e78ebSinoguchi .desc = "Use name as CA friendly name (can be used more than once)", 285e21e78ebSinoguchi .type = OPTION_ARG_FUNC, 286e21e78ebSinoguchi .opt.argfunc = pkcs12_opt_canames, 287e21e78ebSinoguchi }, 288e21e78ebSinoguchi { 289e21e78ebSinoguchi .name = "CApath", 290e21e78ebSinoguchi .argname = "directory", 291e21e78ebSinoguchi .desc = "PEM format directory of CA certificates", 292e21e78ebSinoguchi .type = OPTION_ARG, 293e7718adaStb .opt.arg = &cfg.CApath, 294e21e78ebSinoguchi }, 295e21e78ebSinoguchi { 296e21e78ebSinoguchi .name = "certfile", 297e21e78ebSinoguchi .argname = "file", 298e21e78ebSinoguchi .desc = "Add all certs in file", 299e21e78ebSinoguchi .type = OPTION_ARG, 300e7718adaStb .opt.arg = &cfg.certfile, 301e21e78ebSinoguchi }, 302e21e78ebSinoguchi { 303e21e78ebSinoguchi .name = "certpbe", 304e21e78ebSinoguchi .argname = "alg", 305e21e78ebSinoguchi .desc = "Specify certificate PBE algorithm (default RC2-40)", 306e21e78ebSinoguchi .type = OPTION_ARG_FUNC, 307e21e78ebSinoguchi .opt.argfunc = pkcs12_opt_cert_pbe, 308e21e78ebSinoguchi }, 309e21e78ebSinoguchi { 310e21e78ebSinoguchi .name = "chain", 311e21e78ebSinoguchi .desc = "Add certificate chain", 312e21e78ebSinoguchi .type = OPTION_FLAG, 313e7718adaStb .opt.flag = &cfg.chain, 314e21e78ebSinoguchi }, 315e21e78ebSinoguchi { 316e21e78ebSinoguchi .name = "clcerts", 317e21e78ebSinoguchi .desc = "Only output client certificates", 318e21e78ebSinoguchi .type = OPTION_VALUE_OR, 319e7718adaStb .opt.value = &cfg.options, 320e21e78ebSinoguchi .value = CLCERTS, 321e21e78ebSinoguchi }, 322e21e78ebSinoguchi { 323e21e78ebSinoguchi .name = "descert", 324e21e78ebSinoguchi .desc = "Encrypt PKCS#12 certificates with triple DES (default RC2-40)", 325e21e78ebSinoguchi .type = OPTION_VALUE, 326e7718adaStb .opt.value = &cfg.cert_pbe, 327e21e78ebSinoguchi .value = NID_pbe_WithSHA1And3_Key_TripleDES_CBC, 328e21e78ebSinoguchi }, 329e21e78ebSinoguchi { 330e21e78ebSinoguchi .name = "export", 331e21e78ebSinoguchi .desc = "Output PKCS#12 file", 332e21e78ebSinoguchi .type = OPTION_FLAG, 333e7718adaStb .opt.flag = &cfg.export_cert, 334e21e78ebSinoguchi }, 335e21e78ebSinoguchi { 336e21e78ebSinoguchi .name = "in", 337e21e78ebSinoguchi .argname = "file", 338e21e78ebSinoguchi .desc = "Input filename", 339e21e78ebSinoguchi .type = OPTION_ARG, 340e7718adaStb .opt.arg = &cfg.infile, 341e21e78ebSinoguchi }, 342e21e78ebSinoguchi { 343e21e78ebSinoguchi .name = "info", 344e21e78ebSinoguchi .desc = "Give info about PKCS#12 structure", 345e21e78ebSinoguchi .type = OPTION_VALUE_OR, 346e7718adaStb .opt.value = &cfg.options, 347e21e78ebSinoguchi .value = INFO, 348e21e78ebSinoguchi }, 349e21e78ebSinoguchi { 350e21e78ebSinoguchi .name = "inkey", 351e21e78ebSinoguchi .argname = "file", 352e21e78ebSinoguchi .desc = "Private key if not infile", 353e21e78ebSinoguchi .type = OPTION_ARG, 354e7718adaStb .opt.arg = &cfg.keyname, 355e21e78ebSinoguchi }, 356e21e78ebSinoguchi { 357e21e78ebSinoguchi .name = "keyex", 358e21e78ebSinoguchi .desc = "Set MS key exchange type", 359e21e78ebSinoguchi .type = OPTION_VALUE, 360e7718adaStb .opt.value = &cfg.keytype, 361e21e78ebSinoguchi .value = KEY_EX, 362e21e78ebSinoguchi }, 363e21e78ebSinoguchi { 364e21e78ebSinoguchi .name = "keypbe", 365e21e78ebSinoguchi .argname = "alg", 366e21e78ebSinoguchi .desc = "Specify private key PBE algorithm (default 3DES)", 367e21e78ebSinoguchi .type = OPTION_ARG_FUNC, 368e21e78ebSinoguchi .opt.argfunc = pkcs12_opt_key_pbe, 369e21e78ebSinoguchi }, 370e21e78ebSinoguchi { 371e21e78ebSinoguchi .name = "keysig", 372e21e78ebSinoguchi .desc = "Set MS key signature type", 373e21e78ebSinoguchi .type = OPTION_VALUE, 374e7718adaStb .opt.value = &cfg.keytype, 375e21e78ebSinoguchi .value = KEY_SIG, 376e21e78ebSinoguchi }, 377e21e78ebSinoguchi { 378e21e78ebSinoguchi .name = "macalg", 379e21e78ebSinoguchi .argname = "alg", 380e21e78ebSinoguchi .desc = "Digest algorithm used in MAC (default SHA1)", 381e21e78ebSinoguchi .type = OPTION_ARG, 382e7718adaStb .opt.arg = &cfg.macalg, 383e21e78ebSinoguchi }, 384e21e78ebSinoguchi { 385e21e78ebSinoguchi .name = "maciter", 386e21e78ebSinoguchi .desc = "Use MAC iteration", 387e21e78ebSinoguchi .type = OPTION_VALUE, 388e7718adaStb .opt.value = &cfg.maciter, 389e21e78ebSinoguchi .value = PKCS12_DEFAULT_ITER, 390e21e78ebSinoguchi }, 391e21e78ebSinoguchi { 392e21e78ebSinoguchi .name = "name", 393e21e78ebSinoguchi .argname = "name", 394e21e78ebSinoguchi .desc = "Use name as friendly name", 395e21e78ebSinoguchi .type = OPTION_ARG, 396e7718adaStb .opt.arg = &cfg.name, 397e21e78ebSinoguchi }, 398e21e78ebSinoguchi { 399e21e78ebSinoguchi .name = "nocerts", 400e21e78ebSinoguchi .desc = "Don't output certificates", 401e21e78ebSinoguchi .type = OPTION_VALUE_OR, 402e7718adaStb .opt.value = &cfg.options, 403e21e78ebSinoguchi .value = NOCERTS, 404e21e78ebSinoguchi }, 405e21e78ebSinoguchi { 406e21e78ebSinoguchi .name = "nodes", 407e21e78ebSinoguchi .desc = "Don't encrypt private keys", 408e21e78ebSinoguchi .type = OPTION_ARGV_FUNC, 409e21e78ebSinoguchi .opt.argvfunc = pkcs12_opt_enc, 410e21e78ebSinoguchi }, 411e21e78ebSinoguchi { 412e21e78ebSinoguchi .name = "noiter", 413e21e78ebSinoguchi .desc = "Don't use encryption iteration", 414e21e78ebSinoguchi .type = OPTION_VALUE, 415e7718adaStb .opt.value = &cfg.iter, 416e21e78ebSinoguchi .value = 1, 417e21e78ebSinoguchi }, 418e21e78ebSinoguchi { 419e21e78ebSinoguchi .name = "nokeys", 420e21e78ebSinoguchi .desc = "Don't output private keys", 421e21e78ebSinoguchi .type = OPTION_VALUE_OR, 422e7718adaStb .opt.value = &cfg.options, 423e21e78ebSinoguchi .value = NOKEYS, 424e21e78ebSinoguchi }, 425e21e78ebSinoguchi { 426e21e78ebSinoguchi .name = "nomac", 427e21e78ebSinoguchi .desc = "Don't generate MAC", 428e21e78ebSinoguchi .type = OPTION_VALUE, 429e7718adaStb .opt.value = &cfg.maciter, 430e21e78ebSinoguchi .value = -1, 431e21e78ebSinoguchi }, 432e21e78ebSinoguchi { 433e21e78ebSinoguchi .name = "nomaciter", 434e21e78ebSinoguchi .desc = "Don't use MAC iteration", 435e21e78ebSinoguchi .type = OPTION_VALUE, 436e7718adaStb .opt.value = &cfg.maciter, 437e21e78ebSinoguchi .value = 1, 438e21e78ebSinoguchi }, 439e21e78ebSinoguchi { 440e21e78ebSinoguchi .name = "nomacver", 441e21e78ebSinoguchi .desc = "Don't verify MAC", 442e21e78ebSinoguchi .type = OPTION_VALUE, 443e7718adaStb .opt.value = &cfg.macver, 444e21e78ebSinoguchi .value = 0, 445e21e78ebSinoguchi }, 446e21e78ebSinoguchi { 447e21e78ebSinoguchi .name = "noout", 448e21e78ebSinoguchi .desc = "Don't output anything, just verify", 449e21e78ebSinoguchi .type = OPTION_VALUE_OR, 450e7718adaStb .opt.value = &cfg.options, 451e21e78ebSinoguchi .value = (NOKEYS | NOCERTS), 452e21e78ebSinoguchi }, 453e21e78ebSinoguchi { 454e21e78ebSinoguchi .name = "out", 455e21e78ebSinoguchi .argname = "file", 456e21e78ebSinoguchi .desc = "Output filename", 457e21e78ebSinoguchi .type = OPTION_ARG, 458e7718adaStb .opt.arg = &cfg.outfile, 459e21e78ebSinoguchi }, 460e21e78ebSinoguchi { 461e21e78ebSinoguchi .name = "passin", 462e21e78ebSinoguchi .argname = "arg", 463e21e78ebSinoguchi .desc = "Input file passphrase source", 464e21e78ebSinoguchi .type = OPTION_ARG, 465e7718adaStb .opt.arg = &cfg.passargin, 466e21e78ebSinoguchi }, 467e21e78ebSinoguchi { 468e21e78ebSinoguchi .name = "passout", 469e21e78ebSinoguchi .argname = "arg", 470e21e78ebSinoguchi .desc = "Output file passphrase source", 471e21e78ebSinoguchi .type = OPTION_ARG, 472e7718adaStb .opt.arg = &cfg.passargout, 473e21e78ebSinoguchi }, 474e21e78ebSinoguchi { 475e21e78ebSinoguchi .name = "password", 476e21e78ebSinoguchi .argname = "arg", 477e21e78ebSinoguchi .desc = "Set import/export password source", 478e21e78ebSinoguchi .type = OPTION_ARG_FUNC, 479e21e78ebSinoguchi .opt.argfunc = pkcs12_opt_passarg, 480e21e78ebSinoguchi }, 481e21e78ebSinoguchi { 482e21e78ebSinoguchi .name = "twopass", 483e21e78ebSinoguchi .desc = "Separate MAC, encryption passwords", 484e21e78ebSinoguchi .type = OPTION_FLAG, 485e7718adaStb .opt.flag = &cfg.twopass, 486e21e78ebSinoguchi }, 487e21e78ebSinoguchi { NULL }, 488e21e78ebSinoguchi }; 489e21e78ebSinoguchi 490e21e78ebSinoguchi static void 491e21e78ebSinoguchi pkcs12_usage(void) 492e21e78ebSinoguchi { 493e21e78ebSinoguchi fprintf(stderr, "usage: pkcs12 [-aes128 | -aes192 | -aes256 |"); 494e21e78ebSinoguchi fprintf(stderr, " -camellia128 |\n"); 495e21e78ebSinoguchi fprintf(stderr, " -camellia192 | -camellia256 | -des | -des3 |"); 496e21e78ebSinoguchi fprintf(stderr, " -idea]\n"); 497e21e78ebSinoguchi fprintf(stderr, " [-cacerts] [-CAfile file] [-caname name]\n"); 498e21e78ebSinoguchi fprintf(stderr, " [-CApath directory] [-certfile file]"); 499e21e78ebSinoguchi fprintf(stderr, " [-certpbe alg]\n"); 500e21e78ebSinoguchi fprintf(stderr, " [-chain] [-clcerts] [-CSP name] [-descert]"); 501e21e78ebSinoguchi fprintf(stderr, " [-export]\n"); 502e21e78ebSinoguchi fprintf(stderr, " [-in file] [-info] [-inkey file] [-keyex]"); 503e21e78ebSinoguchi fprintf(stderr, " [-keypbe alg]\n"); 504e21e78ebSinoguchi fprintf(stderr, " [-keysig] [-LMK] [-macalg alg] [-maciter]"); 505e21e78ebSinoguchi fprintf(stderr, " [-name name]\n"); 506e21e78ebSinoguchi fprintf(stderr, " [-nocerts] [-nodes] [-noiter] [-nokeys]"); 507e21e78ebSinoguchi fprintf(stderr, " [-nomac]\n"); 508e21e78ebSinoguchi fprintf(stderr, " [-nomaciter] [-nomacver] [-noout] [-out file]\n"); 509e21e78ebSinoguchi fprintf(stderr, " [-passin arg] [-passout arg] [-password arg]"); 510e21e78ebSinoguchi fprintf(stderr, " [-twopass]\n\n"); 511e21e78ebSinoguchi options_usage(pkcs12_options); 512e21e78ebSinoguchi fprintf(stderr, "\n"); 513e21e78ebSinoguchi } 514e21e78ebSinoguchi 515dab3f910Sjsing int 516dab3f910Sjsing pkcs12_main(int argc, char **argv) 517dab3f910Sjsing { 518dab3f910Sjsing BIO *in = NULL, *out = NULL; 519dab3f910Sjsing PKCS12 *p12 = NULL; 520dab3f910Sjsing char pass[50], macpass[50]; 521dab3f910Sjsing int ret = 1; 522dab3f910Sjsing char *cpass = NULL, *mpass = NULL; 523dab3f910Sjsing char *passin = NULL, *passout = NULL; 524dab3f910Sjsing 52551811eadSderaadt if (pledge("stdio cpath wpath rpath tty", NULL) == -1) { 5269bc487adSdoug perror("pledge"); 527e370f0eeSdoug exit(1); 528e370f0eeSdoug } 5299bc487adSdoug 530e7718adaStb memset(&cfg, 0, sizeof(cfg)); 531e7718adaStb cfg.cert_pbe = NID_pbe_WithSHA1And40BitRC2_CBC; 532e7718adaStb cfg.enc = EVP_des_ede3_cbc(); 533e7718adaStb cfg.iter = PKCS12_DEFAULT_ITER; 534e7718adaStb cfg.key_pbe = NID_pbe_WithSHA1And3_Key_TripleDES_CBC; 535e7718adaStb cfg.maciter = PKCS12_DEFAULT_ITER; 536e7718adaStb cfg.macver = 1; 537dab3f910Sjsing 538e21e78ebSinoguchi if (options_parse(argc, argv, pkcs12_options, NULL, NULL) != 0) { 539e21e78ebSinoguchi pkcs12_usage(); 540dab3f910Sjsing goto end; 541dab3f910Sjsing } 542dab3f910Sjsing 543e7718adaStb if (cfg.passarg != NULL) { 544e7718adaStb if (cfg.export_cert) 545e7718adaStb cfg.passargout = cfg.passarg; 546dab3f910Sjsing else 547e7718adaStb cfg.passargin = cfg.passarg; 548dab3f910Sjsing } 549e7718adaStb if (!app_passwd(bio_err, cfg.passargin, 550e7718adaStb cfg.passargout, &passin, &passout)) { 551dab3f910Sjsing BIO_printf(bio_err, "Error getting passwords\n"); 552dab3f910Sjsing goto end; 553dab3f910Sjsing } 5542cb6c044Sinoguchi if (cpass == NULL) { 555e7718adaStb if (cfg.export_cert) 556dab3f910Sjsing cpass = passout; 557dab3f910Sjsing else 558dab3f910Sjsing cpass = passin; 559dab3f910Sjsing } 5602cb6c044Sinoguchi if (cpass != NULL) { 561dab3f910Sjsing mpass = cpass; 562e7718adaStb cfg.noprompt = 1; 563dab3f910Sjsing } else { 564dab3f910Sjsing cpass = pass; 565dab3f910Sjsing mpass = macpass; 566dab3f910Sjsing } 567dab3f910Sjsing 568e7718adaStb if (cfg.infile == NULL) 569dab3f910Sjsing in = BIO_new_fp(stdin, BIO_NOCLOSE); 570dab3f910Sjsing else 571e7718adaStb in = BIO_new_file(cfg.infile, "rb"); 5722cb6c044Sinoguchi if (in == NULL) { 573dab3f910Sjsing BIO_printf(bio_err, "Error opening input file %s\n", 574e7718adaStb cfg.infile ? cfg.infile : "<stdin>"); 575e7718adaStb perror(cfg.infile); 576dab3f910Sjsing goto end; 577dab3f910Sjsing } 578dab3f910Sjsing 579e7718adaStb if (cfg.outfile == NULL) { 580dab3f910Sjsing out = BIO_new_fp(stdout, BIO_NOCLOSE); 581dab3f910Sjsing } else 582e7718adaStb out = BIO_new_file(cfg.outfile, "wb"); 5832cb6c044Sinoguchi if (out == NULL) { 584dab3f910Sjsing BIO_printf(bio_err, "Error opening output file %s\n", 585e7718adaStb cfg.outfile ? cfg.outfile : "<stdout>"); 586e7718adaStb perror(cfg.outfile); 587dab3f910Sjsing goto end; 588dab3f910Sjsing } 589e7718adaStb if (cfg.twopass) { 59002e96206Sinoguchi if (EVP_read_pw_string(macpass, sizeof macpass, 591e7718adaStb "Enter MAC Password:", cfg.export_cert)) { 592dab3f910Sjsing BIO_printf(bio_err, "Can't read Password\n"); 593dab3f910Sjsing goto end; 594dab3f910Sjsing } 595dab3f910Sjsing } 596e7718adaStb if (cfg.export_cert) { 597dab3f910Sjsing EVP_PKEY *key = NULL; 598dab3f910Sjsing X509 *ucert = NULL, *x = NULL; 599dab3f910Sjsing STACK_OF(X509) *certs = NULL; 600dab3f910Sjsing const EVP_MD *macmd = NULL; 601dab3f910Sjsing unsigned char *catmp = NULL; 602dab3f910Sjsing int i; 603dab3f910Sjsing 604e7718adaStb if ((cfg.options & (NOCERTS | NOKEYS)) == 60502e96206Sinoguchi (NOCERTS | NOKEYS)) { 606dab3f910Sjsing BIO_printf(bio_err, "Nothing to do!\n"); 607dab3f910Sjsing goto export_end; 608dab3f910Sjsing } 609e7718adaStb if (cfg.options & NOCERTS) 610e7718adaStb cfg.chain = 0; 611dab3f910Sjsing 612e7718adaStb if (!(cfg.options & NOKEYS)) { 613e7718adaStb key = load_key(bio_err, cfg.keyname ? 614e7718adaStb cfg.keyname : cfg.infile, 6155284dfeaSbcook FORMAT_PEM, 1, passin, "private key"); 616dab3f910Sjsing if (!key) 617dab3f910Sjsing goto export_end; 618dab3f910Sjsing } 619dab3f910Sjsing 620dab3f910Sjsing /* Load in all certs in input file */ 621e7718adaStb if (!(cfg.options & NOCERTS)) { 622e7718adaStb certs = load_certs(bio_err, cfg.infile, 62302e96206Sinoguchi FORMAT_PEM, NULL, "certificates"); 6242cb6c044Sinoguchi if (certs == NULL) 625dab3f910Sjsing goto export_end; 626dab3f910Sjsing 6272cb6c044Sinoguchi if (key != NULL) { 628dab3f910Sjsing /* Look for matching private key */ 629dab3f910Sjsing for (i = 0; i < sk_X509_num(certs); i++) { 630dab3f910Sjsing x = sk_X509_value(certs, i); 631dab3f910Sjsing if (X509_check_private_key(x, key)) { 632dab3f910Sjsing ucert = x; 633dab3f910Sjsing /* Zero keyid and alias */ 634dab3f910Sjsing X509_keyid_set1(ucert, NULL, 0); 635dab3f910Sjsing X509_alias_set1(ucert, NULL, 0); 636dab3f910Sjsing /* Remove from list */ 637dab3f910Sjsing (void) sk_X509_delete(certs, i); 638dab3f910Sjsing break; 639dab3f910Sjsing } 640dab3f910Sjsing } 6412cb6c044Sinoguchi if (ucert == NULL) { 64202e96206Sinoguchi BIO_printf(bio_err, 64302e96206Sinoguchi "No certificate matches private key\n"); 644dab3f910Sjsing goto export_end; 645dab3f910Sjsing } 646dab3f910Sjsing } 647dab3f910Sjsing } 648dab3f910Sjsing 649dab3f910Sjsing /* Add any more certificates asked for */ 650e7718adaStb if (cfg.certfile != NULL) { 651dab3f910Sjsing STACK_OF(X509) *morecerts = NULL; 6522cb6c044Sinoguchi if ((morecerts = load_certs(bio_err, 653e7718adaStb cfg.certfile, FORMAT_PEM, NULL, 6542cb6c044Sinoguchi "certificates from certfile")) == NULL) 655dab3f910Sjsing goto export_end; 656*e7c3ccd1Stb while (sk_X509_num(morecerts) > 0) { 657*e7c3ccd1Stb X509 *cert = sk_X509_shift(morecerts); 658*e7c3ccd1Stb 659*e7c3ccd1Stb if (!sk_X509_push(certs, cert)) { 660*e7c3ccd1Stb X509_free(cert); 661*e7c3ccd1Stb sk_X509_pop_free(morecerts, X509_free); 662*e7c3ccd1Stb goto export_end; 663*e7c3ccd1Stb } 664*e7c3ccd1Stb } 665*e7c3ccd1Stb 666dab3f910Sjsing sk_X509_free(morecerts); 667dab3f910Sjsing } 668dab3f910Sjsing 669dab3f910Sjsing 670dab3f910Sjsing /* If chaining get chain from user cert */ 671e7718adaStb if (cfg.chain) { 672dab3f910Sjsing int vret; 673dab3f910Sjsing STACK_OF(X509) *chain2; 674dab3f910Sjsing X509_STORE *store = X509_STORE_new(); 6752cb6c044Sinoguchi if (store == NULL) { 67602e96206Sinoguchi BIO_printf(bio_err, 67702e96206Sinoguchi "Memory allocation error\n"); 678dab3f910Sjsing goto export_end; 679dab3f910Sjsing } 68002e96206Sinoguchi if (!X509_STORE_load_locations(store, 681e7718adaStb cfg.CAfile, cfg.CApath)) 682dab3f910Sjsing X509_STORE_set_default_paths(store); 683dab3f910Sjsing 684dab3f910Sjsing vret = get_cert_chain(ucert, store, &chain2); 685dab3f910Sjsing X509_STORE_free(store); 686dab3f910Sjsing 6870bfea675Stb if (vret == X509_V_OK) { 688dab3f910Sjsing /* Exclude verified certificate */ 689*e7c3ccd1Stb X509_free(sk_X509_shift(chain2)); 690*e7c3ccd1Stb 691*e7c3ccd1Stb while (sk_X509_num(chain2) > 0) { 692*e7c3ccd1Stb X509 *cert = sk_X509_shift(chain2); 693*e7c3ccd1Stb 694*e7c3ccd1Stb if (!sk_X509_push(certs, cert)) { 695*e7c3ccd1Stb X509_free(cert); 696*e7c3ccd1Stb sk_X509_pop_free(chain2, 697*e7c3ccd1Stb X509_free); 698*e7c3ccd1Stb goto export_end; 699*e7c3ccd1Stb } 700*e7c3ccd1Stb } 701dab3f910Sjsing sk_X509_free(chain2); 702dab3f910Sjsing } else { 7030bfea675Stb if (vret != X509_V_ERR_UNSPECIFIED) 70402e96206Sinoguchi BIO_printf(bio_err, 70502e96206Sinoguchi "Error %s getting chain.\n", 70602e96206Sinoguchi X509_verify_cert_error_string( 70702e96206Sinoguchi vret)); 708dab3f910Sjsing else 709dab3f910Sjsing ERR_print_errors(bio_err); 710*e7c3ccd1Stb sk_X509_pop_free(chain2, X509_free); 711dab3f910Sjsing goto export_end; 712dab3f910Sjsing } 713dab3f910Sjsing } 714dab3f910Sjsing /* Add any CA names */ 715dab3f910Sjsing 716e7718adaStb for (i = 0; i < sk_OPENSSL_STRING_num(cfg.canames); 71702e96206Sinoguchi i++) { 71802e96206Sinoguchi catmp = (unsigned char *) sk_OPENSSL_STRING_value( 719e7718adaStb cfg.canames, i); 720dab3f910Sjsing X509_alias_set1(sk_X509_value(certs, i), catmp, -1); 721dab3f910Sjsing } 722dab3f910Sjsing 723e7718adaStb if (!cfg.noprompt && 72402e96206Sinoguchi EVP_read_pw_string(pass, sizeof pass, 72502e96206Sinoguchi "Enter Export Password:", 1)) { 726dab3f910Sjsing BIO_printf(bio_err, "Can't read Password\n"); 727dab3f910Sjsing goto export_end; 728dab3f910Sjsing } 729e7718adaStb if (!cfg.twopass) 730dab3f910Sjsing strlcpy(macpass, pass, sizeof macpass); 731dab3f910Sjsing 732dab3f910Sjsing 733e7718adaStb p12 = PKCS12_create(cpass, cfg.name, key, ucert, 734e7718adaStb certs, cfg.key_pbe, cfg.cert_pbe, 735e7718adaStb cfg.iter, -1, cfg.keytype); 736dab3f910Sjsing 7372cb6c044Sinoguchi if (p12 == NULL) { 738dab3f910Sjsing ERR_print_errors(bio_err); 739dab3f910Sjsing goto export_end; 740dab3f910Sjsing } 741e7718adaStb if (cfg.macalg != NULL) { 742e7718adaStb macmd = EVP_get_digestbyname(cfg.macalg); 7432cb6c044Sinoguchi if (macmd == NULL) { 74402e96206Sinoguchi BIO_printf(bio_err, 74502e96206Sinoguchi "Unknown digest algorithm %s\n", 746e7718adaStb cfg.macalg); 747dab3f910Sjsing } 748dab3f910Sjsing } 749e7718adaStb if (cfg.maciter != -1) 75002e96206Sinoguchi PKCS12_set_mac(p12, mpass, -1, NULL, 0, 751e7718adaStb cfg.maciter, macmd); 752dab3f910Sjsing 753dab3f910Sjsing i2d_PKCS12_bio(out, p12); 754dab3f910Sjsing 755dab3f910Sjsing ret = 0; 756dab3f910Sjsing 757dab3f910Sjsing export_end: 758dab3f910Sjsing EVP_PKEY_free(key); 759dab3f910Sjsing sk_X509_pop_free(certs, X509_free); 760dab3f910Sjsing X509_free(ucert); 761dab3f910Sjsing 762dab3f910Sjsing goto end; 763dab3f910Sjsing 764dab3f910Sjsing } 7652cb6c044Sinoguchi if ((p12 = d2i_PKCS12_bio(in, NULL)) == NULL) { 766dab3f910Sjsing ERR_print_errors(bio_err); 767dab3f910Sjsing goto end; 768dab3f910Sjsing } 769e7718adaStb if (!cfg.noprompt && EVP_read_pw_string(pass, sizeof pass, 77002e96206Sinoguchi "Enter Import Password:", 0)) { 771dab3f910Sjsing BIO_printf(bio_err, "Can't read Password\n"); 772dab3f910Sjsing goto end; 773dab3f910Sjsing } 774dab3f910Sjsing 775e7718adaStb if (!cfg.twopass) 776dab3f910Sjsing strlcpy(macpass, pass, sizeof macpass); 777dab3f910Sjsing 778e7718adaStb if ((cfg.options & INFO) != 0 && PKCS12_mac_present(p12)) { 779b81aa332Stb const ASN1_INTEGER *iter; 780b81aa332Stb 781b81aa332Stb PKCS12_get0_mac(NULL, NULL, NULL, &iter, p12); 78202e96206Sinoguchi BIO_printf(bio_err, "MAC Iteration %ld\n", 783b81aa332Stb iter != NULL ? ASN1_INTEGER_get(iter) : 1); 784b81aa332Stb } 785e7718adaStb if (cfg.macver) { 786dab3f910Sjsing /* If we enter empty password try no password first */ 787dab3f910Sjsing if (!mpass[0] && PKCS12_verify_mac(p12, NULL, 0)) { 788dab3f910Sjsing /* If mac and crypto pass the same set it to NULL too */ 789e7718adaStb if (!cfg.twopass) 790dab3f910Sjsing cpass = NULL; 791dab3f910Sjsing } else if (!PKCS12_verify_mac(p12, mpass, -1)) { 79202e96206Sinoguchi BIO_printf(bio_err, 79302e96206Sinoguchi "Mac verify error: invalid password?\n"); 794dab3f910Sjsing ERR_print_errors(bio_err); 795dab3f910Sjsing goto end; 796dab3f910Sjsing } 797dab3f910Sjsing BIO_printf(bio_err, "MAC verified OK\n"); 798dab3f910Sjsing } 799e7718adaStb if (!dump_certs_keys_p12(out, p12, cpass, -1, cfg.options, 80002e96206Sinoguchi passout)) { 801dab3f910Sjsing BIO_printf(bio_err, "Error outputting keys and certificates\n"); 802dab3f910Sjsing ERR_print_errors(bio_err); 803dab3f910Sjsing goto end; 804dab3f910Sjsing } 805dab3f910Sjsing ret = 0; 806dab3f910Sjsing end: 807dab3f910Sjsing PKCS12_free(p12); 808dab3f910Sjsing BIO_free(in); 809dab3f910Sjsing BIO_free_all(out); 810e7718adaStb sk_OPENSSL_STRING_free(cfg.canames); 811dab3f910Sjsing free(passin); 812dab3f910Sjsing free(passout); 813dab3f910Sjsing 814dab3f910Sjsing return (ret); 815dab3f910Sjsing } 816dab3f910Sjsing 8170892a407Sinoguchi static int 8180892a407Sinoguchi dump_certs_keys_p12(BIO *out, PKCS12 *p12, char *pass, int passlen, int options, 8190892a407Sinoguchi char *pempass) 820dab3f910Sjsing { 821dab3f910Sjsing STACK_OF(PKCS7) *asafes = NULL; 822dab3f910Sjsing STACK_OF(PKCS12_SAFEBAG) *bags; 823dab3f910Sjsing int i, bagnid; 824dab3f910Sjsing int ret = 0; 825dab3f910Sjsing PKCS7 *p7; 826dab3f910Sjsing 8272cb6c044Sinoguchi if ((asafes = PKCS12_unpack_authsafes(p12)) == NULL) 828dab3f910Sjsing return 0; 829dab3f910Sjsing for (i = 0; i < sk_PKCS7_num(asafes); i++) { 830dab3f910Sjsing p7 = sk_PKCS7_value(asafes, i); 831dab3f910Sjsing bagnid = OBJ_obj2nid(p7->type); 832dab3f910Sjsing if (bagnid == NID_pkcs7_data) { 833dab3f910Sjsing bags = PKCS12_unpack_p7data(p7); 834dab3f910Sjsing if (options & INFO) 835dab3f910Sjsing BIO_printf(bio_err, "PKCS7 Data\n"); 836dab3f910Sjsing } else if (bagnid == NID_pkcs7_encrypted) { 837dab3f910Sjsing if (options & INFO) { 838dab3f910Sjsing BIO_printf(bio_err, "PKCS7 Encrypted data: "); 839dab3f910Sjsing alg_print(bio_err, 840dab3f910Sjsing p7->d.encrypted->enc_data->algorithm); 841dab3f910Sjsing } 842dab3f910Sjsing bags = PKCS12_unpack_p7encdata(p7, pass, passlen); 843dab3f910Sjsing } else 844dab3f910Sjsing continue; 8452cb6c044Sinoguchi if (bags == NULL) 846dab3f910Sjsing goto err; 847dab3f910Sjsing if (!dump_certs_pkeys_bags(out, bags, pass, passlen, 848dab3f910Sjsing options, pempass)) { 849dab3f910Sjsing sk_PKCS12_SAFEBAG_pop_free(bags, PKCS12_SAFEBAG_free); 850dab3f910Sjsing goto err; 851dab3f910Sjsing } 852dab3f910Sjsing sk_PKCS12_SAFEBAG_pop_free(bags, PKCS12_SAFEBAG_free); 853dab3f910Sjsing bags = NULL; 854dab3f910Sjsing } 855dab3f910Sjsing ret = 1; 856dab3f910Sjsing 857dab3f910Sjsing err: 858dab3f910Sjsing sk_PKCS7_pop_free(asafes, PKCS7_free); 859dab3f910Sjsing return ret; 860dab3f910Sjsing } 861dab3f910Sjsing 8620892a407Sinoguchi static int 863b81aa332Stb dump_certs_pkeys_bags(BIO *out, const STACK_OF(PKCS12_SAFEBAG) *bags, 864b81aa332Stb char *pass, int passlen, int options, char *pempass) 865dab3f910Sjsing { 866dab3f910Sjsing int i; 8670892a407Sinoguchi 868dab3f910Sjsing for (i = 0; i < sk_PKCS12_SAFEBAG_num(bags); i++) { 869dab3f910Sjsing if (!dump_certs_pkeys_bag(out, 870dab3f910Sjsing sk_PKCS12_SAFEBAG_value(bags, i), 871dab3f910Sjsing pass, passlen, 872dab3f910Sjsing options, pempass)) 873dab3f910Sjsing return 0; 874dab3f910Sjsing } 875dab3f910Sjsing return 1; 876dab3f910Sjsing } 877dab3f910Sjsing 8780892a407Sinoguchi static int 8790892a407Sinoguchi dump_certs_pkeys_bag(BIO *out, PKCS12_SAFEBAG *bag, char *pass, int passlen, 8800892a407Sinoguchi int options, char *pempass) 881dab3f910Sjsing { 882dab3f910Sjsing EVP_PKEY *pkey; 883b81aa332Stb const STACK_OF(X509_ATTRIBUTE) *attrs; 884dab3f910Sjsing X509 *x509; 885dab3f910Sjsing 886b81aa332Stb attrs = PKCS12_SAFEBAG_get0_attrs(bag); 887b81aa332Stb 888b81aa332Stb switch (PKCS12_SAFEBAG_get_nid(bag)) { 889dab3f910Sjsing case NID_keyBag: 890b81aa332Stb { 891b81aa332Stb const PKCS8_PRIV_KEY_INFO *p8; 892b81aa332Stb 893dab3f910Sjsing if (options & INFO) 894dab3f910Sjsing BIO_printf(bio_err, "Key bag\n"); 895dab3f910Sjsing if (options & NOKEYS) 896dab3f910Sjsing return 1; 897b81aa332Stb print_attribs(out, attrs, "Bag Attributes"); 898b81aa332Stb if ((p8 = PKCS12_SAFEBAG_get0_p8inf(bag)) == NULL) 899b81aa332Stb return 0; 9000bfea675Stb if ((pkey = EVP_PKCS82PKEY(p8)) == NULL) 901dab3f910Sjsing return 0; 9020bfea675Stb print_attribs(out, PKCS8_pkey_get0_attrs(p8), "Key Attributes"); 903e7718adaStb PEM_write_bio_PrivateKey(out, pkey, cfg.enc, NULL, 0, 90402e96206Sinoguchi NULL, pempass); 905dab3f910Sjsing EVP_PKEY_free(pkey); 906dab3f910Sjsing break; 907b81aa332Stb } 908dab3f910Sjsing 909dab3f910Sjsing case NID_pkcs8ShroudedKeyBag: 910b81aa332Stb { 911b81aa332Stb PKCS8_PRIV_KEY_INFO *p8; 912b81aa332Stb 913dab3f910Sjsing if (options & INFO) { 914b81aa332Stb const X509_SIG *tp8; 9153d522683Stb const X509_ALGOR *tp8alg; 9163d522683Stb 917dab3f910Sjsing BIO_printf(bio_err, "Shrouded Keybag: "); 918b81aa332Stb if ((tp8 = PKCS12_SAFEBAG_get0_pkcs8(bag)) == NULL) 919b81aa332Stb return 0; 920b81aa332Stb X509_SIG_get0(tp8, &tp8alg, NULL); 9213d522683Stb alg_print(bio_err, tp8alg); 922dab3f910Sjsing } 923dab3f910Sjsing if (options & NOKEYS) 924dab3f910Sjsing return 1; 925b81aa332Stb print_attribs(out, attrs, "Bag Attributes"); 9262cb6c044Sinoguchi if ((p8 = PKCS12_decrypt_skey(bag, pass, passlen)) == NULL) 927dab3f910Sjsing return 0; 9282cb6c044Sinoguchi if ((pkey = EVP_PKCS82PKEY(p8)) == NULL) { 929dab3f910Sjsing PKCS8_PRIV_KEY_INFO_free(p8); 930dab3f910Sjsing return 0; 931dab3f910Sjsing } 9320bfea675Stb print_attribs(out, PKCS8_pkey_get0_attrs(p8), "Key Attributes"); 933dab3f910Sjsing PKCS8_PRIV_KEY_INFO_free(p8); 934e7718adaStb PEM_write_bio_PrivateKey(out, pkey, cfg.enc, NULL, 0, 93502e96206Sinoguchi NULL, pempass); 936dab3f910Sjsing EVP_PKEY_free(pkey); 937dab3f910Sjsing break; 938b81aa332Stb } 939dab3f910Sjsing 940dab3f910Sjsing case NID_certBag: 941dab3f910Sjsing if (options & INFO) 942dab3f910Sjsing BIO_printf(bio_err, "Certificate bag\n"); 943dab3f910Sjsing if (options & NOCERTS) 944dab3f910Sjsing return 1; 945b81aa332Stb if (PKCS12_SAFEBAG_get0_attr(bag, NID_localKeyID) != NULL) { 946dab3f910Sjsing if (options & CACERTS) 947dab3f910Sjsing return 1; 948dab3f910Sjsing } else if (options & CLCERTS) 949dab3f910Sjsing return 1; 950b81aa332Stb print_attribs(out, attrs, "Bag Attributes"); 951b81aa332Stb if (PKCS12_SAFEBAG_get_bag_nid(bag) != NID_x509Certificate) 952dab3f910Sjsing return 1; 9532cb6c044Sinoguchi if ((x509 = PKCS12_certbag2x509(bag)) == NULL) 954dab3f910Sjsing return 0; 955dab3f910Sjsing dump_cert_text(out, x509); 956dab3f910Sjsing PEM_write_bio_X509(out, x509); 957dab3f910Sjsing X509_free(x509); 958dab3f910Sjsing break; 959dab3f910Sjsing 960dab3f910Sjsing case NID_safeContentsBag: 961dab3f910Sjsing if (options & INFO) 962dab3f910Sjsing BIO_printf(bio_err, "Safe Contents bag\n"); 963b81aa332Stb print_attribs(out, attrs, "Bag Attributes"); 964b81aa332Stb return dump_certs_pkeys_bags(out, PKCS12_SAFEBAG_get0_safes(bag), 965b81aa332Stb pass, passlen, options, pempass); 966dab3f910Sjsing 967dab3f910Sjsing default: 968dab3f910Sjsing BIO_printf(bio_err, "Warning unsupported bag type: "); 969b81aa332Stb i2a_ASN1_OBJECT(bio_err, PKCS12_SAFEBAG_get0_type(bag)); 970dab3f910Sjsing BIO_printf(bio_err, "\n"); 971dab3f910Sjsing return 1; 972dab3f910Sjsing break; 973dab3f910Sjsing } 974dab3f910Sjsing return 1; 975dab3f910Sjsing } 976dab3f910Sjsing 977dab3f910Sjsing /* Given a single certificate return a verified chain or NULL if error */ 9780892a407Sinoguchi static int 9790bfea675Stb get_cert_chain(X509 *cert, X509_STORE *store, STACK_OF(X509) **out_chain) 980dab3f910Sjsing { 9810bfea675Stb X509_STORE_CTX *store_ctx = NULL; 9820bfea675Stb STACK_OF(X509) *chain = NULL; 9830bfea675Stb int ret = X509_V_ERR_UNSPECIFIED; 984dab3f910Sjsing 9850bfea675Stb if ((store_ctx = X509_STORE_CTX_new()) == NULL) 986dab3f910Sjsing goto err; 9870bfea675Stb if (!X509_STORE_CTX_init(store_ctx, store, cert, NULL)) 9880bfea675Stb goto err; 989dab3f910Sjsing 9900bfea675Stb if (X509_verify_cert(store_ctx) > 0) { 9910bfea675Stb if ((chain = X509_STORE_CTX_get1_chain(store_ctx)) == NULL) 9920bfea675Stb goto err; 9930bfea675Stb } 9940bfea675Stb ret = X509_STORE_CTX_get_error(store_ctx); 9950bfea675Stb 9960bfea675Stb err: 9970bfea675Stb X509_STORE_CTX_free(store_ctx); 9980bfea675Stb *out_chain = chain; 9990bfea675Stb 10000bfea675Stb return ret; 1001dab3f910Sjsing } 1002dab3f910Sjsing 10030892a407Sinoguchi static int 10040bfea675Stb alg_print(BIO *x, const X509_ALGOR *alg) 1005dab3f910Sjsing { 100695489d3bStb PBEPARAM *pbe = NULL; 100795489d3bStb const ASN1_OBJECT *aobj; 100895489d3bStb int param_type; 100995489d3bStb const void *param; 10100892a407Sinoguchi 101195489d3bStb X509_ALGOR_get0(&aobj, ¶m_type, ¶m, alg); 101295489d3bStb if (param_type == V_ASN1_SEQUENCE) 101395489d3bStb pbe = ASN1_item_unpack(param, &PBEPARAM_it); 10142cb6c044Sinoguchi if (pbe == NULL) 1015dab3f910Sjsing return 1; 1016dab3f910Sjsing BIO_printf(bio_err, "%s, Iteration %ld\n", 101795489d3bStb OBJ_nid2ln(OBJ_obj2nid(aobj)), 1018dab3f910Sjsing ASN1_INTEGER_get(pbe->iter)); 1019b4a69dbeStb ASN1_item_free((ASN1_VALUE *)pbe, &PBEPARAM_it); 1020dab3f910Sjsing return 1; 1021dab3f910Sjsing } 1022dab3f910Sjsing 1023dab3f910Sjsing /* Generalised attribute print: handle PKCS#8 and bag attributes */ 10240892a407Sinoguchi static void 10250bfea675Stb print_attribute(BIO *out, const ASN1_TYPE *av) 1026dab3f910Sjsing { 1027dab3f910Sjsing char *value; 1028dab3f910Sjsing 1029dab3f910Sjsing switch (av->type) { 1030dab3f910Sjsing case V_ASN1_BMPSTRING: 103102e96206Sinoguchi value = OPENSSL_uni2asc( 103202e96206Sinoguchi av->value.bmpstring->data, 1033dab3f910Sjsing av->value.bmpstring->length); 1034dab3f910Sjsing BIO_printf(out, "%s\n", value); 1035dab3f910Sjsing free(value); 1036dab3f910Sjsing break; 1037dab3f910Sjsing 1038dab3f910Sjsing case V_ASN1_OCTET_STRING: 1039dab3f910Sjsing hex_prin(out, av->value.octet_string->data, 1040dab3f910Sjsing av->value.octet_string->length); 1041dab3f910Sjsing BIO_printf(out, "\n"); 1042dab3f910Sjsing break; 1043dab3f910Sjsing 1044dab3f910Sjsing case V_ASN1_BIT_STRING: 1045dab3f910Sjsing hex_prin(out, av->value.bit_string->data, 1046dab3f910Sjsing av->value.bit_string->length); 1047dab3f910Sjsing BIO_printf(out, "\n"); 1048dab3f910Sjsing break; 1049dab3f910Sjsing 1050dab3f910Sjsing default: 105102e96206Sinoguchi BIO_printf(out, "<Unsupported tag %d>\n", 105202e96206Sinoguchi av->type); 1053dab3f910Sjsing break; 1054dab3f910Sjsing } 10550bfea675Stb } 10560bfea675Stb 10570892a407Sinoguchi static int 10580892a407Sinoguchi print_attribs(BIO *out, const STACK_OF(X509_ATTRIBUTE) *attrlst, 10590892a407Sinoguchi const char *name) 10600bfea675Stb { 10610bfea675Stb X509_ATTRIBUTE *attr; 10620bfea675Stb ASN1_TYPE *av; 10630bfea675Stb int i, j, attr_nid; 10640892a407Sinoguchi 10652cb6c044Sinoguchi if (attrlst == NULL) { 10660bfea675Stb BIO_printf(out, "%s: <No Attributes>\n", name); 10670bfea675Stb return 1; 10680bfea675Stb } 10690bfea675Stb if (!sk_X509_ATTRIBUTE_num(attrlst)) { 10700bfea675Stb BIO_printf(out, "%s: <Empty Attributes>\n", name); 10710bfea675Stb return 1; 10720bfea675Stb } 10730bfea675Stb BIO_printf(out, "%s\n", name); 10740bfea675Stb for (i = 0; i < sk_X509_ATTRIBUTE_num(attrlst); i++) { 10750bfea675Stb ASN1_OBJECT *obj; 10760bfea675Stb 10770bfea675Stb attr = sk_X509_ATTRIBUTE_value(attrlst, i); 10780bfea675Stb obj = X509_ATTRIBUTE_get0_object(attr); 10790bfea675Stb attr_nid = OBJ_obj2nid(X509_ATTRIBUTE_get0_object(attr)); 10800bfea675Stb BIO_printf(out, " "); 10810bfea675Stb if (attr_nid == NID_undef) { 10820bfea675Stb i2a_ASN1_OBJECT(out, obj); 10830bfea675Stb BIO_printf(out, ": "); 10840bfea675Stb } else 10850bfea675Stb BIO_printf(out, "%s: ", OBJ_nid2ln(attr_nid)); 10860bfea675Stb 10870bfea675Stb if (X509_ATTRIBUTE_count(attr)) { 10880bfea675Stb for (j = 0; j < X509_ATTRIBUTE_count(attr); j++) { 10890bfea675Stb av = X509_ATTRIBUTE_get0_type(attr, j); 10900bfea675Stb print_attribute(out, av); 10910bfea675Stb } 1092dab3f910Sjsing } else 1093dab3f910Sjsing BIO_printf(out, "<No Values>\n"); 1094dab3f910Sjsing } 1095dab3f910Sjsing return 1; 1096dab3f910Sjsing } 1097dab3f910Sjsing 10980892a407Sinoguchi static void 1099dab3f910Sjsing hex_prin(BIO *out, unsigned char *buf, int len) 1100dab3f910Sjsing { 1101dab3f910Sjsing int i; 11020892a407Sinoguchi 1103dab3f910Sjsing for (i = 0; i < len; i++) 1104dab3f910Sjsing BIO_printf(out, "%02X ", buf[i]); 1105dab3f910Sjsing } 1106dab3f910Sjsing 1107dab3f910Sjsing static int 1108dab3f910Sjsing set_pbe(BIO *err, int *ppbe, const char *str) 1109dab3f910Sjsing { 11102cb6c044Sinoguchi if (str == NULL) 1111dab3f910Sjsing return 0; 1112f22d752aSinoguchi if (strcmp(str, "NONE") == 0) { 1113dab3f910Sjsing *ppbe = -1; 1114dab3f910Sjsing return 1; 1115dab3f910Sjsing } 1116dab3f910Sjsing *ppbe = OBJ_txt2nid(str); 1117dab3f910Sjsing if (*ppbe == NID_undef) { 1118dab3f910Sjsing BIO_printf(bio_err, "Unknown PBE algorithm %s\n", str); 1119dab3f910Sjsing return 0; 1120dab3f910Sjsing } 1121dab3f910Sjsing return 1; 1122dab3f910Sjsing } 1123dab3f910Sjsing 1124dab3f910Sjsing #endif 1125