diff options
author | Nikos Mavrogiannopoulos <nmav@gnutls.org> | 2003-02-07 09:06:51 +0000 |
---|---|---|
committer | Nikos Mavrogiannopoulos <nmav@gnutls.org> | 2003-02-07 09:06:51 +0000 |
commit | 31f922d91c510ba6c7560751309d279c0531f64e (patch) | |
tree | f91a322f9958c6abe47d7a6ed42a193065c8b406 | |
parent | 383d3b421c8dec95a48bcd0638601aaad4ff7b5c (diff) | |
download | gnutls-31f922d91c510ba6c7560751309d279c0531f64e.tar.gz |
More improvements in the CRL support, and the X.509 backend. Added a function to get some parts of the DN using an OID.
-rw-r--r-- | THANKS | 1 | ||||
-rw-r--r-- | includes/gnutls/x509.h | 17 | ||||
-rw-r--r-- | lib/Makefile.am | 2 | ||||
-rw-r--r-- | lib/gnutls_x509.c | 423 | ||||
-rw-r--r-- | lib/gnutls_x509.h | 17 | ||||
-rw-r--r-- | lib/x509/Makefile.am | 4 | ||||
-rw-r--r-- | lib/x509/common.c | 459 | ||||
-rw-r--r-- | lib/x509/common.h | 18 | ||||
-rw-r--r-- | lib/x509/crl.c | 40 | ||||
-rw-r--r-- | lib/x509/dn.c | 192 | ||||
-rw-r--r-- | lib/x509/dn.h | 4 | ||||
-rw-r--r-- | lib/x509_extensions.c | 1 | ||||
-rw-r--r-- | lib/x509_xml.c | 1 |
13 files changed, 728 insertions, 451 deletions
@@ -11,7 +11,6 @@ Marco d'Itri <md@linux.it> Mike Siers <mikes@poliac.com> Marc Huber <Marc.Huber@web.de> Guillaume Morin <guillaume@morinfr.org> -Andrew McDonald <andrew@mcdonald.org.uk> Jeff Johnson <jbj@redhat.com> David Taylor <dtaylo11@bigpond.net.au> Ivo Timmermans <ivo@o2w.nl> diff --git a/includes/gnutls/x509.h b/includes/gnutls/x509.h index bc01cc6f55..89b96fa9f3 100644 --- a/includes/gnutls/x509.h +++ b/includes/gnutls/x509.h @@ -32,6 +32,19 @@ extern "C" { #include <gnutls/gnutls.h> +/* 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" + + struct gnutls_crl_int; typedef struct gnutls_crl_int* gnutls_crl; @@ -43,6 +56,10 @@ int gnutls_x509_crl_import(gnutls_crl crl, const gnutls_datum * data, int gnutls_x509_crl_get_issuer_dn(const gnutls_crl crl, char *buf, int *sizeof_buf); +int gnutls_x509_crl_get_issuer_dn_by_oid(gnutls_crl crl, const char* oid, + char *buf, int *sizeof_buf); + + int gnutls_x509_crl_get_signed_data(gnutls_crl crl, gnutls_datum *data); int gnutls_x509_crl_get_signature(gnutls_crl crl, gnutls_datum *data); diff --git a/lib/Makefile.am b/lib/Makefile.am index 926db3205d..01531be70b 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -46,7 +46,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 +libgnutls_la_LIBADD = $(MINITASN1_OBJECTS) x509/dn.lo x509/crl.lo x509/common.lo libgnutls_la_LDFLAGS = $(LIBASN1_LINK) $(LIBGCRYPT_LIBS) \ -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) \ diff --git a/lib/gnutls_x509.c b/lib/gnutls_x509.c index db092cd791..00c00342d2 100644 --- a/lib/gnutls_x509.c +++ b/lib/gnutls_x509.c @@ -43,6 +43,7 @@ #include <x509_b64.h> #include <gnutls_privkey.h> #include <gnutls_x509.h> +#include "x509/common.h" /* * some x509 certificate parsing functions. @@ -51,168 +52,6 @@ int gnutls_x509_pkcs7_extract_certificate(const gnutls_datum * pkcs7_struct, int indx, char* certificate, int* certificate_size); int gnutls_x509_pkcs7_extract_certificate_count(const gnutls_datum * pkcs7_struct); -typedef struct _oid2string { - const char * OID; - const char * DESC; - const char * ldap_desc; - int choice; - int printable; -} oid2string; - -static const oid2string OID2STR[] = { - {"2 5 4 6", "X520countryName", "C", 0, 1}, - {"2 5 4 10", "X520OrganizationName", "O", 1, 1}, - {"2 5 4 11", "X520OrganizationalUnitName", "OU", 1, 1}, - {"2 5 4 3", "X520CommonName", "CN", 1, 1}, - {"2 5 4 7", "X520LocalityName", "L", 1, 1}, - {"2 5 4 8", "X520StateOrProvinceName", "ST", 1, 1}, - {"0 9 2342 19200300 100 1 25", "dc", "DC", 1, 1}, /* FIXME: CHOICE? */ - {"0 9 2342 19200300 100 1 1", "uid", "UID", 1, 1}, /* FIXME: CHOICE? */ - {"1 2 840 113549 1 9 1", "Pkcs9email", NULL, 0, 1}, - {"1 2 840 113549 1 1 1", "rsaEncryption", NULL, 0, 0}, - {"1 2 840 113549 1 1 2", "md2WithRSAEncryption", NULL, 0, 0}, - {"1 2 840 113549 1 1 4", "md5WithRSAEncryption", NULL, 0, 0}, - {"1 2 840 113549 1 1 5", "sha1WithRSAEncryption", NULL, 0, 0}, - {"1 2 840 10040 4 3", "id-dsa-with-sha1", NULL, 0, 0}, - {"1 2 840 10040 4 1", "id-dsa", NULL, 0, 0}, - {NULL, NULL, NULL, 0, 0} -}; - -/* Returns 1 if the data defined by the OID are printable. - */ -int _gnutls_x509_oid_data_printable( const char* OID) { -int i = 0; - - do { - if ( strcmp(OID2STR[i].OID, OID)==0) - return OID2STR[i].printable; - i++; - } while( OID2STR[i].OID != NULL); - - return 0; -} - -/* Returns 1 if the data defined by the OID are of a choice - * type. - */ -int _gnutls_x509_oid_data_choice( const char* OID) { -int i = 0; - - do { - if ( strcmp(OID2STR[i].OID, OID)==0) - return OID2STR[i].choice; - i++; - } while( OID2STR[i].OID != NULL); - - return 0; -} - -const char* _gnutls_x509_oid2string( const char* OID) { -int i = 0; - - do { - if ( strcmp(OID2STR[i].OID, OID)==0) - return OID2STR[i].DESC; - i++; - } while( OID2STR[i].OID != NULL); - - return NULL; -} - -const char* _gnutls_x509_oid2ldap_string( const char* OID) { -int i = 0; - - do { - if ( strcmp(OID2STR[i].OID, OID)==0) - return OID2STR[i].ldap_desc; - i++; - } while( OID2STR[i].OID != NULL); - - return NULL; -} - -/* This function will convert an attribute value, specified by the OID, - * to a string. The result will be a null terminated string. - */ -int _gnutls_x509_oid_data2string( const char* OID, void* value, - int value_size, char * res, int res_size) { - -int result; -char str[1024], tmpname[1024]; -const char* ANAME = NULL; -int CHOICE = -1, len = -1; -ASN1_TYPE tmpasn; - - if (value==NULL || value_size <=0 || res==NULL || res_size <=0) { - gnutls_assert(); - return GNUTLS_E_INVALID_REQUEST; - } - - res[0] = 0; - - if ( _gnutls_x509_oid_data_printable( OID) == 0) { - gnutls_assert(); - return GNUTLS_E_INTERNAL_ERROR; - } - - ANAME = _gnutls_x509_oid2string( OID); - CHOICE = _gnutls_x509_oid_data_choice( OID); - - if (ANAME==NULL) { - gnutls_assert(); - return GNUTLS_E_INTERNAL_ERROR; - } - - _gnutls_str_cpy(str, sizeof(str), "PKIX1."); - _gnutls_str_cat(str, sizeof(str), ANAME); - _gnutls_str_cpy( tmpname, sizeof(tmpname), "temp-structure-"); - _gnutls_str_cat( tmpname, sizeof(tmpname), ANAME); - - if ((result = - _gnutls_asn1_create_element(_gnutls_get_pkix(), str, - &tmpasn, tmpname)) != ASN1_SUCCESS) { - gnutls_assert(); - return _gnutls_asn2err(result); - } - - if ((result = asn1_der_decoding(&tmpasn, value, value_size, NULL)) != ASN1_SUCCESS) { - asn1_delete_structure(&tmpasn); - return _gnutls_asn2err(result); - } - - /* If this is a choice then we read the choice. Otherwise it - * is the value; - */ - len = sizeof( str) - 1; - if ((result = asn1_read_value(tmpasn, tmpname, str, &len)) != ASN1_SUCCESS) { /* CHOICE */ - asn1_delete_structure(&tmpasn); - return _gnutls_asn2err(result); - } - - if (CHOICE == 0) { - str[len] = 0; - _gnutls_str_cpy(res, res_size, str); - - } else { /* CHOICE */ - str[len] = 0; - _gnutls_str_cat( tmpname, sizeof(tmpname), "."); - _gnutls_str_cat( tmpname, sizeof(tmpname), str); - - len = sizeof(str) - 1; - if ((result = - asn1_read_value(tmpasn, tmpname, str, - &len)) != ASN1_SUCCESS) { - asn1_delete_structure(&tmpasn); - return _gnutls_asn2err(result); - } - str[len] = 0; - _gnutls_str_cpy(res, res_size, str); - } - asn1_delete_structure(&tmpasn); - - return 0; - -} static int _IREAD(ASN1_TYPE rasn, char* name, const char *OID, gnutls_x509_dn *dn) @@ -256,22 +95,11 @@ static int _IREAD(ASN1_TYPE rasn, char* name, const char *OID, return 1; } - result = _gnutls_x509_oid_data2string( OID, str, len, res, res_size); + result = _gnutls_x509_oid_data2string( OID, str, len, res, &res_size); if (result < 0) return 1; else return 0; } -/* this function will convert up to 3 digit - * numbers to characters. Use a character string of MAX_INT_DIGITS, in - * order to have enough space for it. - */ -void _gnutls_int2str(unsigned int k, char *data) -{ - if (k > 999) - sprintf(data, "%d", 999); - else - sprintf(data, "%d", k); -} /* This function will attempt to read a Name * ASN.1 structure. (Taken from Fabio's samples!) @@ -362,52 +190,6 @@ int _gnutls_x509_get_name_type(ASN1_TYPE rasn, const char *root, gnutls_x509_dn } -/* Extracts the time in time_t from the ASN1_TYPE given. When should - * be something like "crl2.tbsCertList.thisUpdate". - */ -#define MAX_TIME 1024 -time_t _gnutls_x509_get_time(ASN1_TYPE c2, const char *when) -{ - opaque ttime[MAX_TIME]; - char name[1024]; - time_t ctime = (time_t)-1; - int len, result; - - _gnutls_str_cpy(name, sizeof(name), when); - - len = sizeof(ttime) - 1; - if ((result = asn1_read_value(c2, name, ttime, &len)) < 0) { - gnutls_assert(); - return (time_t) (-1); - } - - /* CHOICE */ - if (strcmp(ttime, "GeneralizedTime") == 0) { - - _gnutls_str_cat(name, sizeof(name), ".generalTime"); - len = sizeof(ttime) - 1; - result = asn1_read_value(c2, name, ttime, &len); - if (result == ASN1_SUCCESS) - ctime = _gnutls_x509_generalTime2gtime(ttime); - } else { /* UTCTIME */ - - _gnutls_str_cat(name, sizeof(name), ".utcTime"); - len = sizeof(ttime) - 1; - result = asn1_read_value(c2, name, ttime, &len); - if (result == ASN1_SUCCESS) - ctime = _gnutls_x509_utcTime2gtime(ttime); - } - - /* We cannot handle dates after 2031 in 32 bit machines. - * a time_t of 64bits has to be used. - */ - - if (result != ASN1_SUCCESS) { - gnutls_assert(); - return (time_t) (-1); - } - return ctime; -} int _gnutls_x509_get_version(ASN1_TYPE c2, const char *root) { @@ -2014,18 +1796,6 @@ static int _read_dsa_pubkey(opaque * der, int dersize, GNUTLS_MPI * params) } -#define PKIX1_RSA_OID "1 2 840 113549 1 1 1" -#define DSA_OID "1 2 840 10040 4 1" - -gnutls_pk_algorithm _gnutls_x509_oid2pk_algorithm( const char* oid) -{ - if (strcmp( oid, PKIX1_RSA_OID) == 0) /* pkix-1 1 - RSA */ - return GNUTLS_PK_RSA; - else if (strcmp( oid, DSA_OID) == 0) - return GNUTLS_PK_DSA; - - return GNUTLS_PK_UNKNOWN; -} /* Extracts DSA and RSA parameters from a certificate. */ @@ -2570,13 +2340,7 @@ int gnutls_x509_extract_certificate_pk_algorithm( const gnutls_datum * cert, int return _gnutls_asn2err(result); } - algo = GNUTLS_E_UNKNOWN_PK_ALGORITHM; - - if ( strcmp( str, PKIX1_RSA_OID)==0) - algo = GNUTLS_PK_RSA; - - if ( strcmp( str, DSA_OID)==0) - algo = GNUTLS_PK_DSA; + algo = _gnutls_x509_oid2pk_algorithm( str); if ( bits==NULL) { asn1_delete_structure(&c2); @@ -2745,187 +2509,6 @@ int gnutls_x509_pkcs7_extract_certificate_count(const gnutls_datum * pkcs7_struc return count; } -/* TIME functions - * Convertions between generalized or UTC time to time_t - * - */ - -/* This is an emulations of the struct tm. - * Since we do not use libc's functions, we don't need to - * depend on the libc structure. - */ -typedef struct fake_tm { - int tm_mon; - int tm_year; /* FULL year - ie 1971 */ - int tm_mday; - int tm_hour; - int tm_min; - int tm_sec; -} fake_tm; - -/* The mktime_utc function is due to Russ Allbery (rra@stanford.edu), - * who placed it under public domain: - */ - -/* The number of days in each month. - */ -static const int MONTHDAYS[] = { - 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 -}; - - /* Whether a given year is a leap year. */ -#define ISLEAP(year) \ - (((year) % 4) == 0 && (((year) % 100) != 0 || ((year) % 400) == 0)) - -/* - ** Given a struct tm representing a calendar time in UTC, convert it to - ** seconds since epoch. Returns (time_t) -1 if the time is not - ** convertable. Note that this function does not canonicalize the provided - ** struct tm, nor does it allow out of range values or years before 1970. - */ -static time_t mktime_utc(const struct fake_tm *tm) -{ - time_t result = 0; - int i; - -/* We do allow some ill-formed dates, but we don't do anything special - * with them and our callers really shouldn't pass them to us. Do - * explicitly disallow the ones that would cause invalid array accesses - * or other algorithm problems. - */ - if (tm->tm_mon < 0 || tm->tm_mon > 11 || tm->tm_year < 1970) - return (time_t) - 1; - -/* Convert to a time_t. - */ - for (i = 1970; i < tm->tm_year; i++) - result += 365 + ISLEAP(i); - for (i = 0; i < tm->tm_mon; i++) - result += MONTHDAYS[i]; - if (tm->tm_mon > 1 && ISLEAP(tm->tm_year)) - result++; - result = 24 * (result + tm->tm_mday - 1) + tm->tm_hour; - result = 60 * result + tm->tm_min; - result = 60 * result + tm->tm_sec; - return result; -} - - -/* this one will parse dates of the form: - * month|day|hour|minute (2 chars each) - * and year is given. Returns a time_t date. - */ -static time_t _gnutls_x509_time2gtime(char *ttime, int year) -{ - char xx[3]; - struct fake_tm etime; - time_t ret; - - if (strlen( ttime) < 8) { - gnutls_assert(); - return (time_t) -1; - } - - etime.tm_year = year; - - /* In order to work with 32 bit - * time_t. - */ - if (sizeof (time_t) <= 4 && etime.tm_year >= 2038) - return (time_t)2145914603; /* 2037-12-31 23:23:23 */ - - xx[2] = 0; - -/* get the month - */ - memcpy(xx, ttime, 2); /* month */ - etime.tm_mon = atoi(xx) - 1; - ttime += 2; - -/* get the day - */ - memcpy(xx, ttime, 2); /* day */ - etime.tm_mday = atoi(xx); - ttime += 2; - -/* get the hour - */ - memcpy(xx, ttime, 2); /* hour */ - etime.tm_hour = atoi(xx); - ttime += 2; - -/* get the minutes - */ - memcpy(xx, ttime, 2); /* minutes */ - etime.tm_min = atoi(xx); - ttime += 2; - - etime.tm_sec = 0; - - ret = mktime_utc(&etime); - - return ret; -} - -/* returns a time_t value that contains the given time. - * The given time is expressed as: - * YEAR(2)|MONTH(2)|DAY(2)|HOUR(2)|MIN(2) - */ -time_t _gnutls_x509_utcTime2gtime(char *ttime) -{ - char xx[3]; - int year; - - if (strlen( ttime) < 10) { - gnutls_assert(); - return (time_t) -1; - } - xx[2] = 0; -/* get the year - */ - memcpy(xx, ttime, 2); /* year */ - year = atoi(xx); - ttime += 2; - - if (year > 49) - year += 1900; - else - year += 2000; - - return _gnutls_x509_time2gtime( ttime, year); -} - -/* returns a time_t value that contains the given time. - * The given time is expressed as: - * YEAR(4)|MONTH(2)|DAY(2)|HOUR(2)|MIN(2) - */ -time_t _gnutls_x509_generalTime2gtime(char *ttime) -{ - char xx[5]; - int year; - - if (strlen( ttime) < 12) { - gnutls_assert(); - return (time_t) -1; - } - - if (strchr(ttime, 'Z') == 0) { - gnutls_assert(); - /* sorry we don't support it yet - */ - return (time_t)-1; - } - xx[4] = 0; - -/* get the year - */ - memcpy(xx, ttime, 4); /* year */ - year = atoi(xx); - ttime += 4; - - return _gnutls_x509_time2gtime( ttime, year); - -} static char* str_escape( char* str, char* buffer, unsigned int buffer_size) { diff --git a/lib/gnutls_x509.h b/lib/gnutls_x509.h index 99309aac81..3a6cf9ee1d 100644 --- a/lib/gnutls_x509.h +++ b/lib/gnutls_x509.h @@ -10,10 +10,6 @@ typedef enum ConvFlags { int _gnutls_x509_cert2gnutls_cert(gnutls_cert * gCert, gnutls_datum derCert, ConvFlags flags); -/* for int2str */ -#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_PKCS7_SEP "-----BEGIN PKCS7" @@ -25,19 +21,6 @@ int _gnutls_check_x509_key_usage( const gnutls_cert * cert, gnutls_kx_algorithm time_t gnutls_x509_extract_certificate_activation_time( const gnutls_datum*); time_t gnutls_x509_extract_certificate_expiration_time( const gnutls_datum*); -time_t _gnutls_x509_utcTime2gtime(char *ttime); -time_t _gnutls_x509_generalTime2gtime(char *ttime); - -int _gnutls_x509_oid_data2string( const char* OID, void* value, - int value_size, char * res, int res_size); - -const char* _gnutls_x509_oid2string( const char* OID); -const char* _gnutls_x509_oid2ldap_string( const char* OID); - -int _gnutls_x509_oid_data_printable( const char* OID); -gnutls_pk_algorithm _gnutls_x509_oid2pk_algorithm( const char* oid); - -time_t _gnutls_x509_get_time(ASN1_TYPE c2, const char *when); int gnutls_x509_extract_certificate_subject_alt_name( const gnutls_datum*, int seq, char*, int*); int gnutls_x509_extract_certificate_dn( const gnutls_datum*, gnutls_x509_dn*); diff --git a/lib/x509/Makefile.am b/lib/x509/Makefile.am index d6fbd8eea8..3c126a866a 100644 --- a/lib/x509/Makefile.am +++ b/lib/x509/Makefile.am @@ -1,8 +1,8 @@ INCLUDES = -I../ -I../minitasn1/ -EXTRA_DIST = crl.h dn.h +EXTRA_DIST = crl.h dn.h common.h noinst_LTLIBRARIES = libx509.la -libx509_la_SOURCES = crl.c dn.c +libx509_la_SOURCES = crl.c dn.c common.c diff --git a/lib/x509/common.c b/lib/x509/common.c new file mode 100644 index 0000000000..06ecf9ad67 --- /dev/null +++ b/lib/x509/common.c @@ -0,0 +1,459 @@ +/* + * 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 <gnutls_str.h> +#include <gnutls_x509.h> +#include <gnutls_num.h> +#include <common.h> + +typedef struct _oid2string { + const char * OID; + const char * DESC; + const char * ldap_desc; + int choice; + int printable; +} oid2string; + +static const oid2string OID2STR[] = { + {"2 5 4 6", "X520countryName", "C", 0, 1}, + {"2 5 4 10", "X520OrganizationName", "O", 1, 1}, + {"2 5 4 11", "X520OrganizationalUnitName", "OU", 1, 1}, + {"2 5 4 3", "X520CommonName", "CN", 1, 1}, + {"2 5 4 7", "X520LocalityName", "L", 1, 1}, + {"2 5 4 8", "X520StateOrProvinceName", "ST", 1, 1}, + {"0 9 2342 19200300 100 1 25", "dc", "DC", 1, 1}, /* FIXME: CHOICE? */ + {"0 9 2342 19200300 100 1 1", "uid", "UID", 1, 1}, /* FIXME: CHOICE? */ + {"1 2 840 113549 1 9 1", "Pkcs9email", NULL, 0, 1}, + {"1 2 840 113549 1 1 1", "rsaEncryption", NULL, 0, 0}, + {"1 2 840 113549 1 1 2", "md2WithRSAEncryption", NULL, 0, 0}, + {"1 2 840 113549 1 1 4", "md5WithRSAEncryption", NULL, 0, 0}, + {"1 2 840 113549 1 1 5", "sha1WithRSAEncryption", NULL, 0, 0}, + {"1 2 840 10040 4 3", "id-dsa-with-sha1", NULL, 0, 0}, + {"1 2 840 10040 4 1", "id-dsa", NULL, 0, 0}, + {NULL, NULL, NULL, 0, 0} +}; + +/* Returns 1 if the data defined by the OID are printable. + */ +int _gnutls_x509_oid_data_printable( const char* OID) { +int i = 0; + + do { + if ( strcmp(OID2STR[i].OID, OID)==0) + return OID2STR[i].printable; + i++; + } while( OID2STR[i].OID != NULL); + + return 0; +} + +/* Returns 1 if the data defined by the OID are of a choice + * type. + */ +int _gnutls_x509_oid_data_choice( const char* OID) { +int i = 0; + + do { + if ( strcmp(OID2STR[i].OID, OID)==0) + return OID2STR[i].choice; + i++; + } while( OID2STR[i].OID != NULL); + + return 0; +} + +const char* _gnutls_x509_oid2string( const char* OID) { +int i = 0; + + do { + if ( strcmp(OID2STR[i].OID, OID)==0) + return OID2STR[i].DESC; + i++; + } while( OID2STR[i].OID != NULL); + + return NULL; +} + +const char* _gnutls_x509_oid2ldap_string( const char* OID) { +int i = 0; + + do { + if ( strcmp(OID2STR[i].OID, OID)==0) + return OID2STR[i].ldap_desc; + i++; + } while( OID2STR[i].OID != NULL); + + return NULL; +} + +/* This function will convert an attribute value, specified by the OID, + * to a string. The result will be a null terminated string. + * + * res may be null. This will just return the res_size, needed to + * hold the string. + */ +int _gnutls_x509_oid_data2string( const char* OID, void* value, + int value_size, char * res, int *res_size) { + +int result; +char str[1024], tmpname[1024]; +const char* ANAME = NULL; +int CHOICE = -1, len = -1; +ASN1_TYPE tmpasn; + + if (value==NULL || value_size <=0 || res_size == NULL) { + gnutls_assert(); + return GNUTLS_E_INVALID_REQUEST; + } + + res[0] = 0; + + if ( _gnutls_x509_oid_data_printable( OID) == 0) { + gnutls_assert(); + return GNUTLS_E_INTERNAL_ERROR; + } + + ANAME = _gnutls_x509_oid2string( OID); + CHOICE = _gnutls_x509_oid_data_choice( OID); + + if (ANAME==NULL) { + gnutls_assert(); + return GNUTLS_E_INTERNAL_ERROR; + } + + _gnutls_str_cpy(str, sizeof(str), "PKIX1."); + _gnutls_str_cat(str, sizeof(str), ANAME); + _gnutls_str_cpy( tmpname, sizeof(tmpname), "temp-structure-"); + _gnutls_str_cat( tmpname, sizeof(tmpname), ANAME); + + if ((result = + _gnutls_asn1_create_element(_gnutls_get_pkix(), str, + &tmpasn, tmpname)) != ASN1_SUCCESS) { + gnutls_assert(); + return _gnutls_asn2err(result); + } + + if ((result = asn1_der_decoding(&tmpasn, value, value_size, NULL)) != ASN1_SUCCESS) { + asn1_delete_structure(&tmpasn); + return _gnutls_asn2err(result); + } + + /* If this is a choice then we read the choice. Otherwise it + * is the value; + */ + len = sizeof( str) - 1; + if ((result = asn1_read_value(tmpasn, tmpname, str, &len)) != ASN1_SUCCESS) { /* CHOICE */ + asn1_delete_structure(&tmpasn); + return _gnutls_asn2err(result); + } + + if (CHOICE == 0) { + str[len] = 0; + if (res) + _gnutls_str_cpy(res, *res_size, str); + *res_size = len; + + } else { /* CHOICE */ + str[len] = 0; + _gnutls_str_cat( tmpname, sizeof(tmpname), "."); + _gnutls_str_cat( tmpname, sizeof(tmpname), str); + + len = sizeof(str) - 1; + if ((result = + asn1_read_value(tmpasn, tmpname, str, + &len)) != ASN1_SUCCESS) { + asn1_delete_structure(&tmpasn); + return _gnutls_asn2err(result); + } + str[len] = 0; + + if (res) + _gnutls_str_cpy(res, *res_size, str); + *res_size = len; + } + asn1_delete_structure(&tmpasn); + + return 0; + +} + + +/* this function will convert up to 3 digit + * numbers to characters. Use a character string of MAX_INT_DIGITS, in + * order to have enough space for it. + */ +void _gnutls_int2str(unsigned int k, char *data) +{ + if (k > 999) + sprintf(data, "%d", 999); + else + sprintf(data, "%d", k); +} + + +#define PKIX1_RSA_OID "1 2 840 113549 1 1 1" +#define DSA_OID "1 2 840 10040 4 1" + +gnutls_pk_algorithm _gnutls_x509_oid2pk_algorithm( const char* oid) +{ + if (strcmp( oid, PKIX1_RSA_OID) == 0) /* pkix-1 1 - RSA */ + return GNUTLS_PK_RSA; + else if (strcmp( oid, DSA_OID) == 0) + return GNUTLS_PK_DSA; + + return GNUTLS_PK_UNKNOWN; +} + + +/* TIME functions + * Convertions between generalized or UTC time to time_t + * + */ + +/* This is an emulations of the struct tm. + * Since we do not use libc's functions, we don't need to + * depend on the libc structure. + */ +typedef struct fake_tm { + int tm_mon; + int tm_year; /* FULL year - ie 1971 */ + int tm_mday; + int tm_hour; + int tm_min; + int tm_sec; +} fake_tm; + +/* The mktime_utc function is due to Russ Allbery (rra@stanford.edu), + * who placed it under public domain: + */ + +/* The number of days in each month. + */ +static const int MONTHDAYS[] = { + 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 +}; + + /* Whether a given year is a leap year. */ +#define ISLEAP(year) \ + (((year) % 4) == 0 && (((year) % 100) != 0 || ((year) % 400) == 0)) + +/* + ** Given a struct tm representing a calendar time in UTC, convert it to + ** seconds since epoch. Returns (time_t) -1 if the time is not + ** convertable. Note that this function does not canonicalize the provided + ** struct tm, nor does it allow out of range values or years before 1970. + */ +static time_t mktime_utc(const struct fake_tm *tm) +{ + time_t result = 0; + int i; + +/* We do allow some ill-formed dates, but we don't do anything special + * with them and our callers really shouldn't pass them to us. Do + * explicitly disallow the ones that would cause invalid array accesses + * or other algorithm problems. + */ + if (tm->tm_mon < 0 || tm->tm_mon > 11 || tm->tm_year < 1970) + return (time_t) - 1; + +/* Convert to a time_t. + */ + for (i = 1970; i < tm->tm_year; i++) + result += 365 + ISLEAP(i); + for (i = 0; i < tm->tm_mon; i++) + result += MONTHDAYS[i]; + if (tm->tm_mon > 1 && ISLEAP(tm->tm_year)) + result++; + result = 24 * (result + tm->tm_mday - 1) + tm->tm_hour; + result = 60 * result + tm->tm_min; + result = 60 * result + tm->tm_sec; + return result; +} + + +/* this one will parse dates of the form: + * month|day|hour|minute (2 chars each) + * and year is given. Returns a time_t date. + */ +static time_t _gnutls_x509_time2gtime(char *ttime, int year) +{ + char xx[3]; + struct fake_tm etime; + time_t ret; + + if (strlen( ttime) < 8) { + gnutls_assert(); + return (time_t) -1; + } + + etime.tm_year = year; + + /* In order to work with 32 bit + * time_t. + */ + if (sizeof (time_t) <= 4 && etime.tm_year >= 2038) + return (time_t)2145914603; /* 2037-12-31 23:23:23 */ + + xx[2] = 0; + +/* get the month + */ + memcpy(xx, ttime, 2); /* month */ + etime.tm_mon = atoi(xx) - 1; + ttime += 2; + +/* get the day + */ + memcpy(xx, ttime, 2); /* day */ + etime.tm_mday = atoi(xx); + ttime += 2; + +/* get the hour + */ + memcpy(xx, ttime, 2); /* hour */ + etime.tm_hour = atoi(xx); + ttime += 2; + +/* get the minutes + */ + memcpy(xx, ttime, 2); /* minutes */ + etime.tm_min = atoi(xx); + ttime += 2; + + etime.tm_sec = 0; + + ret = mktime_utc(&etime); + + return ret; +} + + +/* returns a time_t value that contains the given time. + * The given time is expressed as: + * YEAR(2)|MONTH(2)|DAY(2)|HOUR(2)|MIN(2) + */ +time_t _gnutls_x509_utcTime2gtime(char *ttime) +{ + char xx[3]; + int year; + + if (strlen( ttime) < 10) { + gnutls_assert(); + return (time_t) -1; + } + xx[2] = 0; +/* get the year + */ + memcpy(xx, ttime, 2); /* year */ + year = atoi(xx); + ttime += 2; + + if (year > 49) + year += 1900; + else + year += 2000; + + return _gnutls_x509_time2gtime( ttime, year); +} + +/* returns a time_t value that contains the given time. + * The given time is expressed as: + * YEAR(4)|MONTH(2)|DAY(2)|HOUR(2)|MIN(2) + */ +time_t _gnutls_x509_generalTime2gtime(char *ttime) +{ + char xx[5]; + int year; + + if (strlen( ttime) < 12) { + gnutls_assert(); + return (time_t) -1; + } + + if (strchr(ttime, 'Z') == 0) { + gnutls_assert(); + /* sorry we don't support it yet + */ + return (time_t)-1; + } + xx[4] = 0; + +/* get the year + */ + memcpy(xx, ttime, 4); /* year */ + year = atoi(xx); + ttime += 4; + + return _gnutls_x509_time2gtime( ttime, year); + +} + +/* Extracts the time in time_t from the ASN1_TYPE given. When should + * be something like "crl2.tbsCertList.thisUpdate". + */ +#define MAX_TIME 1024 +time_t _gnutls_x509_get_time(ASN1_TYPE c2, const char *when) +{ + opaque ttime[MAX_TIME]; + char name[1024]; + time_t ctime = (time_t)-1; + int len, result; + + _gnutls_str_cpy(name, sizeof(name), when); + + len = sizeof(ttime) - 1; + if ((result = asn1_read_value(c2, name, ttime, &len)) < 0) { + gnutls_assert(); + return (time_t) (-1); + } + + /* CHOICE */ + if (strcmp(ttime, "GeneralizedTime") == 0) { + + _gnutls_str_cat(name, sizeof(name), ".generalTime"); + len = sizeof(ttime) - 1; + result = asn1_read_value(c2, name, ttime, &len); + if (result == ASN1_SUCCESS) + ctime = _gnutls_x509_generalTime2gtime(ttime); + } else { /* UTCTIME */ + + _gnutls_str_cat(name, sizeof(name), ".utcTime"); + len = sizeof(ttime) - 1; + result = asn1_read_value(c2, name, ttime, &len); + if (result == ASN1_SUCCESS) + ctime = _gnutls_x509_utcTime2gtime(ttime); + } + + /* We cannot handle dates after 2031 in 32 bit machines. + * a time_t of 64bits has to be used. + */ + + if (result != ASN1_SUCCESS) { + gnutls_assert(); + return (time_t) (-1); + } + return ctime; +} diff --git a/lib/x509/common.h b/lib/x509/common.h new file mode 100644 index 0000000000..7da7d2e372 --- /dev/null +++ b/lib/x509/common.h @@ -0,0 +1,18 @@ +/* for int2str */ +#define MAX_INT_DIGITS 4 +void _gnutls_int2str(unsigned int k, char *data); + +time_t _gnutls_x509_utcTime2gtime(char *ttime); +time_t _gnutls_x509_generalTime2gtime(char *ttime); + +int _gnutls_x509_oid_data2string( const char* OID, void* value, + int value_size, char * res, int *res_size); + +const char* _gnutls_x509_oid2string( const char* OID); +const char* _gnutls_x509_oid2ldap_string( const char* OID); + +int _gnutls_x509_oid_data_choice( const char* OID); +int _gnutls_x509_oid_data_printable( const char* OID); +gnutls_pk_algorithm _gnutls_x509_oid2pk_algorithm( const char* oid); + +time_t _gnutls_x509_get_time(ASN1_TYPE c2, const char *when); diff --git a/lib/x509/crl.c b/lib/x509/crl.c index 8daf1feb01..aeb08ab441 100644 --- a/lib/x509/crl.c +++ b/lib/x509/crl.c @@ -24,7 +24,7 @@ #include <gnutls_datum.h> #include <gnutls_global.h> #include <gnutls_errors.h> -#include <gnutls_x509.h> +#include <common.h> #include <x509_b64.h> #include <crl.h> #include <dn.h> @@ -203,12 +203,14 @@ int gnutls_x509_crl_import(gnutls_crl crl, const gnutls_datum * data, /** * gnutls_x509_crl_get_issuer_dn - This function returns the CRL's issuer distinguished name * @crl: should contain a gnutls_crl structure - * @buf: a pointer to a structure to hold the peer's name + * @buf: a pointer to a structure to hold the peer's name (may be null) * @sizeof_buf: initialy holds the size of 'buf' * * This function will copy the name of the CRL issuer in the provided buffer. The name * will be in the form "C=xxxx,O=yyyy,CN=zzzz" as described in RFC2253. * + * If buf is null then only the size will be filled. + * * Returns GNUTLS_E_SHORT_MEMORY_BUFFER if the provided buffer is not long enough, and * in that case the sizeof_buf will be updated with the required size. * On success zero is returned. @@ -217,7 +219,7 @@ int gnutls_x509_crl_import(gnutls_crl crl, const gnutls_datum * data, int gnutls_x509_crl_get_issuer_dn(gnutls_crl crl, char *buf, int *sizeof_buf) { - if (buf == NULL || sizeof_buf == 0 || crl == NULL) { + if (sizeof_buf == 0 || crl == NULL) { return GNUTLS_E_INVALID_REQUEST; } @@ -228,6 +230,38 @@ int gnutls_x509_crl_get_issuer_dn(gnutls_crl crl, char *buf, } /** + * gnutls_x509_crl_get_issuer_dn_by_oid - This function returns the CRL's issuer distinguished name + * @crl: should contain a gnutls_crl structure + * @oid: holds an Object Identified in null terminated string + * @buf: a pointer to a structure to hold the peer's name (may be null) + * @sizeof_buf: initialy holds the size of 'buf' + * + * This function will extract the part of the name of the CRL issuer specified + * by the given OID. The output will be encoded as described in RFC2253. + * + * Some helper macros with popular OIDs can be found in gnutls/x509.h + * + * If buf is null then only the size will be filled. + * + * Returns GNUTLS_E_SHORT_MEMORY_BUFFER if the provided buffer is not long enough, and + * in that case the sizeof_buf will be updated with the required size. + * On success zero is returned. + * + **/ +int gnutls_x509_crl_get_issuer_dn_by_oid(gnutls_crl crl, const char* oid, char *buf, + int *sizeof_buf) +{ + if (sizeof_buf == 0 || crl == NULL) { + return GNUTLS_E_INVALID_REQUEST; + } + + return _gnutls_x509_parse_dn_oid( crl->crl, "crl2.tbsCertList.issuer.rdnSequence", oid, + buf, sizeof_buf); + + +} + +/** * gnutls_x509_crl_get_signed_data - This function returns the CRL's signed portion * @crl: should contain a gnutls_crl structure * @data: a datum which points to the signed data diff --git a/lib/x509/dn.c b/lib/x509/dn.c index bfe2d9ab6f..779229cd5c 100644 --- a/lib/x509/dn.c +++ b/lib/x509/dn.c @@ -25,10 +25,14 @@ #include <gnutls_global.h> #include <gnutls_errors.h> #include <gnutls_str.h> -#include <gnutls_x509.h> +#include <common.h> #include <gnutls_num.h> #include <dn.h> +/* This file includes all the required to parse an X.509 Distriguished + * Name (you need a parser just to read a name in the X.509 protoocols!!!) + */ + /* converts all spaces to dots. Used to convert the * OIDs returned by libtasn1 to the dotted OID format. */ @@ -107,7 +111,7 @@ int _gnutls_x509_parse_dn(ASN1_TYPE asn1_struct, int first = 0; int len, printable; - if (buf == NULL || *sizeof_buf == 0) { + if (*sizeof_buf == 0) { gnutls_assert(); return GNUTLS_E_INVALID_REQUEST; } @@ -231,10 +235,11 @@ int _gnutls_x509_parse_dn(ASN1_TYPE asn1_struct, if (printable==1) { char string[256]; + int sizeof_string = sizeof(string); STR_APPEND(ldap_desc); STR_APPEND("="); - if ( (result=_gnutls_x509_oid_data2string( oid, value, len, string, sizeof(string))) < 0) { + if ( (result=_gnutls_x509_oid_data2string( oid, value, len, string, &sizeof_string)) < 0) { gnutls_assert(); goto cleanup; } @@ -253,19 +258,192 @@ int _gnutls_x509_parse_dn(ASN1_TYPE asn1_struct, } while (1); - if (out_str.length >= *sizeof_buf) { + if (out_str.length >= (unsigned int)*sizeof_buf) { gnutls_assert(); *sizeof_buf = out_str.length; result = GNUTLS_E_SHORT_MEMORY_BUFFER; goto cleanup; } - memcpy(buf, out_str.data, out_str.length); - buf[out_str.length] = 0; + if (buf) { + memcpy(buf, out_str.data, out_str.length); + buf[out_str.length] = 0; + } + *sizeof_buf = out_str.length; - return 0; + result = 0; cleanup: _gnutls_string_clear(&out_str); return result; } + +/* Parses an X509 DN in the asn1_struct, and searches for the + * given OID in the DN. + * The output will be encoded in the LDAP way. (#hex for non printable). + * + * asn1_rdn_name must be a string in the form "crl2.tbsCertificate.issuer.rdnSequence". + * That is to point in the rndSequence. + */ +int _gnutls_x509_parse_dn_oid(ASN1_TYPE asn1_struct, + const char *asn1_rdn_name, const char * given_oid, + char *buf, + int *sizeof_buf) +{ + int k2, k1, result; + char tmpbuffer1[64]; + char tmpbuffer2[64]; + char tmpbuffer3[64]; + char counter[MAX_INT_DIGITS]; + char value[200]; + char escaped[256]; + char oid[128]; + int len, printable; + + if (*sizeof_buf == 0) { + gnutls_assert(); + return GNUTLS_E_INVALID_REQUEST; + } + + buf[0] = 0; + + k1 = 0; + do { + + k1++; + /* create a string like "crl2.tbsCertList.issuer.rdnSequence.?1" + */ + _gnutls_int2str(k1, counter); + _gnutls_str_cpy(tmpbuffer1, sizeof(tmpbuffer1), + asn1_rdn_name); + _gnutls_str_cat(tmpbuffer1, sizeof(tmpbuffer1), ".?"); + _gnutls_str_cat(tmpbuffer1, sizeof(tmpbuffer1), counter); + + len = sizeof(value) - 1; + result = + asn1_read_value(asn1_struct, tmpbuffer1, value, &len); + + if (result == ASN1_ELEMENT_NOT_FOUND) { + gnutls_assert(); + break; + } + + if (result != ASN1_VALUE_NOT_FOUND) { + gnutls_assert(); + result = _gnutls_asn2err(result); + goto cleanup; + } + + k2 = 0; + + do { /* Move to the attibute type and values + */ + k2++; + + _gnutls_int2str(k2, counter); + _gnutls_str_cpy(tmpbuffer2, sizeof(tmpbuffer2), + tmpbuffer1); + _gnutls_str_cat(tmpbuffer2, sizeof(tmpbuffer2), + ".?"); + _gnutls_str_cat(tmpbuffer2, sizeof(tmpbuffer2), + counter); + + /* Try to read the RelativeDistinguishedName attributes. + */ + + len = sizeof(value) - 1; + result = + asn1_read_value(asn1_struct, tmpbuffer2, value, + &len); + + if (result == ASN1_ELEMENT_NOT_FOUND) { + gnutls_assert(); + break; + } + if (result != ASN1_VALUE_NOT_FOUND) { + gnutls_assert(); + result = _gnutls_asn2err(result); + goto cleanup; + } + + /* Read the OID + */ + _gnutls_str_cpy(tmpbuffer3, sizeof(tmpbuffer3), + tmpbuffer2); + _gnutls_str_cat(tmpbuffer3, sizeof(tmpbuffer3), + ".type"); + + len = sizeof(oid) - 1; + result = + asn1_read_value(asn1_struct, tmpbuffer3, oid, + &len); + + if (result == ASN1_ELEMENT_NOT_FOUND) + break; + else if (result != ASN1_SUCCESS) { + gnutls_assert(); + result = _gnutls_asn2err(result); + goto cleanup; + } + + if (strcmp( oid, given_oid) == 0) { + + /* Read the Value + */ + _gnutls_str_cpy(tmpbuffer3, sizeof(tmpbuffer3), + tmpbuffer2); + _gnutls_str_cat(tmpbuffer3, sizeof(tmpbuffer3), + ".value"); + + len = sizeof(value) - 1; + result = + asn1_read_value(asn1_struct, tmpbuffer3, value, + &len); + + if (result != ASN1_SUCCESS) { + gnutls_assert(); + result = _gnutls_asn2err(result); + goto cleanup; + } + + + printable = _gnutls_x509_oid_data_printable(oid); + + if (printable==1) { + if ( (result=_gnutls_x509_oid_data2string( oid, value, len, buf, sizeof_buf)) < 0) { + gnutls_assert(); + goto cleanup; + } + + return 0; + } else { + char * res; + + res = _gnutls_bin2hex( value, len, escaped, sizeof(escaped)); + if (res) { + int size = strlen(res) + 1; + if ( size > *sizeof_buf) { + *sizeof_buf = size; + return GNUTLS_E_SHORT_MEMORY_BUFFER; + } + *sizeof_buf = size - 1; + strcpy( buf, res); + + return 0; + } else { + gnutls_assert(); + return GNUTLS_E_INTERNAL_ERROR; + } + } + } + } while (1); + + } while (1); + + gnutls_assert(); + + result = GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; + + cleanup: + return result; +} diff --git a/lib/x509/dn.h b/lib/x509/dn.h index 894b2e90c7..aa48aab0f2 100644 --- a/lib/x509/dn.h +++ b/lib/x509/dn.h @@ -1,3 +1,7 @@ int _gnutls_x509_parse_dn(ASN1_TYPE asn1_struct, const char* asn1_rdn_name, char *buf, int* sizeof_buf); + +int _gnutls_x509_parse_dn_oid(ASN1_TYPE asn1_struct, + const char* asn1_rdn_name, const char* oid, char *buf, + int* sizeof_buf); diff --git a/lib/x509_extensions.c b/lib/x509_extensions.c index 9232a5e741..70bb6fd5f0 100644 --- a/lib/x509_extensions.c +++ b/lib/x509_extensions.c @@ -31,6 +31,7 @@ #include "debug.h" #include <gnutls_str.h> #include <gnutls_x509.h> +#include "x509/common.h" /* This file contains code to parse the X.509 certificate * extensions. Not all the PKIX extensions are supported. diff --git a/lib/x509_xml.c b/lib/x509_xml.c index d7e8cec4e7..4ab99d837d 100644 --- a/lib/x509_xml.c +++ b/lib/x509_xml.c @@ -38,6 +38,7 @@ #include <gnutls_errors.h> #include <gnutls_str.h> #include <gnutls_x509.h> +#include "x509/common.h" static int _gnutls_x509_expand_extensions(ASN1_TYPE* rasn, const char *root); |