p12_npas.c revision 296465
1/* p12_npas.c */ 2/* 3 * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL project 4 * 1999. 5 */ 6/* ==================================================================== 7 * Copyright (c) 1999 The OpenSSL Project. All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in 18 * the documentation and/or other materials provided with the 19 * distribution. 20 * 21 * 3. All advertising materials mentioning features or use of this 22 * software must display the following acknowledgment: 23 * "This product includes software developed by the OpenSSL Project 24 * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" 25 * 26 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to 27 * endorse or promote products derived from this software without 28 * prior written permission. For written permission, please contact 29 * licensing@OpenSSL.org. 30 * 31 * 5. Products derived from this software may not be called "OpenSSL" 32 * nor may "OpenSSL" appear in their names without prior written 33 * permission of the OpenSSL Project. 34 * 35 * 6. Redistributions of any form whatsoever must retain the following 36 * acknowledgment: 37 * "This product includes software developed by the OpenSSL Project 38 * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" 39 * 40 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY 41 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 42 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 43 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR 44 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 45 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 46 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 47 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 48 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 49 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 50 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 51 * OF THE POSSIBILITY OF SUCH DAMAGE. 52 * ==================================================================== 53 * 54 * This product includes cryptographic software written by Eric Young 55 * (eay@cryptsoft.com). This product includes software written by Tim 56 * Hudson (tjh@cryptsoft.com). 57 * 58 */ 59 60#include <stdio.h> 61#include <stdlib.h> 62#include <string.h> 63#include <openssl/pem.h> 64#include <openssl/err.h> 65#include <openssl/pkcs12.h> 66 67/* PKCS#12 password change routine */ 68 69static int newpass_p12(PKCS12 *p12, char *oldpass, char *newpass); 70static int newpass_bags(STACK_OF(PKCS12_SAFEBAG) *bags, char *oldpass, 71 char *newpass); 72static int newpass_bag(PKCS12_SAFEBAG *bag, char *oldpass, char *newpass); 73static int alg_get(X509_ALGOR *alg, int *pnid, int *piter, int *psaltlen); 74 75/* 76 * Change the password on a PKCS#12 structure. 77 */ 78 79int PKCS12_newpass(PKCS12 *p12, char *oldpass, char *newpass) 80{ 81 /* Check for NULL PKCS12 structure */ 82 83 if (!p12) { 84 PKCS12err(PKCS12_F_PKCS12_NEWPASS, 85 PKCS12_R_INVALID_NULL_PKCS12_POINTER); 86 return 0; 87 } 88 89 /* Check the mac */ 90 91 if (!PKCS12_verify_mac(p12, oldpass, -1)) { 92 PKCS12err(PKCS12_F_PKCS12_NEWPASS, PKCS12_R_MAC_VERIFY_FAILURE); 93 return 0; 94 } 95 96 if (!newpass_p12(p12, oldpass, newpass)) { 97 PKCS12err(PKCS12_F_PKCS12_NEWPASS, PKCS12_R_PARSE_ERROR); 98 return 0; 99 } 100 101 return 1; 102} 103 104/* Parse the outer PKCS#12 structure */ 105 106static int newpass_p12(PKCS12 *p12, char *oldpass, char *newpass) 107{ 108 STACK_OF(PKCS7) *asafes, *newsafes; 109 STACK_OF(PKCS12_SAFEBAG) *bags; 110 int i, bagnid, pbe_nid = 0, pbe_iter = 0, pbe_saltlen = 0; 111 PKCS7 *p7, *p7new; 112 ASN1_OCTET_STRING *p12_data_tmp = NULL, *macnew = NULL; 113 unsigned char mac[EVP_MAX_MD_SIZE]; 114 unsigned int maclen; 115 116 if (!(asafes = PKCS12_unpack_authsafes(p12))) 117 return 0; 118 if (!(newsafes = sk_PKCS7_new_null())) 119 return 0; 120 for (i = 0; i < sk_PKCS7_num(asafes); i++) { 121 p7 = sk_PKCS7_value(asafes, i); 122 bagnid = OBJ_obj2nid(p7->type); 123 if (bagnid == NID_pkcs7_data) { 124 bags = PKCS12_unpack_p7data(p7); 125 } else if (bagnid == NID_pkcs7_encrypted) { 126 bags = PKCS12_unpack_p7encdata(p7, oldpass, -1); 127 if (!alg_get(p7->d.encrypted->enc_data->algorithm, 128 &pbe_nid, &pbe_iter, &pbe_saltlen)) { 129 sk_PKCS12_SAFEBAG_pop_free(bags, PKCS12_SAFEBAG_free); 130 bags = NULL; 131 } 132 } else 133 continue; 134 if (!bags) { 135 sk_PKCS7_pop_free(asafes, PKCS7_free); 136 return 0; 137 } 138 if (!newpass_bags(bags, oldpass, newpass)) { 139 sk_PKCS12_SAFEBAG_pop_free(bags, PKCS12_SAFEBAG_free); 140 sk_PKCS7_pop_free(asafes, PKCS7_free); 141 return 0; 142 } 143 /* Repack bag in same form with new password */ 144 if (bagnid == NID_pkcs7_data) 145 p7new = PKCS12_pack_p7data(bags); 146 else 147 p7new = PKCS12_pack_p7encdata(pbe_nid, newpass, -1, NULL, 148 pbe_saltlen, pbe_iter, bags); 149 sk_PKCS12_SAFEBAG_pop_free(bags, PKCS12_SAFEBAG_free); 150 if (!p7new) { 151 sk_PKCS7_pop_free(asafes, PKCS7_free); 152 return 0; 153 } 154 sk_PKCS7_push(newsafes, p7new); 155 } 156 sk_PKCS7_pop_free(asafes, PKCS7_free); 157 158 /* Repack safe: save old safe in case of error */ 159 160 p12_data_tmp = p12->authsafes->d.data; 161 if (!(p12->authsafes->d.data = ASN1_OCTET_STRING_new())) 162 goto saferr; 163 if (!PKCS12_pack_authsafes(p12, newsafes)) 164 goto saferr; 165 166 if (!PKCS12_gen_mac(p12, newpass, -1, mac, &maclen)) 167 goto saferr; 168 if (!(macnew = ASN1_OCTET_STRING_new())) 169 goto saferr; 170 if (!ASN1_OCTET_STRING_set(macnew, mac, maclen)) 171 goto saferr; 172 ASN1_OCTET_STRING_free(p12->mac->dinfo->digest); 173 p12->mac->dinfo->digest = macnew; 174 ASN1_OCTET_STRING_free(p12_data_tmp); 175 176 return 1; 177 178 saferr: 179 /* Restore old safe */ 180 ASN1_OCTET_STRING_free(p12->authsafes->d.data); 181 ASN1_OCTET_STRING_free(macnew); 182 p12->authsafes->d.data = p12_data_tmp; 183 return 0; 184 185} 186 187static int newpass_bags(STACK_OF(PKCS12_SAFEBAG) *bags, char *oldpass, 188 char *newpass) 189{ 190 int i; 191 for (i = 0; i < sk_PKCS12_SAFEBAG_num(bags); i++) { 192 if (!newpass_bag(sk_PKCS12_SAFEBAG_value(bags, i), oldpass, newpass)) 193 return 0; 194 } 195 return 1; 196} 197 198/* Change password of safebag: only needs handle shrouded keybags */ 199 200static int newpass_bag(PKCS12_SAFEBAG *bag, char *oldpass, char *newpass) 201{ 202 PKCS8_PRIV_KEY_INFO *p8; 203 X509_SIG *p8new; 204 int p8_nid, p8_saltlen, p8_iter; 205 206 if (M_PKCS12_bag_type(bag) != NID_pkcs8ShroudedKeyBag) 207 return 1; 208 209 if (!(p8 = PKCS8_decrypt(bag->value.shkeybag, oldpass, -1))) 210 return 0; 211 if (!alg_get(bag->value.shkeybag->algor, &p8_nid, &p8_iter, &p8_saltlen)) 212 return 0; 213 if (!(p8new = PKCS8_encrypt(p8_nid, NULL, newpass, -1, NULL, p8_saltlen, 214 p8_iter, p8))) 215 return 0; 216 X509_SIG_free(bag->value.shkeybag); 217 bag->value.shkeybag = p8new; 218 return 1; 219} 220 221static int alg_get(X509_ALGOR *alg, int *pnid, int *piter, int *psaltlen) 222{ 223 PBEPARAM *pbe; 224 const unsigned char *p; 225 226 p = alg->parameter->value.sequence->data; 227 pbe = d2i_PBEPARAM(NULL, &p, alg->parameter->value.sequence->length); 228 if (!pbe) 229 return 0; 230 *pnid = OBJ_obj2nid(alg->algorithm); 231 *piter = ASN1_INTEGER_get(pbe->iter); 232 *psaltlen = pbe->salt->length; 233 PBEPARAM_free(pbe); 234 return 1; 235} 236