From c10891c3ee5a37ba4a1f22d4443cadf8c3240a7b Mon Sep 17 00:00:00 2001 From: Nikos Mavrogiannopoulos Date: Tue, 23 Dec 2003 21:47:11 +0000 Subject: Added support for reading and generating CRL distribution points extensions in certificates (not working yet). --- lib/pkix.asn | 17 ++++++- lib/pkix_asn1_tab.c | 17 ++++++- lib/x509/common.c | 5 +- lib/x509/dsa.c | 5 +- lib/x509/extensions.c | 72 ++++++++++++++++++++++++++++ lib/x509/extensions.h | 2 + lib/x509/x509.c | 130 ++++++++++++++++++++++++++++++++++++++++++++++++-- lib/x509/x509_write.c | 56 ++++++++++++++++++++++ 8 files changed, 295 insertions(+), 9 deletions(-) (limited to 'lib') diff --git a/lib/pkix.asn b/lib/pkix.asn index 01b1e7e940..446f5b5455 100644 --- a/lib/pkix.asn +++ b/lib/pkix.asn @@ -184,7 +184,7 @@ SkipCerts ::= INTEGER (0..MAX) id-ce-cRLDistributionPoints OBJECT IDENTIFIER ::= {id-ce 31} -CRLDistPointsSyntax ::= SEQUENCE SIZE (1..MAX) OF DistributionPoint +CRLDistributionPoints ::= SEQUENCE SIZE (1..MAX) OF DistributionPoint DistributionPoint ::= SEQUENCE { distributionPoint [0] DistributionPointName OPTIONAL, @@ -195,6 +195,21 @@ DistributionPointName ::= CHOICE { fullName [0] GeneralNames, nameRelativeToCRLIssuer [1] RelativeDistinguishedName } +-- Those are used to raw write a fullname. + +WritableCRLDistributionPoints ::= SEQUENCE SIZE (1..MAX) OF WritableDistributionPoint + +WritableDistributionPoint ::= SEQUENCE { + distributionPoint [0] WriteableDistributionPointName OPTIONAL, + reasons [1] ReasonFlags OPTIONAL, + cRLIssuer [2] GeneralNames OPTIONAL } + +WriteableDistributionPointName ::= CHOICE { + fullName [0] ANY, + nameRelativeToCRLIssuer [1] RelativeDistinguishedName } + + + ReasonFlags ::= BIT STRING { diff --git a/lib/pkix_asn1_tab.c b/lib/pkix_asn1_tab.c index 26d8ef9942..c773aba042 100644 --- a/lib/pkix_asn1_tab.c +++ b/lib/pkix_asn1_tab.c @@ -171,7 +171,7 @@ const ASN1_ARRAY_TYPE pkix_asn1_tab[]={ {"id-ce-cRLDistributionPoints",1879048204,0}, {0,1073741825,"id-ce"}, {0,1,"31"}, - {"CRLDistPointsSyntax",1612709899,0}, + {"CRLDistributionPoints",1612709899,0}, {"MAX",1074266122,"1"}, {0,2,"DistributionPoint"}, {"DistributionPoint",1610612741,0}, @@ -186,6 +186,21 @@ const ASN1_ARRAY_TYPE pkix_asn1_tab[]={ {0,4104,"0"}, {"nameRelativeToCRLIssuer",536879106,"RelativeDistinguishedName"}, {0,4104,"1"}, + {"WritableCRLDistributionPoints",1612709899,0}, + {"MAX",1074266122,"1"}, + {0,2,"WritableDistributionPoint"}, + {"WritableDistributionPoint",1610612741,0}, + {"distributionPoint",1610637314,"WriteableDistributionPointName"}, + {0,4104,"0"}, + {"reasons",1610637314,"ReasonFlags"}, + {0,4104,"1"}, + {"cRLIssuer",536895490,"GeneralNames"}, + {0,4104,"2"}, + {"WriteableDistributionPointName",1610612754,0}, + {"fullName",1610620941,0}, + {0,4104,"0"}, + {"nameRelativeToCRLIssuer",536879106,"RelativeDistinguishedName"}, + {0,4104,"1"}, {"ReasonFlags",1610874886,0}, {"unused",1073741825,"0"}, {"keyCompromise",1073741825,"1"}, diff --git a/lib/x509/common.c b/lib/x509/common.c index 4e95651b85..003857a716 100644 --- a/lib/x509/common.c +++ b/lib/x509/common.c @@ -598,12 +598,13 @@ int _gnutls_x509_set_time(ASN1_TYPE c2, const char *where, time_t tim) } -gnutls_x509_subject_alt_name _gnutls_x509_san_find_type( char* str_type) { +gnutls_x509_subject_alt_name _gnutls_x509_san_find_type( char* str_type) +{ if (strcmp( str_type, "dNSName")==0) return GNUTLS_SAN_DNSNAME; if (strcmp( str_type, "rfc822Name")==0) return GNUTLS_SAN_RFC822NAME; if (strcmp( str_type, "uniformResourceIdentifier")==0) return GNUTLS_SAN_URI; if (strcmp( str_type, "iPAddress")==0) return GNUTLS_SAN_IPADDRESS; - return -1; + return (gnutls_x509_subject_alt_name)-1; } /* A generic export function. Will export the given ASN.1 encoded data diff --git a/lib/x509/dsa.c b/lib/x509/dsa.c index b5e35b94da..174c0b31b2 100644 --- a/lib/x509/dsa.c +++ b/lib/x509/dsa.c @@ -35,7 +35,10 @@ int _gnutls_dsa_generate_params(GNUTLS_MPI* resarr, int* resarr_len, int bits) int ret; gcry_sexp_t parms, key, list; - if (bits > 1024) bits = 1024; + if (bits > 1024) { + gnutls_assert(); + return GNUTLS_E_INVALID_REQUEST; + } ret = gcry_sexp_build( &parms, NULL, "(genkey(dsa(nbits %d)))", bits); if (ret != 0) { diff --git a/lib/x509/extensions.c b/lib/x509/extensions.c index d290e95f91..e639e61d0c 100644 --- a/lib/x509/extensions.c +++ b/lib/x509/extensions.c @@ -29,6 +29,7 @@ #include #include #include +#include /* This function will attempt to return the requested extension found in * the given X509v3 certificate. The return value is allocated and stored into @@ -564,3 +565,74 @@ int _gnutls_x509_ext_gen_subject_alt_name(gnutls_x509_subject_alt_name type, return 0; } + +int _gnutls_x509_ext_gen_crl_dist_points(gnutls_x509_subject_alt_name type, + const char* data_string, gnutls_datum* der_ext) +{ + ASN1_TYPE ext = ASN1_TYPE_EMPTY; + gnutls_datum name = {NULL, 0}; + int result; + + result = _gnutls_x509_ext_gen_subject_alt_name( type, data_string, &name); + if (result < 0) { + gnutls_assert(); + return result; + } + + result = asn1_create_element(_gnutls_get_pkix(), "PKIX1.WritableCRLDistributionPoints", &ext); + if (result != ASN1_SUCCESS) { + gnutls_assert(); + result = _gnutls_asn2err(result); + goto cleanup; + } + + result = asn1_write_value( ext, "", "NEW", 1); + if (result != ASN1_SUCCESS) { + gnutls_assert(); + result = _gnutls_asn2err(result); + goto cleanup; + } + + result = asn1_write_value( ext, "?LAST.reasons", NULL, 0); + if (result != ASN1_SUCCESS) { + gnutls_assert(); + result = _gnutls_asn2err(result); + goto cleanup; + } + + result = asn1_write_value( ext, "?LAST.cRLIssuer", NULL, 0); + if (result != ASN1_SUCCESS) { + gnutls_assert(); + result = _gnutls_asn2err(result); + goto cleanup; + } + + result = asn1_write_value( ext, "?LAST.distributionPoint", "fullName", 1); + if (result != ASN1_SUCCESS) { + gnutls_assert(); + result = _gnutls_asn2err(result); + goto cleanup; + } + + result = asn1_write_value( ext, "?LAST.distributionPoint.fullName", name.data, name.size); + if (result != ASN1_SUCCESS) { + gnutls_assert(); + result = _gnutls_asn2err(result); + goto cleanup; + } + + result = _gnutls_x509_der_encode( ext, "", der_ext, 0); + + if (result < 0) { + gnutls_assert(); + goto cleanup; + } + + result = 0; + +cleanup: + _gnutls_free_datum( &name); + asn1_delete_structure(&ext); + + return result; +} diff --git a/lib/x509/extensions.h b/lib/x509/extensions.h index 84ea5752f8..7b90d452ee 100644 --- a/lib/x509/extensions.h +++ b/lib/x509/extensions.h @@ -13,3 +13,5 @@ int _gnutls_x509_ext_gen_basicConstraints(int CA, gnutls_datum* der_ext); int _gnutls_x509_ext_gen_keyUsage(uint16 usage, gnutls_datum* der_ext); int _gnutls_x509_ext_gen_subject_alt_name(gnutls_x509_subject_alt_name type, const char* data_string, gnutls_datum* der_ext); +int _gnutls_x509_ext_gen_crl_dist_points(gnutls_x509_subject_alt_name type, + const char* data_string, gnutls_datum* der_ext); diff --git a/lib/x509/x509.c b/lib/x509/x509.c index fccbd302f6..e2f30adb1a 100644 --- a/lib/x509/x509.c +++ b/lib/x509/x509.c @@ -623,7 +623,6 @@ int gnutls_x509_crt_get_subject_alt_name(gnutls_x509_crt cert, if ((result = _gnutls_x509_crt_get_extension(cert, "2.5.29.17", 0, &dnsname, critical)) < 0) { - gnutls_assert(); return result; } @@ -632,9 +631,9 @@ int gnutls_x509_crt_get_subject_alt_name(gnutls_x509_crt cert, return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; } - if ((result=asn1_create_element - (_gnutls_get_pkix(), "PKIX1.SubjectAltName", &c2)) - != ASN1_SUCCESS) { + result=asn1_create_element + (_gnutls_get_pkix(), "PKIX1.SubjectAltName", &c2); + if (result != ASN1_SUCCESS) { gnutls_assert(); _gnutls_free_datum( &dnsname); return _gnutls_asn2err(result); @@ -1305,4 +1304,127 @@ int result; return result; } +/** + * gnutls_x509_crt_get_crl_dist_points - This function returns the CRL distribution points + * @cert: should contain a gnutls_x509_crt structure + * @seq: specifies the sequence number of the distribution point (0 for the first one, 1 for the second etc.) + * @ret: is the place where the distribution point will be copied to + * @ret_size: holds the size of ret. + * @critical: will be non zero if the extension is marked as critical (may be null) + * + * This function will return the CRL distribution points (2.5.29.31), contained in the + * given certificate. + * + * This is specified in X509v3 Certificate Extensions. GNUTLS will return the + * distribution point type, or a negative error code on error. + * + * Returns GNUTLS_E_SHORT_MEMORY_BUFFER if ret_size is not enough to hold the distribution + * point, or the type of the distribution point if everything was ok. The type is + * one of the enumerated gnutls_x509_subject_alt_name. + * + * 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_crt_get_crl_dist_points(gnutls_x509_crt cert, + unsigned int seq, void *ret, size_t *ret_size, unsigned int *critical) +{ + int result; + gnutls_datum dist_points = {NULL, 0}; + ASN1_TYPE c2 = ASN1_TYPE_EMPTY; + char name[128]; + char ext_data[256]; + int len; + char num[MAX_INT_DIGITS]; + gnutls_x509_subject_alt_name type; + + if (cert==NULL) { + gnutls_assert(); + return GNUTLS_E_INVALID_REQUEST; + } + + if (ret) memset(ret, 0, *ret_size); + else *ret_size = 0; + + result = + _gnutls_x509_crt_get_extension(cert, "2.5.29.31", 0, &dist_points, critical); + if (result < 0) { + gnutls_assert(); + return result; + } + + if (dist_points.size == 0 || dist_points.data==NULL) { + gnutls_assert(); + return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; + } + + result=asn1_create_element + (_gnutls_get_pkix(), "PKIX1.CRLDistributionPoints", &c2); + if (result != ASN1_SUCCESS) { + gnutls_assert(); + _gnutls_free_datum( &dist_points); + return _gnutls_asn2err(result); + } + + result = asn1_der_decoding(&c2, dist_points.data, dist_points.size, NULL); + _gnutls_free_datum( &dist_points); + + if (result != ASN1_SUCCESS) { + /* couldn't decode DER */ + + _gnutls_x509_log("X509 certificate: Decoding error %d\n", result); + gnutls_assert(); + asn1_delete_structure(&c2); + return _gnutls_asn2err(result); + } + + seq++; /* 0->1, 1->2 etc */ + _gnutls_int2str( seq, num); + _gnutls_str_cpy( name, sizeof(name), "dn.?"); + _gnutls_str_cat( name, sizeof(name), num); + _gnutls_str_cat( name, sizeof(name), ".distributionPoint.fullName"); + + len = sizeof(ext_data); + result = + asn1_read_value(c2, name, ext_data, &len); + + if (result == ASN1_VALUE_NOT_FOUND) { + asn1_delete_structure(&c2); + return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; + } + + if (result != ASN1_SUCCESS) { + gnutls_assert(); + asn1_delete_structure(&c2); + return _gnutls_asn2err(result); + } + + type = _gnutls_x509_san_find_type( ext_data); + if (type == (gnutls_x509_subject_alt_name)-1) { + asn1_delete_structure(&c2); + gnutls_assert(); + return GNUTLS_E_X509_UNKNOWN_SAN; + } + + _gnutls_str_cat( name, sizeof(name), "."); + _gnutls_str_cat( name, sizeof(name), ext_data); + + len = *ret_size; + result = + asn1_read_value(c2, name, ret, &len); + asn1_delete_structure(&c2); + + *ret_size = len; + + if (result==ASN1_MEM_ERROR) + return GNUTLS_E_SHORT_MEMORY_BUFFER; + + if (result != ASN1_SUCCESS) { + gnutls_assert(); + return _gnutls_asn2err(result); + } + + return type; +} + #endif diff --git a/lib/x509/x509_write.c b/lib/x509/x509_write.c index 0bd9e9d9df..4ab52ade99 100644 --- a/lib/x509/x509_write.c +++ b/lib/x509/x509_write.c @@ -561,5 +561,61 @@ static void disable_optional_stuff( gnutls_x509_crt cert) return; } +/** + * gnutls_x509_crt_set_crl_dist_points - This function will set the CRL dist points + * @crt: should contain a gnutls_x509_crt structure + * @type: is one of the gnutls_x509_subject_alt_name enumerations + * @data_string: The data to be set + * + * This function will set the CRL distribution points certificate extension. + * + * Returns 0 on success. + * + **/ +int gnutls_x509_crt_set_crl_dist_points(gnutls_x509_crt crt, gnutls_x509_subject_alt_name type, + const char* data_string) +{ +int result; +gnutls_datum der_data; +gnutls_datum oldname; +unsigned int critical; + + if (crt==NULL) { + gnutls_assert(); + return GNUTLS_E_INVALID_REQUEST; + } + + /* Check if the extension already exists. + */ + result = _gnutls_x509_crt_get_extension(crt, "2.5.29.31", 0, &oldname, &critical); + + if (result >= 0) _gnutls_free_datum( &oldname); + if (result != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) { + gnutls_assert(); + return GNUTLS_E_INVALID_REQUEST; + } + + /* generate the extension. + */ + result = _gnutls_x509_ext_gen_crl_dist_points( type, data_string, &der_data); + if (result < 0) { + gnutls_assert(); + return result; + } + + result = _gnutls_x509_crt_set_extension( crt, "2.5.29.31", &der_data, 0); + + _gnutls_free_datum( &der_data); + + if (result < 0) { + gnutls_assert(); + return result; + } + + crt->use_extensions = 1; + + return 0; +} + #endif /* ENABLE_PKI */ -- cgit v1.2.1