2 * Copyright (C) 2003-2012 Free Software Foundation, Inc.
4 * Author: Nikos Mavrogiannopoulos
6 * This file is part of GnuTLS.
8 * The GnuTLS is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public License
10 * as published by the Free Software Foundation; either version 3 of
11 * the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>
23 /* Functions that relate on PKCS7 certificate lists parsing.
26 #include <gnutls_int.h>
29 #include <gnutls_datum.h>
30 #include <gnutls_global.h>
31 #include <gnutls_errors.h>
35 #define SIGNED_DATA_OID "1.2.840.113549.1.7.2"
37 /* Decodes the PKCS #7 signed data, and returns an ASN1_TYPE,
38 * which holds them. If raw is non null then the raw decoded
39 * data are copied (they are locally allocated) there.
42 _decode_pkcs7_signed_data (ASN1_TYPE pkcs7
, ASN1_TYPE
* sdata
,
45 char oid
[MAX_OID_SIZE
];
48 int tmp_size
, len
, result
;
50 len
= sizeof (oid
) - 1;
51 result
= asn1_read_value (pkcs7
, "contentType", oid
, &len
);
52 if (result
!= ASN1_SUCCESS
)
55 return _gnutls_asn2err (result
);
58 if (strcmp (oid
, SIGNED_DATA_OID
) != 0)
61 _gnutls_debug_log ("Unknown PKCS7 Content OID '%s'\n", oid
);
62 return GNUTLS_E_UNKNOWN_PKCS_CONTENT_TYPE
;
65 if ((result
= asn1_create_element
66 (_gnutls_get_pkix (), "PKIX1.pkcs-7-SignedData", &c2
)) != ASN1_SUCCESS
)
69 return _gnutls_asn2err (result
);
72 /* the Signed-data has been created, so
76 result
= asn1_read_value (pkcs7
, "content", NULL
, &tmp_size
);
77 if (result
!= ASN1_MEM_ERROR
)
80 result
= _gnutls_asn2err (result
);
84 tmp
= gnutls_malloc (tmp_size
);
88 result
= GNUTLS_E_MEMORY_ERROR
;
92 result
= asn1_read_value (pkcs7
, "content", tmp
, &tmp_size
);
93 if (result
!= ASN1_SUCCESS
)
96 result
= _gnutls_asn2err (result
);
100 /* tmp, tmp_size hold the data and the size of the CertificateSet structure
101 * actually the ANY stuff.
104 /* Step 1. In case of a signed structure extract certificate set.
107 result
= asn1_der_decoding (&c2
, tmp
, tmp_size
, NULL
);
108 if (result
!= ASN1_SUCCESS
)
111 result
= _gnutls_asn2err (result
);
122 raw
->size
= tmp_size
;
131 asn1_delete_structure (&c2
);
138 * @pkcs7: The structure to be initialized
140 * This function will initialize a PKCS7 structure. PKCS7 structures
141 * usually contain lists of X.509 Certificates and X.509 Certificate
144 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
145 * negative error value.
148 gnutls_pkcs7_init (gnutls_pkcs7_t
* pkcs7
)
150 *pkcs7
= gnutls_calloc (1, sizeof (gnutls_pkcs7_int
));
154 int result
= asn1_create_element (_gnutls_get_pkix (),
155 "PKIX1.pkcs-7-ContentInfo",
157 if (result
!= ASN1_SUCCESS
)
160 gnutls_free (*pkcs7
);
161 return _gnutls_asn2err (result
);
163 return 0; /* success */
165 return GNUTLS_E_MEMORY_ERROR
;
169 * gnutls_pkcs7_deinit:
170 * @pkcs7: The structure to be initialized
172 * This function will deinitialize a PKCS7 structure.
175 gnutls_pkcs7_deinit (gnutls_pkcs7_t pkcs7
)
181 asn1_delete_structure (&pkcs7
->pkcs7
);
187 * gnutls_pkcs7_import:
188 * @pkcs7: The structure to store the parsed PKCS7.
189 * @data: The DER or PEM encoded PKCS7.
190 * @format: One of DER or PEM
192 * This function will convert the given DER or PEM encoded PKCS7 to
193 * the native #gnutls_pkcs7_t format. The output will be stored in
196 * If the PKCS7 is PEM encoded it should have a header of "PKCS7".
198 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
199 * negative error value.
202 gnutls_pkcs7_import (gnutls_pkcs7_t pkcs7
, const gnutls_datum_t
* data
,
203 gnutls_x509_crt_fmt_t format
)
205 int result
= 0, need_free
= 0;
206 gnutls_datum_t _data
;
209 return GNUTLS_E_INVALID_REQUEST
;
211 _data
.data
= data
->data
;
212 _data
.size
= data
->size
;
214 /* If the PKCS7 is in PEM format then decode it
216 if (format
== GNUTLS_X509_FMT_PEM
)
220 result
= _gnutls_fbase64_decode (PEM_PKCS7
, data
->data
, data
->size
,
226 result
= GNUTLS_E_INTERNAL_ERROR
;
238 result
= asn1_der_decoding (&pkcs7
->pkcs7
, _data
.data
, _data
.size
, NULL
);
239 if (result
!= ASN1_SUCCESS
)
241 result
= _gnutls_asn2err (result
);
247 _gnutls_free_datum (&_data
);
253 _gnutls_free_datum (&_data
);
258 * gnutls_pkcs7_get_crt_raw:
259 * @pkcs7: should contain a gnutls_pkcs7_t structure
260 * @indx: contains the index of the certificate to extract
261 * @certificate: the contents of the certificate will be copied
262 * there (may be null)
263 * @certificate_size: should hold the size of the certificate
265 * This function will return a certificate of the PKCS7 or RFC2630
268 * After the last certificate has been read
269 * %GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE will be returned.
271 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
272 * negative error value. If the provided buffer is not long enough,
273 * then @certificate_size is updated and
274 * %GNUTLS_E_SHORT_MEMORY_BUFFER is returned.
277 gnutls_pkcs7_get_crt_raw (gnutls_pkcs7_t pkcs7
,
278 int indx
, void *certificate
,
279 size_t * certificate_size
)
281 ASN1_TYPE c2
= ASN1_TYPE_EMPTY
;
283 char root2
[ASN1_MAX_NAME_SIZE
];
284 char oid
[MAX_OID_SIZE
];
285 gnutls_datum_t tmp
= { NULL
, 0 };
287 if (certificate_size
== NULL
|| pkcs7
== NULL
)
288 return GNUTLS_E_INVALID_REQUEST
;
290 /* Step 1. decode the signed data.
292 result
= _decode_pkcs7_signed_data (pkcs7
->pkcs7
, &c2
, &tmp
);
299 /* Step 2. Parse the CertificateSet
302 snprintf (root2
, sizeof (root2
), "certificates.?%u", indx
+ 1);
304 len
= sizeof (oid
) - 1;
306 result
= asn1_read_value (c2
, root2
, oid
, &len
);
308 if (result
== ASN1_VALUE_NOT_FOUND
)
310 result
= GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE
;
314 if (result
!= ASN1_SUCCESS
)
317 result
= _gnutls_asn2err (result
);
321 /* if 'Certificate' is the choice found:
323 if (strcmp (oid
, "certificate") == 0)
327 result
= asn1_der_decoding_startEnd (c2
, tmp
.data
, tmp
.size
,
328 root2
, &start
, &end
);
330 if (result
!= ASN1_SUCCESS
)
333 result
= _gnutls_asn2err (result
);
337 end
= end
- start
+ 1;
339 if ((unsigned) end
> *certificate_size
)
341 *certificate_size
= end
;
342 result
= GNUTLS_E_SHORT_MEMORY_BUFFER
;
347 memcpy (certificate
, &tmp
.data
[start
], end
);
349 *certificate_size
= end
;
356 result
= GNUTLS_E_UNSUPPORTED_CERTIFICATE_TYPE
;
360 _gnutls_free_datum (&tmp
);
362 asn1_delete_structure (&c2
);
367 * gnutls_pkcs7_get_crt_count:
368 * @pkcs7: should contain a #gnutls_pkcs7_t structure
370 * This function will return the number of certifcates in the PKCS7
371 * or RFC2630 certificate set.
373 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
374 * negative error value.
377 gnutls_pkcs7_get_crt_count (gnutls_pkcs7_t pkcs7
)
379 ASN1_TYPE c2
= ASN1_TYPE_EMPTY
;
383 return GNUTLS_E_INVALID_REQUEST
;
385 /* Step 1. decode the signed data.
387 result
= _decode_pkcs7_signed_data (pkcs7
->pkcs7
, &c2
, NULL
);
394 /* Step 2. Count the CertificateSet */
396 result
= asn1_number_of_elements (c2
, "certificates", &count
);
398 asn1_delete_structure (&c2
);
400 if (result
!= ASN1_SUCCESS
)
403 return 0; /* no certificates */
411 * gnutls_pkcs7_export:
412 * @pkcs7: Holds the pkcs7 structure
413 * @format: the format of output params. One of PEM or DER.
414 * @output_data: will contain a structure PEM or DER encoded
415 * @output_data_size: holds the size of output_data (and will be
416 * replaced by the actual size of parameters)
418 * This function will export the pkcs7 structure to DER or PEM format.
420 * If the buffer provided is not long enough to hold the output, then
421 * *@output_data_size is updated and %GNUTLS_E_SHORT_MEMORY_BUFFER
424 * If the structure is PEM encoded, it will have a header
427 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
428 * negative error value.
431 gnutls_pkcs7_export (gnutls_pkcs7_t pkcs7
,
432 gnutls_x509_crt_fmt_t format
, void *output_data
,
433 size_t * output_data_size
)
436 return GNUTLS_E_INVALID_REQUEST
;
438 return _gnutls_x509_export_int (pkcs7
->pkcs7
, format
, PEM_PKCS7
,
439 output_data
, output_data_size
);
442 /* Creates an empty signed data structure in the pkcs7
443 * structure and returns a handle to the signed data.
446 create_empty_signed_data (ASN1_TYPE pkcs7
, ASN1_TYPE
* sdata
)
451 *sdata
= ASN1_TYPE_EMPTY
;
453 if ((result
= asn1_create_element
454 (_gnutls_get_pkix (), "PKIX1.pkcs-7-SignedData",
455 sdata
)) != ASN1_SUCCESS
)
458 result
= _gnutls_asn2err (result
);
464 result
= asn1_write_value (*sdata
, "version", &one
, 1);
465 if (result
!= ASN1_SUCCESS
)
468 result
= _gnutls_asn2err (result
);
472 /* Use no digest algorithms
477 asn1_write_value (*sdata
, "encapContentInfo.eContentType",
478 "1.2.840.113549.1.7.5", 1);
479 if (result
!= ASN1_SUCCESS
)
482 result
= _gnutls_asn2err (result
);
486 result
= asn1_write_value (*sdata
, "encapContentInfo.eContent", NULL
, 0);
487 if (result
!= ASN1_SUCCESS
)
490 result
= _gnutls_asn2err (result
);
494 /* Add no certificates.
500 /* Add no signerInfos.
503 /* Write the content type of the signed data
505 result
= asn1_write_value (pkcs7
, "contentType", SIGNED_DATA_OID
, 1);
506 if (result
!= ASN1_SUCCESS
)
509 result
= _gnutls_asn2err (result
);
516 asn1_delete_structure (sdata
);
522 * gnutls_pkcs7_set_crt_raw:
523 * @pkcs7: should contain a #gnutls_pkcs7_t structure
524 * @crt: the DER encoded certificate to be added
526 * This function will add a certificate to the PKCS7 or RFC2630
529 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
530 * negative error value.
533 gnutls_pkcs7_set_crt_raw (gnutls_pkcs7_t pkcs7
, const gnutls_datum_t
* crt
)
535 ASN1_TYPE c2
= ASN1_TYPE_EMPTY
;
539 return GNUTLS_E_INVALID_REQUEST
;
541 /* Step 1. decode the signed data.
543 result
= _decode_pkcs7_signed_data (pkcs7
->pkcs7
, &c2
, NULL
);
544 if (result
< 0 && result
!= GNUTLS_E_ASN1_VALUE_NOT_FOUND
)
550 /* If the signed data are uninitialized
553 if (result
== GNUTLS_E_ASN1_VALUE_NOT_FOUND
)
555 /* The pkcs7 structure is new, so create the
558 result
= create_empty_signed_data (pkcs7
->pkcs7
, &c2
);
566 /* Step 2. Append the new certificate.
569 result
= asn1_write_value (c2
, "certificates", "NEW", 1);
570 if (result
!= ASN1_SUCCESS
)
573 result
= _gnutls_asn2err (result
);
577 result
= asn1_write_value (c2
, "certificates.?LAST", "certificate", 1);
578 if (result
!= ASN1_SUCCESS
)
581 result
= _gnutls_asn2err (result
);
586 asn1_write_value (c2
, "certificates.?LAST.certificate", crt
->data
,
588 if (result
!= ASN1_SUCCESS
)
591 result
= _gnutls_asn2err (result
);
595 /* Step 3. Replace the old content with the new
598 _gnutls_x509_der_encode_and_copy (c2
, "", pkcs7
->pkcs7
, "content", 0);
605 asn1_delete_structure (&c2
);
611 asn1_delete_structure (&c2
);
616 * gnutls_pkcs7_set_crt:
617 * @pkcs7: should contain a #gnutls_pkcs7_t structure
618 * @crt: the certificate to be copied.
620 * This function will add a parsed certificate to the PKCS7 or
621 * RFC2630 certificate set. This is a wrapper function over
622 * gnutls_pkcs7_set_crt_raw() .
624 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
625 * negative error value.
628 gnutls_pkcs7_set_crt (gnutls_pkcs7_t pkcs7
, gnutls_x509_crt_t crt
)
634 return GNUTLS_E_INVALID_REQUEST
;
636 ret
= _gnutls_x509_der_encode (crt
->cert
, "", &data
, 0);
643 ret
= gnutls_pkcs7_set_crt_raw (pkcs7
, &data
);
645 _gnutls_free_datum (&data
);
658 * gnutls_pkcs7_delete_crt:
659 * @pkcs7: should contain a gnutls_pkcs7_t structure
660 * @indx: the index of the certificate to delete
662 * This function will delete a certificate from a PKCS7 or RFC2630
663 * certificate set. Index starts from 0. Returns 0 on success.
665 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
666 * negative error value.
669 gnutls_pkcs7_delete_crt (gnutls_pkcs7_t pkcs7
, int indx
)
671 ASN1_TYPE c2
= ASN1_TYPE_EMPTY
;
673 char root2
[ASN1_MAX_NAME_SIZE
];
676 return GNUTLS_E_INVALID_REQUEST
;
678 /* Step 1. Decode the signed data.
680 result
= _decode_pkcs7_signed_data (pkcs7
->pkcs7
, &c2
, NULL
);
687 /* Step 2. Delete the certificate.
690 snprintf (root2
, sizeof (root2
), "certificates.?%u", indx
+ 1);
692 result
= asn1_write_value (c2
, root2
, NULL
, 0);
693 if (result
!= ASN1_SUCCESS
)
696 result
= _gnutls_asn2err (result
);
700 /* Step 3. Replace the old content with the new
703 _gnutls_x509_der_encode_and_copy (c2
, "", pkcs7
->pkcs7
, "content", 0);
710 asn1_delete_structure (&c2
);
716 asn1_delete_structure (&c2
);
720 /* Read and write CRLs
724 * gnutls_pkcs7_get_crl_raw:
725 * @pkcs7: should contain a #gnutls_pkcs7_t structure
726 * @indx: contains the index of the crl to extract
727 * @crl: the contents of the crl will be copied there (may be null)
728 * @crl_size: should hold the size of the crl
730 * This function will return a crl of the PKCS7 or RFC2630 crl set.
732 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
733 * negative error value. If the provided buffer is not long enough,
734 * then @crl_size is updated and %GNUTLS_E_SHORT_MEMORY_BUFFER is
735 * returned. After the last crl has been read
736 * %GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE will be returned.
739 gnutls_pkcs7_get_crl_raw (gnutls_pkcs7_t pkcs7
,
740 int indx
, void *crl
, size_t * crl_size
)
742 ASN1_TYPE c2
= ASN1_TYPE_EMPTY
;
744 char root2
[ASN1_MAX_NAME_SIZE
];
745 gnutls_datum_t tmp
= { NULL
, 0 };
748 if (pkcs7
== NULL
|| crl_size
== NULL
)
749 return GNUTLS_E_INVALID_REQUEST
;
751 /* Step 1. decode the signed data.
753 result
= _decode_pkcs7_signed_data (pkcs7
->pkcs7
, &c2
, &tmp
);
760 /* Step 2. Parse the CertificateSet
763 snprintf (root2
, sizeof (root2
), "crls.?%u", indx
+ 1);
767 result
= asn1_der_decoding_startEnd (c2
, tmp
.data
, tmp
.size
,
768 root2
, &start
, &end
);
770 if (result
!= ASN1_SUCCESS
)
773 result
= _gnutls_asn2err (result
);
777 end
= end
- start
+ 1;
779 if ((unsigned) end
> *crl_size
)
782 result
= GNUTLS_E_SHORT_MEMORY_BUFFER
;
787 memcpy (crl
, &tmp
.data
[start
], end
);
794 _gnutls_free_datum (&tmp
);
796 asn1_delete_structure (&c2
);
801 * gnutls_pkcs7_get_crl_count:
802 * @pkcs7: should contain a gnutls_pkcs7_t structure
804 * This function will return the number of certifcates in the PKCS7
805 * or RFC2630 crl set.
807 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
808 * negative error value.
811 gnutls_pkcs7_get_crl_count (gnutls_pkcs7_t pkcs7
)
813 ASN1_TYPE c2
= ASN1_TYPE_EMPTY
;
817 return GNUTLS_E_INVALID_REQUEST
;
819 /* Step 1. decode the signed data.
821 result
= _decode_pkcs7_signed_data (pkcs7
->pkcs7
, &c2
, NULL
);
828 /* Step 2. Count the CertificateSet */
830 result
= asn1_number_of_elements (c2
, "crls", &count
);
832 asn1_delete_structure (&c2
);
834 if (result
!= ASN1_SUCCESS
)
837 return 0; /* no crls */
845 * gnutls_pkcs7_set_crl_raw:
846 * @pkcs7: should contain a #gnutls_pkcs7_t structure
847 * @crl: the DER encoded crl to be added
849 * This function will add a crl to the PKCS7 or RFC2630 crl set.
851 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
852 * negative error value.
855 gnutls_pkcs7_set_crl_raw (gnutls_pkcs7_t pkcs7
, const gnutls_datum_t
* crl
)
857 ASN1_TYPE c2
= ASN1_TYPE_EMPTY
;
861 return GNUTLS_E_INVALID_REQUEST
;
863 /* Step 1. decode the signed data.
865 result
= _decode_pkcs7_signed_data (pkcs7
->pkcs7
, &c2
, NULL
);
866 if (result
< 0 && result
!= GNUTLS_E_ASN1_VALUE_NOT_FOUND
)
872 /* If the signed data are uninitialized
875 if (result
== GNUTLS_E_ASN1_VALUE_NOT_FOUND
)
877 /* The pkcs7 structure is new, so create the
880 result
= create_empty_signed_data (pkcs7
->pkcs7
, &c2
);
888 /* Step 2. Append the new crl.
891 result
= asn1_write_value (c2
, "crls", "NEW", 1);
892 if (result
!= ASN1_SUCCESS
)
895 result
= _gnutls_asn2err (result
);
899 result
= asn1_write_value (c2
, "crls.?LAST", crl
->data
, crl
->size
);
900 if (result
!= ASN1_SUCCESS
)
903 result
= _gnutls_asn2err (result
);
907 /* Step 3. Replace the old content with the new
910 _gnutls_x509_der_encode_and_copy (c2
, "", pkcs7
->pkcs7
, "content", 0);
917 asn1_delete_structure (&c2
);
923 asn1_delete_structure (&c2
);
928 * gnutls_pkcs7_set_crl:
929 * @pkcs7: should contain a #gnutls_pkcs7_t structure
930 * @crl: the DER encoded crl to be added
932 * This function will add a parsed CRL to the PKCS7 or RFC2630 crl
935 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
936 * negative error value.
939 gnutls_pkcs7_set_crl (gnutls_pkcs7_t pkcs7
, gnutls_x509_crl_t crl
)
945 return GNUTLS_E_INVALID_REQUEST
;
947 ret
= _gnutls_x509_der_encode (crl
->crl
, "", &data
, 0);
954 ret
= gnutls_pkcs7_set_crl_raw (pkcs7
, &data
);
956 _gnutls_free_datum (&data
);
968 * gnutls_pkcs7_delete_crl:
969 * @pkcs7: should contain a #gnutls_pkcs7_t structure
970 * @indx: the index of the crl to delete
972 * This function will delete a crl from a PKCS7 or RFC2630 crl set.
973 * Index starts from 0. Returns 0 on success.
975 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
976 * negative error value.
979 gnutls_pkcs7_delete_crl (gnutls_pkcs7_t pkcs7
, int indx
)
981 ASN1_TYPE c2
= ASN1_TYPE_EMPTY
;
983 char root2
[ASN1_MAX_NAME_SIZE
];
986 return GNUTLS_E_INVALID_REQUEST
;
988 /* Step 1. Decode the signed data.
990 result
= _decode_pkcs7_signed_data (pkcs7
->pkcs7
, &c2
, NULL
);
997 /* Step 2. Delete the crl.
1000 snprintf (root2
, sizeof (root2
), "crls.?%u", indx
+ 1);
1002 result
= asn1_write_value (c2
, root2
, NULL
, 0);
1003 if (result
!= ASN1_SUCCESS
)
1006 result
= _gnutls_asn2err (result
);
1010 /* Step 3. Replace the old content with the new
1013 _gnutls_x509_der_encode_and_copy (c2
, "", pkcs7
->pkcs7
, "content", 0);
1020 asn1_delete_structure (&c2
);
1026 asn1_delete_structure (&c2
);