Line data Source code
1 : /*
2 : * Copyright (C) 2003-2014 Free Software Foundation, Inc.
3 : * Copyright (C) 2014 Red Hat
4 : *
5 : * Author: Nikos Mavrogiannopoulos
6 : *
7 : * This file is part of GnuTLS.
8 : *
9 : * The GnuTLS is free software; you can redistribute it and/or
10 : * modify it under the terms of the GNU Lesser General Public License
11 : * as published by the Free Software Foundation; either version 2.1 of
12 : * the License, or (at your option) any later version.
13 : *
14 : * This library is distributed in the hope that it will be useful, but
15 : * WITHOUT ANY WARRANTY; without even the implied warranty of
16 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 : * Lesser General Public License for more details.
18 : *
19 : * You should have received a copy of the GNU Lesser General Public License
20 : * along with this program. If not, see <https://www.gnu.org/licenses/>
21 : *
22 : */
23 :
24 : /* Functions that relate on PKCS12 Bag packet parsing.
25 : */
26 :
27 : #include "gnutls_int.h"
28 :
29 : #include <datum.h>
30 : #include <global.h>
31 : #include "errors.h"
32 : #include <common.h>
33 : #include "x509_int.h"
34 : #include "pkcs7_int.h"
35 :
36 : /**
37 : * gnutls_pkcs12_bag_init:
38 : * @bag: A pointer to the type to be initialized
39 : *
40 : * This function will initialize a PKCS12 bag structure. PKCS12 Bags
41 : * usually contain private keys, lists of X.509 Certificates and X.509
42 : * Certificate revocation lists.
43 : *
44 : * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
45 : * negative error value.
46 : **/
47 751 : int gnutls_pkcs12_bag_init(gnutls_pkcs12_bag_t * bag)
48 : {
49 751 : *bag = gnutls_calloc(1, sizeof(gnutls_pkcs12_bag_int));
50 :
51 751 : if (*bag) {
52 751 : return 0; /* success */
53 : }
54 : return GNUTLS_E_MEMORY_ERROR;
55 : }
56 :
57 765 : static inline void _pkcs12_bag_free_data(gnutls_pkcs12_bag_t bag)
58 : {
59 765 : unsigned i;
60 :
61 1537 : for (i = 0; i < bag->bag_elements; i++) {
62 772 : _gnutls_free_datum(&bag->element[i].data);
63 772 : _gnutls_free_datum(&bag->element[i].local_key_id);
64 772 : gnutls_free(bag->element[i].friendly_name);
65 772 : bag->element[i].type = 0;
66 : }
67 :
68 765 : }
69 :
70 :
71 : /**
72 : * gnutls_pkcs12_bag_deinit:
73 : * @bag: A pointer to the type to be initialized
74 : *
75 : * This function will deinitialize a PKCS12 Bag structure.
76 : **/
77 751 : void gnutls_pkcs12_bag_deinit(gnutls_pkcs12_bag_t bag)
78 : {
79 751 : if (!bag)
80 : return;
81 :
82 751 : _pkcs12_bag_free_data(bag);
83 :
84 751 : gnutls_free(bag);
85 : }
86 :
87 : /**
88 : * gnutls_pkcs12_bag_get_type:
89 : * @bag: The bag
90 : * @indx: The element of the bag to get the type
91 : *
92 : * This function will return the bag's type.
93 : *
94 : * Returns: On error a negative error value or one of the #gnutls_pkcs12_bag_type_t enumerations.
95 : **/
96 : int
97 1319 : gnutls_pkcs12_bag_get_type(gnutls_pkcs12_bag_t bag, unsigned indx)
98 : {
99 1319 : if (bag == NULL) {
100 0 : gnutls_assert();
101 0 : return GNUTLS_E_INVALID_REQUEST;
102 : }
103 :
104 1319 : if (indx >= bag->bag_elements)
105 : return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
106 1318 : return bag->element[indx].type;
107 : }
108 :
109 : /**
110 : * gnutls_pkcs12_bag_get_count:
111 : * @bag: The bag
112 : *
113 : * This function will return the number of the elements within the bag.
114 : *
115 : * Returns: Number of elements in bag, or an negative error code on
116 : * error.
117 : **/
118 693 : int gnutls_pkcs12_bag_get_count(gnutls_pkcs12_bag_t bag)
119 : {
120 693 : if (bag == NULL) {
121 0 : gnutls_assert();
122 0 : return GNUTLS_E_INVALID_REQUEST;
123 : }
124 :
125 693 : return bag->bag_elements;
126 : }
127 :
128 : /**
129 : * gnutls_pkcs12_bag_get_data:
130 : * @bag: The bag
131 : * @indx: The element of the bag to get the data from
132 : * @data: where the bag's data will be. Should be treated as constant.
133 : *
134 : * This function will return the bag's data. The data is a constant
135 : * that is stored into the bag. Should not be accessed after the bag
136 : * is deleted.
137 : *
138 : * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
139 : * negative error value.
140 : **/
141 : int
142 687 : gnutls_pkcs12_bag_get_data(gnutls_pkcs12_bag_t bag, unsigned indx,
143 : gnutls_datum_t * data)
144 : {
145 687 : if (bag == NULL) {
146 0 : gnutls_assert();
147 0 : return GNUTLS_E_INVALID_REQUEST;
148 : }
149 :
150 687 : if (indx >= bag->bag_elements)
151 : return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
152 :
153 687 : data->data = bag->element[indx].data.data;
154 687 : data->size = bag->element[indx].data.size;
155 :
156 687 : return 0;
157 : }
158 :
159 : #define X509_CERT_OID "1.2.840.113549.1.9.22.1"
160 : #define X509_CRL_OID "1.2.840.113549.1.9.23.1"
161 : #define RANDOM_NONCE_OID "1.2.840.113549.1.9.25.3"
162 :
163 : int
164 362 : _pkcs12_decode_crt_bag(gnutls_pkcs12_bag_type_t type,
165 : const gnutls_datum_t * in, gnutls_datum_t * out)
166 : {
167 362 : int ret;
168 362 : ASN1_TYPE c2 = ASN1_TYPE_EMPTY;
169 :
170 362 : switch (type) {
171 344 : case GNUTLS_BAG_CERTIFICATE:
172 344 : if ((ret = asn1_create_element(_gnutls_get_pkix(),
173 : "PKIX1.pkcs-12-CertBag",
174 : &c2)) != ASN1_SUCCESS) {
175 0 : gnutls_assert();
176 0 : ret = _gnutls_asn2err(ret);
177 0 : goto cleanup;
178 : }
179 :
180 344 : ret = asn1_der_decoding(&c2, in->data, in->size, NULL);
181 344 : if (ret != ASN1_SUCCESS) {
182 1 : gnutls_assert();
183 1 : ret = _gnutls_asn2err(ret);
184 1 : goto cleanup;
185 : }
186 :
187 343 : ret =
188 343 : _gnutls_x509_read_string(c2, "certValue", out,
189 : ASN1_ETYPE_OCTET_STRING, 1);
190 343 : if (ret < 0) {
191 1 : gnutls_assert();
192 1 : goto cleanup;
193 : }
194 : break;
195 :
196 17 : case GNUTLS_BAG_CRL:
197 17 : if ((ret = asn1_create_element(_gnutls_get_pkix(),
198 : "PKIX1.pkcs-12-CRLBag",
199 : &c2)) != ASN1_SUCCESS) {
200 0 : gnutls_assert();
201 0 : ret = _gnutls_asn2err(ret);
202 0 : goto cleanup;
203 : }
204 :
205 17 : ret = asn1_der_decoding(&c2, in->data, in->size, NULL);
206 17 : if (ret != ASN1_SUCCESS) {
207 1 : gnutls_assert();
208 1 : ret = _gnutls_asn2err(ret);
209 1 : goto cleanup;
210 : }
211 :
212 16 : ret =
213 16 : _gnutls_x509_read_string(c2, "crlValue", out,
214 : ASN1_ETYPE_OCTET_STRING, 1);
215 16 : if (ret < 0) {
216 0 : gnutls_assert();
217 0 : goto cleanup;
218 : }
219 : break;
220 :
221 1 : case GNUTLS_BAG_SECRET:
222 1 : if ((ret = asn1_create_element(_gnutls_get_pkix(),
223 : "PKIX1.pkcs-12-SecretBag",
224 : &c2)) != ASN1_SUCCESS) {
225 0 : gnutls_assert();
226 0 : ret = _gnutls_asn2err(ret);
227 0 : goto cleanup;
228 : }
229 :
230 1 : ret = asn1_der_decoding(&c2, in->data, in->size, NULL);
231 1 : if (ret != ASN1_SUCCESS) {
232 1 : gnutls_assert();
233 1 : ret = _gnutls_asn2err(ret);
234 1 : goto cleanup;
235 : }
236 :
237 0 : ret =
238 0 : _gnutls_x509_read_string(c2, "secretValue", out,
239 : ASN1_ETYPE_OCTET_STRING, 1);
240 0 : if (ret < 0) {
241 0 : gnutls_assert();
242 0 : goto cleanup;
243 : }
244 : break;
245 :
246 0 : default:
247 0 : gnutls_assert();
248 0 : asn1_delete_structure(&c2);
249 0 : return GNUTLS_E_UNIMPLEMENTED_FEATURE;
250 : }
251 :
252 358 : asn1_delete_structure(&c2);
253 :
254 358 : return 0;
255 :
256 :
257 4 : cleanup:
258 :
259 4 : asn1_delete_structure(&c2);
260 4 : return ret;
261 : }
262 :
263 :
264 : int
265 14 : _pkcs12_encode_crt_bag(gnutls_pkcs12_bag_type_t type,
266 : const gnutls_datum_t * raw, gnutls_datum_t * out)
267 : {
268 14 : int ret;
269 14 : ASN1_TYPE c2 = ASN1_TYPE_EMPTY;
270 :
271 14 : switch (type) {
272 13 : case GNUTLS_BAG_CERTIFICATE:
273 13 : if ((ret = asn1_create_element(_gnutls_get_pkix(),
274 : "PKIX1.pkcs-12-CertBag",
275 : &c2)) != ASN1_SUCCESS) {
276 0 : gnutls_assert();
277 0 : ret = _gnutls_asn2err(ret);
278 0 : goto cleanup;
279 : }
280 :
281 13 : ret = asn1_write_value(c2, "certId", X509_CERT_OID, 1);
282 13 : if (ret != ASN1_SUCCESS) {
283 0 : gnutls_assert();
284 0 : ret = _gnutls_asn2err(ret);
285 0 : goto cleanup;
286 : }
287 :
288 13 : ret =
289 13 : _gnutls_x509_write_string(c2, "certValue", raw,
290 : ASN1_ETYPE_OCTET_STRING);
291 13 : if (ret < 0) {
292 0 : gnutls_assert();
293 0 : goto cleanup;
294 : }
295 : break;
296 :
297 1 : case GNUTLS_BAG_CRL:
298 1 : if ((ret = asn1_create_element(_gnutls_get_pkix(),
299 : "PKIX1.pkcs-12-CRLBag",
300 : &c2)) != ASN1_SUCCESS) {
301 0 : gnutls_assert();
302 0 : ret = _gnutls_asn2err(ret);
303 0 : goto cleanup;
304 : }
305 :
306 1 : ret = asn1_write_value(c2, "crlId", X509_CRL_OID, 1);
307 1 : if (ret != ASN1_SUCCESS) {
308 0 : gnutls_assert();
309 0 : ret = _gnutls_asn2err(ret);
310 0 : goto cleanup;
311 : }
312 :
313 1 : ret =
314 1 : _gnutls_x509_write_string(c2, "crlValue", raw,
315 : ASN1_ETYPE_OCTET_STRING);
316 1 : if (ret < 0) {
317 0 : gnutls_assert();
318 0 : goto cleanup;
319 : }
320 : break;
321 :
322 0 : case GNUTLS_BAG_SECRET:
323 0 : if ((ret = asn1_create_element(_gnutls_get_pkix(),
324 : "PKIX1.pkcs-12-SecretBag",
325 : &c2)) != ASN1_SUCCESS) {
326 0 : gnutls_assert();
327 0 : ret = _gnutls_asn2err(ret);
328 0 : goto cleanup;
329 : }
330 :
331 0 : ret =
332 0 : asn1_write_value(c2, "secretTypeId", RANDOM_NONCE_OID,
333 : 1);
334 0 : if (ret != ASN1_SUCCESS) {
335 0 : gnutls_assert();
336 0 : ret = _gnutls_asn2err(ret);
337 0 : goto cleanup;
338 : }
339 :
340 0 : ret =
341 0 : _gnutls_x509_write_string(c2, "secretValue", raw,
342 : ASN1_ETYPE_OCTET_STRING);
343 0 : if (ret < 0) {
344 0 : gnutls_assert();
345 0 : goto cleanup;
346 : }
347 : break;
348 :
349 0 : default:
350 0 : gnutls_assert();
351 0 : asn1_delete_structure(&c2);
352 0 : return GNUTLS_E_UNIMPLEMENTED_FEATURE;
353 : }
354 :
355 14 : ret = _gnutls_x509_der_encode(c2, "", out, 0);
356 :
357 14 : if (ret < 0) {
358 0 : gnutls_assert();
359 0 : goto cleanup;
360 : }
361 :
362 14 : asn1_delete_structure(&c2);
363 :
364 14 : return 0;
365 :
366 :
367 0 : cleanup:
368 :
369 0 : asn1_delete_structure(&c2);
370 0 : return ret;
371 : }
372 :
373 :
374 : /**
375 : * gnutls_pkcs12_bag_set_data:
376 : * @bag: The bag
377 : * @type: The data's type
378 : * @data: the data to be copied.
379 : *
380 : * This function will insert the given data of the given type into
381 : * the bag.
382 : *
383 : * Returns: the index of the added bag on success, or a negative
384 : * value on error.
385 : **/
386 : int
387 20 : gnutls_pkcs12_bag_set_data(gnutls_pkcs12_bag_t bag,
388 : gnutls_pkcs12_bag_type_t type,
389 : const gnutls_datum_t * data)
390 : {
391 20 : int ret;
392 20 : if (bag == NULL) {
393 0 : gnutls_assert();
394 0 : return GNUTLS_E_INVALID_REQUEST;
395 : }
396 :
397 20 : if (bag->bag_elements == MAX_BAG_ELEMENTS - 1) {
398 0 : gnutls_assert();
399 : /* bag is full */
400 0 : return GNUTLS_E_MEMORY_ERROR;
401 : }
402 :
403 20 : if (bag->bag_elements == 1) {
404 : /* A bag with a key or an encrypted bag, must have
405 : * only one element.
406 : */
407 :
408 0 : if (bag->element[0].type == GNUTLS_BAG_PKCS8_KEY ||
409 : bag->element[0].type == GNUTLS_BAG_PKCS8_ENCRYPTED_KEY
410 0 : || bag->element[0].type == GNUTLS_BAG_ENCRYPTED) {
411 0 : gnutls_assert();
412 0 : return GNUTLS_E_INVALID_REQUEST;
413 : }
414 : }
415 :
416 20 : ret =
417 40 : _gnutls_set_datum(&bag->element[bag->bag_elements].data,
418 20 : data->data, data->size);
419 :
420 20 : if (ret < 0) {
421 0 : gnutls_assert();
422 0 : return ret;
423 : }
424 :
425 20 : bag->element[bag->bag_elements].type = type;
426 :
427 20 : bag->bag_elements++;
428 :
429 20 : return bag->bag_elements - 1;
430 : }
431 :
432 : /**
433 : * gnutls_pkcs12_bag_set_crt:
434 : * @bag: The bag
435 : * @crt: the certificate to be copied.
436 : *
437 : * This function will insert the given certificate into the
438 : * bag. This is just a wrapper over gnutls_pkcs12_bag_set_data().
439 : *
440 : * Returns: the index of the added bag on success, or a negative
441 : * value on failure.
442 : **/
443 : int
444 13 : gnutls_pkcs12_bag_set_crt(gnutls_pkcs12_bag_t bag, gnutls_x509_crt_t crt)
445 : {
446 13 : int ret;
447 13 : gnutls_datum_t data;
448 :
449 13 : if (bag == NULL) {
450 0 : gnutls_assert();
451 0 : return GNUTLS_E_INVALID_REQUEST;
452 : }
453 :
454 13 : ret = _gnutls_x509_der_encode(crt->cert, "", &data, 0);
455 13 : if (ret < 0) {
456 0 : gnutls_assert();
457 0 : return ret;
458 : }
459 :
460 13 : ret =
461 13 : gnutls_pkcs12_bag_set_data(bag, GNUTLS_BAG_CERTIFICATE, &data);
462 :
463 13 : _gnutls_free_datum(&data);
464 :
465 13 : return ret;
466 : }
467 :
468 : /**
469 : * gnutls_pkcs12_bag_set_crl:
470 : * @bag: The bag
471 : * @crl: the CRL to be copied.
472 : *
473 : * This function will insert the given CRL into the
474 : * bag. This is just a wrapper over gnutls_pkcs12_bag_set_data().
475 : *
476 : * Returns: the index of the added bag on success, or a negative error code
477 : * on failure.
478 : **/
479 : int
480 1 : gnutls_pkcs12_bag_set_crl(gnutls_pkcs12_bag_t bag, gnutls_x509_crl_t crl)
481 : {
482 1 : int ret;
483 1 : gnutls_datum_t data;
484 :
485 :
486 1 : if (bag == NULL) {
487 0 : gnutls_assert();
488 0 : return GNUTLS_E_INVALID_REQUEST;
489 : }
490 :
491 1 : ret = _gnutls_x509_der_encode(crl->crl, "", &data, 0);
492 1 : if (ret < 0) {
493 0 : gnutls_assert();
494 0 : return ret;
495 : }
496 :
497 1 : ret = gnutls_pkcs12_bag_set_data(bag, GNUTLS_BAG_CRL, &data);
498 :
499 1 : _gnutls_free_datum(&data);
500 :
501 1 : return ret;
502 : }
503 :
504 : /**
505 : * gnutls_pkcs12_bag_set_key_id:
506 : * @bag: The bag
507 : * @indx: The bag's element to add the id
508 : * @id: the ID
509 : *
510 : * This function will add the given key ID, to the specified, by the
511 : * index, bag element. The key ID will be encoded as a 'Local key
512 : * identifier' bag attribute, which is usually used to distinguish
513 : * the local private key and the certificate pair.
514 : *
515 : * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
516 : * negative error value. or a negative error code on error.
517 : **/
518 : int
519 14 : gnutls_pkcs12_bag_set_key_id(gnutls_pkcs12_bag_t bag, unsigned indx,
520 : const gnutls_datum_t * id)
521 : {
522 14 : int ret;
523 :
524 :
525 14 : if (bag == NULL) {
526 0 : gnutls_assert();
527 0 : return GNUTLS_E_INVALID_REQUEST;
528 : }
529 :
530 14 : if (indx > bag->bag_elements - 1) {
531 0 : gnutls_assert();
532 0 : return GNUTLS_E_INVALID_REQUEST;
533 : }
534 :
535 28 : ret = _gnutls_set_datum(&bag->element[indx].local_key_id,
536 14 : id->data, id->size);
537 :
538 14 : if (ret < 0) {
539 0 : gnutls_assert();
540 0 : return ret;
541 : }
542 :
543 : return 0;
544 : }
545 :
546 : /**
547 : * gnutls_pkcs12_bag_get_key_id:
548 : * @bag: The bag
549 : * @indx: The bag's element to add the id
550 : * @id: where the ID will be copied (to be treated as const)
551 : *
552 : * This function will return the key ID, of the specified bag element.
553 : * The key ID is usually used to distinguish the local private key and
554 : * the certificate pair.
555 : *
556 : * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
557 : * negative error value. or a negative error code on error.
558 : **/
559 : int
560 61 : gnutls_pkcs12_bag_get_key_id(gnutls_pkcs12_bag_t bag, unsigned indx,
561 : gnutls_datum_t * id)
562 : {
563 61 : if (bag == NULL) {
564 0 : gnutls_assert();
565 0 : return GNUTLS_E_INVALID_REQUEST;
566 : }
567 :
568 61 : if (indx > bag->bag_elements - 1) {
569 0 : gnutls_assert();
570 0 : return GNUTLS_E_INVALID_REQUEST;
571 : }
572 :
573 61 : id->data = bag->element[indx].local_key_id.data;
574 61 : id->size = bag->element[indx].local_key_id.size;
575 :
576 61 : return 0;
577 : }
578 :
579 : /**
580 : * gnutls_pkcs12_bag_get_friendly_name:
581 : * @bag: The bag
582 : * @indx: The bag's element to add the id
583 : * @name: will hold a pointer to the name (to be treated as const)
584 : *
585 : * This function will return the friendly name, of the specified bag
586 : * element. The key ID is usually used to distinguish the local
587 : * private key and the certificate pair.
588 : *
589 : * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
590 : * negative error value. or a negative error code on error.
591 : **/
592 : int
593 61 : gnutls_pkcs12_bag_get_friendly_name(gnutls_pkcs12_bag_t bag, unsigned indx,
594 : char **name)
595 : {
596 61 : if (bag == NULL) {
597 0 : gnutls_assert();
598 0 : return GNUTLS_E_INVALID_REQUEST;
599 : }
600 :
601 61 : if (indx > bag->bag_elements - 1) {
602 0 : gnutls_assert();
603 0 : return GNUTLS_E_INVALID_REQUEST;
604 : }
605 :
606 61 : *name = bag->element[indx].friendly_name;
607 :
608 61 : return 0;
609 : }
610 :
611 :
612 : /**
613 : * gnutls_pkcs12_bag_set_friendly_name:
614 : * @bag: The bag
615 : * @indx: The bag's element to add the id
616 : * @name: the name
617 : *
618 : * This function will add the given key friendly name, to the
619 : * specified, by the index, bag element. The name will be encoded as
620 : * a 'Friendly name' bag attribute, which is usually used to set a
621 : * user name to the local private key and the certificate pair.
622 : *
623 : * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
624 : * negative error value. or a negative error code on error.
625 : **/
626 : int
627 14 : gnutls_pkcs12_bag_set_friendly_name(gnutls_pkcs12_bag_t bag, unsigned indx,
628 : const char *name)
629 : {
630 14 : if (bag == NULL) {
631 0 : gnutls_assert();
632 0 : return GNUTLS_E_INVALID_REQUEST;
633 : }
634 :
635 14 : if (indx > bag->bag_elements - 1) {
636 0 : gnutls_assert();
637 0 : return GNUTLS_E_INVALID_REQUEST;
638 : }
639 :
640 14 : bag->element[indx].friendly_name = gnutls_strdup(name);
641 :
642 14 : if (name == NULL) {
643 0 : gnutls_assert();
644 0 : return GNUTLS_E_MEMORY_ERROR;
645 : }
646 :
647 : return 0;
648 : }
649 :
650 :
651 : /**
652 : * gnutls_pkcs12_bag_decrypt:
653 : * @bag: The bag
654 : * @pass: The password used for encryption, must be ASCII.
655 : *
656 : * This function will decrypt the given encrypted bag and return 0 on
657 : * success.
658 : *
659 : * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned,
660 : * otherwise a negative error code is returned.
661 : **/
662 420 : int gnutls_pkcs12_bag_decrypt(gnutls_pkcs12_bag_t bag, const char *pass)
663 : {
664 420 : int ret;
665 420 : gnutls_datum_t dec;
666 :
667 420 : if (bag == NULL) {
668 0 : gnutls_assert();
669 0 : return GNUTLS_E_INVALID_REQUEST;
670 : }
671 :
672 420 : if (bag->element[0].type != GNUTLS_BAG_ENCRYPTED) {
673 0 : gnutls_assert();
674 0 : return GNUTLS_E_INVALID_REQUEST;
675 : }
676 :
677 420 : ret =
678 420 : _gnutls_pkcs7_decrypt_data(&bag->element[0].data, pass, &dec);
679 :
680 420 : if (ret < 0) {
681 22 : gnutls_assert();
682 22 : return ret;
683 : }
684 :
685 : /* decryption succeeded. Now decode the SafeContents
686 : * stuff, and parse it.
687 : */
688 :
689 398 : _gnutls_free_datum(&bag->element[0].data);
690 :
691 398 : ret = _pkcs12_decode_safe_contents(&dec, bag);
692 :
693 398 : _gnutls_free_datum(&dec);
694 :
695 398 : if (ret < 0) {
696 5 : gnutls_assert();
697 5 : return ret;
698 : }
699 :
700 : return 0;
701 : }
702 :
703 : /**
704 : * gnutls_pkcs12_bag_encrypt:
705 : * @bag: The bag
706 : * @pass: The password used for encryption, must be ASCII
707 : * @flags: should be one of #gnutls_pkcs_encrypt_flags_t elements bitwise or'd
708 : *
709 : * This function will encrypt the given bag.
710 : *
711 : * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned,
712 : * otherwise a negative error code is returned.
713 : **/
714 : int
715 14 : gnutls_pkcs12_bag_encrypt(gnutls_pkcs12_bag_t bag, const char *pass,
716 : unsigned int flags)
717 : {
718 14 : int ret;
719 14 : ASN1_TYPE safe_cont = ASN1_TYPE_EMPTY;
720 14 : gnutls_datum_t der = { NULL, 0 };
721 14 : gnutls_datum_t enc = { NULL, 0 };
722 14 : schema_id id;
723 :
724 14 : if (bag == NULL) {
725 0 : gnutls_assert();
726 0 : return GNUTLS_E_INVALID_REQUEST;
727 : }
728 :
729 14 : if (bag->element[0].type == GNUTLS_BAG_ENCRYPTED) {
730 0 : gnutls_assert();
731 0 : return GNUTLS_E_INVALID_REQUEST;
732 : }
733 :
734 : /* Encode the whole bag to a safe contents
735 : * structure.
736 : */
737 14 : ret = _pkcs12_encode_safe_contents(bag, &safe_cont, NULL);
738 14 : if (ret < 0) {
739 0 : gnutls_assert();
740 0 : return ret;
741 : }
742 :
743 : /* DER encode the SafeContents.
744 : */
745 14 : ret = _gnutls_x509_der_encode(safe_cont, "", &der, 0);
746 :
747 14 : asn1_delete_structure(&safe_cont);
748 :
749 14 : if (ret < 0) {
750 0 : gnutls_assert();
751 0 : return ret;
752 : }
753 :
754 14 : if (flags & GNUTLS_PKCS_PLAIN) {
755 0 : gnutls_assert();
756 0 : return GNUTLS_E_INVALID_REQUEST;
757 : }
758 :
759 14 : id = _gnutls_pkcs_flags_to_schema(flags);
760 :
761 : /* Now encrypt them.
762 : */
763 14 : ret = _gnutls_pkcs7_encrypt_data(id, &der, pass, &enc);
764 :
765 14 : _gnutls_free_datum(&der);
766 :
767 14 : if (ret < 0) {
768 0 : gnutls_assert();
769 0 : return ret;
770 : }
771 :
772 : /* encryption succeeded.
773 : */
774 :
775 14 : _pkcs12_bag_free_data(bag);
776 :
777 14 : bag->element[0].type = GNUTLS_BAG_ENCRYPTED;
778 14 : bag->element[0].data = enc;
779 :
780 14 : bag->bag_elements = 1;
781 :
782 :
783 14 : return 0;
784 : }
785 :
786 : /**
787 : * gnutls_pkcs12_bag_enc_info:
788 : * @bag: The bag
789 : * @schema: indicate the schema as one of %gnutls_pkcs_encrypt_flags_t
790 : * @cipher: the cipher used as %gnutls_cipher_algorithm_t
791 : * @salt: PBKDF2 salt (if non-NULL then @salt_size initially holds its size)
792 : * @salt_size: PBKDF2 salt size
793 : * @iter_count: PBKDF2 iteration count
794 : * @oid: if non-NULL it will contain an allocated null-terminated variable with the OID
795 : *
796 : * This function will provide information on the encryption algorithms used
797 : * in an encrypted bag. If the structure algorithms
798 : * are unknown the code %GNUTLS_E_UNKNOWN_CIPHER_TYPE will be returned,
799 : * and only @oid, will be set. That is, @oid will be set on encrypted bags
800 : * whether supported or not. It must be deinitialized using gnutls_free().
801 : * The other variables are only set on supported structures.
802 : *
803 : * Returns: %GNUTLS_E_INVALID_REQUEST if the provided bag isn't encrypted,
804 : * %GNUTLS_E_UNKNOWN_CIPHER_TYPE if the structure's encryption isn't supported, or
805 : * another negative error code in case of a failure. Zero on success.
806 : **/
807 : int
808 32 : gnutls_pkcs12_bag_enc_info(gnutls_pkcs12_bag_t bag, unsigned int *schema, unsigned int *cipher,
809 : void *salt, unsigned int *salt_size, unsigned int *iter_count, char **oid)
810 : {
811 32 : int ret;
812 32 : struct pbkdf2_params kdf;
813 32 : const struct pkcs_cipher_schema_st *p;
814 :
815 32 : if (bag == NULL) {
816 0 : gnutls_assert();
817 0 : return GNUTLS_E_INVALID_REQUEST;
818 : }
819 :
820 32 : if (bag->element[0].type != GNUTLS_BAG_ENCRYPTED) {
821 0 : gnutls_assert();
822 0 : return GNUTLS_E_INVALID_REQUEST;
823 : }
824 :
825 32 : ret =
826 32 : _gnutls_pkcs7_data_enc_info(&bag->element[0].data, &p, &kdf, oid);
827 :
828 32 : if (ret < 0) {
829 4 : gnutls_assert();
830 4 : return ret;
831 : }
832 :
833 28 : if (schema)
834 28 : *schema = p->flag;
835 :
836 28 : if (cipher)
837 28 : *cipher = p->cipher;
838 :
839 28 : if (iter_count)
840 28 : *iter_count = kdf.iter_count;
841 :
842 28 : if (salt) {
843 28 : if (*salt_size >= (unsigned)kdf.salt_size) {
844 28 : memcpy(salt, kdf.salt, kdf.salt_size);
845 : } else {
846 0 : *salt_size = kdf.salt_size;
847 0 : return gnutls_assert_val(GNUTLS_E_SHORT_MEMORY_BUFFER);
848 : }
849 : }
850 :
851 28 : if (salt_size)
852 28 : *salt_size = kdf.salt_size;
853 :
854 :
855 : return 0;
856 : }
857 :
858 : /**
859 : * gnutls_pkcs12_bag_set_privkey:
860 : * @bag: The bag
861 : * @privkey: the private key to be copied.
862 : * @password: the password to protect the key with (may be %NULL)
863 : * @flags: should be one of #gnutls_pkcs_encrypt_flags_t elements bitwise or'd
864 : *
865 : * This function will insert the given private key into the
866 : * bag. This is just a wrapper over gnutls_pkcs12_bag_set_data().
867 : *
868 : * Returns: the index of the added bag on success, or a negative
869 : * value on failure.
870 : **/
871 : int
872 0 : gnutls_pkcs12_bag_set_privkey(gnutls_pkcs12_bag_t bag, gnutls_x509_privkey_t privkey,
873 : const char *password, unsigned flags)
874 : {
875 0 : int ret;
876 0 : gnutls_datum_t data = {NULL, 0};
877 :
878 0 : if (bag == NULL) {
879 0 : gnutls_assert();
880 0 : return GNUTLS_E_INVALID_REQUEST;
881 : }
882 :
883 0 : ret = gnutls_x509_privkey_export2_pkcs8(privkey, GNUTLS_X509_FMT_DER,
884 : password, flags, &data);
885 0 : if (ret < 0)
886 0 : return gnutls_assert_val(ret);
887 :
888 0 : if (password == NULL) {
889 0 : ret = gnutls_pkcs12_bag_set_data(bag, GNUTLS_BAG_PKCS8_KEY, &data);
890 0 : if (ret < 0) {
891 0 : gnutls_assert();
892 0 : goto cleanup;
893 : }
894 : } else {
895 0 : ret = gnutls_pkcs12_bag_set_data(bag, GNUTLS_BAG_PKCS8_ENCRYPTED_KEY, &data);
896 0 : if (ret < 0) {
897 0 : gnutls_assert();
898 0 : goto cleanup;
899 : }
900 : }
901 :
902 0 : cleanup:
903 0 : _gnutls_free_datum(&data);
904 :
905 0 : return ret;
906 : }
|