aboutsummaryrefslogtreecommitdiff
path: root/src/namestore/plugin_gtk_namestore_tlsa.c
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2014-06-07 20:03:27 +0000
committerChristian Grothoff <christian@grothoff.org>2014-06-07 20:03:27 +0000
commite71cdb38f2b520975527141f42fdd3ce3d941fe4 (patch)
tree8dc4b01418936041930f1dc07e1d87883025918a /src/namestore/plugin_gtk_namestore_tlsa.c
parente88cc91be7df92b75430d4748fd201eb03013675 (diff)
downloadgnunet-gtk-e71cdb38f2b520975527141f42fdd3ce3d941fe4.tar.gz
gnunet-gtk-e71cdb38f2b520975527141f42fdd3ce3d941fe4.zip
fixing #2526
Diffstat (limited to 'src/namestore/plugin_gtk_namestore_tlsa.c')
-rw-r--r--src/namestore/plugin_gtk_namestore_tlsa.c375
1 files changed, 369 insertions, 6 deletions
diff --git a/src/namestore/plugin_gtk_namestore_tlsa.c b/src/namestore/plugin_gtk_namestore_tlsa.c
index 19f88d11..d8dc60cd 100644
--- a/src/namestore/plugin_gtk_namestore_tlsa.c
+++ b/src/namestore/plugin_gtk_namestore_tlsa.c
@@ -32,7 +32,7 @@
32#include <gnutls/gnutls.h> 32#include <gnutls/gnutls.h>
33#include <gnutls/x509.h> 33#include <gnutls/x509.h>
34#include <gnutls/abstract.h> 34#include <gnutls/abstract.h>
35 35#include <gnunet/gnunet_resolver_service.h>
36 36
37/** 37/**
38 * The user has edited the target value. Enable/disable 'save' 38 * The user has edited the target value. Enable/disable 'save'
@@ -352,7 +352,7 @@ tlsa_load (void *cls,
352 */ 352 */
353static gchar * 353static gchar *
354tlsa_store (void *cls, 354tlsa_store (void *cls,
355 GtkBuilder *builder) 355 GtkBuilder *builder)
356{ 356{
357 unsigned int protocol; 357 unsigned int protocol;
358 GtkComboBox *cb; 358 GtkComboBox *cb;
@@ -470,6 +470,8 @@ tlsa_validate (void *cls,
470 &ti_start, 470 &ti_start,
471 &ti_end, 471 &ti_end,
472 FALSE); 472 FALSE);
473 if (0 == strlen (value))
474 return GNUNET_SYSERR;
473 { 475 {
474 size_t slen = strlen (value); 476 size_t slen = strlen (value);
475 uint8_t bin[slen / 2]; 477 uint8_t bin[slen / 2];
@@ -565,6 +567,335 @@ tlsa_validate (void *cls,
565 567
566 568
567/** 569/**
570 * We have successfully established a TLS session to
571 * import a certificate from the server. Import the
572 * X509 certificate into the GUI.
573 *
574 * @param session TLS session to import from
575 * @param builder GTK builder to update GUI
576 */
577static void
578import_x509_certificate (gnutls_session_t session,
579 GtkBuilder *builder)
580{
581 const gnutls_datum_t *cert_list;
582 unsigned int cert_list_size = 0;
583 gnutls_x509_crt_t cert;
584 unsigned int matching_type;
585 unsigned int selector;
586 gnutls_pubkey_t pk;
587 char buf[4092];
588 size_t bsize;
589 char *hex;
590 gnutls_datum_t datum;
591 uint8_t sha256[256/8];
592 uint8_t sha512[512/8];
593 size_t ssize;
594 GtkTextBuffer *tb;
595
596 cert_list = gnutls_certificate_get_peers (session,
597 &cert_list_size);
598 if (0 == cert_list_size)
599 {
600 /* is it possible to succeed with TLS handshake and have
601 NO certificates!? If so, how do we get the public key?*/
602 GNUNET_break (0);
603 return;
604 }
605 /* we only import the first certificate. */
606 gnutls_x509_crt_init (&cert);
607 if (GNUTLS_E_SUCCESS !=
608 gnutls_x509_crt_import (cert,
609 &cert_list[0],
610 GNUTLS_X509_FMT_DER))
611 {
612 GNUNET_break (0);
613 gnutls_x509_crt_deinit (cert);
614 return;
615 }
616 selector = get_selected_radio_value (builder,
617 selector_buttons);
618 switch (selector)
619 {
620 case 0: /* full cert */
621 bsize = sizeof (buf);
622 if (GNUTLS_E_SUCCESS !=
623 gnutls_x509_crt_export (cert,
624 GNUTLS_X509_FMT_DER,
625 buf,
626 &bsize))
627 {
628 GNUNET_break (0);
629 gnutls_x509_crt_deinit (cert);
630 return;
631 }
632 break;
633 case 1: /* subject public key only */
634 if (GNUTLS_E_SUCCESS !=
635 gnutls_pubkey_init (&pk))
636 {
637 GNUNET_break (0);
638 gnutls_x509_crt_deinit (cert);
639 return;
640 }
641 if (GNUTLS_E_SUCCESS !=
642 gnutls_pubkey_import_x509 (pk,
643 cert,
644 0))
645 {
646 GNUNET_break (0);
647 gnutls_x509_crt_deinit (cert);
648 gnutls_pubkey_deinit (pk);
649 return;
650 }
651 bsize = sizeof (buf);
652 if (GNUTLS_E_SUCCESS !=
653 gnutls_pubkey_export (pk,
654 GNUTLS_X509_FMT_DER,
655 buf,
656 &bsize))
657 {
658 GNUNET_break (0);
659 gnutls_x509_crt_deinit (cert);
660 gnutls_pubkey_deinit (pk);
661 return;
662 }
663 gnutls_pubkey_deinit (pk);
664 break;
665 default:
666 GNUNET_break (0);
667 gnutls_x509_crt_deinit (cert);
668 return;
669 }
670 gnutls_x509_crt_deinit (cert);
671 /* 'buf' now contains 'bsize' bytes of the binary data to
672 hash or store in the TLSA record; hash depending on
673 user preferences. */
674 matching_type = get_selected_radio_value (builder,
675 matching_type_buttons);
676 switch (matching_type)
677 {
678 case 0: /* exact match */
679 hex = GNUNET_DNSPARSER_bin_to_hex (buf,
680 bsize);
681 break;
682 case 1: /* SHA-256 hash */
683 datum.size = bsize;
684 datum.data = (void *) buf;
685 ssize = sizeof (sha256);
686 GNUNET_assert (GNUTLS_E_SUCCESS ==
687 gnutls_fingerprint (GNUTLS_MAC_SHA256,
688 &datum,
689 sha256,
690 &ssize));
691 hex = GNUNET_DNSPARSER_bin_to_hex (sha256,
692 sizeof (sha256));
693 break;
694 case 2: /* SHA-512 hash */
695 datum.size = bsize;
696 datum.data = (void *) buf;
697 ssize = sizeof (sha512);
698 GNUNET_assert (GNUTLS_E_SUCCESS ==
699 gnutls_fingerprint (GNUTLS_MAC_SHA512,
700 &datum,
701 sha512,
702 &ssize));
703 hex = GNUNET_DNSPARSER_bin_to_hex (sha512,
704 sizeof (sha512));
705 break;
706 default:
707 GNUNET_break (0);
708 return;
709 }
710
711 /* Finally store 'hex' to the text buffer */
712 tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW
713 (gtk_builder_get_object (builder,
714 "edit_dialog_tlsa_value_textview")));
715 gtk_text_buffer_set_text (tb,
716 hex,
717 -1);
718 GNUNET_free (hex);
719}
720
721
722/**
723 * Context for TLS certificate import from network.
724 */
725struct ImportContext
726{
727 /**
728 * The TLS session.
729 */
730 gnutls_session_t session;
731
732 /**
733 * Network handle for the session.
734 */
735 struct GNUNET_NETWORK_Handle *sock;
736
737 /**
738 * DNS resolution request to resolve the domain name.
739 */
740 struct GNUNET_RESOLVER_RequestHandle *rh;
741
742 /**
743 * Builder for accessing widgets.
744 */
745 GtkBuilder *builder;
746};
747
748
749/**
750 * We got an address from DNS, start TLS handshake.
751 *
752 * @param cls our `struct ImportContext`
753 * @param addr one of the addresses of the host, NULL for the last address
754 * @param addrlen length of @a addr
755 */
756static void
757import_address_cb (void *cls,
758 const struct sockaddr *addr,
759 socklen_t addrlen)
760{
761 struct ImportContext *ic = cls;
762 int pf;
763 int ret;
764 gnutls_certificate_credentials_t xcred;
765 struct sockaddr_in v4;
766 struct sockaddr_in6 v6;
767 struct sockaddr *a;
768 unsigned int port;
769 gnutls_certificate_type_t type;
770
771 if (NULL == addr)
772 {
773 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
774 _("Name resolution failed\n"));
775 GNUNET_free (ic);
776 return;
777 }
778 port = gtk_spin_button_get_value
779 (GTK_SPIN_BUTTON (gtk_builder_get_object (ic->builder,
780 "edit_dialog_port_spinbutton")));
781 switch (addr->sa_family)
782 {
783 case AF_INET:
784 pf = PF_INET;
785 memcpy (&v4, addr, addrlen);
786 v4.sin_port = htons ((uint16_t) port);
787 a = (struct sockaddr *) &v4;
788 break;
789 case AF_INET6:
790 pf = PF_INET6;
791 memcpy (&v6, addr, addrlen);
792 v6.sin6_port = htons ((uint16_t) port);
793 a = (struct sockaddr *) &v6;
794 break;
795 default:
796 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
797 _("Unsupported address family %d\n"),
798 addr->sa_family);
799 return;
800 }
801 ic->sock = GNUNET_NETWORK_socket_create (pf,
802 SOCK_STREAM,
803 0);
804 if (NULL == ic->sock)
805 {
806 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
807 "socket");
808 return;
809 }
810 GNUNET_break (GNUNET_OK ==
811 GNUNET_NETWORK_socket_set_blocking (ic->sock,
812 GNUNET_YES));
813 if ( (GNUNET_OK !=
814 GNUNET_NETWORK_socket_connect (ic->sock,
815 a,
816 addrlen)) &&
817 (EINPROGRESS != errno) )
818 {
819 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
820 _("Failed to connect to target address `%s': %s\n"),
821 GNUNET_a2s (addr, addrlen),
822 STRERROR (errno));
823 goto cleanup;
824 }
825
826 GNUNET_RESOLVER_request_cancel (ic->rh);
827
828 /* Use default priorities */
829 if (GNUTLS_E_SUCCESS !=
830 (ret = gnutls_priority_set_direct (ic->session,
831 "PERFORMANCE",
832 NULL)))
833 {
834 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
835 _("Failed to initialize cipher suite: %s\n"),
836 gnutls_strerror (ret));
837 goto cleanup;
838 }
839 /* put the x509 credentials to the current session */
840 gnutls_certificate_allocate_credentials (&xcred);
841 gnutls_credentials_set (ic->session,
842 GNUTLS_CRD_CERTIFICATE,
843 xcred);
844 gnutls_transport_set_int (ic->session,
845 GNUNET_NETWORK_get_fd (ic->sock));
846 gnutls_handshake_set_timeout (ic->session,
847 2000 /* 2s */);
848
849 /* TODO: do this in event loop, with insensitive GUI,
850 with possibly higher timeout ... */
851 /* Perform the TLS handshake */
852 do
853 {
854 ret = gnutls_handshake (ic->session);
855 }
856 while ( (ret < 0) && (0 == gnutls_error_is_fatal (ret)) );
857
858 /* finally, access the certificate */
859 if (GNUTLS_E_SUCCESS == ret)
860 {
861 type = gnutls_certificate_type_get (ic->session);
862 switch (type)
863 {
864 case GNUTLS_CRT_UNKNOWN:
865 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
866 _("Server certificate type not supported\n"));
867 break;
868 case GNUTLS_CRT_X509:
869 import_x509_certificate (ic->session,
870 ic->builder);
871 break;
872 case GNUTLS_CRT_OPENPGP:
873 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
874 _("Server certificate type not supported\n"));
875 break;
876 case GNUTLS_CRT_RAW:
877 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
878 _("Server certificate type not supported\n"));
879 break;
880 }
881 }
882 else
883 {
884 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
885 _("TLS handshake failed: %s\n"),
886 gnutls_strerror (ret));
887 }
888 gnutls_bye (ic->session, GNUTLS_SHUT_RDWR);
889 cleanup:
890 GNUNET_break (GNUNET_OK ==
891 GNUNET_NETWORK_socket_close (ic->sock));
892 gnutls_deinit (ic->session);
893 gnutls_certificate_free_credentials (xcred);
894 GNUNET_free (ic);
895}
896
897
898/**
568 * The user clicked the "import" button. Try to import 899 * The user clicked the "import" button. Try to import
569 * certificate from the server. 900 * certificate from the server.
570 * 901 *
@@ -576,27 +907,59 @@ tlsa_import_button_clicked_cb (GtkButton *button,
576 gpointer user_data) 907 gpointer user_data)
577{ 908{
578 struct GNUNET_GTK_NAMESTORE_PluginEnvironment *edc = user_data; 909 struct GNUNET_GTK_NAMESTORE_PluginEnvironment *edc = user_data;
910 struct ImportContext *ic;
911 const gchar *name;
912 GtkWidget *entry;
579 913
580 GNUNET_break (0); // FIXME: import not implemented 914 entry = GTK_WIDGET (gtk_builder_get_object (edc->builder,
915 "edit_dialog_tlsa_import_entry"));
916 name = gtk_editable_get_chars (GTK_EDITABLE (entry),
917 0, -1);
918 if ( (NULL == name) ||
919 (0 == strlen (name)) ||
920 (GNUNET_OK != GNUNET_DNSPARSER_check_name (name)) )
921 {
922 /* import button should not have been sensitive */
923 GNUNET_break (0);
924 return;
925 }
926 ic = GNUNET_new (struct ImportContext);
927 ic->builder = edc->builder;
928 gnutls_init (&ic->session, GNUTLS_CLIENT);
929 gnutls_session_set_ptr (ic->session, ic);
930 gnutls_server_name_set (ic->session,
931 GNUTLS_NAME_DNS,
932 name,
933 strlen (name));
934 gnutls_set_default_priority (ic->session);
935 ic->rh = GNUNET_RESOLVER_ip_get (name,
936 AF_UNSPEC,
937 GNUNET_TIME_UNIT_SECONDS,
938 &import_address_cb,
939 ic);
581} 940}
582 941
583 942
584/** 943/**
585 * The user has edited the hostname used for the import button. 944 * The user has edited the hostname used for the import button.
586 * Update the import button's sensitivity. 945 * Update the import button's sensitivity.
946 *
947 * @param entry edited entry
948 * @param user_data our plugin environment
587 */ 949 */
588static void 950static void
589edit_dialog_tlsa_import_entry_changed_cb (GtkEditable *entry, 951edit_dialog_tlsa_import_entry_changed_cb (GtkEditable *entry,
590 gpointer user_data) 952 gpointer user_data)
591{ 953{
592 struct GNUNET_GTK_NAMESTORE_PluginEnvironment *edc = user_data; 954 struct GNUNET_GTK_NAMESTORE_PluginEnvironment *edc = user_data;
593 GtkWidget *button;
594 const gchar *preedit; 955 const gchar *preedit;
595 gboolean sens; 956 gboolean sens;
957 GtkWidget *button;
596 958
597 button = GTK_WIDGET (gtk_builder_get_object (edc->builder, 959 button = GTK_WIDGET (gtk_builder_get_object (edc->builder,
598 "edit_dialog_tlsa_entry")); 960 "edit_dialog_tlsa_import_button"));
599 preedit = gtk_editable_get_chars (entry, 0, -1); 961 preedit = gtk_editable_get_chars (GTK_EDITABLE (entry),
962 0, -1);
600 if ( (NULL == preedit) || 963 if ( (NULL == preedit) ||
601 (0 == strlen (preedit)) || 964 (0 == strlen (preedit)) ||
602 (GNUNET_OK != GNUNET_DNSPARSER_check_name (preedit)) ) 965 (GNUNET_OK != GNUNET_DNSPARSER_check_name (preedit)) )