Пример #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
}
Пример #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
}
Пример #3
0
void
patrol_dialog_window_load (PatrolDialogWindow *self, const gchar *host,
                           const gchar *proto, guint16 port, GList *chains,
                           PatrolVerifyRC result, gint chain_result,
                           gint dane_result, gchar *app_name, gboolean notify)
{
    PatrolDialogWindowPrivate *pv = self->pv;
    pv->host = host;
    pv->proto = proto;
    pv->port = port;
    pv->chains = chains;
    pv->result = result;

    if (!chains)
        return;

    PatrolDialogRecord *r = chains->data;

    /* window title */
    gchar *text = g_strdup_printf("%s - %s:%u (%s)", _("Certificate Patrol"),
                                  host, port, proto);
    gtk_window_set_title(GTK_WINDOW(self), text);
    g_free(text);

    /* message icon & text*/
    gtk_image_set_from_stock(GTK_IMAGE(pv->icon),
                             (g_list_length(chains) > 1)
                             ? GTK_STOCK_DIALOG_WARNING
                             : GTK_STOCK_DIALOG_INFO,
                             GTK_ICON_SIZE_DIALOG);

    text = g_strdup_printf(
        (result == PATROL_ARG_UNKNOWN)
        ? _("Pinned public keys for peer <b>%s:%u (%s)</b>")
        : (r->rec.status == PATROL_STATUS_REJECTED)
        ? _("Rejected public key encountered for peer <b>%s:%u (%s)</b>")
        : (g_list_length(chains) > 1)
        ? _("<b>Changed public key</b> encountered for peer <b>%s:%u (%s)</b>\n"
            "in application <b>%s</b>")
        : notify
        ? _("<b>New public key</b> accepted for peer <b>%s:%u (%s)</b>\n"
            "in application <b>%s</b>")
        : _("<b>New public key</b> encountered for peer <b>%s:%u (%s)</b>\n"
            "in application <b>%s</b>"),
        host, port, proto, app_name);
    gtk_label_set_markup(GTK_LABEL(pv->msg), text);
    g_free(text);

    /* chain_msg */
    if (chain_result != PATROL_ARG_UNKNOWN) {
        gtk_image_set_from_stock(GTK_IMAGE(pv->chain_icon),
                                 (chain_result == PATROL_OK)
                                 ? GTK_STOCK_APPLY
                                 : GTK_STOCK_DIALOG_ERROR,
                                 GTK_ICON_SIZE_BUTTON);

        text = g_strdup_printf(
            "<b>%s</b>: %s.",
            _("Certificate chain validation"),
            chain_result == PATROL_OK ? _("Success") : _("Fail"));
        gtk_label_set_markup(GTK_LABEL(pv->chain_msg), text);
        g_free(text);
    } else {
        gtk_widget_hide(gtk_widget_get_parent(pv->chain_msg));
    }

#ifdef HAVE_GNUTLS_DANE
    /* dane_msg */
    if (dane_result != PATROL_ARG_UNKNOWN) {
        gtk_image_set_from_stock(GTK_IMAGE(pv->dane_icon),
                                 (dane_result == DANE_E_SUCCESS)
                                 ? GTK_STOCK_APPLY
                                 : (dane_result == DANE_E_NO_DANE_DATA
                                    || (dane_result > 0 &&
                                        dane_result & DANE_VERIFY_NO_DANE_INFO))
                                 ? GTK_STOCK_DIALOG_INFO
                                 : (dane_result < 0)
                                 ? GTK_STOCK_DIALOG_WARNING
                                 : GTK_STOCK_DIALOG_ERROR,
                                 GTK_ICON_SIZE_BUTTON);

        gnutls_datum_t dane_status_str = { 0 };
        if (dane_result >= 0)
            dane_verification_status_print(dane_result, &dane_status_str, 0);
        text = g_strdup_printf(
            "<b>%s</b>: %s %.*s",
            _("DANE validation"),
            dane_strerror(dane_result < 0 ? dane_result : 0),
            dane_status_str.size, dane_status_str.data);
        gnutls_free(dane_status_str.data);

        gtk_label_set_markup(GTK_LABEL(pv->dane_msg), text);
        g_free(text);
    } else {
        gtk_widget_hide(gtk_widget_get_parent(pv->dane_msg));
    }
#endif

    GList *item = chains;
    guint i;
    for (i = 0; item && item->data; item = item->next, i++)
        load_chain(self, item->data, i, i ? pv->old_chains : pv->new_chain);
}
Пример #4
0
static int
cert_verify_callback (gnutls_session_t session)
{
  int rc;
  unsigned int status = 0;
  int ssh = ENABLED_OPT(TOFU);
#ifdef HAVE_DANE
  int dane = ENABLED_OPT(DANE);
#endif
  int ca_verify = ENABLED_OPT(CA_VERIFICATION);
  const char* txt_service;

  print_cert_info (session, verbose, print_cert);

  if (ca_verify)
    {
      rc = cert_verify(session, hostname);
      if (rc == 0)
        {
          printf ("*** Verifying server certificate failed...\n");
          if (!insecure && !ssh)
            return -1;
        }
      else if (ENABLED_OPT(OCSP) && gnutls_ocsp_status_request_is_checked(session, 0) == 0)
        { /* off-line verification succeeded. Try OCSP */
          rc = cert_verify_ocsp(session);
          if (rc == 0)
            {
              printf ("*** Verifying (with OCSP) server certificate failed...\n");
              if (!insecure && !ssh)
                return -1;
            }
          else if (rc == -1)
            printf("*** OCSP response ignored\n");
        }
    }

  if (ssh) /* try ssh auth */
    {
      unsigned int list_size;
      const gnutls_datum_t * cert;
      
      cert = gnutls_certificate_get_peers(session, &list_size);
      if (cert == NULL)
        {
          fprintf(stderr, "Cannot obtain peer's certificate!\n");
          return -1;
        }

      txt_service = port_to_service(service);
      
      rc = gnutls_verify_stored_pubkey(NULL, NULL, hostname, txt_service, 
                                       GNUTLS_CRT_X509, cert, 0);
      if (rc == GNUTLS_E_NO_CERTIFICATE_FOUND)
        {
          print_cert_info_compact(session);
          fprintf(stderr, "Host %s (%s) has never been contacted before.\n", hostname, txt_service);
          if (status == 0)
            fprintf(stderr, "Its certificate is valid for %s.\n", hostname);

          rc = read_yesno("Are you sure you want to trust it? (y/N): ");
          if (rc == 0)
            return -1;
        }
      else if (rc == GNUTLS_E_CERTIFICATE_KEY_MISMATCH)
        {
          print_cert_info_compact(session);
          fprintf(stderr, "Warning: host %s is known and it is associated with a different key.\n", hostname);
          fprintf(stderr, "It might be that the server has multiple keys, or an attacker replaced the key to eavesdrop this connection .\n");
          if (status == 0)
            fprintf(stderr, "Its certificate is valid for %s.\n", hostname);

          rc = read_yesno("Do you trust the received key? (y/N): ");
          if (rc == 0)
            return -1;
        }
      else if (rc < 0)
        {
          fprintf(stderr, "gnutls_verify_stored_pubkey: %s\n", gnutls_strerror(rc));
          return -1;
        }
      
      if (rc != 0)
        {
          rc = gnutls_store_pubkey(NULL, NULL, hostname, txt_service, 
                                   GNUTLS_CRT_X509, cert, 0, 0);
          if (rc < 0)
            fprintf(stderr, "Could not store key: %s\n", gnutls_strerror(rc));
        }
    }

#ifdef HAVE_DANE
  if (dane) /* try DANE auth */
    {
      unsigned int sflags = ENABLED_OPT(LOCAL_DNS)?0:DANE_F_IGNORE_LOCAL_RESOLVER;
      rc = dane_verify_session_crt( NULL, session, hostname, udp?"udp":"tcp", atoi(service), 
                                    sflags, 0, &status);
      if (rc < 0)
        {
          fprintf(stderr, "*** DANE verification error: %s\n", dane_strerror(rc));
          if (!insecure)
            return -1;
        }
      else
        {
          gnutls_datum_t out;

          rc = dane_verification_status_print( status, &out, 0);
          if (rc < 0)
            {
              fprintf(stderr, "*** DANE error: %s\n", dane_strerror(rc));
              if (!insecure)
                return -1;
            }
          
          fprintf(stderr, "- %s\n", out.data);
          gnutls_free(out.data);
        }

    }
#endif

  return 0;
}