diff options
author | Nikos Mavrogiannopoulos <nmav@gnutls.org> | 2013-03-05 16:46:32 +0100 |
---|---|---|
committer | Nikos Mavrogiannopoulos <nmav@gnutls.org> | 2013-03-05 19:48:48 +0100 |
commit | b71abe5d67d9812bc49d667cacb0e1f0267ccee5 (patch) | |
tree | 42696fd8613ecf5db242f27efb34bcea795aeb06 /lib/x509 | |
parent | 291a467dbf4dd7576f899470c338bdd1bb483f02 (diff) | |
download | gnutls-b71abe5d67d9812bc49d667cacb0e1f0267ccee5.tar.gz |
Several optimizations on certificate comparisons including DN. This speeds up CA certificate loading, and certificate verification.
Diffstat (limited to 'lib/x509')
-rw-r--r-- | lib/x509/common.c | 32 | ||||
-rw-r--r-- | lib/x509/common.h | 6 | ||||
-rw-r--r-- | lib/x509/crl.c | 75 | ||||
-rw-r--r-- | lib/x509/dn.c | 26 | ||||
-rw-r--r-- | lib/x509/ocsp.c | 7 | ||||
-rw-r--r-- | lib/x509/verify-high.c | 134 | ||||
-rw-r--r-- | lib/x509/verify.c | 280 | ||||
-rw-r--r-- | lib/x509/x509.c | 125 | ||||
-rw-r--r-- | lib/x509/x509_int.h | 9 |
9 files changed, 203 insertions, 491 deletions
diff --git a/lib/x509/common.c b/lib/x509/common.c index 7557976ad3..d120e3bb3a 100644 --- a/lib/x509/common.c +++ b/lib/x509/common.c @@ -1799,3 +1799,35 @@ cleanup: return ret; } + +int +_gnutls_x509_get_raw_dn2 (ASN1_TYPE c2, gnutls_datum_t* raw, + const char *whom, gnutls_datum_t * dn) +{ + int result, len1; + int start1, end1; + result = + asn1_der_decoding_startEnd (c2, raw->data, raw->size, + whom, &start1, &end1); + + if (result != ASN1_SUCCESS) + { + gnutls_assert (); + result = _gnutls_asn2err (result); + goto cleanup; + } + + len1 = end1 - start1 + 1; + + result = _gnutls_set_datum (dn, &raw->data[start1], len1); + if (result < 0) + { + gnutls_assert(); + goto cleanup; + } + + result = 0; + +cleanup: + return result; +} diff --git a/lib/x509/common.h b/lib/x509/common.h index 5aa5c8fa1d..ebffe489d7 100644 --- a/lib/x509/common.h +++ b/lib/x509/common.h @@ -162,7 +162,11 @@ void _asnstr_append_name (char *name, size_t name_size, const char *part1, const char *part2); int -check_if_same_cert (gnutls_x509_crt_t cert1, gnutls_x509_crt_t cert2); +_gnutls_x509_get_raw_dn2 (ASN1_TYPE c2, gnutls_datum_t* raw, + const char *whom, gnutls_datum_t * dn); + +int +_gnutls_check_if_same_cert (gnutls_x509_crt_t cert1, gnutls_x509_crt_t cert2); time_t _gnutls_x509_generalTime2gtime (const char *ttime); diff --git a/lib/x509/crl.c b/lib/x509/crl.c index 392ef3140c..152ab33ba9 100644 --- a/lib/x509/crl.c +++ b/lib/x509/crl.c @@ -79,6 +79,7 @@ gnutls_x509_crl_deinit (gnutls_x509_crl_t crl) if (crl->crl) asn1_delete_structure (&crl->crl); + gnutls_free(crl->raw_issuer_dn.data); gnutls_free (crl); } @@ -129,7 +130,6 @@ gnutls_x509_crl_import (gnutls_x509_crl_t crl, need_free = 1; } - result = asn1_der_decoding (&crl->crl, _data.data, _data.size, NULL); if (result != ASN1_SUCCESS) { @@ -138,6 +138,15 @@ gnutls_x509_crl_import (gnutls_x509_crl_t crl, goto cleanup; } + result = _gnutls_x509_get_raw_dn2 (crl->crl, &_data, + "tbsCertList.issuer.rdnSequence", + &crl->raw_issuer_dn); + if (result < 0) + { + gnutls_assert (); + goto cleanup; + } + if (need_free) _gnutls_free_datum (&_data); @@ -146,6 +155,7 @@ gnutls_x509_crl_import (gnutls_x509_crl_t crl, cleanup: if (need_free) _gnutls_free_datum (&_data); + _gnutls_free_datum (&crl->raw_issuer_dn); return result; } @@ -574,68 +584,7 @@ int gnutls_x509_crl_get_raw_issuer_dn (gnutls_x509_crl_t crl, gnutls_datum_t * dn) { - ASN1_TYPE c2 = ASN1_TYPE_EMPTY; - int result, len1; - int start1, end1; - gnutls_datum_t crl_signed_data; - - if (crl == NULL) - { - gnutls_assert (); - return GNUTLS_E_INVALID_REQUEST; - } - - /* get the issuer of 'crl' - */ - if ((result = - asn1_create_element (_gnutls_get_pkix (), "PKIX1.TBSCertList", - &c2)) != ASN1_SUCCESS) - { - gnutls_assert (); - return _gnutls_asn2err (result); - } - - result = - _gnutls_x509_get_signed_data (crl->crl, "tbsCertList", &crl_signed_data); - if (result < 0) - { - gnutls_assert (); - goto cleanup; - } - - result = - asn1_der_decoding (&c2, crl_signed_data.data, crl_signed_data.size, NULL); - if (result != ASN1_SUCCESS) - { - /* couldn't decode DER */ - gnutls_assert (); - asn1_delete_structure (&c2); - result = _gnutls_asn2err (result); - goto cleanup; - } - - result = - asn1_der_decoding_startEnd (c2, crl_signed_data.data, - crl_signed_data.size, "issuer", - &start1, &end1); - - if (result != ASN1_SUCCESS) - { - gnutls_assert (); - result = _gnutls_asn2err (result); - goto cleanup; - } - - len1 = end1 - start1 + 1; - - _gnutls_set_datum (dn, &crl_signed_data.data[start1], len1); - - result = 0; - -cleanup: - asn1_delete_structure (&c2); - _gnutls_free_datum (&crl_signed_data); - return result; + return _gnutls_set_datum (dn, crl->raw_issuer_dn.data, crl->raw_issuer_dn.size); } /** diff --git a/lib/x509/dn.c b/lib/x509/dn.c index 99d41ffcc5..817f7b9678 100644 --- a/lib/x509/dn.c +++ b/lib/x509/dn.c @@ -1069,32 +1069,6 @@ gnutls_x509_rdn_get_oid (const gnutls_datum_t * idn, } -/* - * Compares the DER encoded part of a DN. - * - * FIXME: use a real DN comparison algorithm. - * - * Returns 1 if the DN's match and (0) if they don't match. Otherwise - * a negative error code is returned to indicate error. - */ -int -_gnutls_x509_compare_raw_dn (const gnutls_datum_t * dn1, - const gnutls_datum_t * dn2) -{ - - if (dn1->size != dn2->size) - { - gnutls_assert (); - return 0; - } - if (memcmp (dn1->data, dn2->data, dn2->size) != 0) - { - gnutls_assert (); - return 0; - } - return 1; /* they match */ -} - /** * gnutls_x509_dn_export: * @dn: Holds the uint8_t DN object diff --git a/lib/x509/ocsp.c b/lib/x509/ocsp.c index 7dd0f85619..bec927a332 100644 --- a/lib/x509/ocsp.c +++ b/lib/x509/ocsp.c @@ -2241,12 +2241,7 @@ gnutls_ocsp_resp_verify (gnutls_ocsp_resp_t resp, is directly signed by something in trustlist and has proper OCSP extkeyusage. */ rc = _gnutls_trustlist_inlist (trustlist, signercert); - if (rc < 0) - { - gnutls_assert (); - goto done; - } - if (rc == 1) + if (rc == 0) { /* not in trustlist, need to verify signature and bits */ gnutls_x509_crt_t issuer; diff --git a/lib/x509/verify-high.c b/lib/x509/verify-high.c index fc59495198..ace0bf2672 100644 --- a/lib/x509/verify-high.c +++ b/lib/x509/verify-high.c @@ -159,21 +159,13 @@ gnutls_x509_trust_list_add_cas(gnutls_x509_trust_list_t list, const gnutls_x509_crt_t * clist, int clist_size, unsigned int flags) { - gnutls_datum_t dn; - int ret, i; + int i; uint32_t hash; for (i = 0; i < clist_size; i++) { - ret = gnutls_x509_crt_get_raw_dn(clist[i], &dn); - if (ret < 0) { - gnutls_assert(); - return i; - } - - hash = hash_pjw_bare(dn.data, dn.size); + hash = hash_pjw_bare(clist[i]->raw_dn.data, clist[i]->raw_dn.size); hash %= list->size; - _gnutls_free_datum(&dn); list->node[hash].trusted_cas = gnutls_realloc_fast(list->node[hash].trusted_cas, (list->node[hash].trusted_ca_size + @@ -223,24 +215,14 @@ gnutls_x509_trust_list_add_named_crt(gnutls_x509_trust_list_t list, const void *name, size_t name_size, unsigned int flags) { - gnutls_datum_t dn; - int ret; uint32_t hash; if (name_size >= MAX_SERVER_NAME_SIZE) return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); - ret = gnutls_x509_crt_get_raw_issuer_dn(cert, &dn); - if (ret < 0) { - gnutls_assert(); - return ret; - } - - hash = hash_pjw_bare(dn.data, dn.size); + hash = hash_pjw_bare(cert->raw_issuer_dn.data, cert->raw_issuer_dn.size); hash %= list->size; - _gnutls_free_datum(&dn); - list->node[hash].named_certs = gnutls_realloc_fast(list->node[hash].named_certs, (list->node[hash].named_cert_size + @@ -286,29 +268,19 @@ gnutls_x509_trust_list_add_crls(gnutls_x509_trust_list_t list, unsigned int verification_flags) { int ret, i, j = 0; - gnutls_datum_t dn; unsigned int vret = 0; uint32_t hash; /* Probably we can optimize things such as removing duplicates * etc. */ - if (crl_size == 0 || crl_list == NULL) return 0; for (i = 0; i < crl_size; i++) { - ret = gnutls_x509_crl_get_raw_issuer_dn(crl_list[i], &dn); - if (ret < 0) { - gnutls_assert(); - return i; - } - - hash = hash_pjw_bare(dn.data, dn.size); + hash = hash_pjw_bare(crl_list[i]->raw_issuer_dn.data, crl_list[i]->raw_issuer_dn.size); hash %= list->size; - _gnutls_free_datum(&dn); - if (flags & GNUTLS_TL_VERIFY_CRL) { ret = @@ -349,10 +321,8 @@ static int shorten_clist(gnutls_x509_trust_list_t list, gnutls_x509_crt_t * certificate_list, unsigned int clist_size) { - int ret; unsigned int j, i; uint32_t hash; - gnutls_datum_t dn; if (clist_size > 1) { /* Check if the last certificate in the path is self signed. @@ -366,7 +336,7 @@ static int shorten_clist(gnutls_x509_trust_list_t list, */ if (gnutls_x509_crt_check_issuer(certificate_list[clist_size - 1], certificate_list[clist_size - - 1]) > 0) { + 1]) != 0) { clist_size--; } } @@ -377,21 +347,13 @@ static int shorten_clist(gnutls_x509_trust_list_t list, * self-signed E but already removed above), and we trust B, remove * B, C and D. */ for (i = 1; i < clist_size; i++) { - ret = gnutls_x509_crt_get_raw_issuer_dn(certificate_list[i], &dn); - if (ret < 0) { - gnutls_assert(); - return ret; - } - - hash = hash_pjw_bare(dn.data, dn.size); + hash = hash_pjw_bare(certificate_list[i]->raw_issuer_dn.data, certificate_list[i]->raw_issuer_dn.size); hash %= list->size; - _gnutls_free_datum(&dn); - for (j = 0; j < list->node[hash].trusted_ca_size; j++) { - if (check_if_same_cert + if (_gnutls_check_if_same_cert (certificate_list[i], - list->node[hash].trusted_cas[j]) == 0) { + list->node[hash].trusted_cas[j]) != 0) { /* cut the list at the point of first the trusted certificate */ clist_size = i + 1; break; @@ -437,7 +399,7 @@ static gnutls_x509_crt_t* sort_clist(gnutls_x509_crt_t sorted[DEFAULT_MAX_VERIFY if (i==j) continue; if (gnutls_x509_crt_check_issuer(clist[i], - clist[j])) + clist[j]) != 0) { issuer[i] = j; break; @@ -487,27 +449,18 @@ int gnutls_x509_trust_list_get_issuer(gnutls_x509_trust_list_t list, gnutls_x509_crt_t * issuer, unsigned int flags) { - gnutls_datum_t dn; int ret; unsigned int i; uint32_t hash; - ret = gnutls_x509_crt_get_raw_issuer_dn(cert, &dn); - if (ret < 0) { - gnutls_assert(); - return ret; - } - - hash = hash_pjw_bare(dn.data, dn.size); + hash = hash_pjw_bare(cert->raw_issuer_dn.data, cert->raw_issuer_dn.size); hash %= list->size; - _gnutls_free_datum(&dn); - for (i = 0; i < list->node[hash].trusted_ca_size; i++) { ret = gnutls_x509_crt_check_issuer(cert, list->node[hash].trusted_cas[i]); - if (ret > 0) { + if (ret != 0) { *issuer = list->node[hash].trusted_cas[i]; return 0; } @@ -544,7 +497,6 @@ gnutls_x509_trust_list_verify_crt(gnutls_x509_trust_list_t list, unsigned int *verify, gnutls_verify_output_function func) { - gnutls_datum_t dn; int ret; unsigned int i; uint32_t hash; @@ -560,19 +512,10 @@ gnutls_x509_trust_list_verify_crt(gnutls_x509_trust_list_t list, if (cert_list_size <= 0) return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); - ret = - gnutls_x509_crt_get_raw_issuer_dn(cert_list[cert_list_size - 1], - &dn); - if (ret < 0) { - gnutls_assert(); - return ret; - } - - hash = hash_pjw_bare(dn.data, dn.size); + hash = hash_pjw_bare(cert_list[cert_list_size - 1]->raw_issuer_dn.data, + cert_list[cert_list_size - 1]->raw_issuer_dn.size); hash %= list->size; - _gnutls_free_datum(&dn); - *verify = _gnutls_x509_verify_certificate(cert_list, cert_list_size, list->node[hash].trusted_cas, list->node[hash]. @@ -596,17 +539,9 @@ gnutls_x509_trust_list_verify_crt(gnutls_x509_trust_list_t list, } for (i = 0; i < cert_list_size - 1; i++) { - ret = gnutls_x509_crt_get_raw_issuer_dn(cert_list[i], &dn); - if (ret < 0) { - gnutls_assert(); - return ret; - } - - hash = hash_pjw_bare(dn.data, dn.size); + hash = hash_pjw_bare(cert_list[i]->raw_issuer_dn.data, cert_list[i]->raw_issuer_dn.size); hash %= list->size; - _gnutls_free_datum(&dn); - ret = _gnutls_x509_crt_check_revocation(cert_list[i], list->node[hash].crls, list->node[hash].crl_size, @@ -650,26 +585,17 @@ gnutls_x509_trust_list_verify_named_crt(gnutls_x509_trust_list_t list, unsigned int *verify, gnutls_verify_output_function func) { - gnutls_datum_t dn; int ret; unsigned int i; uint32_t hash; - ret = gnutls_x509_crt_get_raw_issuer_dn(cert, &dn); - if (ret < 0) { - gnutls_assert(); - return ret; - } - - hash = hash_pjw_bare(dn.data, dn.size); + hash = hash_pjw_bare(cert->raw_issuer_dn.data, cert->raw_issuer_dn.size); hash %= list->size; - _gnutls_free_datum(&dn); - *verify = GNUTLS_CERT_INVALID | GNUTLS_CERT_SIGNER_NOT_FOUND; for (i = 0; i < list->node[hash].named_cert_size; i++) { - if (check_if_same_cert(cert, list->node[hash].named_certs[i].cert) == 0) { /* check if name matches */ + if (_gnutls_check_if_same_cert(cert, list->node[hash].named_certs[i].cert) != 0) { /* check if name matches */ if (list->node[hash].named_certs[i].name_size == name_size && memcmp(list->node[hash].named_certs[i].name, name, name_size) == 0) { @@ -698,40 +624,24 @@ gnutls_x509_trust_list_verify_named_crt(gnutls_x509_trust_list_t list, return 0; } -/* return 0 if @cert is in @list, 1 if not, or < 0 on error. */ +/* return 1 if @cert is in @list, 0 if not */ int _gnutls_trustlist_inlist (gnutls_x509_trust_list_t list, gnutls_x509_crt_t cert) { - gnutls_datum_t dn; int ret; unsigned int i; uint32_t hash; - ret = gnutls_x509_crt_get_raw_dn (cert, &dn); - if (ret < 0) - { - gnutls_assert(); - return ret; - } - - hash = hash_pjw_bare(dn.data, dn.size); + hash = hash_pjw_bare(cert->raw_dn.data, cert->raw_dn.size); hash %= list->size; - _gnutls_free_datum (&dn); - for (i = 0; i < list->node[hash].trusted_ca_size; i++) { - ret = check_if_same_cert (cert, list->node[hash].trusted_cas[i]); - if (ret < 0) - { - gnutls_assert (); - return ret; - } - - if (ret == 0) - return 0; + ret = _gnutls_check_if_same_cert (cert, list->node[hash].trusted_cas[i]); + if (ret != 0) + return 1; } - return 1; + return 0; } diff --git a/lib/x509/verify.c b/lib/x509/verify.c index 0d55ec4714..6e25b07998 100644 --- a/lib/x509/verify.c +++ b/lib/x509/verify.c @@ -36,51 +36,22 @@ #include <common.h> #include <gnutls_pk.h> -static int is_crl_issuer (gnutls_x509_crl_t crl, - gnutls_x509_crt_t issuer_cert); - -static int _gnutls_verify_crl2 (gnutls_x509_crl_t crl, - const gnutls_x509_crt_t * trusted_cas, - int tcas_size, unsigned int flags, - unsigned int *output); - -/* Checks if two certs are identical. Return 0 on match. */ +/* Checks if two certs are identical. Return 1 on match. */ int -check_if_same_cert (gnutls_x509_crt_t cert1, gnutls_x509_crt_t cert2) +_gnutls_check_if_same_cert (gnutls_x509_crt_t cert1, gnutls_x509_crt_t cert2) { gnutls_datum_t cert1bin = { NULL, 0 }, cert2bin = - { - NULL, 0}; + { NULL, 0}; int result; - uint8_t serial1[128], serial2[128]; - size_t serial1_size, serial2_size; - serial1_size = sizeof (serial1); - result = gnutls_x509_crt_get_serial (cert1, serial1, &serial1_size); - if (result < 0) - { - gnutls_assert (); - goto cmp; - } + result = _gnutls_is_same_dn (cert1, cert2); + if (result == 0) + return 0; - serial2_size = sizeof (serial2); - result = gnutls_x509_crt_get_serial (cert2, serial2, &serial2_size); - if (result < 0) - { - gnutls_assert (); - goto cmp; - } - - if (serial2_size != serial1_size - || memcmp (serial1, serial2, serial1_size) != 0) - { - return 1; - } - -cmp: result = _gnutls_x509_der_encode (cert1->cert, "", &cert1bin, 0); if (result < 0) { + result = 0; gnutls_assert (); goto cleanup; } @@ -88,15 +59,16 @@ cmp: result = _gnutls_x509_der_encode (cert2->cert, "", &cert2bin, 0); if (result < 0) { + result = 0; gnutls_assert (); goto cleanup; } if ((cert1bin.size == cert2bin.size) && (memcmp (cert1bin.data, cert2bin.data, cert1bin.size) == 0)) - result = 0; - else result = 1; + else + result = 0; cleanup: _gnutls_free_datum (&cert1bin); @@ -202,7 +174,7 @@ check_if_ca (gnutls_x509_crt_t cert, gnutls_x509_crt_t issuer, else if ((result == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) && ((flags & GNUTLS_VERIFY_ALLOW_ANY_X509_V1_CA_CRT) || (!(flags & GNUTLS_VERIFY_DO_NOT_ALLOW_X509_V1_CA_CRT) && - (gnutls_x509_crt_check_issuer (issuer, issuer) == 1)))) + (gnutls_x509_crt_check_issuer (issuer, issuer) != 0)))) { gnutls_assert (); result = 1; @@ -222,40 +194,27 @@ cleanup: } -/* This function checks if 'certs' issuer is 'issuer_cert'. - * This does a straight (DER) compare of the issuer/subject fields in - * the given certificates. +/* This function checks if cert's issuer is issuer. + * This does a straight (DER) compare of the issuer/subject DN fields in + * the given certificates, as well as check the authority key ID. * - * Returns 1 if they match and (0) if they don't match. Otherwise - * a negative error code is returned to indicate error. + * Returns 1 if they match and (0) if they don't match. */ static int -is_issuer (gnutls_x509_crt_t cert, gnutls_x509_crt_t issuer_cert) +is_issuer (gnutls_x509_crt_t cert, gnutls_x509_crt_t issuer) { - gnutls_datum_t dn1 = { NULL, 0 }, - dn2 = { NULL, 0}; uint8_t id1[512]; uint8_t id2[512]; size_t id1_size; size_t id2_size; int ret; - ret = gnutls_x509_crt_get_raw_issuer_dn (cert, &dn1); - if (ret < 0) - { - gnutls_assert (); - goto cleanup; - } - - ret = gnutls_x509_crt_get_raw_dn (issuer_cert, &dn2); - if (ret < 0) - { - gnutls_assert (); - goto cleanup; - } + if (cert->raw_issuer_dn.size == issuer->raw_dn.size && + memcmp(cert->raw_issuer_dn.data, issuer->raw_dn.data, issuer->raw_dn.size) == 0) + ret = 1; + else + ret = 0; - ret = _gnutls_x509_compare_raw_dn (&dn1, &dn2); - if (ret != 0) { /* check if the authority key identifier matches the subject key identifier @@ -270,7 +229,7 @@ is_issuer (gnutls_x509_crt_t cert, gnutls_x509_crt_t issuer_cert) } id2_size = sizeof(id2); - ret = gnutls_x509_crt_get_subject_key_id(issuer_cert, id2, &id2_size, NULL); + ret = gnutls_x509_crt_get_subject_key_id(issuer, id2, &id2_size, NULL); if (ret < 0) { ret = 1; @@ -285,10 +244,20 @@ is_issuer (gnutls_x509_crt_t cert, gnutls_x509_crt_t issuer_cert) } cleanup: - _gnutls_free_datum (&dn1); - _gnutls_free_datum (&dn2); return ret; +} +/* Check if the given certificate is the issuer of the CRL. + * Returns 1 on success and 0 otherwise. + */ +static int +is_crl_issuer (gnutls_x509_crl_t crl, gnutls_x509_crt_t issuer) +{ + if (crl->raw_issuer_dn.size == issuer->raw_dn.size && + memcmp(crl->raw_issuer_dn.data, issuer->raw_dn.data, issuer->raw_dn.size) == 0) + return 1; + else + return 0; } /* Checks if the DN of two certificates is the same. @@ -298,31 +267,11 @@ cleanup: int _gnutls_is_same_dn (gnutls_x509_crt_t cert1, gnutls_x509_crt_t cert2) { - gnutls_datum_t dn1 = { NULL, 0 }, dn2 = - { - NULL, 0}; - int ret; - - ret = gnutls_x509_crt_get_raw_dn (cert1, &dn1); - if (ret < 0) - { - gnutls_assert (); - goto cleanup; - } - - ret = gnutls_x509_crt_get_raw_dn (cert2, &dn2); - if (ret < 0) - { - gnutls_assert (); - goto cleanup; - } - - ret = _gnutls_x509_compare_raw_dn (&dn1, &dn2); - -cleanup: - _gnutls_free_datum (&dn1); - _gnutls_free_datum (&dn2); - return ret; + if (cert1->raw_dn.size == cert2->raw_dn.size && + memcmp(cert1->raw_dn.data, cert2->raw_dn.data, cert2->raw_dn.size) == 0) + return 1; + else + return 0; } /* Finds an issuer of the certificate. If multiple issuers @@ -340,7 +289,7 @@ gnutls_x509_crt_t issuer = NULL; for (i = 0; i < tcas_size; i++) { - if (is_issuer (cert, trusted_cas[i]) == 1) + if (is_issuer (cert, trusted_cas[i]) != 0) { if (issuer == NULL) { @@ -598,8 +547,7 @@ cleanup: * key identifier and subject key identifier fields match. * * Returns: It will return true (1) if the given certificate is issued - * by the given issuer, and false (0) if not. A negative error code is - * returned in case of an error. + * by the given issuer, and false (0) if not. **/ int gnutls_x509_crt_check_issuer (gnutls_x509_crt_t cert, @@ -641,7 +589,7 @@ _gnutls_x509_verify_certificate (const gnutls_x509_crt_t * certificate_list, * MD2 algorithm. */ if (gnutls_x509_crt_check_issuer (certificate_list[clist_size - 1], - certificate_list[clist_size - 1]) > 0) + certificate_list[clist_size - 1]) != 0) { clist_size--; } @@ -663,7 +611,7 @@ _gnutls_x509_verify_certificate (const gnutls_x509_crt_t * certificate_list, for (j = 0; j < tcas_size; j++) { - if (check_if_same_cert (certificate_list[i], trusted_cas[j]) == 0) + if (_gnutls_check_if_same_cert (certificate_list[i], trusted_cas[j]) != 0) { /* explicity time check for trusted CA that we remove from * list. GNUTLS_VERIFY_DISABLE_TRUSTED_TIME_CHECKS @@ -898,11 +846,10 @@ gnutls_x509_crt_verify (gnutls_x509_crt_t cert, * @issuer: is the certificate of a possible issuer * * This function will check if the given CRL was issued by the given - * issuer certificate. It will return true (1) if the given CRL was - * issued by the given issuer, and false (0) if not. + * issuer certificate. * - * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a - * negative error value. + * Returns: true (1) if the given CRL was issued by the given issuer, + * and false (0) if not. **/ int gnutls_x509_crl_check_issuer (gnutls_x509_crl_t crl, @@ -911,75 +858,6 @@ gnutls_x509_crl_check_issuer (gnutls_x509_crl_t crl, return is_crl_issuer (crl, issuer); } -/** - * gnutls_x509_crl_verify: - * @crl: is the crl to be verified - * @CA_list: is a certificate list that is considered to be trusted one - * @CA_list_length: holds the number of CA certificates in CA_list - * @flags: Flags that may be used to change the verification algorithm. Use OR of the gnutls_certificate_verify_flags enumerations. - * @verify: will hold the crl verification output. - * - * This function will try to verify the given crl and return its status. - * See gnutls_x509_crt_list_verify() for a detailed description of - * return values. Note that since GnuTLS 3.1.4 this function includes - * the time checks. - * - * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a - * negative error value. - **/ -int -gnutls_x509_crl_verify (gnutls_x509_crl_t crl, - const gnutls_x509_crt_t * CA_list, - int CA_list_length, unsigned int flags, - unsigned int *verify) -{ - int ret; - /* Verify crl - */ - ret = _gnutls_verify_crl2 (crl, CA_list, CA_list_length, flags, verify); - if (ret < 0) - { - gnutls_assert (); - return ret; - } - - return 0; -} - - -/* The same as above, but here we've got a CRL. - */ -static int -is_crl_issuer (gnutls_x509_crl_t crl, gnutls_x509_crt_t issuer_cert) -{ - gnutls_datum_t dn1 = { NULL, 0 }, dn2 = - { - NULL, 0}; - int ret; - - ret = gnutls_x509_crl_get_raw_issuer_dn (crl, &dn1); - if (ret < 0) - { - gnutls_assert (); - goto cleanup; - } - - ret = gnutls_x509_crt_get_raw_dn (issuer_cert, &dn2); - if (ret < 0) - { - gnutls_assert (); - return ret; - } - - ret = _gnutls_x509_compare_raw_dn (&dn1, &dn2); - -cleanup: - _gnutls_free_datum (&dn1); - _gnutls_free_datum (&dn2); - - return ret; -} - static inline gnutls_x509_crt_t find_crl_issuer (gnutls_x509_crl_t crl, const gnutls_x509_crt_t * trusted_cas, int tcas_size) @@ -991,7 +869,7 @@ find_crl_issuer (gnutls_x509_crl_t crl, for (i = 0; i < tcas_size; i++) { - if (is_crl_issuer (crl, trusted_cas[i]) == 1) + if (is_crl_issuer (crl, trusted_cas[i]) != 0) return trusted_cas[i]; } @@ -999,19 +877,30 @@ find_crl_issuer (gnutls_x509_crl_t crl, return NULL; } -/* - * Returns only 0 or 1. If 1 it means that the CRL - * was successfuly verified. +/** + * gnutls_x509_crl_verify: + * @crl: is the crl to be verified + * @trusted_cas: is a certificate list that is considered to be trusted one + * @tcas_size: holds the number of CA certificates in CA_list + * @flags: Flags that may be used to change the verification algorithm. Use OR of the gnutls_certificate_verify_flags enumerations. + * @verify: will hold the crl verification output. * - * 'flags': an OR of the gnutls_certificate_verify_flags enumeration. + * This function will try to verify the given crl and return its verification status. + * See gnutls_x509_crt_list_verify() for a detailed description of + * return values. Note that since GnuTLS 3.1.4 this function includes + * the time checks. * - * Output will hold information about the verification - * procedure. - */ -static int -_gnutls_verify_crl2 (gnutls_x509_crl_t crl, - const gnutls_x509_crt_t * trusted_cas, - int tcas_size, unsigned int flags, unsigned int *output) + * Note that value in @verify is set only when the return value of this + * function is success (i.e, failure to trust a CRL a certificate does not imply + * a negative return value). + * + * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a + * negative error value. + **/ +int +gnutls_x509_crl_verify (gnutls_x509_crl_t crl, + const gnutls_x509_crt_t * trusted_cas, + int tcas_size, unsigned int flags, unsigned int *verify) { /* CRL is ignored for now */ gnutls_datum_t crl_signed_data = { NULL, 0 }; @@ -1021,8 +910,8 @@ _gnutls_verify_crl2 (gnutls_x509_crl_t crl, time_t now = gnutls_time(0); unsigned int usage; - if (output) - *output = 0; + if (verify) + *verify = 0; if (tcas_size >= 1) issuer = find_crl_issuer (crl, trusted_cas, tcas_size); @@ -1033,8 +922,8 @@ _gnutls_verify_crl2 (gnutls_x509_crl_t crl, if (issuer == NULL) { gnutls_assert (); - if (output) - *output |= GNUTLS_CERT_SIGNER_NOT_FOUND | GNUTLS_CERT_INVALID; + if (verify) + *verify |= GNUTLS_CERT_SIGNER_NOT_FOUND | GNUTLS_CERT_INVALID; return 0; } @@ -1043,8 +932,8 @@ _gnutls_verify_crl2 (gnutls_x509_crl_t crl, if (gnutls_x509_crt_get_ca_status (issuer, NULL) != 1) { gnutls_assert (); - if (output) - *output |= GNUTLS_CERT_SIGNER_NOT_CA | GNUTLS_CERT_INVALID; + if (verify) + *verify |= GNUTLS_CERT_SIGNER_NOT_CA | GNUTLS_CERT_INVALID; return 0; } @@ -1054,8 +943,8 @@ _gnutls_verify_crl2 (gnutls_x509_crl_t crl, if (!(usage & GNUTLS_KEY_CRL_SIGN)) { gnutls_assert(); - if (output) - *output |= GNUTLS_CERT_SIGNER_CONSTRAINTS_FAILURE | GNUTLS_CERT_INVALID; + if (verify) + *verify |= GNUTLS_CERT_SIGNER_CONSTRAINTS_FAILURE | GNUTLS_CERT_INVALID; return 0; } } @@ -1092,8 +981,8 @@ _gnutls_verify_crl2 (gnutls_x509_crl_t crl, { gnutls_assert (); /* error. ignore it */ - if (output) - *output |= GNUTLS_CERT_SIGNATURE_FAILURE; + if (verify) + *verify |= GNUTLS_CERT_SIGNATURE_FAILURE; result = 0; } else if (result < 0) @@ -1112,25 +1001,24 @@ _gnutls_verify_crl2 (gnutls_x509_crl_t crl, ((sigalg == GNUTLS_SIGN_RSA_MD5) && !(flags & GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5))) { - if (output) - *output |= GNUTLS_CERT_INSECURE_ALGORITHM; + if (verify) + *verify |= GNUTLS_CERT_INSECURE_ALGORITHM; result = 0; } } if (gnutls_x509_crl_get_this_update (crl) > now) - *output |= GNUTLS_CERT_REVOCATION_DATA_ISSUED_IN_FUTURE; + *verify |= GNUTLS_CERT_REVOCATION_DATA_ISSUED_IN_FUTURE; if (gnutls_x509_crl_get_next_update (crl) < now) - *output |= GNUTLS_CERT_REVOCATION_DATA_SUPERSEDED; + *verify |= GNUTLS_CERT_REVOCATION_DATA_SUPERSEDED; cleanup: - if (*output) *output |= GNUTLS_CERT_INVALID; + if (*verify) *verify |= GNUTLS_CERT_INVALID; _gnutls_free_datum (&crl_signed_data); _gnutls_free_datum (&crl_signature); return result; } - diff --git a/lib/x509/x509.c b/lib/x509/x509.c index 957328a851..01455f924c 100644 --- a/lib/x509/x509.c +++ b/lib/x509/x509.c @@ -137,7 +137,8 @@ gnutls_x509_crt_deinit (gnutls_x509_crt_t cert) if (cert->cert) asn1_delete_structure (&cert->cert); - + gnutls_free(cert->raw_dn.data); + gnutls_free(cert->raw_issuer_dn.data); gnutls_free (cert); } @@ -205,6 +206,8 @@ gnutls_x509_crt_import (gnutls_x509_crt_t cert, structure, so we need to replace it with a fresh structure. */ asn1_delete_structure (&cert->cert); + _gnutls_free_datum(&cert->raw_dn); + _gnutls_free_datum(&cert->raw_issuer_dn); result = asn1_create_element (_gnutls_get_pkix (), "PKIX1.Certificate", &cert->cert); @@ -224,6 +227,24 @@ gnutls_x509_crt_import (gnutls_x509_crt_t cert, goto cleanup; } + result = _gnutls_x509_get_raw_dn2 (cert->cert, &_data, + "tbsCertificate.issuer.rdnSequence", + &cert->raw_issuer_dn); + if (result < 0) + { + gnutls_assert (); + goto cleanup; + } + + result = _gnutls_x509_get_raw_dn2 (cert->cert, &_data, + "tbsCertificate.subject.rdnSequence", + &cert->raw_dn); + if (result < 0) + { + gnutls_assert (); + goto cleanup; + } + cert->expanded = 1; /* Since we do not want to disable any extension @@ -237,6 +258,8 @@ gnutls_x509_crt_import (gnutls_x509_crt_t cert, cleanup: if (need_free) _gnutls_free_datum (&_data); + _gnutls_free_datum (&cert->raw_dn); + _gnutls_free_datum (&cert->raw_issuer_dn); return result; } @@ -2313,69 +2336,10 @@ gnutls_x509_crt_get_extension_data (gnutls_x509_crt_t cert, int indx, return 0; } -static int -_gnutls_x509_crt_get_raw_dn2 (gnutls_x509_crt_t cert, - const char *whom, gnutls_datum_t * start) -{ - ASN1_TYPE c2 = ASN1_TYPE_EMPTY; - int result, len1; - int start1, end1; - gnutls_datum_t signed_data = { NULL, 0 }; - - /* get the issuer of 'cert' - */ - if ((result = - asn1_create_element (_gnutls_get_pkix (), "PKIX1.TBSCertificate", - &c2)) != ASN1_SUCCESS) - { - gnutls_assert (); - return _gnutls_asn2err (result); - } - - result = - _gnutls_x509_get_signed_data (cert->cert, "tbsCertificate", &signed_data); - if (result < 0) - { - gnutls_assert (); - goto cleanup; - } - - result = asn1_der_decoding (&c2, signed_data.data, signed_data.size, NULL); - if (result != ASN1_SUCCESS) - { - gnutls_assert (); - asn1_delete_structure (&c2); - result = _gnutls_asn2err (result); - goto cleanup; - } - - result = - asn1_der_decoding_startEnd (c2, signed_data.data, signed_data.size, - whom, &start1, &end1); - - if (result != ASN1_SUCCESS) - { - gnutls_assert (); - result = _gnutls_asn2err (result); - goto cleanup; - } - - len1 = end1 - start1 + 1; - - _gnutls_set_datum (start, &signed_data.data[start1], len1); - - result = 0; - -cleanup: - asn1_delete_structure (&c2); - _gnutls_free_datum (&signed_data); - return result; -} - /** * gnutls_x509_crt_get_raw_issuer_dn: * @cert: should contain a #gnutls_x509_crt_t structure - * @start: will hold the starting point of the DN + * @dn: will hold the starting point of the DN * * This function will return a pointer to the DER encoded DN structure * and the length. This points to allocated data that must be free'd using gnutls_free(). @@ -2386,15 +2350,15 @@ cleanup: **/ int gnutls_x509_crt_get_raw_issuer_dn (gnutls_x509_crt_t cert, - gnutls_datum_t * start) + gnutls_datum_t * dn) { - return _gnutls_x509_crt_get_raw_dn2 (cert, "issuer", start); + return _gnutls_set_datum (dn, cert->raw_issuer_dn.data, cert->raw_issuer_dn.size); } /** * gnutls_x509_crt_get_raw_dn: * @cert: should contain a #gnutls_x509_crt_t structure - * @start: will hold the starting point of the DN + * @dn: will hold the starting point of the DN * * This function will return a pointer to the DER encoded DN structure and * the length. This points to allocated data that must be free'd using gnutls_free(). @@ -2404,9 +2368,9 @@ gnutls_x509_crt_get_raw_issuer_dn (gnutls_x509_crt_t cert, * **/ int -gnutls_x509_crt_get_raw_dn (gnutls_x509_crt_t cert, gnutls_datum_t * start) +gnutls_x509_crt_get_raw_dn (gnutls_x509_crt_t cert, gnutls_datum_t * dn) { - return _gnutls_x509_crt_get_raw_dn2 (cert, "subject", start); + return _gnutls_set_datum (dn, cert->raw_dn.data, cert->raw_dn.size); } static int @@ -2798,6 +2762,15 @@ gnutls_x509_crt_get_key_id (gnutls_x509_crt_t crt, unsigned int flags, return ret; } +static int +crl_issuer_matches (gnutls_x509_crl_t crl, gnutls_x509_crt_t cert) +{ + if (crl->raw_issuer_dn.size == cert->raw_issuer_dn.size && + memcmp(crl->raw_issuer_dn.data, cert->raw_issuer_dn.data, cert->raw_issuer_dn.size) == 0) + return 1; + else + return 0; +} /* This is exactly as gnutls_x509_crt_check_revocation() except that * it calls func. @@ -2812,7 +2785,6 @@ _gnutls_x509_crt_check_revocation (gnutls_x509_crt_t cert, uint8_t cert_serial[128]; size_t serial_size, cert_serial_size; int ncerts, ret, i, j; - gnutls_datum_t dn1, dn2; if (cert == NULL) { @@ -2825,28 +2797,13 @@ _gnutls_x509_crt_check_revocation (gnutls_x509_crt_t cert, /* Step 1. check if issuer's DN match */ - ret = gnutls_x509_crl_get_raw_issuer_dn (crl_list[j], &dn1); - if (ret < 0) - { - gnutls_assert (); - return ret; - } - - ret = gnutls_x509_crt_get_raw_issuer_dn (cert, &dn2); - if (ret < 0) - { - gnutls_assert (); - return ret; - } - - ret = _gnutls_x509_compare_raw_dn (&dn1, &dn2); - _gnutls_free_datum (&dn1); - _gnutls_free_datum (&dn2); + ret = crl_issuer_matches(crl_list[j], cert); if (ret == 0) { /* issuers do not match so don't even * bother checking. */ + gnutls_assert(); continue; } diff --git a/lib/x509/x509_int.h b/lib/x509/x509_int.h index 26ad9c45dc..053f00c1ea 100644 --- a/lib/x509/x509_int.h +++ b/lib/x509/x509_int.h @@ -44,6 +44,7 @@ typedef struct gnutls_x509_crl_int { ASN1_TYPE crl; int use_extensions; + gnutls_datum_t raw_issuer_dn; } gnutls_x509_crl_int; typedef struct gnutls_x509_crt_int @@ -51,6 +52,11 @@ typedef struct gnutls_x509_crt_int ASN1_TYPE cert; int use_extensions; int expanded; /* a certificate has been expanded */ + + /* These two cached values allow fast calls to + * get_raw_*_dn(). */ + gnutls_datum_t raw_dn; + gnutls_datum_t raw_issuer_dn; struct pin_info_st pin; } gnutls_x509_crt_int; @@ -80,9 +86,6 @@ typedef struct gnutls_x509_privkey_int int _gnutls_x509_crt_cpy (gnutls_x509_crt_t dest, gnutls_x509_crt_t src); -int _gnutls_x509_compare_raw_dn (const gnutls_datum_t * dn1, - const gnutls_datum_t * dn2); - int _gnutls_x509_crl_cpy (gnutls_x509_crl_t dest, gnutls_x509_crl_t src); int _gnutls_x509_crl_get_raw_issuer_dn (gnutls_x509_crl_t crl, |