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