static void dane_check(const char *host, const char *proto, unsigned int port, common_info_st * cinfo) { #ifdef HAVE_DANE dane_state_t s; dane_query_t q; int ret, retcode = 1; unsigned entries; unsigned int flags = DANE_F_IGNORE_LOCAL_RESOLVER, i; unsigned int usage, type, match; gnutls_datum_t data, file; size_t size; unsigned del = 0; unsigned vflags = DANE_VFLAG_FAIL_IF_NOT_CHECKED; const char *cstr; char *str; gnutls_x509_crt_t *clist = NULL; unsigned int clist_size = 0; gnutls_datum_t certs[MAX_CLIST_SIZE]; if (ENABLED_OPT(LOCAL_DNS)) flags = 0; if (HAVE_OPT(INSECURE)) flags |= DANE_F_INSECURE; if (HAVE_OPT(CHECK_EE)) vflags |= DANE_VFLAG_ONLY_CHECK_EE_USAGE; if (HAVE_OPT(CHECK_CA)) vflags |= DANE_VFLAG_ONLY_CHECK_CA_USAGE; if (!cinfo->cert) { const char *app_proto = NULL; if (HAVE_OPT(APP_PROTO)) app_proto = OPT_ARG(APP_PROTO); cinfo->cert = obtain_cert(host, proto, port, app_proto, HAVE_OPT(QUIET)); del = 1; } if (!HAVE_OPT(QUIET)) fprintf(stderr, "Querying DNS for %s (%s:%d)...\n", host, proto, port); ret = dane_state_init(&s, flags); if (ret < 0) { fprintf(stderr, "dane_state_init: %s\n", dane_strerror(ret)); retcode = 1; goto error; } if (HAVE_OPT(DLV)) { ret = dane_state_set_dlv_file(s, OPT_ARG(DLV)); if (ret < 0) { fprintf(stderr, "dane_state_set_dlv_file: %s\n", dane_strerror(ret)); retcode = 1; goto error; } } ret = dane_query_tlsa(s, &q, host, proto, port); if (ret < 0) { fprintf(stderr, "dane_query_tlsa: %s\n", dane_strerror(ret)); retcode = 1; goto error; } if (ENABLED_OPT(PRINT_RAW)) { gnutls_datum_t t; char **dane_data; int *dane_data_len; int secure; int bogus; ret = dane_query_to_raw_tlsa(q, &entries, &dane_data, &dane_data_len, &secure, &bogus); if (ret < 0) { fprintf(stderr, "dane_query_to_raw_tlsa: %s\n", dane_strerror(ret)); retcode = 1; goto error; } for (i=0;i<entries;i++) { size_t str_size; t.data = (void*)dane_data[i]; t.size = dane_data_len[i]; str_size = t.size * 2 + 1; str = gnutls_malloc(str_size); ret = gnutls_hex_encode(&t, str, &str_size); if (ret < 0) { fprintf(stderr, "gnutls_hex_encode: %s\n", dane_strerror(ret)); retcode = 1; goto error; } fprintf(outfile, "[%u]: %s\n", i, str); gnutls_free(str); } fprintf(outfile, "\n"); } if (cinfo->cert) { ret = gnutls_load_file(cinfo->cert, &file); if (ret < 0) { fprintf(stderr, "gnutls_load_file: %s\n", gnutls_strerror(ret)); retcode = 1; goto error; } ret = gnutls_x509_crt_list_import2(&clist, &clist_size, &file, cinfo-> incert_format, 0); if (ret < 0) { fprintf(stderr, "gnutls_x509_crt_list_import2: %s\n", gnutls_strerror(ret)); retcode = 1; goto error; } if (clist_size > 0) { for (i = 0; i < MIN(MAX_CLIST_SIZE,clist_size); i++) { ret = gnutls_x509_crt_export2(clist [i], GNUTLS_X509_FMT_DER, &certs [i]); if (ret < 0) { fprintf(stderr, "gnutls_x509_crt_export2: %s\n", gnutls_strerror (ret)); retcode = 1; goto error; } } } } entries = dane_query_entries(q); for (i = 0; i < entries; i++) { ret = dane_query_data(q, i, &usage, &type, &match, &data); if (ret < 0) { fprintf(stderr, "dane_query_data: %s\n", dane_strerror(ret)); retcode = 1; goto error; } size = lbuffer_size; ret = gnutls_hex_encode(&data, (void *) lbuffer, &size); if (ret < 0) { fprintf(stderr, "gnutls_hex_encode: %s\n", dane_strerror(ret)); retcode = 1; goto error; } if (entries > 1 && !HAVE_OPT(QUIET)) fprintf(outfile, "\n==== Entry %d ====\n", i + 1); fprintf(outfile, "_%u._%s.%s. IN TLSA ( %.2x %.2x %.2x %s )\n", port, proto, host, usage, type, match, lbuffer); if (!HAVE_OPT(QUIET)) { cstr = dane_cert_usage_name(usage); if (cstr == NULL) cstr= "Unknown"; fprintf(outfile, "Certificate usage: %s (%.2x)\n", cstr, usage); cstr = dane_cert_type_name(type); if (cstr == NULL) cstr= "Unknown"; fprintf(outfile, "Certificate type: %s (%.2x)\n", cstr, type); cstr = dane_match_type_name(match); if (cstr == NULL) cstr= "Unknown"; fprintf(outfile, "Contents: %s (%.2x)\n", cstr, match); fprintf(outfile, "Data: %s\n", lbuffer); } /* Verify the DANE data */ if (cinfo->cert) { unsigned int status; gnutls_datum_t out; ret = dane_verify_crt(s, certs, clist_size, GNUTLS_CRT_X509, host, proto, port, 0, vflags, &status); if (ret < 0) { fprintf(stderr, "dane_verify_crt: %s\n", dane_strerror(ret)); retcode = 1; goto error; } ret = dane_verification_status_print(status, &out, 0); if (ret < 0) { fprintf(stderr, "dane_verification_status_print: %s\n", dane_strerror(ret)); retcode = 1; goto error; } if (!HAVE_OPT(QUIET)) fprintf(outfile, "\nVerification: %s\n", out.data); gnutls_free(out.data); /* if there is at least one correct accept */ if (status == 0) retcode = 0; } else { fprintf(stderr, "\nCertificate could not be obtained. You can explicitly load the certificate using --load-certificate.\n"); } } if (clist_size > 0) { for (i = 0; i < clist_size; i++) { gnutls_free(certs[i].data); gnutls_x509_crt_deinit(clist[i]); } gnutls_free(clist); } dane_query_deinit(q); dane_state_deinit(s); error: if (del != 0 && cinfo->cert) { remove(cinfo->cert); } exit(retcode); #else fprintf(stderr, "This functionality is disabled (GnuTLS was not compiled with support for DANE).\n"); return; #endif }
static void dane_check(const char *host, const char *proto, unsigned int port, common_info_st * cinfo) { #ifdef HAVE_DANE dane_state_t s; dane_query_t q; int ret, retcode = 0; unsigned entries; unsigned int flags = DANE_F_IGNORE_LOCAL_RESOLVER, i; unsigned int usage, type, match; gnutls_datum_t data, file; size_t size; unsigned vflags = DANE_VFLAG_FAIL_IF_NOT_CHECKED; if (ENABLED_OPT(LOCAL_DNS)) flags = 0; if (HAVE_OPT(INSECURE)) flags |= DANE_F_INSECURE; if (HAVE_OPT(CHECK_EE)) vflags |= DANE_VFLAG_ONLY_CHECK_EE_USAGE; if (HAVE_OPT(CHECK_CA)) vflags |= DANE_VFLAG_ONLY_CHECK_CA_USAGE; printf("Querying %s (%s:%d)...\n", host, proto, port); ret = dane_state_init(&s, flags); if (ret < 0) { fprintf(stderr, "dane_state_init: %s\n", dane_strerror(ret)); exit(1); } if (HAVE_OPT(DLV)) { ret = dane_state_set_dlv_file(s, OPT_ARG(DLV)); if (ret < 0) { fprintf(stderr, "dane_state_set_dlv_file: %s\n", dane_strerror(ret)); exit(1); } } ret = dane_query_tlsa(s, &q, host, proto, port); if (ret < 0) { fprintf(stderr, "dane_query_tlsa: %s\n", dane_strerror(ret)); exit(1); } entries = dane_query_entries(q); for (i = 0; i < entries; i++) { ret = dane_query_data(q, i, &usage, &type, &match, &data); if (ret < 0) { fprintf(stderr, "dane_query_data: %s\n", dane_strerror(ret)); exit(1); } size = buffer_size; ret = gnutls_hex_encode(&data, (void *) buffer, &size); if (ret < 0) { fprintf(stderr, "gnutls_hex_encode: %s\n", dane_strerror(ret)); exit(1); } if (entries > 1) printf("\nEntry %d:\n", i + 1); fprintf(outfile, "_%u._%s.%s. IN TLSA ( %.2x %.2x %.2x %s )\n", port, proto, host, usage, type, match, buffer); printf("Certificate usage: %s (%.2x)\n", dane_cert_usage_name(usage), usage); printf("Certificate type: %s (%.2x)\n", dane_cert_type_name(type), type); printf("Contents: %s (%.2x)\n", dane_match_type_name(match), match); printf("Data: %s\n", buffer); /* Verify the DANE data */ if (cinfo->cert) { gnutls_x509_crt_t *clist; unsigned int clist_size, status; ret = gnutls_load_file(cinfo->cert, &file); if (ret < 0) { fprintf(stderr, "gnutls_load_file: %s\n", gnutls_strerror(ret)); exit(1); } ret = gnutls_x509_crt_list_import2(&clist, &clist_size, &file, cinfo-> incert_format, 0); if (ret < 0) { fprintf(stderr, "gnutls_x509_crt_list_import2: %s\n", gnutls_strerror(ret)); exit(1); } if (clist_size > 0) { gnutls_datum_t certs[clist_size]; gnutls_datum_t out; unsigned int i; for (i = 0; i < clist_size; i++) { ret = gnutls_x509_crt_export2(clist [i], GNUTLS_X509_FMT_DER, &certs [i]); if (ret < 0) { fprintf(stderr, "gnutls_x509_crt_export2: %s\n", gnutls_strerror (ret)); exit(1); } } ret = dane_verify_crt(s, certs, clist_size, GNUTLS_CRT_X509, host, proto, port, 0, vflags, &status); if (ret < 0) { fprintf(stderr, "dane_verify_crt: %s\n", dane_strerror(ret)); exit(1); } ret = dane_verification_status_print(status, &out, 0); if (ret < 0) { fprintf(stderr, "dane_verification_status_print: %s\n", dane_strerror(ret)); exit(1); } printf("\nVerification: %s\n", out.data); gnutls_free(out.data); if (status != 0) retcode = 1; for (i = 0; i < clist_size; i++) { gnutls_free(certs[i].data); gnutls_x509_crt_deinit(clist[i]); } gnutls_free(clist); } } else { fprintf(stderr, "\nCertificate was not verified. Use --load-certificate.\n"); } } dane_query_deinit(q); dane_state_deinit(s); exit(retcode); #else fprintf(stderr, "This functionality was disabled (GnuTLS was not compiled with support for DANE).\n"); return; #endif }