summaryrefslogtreecommitdiff
path: root/lib/gnutls_x509.c
diff options
context:
space:
mode:
authorNikos Mavrogiannopoulos <nmav@gnutls.org>2002-03-24 18:41:08 +0000
committerNikos Mavrogiannopoulos <nmav@gnutls.org>2002-03-24 18:41:08 +0000
commit2df21200d50373ebf95be5f8f81200863213e9e3 (patch)
treedda71fa6b1c3f014905014f49bccff25de2fd5e3 /lib/gnutls_x509.c
parent3e2db931ea0f9cf1cf1badaec001baeb890a1fa5 (diff)
downloadgnutls-2df21200d50373ebf95be5f8f81200863213e9e3.tar.gz
Added support for RFC2630 - PKCS7 formated structures
Diffstat (limited to 'lib/gnutls_x509.c')
-rw-r--r--lib/gnutls_x509.c425
1 files changed, 328 insertions, 97 deletions
diff --git a/lib/gnutls_x509.c b/lib/gnutls_x509.c
index e6180ff16e..2a6b4e4ca1 100644
--- a/lib/gnutls_x509.c
+++ b/lib/gnutls_x509.c
@@ -48,6 +48,9 @@
* some x509 certificate parsing functions.
*/
+int gnutls_x509_pkcs7_extract_certificate(const gnutls_datum * pkcs7_struct, int indx, char* certificate, int* certificate_size);
+
+
#define _READ(a, aa, b, c, d, e, res, f) \
result = _IREAD(a, aa, sizeof(aa), b, c, d, e, res, sizeof(res)-1, f); \
if (result<0) return result; \
@@ -64,7 +67,7 @@ static int _IREAD(node_asn * rasn, char *name3, int name3_size, char *rstr, char
if (strcmp(rstr, OID) == 0) {
- _gnutls_str_cpy(str, sizeof(str), "PKIX1Implicit88.");
+ _gnutls_str_cpy(str, sizeof(str), "PKIX1.");
_gnutls_str_cat(str, sizeof(str), ANAME);
_gnutls_str_cpy(name2, sizeof(name2), "temp-structure-");
_gnutls_str_cat(name2, sizeof(name2), TYPE);
@@ -333,7 +336,7 @@ int gnutls_x509_extract_dn(const gnutls_datum * idn, gnutls_x509_dn * rdn)
if ((result =
asn1_create_structure(_gnutls_get_pkix(),
- "PKIX1Implicit88.Name", &dn,
+ "PKIX1.Name", &dn,
"dn")) != ASN_OK) {
gnutls_assert();
return result;
@@ -378,9 +381,9 @@ int gnutls_x509_extract_certificate_dn(const gnutls_datum * cert,
memset(ret, 0, sizeof(gnutls_x509_dn));
- if (asn1_create_structure
- (_gnutls_get_pkix(), "PKIX1Implicit88.Certificate", &c2,
- "certificate2")
+ if ((result=asn1_create_structure
+ (_gnutls_get_pkix(), "PKIX1.Certificate", &c2,
+ "certificate2"))
!= ASN_OK) {
gnutls_assert();
return result;
@@ -430,9 +433,9 @@ int gnutls_x509_extract_certificate_issuer_dn(const gnutls_datum * cert,
memset(ret, 0, sizeof(gnutls_x509_dn));
- if (asn1_create_structure
- (_gnutls_get_pkix(), "PKIX1Implicit88.Certificate", &c2,
- "certificate2")
+ if ((result=asn1_create_structure
+ (_gnutls_get_pkix(), "PKIX1.Certificate", &c2,
+ "certificate2"))
!= ASN_OK) {
gnutls_assert();
return result;
@@ -487,7 +490,8 @@ static GNUTLS_X509_SUBJECT_ALT_NAME _find_type( char* str_type) {
* or the type of alternative name if everything was ok. The type is one of the
* enumerated GNUTLS_X509_SUBJECT_ALT_NAME.
*
- * If the certificate does not have a Alternative name then returns GNUTLS_E_DATA_NOT_AVAILABLE;
+ * If the certificate does not have an Alternative name with the specified sequence number
+ * then returns GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
*
**/
int gnutls_x509_extract_subject_alt_name(const gnutls_datum * cert, int seq, char *ret, int *ret_size)
@@ -515,7 +519,7 @@ int gnutls_x509_extract_subject_alt_name(const gnutls_datum * cert, int seq, cha
}
if ((result=asn1_create_structure
- (_gnutls_get_pkix(), "PKIX1Implicit88.SubjectAltName", &c2, "san"))
+ (_gnutls_get_pkix(), "PKIX1.SubjectAltName", &c2, "san"))
!= ASN_OK) {
gnutls_assert();
gnutls_free_datum( &dnsname);
@@ -540,8 +544,15 @@ int gnutls_x509_extract_subject_alt_name(const gnutls_datum * cert, int seq, cha
_gnutls_str_cat( nptr, sizeof(nptr), num);
len = sizeof(ext_data);
- if ((result =
- asn1_read_value(c2, nptr, ext_data, &len)) != ASN_OK) {
+ result =
+ asn1_read_value(c2, nptr, ext_data, &len);
+
+ if (result == ASN_VALUE_NOT_FOUND) {
+ asn1_delete_structure(c2);
+ return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
+ }
+
+ if (result != ASN_OK) {
gnutls_assert();
asn1_delete_structure(c2);
return result;
@@ -588,7 +599,7 @@ time_t gnutls_x509_extract_certificate_activation_time(const
time_t ret;
if (asn1_create_structure
- (_gnutls_get_pkix(), "PKIX1Implicit88.Certificate", &c2,
+ (_gnutls_get_pkix(), "PKIX1.Certificate", &c2,
"certificate2")
!= ASN_OK) {
gnutls_assert();
@@ -630,7 +641,7 @@ time_t gnutls_x509_extract_certificate_expiration_time(const
time_t ret;
if (asn1_create_structure
- (_gnutls_get_pkix(), "PKIX1Implicit88.Certificate", &c2,
+ (_gnutls_get_pkix(), "PKIX1.Certificate", &c2,
"certificate2")
!= ASN_OK) {
gnutls_assert();
@@ -668,7 +679,7 @@ int gnutls_x509_extract_certificate_version(const gnutls_datum * cert)
int result;
if ((result=asn1_create_structure
- (_gnutls_get_pkix(), "PKIX1Implicit88.Certificate", &c2,
+ (_gnutls_get_pkix(), "PKIX1.Certificate", &c2,
"certificate2"))
!= ASN_OK) {
gnutls_assert();
@@ -897,7 +908,7 @@ int gnutls_x509_extract_certificate_serial(const gnutls_datum * cert, char* resu
int ret;
if ((ret=asn1_create_structure
- (_gnutls_get_pkix(), "PKIX1Implicit88.Certificate", &c2,
+ (_gnutls_get_pkix(), "PKIX1.Certificate", &c2,
"certificate2"))
!= ASN_OK) {
gnutls_assert();
@@ -946,37 +957,106 @@ static int _gnutls_check_key_cert_match( GNUTLS_CERTIFICATE_CREDENTIALS res) {
#define MAX_FILE_SIZE 100*1024
#define CERT_SEP "-----BEGIN"
-/* Reads a base64 encoded certificate from memory
+/* Reads a PKCS7 base64 encoded certificate list from memory and stores it to
+ * a gnutls_cert structure.
*/
-static int read_cert_mem(GNUTLS_CERTIFICATE_CREDENTIALS res, const char *cert, int cert_size)
+static int parse_pkcs7_cert_mem( gnutls_cert** cert_list, int* ncerts,
+ const char *input_cert, int input_cert_size)
{
- int siz, i, siz2;
+ int siz, i, j;
opaque *b64;
const char *ptr;
- gnutls_datum tmp;
+ gnutls_datum tmp, tmp2;
int ret;
+ opaque pcert[MAX_X509_CERT_SIZE];
+ int pcert_size;
- /* allocate space for the certificate to add
- */
- res->cert_list = gnutls_realloc( res->cert_list, (1+res->ncerts)*sizeof(gnutls_cert*));
- if (res->cert_list==NULL) {
- gnutls_assert();
- return GNUTLS_E_MEMORY_ERROR;
- }
+ ptr = input_cert;
+ siz = input_cert_size;
+ i = *ncerts + 1;
- res->cert_list_length = gnutls_realloc( res->cert_list_length,
- (1+res->ncerts)*sizeof(int));
- if (res->cert_list_length==NULL) {
+ ret = _gnutls_fbase64_decode(ptr, siz, &b64);
+
+ if (ret < 0) {
gnutls_assert();
- return GNUTLS_E_MEMORY_ERROR;
+ return GNUTLS_E_PARSING_ERROR;
}
+
+ /* tmp now contains the decoded certificate list */
+ tmp.data = b64;
+ tmp.size = ret;
+ j = 0;
+ do {
+ pcert_size = sizeof(pcert);
+ ret = gnutls_x509_pkcs7_extract_certificate( &tmp, j, pcert, &pcert_size);
- ptr = cert;
- siz = cert_size;
- i = 1;
+ /* if the current certificate is too long, just ignore
+ * it. */
+ if (ret==GNUTLS_E_MEMORY_ERROR) continue;
+
+ if (ret >= 0) {
+ *cert_list =
+ (gnutls_cert *) gnutls_realloc( *cert_list,
+ i * sizeof(gnutls_cert));
+
+ if ( *cert_list == NULL) {
+ gnutls_assert();
+ gnutls_free(b64);
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+
+ /* set defaults to zero
+ */
+ memset( &cert_list[0][i - 1], 0, sizeof(gnutls_cert));
+
+ tmp2.data = pcert;
+ tmp2.size = pcert_size;
+
+ if ((ret =
+ _gnutls_x509_cert2gnutls_cert(
+ &cert_list[0][i - 1],
+ tmp2)) < 0) {
+ gnutls_free(b64);
+ gnutls_assert();
+ return ret;
+ }
+
+ i++;
+ }
+ j++;
+
+ } while (ret >= 0);
+
+ gnutls_free(b64);
+
+ *ncerts = i - 1;
+
+ return 0;
+}
+
+
+/* Reads a base64 encoded certificate list from memory and stores it to
+ * a gnutls_cert structure.
+ */
+static int parse_cert_mem( gnutls_cert** cert_list, int* ncerts,
+ const char *input_cert, int input_cert_size)
+{
+ int siz, i, siz2;
+ opaque *b64;
+ const char *ptr;
+ gnutls_datum tmp;
+ int ret;
- res->cert_list[res->ncerts] = NULL;
+ if (strstr( input_cert, "-----BEGIN PKCS7")!=NULL) {
+ return parse_pkcs7_cert_mem( cert_list, ncerts, input_cert,
+ input_cert_size);
+ }
+
+
+ ptr = input_cert;
+ siz = input_cert_size;
+ i = *ncerts + 1;
do {
siz2 = _gnutls_fbase64_decode(ptr, siz, &b64);
@@ -989,28 +1069,27 @@ static int read_cert_mem(GNUTLS_CERTIFICATE_CREDENTIALS res, const char *cert, i
}
- res->cert_list[res->ncerts] =
- (gnutls_cert *) gnutls_realloc(res->
- cert_list[res->ncerts],
+ *cert_list =
+ (gnutls_cert *) gnutls_realloc( *cert_list,
i *
sizeof(gnutls_cert));
- if (res->cert_list[res->ncerts] == NULL) {
+ if ( *cert_list == NULL) {
gnutls_assert();
gnutls_free(b64);
return GNUTLS_E_MEMORY_ERROR;
}
/* set defaults to zero
*/
- memset(&res->cert_list[res->ncerts][i - 1], 0,
+ memset( &cert_list[0][i - 1], 0,
sizeof(gnutls_cert));
tmp.data = b64;
tmp.size = siz2;
if ((ret =
- _gnutls_x509_cert2gnutls_cert(&res->
- cert_list[res->ncerts][i - 1],
+ _gnutls_x509_cert2gnutls_cert(
+ &cert_list[0][i - 1],
tmp)) < 0) {
gnutls_free(b64);
gnutls_assert();
@@ -1026,73 +1105,57 @@ static int read_cert_mem(GNUTLS_CERTIFICATE_CREDENTIALS res, const char *cert, i
i++;
} while ((ptr = strstr(ptr, CERT_SEP)) != NULL);
- res->cert_list_length[res->ncerts] = i - 1;
-
+ *ncerts = i - 1;
return 0;
}
-/* Reads a base64 encoded CA list from memory
- * This is to be called once.
+
+
+/* Reads a base64 encoded certificate from memory
*/
-static int read_ca_mem(GNUTLS_CERTIFICATE_CREDENTIALS res, const char *ca, int ca_size)
+static int read_cert_mem(GNUTLS_CERTIFICATE_CREDENTIALS res, const char *cert, int cert_size)
{
- int siz, siz2, i;
- opaque *b64;
- const char *ptr;
int ret;
- gnutls_datum tmp;
- siz = ca_size;
-
- ptr = ca;
-
- i = res->x509_ncas + 1;
-
- do {
- siz2 = _gnutls_fbase64_decode(ptr, siz, &b64);
- siz -= siz2; /* FIXME: this is not enough
- */
+ /* allocate space for the certificate to add
+ */
+ res->cert_list = gnutls_realloc( res->cert_list, (1+ res->ncerts)*sizeof(gnutls_cert*));
+ if ( res->cert_list==NULL) {
+ gnutls_assert();
+ return GNUTLS_E_MEMORY_ERROR;
+ }
- if (siz2 < 0) {
- gnutls_assert();
- return GNUTLS_E_PARSING_ERROR;
- }
+ res->cert_list_length = gnutls_realloc( res->cert_list_length,
+ (1+ res->ncerts)*sizeof(int));
+ if (res->cert_list_length==NULL) {
+ gnutls_assert();
+ return GNUTLS_E_MEMORY_ERROR;
+ }
- res->x509_ca_list =
- (gnutls_cert *) gnutls_realloc(res->x509_ca_list,
- i *
- sizeof(gnutls_cert));
- if (res->x509_ca_list == NULL) {
- gnutls_assert();
- gnutls_free(b64);
- return GNUTLS_E_MEMORY_ERROR;
- }
- memset(&res->x509_ca_list[i - 1], 0, sizeof(gnutls_cert));
+ res->cert_list[res->ncerts] = NULL; /* for realloc */
+ res->cert_list_length[res->ncerts] = 0;
- tmp.data = b64;
- tmp.size = siz2;
+ ret = parse_cert_mem( &res->cert_list[res->ncerts], &res->cert_list_length[res->ncerts],
+ cert, cert_size);
- if ((ret =
- _gnutls_x509_cert2gnutls_cert(&res->x509_ca_list[i - 1],
- tmp)) < 0) {
- gnutls_assert();
- gnutls_free(b64);
- return ret;
- }
- gnutls_free(b64);
+ if (ret < 0) {
+ gnutls_assert();
+ return ret;
+ }
- /* now we move ptr after the pem header */
- ptr = strstr(ptr, CERT_SEP);
- if (ptr!=NULL)
- ptr++;
+ return 0;
+}
- i++;
- } while ((ptr = strstr(ptr, CERT_SEP)) != NULL);
+/* Reads a base64 encoded CA list from memory
+ * This is to be called once.
+ */
+static int read_ca_mem(GNUTLS_CERTIFICATE_CREDENTIALS res, const char *ca, int ca_size)
+{
- res->x509_ncas = i - 1;
+ return parse_cert_mem( &res->x509_ca_list, &res->x509_ncas,
+ ca, ca_size);
- return 0;
}
@@ -1230,7 +1293,7 @@ static int read_key_file(GNUTLS_CERTIFICATE_CREDENTIALS res, char *keyfile)
* gnutls_certificate_set_x509_key_file - Used to set keys in a GNUTLS_CERTIFICATE_CREDENTIALS structure
* @res: is an &GNUTLS_CERTIFICATE_CREDENTIALS structure.
* @CERTFILE: is a PEM encoded file containing the certificate list (path) for
- * the specified private key
+ * the specified private key or a PEM encoded PKCS7 file
* @KEYFILE: is a PEM encoded file containing a private key
*
* This function sets a certificate/private key pair in the
@@ -1320,7 +1383,7 @@ opaque *pdata;
/**
* gnutls_certificate_set_x509_trust_mem - Used to add trusted CAs in a GNUTLS_CERTIFICATE_CREDENTIALS structure
* @res: is an &GNUTLS_CERTIFICATE_CREDENTIALS structure.
- * @CA: is a PEM encoded list of trusted CAs
+ * @CA: is a PEM encoded list of trusted CAs or a PKCS7 pem encoded list
* @CRL: is a PEM encoded list of CRLs (ignored for now)
*
* This function adds the trusted CAs in order to verify client
@@ -1459,7 +1522,7 @@ static int _read_dsa_params(opaque * der, int dersize, MPI * params)
node_asn *spk;
if ((result=asn1_create_structure
- (_gnutls_get_pkix(), "PKIX1Implicit88.Dss-Parms", &spk,
+ (_gnutls_get_pkix(), "PKIX1.Dss-Parms", &spk,
"dsa_parms")) != ASN_OK) {
gnutls_assert();
return result;
@@ -1685,7 +1748,7 @@ int _gnutls_x509_cert2gnutls_cert(gnutls_cert * gCert, gnutls_datum derCert)
}
if ((result=asn1_create_structure
- (_gnutls_get_pkix(), "PKIX1Implicit88.Certificate", &c2,
+ (_gnutls_get_pkix(), "PKIX1.Certificate", &c2,
"certificate2"))
!= ASN_OK) {
gnutls_assert();
@@ -1767,6 +1830,7 @@ int _gnutls_x509_cert2gnutls_cert(gnutls_cert * gCert, gnutls_datum derCert)
if (gCert->version < 0) {
gnutls_assert();
asn1_delete_structure(c2);
+ gnutls_free_datum( &gCert->raw);
return GNUTLS_E_ASN1_GENERIC_ERROR;
}
@@ -1923,4 +1987,171 @@ int _gnutls_verify_x509_file( char *cafile)
return _gnutls_verify_x509_mem( x, siz);
}
+
+
#endif
+
+/**
+ * gnutls_x509_pkcs7_extract_certificate - This function returns a certificate in a PKCS7 certificate set
+ * @pkcs7_struct: should contain a PKCS7 DER formatted structure
+ * @indx: contains the index of the certificate to extract
+ * @certificate: the contents of the certificate will be copied there
+ * @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.
+ *
+ **/
+int gnutls_x509_pkcs7_extract_certificate(const gnutls_datum * pkcs7_struct, int indx, char* certificate, int* certificate_size)
+{
+ node_asn *c2, *c1;
+ int result, len;
+ char root1[128];
+ char oid[128];
+ char root2[128];
+ char counter[MAX_INT_DIGITS];
+ opaque* pkcs7_str = pkcs7_struct->data;
+ int pkcs7_str_size = pkcs7_struct->size;
+
+ opaque* pcert;
+ int pcert_size;
+
+ /* Step 1. Parse content and content info */
+
+ if (pkcs7_str_size == 0 || pkcs7_str == NULL) {
+ gnutls_assert();
+ return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
+ }
+
+ _gnutls_str_cpy( root1, sizeof(root1), "PKIX1.ContentInfo");
+ if ((result=asn1_create_structure
+ (_gnutls_get_pkix(), root1, &c1, "c1")) != ASN_OK) {
+ gnutls_assert();
+ return result;
+ }
+
+ result = asn1_get_der(c1, pkcs7_str, pkcs7_str_size);
+ if (result != ASN_OK) {
+ /* couldn't decode DER */
+
+ _gnutls_log("X509_auth: Decoding error %d\n");
+
+ gnutls_assert();
+ asn1_delete_structure(c1);
+ return result;
+ }
+
+ len = sizeof(oid) - 1;
+
+ /* root2 is used as a temp storage area
+ */
+ _gnutls_str_cpy( root2, sizeof(root2), "c1.contentType");
+ result = asn1_read_value(c1, root2, oid, &len);
+ if (result != ASN_OK) {
+ gnutls_assert();
+ asn1_delete_structure(c1);
+ return result;
+ }
+
+ if ( strcmp( oid, "1 2 840 113549 1 7 2") != 0) {
+ gnutls_assert();
+ asn1_delete_structure(c1);
+ return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
+ }
+
+ pcert_size = *certificate_size - 1;
+ pcert = certificate;
+
+ _gnutls_str_cpy( root2, sizeof(root2), "c1.content");
+ result = asn1_read_value(c1, root2, pcert, &pcert_size);
+
+ asn1_delete_structure(c1);
+
+ if (result != ASN_OK) {
+ gnutls_assert();
+ return result;
+ }
+
+ /* pcert, pcert_size hold the data and the size of the CertificateSet structure
+ * actually the ANY stuff.
+ */
+
+
+ /* Step 1.5. In case of a signed structure extract certificate set.
+ */
+ _gnutls_str_cpy( root2, sizeof(root2), "PKIX1.SignedData");
+ if ((result=asn1_create_structure
+ (_gnutls_get_pkix(), root2, &c2, "c2")) != ASN_OK) {
+ gnutls_assert();
+ return result;
+ }
+
+ result = asn1_get_der(c2, pcert, pcert_size);
+ if (result != ASN_OK) {
+ /* couldn't decode DER */
+
+ _gnutls_log("X509_auth: Decoding error %d\n");
+
+ gnutls_assert();
+ asn1_delete_structure(c2);
+ return result;
+ }
+
+
+ /* Step 2. Parse 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 == ASN_VALUE_NOT_FOUND) {
+ asn1_delete_structure(c2);
+ return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
+ }
+
+ if (result != ASN_OK) {
+ gnutls_assert();
+ asn1_delete_structure(c2);
+ return result;
+ }
+
+ /* if 'Certificate' is the choice found: */
+ if (strcmp( oid, "certificate") == 0) {
+ int start, end;
+
+/* _gnutls_str_cat( root2, sizeof(root2), ".certificate"); */
+
+ result = asn1_get_start_end_der(c2, pcert, pcert_size,
+ root2, &start, &end);
+
+ if (result != ASN_OK) {
+ gnutls_assert();
+ asn1_delete_structure(c2);
+ return result;
+ }
+
+ end = end-start+1;
+
+ if (certificate!=NULL && end <= *certificate_size)
+ memcpy( certificate, &pcert[start], end);
+ else {
+ *certificate_size = end;
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+
+ *certificate_size = end;
+
+ } else {
+ asn1_delete_structure(c2);
+ return GNUTLS_E_UNSUPPORTED_CERTIFICATE_TYPE;
+ }
+
+ asn1_delete_structure(c2);
+
+ return 0;
+}