/* * 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