]> git.ipfire.org Git - thirdparty/gnutls.git/commitdiff
Added the new PKCS7 parsing functions.
authorNikos Mavrogiannopoulos <nmav@gnutls.org>
Fri, 7 Feb 2003 13:33:10 +0000 (13:33 +0000)
committerNikos Mavrogiannopoulos <nmav@gnutls.org>
Fri, 7 Feb 2003 13:33:10 +0000 (13:33 +0000)
includes/gnutls/x509.h
lib/Makefile.am
lib/gnutls_x509.h
lib/x509/Makefile.am
lib/x509/common.h
lib/x509/crl.c
lib/x509/pkcs7.c [new file with mode: 0644]
lib/x509/pkcs7.h [new file with mode: 0644]
lib/x509/x509.c

index 39f35c81434d8fafdbcc5756ab53a9df17bff7fc..aa728d0dcf26de6fd1b5845448934fde4006909c 100644 (file)
@@ -34,15 +34,15 @@ extern "C" {
 
 /* Some OIDs usually found in Distinguished names
  */
-#define X520_COUNTRY_NAME              "2 5 4 6"
-#define X520_ORGANIZATION_NAME                 "2 5 4 10"
-#define X520_ORGANIZATIONAL_UNIT_NAME  "2 5 4 11"
-#define X520_COMMON_NAME               "2 5 4 3"
-#define X520_LOCALITY_NAME             "2 5 4 7"
-#define X520_STATE_OR_PROVINCE_NAME    "2 5 4 8"
-#define LDAP_DC                                "0 9 2342 19200300 100 1 25"
-#define LDAP_UID                       "0 9 2342 19200300 100 1 1"
-#define PKCS9_EMAIL                    "1 2 840 113549 1 9 1"
+#define GNUTLS_OID_X520_COUNTRY_NAME           "2 5 4 6"
+#define GNUTLS_OID_X520_ORGANIZATION_NAME      "2 5 4 10"
+#define GNUTLS_OID_X520_ORGANIZATIONAL_UNIT_NAME "2 5 4 11"
+#define GNUTLS_OID_X520_COMMON_NAME            "2 5 4 3"
+#define GNUTLS_OID_X520_LOCALITY_NAME          "2 5 4 7"
+#define GNUTLS_OID_X520_STATE_OR_PROVINCE_NAME         "2 5 4 8"
+#define GNUTLS_OID_LDAP_DC                     "0 9 2342 19200300 100 1 25"
+#define GNUTLS_OID_LDAP_UID                    "0 9 2342 19200300 100 1 1"
+#define GNUTLS_OID_PKCS9_EMAIL                         "1 2 840 113549 1 9 1"
 
 /* Certificate handling functions */
                       
@@ -110,6 +110,22 @@ int gnutls_x509_crl_get_certificate_count(gnutls_x509_crl crl);
 int gnutls_x509_crl_get_certificate(gnutls_x509_crl crl, int index, unsigned char* serial,
         int* serial_size, time_t* time);
 
+
+/* PKCS7 structures handling 
+ */
+
+struct gnutls_pkcs7_int;
+typedef struct gnutls_pkcs7_int* gnutls_pkcs7;
+
+int gnutls_pkcs7_init(gnutls_pkcs7 * pkcs7);
+void gnutls_pkcs7_deinit(gnutls_pkcs7 pkcs7);
+int gnutls_pkcs7_import(gnutls_pkcs7 pkcs7, const gnutls_datum * data,
+       gnutls_x509_certificate_format format);
+int gnutls_pkcs7_get_certificate(gnutls_pkcs7 pkcs7, 
+       int indx, char* certificate, int* certificate_size);
+int gnutls_pkcs7_extract_certificate_count(gnutls_pkcs7 pkcs7);
+
+
 #ifdef __cplusplus
 }
 #endif
index 7be6afbbf81bed1e06b7b50d2fc6b19c14ab11b4..92b38490351de6bd7fab92c2d33d5517567edfde 100644 (file)
@@ -47,7 +47,7 @@ COBJECTS = gnutls_record.c gnutls_compress.c debug.c \
 libgnutls_la_SOURCES = $(COBJECTS) 
 
 libgnutls_la_LIBADD = $(MINITASN1_OBJECTS) x509/dn.lo x509/crl.lo x509/common.lo \
-       x509/x509.lo
+       x509/x509.lo x509/pkcs7.lo x509/extensions.lo
 
 libgnutls_la_LDFLAGS = $(LIBASN1_LINK) $(LIBGCRYPT_LIBS) \
        -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) \
index 6f15892ef5ecc8e84ea5298cc740099c0b41288e..dde7427f205504d71cc51f284438074c6ef5212d 100644 (file)
@@ -10,6 +10,8 @@ typedef enum ConvFlags {
 
 int _gnutls_x509_cert2gnutls_cert(gnutls_cert * gCert, gnutls_datum derCert, ConvFlags flags);
 
+#define PEM_CERT_SEP2 "-----BEGIN X509 CERTIFICATE"
+#define PEM_CERT_SEP "-----BEGIN CERTIFICATE"
 #define PEM_PKCS7_SEP "-----BEGIN PKCS7"
 
 #define PEM_KEY_RSA_SEP "-----BEGIN RSA"
index 13e700c9dd07f3db7a90c1b056bffd3b99ba0f52..7590361274a573801014ba1f23bb4c4367ddbe42 100644 (file)
@@ -1,8 +1,10 @@
 INCLUDES = -I../ -I../minitasn1/
-EXTRA_DIST = crl.h dn.h common.h x509.h extensions.h
+EXTRA_DIST = crl.h dn.h common.h x509.h extensions.h pkcs7.h
 
 noinst_LTLIBRARIES = libx509.la
 
-libx509_la_SOURCES = crl.c dn.c common.c x509.c extensions.c
+libx509_la_SOURCES = crl.c dn.c common.c x509.c extensions.c \
+       pkcs7.c
+
 
 
index 56cc4910f37dc0095c63798e7e28e63658b1ce73..368677f0cb0ddb56e6a0acf04647fe902a4895c7 100644 (file)
@@ -2,8 +2,10 @@
 #define MAX_INT_DIGITS 4
 void _gnutls_int2str(unsigned int k, char *data);
 
-#define PEM_CERT_SEP2 "-----BEGIN X509 CERTIFICATE"
-#define PEM_CERT_SEP "-----BEGIN CERTIFICATE"
+#define PEM_CRL "X509 CRL"
+#define PEM_X509_CERT "X509 CERTIFICATE"
+#define PEM_X509_CERT2 "CERTIFICATE"
+#define PEM_PKCS7 "PKCS7"
 
 time_t _gnutls_x509_utcTime2gtime(char *ttime);
 time_t _gnutls_x509_generalTime2gtime(char *ttime);
index b4475ab45051e52798177df62ae781da3cc8e4ac..597b4102e1355ab6c9401aeb648c9105c35236d8 100644 (file)
@@ -91,7 +91,7 @@ int gnutls_x509_crl_import(gnutls_x509_crl crl, const gnutls_datum * data,
        if (format == GNUTLS_X509_FMT_PEM) {
                opaque *out;
                
-               result = _gnutls_fbase64_decode("X509 CRL", data->data, data->size,
+               result = _gnutls_fbase64_decode(PEM_CRL, data->data, data->size,
                        &out);
 
                if (result <= 0) {
@@ -193,7 +193,8 @@ int gnutls_x509_crl_import(gnutls_x509_crl crl, const gnutls_datum * data,
        return 0;
 
       cleanup:
-       asn1_delete_structure(&crl->crl);
+       if (crl->crl)
+               asn1_delete_structure(&crl->crl);
        _gnutls_free_datum(&crl->signed_data);
        _gnutls_free_datum(&crl->signature);
        if (need_free) _gnutls_free_datum( &_data);
diff --git a/lib/x509/pkcs7.c b/lib/x509/pkcs7.c
new file mode 100644 (file)
index 0000000..df84ca8
--- /dev/null
@@ -0,0 +1,383 @@
+/*
+ *  Copyright (C) 2003 Nikos Mavroyanopoulos
+ *
+ *  This file is part of GNUTLS.
+ *
+ *  The GNUTLS library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public   
+ *  License as published by the Free Software Foundation; either 
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
+ *
+ */
+
+#include <libtasn1.h>
+#include <gnutls_int.h>
+#include <gnutls_datum.h>
+#include <gnutls_global.h>
+#include <gnutls_errors.h>
+#include <common.h>
+#include <x509_b64.h>
+#include <pkcs7.h>
+#include <dn.h>
+
+/**
+  * gnutls_pkcs7_init - This function initializes a gnutls_pkcs7 structure
+  * @pkcs7: The structure to be initialized
+  *
+  * This function will initialize a PKCS7 structure. PKCS7 stands for
+  * Certificate Revocation List.
+  *
+  * Returns 0 on success.
+  *
+  **/
+int gnutls_pkcs7_init(gnutls_pkcs7 * pkcs7)
+{
+       *pkcs7 = gnutls_calloc( 1, sizeof(gnutls_pkcs7_int));
+
+       if (*pkcs7) return 0;           /* success */
+       return GNUTLS_E_MEMORY_ERROR;
+}
+
+/**
+  * gnutls_pkcs7_deinit - This function deinitializes memory used by a gnutls_pkcs7 structure
+  * @pkcs7: The structure to be initialized
+  *
+  * This function will deinitialize a PKCS7 structure. 
+  *
+  **/
+void gnutls_pkcs7_deinit(gnutls_pkcs7 pkcs7)
+{
+       if (pkcs7->pkcs7)
+               asn1_delete_structure(&pkcs7->pkcs7);
+
+       gnutls_free(pkcs7);
+}
+
+/**
+  * gnutls_pkcs7_import - This function will import a DER or PEM encoded PKCS7
+  * @pkcs7: The structure to store the parsed PKCS7.
+  * @data: The DER or PEM encoded PKCS7.
+  * @format: One of DER or PEM
+  *
+  * This function will convert the given DER or PEM encoded PKCS7
+  * to the native gnutls_pkcs7 format. The output will be stored in 'pkcs7'.
+  *
+  * If the PKCS7 is PEM encoded it should have a header of "X509 PKCS7", and
+  * it must be a null terminated string.
+  *
+  * Returns 0 on success.
+  *
+  **/
+int gnutls_pkcs7_import(gnutls_pkcs7 pkcs7, const gnutls_datum * data,
+       gnutls_x509_certificate_format format)
+{
+       int result = 0, need_free = 0;
+       gnutls_datum _data = { data->data, data->size };
+
+       /* If the PKCS7 is in PEM format then decode it
+        */
+       if (format == GNUTLS_X509_FMT_PEM) {
+               opaque *out;
+               
+               result = _gnutls_fbase64_decode(PEM_PKCS7, data->data, data->size,
+                       &out);
+
+               if (result <= 0) {
+                       if (result==0) result = GNUTLS_E_INTERNAL_ERROR;
+                       gnutls_assert();
+                       return result;
+               }
+               
+               _data.data = out;
+               _data.size = result;
+               
+               need_free = 1;
+       }
+
+       pkcs7->pkcs7 = ASN1_TYPE_EMPTY;
+
+       result = asn1_create_element(_gnutls_get_pkix(),
+                                    "PKIX1.ContentInfo",
+                                    &pkcs7->pkcs7, "pkcs7");
+       if (result != ASN1_SUCCESS) {
+               gnutls_assert();
+               return _gnutls_asn2err(result);
+       }
+
+       result = asn1_der_decoding(&pkcs7->pkcs7, _data.data, _data.size, NULL);
+       if (result != ASN1_SUCCESS) {
+               result = _gnutls_asn2err(result);
+               gnutls_assert();
+               goto cleanup;
+       }
+
+       if (need_free) _gnutls_free_datum( &_data);
+
+       return 0;
+
+      cleanup:
+       if (pkcs7->pkcs7)
+               asn1_delete_structure(&pkcs7->pkcs7);
+       if (need_free) _gnutls_free_datum( &_data);
+       return result;
+}
+
+
+/**
+  * gnutls_pkcs7_get_certificate - This function returns a certificate in a PKCS7 certificate set
+  * @pkcs7_struct: should contain a gnutls_pkcs7 structure
+  * @indx: contains the index of the certificate to extract
+  * @certificate: the contents of the certificate will be copied there (may be null)
+  * @certificate_size: should hold the size of the certificate
+  *
+  * This function will return a certificate of the PKCS7 or RFC2630 certificate set.
+  * Returns 0 on success. If the provided buffer is not long enough,
+  * then GNUTLS_E_SHORT_MEMORY_BUFFER is returned.
+  *
+  * After the last certificate has been read GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE
+  * will be returned.
+  *
+  **/
+int gnutls_pkcs7_get_certificate(gnutls_pkcs7 pkcs7, 
+       int indx, char* certificate, int* certificate_size)
+{
+       ASN1_TYPE c2 = NULL;
+       int result, len;
+       char oid[128];
+       opaque *tmp = NULL;
+       char root2[64];
+       char counter[MAX_INT_DIGITS];
+       int tmp_size;
+
+       if (certificate_size == NULL) return GNUTLS_E_INVALID_REQUEST;
+
+       /* root2 is used as a temp storage area
+        */
+       len = sizeof(oid) - 1;
+       result = asn1_read_value(pkcs7->pkcs7, "pkcs7.contentType", oid, &len);
+       if (result != ASN1_SUCCESS) {
+               gnutls_assert();
+               return _gnutls_asn2err(result);
+       }
+
+       if ( strcmp( oid, "1 2 840 113549 1 7 2") != 0) {
+               gnutls_assert();
+               return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
+       }                                                               
+
+       tmp_size = 256; /* some initial size */
+       tmp = gnutls_malloc(tmp_size);
+       if (tmp==NULL) {
+               gnutls_assert();
+               return GNUTLS_E_MEMORY_ERROR;
+       }
+
+       result = asn1_read_value(pkcs7->pkcs7, "pkcs7.content", tmp, &tmp_size);
+       /* FIXME: a hard coded value
+        */
+       if (result==ASN1_MEM_ERROR && tmp_size > 0 && tmp_size < 50*1024) {
+               tmp = gnutls_realloc_fast( tmp, tmp_size);
+               if (tmp==NULL) {
+                       gnutls_assert();
+                       return GNUTLS_E_MEMORY_ERROR;
+               }
+               result = asn1_read_value(pkcs7->pkcs7, "pkcs7.content", tmp, &tmp_size);
+       } 
+       
+       if (result != ASN1_SUCCESS) {
+               gnutls_assert();
+               result = _gnutls_asn2err(result);
+               goto cleanup;
+       }
+
+       /* tmp, tmp_size hold the data and the size of the CertificateSet structure
+        * actually the ANY stuff.
+        */
+
+       /* Step 1. In case of a signed structure extract certificate set.
+        */
+       if ((result=_gnutls_asn1_create_element
+           (_gnutls_get_pkix(), "PKIX1.SignedData", &c2, "c2")) != ASN1_SUCCESS) {
+               gnutls_assert();
+               result = _gnutls_asn2err(result);
+               goto cleanup;   }
+
+       result = asn1_der_decoding(&c2, tmp, tmp_size, NULL);
+       if (result != ASN1_SUCCESS) {
+               /* couldn't decode DER */
+               gnutls_assert();
+               result = _gnutls_asn2err(result);
+               goto cleanup;   
+       }
+
+       /* Step 2. Parse the CertificateSet 
+        */
+       
+       _gnutls_str_cpy( root2, sizeof(root2), "c2.certificates.?"); 
+       _gnutls_int2str( indx+1, counter);
+       _gnutls_str_cat( root2, sizeof(root2), counter); 
+
+       len = sizeof(oid) - 1;
+
+       result = asn1_read_value(c2, root2, oid, &len);
+
+       if (result == ASN1_VALUE_NOT_FOUND) {
+               result = GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
+               goto cleanup;   
+       }
+       
+       if (result != ASN1_SUCCESS) {
+               gnutls_assert();
+               result = _gnutls_asn2err(result);
+               goto cleanup;   
+       }
+
+       /* if 'Certificate' is the choice found: 
+        */
+       if (strcmp( oid, "certificate") == 0) {
+               int start, end;
+
+               result = asn1_der_decoding_startEnd(c2, tmp, tmp_size, 
+                       root2, &start, &end);
+
+               if (result != ASN1_SUCCESS) {
+                       gnutls_assert();
+                       result = _gnutls_asn2err(result);
+                       goto cleanup;
+               }
+                       
+               end = end-start+1;
+               
+               if (certificate!=NULL && end <= *certificate_size)
+                       memcpy( certificate, &tmp[start], end);
+               else {
+                       *certificate_size = end;
+                       result = GNUTLS_E_SHORT_MEMORY_BUFFER;
+                       goto cleanup;
+               }
+
+               *certificate_size = end;
+
+               result = 0;
+
+       } else {
+               result = GNUTLS_E_UNSUPPORTED_CERTIFICATE_TYPE;
+       }
+
+       cleanup:
+               if (c2) asn1_delete_structure(&c2);
+               gnutls_free(tmp);
+               return result;
+}
+
+
+/**
+  * gnutls_pkcs7_get_certificate_count - This function returns the number of certificates in a PKCS7 certificate set
+  * @pkcs7_struct: should contain a gnutls_pkcs7 structure
+  *
+  * This function will return the number of certifcates in the PKCS7 or 
+  * RFC2630 certificate set.
+  *
+  * Returns a negative value on failure.
+  *
+  **/
+int gnutls_pkcs7_get_certificate_count(gnutls_pkcs7 pkcs7)
+{
+       ASN1_TYPE c2;
+       int result, len, count;
+       char oid[64];
+       opaque *tmp = NULL;
+       int tmp_size;
+
+       len = sizeof(oid) - 1;
+
+       /* root2 is used as a temp storage area
+        */
+       result = asn1_read_value(pkcs7->pkcs7, "pkcs7.contentType", oid, &len);
+       if (result != ASN1_SUCCESS) {
+               gnutls_assert();
+               return _gnutls_asn2err(result);
+       }
+
+       if ( strcmp( oid, "1 2 840 113549 1 7 2") != 0) {
+               gnutls_assert();
+               return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
+       }                                                               
+
+       tmp_size = 256; /* some initial size */
+       tmp = gnutls_malloc(tmp_size);
+       if (tmp==NULL) {
+               gnutls_assert();
+               return GNUTLS_E_MEMORY_ERROR;
+       }
+
+       result = asn1_read_value(pkcs7->pkcs7, "pkcs7.content", tmp, &tmp_size);
+       /* FIXME: a hard coded value
+        */
+       if (result==ASN1_MEM_ERROR && tmp_size > 0 && tmp_size < 50*1024) {
+               tmp = gnutls_realloc_fast( tmp, tmp_size);
+               if (tmp==NULL) {
+                       gnutls_assert();
+                       return GNUTLS_E_MEMORY_ERROR;
+               }
+               result = asn1_read_value(pkcs7->pkcs7, "pkcs7.content", tmp, &tmp_size);
+       } 
+
+       if (result != ASN1_SUCCESS) {
+               gnutls_assert();
+               result = _gnutls_asn2err(result);
+               goto cleanup;
+       }
+
+       /* tmp, tmp_size hold the data and the size of the CertificateSet structure
+        * actually the ANY stuff.
+        */
+
+       /* Step 1. In case of a signed structure count the certificate set.
+        */
+       if ((result=_gnutls_asn1_create_element
+           (_gnutls_get_pkix(), "PKIX1.SignedData", &c2, "c2")) != ASN1_SUCCESS) {
+               gnutls_assert();
+               result = _gnutls_asn2err(result);
+               goto cleanup;
+       }
+
+       result = asn1_der_decoding(&c2, tmp, tmp_size, NULL);
+       if (result != ASN1_SUCCESS) {
+               /* couldn't decode DER */
+       
+               gnutls_assert();
+               asn1_delete_structure(&c2);
+               result = _gnutls_asn2err(result);
+               goto cleanup;
+       }
+               
+       gnutls_free(tmp);
+
+       /* Step 2. Count the CertificateSet */
+       
+       result = asn1_number_of_elements( c2, "c2.certificates", &count);
+
+       asn1_delete_structure(&c2);
+       
+       if (result != ASN1_SUCCESS) {
+               gnutls_assert();
+               return 0; /* no certificates */
+       }
+
+       return count;
+       
+       cleanup:
+               gnutls_free(tmp);
+               return result;
+}
+
diff --git a/lib/x509/pkcs7.h b/lib/x509/pkcs7.h
new file mode 100644 (file)
index 0000000..68979de
--- /dev/null
@@ -0,0 +1,6 @@
+
+typedef struct gnutls_pkcs7_int {
+       ASN1_TYPE pkcs7;
+} gnutls_pkcs7_int;
+
+typedef struct gnutls_pkcs7_int *gnutls_pkcs7;
index ee7d5e239060bd1f9777604d572f000c80669e62..498fa8c1699f6ffb6eb73e1b8dc2831c4fb020a8 100644 (file)
@@ -93,12 +93,12 @@ int gnutls_x509_certificate_import(gnutls_x509_certificate cert, const gnutls_da
                opaque *out;
                
                /* Try the first header */
-               result = _gnutls_fbase64_decode(PEM_CERT_SEP, data->data, data->size,
+               result = _gnutls_fbase64_decode(PEM_X509_CERT, data->data, data->size,
                        &out);
 
                if (result <= 0) {
                        /* try for the second header */
-                       result = _gnutls_fbase64_decode(PEM_CERT_SEP2, data->data, data->size,
+                       result = _gnutls_fbase64_decode(PEM_X509_CERT2, data->data, data->size,
                                &out);
                        
                        if (result <= 0) {
@@ -201,7 +201,8 @@ int gnutls_x509_certificate_import(gnutls_x509_certificate cert, const gnutls_da
        return 0;
 
       cleanup:
-       asn1_delete_structure(&cert->cert);
+       if (cert->cert)
+               asn1_delete_structure(&cert->cert);
        _gnutls_free_datum(&cert->signed_data);
        _gnutls_free_datum(&cert->signature);
        if (need_free) _gnutls_free_datum( &_data);