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, ¶m, CBS_ASN1_SEQUENCE) || 342b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez !CBB_add_asn1(¶m, &salt_cbb, CBS_ASN1_OCTETSTRING) || 343b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez !CBB_add_bytes(&salt_cbb, salt, salt_len) || 344b0b45c63bbbf16b7f5ff3cbe3f1d0905108038aaSteven Valdez !CBB_add_asn1_uint64(¶m, 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