From: Nikos Mavrogiannopoulos Date: Tue, 9 Oct 2012 22:24:41 +0000 (+0200) Subject: Updates in DANE support. Allow caching of queries. X-Git-Tag: gnutls_3_1_3~18 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=b69e8d5531cc4db35fbb046e395eda559b5f499a;p=thirdparty%2Fgnutls.git Updates in DANE support. Allow caching of queries. --- diff --git a/.gitignore b/.gitignore index 80ac853faa..3d9f114098 100644 --- a/.gitignore +++ b/.gitignore @@ -596,4 +596,5 @@ tests/mini-dtls-heartbeat tests/mini-handshake-timeout tests/mini-x509-callbacks doc/manpages/stamp_mans -libdane/libdane.la +libdane/libgnutls-dane.la +doc/latex/dane-api.tex diff --git a/NEWS b/NEWS index 9966ba0328..b5bb53ec3a 100644 --- a/NEWS +++ b/NEWS @@ -50,14 +50,15 @@ gnutls_pkcs11_obj_export2: Added gnutls_pkcs12_export2: Added gnutls_pubkey_import_openpgp_raw: Added gnutls_pubkey_import_x509_raw: Added -dane_query_init: Added -dane_query_deinit: Added -dane_query_resolve_tlsa: Added -dane_query_data: Added +dane_state_init: Added +dane_state_deinit: Added +dane_query_tlsa: Added dane_query_status: Added dane_query_entries: Added -dane_verify_crt: Added +dane_query_data: Added +dane_query_deinit: Added dane_verify_session_crt: Added +dane_verify_crt: Added dane_strerror: Added diff --git a/doc/cha-cert-auth.texi b/doc/cha-cert-auth.texi index e6c7c963e3..10f0ef91fb 100644 --- a/doc/cha-cert-auth.texi +++ b/doc/cha-cert-auth.texi @@ -507,10 +507,9 @@ high level verification functions are shown below. @showfuncB{dane_verify_session_crt,dane_strerror} -The allowed flags for the verification function follow. - -@showenumdesc{dane_verify_flags_t,The DANE verification flags.} - +Note that the @code{dane_state_t} structure that is accepted by both +verification functions is optional. It is required when many queries +are performed to facilitate caching. The following flags are returned by the verify functions to indicate the status of the verification. diff --git a/doc/invoke-certtool.texi b/doc/invoke-certtool.texi index 21f3bcb83f..8228754c25 100644 --- a/doc/invoke-certtool.texi +++ b/doc/invoke-certtool.texi @@ -7,7 +7,7 @@ # # DO NOT EDIT THIS FILE (invoke-certtool.texi) # -# It has been AutoGen-ed October 9, 2012 at 08:27:51 PM by AutoGen 5.16 +# It has been AutoGen-ed October 9, 2012 at 10:59:40 PM by AutoGen 5.16 # From the definitions ../src/certtool-args.def # and the template file agtexi-cmd.tpl @end ignore @@ -108,7 +108,7 @@ USAGE: certtool [ - [] | --[@{=| @}] ]... --template=file Template file to use for non-interactive operation - file must pre-exist --pkcs-cipher=str Cipher to use for PKCS #8 and #12 operations - --dane-rr Print the DANE RR data on a certificate or public key + --dane-tlsa-rr Print the DANE RR data on a certificate or public key - requires these options: dane-host --dane-host=str Specify the hostname to be used in the DANE RR @@ -116,7 +116,7 @@ USAGE: certtool [ - [] | --[@{=| @}] ]... --dane-port=num Specify the port number for the DANE data. --dane-ca Whether the provided certificate or public key is a Certificate authority. - --dane-full-x509 Use the hash of the X.509 certificate, rather than the public key. + --dane-x509 Use the hash of the X.509 certificate, rather than the public key. --dane-local The provided certificate or public key is a local entity. -v, --version[=arg] Output version information and exit -h, --help Display extended usage information and exit @@ -290,9 +290,9 @@ This is alternative to the bits option. This is the ``cipher to use for pkcs #8 and #12 operations'' option. This option takes an argument string @file{Cipher}. Cipher may be one of 3des, 3des-pkcs12, aes-128, aes-192, aes-256, rc2-40, arcfour. -@anchor{certtool dane-rr} -@subheading dane-rr option -@cindex certtool-dane-rr +@anchor{certtool dane-tlsa-rr} +@subheading dane-tlsa-rr option +@cindex certtool-dane-tlsa-rr This is the ``print the dane rr data on a certificate or public key'' option. @@ -325,9 +325,9 @@ This command specifies the protocol for the service set in the DANE data. This is the ``whether the provided certificate or public key is a certificate authority.'' option. Marks the DANE RR as a CA certificate if specified. -@anchor{certtool dane-full-x509} -@subheading dane-full-x509 option -@cindex certtool-dane-full-x509 +@anchor{certtool dane-x509} +@subheading dane-x509 option +@cindex certtool-dane-x509 This is the ``use the hash of the x.509 certificate, rather than the public key.'' option. This option forces the generated record to contain the hash of the full X.509 certificate. By default only the hash of the public key is used. @@ -476,12 +476,12 @@ $ certtool --verify-crl --load-ca-certificate x509-ca.pem < crl.pem To create a DANE TLSA resource record for a CA signed certificate use the following commands. @example -$ certtool --dane-rr --dane-host www.example.com --load-certificate cert.pem +$ certtool --dane-tlsa-rr --dane-host www.example.com --load-certificate cert.pem @end example For a self signed certificate use: @example -$ certtool --dane-rr --dane-host www.example.com --load-certificate cert.pem \ +$ certtool --dane-tlsa-rr --dane-host www.example.com --load-certificate cert.pem \ --dane-local @end example @@ -491,7 +491,7 @@ certificate using DANE. In order to create a record for the signer of your certificate use: @example -$ certtool --dane-rr --dane-host www.example.com --load-certificate cert.pem \ +$ certtool --dane-tlsa-rr --dane-host www.example.com --load-certificate cert.pem \ --dane-ca @end example diff --git a/libdane/dane.c b/libdane/dane.c index e008ad899e..4f4569a59b 100644 --- a/libdane/dane.c +++ b/libdane/dane.c @@ -35,22 +35,27 @@ #define MAX_DATA_ENTRIES 4 +struct dane_state_st +{ + struct ub_ctx* ctx; + unsigned int flags; +}; + struct dane_query_st { + struct ub_result* result; unsigned int data_entries; dane_cert_usage_t usage[MAX_DATA_ENTRIES]; dane_cert_type_t type[MAX_DATA_ENTRIES]; dane_match_type_t match[MAX_DATA_ENTRIES]; gnutls_datum_t data[MAX_DATA_ENTRIES]; - struct ub_ctx* ctx; - struct ub_result* result; unsigned int flags; dane_query_status_t status; }; /** * dane_query_status: - * @q: The query structure + * @q: The query result structure * * This function will return the status of the query response. * See %dane_query_status_t for the possible types. @@ -64,7 +69,7 @@ dane_query_status_t dane_query_status(dane_query_t q) /** * dane_query_entries: - * @q: The query structure + * @q: The query result structure * * This function will return the number of entries in a query. * @@ -77,7 +82,7 @@ unsigned int dane_query_entries(dane_query_t q) /** * dane_query_data: - * @q: The query structure + * @q: The query result structure * @idx: The index of the query response. * @usage: The certificate usage (see %dane_cert_usage_t) * @type: The certificate type (see %dane_cert_type_t) @@ -112,22 +117,22 @@ int dane_query_data(dane_query_t q, unsigned int idx, } /** - * dane_query_init: - * @q: The structure to be initialized - * @flags: flags from the DANE_F_* definitions + * dane_state_init: + * @s: The structure to be initialized + * @flags: flags from the %dane_state_flags enumeration * * This function will initialize a DANE query structure. * * Returns: On success, %DANE_E_SUCCESS (0) is returned, otherwise a * negative error value. **/ -int dane_query_init(dane_query_t* q, unsigned int flags) +int dane_state_init(dane_state_t* s, unsigned int flags) { struct ub_ctx* ctx; int ret; - *q = calloc(1, sizeof(struct dane_query_st)); - if (*q == NULL) + *s = calloc(1, sizeof(struct dane_state_st)); + if (*s == NULL) return DANE_E_MEMORY_ERROR; ctx = ub_ctx_create(); @@ -155,38 +160,50 @@ int dane_query_init(dane_query_t* q, unsigned int flags) goto cleanup; } - (*q)->ctx = ctx; - (*q)->flags = flags; + (*s)->ctx = ctx; + (*s)->flags = flags; return DANE_E_SUCCESS; cleanup: if (ctx) ub_ctx_delete(ctx); - free(*q); + free(*s); return ret; } /** - * dane_query_init: - * @q: The structure to be deinitialized + * dane_state_deinit: + * @s: The structure to be deinitialized * * This function will deinitialize a DANE query structure. * **/ -void dane_query_deinit(dane_query_t q) +void dane_state_deinit(dane_state_t s) { - if (q->result) - ub_ctx_delete(q->ctx); - ub_resolve_free(q->result); + ub_ctx_delete(s->ctx); + free(s); +} + +/** + * dane_query_deinit: + * @q: The structure to be deinitialized + * + * This function will deinitialize a DANE query result structure. + * + **/ +void dane_query_deinit(dane_query_t q) +{ + ub_resolve_free(q->result); free(q); } /** - * dane_query_resolve_tlsa: - * @q: The query structure + * dane_query_tlsa: + * @s: The DANE state structure + * @r: A structure to place the result * @host: The host name to resolve. * @proto: The protocol type (tcp, udp, etc.) * @port: The service port number (eg. 443). @@ -197,62 +214,61 @@ void dane_query_deinit(dane_query_t q) * Returns: On success, %DANE_E_SUCCESS (0) is returned, otherwise a * negative error value. **/ -int dane_query_resolve_tlsa(dane_query_t q, const char* host, const char* proto, unsigned int port) +int dane_query_tlsa(dane_state_t s, dane_query_t *r, const char* host, const char* proto, unsigned int port) { char ns[1024]; int ret; unsigned int i; - if (q->result) { - ub_resolve_free(q->result); - q->result = NULL; - } - + *r = calloc(1, sizeof(struct dane_query_st)); + if (*r == NULL) + return DANE_E_MEMORY_ERROR; + snprintf(ns, sizeof(ns), "_%u._%s.%s", port, proto, host); /* query for webserver */ - ret = ub_resolve(q->ctx, ns, 52, 1, &q->result); + ret = ub_resolve(s->ctx, ns, 52, 1, &(*r)->result); if(ret != 0) { return DANE_E_RESOLVING_ERROR; } /* show first result */ - if(!q->result->havedata) { + if(!(*r)->result->havedata) { return DANE_E_NO_DANE_DATA; } i = 0; do { - if (q->result->len[i] > 3) + if ((*r)->result->len[i] > 3) ret = DANE_E_SUCCESS; else { return DANE_E_RECEIVED_CORRUPT_DATA; } - q->usage[i] = q->result->data[i][0]; - q->type[i] = q->result->data[i][1]; - q->match[i] = q->result->data[i][2]; - q->data[i].data = (void*)&q->result->data[i][3]; - q->data[i].size = q->result->len[i] - 3; + (*r)->usage[i] = (*r)->result->data[i][0]; + (*r)->type[i] = (*r)->result->data[i][1]; + (*r)->match[i] = (*r)->result->data[i][2]; + (*r)->data[i].data = (void*)&(*r)->result->data[i][3]; + (*r)->data[i].size = (*r)->result->len[i] - 3; i++; - } while(q->result->data[i] != NULL); + } while((*r)->result->data[i] != NULL); - q->data_entries = i; + (*r)->data_entries = i; - if (!q->result->secure) { - if (q->result->bogus) + if (!(*r)->result->secure) { + if ((*r)->result->bogus) ret = DANE_E_INVALID_DNSSEC_SIG; else ret = DANE_E_NO_DNSSEC_SIG; } /* show security status */ - if (q->result->secure) - q->status = DANE_QUERY_DNSSEC_VERIFIED; - else if (q->result->bogus) - q->status = DANE_QUERY_BOGUS; - else q->status = DANE_QUERY_NO_DNSSEC; + if ((*r)->result->secure) + (*r)->status = DANE_QUERY_DNSSEC_VERIFIED; + else if ((*r)->result->bogus) + (*r)->status = DANE_QUERY_BOGUS; + else (*r)->status = DANE_QUERY_NO_DNSSEC; return ret; } @@ -413,13 +429,14 @@ cleanup: /** * dane_verify_crt: + * @s: A DANE state structure (may be NULL) * @chain: A certificate chain * @chain_size: The size of the chain * @chain_type: The type of the certificate chain * @hostname: The hostname associated with the chain * @proto: The protocol of the service connecting (e.g. tcp) * @port: The port of the service connecting (e.g. 443) - * @flags: The %DANE_F flags. + * @flags: should be zero * @verify: An OR'ed list of %dane_verify_status_t. * * This function will verify the given certificate chain against the @@ -433,17 +450,20 @@ cleanup: * it may be better to mention: DANE verification did not reject the certificate, * rather than mentioning a successful DANE verication. * + * If the @q parameter is provided it will be used for caching entries. + * * Returns: On success, %DANE_E_SUCCESS (0) is returned, otherwise a * negative error value. * **/ -int dane_verify_crt ( +int dane_verify_crt (dane_state_t s, const gnutls_datum_t *chain, unsigned chain_size, gnutls_certificate_type_t chain_type, const char * hostname, const char* proto, unsigned int port, unsigned int flags, unsigned int *verify) { -dane_query_t q; +dane_state_t _s = NULL; +dane_query_t r = NULL; int ret; unsigned int usage, type, match, idx; gnutls_datum_t data; @@ -453,19 +473,22 @@ gnutls_datum_t data; *verify = 0; - ret = dane_query_init(&q, flags); - if (ret < 0) { - return ret; - } + if (s == NULL) { + ret = dane_state_init(&_s, flags); + if (ret < 0) { + return ret; + } + } else + _s = s; - ret = dane_query_resolve_tlsa(q, hostname, proto, port); + ret = dane_query_tlsa(_s, &r, hostname, proto, port); if (ret < 0) { goto cleanup; } idx = 0; do { - ret = dane_query_data(q, idx++, &usage, &type, &match, &data); + ret = dane_query_data(r, idx++, &usage, &type, &match, &data); if (ret == DANE_E_REQUESTED_DATA_NOT_AVAILABLE) break; @@ -488,17 +511,19 @@ gnutls_datum_t data; ret = 0; cleanup: - dane_query_deinit(q); + if (s == NULL) dane_state_deinit(_s); + if (r != NULL) dane_query_deinit(r); return ret; } /** * dane_verify_session_crt: + * @s: A DANE state structure (may be NULL) * @session: A gnutls session * @hostname: The hostname associated with the chain * @proto: The protocol of the service connecting (e.g. tcp) * @port: The port of the service connecting (e.g. 443) - * @flags: The %DANE_F flags. + * @flags: should be zero. * @verify: An OR'ed list of %dane_verify_status_t. * * This function will verify session's certificate chain against the @@ -510,6 +535,7 @@ cleanup: * **/ int dane_verify_session_crt ( + dane_state_t s, gnutls_session_t session, const char * hostname, const char* proto, unsigned int port, unsigned int flags, unsigned int *verify) @@ -525,5 +551,5 @@ unsigned int type; type = gnutls_certificate_type_get(session); - return dane_verify_crt(cert_list, cert_list_size, type, hostname, proto, port, flags, verify); + return dane_verify_crt(s, cert_list, cert_list_size, type, hostname, proto, port, flags, verify); } diff --git a/libdane/includes/gnutls/dane.h b/libdane/includes/gnutls/dane.h index 366d10a980..74a28f9bd0 100644 --- a/libdane/includes/gnutls/dane.h +++ b/libdane/includes/gnutls/dane.h @@ -89,17 +89,31 @@ typedef enum dane_query_status_t DANE_QUERY_NO_DNSSEC } dane_query_status_t; +typedef struct dane_state_st *dane_state_t; typedef struct dane_query_st *dane_query_t; +/** + * dane_state_flags_t: + * @DANE_F_IGNORE_LOCAL_RESOLVER: Many systems are not DNSSEC-ready. In that case the local resolver is ignored, and a direct recursive resolve occurs. + * + * Enumeration of different verification flags. + */ +typedef enum dane_state_flags_t +{ + DANE_F_IGNORE_LOCAL_RESOLVER = 1, +} dane_verify_flags_t; + +int dane_state_init (dane_state_t* s, unsigned int flags); +void dane_state_deinit (dane_state_t s); + +int dane_query_tlsa(dane_state_t s, dane_query_t *r, const char* host, const char* proto, unsigned int port); -int dane_query_init (dane_query_t* q, unsigned int flags); -void dane_query_deinit (dane_query_t q); -int dane_query_resolve_tlsa (dane_query_t q, const char* host, const char* proto, unsigned int port); -int dane_query_data(dane_query_t q, unsigned int idx, - unsigned int *usage, unsigned int *type, - unsigned int *match, gnutls_datum_t * data); dane_query_status_t dane_query_status(dane_query_t q); unsigned int dane_query_entries(dane_query_t q); +int dane_query_data(dane_query_t q, unsigned int idx, + unsigned int *usage, unsigned int *type, + unsigned int *match, gnutls_datum_t * data); +void dane_query_deinit(dane_query_t q); /** @@ -117,25 +131,15 @@ typedef enum dane_verify_status_t DANE_VERIFY_NO_DANE_INFO = 1<<2, } dane_verify_status_t; -/** - * dane_verify_flags_t: - * @DANE_F_REQUIRE_DNSSEC: Require DNSSEC for verification. - * @DANE_F_IGNORE_LOCAL_RESOLVER: Many systems are not DNSSEC-ready. In that case the local resolver is ignored, and a direct recursive resolve occurs. - * - * Enumeration of different verification flags. - */ -typedef enum dane_verify_flags_t -{ - DANE_F_IGNORE_LOCAL_RESOLVER = 1, -} dane_verify_flags_t; -int dane_verify_crt ( +int dane_verify_crt (dane_state_t s, const gnutls_datum_t *chain, unsigned chain_size, gnutls_certificate_type_t chain_type, const char * hostname, const char* proto, unsigned int port, unsigned int flags, unsigned int *verify); int dane_verify_session_crt ( + dane_state_t s, gnutls_session_t session, const char * hostname, const char* proto, unsigned int port, unsigned int flags, unsigned int *verify); diff --git a/libdane/libdane.map b/libdane/libdane.map index a5af3538d2..0bdd7a0a0e 100644 --- a/libdane/libdane.map +++ b/libdane/libdane.map @@ -4,15 +4,15 @@ DANE_0_0 { global: dane_strerror; - dane_verify_session_crt; - dane_verify_crt; - dane_query_init; - dane_query_deinit; - dane_query_resolve_tlsa; - dane_query_data; + dane_state_init; + dane_state_deinit; + dane_query_tlsa; dane_query_status; dane_query_entries; - + dane_query_data; + dane_query_deinit; + dane_verify_session_crt; + dane_verify_crt; local: *; }; diff --git a/src/Makefile.am b/src/Makefile.am index f4aa7e024d..4796c70c21 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -104,7 +104,7 @@ gnutls_cli_SOURCES = cli.c common.h common.c \ $(BENCHMARK_SRCS) gnutls_cli_LDADD = ../lib/libgnutls.la if ENABLE_DANE -gnutls_cli_LDADD += ../libdane/libdane.la +gnutls_cli_LDADD += ../libdane/libgnutls-dane.la endif gnutls_cli_LDADD += libcmd-cli.la ../gl/libgnu.la $(LIBOPTS_LDADD) $(LTLIBINTL) gnutls_cli_LDADD += $(LIBSOCKET) $(GETADDRINFO_LIB) $(LIB_CLOCK_GETTIME) \ diff --git a/src/cli.c b/src/cli.c index ca3a4f8886..8dad5484d7 100644 --- a/src/cli.c +++ b/src/cli.c @@ -484,7 +484,7 @@ cert_verify_callback (gnutls_session_t session) #ifdef HAVE_DANE if (dane) /* try DANE auth */ { - rc = dane_verify_session_crt( session, hostname, udp?"udp":"tcp", atoi(service), + rc = dane_verify_session_crt( NULL, session, hostname, udp?"udp":"tcp", atoi(service), DANE_F_IGNORE_LOCAL_RESOLVER, &status); if (rc < 0) {