195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * project 1999.
395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley */
495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley/* ====================================================================
595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * Copyright (c) 1999 The OpenSSL Project.  All rights reserved.
695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley *
795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * Redistribution and use in source and binary forms, with or without
895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * modification, are permitted provided that the following conditions
995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * are met:
1095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley *
1195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * 1. Redistributions of source code must retain the above copyright
1295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley *    notice, this list of conditions and the following disclaimer.
1395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley *
1495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * 2. Redistributions in binary form must reproduce the above copyright
1595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley *    notice, this list of conditions and the following disclaimer in
1695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley *    the documentation and/or other materials provided with the
1795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley *    distribution.
1895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley *
1995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * 3. All advertising materials mentioning features or use of this
2095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley *    software must display the following acknowledgment:
2195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley *    "This product includes software developed by the OpenSSL Project
2295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
2395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley *
2495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
2595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley *    endorse or promote products derived from this software without
2695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley *    prior written permission. For written permission, please contact
2795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley *    licensing@OpenSSL.org.
2895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley *
2995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * 5. Products derived from this software may not be called "OpenSSL"
3095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley *    nor may "OpenSSL" appear in their names without prior written
3195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley *    permission of the OpenSSL Project.
3295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley *
3395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * 6. Redistributions of any form whatsoever must retain the following
3495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley *    acknowledgment:
3595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley *    "This product includes software developed by the OpenSSL Project
3695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
3795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley *
3895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
3995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
4095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
4195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
4295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
4395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
4495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
4595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
4695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
4795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
4895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
4995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * OF THE POSSIBILITY OF SUCH DAMAGE.
5095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * ====================================================================
5195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley *
5295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * This product includes cryptographic software written by Eric Young
5395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * (eay@cryptsoft.com).  This product includes software written by Tim
5495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * Hudson (tjh@cryptsoft.com). */
5595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
5695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#include <openssl/pkcs8.h>
5795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
585127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley#include <assert.h>
595127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley#include <limits.h>
605127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley
6195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#include <openssl/asn1.h>
6295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#include <openssl/bn.h>
635127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley#include <openssl/buf.h>
6495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#include <openssl/cipher.h>
6595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#include <openssl/digest.h>
6695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#include <openssl/err.h>
678e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley#include <openssl/hmac.h>
6895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#include <openssl/mem.h>
6995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#include <openssl/x509.h>
7095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
718e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley#include "../bytestring/internal.h"
7295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#include "../evp/internal.h"
7395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
7495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
7595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#define PKCS12_KEY_ID 1
7695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#define PKCS12_IV_ID 2
778e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley#define PKCS12_MAC_ID 3
7895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
7995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleystatic int ascii_to_ucs2(const char *ascii, size_t ascii_len,
80e216d6bb9f9139656e1d0c6b6312787fc2e596f9David Benjamin                         uint8_t **out, size_t *out_len) {
8195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  uint8_t *unitmp;
8295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  size_t ulen, i;
8395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
8495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  ulen = ascii_len * 2 + 2;
8595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  if (ulen < ascii_len) {
8695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    return 0;
8795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
8895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  unitmp = OPENSSL_malloc(ulen);
8995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  if (unitmp == NULL) {
9095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    return 0;
9195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
9295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  for (i = 0; i < ulen - 2; i += 2) {
9395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    unitmp[i] = 0;
9495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    unitmp[i + 1] = ascii[i >> 1];
9595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
9695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
9795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  /* Make result double null terminated */
9895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  unitmp[ulen - 2] = 0;
9995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  unitmp[ulen - 1] = 0;
10095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  *out_len = ulen;
10195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  *out = unitmp;
10295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  return 1;
10395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley}
10495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
105e216d6bb9f9139656e1d0c6b6312787fc2e596f9David Benjaminstatic int pkcs12_key_gen_raw(const uint8_t *pass_raw, size_t pass_raw_len,
1068e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley                              const uint8_t *salt, size_t salt_len,
107e216d6bb9f9139656e1d0c6b6312787fc2e596f9David Benjamin                              int id, int iterations,
10895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley                              size_t out_len, uint8_t *out,
10995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley                              const EVP_MD *md_type) {
11095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  uint8_t *B, *D, *I, *p, *Ai;
11195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  int Slen, Plen, Ilen, Ijlen;
11295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  int i, j, v;
11395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  size_t u;
11495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  int ret = 0;
11595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  BIGNUM *Ij, *Bpl1; /* These hold Ij and B + 1 */
11695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  EVP_MD_CTX ctx;
11795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
11895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  EVP_MD_CTX_init(&ctx);
11995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  v = EVP_MD_block_size(md_type);
12095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  u = EVP_MD_size(md_type);
12195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  D = OPENSSL_malloc(v);
12295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  Ai = OPENSSL_malloc(u);
12395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  B = OPENSSL_malloc(v + 1);
12495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  Slen = v * ((salt_len + v - 1) / v);
125e216d6bb9f9139656e1d0c6b6312787fc2e596f9David Benjamin  if (pass_raw_len)
126e216d6bb9f9139656e1d0c6b6312787fc2e596f9David Benjamin    Plen = v * ((pass_raw_len + v - 1) / v);
12795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  else
12895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    Plen = 0;
12995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  Ilen = Slen + Plen;
13095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  I = OPENSSL_malloc(Ilen);
13195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  Ij = BN_new();
13295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  Bpl1 = BN_new();
13395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  if (!D || !Ai || !B || !I || !Ij || !Bpl1)
13495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    goto err;
13595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  for (i = 0; i < v; i++)
13695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    D[i] = id;
13795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  p = I;
13895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  for (i = 0; i < Slen; i++)
13995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    *p++ = salt[i % salt_len];
14095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  for (i = 0; i < Plen; i++)
141e216d6bb9f9139656e1d0c6b6312787fc2e596f9David Benjamin    *p++ = pass_raw[i % pass_raw_len];
14295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  for (;;) {
14395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    if (!EVP_DigestInit_ex(&ctx, md_type, NULL) ||
14495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley        !EVP_DigestUpdate(&ctx, D, v) ||
14595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley        !EVP_DigestUpdate(&ctx, I, Ilen) ||
14695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley        !EVP_DigestFinal_ex(&ctx, Ai, NULL)) {
14795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      goto err;
14895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    }
14995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    for (j = 1; j < iterations; j++) {
15095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      if (!EVP_DigestInit_ex(&ctx, md_type, NULL) ||
15195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley          !EVP_DigestUpdate(&ctx, Ai, u) ||
15295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley          !EVP_DigestFinal_ex(&ctx, Ai, NULL)) {
15395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley        goto err;
15495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      }
15595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    }
15695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    memcpy(out, Ai, out_len < u ? out_len : u);
15795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    if (u >= out_len) {
15895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      ret = 1;
15995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      goto end;
16095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    }
16195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    out_len -= u;
16295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    out += u;
16395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    for (j = 0; j < v; j++)
16495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      B[j] = Ai[j % u];
16595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    /* Work out B + 1 first then can use B as tmp space */
16695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    if (!BN_bin2bn(B, v, Bpl1))
16795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      goto err;
16895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    if (!BN_add_word(Bpl1, 1))
16995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      goto err;
17095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    for (j = 0; j < Ilen; j += v) {
17195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      if (!BN_bin2bn(I + j, v, Ij))
17295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley        goto err;
17395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      if (!BN_add(Ij, Ij, Bpl1))
17495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley        goto err;
17595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      if (!BN_bn2bin(Ij, B))
17695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley        goto err;
17795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      Ijlen = BN_num_bytes(Ij);
17895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      /* If more than 2^(v*8) - 1 cut off MSB */
17995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      if (Ijlen > v) {
18095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley        if (!BN_bn2bin(Ij, B))
18195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley          goto err;
18295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley        memcpy(I + j, B + 1, v);
18395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley        /* If less than v bytes pad with zeroes */
18495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      } else if (Ijlen < v) {
18595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley        memset(I + j, 0, v - Ijlen);
18695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley        if (!BN_bn2bin(Ij, I + j + v - Ijlen))
18795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley          goto err;
18895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      } else if (!BN_bn2bin(Ij, I + j)) {
18995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley        goto err;
19095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      }
19195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    }
19295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
19395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
19495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleyerr:
195e216d6bb9f9139656e1d0c6b6312787fc2e596f9David Benjamin  OPENSSL_PUT_ERROR(PKCS8, pkcs12_key_gen_raw, ERR_R_MALLOC_FAILURE);
19695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
19795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleyend:
19895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  OPENSSL_free(Ai);
19995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  OPENSSL_free(B);
20095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  OPENSSL_free(D);
20195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  OPENSSL_free(I);
20295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  BN_free(Ij);
20395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  BN_free(Bpl1);
20495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  EVP_MD_CTX_cleanup(&ctx);
20595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
20695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  return ret;
20795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley}
20895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
209e216d6bb9f9139656e1d0c6b6312787fc2e596f9David Benjaminstatic int pkcs12_pbe_keyivgen(EVP_CIPHER_CTX *ctx, const uint8_t *pass_raw,
210e216d6bb9f9139656e1d0c6b6312787fc2e596f9David Benjamin                               size_t pass_raw_len, ASN1_TYPE *param,
21195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley                               const EVP_CIPHER *cipher, const EVP_MD *md,
21295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley                               int is_encrypt) {
21395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  PBEPARAM *pbe;
21495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  int salt_len, iterations, ret;
21595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  uint8_t *salt;
21695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  const uint8_t *pbuf;
21795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  uint8_t key[EVP_MAX_KEY_LENGTH], iv[EVP_MAX_IV_LENGTH];
21895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
21995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  /* Extract useful info from parameter */
22095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  if (param == NULL || param->type != V_ASN1_SEQUENCE ||
22195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      param->value.sequence == NULL) {
22295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    OPENSSL_PUT_ERROR(PKCS8, pkcs12_pbe_keyivgen, PKCS8_R_DECODE_ERROR);
22395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    return 0;
22495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
22595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
22695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  pbuf = param->value.sequence->data;
22795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  pbe = d2i_PBEPARAM(NULL, &pbuf, param->value.sequence->length);
22895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  if (pbe == NULL) {
22995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    OPENSSL_PUT_ERROR(PKCS8, pkcs12_pbe_keyivgen, PKCS8_R_DECODE_ERROR);
23095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    return 0;
23195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
23295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
23395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  if (!pbe->iter) {
23495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    iterations = 1;
23595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  } else {
23695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    iterations = ASN1_INTEGER_get(pbe->iter);
23795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
23895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  salt = pbe->salt->data;
23995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  salt_len = pbe->salt->length;
240e216d6bb9f9139656e1d0c6b6312787fc2e596f9David Benjamin  if (!pkcs12_key_gen_raw(pass_raw, pass_raw_len, salt, salt_len, PKCS12_KEY_ID,
24195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley                          iterations, EVP_CIPHER_key_length(cipher), key, md)) {
24295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    OPENSSL_PUT_ERROR(PKCS8, pkcs12_pbe_keyivgen, PKCS8_R_KEY_GEN_ERROR);
24395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    PBEPARAM_free(pbe);
24495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    return 0;
24595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
246e216d6bb9f9139656e1d0c6b6312787fc2e596f9David Benjamin  if (!pkcs12_key_gen_raw(pass_raw, pass_raw_len, salt, salt_len, PKCS12_IV_ID,
24795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley                          iterations, EVP_CIPHER_iv_length(cipher), iv, md)) {
24895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    OPENSSL_PUT_ERROR(PKCS8, pkcs12_pbe_keyivgen, PKCS8_R_KEY_GEN_ERROR);
24995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    PBEPARAM_free(pbe);
25095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    return 0;
25195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
25295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  PBEPARAM_free(pbe);
25395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  ret = EVP_CipherInit_ex(ctx, cipher, NULL, key, iv, is_encrypt);
25495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  OPENSSL_cleanse(key, EVP_MAX_KEY_LENGTH);
25595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  OPENSSL_cleanse(iv, EVP_MAX_IV_LENGTH);
25695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  return ret;
25795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley}
25895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
259e216d6bb9f9139656e1d0c6b6312787fc2e596f9David Benjamintypedef int (*keygen_func)(EVP_CIPHER_CTX *ctx, const uint8_t *pass_raw,
260e216d6bb9f9139656e1d0c6b6312787fc2e596f9David Benjamin                           size_t pass_raw_len, ASN1_TYPE *param,
26195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley                           const EVP_CIPHER *cipher, const EVP_MD *md,
26295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley                           int is_encrypt);
26395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
26495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleystruct pbe_suite {
26595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  int pbe_nid;
2668e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley  const EVP_CIPHER* (*cipher_func)();
2678e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley  const EVP_MD* (*md_func)();
26895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  keygen_func keygen;
26995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley};
27095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
27195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleystatic const struct pbe_suite kBuiltinPBE[] = {
27295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    {
2738e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley     NID_pbe_WithSHA1And40BitRC2_CBC, EVP_rc2_40_cbc, EVP_sha1, pkcs12_pbe_keyivgen,
2748e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    },
2758e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    {
2768e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley     NID_pbe_WithSHA1And128BitRC4, EVP_rc4, EVP_sha1, pkcs12_pbe_keyivgen,
27795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    },
27895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    {
2798e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley     NID_pbe_WithSHA1And3_Key_TripleDES_CBC, EVP_des_ede3_cbc, EVP_sha1,
28095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley     pkcs12_pbe_keyivgen,
28195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    },
28295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley};
28395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
284e216d6bb9f9139656e1d0c6b6312787fc2e596f9David Benjaminstatic int pbe_cipher_init(ASN1_OBJECT *pbe_obj,
285e216d6bb9f9139656e1d0c6b6312787fc2e596f9David Benjamin                           const uint8_t *pass_raw, size_t pass_raw_len,
286e216d6bb9f9139656e1d0c6b6312787fc2e596f9David Benjamin                           ASN1_TYPE *param,
28795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley                           EVP_CIPHER_CTX *ctx, int is_encrypt) {
28895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  const EVP_CIPHER *cipher;
28995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  const EVP_MD *md;
29095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  unsigned i;
29195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
29295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  const struct pbe_suite *suite = NULL;
29395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  const int pbe_nid = OBJ_obj2nid(pbe_obj);
29495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
29595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  for (i = 0; i < sizeof(kBuiltinPBE) / sizeof(struct pbe_suite); i++) {
2968e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    if (kBuiltinPBE[i].pbe_nid == pbe_nid) {
2978e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley      suite = &kBuiltinPBE[i];
29895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      break;
29995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    }
30095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
30195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
30295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  if (suite == NULL) {
30395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    char obj_str[80];
30495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    OPENSSL_PUT_ERROR(PKCS8, pbe_cipher_init, PKCS8_R_UNKNOWN_ALGORITHM);
30595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    if (!pbe_obj) {
30695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      strncpy(obj_str, "NULL", sizeof(obj_str));
30795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    } else {
30895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      i2t_ASN1_OBJECT(obj_str, sizeof(obj_str), pbe_obj);
30995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    }
31095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    ERR_add_error_data(2, "TYPE=", obj_str);
31195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    return 0;
31295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
31395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
3148e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley  if (suite->cipher_func == NULL) {
31595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    cipher = NULL;
31695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  } else {
3178e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    cipher = suite->cipher_func();
31895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    if (!cipher) {
31995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      OPENSSL_PUT_ERROR(PKCS8, pbe_cipher_init, PKCS8_R_UNKNOWN_CIPHER);
32095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      return 0;
32195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    }
32295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
32395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
3248e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley  if (suite->md_func == NULL) {
32595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    md = NULL;
32695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  } else {
3278e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    md = suite->md_func();
32895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    if (!md) {
32995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      OPENSSL_PUT_ERROR(PKCS8, pbe_cipher_init, PKCS8_R_UNKNOWN_DIGEST);
33095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      return 0;
33195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    }
33295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
33395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
334e216d6bb9f9139656e1d0c6b6312787fc2e596f9David Benjamin  if (!suite->keygen(ctx, pass_raw, pass_raw_len, param, cipher, md,
335e216d6bb9f9139656e1d0c6b6312787fc2e596f9David Benjamin                     is_encrypt)) {
33695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    OPENSSL_PUT_ERROR(PKCS8, pbe_cipher_init, PKCS8_R_KEYGEN_FAILURE);
33795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    return 0;
33895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
33995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
34095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  return 1;
34195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley}
34295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
343e216d6bb9f9139656e1d0c6b6312787fc2e596f9David Benjaminstatic int pbe_crypt(const X509_ALGOR *algor,
344e216d6bb9f9139656e1d0c6b6312787fc2e596f9David Benjamin                     const uint8_t *pass_raw, size_t pass_raw_len,
3458e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley                     const uint8_t *in, size_t in_len,
3468e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley                     uint8_t **out, size_t *out_len,
34795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley                     int is_encrypt) {
34895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  uint8_t *buf;
34995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  int n, ret = 0;
35095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  EVP_CIPHER_CTX ctx;
35195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  unsigned block_size;
35295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
35395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  EVP_CIPHER_CTX_init(&ctx);
35495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
355e216d6bb9f9139656e1d0c6b6312787fc2e596f9David Benjamin  if (!pbe_cipher_init(algor->algorithm, pass_raw, pass_raw_len,
356e216d6bb9f9139656e1d0c6b6312787fc2e596f9David Benjamin                       algor->parameter, &ctx, is_encrypt)) {
35795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    OPENSSL_PUT_ERROR(PKCS8, pbe_crypt, PKCS8_R_UNKNOWN_CIPHER_ALGORITHM);
35895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    return 0;
35995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
36095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  block_size = EVP_CIPHER_CTX_block_size(&ctx);
36195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
36295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  if (in_len + block_size < in_len) {
36395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    OPENSSL_PUT_ERROR(PKCS8, pbe_crypt, PKCS8_R_TOO_LONG);
36495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    goto err;
36595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
36695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
36795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  buf = OPENSSL_malloc(in_len + block_size);
36895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  if (buf == NULL) {
36995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    OPENSSL_PUT_ERROR(PKCS8, pbe_crypt, ERR_R_MALLOC_FAILURE);
37095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    goto err;
37195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
37295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
37395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  if (!EVP_CipherUpdate(&ctx, buf, &n, in, in_len)) {
37495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    OPENSSL_free(buf);
37595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    OPENSSL_PUT_ERROR(PKCS8, pbe_crypt, ERR_R_EVP_LIB);
37695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    goto err;
37795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
37895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  *out_len = n;
37995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
38095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  if (!EVP_CipherFinal_ex(&ctx, buf + n, &n)) {
38195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    OPENSSL_free(buf);
38295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    OPENSSL_PUT_ERROR(PKCS8, pbe_crypt, ERR_R_EVP_LIB);
38395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    goto err;
38495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
38595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  *out_len += n;
38695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  *out = buf;
38795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  ret = 1;
38895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
38995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleyerr:
39095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  EVP_CIPHER_CTX_cleanup(&ctx);
39195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  return ret;
39295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley}
39395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
39495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleystatic void *pkcs12_item_decrypt_d2i(X509_ALGOR *algor, const ASN1_ITEM *it,
395e216d6bb9f9139656e1d0c6b6312787fc2e596f9David Benjamin                                     const uint8_t *pass_raw,
396e216d6bb9f9139656e1d0c6b6312787fc2e596f9David Benjamin                                     size_t pass_raw_len,
39795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley                                     ASN1_OCTET_STRING *oct) {
39895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  uint8_t *out;
39995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  const uint8_t *p;
40095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  void *ret;
40195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  size_t out_len;
40295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
403e216d6bb9f9139656e1d0c6b6312787fc2e596f9David Benjamin  if (!pbe_crypt(algor, pass_raw, pass_raw_len, oct->data, oct->length,
404e216d6bb9f9139656e1d0c6b6312787fc2e596f9David Benjamin                 &out, &out_len, 0 /* decrypt */)) {
40595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    OPENSSL_PUT_ERROR(PKCS8, pkcs12_item_decrypt_d2i, PKCS8_R_CRYPT_ERROR);
40695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    return NULL;
40795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
40895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  p = out;
40995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  ret = ASN1_item_d2i(NULL, &p, out_len, it);
41095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  OPENSSL_cleanse(out, out_len);
41195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  if (!ret) {
41295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    OPENSSL_PUT_ERROR(PKCS8, pkcs12_item_decrypt_d2i, PKCS8_R_DECODE_ERROR);
41395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
41495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  OPENSSL_free(out);
41595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  return ret;
41695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley}
41795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
41895c29f3cd1f6c08c6c0927868683392eea727ccAdam LangleyPKCS8_PRIV_KEY_INFO *PKCS8_decrypt(X509_SIG *pkcs8, const char *pass,
41995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley                                   int pass_len) {
420e216d6bb9f9139656e1d0c6b6312787fc2e596f9David Benjamin  uint8_t *pass_raw = NULL;
421e216d6bb9f9139656e1d0c6b6312787fc2e596f9David Benjamin  size_t pass_raw_len = 0;
422e216d6bb9f9139656e1d0c6b6312787fc2e596f9David Benjamin  PKCS8_PRIV_KEY_INFO *ret;
423e216d6bb9f9139656e1d0c6b6312787fc2e596f9David Benjamin
424e216d6bb9f9139656e1d0c6b6312787fc2e596f9David Benjamin  if (pass) {
425e216d6bb9f9139656e1d0c6b6312787fc2e596f9David Benjamin    if (pass_len == -1) {
426e216d6bb9f9139656e1d0c6b6312787fc2e596f9David Benjamin      pass_len = strlen(pass);
427e216d6bb9f9139656e1d0c6b6312787fc2e596f9David Benjamin    }
428e216d6bb9f9139656e1d0c6b6312787fc2e596f9David Benjamin    if (!ascii_to_ucs2(pass, pass_len, &pass_raw, &pass_raw_len)) {
429e216d6bb9f9139656e1d0c6b6312787fc2e596f9David Benjamin      OPENSSL_PUT_ERROR(PKCS8, pkcs12_key_gen_asc, PKCS8_R_DECODE_ERROR);
430e216d6bb9f9139656e1d0c6b6312787fc2e596f9David Benjamin      return NULL;
431e216d6bb9f9139656e1d0c6b6312787fc2e596f9David Benjamin    }
43295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
433e216d6bb9f9139656e1d0c6b6312787fc2e596f9David Benjamin
434e216d6bb9f9139656e1d0c6b6312787fc2e596f9David Benjamin  ret = PKCS8_decrypt_pbe(pkcs8, pass_raw, pass_raw_len);
435e216d6bb9f9139656e1d0c6b6312787fc2e596f9David Benjamin
436e216d6bb9f9139656e1d0c6b6312787fc2e596f9David Benjamin  if (pass_raw) {
437e216d6bb9f9139656e1d0c6b6312787fc2e596f9David Benjamin    OPENSSL_cleanse(pass_raw, pass_raw_len);
438e216d6bb9f9139656e1d0c6b6312787fc2e596f9David Benjamin    OPENSSL_free(pass_raw);
439e216d6bb9f9139656e1d0c6b6312787fc2e596f9David Benjamin  }
440e216d6bb9f9139656e1d0c6b6312787fc2e596f9David Benjamin  return ret;
441e216d6bb9f9139656e1d0c6b6312787fc2e596f9David Benjamin}
442e216d6bb9f9139656e1d0c6b6312787fc2e596f9David Benjamin
443e216d6bb9f9139656e1d0c6b6312787fc2e596f9David BenjaminPKCS8_PRIV_KEY_INFO *PKCS8_decrypt_pbe(X509_SIG *pkcs8, const uint8_t *pass_raw,
444e216d6bb9f9139656e1d0c6b6312787fc2e596f9David Benjamin                                       size_t pass_raw_len) {
44595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  return pkcs12_item_decrypt_d2i(pkcs8->algor,
446e216d6bb9f9139656e1d0c6b6312787fc2e596f9David Benjamin                                 ASN1_ITEM_rptr(PKCS8_PRIV_KEY_INFO), pass_raw,
447e216d6bb9f9139656e1d0c6b6312787fc2e596f9David Benjamin                                 pass_raw_len, pkcs8->digest);
44895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley}
44995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
45095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleystatic ASN1_OCTET_STRING *pkcs12_item_i2d_encrypt(X509_ALGOR *algor,
45195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley                                                  const ASN1_ITEM *it,
452e216d6bb9f9139656e1d0c6b6312787fc2e596f9David Benjamin                                                  const uint8_t *pass_raw,
453e216d6bb9f9139656e1d0c6b6312787fc2e596f9David Benjamin                                                  size_t pass_raw_len, void *obj) {
45495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  ASN1_OCTET_STRING *oct;
45595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  uint8_t *in = NULL;
45695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  int in_len;
45795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  size_t crypt_len;
45895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
45995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  oct = M_ASN1_OCTET_STRING_new();
46095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  if (oct == NULL) {
46195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    OPENSSL_PUT_ERROR(PKCS8, pkcs12_item_i2d_encrypt, ERR_R_MALLOC_FAILURE);
46295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    return NULL;
46395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
46495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  in_len = ASN1_item_i2d(obj, &in, it);
46595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  if (!in) {
46695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    OPENSSL_PUT_ERROR(PKCS8, pkcs12_item_i2d_encrypt, PKCS8_R_ENCODE_ERROR);
46795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    return NULL;
46895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
469e216d6bb9f9139656e1d0c6b6312787fc2e596f9David Benjamin  if (!pbe_crypt(algor, pass_raw, pass_raw_len, in, in_len, &oct->data, &crypt_len,
47095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley                 1 /* encrypt */)) {
47195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    OPENSSL_PUT_ERROR(PKCS8, pkcs12_item_i2d_encrypt, PKCS8_R_ENCRYPT_ERROR);
47295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    OPENSSL_free(in);
47395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    return NULL;
47495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
47595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  oct->length = crypt_len;
47695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  OPENSSL_cleanse(in, in_len);
47795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  OPENSSL_free(in);
47895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  return oct;
47995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley}
48095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
48195c29f3cd1f6c08c6c0927868683392eea727ccAdam LangleyX509_SIG *PKCS8_encrypt(int pbe_nid, const EVP_CIPHER *cipher, const char *pass,
48295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley                        int pass_len, uint8_t *salt, size_t salt_len,
48395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley                        int iterations, PKCS8_PRIV_KEY_INFO *p8inf) {
484e216d6bb9f9139656e1d0c6b6312787fc2e596f9David Benjamin  uint8_t *pass_raw = NULL;
485e216d6bb9f9139656e1d0c6b6312787fc2e596f9David Benjamin  size_t pass_raw_len = 0;
486e216d6bb9f9139656e1d0c6b6312787fc2e596f9David Benjamin  X509_SIG *ret;
48795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
488e216d6bb9f9139656e1d0c6b6312787fc2e596f9David Benjamin  if (pass) {
489e216d6bb9f9139656e1d0c6b6312787fc2e596f9David Benjamin    if (pass_len == -1) {
490e216d6bb9f9139656e1d0c6b6312787fc2e596f9David Benjamin      pass_len = strlen(pass);
491e216d6bb9f9139656e1d0c6b6312787fc2e596f9David Benjamin    }
492e216d6bb9f9139656e1d0c6b6312787fc2e596f9David Benjamin    if (!ascii_to_ucs2(pass, pass_len, &pass_raw, &pass_raw_len)) {
493e216d6bb9f9139656e1d0c6b6312787fc2e596f9David Benjamin      OPENSSL_PUT_ERROR(PKCS8, pkcs12_key_gen_asc, PKCS8_R_DECODE_ERROR);
494e216d6bb9f9139656e1d0c6b6312787fc2e596f9David Benjamin      return NULL;
495e216d6bb9f9139656e1d0c6b6312787fc2e596f9David Benjamin    }
49695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
49795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
498e216d6bb9f9139656e1d0c6b6312787fc2e596f9David Benjamin  ret = PKCS8_encrypt_pbe(pbe_nid, pass_raw, pass_raw_len,
499e216d6bb9f9139656e1d0c6b6312787fc2e596f9David Benjamin                          salt, salt_len, iterations, p8inf);
500e216d6bb9f9139656e1d0c6b6312787fc2e596f9David Benjamin
501e216d6bb9f9139656e1d0c6b6312787fc2e596f9David Benjamin  if (pass_raw) {
502e216d6bb9f9139656e1d0c6b6312787fc2e596f9David Benjamin    OPENSSL_cleanse(pass_raw, pass_raw_len);
503e216d6bb9f9139656e1d0c6b6312787fc2e596f9David Benjamin    OPENSSL_free(pass_raw);
504e216d6bb9f9139656e1d0c6b6312787fc2e596f9David Benjamin  }
505e216d6bb9f9139656e1d0c6b6312787fc2e596f9David Benjamin  return ret;
506e216d6bb9f9139656e1d0c6b6312787fc2e596f9David Benjamin}
507e216d6bb9f9139656e1d0c6b6312787fc2e596f9David Benjamin
508e216d6bb9f9139656e1d0c6b6312787fc2e596f9David BenjaminX509_SIG *PKCS8_encrypt_pbe(int pbe_nid,
509e216d6bb9f9139656e1d0c6b6312787fc2e596f9David Benjamin                            const uint8_t *pass_raw, size_t pass_raw_len,
510e216d6bb9f9139656e1d0c6b6312787fc2e596f9David Benjamin                            uint8_t *salt, size_t salt_len,
511e216d6bb9f9139656e1d0c6b6312787fc2e596f9David Benjamin                            int iterations, PKCS8_PRIV_KEY_INFO *p8inf) {
512e216d6bb9f9139656e1d0c6b6312787fc2e596f9David Benjamin  X509_SIG *pkcs8 = NULL;
513e216d6bb9f9139656e1d0c6b6312787fc2e596f9David Benjamin  X509_ALGOR *pbe;
514e216d6bb9f9139656e1d0c6b6312787fc2e596f9David Benjamin
51595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  pkcs8 = X509_SIG_new();
51695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  if (pkcs8 == NULL) {
517e216d6bb9f9139656e1d0c6b6312787fc2e596f9David Benjamin    OPENSSL_PUT_ERROR(PKCS8, PKCS8_encrypt_pbe, ERR_R_MALLOC_FAILURE);
51895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    goto err;
51995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
52095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
521e216d6bb9f9139656e1d0c6b6312787fc2e596f9David Benjamin  pbe = PKCS5_pbe_set(pbe_nid, iterations, salt, salt_len);
52295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  if (!pbe) {
523e216d6bb9f9139656e1d0c6b6312787fc2e596f9David Benjamin    OPENSSL_PUT_ERROR(PKCS8, PKCS8_encrypt_pbe, ERR_R_ASN1_LIB);
52495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    goto err;
52595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
52695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
52795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  X509_ALGOR_free(pkcs8->algor);
52895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  pkcs8->algor = pbe;
52995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  M_ASN1_OCTET_STRING_free(pkcs8->digest);
53095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  pkcs8->digest = pkcs12_item_i2d_encrypt(
531e216d6bb9f9139656e1d0c6b6312787fc2e596f9David Benjamin      pbe, ASN1_ITEM_rptr(PKCS8_PRIV_KEY_INFO), pass_raw, pass_raw_len, p8inf);
53295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  if (!pkcs8->digest) {
533e216d6bb9f9139656e1d0c6b6312787fc2e596f9David Benjamin    OPENSSL_PUT_ERROR(PKCS8, PKCS8_encrypt_pbe, PKCS8_R_ENCRYPT_ERROR);
53495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    goto err;
53595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
53695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
53795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  return pkcs8;
53895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
53995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleyerr:
54095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  X509_SIG_free(pkcs8);
54195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  return NULL;
54295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley}
54395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
54495c29f3cd1f6c08c6c0927868683392eea727ccAdam LangleyEVP_PKEY *EVP_PKCS82PKEY(PKCS8_PRIV_KEY_INFO *p8) {
54595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  EVP_PKEY *pkey = NULL;
54695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  ASN1_OBJECT *algoid;
54795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  char obj_tmp[80];
54895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
54995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  if (!PKCS8_pkey_get0(&algoid, NULL, NULL, NULL, p8))
55095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    return NULL;
55195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
55295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  pkey = EVP_PKEY_new();
55395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  if (pkey == NULL) {
55495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    OPENSSL_PUT_ERROR(PKCS8, EVP_PKCS82PKEY, ERR_R_MALLOC_FAILURE);
55595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    return NULL;
55695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
55795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
55895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  if (!EVP_PKEY_set_type(pkey, OBJ_obj2nid(algoid))) {
55995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    OPENSSL_PUT_ERROR(PKCS8, EVP_PKCS82PKEY,
56095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley                      PKCS8_R_UNSUPPORTED_PRIVATE_KEY_ALGORITHM);
56195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    i2t_ASN1_OBJECT(obj_tmp, 80, algoid);
56295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    ERR_add_error_data(2, "TYPE=", obj_tmp);
56395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    goto error;
56495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
56595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
56695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  if (pkey->ameth->priv_decode) {
56795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    if (!pkey->ameth->priv_decode(pkey, p8)) {
56895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      OPENSSL_PUT_ERROR(PKCS8, EVP_PKCS82PKEY, PKCS8_R_PRIVATE_KEY_DECODE_ERROR);
56995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      goto error;
57095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    }
57195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  } else {
57295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    OPENSSL_PUT_ERROR(PKCS8, EVP_PKCS82PKEY, PKCS8_R_METHOD_NOT_SUPPORTED);
57395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    goto error;
57495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
57595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
57695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  return pkey;
57795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
57895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleyerror:
57995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  EVP_PKEY_free(pkey);
58095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  return NULL;
58195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley}
58295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
58395c29f3cd1f6c08c6c0927868683392eea727ccAdam LangleyPKCS8_PRIV_KEY_INFO *EVP_PKEY2PKCS8(EVP_PKEY *pkey) {
58495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  PKCS8_PRIV_KEY_INFO *p8;
58595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
58695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  p8 = PKCS8_PRIV_KEY_INFO_new();
58795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  if (p8 == NULL) {
58895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    OPENSSL_PUT_ERROR(PKCS8, EVP_PKEY2PKCS8, ERR_R_MALLOC_FAILURE);
58995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    return NULL;
59095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
59195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  p8->broken = PKCS8_OK;
59295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
59395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  if (pkey->ameth) {
59495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    if (pkey->ameth->priv_encode) {
59595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      if (!pkey->ameth->priv_encode(p8, pkey)) {
59695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley        OPENSSL_PUT_ERROR(PKCS8, EVP_PKEY2PKCS8,
59795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley                          PKCS8_R_PRIVATE_KEY_ENCODE_ERROR);
59895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley        goto error;
59995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      }
60095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    } else {
60195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      OPENSSL_PUT_ERROR(PKCS8, EVP_PKEY2PKCS8, PKCS8_R_METHOD_NOT_SUPPORTED);
60295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      goto error;
60395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    }
60495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  } else {
60595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    OPENSSL_PUT_ERROR(PKCS8, EVP_PKEY2PKCS8,
60695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley                      PKCS8_R_UNSUPPORTED_PRIVATE_KEY_ALGORITHM);
60795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    goto error;
60895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
60995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  return p8;
61095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
61195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleyerror:
61295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  PKCS8_PRIV_KEY_INFO_free(p8);
61395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  return NULL;
61495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley}
6158e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley
6168e16b6e6582810de46b4db7926a2462be8e789d2Adam Langleystruct pkcs12_context {
6178e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley  EVP_PKEY **out_key;
6188e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley  STACK_OF(X509) *out_certs;
6198e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley  uint8_t *password;
6208e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley  size_t password_len;
6218e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley};
6228e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley
6238e16b6e6582810de46b4db7926a2462be8e789d2Adam Langleystatic int PKCS12_handle_content_info(CBS *content_info, unsigned depth,
6248e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley                                      struct pkcs12_context *ctx);
6258e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley
6268e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley/* PKCS12_handle_content_infos parses a series of PKCS#7 ContentInfos in a
6278e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley * SEQUENCE. */
6288e16b6e6582810de46b4db7926a2462be8e789d2Adam Langleystatic int PKCS12_handle_content_infos(CBS *content_infos,
6298e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley                                       unsigned depth,
6308e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley                                       struct pkcs12_context *ctx) {
6318e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley  uint8_t *der_bytes = NULL;
6328e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley  size_t der_len;
6338e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley  CBS in;
6348e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley  int ret = 0;
6358e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley
6368e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley  /* Generally we only expect depths 0 (the top level, with a
6378e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley   * pkcs7-encryptedData and a pkcs7-data) and depth 1 (the various PKCS#12
6388e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley   * bags). */
6398e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley  if (depth > 3) {
6408e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    OPENSSL_PUT_ERROR(PKCS8, PKCS12_handle_content_infos,
6418e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley                      PKCS8_R_PKCS12_TOO_DEEPLY_NESTED);
6428e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    return 0;
6438e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley  }
6448e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley
6458e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley  /* Although a BER->DER conversion is done at the beginning of |PKCS12_parse|,
6468e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley   * the ASN.1 data gets wrapped in OCTETSTRINGs and/or encrypted and the
6478e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley   * conversion cannot see through those wrappings. So each time we step
6488e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley   * through one we need to convert to DER again. */
6498e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley  if (!CBS_asn1_ber_to_der(content_infos, &der_bytes, &der_len)) {
6508e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    return 0;
6518e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley  }
6528e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley
6538e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley  if (der_bytes != NULL) {
6548e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    CBS_init(&in, der_bytes, der_len);
6558e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley  } else {
6568e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    CBS_init(&in, CBS_data(content_infos), CBS_len(content_infos));
6578e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley  }
6588e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley
6598e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley  if (!CBS_get_asn1(&in, &in, CBS_ASN1_SEQUENCE)) {
6608e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    OPENSSL_PUT_ERROR(PKCS8, PKCS12_handle_content_infos,
6618e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley                      PKCS8_R_BAD_PKCS12_DATA);
6628e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    goto err;
6638e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley  }
6648e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley
6658e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley  while (CBS_len(&in) > 0) {
6668e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    CBS content_info;
6678e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    if (!CBS_get_asn1(&in, &content_info, CBS_ASN1_SEQUENCE)) {
6688e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley      OPENSSL_PUT_ERROR(PKCS8, PKCS12_handle_content_infos,
6698e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley                        PKCS8_R_BAD_PKCS12_DATA);
6708e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley      goto err;
6718e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    }
6728e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley
6738e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    if (!PKCS12_handle_content_info(&content_info, depth + 1, ctx)) {
6748e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley      goto err;
6758e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    }
6768e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley  }
6778e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley
6788e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley  /* NSS includes additional data after the SEQUENCE, but it's an (unwrapped)
6798e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley   * copy of the same encrypted private key (with the same IV and
6808e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley   * ciphertext)! */
6818e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley
6828e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley  ret = 1;
6838e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley
6848e16b6e6582810de46b4db7926a2462be8e789d2Adam Langleyerr:
6858e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley  if (der_bytes != NULL) {
6868e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    OPENSSL_free(der_bytes);
6878e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley  }
6888e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley  return ret;
6898e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley}
6908e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley
6918e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley/* PKCS12_handle_content_info parses a single PKCS#7 ContentInfo element in a
6928e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley * PKCS#12 structure. */
6938e16b6e6582810de46b4db7926a2462be8e789d2Adam Langleystatic int PKCS12_handle_content_info(CBS *content_info, unsigned depth,
6948e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley                                      struct pkcs12_context *ctx) {
6958e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley  CBS content_type, wrapped_contents, contents, content_infos;
6968e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley  int nid, ret = 0;
6978e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley
6988e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley  if (!CBS_get_asn1(content_info, &content_type, CBS_ASN1_OBJECT) ||
6998e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley      !CBS_get_asn1(content_info, &wrapped_contents,
7008e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley                        CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0)) {
7018e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    OPENSSL_PUT_ERROR(PKCS8, PKCS12_parse, PKCS8_R_BAD_PKCS12_DATA);
7028e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    goto err;
7038e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley  }
7048e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley
7058e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley  nid = OBJ_cbs2nid(&content_type);
7068e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley  if (nid == NID_pkcs7_encrypted) {
7078e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    /* See https://tools.ietf.org/html/rfc2315#section-13.
7088e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley     *
7098e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley     * PKCS#7 encrypted data inside a PKCS#12 structure is generally an
7108e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley     * encrypted certificate bag and it's generally encrypted with 40-bit
7118e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley     * RC2-CBC. */
71258f90951eb8d4393925d3155a69be49236816f82Adam Langley    CBS version_bytes, eci, contents_type, ai, encrypted_contents;
7138e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    X509_ALGOR *algor = NULL;
7148e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    const uint8_t *inp;
7158e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    uint8_t *out;
7168e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    size_t out_len;
7178e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley
7188e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    if (!CBS_get_asn1(&wrapped_contents, &contents, CBS_ASN1_SEQUENCE) ||
7198e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley        !CBS_get_asn1(&contents, &version_bytes, CBS_ASN1_INTEGER) ||
7208e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley        /* EncryptedContentInfo, see
7218e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley         * https://tools.ietf.org/html/rfc2315#section-10.1 */
7228e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley        !CBS_get_asn1(&contents, &eci, CBS_ASN1_SEQUENCE) ||
7238e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley        !CBS_get_asn1(&eci, &contents_type, CBS_ASN1_OBJECT) ||
7248e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley        /* AlgorithmIdentifier, see
7258e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley         * https://tools.ietf.org/html/rfc5280#section-4.1.1.2 */
72658f90951eb8d4393925d3155a69be49236816f82Adam Langley        !CBS_get_asn1_element(&eci, &ai, CBS_ASN1_SEQUENCE) ||
72758f90951eb8d4393925d3155a69be49236816f82Adam Langley        !CBS_get_asn1(&eci, &encrypted_contents,
72858f90951eb8d4393925d3155a69be49236816f82Adam Langley                      CBS_ASN1_CONTEXT_SPECIFIC | 0)) {
7298e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley      OPENSSL_PUT_ERROR(PKCS8, PKCS12_handle_content_info,
7308e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley                        PKCS8_R_BAD_PKCS12_DATA);
7318e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley      goto err;
7328e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    }
7338e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley
7348e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    if (OBJ_cbs2nid(&contents_type) != NID_pkcs7_data) {
7358e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley      OPENSSL_PUT_ERROR(PKCS8, PKCS12_handle_content_info,
7368e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley                        PKCS8_R_BAD_PKCS12_DATA);
7378e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley      goto err;
7388e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    }
7398e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley
7408e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    inp = CBS_data(&ai);
7418e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    algor = d2i_X509_ALGOR(NULL, &inp, CBS_len(&ai));
7428e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    if (algor == NULL) {
7438e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley      goto err;
7448e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    }
7458e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    if (inp != CBS_data(&ai) + CBS_len(&ai)) {
7468e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley      X509_ALGOR_free(algor);
7478e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley      OPENSSL_PUT_ERROR(PKCS8, PKCS12_handle_content_info,
7488e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley                        PKCS8_R_BAD_PKCS12_DATA);
7498e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley      goto err;
7508e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    }
7518e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley
7528e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    if (!pbe_crypt(algor, ctx->password, ctx->password_len,
7538e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley                   CBS_data(&encrypted_contents), CBS_len(&encrypted_contents),
7548e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley                   &out, &out_len, 0 /* decrypt */)) {
7558e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley      X509_ALGOR_free(algor);
7568e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley      goto err;
7578e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    }
7588e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    X509_ALGOR_free(algor);
7598e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley
7608e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    CBS_init(&content_infos, out, out_len);
7618e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    ret = PKCS12_handle_content_infos(&content_infos, depth + 1, ctx);
7628e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    OPENSSL_free(out);
7638e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley  } else if (nid == NID_pkcs7_data) {
7648e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    CBS octet_string_contents;
7658e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley
7668e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    if (!CBS_get_asn1(&wrapped_contents, &octet_string_contents,
7678e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley                          CBS_ASN1_OCTETSTRING)) {
7688e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley      OPENSSL_PUT_ERROR(PKCS8, PKCS12_handle_content_info,
7698e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley                        PKCS8_R_BAD_PKCS12_DATA);
7708e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley      goto err;
7718e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    }
7728e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley
7738e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    ret = PKCS12_handle_content_infos(&octet_string_contents, depth + 1, ctx);
7748e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley  } else if (nid == NID_pkcs8ShroudedKeyBag) {
7758e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    /* See ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-12/pkcs-12v1.pdf, section
7768e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley     * 4.2.2. */
7778e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    const uint8_t *inp = CBS_data(&wrapped_contents);
7788e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    PKCS8_PRIV_KEY_INFO *pki = NULL;
7798e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    X509_SIG *encrypted = NULL;
7808e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley
7818e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    if (*ctx->out_key) {
7828e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley      OPENSSL_PUT_ERROR(PKCS8, PKCS12_handle_content_info,
7838e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley                        PKCS8_R_MULTIPLE_PRIVATE_KEYS_IN_PKCS12);
7848e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley      goto err;
7858e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    }
7868e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley
7878e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    /* encrypted isn't actually an X.509 signature, but it has the same
7888e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley     * structure as one and so |X509_SIG| is reused to store it. */
7898e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    encrypted = d2i_X509_SIG(NULL, &inp, CBS_len(&wrapped_contents));
7908e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    if (encrypted == NULL) {
7918e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley      OPENSSL_PUT_ERROR(PKCS8, PKCS12_handle_content_info,
7928e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley                        PKCS8_R_BAD_PKCS12_DATA);
7938e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley      goto err;
7948e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    }
7958e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    if (inp != CBS_data(&wrapped_contents) + CBS_len(&wrapped_contents)) {
7968e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley      OPENSSL_PUT_ERROR(PKCS8, PKCS12_handle_content_info,
7978e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley                        PKCS8_R_BAD_PKCS12_DATA);
7988e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley      X509_SIG_free(encrypted);
7998e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley      goto err;
8008e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    }
8018e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley
8028e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    pki = PKCS8_decrypt_pbe(encrypted, ctx->password, ctx->password_len);
8038e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    X509_SIG_free(encrypted);
8048e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    if (pki == NULL) {
8058e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley      goto err;
8068e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    }
8078e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley
8088e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    *ctx->out_key = EVP_PKCS82PKEY(pki);
8098e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    PKCS8_PRIV_KEY_INFO_free(pki);
8108e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley
8118e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    if (ctx->out_key == NULL) {
8128e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley      goto err;
8138e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    }
8148e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    ret = 1;
8158e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley  } else if (nid == NID_certBag) {
8168e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    CBS cert_bag, cert_type, wrapped_cert, cert;
8178e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley
8188e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    if (!CBS_get_asn1(&wrapped_contents, &cert_bag, CBS_ASN1_SEQUENCE) ||
8198e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley        !CBS_get_asn1(&cert_bag, &cert_type, CBS_ASN1_OBJECT) ||
8208e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley        !CBS_get_asn1(&cert_bag, &wrapped_cert,
8218e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley                      CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0) ||
8228e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley        !CBS_get_asn1(&wrapped_cert, &cert, CBS_ASN1_OCTETSTRING)) {
8238e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley      OPENSSL_PUT_ERROR(PKCS8, PKCS12_handle_content_info,
8248e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley                        PKCS8_R_BAD_PKCS12_DATA);
8258e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley      goto err;
8268e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    }
8278e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley
8288e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    if (OBJ_cbs2nid(&cert_type) == NID_x509Certificate) {
8298e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley      const uint8_t *inp = CBS_data(&cert);
8308e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley      X509 *x509 = d2i_X509(NULL, &inp, CBS_len(&cert));
8318e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley      if (!x509) {
8328e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley        OPENSSL_PUT_ERROR(PKCS8, PKCS12_handle_content_info,
8338e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley                          PKCS8_R_BAD_PKCS12_DATA);
8348e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley        goto err;
8358e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley      }
8368e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley      if (inp != CBS_data(&cert) + CBS_len(&cert)) {
8378e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley        OPENSSL_PUT_ERROR(PKCS8, PKCS12_handle_content_info,
8388e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley                          PKCS8_R_BAD_PKCS12_DATA);
8398e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley        X509_free(x509);
8408e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley        goto err;
8418e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley      }
8428e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley
8438e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley      if (0 == sk_X509_push(ctx->out_certs, x509)) {
8448e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley        X509_free(x509);
8458e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley        goto err;
8468e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley      }
8478e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    }
8488e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    ret = 1;
8498e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley  } else {
8508e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    /* Unknown element type - ignore it. */
8518e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    ret = 1;
8528e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley  }
8538e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley
8548e16b6e6582810de46b4db7926a2462be8e789d2Adam Langleyerr:
8558e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley  return ret;
8568e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley}
8578e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley
8588e16b6e6582810de46b4db7926a2462be8e789d2Adam Langleyint PKCS12_get_key_and_certs(EVP_PKEY **out_key, STACK_OF(X509) *out_certs,
8598e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley                             CBS *ber_in, const char *password) {
8608e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley  uint8_t *der_bytes = NULL;
8618e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley  size_t der_len;
8628e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley  CBS in, pfx, mac_data, authsafe, content_type, wrapped_authsafes, authsafes;
8638e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley  uint64_t version;
8648e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley  int ret = 0;
8658e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley  struct pkcs12_context ctx;
8668e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley  const size_t original_out_certs_len = sk_X509_num(out_certs);
8678e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley
8688e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley  /* The input may be in BER format. */
8698e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley  if (!CBS_asn1_ber_to_der(ber_in, &der_bytes, &der_len)) {
8708e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    return 0;
8718e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley  }
8728e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley  if (der_bytes != NULL) {
8738e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    CBS_init(&in, der_bytes, der_len);
8748e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley  } else {
8758e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    CBS_init(&in, CBS_data(ber_in), CBS_len(ber_in));
8768e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley  }
8778e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley
8788e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley  *out_key = NULL;
8798e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley  memset(&ctx, 0, sizeof(ctx));
8808e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley
8818e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley  /* See ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-12/pkcs-12v1.pdf, section
8828e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley   * four. */
8838e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley  if (!CBS_get_asn1(&in, &pfx, CBS_ASN1_SEQUENCE) ||
8845127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley      CBS_len(&in) != 0 ||
8858e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley      !CBS_get_asn1_uint64(&pfx, &version)) {
8868e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    OPENSSL_PUT_ERROR(PKCS8, PKCS12_parse, PKCS8_R_BAD_PKCS12_DATA);
8878e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    goto err;
8888e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley  }
8898e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley
8908e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley  if (version < 3) {
8918e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    OPENSSL_PUT_ERROR(PKCS8, PKCS12_parse, PKCS8_R_BAD_PKCS12_VERSION);
8928e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    goto err;
8938e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley  }
8948e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley
8958e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley  if (!CBS_get_asn1(&pfx, &authsafe, CBS_ASN1_SEQUENCE)) {
8968e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    OPENSSL_PUT_ERROR(PKCS8, PKCS12_parse, PKCS8_R_BAD_PKCS12_DATA);
8978e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    goto err;
8988e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley  }
8998e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley
9008e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley  if (CBS_len(&pfx) == 0) {
9018e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    OPENSSL_PUT_ERROR(PKCS8, PKCS12_parse, PKCS8_R_MISSING_MAC);
9028e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    goto err;
9038e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley  }
9048e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley
9058e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley  if (!CBS_get_asn1(&pfx, &mac_data, CBS_ASN1_SEQUENCE)) {
9068e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    OPENSSL_PUT_ERROR(PKCS8, PKCS12_parse, PKCS8_R_BAD_PKCS12_DATA);
9078e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    goto err;
9088e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley  }
9098e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley
9108e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley  /* authsafe is a PKCS#7 ContentInfo. See
9118e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley   * https://tools.ietf.org/html/rfc2315#section-7. */
9128e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley  if (!CBS_get_asn1(&authsafe, &content_type, CBS_ASN1_OBJECT) ||
9138e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley      !CBS_get_asn1(&authsafe, &wrapped_authsafes,
9148e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley                        CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0)) {
9158e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    OPENSSL_PUT_ERROR(PKCS8, PKCS12_parse, PKCS8_R_BAD_PKCS12_DATA);
9168e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    goto err;
9178e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley  }
9188e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley
9198e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley  /* The content type can either be |NID_pkcs7_data| or |NID_pkcs7_signed|. The
9208e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley   * latter indicates that it's signed by a public key, which isn't
9218e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley   * supported. */
9228e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley  if (OBJ_cbs2nid(&content_type) != NID_pkcs7_data) {
9238e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    OPENSSL_PUT_ERROR(PKCS8, PKCS12_parse,
9248e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley                      PKCS8_R_PKCS12_PUBLIC_KEY_INTEGRITY_NOT_SUPPORTED);
9258e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    goto err;
9268e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley  }
9278e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley
9288e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley  if (!CBS_get_asn1(&wrapped_authsafes, &authsafes, CBS_ASN1_OCTETSTRING)) {
9298e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    OPENSSL_PUT_ERROR(PKCS8, PKCS12_parse, PKCS8_R_BAD_PKCS12_DATA);
9308e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    goto err;
9318e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley  }
9328e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley
9338e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley  ctx.out_key = out_key;
9348e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley  ctx.out_certs = out_certs;
9358e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley  if (!ascii_to_ucs2(password, strlen(password), &ctx.password,
9368e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley                     &ctx.password_len)) {
9378e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    OPENSSL_PUT_ERROR(PKCS8, PKCS12_parse, PKCS8_R_DECODE_ERROR);
9388e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    goto err;
9398e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley  }
9408e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley
9418e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley  /* Verify the MAC. */
9428e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley  {
9438e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    CBS mac, hash_type_seq, hash_oid, salt, expected_mac;
9448e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    uint64_t iterations;
9458e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    int hash_nid;
9468e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    const EVP_MD *md;
9478e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    uint8_t hmac_key[EVP_MAX_MD_SIZE];
9488e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    uint8_t hmac[EVP_MAX_MD_SIZE];
9498e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    unsigned hmac_len;
9508e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley
9518e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    if (!CBS_get_asn1(&mac_data, &mac, CBS_ASN1_SEQUENCE) ||
9528e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley        !CBS_get_asn1(&mac, &hash_type_seq, CBS_ASN1_SEQUENCE) ||
9538e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley        !CBS_get_asn1(&hash_type_seq, &hash_oid, CBS_ASN1_OBJECT) ||
9548e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley        !CBS_get_asn1(&mac, &expected_mac, CBS_ASN1_OCTETSTRING) ||
9558e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley        !CBS_get_asn1(&mac_data, &salt, CBS_ASN1_OCTETSTRING)) {
9568e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley      OPENSSL_PUT_ERROR(PKCS8, PKCS12_parse, PKCS8_R_BAD_PKCS12_DATA);
9578e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley      goto err;
9588e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    }
9598e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley
9608e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    /* The iteration count is optional and the default is one. */
9618e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    iterations = 1;
9628e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    if (CBS_len(&mac_data) > 0) {
9638e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley      if (!CBS_get_asn1_uint64(&mac_data, &iterations) ||
9648e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley          iterations > INT_MAX) {
9658e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley        OPENSSL_PUT_ERROR(PKCS8, PKCS12_parse, PKCS8_R_BAD_PKCS12_DATA);
9668e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley        goto err;
9678e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley      }
9688e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    }
9698e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley
9708e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    hash_nid = OBJ_cbs2nid(&hash_oid);
9718e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    if (hash_nid == NID_undef ||
9728e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley        (md = EVP_get_digestbynid(hash_nid)) == NULL) {
9738e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley      OPENSSL_PUT_ERROR(PKCS8, PKCS12_parse, PKCS8_R_UNKNOWN_HASH);
9748e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley      goto err;
9758e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    }
9768e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley
9778e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    if (!pkcs12_key_gen_raw(ctx.password, ctx.password_len, CBS_data(&salt),
9788e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley                            CBS_len(&salt), PKCS12_MAC_ID, iterations,
9798e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley                            EVP_MD_size(md), hmac_key, md)) {
9808e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley      goto err;
9818e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    }
9828e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley
9838e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    if (NULL == HMAC(md, hmac_key, EVP_MD_size(md), CBS_data(&authsafes),
9848e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley                     CBS_len(&authsafes), hmac, &hmac_len)) {
9858e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley      goto err;
9868e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    }
9878e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley
9888e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    if (!CBS_mem_equal(&expected_mac, hmac, hmac_len)) {
9898e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley      OPENSSL_PUT_ERROR(PKCS8, PKCS12_parse, PKCS8_R_INCORRECT_PASSWORD);
9908e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley      goto err;
9918e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    }
9928e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley  }
9938e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley
9948e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley  /* authsafes contains a series of PKCS#7 ContentInfos. */
9958e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley  if (!PKCS12_handle_content_infos(&authsafes, 0, &ctx)) {
9968e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    goto err;
9978e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley  }
9988e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley
9998e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley  ret = 1;
10008e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley
10018e16b6e6582810de46b4db7926a2462be8e789d2Adam Langleyerr:
10028e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley  if (ctx.password) {
10038e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    OPENSSL_free(ctx.password);
10048e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley  }
10058e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley  if (der_bytes) {
10068e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    OPENSSL_free(der_bytes);
10078e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley  }
10088e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley  if (!ret) {
10098e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    if (*out_key) {
10108e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley      EVP_PKEY_free(*out_key);
10118e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley      *out_key = NULL;
10128e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    }
10138e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    while (sk_X509_num(out_certs) > original_out_certs_len) {
10148e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley      X509 *x509 = sk_X509_pop(out_certs);
10158e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley      X509_free(x509);
10168e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley    }
10178e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley  }
10188e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley
10198e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley  return ret;
10208e16b6e6582810de46b4db7926a2462be8e789d2Adam Langley}
1021bed8ce78f001c600a143966b932f8e587c35e573Adam Langley
1022bed8ce78f001c600a143966b932f8e587c35e573Adam Langleyvoid PKCS12_PBE_add(){};
10235127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley
10245127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langleystruct pkcs12_st {
10255127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley  uint8_t *ber_bytes;
10265127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley  size_t ber_len;
10275127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley};
10285127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley
10295127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam LangleyPKCS12* d2i_PKCS12(PKCS12 **out_p12, const uint8_t **ber_bytes, size_t ber_len) {
10305127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley  PKCS12 *p12;
10315127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley
10325127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley  /* out_p12 must be NULL because we don't export the PKCS12 structure. */
10335127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley  assert(out_p12 == NULL);
10345127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley
10355127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley  p12 = OPENSSL_malloc(sizeof(PKCS12));
10365127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley  if (!p12) {
10375127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley    return NULL;
10385127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley  }
10395127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley
10405127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley  p12->ber_bytes = OPENSSL_malloc(ber_len);
10415127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley  if (!p12->ber_bytes) {
10425127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley    OPENSSL_free(p12);
10435127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley    return NULL;
10445127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley  }
10455127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley
10465127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley  memcpy(p12->ber_bytes, *ber_bytes, ber_len);
10475127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley  p12->ber_len = ber_len;
10485127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley  *ber_bytes += ber_len;
10495127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley
10505127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley  return p12;
10515127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley}
10525127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley
10535127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam LangleyPKCS12* d2i_PKCS12_bio(BIO *bio, PKCS12 **out_p12) {
10545127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley  size_t used = 0;
10555127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley  BUF_MEM *buf;
10565127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley  const uint8_t *dummy;
10575127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley  static const size_t kMaxSize = 256 * 1024;
10585127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley  PKCS12 *ret = NULL;
10595127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley
10605127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley  buf = BUF_MEM_new();
10615127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley  if (buf == NULL) {
10625127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley    return NULL;
10635127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley  }
10645127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley  if (BUF_MEM_grow(buf, 8192) == 0) {
10655127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley    goto out;
10665127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley  }
10675127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley
10685127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley  for (;;) {
10695127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley    int n = BIO_read(bio, &buf->data[used], buf->length - used);
10705127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley    if (n < 0) {
10715127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley      goto out;
10725127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley    }
10735127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley
10745127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley    if (n == 0) {
10755127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley      break;
10765127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley    }
10775127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley    used += n;
10785127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley
10795127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley    if (used < buf->length) {
10805127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley      continue;
10815127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley    }
10825127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley
10835127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley    if (buf->length > kMaxSize ||
10845127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley        BUF_MEM_grow(buf, buf->length * 2) == 0) {
10855127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley      goto out;
10865127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley    }
10875127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley  }
10885127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley
10895127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley  dummy = (uint8_t*) buf->data;
10905127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley  ret = d2i_PKCS12(out_p12, &dummy, used);
10915127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley
10925127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langleyout:
10935127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley  BUF_MEM_free(buf);
10945127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley  return ret;
10955127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley}
10965127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley
10975127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam LangleyPKCS12* d2i_PKCS12_fp(FILE *fp, PKCS12 **out_p12) {
10985127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley  BIO *bio;
10995127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley  PKCS12 *ret;
11005127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley
11015127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley  bio = BIO_new_fp(fp, 0 /* don't take ownership */);
11025127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley  if (!bio) {
11035127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley    return NULL;
11045127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley  }
11055127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley
11065127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley  ret = d2i_PKCS12_bio(bio, out_p12);
11075127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley  BIO_free(bio);
11085127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley  return ret;
11095127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley}
11105127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley
11115127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langleyint PKCS12_parse(const PKCS12 *p12, const char *password, EVP_PKEY **out_pkey,
11125127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley                 X509 **out_cert, STACK_OF(X509) **out_ca_certs) {
11135127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley  CBS ber_bytes;
11145127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley  STACK_OF(X509) *ca_certs = NULL;
11155127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley  char ca_certs_alloced = 0;
11165127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley
11175127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley  if (out_ca_certs != NULL && *out_ca_certs != NULL) {
11185127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley    ca_certs = *out_ca_certs;
11195127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley  }
11205127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley
11215127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley  if (!ca_certs) {
11225127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley    ca_certs = sk_X509_new_null();
11235127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley    if (ca_certs == NULL) {
11245127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley      return 0;
11255127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley    }
11265127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley    ca_certs_alloced = 1;
11275127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley  }
11285127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley
11295127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley  CBS_init(&ber_bytes, p12->ber_bytes, p12->ber_len);
11305127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley  if (!PKCS12_get_key_and_certs(out_pkey, ca_certs, &ber_bytes, password)) {
11315127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley    if (ca_certs_alloced) {
11325127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley      sk_X509_free(ca_certs);
11335127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley    }
11345127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley    return 0;
11355127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley  }
11365127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley
11375127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley  *out_cert = NULL;
11385127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley  if (sk_X509_num(ca_certs) > 0) {
11395127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley    *out_cert = sk_X509_shift(ca_certs);
11405127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley  }
11415127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley
11425127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley  if (out_ca_certs) {
11435127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley    *out_ca_certs = ca_certs;
11445127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley  } else {
11455127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley    sk_X509_pop_free(ca_certs, X509_free);
11465127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley  }
11475127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley
11485127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley  return 1;
11495127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley}
11505127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley
11515127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langleyvoid PKCS12_free(PKCS12 *p12) {
11525127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley  OPENSSL_free(p12->ber_bytes);
11535127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley  OPENSSL_free(p12);
11545127db3b4d59066126a1f8c8f7fdf4841a8c58b9Adam Langley}
1155