/*
* Copyright (C) 2012 Free Software Foundation, Inc.
*
* This file is part of GnuTLS.
*
* GnuTLS is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GnuTLS is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see
* .
*/
#include
#include
#include
#include
#include
#include
#include
#include
#ifdef HAVE_DANE
# include
#endif
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
/* Gnulib portability files. */
#include
#include
#include
#include
#include "danetool-args.h"
#include "certtool-common.h"
static void cmd_parser (int argc, char **argv);
static void dane_info(const char* host, const char* proto, unsigned int port,
unsigned int ca, unsigned int domain, common_info_st * cinfo);
static void dane_check(const char* host, const char* proto, unsigned int port,
common_info_st * cinfo);
FILE *outfile;
static gnutls_digest_algorithm_t default_dig;
/* non interactive operation if set
*/
int batch;
static void
tls_log_func (int level, const char *str)
{
fprintf (stderr, "|<%d>| %s", level, str);
}
int
main (int argc, char **argv)
{
set_program_name (argv[0]);
cmd_parser (argc, argv);
return 0;
}
static void
cmd_parser (int argc, char **argv)
{
int ret, privkey_op = 0;
common_info_st cinfo;
const char* proto = "tcp";
unsigned int port = 443;
optionProcess( &danetoolOptions, argc, argv);
if (HAVE_OPT(OUTFILE))
{
outfile = safe_open_rw (OPT_ARG(OUTFILE), privkey_op);
if (outfile == NULL)
error (EXIT_FAILURE, errno, "%s", OPT_ARG(OUTFILE));
}
else
outfile = stdout;
default_dig = GNUTLS_DIG_UNKNOWN;
if (HAVE_OPT(HASH))
{
if (strcasecmp (OPT_ARG(HASH), "md5") == 0)
{
fprintf (stderr,
"Warning: MD5 is broken, and should not be used any more for digital signatures.\n");
default_dig = GNUTLS_DIG_MD5;
}
else if (strcasecmp (OPT_ARG(HASH), "sha1") == 0)
default_dig = GNUTLS_DIG_SHA1;
else if (strcasecmp (OPT_ARG(HASH), "sha256") == 0)
default_dig = GNUTLS_DIG_SHA256;
else if (strcasecmp (OPT_ARG(HASH), "sha224") == 0)
default_dig = GNUTLS_DIG_SHA224;
else if (strcasecmp (OPT_ARG(HASH), "sha384") == 0)
default_dig = GNUTLS_DIG_SHA384;
else if (strcasecmp (OPT_ARG(HASH), "sha512") == 0)
default_dig = GNUTLS_DIG_SHA512;
else if (strcasecmp (OPT_ARG(HASH), "rmd160") == 0)
default_dig = GNUTLS_DIG_RMD160;
else
error (EXIT_FAILURE, 0, "invalid hash: %s", OPT_ARG(HASH));
}
gnutls_global_set_log_function (tls_log_func);
if (HAVE_OPT(DEBUG))
{
gnutls_global_set_log_level (OPT_VALUE_DEBUG);
printf ("Setting log level to %d\n", (int)OPT_VALUE_DEBUG);
}
if ((ret = gnutls_global_init ()) < 0)
error (EXIT_FAILURE, 0, "global_init: %s", gnutls_strerror (ret));
#ifdef ENABLE_PKCS11
pkcs11_common();
#endif
memset (&cinfo, 0, sizeof (cinfo));
if (HAVE_OPT(INDER) || HAVE_OPT(INRAW))
cinfo.incert_format = GNUTLS_X509_FMT_DER;
else
cinfo.incert_format = GNUTLS_X509_FMT_PEM;
if (HAVE_OPT(VERBOSE))
cinfo.verbose = 1;
if (HAVE_OPT(LOAD_PUBKEY))
cinfo.pubkey = OPT_ARG(LOAD_PUBKEY);
if (HAVE_OPT(LOAD_CERTIFICATE))
cinfo.cert = OPT_ARG(LOAD_CERTIFICATE);
if (HAVE_OPT(PORT))
port = OPT_VALUE_PORT;
if (HAVE_OPT(PROTO))
proto = OPT_ARG(PROTO);
if (HAVE_OPT(TLSA_RR))
dane_info (OPT_ARG(HOST), proto, port,
HAVE_OPT(CA), ENABLED_OPT(DOMAIN), &cinfo);
else if (HAVE_OPT(CHECK))
dane_check (OPT_ARG(CHECK), proto, port,
&cinfo);
else
USAGE(1);
fclose (outfile);
#ifdef ENABLE_PKCS11
gnutls_pkcs11_deinit ();
#endif
gnutls_global_deinit ();
}
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)
error (EXIT_FAILURE, 0, "dane_state_init: %s", dane_strerror (ret));
if (HAVE_OPT(DLV))
{
ret = dane_state_set_dlv_file(s, OPT_ARG(DLV));
if (ret < 0)
error (EXIT_FAILURE, 0, "dane_state_set_dlv_file: %s", dane_strerror (ret));
}
ret = dane_query_tlsa(s, &q, host, proto, port);
if (ret < 0)
error (EXIT_FAILURE, 0, "dane_query_tlsa: %s", dane_strerror (ret));
entries = dane_query_entries(q);
for (i=0;i 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)
error (EXIT_FAILURE, 0, "gnutls_load_file: %s", gnutls_strerror (ret));
ret = gnutls_x509_crt_list_import2( &clist, &clist_size, &file, cinfo->incert_format, 0);
if (ret < 0)
error (EXIT_FAILURE, 0, "gnutls_x509_crt_list_import2: %s", gnutls_strerror (ret));
if (clist_size > 0)
{
gnutls_datum_t certs[clist_size];
gnutls_datum_t out;
unsigned int i;
for (i=0;i