1 | /*
|
---|
2 | * Copyright 1999-2020 The OpenSSL Project Authors. All Rights Reserved.
|
---|
3 | *
|
---|
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
|
---|
8 | */
|
---|
9 |
|
---|
10 | #include <stdio.h>
|
---|
11 | #include <stdlib.h>
|
---|
12 | #include <string.h>
|
---|
13 | #include <openssl/pem.h>
|
---|
14 | #include <openssl/err.h>
|
---|
15 | #include <openssl/pkcs12.h>
|
---|
16 | #include "p12_local.h"
|
---|
17 |
|
---|
18 | /* PKCS#12 password change routine */
|
---|
19 |
|
---|
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,
|
---|
22 | const char *newpass);
|
---|
23 | static int newpass_bag(PKCS12_SAFEBAG *bag, const char *oldpass,
|
---|
24 | const char *newpass);
|
---|
25 | static int alg_get(const X509_ALGOR *alg, int *pnid, int *piter,
|
---|
26 | int *psaltlen);
|
---|
27 |
|
---|
28 | /*
|
---|
29 | * Change the password on a PKCS#12 structure.
|
---|
30 | */
|
---|
31 |
|
---|
32 | int PKCS12_newpass(PKCS12 *p12, const char *oldpass, const char *newpass)
|
---|
33 | {
|
---|
34 | /* Check for NULL PKCS12 structure */
|
---|
35 |
|
---|
36 | if (p12 == NULL) {
|
---|
37 | ERR_raise(ERR_LIB_PKCS12, PKCS12_R_INVALID_NULL_PKCS12_POINTER);
|
---|
38 | return 0;
|
---|
39 | }
|
---|
40 |
|
---|
41 | /* Check the mac */
|
---|
42 |
|
---|
43 | if (!PKCS12_verify_mac(p12, oldpass, -1)) {
|
---|
44 | ERR_raise(ERR_LIB_PKCS12, PKCS12_R_MAC_VERIFY_FAILURE);
|
---|
45 | return 0;
|
---|
46 | }
|
---|
47 |
|
---|
48 | if (!newpass_p12(p12, oldpass, newpass)) {
|
---|
49 | ERR_raise(ERR_LIB_PKCS12, PKCS12_R_PARSE_ERROR);
|
---|
50 | return 0;
|
---|
51 | }
|
---|
52 |
|
---|
53 | return 1;
|
---|
54 | }
|
---|
55 |
|
---|
56 | /* Parse the outer PKCS#12 structure */
|
---|
57 |
|
---|
58 | static int newpass_p12(PKCS12 *p12, const char *oldpass, const char *newpass)
|
---|
59 | {
|
---|
60 | STACK_OF(PKCS7) *asafes = NULL, *newsafes = NULL;
|
---|
61 | STACK_OF(PKCS12_SAFEBAG) *bags = NULL;
|
---|
62 | int i, bagnid, pbe_nid = 0, pbe_iter = 0, pbe_saltlen = 0;
|
---|
63 | PKCS7 *p7, *p7new;
|
---|
64 | ASN1_OCTET_STRING *p12_data_tmp = NULL, *macoct = NULL;
|
---|
65 | unsigned char mac[EVP_MAX_MD_SIZE];
|
---|
66 | unsigned int maclen;
|
---|
67 | int rv = 0;
|
---|
68 |
|
---|
69 | if ((asafes = PKCS12_unpack_authsafes(p12)) == NULL)
|
---|
70 | goto err;
|
---|
71 | if ((newsafes = sk_PKCS7_new_null()) == NULL)
|
---|
72 | goto err;
|
---|
73 | for (i = 0; i < sk_PKCS7_num(asafes); i++) {
|
---|
74 | p7 = sk_PKCS7_value(asafes, i);
|
---|
75 | bagnid = OBJ_obj2nid(p7->type);
|
---|
76 | if (bagnid == NID_pkcs7_data) {
|
---|
77 | bags = PKCS12_unpack_p7data(p7);
|
---|
78 | } else if (bagnid == NID_pkcs7_encrypted) {
|
---|
79 | bags = PKCS12_unpack_p7encdata(p7, oldpass, -1);
|
---|
80 | if (!alg_get(p7->d.encrypted->enc_data->algorithm,
|
---|
81 | &pbe_nid, &pbe_iter, &pbe_saltlen))
|
---|
82 | goto err;
|
---|
83 | } else {
|
---|
84 | continue;
|
---|
85 | }
|
---|
86 | if (bags == NULL)
|
---|
87 | goto err;
|
---|
88 | if (!newpass_bags(bags, oldpass, newpass))
|
---|
89 | goto err;
|
---|
90 | /* Repack bag in same form with new password */
|
---|
91 | if (bagnid == NID_pkcs7_data)
|
---|
92 | p7new = PKCS12_pack_p7data(bags);
|
---|
93 | else
|
---|
94 | p7new = PKCS12_pack_p7encdata(pbe_nid, newpass, -1, NULL,
|
---|
95 | pbe_saltlen, pbe_iter, bags);
|
---|
96 | if (p7new == NULL || !sk_PKCS7_push(newsafes, p7new))
|
---|
97 | goto err;
|
---|
98 | sk_PKCS12_SAFEBAG_pop_free(bags, PKCS12_SAFEBAG_free);
|
---|
99 | bags = NULL;
|
---|
100 | }
|
---|
101 |
|
---|
102 | /* Repack safe: save old safe in case of error */
|
---|
103 |
|
---|
104 | p12_data_tmp = p12->authsafes->d.data;
|
---|
105 | if ((p12->authsafes->d.data = ASN1_OCTET_STRING_new()) == NULL)
|
---|
106 | goto err;
|
---|
107 | if (!PKCS12_pack_authsafes(p12, newsafes))
|
---|
108 | goto err;
|
---|
109 |
|
---|
110 | if (!PKCS12_gen_mac(p12, newpass, -1, mac, &maclen))
|
---|
111 | goto err;
|
---|
112 | X509_SIG_getm(p12->mac->dinfo, NULL, &macoct);
|
---|
113 | if (!ASN1_OCTET_STRING_set(macoct, mac, maclen))
|
---|
114 | goto err;
|
---|
115 |
|
---|
116 | rv = 1;
|
---|
117 |
|
---|
118 | err:
|
---|
119 | /* Restore old safe if necessary */
|
---|
120 | if (rv == 1) {
|
---|
121 | ASN1_OCTET_STRING_free(p12_data_tmp);
|
---|
122 | } else if (p12_data_tmp != NULL) {
|
---|
123 | ASN1_OCTET_STRING_free(p12->authsafes->d.data);
|
---|
124 | p12->authsafes->d.data = p12_data_tmp;
|
---|
125 | }
|
---|
126 | sk_PKCS12_SAFEBAG_pop_free(bags, PKCS12_SAFEBAG_free);
|
---|
127 | sk_PKCS7_pop_free(asafes, PKCS7_free);
|
---|
128 | sk_PKCS7_pop_free(newsafes, PKCS7_free);
|
---|
129 | return rv;
|
---|
130 | }
|
---|
131 |
|
---|
132 | static int newpass_bags(STACK_OF(PKCS12_SAFEBAG) *bags, const char *oldpass,
|
---|
133 | const char *newpass)
|
---|
134 | {
|
---|
135 | int i;
|
---|
136 | for (i = 0; i < sk_PKCS12_SAFEBAG_num(bags); i++) {
|
---|
137 | if (!newpass_bag(sk_PKCS12_SAFEBAG_value(bags, i), oldpass, newpass))
|
---|
138 | return 0;
|
---|
139 | }
|
---|
140 | return 1;
|
---|
141 | }
|
---|
142 |
|
---|
143 | /* Change password of safebag: only needs handle shrouded keybags */
|
---|
144 |
|
---|
145 | static int newpass_bag(PKCS12_SAFEBAG *bag, const char *oldpass,
|
---|
146 | const char *newpass)
|
---|
147 | {
|
---|
148 | PKCS8_PRIV_KEY_INFO *p8;
|
---|
149 | X509_SIG *p8new;
|
---|
150 | int p8_nid, p8_saltlen, p8_iter;
|
---|
151 | const X509_ALGOR *shalg;
|
---|
152 |
|
---|
153 | if (PKCS12_SAFEBAG_get_nid(bag) != NID_pkcs8ShroudedKeyBag)
|
---|
154 | return 1;
|
---|
155 |
|
---|
156 | if ((p8 = PKCS8_decrypt(bag->value.shkeybag, oldpass, -1)) == NULL)
|
---|
157 | return 0;
|
---|
158 | X509_SIG_get0(bag->value.shkeybag, &shalg, NULL);
|
---|
159 | if (!alg_get(shalg, &p8_nid, &p8_iter, &p8_saltlen)) {
|
---|
160 | PKCS8_PRIV_KEY_INFO_free(p8);
|
---|
161 | return 0;
|
---|
162 | }
|
---|
163 | p8new = PKCS8_encrypt(p8_nid, NULL, newpass, -1, NULL, p8_saltlen,
|
---|
164 | p8_iter, p8);
|
---|
165 | PKCS8_PRIV_KEY_INFO_free(p8);
|
---|
166 | if (p8new == NULL)
|
---|
167 | return 0;
|
---|
168 | X509_SIG_free(bag->value.shkeybag);
|
---|
169 | bag->value.shkeybag = p8new;
|
---|
170 | return 1;
|
---|
171 | }
|
---|
172 |
|
---|
173 | static int alg_get(const X509_ALGOR *alg, int *pnid, int *piter,
|
---|
174 | int *psaltlen)
|
---|
175 | {
|
---|
176 | PBEPARAM *pbe;
|
---|
177 |
|
---|
178 | pbe = ASN1_TYPE_unpack_sequence(ASN1_ITEM_rptr(PBEPARAM), alg->parameter);
|
---|
179 | if (pbe == NULL)
|
---|
180 | return 0;
|
---|
181 | *pnid = OBJ_obj2nid(alg->algorithm);
|
---|
182 | *piter = ASN1_INTEGER_get(pbe->iter);
|
---|
183 | *psaltlen = pbe->salt->length;
|
---|
184 | PBEPARAM_free(pbe);
|
---|
185 | return 1;
|
---|
186 | }
|
---|