From: Willem Toorop Date: Wed, 12 Sep 2012 14:49:51 +0000 (+0000) Subject: Some more documentation for the dane functions. X-Git-Tag: release-1.6.14rc1~31 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=172a22245e3e997a01ae95467f01824d30da67c2;p=thirdparty%2Fldns.git Some more documentation for the dane functions. --- diff --git a/dane.c b/dane.c index 54561e01..1d8cdc7a 100644 --- a/dane.c +++ b/dane.c @@ -26,6 +26,10 @@ #include #endif +#ifndef max +#define max( a, b ) ( ((a) > (b)) ? (a) : (b) ) +#endif + ldns_status ldns_dane_create_tlsa_owner(ldns_rdf** tlsa_owner, const ldns_rdf* name, uint16_t port, ldns_dane_transport transport) @@ -68,6 +72,7 @@ ldns_dane_create_tlsa_owner(ldns_rdf** tlsa_owner, const ldns_rdf* name, return LDNS_STATUS_OK; } + #ifdef HAVE_SSL ldns_status ldns_dane_cert2rdf(ldns_rdf** rdf, X509* cert, @@ -155,6 +160,9 @@ ldns_dane_cert2rdf(ldns_rdf** rdf, X509* cert, } +/* Ordinary PKIX validation of cert (with extra_certs to help) + * against the CA's in store + */ static ldns_status ldns_dane_pkix_validate(X509* cert, STACK_OF(X509)* extra_certs, X509_STORE* store) @@ -186,6 +194,9 @@ ldns_dane_pkix_validate(X509* cert, STACK_OF(X509)* extra_certs, } +/* Orinary PKIX validation of cert (with extra_certs to help) + * against the CA's in store, but also return the validation chain. + */ static ldns_status ldns_dane_pkix_validate_and_get_chain(STACK_OF(X509)** chain, X509* cert, STACK_OF(X509)* extra_certs, X509_STORE* store) @@ -232,6 +243,8 @@ exit_free_empty_store: } +/* Return the validation chain that can be build out of cert, with extra_certs. + */ static ldns_status ldns_dane_pkix_get_chain(STACK_OF(X509)** chain, X509* cert, STACK_OF(X509)* extra_certs) @@ -269,6 +282,8 @@ exit_free_empty_store: } +/* Pop n+1 certs and return the last popped. + */ static ldns_status ldns_dane_get_nth_cert_from_validation_chain( X509** cert, STACK_OF(X509)* chain, int n) @@ -287,6 +302,9 @@ ldns_dane_get_nth_cert_from_validation_chain( } +/* Create validation chain with cert and extra_certs and returns the last + * self-signed (if present). + */ static ldns_status ldns_dane_pkix_get_last_self_signed(X509** out_cert, X509* cert, STACK_OF(X509)* extra_certs) @@ -484,6 +502,9 @@ memerror: } +/* Return tlsas that actually are TLSA resource records with known values + * for the Certificate usage, Selector and Matching type rdata fields. + */ static ldns_rr_list* ldns_dane_filter_unusable_records(const ldns_rr_list* tlsas) { @@ -512,6 +533,8 @@ ldns_dane_filter_unusable_records(const ldns_rr_list* tlsas) } +/* Return whether cert/selector/matching_type matches data. + */ static ldns_status ldns_dane_match_cert_with_data(X509* cert, ldns_tlsa_selector selector, ldns_tlsa_matching_type matching_type, ldns_rdf* data) @@ -530,6 +553,9 @@ ldns_dane_match_cert_with_data(X509* cert, ldns_tlsa_selector selector, } +/* Return whether any certificate from the chain with selector/matching_type + * matches data. + */ static ldns_status ldns_dane_match_any_cert_with_data(STACK_OF(X509)* chain, ldns_tlsa_selector selector, @@ -683,11 +709,11 @@ ldns_dane_verify_rr(const ldns_rr* tlsa_rr, ldns_status ldns_dane_verify(ldns_rr_list* tlsas, X509* cert, STACK_OF(X509)* extra_certs, - X509_STORE* validate_store) + X509_STORE* pkix_validation_store) { size_t i; ldns_rr* tlsa_rr; - ldns_status s = LDNS_STATUS_DANE_TLSA_DID_NOT_MATCH; + ldns_status s = LDNS_STATUS_OK, ps; assert(cert != NULL); @@ -698,17 +724,19 @@ ldns_dane_verify(ldns_rr_list* tlsas, } } if (! tlsas || ldns_rr_list_rr_count(tlsas) == 0) { - - return ldns_dane_verify_rr(NULL, - cert, extra_certs, validate_store); + /* No TLSA's, so regular PKIX validation + */ + return ldns_dane_pkix_validate(cert, extra_certs, + pkix_validation_store); } else { for (i = 0; i < ldns_rr_list_rr_count(tlsas); i++) { tlsa_rr = ldns_rr_list_rr(tlsas, i); - s = ldns_dane_verify_rr(tlsa_rr, - cert, extra_certs, validate_store); + ps = s; + s = ldns_dane_verify_rr(tlsa_rr, cert, extra_certs, + pkix_validation_store); if (s != LDNS_STATUS_DANE_TLSA_DID_NOT_MATCH && - s != LDNS_STATUS_DANE_PKIX_DID_NOT_VALIDATE){ + s != LDNS_STATUS_DANE_PKIX_DID_NOT_VALIDATE) { /* which would be LDNS_STATUS_OK (match) * or some fatal error preventing use from @@ -716,6 +744,9 @@ ldns_dane_verify(ldns_rr_list* tlsas, */ break; } + s = max(s, ps); /* prefer PKIX_DID_NOT_VALIDATE + * over TLSA_DID_NOT_MATCH + */ } ldns_rr_list_free(tlsas); } diff --git a/doc/function_manpages b/doc/function_manpages index 15706fad..ce05899b 100644 --- a/doc/function_manpages +++ b/doc/function_manpages @@ -39,6 +39,11 @@ ldns_dname_compare, ldns_dname_interval | ldns_dname_is_subdomain | ldns_dname ldns_dname | ldns_dname_left_chop, ldns_dname_label_count, ldns_dname2canonical, ldns_dname_cat, ldns_dname_cat_clone, ldns_dname_new, ldns_dname_new_frm_str, ldns_dname_new_frm_data, ldns_dname_is_subdomain, ldns_dname_str_absolute, ldns_dname_label, ldns_dname_compare, ldns_dname_interval ### /dname.h +### dane.h +ldns_dane_create_tlsa_owner, ldns_dane_cert2rdf, ldns_dane_select_certificate, ldns_dane_create_tlsa_rr | ldns_dane_verify, ldns_dane_verify_rr +ldns_dane_verify, ldns_dane_verify_rr | ldns_dane_create_tlsa_owner, ldns_dane_cert2rdf, ldns_dane_select_certificate, ldns_dane_create_tlsa_rr +### /dane.h + ### rdata.h ldns_rdf, ldns_rdf_type | ldns_rdf_set_size, ldns_rdf_set_type, ldns_rdf_set_data, ldns_rdf_size, ldns_rdf_get_type, ldns_rdf_data, ldns_rdf_compare, ldns_rdf_new, ldns_rdf_clone, ldns_rdf_new_frm_data, ldns_rdf_new_frm_str, ldns_rdf_new_frm_fp, ldns_rdf_free, ldns_rdf_deep_free, ldns_rdf_print, ldns_native2rdf_int8, ldns_native2rdf_int16, ldns_native2rdf_int32, ldns_native2rdf_int16_data, ldns_rdf2native_int8, ldns_rdf2native_int16, ldns_rdf2native_int32, ldns_rdf2native_sockaddr_storage, ldns_rdf2native_time_t, ldns_native2rdf_int8, ldns_native2rdf_int16, ldns_native2rdf_int32, ldns_native2rdf_int16_data, ldns_rdf2native_int8, ldns_rdf2native_int16, ldns_rdf2native_int32, ldns_rdf2native_sockaddr_storage, ldns_rdf2native_time_t, ldns_native2rdf_int8, ldns_native2rdf_int16, ldns_native2rdf_int32, ldns_native2rdf_int16_data, ldns_rdf2native_int8, ldns_rdf2native_int16, ldns_rdf2native_int32, ldns_rdf2native_sockaddr_storage, ldns_rdf2native_time_t ldns_rdf_set_size, ldns_rdf_set_type, ldns_rdf_set_data | ldns_rdf diff --git a/examples/ldns-dane.c b/examples/ldns-dane.c index 334df861..e20f19e0 100644 --- a/examples/ldns-dane.c +++ b/examples/ldns-dane.c @@ -544,7 +544,7 @@ dane_query(ldns_rr_list** rrs, ldns_resolver* r, ldns_rr_list* dane_lookup_addresses(ldns_resolver* res, ldns_rdf* dname, - ldns_dane_protocol protocol) + int ai_family) { ldns_status s; ldns_rr_list *as = NULL; @@ -554,8 +554,7 @@ dane_lookup_addresses(ldns_resolver* res, ldns_rdf* dname, if (r == NULL) { MEMERR("ldns_rr_list_new"); } - if (protocol == LDNS_DANE_PROTOCOL_UNSPEC || - (protocol & LDNS_DANE_PROTOCOL_IPV4)) { + if (ai_family == AF_UNSPEC || ai_family == AF_INET) { s = dane_query(&as, res, dname, LDNS_RR_TYPE_A, LDNS_RR_CLASS_IN, @@ -572,8 +571,7 @@ dane_lookup_addresses(ldns_resolver* res, ldns_rdf* dname, MEMERR("ldns_rr_list_push_rr_list"); } } - if (protocol == LDNS_DANE_PROTOCOL_UNSPEC || - (protocol & LDNS_DANE_PROTOCOL_IPV6)) { + if (ai_family == AF_UNSPEC || ai_family == AF_INET6) { s = dane_query(&aaas, res, dname, LDNS_RR_TYPE_AAAA, LDNS_RR_CLASS_IN, @@ -680,7 +678,7 @@ main(int argc, char **argv) ldns_rr* address_rr; ldns_rdf* address; - int protocol = LDNS_DANE_PROTOCOL_UNSPEC; + int ai_family = AF_UNSPEC; int transport = LDNS_DANE_TRANSPORT_TCP; char* name_str; @@ -719,10 +717,10 @@ main(int argc, char **argv) print_usage("ldns-dane"); break; case '4': - protocol = LDNS_DANE_PROTOCOL_IPV4; + ai_family = AF_INET; break; case '6': - protocol = LDNS_DANE_PROTOCOL_IPV6; + ai_family = AF_INET6; break; case 'a': s = ldns_str2rdf_a(&address, optarg); @@ -810,11 +808,11 @@ main(int argc, char **argv) * and IPv6 addresses when -4 was given. */ if (ldns_rr_list_rr_count(addresses) > 0 && - protocol != LDNS_DANE_PROTOCOL_UNSPEC) { + ai_family != AF_UNSPEC) { /* TODO: resource leak, previous addresses */ originals = addresses; addresses = rr_list_filter_rr_type(originals, - (protocol == LDNS_DANE_PROTOCOL_IPV4 + (ai_family == AF_INET ? LDNS_RR_TYPE_A : LDNS_RR_TYPE_AAAA)); ldns_rr_list_free(originals); if (addresses == NULL) { @@ -983,7 +981,7 @@ main(int argc, char **argv) assume_dnssec_validity); LDNS_ERR(s, "could not dane_setup_resolver"); ldns_rr_list_free(addresses); - addresses = dane_lookup_addresses(res, name, protocol); + addresses =dane_lookup_addresses(res, name, ai_family); ldns_resolver_free(res); } if (ldns_rr_list_rr_count(addresses) == 0) { diff --git a/ldns/dane.h b/ldns/dane.h index de191a83..47d99ae6 100644 --- a/ldns/dane.h +++ b/ldns/dane.h @@ -36,58 +36,77 @@ extern "C" { #endif +/** + * The different "Certificate usage" rdata field values for a TLSA RR. + */ enum ldns_enum_tlsa_certificate_usage { + /** CA constraint */ LDNS_TLSA_USAGE_CA_CONSTRAINT = 0, + /** Sevice certificate constraint */ LDNS_TLSA_USAGE_SERVICE_CERTIFICATE_CONSTRAINT = 1, + /** Trust anchor assertion */ LDNS_TLSA_USAGE_TRUST_ANCHOR_ASSERTION = 2, + /** Domain issued certificate */ LDNS_TLSA_USAGE_DOMAIN_ISSUED_CERTIFICATE = 3 }; typedef enum ldns_enum_tlsa_certificate_usage ldns_tlsa_certificate_usage; +/** + * The different "Selector" rdata field values for a TLSA RR. + */ enum ldns_enum_tlsa_selector { + /** + * Full certificate: the Certificate binary structure + * as defined in [RFC5280] + */ LDNS_TLSA_SELECTOR_FULL_CERTIFICATE = 0, + + /** + * SubjectPublicKeyInfo: DER-encoded binary structure + * as defined in [RFC5280] + */ LDNS_TLSA_SELECTOR_SUBJECTPUBLICKEYINFO = 1 }; typedef enum ldns_enum_tlsa_selector ldns_tlsa_selector; +/** + * The different "Matching type" rdata field values for a TLSA RR. + */ enum ldns_enum_tlsa_matching_type { + /** Exact match on selected content */ LDNS_TLSA_MATCHING_TYPE_NO_HASH_USED = 0, + /** SHA-256 hash of selected content [RFC6234] */ LDNS_TLSA_MATCHING_TYPE_SHA256 = 1, + /** SHA-512 hash of selected content [RFC6234] */ LDNS_TLSA_MATCHING_TYPE_SHA512 = 2 }; typedef enum ldns_enum_tlsa_matching_type ldns_tlsa_matching_type; -enum ldns_enum_dane_protocol -{ - LDNS_DANE_PROTOCOL_UNSPEC = 0, - LDNS_DANE_PROTOCOL_IPV4 = 1, - LDNS_DANE_PROTOCOL_IPV6 = 2, - LDNS_DANE_PROTOCOL_IP = 3 -}; -typedef enum ldns_enum_dane_protocol ldns_dane_protocol; - +/** + * Known transports to use with TLSA owner names. + */ enum ldns_enum_dane_transport { + /** TCP */ LDNS_DANE_TRANSPORT_TCP = 0, + /** UDP */ LDNS_DANE_TRANSPORT_UDP = 1, + /** SCTP */ LDNS_DANE_TRANSPORT_SCTP = 2 }; typedef enum ldns_enum_dane_transport ldns_dane_transport; /** - * Creates a dname consisting of the given name, prefixed by the service - * port and protocol name of the transport: - * _._. - * TODO: How to choose protocol SCTP? + * Creates a dname consisting of the given name, prefixed by the service port + * and type of transport: _port._transport.name. * * \param[out] tlsa_owner The created dname. - * \param[in] name The dname that should be prefixed by the service and - * protocol. - * \param[in] port The service port number. + * \param[in] name The dname that should be prefixed. + * \param[in] port The service port number for wich the name should be created. * \param[in] transport The transport for wich the name should be created. * \return LDNS_STATUS_OK on success or an error code otherwise. */ @@ -105,7 +124,7 @@ ldns_status ldns_dane_create_tlsa_owner(ldns_rdf** tlsa_owner, * \param[in] cert The certificate from which the data is selected * \param[in] selector The full certificate or the public key * \param[in] matching_type The full data or the SHA256 or SHA512 hash - * of the selected data + * of the selected data * \return LDNS_STATUS_OK on success or an error code otherwise. */ ldns_status ldns_dane_cert2rdf(ldns_rdf** rdf, X509* cert, @@ -138,6 +157,7 @@ ldns_status ldns_dane_cert2rdf(ldns_rdf** rdf, X509* cert, * This can help to make sure that the intended (self signed) * trust anchor is actually present in extra_certs (which is a * DANE requirement). + * * \return LDNS_STATUS_OK on success or an error code otherwise. */ ldns_status ldns_dane_select_certificate(X509** selected_cert, @@ -158,18 +178,61 @@ ldns_status ldns_dane_select_certificate(X509** selected_cert, * * \return LDNS_STATUS_OK on success or an error code otherwise. */ -ldns_status -ldns_dane_create_tlsa_rr(ldns_rr** tlsa, +ldns_status ldns_dane_create_tlsa_rr(ldns_rr** tlsa, ldns_tlsa_certificate_usage certificate_usage, ldns_tlsa_selector selector, ldns_tlsa_matching_type matching_type, X509* cert); +/** + * Verify if the given TLSA resource record matces the given certificate. + * Reporting on a TLSA rr mismatch (LDNS_STATUS_DANE_TLSA_DID_NOT_MATCH) + * is preferred over PKIX failure (LDNS_STATUS_DANE_PKIX_DID_NOT_VALIDATE). + * So when PKIX validation is required by the TLSA Certificate usage, + * but the TLSA data does not match, LDNS_STATUS_DANE_TLSA_DID_NOT_MATCH + * is returned whether the PKIX validated or not. + * + * \param[in] tlsa_rr The resource record that specifies what and how to + * match the certificate. With tlsa_rr == NULL, regular PKIX + * validation is performed. + * \param[in] cert The certificate to match (and validate) + * \param[in] extra_certs Intermediate certificates that might be necessary + * creating the validation chain. + * \param[in] pkix_validation_store Used when the certificate usage is + * "CA constraint" or "Service Certificate Constraint" to + * validate the certificate. + * + * \return LDNS_STATUS_OK on success, + * LDNS_STATUS_DANE_TLSA_DID_NOT_MATCH on TLSA data mismatch, + * LDNS_STATUS_DANE_PKIX_DID_NOT_VALIDATE when TLSA matched, + * but the PKIX validation failed, or other ldns_status errors. + */ ldns_status ldns_dane_verify_rr(const ldns_rr* tlsa_rr, X509* cert, STACK_OF(X509)* extra_certs, X509_STORE* pkix_validation_store); +/** + * Verify if any of the given TLSA resource records matces the given + * certificate. + * + * \param[in] tlsas The resource records that specify what and how to + * match the certificate. One must match for this function + * to succeed. With tlsas == NULL or the number of TLSA records + * in tlsas == 0, regular PKIX validation is performed. + * \param[in] cert The certificate to match (and validate) + * \param[in] extra_certs Intermediate certificates that might be necessary + * creating the validation chain. + * \param[in] pkix_validation_store Used when the certificate usage is + * "CA constraint" or "Service Certificate Constraint" to + * validate the certificate. + * + * \return LDNS_STATUS_OK on success, + * LDNS_STATUS_DANE_PKIX_DID_NOT_VALIDATE when one of the TLSA's + * matched but the PKIX validation failed, + * LDNS_STATUS_DANE_TLSA_DID_NOT_MATCH when none of the TLSA's matched, + * or other ldns_status errors. + */ ldns_status ldns_dane_verify(ldns_rr_list* tlsas, X509* cert, STACK_OF(X509)* extra_certs, diff --git a/ldns/dname.h b/ldns/dname.h index bc06a715..d4d712f3 100644 --- a/ldns/dname.h +++ b/ldns/dname.h @@ -182,7 +182,7 @@ bool ldns_dname_str_absolute(const char *dname_str); * \param[in] *dname a rdf representing the dname * \return true or false */ -bool ldns_dname_absolute(const ldns_rdf *rdf); +bool ldns_dname_absolute(const ldns_rdf *dname); /** * look inside the rdf and if it is an LDNS_RDF_TYPE_DNAME diff --git a/libdns.doxygen b/libdns.doxygen index 3325db94..ef94a55b 100644 --- a/libdns.doxygen +++ b/libdns.doxygen @@ -1399,7 +1399,7 @@ SEARCH_INCLUDES = YES # contain include files that are not input files but should be processed by # the preprocessor. -INCLUDE_PATH = +INCLUDE_PATH = . # You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard # patterns (like *.h and *.hpp) to filter out the header-files in the