1d9e397b599b13d642138480a28c14db7a136bf0Adam Langley/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
2d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * project 1999.
3d9e397b599b13d642138480a28c14db7a136bf0Adam Langley */
4d9e397b599b13d642138480a28c14db7a136bf0Adam Langley/* ====================================================================
5d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * Copyright (c) 1999 The OpenSSL Project.  All rights reserved.
6d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *
7d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * Redistribution and use in source and binary forms, with or without
8d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * modification, are permitted provided that the following conditions
9d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * are met:
10d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *
11d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * 1. Redistributions of source code must retain the above copyright
12d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *    notice, this list of conditions and the following disclaimer.
13d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *
14d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * 2. Redistributions in binary form must reproduce the above copyright
15d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *    notice, this list of conditions and the following disclaimer in
16d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *    the documentation and/or other materials provided with the
17d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *    distribution.
18d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *
19d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * 3. All advertising materials mentioning features or use of this
20d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *    software must display the following acknowledgment:
21d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *    "This product includes software developed by the OpenSSL Project
22d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
23d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *
24d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
25d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *    endorse or promote products derived from this software without
26d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *    prior written permission. For written permission, please contact
27d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *    licensing@OpenSSL.org.
28d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *
29d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * 5. Products derived from this software may not be called "OpenSSL"
30d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *    nor may "OpenSSL" appear in their names without prior written
31d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *    permission of the OpenSSL Project.
32d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *
33d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * 6. Redistributions of any form whatsoever must retain the following
34d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *    acknowledgment:
35d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *    "This product includes software developed by the OpenSSL Project
36d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
37d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *
38d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
39d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
40d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
41d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
42d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
43d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
44d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
45d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
46d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
47d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
48d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
49d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * OF THE POSSIBILITY OF SUCH DAMAGE.
50d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * ====================================================================
51d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *
52d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * This product includes cryptographic software written by Eric Young
53d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * (eay@cryptsoft.com).  This product includes software written by Tim
54d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * Hudson (tjh@cryptsoft.com). */
55d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
56d9e397b599b13d642138480a28c14db7a136bf0Adam Langley#include <openssl/pkcs8.h>
57d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
58d9e397b599b13d642138480a28c14db7a136bf0Adam Langley#include <assert.h>
59d9e397b599b13d642138480a28c14db7a136bf0Adam Langley#include <limits.h>
60d9e397b599b13d642138480a28c14db7a136bf0Adam Langley#include <string.h>
61d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
624969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin#include <openssl/bytestring.h>
63d9e397b599b13d642138480a28c14db7a136bf0Adam Langley#include <openssl/cipher.h>
64d9e397b599b13d642138480a28c14db7a136bf0Adam Langley#include <openssl/digest.h>
65d9e397b599b13d642138480a28c14db7a136bf0Adam Langley#include <openssl/err.h>
66d9e397b599b13d642138480a28c14db7a136bf0Adam Langley#include <openssl/mem.h>
676d0d00e090b753250659b9a2d67dab7467257900Robert Sloan#include <openssl/nid.h>
68b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez#include <openssl/rand.h>
69d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
70b8494591d1b1a143f3b192d845c238bbf3bc629dKenny Root#include "internal.h"
71f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin#include "../internal.h"
72d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
73d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
74d9e397b599b13d642138480a28c14db7a136bf0Adam Langleystatic int ascii_to_ucs2(const char *ascii, size_t ascii_len,
75d9e397b599b13d642138480a28c14db7a136bf0Adam Langley                         uint8_t **out, size_t *out_len) {
76b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez  size_t ulen = ascii_len * 2 + 2;
77b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez  if (ascii_len * 2 < ascii_len || ulen < ascii_len * 2) {
78d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    return 0;
79d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  }
80b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez
81b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez  uint8_t *unitmp = OPENSSL_malloc(ulen);
82d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  if (unitmp == NULL) {
836d0d00e090b753250659b9a2d67dab7467257900Robert Sloan    OPENSSL_PUT_ERROR(PKCS8, ERR_R_MALLOC_FAILURE);
84d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    return 0;
85d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  }
86b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez  for (size_t i = 0; i < ulen - 2; i += 2) {
87d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    unitmp[i] = 0;
88d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    unitmp[i + 1] = ascii[i >> 1];
89d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  }
90d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
91b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez  /* Terminate the result with a UCS-2 NUL. */
92d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  unitmp[ulen - 2] = 0;
93d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  unitmp[ulen - 1] = 0;
94d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  *out_len = ulen;
95d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  *out = unitmp;
96d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  return 1;
97d9e397b599b13d642138480a28c14db7a136bf0Adam Langley}
98d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
996d0d00e090b753250659b9a2d67dab7467257900Robert Sloanint pkcs12_key_gen(const char *pass, size_t pass_len, const uint8_t *salt,
1006d0d00e090b753250659b9a2d67dab7467257900Robert Sloan                   size_t salt_len, uint8_t id, unsigned iterations,
1016d0d00e090b753250659b9a2d67dab7467257900Robert Sloan                   size_t out_len, uint8_t *out, const EVP_MD *md) {
1024969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin  /* See https://tools.ietf.org/html/rfc7292#appendix-B. Quoted parts of the
1034969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin   * specification have errata applied and other typos fixed. */
104d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
1054969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin  if (iterations < 1) {
1064969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin    OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_ITERATION_COUNT);
1074969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin    return 0;
108e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley  }
1094969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin
1106d0d00e090b753250659b9a2d67dab7467257900Robert Sloan  int ret = 0;
1116d0d00e090b753250659b9a2d67dab7467257900Robert Sloan  EVP_MD_CTX ctx;
1126d0d00e090b753250659b9a2d67dab7467257900Robert Sloan  EVP_MD_CTX_init(&ctx);
1136d0d00e090b753250659b9a2d67dab7467257900Robert Sloan  uint8_t *pass_raw = NULL, *I = NULL;
1146d0d00e090b753250659b9a2d67dab7467257900Robert Sloan  size_t pass_raw_len = 0, I_len = 0;
1156d0d00e090b753250659b9a2d67dab7467257900Robert Sloan  /* If |pass| is NULL, we use the empty string rather than {0, 0} as the raw
1166d0d00e090b753250659b9a2d67dab7467257900Robert Sloan   * password. */
1176d0d00e090b753250659b9a2d67dab7467257900Robert Sloan  if (pass != NULL &&
1186d0d00e090b753250659b9a2d67dab7467257900Robert Sloan      !ascii_to_ucs2(pass, pass_len, &pass_raw, &pass_raw_len)) {
1196d0d00e090b753250659b9a2d67dab7467257900Robert Sloan    goto err;
1206d0d00e090b753250659b9a2d67dab7467257900Robert Sloan  }
1216d0d00e090b753250659b9a2d67dab7467257900Robert Sloan
1224969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin  /* In the spec, |block_size| is called "v", but measured in bits. */
1234969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin  size_t block_size = EVP_MD_block_size(md);
1244969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin
1254969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin  /* 1. Construct a string, D (the "diversifier"), by concatenating v/8 copies
1264969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin   * of ID. */
1274969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin  uint8_t D[EVP_MAX_MD_BLOCK_SIZE];
12869939df2891f62f7f00ff2ac275f1cd81a67454cRobert Sloan  OPENSSL_memset(D, id, block_size);
1294969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin
1304969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin  /* 2. Concatenate copies of the salt together to create a string S of length
1314969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin   * v(ceiling(s/v)) bits (the final copy of the salt may be truncated to
1324969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin   * create S). Note that if the salt is the empty string, then so is S.
1334969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin   *
1344969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin   * 3. Concatenate copies of the password together to create a string P of
1354969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin   * length v(ceiling(p/v)) bits (the final copy of the password may be
1364969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin   * truncated to create P).  Note that if the password is the empty string,
1374969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin   * then so is P.
1384969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin   *
1394969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin   * 4. Set I=S||P to be the concatenation of S and P. */
1404969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin  if (salt_len + block_size - 1 < salt_len ||
1414969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin      pass_raw_len + block_size - 1 < pass_raw_len) {
1424969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin    OPENSSL_PUT_ERROR(PKCS8, ERR_R_OVERFLOW);
1436d0d00e090b753250659b9a2d67dab7467257900Robert Sloan    goto err;
144e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley  }
1454969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin  size_t S_len = block_size * ((salt_len + block_size - 1) / block_size);
1464969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin  size_t P_len = block_size * ((pass_raw_len + block_size - 1) / block_size);
1476d0d00e090b753250659b9a2d67dab7467257900Robert Sloan  I_len = S_len + P_len;
1484969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin  if (I_len < S_len) {
1494969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin    OPENSSL_PUT_ERROR(PKCS8, ERR_R_OVERFLOW);
1506d0d00e090b753250659b9a2d67dab7467257900Robert Sloan    goto err;
151e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley  }
1524969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin
1536d0d00e090b753250659b9a2d67dab7467257900Robert Sloan  I = OPENSSL_malloc(I_len);
1544969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin  if (I_len != 0 && I == NULL) {
1554969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin    OPENSSL_PUT_ERROR(PKCS8, ERR_R_MALLOC_FAILURE);
1566d0d00e090b753250659b9a2d67dab7467257900Robert Sloan    goto err;
157e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley  }
1584969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin
1597c0d06c221ce9edf44bbf978b909b38a0aee2084David Benjamin  for (size_t i = 0; i < S_len; i++) {
1604969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin    I[i] = salt[i % salt_len];
161e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley  }
1627c0d06c221ce9edf44bbf978b909b38a0aee2084David Benjamin  for (size_t i = 0; i < P_len; i++) {
1634969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin    I[i + S_len] = pass_raw[i % pass_raw_len];
1644969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin  }
1654969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin
1664969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin  while (out_len != 0) {
1674969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin    /* A. Set A_i=H^r(D||I). (i.e., the r-th hash of D||I,
1684969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin     * H(H(H(... H(D||I)))) */
1694969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin    uint8_t A[EVP_MAX_MD_SIZE];
1704969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin    unsigned A_len;
1714969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin    if (!EVP_DigestInit_ex(&ctx, md, NULL) ||
1724969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin        !EVP_DigestUpdate(&ctx, D, block_size) ||
1734969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin        !EVP_DigestUpdate(&ctx, I, I_len) ||
1744969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin        !EVP_DigestFinal_ex(&ctx, A, &A_len)) {
175d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      goto err;
176d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    }
177b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez    for (unsigned iter = 1; iter < iterations; iter++) {
1784969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin      if (!EVP_DigestInit_ex(&ctx, md, NULL) ||
1794969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin          !EVP_DigestUpdate(&ctx, A, A_len) ||
1804969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin          !EVP_DigestFinal_ex(&ctx, A, &A_len)) {
181d9e397b599b13d642138480a28c14db7a136bf0Adam Langley        goto err;
182d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      }
183d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    }
1844969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin
1854969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin    size_t todo = out_len < A_len ? out_len : A_len;
18669939df2891f62f7f00ff2ac275f1cd81a67454cRobert Sloan    OPENSSL_memcpy(out, A, todo);
1874969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin    out += todo;
1884969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin    out_len -= todo;
1894969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin    if (out_len == 0) {
1904969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin      break;
191e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley    }
1924969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin
1934969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin    /* B. Concatenate copies of A_i to create a string B of length v bits (the
1944969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin     * final copy of A_i may be truncated to create B). */
1954969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin    uint8_t B[EVP_MAX_MD_BLOCK_SIZE];
1967c0d06c221ce9edf44bbf978b909b38a0aee2084David Benjamin    for (size_t i = 0; i < block_size; i++) {
1974969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin      B[i] = A[i % A_len];
198e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley    }
1994969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin
2004969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin    /* C. Treating I as a concatenation I_0, I_1, ..., I_(k-1) of v-bit blocks,
2014969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin     * where k=ceiling(s/v)+ceiling(p/v), modify I by setting I_j=(I_j+B+1) mod
2024969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin     * 2^v for each j. */
2034969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin    assert(I_len % block_size == 0);
2047c0d06c221ce9edf44bbf978b909b38a0aee2084David Benjamin    for (size_t i = 0; i < I_len; i += block_size) {
2054969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin      unsigned carry = 1;
2067c0d06c221ce9edf44bbf978b909b38a0aee2084David Benjamin      for (size_t j = block_size - 1; j < block_size; j--) {
2074969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin        carry += I[i + j] + B[j];
2084969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin        I[i + j] = (uint8_t)carry;
2094969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin        carry >>= 8;
210d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      }
211d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    }
212d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  }
213d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
2144969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin  ret = 1;
215d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
2164969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjaminerr:
2176d0d00e090b753250659b9a2d67dab7467257900Robert Sloan  if (I != NULL) {
2186d0d00e090b753250659b9a2d67dab7467257900Robert Sloan    OPENSSL_cleanse(I, I_len);
2196d0d00e090b753250659b9a2d67dab7467257900Robert Sloan    OPENSSL_free(I);
2206d0d00e090b753250659b9a2d67dab7467257900Robert Sloan  }
2216d0d00e090b753250659b9a2d67dab7467257900Robert Sloan  if (pass_raw != NULL) {
2226d0d00e090b753250659b9a2d67dab7467257900Robert Sloan    OPENSSL_cleanse(pass_raw, pass_raw_len);
2236d0d00e090b753250659b9a2d67dab7467257900Robert Sloan    OPENSSL_free(pass_raw);
2246d0d00e090b753250659b9a2d67dab7467257900Robert Sloan  }
225d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  EVP_MD_CTX_cleanup(&ctx);
226d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  return ret;
227d9e397b599b13d642138480a28c14db7a136bf0Adam Langley}
228d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
229b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdezstatic int pkcs12_pbe_cipher_init(const struct pbe_suite *suite,
230b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez                                  EVP_CIPHER_CTX *ctx, unsigned iterations,
2316d0d00e090b753250659b9a2d67dab7467257900Robert Sloan                                  const char *pass, size_t pass_len,
232b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez                                  const uint8_t *salt, size_t salt_len,
233b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez                                  int is_encrypt) {
234b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez  const EVP_CIPHER *cipher = suite->cipher_func();
235b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez  const EVP_MD *md = suite->md_func();
236b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez
237b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez  uint8_t key[EVP_MAX_KEY_LENGTH];
238b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez  uint8_t iv[EVP_MAX_IV_LENGTH];
2396d0d00e090b753250659b9a2d67dab7467257900Robert Sloan  if (!pkcs12_key_gen(pass, pass_len, salt, salt_len, PKCS12_KEY_ID, iterations,
2406d0d00e090b753250659b9a2d67dab7467257900Robert Sloan                      EVP_CIPHER_key_length(cipher), key, md) ||
2416d0d00e090b753250659b9a2d67dab7467257900Robert Sloan      !pkcs12_key_gen(pass, pass_len, salt, salt_len, PKCS12_IV_ID, iterations,
2426d0d00e090b753250659b9a2d67dab7467257900Robert Sloan                      EVP_CIPHER_iv_length(cipher), iv, md)) {
243b8494591d1b1a143f3b192d845c238bbf3bc629dKenny Root    OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_KEY_GEN_ERROR);
244d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    return 0;
245d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  }
246b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez
247b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez  int ret = EVP_CipherInit_ex(ctx, cipher, NULL, key, iv, is_encrypt);
248d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  OPENSSL_cleanse(key, EVP_MAX_KEY_LENGTH);
249d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  OPENSSL_cleanse(iv, EVP_MAX_IV_LENGTH);
250d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  return ret;
251d9e397b599b13d642138480a28c14db7a136bf0Adam Langley}
252d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
253b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdezstatic int pkcs12_pbe_decrypt_init(const struct pbe_suite *suite,
2546d0d00e090b753250659b9a2d67dab7467257900Robert Sloan                                   EVP_CIPHER_CTX *ctx, const char *pass,
2556d0d00e090b753250659b9a2d67dab7467257900Robert Sloan                                   size_t pass_len, CBS *param) {
256b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez  CBS pbe_param, salt;
257b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez  uint64_t iterations;
258b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez  if (!CBS_get_asn1(param, &pbe_param, CBS_ASN1_SEQUENCE) ||
259b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez      !CBS_get_asn1(&pbe_param, &salt, CBS_ASN1_OCTETSTRING) ||
260b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez      !CBS_get_asn1_uint64(&pbe_param, &iterations) ||
261b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez      CBS_len(&pbe_param) != 0 ||
262b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez      CBS_len(param) != 0) {
263b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez    OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_DECODE_ERROR);
264b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez    return 0;
265b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez  }
266b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez
267b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez  if (iterations == 0 || iterations > UINT_MAX) {
268b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez    OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_ITERATION_COUNT);
269b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez    return 0;
270b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez  }
271d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
2726d0d00e090b753250659b9a2d67dab7467257900Robert Sloan  return pkcs12_pbe_cipher_init(suite, ctx, (unsigned)iterations, pass,
2736d0d00e090b753250659b9a2d67dab7467257900Robert Sloan                                pass_len, CBS_data(&salt), CBS_len(&salt),
274b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez                                0 /* decrypt */);
275b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez}
276b8494591d1b1a143f3b192d845c238bbf3bc629dKenny Root
277d9e397b599b13d642138480a28c14db7a136bf0Adam Langleystatic const struct pbe_suite kBuiltinPBE[] = {
278d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    {
2796d0d00e090b753250659b9a2d67dab7467257900Robert Sloan        NID_pbe_WithSHA1And40BitRC2_CBC,
2806d0d00e090b753250659b9a2d67dab7467257900Robert Sloan        /* 1.2.840.113549.1.12.1.6 */
2816d0d00e090b753250659b9a2d67dab7467257900Robert Sloan        {0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x0c, 0x01, 0x06},
2826d0d00e090b753250659b9a2d67dab7467257900Robert Sloan        10,
2836d0d00e090b753250659b9a2d67dab7467257900Robert Sloan        EVP_rc2_40_cbc,
2846d0d00e090b753250659b9a2d67dab7467257900Robert Sloan        EVP_sha1,
2856d0d00e090b753250659b9a2d67dab7467257900Robert Sloan        pkcs12_pbe_decrypt_init,
286d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    },
287d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    {
2886d0d00e090b753250659b9a2d67dab7467257900Robert Sloan        NID_pbe_WithSHA1And128BitRC4,
2896d0d00e090b753250659b9a2d67dab7467257900Robert Sloan        /* 1.2.840.113549.1.12.1.1 */
2906d0d00e090b753250659b9a2d67dab7467257900Robert Sloan        {0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x0c, 0x01, 0x01},
2916d0d00e090b753250659b9a2d67dab7467257900Robert Sloan        10,
2926d0d00e090b753250659b9a2d67dab7467257900Robert Sloan        EVP_rc4,
2936d0d00e090b753250659b9a2d67dab7467257900Robert Sloan        EVP_sha1,
2946d0d00e090b753250659b9a2d67dab7467257900Robert Sloan        pkcs12_pbe_decrypt_init,
295d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    },
296d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    {
2976d0d00e090b753250659b9a2d67dab7467257900Robert Sloan        NID_pbe_WithSHA1And3_Key_TripleDES_CBC,
2986d0d00e090b753250659b9a2d67dab7467257900Robert Sloan        /* 1.2.840.113549.1.12.1.3 */
2996d0d00e090b753250659b9a2d67dab7467257900Robert Sloan        {0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x0c, 0x01, 0x03},
3006d0d00e090b753250659b9a2d67dab7467257900Robert Sloan        10,
3016d0d00e090b753250659b9a2d67dab7467257900Robert Sloan        EVP_des_ede3_cbc,
3026d0d00e090b753250659b9a2d67dab7467257900Robert Sloan        EVP_sha1,
3036d0d00e090b753250659b9a2d67dab7467257900Robert Sloan        pkcs12_pbe_decrypt_init,
304b8494591d1b1a143f3b192d845c238bbf3bc629dKenny Root    },
305b8494591d1b1a143f3b192d845c238bbf3bc629dKenny Root    {
3066d0d00e090b753250659b9a2d67dab7467257900Robert Sloan        NID_pbes2,
3076d0d00e090b753250659b9a2d67dab7467257900Robert Sloan        /* 1.2.840.113549.1.5.13 */
3086d0d00e090b753250659b9a2d67dab7467257900Robert Sloan        {0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x05, 0x0d},
3096d0d00e090b753250659b9a2d67dab7467257900Robert Sloan        9,
3106d0d00e090b753250659b9a2d67dab7467257900Robert Sloan        NULL,
3116d0d00e090b753250659b9a2d67dab7467257900Robert Sloan        NULL,
3126d0d00e090b753250659b9a2d67dab7467257900Robert Sloan        PKCS5_pbe2_decrypt_init,
313d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    },
314d9e397b599b13d642138480a28c14db7a136bf0Adam Langley};
315d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
316b8494591d1b1a143f3b192d845c238bbf3bc629dKenny Rootstatic const struct pbe_suite *get_pbe_suite(int pbe_nid) {
3176d0d00e090b753250659b9a2d67dab7467257900Robert Sloan  for (unsigned i = 0; i < OPENSSL_ARRAY_SIZE(kBuiltinPBE); i++) {
318b8494591d1b1a143f3b192d845c238bbf3bc629dKenny Root    if (kBuiltinPBE[i].pbe_nid == pbe_nid) {
319b8494591d1b1a143f3b192d845c238bbf3bc629dKenny Root      return &kBuiltinPBE[i];
320b8494591d1b1a143f3b192d845c238bbf3bc629dKenny Root    }
321b8494591d1b1a143f3b192d845c238bbf3bc629dKenny Root  }
322b8494591d1b1a143f3b192d845c238bbf3bc629dKenny Root
323b8494591d1b1a143f3b192d845c238bbf3bc629dKenny Root  return NULL;
324b8494591d1b1a143f3b192d845c238bbf3bc629dKenny Root}
325b8494591d1b1a143f3b192d845c238bbf3bc629dKenny Root
326b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdezstatic int pkcs12_pbe_encrypt_init(CBB *out, EVP_CIPHER_CTX *ctx, int alg,
3276d0d00e090b753250659b9a2d67dab7467257900Robert Sloan                                   unsigned iterations, const char *pass,
3286d0d00e090b753250659b9a2d67dab7467257900Robert Sloan                                   size_t pass_len, const uint8_t *salt,
329b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez                                   size_t salt_len) {
330b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez  const struct pbe_suite *suite = get_pbe_suite(alg);
331d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  if (suite == NULL) {
332b8494591d1b1a143f3b192d845c238bbf3bc629dKenny Root    OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_UNKNOWN_ALGORITHM);
333d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    return 0;
334d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  }
335d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
336b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez  /* See RFC 2898, appendix A.3. */
3376d0d00e090b753250659b9a2d67dab7467257900Robert Sloan  CBB algorithm, oid, param, salt_cbb;
338b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez  if (!CBB_add_asn1(out, &algorithm, CBS_ASN1_SEQUENCE) ||
3396d0d00e090b753250659b9a2d67dab7467257900Robert Sloan      !CBB_add_asn1(&algorithm, &oid, CBS_ASN1_OBJECT) ||
3406d0d00e090b753250659b9a2d67dab7467257900Robert Sloan      !CBB_add_bytes(&oid, suite->oid, suite->oid_len) ||
341b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez      !CBB_add_asn1(&algorithm, &param, CBS_ASN1_SEQUENCE) ||
342b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez      !CBB_add_asn1(&param, &salt_cbb, CBS_ASN1_OCTETSTRING) ||
343b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez      !CBB_add_bytes(&salt_cbb, salt, salt_len) ||
344b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez      !CBB_add_asn1_uint64(&param, iterations) ||
345b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez      !CBB_flush(out)) {
346d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    return 0;
347d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  }
348d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
3496d0d00e090b753250659b9a2d67dab7467257900Robert Sloan  return pkcs12_pbe_cipher_init(suite, ctx, iterations, pass, pass_len, salt,
3506d0d00e090b753250659b9a2d67dab7467257900Robert Sloan                                salt_len, 1 /* encrypt */);
351d9e397b599b13d642138480a28c14db7a136bf0Adam Langley}
352d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
3536d0d00e090b753250659b9a2d67dab7467257900Robert Sloanint pkcs8_pbe_decrypt(uint8_t **out, size_t *out_len, CBS *algorithm,
3546d0d00e090b753250659b9a2d67dab7467257900Robert Sloan                      const char *pass, size_t pass_len, const uint8_t *in,
3556d0d00e090b753250659b9a2d67dab7467257900Robert Sloan                      size_t in_len) {
356b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez  int ret = 0;
357b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez  uint8_t *buf = NULL;;
358d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  EVP_CIPHER_CTX ctx;
359d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  EVP_CIPHER_CTX_init(&ctx);
360d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
361b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez  CBS obj;
362b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez  if (!CBS_get_asn1(algorithm, &obj, CBS_ASN1_OBJECT)) {
363b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez    OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_DECODE_ERROR);
364b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez    goto err;
365d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  }
366d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
3676d0d00e090b753250659b9a2d67dab7467257900Robert Sloan  const struct pbe_suite *suite = NULL;
3686d0d00e090b753250659b9a2d67dab7467257900Robert Sloan  for (unsigned i = 0; i < OPENSSL_ARRAY_SIZE(kBuiltinPBE); i++) {
3696d0d00e090b753250659b9a2d67dab7467257900Robert Sloan    if (CBS_mem_equal(&obj, kBuiltinPBE[i].oid, kBuiltinPBE[i].oid_len)) {
3706d0d00e090b753250659b9a2d67dab7467257900Robert Sloan      suite = &kBuiltinPBE[i];
3716d0d00e090b753250659b9a2d67dab7467257900Robert Sloan      break;
3726d0d00e090b753250659b9a2d67dab7467257900Robert Sloan    }
3736d0d00e090b753250659b9a2d67dab7467257900Robert Sloan  }
374b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez  if (suite == NULL) {
375b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez    OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_UNKNOWN_ALGORITHM);
376d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    goto err;
377d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  }
378d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
3796d0d00e090b753250659b9a2d67dab7467257900Robert Sloan  if (!suite->decrypt_init(suite, &ctx, pass, pass_len, algorithm)) {
380b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez    OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_KEYGEN_FAILURE);
381b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez    goto err;
382b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez  }
383b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez
384b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez  buf = OPENSSL_malloc(in_len);
385d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  if (buf == NULL) {
386b8494591d1b1a143f3b192d845c238bbf3bc629dKenny Root    OPENSSL_PUT_ERROR(PKCS8, ERR_R_MALLOC_FAILURE);
387d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    goto err;
388d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  }
389d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
390b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez  if (in_len > INT_MAX) {
391b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez    OPENSSL_PUT_ERROR(PKCS8, ERR_R_OVERFLOW);
392d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    goto err;
393d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  }
394d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
395b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez  int n1, n2;
396b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez  if (!EVP_DecryptUpdate(&ctx, buf, &n1, in, (int)in_len) ||
397b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez      !EVP_DecryptFinal_ex(&ctx, buf + n1, &n2)) {
398d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    goto err;
399d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  }
400b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez
401d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  *out = buf;
402b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez  *out_len = n1 + n2;
403d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  ret = 1;
404b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez  buf = NULL;
405d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
406d9e397b599b13d642138480a28c14db7a136bf0Adam Langleyerr:
407b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez  OPENSSL_free(buf);
408d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  EVP_CIPHER_CTX_cleanup(&ctx);
409d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  return ret;
410d9e397b599b13d642138480a28c14db7a136bf0Adam Langley}
411d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
4126d0d00e090b753250659b9a2d67dab7467257900Robert SloanEVP_PKEY *PKCS8_parse_encrypted_private_key(CBS *cbs, const char *pass,
4136d0d00e090b753250659b9a2d67dab7467257900Robert Sloan                                            size_t pass_len) {
414b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez  /* See RFC 5208, section 6. */
4156d0d00e090b753250659b9a2d67dab7467257900Robert Sloan  CBS epki, algorithm, ciphertext;
4166d0d00e090b753250659b9a2d67dab7467257900Robert Sloan  if (!CBS_get_asn1(cbs, &epki, CBS_ASN1_SEQUENCE) ||
417b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez      !CBS_get_asn1(&epki, &algorithm, CBS_ASN1_SEQUENCE) ||
418b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez      !CBS_get_asn1(&epki, &ciphertext, CBS_ASN1_OCTETSTRING) ||
4196d0d00e090b753250659b9a2d67dab7467257900Robert Sloan      CBS_len(&epki) != 0) {
420b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez    OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_DECODE_ERROR);
4216d0d00e090b753250659b9a2d67dab7467257900Robert Sloan    return 0;
422b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez  }
423b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez
4246d0d00e090b753250659b9a2d67dab7467257900Robert Sloan  uint8_t *out;
4256d0d00e090b753250659b9a2d67dab7467257900Robert Sloan  size_t out_len;
4266d0d00e090b753250659b9a2d67dab7467257900Robert Sloan  if (!pkcs8_pbe_decrypt(&out, &out_len, &algorithm, pass, pass_len,
4276d0d00e090b753250659b9a2d67dab7467257900Robert Sloan                         CBS_data(&ciphertext), CBS_len(&ciphertext))) {
4286d0d00e090b753250659b9a2d67dab7467257900Robert Sloan    return 0;
429b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez  }
430b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez
4316d0d00e090b753250659b9a2d67dab7467257900Robert Sloan  CBS pki;
4326d0d00e090b753250659b9a2d67dab7467257900Robert Sloan  CBS_init(&pki, out, out_len);
4336d0d00e090b753250659b9a2d67dab7467257900Robert Sloan  EVP_PKEY *ret = EVP_parse_private_key(&pki);
434b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez  OPENSSL_cleanse(out, out_len);
435b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez  OPENSSL_free(out);
436b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez  return ret;
437d9e397b599b13d642138480a28c14db7a136bf0Adam Langley}
438d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
4396d0d00e090b753250659b9a2d67dab7467257900Robert Sloanint PKCS8_marshal_encrypted_private_key(CBB *out, int pbe_nid,
4406d0d00e090b753250659b9a2d67dab7467257900Robert Sloan                                        const EVP_CIPHER *cipher,
4416d0d00e090b753250659b9a2d67dab7467257900Robert Sloan                                        const char *pass, size_t pass_len,
4426d0d00e090b753250659b9a2d67dab7467257900Robert Sloan                                        const uint8_t *salt, size_t salt_len,
4436d0d00e090b753250659b9a2d67dab7467257900Robert Sloan                                        int iterations, const EVP_PKEY *pkey) {
4446d0d00e090b753250659b9a2d67dab7467257900Robert Sloan  int ret = 0;
4456d0d00e090b753250659b9a2d67dab7467257900Robert Sloan  uint8_t *plaintext = NULL, *salt_buf = NULL;
4466d0d00e090b753250659b9a2d67dab7467257900Robert Sloan  size_t plaintext_len = 0;
447b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez  EVP_CIPHER_CTX ctx;
448b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez  EVP_CIPHER_CTX_init(&ctx);
449d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
450b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez  /* Generate a random salt if necessary. */
451b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez  if (salt == NULL) {
452b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez    if (salt_len == 0) {
453b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez      salt_len = PKCS5_SALT_LEN;
454b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez    }
455b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez
456b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez    salt_buf = OPENSSL_malloc(salt_len);
457b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez    if (salt_buf == NULL ||
458b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez        !RAND_bytes(salt_buf, salt_len)) {
459b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez      goto err;
460b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez    }
461b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez
462b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez    salt = salt_buf;
463b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez  }
464b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez
465b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez  if (iterations <= 0) {
466b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez    iterations = PKCS5_DEFAULT_ITERATIONS;
467b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez  }
468b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez
4696d0d00e090b753250659b9a2d67dab7467257900Robert Sloan  /* Serialize the input key. */
4706d0d00e090b753250659b9a2d67dab7467257900Robert Sloan  CBB plaintext_cbb;
4716d0d00e090b753250659b9a2d67dab7467257900Robert Sloan  if (!CBB_init(&plaintext_cbb, 128) ||
4726d0d00e090b753250659b9a2d67dab7467257900Robert Sloan      !EVP_marshal_private_key(&plaintext_cbb, pkey) ||
4736d0d00e090b753250659b9a2d67dab7467257900Robert Sloan      !CBB_finish(&plaintext_cbb, &plaintext, &plaintext_len)) {
4746d0d00e090b753250659b9a2d67dab7467257900Robert Sloan    CBB_cleanup(&plaintext_cbb);
475b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez    goto err;
476b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez  }
477b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez
478b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez  CBB epki;
4796d0d00e090b753250659b9a2d67dab7467257900Robert Sloan  if (!CBB_add_asn1(out, &epki, CBS_ASN1_SEQUENCE)) {
480d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    goto err;
481d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  }
482d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
483b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez  int alg_ok;
484b8494591d1b1a143f3b192d845c238bbf3bc629dKenny Root  if (pbe_nid == -1) {
485b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez    alg_ok = PKCS5_pbe2_encrypt_init(&epki, &ctx, cipher, (unsigned)iterations,
4866d0d00e090b753250659b9a2d67dab7467257900Robert Sloan                                     pass, pass_len, salt, salt_len);
487b8494591d1b1a143f3b192d845c238bbf3bc629dKenny Root  } else {
488b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez    alg_ok = pkcs12_pbe_encrypt_init(&epki, &ctx, pbe_nid, (unsigned)iterations,
4896d0d00e090b753250659b9a2d67dab7467257900Robert Sloan                                     pass, pass_len, salt, salt_len);
490b8494591d1b1a143f3b192d845c238bbf3bc629dKenny Root  }
491b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez  if (!alg_ok) {
492d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    goto err;
493d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  }
494d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
4956d0d00e090b753250659b9a2d67dab7467257900Robert Sloan  size_t max_out = plaintext_len + EVP_CIPHER_CTX_block_size(&ctx);
4966d0d00e090b753250659b9a2d67dab7467257900Robert Sloan  if (max_out < plaintext_len) {
497b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez    OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_TOO_LONG);
498d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    goto err;
499d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  }
500d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
501b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez  CBB ciphertext;
5026d0d00e090b753250659b9a2d67dab7467257900Robert Sloan  uint8_t *ptr;
503b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez  int n1, n2;
504b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez  if (!CBB_add_asn1(&epki, &ciphertext, CBS_ASN1_OCTETSTRING) ||
5056d0d00e090b753250659b9a2d67dab7467257900Robert Sloan      !CBB_reserve(&ciphertext, &ptr, max_out) ||
5066d0d00e090b753250659b9a2d67dab7467257900Robert Sloan      !EVP_CipherUpdate(&ctx, ptr, &n1, plaintext, plaintext_len) ||
5076d0d00e090b753250659b9a2d67dab7467257900Robert Sloan      !EVP_CipherFinal_ex(&ctx, ptr + n1, &n2) ||
508b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez      !CBB_did_write(&ciphertext, n1 + n2) ||
5096d0d00e090b753250659b9a2d67dab7467257900Robert Sloan      !CBB_flush(out)) {
510b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez    goto err;
511b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez  }
512b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez
5136d0d00e090b753250659b9a2d67dab7467257900Robert Sloan  ret = 1;
514d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
515d9e397b599b13d642138480a28c14db7a136bf0Adam Langleyerr:
5166d0d00e090b753250659b9a2d67dab7467257900Robert Sloan  if (plaintext != NULL) {
517b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez    OPENSSL_cleanse(plaintext, plaintext_len);
5186d0d00e090b753250659b9a2d67dab7467257900Robert Sloan    OPENSSL_free(plaintext);
519b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez  }
520b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez  OPENSSL_free(salt_buf);
521b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez  EVP_CIPHER_CTX_cleanup(&ctx);
522b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez  return ret;
523d9e397b599b13d642138480a28c14db7a136bf0Adam Langley}
524