Example #1
0
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
}
Example #2
0
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
}