diff options
author | Nikos Mavrogiannopoulos <nmav@gnutls.org> | 2017-02-02 22:59:43 +0100 |
---|---|---|
committer | Nikos Mavrogiannopoulos <nmav@redhat.com> | 2017-02-05 07:38:15 +0100 |
commit | 1a5e67d6bd80afe75ec78b3e9a002ae1130ca089 (patch) | |
tree | e0ae79a5a22821f27efc01defc3e46f7bc88d102 | |
parent | 020d7553ea83e903929afaa61560f432285d7315 (diff) | |
download | gnutls-1a5e67d6bd80afe75ec78b3e9a002ae1130ca089.tar.gz |
x509: optimize subject alternative name accesstmp-san-parsing-optimization
That reads SAN and IAN early on import, significantly reducing
the running time of functions which iterate over the alternative
names of a certificate, e.g., gnutls_x509_crt_check_hostname().
Relates #165
Signed-off-by: Nikos Mavrogiannopoulos <nmav@gnutls.org>
-rw-r--r-- | lib/x509/x509.c | 138 | ||||
-rw-r--r-- | lib/x509/x509_int.h | 4 | ||||
-rw-r--r-- | tests/certs-interesting/cert5.der.err | 1 |
3 files changed, 96 insertions, 47 deletions
diff --git a/lib/x509/x509.c b/lib/x509/x509.c index 043d38b479..3f2e0b1a57 100644 --- a/lib/x509/x509.c +++ b/lib/x509/x509.c @@ -58,6 +58,20 @@ static int crt_reinit(gnutls_x509_crt_t crt) return result; } + gnutls_subject_alt_names_deinit(crt->san); + result = gnutls_subject_alt_names_init(&crt->san); + if (result < 0) { + gnutls_assert(); + return result; + } + + gnutls_subject_alt_names_deinit(crt->ian); + result = gnutls_subject_alt_names_init(&crt->ian); + if (result < 0) { + gnutls_assert(); + return result; + } + return 0; } @@ -179,12 +193,12 @@ gnutls_x509_crt_equals2(gnutls_x509_crt_t cert1, int gnutls_x509_crt_init(gnutls_x509_crt_t * cert) { gnutls_x509_crt_t tmp; + int result; FAIL_IF_LIB_ERROR; tmp = gnutls_calloc(1, sizeof(gnutls_x509_crt_int)); - int result; if (!tmp) return GNUTLS_E_MEMORY_ERROR; @@ -197,6 +211,23 @@ int gnutls_x509_crt_init(gnutls_x509_crt_t * cert) return _gnutls_asn2err(result); } + result = gnutls_subject_alt_names_init(&tmp->san); + if (result < 0) { + gnutls_assert(); + asn1_delete_structure(&tmp->cert); + gnutls_free(tmp); + return result; + } + + result = gnutls_subject_alt_names_init(&tmp->ian); + if (result < 0) { + gnutls_assert(); + asn1_delete_structure(&tmp->cert); + gnutls_free(tmp); + gnutls_subject_alt_names_deinit(tmp->san); + return result; + } + /* If you add anything here, be sure to check if it has to be added to gnutls_x509_crt_import as well. */ @@ -259,6 +290,8 @@ void gnutls_x509_crt_deinit(gnutls_x509_crt_t cert) if (cert->cert) asn1_delete_structure(&cert->cert); gnutls_free(cert->der.data); + gnutls_subject_alt_names_deinit(cert->san); + gnutls_subject_alt_names_deinit(cert->ian); gnutls_free(cert); } @@ -327,6 +360,39 @@ static int compare_sig_algorithm(gnutls_x509_crt_t cert) return ret; } +static int cache_alt_names(gnutls_x509_crt_t cert) +{ + gnutls_datum_t tmpder = {NULL, 0}; + int ret; + + /* pre-parse subject alt name */ + ret = _gnutls_x509_crt_get_extension(cert, "2.5.29.17", 0, &tmpder, NULL); + if (ret < 0 && ret != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) { + gnutls_free(tmpder.data); + return gnutls_assert_val(ret); + } + + if (ret >= 0) { + ret = gnutls_x509_ext_import_subject_alt_names(&tmpder, cert->san, 0); + gnutls_free(tmpder.data); + tmpder.data = NULL; + if (ret < 0) + return gnutls_assert_val(ret); + } + + ret = _gnutls_x509_crt_get_extension(cert, "2.5.29.18", 0, &tmpder, NULL); + if (ret < 0 && ret != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) + return gnutls_assert_val(ret); + + if (ret >= 0) { + ret = gnutls_x509_ext_import_subject_alt_names(&tmpder, cert->ian, 0); + gnutls_free(tmpder.data); + if (ret < 0) + return gnutls_assert_val(ret); + } + + return 0; +} /** * gnutls_x509_crt_import: * @cert: The data to store the parsed certificate. @@ -437,6 +503,12 @@ gnutls_x509_crt_import(gnutls_x509_crt_t cert, goto cleanup; } + result = cache_alt_names(cert); + if (result < 0) { + gnutls_assert(); + goto cleanup; + } + /* enforce the rule that only version 3 certificates carry extensions */ result = gnutls_x509_crt_get_version(cert); if (result < 0) { @@ -1605,50 +1677,26 @@ cleanup: } static int -get_alt_name(gnutls_x509_crt_t cert, const char *extension_id, +get_alt_name(gnutls_subject_alt_names_t san, unsigned int seq, uint8_t *alt, size_t * alt_size, unsigned int *alt_type, unsigned int *critical, int othername_oid) { int ret; - gnutls_datum_t dnsname = {NULL, 0}; gnutls_datum_t ooid = {NULL, 0}; - gnutls_datum_t res; - gnutls_subject_alt_names_t sans = NULL; + gnutls_datum_t oname; + gnutls_datum_t virt = {NULL, 0}; unsigned int type; - if (cert == NULL) { + if (san == NULL) { gnutls_assert(); - return GNUTLS_E_INVALID_REQUEST; + return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; } if (alt == NULL) *alt_size = 0; - if ((ret = - _gnutls_x509_crt_get_extension(cert, extension_id, 0, - &dnsname, critical)) < 0) { - return ret; - } - - if (dnsname.size == 0 || dnsname.data == NULL) { - gnutls_assert(); - return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; - } - - ret = gnutls_subject_alt_names_init(&sans); - if (ret < 0) { - gnutls_assert(); - goto cleanup; - } - - ret = gnutls_x509_ext_import_subject_alt_names(&dnsname, sans, 0); - if (ret < 0) { - gnutls_assert(); - goto cleanup; - } - - ret = gnutls_subject_alt_names_get(sans, seq, &type, &res, &ooid); + ret = gnutls_subject_alt_names_get(san, seq, &type, &oname, &ooid); if (ret < 0) { gnutls_assert(); goto cleanup; @@ -1656,13 +1704,11 @@ get_alt_name(gnutls_x509_crt_t cert, const char *extension_id, if (othername_oid && type == GNUTLS_SAN_OTHERNAME) { unsigned vtype; - gnutls_datum_t virt; - ret = gnutls_x509_othername_to_virtual((char*)ooid.data, &res, &vtype, &virt); + ret = gnutls_x509_othername_to_virtual((char*)ooid.data, &oname, &vtype, &virt); if (ret >= 0) { type = vtype; - gnutls_free(res.data); - res.data = virt.data; - res.size = virt.size; + oname.data = virt.data; + oname.size = virt.size; } } @@ -1673,9 +1719,9 @@ get_alt_name(gnutls_x509_crt_t cert, const char *extension_id, ret = _gnutls_copy_string(&ooid, alt, alt_size); } else { if (is_type_printable(type)) { - ret = _gnutls_copy_string(&res, alt, alt_size); + ret = _gnutls_copy_string(&oname, alt, alt_size); } else { - ret = _gnutls_copy_data(&res, alt, alt_size); + ret = _gnutls_copy_data(&oname, alt, alt_size); } } @@ -1686,9 +1732,7 @@ get_alt_name(gnutls_x509_crt_t cert, const char *extension_id, ret = type; cleanup: - gnutls_free(dnsname.data); - if (sans != NULL) - gnutls_subject_alt_names_deinit(sans); + gnutls_free(virt.data); return ret; } @@ -1729,7 +1773,7 @@ gnutls_x509_crt_get_subject_alt_name(gnutls_x509_crt_t cert, size_t * san_size, unsigned int *critical) { - return get_alt_name(cert, "2.5.29.17", seq, san, san_size, NULL, + return get_alt_name(cert->san, seq, san, san_size, NULL, critical, 0); } @@ -1772,7 +1816,7 @@ gnutls_x509_crt_get_issuer_alt_name(gnutls_x509_crt_t cert, size_t * ian_size, unsigned int *critical) { - return get_alt_name(cert, "2.5.29.18", seq, ian, ian_size, NULL, + return get_alt_name(cert->ian, seq, ian, ian_size, NULL, critical, 0); } @@ -1807,7 +1851,7 @@ gnutls_x509_crt_get_subject_alt_name2(gnutls_x509_crt_t cert, unsigned int *san_type, unsigned int *critical) { - return get_alt_name(cert, "2.5.29.17", seq, san, san_size, + return get_alt_name(cert->san, seq, san, san_size, san_type, critical, 0); } @@ -1845,7 +1889,7 @@ gnutls_x509_crt_get_issuer_alt_name2(gnutls_x509_crt_t cert, unsigned int *ian_type, unsigned int *critical) { - return get_alt_name(cert, "2.5.29.18", seq, ian, ian_size, + return get_alt_name(cert->ian, seq, ian, ian_size, ian_type, critical, 0); } @@ -1884,7 +1928,7 @@ gnutls_x509_crt_get_subject_alt_othername_oid(gnutls_x509_crt_t cert, unsigned int seq, void *oid, size_t * oid_size) { - return get_alt_name(cert, "2.5.29.17", seq, oid, oid_size, NULL, + return get_alt_name(cert->san, seq, oid, oid_size, NULL, NULL, 1); } @@ -1925,7 +1969,7 @@ gnutls_x509_crt_get_issuer_alt_othername_oid(gnutls_x509_crt_t cert, unsigned int seq, void *ret, size_t * ret_size) { - return get_alt_name(cert, "2.5.29.18", seq, ret, ret_size, NULL, + return get_alt_name(cert->ian, seq, ret, ret_size, NULL, NULL, 1); } diff --git a/lib/x509/x509_int.h b/lib/x509/x509_int.h index 198a69d500..85c4e17b42 100644 --- a/lib/x509/x509_int.h +++ b/lib/x509/x509_int.h @@ -85,6 +85,10 @@ typedef struct gnutls_x509_crt_int { gnutls_datum_t der; + /* this cached value allows fast access to alt names */ + gnutls_subject_alt_names_t san; + gnutls_subject_alt_names_t ian; + /* backwards compatibility for gnutls_x509_crt_get_subject() * and gnutls_x509_crt_get_issuer() */ gnutls_x509_dn_st dn; diff --git a/tests/certs-interesting/cert5.der.err b/tests/certs-interesting/cert5.der.err new file mode 100644 index 0000000000..a6605e8630 --- /dev/null +++ b/tests/certs-interesting/cert5.der.err @@ -0,0 +1 @@ +-62 |