2 * Copyright 1999-2024 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 /* PKCS#12 password change routine */
20 static int newpass_p12(PKCS12
*p12
, const char *oldpass
, const char *newpass
);
21 static int newpass_bags(STACK_OF(PKCS12_SAFEBAG
) *bags
, const char *oldpass
,
23 OSSL_LIB_CTX
*libctx
, const char *propq
);
24 static int newpass_bag(PKCS12_SAFEBAG
*bag
, const char *oldpass
,
26 OSSL_LIB_CTX
*libctx
, const char *propq
);
27 static int alg_get(const X509_ALGOR
*alg
, int *pnid
, int *piter
,
28 int *psaltlen
, int *cipherid
);
31 * Change the password on a PKCS#12 structure.
34 int PKCS12_newpass(PKCS12
*p12
, const char *oldpass
, const char *newpass
)
36 /* Check for NULL PKCS12 structure */
39 ERR_raise(ERR_LIB_PKCS12
, PKCS12_R_INVALID_NULL_PKCS12_POINTER
);
44 if (p12
->mac
!= NULL
) {
45 if (!PKCS12_verify_mac(p12
, oldpass
, -1)) {
46 ERR_raise(ERR_LIB_PKCS12
, PKCS12_R_MAC_VERIFY_FAILURE
);
50 if (!newpass_p12(p12
, oldpass
, newpass
)) {
51 ERR_raise(ERR_LIB_PKCS12
, PKCS12_R_PARSE_ERROR
);
58 /* Parse the outer PKCS#12 structure */
60 static int newpass_p12(PKCS12
*p12
, const char *oldpass
, const char *newpass
)
62 STACK_OF(PKCS7
) *asafes
= NULL
, *newsafes
= NULL
;
63 STACK_OF(PKCS12_SAFEBAG
) *bags
= NULL
;
64 int i
, bagnid
, pbe_nid
= 0, pbe_iter
= 0, pbe_saltlen
= 0, cipherid
= NID_undef
;
66 ASN1_OCTET_STRING
*p12_data_tmp
= NULL
, *macoct
= NULL
;
67 unsigned char mac
[EVP_MAX_MD_SIZE
];
71 if ((asafes
= PKCS12_unpack_authsafes(p12
)) == NULL
)
73 if ((newsafes
= sk_PKCS7_new_null()) == NULL
)
75 for (i
= 0; i
< sk_PKCS7_num(asafes
); i
++) {
76 p7
= sk_PKCS7_value(asafes
, i
);
78 bagnid
= OBJ_obj2nid(p7
->type
);
79 if (bagnid
== NID_pkcs7_data
) {
80 bags
= PKCS12_unpack_p7data(p7
);
81 } else if (bagnid
== NID_pkcs7_encrypted
) {
82 bags
= PKCS12_unpack_p7encdata(p7
, oldpass
, -1);
83 if (p7
->d
.encrypted
== NULL
84 || !alg_get(p7
->d
.encrypted
->enc_data
->algorithm
,
85 &pbe_nid
, &pbe_iter
, &pbe_saltlen
, &cipherid
))
92 if (!newpass_bags(bags
, oldpass
, newpass
,
93 p7
->ctx
.libctx
, p7
->ctx
.propq
))
95 /* Repack bag in same form with new password */
96 if (bagnid
== NID_pkcs7_data
)
97 p7new
= PKCS12_pack_p7data(bags
);
99 p7new
= PKCS12_pack_p7encdata_ex(pbe_nid
, newpass
, -1, NULL
,
100 pbe_saltlen
, pbe_iter
, bags
,
101 p7
->ctx
.libctx
, p7
->ctx
.propq
);
102 if (p7new
== NULL
|| !sk_PKCS7_push(newsafes
, p7new
))
104 sk_PKCS12_SAFEBAG_pop_free(bags
, PKCS12_SAFEBAG_free
);
108 /* Repack safe: save old safe in case of error */
110 p12_data_tmp
= p12
->authsafes
->d
.data
;
111 if ((p12
->authsafes
->d
.data
= ASN1_OCTET_STRING_new()) == NULL
)
113 if (!PKCS12_pack_authsafes(p12
, newsafes
))
116 if (p12
->mac
!= NULL
) {
117 if (!PKCS12_gen_mac(p12
, newpass
, -1, mac
, &maclen
))
119 X509_SIG_getm(p12
->mac
->dinfo
, NULL
, &macoct
);
120 if (!ASN1_OCTET_STRING_set(macoct
, mac
, maclen
))
127 /* Restore old safe if necessary */
129 ASN1_OCTET_STRING_free(p12_data_tmp
);
130 } else if (p12_data_tmp
!= NULL
) {
131 ASN1_OCTET_STRING_free(p12
->authsafes
->d
.data
);
132 p12
->authsafes
->d
.data
= p12_data_tmp
;
134 sk_PKCS12_SAFEBAG_pop_free(bags
, PKCS12_SAFEBAG_free
);
135 sk_PKCS7_pop_free(asafes
, PKCS7_free
);
136 sk_PKCS7_pop_free(newsafes
, PKCS7_free
);
140 static int newpass_bags(STACK_OF(PKCS12_SAFEBAG
) *bags
, const char *oldpass
,
142 OSSL_LIB_CTX
*libctx
, const char *propq
)
145 for (i
= 0; i
< sk_PKCS12_SAFEBAG_num(bags
); i
++) {
146 if (!newpass_bag(sk_PKCS12_SAFEBAG_value(bags
, i
), oldpass
, newpass
,
153 /* Change password of safebag: only needs handle shrouded keybags */
155 static int newpass_bag(PKCS12_SAFEBAG
*bag
, const char *oldpass
,
157 OSSL_LIB_CTX
*libctx
, const char *propq
)
159 EVP_CIPHER
*cipher
= NULL
;
160 PKCS8_PRIV_KEY_INFO
*p8
;
162 int p8_nid
, p8_saltlen
, p8_iter
, cipherid
= 0;
163 const X509_ALGOR
*shalg
;
165 if (PKCS12_SAFEBAG_get_nid(bag
) != NID_pkcs8ShroudedKeyBag
)
168 if ((p8
= PKCS8_decrypt_ex(bag
->value
.shkeybag
, oldpass
, -1,
169 libctx
, propq
)) == NULL
)
171 X509_SIG_get0(bag
->value
.shkeybag
, &shalg
, NULL
);
172 if (!alg_get(shalg
, &p8_nid
, &p8_iter
, &p8_saltlen
, &cipherid
)) {
173 PKCS8_PRIV_KEY_INFO_free(p8
);
176 if (cipherid
!= NID_undef
) {
177 cipher
= EVP_CIPHER_fetch(libctx
, OBJ_nid2sn(cipherid
), propq
);
178 if (cipher
== NULL
) {
179 PKCS8_PRIV_KEY_INFO_free(p8
);
183 p8new
= PKCS8_encrypt_ex(p8_nid
, cipher
, newpass
, -1, NULL
, p8_saltlen
,
184 p8_iter
, p8
, libctx
, propq
);
185 PKCS8_PRIV_KEY_INFO_free(p8
);
186 EVP_CIPHER_free(cipher
);
189 X509_SIG_free(bag
->value
.shkeybag
);
190 bag
->value
.shkeybag
= p8new
;
194 static int alg_get(const X509_ALGOR
*alg
, int *pnid
, int *piter
,
195 int *psaltlen
, int *cipherid
)
197 int ret
= 0, pbenid
, aparamtype
;
199 const ASN1_OBJECT
*aoid
;
201 PBEPARAM
*pbe
= NULL
;
202 PBE2PARAM
*pbe2
= NULL
;
203 PBKDF2PARAM
*kdf
= NULL
;
205 X509_ALGOR_get0(&aoid
, &aparamtype
, &aparam
, alg
);
206 pbenid
= OBJ_obj2nid(aoid
);
210 if (aparamtype
== V_ASN1_SEQUENCE
)
211 pbe2
= ASN1_item_unpack(aparam
, ASN1_ITEM_rptr(PBE2PARAM
));
215 X509_ALGOR_get0(&aoid
, &aparamtype
, &aparam
, pbe2
->keyfunc
);
216 pbenid
= OBJ_obj2nid(aoid
);
217 X509_ALGOR_get0(&aoid
, NULL
, NULL
, pbe2
->encryption
);
218 encnid
= OBJ_obj2nid(aoid
);
220 if (aparamtype
== V_ASN1_SEQUENCE
)
221 kdf
= ASN1_item_unpack(aparam
, ASN1_ITEM_rptr(PBKDF2PARAM
));
225 /* Only OCTET_STRING is supported */
226 if (kdf
->salt
->type
!= V_ASN1_OCTET_STRING
)
229 if (kdf
->prf
== NULL
) {
230 prfnid
= NID_hmacWithSHA1
;
232 X509_ALGOR_get0(&aoid
, NULL
, NULL
, kdf
->prf
);
233 prfnid
= OBJ_obj2nid(aoid
);
235 *psaltlen
= kdf
->salt
->value
.octet_string
->length
;
236 *piter
= ASN1_INTEGER_get(kdf
->iter
);
241 pbe
= ASN1_TYPE_unpack_sequence(ASN1_ITEM_rptr(PBEPARAM
), alg
->parameter
);
244 *pnid
= OBJ_obj2nid(alg
->algorithm
);
245 *piter
= ASN1_INTEGER_get(pbe
->iter
);
246 *psaltlen
= pbe
->salt
->length
;
247 *cipherid
= NID_undef
;
254 PBKDF2PARAM_free(kdf
);
256 PBE2PARAM_free(pbe2
);