159191Skris/* p12_npas.c */
2280297Sjkim/*
3280297Sjkim * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL project
4280297Sjkim * 1999.
559191Skris */
659191Skris/* ====================================================================
759191Skris * Copyright (c) 1999 The OpenSSL Project.  All rights reserved.
859191Skris *
959191Skris * Redistribution and use in source and binary forms, with or without
1059191Skris * modification, are permitted provided that the following conditions
1159191Skris * are met:
1259191Skris *
1359191Skris * 1. Redistributions of source code must retain the above copyright
14280297Sjkim *    notice, this list of conditions and the following disclaimer.
1559191Skris *
1659191Skris * 2. Redistributions in binary form must reproduce the above copyright
1759191Skris *    notice, this list of conditions and the following disclaimer in
1859191Skris *    the documentation and/or other materials provided with the
1959191Skris *    distribution.
2059191Skris *
2159191Skris * 3. All advertising materials mentioning features or use of this
2259191Skris *    software must display the following acknowledgment:
2359191Skris *    "This product includes software developed by the OpenSSL Project
2459191Skris *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
2559191Skris *
2659191Skris * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
2759191Skris *    endorse or promote products derived from this software without
2859191Skris *    prior written permission. For written permission, please contact
2959191Skris *    licensing@OpenSSL.org.
3059191Skris *
3159191Skris * 5. Products derived from this software may not be called "OpenSSL"
3259191Skris *    nor may "OpenSSL" appear in their names without prior written
3359191Skris *    permission of the OpenSSL Project.
3459191Skris *
3559191Skris * 6. Redistributions of any form whatsoever must retain the following
3659191Skris *    acknowledgment:
3759191Skris *    "This product includes software developed by the OpenSSL Project
3859191Skris *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
3959191Skris *
4059191Skris * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
4159191Skris * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
4259191Skris * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
4359191Skris * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
4459191Skris * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
4559191Skris * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
4659191Skris * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
4759191Skris * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
4859191Skris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
4959191Skris * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
5059191Skris * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
5159191Skris * OF THE POSSIBILITY OF SUCH DAMAGE.
5259191Skris * ====================================================================
5359191Skris *
5459191Skris * This product includes cryptographic software written by Eric Young
5559191Skris * (eay@cryptsoft.com).  This product includes software written by Tim
5659191Skris * Hudson (tjh@cryptsoft.com).
5759191Skris *
5859191Skris */
5959191Skris
6059191Skris#include <stdio.h>
6159191Skris#include <stdlib.h>
6259191Skris#include <string.h>
6359191Skris#include <openssl/pem.h>
6459191Skris#include <openssl/err.h>
6559191Skris#include <openssl/pkcs12.h>
6659191Skris
6759191Skris/* PKCS#12 password change routine */
6859191Skris
69306198Sjkimstatic int newpass_p12(PKCS12 *p12, const char *oldpass, const char *newpass);
70306198Sjkimstatic int newpass_bags(STACK_OF(PKCS12_SAFEBAG) *bags, const char *oldpass,
71306198Sjkim                        const char *newpass);
72306198Sjkimstatic int newpass_bag(PKCS12_SAFEBAG *bag, const char *oldpass,
73306198Sjkim                        const char *newpass);
7459191Skrisstatic int alg_get(X509_ALGOR *alg, int *pnid, int *piter, int *psaltlen);
7559191Skris
76280297Sjkim/*
7759191Skris * Change the password on a PKCS#12 structure.
7859191Skris */
7959191Skris
80306198Sjkimint PKCS12_newpass(PKCS12 *p12, const char *oldpass, const char *newpass)
8159191Skris{
82280297Sjkim    /* Check for NULL PKCS12 structure */
8359191Skris
84280297Sjkim    if (!p12) {
85280297Sjkim        PKCS12err(PKCS12_F_PKCS12_NEWPASS,
86280297Sjkim                  PKCS12_R_INVALID_NULL_PKCS12_POINTER);
87280297Sjkim        return 0;
88280297Sjkim    }
8959191Skris
90280297Sjkim    /* Check the mac */
9159191Skris
92280297Sjkim    if (!PKCS12_verify_mac(p12, oldpass, -1)) {
93280297Sjkim        PKCS12err(PKCS12_F_PKCS12_NEWPASS, PKCS12_R_MAC_VERIFY_FAILURE);
94280297Sjkim        return 0;
95280297Sjkim    }
9659191Skris
97280297Sjkim    if (!newpass_p12(p12, oldpass, newpass)) {
98280297Sjkim        PKCS12err(PKCS12_F_PKCS12_NEWPASS, PKCS12_R_PARSE_ERROR);
99280297Sjkim        return 0;
100280297Sjkim    }
101280297Sjkim
102280297Sjkim    return 1;
10359191Skris}
10459191Skris
10559191Skris/* Parse the outer PKCS#12 structure */
10659191Skris
107306198Sjkimstatic int newpass_p12(PKCS12 *p12, const char *oldpass, const char *newpass)
10859191Skris{
109306198Sjkim    STACK_OF(PKCS7) *asafes = NULL, *newsafes = NULL;
110306198Sjkim    STACK_OF(PKCS12_SAFEBAG) *bags = NULL;
111280297Sjkim    int i, bagnid, pbe_nid = 0, pbe_iter = 0, pbe_saltlen = 0;
112280297Sjkim    PKCS7 *p7, *p7new;
113306198Sjkim    ASN1_OCTET_STRING *p12_data_tmp = NULL;
114280297Sjkim    unsigned char mac[EVP_MAX_MD_SIZE];
115280297Sjkim    unsigned int maclen;
116306198Sjkim    int rv = 0;
11768651Skris
118306198Sjkim    if ((asafes = PKCS12_unpack_authsafes(p12)) == NULL)
119306198Sjkim        goto err;
120306198Sjkim    if ((newsafes = sk_PKCS7_new_null()) == NULL)
121306198Sjkim        goto err;
122280297Sjkim    for (i = 0; i < sk_PKCS7_num(asafes); i++) {
123280297Sjkim        p7 = sk_PKCS7_value(asafes, i);
124280297Sjkim        bagnid = OBJ_obj2nid(p7->type);
125280297Sjkim        if (bagnid == NID_pkcs7_data) {
126280297Sjkim            bags = PKCS12_unpack_p7data(p7);
127280297Sjkim        } else if (bagnid == NID_pkcs7_encrypted) {
128280297Sjkim            bags = PKCS12_unpack_p7encdata(p7, oldpass, -1);
129280297Sjkim            if (!alg_get(p7->d.encrypted->enc_data->algorithm,
130306198Sjkim                         &pbe_nid, &pbe_iter, &pbe_saltlen))
131306198Sjkim                goto err;
132306198Sjkim        } else {
133280297Sjkim            continue;
134280297Sjkim        }
135306198Sjkim        if (bags == NULL)
136306198Sjkim            goto err;
137306198Sjkim        if (!newpass_bags(bags, oldpass, newpass))
138306198Sjkim            goto err;
139280297Sjkim        /* Repack bag in same form with new password */
140280297Sjkim        if (bagnid == NID_pkcs7_data)
141280297Sjkim            p7new = PKCS12_pack_p7data(bags);
142280297Sjkim        else
143280297Sjkim            p7new = PKCS12_pack_p7encdata(pbe_nid, newpass, -1, NULL,
144280297Sjkim                                          pbe_saltlen, pbe_iter, bags);
145306198Sjkim        if (!p7new || !sk_PKCS7_push(newsafes, p7new))
146306198Sjkim            goto err;
147280297Sjkim        sk_PKCS12_SAFEBAG_pop_free(bags, PKCS12_SAFEBAG_free);
148306198Sjkim        bags = NULL;
149280297Sjkim    }
15059191Skris
151280297Sjkim    /* Repack safe: save old safe in case of error */
15259191Skris
153280297Sjkim    p12_data_tmp = p12->authsafes->d.data;
154306198Sjkim    if ((p12->authsafes->d.data = ASN1_OCTET_STRING_new()) == NULL)
155306198Sjkim        goto err;
156280297Sjkim    if (!PKCS12_pack_authsafes(p12, newsafes))
157306198Sjkim        goto err;
158280297Sjkim    if (!PKCS12_gen_mac(p12, newpass, -1, mac, &maclen))
159306198Sjkim        goto err;
160306198Sjkim    if (!ASN1_OCTET_STRING_set(p12->mac->dinfo->digest, mac, maclen))
161306198Sjkim        goto err;
16259191Skris
163306198Sjkim    rv = 1;
16459191Skris
165306198Sjkimerr:
166306198Sjkim    /* Restore old safe if necessary */
167306198Sjkim    if (rv == 1) {
168306198Sjkim        ASN1_OCTET_STRING_free(p12_data_tmp);
169306198Sjkim    } else if (p12_data_tmp != NULL) {
170306198Sjkim        ASN1_OCTET_STRING_free(p12->authsafes->d.data);
171306198Sjkim        p12->authsafes->d.data = p12_data_tmp;
172306198Sjkim    }
173306198Sjkim    sk_PKCS12_SAFEBAG_pop_free(bags, PKCS12_SAFEBAG_free);
174306198Sjkim    sk_PKCS7_pop_free(asafes, PKCS7_free);
175306198Sjkim    sk_PKCS7_pop_free(newsafes, PKCS7_free);
176306198Sjkim    return rv;
17759191Skris}
17859191Skris
179306198Sjkimstatic int newpass_bags(STACK_OF(PKCS12_SAFEBAG) *bags, const char *oldpass,
180306198Sjkim                        const char *newpass)
18159191Skris{
182280297Sjkim    int i;
183280297Sjkim    for (i = 0; i < sk_PKCS12_SAFEBAG_num(bags); i++) {
184280297Sjkim        if (!newpass_bag(sk_PKCS12_SAFEBAG_value(bags, i), oldpass, newpass))
185280297Sjkim            return 0;
186280297Sjkim    }
187280297Sjkim    return 1;
18859191Skris}
18959191Skris
19059191Skris/* Change password of safebag: only needs handle shrouded keybags */
19159191Skris
192306198Sjkimstatic int newpass_bag(PKCS12_SAFEBAG *bag, const char *oldpass,
193306198Sjkim                       const char *newpass)
19459191Skris{
195280297Sjkim    PKCS8_PRIV_KEY_INFO *p8;
196280297Sjkim    X509_SIG *p8new;
197280297Sjkim    int p8_nid, p8_saltlen, p8_iter;
19859191Skris
199280297Sjkim    if (M_PKCS12_bag_type(bag) != NID_pkcs8ShroudedKeyBag)
200280297Sjkim        return 1;
20159191Skris
202280297Sjkim    if (!(p8 = PKCS8_decrypt(bag->value.shkeybag, oldpass, -1)))
203280297Sjkim        return 0;
204280297Sjkim    if (!alg_get(bag->value.shkeybag->algor, &p8_nid, &p8_iter, &p8_saltlen))
205280297Sjkim        return 0;
206306198Sjkim    p8new = PKCS8_encrypt(p8_nid, NULL, newpass, -1, NULL, p8_saltlen,
207306198Sjkim                          p8_iter, p8);
208306198Sjkim    PKCS8_PRIV_KEY_INFO_free(p8);
209306198Sjkim    if (p8new == NULL)
210280297Sjkim        return 0;
211280297Sjkim    X509_SIG_free(bag->value.shkeybag);
212280297Sjkim    bag->value.shkeybag = p8new;
213280297Sjkim    return 1;
21459191Skris}
21559191Skris
21659191Skrisstatic int alg_get(X509_ALGOR *alg, int *pnid, int *piter, int *psaltlen)
21759191Skris{
218280297Sjkim    PBEPARAM *pbe;
219280297Sjkim    const unsigned char *p;
220160814Ssimon
221280297Sjkim    p = alg->parameter->value.sequence->data;
222280297Sjkim    pbe = d2i_PBEPARAM(NULL, &p, alg->parameter->value.sequence->length);
223280297Sjkim    if (!pbe)
224280297Sjkim        return 0;
225280297Sjkim    *pnid = OBJ_obj2nid(alg->algorithm);
226280297Sjkim    *piter = ASN1_INTEGER_get(pbe->iter);
227280297Sjkim    *psaltlen = pbe->salt->length;
228280297Sjkim    PBEPARAM_free(pbe);
229280297Sjkim    return 1;
23059191Skris}
231