2 * Copyright 1999-2020 The OpenSSL Project Authors. All Rights Reserved.
4 * Licensed under the Apache License 2.0 (the "License"). You may not use
5 * this file except in compliance with the License. You can obtain a copy
6 * in the file LICENSE in the source distribution or at
7 * https://www.openssl.org/source/license.html
13 #include <openssl/pem.h>
14 #include <openssl/err.h>
15 #include <openssl/pkcs12.h>
16 #include "p12_local.h"
18 DEFINE_STACK_OF(PKCS7
)
19 DEFINE_STACK_OF(PKCS12_SAFEBAG
)
21 /* PKCS#12 password change routine */
23 static int newpass_p12(PKCS12
*p12
, const char *oldpass
, const char *newpass
);
24 static int newpass_bags(STACK_OF(PKCS12_SAFEBAG
) *bags
, const char *oldpass
,
26 static int newpass_bag(PKCS12_SAFEBAG
*bag
, const char *oldpass
,
28 static int alg_get(const X509_ALGOR
*alg
, int *pnid
, int *piter
,
32 * Change the password on a PKCS#12 structure.
35 int PKCS12_newpass(PKCS12
*p12
, const char *oldpass
, const char *newpass
)
37 /* Check for NULL PKCS12 structure */
40 PKCS12err(PKCS12_F_PKCS12_NEWPASS
,
41 PKCS12_R_INVALID_NULL_PKCS12_POINTER
);
47 if (!PKCS12_verify_mac(p12
, oldpass
, -1)) {
48 PKCS12err(PKCS12_F_PKCS12_NEWPASS
, PKCS12_R_MAC_VERIFY_FAILURE
);
52 if (!newpass_p12(p12
, oldpass
, newpass
)) {
53 PKCS12err(PKCS12_F_PKCS12_NEWPASS
, PKCS12_R_PARSE_ERROR
);
60 /* Parse the outer PKCS#12 structure */
62 static int newpass_p12(PKCS12
*p12
, const char *oldpass
, const char *newpass
)
64 STACK_OF(PKCS7
) *asafes
= NULL
, *newsafes
= NULL
;
65 STACK_OF(PKCS12_SAFEBAG
) *bags
= NULL
;
66 int i
, bagnid
, pbe_nid
= 0, pbe_iter
= 0, pbe_saltlen
= 0;
68 ASN1_OCTET_STRING
*p12_data_tmp
= NULL
, *macoct
= NULL
;
69 unsigned char mac
[EVP_MAX_MD_SIZE
];
73 if ((asafes
= PKCS12_unpack_authsafes(p12
)) == NULL
)
75 if ((newsafes
= sk_PKCS7_new_null()) == NULL
)
77 for (i
= 0; i
< sk_PKCS7_num(asafes
); i
++) {
78 p7
= sk_PKCS7_value(asafes
, i
);
79 bagnid
= OBJ_obj2nid(p7
->type
);
80 if (bagnid
== NID_pkcs7_data
) {
81 bags
= PKCS12_unpack_p7data(p7
);
82 } else if (bagnid
== NID_pkcs7_encrypted
) {
83 bags
= PKCS12_unpack_p7encdata(p7
, oldpass
, -1);
84 if (!alg_get(p7
->d
.encrypted
->enc_data
->algorithm
,
85 &pbe_nid
, &pbe_iter
, &pbe_saltlen
))
92 if (!newpass_bags(bags
, oldpass
, newpass
))
94 /* Repack bag in same form with new password */
95 if (bagnid
== NID_pkcs7_data
)
96 p7new
= PKCS12_pack_p7data(bags
);
98 p7new
= PKCS12_pack_p7encdata(pbe_nid
, newpass
, -1, NULL
,
99 pbe_saltlen
, pbe_iter
, bags
);
100 if (p7new
== NULL
|| !sk_PKCS7_push(newsafes
, p7new
))
102 sk_PKCS12_SAFEBAG_pop_free(bags
, PKCS12_SAFEBAG_free
);
106 /* Repack safe: save old safe in case of error */
108 p12_data_tmp
= p12
->authsafes
->d
.data
;
109 if ((p12
->authsafes
->d
.data
= ASN1_OCTET_STRING_new()) == NULL
)
111 if (!PKCS12_pack_authsafes(p12
, newsafes
))
114 if (!PKCS12_gen_mac(p12
, newpass
, -1, mac
, &maclen
))
116 X509_SIG_getm(p12
->mac
->dinfo
, NULL
, &macoct
);
117 if (!ASN1_OCTET_STRING_set(macoct
, mac
, maclen
))
123 /* Restore old safe if necessary */
125 ASN1_OCTET_STRING_free(p12_data_tmp
);
126 } else if (p12_data_tmp
!= NULL
) {
127 ASN1_OCTET_STRING_free(p12
->authsafes
->d
.data
);
128 p12
->authsafes
->d
.data
= p12_data_tmp
;
130 sk_PKCS12_SAFEBAG_pop_free(bags
, PKCS12_SAFEBAG_free
);
131 sk_PKCS7_pop_free(asafes
, PKCS7_free
);
132 sk_PKCS7_pop_free(newsafes
, PKCS7_free
);
136 static int newpass_bags(STACK_OF(PKCS12_SAFEBAG
) *bags
, const char *oldpass
,
140 for (i
= 0; i
< sk_PKCS12_SAFEBAG_num(bags
); i
++) {
141 if (!newpass_bag(sk_PKCS12_SAFEBAG_value(bags
, i
), oldpass
, newpass
))
147 /* Change password of safebag: only needs handle shrouded keybags */
149 static int newpass_bag(PKCS12_SAFEBAG
*bag
, const char *oldpass
,
152 PKCS8_PRIV_KEY_INFO
*p8
;
154 int p8_nid
, p8_saltlen
, p8_iter
;
155 const X509_ALGOR
*shalg
;
157 if (PKCS12_SAFEBAG_get_nid(bag
) != NID_pkcs8ShroudedKeyBag
)
160 if ((p8
= PKCS8_decrypt(bag
->value
.shkeybag
, oldpass
, -1)) == NULL
)
162 X509_SIG_get0(bag
->value
.shkeybag
, &shalg
, NULL
);
163 if (!alg_get(shalg
, &p8_nid
, &p8_iter
, &p8_saltlen
))
165 p8new
= PKCS8_encrypt(p8_nid
, NULL
, newpass
, -1, NULL
, p8_saltlen
,
167 PKCS8_PRIV_KEY_INFO_free(p8
);
170 X509_SIG_free(bag
->value
.shkeybag
);
171 bag
->value
.shkeybag
= p8new
;
175 static int alg_get(const X509_ALGOR
*alg
, int *pnid
, int *piter
,
180 pbe
= ASN1_TYPE_unpack_sequence(ASN1_ITEM_rptr(PBEPARAM
), alg
->parameter
);
183 *pnid
= OBJ_obj2nid(alg
->algorithm
);
184 *piter
= ASN1_INTEGER_get(pbe
->iter
);
185 *psaltlen
= pbe
->salt
->length
;