OLD | NEW |
1 /* This Source Code Form is subject to the terms of the Mozilla Public | 1 /* This Source Code Form is subject to the terms of the Mozilla Public |
2 * License, v. 2.0. If a copy of the MPL was not distributed with this | 2 * License, v. 2.0. If a copy of the MPL was not distributed with this |
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
4 | 4 |
5 #include "pkcs12.h" | 5 #include "pkcs12.h" |
6 #include "plarena.h" | 6 #include "plarena.h" |
7 #include "secpkcs7.h" | 7 #include "secpkcs7.h" |
8 #include "p12local.h" | 8 #include "p12local.h" |
9 #include "secoid.h" | 9 #include "secoid.h" |
10 #include "secitem.h" | 10 #include "secitem.h" |
11 #include "secport.h" | 11 #include "secport.h" |
12 #include "secasn1.h" | 12 #include "secasn1.h" |
13 #include "secder.h" | 13 #include "secder.h" |
14 #include "secerr.h" | 14 #include "secerr.h" |
15 #include "cert.h" | 15 #include "cert.h" |
16 #include "certdb.h" | 16 #include "certdb.h" |
17 #include "p12plcy.h" | 17 #include "p12plcy.h" |
18 #include "p12.h" | 18 #include "p12.h" |
19 #include "secpkcs5.h" | 19 #include "secpkcs5.h" |
20 | 20 |
21 /* PFX extraction and validation routines */ | 21 /* PFX extraction and validation routines */ |
22 | 22 |
23 /* decode the DER encoded PFX item. if unable to decode, check to see if it | 23 /* decode the DER encoded PFX item. if unable to decode, check to see if it |
24 * is an older PFX item. If that fails, assume the file was not a valid | 24 * is an older PFX item. If that fails, assume the file was not a valid |
25 * pfx file. | 25 * pfx file. |
26 * the returned pfx structure should be destroyed using SEC_PKCS12DestroyPFX | 26 * the returned pfx structure should be destroyed using SEC_PKCS12DestroyPFX |
27 */ | 27 */ |
28 static SEC_PKCS12PFXItem * | 28 static SEC_PKCS12PFXItem *sec_pkcs12_decode_pfx(SECItem *der_pfx) { |
29 sec_pkcs12_decode_pfx(SECItem *der_pfx) | 29 SEC_PKCS12PFXItem *pfx; |
30 { | 30 SECStatus rv; |
31 SEC_PKCS12PFXItem *pfx; | 31 |
32 SECStatus rv; | 32 if (der_pfx == NULL) { |
33 | 33 return NULL; |
34 if(der_pfx == NULL) { | 34 } |
35 » return NULL; | 35 |
36 } | 36 /* allocate the space for a new PFX item */ |
37 | 37 pfx = sec_pkcs12_new_pfx(); |
38 /* allocate the space for a new PFX item */ | 38 if (pfx == NULL) { |
| 39 return NULL; |
| 40 } |
| 41 |
| 42 rv = SEC_ASN1DecodeItem(pfx->poolp, pfx, SEC_PKCS12PFXItemTemplate, der_pfx); |
| 43 |
| 44 /* if a failure occurred, check for older version... |
| 45 * we also get rid of the old pfx structure, because we don't |
| 46 * know where it failed and what data in may contain |
| 47 */ |
| 48 if (rv != SECSuccess) { |
| 49 SEC_PKCS12DestroyPFX(pfx); |
39 pfx = sec_pkcs12_new_pfx(); | 50 pfx = sec_pkcs12_new_pfx(); |
40 if(pfx == NULL) { | 51 if (pfx == NULL) { |
41 » return NULL; | 52 return NULL; |
42 } | 53 } |
43 | 54 rv = SEC_ASN1DecodeItem(pfx->poolp, pfx, SEC_PKCS12PFXItemTemplate_OLD, |
44 rv = SEC_ASN1DecodeItem(pfx->poolp, pfx, SEC_PKCS12PFXItemTemplate,· | 55 der_pfx); |
45 » » » der_pfx); | 56 if (rv != SECSuccess) { |
46 | 57 PORT_SetError(SEC_ERROR_PKCS12_DECODING_PFX); |
47 /* if a failure occurred, check for older version... | 58 PORT_FreeArena(pfx->poolp, PR_TRUE); |
48 * we also get rid of the old pfx structure, because we don't | 59 return NULL; |
49 * know where it failed and what data in may contain | 60 } |
50 */ | 61 pfx->old = PR_TRUE; |
51 if(rv != SECSuccess) { | 62 SGN_CopyDigestInfo(pfx->poolp, &pfx->macData.safeMac, &pfx->old_safeMac); |
52 » SEC_PKCS12DestroyPFX(pfx); | 63 SECITEM_CopyItem(pfx->poolp, &pfx->macData.macSalt, &pfx->old_macSalt); |
53 » pfx = sec_pkcs12_new_pfx(); | 64 } else { |
54 » if(pfx == NULL) { | 65 pfx->old = PR_FALSE; |
55 » return NULL; | 66 } |
56 » } | 67 |
57 » rv = SEC_ASN1DecodeItem(pfx->poolp, pfx, SEC_PKCS12PFXItemTemplate_OLD,· | 68 /* convert bit string from bits to bytes */ |
58 » » » » der_pfx); | 69 pfx->macData.macSalt.len /= 8; |
59 » if(rv != SECSuccess) { | 70 |
60 » PORT_SetError(SEC_ERROR_PKCS12_DECODING_PFX); | 71 return pfx; |
61 » PORT_FreeArena(pfx->poolp, PR_TRUE); | |
62 » return NULL; | |
63 » } | |
64 » pfx->old = PR_TRUE; | |
65 » SGN_CopyDigestInfo(pfx->poolp, &pfx->macData.safeMac, &pfx->old_safeMac)
; | |
66 » SECITEM_CopyItem(pfx->poolp, &pfx->macData.macSalt, &pfx->old_macSalt); | |
67 } else { | |
68 » pfx->old = PR_FALSE; | |
69 } | |
70 | |
71 /* convert bit string from bits to bytes */ | |
72 pfx->macData.macSalt.len /= 8; | |
73 | |
74 return pfx; | |
75 } | 72 } |
76 | 73 |
77 /* validate the integrity MAC used in the PFX. The MAC is generated | 74 /* validate the integrity MAC used in the PFX. The MAC is generated |
78 * per the PKCS 12 document. If the MAC is incorrect, it is most likely | 75 * per the PKCS 12 document. If the MAC is incorrect, it is most likely |
79 * due to an invalid password. | 76 * due to an invalid password. |
80 * pwitem is the integrity password | 77 * pwitem is the integrity password |
81 * pfx is the decoded pfx item | 78 * pfx is the decoded pfx item |
82 */ | 79 */ |
83 static PRBool | 80 static PRBool sec_pkcs12_check_pfx_mac(SEC_PKCS12PFXItem *pfx, |
84 sec_pkcs12_check_pfx_mac(SEC_PKCS12PFXItem *pfx, | 81 SECItem *pwitem) { |
85 » » » SECItem *pwitem) | 82 SECItem *key = NULL, *mac = NULL, *data = NULL; |
86 { | 83 SECItem *vpwd = NULL; |
87 SECItem *key = NULL, *mac = NULL, *data = NULL; | 84 SECOidTag algorithm; |
88 SECItem *vpwd = NULL; | 85 PRBool ret = PR_FALSE; |
89 SECOidTag algorithm; | 86 |
90 PRBool ret = PR_FALSE; | 87 if (pfx == NULL) { |
91 | 88 return PR_FALSE; |
92 if(pfx == NULL) { | 89 } |
93 » return PR_FALSE; | 90 |
94 } | 91 algorithm = SECOID_GetAlgorithmTag(&pfx->macData.safeMac.digestAlgorithm); |
95 | 92 switch (algorithm) { |
96 algorithm = SECOID_GetAlgorithmTag(&pfx->macData.safeMac.digestAlgorithm); | 93 /* only SHA1 hashing supported as a MACing algorithm */ |
97 switch(algorithm) { | 94 case SEC_OID_SHA1: |
98 » /* only SHA1 hashing supported as a MACing algorithm */ | 95 if (pfx->old == PR_FALSE) { |
99 » case SEC_OID_SHA1: | 96 pfx->swapUnicode = PR_FALSE; |
100 » if(pfx->old == PR_FALSE) { | 97 } |
101 » » pfx->swapUnicode = PR_FALSE; | 98 |
102 » } | 99 recheckUnicodePassword: |
103 | 100 vpwd = sec_pkcs12_create_virtual_password(pwitem, &pfx->macData.macSalt, |
104 recheckUnicodePassword: | 101 pfx->swapUnicode); |
105 » vpwd = sec_pkcs12_create_virtual_password(pwitem, | 102 if (vpwd == NULL) { |
106 » » » » » » &pfx->macData.macSalt,· | 103 return PR_FALSE; |
107 » » » » » » pfx->swapUnicode); | 104 } |
108 » if(vpwd == NULL) { | 105 |
109 » » return PR_FALSE; | 106 key = sec_pkcs12_generate_key_from_password( |
110 » } | 107 algorithm, &pfx->macData.macSalt, (pfx->old ? pwitem : vpwd)); |
111 | 108 /* free vpwd only for newer PFX */ |
112 » key = sec_pkcs12_generate_key_from_password(algorithm, | 109 if (vpwd) { |
113 » » » » » » &pfx->macData.macSalt, | 110 SECITEM_ZfreeItem(vpwd, PR_TRUE); |
114 » » » » » » (pfx->old ? pwitem : vpwd)); | 111 } |
115 » /* free vpwd only for newer PFX */ | 112 if (key == NULL) { |
116 » if(vpwd) { | 113 return PR_FALSE; |
117 » » SECITEM_ZfreeItem(vpwd, PR_TRUE); | 114 } |
118 » } | 115 |
119 » if(key == NULL) { | 116 data = SEC_PKCS7GetContent(&pfx->authSafe); |
120 » » return PR_FALSE; | 117 if (data == NULL) { |
121 » } | 118 break; |
122 | 119 } |
123 » data = SEC_PKCS7GetContent(&pfx->authSafe); | 120 |
124 » if(data == NULL) { | 121 /* check MAC */ |
125 » » break; | 122 mac = sec_pkcs12_generate_mac(key, data, pfx->old); |
126 » } | 123 ret = PR_TRUE; |
127 | 124 if (mac) { |
128 » /* check MAC */ | 125 SECItem *safeMac = &pfx->macData.safeMac.digest; |
129 » mac = sec_pkcs12_generate_mac(key, data, pfx->old); | 126 if (SECITEM_CompareItem(mac, safeMac) != SECEqual) { |
130 » ret = PR_TRUE; | 127 |
131 » if(mac) { | 128 /* if we encounter an invalid mac, lets invert the |
132 » » SECItem *safeMac = &pfx->macData.safeMac.digest; | 129 * password in case of unicode changes |
133 » » if(SECITEM_CompareItem(mac, safeMac) != SECEqual) { | 130 */ |
134 | 131 if (((!pfx->old) && pfx->swapUnicode) || (pfx->old)) { |
135 » » /* if we encounter an invalid mac, lets invert the | 132 PORT_SetError(SEC_ERROR_PKCS12_INVALID_MAC); |
136 » » * password in case of unicode changes· | 133 ret = PR_FALSE; |
137 » » */ | 134 } else { |
138 » » if(((!pfx->old) && pfx->swapUnicode) || (pfx->old)){ | 135 SECITEM_ZfreeItem(mac, PR_TRUE); |
139 » » » PORT_SetError(SEC_ERROR_PKCS12_INVALID_MAC); | 136 pfx->swapUnicode = PR_TRUE; |
140 » » » ret = PR_FALSE; | 137 goto recheckUnicodePassword; |
141 » » } else { | 138 } |
142 » » » SECITEM_ZfreeItem(mac, PR_TRUE); | 139 } |
143 » » » pfx->swapUnicode = PR_TRUE; | 140 SECITEM_ZfreeItem(mac, PR_TRUE); |
144 » » » goto recheckUnicodePassword; | 141 } else { |
145 » » } | 142 ret = PR_FALSE; |
146 » » }· | 143 } |
147 » » SECITEM_ZfreeItem(mac, PR_TRUE); | 144 break; |
148 » } else { | 145 default: |
149 » » ret = PR_FALSE; | 146 PORT_SetError(SEC_ERROR_PKCS12_UNSUPPORTED_MAC_ALGORITHM); |
150 » } | 147 ret = PR_FALSE; |
151 » break; | 148 break; |
152 » default: | 149 } |
153 » PORT_SetError(SEC_ERROR_PKCS12_UNSUPPORTED_MAC_ALGORITHM); | 150 |
154 » ret = PR_FALSE; | 151 /* let success fall through */ |
155 » break; | 152 if (key != NULL) SECITEM_ZfreeItem(key, PR_TRUE); |
156 } | 153 |
157 | 154 return ret; |
158 /* let success fall through */ | |
159 if(key != NULL) | |
160 » SECITEM_ZfreeItem(key, PR_TRUE); | |
161 | |
162 return ret; | |
163 } | 155 } |
164 | 156 |
165 /* check the validity of the pfx structure. we currently only support | 157 /* check the validity of the pfx structure. we currently only support |
166 * password integrity mode, so we check the MAC. | 158 * password integrity mode, so we check the MAC. |
167 */ | 159 */ |
168 static PRBool | 160 static PRBool sec_pkcs12_validate_pfx(SEC_PKCS12PFXItem *pfx, SECItem *pwitem) { |
169 sec_pkcs12_validate_pfx(SEC_PKCS12PFXItem *pfx, | 161 SECOidTag contentType; |
170 » » » SECItem *pwitem) | 162 |
171 { | 163 contentType = SEC_PKCS7ContentType(&pfx->authSafe); |
172 SECOidTag contentType; | 164 switch (contentType) { |
173 | 165 case SEC_OID_PKCS7_DATA: |
174 contentType = SEC_PKCS7ContentType(&pfx->authSafe); | 166 return sec_pkcs12_check_pfx_mac(pfx, pwitem); |
175 switch(contentType) | 167 break; |
176 { | 168 case SEC_OID_PKCS7_SIGNED_DATA: |
177 » case SEC_OID_PKCS7_DATA: | 169 default: |
178 » return sec_pkcs12_check_pfx_mac(pfx, pwitem); | 170 PORT_SetError(SEC_ERROR_PKCS12_UNSUPPORTED_TRANSPORT_MODE); |
179 » break; | 171 break; |
180 » case SEC_OID_PKCS7_SIGNED_DATA: | 172 } |
181 » default: | 173 |
182 » PORT_SetError(SEC_ERROR_PKCS12_UNSUPPORTED_TRANSPORT_MODE); | 174 return PR_FALSE; |
183 » break; | |
184 } | |
185 | |
186 return PR_FALSE; | |
187 } | 175 } |
188 | 176 |
189 /* decode and return the valid PFX. if the PFX item is not valid, | 177 /* decode and return the valid PFX. if the PFX item is not valid, |
190 * NULL is returned. | 178 * NULL is returned. |
191 */ | 179 */ |
192 static SEC_PKCS12PFXItem * | 180 static SEC_PKCS12PFXItem *sec_pkcs12_get_pfx(SECItem *pfx_data, |
193 sec_pkcs12_get_pfx(SECItem *pfx_data,· | 181 SECItem *pwitem) { |
194 » » SECItem *pwitem) | 182 SEC_PKCS12PFXItem *pfx; |
195 { | 183 PRBool valid_pfx; |
196 SEC_PKCS12PFXItem *pfx; | 184 |
197 PRBool valid_pfx; | 185 if ((pfx_data == NULL) || (pwitem == NULL)) { |
198 | 186 return NULL; |
199 if((pfx_data == NULL) || (pwitem == NULL)) { | 187 } |
200 » return NULL; | 188 |
201 } | 189 pfx = sec_pkcs12_decode_pfx(pfx_data); |
202 | 190 if (pfx == NULL) { |
203 pfx = sec_pkcs12_decode_pfx(pfx_data); | 191 return NULL; |
204 if(pfx == NULL) { | 192 } |
205 » return NULL; | 193 |
206 } | 194 valid_pfx = sec_pkcs12_validate_pfx(pfx, pwitem); |
207 | 195 if (valid_pfx != PR_TRUE) { |
208 valid_pfx = sec_pkcs12_validate_pfx(pfx, pwitem); | 196 SEC_PKCS12DestroyPFX(pfx); |
209 if(valid_pfx != PR_TRUE) { | 197 pfx = NULL; |
210 » SEC_PKCS12DestroyPFX(pfx); | 198 } |
211 » pfx = NULL; | 199 |
212 } | 200 return pfx; |
213 | |
214 return pfx; | |
215 } | 201 } |
216 | 202 |
217 /* authenticated safe decoding, validation, and access routines | 203 /* authenticated safe decoding, validation, and access routines |
218 */ | 204 */ |
219 | 205 |
220 /* convert dogbert beta 3 authenticated safe structure to a post | 206 /* convert dogbert beta 3 authenticated safe structure to a post |
221 * beta three structure, so that we don't have to change more routines. | 207 * beta three structure, so that we don't have to change more routines. |
222 */ | 208 */ |
223 static SECStatus | 209 static SECStatus sec_pkcs12_convert_old_auth_safe( |
224 sec_pkcs12_convert_old_auth_safe(SEC_PKCS12AuthenticatedSafe *asafe) | 210 SEC_PKCS12AuthenticatedSafe *asafe) { |
225 { | 211 SEC_PKCS12Baggage *baggage; |
226 SEC_PKCS12Baggage *baggage; | 212 SEC_PKCS12BaggageItem *bag; |
227 SEC_PKCS12BaggageItem *bag; | 213 SECStatus rv = SECSuccess; |
228 SECStatus rv = SECSuccess; | 214 |
229 | 215 if (asafe->old_baggage.espvks == NULL) { |
230 if(asafe->old_baggage.espvks == NULL) { | 216 /* XXX should the ASN1 engine produce a single NULL element list |
231 » /* XXX should the ASN1 engine produce a single NULL element list | 217 * rather than setting the pointer to NULL? |
232 » * rather than setting the pointer to NULL?·· | 218 * There is no need to return an error -- assume that the list |
233 » * There is no need to return an error -- assume that the list | 219 * was empty. |
234 » * was empty. | 220 */ |
235 » */ | 221 return SECSuccess; |
236 » return SECSuccess; | 222 } |
237 } | 223 |
238 | 224 baggage = sec_pkcs12_create_baggage(asafe->poolp); |
239 baggage = sec_pkcs12_create_baggage(asafe->poolp); | 225 if (!baggage) { |
240 if(!baggage) { | 226 return SECFailure; |
241 » return SECFailure; | 227 } |
242 } | 228 bag = sec_pkcs12_create_external_bag(baggage); |
243 bag = sec_pkcs12_create_external_bag(baggage); | 229 if (!bag) { |
244 if(!bag) { | 230 return SECFailure; |
245 » return SECFailure; | 231 } |
246 } | 232 |
247 | 233 PORT_Memcpy(&asafe->baggage, baggage, sizeof(SEC_PKCS12Baggage)); |
248 PORT_Memcpy(&asafe->baggage, baggage, sizeof(SEC_PKCS12Baggage)); | 234 |
249 | 235 /* if there are shrouded keys, append them to the bag */ |
250 /* if there are shrouded keys, append them to the bag */ | 236 rv = SECSuccess; |
| 237 if (asafe->old_baggage.espvks[0] != NULL) { |
| 238 int nEspvk = 0; |
251 rv = SECSuccess; | 239 rv = SECSuccess; |
252 if(asafe->old_baggage.espvks[0] != NULL) { | 240 while ((asafe->old_baggage.espvks[nEspvk] != NULL) && (rv == SECSuccess)) { |
253 » int nEspvk = 0; | 241 rv = sec_pkcs12_append_shrouded_key(bag, |
254 » rv = SECSuccess; | 242 asafe->old_baggage.espvks[nEspvk]); |
255 » while((asafe->old_baggage.espvks[nEspvk] != NULL) && | 243 nEspvk++; |
256 » » (rv == SECSuccess)) { | 244 } |
257 » rv = sec_pkcs12_append_shrouded_key(bag, | 245 } |
258 » » » » » asafe->old_baggage.espvks[nEspvk]); | 246 |
259 » nEspvk++; | 247 return rv; |
260 » } | 248 } |
261 } | |
262 | |
263 return rv; | |
264 } | |
265 | 249 |
266 /* decodes the authenticated safe item. a return of NULL indicates | 250 /* decodes the authenticated safe item. a return of NULL indicates |
267 * an error. however, the error will have occurred either in memory | 251 * an error. however, the error will have occurred either in memory |
268 * allocation or in decoding the authenticated safe. | 252 * allocation or in decoding the authenticated safe. |
269 * | 253 * |
270 * if an old PFX item has been found, we want to convert the | 254 * if an old PFX item has been found, we want to convert the |
271 * old authenticated safe to the new one. | 255 * old authenticated safe to the new one. |
272 */ | 256 */ |
273 static SEC_PKCS12AuthenticatedSafe * | 257 static SEC_PKCS12AuthenticatedSafe *sec_pkcs12_decode_authenticated_safe( |
274 sec_pkcs12_decode_authenticated_safe(SEC_PKCS12PFXItem *pfx) | 258 SEC_PKCS12PFXItem *pfx) { |
275 { | 259 SECItem *der_asafe = NULL; |
276 SECItem *der_asafe = NULL; | 260 SEC_PKCS12AuthenticatedSafe *asafe = NULL; |
277 SEC_PKCS12AuthenticatedSafe *asafe = NULL; | 261 SECStatus rv; |
278 SECStatus rv; | 262 |
279 | 263 if (pfx == NULL) { |
280 if(pfx == NULL) { | 264 return NULL; |
281 » return NULL; | 265 } |
282 } | 266 |
283 | 267 der_asafe = SEC_PKCS7GetContent(&pfx->authSafe); |
284 der_asafe = SEC_PKCS7GetContent(&pfx->authSafe); | 268 if (der_asafe == NULL) { |
285 if(der_asafe == NULL) { | 269 /* XXX set error ? */ |
286 » /* XXX set error ? */ | 270 goto loser; |
287 » goto loser; | 271 } |
288 } | 272 |
289 | 273 asafe = sec_pkcs12_new_asafe(pfx->poolp); |
290 asafe = sec_pkcs12_new_asafe(pfx->poolp); | 274 if (asafe == NULL) { |
291 if(asafe == NULL) { | 275 goto loser; |
292 » goto loser; | 276 } |
293 } | 277 |
294 | 278 if (pfx->old == PR_FALSE) { |
295 if(pfx->old == PR_FALSE) { | 279 rv = SEC_ASN1DecodeItem(pfx->poolp, asafe, |
296 » rv = SEC_ASN1DecodeItem(pfx->poolp, asafe,· | 280 SEC_PKCS12AuthenticatedSafeTemplate, der_asafe); |
297 » » » » SEC_PKCS12AuthenticatedSafeTemplate, | 281 asafe->old = PR_FALSE; |
298 » » » » der_asafe); | 282 asafe->swapUnicode = pfx->swapUnicode; |
299 » asafe->old = PR_FALSE; | 283 } else { |
300 » asafe->swapUnicode = pfx->swapUnicode; | 284 /* handle beta exported files */ |
301 } else { | 285 rv = SEC_ASN1DecodeItem(pfx->poolp, asafe, |
302 » /* handle beta exported files */ | 286 SEC_PKCS12AuthenticatedSafeTemplate_OLD, der_asafe); |
303 » rv = SEC_ASN1DecodeItem(pfx->poolp, asafe,· | 287 asafe->safe = &(asafe->old_safe); |
304 » » » » SEC_PKCS12AuthenticatedSafeTemplate_OLD, | 288 rv = sec_pkcs12_convert_old_auth_safe(asafe); |
305 » » » » der_asafe); | 289 asafe->old = PR_TRUE; |
306 » asafe->safe = &(asafe->old_safe); | 290 } |
307 » rv = sec_pkcs12_convert_old_auth_safe(asafe); | 291 |
308 » asafe->old = PR_TRUE; | 292 if (rv != SECSuccess) { |
309 } | 293 goto loser; |
310 | 294 } |
311 if(rv != SECSuccess) { | 295 |
312 » goto loser; | 296 asafe->poolp = pfx->poolp; |
313 } | 297 |
314 | 298 return asafe; |
315 asafe->poolp = pfx->poolp; | |
316 ···· | |
317 return asafe; | |
318 | 299 |
319 loser: | 300 loser: |
320 return NULL; | 301 return NULL; |
321 } | 302 } |
322 | 303 |
323 /* validates the safe within the authenticated safe item. | 304 /* validates the safe within the authenticated safe item. |
324 * in order to be valid: | 305 * in order to be valid: |
325 * 1. the privacy salt must be present | 306 * 1. the privacy salt must be present |
326 * 2. the encryption algorithm must be supported (including | 307 * 2. the encryption algorithm must be supported (including |
327 * export policy) | 308 * export policy) |
328 * PR_FALSE indicates an error, PR_TRUE indicates a valid safe | 309 * PR_FALSE indicates an error, PR_TRUE indicates a valid safe |
329 */ | 310 */ |
330 static PRBool· | 311 static PRBool sec_pkcs12_validate_encrypted_safe( |
331 sec_pkcs12_validate_encrypted_safe(SEC_PKCS12AuthenticatedSafe *asafe) | 312 SEC_PKCS12AuthenticatedSafe *asafe) { |
332 { | 313 PRBool valid = PR_FALSE; |
333 PRBool valid = PR_FALSE; | 314 SECAlgorithmID *algid; |
334 SECAlgorithmID *algid; | 315 |
335 | 316 if (asafe == NULL) { |
336 if(asafe == NULL) { | 317 return PR_FALSE; |
337 » return PR_FALSE; | 318 } |
338 } | 319 |
339 | 320 /* if mode is password privacy, then privacySalt is assumed |
340 /* if mode is password privacy, then privacySalt is assumed | 321 * to be non-zero. |
341 * to be non-zero. | 322 */ |
342 */ | 323 if (asafe->privacySalt.len != 0) { |
343 if(asafe->privacySalt.len != 0) { | 324 valid = PR_TRUE; |
344 » valid = PR_TRUE; | 325 asafe->privacySalt.len /= 8; |
345 » asafe->privacySalt.len /= 8; | 326 } else { |
| 327 PORT_SetError(SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE); |
| 328 return PR_FALSE; |
| 329 } |
| 330 |
| 331 /* until spec changes, content will have between 2 and 8 bytes depending |
| 332 * upon the algorithm used if certs are unencrypted... |
| 333 * also want to support case where content is empty -- which we produce |
| 334 */ |
| 335 if (SEC_PKCS7IsContentEmpty(asafe->safe, 8) == PR_TRUE) { |
| 336 asafe->emptySafe = PR_TRUE; |
| 337 return PR_TRUE; |
| 338 } |
| 339 |
| 340 asafe->emptySafe = PR_FALSE; |
| 341 |
| 342 /* make sure that a pbe algorithm is being used */ |
| 343 algid = SEC_PKCS7GetEncryptionAlgorithm(asafe->safe); |
| 344 if (algid != NULL) { |
| 345 if (SEC_PKCS5IsAlgorithmPBEAlg(algid)) { |
| 346 valid = SEC_PKCS12DecryptionAllowed(algid); |
| 347 |
| 348 if (valid == PR_FALSE) { |
| 349 PORT_SetError(SEC_ERROR_BAD_EXPORT_ALGORITHM); |
| 350 } |
346 } else { | 351 } else { |
347 » PORT_SetError(SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE); | 352 PORT_SetError(SEC_ERROR_PKCS12_UNSUPPORTED_PBE_ALGORITHM); |
348 » return PR_FALSE; | 353 valid = PR_FALSE; |
349 } | 354 } |
350 | 355 } else { |
351 /* until spec changes, content will have between 2 and 8 bytes depending | 356 valid = PR_FALSE; |
352 * upon the algorithm used if certs are unencrypted... | 357 PORT_SetError(SEC_ERROR_PKCS12_UNSUPPORTED_PBE_ALGORITHM); |
353 * also want to support case where content is empty -- which we produce· | 358 } |
354 */· | 359 |
355 if(SEC_PKCS7IsContentEmpty(asafe->safe, 8) == PR_TRUE) { | 360 return valid; |
356 » asafe->emptySafe = PR_TRUE; | |
357 » return PR_TRUE; | |
358 } | |
359 | |
360 asafe->emptySafe = PR_FALSE; | |
361 | |
362 /* make sure that a pbe algorithm is being used */ | |
363 algid = SEC_PKCS7GetEncryptionAlgorithm(asafe->safe); | |
364 if(algid != NULL) { | |
365 » if(SEC_PKCS5IsAlgorithmPBEAlg(algid)) { | |
366 » valid = SEC_PKCS12DecryptionAllowed(algid); | |
367 | |
368 » if(valid == PR_FALSE) { | |
369 » » PORT_SetError(SEC_ERROR_BAD_EXPORT_ALGORITHM); | |
370 » } | |
371 » } else { | |
372 » PORT_SetError(SEC_ERROR_PKCS12_UNSUPPORTED_PBE_ALGORITHM); | |
373 » valid = PR_FALSE; | |
374 » } | |
375 } else { | |
376 » valid = PR_FALSE; | |
377 » PORT_SetError(SEC_ERROR_PKCS12_UNSUPPORTED_PBE_ALGORITHM); | |
378 } | |
379 | |
380 return valid; | |
381 } | 361 } |
382 | 362 |
383 /* validates authenticates safe: | 363 /* validates authenticates safe: |
384 * 1. checks that the version is supported | 364 * 1. checks that the version is supported |
385 * 2. checks that only password privacy mode is used (currently) | 365 * 2. checks that only password privacy mode is used (currently) |
386 * 3. further, makes sure safe has appropriate policies per above function | 366 * 3. further, makes sure safe has appropriate policies per above function |
387 * PR_FALSE indicates failure. | 367 * PR_FALSE indicates failure. |
388 */ | 368 */ |
389 static PRBool | 369 static PRBool sec_pkcs12_validate_auth_safe( |
390 sec_pkcs12_validate_auth_safe(SEC_PKCS12AuthenticatedSafe *asafe) | 370 SEC_PKCS12AuthenticatedSafe *asafe) { |
391 { | 371 PRBool valid = PR_TRUE; |
392 PRBool valid = PR_TRUE; | 372 SECOidTag safe_type; |
393 SECOidTag safe_type; | 373 int version; |
394 int version; | 374 |
395 | 375 if (asafe == NULL) { |
396 if(asafe == NULL) { | 376 return PR_FALSE; |
397 » return PR_FALSE; | 377 } |
398 } | 378 |
399 | 379 /* check version, since it is default it may not be present. |
400 /* check version, since it is default it may not be present. | 380 * therefore, assume ok |
401 * therefore, assume ok | 381 */ |
402 */ | 382 if ((asafe->version.len > 0) && (asafe->old == PR_FALSE)) { |
403 if((asafe->version.len > 0) && (asafe->old == PR_FALSE)) { | 383 version = DER_GetInteger(&asafe->version); |
404 » version = DER_GetInteger(&asafe->version); | 384 if (version > SEC_PKCS12_PFX_VERSION) { |
405 » if(version > SEC_PKCS12_PFX_VERSION) { | 385 PORT_SetError(SEC_ERROR_PKCS12_UNSUPPORTED_VERSION); |
406 » PORT_SetError(SEC_ERROR_PKCS12_UNSUPPORTED_VERSION); | 386 return PR_FALSE; |
407 » return PR_FALSE; | 387 } |
408 » } | 388 } |
409 } | 389 |
410 | 390 /* validate password mode is being used */ |
411 /* validate password mode is being used */ | 391 safe_type = SEC_PKCS7ContentType(asafe->safe); |
412 safe_type = SEC_PKCS7ContentType(asafe->safe); | 392 switch (safe_type) { |
413 switch(safe_type) | 393 case SEC_OID_PKCS7_ENCRYPTED_DATA: |
414 { | 394 valid = sec_pkcs12_validate_encrypted_safe(asafe); |
415 » case SEC_OID_PKCS7_ENCRYPTED_DATA: | 395 break; |
416 » valid = sec_pkcs12_validate_encrypted_safe(asafe); | 396 case SEC_OID_PKCS7_ENVELOPED_DATA: |
417 » break; | 397 default: |
418 » case SEC_OID_PKCS7_ENVELOPED_DATA: | 398 PORT_SetError(SEC_ERROR_PKCS12_UNSUPPORTED_TRANSPORT_MODE); |
419 » default: | 399 valid = PR_FALSE; |
420 » PORT_SetError(SEC_ERROR_PKCS12_UNSUPPORTED_TRANSPORT_MODE); | 400 break; |
421 » valid = PR_FALSE; | 401 } |
422 » break; | 402 |
423 } | 403 return valid; |
424 | |
425 return valid; | |
426 } | 404 } |
427 | 405 |
428 /* retrieves the authenticated safe item from the PFX item | 406 /* retrieves the authenticated safe item from the PFX item |
429 * before returning the authenticated safe, the validity of the | 407 * before returning the authenticated safe, the validity of the |
430 * authenticated safe is checked and if valid, returned. | 408 * authenticated safe is checked and if valid, returned. |
431 * a return of NULL indicates that an error occurred. | 409 * a return of NULL indicates that an error occurred. |
432 */ | 410 */ |
433 static SEC_PKCS12AuthenticatedSafe * | 411 static SEC_PKCS12AuthenticatedSafe *sec_pkcs12_get_auth_safe( |
434 sec_pkcs12_get_auth_safe(SEC_PKCS12PFXItem *pfx) | 412 SEC_PKCS12PFXItem *pfx) { |
435 { | 413 SEC_PKCS12AuthenticatedSafe *asafe; |
436 SEC_PKCS12AuthenticatedSafe *asafe; | 414 PRBool valid_safe; |
437 PRBool valid_safe; | 415 |
438 | 416 if (pfx == NULL) { |
439 if(pfx == NULL) { | 417 return NULL; |
440 » return NULL; | 418 } |
441 } | 419 |
442 | 420 asafe = sec_pkcs12_decode_authenticated_safe(pfx); |
443 asafe = sec_pkcs12_decode_authenticated_safe(pfx); | 421 if (asafe == NULL) { |
444 if(asafe == NULL) { | 422 return NULL; |
445 » return NULL; | 423 } |
446 } | 424 |
447 | 425 valid_safe = sec_pkcs12_validate_auth_safe(asafe); |
448 valid_safe = sec_pkcs12_validate_auth_safe(asafe); | 426 if (valid_safe != PR_TRUE) { |
449 if(valid_safe != PR_TRUE) { | 427 asafe = NULL; |
450 » asafe = NULL; | 428 } else if (asafe) { |
451 } else if(asafe) { | 429 asafe->baggage.poolp = asafe->poolp; |
452 » asafe->baggage.poolp = asafe->poolp; | 430 } |
453 } | 431 |
454 | 432 return asafe; |
455 return asafe; | |
456 } | 433 } |
457 | 434 |
458 /* decrypts the authenticated safe. | 435 /* decrypts the authenticated safe. |
459 * a return of anything but SECSuccess indicates an error. the | 436 * a return of anything but SECSuccess indicates an error. the |
460 * password is not known to be valid until the call to the | 437 * password is not known to be valid until the call to the |
461 * function sec_pkcs12_get_safe_contents. If decoding the safe | 438 * function sec_pkcs12_get_safe_contents. If decoding the safe |
462 * fails, it is assumed the password was incorrect and the error | 439 * fails, it is assumed the password was incorrect and the error |
463 * is set then. any failure here is assumed to be due to | 440 * is set then. any failure here is assumed to be due to |
464 * internal problems in SEC_PKCS7DecryptContents or below. | 441 * internal problems in SEC_PKCS7DecryptContents or below. |
465 */ | 442 */ |
466 static SECStatus | 443 static SECStatus sec_pkcs12_decrypt_auth_safe( |
467 sec_pkcs12_decrypt_auth_safe(SEC_PKCS12AuthenticatedSafe *asafe,· | 444 SEC_PKCS12AuthenticatedSafe *asafe, SECItem *pwitem, void *wincx) { |
468 » » » SECItem *pwitem, | 445 SECStatus rv = SECFailure; |
469 » » » void *wincx) | 446 SECItem *vpwd = NULL; |
470 { | 447 |
471 SECStatus rv = SECFailure; | 448 if ((asafe == NULL) || (pwitem == NULL)) { |
472 SECItem *vpwd = NULL; | 449 return SECFailure; |
473 | 450 } |
474 if((asafe == NULL) || (pwitem == NULL)) { | 451 |
475 » return SECFailure; | 452 if (asafe->old == PR_FALSE) { |
476 } | 453 vpwd = sec_pkcs12_create_virtual_password(pwitem, &asafe->privacySalt, |
477 | 454 asafe->swapUnicode); |
478 if(asafe->old == PR_FALSE) { | 455 if (vpwd == NULL) { |
479 » vpwd = sec_pkcs12_create_virtual_password(pwitem, &asafe->privacySalt, | 456 return SECFailure; |
480 » » » » » » asafe->swapUnicode); | 457 } |
481 » if(vpwd == NULL) { | 458 } |
482 » return SECFailure; | 459 |
483 » } | 460 rv = SEC_PKCS7DecryptContents(asafe->poolp, asafe->safe, |
484 } | 461 (asafe->old ? pwitem : vpwd), wincx); |
485 | 462 |
486 rv = SEC_PKCS7DecryptContents(asafe->poolp, asafe->safe,· | 463 if (asafe->old == PR_FALSE) { |
487 » » » » (asafe->old ? pwitem : vpwd), wincx); | 464 SECITEM_ZfreeItem(vpwd, PR_TRUE); |
488 | 465 } |
489 if(asafe->old == PR_FALSE) { | 466 |
490 » SECITEM_ZfreeItem(vpwd, PR_TRUE); | 467 return rv; |
491 } | |
492 | |
493 return rv; | |
494 } | 468 } |
495 | 469 |
496 /* extract the safe from the authenticated safe. | 470 /* extract the safe from the authenticated safe. |
497 * if we are unable to decode the safe, then it is likely that the | 471 * if we are unable to decode the safe, then it is likely that the |
498 * safe has not been decrypted or the password used to decrypt | 472 * safe has not been decrypted or the password used to decrypt |
499 * the safe was invalid. we assume that the password was invalid and | 473 * the safe was invalid. we assume that the password was invalid and |
500 * set an error accordingly. | 474 * set an error accordingly. |
501 * a return of NULL indicates that an error occurred. | 475 * a return of NULL indicates that an error occurred. |
502 */ | 476 */ |
503 static SEC_PKCS12SafeContents * | 477 static SEC_PKCS12SafeContents *sec_pkcs12_get_safe_contents( |
504 sec_pkcs12_get_safe_contents(SEC_PKCS12AuthenticatedSafe *asafe) | 478 SEC_PKCS12AuthenticatedSafe *asafe) { |
505 { | 479 SECItem *src = NULL; |
506 SECItem *src = NULL; | 480 SEC_PKCS12SafeContents *safe = NULL; |
507 SEC_PKCS12SafeContents *safe = NULL; | 481 SECStatus rv = SECFailure; |
508 SECStatus rv = SECFailure; | 482 |
509 | 483 if (asafe == NULL) { |
510 if(asafe == NULL) { | 484 return NULL; |
511 » return NULL; | 485 } |
512 } | 486 |
513 | 487 safe = (SEC_PKCS12SafeContents *)PORT_ArenaZAlloc( |
514 safe = (SEC_PKCS12SafeContents *)PORT_ArenaZAlloc(asafe->poolp, | 488 asafe->poolp, sizeof(SEC_PKCS12SafeContents)); |
515 » » » » » » sizeof(SEC_PKCS12SafeContents)); | 489 if (safe == NULL) { |
516 if(safe == NULL) { | 490 return NULL; |
517 » return NULL; | 491 } |
518 } | 492 safe->poolp = asafe->poolp; |
519 safe->poolp = asafe->poolp; | 493 safe->old = asafe->old; |
520 safe->old = asafe->old; | 494 safe->swapUnicode = asafe->swapUnicode; |
521 safe->swapUnicode = asafe->swapUnicode; | 495 |
522 | 496 src = SEC_PKCS7GetContent(asafe->safe); |
523 src = SEC_PKCS7GetContent(asafe->safe); | 497 if (src != NULL) { |
524 if(src != NULL) { | 498 const SEC_ASN1Template *theTemplate; |
525 » const SEC_ASN1Template *theTemplate; | 499 if (asafe->old != PR_TRUE) { |
526 » if(asafe->old != PR_TRUE) { | 500 theTemplate = SEC_PKCS12SafeContentsTemplate; |
527 » theTemplate = SEC_PKCS12SafeContentsTemplate; | |
528 » } else { | |
529 » theTemplate = SEC_PKCS12SafeContentsTemplate_OLD; | |
530 » } | |
531 | |
532 » rv = SEC_ASN1DecodeItem(asafe->poolp, safe, theTemplate, src); | |
533 | |
534 » /* if we could not decode the item, password was probably invalid */ | |
535 » if(rv != SECSuccess) { | |
536 » safe = NULL; | |
537 » PORT_SetError(SEC_ERROR_PKCS12_PRIVACY_PASSWORD_INCORRECT); | |
538 » } | |
539 } else { | 501 } else { |
540 » PORT_SetError(SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE); | 502 theTemplate = SEC_PKCS12SafeContentsTemplate_OLD; |
541 » rv = SECFailure; | 503 } |
542 } | 504 |
543 | 505 rv = SEC_ASN1DecodeItem(asafe->poolp, safe, theTemplate, src); |
544 return safe; | 506 |
545 } | 507 /* if we could not decode the item, password was probably invalid */ |
546 | 508 if (rv != SECSuccess) { |
547 /* import PFX item· | 509 safe = NULL; |
| 510 PORT_SetError(SEC_ERROR_PKCS12_PRIVACY_PASSWORD_INCORRECT); |
| 511 } |
| 512 } else { |
| 513 PORT_SetError(SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE); |
| 514 rv = SECFailure; |
| 515 } |
| 516 |
| 517 return safe; |
| 518 } |
| 519 |
| 520 /* import PFX item |
548 * der_pfx is the der encoded pfx structure | 521 * der_pfx is the der encoded pfx structure |
549 * pbef and pbearg are the integrity/encryption password call back | 522 * pbef and pbearg are the integrity/encryption password call back |
550 * ncCall is the nickname collision calllback | 523 * ncCall is the nickname collision calllback |
551 * slot is the destination token | 524 * slot is the destination token |
552 * wincx window handler | 525 * wincx window handler |
553 * | 526 * |
554 * on error, error code set and SECFailure returned | 527 * on error, error code set and SECFailure returned |
555 */ | 528 */ |
556 SECStatus | 529 SECStatus SEC_PKCS12PutPFX(SECItem *der_pfx, SECItem *pwitem, |
557 SEC_PKCS12PutPFX(SECItem *der_pfx, SECItem *pwitem, | 530 SEC_PKCS12NicknameCollisionCallback ncCall, |
558 » » SEC_PKCS12NicknameCollisionCallback ncCall, | 531 PK11SlotInfo *slot, void *wincx) { |
559 » » PK11SlotInfo *slot, | 532 SEC_PKCS12PFXItem *pfx; |
560 » » void *wincx) | 533 SEC_PKCS12AuthenticatedSafe *asafe; |
561 { | 534 SEC_PKCS12SafeContents *safe_contents = NULL; |
562 SEC_PKCS12PFXItem *pfx; | 535 SECStatus rv; |
563 SEC_PKCS12AuthenticatedSafe *asafe; | 536 |
564 SEC_PKCS12SafeContents *safe_contents = NULL; | 537 if (!der_pfx || !pwitem || !slot) { |
565 SECStatus rv; | 538 return SECFailure; |
566 | 539 } |
567 if(!der_pfx || !pwitem || !slot) { | 540 |
568 » return SECFailure; | 541 /* decode and validate each section */ |
569 } | 542 rv = SECFailure; |
570 | 543 |
571 /* decode and validate each section */ | 544 pfx = sec_pkcs12_get_pfx(der_pfx, pwitem); |
572 rv = SECFailure; | 545 if (pfx != NULL) { |
573 | 546 asafe = sec_pkcs12_get_auth_safe(pfx); |
574 pfx = sec_pkcs12_get_pfx(der_pfx, pwitem); | 547 if (asafe != NULL) { |
575 if(pfx != NULL) { | 548 |
576 » asafe = sec_pkcs12_get_auth_safe(pfx); | 549 /* decrypt safe -- only if not empty */ |
577 » if(asafe != NULL) { | 550 if (asafe->emptySafe != PR_TRUE) { |
578 | 551 rv = sec_pkcs12_decrypt_auth_safe(asafe, pwitem, wincx); |
579 » /* decrypt safe -- only if not empty */ | 552 if (rv == SECSuccess) { |
580 » if(asafe->emptySafe != PR_TRUE) { | 553 safe_contents = sec_pkcs12_get_safe_contents(asafe); |
581 » » rv = sec_pkcs12_decrypt_auth_safe(asafe, pwitem, wincx); | 554 if (safe_contents == NULL) { |
582 » » if(rv == SECSuccess) { | 555 rv = SECFailure; |
583 » » safe_contents = sec_pkcs12_get_safe_contents(asafe); | 556 } |
584 » » if(safe_contents == NULL) { | 557 } |
585 » » » rv = SECFailure; | 558 } else { |
586 » » } | 559 safe_contents = sec_pkcs12_create_safe_contents(asafe->poolp); |
587 » » } | 560 if (safe_contents == NULL) { |
588 » } else { | 561 rv = SECFailure; |
589 » » safe_contents = sec_pkcs12_create_safe_contents(asafe->poolp); | 562 } else { |
590 » » if(safe_contents == NULL) { | 563 safe_contents->swapUnicode = pfx->swapUnicode; |
591 » » rv = SECFailure; | 564 rv = SECSuccess; |
592 » » } else { | 565 } |
593 safe_contents->swapUnicode = pfx->swapUnicode; | 566 } |
594 » » rv = SECSuccess; | 567 |
595 » » } | 568 /* get safe contents and begin import */ |
596 » } | 569 if (rv == SECSuccess) { |
597 | 570 SEC_PKCS12DecoderContext *p12dcx; |
598 » /* get safe contents and begin import */ | 571 |
599 » if(rv == SECSuccess) { | 572 p12dcx = sec_PKCS12ConvertOldSafeToNew(pfx->poolp, slot, |
600 » » SEC_PKCS12DecoderContext *p12dcx; | 573 pfx->swapUnicode, pwitem, wincx, |
601 | 574 safe_contents, &asafe->baggage); |
602 » » p12dcx = sec_PKCS12ConvertOldSafeToNew(pfx->poolp, slot, | 575 if (!p12dcx) { |
603 » » » » » pfx->swapUnicode, | 576 rv = SECFailure; |
604 » » » » » pwitem, wincx, safe_contents, | 577 goto loser; |
605 » » » » » &asafe->baggage); | 578 } |
606 » » if(!p12dcx) { | 579 |
607 » » rv = SECFailure; | 580 if (SEC_PKCS12DecoderValidateBags(p12dcx, ncCall) != SECSuccess) { |
608 » » goto loser; | 581 rv = SECFailure; |
609 » » } | 582 goto loser; |
610 | 583 } |
611 » » if(SEC_PKCS12DecoderValidateBags(p12dcx, ncCall) | 584 |
612 » » » » != SECSuccess) { | 585 rv = SEC_PKCS12DecoderImportBags(p12dcx); |
613 » » rv = SECFailure; | 586 } |
614 » » goto loser; | 587 } |
615 » » } | 588 } |
616 | |
617 » » rv = SEC_PKCS12DecoderImportBags(p12dcx); | |
618 » } | |
619 | |
620 » } | |
621 } | |
622 | 589 |
623 loser: | 590 loser: |
624 | 591 |
625 if(pfx) { | 592 if (pfx) { |
626 » SEC_PKCS12DestroyPFX(pfx); | 593 SEC_PKCS12DestroyPFX(pfx); |
627 } | 594 } |
628 | 595 |
629 return rv; | 596 return rv; |
630 } | 597 } |
631 | 598 |
632 PRBool | 599 PRBool SEC_PKCS12ValidData(char *buf, int bufLen, long int totalLength) { |
633 SEC_PKCS12ValidData(char *buf, int bufLen, long int totalLength) | 600 int lengthLength; |
634 { | 601 |
635 int lengthLength; | 602 PRBool valid = PR_FALSE; |
636 | 603 |
637 PRBool valid = PR_FALSE; | 604 if (buf == NULL) { |
638 | 605 return PR_FALSE; |
639 if(buf == NULL) { | 606 } |
640 » return PR_FALSE; | 607 |
641 } | 608 /* check for constructed sequence identifier tag */ |
642 | 609 if (*buf == (SEC_ASN1_CONSTRUCTED | SEC_ASN1_SEQUENCE)) { |
643 /* check for constructed sequence identifier tag */ | 610 totalLength--; /* header byte taken care of */ |
644 if(*buf == (SEC_ASN1_CONSTRUCTED | SEC_ASN1_SEQUENCE)) { | 611 buf++; |
645 » totalLength--; /* header byte taken care of */ | 612 |
646 » buf++; | 613 lengthLength = (long int)SEC_ASN1LengthLength(totalLength - 1); |
647 | 614 if (totalLength > 0x7f) { |
648 » lengthLength = (long int)SEC_ASN1LengthLength(totalLength - 1); | 615 lengthLength--; |
649 » if(totalLength > 0x7f) { | 616 *buf &= 0x7f; /* remove bit 8 indicator */ |
650 » lengthLength--; | 617 if ((*buf - (char)lengthLength) == 0) { |
651 » *buf &= 0x7f; /* remove bit 8 indicator */ | 618 valid = PR_TRUE; |
652 » if((*buf - (char)lengthLength) == 0) { | 619 } |
653 » » valid = PR_TRUE; | 620 } else { |
654 » } | 621 lengthLength--; |
655 » } else { | 622 if ((*buf - (char)lengthLength) == 0) { |
656 » lengthLength--; | 623 valid = PR_TRUE; |
657 » if((*buf - (char)lengthLength) == 0) { | 624 } |
658 » » valid = PR_TRUE; | 625 } |
659 » } | 626 } |
660 » } | 627 |
661 } | 628 return valid; |
662 | 629 } |
663 return valid; | |
664 } | |
OLD | NEW |