1e1051a39Sopenharmony_ci/* 2e1051a39Sopenharmony_ci * Copyright 1999-2020 The OpenSSL Project Authors. All Rights Reserved. 3e1051a39Sopenharmony_ci * 4e1051a39Sopenharmony_ci * Licensed under the Apache License 2.0 (the "License"). You may not use 5e1051a39Sopenharmony_ci * this file except in compliance with the License. You can obtain a copy 6e1051a39Sopenharmony_ci * in the file LICENSE in the source distribution or at 7e1051a39Sopenharmony_ci * https://www.openssl.org/source/license.html 8e1051a39Sopenharmony_ci */ 9e1051a39Sopenharmony_ci 10e1051a39Sopenharmony_ci#include <stdio.h> 11e1051a39Sopenharmony_ci#include <stdlib.h> 12e1051a39Sopenharmony_ci#include <string.h> 13e1051a39Sopenharmony_ci#include <openssl/pem.h> 14e1051a39Sopenharmony_ci#include <openssl/err.h> 15e1051a39Sopenharmony_ci#include <openssl/pkcs12.h> 16e1051a39Sopenharmony_ci#include "p12_local.h" 17e1051a39Sopenharmony_ci 18e1051a39Sopenharmony_ci/* PKCS#12 password change routine */ 19e1051a39Sopenharmony_ci 20e1051a39Sopenharmony_cistatic int newpass_p12(PKCS12 *p12, const char *oldpass, const char *newpass); 21e1051a39Sopenharmony_cistatic int newpass_bags(STACK_OF(PKCS12_SAFEBAG) *bags, const char *oldpass, 22e1051a39Sopenharmony_ci const char *newpass); 23e1051a39Sopenharmony_cistatic int newpass_bag(PKCS12_SAFEBAG *bag, const char *oldpass, 24e1051a39Sopenharmony_ci const char *newpass); 25e1051a39Sopenharmony_cistatic int alg_get(const X509_ALGOR *alg, int *pnid, int *piter, 26e1051a39Sopenharmony_ci int *psaltlen); 27e1051a39Sopenharmony_ci 28e1051a39Sopenharmony_ci/* 29e1051a39Sopenharmony_ci * Change the password on a PKCS#12 structure. 30e1051a39Sopenharmony_ci */ 31e1051a39Sopenharmony_ci 32e1051a39Sopenharmony_ciint PKCS12_newpass(PKCS12 *p12, const char *oldpass, const char *newpass) 33e1051a39Sopenharmony_ci{ 34e1051a39Sopenharmony_ci /* Check for NULL PKCS12 structure */ 35e1051a39Sopenharmony_ci 36e1051a39Sopenharmony_ci if (p12 == NULL) { 37e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_PKCS12, PKCS12_R_INVALID_NULL_PKCS12_POINTER); 38e1051a39Sopenharmony_ci return 0; 39e1051a39Sopenharmony_ci } 40e1051a39Sopenharmony_ci 41e1051a39Sopenharmony_ci /* Check the mac */ 42e1051a39Sopenharmony_ci 43e1051a39Sopenharmony_ci if (!PKCS12_verify_mac(p12, oldpass, -1)) { 44e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_PKCS12, PKCS12_R_MAC_VERIFY_FAILURE); 45e1051a39Sopenharmony_ci return 0; 46e1051a39Sopenharmony_ci } 47e1051a39Sopenharmony_ci 48e1051a39Sopenharmony_ci if (!newpass_p12(p12, oldpass, newpass)) { 49e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_PKCS12, PKCS12_R_PARSE_ERROR); 50e1051a39Sopenharmony_ci return 0; 51e1051a39Sopenharmony_ci } 52e1051a39Sopenharmony_ci 53e1051a39Sopenharmony_ci return 1; 54e1051a39Sopenharmony_ci} 55e1051a39Sopenharmony_ci 56e1051a39Sopenharmony_ci/* Parse the outer PKCS#12 structure */ 57e1051a39Sopenharmony_ci 58e1051a39Sopenharmony_cistatic int newpass_p12(PKCS12 *p12, const char *oldpass, const char *newpass) 59e1051a39Sopenharmony_ci{ 60e1051a39Sopenharmony_ci STACK_OF(PKCS7) *asafes = NULL, *newsafes = NULL; 61e1051a39Sopenharmony_ci STACK_OF(PKCS12_SAFEBAG) *bags = NULL; 62e1051a39Sopenharmony_ci int i, bagnid, pbe_nid = 0, pbe_iter = 0, pbe_saltlen = 0; 63e1051a39Sopenharmony_ci PKCS7 *p7, *p7new; 64e1051a39Sopenharmony_ci ASN1_OCTET_STRING *p12_data_tmp = NULL, *macoct = NULL; 65e1051a39Sopenharmony_ci unsigned char mac[EVP_MAX_MD_SIZE]; 66e1051a39Sopenharmony_ci unsigned int maclen; 67e1051a39Sopenharmony_ci int rv = 0; 68e1051a39Sopenharmony_ci 69e1051a39Sopenharmony_ci if ((asafes = PKCS12_unpack_authsafes(p12)) == NULL) 70e1051a39Sopenharmony_ci goto err; 71e1051a39Sopenharmony_ci if ((newsafes = sk_PKCS7_new_null()) == NULL) 72e1051a39Sopenharmony_ci goto err; 73e1051a39Sopenharmony_ci for (i = 0; i < sk_PKCS7_num(asafes); i++) { 74e1051a39Sopenharmony_ci p7 = sk_PKCS7_value(asafes, i); 75e1051a39Sopenharmony_ci bagnid = OBJ_obj2nid(p7->type); 76e1051a39Sopenharmony_ci if (bagnid == NID_pkcs7_data) { 77e1051a39Sopenharmony_ci bags = PKCS12_unpack_p7data(p7); 78e1051a39Sopenharmony_ci } else if (bagnid == NID_pkcs7_encrypted) { 79e1051a39Sopenharmony_ci bags = PKCS12_unpack_p7encdata(p7, oldpass, -1); 80e1051a39Sopenharmony_ci if (p7->d.encrypted == NULL 81e1051a39Sopenharmony_ci || !alg_get(p7->d.encrypted->enc_data->algorithm, 82e1051a39Sopenharmony_ci &pbe_nid, &pbe_iter, &pbe_saltlen)) 83e1051a39Sopenharmony_ci goto err; 84e1051a39Sopenharmony_ci } else { 85e1051a39Sopenharmony_ci continue; 86e1051a39Sopenharmony_ci } 87e1051a39Sopenharmony_ci if (bags == NULL) 88e1051a39Sopenharmony_ci goto err; 89e1051a39Sopenharmony_ci if (!newpass_bags(bags, oldpass, newpass)) 90e1051a39Sopenharmony_ci goto err; 91e1051a39Sopenharmony_ci /* Repack bag in same form with new password */ 92e1051a39Sopenharmony_ci if (bagnid == NID_pkcs7_data) 93e1051a39Sopenharmony_ci p7new = PKCS12_pack_p7data(bags); 94e1051a39Sopenharmony_ci else 95e1051a39Sopenharmony_ci p7new = PKCS12_pack_p7encdata(pbe_nid, newpass, -1, NULL, 96e1051a39Sopenharmony_ci pbe_saltlen, pbe_iter, bags); 97e1051a39Sopenharmony_ci if (p7new == NULL || !sk_PKCS7_push(newsafes, p7new)) 98e1051a39Sopenharmony_ci goto err; 99e1051a39Sopenharmony_ci sk_PKCS12_SAFEBAG_pop_free(bags, PKCS12_SAFEBAG_free); 100e1051a39Sopenharmony_ci bags = NULL; 101e1051a39Sopenharmony_ci } 102e1051a39Sopenharmony_ci 103e1051a39Sopenharmony_ci /* Repack safe: save old safe in case of error */ 104e1051a39Sopenharmony_ci 105e1051a39Sopenharmony_ci p12_data_tmp = p12->authsafes->d.data; 106e1051a39Sopenharmony_ci if ((p12->authsafes->d.data = ASN1_OCTET_STRING_new()) == NULL) 107e1051a39Sopenharmony_ci goto err; 108e1051a39Sopenharmony_ci if (!PKCS12_pack_authsafes(p12, newsafes)) 109e1051a39Sopenharmony_ci goto err; 110e1051a39Sopenharmony_ci 111e1051a39Sopenharmony_ci if (!PKCS12_gen_mac(p12, newpass, -1, mac, &maclen)) 112e1051a39Sopenharmony_ci goto err; 113e1051a39Sopenharmony_ci X509_SIG_getm(p12->mac->dinfo, NULL, &macoct); 114e1051a39Sopenharmony_ci if (!ASN1_OCTET_STRING_set(macoct, mac, maclen)) 115e1051a39Sopenharmony_ci goto err; 116e1051a39Sopenharmony_ci 117e1051a39Sopenharmony_ci rv = 1; 118e1051a39Sopenharmony_ci 119e1051a39Sopenharmony_cierr: 120e1051a39Sopenharmony_ci /* Restore old safe if necessary */ 121e1051a39Sopenharmony_ci if (rv == 1) { 122e1051a39Sopenharmony_ci ASN1_OCTET_STRING_free(p12_data_tmp); 123e1051a39Sopenharmony_ci } else if (p12_data_tmp != NULL) { 124e1051a39Sopenharmony_ci ASN1_OCTET_STRING_free(p12->authsafes->d.data); 125e1051a39Sopenharmony_ci p12->authsafes->d.data = p12_data_tmp; 126e1051a39Sopenharmony_ci } 127e1051a39Sopenharmony_ci sk_PKCS12_SAFEBAG_pop_free(bags, PKCS12_SAFEBAG_free); 128e1051a39Sopenharmony_ci sk_PKCS7_pop_free(asafes, PKCS7_free); 129e1051a39Sopenharmony_ci sk_PKCS7_pop_free(newsafes, PKCS7_free); 130e1051a39Sopenharmony_ci return rv; 131e1051a39Sopenharmony_ci} 132e1051a39Sopenharmony_ci 133e1051a39Sopenharmony_cistatic int newpass_bags(STACK_OF(PKCS12_SAFEBAG) *bags, const char *oldpass, 134e1051a39Sopenharmony_ci const char *newpass) 135e1051a39Sopenharmony_ci{ 136e1051a39Sopenharmony_ci int i; 137e1051a39Sopenharmony_ci for (i = 0; i < sk_PKCS12_SAFEBAG_num(bags); i++) { 138e1051a39Sopenharmony_ci if (!newpass_bag(sk_PKCS12_SAFEBAG_value(bags, i), oldpass, newpass)) 139e1051a39Sopenharmony_ci return 0; 140e1051a39Sopenharmony_ci } 141e1051a39Sopenharmony_ci return 1; 142e1051a39Sopenharmony_ci} 143e1051a39Sopenharmony_ci 144e1051a39Sopenharmony_ci/* Change password of safebag: only needs handle shrouded keybags */ 145e1051a39Sopenharmony_ci 146e1051a39Sopenharmony_cistatic int newpass_bag(PKCS12_SAFEBAG *bag, const char *oldpass, 147e1051a39Sopenharmony_ci const char *newpass) 148e1051a39Sopenharmony_ci{ 149e1051a39Sopenharmony_ci PKCS8_PRIV_KEY_INFO *p8; 150e1051a39Sopenharmony_ci X509_SIG *p8new; 151e1051a39Sopenharmony_ci int p8_nid, p8_saltlen, p8_iter; 152e1051a39Sopenharmony_ci const X509_ALGOR *shalg; 153e1051a39Sopenharmony_ci 154e1051a39Sopenharmony_ci if (PKCS12_SAFEBAG_get_nid(bag) != NID_pkcs8ShroudedKeyBag) 155e1051a39Sopenharmony_ci return 1; 156e1051a39Sopenharmony_ci 157e1051a39Sopenharmony_ci if ((p8 = PKCS8_decrypt(bag->value.shkeybag, oldpass, -1)) == NULL) 158e1051a39Sopenharmony_ci return 0; 159e1051a39Sopenharmony_ci X509_SIG_get0(bag->value.shkeybag, &shalg, NULL); 160e1051a39Sopenharmony_ci if (!alg_get(shalg, &p8_nid, &p8_iter, &p8_saltlen)) { 161e1051a39Sopenharmony_ci PKCS8_PRIV_KEY_INFO_free(p8); 162e1051a39Sopenharmony_ci return 0; 163e1051a39Sopenharmony_ci } 164e1051a39Sopenharmony_ci p8new = PKCS8_encrypt(p8_nid, NULL, newpass, -1, NULL, p8_saltlen, 165e1051a39Sopenharmony_ci p8_iter, p8); 166e1051a39Sopenharmony_ci PKCS8_PRIV_KEY_INFO_free(p8); 167e1051a39Sopenharmony_ci if (p8new == NULL) 168e1051a39Sopenharmony_ci return 0; 169e1051a39Sopenharmony_ci X509_SIG_free(bag->value.shkeybag); 170e1051a39Sopenharmony_ci bag->value.shkeybag = p8new; 171e1051a39Sopenharmony_ci return 1; 172e1051a39Sopenharmony_ci} 173e1051a39Sopenharmony_ci 174e1051a39Sopenharmony_cistatic int alg_get(const X509_ALGOR *alg, int *pnid, int *piter, 175e1051a39Sopenharmony_ci int *psaltlen) 176e1051a39Sopenharmony_ci{ 177e1051a39Sopenharmony_ci PBEPARAM *pbe; 178e1051a39Sopenharmony_ci 179e1051a39Sopenharmony_ci pbe = ASN1_TYPE_unpack_sequence(ASN1_ITEM_rptr(PBEPARAM), alg->parameter); 180e1051a39Sopenharmony_ci if (pbe == NULL) 181e1051a39Sopenharmony_ci return 0; 182e1051a39Sopenharmony_ci *pnid = OBJ_obj2nid(alg->algorithm); 183e1051a39Sopenharmony_ci *piter = ASN1_INTEGER_get(pbe->iter); 184e1051a39Sopenharmony_ci *psaltlen = pbe->salt->length; 185e1051a39Sopenharmony_ci PBEPARAM_free(pbe); 186e1051a39Sopenharmony_ci return 1; 187e1051a39Sopenharmony_ci} 188