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
)
218 result
= _gnutls_fbase64_decode (PEM_PKCS7
, data
->data
, data
->size
,
231 result
= asn1_der_decoding (&pkcs7
->pkcs7
, _data
.data
, _data
.size
, NULL
);
232 if (result
!= ASN1_SUCCESS
)
234 result
= _gnutls_asn2err (result
);
240 _gnutls_free_datum (&_data
);
246 _gnutls_free_datum (&_data
);
251 * gnutls_pkcs7_get_crt_raw:
252 * @pkcs7: should contain a gnutls_pkcs7_t structure
253 * @indx: contains the index of the certificate to extract
254 * @certificate: the contents of the certificate will be copied
255 * there (may be null)
256 * @certificate_size: should hold the size of the certificate
258 * This function will return a certificate of the PKCS7 or RFC2630
261 * After the last certificate has been read
262 * %GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE will be returned.
264 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
265 * negative error value. If the provided buffer is not long enough,
266 * then @certificate_size is updated and
267 * %GNUTLS_E_SHORT_MEMORY_BUFFER is returned.
270 gnutls_pkcs7_get_crt_raw (gnutls_pkcs7_t pkcs7
,
271 int indx
, void *certificate
,
272 size_t * certificate_size
)
274 ASN1_TYPE c2
= ASN1_TYPE_EMPTY
;
276 char root2
[ASN1_MAX_NAME_SIZE
];
277 char oid
[MAX_OID_SIZE
];
278 gnutls_datum_t tmp
= { NULL
, 0 };
280 if (certificate_size
== NULL
|| pkcs7
== NULL
)
281 return GNUTLS_E_INVALID_REQUEST
;
283 /* Step 1. decode the signed data.
285 result
= _decode_pkcs7_signed_data (pkcs7
->pkcs7
, &c2
, &tmp
);
292 /* Step 2. Parse the CertificateSet
295 snprintf (root2
, sizeof (root2
), "certificates.?%u", indx
+ 1);
297 len
= sizeof (oid
) - 1;
299 result
= asn1_read_value (c2
, root2
, oid
, &len
);
301 if (result
== ASN1_VALUE_NOT_FOUND
)
303 result
= GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE
;
307 if (result
!= ASN1_SUCCESS
)
310 result
= _gnutls_asn2err (result
);
314 /* if 'Certificate' is the choice found:
316 if (strcmp (oid
, "certificate") == 0)
320 result
= asn1_der_decoding_startEnd (c2
, tmp
.data
, tmp
.size
,
321 root2
, &start
, &end
);
323 if (result
!= ASN1_SUCCESS
)
326 result
= _gnutls_asn2err (result
);
330 end
= end
- start
+ 1;
332 if ((unsigned) end
> *certificate_size
)
334 *certificate_size
= end
;
335 result
= GNUTLS_E_SHORT_MEMORY_BUFFER
;
340 memcpy (certificate
, &tmp
.data
[start
], end
);
342 *certificate_size
= end
;
349 result
= GNUTLS_E_UNSUPPORTED_CERTIFICATE_TYPE
;
353 _gnutls_free_datum (&tmp
);
355 asn1_delete_structure (&c2
);
360 * gnutls_pkcs7_get_crt_count:
361 * @pkcs7: should contain a #gnutls_pkcs7_t structure
363 * This function will return the number of certifcates in the PKCS7
364 * or RFC2630 certificate set.
366 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
367 * negative error value.
370 gnutls_pkcs7_get_crt_count (gnutls_pkcs7_t pkcs7
)
372 ASN1_TYPE c2
= ASN1_TYPE_EMPTY
;
376 return GNUTLS_E_INVALID_REQUEST
;
378 /* Step 1. decode the signed data.
380 result
= _decode_pkcs7_signed_data (pkcs7
->pkcs7
, &c2
, NULL
);
387 /* Step 2. Count the CertificateSet */
389 result
= asn1_number_of_elements (c2
, "certificates", &count
);
391 asn1_delete_structure (&c2
);
393 if (result
!= ASN1_SUCCESS
)
396 return 0; /* no certificates */
404 * gnutls_pkcs7_export:
405 * @pkcs7: Holds the pkcs7 structure
406 * @format: the format of output params. One of PEM or DER.
407 * @output_data: will contain a structure PEM or DER encoded
408 * @output_data_size: holds the size of output_data (and will be
409 * replaced by the actual size of parameters)
411 * This function will export the pkcs7 structure to DER or PEM format.
413 * If the buffer provided is not long enough to hold the output, then
414 * *@output_data_size is updated and %GNUTLS_E_SHORT_MEMORY_BUFFER
417 * If the structure is PEM encoded, it will have a header
420 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
421 * negative error value.
424 gnutls_pkcs7_export (gnutls_pkcs7_t pkcs7
,
425 gnutls_x509_crt_fmt_t format
, void *output_data
,
426 size_t * output_data_size
)
429 return GNUTLS_E_INVALID_REQUEST
;
431 return _gnutls_x509_export_int (pkcs7
->pkcs7
, format
, PEM_PKCS7
,
432 output_data
, output_data_size
);
436 * gnutls_pkcs7_export2:
437 * @pkcs7: Holds the pkcs7 structure
438 * @format: the format of output params. One of PEM or DER.
439 * @out: will contain a structure PEM or DER encoded
441 * This function will export the pkcs7 structure to DER or PEM format.
443 * The output buffer is allocated using gnutls_malloc().
445 * If the structure is PEM encoded, it will have a header
448 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
449 * negative error value.
452 gnutls_pkcs7_export2 (gnutls_pkcs7_t pkcs7
,
453 gnutls_x509_crt_fmt_t format
, gnutls_datum_t
*out
)
456 return GNUTLS_E_INVALID_REQUEST
;
458 return _gnutls_x509_export_int2 (pkcs7
->pkcs7
, format
, PEM_PKCS7
, out
);
461 /* Creates an empty signed data structure in the pkcs7
462 * structure and returns a handle to the signed data.
465 create_empty_signed_data (ASN1_TYPE pkcs7
, ASN1_TYPE
* sdata
)
470 *sdata
= ASN1_TYPE_EMPTY
;
472 if ((result
= asn1_create_element
473 (_gnutls_get_pkix (), "PKIX1.pkcs-7-SignedData",
474 sdata
)) != ASN1_SUCCESS
)
477 result
= _gnutls_asn2err (result
);
483 result
= asn1_write_value (*sdata
, "version", &one
, 1);
484 if (result
!= ASN1_SUCCESS
)
487 result
= _gnutls_asn2err (result
);
491 /* Use no digest algorithms
496 asn1_write_value (*sdata
, "encapContentInfo.eContentType",
497 "1.2.840.113549.1.7.5", 1);
498 if (result
!= ASN1_SUCCESS
)
501 result
= _gnutls_asn2err (result
);
505 result
= asn1_write_value (*sdata
, "encapContentInfo.eContent", NULL
, 0);
506 if (result
!= ASN1_SUCCESS
)
509 result
= _gnutls_asn2err (result
);
513 /* Add no certificates.
519 /* Add no signerInfos.
522 /* Write the content type of the signed data
524 result
= asn1_write_value (pkcs7
, "contentType", SIGNED_DATA_OID
, 1);
525 if (result
!= ASN1_SUCCESS
)
528 result
= _gnutls_asn2err (result
);
535 asn1_delete_structure (sdata
);
541 * gnutls_pkcs7_set_crt_raw:
542 * @pkcs7: should contain a #gnutls_pkcs7_t structure
543 * @crt: the DER encoded certificate to be added
545 * This function will add a certificate to the PKCS7 or RFC2630
548 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
549 * negative error value.
552 gnutls_pkcs7_set_crt_raw (gnutls_pkcs7_t pkcs7
, const gnutls_datum_t
* crt
)
554 ASN1_TYPE c2
= ASN1_TYPE_EMPTY
;
558 return GNUTLS_E_INVALID_REQUEST
;
560 /* Step 1. decode the signed data.
562 result
= _decode_pkcs7_signed_data (pkcs7
->pkcs7
, &c2
, NULL
);
563 if (result
< 0 && result
!= GNUTLS_E_ASN1_VALUE_NOT_FOUND
)
569 /* If the signed data are uninitialized
572 if (result
== GNUTLS_E_ASN1_VALUE_NOT_FOUND
)
574 /* The pkcs7 structure is new, so create the
577 result
= create_empty_signed_data (pkcs7
->pkcs7
, &c2
);
585 /* Step 2. Append the new certificate.
588 result
= asn1_write_value (c2
, "certificates", "NEW", 1);
589 if (result
!= ASN1_SUCCESS
)
592 result
= _gnutls_asn2err (result
);
596 result
= asn1_write_value (c2
, "certificates.?LAST", "certificate", 1);
597 if (result
!= ASN1_SUCCESS
)
600 result
= _gnutls_asn2err (result
);
605 asn1_write_value (c2
, "certificates.?LAST.certificate", crt
->data
,
607 if (result
!= ASN1_SUCCESS
)
610 result
= _gnutls_asn2err (result
);
614 /* Step 3. Replace the old content with the new
617 _gnutls_x509_der_encode_and_copy (c2
, "", pkcs7
->pkcs7
, "content", 0);
624 asn1_delete_structure (&c2
);
630 asn1_delete_structure (&c2
);
635 * gnutls_pkcs7_set_crt:
636 * @pkcs7: should contain a #gnutls_pkcs7_t structure
637 * @crt: the certificate to be copied.
639 * This function will add a parsed certificate to the PKCS7 or
640 * RFC2630 certificate set. This is a wrapper function over
641 * gnutls_pkcs7_set_crt_raw() .
643 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
644 * negative error value.
647 gnutls_pkcs7_set_crt (gnutls_pkcs7_t pkcs7
, gnutls_x509_crt_t crt
)
653 return GNUTLS_E_INVALID_REQUEST
;
655 ret
= _gnutls_x509_der_encode (crt
->cert
, "", &data
, 0);
662 ret
= gnutls_pkcs7_set_crt_raw (pkcs7
, &data
);
664 _gnutls_free_datum (&data
);
677 * gnutls_pkcs7_delete_crt:
678 * @pkcs7: should contain a gnutls_pkcs7_t structure
679 * @indx: the index of the certificate to delete
681 * This function will delete a certificate from a PKCS7 or RFC2630
682 * certificate set. Index starts from 0. Returns 0 on success.
684 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
685 * negative error value.
688 gnutls_pkcs7_delete_crt (gnutls_pkcs7_t pkcs7
, int indx
)
690 ASN1_TYPE c2
= ASN1_TYPE_EMPTY
;
692 char root2
[ASN1_MAX_NAME_SIZE
];
695 return GNUTLS_E_INVALID_REQUEST
;
697 /* Step 1. Decode the signed data.
699 result
= _decode_pkcs7_signed_data (pkcs7
->pkcs7
, &c2
, NULL
);
706 /* Step 2. Delete the certificate.
709 snprintf (root2
, sizeof (root2
), "certificates.?%u", indx
+ 1);
711 result
= asn1_write_value (c2
, root2
, NULL
, 0);
712 if (result
!= ASN1_SUCCESS
)
715 result
= _gnutls_asn2err (result
);
719 /* Step 3. Replace the old content with the new
722 _gnutls_x509_der_encode_and_copy (c2
, "", pkcs7
->pkcs7
, "content", 0);
729 asn1_delete_structure (&c2
);
735 asn1_delete_structure (&c2
);
739 /* Read and write CRLs
743 * gnutls_pkcs7_get_crl_raw:
744 * @pkcs7: should contain a #gnutls_pkcs7_t structure
745 * @indx: contains the index of the crl to extract
746 * @crl: the contents of the crl will be copied there (may be null)
747 * @crl_size: should hold the size of the crl
749 * This function will return a crl of the PKCS7 or RFC2630 crl set.
751 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
752 * negative error value. If the provided buffer is not long enough,
753 * then @crl_size is updated and %GNUTLS_E_SHORT_MEMORY_BUFFER is
754 * returned. After the last crl has been read
755 * %GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE will be returned.
758 gnutls_pkcs7_get_crl_raw (gnutls_pkcs7_t pkcs7
,
759 int indx
, void *crl
, size_t * crl_size
)
761 ASN1_TYPE c2
= ASN1_TYPE_EMPTY
;
763 char root2
[ASN1_MAX_NAME_SIZE
];
764 gnutls_datum_t tmp
= { NULL
, 0 };
767 if (pkcs7
== NULL
|| crl_size
== NULL
)
768 return GNUTLS_E_INVALID_REQUEST
;
770 /* Step 1. decode the signed data.
772 result
= _decode_pkcs7_signed_data (pkcs7
->pkcs7
, &c2
, &tmp
);
779 /* Step 2. Parse the CertificateSet
782 snprintf (root2
, sizeof (root2
), "crls.?%u", indx
+ 1);
786 result
= asn1_der_decoding_startEnd (c2
, tmp
.data
, tmp
.size
,
787 root2
, &start
, &end
);
789 if (result
!= ASN1_SUCCESS
)
792 result
= _gnutls_asn2err (result
);
796 end
= end
- start
+ 1;
798 if ((unsigned) end
> *crl_size
)
801 result
= GNUTLS_E_SHORT_MEMORY_BUFFER
;
806 memcpy (crl
, &tmp
.data
[start
], end
);
813 _gnutls_free_datum (&tmp
);
815 asn1_delete_structure (&c2
);
820 * gnutls_pkcs7_get_crl_count:
821 * @pkcs7: should contain a gnutls_pkcs7_t structure
823 * This function will return the number of certifcates in the PKCS7
824 * or RFC2630 crl set.
826 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
827 * negative error value.
830 gnutls_pkcs7_get_crl_count (gnutls_pkcs7_t pkcs7
)
832 ASN1_TYPE c2
= ASN1_TYPE_EMPTY
;
836 return GNUTLS_E_INVALID_REQUEST
;
838 /* Step 1. decode the signed data.
840 result
= _decode_pkcs7_signed_data (pkcs7
->pkcs7
, &c2
, NULL
);
847 /* Step 2. Count the CertificateSet */
849 result
= asn1_number_of_elements (c2
, "crls", &count
);
851 asn1_delete_structure (&c2
);
853 if (result
!= ASN1_SUCCESS
)
856 return 0; /* no crls */
864 * gnutls_pkcs7_set_crl_raw:
865 * @pkcs7: should contain a #gnutls_pkcs7_t structure
866 * @crl: the DER encoded crl to be added
868 * This function will add a crl to the PKCS7 or RFC2630 crl set.
870 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
871 * negative error value.
874 gnutls_pkcs7_set_crl_raw (gnutls_pkcs7_t pkcs7
, const gnutls_datum_t
* crl
)
876 ASN1_TYPE c2
= ASN1_TYPE_EMPTY
;
880 return GNUTLS_E_INVALID_REQUEST
;
882 /* Step 1. decode the signed data.
884 result
= _decode_pkcs7_signed_data (pkcs7
->pkcs7
, &c2
, NULL
);
885 if (result
< 0 && result
!= GNUTLS_E_ASN1_VALUE_NOT_FOUND
)
891 /* If the signed data are uninitialized
894 if (result
== GNUTLS_E_ASN1_VALUE_NOT_FOUND
)
896 /* The pkcs7 structure is new, so create the
899 result
= create_empty_signed_data (pkcs7
->pkcs7
, &c2
);
907 /* Step 2. Append the new crl.
910 result
= asn1_write_value (c2
, "crls", "NEW", 1);
911 if (result
!= ASN1_SUCCESS
)
914 result
= _gnutls_asn2err (result
);
918 result
= asn1_write_value (c2
, "crls.?LAST", crl
->data
, crl
->size
);
919 if (result
!= ASN1_SUCCESS
)
922 result
= _gnutls_asn2err (result
);
926 /* Step 3. Replace the old content with the new
929 _gnutls_x509_der_encode_and_copy (c2
, "", pkcs7
->pkcs7
, "content", 0);
936 asn1_delete_structure (&c2
);
942 asn1_delete_structure (&c2
);
947 * gnutls_pkcs7_set_crl:
948 * @pkcs7: should contain a #gnutls_pkcs7_t structure
949 * @crl: the DER encoded crl to be added
951 * This function will add a parsed CRL to the PKCS7 or RFC2630 crl
954 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
955 * negative error value.
958 gnutls_pkcs7_set_crl (gnutls_pkcs7_t pkcs7
, gnutls_x509_crl_t crl
)
964 return GNUTLS_E_INVALID_REQUEST
;
966 ret
= _gnutls_x509_der_encode (crl
->crl
, "", &data
, 0);
973 ret
= gnutls_pkcs7_set_crl_raw (pkcs7
, &data
);
975 _gnutls_free_datum (&data
);
987 * gnutls_pkcs7_delete_crl:
988 * @pkcs7: should contain a #gnutls_pkcs7_t structure
989 * @indx: the index of the crl to delete
991 * This function will delete a crl from a PKCS7 or RFC2630 crl set.
992 * Index starts from 0. Returns 0 on success.
994 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
995 * negative error value.
998 gnutls_pkcs7_delete_crl (gnutls_pkcs7_t pkcs7
, int indx
)
1000 ASN1_TYPE c2
= ASN1_TYPE_EMPTY
;
1002 char root2
[ASN1_MAX_NAME_SIZE
];
1005 return GNUTLS_E_INVALID_REQUEST
;
1007 /* Step 1. Decode the signed data.
1009 result
= _decode_pkcs7_signed_data (pkcs7
->pkcs7
, &c2
, NULL
);
1016 /* Step 2. Delete the crl.
1019 snprintf (root2
, sizeof (root2
), "crls.?%u", indx
+ 1);
1021 result
= asn1_write_value (c2
, root2
, NULL
, 0);
1022 if (result
!= ASN1_SUCCESS
)
1025 result
= _gnutls_asn2err (result
);
1029 /* Step 3. Replace the old content with the new
1032 _gnutls_x509_der_encode_and_copy (c2
, "", pkcs7
->pkcs7
, "content", 0);
1039 asn1_delete_structure (&c2
);
1045 asn1_delete_structure (&c2
);