Blame src/danetool.c

Packit Service 4684c1
/*
Packit Service 4684c1
 * Copyright (C) 2012 Free Software Foundation, Inc.
Packit Service 4684c1
 *
Packit Service 4684c1
 * This file is part of GnuTLS.
Packit Service 4684c1
 *
Packit Service 4684c1
 * GnuTLS is free software: you can redistribute it and/or modify it
Packit Service 4684c1
 * under the terms of the GNU General Public License as published by
Packit Service 4684c1
 * the Free Software Foundation, either version 3 of the License, or
Packit Service 4684c1
 * (at your option) any later version.
Packit Service 4684c1
 *
Packit Service 4684c1
 * GnuTLS is distributed in the hope that it will be useful, but
Packit Service 4684c1
 * WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 4684c1
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service 4684c1
 * General Public License for more details.
Packit Service 4684c1
 *
Packit Service 4684c1
 * You should have received a copy of the GNU General Public License
Packit Service 4684c1
 * along with this program.  If not, see
Packit Service 4684c1
 * <https://www.gnu.org/licenses/>.
Packit Service 4684c1
 */
Packit Service 4684c1
Packit Service 4684c1
#include <config.h>
Packit Service 4684c1
Packit Service 4684c1
#include <gnutls/gnutls.h>
Packit Service 4684c1
#include <gnutls/x509.h>
Packit Service 4684c1
#include <gnutls/openpgp.h>
Packit Service 4684c1
#include <gnutls/pkcs12.h>
Packit Service 4684c1
#include <gnutls/pkcs11.h>
Packit Service 4684c1
#include <gnutls/abstract.h>
Packit Service 4684c1
#include <gnutls/crypto.h>
Packit Service 4684c1
Packit Service 4684c1
#ifdef HAVE_DANE
Packit Service 4684c1
#include <gnutls/dane.h>
Packit Service 4684c1
#endif
Packit Service 4684c1
Packit Service 4684c1
#include <stdio.h>
Packit Service 4684c1
#include <stdlib.h>
Packit Service 4684c1
#include <string.h>
Packit Service 4684c1
#include <ctype.h>
Packit Service 4684c1
#include <time.h>
Packit Service 4684c1
#include <unistd.h>
Packit Service 4684c1
#include <errno.h>
Packit Service 4684c1
#include <sys/types.h>
Packit Service 4684c1
#include <sys/stat.h>
Packit Service 4684c1
#include <fcntl.h>
Packit Service 4684c1
Packit Service 4684c1
/* Gnulib portability files. */
Packit Service 4684c1
#include <read-file.h>
Packit Service 4684c1
#include <minmax.h>
Packit Service 4684c1
Packit Service 4684c1
#include <common.h>
Packit Service 4684c1
#include "danetool-args.h"
Packit Service 4684c1
#include "certtool-common.h"
Packit Service 4684c1
#include "socket.h"
Packit Service 4684c1
Packit Service 4684c1
static const char *obtain_cert(const char *hostname, const char *proto, const char *service,
Packit Service 4684c1
				const char *app_proto, unsigned quiet);
Packit Service 4684c1
static void cmd_parser(int argc, char **argv);
Packit Service 4684c1
static void dane_info(const char *host, const char *proto,
Packit Service 4684c1
		      const char *service, unsigned int ca,
Packit Service 4684c1
		      unsigned int domain, common_info_st * cinfo);
Packit Service 4684c1
Packit Service 4684c1
static void dane_check(const char *host, const char *proto,
Packit Service 4684c1
		       const char *service, common_info_st * cinfo);
Packit Service 4684c1
Packit Service 4684c1
FILE *outfile;
Packit Service 4684c1
static const char *outfile_name = NULL;
Packit Service 4684c1
static gnutls_digest_algorithm_t default_dig;
Packit Service 4684c1
Packit Service 4684c1
/* non interactive operation if set
Packit Service 4684c1
 */
Packit Service 4684c1
int batch = 0;
Packit Service 4684c1
int ask_pass = 0;
Packit Service 4684c1
Packit Service 4684c1
void app_exit(int val)
Packit Service 4684c1
{
Packit Service 4684c1
	if (val != 0) {
Packit Service 4684c1
		if (outfile_name)
Packit Service 4684c1
			(void)remove(outfile_name);
Packit Service 4684c1
	}
Packit Service 4684c1
	exit(val);
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
static void tls_log_func(int level, const char *str)
Packit Service 4684c1
{
Packit Service 4684c1
	fprintf(stderr, "|<%d>| %s", level, str);
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
int main(int argc, char **argv)
Packit Service 4684c1
{
Packit Service 4684c1
	fix_lbuffer(0);
Packit Service 4684c1
	cmd_parser(argc, argv);
Packit Service 4684c1
Packit Service 4684c1
	return 0;
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
Packit Service 4684c1
static void cmd_parser(int argc, char **argv)
Packit Service 4684c1
{
Packit Service 4684c1
	int ret, privkey_op = 0;
Packit Service 4684c1
	common_info_st cinfo;
Packit Service 4684c1
	const char *proto = "tcp";
Packit Service 4684c1
	char service[32] = "443";
Packit Service 4684c1
Packit Service 4684c1
	optionProcess(&danetoolOptions, argc, argv);
Packit Service 4684c1
Packit Service 4684c1
	if (HAVE_OPT(OUTFILE)) {
Packit Service 4684c1
		outfile = safe_open_rw(OPT_ARG(OUTFILE), privkey_op);
Packit Service 4684c1
		if (outfile == NULL) {
Packit Service 4684c1
			fprintf(stderr, "%s", OPT_ARG(OUTFILE));
Packit Service 4684c1
			app_exit(1);
Packit Service 4684c1
		}
Packit Service 4684c1
		outfile_name = OPT_ARG(OUTFILE);
Packit Service 4684c1
	} else
Packit Service 4684c1
		outfile = stdout;
Packit Service 4684c1
Packit Service 4684c1
	default_dig = GNUTLS_DIG_UNKNOWN;
Packit Service 4684c1
	if (HAVE_OPT(HASH)) {
Packit Service 4684c1
		if (strcasecmp(OPT_ARG(HASH), "md5") == 0) {
Packit Service 4684c1
			fprintf(stderr,
Packit Service 4684c1
				"Warning: MD5 is broken, and should not be used any more for digital signatures.\n");
Packit Service 4684c1
			default_dig = GNUTLS_DIG_MD5;
Packit Service 4684c1
		} else if (strcasecmp(OPT_ARG(HASH), "sha1") == 0)
Packit Service 4684c1
			default_dig = GNUTLS_DIG_SHA1;
Packit Service 4684c1
		else if (strcasecmp(OPT_ARG(HASH), "sha256") == 0)
Packit Service 4684c1
			default_dig = GNUTLS_DIG_SHA256;
Packit Service 4684c1
		else if (strcasecmp(OPT_ARG(HASH), "sha224") == 0)
Packit Service 4684c1
			default_dig = GNUTLS_DIG_SHA224;
Packit Service 4684c1
		else if (strcasecmp(OPT_ARG(HASH), "sha384") == 0)
Packit Service 4684c1
			default_dig = GNUTLS_DIG_SHA384;
Packit Service 4684c1
		else if (strcasecmp(OPT_ARG(HASH), "sha512") == 0)
Packit Service 4684c1
			default_dig = GNUTLS_DIG_SHA512;
Packit Service 4684c1
		else if (strcasecmp(OPT_ARG(HASH), "rmd160") == 0)
Packit Service 4684c1
			default_dig = GNUTLS_DIG_RMD160;
Packit Service 4684c1
		else {
Packit Service 4684c1
			fprintf(stderr, "invalid hash: %s", OPT_ARG(HASH));
Packit Service 4684c1
			app_exit(1);
Packit Service 4684c1
		}
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	gnutls_global_set_log_function(tls_log_func);
Packit Service 4684c1
Packit Service 4684c1
	if (HAVE_OPT(DEBUG)) {
Packit Service 4684c1
		gnutls_global_set_log_level(OPT_VALUE_DEBUG);
Packit Service 4684c1
		printf("Setting log level to %d\n", (int) OPT_VALUE_DEBUG);
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	if ((ret = gnutls_global_init()) < 0) {
Packit Service 4684c1
		fprintf(stderr, "global_init: %s", gnutls_strerror(ret));
Packit Service 4684c1
		app_exit(1);
Packit Service 4684c1
	}
Packit Service 4684c1
#ifdef ENABLE_PKCS11
Packit Service 4684c1
	pkcs11_common(NULL);
Packit Service 4684c1
#endif
Packit Service 4684c1
Packit Service 4684c1
	memset(&cinfo, 0, sizeof(cinfo));
Packit Service 4684c1
Packit Service 4684c1
	if (HAVE_OPT(INDER) || HAVE_OPT(INRAW))
Packit Service 4684c1
		cinfo.incert_format = GNUTLS_X509_FMT_DER;
Packit Service 4684c1
	else
Packit Service 4684c1
		cinfo.incert_format = GNUTLS_X509_FMT_PEM;
Packit Service 4684c1
Packit Service 4684c1
	if (HAVE_OPT(VERBOSE))
Packit Service 4684c1
		cinfo.verbose = 1;
Packit Service 4684c1
Packit Service 4684c1
	if (HAVE_OPT(LOAD_PUBKEY))
Packit Service 4684c1
		cinfo.pubkey = OPT_ARG(LOAD_PUBKEY);
Packit Service 4684c1
Packit Service 4684c1
	if (HAVE_OPT(LOAD_CERTIFICATE))
Packit Service 4684c1
		cinfo.cert = OPT_ARG(LOAD_CERTIFICATE);
Packit Service 4684c1
Packit Service 4684c1
	if (HAVE_OPT(PORT)) {
Packit Service 4684c1
		snprintf(service, sizeof(service), "%s", OPT_ARG(PORT));
Packit Service 4684c1
	} else {
Packit Service 4684c1
		if (HAVE_OPT(STARTTLS_PROTO))
Packit Service 4684c1
			snprintf(service, sizeof(service), "%s", starttls_proto_to_service(OPT_ARG(STARTTLS_PROTO)));
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	if (HAVE_OPT(PROTO))
Packit Service 4684c1
		proto = OPT_ARG(PROTO);
Packit Service 4684c1
Packit Service 4684c1
	if (HAVE_OPT(TLSA_RR))
Packit Service 4684c1
		dane_info(OPT_ARG(HOST), proto, service,
Packit Service 4684c1
			  HAVE_OPT(CA), ENABLED_OPT(DOMAIN), &cinfo);
Packit Service 4684c1
	else if (HAVE_OPT(CHECK))
Packit Service 4684c1
		dane_check(OPT_ARG(CHECK), proto, service, &cinfo);
Packit Service 4684c1
	else
Packit Service 4684c1
		USAGE(1);
Packit Service 4684c1
Packit Service 4684c1
	fclose(outfile);
Packit Service 4684c1
Packit Service 4684c1
#ifdef ENABLE_PKCS11
Packit Service 4684c1
	gnutls_pkcs11_deinit();
Packit Service 4684c1
#endif
Packit Service 4684c1
	gnutls_global_deinit();
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
#define MAX_CLIST_SIZE 32
Packit Service 4684c1
static void dane_check(const char *host, const char *proto,
Packit Service 4684c1
		       const char *service, common_info_st * cinfo)
Packit Service 4684c1
{
Packit Service 4684c1
#ifdef HAVE_DANE
Packit Service 4684c1
	dane_state_t s;
Packit Service 4684c1
	dane_query_t q;
Packit Service 4684c1
	int ret, retcode = 1;
Packit Service 4684c1
	unsigned entries;
Packit Service 4684c1
	unsigned int flags = DANE_F_IGNORE_LOCAL_RESOLVER, i;
Packit Service 4684c1
	unsigned int usage, type, match;
Packit Service 4684c1
	gnutls_datum_t data, file;
Packit Service 4684c1
	size_t size;
Packit Service 4684c1
	unsigned del = 0;
Packit Service 4684c1
	unsigned vflags = DANE_VFLAG_FAIL_IF_NOT_CHECKED;
Packit Service 4684c1
	const char *cstr;
Packit Service 4684c1
	char *str;
Packit Service 4684c1
	gnutls_x509_crt_t *clist = NULL;
Packit Service 4684c1
	unsigned int clist_size = 0;
Packit Service 4684c1
	gnutls_datum_t certs[MAX_CLIST_SIZE];
Packit Service 4684c1
	int port = service_to_port(service, proto);
Packit Service 4684c1
Packit Service 4684c1
	if (ENABLED_OPT(LOCAL_DNS))
Packit Service 4684c1
		flags = 0;
Packit Service 4684c1
Packit Service 4684c1
	if (HAVE_OPT(INSECURE))
Packit Service 4684c1
		flags |= DANE_F_INSECURE;
Packit Service 4684c1
Packit Service 4684c1
	if (HAVE_OPT(CHECK_EE))
Packit Service 4684c1
		vflags |= DANE_VFLAG_ONLY_CHECK_EE_USAGE;
Packit Service 4684c1
Packit Service 4684c1
	if (HAVE_OPT(CHECK_CA))
Packit Service 4684c1
		vflags |= DANE_VFLAG_ONLY_CHECK_CA_USAGE;
Packit Service 4684c1
Packit Service 4684c1
	if (!cinfo->cert) {
Packit Service 4684c1
		const char *app_proto = NULL;
Packit Service 4684c1
		if (HAVE_OPT(STARTTLS_PROTO))
Packit Service 4684c1
			app_proto = OPT_ARG(STARTTLS_PROTO);
Packit Service 4684c1
Packit Service 4684c1
		cinfo->cert = obtain_cert(host, proto, service, app_proto, HAVE_OPT(QUIET));
Packit Service 4684c1
		del = 1;
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	if (!HAVE_OPT(QUIET))
Packit Service 4684c1
		fprintf(stderr, "Querying DNS for %s (%s:%d)...\n", host, proto, port);
Packit Service 4684c1
	ret = dane_state_init(&s, flags);
Packit Service 4684c1
	if (ret < 0) {
Packit Service 4684c1
		fprintf(stderr, "dane_state_init: %s\n",
Packit Service 4684c1
			dane_strerror(ret));
Packit Service 4684c1
		retcode = 1;
Packit Service 4684c1
		goto error;
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	if (HAVE_OPT(DLV)) {
Packit Service 4684c1
		ret = dane_state_set_dlv_file(s, OPT_ARG(DLV));
Packit Service 4684c1
		if (ret < 0) {
Packit Service 4684c1
			fprintf(stderr, "dane_state_set_dlv_file: %s\n",
Packit Service 4684c1
				dane_strerror(ret));
Packit Service 4684c1
			retcode = 1;
Packit Service 4684c1
			goto error;
Packit Service 4684c1
		}
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	ret = dane_query_tlsa(s, &q, host, proto, port);
Packit Service 4684c1
	if (ret < 0) {
Packit Service 4684c1
		fprintf(stderr, "dane_query_tlsa: %s\n",
Packit Service 4684c1
			dane_strerror(ret));
Packit Service 4684c1
		retcode = 1;
Packit Service 4684c1
		goto error;
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	if (ENABLED_OPT(PRINT_RAW)) {
Packit Service 4684c1
		gnutls_datum_t t;
Packit Service 4684c1
		char **dane_data;
Packit Service 4684c1
		int *dane_data_len;
Packit Service 4684c1
		int secure;
Packit Service 4684c1
		int bogus;
Packit Service 4684c1
Packit Service 4684c1
		ret = dane_query_to_raw_tlsa(q, &entries, &dane_data,
Packit Service 4684c1
			&dane_data_len, &secure, &bogus);
Packit Service 4684c1
		if (ret < 0) {
Packit Service 4684c1
			fprintf(stderr, "dane_query_to_raw_tlsa: %s\n",
Packit Service 4684c1
				dane_strerror(ret));
Packit Service 4684c1
			retcode = 1;
Packit Service 4684c1
			goto error;
Packit Service 4684c1
		}
Packit Service 4684c1
Packit Service 4684c1
		for (i=0;i
Packit Service 4684c1
			size_t str_size;
Packit Service 4684c1
			t.data = (void*)dane_data[i];
Packit Service 4684c1
			t.size = dane_data_len[i];
Packit Service 4684c1
Packit Service 4684c1
			str_size = t.size * 2 + 1;
Packit Service 4684c1
			str = gnutls_malloc(str_size);
Packit Service 4684c1
Packit Service 4684c1
			ret = gnutls_hex_encode(&t, str, &str_size);
Packit Service 4684c1
			if (ret < 0) {
Packit Service 4684c1
				fprintf(stderr, "gnutls_hex_encode: %s\n",
Packit Service 4684c1
					dane_strerror(ret));
Packit Service 4684c1
				retcode = 1;
Packit Service 4684c1
				goto error;
Packit Service 4684c1
			}
Packit Service 4684c1
			fprintf(outfile, "[%u]: %s\n", i, str);
Packit Service 4684c1
			gnutls_free(str);
Packit Service 4684c1
		}
Packit Service 4684c1
		fprintf(outfile, "\n");
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	if (cinfo->cert) {
Packit Service 4684c1
		ret = gnutls_load_file(cinfo->cert, &file;;
Packit Service 4684c1
		if (ret < 0) {
Packit Service 4684c1
			fprintf(stderr, "gnutls_load_file: %s\n",
Packit Service 4684c1
				gnutls_strerror(ret));
Packit Service 4684c1
			retcode = 1;
Packit Service 4684c1
			goto error;
Packit Service 4684c1
		}
Packit Service 4684c1
Packit Service 4684c1
		ret =
Packit Service 4684c1
		    gnutls_x509_crt_list_import2(&clist,
Packit Service 4684c1
						 &clist_size,
Packit Service 4684c1
						 &file,
Packit Service 4684c1
						 cinfo->
Packit Service 4684c1
						 incert_format, 0);
Packit Service 4684c1
		if (ret < 0) {
Packit Service 4684c1
			fprintf(stderr,
Packit Service 4684c1
				"gnutls_x509_crt_list_import2: %s\n",
Packit Service 4684c1
				gnutls_strerror(ret));
Packit Service 4684c1
			retcode = 1;
Packit Service 4684c1
			goto error;
Packit Service 4684c1
		}
Packit Service 4684c1
Packit Service 4684c1
		if (clist_size > 0) {
Packit Service 4684c1
			for (i = 0; i < MIN(MAX_CLIST_SIZE,clist_size); i++) {
Packit Service 4684c1
				ret =
Packit Service 4684c1
				    gnutls_x509_crt_export2(clist
Packit Service 4684c1
							    [i],
Packit Service 4684c1
							    GNUTLS_X509_FMT_DER,
Packit Service 4684c1
							    &certs
Packit Service 4684c1
							    [i]);
Packit Service 4684c1
				if (ret < 0) {
Packit Service 4684c1
					fprintf(stderr,
Packit Service 4684c1
						"gnutls_x509_crt_export2: %s\n",
Packit Service 4684c1
						gnutls_strerror
Packit Service 4684c1
						(ret));
Packit Service 4684c1
					retcode = 1;
Packit Service 4684c1
					goto error;
Packit Service 4684c1
				}
Packit Service 4684c1
			}
Packit Service 4684c1
		}
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	entries = dane_query_entries(q);
Packit Service 4684c1
	for (i = 0; i < entries; i++) {
Packit Service 4684c1
		ret = dane_query_data(q, i, &usage, &type, &match, &data);
Packit Service 4684c1
		if (ret < 0) {
Packit Service 4684c1
			fprintf(stderr, "dane_query_data: %s\n",
Packit Service 4684c1
				dane_strerror(ret));
Packit Service 4684c1
			retcode = 1;
Packit Service 4684c1
			goto error;
Packit Service 4684c1
		}
Packit Service 4684c1
Packit Service 4684c1
		size = lbuffer_size;
Packit Service 4684c1
		ret = gnutls_hex_encode(&data, (void *) lbuffer, &size);
Packit Service 4684c1
		if (ret < 0) {
Packit Service 4684c1
			fprintf(stderr, "gnutls_hex_encode: %s\n",
Packit Service 4684c1
				dane_strerror(ret));
Packit Service 4684c1
			retcode = 1;
Packit Service 4684c1
			goto error;
Packit Service 4684c1
		}
Packit Service 4684c1
Packit Service 4684c1
		if (entries > 1 && !HAVE_OPT(QUIET))
Packit Service 4684c1
			fprintf(outfile, "\n==== Entry %d ====\n", i + 1);
Packit Service 4684c1
Packit Service 4684c1
		fprintf(outfile,
Packit Service 4684c1
			"_%u._%s.%s. IN TLSA ( %.2x %.2x %.2x %s )\n",
Packit Service 4684c1
			port, proto, host, usage, type, match, lbuffer);
Packit Service 4684c1
Packit Service 4684c1
		if (!HAVE_OPT(QUIET)) {
Packit Service 4684c1
			cstr = dane_cert_usage_name(usage);
Packit Service 4684c1
			if (cstr == NULL) cstr= "Unknown";
Packit Service 4684c1
			fprintf(outfile, "Certificate usage: %s (%.2x)\n", cstr, usage);
Packit Service 4684c1
Packit Service 4684c1
			cstr = dane_cert_type_name(type);
Packit Service 4684c1
			if (cstr == NULL) cstr= "Unknown";
Packit Service 4684c1
			fprintf(outfile, "Certificate type:  %s (%.2x)\n", cstr, type);
Packit Service 4684c1
Packit Service 4684c1
			cstr = dane_match_type_name(match);
Packit Service 4684c1
			if (cstr == NULL) cstr= "Unknown";
Packit Service 4684c1
			fprintf(outfile, "Contents:	  %s (%.2x)\n", cstr, match);
Packit Service 4684c1
			fprintf(outfile, "Data:	      %s\n", lbuffer);
Packit Service 4684c1
		}
Packit Service 4684c1
Packit Service 4684c1
		/* Verify the DANE data */
Packit Service 4684c1
		if (cinfo->cert) {
Packit Service 4684c1
			unsigned int status;
Packit Service 4684c1
			gnutls_datum_t out;
Packit Service 4684c1
Packit Service 4684c1
			ret =
Packit Service 4684c1
			    dane_verify_crt(s, certs, clist_size,
Packit Service 4684c1
					    GNUTLS_CRT_X509, host,
Packit Service 4684c1
					    proto, port, 0, vflags,
Packit Service 4684c1
					    &status);
Packit Service 4684c1
			if (ret < 0) {
Packit Service 4684c1
				fprintf(stderr,
Packit Service 4684c1
					"dane_verify_crt: %s\n",
Packit Service 4684c1
					dane_strerror(ret));
Packit Service 4684c1
				retcode = 1;
Packit Service 4684c1
				goto error;
Packit Service 4684c1
			}
Packit Service 4684c1
Packit Service 4684c1
			ret =
Packit Service 4684c1
			    dane_verification_status_print(status,
Packit Service 4684c1
							   &out,
Packit Service 4684c1
							   0);
Packit Service 4684c1
			if (ret < 0) {
Packit Service 4684c1
				fprintf(stderr,
Packit Service 4684c1
					"dane_verification_status_print: %s\n",
Packit Service 4684c1
					dane_strerror(ret));
Packit Service 4684c1
				retcode = 1;
Packit Service 4684c1
				goto error;
Packit Service 4684c1
			}
Packit Service 4684c1
Packit Service 4684c1
			if (!HAVE_OPT(QUIET))
Packit Service 4684c1
				fprintf(outfile, "\nVerification: %s\n", out.data);
Packit Service 4684c1
			gnutls_free(out.data);
Packit Service 4684c1
Packit Service 4684c1
			/* if there is at least one correct accept */
Packit Service 4684c1
			if (status == 0)
Packit Service 4684c1
				retcode = 0;
Packit Service 4684c1
		} else {
Packit Service 4684c1
			fprintf(stderr,
Packit Service 4684c1
				"\nCertificate could not be obtained. You can explicitly load the certificate using --load-certificate.\n");
Packit Service 4684c1
		}
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	if (clist_size > 0) {
Packit Service 4684c1
		for (i = 0; i < clist_size; i++) {
Packit Service 4684c1
			gnutls_free(certs[i].data);
Packit Service 4684c1
			gnutls_x509_crt_deinit(clist[i]);
Packit Service 4684c1
		}
Packit Service 4684c1
		gnutls_free(clist);
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
Packit Service 4684c1
Packit Service 4684c1
	dane_query_deinit(q);
Packit Service 4684c1
	dane_state_deinit(s);
Packit Service 4684c1
Packit Service 4684c1
 error:
Packit Service 4684c1
	if (del != 0 && cinfo->cert) {
Packit Service 4684c1
		(void)remove(cinfo->cert);
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	app_exit(retcode);
Packit Service 4684c1
#else
Packit Service 4684c1
	fprintf(stderr,
Packit Service 4684c1
		"This functionality is disabled (GnuTLS was not compiled with support for DANE).\n");
Packit Service 4684c1
	return;
Packit Service 4684c1
#endif
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
static void dane_info(const char *host, const char *proto,
Packit Service 4684c1
		      const char *service, unsigned int ca,
Packit Service 4684c1
		      unsigned int domain, common_info_st * cinfo)
Packit Service 4684c1
{
Packit Service 4684c1
	gnutls_pubkey_t pubkey;
Packit Service 4684c1
	gnutls_x509_crt_t crt;
Packit Service 4684c1
	unsigned char digest[64];
Packit Service 4684c1
	gnutls_datum_t t;
Packit Service 4684c1
	int ret;
Packit Service 4684c1
	unsigned int usage, selector, type;
Packit Service 4684c1
	size_t size;
Packit Service 4684c1
	int port = service_to_port(service, proto);
Packit Service 4684c1
Packit Service 4684c1
	if (proto == NULL)
Packit Service 4684c1
		proto = "tcp";
Packit Service 4684c1
Packit Service 4684c1
	crt = load_cert(0, cinfo);
Packit Service 4684c1
	if (crt != NULL && HAVE_OPT(X509)) {
Packit Service 4684c1
		selector = 0;	/* X.509 */
Packit Service 4684c1
Packit Service 4684c1
		size = lbuffer_size;
Packit Service 4684c1
		ret =
Packit Service 4684c1
		    gnutls_x509_crt_export(crt, GNUTLS_X509_FMT_DER,
Packit Service 4684c1
					   lbuffer, &size);
Packit Service 4684c1
		if (ret < 0) {
Packit Service 4684c1
			fprintf(stderr, "export error: %s\n",
Packit Service 4684c1
				gnutls_strerror(ret));
Packit Service 4684c1
			app_exit(1);
Packit Service 4684c1
		}
Packit Service 4684c1
Packit Service 4684c1
		gnutls_x509_crt_deinit(crt);
Packit Service 4684c1
	} else {		/* use public key only */
Packit Service 4684c1
Packit Service 4684c1
		selector = 1;
Packit Service 4684c1
Packit Service 4684c1
		ret = gnutls_pubkey_init(&pubkey);
Packit Service 4684c1
		if (ret < 0) {
Packit Service 4684c1
			fprintf(stderr, "pubkey_init: %s\n",
Packit Service 4684c1
				gnutls_strerror(ret));
Packit Service 4684c1
			app_exit(1);
Packit Service 4684c1
		}
Packit Service 4684c1
Packit Service 4684c1
		if (crt != NULL) {
Packit Service 4684c1
Packit Service 4684c1
			ret = gnutls_pubkey_import_x509(pubkey, crt, 0);
Packit Service 4684c1
			if (ret < 0) {
Packit Service 4684c1
				fprintf(stderr, "pubkey_import_x509: %s\n",
Packit Service 4684c1
					gnutls_strerror(ret));
Packit Service 4684c1
				app_exit(1);
Packit Service 4684c1
			}
Packit Service 4684c1
Packit Service 4684c1
			size = lbuffer_size;
Packit Service 4684c1
			ret =
Packit Service 4684c1
			    gnutls_pubkey_export(pubkey,
Packit Service 4684c1
						 GNUTLS_X509_FMT_DER,
Packit Service 4684c1
						 lbuffer, &size);
Packit Service 4684c1
			if (ret < 0) {
Packit Service 4684c1
				fprintf(stderr, "pubkey_export: %s\n",
Packit Service 4684c1
					gnutls_strerror(ret));
Packit Service 4684c1
				app_exit(1);
Packit Service 4684c1
			}
Packit Service 4684c1
Packit Service 4684c1
			gnutls_x509_crt_deinit(crt);
Packit Service 4684c1
		} else {
Packit Service 4684c1
			pubkey = load_pubkey(1, cinfo);
Packit Service 4684c1
Packit Service 4684c1
			size = lbuffer_size;
Packit Service 4684c1
			ret =
Packit Service 4684c1
			    gnutls_pubkey_export(pubkey,
Packit Service 4684c1
						 GNUTLS_X509_FMT_DER,
Packit Service 4684c1
						 lbuffer, &size);
Packit Service 4684c1
			if (ret < 0) {
Packit Service 4684c1
				fprintf(stderr, "export error: %s\n",
Packit Service 4684c1
					gnutls_strerror(ret));
Packit Service 4684c1
				app_exit(1);
Packit Service 4684c1
			}
Packit Service 4684c1
		}
Packit Service 4684c1
Packit Service 4684c1
		gnutls_pubkey_deinit(pubkey);
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	if (default_dig != GNUTLS_DIG_SHA256
Packit Service 4684c1
	    && default_dig != GNUTLS_DIG_SHA512) {
Packit Service 4684c1
		if (default_dig != GNUTLS_DIG_UNKNOWN)
Packit Service 4684c1
			fprintf(stderr,
Packit Service 4684c1
				"Unsupported digest. Assuming SHA256.\n");
Packit Service 4684c1
		default_dig = GNUTLS_DIG_SHA256;
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	ret = gnutls_hash_fast(default_dig, lbuffer, size, digest);
Packit Service 4684c1
	if (ret < 0) {
Packit Service 4684c1
		fprintf(stderr, "hash error: %s\n", gnutls_strerror(ret));
Packit Service 4684c1
		app_exit(1);
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	if (default_dig == GNUTLS_DIG_SHA256)
Packit Service 4684c1
		type = 1;
Packit Service 4684c1
	else
Packit Service 4684c1
		type = 2;
Packit Service 4684c1
Packit Service 4684c1
	/* DANE certificate classification crap */
Packit Service 4684c1
	if (domain == 0) {
Packit Service 4684c1
		if (ca)
Packit Service 4684c1
			usage = 0;
Packit Service 4684c1
		else
Packit Service 4684c1
			usage = 1;
Packit Service 4684c1
	} else {
Packit Service 4684c1
		if (ca)
Packit Service 4684c1
			usage = 2;
Packit Service 4684c1
		else
Packit Service 4684c1
			usage = 3;
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	t.data = digest;
Packit Service 4684c1
	t.size = gnutls_hash_get_len(default_dig);
Packit Service 4684c1
Packit Service 4684c1
	size = lbuffer_size;
Packit Service 4684c1
	ret = gnutls_hex_encode(&t, (void *) lbuffer, &size);
Packit Service 4684c1
	if (ret < 0) {
Packit Service 4684c1
		fprintf(stderr, "hex encode error: %s\n",
Packit Service 4684c1
			gnutls_strerror(ret));
Packit Service 4684c1
		app_exit(1);
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	fprintf(outfile, "_%u._%s.%s. IN TLSA ( %.2x %.2x %.2x %s )\n",
Packit Service 4684c1
		port, proto, host, usage, selector, type, lbuffer);
Packit Service 4684c1
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
Packit Service 4684c1
struct priv_st {
Packit Service 4684c1
	int fd;
Packit Service 4684c1
	int found;
Packit Service 4684c1
};
Packit Service 4684c1
Packit Service 4684c1
#ifdef HAVE_DANE
Packit Service 4684c1
static int cert_callback(gnutls_session_t session)
Packit Service 4684c1
{
Packit Service 4684c1
	const gnutls_datum_t *cert_list;
Packit Service 4684c1
	unsigned int cert_list_size = 0;
Packit Service 4684c1
	int ret;
Packit Service 4684c1
	unsigned i;
Packit Service 4684c1
	gnutls_datum_t t;
Packit Service 4684c1
	struct priv_st *priv;
Packit Service 4684c1
Packit Service 4684c1
	cert_list = gnutls_certificate_get_peers(session, &cert_list_size);
Packit Service 4684c1
	if (cert_list_size == 0) {
Packit Service 4684c1
		fprintf(stderr, "no certificates sent by server!\n");
Packit Service 4684c1
		return -1;
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	priv = gnutls_session_get_ptr(session);
Packit Service 4684c1
Packit Service 4684c1
	for (i=0;i
Packit Service 4684c1
		ret = gnutls_pem_base64_encode_alloc("CERTIFICATE", &cert_list[i], &t);
Packit Service 4684c1
		if (ret < 0) {
Packit Service 4684c1
			fprintf(stderr, "error[%d]: %s\n", __LINE__,
Packit Service 4684c1
				gnutls_strerror(ret));
Packit Service 4684c1
			app_exit(1);
Packit Service 4684c1
		}
Packit Service 4684c1
Packit Service 4684c1
		write(priv->fd, t.data, t.size);
Packit Service 4684c1
		gnutls_free(t.data);
Packit Service 4684c1
	}
Packit Service 4684c1
	priv->found = 1;
Packit Service 4684c1
Packit Service 4684c1
	return -1;
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
static gnutls_certificate_credentials_t xcred;
Packit Service 4684c1
static int file_fd = -1;
Packit Service 4684c1
static unsigned udp = 0;
Packit Service 4684c1
Packit Service 4684c1
gnutls_session_t init_tls_session(const char *hostname)
Packit Service 4684c1
{
Packit Service 4684c1
	gnutls_session_t session;
Packit Service 4684c1
	int ret;
Packit Service 4684c1
	static struct priv_st priv;
Packit Service 4684c1
Packit Service 4684c1
	priv.found = 0;
Packit Service 4684c1
	priv.fd = file_fd;
Packit Service 4684c1
Packit Service 4684c1
	ret = gnutls_init(&session, (udp?GNUTLS_DATAGRAM:0)|GNUTLS_CLIENT);
Packit Service 4684c1
	if (ret < 0) {
Packit Service 4684c1
		fprintf(stderr, "error[%d]: %s\n", __LINE__,
Packit Service 4684c1
			gnutls_strerror(ret));
Packit Service 4684c1
		app_exit(1);
Packit Service 4684c1
	}
Packit Service 4684c1
	gnutls_session_set_ptr(session, &priv;;
Packit Service 4684c1
Packit Service 4684c1
	ret = gnutls_set_default_priority(session);
Packit Service 4684c1
	if (ret < 0) {
Packit Service 4684c1
		fprintf(stderr, "error[%d]: %s\n", __LINE__,
Packit Service 4684c1
			gnutls_strerror(ret));
Packit Service 4684c1
		app_exit(1);
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	if (hostname && is_ip(hostname)==0) {
Packit Service 4684c1
		gnutls_server_name_set(session, GNUTLS_NAME_DNS, hostname, strlen(hostname));
Packit Service 4684c1
	}
Packit Service 4684c1
	gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, xcred);
Packit Service 4684c1
Packit Service 4684c1
	return session;
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
int do_handshake(socket_st * socket)
Packit Service 4684c1
{
Packit Service 4684c1
	int ret;
Packit Service 4684c1
Packit Service 4684c1
	do {
Packit Service 4684c1
		ret = gnutls_handshake(socket->session);
Packit Service 4684c1
	} while(ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_WARNING_ALERT_RECEIVED);
Packit Service 4684c1
	/* we don't care on the result */
Packit Service 4684c1
Packit Service 4684c1
	return 0;
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
Packit Service 4684c1
static const char *obtain_cert(const char *hostname, const char *proto, const char *service,
Packit Service 4684c1
				const char *app_proto, unsigned quiet)
Packit Service 4684c1
{
Packit Service 4684c1
	socket_st hd;
Packit Service 4684c1
	const char *txt_service;
Packit Service 4684c1
	static char tmpfile[32];
Packit Service 4684c1
	int ret;
Packit Service 4684c1
	const char *str = "Obtaining certificate from";
Packit Service 4684c1
	int socket_flags = 0;
Packit Service 4684c1
	struct priv_st *priv;
Packit Service 4684c1
Packit Service 4684c1
	ret = gnutls_certificate_allocate_credentials(&xcred);
Packit Service 4684c1
	if (ret < 0) {
Packit Service 4684c1
		fprintf(stderr, "error[%d]: %s\n", __LINE__,
Packit Service 4684c1
			gnutls_strerror(ret));
Packit Service 4684c1
		app_exit(1);
Packit Service 4684c1
	}
Packit Service 4684c1
	gnutls_certificate_set_verify_function(xcred, cert_callback);
Packit Service 4684c1
Packit Service 4684c1
	if (strcmp(proto, "udp") == 0)
Packit Service 4684c1
		udp = 1;
Packit Service 4684c1
	else if (strcmp(proto, "tcp") != 0) {
Packit Service 4684c1
		/* we cannot handle this protocol */
Packit Service 4684c1
		return NULL;
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	strcpy(tmpfile, "danetool-certXXXXXX");
Packit Service 4684c1
Packit Service 4684c1
	sockets_init();
Packit Service 4684c1
	txt_service = port_to_service(service, proto);
Packit Service 4684c1
Packit Service 4684c1
	if (quiet)
Packit Service 4684c1
		str = NULL;
Packit Service 4684c1
Packit Service 4684c1
	if (app_proto == NULL) app_proto = txt_service;
Packit Service 4684c1
Packit Service 4684c1
	if (udp)
Packit Service 4684c1
		socket_flags |= SOCKET_FLAG_UDP;
Packit Service 4684c1
	
Packit Service 4684c1
Packit Service 4684c1
	umask(066);
Packit Service 4684c1
	file_fd = mkstemp(tmpfile);
Packit Service 4684c1
	if (file_fd == -1) {
Packit Service 4684c1
		int e = errno;
Packit Service 4684c1
		fprintf(stderr, "error[%d]: %s\n", __LINE__,
Packit Service 4684c1
			strerror(e));
Packit Service 4684c1
		app_exit(1);
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	socket_open(&hd, hostname, txt_service, app_proto, socket_flags|SOCKET_FLAG_STARTTLS, str, NULL);
Packit Service 4684c1
Packit Service 4684c1
	close(file_fd);
Packit Service 4684c1
Packit Service 4684c1
	ret = 0;
Packit Service 4684c1
	priv = gnutls_session_get_ptr(hd.session);
Packit Service 4684c1
	if (priv->found == 0)
Packit Service 4684c1
		ret = -1;
Packit Service 4684c1
Packit Service 4684c1
	socket_bye(&hd, 1);
Packit Service 4684c1
	gnutls_certificate_free_credentials(xcred);
Packit Service 4684c1
Packit Service 4684c1
	if (ret == -1)
Packit Service 4684c1
		return NULL;
Packit Service 4684c1
	else
Packit Service 4684c1
		return tmpfile;
Packit Service 4684c1
}
Packit Service 4684c1
#endif