/src/wolfssl-openssl-api/src/ssl_p7p12.c
Line | Count | Source |
1 | | /* ssl_p7p12.c |
2 | | * |
3 | | * Copyright (C) 2006-2025 wolfSSL Inc. |
4 | | * |
5 | | * This file is part of wolfSSL. |
6 | | * |
7 | | * wolfSSL is free software; you can redistribute it and/or modify |
8 | | * it under the terms of the GNU General Public License as published by |
9 | | * the Free Software Foundation; either version 3 of the License, or |
10 | | * (at your option) any later version. |
11 | | * |
12 | | * wolfSSL is distributed in the hope that it will be useful, |
13 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 | | * GNU General Public License for more details. |
16 | | * |
17 | | * You should have received a copy of the GNU General Public License |
18 | | * along with this program; if not, write to the Free Software |
19 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA |
20 | | */ |
21 | | |
22 | | #include <wolfssl/wolfcrypt/libwolfssl_sources.h> |
23 | | |
24 | | #if defined(OPENSSL_EXTRA) && (defined(HAVE_FIPS) || defined(HAVE_SELFTEST)) |
25 | | #include <wolfssl/wolfcrypt/pkcs7.h> |
26 | | #endif |
27 | | #if defined(OPENSSL_ALL) && defined(HAVE_PKCS7) |
28 | | #include <wolfssl/openssl/pkcs7.h> |
29 | | #endif |
30 | | |
31 | | #if !defined(WOLFSSL_SSL_P7P12_INCLUDED) |
32 | | #ifndef WOLFSSL_IGNORE_FILE_WARN |
33 | | #warning ssl_p7p12.c does not need to be compiled separately from ssl.c |
34 | | #endif |
35 | | #else |
36 | | |
37 | | #if !defined(WOLFCRYPT_ONLY) && !defined(NO_CERTS) |
38 | | |
39 | | /******************************************************************************* |
40 | | * START OF PKCS7 APIs |
41 | | ******************************************************************************/ |
42 | | #ifdef HAVE_PKCS7 |
43 | | |
44 | | #ifdef OPENSSL_ALL |
45 | | PKCS7* wolfSSL_PKCS7_new(void) |
46 | | { |
47 | | WOLFSSL_PKCS7* pkcs7; |
48 | | int ret = 0; |
49 | | |
50 | | pkcs7 = (WOLFSSL_PKCS7*)XMALLOC(sizeof(WOLFSSL_PKCS7), NULL, |
51 | | DYNAMIC_TYPE_PKCS7); |
52 | | if (pkcs7 != NULL) { |
53 | | XMEMSET(pkcs7, 0, sizeof(WOLFSSL_PKCS7)); |
54 | | ret = wc_PKCS7_Init(&pkcs7->pkcs7, NULL, INVALID_DEVID); |
55 | | } |
56 | | |
57 | | if (ret != 0 && pkcs7 != NULL) { |
58 | | XFREE(pkcs7, NULL, DYNAMIC_TYPE_PKCS7); |
59 | | pkcs7 = NULL; |
60 | | } |
61 | | |
62 | | return (PKCS7*)pkcs7; |
63 | | } |
64 | | |
65 | | /****************************************************************************** |
66 | | * wolfSSL_PKCS7_SIGNED_new - allocates PKCS7 and initialize it for a signed data |
67 | | * |
68 | | * RETURNS: |
69 | | * returns pointer to the PKCS7 structure on success, otherwise returns NULL |
70 | | */ |
71 | | PKCS7_SIGNED* wolfSSL_PKCS7_SIGNED_new(void) |
72 | | { |
73 | | byte signedData[]= { 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x02}; |
74 | | PKCS7* pkcs7 = NULL; |
75 | | |
76 | | if ((pkcs7 = wolfSSL_PKCS7_new()) == NULL) |
77 | | return NULL; |
78 | | pkcs7->contentOID = SIGNED_DATA; |
79 | | if ((wc_PKCS7_SetContentType(pkcs7, signedData, sizeof(signedData))) < 0) { |
80 | | if (pkcs7) { |
81 | | wolfSSL_PKCS7_free(pkcs7); |
82 | | return NULL; |
83 | | } |
84 | | } |
85 | | return pkcs7; |
86 | | } |
87 | | |
88 | | void wolfSSL_PKCS7_free(PKCS7* pkcs7) |
89 | | { |
90 | | WOLFSSL_PKCS7* p7 = (WOLFSSL_PKCS7*)pkcs7; |
91 | | |
92 | | if (p7 != NULL) { |
93 | | XFREE(p7->data, NULL, DYNAMIC_TYPE_PKCS7); |
94 | | wc_PKCS7_Free(&p7->pkcs7); |
95 | | if (p7->certs) |
96 | | wolfSSL_sk_pop_free(p7->certs, NULL); |
97 | | XFREE(p7, NULL, DYNAMIC_TYPE_PKCS7); |
98 | | } |
99 | | } |
100 | | |
101 | | void wolfSSL_PKCS7_SIGNED_free(PKCS7_SIGNED* p7) |
102 | | { |
103 | | wolfSSL_PKCS7_free(p7); |
104 | | return; |
105 | | } |
106 | | |
107 | | /** |
108 | | * Convert DER/ASN.1 encoded signedData structure to internal PKCS7 |
109 | | * structure. Note, does not support detached content. |
110 | | * |
111 | | * p7 - pointer to set to address of newly created PKCS7 structure on return |
112 | | * in - pointer to pointer of DER/ASN.1 data |
113 | | * len - length of input data, bytes |
114 | | * |
115 | | * Returns newly allocated and populated PKCS7 structure or NULL on error. |
116 | | */ |
117 | | PKCS7* wolfSSL_d2i_PKCS7(PKCS7** p7, const unsigned char** in, int len) |
118 | | { |
119 | | return wolfSSL_d2i_PKCS7_ex(p7, in, len, NULL, 0); |
120 | | } |
121 | | |
122 | | /* This internal function is only decoding and setting up the PKCS7 struct. It |
123 | | * does not verify the PKCS7 signature. |
124 | | * |
125 | | * RETURNS: |
126 | | * returns pointer to a PKCS7 structure on success, otherwise returns NULL |
127 | | */ |
128 | | static PKCS7* wolfSSL_d2i_PKCS7_only(PKCS7** p7, const unsigned char** in, |
129 | | int len, byte* content, word32 contentSz) |
130 | | { |
131 | | WOLFSSL_PKCS7* pkcs7 = NULL; |
132 | | |
133 | | WOLFSSL_ENTER("wolfSSL_d2i_PKCS7_ex"); |
134 | | |
135 | | if (in == NULL || *in == NULL || len < 0) |
136 | | return NULL; |
137 | | |
138 | | if ((pkcs7 = (WOLFSSL_PKCS7*)wolfSSL_PKCS7_new()) == NULL) |
139 | | return NULL; |
140 | | |
141 | | pkcs7->len = len; |
142 | | pkcs7->data = (byte*)XMALLOC(pkcs7->len, NULL, DYNAMIC_TYPE_PKCS7); |
143 | | if (pkcs7->data == NULL) { |
144 | | wolfSSL_PKCS7_free((PKCS7*)pkcs7); |
145 | | return NULL; |
146 | | } |
147 | | XMEMCPY(pkcs7->data, *in, pkcs7->len); |
148 | | |
149 | | if (content != NULL) { |
150 | | pkcs7->pkcs7.content = content; |
151 | | pkcs7->pkcs7.contentSz = contentSz; |
152 | | } |
153 | | |
154 | | if (p7 != NULL) |
155 | | *p7 = (PKCS7*)pkcs7; |
156 | | *in += pkcs7->len; |
157 | | return (PKCS7*)pkcs7; |
158 | | } |
159 | | |
160 | | |
161 | | /***************************************************************************** |
162 | | * wolfSSL_d2i_PKCS7_ex - Converts the given unsigned char buffer of size len |
163 | | * into a PKCS7 object. Optionally, accepts a byte buffer of content which |
164 | | * is stored as the PKCS7 object's content, to support detached signatures. |
165 | | * @param content The content which is signed, in case the signature is |
166 | | * detached. Ignored if NULL. |
167 | | * @param contentSz The size of the passed in content. |
168 | | * |
169 | | * RETURNS: |
170 | | * returns pointer to a PKCS7 structure on success, otherwise returns NULL |
171 | | */ |
172 | | PKCS7* wolfSSL_d2i_PKCS7_ex(PKCS7** p7, const unsigned char** in, int len, |
173 | | byte* content, word32 contentSz) |
174 | | { |
175 | | WOLFSSL_PKCS7* pkcs7 = NULL; |
176 | | |
177 | | WOLFSSL_ENTER("wolfSSL_d2i_PKCS7_ex"); |
178 | | |
179 | | if (in == NULL || *in == NULL || len < 0) |
180 | | return NULL; |
181 | | |
182 | | pkcs7 = (WOLFSSL_PKCS7*)wolfSSL_d2i_PKCS7_only(p7, in, len, content, |
183 | | contentSz); |
184 | | if (pkcs7 != NULL) { |
185 | | if (wc_PKCS7_VerifySignedData(&pkcs7->pkcs7, pkcs7->data, pkcs7->len) |
186 | | != 0) { |
187 | | WOLFSSL_MSG("wc_PKCS7_VerifySignedData failed"); |
188 | | wolfSSL_PKCS7_free((PKCS7*)pkcs7); |
189 | | if (p7 != NULL) { |
190 | | *p7 = NULL; |
191 | | } |
192 | | return NULL; |
193 | | } |
194 | | } |
195 | | |
196 | | return (PKCS7*)pkcs7; |
197 | | } |
198 | | |
199 | | |
200 | | /** |
201 | | * This API was added as a helper function for libest. It |
202 | | * extracts a stack of certificates from the pkcs7 object. |
203 | | * @param pkcs7 PKCS7 parameter object |
204 | | * @return WOLFSSL_STACK_OF(WOLFSSL_X509)* |
205 | | */ |
206 | | WOLFSSL_STACK* wolfSSL_PKCS7_to_stack(PKCS7* pkcs7) |
207 | | { |
208 | | int i; |
209 | | WOLFSSL_PKCS7* p7 = (WOLFSSL_PKCS7*)pkcs7; |
210 | | WOLF_STACK_OF(WOLFSSL_X509)* ret = NULL; |
211 | | |
212 | | WOLFSSL_ENTER("wolfSSL_PKCS7_to_stack"); |
213 | | |
214 | | if (!p7) { |
215 | | WOLFSSL_MSG("Bad parameter"); |
216 | | return NULL; |
217 | | } |
218 | | |
219 | | if (p7->certs) |
220 | | return p7->certs; |
221 | | |
222 | | for (i = 0; i < MAX_PKCS7_CERTS && p7->pkcs7.cert[i]; i++) { |
223 | | WOLFSSL_X509* x509 = wolfSSL_X509_d2i_ex(NULL, p7->pkcs7.cert[i], |
224 | | p7->pkcs7.certSz[i], pkcs7->heap); |
225 | | if (!ret) |
226 | | ret = wolfSSL_sk_X509_new_null(); |
227 | | if (x509) { |
228 | | if (wolfSSL_sk_X509_push(ret, x509) <= 0) { |
229 | | wolfSSL_X509_free(x509); |
230 | | x509 = NULL; |
231 | | WOLFSSL_MSG("wolfSSL_sk_X509_push error"); |
232 | | goto error; |
233 | | } |
234 | | } |
235 | | else { |
236 | | WOLFSSL_MSG("wolfSSL_X509_d2i error"); |
237 | | goto error; |
238 | | } |
239 | | } |
240 | | |
241 | | /* Save stack to free later */ |
242 | | if (p7->certs) |
243 | | wolfSSL_sk_pop_free(p7->certs, NULL); |
244 | | p7->certs = ret; |
245 | | |
246 | | return ret; |
247 | | error: |
248 | | if (ret) { |
249 | | wolfSSL_sk_pop_free(ret, NULL); |
250 | | } |
251 | | return NULL; |
252 | | } |
253 | | |
254 | | /** |
255 | | * Return stack of signers contained in PKCS7 cert. |
256 | | * Notes: |
257 | | * - Currently only PKCS#7 messages with a single signer cert is supported. |
258 | | * - Returned WOLFSSL_STACK must be freed by caller. |
259 | | * |
260 | | * pkcs7 - PKCS7 struct to retrieve signer certs from. |
261 | | * certs - currently unused |
262 | | * flags - flags to control function behavior. |
263 | | * |
264 | | * Return WOLFSSL_STACK of signers on success, NULL on error. |
265 | | */ |
266 | | WOLFSSL_STACK* wolfSSL_PKCS7_get0_signers(PKCS7* pkcs7, WOLFSSL_STACK* certs, |
267 | | int flags) |
268 | | { |
269 | | WOLFSSL_X509* x509 = NULL; |
270 | | WOLFSSL_STACK* signers = NULL; |
271 | | WOLFSSL_PKCS7* p7 = (WOLFSSL_PKCS7*)pkcs7; |
272 | | |
273 | | if (p7 == NULL) |
274 | | return NULL; |
275 | | |
276 | | /* Only PKCS#7 messages with a single cert that is the verifying certificate |
277 | | * is supported. |
278 | | */ |
279 | | if (flags & PKCS7_NOINTERN) { |
280 | | WOLFSSL_MSG("PKCS7_NOINTERN flag not supported"); |
281 | | return NULL; |
282 | | } |
283 | | |
284 | | signers = wolfSSL_sk_X509_new_null(); |
285 | | if (signers == NULL) |
286 | | return NULL; |
287 | | |
288 | | if (wolfSSL_d2i_X509(&x509, (const byte**)&p7->pkcs7.singleCert, |
289 | | p7->pkcs7.singleCertSz) == NULL) { |
290 | | wolfSSL_sk_X509_pop_free(signers, NULL); |
291 | | return NULL; |
292 | | } |
293 | | |
294 | | if (wolfSSL_sk_X509_push(signers, x509) <= 0) { |
295 | | wolfSSL_sk_X509_pop_free(signers, NULL); |
296 | | return NULL; |
297 | | } |
298 | | |
299 | | (void)certs; |
300 | | |
301 | | return signers; |
302 | | } |
303 | | |
304 | | #ifndef NO_BIO |
305 | | |
306 | | PKCS7* wolfSSL_d2i_PKCS7_bio(WOLFSSL_BIO* bio, PKCS7** p7) |
307 | | { |
308 | | WOLFSSL_PKCS7* pkcs7; |
309 | | int ret; |
310 | | |
311 | | WOLFSSL_ENTER("wolfSSL_d2i_PKCS7_bio"); |
312 | | |
313 | | if (bio == NULL) |
314 | | return NULL; |
315 | | |
316 | | if ((pkcs7 = (WOLFSSL_PKCS7*)wolfSSL_PKCS7_new()) == NULL) |
317 | | return NULL; |
318 | | |
319 | | pkcs7->len = wolfSSL_BIO_get_len(bio); |
320 | | if (pkcs7->len < 0){ |
321 | | wolfSSL_PKCS7_free((PKCS7*)pkcs7); |
322 | | return NULL; |
323 | | } |
324 | | pkcs7->data = (byte*)XMALLOC(pkcs7->len, NULL, DYNAMIC_TYPE_PKCS7); |
325 | | if (pkcs7->data == NULL) { |
326 | | wolfSSL_PKCS7_free((PKCS7*)pkcs7); |
327 | | return NULL; |
328 | | } |
329 | | |
330 | | if ((ret = wolfSSL_BIO_read(bio, pkcs7->data, pkcs7->len)) <= 0) { |
331 | | wolfSSL_PKCS7_free((PKCS7*)pkcs7); |
332 | | return NULL; |
333 | | } |
334 | | /* pkcs7->len may change if using b64 for example */ |
335 | | pkcs7->len = ret; |
336 | | |
337 | | if (wc_PKCS7_VerifySignedData(&pkcs7->pkcs7, pkcs7->data, pkcs7->len) |
338 | | != 0) { |
339 | | WOLFSSL_MSG("wc_PKCS7_VerifySignedData failed"); |
340 | | wolfSSL_PKCS7_free((PKCS7*)pkcs7); |
341 | | return NULL; |
342 | | } |
343 | | |
344 | | if (p7 != NULL) |
345 | | *p7 = (PKCS7*)pkcs7; |
346 | | return (PKCS7*)pkcs7; |
347 | | } |
348 | | |
349 | | int wolfSSL_i2d_PKCS7(PKCS7 *p7, unsigned char **out) |
350 | | { |
351 | | byte* output = NULL; |
352 | | int localBuf = 0; |
353 | | int len; |
354 | | WC_RNG rng; |
355 | | int ret = WC_NO_ERR_TRACE(WOLFSSL_FAILURE); |
356 | | WOLFSSL_ENTER("wolfSSL_i2d_PKCS7"); |
357 | | |
358 | | if (!out || !p7) { |
359 | | WOLFSSL_MSG("Bad parameter"); |
360 | | return WOLFSSL_FAILURE; |
361 | | } |
362 | | |
363 | | if (!p7->rng) { |
364 | | if (wc_InitRng(&rng) != 0) { |
365 | | WOLFSSL_MSG("wc_InitRng error"); |
366 | | return WOLFSSL_FAILURE; |
367 | | } |
368 | | p7->rng = &rng; /* cppcheck-suppress autoVariables |
369 | | */ |
370 | | } |
371 | | |
372 | | if ((len = wc_PKCS7_EncodeSignedData(p7, NULL, 0)) < 0) { |
373 | | WOLFSSL_MSG("wc_PKCS7_EncodeSignedData error"); |
374 | | goto cleanup; |
375 | | } |
376 | | |
377 | | if (*out == NULL) { |
378 | | output = (byte*)XMALLOC(len, NULL, DYNAMIC_TYPE_TMP_BUFFER); |
379 | | if (!output) { |
380 | | WOLFSSL_MSG("malloc error"); |
381 | | goto cleanup; |
382 | | } |
383 | | localBuf = 1; |
384 | | } |
385 | | else { |
386 | | output = *out; |
387 | | } |
388 | | |
389 | | if ((len = wc_PKCS7_EncodeSignedData(p7, output, (word32)len)) < 0) { |
390 | | WOLFSSL_MSG("wc_PKCS7_EncodeSignedData error"); |
391 | | goto cleanup; |
392 | | } |
393 | | |
394 | | ret = len; |
395 | | cleanup: |
396 | | if (p7->rng == &rng) { |
397 | | wc_FreeRng(&rng); |
398 | | p7->rng = NULL; |
399 | | } |
400 | | if (ret == WC_NO_ERR_TRACE(WOLFSSL_FAILURE) && localBuf) |
401 | | XFREE(output, NULL, DYNAMIC_TYPE_TMP_BUFFER); |
402 | | if (ret != WC_NO_ERR_TRACE(WOLFSSL_FAILURE)) |
403 | | *out = output; |
404 | | return ret; |
405 | | } |
406 | | |
407 | | int wolfSSL_i2d_PKCS7_bio(WOLFSSL_BIO *bio, PKCS7 *p7) |
408 | | { |
409 | | byte* output = NULL; |
410 | | int len; |
411 | | int ret = WC_NO_ERR_TRACE(WOLFSSL_FAILURE); |
412 | | WOLFSSL_ENTER("wolfSSL_i2d_PKCS7_bio"); |
413 | | |
414 | | if (!bio || !p7) { |
415 | | WOLFSSL_MSG("Bad parameter"); |
416 | | return WOLFSSL_FAILURE; |
417 | | } |
418 | | |
419 | | if ((len = wolfSSL_i2d_PKCS7(p7, &output)) == |
420 | | WC_NO_ERR_TRACE(WOLFSSL_FAILURE)) |
421 | | { |
422 | | WOLFSSL_MSG("wolfSSL_i2d_PKCS7 error"); |
423 | | goto cleanup; |
424 | | } |
425 | | |
426 | | if (wolfSSL_BIO_write(bio, output, len) <= 0) { |
427 | | WOLFSSL_MSG("wolfSSL_BIO_write error"); |
428 | | goto cleanup; |
429 | | } |
430 | | |
431 | | ret = WOLFSSL_SUCCESS; |
432 | | cleanup: |
433 | | XFREE(output, NULL, DYNAMIC_TYPE_TMP_BUFFER); |
434 | | return ret; |
435 | | } |
436 | | |
437 | | /** |
438 | | * Creates and returns a PKCS7 signedData structure. |
439 | | * |
440 | | * Inner content type is set to DATA to match OpenSSL behavior. |
441 | | * |
442 | | * signer - certificate to sign bundle with |
443 | | * pkey - private key matching signer |
444 | | * certs - optional additional set of certificates to include |
445 | | * in - input data to be signed |
446 | | * flags - optional set of flags to control sign behavior |
447 | | * |
448 | | * PKCS7_BINARY - Do not translate input data to MIME canonical |
449 | | * format (\r\n line endings), thus preventing corruption of |
450 | | * binary content. |
451 | | * PKCS7_TEXT - Prepend MIME headers for text/plain to content. |
452 | | * PKCS7_DETACHED - Set signature detached, omit content from output bundle. |
453 | | * PKCS7_STREAM - initialize PKCS7 struct for signing, do not read data. |
454 | | * |
455 | | * Flags not currently supported: |
456 | | * PKCS7_NOCERTS - Do not include the signer cert in the output bundle. |
457 | | * PKCS7_PARTIAL - Allow for PKCS7_sign() to be only partially set up, |
458 | | * then signers etc to be added separately before |
459 | | * calling PKCS7_final(). |
460 | | * |
461 | | * Returns valid PKCS7 structure pointer, or NULL if an error occurred. |
462 | | */ |
463 | | PKCS7* wolfSSL_PKCS7_sign(WOLFSSL_X509* signer, WOLFSSL_EVP_PKEY* pkey, |
464 | | WOLFSSL_STACK* certs, WOLFSSL_BIO* in, int flags) |
465 | | { |
466 | | int err = 0; |
467 | | WOLFSSL_PKCS7* p7 = NULL; |
468 | | WOLFSSL_STACK* cert = certs; |
469 | | |
470 | | WOLFSSL_ENTER("wolfSSL_PKCS7_sign"); |
471 | | |
472 | | if (flags & PKCS7_NOCERTS) { |
473 | | WOLFSSL_MSG("PKCS7_NOCERTS flag not yet supported"); |
474 | | err = 1; |
475 | | } |
476 | | |
477 | | if (flags & PKCS7_PARTIAL) { |
478 | | WOLFSSL_MSG("PKCS7_PARTIAL flag not yet supported"); |
479 | | err = 1; |
480 | | } |
481 | | |
482 | | if ((err == 0) && (signer == NULL || signer->derCert == NULL || |
483 | | signer->derCert->length == 0)) { |
484 | | WOLFSSL_MSG("Bad function arg, signer is NULL or incomplete"); |
485 | | err = 1; |
486 | | } |
487 | | |
488 | | if ((err == 0) && (pkey == NULL || pkey->pkey.ptr == NULL || |
489 | | pkey->pkey_sz <= 0)) { |
490 | | WOLFSSL_MSG("Bad function arg, pkey is NULL or incomplete"); |
491 | | err = 1; |
492 | | } |
493 | | |
494 | | if ((err == 0) && (in == NULL) && !(flags & PKCS7_STREAM)) { |
495 | | WOLFSSL_MSG("input data required unless PKCS7_STREAM used"); |
496 | | err = 1; |
497 | | } |
498 | | |
499 | | if ((err == 0) && ((p7 = (WOLFSSL_PKCS7*)wolfSSL_PKCS7_new()) == NULL)) { |
500 | | WOLFSSL_MSG("Error allocating new WOLFSSL_PKCS7"); |
501 | | err = 1; |
502 | | } |
503 | | |
504 | | /* load signer certificate */ |
505 | | if (err == 0) { |
506 | | if (wc_PKCS7_InitWithCert(&p7->pkcs7, signer->derCert->buffer, |
507 | | signer->derCert->length) != 0) { |
508 | | WOLFSSL_MSG("Failed to load signer certificate"); |
509 | | err = 1; |
510 | | } |
511 | | } |
512 | | |
513 | | /* set signer private key, data types, defaults */ |
514 | | if (err == 0) { |
515 | | p7->pkcs7.privateKey = (byte*)pkey->pkey.ptr; |
516 | | p7->pkcs7.privateKeySz = (word32)pkey->pkey_sz; |
517 | | p7->pkcs7.contentOID = DATA; /* inner content default is DATA */ |
518 | | p7->pkcs7.hashOID = SHA256h; /* default to SHA-256 hash type */ |
519 | | p7->type = SIGNED_DATA; /* PKCS7_final switches on type */ |
520 | | } |
521 | | |
522 | | /* add additional chain certs if provided */ |
523 | | while (cert && (err == 0)) { |
524 | | if (cert->data.x509 != NULL && cert->data.x509->derCert != NULL) { |
525 | | if (wc_PKCS7_AddCertificate(&p7->pkcs7, |
526 | | cert->data.x509->derCert->buffer, |
527 | | cert->data.x509->derCert->length) != 0) { |
528 | | WOLFSSL_MSG("Error in wc_PKCS7_AddCertificate"); |
529 | | err = 1; |
530 | | } |
531 | | } |
532 | | cert = cert->next; |
533 | | } |
534 | | |
535 | | if ((err == 0) && (flags & PKCS7_DETACHED)) { |
536 | | if (wc_PKCS7_SetDetached(&p7->pkcs7, 1) != 0) { |
537 | | WOLFSSL_MSG("Failed to set signature detached"); |
538 | | err = 1; |
539 | | } |
540 | | } |
541 | | |
542 | | if ((err == 0) && (flags & PKCS7_STREAM)) { |
543 | | /* if streaming, return before finalizing */ |
544 | | return (PKCS7*)p7; |
545 | | } |
546 | | |
547 | | if ((err == 0) && (wolfSSL_PKCS7_final((PKCS7*)p7, in, flags) != 1)) { |
548 | | WOLFSSL_MSG("Error calling wolfSSL_PKCS7_final"); |
549 | | err = 1; |
550 | | } |
551 | | |
552 | | if ((err != 0) && (p7 != NULL)) { |
553 | | wolfSSL_PKCS7_free((PKCS7*)p7); |
554 | | p7 = NULL; |
555 | | } |
556 | | |
557 | | return (PKCS7*)p7; |
558 | | } |
559 | | |
560 | | #ifdef HAVE_SMIME |
561 | | |
562 | | #ifndef MAX_MIME_LINE_LEN |
563 | | #define MAX_MIME_LINE_LEN 1024 |
564 | | #endif |
565 | | |
566 | | /** |
567 | | * Copy input BIO to output BIO, but convert all line endings to CRLF (\r\n), |
568 | | * used by PKCS7_final(). |
569 | | * |
570 | | * in - input WOLFSSL_BIO to be converted |
571 | | * out - output WOLFSSL_BIO to hold copy of in, with line endings adjusted |
572 | | * |
573 | | * Return 0 on success, negative on error |
574 | | */ |
575 | | static int wolfSSL_BIO_to_MIME_crlf(WOLFSSL_BIO* in, WOLFSSL_BIO* out) |
576 | | { |
577 | | int ret = 0; |
578 | | int lineLen = 0; |
579 | | word32 canonLineLen = 0; |
580 | | char* canonLine = NULL; |
581 | | WC_DECLARE_VAR(line, char, MAX_MIME_LINE_LEN, 0); |
582 | | |
583 | | if (in == NULL || out == NULL) { |
584 | | return BAD_FUNC_ARG; |
585 | | } |
586 | | |
587 | | #ifdef WOLFSSL_SMALL_STACK |
588 | | line = (char*)XMALLOC(MAX_MIME_LINE_LEN, in->heap, |
589 | | DYNAMIC_TYPE_TMP_BUFFER); |
590 | | if (line == NULL) { |
591 | | return MEMORY_E; |
592 | | } |
593 | | #endif |
594 | | XMEMSET(line, 0, MAX_MIME_LINE_LEN); |
595 | | |
596 | | while ((lineLen = wolfSSL_BIO_gets(in, line, MAX_MIME_LINE_LEN)) > 0) { |
597 | | |
598 | | if (line[lineLen - 1] == '\r' || line[lineLen - 1] == '\n') { |
599 | | canonLineLen = (word32)lineLen; |
600 | | if ((canonLine = wc_MIME_single_canonicalize( |
601 | | line, &canonLineLen)) == NULL) { |
602 | | ret = WOLFSSL_FATAL_ERROR; |
603 | | break; |
604 | | } |
605 | | |
606 | | /* remove trailing null */ |
607 | | if (canonLineLen >= 1 && canonLine[canonLineLen-1] == '\0') { |
608 | | canonLineLen--; |
609 | | } |
610 | | |
611 | | if (wolfSSL_BIO_write(out, canonLine, (int)canonLineLen) < 0) { |
612 | | ret = WOLFSSL_FATAL_ERROR; |
613 | | break; |
614 | | } |
615 | | XFREE(canonLine, NULL, DYNAMIC_TYPE_PKCS7); |
616 | | canonLine = NULL; |
617 | | } |
618 | | else { |
619 | | /* no line ending in current line, write direct to out */ |
620 | | if (wolfSSL_BIO_write(out, line, lineLen) < 0) { |
621 | | ret = WOLFSSL_FATAL_ERROR; |
622 | | break; |
623 | | } |
624 | | } |
625 | | } |
626 | | |
627 | | XFREE(canonLine, NULL, DYNAMIC_TYPE_PKCS7); |
628 | | WC_FREE_VAR_EX(line, in->heap, DYNAMIC_TYPE_TMP_BUFFER); |
629 | | |
630 | | return ret; |
631 | | } |
632 | | |
633 | | #endif /* HAVE_SMIME */ |
634 | | |
635 | | /* Used by both PKCS7_final() and PKCS7_verify() */ |
636 | | static const char contTypeText[] = "Content-Type: text/plain\r\n\r\n"; |
637 | | |
638 | | /** |
639 | | * Finalize PKCS7 structure, currently supports signedData only. |
640 | | * |
641 | | * Does not generate final bundle (ie: signedData), but finalizes |
642 | | * the PKCS7 structure in preparation for a output function to be called next. |
643 | | * |
644 | | * pkcs7 - initialized PKCS7 structure, populated with signer, etc |
645 | | * in - input data |
646 | | * flags - flags to control PKCS7 behavior. Other flags except those noted |
647 | | * below are ignored: |
648 | | * |
649 | | * PKCS7_BINARY - Do not translate input data to MIME canonical |
650 | | * format (\r\n line endings), thus preventing corruption of |
651 | | * binary content. |
652 | | * PKCS7_TEXT - Prepend MIME headers for text/plain to content. |
653 | | * |
654 | | * Returns 1 on success, 0 on error |
655 | | */ |
656 | | int wolfSSL_PKCS7_final(PKCS7* pkcs7, WOLFSSL_BIO* in, int flags) |
657 | | { |
658 | | int ret = 1; |
659 | | int memSz = 0; |
660 | | unsigned char* mem = NULL; |
661 | | WOLFSSL_PKCS7* p7 = (WOLFSSL_PKCS7*)pkcs7; |
662 | | WOLFSSL_BIO* data = NULL; |
663 | | |
664 | | WOLFSSL_ENTER("wolfSSL_PKCS7_final"); |
665 | | |
666 | | if (p7 == NULL || in == NULL) { |
667 | | WOLFSSL_MSG("Bad input args to PKCS7_final"); |
668 | | ret = 0; |
669 | | } |
670 | | |
671 | | if (ret == 1) { |
672 | | if ((data = wolfSSL_BIO_new(wolfSSL_BIO_s_mem())) == NULL) { |
673 | | WOLFSSL_MSG("Error in wolfSSL_BIO_new"); |
674 | | ret = 0; |
675 | | } |
676 | | } |
677 | | |
678 | | /* prepend Content-Type header if PKCS7_TEXT */ |
679 | | if ((ret == 1) && (flags & PKCS7_TEXT)) { |
680 | | if (wolfSSL_BIO_write(data, contTypeText, |
681 | | (int)XSTR_SIZEOF(contTypeText)) < 0) { |
682 | | WOLFSSL_MSG("Error prepending Content-Type header"); |
683 | | ret = 0; |
684 | | } |
685 | | } |
686 | | |
687 | | /* convert line endings to CRLF if !PKCS7_BINARY */ |
688 | | if (ret == 1) { |
689 | | if (flags & PKCS7_BINARY) { |
690 | | |
691 | | /* no CRLF conversion, direct copy content */ |
692 | | if ((memSz = wolfSSL_BIO_get_len(in)) <= 0) { |
693 | | ret = 0; |
694 | | } |
695 | | if (ret == 1) { |
696 | | mem = (unsigned char*)XMALLOC(memSz, in->heap, |
697 | | DYNAMIC_TYPE_TMP_BUFFER); |
698 | | if (mem == NULL) { |
699 | | WOLFSSL_MSG("Failed to allocate memory for input data"); |
700 | | ret = 0; |
701 | | } |
702 | | } |
703 | | |
704 | | if (ret == 1) { |
705 | | if (wolfSSL_BIO_read(in, mem, memSz) != memSz) { |
706 | | WOLFSSL_MSG("Error reading from input BIO"); |
707 | | ret = 0; |
708 | | } |
709 | | else if (wolfSSL_BIO_write(data, mem, memSz) < 0) { |
710 | | ret = 0; |
711 | | } |
712 | | } |
713 | | |
714 | | XFREE(mem, in->heap, DYNAMIC_TYPE_TMP_BUFFER); |
715 | | } |
716 | | else { |
717 | | #ifdef HAVE_SMIME |
718 | | /* convert content line endings to CRLF */ |
719 | | if (wolfSSL_BIO_to_MIME_crlf(in, data) != 0) { |
720 | | WOLFSSL_MSG("Error converting line endings to CRLF"); |
721 | | ret = 0; |
722 | | } |
723 | | else { |
724 | | p7->pkcs7.contentCRLF = 1; |
725 | | } |
726 | | #else |
727 | | WOLFSSL_MSG("Without PKCS7_BINARY requires wolfSSL to be built " |
728 | | "with HAVE_SMIME"); |
729 | | ret = 0; |
730 | | #endif |
731 | | } |
732 | | } |
733 | | |
734 | | if ((ret == 1) && ((memSz = wolfSSL_BIO_get_mem_data(data, &mem)) < 0)) { |
735 | | WOLFSSL_MSG("Error in wolfSSL_BIO_get_mem_data"); |
736 | | ret = 0; |
737 | | } |
738 | | |
739 | | if (ret == 1) { |
740 | | XFREE(p7->data, NULL, DYNAMIC_TYPE_PKCS7); |
741 | | p7->data = (byte*)XMALLOC(memSz, NULL, DYNAMIC_TYPE_PKCS7); |
742 | | if (p7->data == NULL) { |
743 | | ret = 0; |
744 | | } |
745 | | else { |
746 | | XMEMCPY(p7->data, mem, memSz); |
747 | | p7->len = memSz; |
748 | | } |
749 | | } |
750 | | |
751 | | if (ret == 1) { |
752 | | p7->pkcs7.content = p7->data; |
753 | | p7->pkcs7.contentSz = (word32)p7->len; |
754 | | } |
755 | | |
756 | | if (data != NULL) { |
757 | | wolfSSL_BIO_free(data); |
758 | | } |
759 | | |
760 | | return ret; |
761 | | } |
762 | | |
763 | | int wolfSSL_PKCS7_verify(PKCS7* pkcs7, WOLFSSL_STACK* certs, |
764 | | WOLFSSL_X509_STORE* store, WOLFSSL_BIO* in, WOLFSSL_BIO* out, int flags) |
765 | | { |
766 | | int i, ret = 0; |
767 | | unsigned char* mem = NULL; |
768 | | int memSz = 0; |
769 | | WOLFSSL_PKCS7* p7 = (WOLFSSL_PKCS7*)pkcs7; |
770 | | int contTypeLen; |
771 | | WOLFSSL_X509* signer = NULL; |
772 | | WOLFSSL_STACK* signers = NULL; |
773 | | X509_STORE_CTX* ctx = NULL; |
774 | | |
775 | | |
776 | | WOLFSSL_ENTER("wolfSSL_PKCS7_verify"); |
777 | | |
778 | | if (pkcs7 == NULL) |
779 | | return WOLFSSL_FAILURE; |
780 | | |
781 | | if (in != NULL) { |
782 | | if ((memSz = wolfSSL_BIO_get_mem_data(in, &mem)) < 0) |
783 | | return WOLFSSL_FAILURE; |
784 | | |
785 | | p7->pkcs7.content = mem; |
786 | | p7->pkcs7.contentSz = (word32)memSz; |
787 | | } |
788 | | |
789 | | /* certs is the list of certificates to find the cert with issuer/serial. */ |
790 | | (void)certs; |
791 | | /* store is the certificate store to use to verify signer certificate |
792 | | * associated with the signers. |
793 | | */ |
794 | | (void)store; |
795 | | |
796 | | ret = wc_PKCS7_VerifySignedData(&p7->pkcs7, p7->data, p7->len); |
797 | | if (ret != 0) |
798 | | return WOLFSSL_FAILURE; |
799 | | |
800 | | if ((flags & PKCS7_NOVERIFY) != PKCS7_NOVERIFY) { |
801 | | /* Verify signer certificates */ |
802 | | if (store == NULL || store->cm == NULL) { |
803 | | WOLFSSL_MSG("No store or store certs, but PKCS7_NOVERIFY not set"); |
804 | | return WOLFSSL_FAILURE; |
805 | | } |
806 | | |
807 | | ctx = X509_STORE_CTX_new(); |
808 | | if (ctx == NULL) { |
809 | | WOLFSSL_MSG("Error allocating X509 Store Context"); |
810 | | return WOLFSSL_FAILURE; |
811 | | } |
812 | | |
813 | | signers = wolfSSL_PKCS7_get0_signers(pkcs7, certs, flags); |
814 | | if (signers == NULL) { |
815 | | WOLFSSL_MSG("No signers found to verify"); |
816 | | wolfSSL_X509_STORE_CTX_free(ctx); |
817 | | return WOLFSSL_FAILURE; |
818 | | } |
819 | | |
820 | | for (i = 0; i < wolfSSL_sk_X509_num(signers); i++) { |
821 | | signer = wolfSSL_sk_X509_value(signers, i); |
822 | | if (wolfSSL_X509_STORE_CTX_init(ctx, store, signer, NULL) |
823 | | != WOLFSSL_SUCCESS) { |
824 | | WOLFSSL_MSG("Failed to initialize X509 STORE CTX"); |
825 | | wolfSSL_sk_X509_pop_free(signers, NULL); |
826 | | wolfSSL_X509_STORE_CTX_free(ctx); |
827 | | return WOLFSSL_FAILURE; |
828 | | } |
829 | | if (wolfSSL_X509_verify_cert(ctx) != WOLFSSL_SUCCESS) { |
830 | | WOLFSSL_MSG("Failed to verify signer certificate"); |
831 | | wolfSSL_sk_X509_pop_free(signers, NULL); |
832 | | wolfSSL_X509_STORE_CTX_free(ctx); |
833 | | return WOLFSSL_FAILURE; |
834 | | } |
835 | | } |
836 | | wolfSSL_sk_X509_pop_free(signers, NULL); |
837 | | wolfSSL_X509_STORE_CTX_free(ctx); |
838 | | } |
839 | | |
840 | | if (flags & PKCS7_TEXT) { |
841 | | /* strip MIME header for text/plain, otherwise error */ |
842 | | contTypeLen = XSTR_SIZEOF(contTypeText); |
843 | | if ((p7->pkcs7.contentSz < (word32)contTypeLen) || |
844 | | (XMEMCMP(p7->pkcs7.content, contTypeText, contTypeLen) != 0)) { |
845 | | WOLFSSL_MSG("Error PKCS7 Content-Type not found with PKCS7_TEXT"); |
846 | | return WOLFSSL_FAILURE; |
847 | | } |
848 | | p7->pkcs7.content += contTypeLen; |
849 | | p7->pkcs7.contentSz -= contTypeLen; |
850 | | } |
851 | | |
852 | | if (out != NULL) { |
853 | | wolfSSL_BIO_write(out, p7->pkcs7.content, p7->pkcs7.contentSz); |
854 | | } |
855 | | |
856 | | WOLFSSL_LEAVE("wolfSSL_PKCS7_verify", WOLFSSL_SUCCESS); |
857 | | |
858 | | return WOLFSSL_SUCCESS; |
859 | | } |
860 | | |
861 | | /** |
862 | | * This API was added as a helper function for libest. It |
863 | | * encodes a stack of certificates to pkcs7 format. |
864 | | * @param pkcs7 PKCS7 parameter object |
865 | | * @param certs WOLFSSL_STACK_OF(WOLFSSL_X509)* |
866 | | * @param out Output bio |
867 | | * @return WOLFSSL_SUCCESS on success and WOLFSSL_FAILURE on failure |
868 | | */ |
869 | | int wolfSSL_PKCS7_encode_certs(PKCS7* pkcs7, WOLFSSL_STACK* certs, |
870 | | WOLFSSL_BIO* out) |
871 | | { |
872 | | int ret; |
873 | | WOLFSSL_PKCS7* p7; |
874 | | WOLFSSL_ENTER("wolfSSL_PKCS7_encode_certs"); |
875 | | |
876 | | if (!pkcs7 || !certs || !out) { |
877 | | WOLFSSL_MSG("Bad parameter"); |
878 | | return WOLFSSL_FAILURE; |
879 | | } |
880 | | |
881 | | p7 = (WOLFSSL_PKCS7*)pkcs7; |
882 | | |
883 | | /* take ownership of certs */ |
884 | | p7->certs = certs; |
885 | | /* TODO: takes ownership even on failure below but not on above failure. */ |
886 | | |
887 | | if (pkcs7->certList) { |
888 | | WOLFSSL_MSG("wolfSSL_PKCS7_encode_certs called multiple times on same " |
889 | | "struct"); |
890 | | return WOLFSSL_FAILURE; |
891 | | } |
892 | | |
893 | | if (certs) { |
894 | | /* Save some of the values */ |
895 | | int hashOID = pkcs7->hashOID; |
896 | | byte version = pkcs7->version; |
897 | | |
898 | | if (!certs->data.x509 || !certs->data.x509->derCert) { |
899 | | WOLFSSL_MSG("Missing cert"); |
900 | | return WOLFSSL_FAILURE; |
901 | | } |
902 | | |
903 | | if (wc_PKCS7_InitWithCert(pkcs7, certs->data.x509->derCert->buffer, |
904 | | certs->data.x509->derCert->length) != 0) { |
905 | | WOLFSSL_MSG("wc_PKCS7_InitWithCert error"); |
906 | | return WOLFSSL_FAILURE; |
907 | | } |
908 | | certs = certs->next; |
909 | | |
910 | | pkcs7->hashOID = hashOID; |
911 | | pkcs7->version = version; |
912 | | } |
913 | | |
914 | | /* Add the certs to the PKCS7 struct */ |
915 | | while (certs) { |
916 | | if (!certs->data.x509 || !certs->data.x509->derCert) { |
917 | | WOLFSSL_MSG("Missing cert"); |
918 | | return WOLFSSL_FAILURE; |
919 | | } |
920 | | if (wc_PKCS7_AddCertificate(pkcs7, certs->data.x509->derCert->buffer, |
921 | | certs->data.x509->derCert->length) != 0) { |
922 | | WOLFSSL_MSG("wc_PKCS7_AddCertificate error"); |
923 | | return WOLFSSL_FAILURE; |
924 | | } |
925 | | certs = certs->next; |
926 | | } |
927 | | |
928 | | if (wc_PKCS7_SetSignerIdentifierType(pkcs7, DEGENERATE_SID) != 0) { |
929 | | WOLFSSL_MSG("wc_PKCS7_SetSignerIdentifierType error"); |
930 | | return WOLFSSL_FAILURE; |
931 | | } |
932 | | |
933 | | ret = wolfSSL_i2d_PKCS7_bio(out, pkcs7); |
934 | | |
935 | | return ret; |
936 | | } |
937 | | |
938 | | /****************************************************************************** |
939 | | * wolfSSL_PEM_write_bio_PKCS7 - writes the PKCS7 data to BIO |
940 | | * |
941 | | * RETURNS: |
942 | | * returns WOLFSSL_SUCCESS on success, otherwise returns WOLFSSL_FAILURE |
943 | | */ |
944 | | int wolfSSL_PEM_write_bio_PKCS7(WOLFSSL_BIO* bio, PKCS7* p7) |
945 | | { |
946 | | #ifdef WOLFSSL_SMALL_STACK |
947 | | byte* outputHead; |
948 | | byte* outputFoot; |
949 | | #else |
950 | | byte outputHead[2048]; |
951 | | byte outputFoot[2048]; |
952 | | #endif |
953 | | word32 outputHeadSz = 2048; |
954 | | word32 outputFootSz = 2048; |
955 | | word32 outputSz = 0; |
956 | | byte* output = NULL; |
957 | | byte* pem = NULL; |
958 | | int pemSz = -1; |
959 | | enum wc_HashType hashType; |
960 | | byte hashBuf[WC_MAX_DIGEST_SIZE]; |
961 | | word32 hashSz = 0; |
962 | | |
963 | | WOLFSSL_ENTER("wolfSSL_PEM_write_bio_PKCS7"); |
964 | | |
965 | | if (bio == NULL || p7 == NULL) |
966 | | return WOLFSSL_FAILURE; |
967 | | |
968 | | #ifdef WOLFSSL_SMALL_STACK |
969 | | outputHead = (byte*)XMALLOC(outputHeadSz, bio->heap, |
970 | | DYNAMIC_TYPE_TMP_BUFFER); |
971 | | if (outputHead == NULL) |
972 | | return MEMORY_E; |
973 | | |
974 | | outputFoot = (byte*)XMALLOC(outputFootSz, bio->heap, |
975 | | DYNAMIC_TYPE_TMP_BUFFER); |
976 | | if (outputFoot == NULL) |
977 | | goto error; |
978 | | |
979 | | #endif |
980 | | |
981 | | XMEMSET(hashBuf, 0, WC_MAX_DIGEST_SIZE); |
982 | | XMEMSET(outputHead, 0, outputHeadSz); |
983 | | XMEMSET(outputFoot, 0, outputFootSz); |
984 | | |
985 | | hashType = wc_OidGetHash(p7->hashOID); |
986 | | hashSz = (word32)wc_HashGetDigestSize(hashType); |
987 | | if (hashSz > WC_MAX_DIGEST_SIZE) |
988 | | goto error; |
989 | | |
990 | | /* only SIGNED_DATA is supported */ |
991 | | switch (p7->contentOID) { |
992 | | case SIGNED_DATA: |
993 | | break; |
994 | | default: |
995 | | WOLFSSL_MSG("Unknown PKCS#7 Type"); |
996 | | goto error; |
997 | | }; |
998 | | |
999 | | if ((wc_PKCS7_EncodeSignedData_ex(p7, hashBuf, hashSz, |
1000 | | outputHead, &outputHeadSz, outputFoot, &outputFootSz)) != 0) |
1001 | | goto error; |
1002 | | |
1003 | | outputSz = outputHeadSz + p7->contentSz + outputFootSz; |
1004 | | output = (byte*)XMALLOC(outputSz, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); |
1005 | | |
1006 | | if (!output) |
1007 | | goto error; |
1008 | | |
1009 | | XMEMSET(output, 0, outputSz); |
1010 | | outputSz = 0; |
1011 | | XMEMCPY(&output[outputSz], outputHead, outputHeadSz); |
1012 | | outputSz += outputHeadSz; |
1013 | | XMEMCPY(&output[outputSz], p7->content, p7->contentSz); |
1014 | | outputSz += p7->contentSz; |
1015 | | XMEMCPY(&output[outputSz], outputFoot, outputFootSz); |
1016 | | outputSz += outputFootSz; |
1017 | | |
1018 | | /* get PEM size */ |
1019 | | pemSz = wc_DerToPemEx(output, outputSz, NULL, 0, NULL, CERT_TYPE); |
1020 | | if (pemSz < 0) |
1021 | | goto error; |
1022 | | |
1023 | | pemSz++; /* for '\0'*/ |
1024 | | |
1025 | | /* create PEM buffer and convert from DER to PEM*/ |
1026 | | if ((pem = (byte*)XMALLOC(pemSz, bio->heap, DYNAMIC_TYPE_TMP_BUFFER)) |
1027 | | == NULL) |
1028 | | goto error; |
1029 | | |
1030 | | XMEMSET(pem, 0, pemSz); |
1031 | | |
1032 | | if (wc_DerToPemEx(output, outputSz, pem, (word32)pemSz, NULL,CERT_TYPE) |
1033 | | < 0) { |
1034 | | goto error; |
1035 | | } |
1036 | | if ((wolfSSL_BIO_write(bio, pem, pemSz) == pemSz)) { |
1037 | | XFREE(output, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); |
1038 | | XFREE(pem, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); |
1039 | | WC_FREE_VAR_EX(outputHead, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); |
1040 | | WC_FREE_VAR_EX(outputFoot, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); |
1041 | | return WOLFSSL_SUCCESS; |
1042 | | } |
1043 | | |
1044 | | error: |
1045 | | WC_FREE_VAR_EX(outputHead, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); |
1046 | | WC_FREE_VAR_EX(outputFoot, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); |
1047 | | XFREE(output, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); |
1048 | | XFREE(pem, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); |
1049 | | return WOLFSSL_FAILURE; |
1050 | | } |
1051 | | |
1052 | | #ifdef HAVE_SMIME |
1053 | | /***************************************************************************** |
1054 | | * wolfSSL_SMIME_read_PKCS7 - Reads the given S/MIME message and parses it into |
1055 | | * a PKCS7 object. In case of a multipart message, stores the signed data in |
1056 | | * bcont. |
1057 | | * |
1058 | | * RETURNS: |
1059 | | * returns pointer to a PKCS7 structure on success, otherwise returns NULL |
1060 | | */ |
1061 | | PKCS7* wolfSSL_SMIME_read_PKCS7(WOLFSSL_BIO* in, |
1062 | | WOLFSSL_BIO** bcont) |
1063 | | { |
1064 | | MimeHdr* allHdrs = NULL; |
1065 | | MimeHdr* curHdr = NULL; |
1066 | | MimeParam* curParam = NULL; |
1067 | | int inLen = 0; |
1068 | | byte* bcontMem = NULL; |
1069 | | int bcontMemSz = 0; |
1070 | | int sectionLen = 0; |
1071 | | int ret = -1; |
1072 | | char* section = NULL; |
1073 | | char* canonLine = NULL; |
1074 | | char* canonSection = NULL; |
1075 | | PKCS7* pkcs7 = NULL; |
1076 | | word32 outLen = 0; |
1077 | | word32 canonLineLen = 0; |
1078 | | byte* out = NULL; |
1079 | | byte* outHead = NULL; |
1080 | | |
1081 | | int canonPos = 0; |
1082 | | int lineLen = 0; |
1083 | | int remainLen = 0; |
1084 | | byte isEnd = 0; |
1085 | | size_t canonSize = 0; |
1086 | | size_t boundLen = 0; |
1087 | | char* boundary = NULL; |
1088 | | |
1089 | | static const char kContType[] = "Content-Type"; |
1090 | | static const char kCTE[] = "Content-Transfer-Encoding"; |
1091 | | static const char kMultSigned[] = "multipart/signed"; |
1092 | | static const char kAppPkcsSign[] = "application/pkcs7-signature"; |
1093 | | static const char kAppXPkcsSign[] = "application/x-pkcs7-signature"; |
1094 | | static const char kAppPkcs7Mime[] = "application/pkcs7-mime"; |
1095 | | static const char kAppXPkcs7Mime[] = "application/x-pkcs7-mime"; |
1096 | | |
1097 | | WOLFSSL_ENTER("wolfSSL_SMIME_read_PKCS7"); |
1098 | | |
1099 | | if (in == NULL || bcont == NULL) { |
1100 | | goto error; |
1101 | | } |
1102 | | inLen = wolfSSL_BIO_get_len(in); |
1103 | | if (inLen <= 0) { |
1104 | | goto error; |
1105 | | } |
1106 | | remainLen = wolfSSL_BIO_get_len(in); |
1107 | | if (remainLen <= 0) { |
1108 | | goto error; |
1109 | | } |
1110 | | |
1111 | | section = (char*)XMALLOC(remainLen+1, NULL, DYNAMIC_TYPE_PKCS7); |
1112 | | if (section == NULL) { |
1113 | | goto error; |
1114 | | } |
1115 | | lineLen = wolfSSL_BIO_gets(in, section, remainLen); |
1116 | | if (lineLen <= 0) { |
1117 | | goto error; |
1118 | | } |
1119 | | while (isEnd == 0 && remainLen > 0) { |
1120 | | sectionLen += lineLen; |
1121 | | remainLen -= lineLen; |
1122 | | lineLen = wolfSSL_BIO_gets(in, §ion[sectionLen], remainLen); |
1123 | | if (lineLen <= 0) { |
1124 | | goto error; |
1125 | | } |
1126 | | /* Line with just newline signals end of headers. */ |
1127 | | if ((lineLen==2 && !XSTRNCMP(§ion[sectionLen], |
1128 | | "\r\n", 2)) || |
1129 | | (lineLen==1 && (section[sectionLen] == '\r' || |
1130 | | section[sectionLen] == '\n'))) { |
1131 | | isEnd = 1; |
1132 | | } |
1133 | | } |
1134 | | section[sectionLen] = '\0'; |
1135 | | ret = wc_MIME_parse_headers(section, sectionLen, &allHdrs); |
1136 | | if (ret < 0) { |
1137 | | WOLFSSL_MSG("Parsing MIME headers failed."); |
1138 | | goto error; |
1139 | | } |
1140 | | isEnd = 0; |
1141 | | section[0] = '\0'; |
1142 | | sectionLen = 0; |
1143 | | |
1144 | | curHdr = wc_MIME_find_header_name(kContType, allHdrs); |
1145 | | if (curHdr && !XSTRNCMP(curHdr->body, kMultSigned, |
1146 | | XSTR_SIZEOF(kMultSigned))) { |
1147 | | curParam = wc_MIME_find_param_attr("protocol", curHdr->params); |
1148 | | if (curParam && (!XSTRNCMP(curParam->value, kAppPkcsSign, |
1149 | | XSTR_SIZEOF(kAppPkcsSign)) || |
1150 | | !XSTRNCMP(curParam->value, kAppXPkcsSign, |
1151 | | XSTR_SIZEOF(kAppXPkcsSign)))) { |
1152 | | curParam = wc_MIME_find_param_attr("boundary", curHdr->params); |
1153 | | if (curParam == NULL) { |
1154 | | goto error; |
1155 | | } |
1156 | | |
1157 | | boundLen = XSTRLEN(curParam->value) + 2; |
1158 | | boundary = (char*)XMALLOC(boundLen+1, NULL, DYNAMIC_TYPE_PKCS7); |
1159 | | if (boundary == NULL) { |
1160 | | goto error; |
1161 | | } |
1162 | | XMEMSET(boundary, 0, (word32)(boundLen+1)); |
1163 | | boundary[0] = boundary[1] = '-'; |
1164 | | /* analyzers have issues with using strncpy and strcpy here */ |
1165 | | XMEMCPY(&boundary[2], curParam->value, boundLen - 2); |
1166 | | |
1167 | | /* Parse up to first boundary, ignore everything here. */ |
1168 | | lineLen = wolfSSL_BIO_gets(in, section, remainLen); |
1169 | | if (lineLen <= 0) { |
1170 | | goto error; |
1171 | | } |
1172 | | while (XSTRNCMP(§ion[sectionLen], boundary, boundLen) && |
1173 | | remainLen > 0) { |
1174 | | sectionLen += lineLen; |
1175 | | remainLen -= lineLen; |
1176 | | lineLen = wolfSSL_BIO_gets(in, §ion[sectionLen], |
1177 | | remainLen); |
1178 | | if (lineLen <= 0) { |
1179 | | goto error; |
1180 | | } |
1181 | | } |
1182 | | |
1183 | | section[0] = '\0'; |
1184 | | sectionLen = 0; |
1185 | | canonSize = (size_t)remainLen + 1; |
1186 | | canonSection = (char*)XMALLOC(canonSize, NULL, |
1187 | | DYNAMIC_TYPE_PKCS7); |
1188 | | if (canonSection == NULL) { |
1189 | | goto error; |
1190 | | } else { |
1191 | | XMEMSET(canonSection, 0, (word32)canonSize); |
1192 | | } |
1193 | | |
1194 | | lineLen = wolfSSL_BIO_gets(in, section, remainLen); |
1195 | | if (lineLen < 0) { |
1196 | | goto error; |
1197 | | } |
1198 | | while (XSTRNCMP(§ion[sectionLen], boundary, boundLen) && |
1199 | | remainLen > 0) { |
1200 | | canonLineLen = (word32)lineLen; |
1201 | | canonLine = wc_MIME_single_canonicalize(§ion[sectionLen], |
1202 | | &canonLineLen); |
1203 | | if (canonLine == NULL) { |
1204 | | goto error; |
1205 | | } |
1206 | | /* If line endings were added, the initial length may be |
1207 | | * exceeded. */ |
1208 | | if ((canonPos + canonLineLen) >= canonSize) { |
1209 | | char* newCanonSection; |
1210 | | canonSize = canonPos + canonLineLen; |
1211 | | newCanonSection = (char*)XREALLOC(canonSection, canonSize, |
1212 | | NULL, DYNAMIC_TYPE_PKCS7); |
1213 | | if (newCanonSection == NULL) { |
1214 | | goto error; |
1215 | | } |
1216 | | canonSection = newCanonSection; |
1217 | | } |
1218 | | XMEMCPY(&canonSection[canonPos], canonLine, |
1219 | | (int)canonLineLen - 1); |
1220 | | canonPos += canonLineLen - 1; |
1221 | | XFREE(canonLine, NULL, DYNAMIC_TYPE_PKCS7); |
1222 | | canonLine = NULL; |
1223 | | |
1224 | | sectionLen += lineLen; |
1225 | | remainLen -= lineLen; |
1226 | | |
1227 | | lineLen = wolfSSL_BIO_gets(in, §ion[sectionLen], |
1228 | | remainLen); |
1229 | | if (lineLen <= 0) { |
1230 | | goto error; |
1231 | | } |
1232 | | } |
1233 | | |
1234 | | if (canonPos > 0) { |
1235 | | canonPos--; |
1236 | | } |
1237 | | |
1238 | | /* Strip the final trailing newline. Support \r, \n or \r\n. */ |
1239 | | if (canonSection[canonPos] == '\n') { |
1240 | | if (canonPos > 0) { |
1241 | | canonPos--; |
1242 | | } |
1243 | | } |
1244 | | |
1245 | | if (canonSection[canonPos] == '\r') { |
1246 | | if (canonPos > 0) { |
1247 | | canonPos--; |
1248 | | } |
1249 | | } |
1250 | | |
1251 | | canonSection[canonPos+1] = '\0'; |
1252 | | |
1253 | | *bcont = wolfSSL_BIO_new(wolfSSL_BIO_s_mem()); |
1254 | | ret = wolfSSL_BIO_write(*bcont, canonSection, |
1255 | | canonPos + 1); |
1256 | | if (ret != (canonPos+1)) { |
1257 | | goto error; |
1258 | | } |
1259 | | if ((bcontMemSz = wolfSSL_BIO_get_mem_data(*bcont, &bcontMem)) |
1260 | | < 0) { |
1261 | | goto error; |
1262 | | } |
1263 | | XFREE(canonSection, NULL, DYNAMIC_TYPE_PKCS7); |
1264 | | canonSection = NULL; |
1265 | | |
1266 | | wc_MIME_free_hdrs(allHdrs); |
1267 | | allHdrs = NULL; |
1268 | | section[0] = '\0'; |
1269 | | sectionLen = 0; |
1270 | | lineLen = wolfSSL_BIO_gets(in, section, remainLen); |
1271 | | if (lineLen <= 0) { |
1272 | | goto error; |
1273 | | } |
1274 | | while (isEnd == 0 && remainLen > 0) { |
1275 | | sectionLen += lineLen; |
1276 | | remainLen -= lineLen; |
1277 | | lineLen = wolfSSL_BIO_gets(in, §ion[sectionLen], |
1278 | | remainLen); |
1279 | | if (lineLen <= 0) { |
1280 | | goto error; |
1281 | | } |
1282 | | /* Line with just newline signals end of headers. */ |
1283 | | if ((lineLen==2 && !XSTRNCMP(§ion[sectionLen], |
1284 | | "\r\n", 2)) || |
1285 | | (lineLen==1 && (section[sectionLen] == '\r' || |
1286 | | section[sectionLen] == '\n'))) { |
1287 | | isEnd = 1; |
1288 | | } |
1289 | | } |
1290 | | section[sectionLen] = '\0'; |
1291 | | ret = wc_MIME_parse_headers(section, sectionLen, &allHdrs); |
1292 | | if (ret < 0) { |
1293 | | WOLFSSL_MSG("Parsing MIME headers failed."); |
1294 | | goto error; |
1295 | | } |
1296 | | curHdr = wc_MIME_find_header_name(kContType, allHdrs); |
1297 | | if (curHdr == NULL || (XSTRNCMP(curHdr->body, kAppPkcsSign, |
1298 | | XSTR_SIZEOF(kAppPkcsSign)) && |
1299 | | XSTRNCMP(curHdr->body, kAppXPkcsSign, |
1300 | | XSTR_SIZEOF(kAppXPkcsSign)))) { |
1301 | | WOLFSSL_MSG("S/MIME headers not found inside " |
1302 | | "multipart message.\n"); |
1303 | | goto error; |
1304 | | } |
1305 | | |
1306 | | section[0] = '\0'; |
1307 | | sectionLen = 0; |
1308 | | lineLen = wolfSSL_BIO_gets(in, section, remainLen); |
1309 | | while (XSTRNCMP(§ion[sectionLen], boundary, boundLen) && |
1310 | | remainLen > 0) { |
1311 | | sectionLen += lineLen; |
1312 | | remainLen -= lineLen; |
1313 | | lineLen = wolfSSL_BIO_gets(in, §ion[sectionLen], |
1314 | | remainLen); |
1315 | | if (lineLen <= 0) { |
1316 | | goto error; |
1317 | | } |
1318 | | } |
1319 | | |
1320 | | XFREE(boundary, NULL, DYNAMIC_TYPE_PKCS7); |
1321 | | boundary = NULL; |
1322 | | } |
1323 | | } |
1324 | | else if (curHdr && (!XSTRNCMP(curHdr->body, kAppPkcs7Mime, |
1325 | | XSTR_SIZEOF(kAppPkcs7Mime)) || |
1326 | | !XSTRNCMP(curHdr->body, kAppXPkcs7Mime, |
1327 | | XSTR_SIZEOF(kAppXPkcs7Mime)))) { |
1328 | | sectionLen = wolfSSL_BIO_get_len(in); |
1329 | | if (sectionLen <= 0) { |
1330 | | goto error; |
1331 | | } |
1332 | | ret = wolfSSL_BIO_read(in, section, sectionLen); |
1333 | | if (ret < 0 || ret != sectionLen) { |
1334 | | WOLFSSL_MSG("Error reading input BIO."); |
1335 | | goto error; |
1336 | | } |
1337 | | } |
1338 | | else { |
1339 | | WOLFSSL_MSG("S/MIME headers not found."); |
1340 | | goto error; |
1341 | | } |
1342 | | |
1343 | | curHdr = wc_MIME_find_header_name(kCTE, allHdrs); |
1344 | | if (curHdr == NULL) { |
1345 | | WOLFSSL_MSG("Content-Transfer-Encoding header not found, " |
1346 | | "assuming base64 encoding."); |
1347 | | } |
1348 | | else if (XSTRNCMP(curHdr->body, "base64", XSTRLEN("base64"))) { |
1349 | | WOLFSSL_MSG("S/MIME encodings other than base64 are not " |
1350 | | "currently supported.\n"); |
1351 | | goto error; |
1352 | | } |
1353 | | |
1354 | | if (section == NULL || sectionLen <= 0) { |
1355 | | goto error; |
1356 | | } |
1357 | | outLen = (word32)((sectionLen*3+3)/4)+1; |
1358 | | out = (byte*)XMALLOC(outLen*sizeof(byte), NULL, DYNAMIC_TYPE_PKCS7); |
1359 | | outHead = out; |
1360 | | if (outHead == NULL) { |
1361 | | goto error; |
1362 | | } |
1363 | | /* Strip trailing newlines. */ |
1364 | | while ((sectionLen > 0) && |
1365 | | (section[sectionLen-1] == '\r' || section[sectionLen-1] == '\n')) { |
1366 | | sectionLen--; |
1367 | | } |
1368 | | section[sectionLen] = '\0'; |
1369 | | ret = Base64_Decode((const byte*)section, (word32)sectionLen, out, &outLen); |
1370 | | if (ret < 0) { |
1371 | | WOLFSSL_MSG("Error base64 decoding S/MIME message."); |
1372 | | goto error; |
1373 | | } |
1374 | | pkcs7 = wolfSSL_d2i_PKCS7_only(NULL, (const unsigned char**)&out, |
1375 | | (int)outLen, bcontMem, (word32)bcontMemSz); |
1376 | | |
1377 | | wc_MIME_free_hdrs(allHdrs); |
1378 | | XFREE(outHead, NULL, DYNAMIC_TYPE_PKCS7); |
1379 | | XFREE(section, NULL, DYNAMIC_TYPE_PKCS7); |
1380 | | |
1381 | | return pkcs7; |
1382 | | |
1383 | | error: |
1384 | | wc_MIME_free_hdrs(allHdrs); |
1385 | | XFREE(boundary, NULL, DYNAMIC_TYPE_PKCS7); |
1386 | | XFREE(outHead, NULL, DYNAMIC_TYPE_PKCS7); |
1387 | | XFREE(section, NULL, DYNAMIC_TYPE_PKCS7); |
1388 | | XFREE(canonSection, NULL, DYNAMIC_TYPE_PKCS7); |
1389 | | XFREE(canonLine, NULL, DYNAMIC_TYPE_PKCS7); |
1390 | | if (bcont) { |
1391 | | wolfSSL_BIO_free(*bcont); |
1392 | | *bcont = NULL; /* reset 'bcount' pointer to NULL on failure */ |
1393 | | } |
1394 | | |
1395 | | return NULL; |
1396 | | } |
1397 | | |
1398 | | /* Convert hash algo OID (from Hash_Sum in asn.h) to SMIME string equivalent. |
1399 | | * Returns hash algorithm string or "unknown" if not found */ |
1400 | | static const char* wolfSSL_SMIME_HashOIDToString(int hashOID) |
1401 | | { |
1402 | | switch (hashOID) { |
1403 | | case MD5h: |
1404 | | return "md5"; |
1405 | | case SHAh: |
1406 | | return "sha1"; |
1407 | | case SHA224h: |
1408 | | return "sha-224"; |
1409 | | case SHA256h: |
1410 | | return "sha-256"; |
1411 | | case SHA384h: |
1412 | | return "sha-384"; |
1413 | | case SHA512h: |
1414 | | return "sha-512"; |
1415 | | case SHA3_224h: |
1416 | | return "sha3-224"; |
1417 | | case SHA3_384h: |
1418 | | return "sha3-384"; |
1419 | | case SHA3_512h: |
1420 | | return "sha3-512"; |
1421 | | default: |
1422 | | break; |
1423 | | } |
1424 | | |
1425 | | return "unknown"; |
1426 | | } |
1427 | | |
1428 | | /* Convert PKCS#7 type (from PKCS7_TYPES in pkcs7.h) to SMIME string. |
1429 | | * RFC2633 only defines signed-data, enveloped-data, certs-only. |
1430 | | * Returns string on success, NULL on unknown type. */ |
1431 | | static const char* wolfSSL_SMIME_PKCS7TypeToString(int type) |
1432 | | { |
1433 | | switch (type) { |
1434 | | case SIGNED_DATA: |
1435 | | return "signed-data"; |
1436 | | case ENVELOPED_DATA: |
1437 | | return "enveloped-data"; |
1438 | | default: |
1439 | | break; |
1440 | | } |
1441 | | |
1442 | | return NULL; |
1443 | | } |
1444 | | |
1445 | | /** |
1446 | | * Convert PKCS7 structure to SMIME format, adding necessary headers. |
1447 | | * |
1448 | | * Handles generation of PKCS7 bundle (ie: signedData). PKCS7 structure |
1449 | | * should be set up beforehand with PKCS7_sign/final/etc. Output is always |
1450 | | * Base64 encoded. |
1451 | | * |
1452 | | * out - output BIO for SMIME formatted data to be placed |
1453 | | * pkcs7 - input PKCS7 structure, initialized and set up |
1454 | | * in - input content to be encoded into PKCS7 |
1455 | | * flags - flags to control behavior of PKCS7 generation |
1456 | | * |
1457 | | * Returns 1 on success, 0 or negative on failure |
1458 | | */ |
1459 | | int wolfSSL_SMIME_write_PKCS7(WOLFSSL_BIO* out, PKCS7* pkcs7, WOLFSSL_BIO* in, |
1460 | | int flags) |
1461 | | { |
1462 | | int i; |
1463 | | int ret = 1; |
1464 | | WOLFSSL_PKCS7* p7 = (WOLFSSL_PKCS7*)pkcs7; |
1465 | | byte* p7out = NULL; |
1466 | | int len = 0; |
1467 | | |
1468 | | char boundary[33]; /* 32 chars + \0 */ |
1469 | | byte* sigBase64 = NULL; |
1470 | | word32 sigBase64Len = 0; |
1471 | | const char* p7TypeString = NULL; |
1472 | | |
1473 | | static const char alphanum[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; |
1474 | | |
1475 | | if (out == NULL || p7 == NULL) { |
1476 | | WOLFSSL_MSG("Bad function arguments"); |
1477 | | return 0; |
1478 | | } |
1479 | | |
1480 | | if (in != NULL && (p7->pkcs7.content == NULL || p7->pkcs7.contentSz == 0 || |
1481 | | p7->pkcs7.contentCRLF == 0)) { |
1482 | | /* store and adjust content line endings for CRLF if needed */ |
1483 | | if (wolfSSL_PKCS7_final((PKCS7*)p7, in, flags) != 1) { |
1484 | | ret = 0; |
1485 | | } |
1486 | | } |
1487 | | |
1488 | | if (ret > 0) { |
1489 | | /* Generate signedData bundle, DER in output (dynamic) */ |
1490 | | if ((len = wolfSSL_i2d_PKCS7((PKCS7*)p7, &p7out)) == |
1491 | | WC_NO_ERR_TRACE(WOLFSSL_FAILURE)) |
1492 | | { |
1493 | | WOLFSSL_MSG("Error in wolfSSL_i2d_PKCS7"); |
1494 | | ret = 0; |
1495 | | } |
1496 | | } |
1497 | | |
1498 | | /* Base64 encode signedData bundle */ |
1499 | | if (ret > 0) { |
1500 | | if (Base64_Encode(p7out, (word32)len, NULL, &sigBase64Len) != |
1501 | | WC_NO_ERR_TRACE(LENGTH_ONLY_E)) { |
1502 | | ret = 0; |
1503 | | } |
1504 | | else { |
1505 | | sigBase64 = (byte*)XMALLOC(sigBase64Len, NULL, |
1506 | | DYNAMIC_TYPE_TMP_BUFFER); |
1507 | | if (sigBase64 == NULL) { |
1508 | | ret = 0; |
1509 | | } |
1510 | | } |
1511 | | } |
1512 | | |
1513 | | if (ret > 0) { |
1514 | | XMEMSET(sigBase64, 0, sigBase64Len); |
1515 | | if (Base64_Encode(p7out, (word32)len, sigBase64, &sigBase64Len) < 0) { |
1516 | | WOLFSSL_MSG("Error in Base64_Encode of signature"); |
1517 | | ret = 0; |
1518 | | } |
1519 | | } |
1520 | | |
1521 | | /* build up SMIME message */ |
1522 | | if (ret > 0) { |
1523 | | if (flags & PKCS7_DETACHED) { |
1524 | | |
1525 | | /* generate random boundary */ |
1526 | | if (initGlobalRNG == 0 && wolfSSL_RAND_Init() != WOLFSSL_SUCCESS) { |
1527 | | WOLFSSL_MSG("No RNG to use"); |
1528 | | ret = 0; |
1529 | | } |
1530 | | |
1531 | | /* no need to generate random byte for null terminator (size-1) */ |
1532 | | if ((ret > 0) && (wc_RNG_GenerateBlock(&globalRNG, (byte*)boundary, |
1533 | | sizeof(boundary) - 1 ) != 0)) { |
1534 | | WOLFSSL_MSG("Error in wc_RNG_GenerateBlock"); |
1535 | | ret = 0; |
1536 | | } |
1537 | | |
1538 | | if (ret > 0) { |
1539 | | for (i = 0; i < (int)sizeof(boundary) - 1; i++) { |
1540 | | boundary[i] = |
1541 | | alphanum[boundary[i] % XSTR_SIZEOF(alphanum)]; |
1542 | | } |
1543 | | boundary[sizeof(boundary)-1] = 0; |
1544 | | } |
1545 | | |
1546 | | if (ret > 0) { |
1547 | | /* S/MIME header beginning */ |
1548 | | ret = wolfSSL_BIO_printf(out, |
1549 | | "MIME-Version: 1.0\n" |
1550 | | "Content-Type: multipart/signed; " |
1551 | | "protocol=\"application/x-pkcs7-signature\"; " |
1552 | | "micalg=\"%s\"; " |
1553 | | "boundary=\"----%s\"\n\n" |
1554 | | "This is an S/MIME signed message\n\n" |
1555 | | "------%s\n", |
1556 | | wolfSSL_SMIME_HashOIDToString(p7->pkcs7.hashOID), |
1557 | | boundary, boundary); |
1558 | | } |
1559 | | |
1560 | | if (ret > 0) { |
1561 | | /* S/MIME content */ |
1562 | | ret = wolfSSL_BIO_write(out, |
1563 | | p7->pkcs7.content, p7->pkcs7.contentSz); |
1564 | | } |
1565 | | |
1566 | | if (ret > 0) { |
1567 | | /* S/SMIME header end boundary */ |
1568 | | ret = wolfSSL_BIO_printf(out, |
1569 | | "\n------%s\n", boundary); |
1570 | | } |
1571 | | |
1572 | | if (ret > 0) { |
1573 | | /* Signature and header */ |
1574 | | ret = wolfSSL_BIO_printf(out, |
1575 | | "Content-Type: application/x-pkcs7-signature; " |
1576 | | "name=\"smime.p7s\"\n" |
1577 | | "Content-Transfer-Encoding: base64\n" |
1578 | | "Content-Disposition: attachment; " |
1579 | | "filename=\"smime.p7s\"\n\n" |
1580 | | "%.*s\n" /* Base64 encoded signature */ |
1581 | | "------%s--\n\n", |
1582 | | sigBase64Len, sigBase64, |
1583 | | boundary); |
1584 | | } |
1585 | | } |
1586 | | else { |
1587 | | p7TypeString = wolfSSL_SMIME_PKCS7TypeToString(p7->type); |
1588 | | if (p7TypeString == NULL) { |
1589 | | WOLFSSL_MSG("Unsupported PKCS7 SMIME type"); |
1590 | | ret = 0; |
1591 | | } |
1592 | | |
1593 | | if (ret > 0) { |
1594 | | /* not detached */ |
1595 | | ret = wolfSSL_BIO_printf(out, |
1596 | | "MIME-Version: 1.0\n" |
1597 | | "Content-Disposition: attachment; " |
1598 | | "filename=\"smime.p7m\"\n" |
1599 | | "Content-Type: application/x-pkcs7-mime; " |
1600 | | "smime-type=%s; name=\"smime.p7m\"\n" |
1601 | | "Content-Transfer-Encoding: base64\n\n" |
1602 | | "%.*s\n" /* signature */, |
1603 | | p7TypeString, sigBase64Len, sigBase64); |
1604 | | } |
1605 | | } |
1606 | | } |
1607 | | |
1608 | | XFREE(p7out, NULL, DYNAMIC_TYPE_TMP_BUFFER); |
1609 | | XFREE(sigBase64, NULL, DYNAMIC_TYPE_TMP_BUFFER); |
1610 | | |
1611 | | if (ret > 0) { |
1612 | | return WOLFSSL_SUCCESS; |
1613 | | } |
1614 | | |
1615 | | return WOLFSSL_FAILURE; |
1616 | | } |
1617 | | |
1618 | | #endif /* HAVE_SMIME */ |
1619 | | #endif /* !NO_BIO */ |
1620 | | #endif /* OPENSSL_ALL */ |
1621 | | |
1622 | | #endif /* HAVE_PKCS7 */ |
1623 | | /******************************************************************************* |
1624 | | * END OF PKCS7 APIs |
1625 | | ******************************************************************************/ |
1626 | | |
1627 | | /******************************************************************************* |
1628 | | * START OF PKCS12 APIs |
1629 | | ******************************************************************************/ |
1630 | | #ifdef OPENSSL_EXTRA |
1631 | | |
1632 | | /* no-op function. Was initially used for adding encryption algorithms available |
1633 | | * for PKCS12 */ |
1634 | | void wolfSSL_PKCS12_PBE_add(void) |
1635 | 0 | { |
1636 | 0 | WOLFSSL_ENTER("wolfSSL_PKCS12_PBE_add"); |
1637 | 0 | } |
1638 | | |
1639 | | #if !defined(NO_FILESYSTEM) && !defined(NO_STDIO_FILESYSTEM) |
1640 | | WOLFSSL_X509_PKCS12 *wolfSSL_d2i_PKCS12_fp(XFILE fp, |
1641 | | WOLFSSL_X509_PKCS12 **pkcs12) |
1642 | 0 | { |
1643 | 0 | WOLFSSL_ENTER("wolfSSL_d2i_PKCS12_fp"); |
1644 | 0 | return (WOLFSSL_X509_PKCS12 *)wolfSSL_d2i_X509_fp_ex(fp, (void **)pkcs12, |
1645 | 0 | PKCS12_TYPE); |
1646 | 0 | } |
1647 | | #endif /* !NO_FILESYSTEM */ |
1648 | | |
1649 | | #endif /* OPENSSL_EXTRA */ |
1650 | | |
1651 | | #if defined(HAVE_PKCS12) |
1652 | | |
1653 | | #ifdef OPENSSL_EXTRA |
1654 | | |
1655 | | #if !defined(NO_ASN) && !defined(NO_PWDBASED) |
1656 | | |
1657 | | #ifndef NO_BIO |
1658 | | WC_PKCS12* wolfSSL_d2i_PKCS12_bio(WOLFSSL_BIO* bio, WC_PKCS12** pkcs12) |
1659 | 0 | { |
1660 | 0 | WC_PKCS12* localPkcs12 = NULL; |
1661 | 0 | unsigned char* mem = NULL; |
1662 | 0 | long memSz; |
1663 | 0 | int ret = -1; |
1664 | |
|
1665 | 0 | WOLFSSL_ENTER("wolfSSL_d2i_PKCS12_bio"); |
1666 | |
|
1667 | 0 | if (bio == NULL) { |
1668 | 0 | WOLFSSL_MSG("Bad Function Argument bio is NULL"); |
1669 | 0 | return NULL; |
1670 | 0 | } |
1671 | | |
1672 | 0 | memSz = wolfSSL_BIO_get_len(bio); |
1673 | 0 | if (memSz <= 0) { |
1674 | 0 | return NULL; |
1675 | 0 | } |
1676 | 0 | mem = (unsigned char*)XMALLOC(memSz, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); |
1677 | 0 | if (mem == NULL) { |
1678 | 0 | return NULL; |
1679 | 0 | } |
1680 | | |
1681 | 0 | if (mem != NULL) { |
1682 | 0 | localPkcs12 = wc_PKCS12_new_ex(bio->heap); |
1683 | 0 | if (localPkcs12 == NULL) { |
1684 | 0 | WOLFSSL_MSG("Memory error"); |
1685 | 0 | } |
1686 | 0 | } |
1687 | |
|
1688 | 0 | if (mem != NULL && localPkcs12 != NULL) { |
1689 | 0 | if (wolfSSL_BIO_read(bio, mem, (int)memSz) == memSz) { |
1690 | 0 | ret = wc_d2i_PKCS12(mem, (word32)memSz, localPkcs12); |
1691 | 0 | if (ret < 0) { |
1692 | 0 | WOLFSSL_MSG("Failed to get PKCS12 sequence"); |
1693 | 0 | } |
1694 | 0 | } |
1695 | 0 | else { |
1696 | 0 | WOLFSSL_MSG("Failed to get data from bio struct"); |
1697 | 0 | } |
1698 | 0 | } |
1699 | | |
1700 | | /* cleanup */ |
1701 | 0 | XFREE(mem, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); |
1702 | 0 | if (ret < 0 && localPkcs12 != NULL) { |
1703 | 0 | wc_PKCS12_free(localPkcs12); |
1704 | 0 | localPkcs12 = NULL; |
1705 | 0 | } |
1706 | 0 | if (pkcs12 != NULL) |
1707 | 0 | *pkcs12 = localPkcs12; |
1708 | |
|
1709 | 0 | return localPkcs12; |
1710 | 0 | } |
1711 | | |
1712 | | /* Converts the PKCS12 to DER format and outputs it into bio. |
1713 | | * |
1714 | | * bio is the structure to hold output DER |
1715 | | * pkcs12 structure to create DER from |
1716 | | * |
1717 | | * return 1 for success or 0 if an error occurs |
1718 | | */ |
1719 | | int wolfSSL_i2d_PKCS12_bio(WOLFSSL_BIO *bio, WC_PKCS12 *pkcs12) |
1720 | 0 | { |
1721 | 0 | int ret = WC_NO_ERR_TRACE(WOLFSSL_FAILURE); |
1722 | |
|
1723 | 0 | WOLFSSL_ENTER("wolfSSL_i2d_PKCS12_bio"); |
1724 | |
|
1725 | 0 | if ((bio != NULL) && (pkcs12 != NULL)) { |
1726 | 0 | word32 certSz = 0; |
1727 | 0 | byte *certDer = NULL; |
1728 | |
|
1729 | 0 | certSz = (word32)wc_i2d_PKCS12(pkcs12, &certDer, NULL); |
1730 | 0 | if ((certSz > 0) && (certDer != NULL)) { |
1731 | 0 | if (wolfSSL_BIO_write(bio, certDer, (int)certSz) == (int)certSz) { |
1732 | 0 | ret = WOLFSSL_SUCCESS; |
1733 | 0 | } |
1734 | 0 | } |
1735 | |
|
1736 | 0 | XFREE(certDer, NULL, DYNAMIC_TYPE_PKCS); |
1737 | 0 | } |
1738 | |
|
1739 | 0 | return ret; |
1740 | 0 | } |
1741 | | #endif /* !NO_BIO */ |
1742 | | |
1743 | | /* Creates a new WC_PKCS12 structure |
1744 | | * |
1745 | | * pass password to use |
1746 | | * name friendlyName to use |
1747 | | * pkey private key to go into PKCS12 bundle |
1748 | | * cert certificate to go into PKCS12 bundle |
1749 | | * ca extra certificates that can be added to bundle. Can be NULL |
1750 | | * keyNID type of encryption to use on the key (-1 means no encryption) |
1751 | | * certNID type of encryption to use on the certificate |
1752 | | * itt number of iterations with encryption |
1753 | | * macItt number of iterations with mac creation |
1754 | | * keyType flag for signature and/or encryption key |
1755 | | * |
1756 | | * returns a pointer to a new WC_PKCS12 structure on success and NULL on fail |
1757 | | */ |
1758 | | WC_PKCS12* wolfSSL_PKCS12_create(char* pass, char* name, WOLFSSL_EVP_PKEY* pkey, |
1759 | | WOLFSSL_X509* cert, WOLF_STACK_OF(WOLFSSL_X509)* ca, int keyNID, |
1760 | | int certNID, int itt, int macItt, int keyType) |
1761 | 0 | { |
1762 | 0 | WC_PKCS12* pkcs12; |
1763 | 0 | WC_DerCertList* list = NULL; |
1764 | 0 | word32 passSz; |
1765 | 0 | byte* keyDer = NULL; |
1766 | 0 | word32 keyDerSz; |
1767 | 0 | byte* certDer; |
1768 | 0 | int certDerSz; |
1769 | |
|
1770 | 0 | WOLFSSL_ENTER("wolfSSL_PKCS12_create"); |
1771 | |
|
1772 | 0 | if (pass == NULL || pkey == NULL || cert == NULL) { |
1773 | 0 | WOLFSSL_LEAVE("wolfSSL_PKCS12_create", BAD_FUNC_ARG); |
1774 | 0 | return NULL; |
1775 | 0 | } |
1776 | 0 | passSz = (word32)XSTRLEN(pass); |
1777 | |
|
1778 | 0 | keyDer = (byte*)pkey->pkey.ptr; |
1779 | 0 | keyDerSz = (word32)pkey->pkey_sz; |
1780 | |
|
1781 | 0 | certDer = (byte*)wolfSSL_X509_get_der(cert, &certDerSz); |
1782 | 0 | if (certDer == NULL) { |
1783 | 0 | return NULL; |
1784 | 0 | } |
1785 | | |
1786 | 0 | if (ca != NULL) { |
1787 | 0 | unsigned long numCerts = ca->num; |
1788 | 0 | WOLFSSL_STACK* sk = ca; |
1789 | |
|
1790 | 0 | while (numCerts > 0 && sk != NULL) { |
1791 | 0 | byte* curDer; |
1792 | 0 | WC_DerCertList* cur; |
1793 | 0 | int curDerSz = 0; |
1794 | |
|
1795 | 0 | cur = (WC_DerCertList*)XMALLOC(sizeof(WC_DerCertList), NULL, |
1796 | 0 | DYNAMIC_TYPE_PKCS); |
1797 | 0 | if (cur == NULL) { |
1798 | 0 | wc_FreeCertList(list, NULL); |
1799 | 0 | return NULL; |
1800 | 0 | } |
1801 | | |
1802 | 0 | curDer = (byte*)wolfSSL_X509_get_der(sk->data.x509, &curDerSz); |
1803 | 0 | if (curDer == NULL || curDerSz < 0) { |
1804 | 0 | XFREE(cur, NULL, DYNAMIC_TYPE_PKCS); |
1805 | 0 | wc_FreeCertList(list, NULL); |
1806 | 0 | return NULL; |
1807 | 0 | } |
1808 | | |
1809 | 0 | cur->buffer = (byte*)XMALLOC(curDerSz, NULL, DYNAMIC_TYPE_PKCS); |
1810 | 0 | if (cur->buffer == NULL) { |
1811 | 0 | XFREE(cur, NULL, DYNAMIC_TYPE_PKCS); |
1812 | 0 | wc_FreeCertList(list, NULL); |
1813 | 0 | return NULL; |
1814 | 0 | } |
1815 | 0 | XMEMCPY(cur->buffer, curDer, curDerSz); |
1816 | 0 | cur->bufferSz = (word32)curDerSz; |
1817 | 0 | cur->next = list; |
1818 | 0 | list = cur; |
1819 | |
|
1820 | 0 | sk = sk->next; |
1821 | 0 | numCerts--; |
1822 | 0 | } |
1823 | 0 | } |
1824 | | |
1825 | 0 | pkcs12 = wc_PKCS12_create(pass, passSz, name, keyDer, keyDerSz, |
1826 | 0 | certDer, (word32)certDerSz, list, keyNID, certNID, itt, macItt, |
1827 | 0 | keyType, NULL); |
1828 | |
|
1829 | 0 | if (ca != NULL) { |
1830 | 0 | wc_FreeCertList(list, NULL); |
1831 | 0 | } |
1832 | |
|
1833 | 0 | return pkcs12; |
1834 | 0 | } |
1835 | | |
1836 | | |
1837 | | /* return WOLFSSL_SUCCESS on success, WOLFSSL_FAILURE on failure */ |
1838 | | int wolfSSL_PKCS12_parse(WC_PKCS12* pkcs12, const char* psw, |
1839 | | WOLFSSL_EVP_PKEY** pkey, WOLFSSL_X509** cert, |
1840 | | WOLF_STACK_OF(WOLFSSL_X509)** ca) |
1841 | 0 | { |
1842 | 0 | void* heap = NULL; |
1843 | 0 | int ret; |
1844 | 0 | byte* certData = NULL; |
1845 | 0 | word32 certDataSz; |
1846 | 0 | byte* pk = NULL; |
1847 | 0 | word32 pkSz; |
1848 | 0 | WC_DerCertList* certList = NULL; |
1849 | 0 | WC_DECLARE_VAR(DeCert, DecodedCert, 1, 0); |
1850 | |
|
1851 | 0 | WOLFSSL_ENTER("wolfSSL_PKCS12_parse"); |
1852 | | |
1853 | | /* make sure we init return args */ |
1854 | 0 | if (pkey) *pkey = NULL; |
1855 | 0 | if (cert) *cert = NULL; |
1856 | 0 | if (ca) *ca = NULL; |
1857 | |
|
1858 | 0 | if (pkcs12 == NULL || psw == NULL || pkey == NULL || cert == NULL) { |
1859 | 0 | WOLFSSL_MSG("Bad argument value"); |
1860 | 0 | return WOLFSSL_FAILURE; |
1861 | 0 | } |
1862 | | |
1863 | 0 | heap = wc_PKCS12_GetHeap(pkcs12); |
1864 | |
|
1865 | 0 | if (ca == NULL) { |
1866 | 0 | ret = wc_PKCS12_parse(pkcs12, psw, &pk, &pkSz, &certData, &certDataSz, |
1867 | 0 | NULL); |
1868 | 0 | } |
1869 | 0 | else { |
1870 | 0 | ret = wc_PKCS12_parse(pkcs12, psw, &pk, &pkSz, &certData, &certDataSz, |
1871 | 0 | &certList); |
1872 | 0 | } |
1873 | 0 | if (ret < 0) { |
1874 | 0 | WOLFSSL_LEAVE("wolfSSL_PKCS12_parse", ret); |
1875 | 0 | return WOLFSSL_FAILURE; |
1876 | 0 | } |
1877 | | |
1878 | 0 | #ifdef WOLFSSL_SMALL_STACK |
1879 | 0 | DeCert = (DecodedCert *)XMALLOC(sizeof(*DeCert), heap, |
1880 | 0 | DYNAMIC_TYPE_DCERT); |
1881 | 0 | if (DeCert == NULL) { |
1882 | 0 | WOLFSSL_MSG("out of memory"); |
1883 | 0 | return WOLFSSL_FAILURE; |
1884 | 0 | } |
1885 | 0 | #endif |
1886 | | |
1887 | | /* Decode cert and place in X509 stack struct */ |
1888 | 0 | if (certList != NULL) { |
1889 | 0 | WC_DerCertList* current = certList; |
1890 | |
|
1891 | 0 | *ca = (WOLF_STACK_OF(WOLFSSL_X509)*)XMALLOC( |
1892 | 0 | sizeof(WOLF_STACK_OF(WOLFSSL_X509)), heap, DYNAMIC_TYPE_X509); |
1893 | 0 | if (*ca == NULL) { |
1894 | 0 | XFREE(pk, heap, DYNAMIC_TYPE_PUBLIC_KEY); |
1895 | 0 | XFREE(certData, heap, DYNAMIC_TYPE_PKCS); |
1896 | | /* Free up WC_DerCertList and move on */ |
1897 | 0 | while (current != NULL) { |
1898 | 0 | WC_DerCertList* next = current->next; |
1899 | |
|
1900 | 0 | XFREE(current->buffer, heap, DYNAMIC_TYPE_PKCS); |
1901 | 0 | XFREE(current, heap, DYNAMIC_TYPE_PKCS); |
1902 | 0 | current = next; |
1903 | 0 | } |
1904 | 0 | ret = WOLFSSL_FAILURE; |
1905 | 0 | goto out; |
1906 | 0 | } |
1907 | 0 | XMEMSET(*ca, 0, sizeof(WOLF_STACK_OF(WOLFSSL_X509))); |
1908 | | |
1909 | | /* add list of DER certs as X509's to stack */ |
1910 | 0 | while (current != NULL) { |
1911 | 0 | WC_DerCertList* toFree = current; |
1912 | 0 | WOLFSSL_X509* x509; |
1913 | |
|
1914 | 0 | x509 = (WOLFSSL_X509*)XMALLOC(sizeof(WOLFSSL_X509), heap, |
1915 | 0 | DYNAMIC_TYPE_X509); |
1916 | 0 | InitX509(x509, 1, heap); |
1917 | 0 | InitDecodedCert(DeCert, current->buffer, current->bufferSz, heap); |
1918 | 0 | if (ParseCertRelative(DeCert, CERT_TYPE, NO_VERIFY, NULL, NULL) |
1919 | 0 | != 0) { |
1920 | 0 | WOLFSSL_MSG("Issue with parsing certificate"); |
1921 | 0 | FreeDecodedCert(DeCert); |
1922 | 0 | wolfSSL_X509_free(x509); |
1923 | 0 | x509 = NULL; |
1924 | 0 | } |
1925 | 0 | else { |
1926 | 0 | if (CopyDecodedToX509(x509, DeCert) != 0) { |
1927 | 0 | WOLFSSL_MSG("Failed to copy decoded cert"); |
1928 | 0 | FreeDecodedCert(DeCert); |
1929 | 0 | wolfSSL_X509_free(x509); |
1930 | 0 | x509 = NULL; |
1931 | 0 | wolfSSL_sk_X509_pop_free(*ca, NULL); *ca = NULL; |
1932 | 0 | XFREE(pk, heap, DYNAMIC_TYPE_PUBLIC_KEY); |
1933 | 0 | XFREE(certData, heap, DYNAMIC_TYPE_PKCS); |
1934 | | /* Free up WC_DerCertList */ |
1935 | 0 | while (current != NULL) { |
1936 | 0 | WC_DerCertList* next = current->next; |
1937 | |
|
1938 | 0 | XFREE(current->buffer, heap, DYNAMIC_TYPE_PKCS); |
1939 | 0 | XFREE(current, heap, DYNAMIC_TYPE_PKCS); |
1940 | 0 | current = next; |
1941 | 0 | } |
1942 | 0 | ret = WOLFSSL_FAILURE; |
1943 | 0 | goto out; |
1944 | 0 | } |
1945 | 0 | FreeDecodedCert(DeCert); |
1946 | |
|
1947 | 0 | if (wolfSSL_sk_X509_push(*ca, x509) <= 0) { |
1948 | 0 | WOLFSSL_MSG("Failed to push x509 onto stack"); |
1949 | 0 | wolfSSL_X509_free(x509); |
1950 | 0 | x509 = NULL; |
1951 | 0 | wolfSSL_sk_X509_pop_free(*ca, NULL); *ca = NULL; |
1952 | 0 | XFREE(pk, heap, DYNAMIC_TYPE_PUBLIC_KEY); |
1953 | 0 | XFREE(certData, heap, DYNAMIC_TYPE_PKCS); |
1954 | | |
1955 | | /* Free up WC_DerCertList */ |
1956 | 0 | while (current != NULL) { |
1957 | 0 | WC_DerCertList* next = current->next; |
1958 | |
|
1959 | 0 | XFREE(current->buffer, heap, DYNAMIC_TYPE_PKCS); |
1960 | 0 | XFREE(current, heap, DYNAMIC_TYPE_PKCS); |
1961 | 0 | current = next; |
1962 | 0 | } |
1963 | 0 | ret = WOLFSSL_FAILURE; |
1964 | 0 | goto out; |
1965 | 0 | } |
1966 | 0 | } |
1967 | 0 | current = current->next; |
1968 | 0 | XFREE(toFree->buffer, heap, DYNAMIC_TYPE_PKCS); |
1969 | 0 | XFREE(toFree, heap, DYNAMIC_TYPE_PKCS); |
1970 | 0 | } |
1971 | 0 | } |
1972 | | |
1973 | | |
1974 | | /* Decode cert and place in X509 struct */ |
1975 | 0 | if (certData != NULL) { |
1976 | 0 | *cert = (WOLFSSL_X509*)XMALLOC(sizeof(WOLFSSL_X509), heap, |
1977 | 0 | DYNAMIC_TYPE_X509); |
1978 | 0 | if (*cert == NULL) { |
1979 | 0 | XFREE(pk, heap, DYNAMIC_TYPE_PUBLIC_KEY); |
1980 | 0 | if (ca != NULL) { |
1981 | 0 | wolfSSL_sk_X509_pop_free(*ca, NULL); *ca = NULL; |
1982 | 0 | } |
1983 | 0 | XFREE(certData, heap, DYNAMIC_TYPE_PKCS); |
1984 | 0 | ret = WOLFSSL_FAILURE; |
1985 | 0 | goto out; |
1986 | 0 | } |
1987 | 0 | InitX509(*cert, 1, heap); |
1988 | 0 | InitDecodedCert(DeCert, certData, certDataSz, heap); |
1989 | 0 | if (ParseCertRelative(DeCert, CERT_TYPE, NO_VERIFY, NULL, NULL) != 0) { |
1990 | 0 | WOLFSSL_MSG("Issue with parsing certificate"); |
1991 | 0 | } |
1992 | 0 | if (CopyDecodedToX509(*cert, DeCert) != 0) { |
1993 | 0 | WOLFSSL_MSG("Failed to copy decoded cert"); |
1994 | 0 | FreeDecodedCert(DeCert); |
1995 | 0 | XFREE(pk, heap, DYNAMIC_TYPE_PUBLIC_KEY); |
1996 | 0 | if (ca != NULL) { |
1997 | 0 | wolfSSL_sk_X509_pop_free(*ca, NULL); *ca = NULL; |
1998 | 0 | } |
1999 | 0 | wolfSSL_X509_free(*cert); *cert = NULL; |
2000 | 0 | XFREE(certData, heap, DYNAMIC_TYPE_PKCS); |
2001 | 0 | ret = WOLFSSL_FAILURE; |
2002 | 0 | goto out; |
2003 | 0 | } |
2004 | 0 | FreeDecodedCert(DeCert); |
2005 | 0 | XFREE(certData, heap, DYNAMIC_TYPE_PKCS); |
2006 | 0 | } |
2007 | | |
2008 | | |
2009 | | /* get key type */ |
2010 | 0 | ret = BAD_STATE_E; |
2011 | 0 | if (pk != NULL) { /* decode key if present */ |
2012 | 0 | *pkey = wolfSSL_EVP_PKEY_new_ex(heap); |
2013 | 0 | if (*pkey == NULL) { |
2014 | 0 | wolfSSL_X509_free(*cert); *cert = NULL; |
2015 | 0 | if (ca != NULL) { |
2016 | 0 | wolfSSL_sk_X509_pop_free(*ca, NULL); *ca = NULL; |
2017 | 0 | } |
2018 | 0 | XFREE(pk, heap, DYNAMIC_TYPE_PUBLIC_KEY); |
2019 | 0 | ret = WOLFSSL_FAILURE; |
2020 | 0 | goto out; |
2021 | 0 | } |
2022 | | |
2023 | 0 | #ifndef NO_RSA |
2024 | 0 | { |
2025 | 0 | const unsigned char* pt = pk; |
2026 | 0 | if (wolfSSL_d2i_PrivateKey(WC_EVP_PKEY_RSA, pkey, &pt, pkSz) != |
2027 | 0 | NULL) { |
2028 | 0 | ret = 0; |
2029 | 0 | } |
2030 | 0 | } |
2031 | 0 | #endif /* NO_RSA */ |
2032 | |
|
2033 | 0 | #ifdef HAVE_ECC |
2034 | 0 | if (ret != 0) { /* if is in fail state check if ECC key */ |
2035 | 0 | const unsigned char* pt = pk; |
2036 | 0 | if (wolfSSL_d2i_PrivateKey(WC_EVP_PKEY_EC, pkey, &pt, pkSz) != |
2037 | 0 | NULL) { |
2038 | 0 | ret = 0; |
2039 | 0 | } |
2040 | 0 | } |
2041 | 0 | #endif /* HAVE_ECC */ |
2042 | 0 | XFREE(pk, heap, DYNAMIC_TYPE_PKCS); |
2043 | 0 | if (ret != 0) { /* if is in fail state and no PKEY then fail */ |
2044 | 0 | wolfSSL_X509_free(*cert); *cert = NULL; |
2045 | 0 | if (ca != NULL) { |
2046 | 0 | wolfSSL_sk_X509_pop_free(*ca, NULL); *ca = NULL; |
2047 | 0 | } |
2048 | 0 | wolfSSL_EVP_PKEY_free(*pkey); *pkey = NULL; |
2049 | 0 | WOLFSSL_MSG("Bad PKCS12 key format"); |
2050 | 0 | ret = WOLFSSL_FAILURE; |
2051 | 0 | goto out; |
2052 | 0 | } |
2053 | | |
2054 | 0 | if (pkey != NULL && *pkey != NULL) { |
2055 | 0 | (*pkey)->save_type = 0; |
2056 | 0 | } |
2057 | 0 | } |
2058 | | |
2059 | 0 | (void)ret; |
2060 | 0 | (void)ca; |
2061 | |
|
2062 | 0 | ret = WOLFSSL_SUCCESS; |
2063 | |
|
2064 | 0 | out: |
2065 | |
|
2066 | 0 | WC_FREE_VAR_EX(DeCert, heap, DYNAMIC_TYPE_DCERT); |
2067 | |
|
2068 | 0 | return ret; |
2069 | 0 | } |
2070 | | |
2071 | | int wolfSSL_PKCS12_verify_mac(WC_PKCS12 *pkcs12, const char *psw, |
2072 | | int pswLen) |
2073 | 0 | { |
2074 | 0 | WOLFSSL_ENTER("wolfSSL_PKCS12_verify_mac"); |
2075 | |
|
2076 | 0 | if (!pkcs12) { |
2077 | 0 | return WOLFSSL_FAILURE; |
2078 | 0 | } |
2079 | | |
2080 | 0 | return wc_PKCS12_verify_ex(pkcs12, (const byte*)psw, (word32)pswLen) == 0 ? |
2081 | 0 | WOLFSSL_SUCCESS : WOLFSSL_FAILURE; |
2082 | 0 | } |
2083 | | |
2084 | | #endif /* !NO_ASN && !NO_PWDBASED */ |
2085 | | |
2086 | | #endif /* OPENSSL_EXTRA */ |
2087 | | |
2088 | | #endif /* HAVE_PKCS12 */ |
2089 | | /******************************************************************************* |
2090 | | * END OF PKCS12 APIs |
2091 | | ******************************************************************************/ |
2092 | | |
2093 | | #endif /* !WOLFCRYPT_ONLY && !NO_CERTS */ |
2094 | | |
2095 | | #endif /* !WOLFSSL_SSL_P7P12_INCLUDED */ |