diff options
author | Nikos Mavrogiannopoulos <nmav@redhat.com> | 2014-02-13 14:47:14 +0100 |
---|---|---|
committer | Nikos Mavrogiannopoulos <nmav@redhat.com> | 2014-02-17 13:45:28 +0100 |
commit | 40a9a1a450c2b3c045e7b9bfb8f3c3f13715f35d (patch) | |
tree | 9533d5642dc4eb3e005187ee841b2b4854a3a6f6 /lib/x509 | |
parent | 4b4b7bf4614c9ad3dc553d385004f07da8becf9d (diff) | |
download | gnutls-40a9a1a450c2b3c045e7b9bfb8f3c3f13715f35d.tar.gz |
Added support for name constraints X.509 extension.
This allows to generate and read the name constraints extension,
as well as check against the DNSNAME value.
Diffstat (limited to 'lib/x509')
-rw-r--r-- | lib/x509/Makefile.am | 1 | ||||
-rw-r--r-- | lib/x509/extensions.c | 53 | ||||
-rw-r--r-- | lib/x509/name_constraints.c | 641 | ||||
-rw-r--r-- | lib/x509/output.c | 78 | ||||
-rw-r--r-- | lib/x509/x509.c | 21 | ||||
-rw-r--r-- | lib/x509/x509_int.h | 5 |
6 files changed, 775 insertions, 24 deletions
diff --git a/lib/x509/Makefile.am b/lib/x509/Makefile.am index 4fc657969b..b2e5a17a48 100644 --- a/lib/x509/Makefile.am +++ b/lib/x509/Makefile.am @@ -56,6 +56,7 @@ libgnutls_x509_la_SOURCES = \ x509.c x509_dn.c \ x509_int.h \ x509_write.c \ + name_constraints.c \ verify-high.c \ verify-high2.c \ verify-high.h diff --git a/lib/x509/extensions.c b/lib/x509/extensions.c index 4748421b68..5b2da0e38c 100644 --- a/lib/x509/extensions.c +++ b/lib/x509/extensions.c @@ -820,8 +820,8 @@ int _gnutls_x509_ext_gen_keyUsage(uint16_t usage, gnutls_datum_t * der_ext) return 0; } -static int -write_new_general_name(ASN1_TYPE ext, const char *ext_name, +int +_gnutls_write_general_name(ASN1_TYPE ext, const char *ext_name, gnutls_x509_subject_alt_name_t type, const void *data, unsigned int data_size) { @@ -829,12 +829,6 @@ write_new_general_name(ASN1_TYPE ext, const char *ext_name, int result; char name[128]; - result = asn1_write_value(ext, ext_name, "NEW", 1); - if (result != ASN1_SUCCESS) { - gnutls_assert(); - return _gnutls_asn2err(result); - } - switch (type) { case GNUTLS_SAN_DNSNAME: str = "dNSName"; @@ -853,21 +847,13 @@ write_new_general_name(ASN1_TYPE ext, const char *ext_name, return GNUTLS_E_INTERNAL_ERROR; } - if (ext_name[0] == 0) { /* no dot */ - _gnutls_str_cpy(name, sizeof(name), "?LAST"); - } else { - _gnutls_str_cpy(name, sizeof(name), ext_name); - _gnutls_str_cat(name, sizeof(name), ".?LAST"); - } - - result = asn1_write_value(ext, name, str, 1); + result = asn1_write_value(ext, ext_name, str, 1); if (result != ASN1_SUCCESS) { gnutls_assert(); return _gnutls_asn2err(result); } - _gnutls_str_cat(name, sizeof(name), "."); - _gnutls_str_cat(name, sizeof(name), str); + snprintf(name, sizeof(name), "%s.%s", ext_name, str); result = asn1_write_value(ext, name, data, data_size); if (result != ASN1_SUCCESS) { @@ -879,6 +865,37 @@ write_new_general_name(ASN1_TYPE ext, const char *ext_name, return 0; } +static int +write_new_general_name(ASN1_TYPE ext, const char *ext_name, + gnutls_x509_subject_alt_name_t type, + const void *data, unsigned int data_size) +{ + int result; + char name[128]; + + result = asn1_write_value(ext, ext_name, "NEW", 1); + if (result != ASN1_SUCCESS) { + gnutls_assert(); + return _gnutls_asn2err(result); + } + + if (ext_name[0] == 0) { /* no dot */ + _gnutls_str_cpy(name, sizeof(name), "?LAST"); + } else { + _gnutls_str_cpy(name, sizeof(name), ext_name); + _gnutls_str_cat(name, sizeof(name), ".?LAST"); + } + + result = _gnutls_write_general_name(ext, name, type, + data, data_size); + if (result < 0) { + gnutls_assert(); + return result; + } + + return 0; +} + /* Convert the given name to GeneralNames in a DER encoded extension. * This is the same as subject alternative name. */ diff --git a/lib/x509/name_constraints.c b/lib/x509/name_constraints.c new file mode 100644 index 0000000000..bdcfdefaf9 --- /dev/null +++ b/lib/x509/name_constraints.c @@ -0,0 +1,641 @@ +/* + * Copyright (C) 2014 Free Software Foundation, Inc. + * + * This file is part of GnuTLS. + * + * The GnuTLS 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 program. If not, see <http://www.gnu.org/licenses/> + * + */ + +/* Functions on X.509 Certificate parsing + */ + +#include <gnutls_int.h> +#include <gnutls_datum.h> +#include <gnutls_global.h> +#include <gnutls_errors.h> +#include <common.h> +#include <gnutls_x509.h> +#include <x509_b64.h> +#include <x509_int.h> +#include <libtasn1.h> + +/* Name constraints is limited to DNS names. + */ +typedef struct gnutls_name_constraints_st { + struct name_constraints_node_st * permitted; + struct name_constraints_node_st * excluded; +} gnutls_name_constraints_st; + +typedef struct name_constraints_node_st { + unsigned type; + gnutls_datum_t name; + struct name_constraints_node_st *next; +} name_constraints_node_st; + +static int extract_name_constraints(ASN1_TYPE c2, const char *vstr, + name_constraints_node_st ** _nc) +{ + int ret; + char tmpstr[128]; + unsigned indx = 0; + gnutls_datum_t tmp = { NULL, 0 }; + unsigned int type; + struct name_constraints_node_st *nc, *prev; + + nc = prev = *_nc; + + do { + indx++; + snprintf(tmpstr, sizeof(tmpstr), "%s.?%u.base", vstr, indx); + + ret = + _gnutls_parse_general_name2(c2, tmpstr, -1, &tmp, &type, 0); + + if (ret < 0) + break; + + if (type != GNUTLS_SAN_DNSNAME && type != GNUTLS_SAN_RFC822NAME + && type != GNUTLS_SAN_DN && type != GNUTLS_SAN_URI) { + gnutls_assert(); + ret = GNUTLS_E_ILLEGAL_PARAMETER; + goto cleanup; + } + + nc = gnutls_malloc(sizeof(struct name_constraints_node_st)); + if (nc == NULL) { + gnutls_assert(); + ret = GNUTLS_E_MEMORY_ERROR; + goto cleanup; + } + + memcpy(&nc->name, &tmp, sizeof(gnutls_datum_t)); + nc->type = type; + nc->next = NULL; + + if (prev == NULL) { + *_nc = prev = nc; + } else { + prev->next = nc; + prev = nc; + } + + tmp.data = NULL; + } while (ret >= 0); + + if (ret < 0 && ret != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) { + gnutls_assert(); + goto cleanup; + } + + ret = 0; + cleanup: + if (ret < 0) { + nc = *_nc; + while (nc != NULL) { + prev = nc->next; + free(nc->name.data); + free(nc); + nc = prev; + } + *_nc = NULL; + } + gnutls_free(tmp.data); + return ret; +} + +/** + * gnutls_x509_crt_get_name_constraints: + * @crt: should contain a #gnutls_x509_crt_t structure + * @nc: The nameconstraints intermediate structure + * @critical: the extension status + * + * This function will return an intermediate structure containing + * the name constraints of the provided CA certificate. That + * structure can be used in combination with gnutls_x509_name_constraints_check() + * to verify whether a server's name is in accordance with the constraints. + * + * Note that @nc must be initialized prior to calling this function. + * + * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, %GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE + * if the extension is not present, otherwise a negative error value. + * + * Since: 3.3.0 + **/ +int gnutls_x509_crt_get_name_constraints(gnutls_x509_crt_t crt, + gnutls_x509_name_constraints_t nc, + unsigned int *critical) +{ + int result, ret; + gnutls_datum_t der = { NULL, 0 }; + ASN1_TYPE c2 = ASN1_TYPE_EMPTY; + + if (crt == NULL) { + gnutls_assert(); + return GNUTLS_E_INVALID_REQUEST; + } + + ret = + _gnutls_x509_crt_get_extension(crt, "2.5.29.30", 0, &der, + critical); + if (ret < 0) + return gnutls_assert_val(ret); + + if (der.size == 0 || der.data == NULL) + return gnutls_assert_val(GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE); + + result = asn1_create_element + (_gnutls_get_pkix(), "PKIX1.NameConstraints", &c2); + if (result != ASN1_SUCCESS) { + gnutls_assert(); + ret = _gnutls_asn2err(result); + goto cleanup; + } + + result = asn1_der_decoding(&c2, der.data, der.size, NULL); + if (result != ASN1_SUCCESS) { + gnutls_assert(); + ret = _gnutls_asn2err(result); + goto cleanup; + } + + ret = extract_name_constraints(c2, "permittedSubtrees", &nc->permitted); + if (ret < 0) { + gnutls_assert(); + goto cleanup; + } + + ret = extract_name_constraints(c2, "excludedSubtrees", &nc->excluded); + if (ret < 0) { + gnutls_assert(); + goto cleanup; + } + + ret = 0; + + cleanup: + _gnutls_free_datum(&der); + asn1_delete_structure(&c2); + + return ret; + +} + +/** + * gnutls_x509_name_constraints_deinit: + * @nc: The nameconstraints structure + * + * This function will deinitialize a name constraints structure. + * + * Since: 3.3.0 + **/ +void gnutls_x509_name_constraints_deinit(gnutls_x509_name_constraints_t nc) +{ + name_constraints_node_st * next, *t; + + t = nc->permitted; + while (t != NULL) { + next = t->next; + free(t->name.data); + free(t); + t = next; + } + + t = nc->excluded; + while (t != NULL) { + next = t->next; + free(t->name.data); + free(t); + t = next; + } +} + +/** + * gnutls_x509_name_constraints_init: + * @nc: The nameconstraints structure + * + * This function will initialize a name constraints structure. + * + * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a negative error value. + * + * Since: 3.3.0 + **/ +int gnutls_x509_name_constraints_init(gnutls_x509_name_constraints_t *nc) +{ + *nc = gnutls_calloc(1, sizeof(struct gnutls_name_constraints_st)); + if (*nc == NULL) { + gnutls_assert(); + return GNUTLS_E_MEMORY_ERROR; + } + + return 0; +} + +static +int name_constraints_add(gnutls_x509_name_constraints_t nc, + gnutls_x509_subject_alt_name_t type, + const gnutls_datum_t * name, + unsigned permitted) +{ + struct name_constraints_node_st * tmp, *prev = NULL; + int ret; + + if (type != GNUTLS_SAN_DNSNAME && type != GNUTLS_SAN_RFC822NAME && + type != GNUTLS_SAN_DN && type != GNUTLS_SAN_URI) + return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); + + if (type == GNUTLS_SAN_DNSNAME && name->size > 0 && name->data[0] == '.') { + _gnutls_debug_log("DNSNAME constraints cannot start with '.'. They must contain a domain name\n"); + return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); + } + + if (permitted != 0) + prev = tmp = nc->permitted; + else + prev = tmp = nc->excluded; + + while(tmp != NULL) { + tmp = tmp->next; + if (tmp != NULL) + prev = tmp; + } + + tmp = gnutls_malloc(sizeof(struct name_constraints_node_st)); + if (tmp == NULL) + return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); + + tmp->next = NULL; + tmp->type = type; + ret = _gnutls_set_datum(&tmp->name, name->data, name->size); + if (ret < 0) { + gnutls_assert(); + gnutls_free(tmp); + return ret; + } + + if (prev == NULL) { + if (permitted != 0) + nc->permitted = tmp; + else + nc->excluded = tmp; + } else + prev->next = tmp; + + return 0; +} + +/** + * gnutls_x509_name_constraints_add_permitted: + * @nc: The nameconstraints structure + * @type: The type of the constraints + * @name: The data of the constraints + * + * This function will add a name constraint to the list of permitted + * constraints. + * + * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a negative error value. + * + * Since: 3.3.0 + **/ +int gnutls_x509_name_constraints_add_permitted(gnutls_x509_name_constraints_t nc, + gnutls_x509_subject_alt_name_t type, + const gnutls_datum_t * name) +{ + return name_constraints_add(nc, type, name, 1); +} + +/** + * gnutls_x509_name_constraints_add_excluded: + * @nc: The nameconstraints structure + * @type: The type of the constraints + * @name: The data of the constraints + * + * This function will add a name constraint to the list of excluded + * constraints. + * + * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a negative error value. + * + * Since: 3.3.0 + **/ +int gnutls_x509_name_constraints_add_excluded(gnutls_x509_name_constraints_t nc, + gnutls_x509_subject_alt_name_t type, + const gnutls_datum_t * name) +{ + return name_constraints_add(nc, type, name, 0); +} + +/** + * gnutls_x509_crt_set_name_constraints: + * @crt: The certificate structure + * @nc: The nameconstraints structure + * + * This function will set the provided name constraints to + * the certificate extension list. This extension is always + * marked as critical. + * + * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a negative error value. + * + * Since: 3.3.0 + **/ +int gnutls_x509_crt_set_name_constraints(gnutls_x509_crt_t crt, + gnutls_x509_name_constraints_t nc) +{ +int ret, result; +gnutls_datum_t der_data; +uint8_t null = 0; +ASN1_TYPE c2 = ASN1_TYPE_EMPTY; +struct name_constraints_node_st * tmp; + + if (nc->permitted == NULL && nc->excluded == NULL) + return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); + + result = asn1_create_element + (_gnutls_get_pkix(), "PKIX1.NameConstraints", &c2); + if (result != ASN1_SUCCESS) { + gnutls_assert(); + return _gnutls_asn2err(result); + } + + if (nc->permitted == NULL) { + asn1_write_value(c2, "permittedSubtrees", NULL, 0); + } else { + tmp = nc->permitted; + do { + result = asn1_write_value(c2, "permittedSubtrees", "NEW", 1); + if (result != ASN1_SUCCESS) { + gnutls_assert(); + ret = _gnutls_asn2err(result); + goto cleanup; + } + + result = asn1_write_value(c2, "permittedSubtrees.?LAST.maximum", NULL, 0); + if (result != ASN1_SUCCESS) { + gnutls_assert(); + ret = _gnutls_asn2err(result); + goto cleanup; + } + + result = asn1_write_value(c2, "permittedSubtrees.?LAST.minimum", &null, 1); + if (result != ASN1_SUCCESS) { + gnutls_assert(); + ret = _gnutls_asn2err(result); + goto cleanup; + } + + ret = _gnutls_write_general_name(c2, "permittedSubtrees.?LAST.base", + tmp->type, tmp->name.data, tmp->name.size); + if (ret < 0) { + gnutls_assert(); + goto cleanup; + } + tmp = tmp->next; + } while(tmp != NULL); + } + + if (nc->excluded == NULL) { + asn1_write_value(c2, "excludedSubtrees", NULL, 0); + } else { + tmp = nc->excluded; + do { + result = asn1_write_value(c2, "excludedSubtrees", "NEW", 1); + if (result != ASN1_SUCCESS) { + gnutls_assert(); + ret = _gnutls_asn2err(result); + goto cleanup; + } + + result = asn1_write_value(c2, "excludedSubtrees.?LAST.maximum", NULL, 0); + if (result != ASN1_SUCCESS) { + gnutls_assert(); + ret = _gnutls_asn2err(result); + goto cleanup; + } + + result = asn1_write_value(c2, "excludedSubtrees.?LAST.minimum", &null, 1); + if (result != ASN1_SUCCESS) { + gnutls_assert(); + ret = _gnutls_asn2err(result); + goto cleanup; + } + + ret = _gnutls_write_general_name(c2, "excludedSubtrees.?LAST.base", + tmp->type, tmp->name.data, tmp->name.size); + if (ret < 0) { + gnutls_assert(); + goto cleanup; + } + tmp = tmp->next; + } while(tmp != NULL); + + } + + ret = _gnutls_x509_der_encode(c2, "", &der_data, 0); + if (ret < 0) { + gnutls_assert(); + goto cleanup; + } + + ret = + _gnutls_x509_crt_set_extension(crt, "2.5.29.30", &der_data, 1); + + _gnutls_free_datum(&der_data); + + if (ret < 0) { + gnutls_assert(); + goto cleanup; + } + + ret = 0; + crt->use_extensions = 1; + +cleanup: + asn1_delete_structure(&c2); + return ret; + +} + +static +unsigned ends_with(const gnutls_datum_t * str, const gnutls_datum_t * suffix) +{ + if (suffix->size >= str->size) + return 0; + + if (memcmp(str->data + str->size - suffix->size, suffix->data, suffix->size) == 0 && + str->data[str->size - suffix->size -1] == '.') + return 1; + + return 0; +} + +static unsigned dnsname_matches(const gnutls_datum_t *name, const gnutls_datum_t *suffix) +{ + _gnutls_hard_log("matching %.*s with constraint %.*s\n", name->size, name->data, + suffix->size, suffix->data); + + if (suffix->size == name->size && memcmp(suffix->data, name->data, suffix->size) == 0) + return 1; /* match */ + + return ends_with(name, suffix); +} + +/** + * gnutls_x509_name_constraints_check: + * @nc: the extracted name constraints structure + * @type: the type of the constraint to check (of type gnutls_x509_subject_alt_name_t) + * @name: the name to be checked + * + * This function will check the provided name against the constraints in + * @nc using the RFC5280 rules. Currently this function is limited to DNS + * names (of type %GNUTLS_SAN_DNSNAME). + * + * Returns: zero if the provided name is not acceptable, and non-zero otherwise. + * + * Since: 3.3.0 + **/ +unsigned gnutls_x509_name_constraints_check(gnutls_x509_name_constraints_t nc, + gnutls_x509_subject_alt_name_t type, + const gnutls_datum_t * name) +{ +unsigned i; +int ret; +unsigned rtype; +unsigned allowed_found = 0; +gnutls_datum_t rname; + + if (type != GNUTLS_SAN_DNSNAME) + return gnutls_assert_val(0); + + /* check restrictions */ + i = 0; + do { + ret = gnutls_x509_name_constraints_get_excluded(nc, i++, &rtype, &rname); + if (ret >= 0 && rtype != type) + continue; + + if (rname.size == 0) + continue; + + if (dnsname_matches(name, &rname) != 0) + return gnutls_assert_val(0); /* rejected */ + } while(ret == 0); + + /* check allowed */ + i = 0; + do { + ret = gnutls_x509_name_constraints_get_permitted(nc, i++, &rtype, &rname); + if (ret >= 0 && rtype != type) + continue; + + if (rname.size == 0) + continue; + + allowed_found = 1; + + if (dnsname_matches(name, &rname) != 0) + return 1; /* accepted */ + } while(ret == 0); + + if (allowed_found != 0) /* there are allowed directives but this host wasn't found */ + return gnutls_assert_val(0); + + return 1; +} + +/** + * gnutls_x509_name_constraints_get_permitted: + * @nc: the extracted name constraints structure + * @idx: the index of the constraint + * @type: the type of the constraint (of type gnutls_x509_subject_alt_name_t) + * @name: the name in the constraint (of the specific type) + * + * This function will return an intermediate structure containing + * the name constraints of the provided CA certificate. That + * structure can be used in combination with gnutls_x509_name_constraints_check() + * to verify whether a server's name is in accordance with the constraints. + * + * The name should be treated as constant and valid for the lifetime of @nc. + * + * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, %GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE + * if the extension is not present, otherwise a negative error value. + * + * Since: 3.3.0 + **/ +int gnutls_x509_name_constraints_get_permitted(gnutls_x509_name_constraints_t nc, + unsigned idx, + unsigned *type, gnutls_datum_t * name) +{ + unsigned int i; + struct name_constraints_node_st * tmp = nc->permitted; + + for (i = 0; i < idx; i++) { + if (tmp == NULL) + return + gnutls_assert_val + (GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE); + + tmp = tmp->next; + } + + if (tmp == NULL) + return gnutls_assert_val(GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE); + + *type = tmp->type; + *name = tmp->name; + + return 0; +} + +/** + * gnutls_x509_name_constraints_get_excluded: + * @nc: the extracted name constraints structure + * @idx: the index of the constraint + * @type: the type of the constraint (of type gnutls_x509_subject_alt_name_t) + * @name: the name in the constraint (of the specific type) + * + * This function will return an intermediate structure containing + * the name constraints of the provided CA certificate. That + * structure can be used in combination with gnutls_x509_name_constraints_check() + * to verify whether a server's name is in accordance with the constraints. + * + * The name should be treated as constant and valid for the lifetime of @nc. + * + * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, %GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE + * if the extension is not present, otherwise a negative error value. + * + * Since: 3.3.0 + **/ +int gnutls_x509_name_constraints_get_excluded(gnutls_x509_name_constraints_t nc, + unsigned idx, + unsigned *type, gnutls_datum_t * name) +{ + unsigned int i; + struct name_constraints_node_st * tmp = nc->excluded; + + for (i = 0; i < idx; i++) { + if (tmp == NULL) + return + gnutls_assert_val + (GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE); + + tmp = tmp->next; + } + + if (tmp == NULL) + return gnutls_assert_val(GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE); + + *type = tmp->type; + *name = tmp->name; + + return 0; +} diff --git a/lib/x509/output.c b/lib/x509/output.c index f88b1a802d..fd3fd1a72e 100644 --- a/lib/x509/output.c +++ b/lib/x509/output.c @@ -158,6 +158,69 @@ static void print_proxy(gnutls_buffer_st * str, gnutls_x509_crt_t cert) } } +static void print_nc(gnutls_buffer_st * str, const char* prefix, gnutls_x509_crt_t cert) +{ + gnutls_x509_name_constraints_t nc; + int ret; + unsigned critical, idx = 0; + gnutls_datum_t name; + unsigned type; + + ret = gnutls_x509_name_constraints_init(&nc); + if (ret < 0) + return; + + ret = gnutls_x509_crt_get_name_constraints(cert, nc, &critical); + if (ret < 0) + goto cleanup; + + do { + ret = gnutls_x509_name_constraints_get_permitted(nc, idx++, &type, &name); + + if (ret >= 0) { + if (idx == 1) + addf(str, _("%s\t\t\tPermitted:\n"), prefix); + + if (type == GNUTLS_SAN_DNSNAME) { + addf(str, _("%s\t\t\tDNSname:%s\n"), prefix, name.data); + } else if (type == GNUTLS_SAN_RFC822NAME) { + addf(str, _("%s\t\t\tRFC822Name:%s\n"), prefix, name.data); + } else if (type == GNUTLS_SAN_URI) { + addf(str, _("%s\t\t\tURI:%s\n"), prefix, name.data); + } else if (type == GNUTLS_SAN_DN) { + addf(str, _("%s\t\t\tdirectoryName:"), prefix); + _gnutls_buffer_hexprint(str, name.data, name.size); + adds(str, _(" \n")); + } + } + } while (ret == 0); + + idx = 0; + do { + ret = gnutls_x509_name_constraints_get_excluded(nc, idx++, &type, &name); + + if (ret >= 0) { + if (idx == 1) + addf(str, _("%s\t\t\tExcluded:\n"), prefix); + + if (type == GNUTLS_SAN_DNSNAME) { + addf(str, _("%s\t\t\tDNSname:%s\n"), prefix, name.data); + } else if (type == GNUTLS_SAN_RFC822NAME) { + addf(str, _("%s\t\t\tRFC822Name:%s\n"), prefix, name.data); + } else if (type == GNUTLS_SAN_URI) { + addf(str, _("%s\t\t\tURI:%s\n"), prefix, name.data); + } else if (type == GNUTLS_SAN_DN) { + addf(str, _("%s\t\t\tdirectoryName:"), prefix); + _gnutls_buffer_hexprint(str, name.data, name.size); + adds(str, _(" \n")); + } + } + } while (ret == 0); + +cleanup: + gnutls_x509_name_constraints_deinit(nc); +} + static void print_aia(gnutls_buffer_st * str, gnutls_x509_crt_t cert) { int err; @@ -982,7 +1045,7 @@ print_extensions(gnutls_buffer_st * str, const char *prefix, int type, int keyusage_idx = 0; int keypurpose_idx = 0; int ski_idx = 0; - int aki_idx = 0; + int aki_idx = 0, nc_idx = 0; int crldist_idx = 0, pkey_usage_period_idx = 0; char pfx[16]; @@ -1225,6 +1288,19 @@ print_extensions(gnutls_buffer_st * str, const char *prefix, int type, if (type == TYPE_CRT) print_aia(str, cert.crt); + } else if (strcmp(oid, "2.5.29.30") == 0) { + if (nc_idx) { + addf(str, + "error: more than one name constraints extension\n"); + continue; + } + nc_idx++; + + addf(str, _("%s\t\tName Constraints (%s):\n"), prefix, + critical ? _("critical") : _("not critical")); + + if (type == TYPE_CRT) + print_nc(str, prefix, cert.crt); } else { char *buffer; size_t extlen = 0; diff --git a/lib/x509/x509.c b/lib/x509/x509.c index cf9afa5554..24722cff2b 100644 --- a/lib/x509/x509.c +++ b/lib/x509/x509.c @@ -1108,6 +1108,13 @@ inline static int is_type_printable(int type) /* returns the type and the name on success. * Type is also returned as a parameter in case of an error. + * + * @seq: in case of GeneralNames it will return the corresponding name. + * in case of GeneralName, it must be -1 + * @dname: the name returned + * @ret_type: The type of the name + * @othername_oid: if the name is AnotherName return the OID + * */ int _gnutls_parse_general_name2(ASN1_TYPE src, const char *src_name, @@ -1121,12 +1128,16 @@ _gnutls_parse_general_name2(ASN1_TYPE src, const char *src_name, char choice_type[128]; gnutls_x509_subject_alt_name_t type; - seq++; /* 0->1, 1->2 etc */ + if (seq != -1) { + seq++; /* 0->1, 1->2 etc */ - if (src_name[0] != 0) - snprintf(nptr, sizeof(nptr), "%s.?%u", src_name, seq); - else - snprintf(nptr, sizeof(nptr), "?%u", seq); + if (src_name[0] != 0) + snprintf(nptr, sizeof(nptr), "%s.?%u", src_name, seq); + else + snprintf(nptr, sizeof(nptr), "?%u", seq); + } else { + snprintf(nptr, sizeof(nptr), "%s", src_name); + } len = sizeof(choice_type); result = asn1_read_value(src, nptr, choice_type, &len); diff --git a/lib/x509/x509_int.h b/lib/x509/x509_int.h index ae3871c779..0389de8133 100644 --- a/lib/x509/x509_int.h +++ b/lib/x509/x509_int.h @@ -215,6 +215,11 @@ _gnutls_x509_ext_gen_number(const uint8_t * nuber, size_t nr_size, gnutls_datum_t * der_ext); +int +_gnutls_write_general_name(ASN1_TYPE ext, const char *ext_name, + gnutls_x509_subject_alt_name_t type, + const void *data, unsigned int data_size); + int _gnutls_x509_ext_gen_basicConstraints(int CA, int pathLenConstraint, gnutls_datum_t * der_ext); int _gnutls_x509_ext_gen_keyUsage(uint16_t usage, |