159191Skris/* p12_npas.c */
2280304Sjkim/*
3280304Sjkim * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL project
4280304Sjkim * 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
14280304Sjkim *    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
69306196Sjkimstatic int newpass_p12(PKCS12 *p12, const char *oldpass, const char *newpass);
70306196Sjkimstatic int newpass_bags(STACK_OF(PKCS12_SAFEBAG) *bags, const char *oldpass,
71306196Sjkim                        const char *newpass);
72306196Sjkimstatic int newpass_bag(PKCS12_SAFEBAG *bag, const char *oldpass,
73306196Sjkim                        const char *newpass);
7459191Skrisstatic int alg_get(X509_ALGOR *alg, int *pnid, int *piter, int *psaltlen);
7559191Skris
76280304Sjkim/*
7759191Skris * Change the password on a PKCS#12 structure.
7859191Skris */
7959191Skris
80306196Sjkimint PKCS12_newpass(PKCS12 *p12, const char *oldpass, const char *newpass)
8159191Skris{
82280304Sjkim    /* Check for NULL PKCS12 structure */
8359191Skris
84280304Sjkim    if (!p12) {
85280304Sjkim        PKCS12err(PKCS12_F_PKCS12_NEWPASS,
86280304Sjkim                  PKCS12_R_INVALID_NULL_PKCS12_POINTER);
87280304Sjkim        return 0;
88280304Sjkim    }
8959191Skris
90280304Sjkim    /* Check the mac */
9159191Skris
92280304Sjkim    if (!PKCS12_verify_mac(p12, oldpass, -1)) {
93280304Sjkim        PKCS12err(PKCS12_F_PKCS12_NEWPASS, PKCS12_R_MAC_VERIFY_FAILURE);
94280304Sjkim        return 0;
95280304Sjkim    }
9659191Skris
97280304Sjkim    if (!newpass_p12(p12, oldpass, newpass)) {
98280304Sjkim        PKCS12err(PKCS12_F_PKCS12_NEWPASS, PKCS12_R_PARSE_ERROR);
99280304Sjkim        return 0;
100280304Sjkim    }
101280304Sjkim
102280304Sjkim    return 1;
10359191Skris}
10459191Skris
10559191Skris/* Parse the outer PKCS#12 structure */
10659191Skris
107306196Sjkimstatic int newpass_p12(PKCS12 *p12, const char *oldpass, const char *newpass)
10859191Skris{
109306196Sjkim    STACK_OF(PKCS7) *asafes = NULL, *newsafes = NULL;
110306196Sjkim    STACK_OF(PKCS12_SAFEBAG) *bags = NULL;
111280304Sjkim    int i, bagnid, pbe_nid = 0, pbe_iter = 0, pbe_saltlen = 0;
112280304Sjkim    PKCS7 *p7, *p7new;
113306196Sjkim    ASN1_OCTET_STRING *p12_data_tmp = NULL;
114280304Sjkim    unsigned char mac[EVP_MAX_MD_SIZE];
115280304Sjkim    unsigned int maclen;
116306196Sjkim    int rv = 0;
11768651Skris
118306196Sjkim    if ((asafes = PKCS12_unpack_authsafes(p12)) == NULL)
119306196Sjkim        goto err;
120306196Sjkim    if ((newsafes = sk_PKCS7_new_null()) == NULL)
121306196Sjkim        goto err;
122280304Sjkim    for (i = 0; i < sk_PKCS7_num(asafes); i++) {
123280304Sjkim        p7 = sk_PKCS7_value(asafes, i);
124280304Sjkim        bagnid = OBJ_obj2nid(p7->type);
125280304Sjkim        if (bagnid == NID_pkcs7_data) {
126280304Sjkim            bags = PKCS12_unpack_p7data(p7);
127280304Sjkim        } else if (bagnid == NID_pkcs7_encrypted) {
128280304Sjkim            bags = PKCS12_unpack_p7encdata(p7, oldpass, -1);
129280304Sjkim            if (!alg_get(p7->d.encrypted->enc_data->algorithm,
130306196Sjkim                         &pbe_nid, &pbe_iter, &pbe_saltlen))
131306196Sjkim                goto err;
132306196Sjkim        } else {
133280304Sjkim            continue;
134280304Sjkim        }
135306196Sjkim        if (bags == NULL)
136306196Sjkim            goto err;
137306196Sjkim        if (!newpass_bags(bags, oldpass, newpass))
138306196Sjkim            goto err;
139280304Sjkim        /* Repack bag in same form with new password */
140280304Sjkim        if (bagnid == NID_pkcs7_data)
141280304Sjkim            p7new = PKCS12_pack_p7data(bags);
142280304Sjkim        else
143280304Sjkim            p7new = PKCS12_pack_p7encdata(pbe_nid, newpass, -1, NULL,
144280304Sjkim                                          pbe_saltlen, pbe_iter, bags);
145306196Sjkim        if (!p7new || !sk_PKCS7_push(newsafes, p7new))
146306196Sjkim            goto err;
147280304Sjkim        sk_PKCS12_SAFEBAG_pop_free(bags, PKCS12_SAFEBAG_free);
148306196Sjkim        bags = NULL;
149280304Sjkim    }
15059191Skris
151280304Sjkim    /* Repack safe: save old safe in case of error */
15259191Skris
153280304Sjkim    p12_data_tmp = p12->authsafes->d.data;
154306196Sjkim    if ((p12->authsafes->d.data = ASN1_OCTET_STRING_new()) == NULL)
155306196Sjkim        goto err;
156280304Sjkim    if (!PKCS12_pack_authsafes(p12, newsafes))
157306196Sjkim        goto err;
158280304Sjkim    if (!PKCS12_gen_mac(p12, newpass, -1, mac, &maclen))
159306196Sjkim        goto err;
160306196Sjkim    if (!ASN1_OCTET_STRING_set(p12->mac->dinfo->digest, mac, maclen))
161306196Sjkim        goto err;
16259191Skris
163306196Sjkim    rv = 1;
16459191Skris
165306196Sjkimerr:
166306196Sjkim    /* Restore old safe if necessary */
167306196Sjkim    if (rv == 1) {
168306196Sjkim        ASN1_OCTET_STRING_free(p12_data_tmp);
169306196Sjkim    } else if (p12_data_tmp != NULL) {
170306196Sjkim        ASN1_OCTET_STRING_free(p12->authsafes->d.data);
171306196Sjkim        p12->authsafes->d.data = p12_data_tmp;
172306196Sjkim    }
173306196Sjkim    sk_PKCS12_SAFEBAG_pop_free(bags, PKCS12_SAFEBAG_free);
174306196Sjkim    sk_PKCS7_pop_free(asafes, PKCS7_free);
175306196Sjkim    sk_PKCS7_pop_free(newsafes, PKCS7_free);
176306196Sjkim    return rv;
17759191Skris}
17859191Skris
179306196Sjkimstatic int newpass_bags(STACK_OF(PKCS12_SAFEBAG) *bags, const char *oldpass,
180306196Sjkim                        const char *newpass)
18159191Skris{
182280304Sjkim    int i;
183280304Sjkim    for (i = 0; i < sk_PKCS12_SAFEBAG_num(bags); i++) {
184280304Sjkim        if (!newpass_bag(sk_PKCS12_SAFEBAG_value(bags, i), oldpass, newpass))
185280304Sjkim            return 0;
186280304Sjkim    }
187280304Sjkim    return 1;
18859191Skris}
18959191Skris
19059191Skris/* Change password of safebag: only needs handle shrouded keybags */
19159191Skris
192306196Sjkimstatic int newpass_bag(PKCS12_SAFEBAG *bag, const char *oldpass,
193306196Sjkim                       const char *newpass)
19459191Skris{
195280304Sjkim    PKCS8_PRIV_KEY_INFO *p8;
196280304Sjkim    X509_SIG *p8new;
197280304Sjkim    int p8_nid, p8_saltlen, p8_iter;
19859191Skris
199280304Sjkim    if (M_PKCS12_bag_type(bag) != NID_pkcs8ShroudedKeyBag)
200280304Sjkim        return 1;
20159191Skris
202280304Sjkim    if (!(p8 = PKCS8_decrypt(bag->value.shkeybag, oldpass, -1)))
203280304Sjkim        return 0;
204280304Sjkim    if (!alg_get(bag->value.shkeybag->algor, &p8_nid, &p8_iter, &p8_saltlen))
205280304Sjkim        return 0;
206306196Sjkim    p8new = PKCS8_encrypt(p8_nid, NULL, newpass, -1, NULL, p8_saltlen,
207306196Sjkim                          p8_iter, p8);
208306196Sjkim    PKCS8_PRIV_KEY_INFO_free(p8);
209306196Sjkim    if (p8new == NULL)
210280304Sjkim        return 0;
211280304Sjkim    X509_SIG_free(bag->value.shkeybag);
212280304Sjkim    bag->value.shkeybag = p8new;
213280304Sjkim    return 1;
21459191Skris}
21559191Skris
21659191Skrisstatic int alg_get(X509_ALGOR *alg, int *pnid, int *piter, int *psaltlen)
21759191Skris{
218280304Sjkim    PBEPARAM *pbe;
219280304Sjkim    const unsigned char *p;
220160814Ssimon
221280304Sjkim    p = alg->parameter->value.sequence->data;
222280304Sjkim    pbe = d2i_PBEPARAM(NULL, &p, alg->parameter->value.sequence->length);
223280304Sjkim    if (!pbe)
224280304Sjkim        return 0;
225280304Sjkim    *pnid = OBJ_obj2nid(alg->algorithm);
226280304Sjkim    *piter = ASN1_INTEGER_get(pbe->iter);
227280304Sjkim    *psaltlen = pbe->salt->length;
228280304Sjkim    PBEPARAM_free(pbe);
229280304Sjkim    return 1;
23059191Skris}
231