| /* | 
 |  * Copyright 1999-2016 The OpenSSL Project Authors. All Rights Reserved. | 
 |  * | 
 |  * Licensed under the OpenSSL license (the "License").  You may not use | 
 |  * this file except in compliance with the License.  You can obtain a copy | 
 |  * in the file LICENSE in the source distribution or at | 
 |  * https://www.openssl.org/source/license.html | 
 |  */ | 
 |  | 
 | #include <stdio.h> | 
 | #include "internal/cryptlib.h" | 
 | #include <openssl/pkcs12.h> | 
 |  | 
 | /* Define this to dump decrypted output to files called DERnnn */ | 
 | /* | 
 |  * #define OPENSSL_DEBUG_DECRYPT | 
 |  */ | 
 |  | 
 | /* | 
 |  * Encrypt/Decrypt a buffer based on password and algor, result in a | 
 |  * OPENSSL_malloc'ed buffer | 
 |  */ | 
 | unsigned char *PKCS12_pbe_crypt(const X509_ALGOR *algor, | 
 |                                 const char *pass, int passlen, | 
 |                                 const unsigned char *in, int inlen, | 
 |                                 unsigned char **data, int *datalen, int en_de) | 
 | { | 
 |     unsigned char *out = NULL; | 
 |     int outlen, i; | 
 |     EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); | 
 |  | 
 |     if (ctx == NULL) { | 
 |         PKCS12err(PKCS12_F_PKCS12_PBE_CRYPT, ERR_R_MALLOC_FAILURE); | 
 |         goto err; | 
 |     } | 
 |  | 
 |     /* Decrypt data */ | 
 |     if (!EVP_PBE_CipherInit(algor->algorithm, pass, passlen, | 
 |                             algor->parameter, ctx, en_de)) { | 
 |         PKCS12err(PKCS12_F_PKCS12_PBE_CRYPT, | 
 |                   PKCS12_R_PKCS12_ALGOR_CIPHERINIT_ERROR); | 
 |         goto err; | 
 |     } | 
 |  | 
 |     if ((out = OPENSSL_malloc(inlen + EVP_CIPHER_CTX_block_size(ctx))) | 
 |             == NULL) { | 
 |         PKCS12err(PKCS12_F_PKCS12_PBE_CRYPT, ERR_R_MALLOC_FAILURE); | 
 |         goto err; | 
 |     } | 
 |  | 
 |     if (!EVP_CipherUpdate(ctx, out, &i, in, inlen)) { | 
 |         OPENSSL_free(out); | 
 |         out = NULL; | 
 |         PKCS12err(PKCS12_F_PKCS12_PBE_CRYPT, ERR_R_EVP_LIB); | 
 |         goto err; | 
 |     } | 
 |  | 
 |     outlen = i; | 
 |     if (!EVP_CipherFinal_ex(ctx, out + i, &i)) { | 
 |         OPENSSL_free(out); | 
 |         out = NULL; | 
 |         PKCS12err(PKCS12_F_PKCS12_PBE_CRYPT, | 
 |                   PKCS12_R_PKCS12_CIPHERFINAL_ERROR); | 
 |         goto err; | 
 |     } | 
 |     outlen += i; | 
 |     if (datalen) | 
 |         *datalen = outlen; | 
 |     if (data) | 
 |         *data = out; | 
 |  err: | 
 |     EVP_CIPHER_CTX_free(ctx); | 
 |     return out; | 
 |  | 
 | } | 
 |  | 
 | /* | 
 |  * Decrypt an OCTET STRING and decode ASN1 structure if zbuf set zero buffer | 
 |  * after use. | 
 |  */ | 
 |  | 
 | void *PKCS12_item_decrypt_d2i(const X509_ALGOR *algor, const ASN1_ITEM *it, | 
 |                               const char *pass, int passlen, | 
 |                               const ASN1_OCTET_STRING *oct, int zbuf) | 
 | { | 
 |     unsigned char *out; | 
 |     const unsigned char *p; | 
 |     void *ret; | 
 |     int outlen; | 
 |  | 
 |     if (!PKCS12_pbe_crypt(algor, pass, passlen, oct->data, oct->length, | 
 |                           &out, &outlen, 0)) { | 
 |         PKCS12err(PKCS12_F_PKCS12_ITEM_DECRYPT_D2I, | 
 |                   PKCS12_R_PKCS12_PBE_CRYPT_ERROR); | 
 |         return NULL; | 
 |     } | 
 |     p = out; | 
 | #ifdef OPENSSL_DEBUG_DECRYPT | 
 |     { | 
 |         FILE *op; | 
 |  | 
 |         char fname[30]; | 
 |         static int fnm = 1; | 
 |         sprintf(fname, "DER%d", fnm++); | 
 |         op = fopen(fname, "wb"); | 
 |         fwrite(p, 1, outlen, op); | 
 |         fclose(op); | 
 |     } | 
 | #endif | 
 |     ret = ASN1_item_d2i(NULL, &p, outlen, it); | 
 |     if (zbuf) | 
 |         OPENSSL_cleanse(out, outlen); | 
 |     if (!ret) | 
 |         PKCS12err(PKCS12_F_PKCS12_ITEM_DECRYPT_D2I, PKCS12_R_DECODE_ERROR); | 
 |     OPENSSL_free(out); | 
 |     return ret; | 
 | } | 
 |  | 
 | /* | 
 |  * Encode ASN1 structure and encrypt, return OCTET STRING if zbuf set zero | 
 |  * encoding. | 
 |  */ | 
 |  | 
 | ASN1_OCTET_STRING *PKCS12_item_i2d_encrypt(X509_ALGOR *algor, | 
 |                                            const ASN1_ITEM *it, | 
 |                                            const char *pass, int passlen, | 
 |                                            void *obj, int zbuf) | 
 | { | 
 |     ASN1_OCTET_STRING *oct = NULL; | 
 |     unsigned char *in = NULL; | 
 |     int inlen; | 
 |  | 
 |     if ((oct = ASN1_OCTET_STRING_new()) == NULL) { | 
 |         PKCS12err(PKCS12_F_PKCS12_ITEM_I2D_ENCRYPT, ERR_R_MALLOC_FAILURE); | 
 |         goto err; | 
 |     } | 
 |     inlen = ASN1_item_i2d(obj, &in, it); | 
 |     if (!in) { | 
 |         PKCS12err(PKCS12_F_PKCS12_ITEM_I2D_ENCRYPT, PKCS12_R_ENCODE_ERROR); | 
 |         goto err; | 
 |     } | 
 |     if (!PKCS12_pbe_crypt(algor, pass, passlen, in, inlen, &oct->data, | 
 |                           &oct->length, 1)) { | 
 |         PKCS12err(PKCS12_F_PKCS12_ITEM_I2D_ENCRYPT, PKCS12_R_ENCRYPT_ERROR); | 
 |         OPENSSL_free(in); | 
 |         goto err; | 
 |     } | 
 |     if (zbuf) | 
 |         OPENSSL_cleanse(in, inlen); | 
 |     OPENSSL_free(in); | 
 |     return oct; | 
 |  err: | 
 |     ASN1_OCTET_STRING_free(oct); | 
 |     return NULL; | 
 | } |