summaryrefslogtreecommitdiff
path: root/libdane
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2013-10-21 16:48:02 +0200
committerNikos Mavrogiannopoulos <nmav@gnutls.org>2013-10-21 18:09:20 +0200
commited51e5e53cfbab3103d6b7b85b7ba4515e4f30c3 (patch)
treec0f64907219a27f7b1e573618f0264cbc7c7acd8 /libdane
parent6e403662fa100fec9c159e4c3c620f77cd783f61 (diff)
downloadgnutls-ed51e5e53cfbab3103d6b7b85b7ba4515e4f30c3.tar.gz
Adding dane_raw_tlsa to allow initialization of dane_query_t from DANE records based on external DNS resolutions. Also fixing a buffer overflow.
Signed-off-by: Nikos Mavrogiannopoulos <nmav@gnutls.org>
Diffstat (limited to 'libdane')
-rw-r--r--libdane/dane.c173
-rw-r--r--libdane/includes/gnutls/dane.h15
2 files changed, 115 insertions, 73 deletions
diff --git a/libdane/dane.c b/libdane/dane.c
index 50671c755f..c53e2f95c4 100644
--- a/libdane/dane.c
+++ b/libdane/dane.c
@@ -180,14 +180,14 @@ int dane_state_init(dane_state_t* s, unsigned int flags)
(*s)->ctx = ctx;
(*s)->flags = flags;
-
+
return DANE_E_SUCCESS;
cleanup:
if (ctx)
ub_ctx_delete(ctx);
free(*s);
-
+
return ret;
}
@@ -209,18 +209,18 @@ void dane_state_deinit(dane_state_t s)
* @s: The structure to be deinitialized
* @file: The file holding the DLV keys.
*
- * This function will set a file with trusted keys
+ * This function will set a file with trusted keys
* for DLV (DNSSEC Lookaside Validation).
*
**/
int dane_state_set_dlv_file(dane_state_t s, const char* file)
{
int ret;
-
+
ret = ub_ctx_set_option(s->ctx, (char*)"dlv-anchor-file:", (void*)file);
if (ret != 0)
return gnutls_assert_val(DANE_E_FILE_ERROR);
-
+
return 0;
}
@@ -233,77 +233,71 @@ int ret;
**/
void dane_query_deinit(dane_query_t q)
{
- ub_resolve_free(q->result);
+ if (q->result) ub_resolve_free(q->result);
free(q);
}
+
/**
- * dane_query_tlsa:
+ * dane_raw_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).
+ * @dane_data: array of DNS rdata items, terminated with a NULL pointer;
+ * caller must guarantee that the referenced data remains
+ * valid until dane_query_deinit() is called.
+ * @dane_data_len: the length n bytes of the dane_data items
+ * @param secure true if the result is validated securely, false if
+ * validation failed or the domain queried has no security info
+ * @param bogus if the result was not secure (secure = 0) due to a security failure,
+ * and the result is due to a security failure, bogus is true.
*
- * This function will query the DNS server for the TLSA (DANE)
- * data for the given host.
+ *
+ * This function will fill in the TLSA (DANE) structure from
+ * the given raw DNS record data.
*
* Returns: On success, %DANE_E_SUCCESS (0) is returned, otherwise a
* negative error value.
**/
-int dane_query_tlsa(dane_state_t s, dane_query_t *r, const char* host, const char* proto, unsigned int port)
+int dane_raw_tlsa(dane_state_t s, dane_query_t *r, char *const*dane_data, const int *dane_data_len, int secure, int bogus)
{
- char ns[1024];
int ret;
unsigned int i;
*r = calloc(1, sizeof(struct dane_query_st));
if (*r == NULL)
return gnutls_assert_val(DANE_E_MEMORY_ERROR);
-
- snprintf(ns, sizeof(ns), "_%u._%s.%s", port, proto, host);
-
- /* query for webserver */
- ret = ub_resolve(s->ctx, ns, 52, 1, &(*r)->result);
- if(ret != 0) {
- return gnutls_assert_val(DANE_E_RESOLVING_ERROR);
- }
-
-/* show first result */
- if(!(*r)->result->havedata) {
- return gnutls_assert_val(DANE_E_NO_DANE_DATA);
- }
-
i = 0;
do {
- if ((*r)->result->len[i] > 3)
+ if (dane_data_len[i] > 3)
ret = DANE_E_SUCCESS;
else {
return gnutls_assert_val(DANE_E_RECEIVED_CORRUPT_DATA);
}
-
- (*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;
+
+ (*r)->usage[i] = dane_data[i][0];
+ (*r)->type[i] = dane_data[i][1];
+ (*r)->match[i] = dane_data[i][2];
+ (*r)->data[i].data = (void*)&dane_data[i][3];
+ (*r)->data[i].size = dane_data_len[i] - 3;
i++;
- } while((*r)->result->data[i] != NULL);
-
+ if (i > MAX_DATA_ENTRIES)
+ break;
+ } while(dane_data[i] != NULL);
+
(*r)->data_entries = i;
- if (!(s->flags & DANE_F_INSECURE) && !(*r)->result->secure) {
- if ((*r)->result->bogus)
+ if (!(s->flags & DANE_F_INSECURE) && !secure) {
+ if (bogus)
ret = gnutls_assert_val(DANE_E_INVALID_DNSSEC_SIG);
else
ret = gnutls_assert_val(DANE_E_NO_DNSSEC_SIG);
}
/* show security status */
- if ((*r)->result->secure) {
+ if (secure) {
(*r)->status = DANE_QUERY_DNSSEC_VERIFIED;
- } else if ((*r)->result->bogus) {
+ } else if (bogus) {
gnutls_assert();
(*r)->status = DANE_QUERY_BOGUS;
} else {
@@ -314,7 +308,52 @@ int dane_query_tlsa(dane_state_t s, dane_query_t *r, const char* host, const cha
return ret;
}
-static unsigned int matches(const gnutls_datum_t *raw1, const gnutls_datum_t *raw2,
+
+/**
+ * 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).
+ *
+ * This function will query the DNS server for the TLSA (DANE)
+ * data for the given host.
+ *
+ * Returns: On success, %DANE_E_SUCCESS (0) is returned, otherwise a
+ * negative error value.
+ **/
+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;
+ struct ub_result *result;
+
+ snprintf(ns, sizeof(ns), "_%u._%s.%s", port, proto, host);
+
+ /* query for webserver */
+ ret = ub_resolve(s->ctx, ns, 52, 1, &result);
+ if(ret != 0) {
+ return gnutls_assert_val(DANE_E_RESOLVING_ERROR);
+ }
+
+/* show first result */
+ if(!result->havedata) {
+ ub_resolve_free (result);
+ return gnutls_assert_val(DANE_E_NO_DANE_DATA);
+ }
+
+ ret = dane_raw_tlsa (s, r, result->data, result->len, result->secure, result->bogus);
+ if (*r == NULL) {
+ ub_resolve_free (result);
+ return ret;
+ }
+ (*r)->result = result;
+ return ret;
+}
+
+
+static unsigned int matches(const gnutls_datum_t *raw1, const gnutls_datum_t *raw2,
dane_match_type_t match)
{
uint8_t digest[64];
@@ -326,35 +365,35 @@ int ret;
if (memcmp(raw1->data, raw2->data, raw1->size) != 0)
return gnutls_assert_val(0);
-
+
return 1;
} else if (match == DANE_MATCH_SHA2_256) {
if (raw2->size != 32)
return gnutls_assert_val(0);
-
+
ret = gnutls_hash_fast(GNUTLS_DIG_SHA256, raw1->data, raw1->size, digest);
if (ret < 0)
return gnutls_assert_val(0);
if (memcmp(digest, raw2->data, 32) != 0)
return gnutls_assert_val(0);
-
+
return 1;
} else if (match == DANE_MATCH_SHA2_512) {
if (raw2->size != 64)
return gnutls_assert_val(0);
-
+
ret = gnutls_hash_fast(GNUTLS_DIG_SHA512, raw1->data, raw1->size, digest);
if (ret < 0)
return gnutls_assert_val(0);
-
+
if (memcmp(digest, raw2->data, 64) != 0)
return gnutls_assert_val(0);
-
+
return 1;
}
-
+
return gnutls_assert_val(0);
}
@@ -376,7 +415,7 @@ int ret;
ret = DANE_E_PUBKEY_ERROR;
goto cleanup;
}
-
+
ret = gnutls_x509_crt_import(crt, raw_crt, GNUTLS_X509_FMT_DER);
if (ret < 0) {
gnutls_assert();
@@ -397,7 +436,7 @@ int ret;
ret = DANE_E_PUBKEY_ERROR;
goto cleanup;
}
-
+
ret = 0;
goto clean_certs;
@@ -428,7 +467,7 @@ gnutls_x509_crt_t crt = NULL, ca = NULL;
return gnutls_assert_val(DANE_E_INVALID_REQUEST);
if (ctype == DANE_CERT_X509 && crt_type == GNUTLS_CRT_X509) {
-
+
if (!matches(&raw_crt[1], data, match)) {
gnutls_assert();
*verify |= DANE_VERIFY_CA_CONSTRAINTS_VIOLATED;
@@ -449,7 +488,7 @@ gnutls_x509_crt_t crt = NULL, ca = NULL;
ret = gnutls_assert_val(DANE_E_UNKNOWN_DANE_DATA);
goto cleanup;
}
-
+
/* check if the certificate chain is actually a chain */
ret = gnutls_x509_crt_init(&crt);
if (ret < 0) {
@@ -474,7 +513,7 @@ gnutls_x509_crt_t crt = NULL, ca = NULL;
ret = gnutls_assert_val(DANE_E_CERT_ERROR);
goto cleanup;
}
-
+
ret = gnutls_x509_crt_check_issuer(crt, ca);
if (ret == 0) {
gnutls_assert();
@@ -550,19 +589,19 @@ cleanup:
* @verify: An OR'ed list of %dane_verify_status_t.
*
* This function will verify the given certificate chain against the
- * CA constrains and/or the certificate available via DANE.
+ * CA constrains and/or the certificate available via DANE.
* If no information via DANE can be obtained the flag %DANE_VERIFY_NO_DANE_INFO
- * is set. If a DNSSEC signature is not available for the DANE
+ * is set. If a DNSSEC signature is not available for the DANE
* record then the verify flag %DANE_VERIFY_NO_DNSSEC_DATA is set.
*
* Note that the CA constraint only applies for the directly certifying CA
* and does not account for long CA chains.
- *
+ *
* Due to the many possible options of DANE, there is no single threat
* model countered. When notifying the user about DANE verification results
* 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
@@ -582,12 +621,12 @@ int ret;
unsigned checked = 0;
unsigned int usage, type, match, idx;
gnutls_datum_t data;
-
+
if (chain_type != GNUTLS_CRT_X509)
return gnutls_assert_val(DANE_E_INVALID_REQUEST);
-
+
*verify = 0;
-
+
if (s == NULL) {
ret = dane_state_init(&_s, sflags);
if (ret < 0) {
@@ -596,7 +635,7 @@ gnutls_datum_t data;
}
} else
_s = s;
-
+
ret = dane_query_tlsa(_s, &r, hostname, proto, port);
if (ret < 0) {
gnutls_assert();
@@ -613,7 +652,7 @@ gnutls_datum_t data;
gnutls_assert();
goto cleanup;
}
-
+
if (!(vflags & DANE_VFLAG_ONLY_CHECK_EE_USAGE) && (usage == DANE_CERT_USAGE_LOCAL_CA || usage == DANE_CERT_USAGE_CA)) {
ret = verify_ca(chain, chain_size, chain_type, type, match, &data, verify);
if (ret < 0) {
@@ -654,7 +693,7 @@ cleanup:
* @verify: An OR'ed list of %dane_verify_status_t.
*
* This function will verify session's certificate chain against the
- * CA constrains and/or the certificate available via DANE.
+ * CA constrains and/or the certificate available via DANE.
* See dane_verify_crt() for more information.
*
* Returns: On success, %DANE_E_SUCCESS (0) is returned, otherwise a
@@ -676,9 +715,9 @@ unsigned int type;
if (cert_list_size == 0) {
return gnutls_assert_val(DANE_E_NO_CERT);
}
-
+
type = gnutls_certificate_type_get(session);
-
+
return dane_verify_crt(s, cert_list, cert_list_size, type, hostname, proto, port, sflags, vflags, verify);
}
@@ -722,6 +761,6 @@ dane_verification_status_print (unsigned int status,
ret = _gnutls_buffer_to_datum( &str, out);
if (out->size > 0) out->size--;
-
+
return ret;
}
diff --git a/libdane/includes/gnutls/dane.h b/libdane/includes/gnutls/dane.h
index 487e731142..3b0bbf63b9 100644
--- a/libdane/includes/gnutls/dane.h
+++ b/libdane/includes/gnutls/dane.h
@@ -51,7 +51,7 @@ typedef enum dane_cert_usage_t
*
* Enumeration of different certificate types.
*/
-typedef enum dane_cert_type_t
+typedef enum dane_cert_type_t
{
DANE_CERT_X509 = 0,
DANE_CERT_PK = 1
@@ -65,7 +65,7 @@ typedef enum dane_cert_type_t
*
* Enumeration of different content matching types.
*/
-typedef enum dane_match_type_t
+typedef enum dane_match_type_t
{
DANE_MATCH_EXACT = 0,
DANE_MATCH_SHA2_256 = 1,
@@ -81,7 +81,7 @@ typedef enum dane_match_type_t
*
* Enumeration of different certificate types.
*/
-typedef enum dane_query_status_t
+typedef enum dane_query_status_t
{
DANE_QUERY_UNKNOWN = 0,
DANE_QUERY_DNSSEC_VERIFIED,
@@ -99,7 +99,7 @@ typedef struct dane_query_st *dane_query_t;
*
* Enumeration of different verification flags.
*/
-typedef enum dane_state_flags_t
+typedef enum dane_state_flags_t
{
DANE_F_IGNORE_LOCAL_RESOLVER = 1,
DANE_F_INSECURE=2,
@@ -109,6 +109,9 @@ int dane_state_init (dane_state_t* s, unsigned int flags);
int dane_state_set_dlv_file(dane_state_t s, const char* file);
void dane_state_deinit (dane_state_t s);
+
+int dane_raw_tlsa(dane_state_t s, dane_query_t *r, char *const*dane_data, const int *dane_data_len, int secure, int bogus);
+
int dane_query_tlsa(dane_state_t s, dane_query_t *r, const char* host, const char* proto, unsigned int port);
dane_query_status_t dane_query_status(dane_query_t q);
@@ -130,7 +133,7 @@ const char* dane_cert_usage_name(dane_cert_usage_t usage);
*
* Enumeration of different verification status flags.
*/
-typedef enum dane_verify_flags_t
+typedef enum dane_verify_flags_t
{
DANE_VFLAG_FAIL_IF_NOT_CHECKED = 1,
DANE_VFLAG_ONLY_CHECK_EE_USAGE = 1<<1,
@@ -145,7 +148,7 @@ typedef enum dane_verify_flags_t
*
* Enumeration of different verification status flags.
*/
-typedef enum dane_verify_status_t
+typedef enum dane_verify_status_t
{
DANE_VERIFY_CA_CONSTRAINTS_VIOLATED = 1,
DANE_VERIFY_CERT_DIFFERS = 1<<1,