1 /* $OpenBSD: p12_npas.c,v 1.27 2024/01/25 15:33:35 tb Exp $ */ 2 /* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL 3 * project 1999. 4 */ 5 /* ==================================================================== 6 * Copyright (c) 1999 The OpenSSL Project. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in 17 * the documentation and/or other materials provided with the 18 * distribution. 19 * 20 * 3. All advertising materials mentioning features or use of this 21 * software must display the following acknowledgment: 22 * "This product includes software developed by the OpenSSL Project 23 * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" 24 * 25 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to 26 * endorse or promote products derived from this software without 27 * prior written permission. For written permission, please contact 28 * licensing@OpenSSL.org. 29 * 30 * 5. Products derived from this software may not be called "OpenSSL" 31 * nor may "OpenSSL" appear in their names without prior written 32 * permission of the OpenSSL Project. 33 * 34 * 6. Redistributions of any form whatsoever must retain the following 35 * acknowledgment: 36 * "This product includes software developed by the OpenSSL Project 37 * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" 38 * 39 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY 40 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 41 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 42 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR 43 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 44 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 45 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 46 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 47 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 48 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 49 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 50 * OF THE POSSIBILITY OF SUCH DAMAGE. 51 * ==================================================================== 52 * 53 * This product includes cryptographic software written by Eric Young 54 * (eay@cryptsoft.com). This product includes software written by Tim 55 * Hudson (tjh@cryptsoft.com). 56 * 57 */ 58 59 #include <stdio.h> 60 #include <stdlib.h> 61 #include <string.h> 62 #include <openssl/pem.h> 63 #include <openssl/err.h> 64 #include <openssl/pkcs12.h> 65 66 #include "pkcs12_local.h" 67 #include "x509_local.h" 68 69 /* PKCS#12 password change routine */ 70 71 static int 72 alg_get(X509_ALGOR *alg, int *nid, int *iter, int *salt_len) 73 { 74 const ASN1_OBJECT *aobj; 75 int param_type; 76 const void *param; 77 PBEPARAM *pbe = NULL; 78 int ret = 0; 79 80 *nid = *iter = *salt_len = 0; 81 82 X509_ALGOR_get0(&aobj, ¶m_type, ¶m, alg); 83 if (param_type != V_ASN1_SEQUENCE) 84 goto err; 85 if ((pbe = ASN1_item_unpack(param, &PBEPARAM_it)) == NULL) 86 goto err; 87 88 /* XXX - can we validate these somehow? */ 89 *nid = OBJ_obj2nid(alg->algorithm); 90 *iter = ASN1_INTEGER_get(pbe->iter); 91 *salt_len = pbe->salt->length; 92 93 ret = 1; 94 95 err: 96 PBEPARAM_free(pbe); 97 98 return ret; 99 } 100 101 /* Change password of safebag: only needs handle shrouded keybags */ 102 static int 103 newpass_bag(PKCS12_SAFEBAG *bag, const char *oldpass, const char *newpass) 104 { 105 PKCS8_PRIV_KEY_INFO *p8 = NULL; 106 X509_SIG *keybag; 107 int nid, salt_len, iter; 108 int ret = 0; 109 110 if (OBJ_obj2nid(bag->type) != NID_pkcs8ShroudedKeyBag) 111 goto done; 112 113 if ((p8 = PKCS8_decrypt(bag->value.shkeybag, oldpass, -1)) == NULL) 114 goto err; 115 if (!alg_get(bag->value.shkeybag->algor, &nid, &iter, &salt_len)) 116 goto err; 117 118 if ((keybag = PKCS8_encrypt(nid, NULL, newpass, -1, NULL, salt_len, 119 iter, p8)) == NULL) 120 goto err; 121 122 X509_SIG_free(bag->value.shkeybag); 123 bag->value.shkeybag = keybag; 124 125 done: 126 ret = 1; 127 128 err: 129 PKCS8_PRIV_KEY_INFO_free(p8); 130 131 return ret; 132 } 133 134 static int 135 newpass_bags(STACK_OF(PKCS12_SAFEBAG) *bags, const char *oldpass, 136 const char *newpass) 137 { 138 int i; 139 140 for (i = 0; i < sk_PKCS12_SAFEBAG_num(bags); i++) { 141 PKCS12_SAFEBAG *bag = sk_PKCS12_SAFEBAG_value(bags, i); 142 143 if (!newpass_bag(bag, oldpass, newpass)) 144 return 0; 145 } 146 147 return 1; 148 } 149 150 static int 151 pkcs7_repack_data(PKCS7 *pkcs7, STACK_OF(PKCS7) *safes, const char *oldpass, 152 const char *newpass) 153 { 154 STACK_OF(PKCS12_SAFEBAG) *bags; 155 PKCS7 *data = NULL; 156 int ret = 0; 157 158 if ((bags = PKCS12_unpack_p7data(pkcs7)) == NULL) 159 goto err; 160 if (!newpass_bags(bags, oldpass, newpass)) 161 goto err; 162 if ((data = PKCS12_pack_p7data(bags)) == NULL) 163 goto err; 164 if (sk_PKCS7_push(safes, data) == 0) 165 goto err; 166 data = NULL; 167 168 ret = 1; 169 170 err: 171 sk_PKCS12_SAFEBAG_pop_free(bags, PKCS12_SAFEBAG_free); 172 PKCS7_free(data); 173 174 return ret; 175 } 176 177 static int 178 pkcs7_repack_encdata(PKCS7 *pkcs7, STACK_OF(PKCS7) *safes, const char *oldpass, 179 const char *newpass) 180 { 181 STACK_OF(PKCS12_SAFEBAG) *bags; 182 int nid, iter, salt_len; 183 PKCS7 *data = NULL; 184 int ret = 0; 185 186 if ((bags = PKCS12_unpack_p7encdata(pkcs7, oldpass, -1)) == NULL) 187 goto err; 188 if (!alg_get(pkcs7->d.encrypted->enc_data->algorithm, &nid, 189 &iter, &salt_len)) 190 goto err; 191 if (!newpass_bags(bags, oldpass, newpass)) 192 goto err; 193 if ((data = PKCS12_pack_p7encdata(nid, newpass, -1, NULL, salt_len, 194 iter, bags)) == NULL) 195 goto err; 196 if (!sk_PKCS7_push(safes, data)) 197 goto err; 198 data = NULL; 199 200 ret = 1; 201 202 err: 203 sk_PKCS12_SAFEBAG_pop_free(bags, PKCS12_SAFEBAG_free); 204 PKCS7_free(data); 205 206 return ret; 207 } 208 209 static int 210 pkcs12_repack_authsafes(PKCS12 *pkcs12, STACK_OF(PKCS7) *safes, 211 const char *newpass) 212 { 213 ASN1_OCTET_STRING *old_data; 214 ASN1_OCTET_STRING *new_mac = NULL; 215 unsigned char mac[EVP_MAX_MD_SIZE]; 216 unsigned int mac_len; 217 int ret = 0; 218 219 if ((old_data = pkcs12->authsafes->d.data) == NULL) 220 goto err; 221 if ((pkcs12->authsafes->d.data = ASN1_OCTET_STRING_new()) == NULL) 222 goto err; 223 if (!PKCS12_pack_authsafes(pkcs12, safes)) 224 goto err; 225 if (!PKCS12_gen_mac(pkcs12, newpass, -1, mac, &mac_len)) 226 goto err; 227 if ((new_mac = ASN1_OCTET_STRING_new()) == NULL) 228 goto err; 229 if (!ASN1_OCTET_STRING_set(new_mac, mac, mac_len)) 230 goto err; 231 232 ASN1_OCTET_STRING_free(pkcs12->mac->dinfo->digest); 233 pkcs12->mac->dinfo->digest = new_mac; 234 new_mac = NULL; 235 236 ASN1_OCTET_STRING_free(old_data); 237 old_data = NULL; 238 239 ret = 1; 240 241 err: 242 if (old_data != NULL) { 243 ASN1_OCTET_STRING_free(pkcs12->authsafes->d.data); 244 pkcs12->authsafes->d.data = old_data; 245 } 246 explicit_bzero(mac, sizeof(mac)); 247 ASN1_OCTET_STRING_free(new_mac); 248 249 return ret; 250 } 251 252 int 253 PKCS12_newpass(PKCS12 *pkcs12, const char *oldpass, const char *newpass) 254 { 255 STACK_OF(PKCS7) *authsafes = NULL, *safes = NULL; 256 int i; 257 int ret = 0; 258 259 if (pkcs12 == NULL) { 260 PKCS12error(PKCS12_R_INVALID_NULL_PKCS12_POINTER); 261 goto err; 262 } 263 264 if (!PKCS12_verify_mac(pkcs12, oldpass, -1)) { 265 PKCS12error(PKCS12_R_MAC_VERIFY_FAILURE); 266 goto err; 267 } 268 269 if ((authsafes = PKCS12_unpack_authsafes(pkcs12)) == NULL) 270 goto err; 271 if ((safes = sk_PKCS7_new_null()) == NULL) 272 goto err; 273 274 for (i = 0; i < sk_PKCS7_num(authsafes); i++) { 275 PKCS7 *pkcs7 = sk_PKCS7_value(authsafes, i); 276 277 switch (OBJ_obj2nid(pkcs7->type)) { 278 case NID_pkcs7_data: 279 if (pkcs7_repack_data(pkcs7, safes, oldpass, newpass)) 280 goto err; 281 break; 282 case NID_pkcs7_encrypted: 283 if (pkcs7_repack_encdata(pkcs7, safes, oldpass, newpass)) 284 goto err; 285 break; 286 } 287 } 288 289 if (!pkcs12_repack_authsafes(pkcs12, safes, newpass)) 290 goto err; 291 292 ret = 1; 293 294 err: 295 sk_PKCS7_pop_free(authsafes, PKCS7_free); 296 sk_PKCS7_pop_free(safes, PKCS7_free); 297 298 return ret; 299 } 300 LCRYPTO_ALIAS(PKCS12_newpass); 301