dirmngr: First take on ntbtls cert verification.
authorWerner Koch <wk@gnupg.org>
Sun, 19 Feb 2017 09:36:43 +0000 (10:36 +0100)
committerWerner Koch <wk@gnupg.org>
Sun, 19 Feb 2017 09:36:43 +0000 (10:36 +0100)
* dirmngr/http-ntbtls.c: New.
* dirmngr/Makefile.am (dirmngr_SOURCES): Add file.
* dirmngr/dirmngr.h (SERVER_CONTROL_MAGIC): New.
(server_conrol_s): Add field 'magic',
* dirmngr/dirmngr.c (dirmngr_init_default_ctrl): Set MAGIC.
(dirmngr_deinit_default_ctrl): Set MAGIC to deadbeef.
* dirmngr/http.c (my_ntbtls_verify_cb): New.
(http_session_new) [HTTP_USE_NTBTLS]: Remove all CA setting code.
(send_request) [HTTP_USE_NTBTLS]: Set the verify callback.  Do not call
the verify callback after the handshake.
* dirmngr/ks-engine-hkp.c (send_request): Pass
gnupg_http_tls_verify_cb to http_session_new.
* dirmngr/ks-engine-http.c (ks_http_fetch): Ditto.

* dirmngr/t-http.c (my_http_tls_verify_cb): New.
(main): Rename option --gnutls-debug to --tls-debug.
(main) [HTTP_USE_NTBTLS]: Create a session.

Signed-off-by: Werner Koch <wk@gnupg.org>
dirmngr/Makefile.am
dirmngr/dirmngr.c
dirmngr/dirmngr.h
dirmngr/http-ntbtls.c [new file with mode: 0644]
dirmngr/http.c
dirmngr/ks-engine-hkp.c
dirmngr/ks-engine-http.c
dirmngr/t-http.c

index d3f89bc..7fa4282 100644 (file)
@@ -62,6 +62,7 @@ dirmngr_SOURCES = dirmngr.c dirmngr.h server.c crlcache.c crlfetch.c  \
        ocsp.c ocsp.h validate.c validate.h  \
        dns-stuff.c dns-stuff.h \
        http.c http.h \
+       http-ntbtls.c \
        ks-action.c ks-action.h ks-engine.h \
        ks-engine-hkp.c ks-engine-http.c ks-engine-finger.c ks-engine-kdns.c
 
index bb07656..718296d 100644 (file)
@@ -1468,6 +1468,7 @@ dirmngr_exit (int rc)
 void
 dirmngr_init_default_ctrl (ctrl_t ctrl)
 {
+  ctrl->magic = SERVER_CONTROL_MAGIC;
   if (opt.http_proxy)
     ctrl->http_proxy = xstrdup (opt.http_proxy);
 }
@@ -1478,6 +1479,8 @@ dirmngr_deinit_default_ctrl (ctrl_t ctrl)
 {
   if (!ctrl)
     return;
+  ctrl->magic = 0xdeadbeef;
+
   xfree (ctrl->http_proxy);
   ctrl->http_proxy = NULL;
 }
index 19d2303..57e3372 100644 (file)
@@ -168,12 +168,19 @@ typedef struct cert_ref_s *cert_ref_t;
 /* Forward references; access only through server.c.  */
 struct server_local_s;
 
+#if SIZEOF_UNSIGNED_LONG == 8
+# define SERVER_CONTROL_MAGIC 0x6469726d6e677220
+#else
+# define SERVER_CONTROL_MAGIC 0x6469726d
+#endif
+
 /* Connection control structure.  */
 struct server_control_s
 {
-  int refcount;      /* Count additional references to this object.  */
-  int no_server;     /* We are not running under server control. */
-  int status_fd;     /* Only for non-server mode. */
+  unsigned long magic;/* Always has SERVER_CONTROL_MAGIC.  */
+  int refcount;       /* Count additional references to this object.  */
+  int no_server;      /* We are not running under server control. */
+  int status_fd;      /* Only for non-server mode. */
   struct server_local_s *server_local;
   int force_crl_refresh; /* Always load a fresh CRL. */
 
@@ -213,6 +220,15 @@ gpg_error_t dirmngr_status (ctrl_t ctrl, const char *keyword, ...);
 gpg_error_t dirmngr_status_help (ctrl_t ctrl, const char *text);
 gpg_error_t dirmngr_tick (ctrl_t ctrl);
 
+/*-- http-ntbtls.c --*/
+/* Note that we don't use a callback for gnutls.  */
+
+gpg_error_t gnupg_http_tls_verify_cb (void *opaque,
+                                      http_t http,
+                                      http_session_t session,
+                                      unsigned int flags,
+                                      void *tls_context);
+
 
 /*-- loadswdb.c --*/
 gpg_error_t dirmngr_load_swdb (ctrl_t ctrl, int force);
diff --git a/dirmngr/http-ntbtls.c b/dirmngr/http-ntbtls.c
new file mode 100644 (file)
index 0000000..5686877
--- /dev/null
@@ -0,0 +1,109 @@
+/* http-ntbtls.c - Support for using NTBTLS with http.c
+ * Copyright (C) 2017  Werner Koch
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG 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.
+ *
+ * GnuPG 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 <https://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "dirmngr.h"
+#include "certcache.h"
+#include "validate.h"
+
+#ifdef HTTP_USE_NTBTLS
+# include <ntbtls.h>
+
+
+
+/* The callback used to verify the peer's certificate.  */
+gpg_error_t
+gnupg_http_tls_verify_cb (void *opaque,
+                          http_t http,
+                          http_session_t session,
+                          unsigned int http_flags,
+                          void *tls_context)
+{
+  ctrl_t ctrl = opaque;
+  gpg_error_t err;
+  int idx;
+  ksba_cert_t cert;
+  ksba_cert_t hostcert = NULL;
+  unsigned int validate_flags;
+
+  (void)http;
+  (void)session;
+
+  log_assert (ctrl && ctrl->magic == SERVER_CONTROL_MAGIC);
+
+  /* Get the peer's certs fron ntbtls.  */
+  for (idx = 0;
+       (cert = ntbtls_x509_get_peer_cert (tls_context, idx)); idx++)
+    {
+      if (!idx)
+        hostcert = cert;
+      else
+        {
+          /* Quick hack to make verification work by inserting the supplied
+           * certs into the cache.  FIXME! */
+          cache_cert (cert);
+          ksba_cert_release (cert);
+        }
+    }
+  if (!idx)
+    {
+      err  = gpg_error (GPG_ERR_MISSING_CERT);
+      goto leave;
+    }
+
+  validate_flags = VALIDATE_FLAG_TLS;
+  /* if ((http_flags & HTTP_FLAG_TRUST_DEF)) */
+  /*   validate_flags |= VALIDATE_FLAG_??; */
+  if ((http_flags & HTTP_FLAG_TRUST_SYS))
+    validate_flags |= VALIDATE_FLAG_SYSTRUST;
+
+  /* FIXME: For now we don't use CRLs.  */
+  validate_flags |= VALIDATE_FLAG_NOCRLCHECK;
+
+  err = validate_cert_chain (ctrl, hostcert, NULL, validate_flags, NULL);
+
+ leave:
+  ksba_cert_release (hostcert);
+  return err;
+}
+
+
+#else /*!HTTP_USE_NTBTLS*/
+
+/* Dummy function used when not build without ntbtls support.  */
+gpg_error_t
+gnupg_http_tls_verify_cb (void *opaque,
+                          http_t http,
+                          http_session_t session,
+                          unsigned int flags,
+                          void *tls_context)
+{
+  (void)opaque;
+  (void)http;
+  (void)session;
+  (void)flags;
+  (void)tls_context;
+  return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
+}
+#endif /*!HTTP_USE_NTBTLS*/
index 51aec7e..e7c6d42 100644 (file)
@@ -413,6 +413,21 @@ my_gnutls_write (gnutls_transport_ptr_t ptr, const void *buffer, size_t size)
 #endif /*HTTP_USE_GNUTLS*/
 
 
+#ifdef HTTP_USE_NTBTLS
+/* Connect the ntbls callback to our generic callback.  */
+static gpg_error_t
+my_ntbtls_verify_cb (void *opaque, ntbtls_t tls, unsigned int verify_flags)
+{
+  http_t hd = opaque;
+  log_assert (hd && hd->session && hd->session->verify_cb);
+  return hd->session->verify_cb (hd->session->verify_cb_value,
+                                 hd, hd->session,
+                                 (hd->flags | hd->session->flags),
+                                 tls);
+}
+#endif /*HTTP_USE_NTBTLS*/
+
+
 
 \f
 /* This notification function is called by estream whenever stream is
@@ -632,91 +647,16 @@ http_session_new (http_session_t *r_session,
 
 #if HTTP_USE_NTBTLS
   {
-    x509_cert_t ca_chain;
-    char line[256];
-    estream_t fp, mem_p;
-    size_t nread, nbytes;
-    struct b64state state;
-    void *buf;
-    size_t buflen;
-    char *pemname;
-
-    pemname = make_filename_try (gnupg_datadir (),
-                                 "sks-keyservers.netCA.pem", NULL);
-    if (!pemname)
-      {
-        err = gpg_error_from_syserror ();
-        log_error ("setting CA from file '%s' failed: %s\n",
-                   pemname, gpg_strerror (err));
-        goto leave;
-      }
-
-    fp = es_fopen (pemname, "r");
-    if (!fp)
-      {
-        err = gpg_error_from_syserror ();
-        log_error ("can't open '%s': %s\n", pemname, gpg_strerror (err));
-        xfree (pemname);
-        goto leave;
-      }
-    xfree (pemname);
-
-    mem_p = es_fopenmem (0, "r+b");
-    err = b64dec_start (&state, "CERTIFICATE");
-    if (err)
-      {
-        log_error ("b64dec failure: %s\n", gpg_strerror (err));
-        goto leave;
-      }
-
-    while ( (nread = es_fread (line, 1, DIM (line), fp)) )
-      {
-        err = b64dec_proc (&state, line, nread, &nbytes);
-        if (err)
-          {
-            if (gpg_err_code (err) == GPG_ERR_EOF)
-              break;
-
-            log_error ("b64dec failure: %s\n", gpg_strerror (err));
-            es_fclose (fp);
-            es_fclose (mem_p);
-            goto leave;
-          }
-        else if (nbytes)
-          es_fwrite (line, 1, nbytes, mem_p);
-      }
-    err = b64dec_finish (&state);
-    if (err)
-      {
-        log_error ("b64dec failure: %s\n", gpg_strerror (err));
-        es_fclose (fp);
-        es_fclose (mem_p);
-        goto leave;
-      }
-
-    es_fclose_snatch (mem_p, &buf, &buflen);
-    es_fclose (fp);
-
-    err = ntbtls_x509_cert_new (&ca_chain);
-    if (err)
-      {
-        log_error ("ntbtls_x509_new failed: %s\n", gpg_strerror (err));
-        xfree (buf);
-        goto leave;
-      }
-
-    err = ntbtls_x509_append_cert (ca_chain, buf, buflen);
-    xfree (buf);
+    (void)intended_hostname; /* Not needed because we do not preload
+                              * certificates.  */
 
     err = ntbtls_new (&sess->tls_session, NTBTLS_CLIENT);
     if (err)
       {
         log_error ("ntbtls_new failed: %s\n", gpg_strerror (err));
-        ntbtls_x509_cert_release (ca_chain);
         goto leave;
       }
 
-    err = ntbtls_set_ca_chain (sess->tls_session, ca_chain, NULL);
   }
 #elif HTTP_USE_GNUTLS
   {
@@ -1819,6 +1759,21 @@ send_request (http_t hd, const char *httphost, const char *auth,
           return err;
         }
 
+#ifdef HTTP_USE_NTBTLS
+      if (hd->session->verify_cb)
+        {
+          err = ntbtls_set_verify_cb (hd->session->tls_session,
+                                      my_ntbtls_verify_cb, hd);
+          if (err)
+            {
+              log_error ("ntbtls_set_verify_cb failed: %s\n",
+                         gpg_strerror (err));
+              xfree (proxy_authstr);
+              return err;
+            }
+        }
+#endif /*HTTP_USE_NTBTLS*/
+
       while ((err = ntbtls_handshake (hd->session->tls_session)))
         {
           switch (err)
@@ -1833,12 +1788,18 @@ send_request (http_t hd, const char *httphost, const char *auth,
 
       hd->session->verify.done = 0;
 
-
       /* Try the available verify callbacks until one returns success
-       * or a real error.  */
+       * or a real error.  Note that NTBTLS does the verification
+       * during the handshake via   */
+#ifdef HTTP_USE_NTBTLS
+      err = 0; /* Fixme check that the CB has been called.  */
+#else
       err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
+#endif
 
-      if (hd->session->verify_cb)
+      if (hd->session->verify_cb
+          && gpg_err_source (err) == GPG_ERR_SOURCE_DIRMNGR
+          && gpg_err_code (err) == GPG_ERR_NOT_IMPLEMENTED)
         err = hd->session->verify_cb (hd->session->verify_cb_value,
                                       hd, hd->session,
                                       (hd->flags | hd->session->flags),
index b342f09..4ca1e00 100644 (file)
@@ -1124,7 +1124,7 @@ send_request (ctrl_t ctrl, const char *request, const char *hostportstr,
   *r_fp = NULL;
 
   err = http_session_new (&session, httphost, HTTP_FLAG_TRUST_DEF,
-                          NULL, ctrl);
+                          gnupg_http_tls_verify_cb, ctrl);
   if (err)
     goto leave;
   http_session_set_log_cb (session, cert_log_cb);
index f070019..9352a0f 100644 (file)
@@ -77,7 +77,7 @@ ks_http_fetch (ctrl_t ctrl, const char *url, estream_t *r_fp)
   /* Note that we only use the system provided certificates with the
    * fetch command.  */
   err = http_session_new (&session, NULL, HTTP_FLAG_TRUST_SYS,
-                          NULL, ctrl);
+                          gnupg_http_tls_verify_cb, ctrl);
   if (err)
     goto leave;
   http_session_set_log_cb (session, cert_log_cb);
index 8b1d89a..4641121 100644 (file)
@@ -42,7 +42,6 @@
 #include "logging.h"
 #include "http.h"
 
-
 #if HTTP_USE_NTBTLS
 # include <ntbtls.h>
 #elif HTTP_USE_GNUTLS
@@ -118,6 +117,56 @@ my_gnutls_log (int level, const char *text)
 }
 #endif
 
+
+static gpg_error_t
+my_http_tls_verify_cb (void *opaque,
+                       http_t http,
+                       http_session_t session,
+                       unsigned int http_flags,
+                       void *tls_context)
+{
+  gpg_error_t err;
+  int idx;
+  ksba_cert_t cert;
+  ksba_cert_t hostcert = NULL;
+
+  (void)opaque;
+  (void)http;
+  (void)session;
+
+
+  /* Get the peer's certs fron ntbtls.  */
+  for (idx = 0;
+       (cert = ntbtls_x509_get_peer_cert (tls_context, idx)); idx++)
+    {
+      if (!idx)
+        {
+          log_info ("Received host certificate\n");
+          hostcert = cert;
+        }
+      else
+        {
+
+          log_info ("Received additional certificate\n");
+          ksba_cert_release (cert);
+        }
+    }
+  if (!idx)
+    {
+      err  = gpg_error (GPG_ERR_MISSING_CERT);
+      goto leave;
+    }
+
+  err = 0;
+
+ leave:
+  ksba_cert_release (hostcert);
+  log_info ("my_http_tls_verify_cb returns: %s\n", gpg_strerror (err));
+  return err;
+}
+
+
+
 /* Prepend FNAME with the srcdir environment variable's value and
    return an allocated filename. */
 static char *
@@ -142,8 +191,7 @@ main (int argc, char **argv)
 {
   int last_argc = -1;
   gpg_error_t err;
-  int rc;
-  parsed_uri_t uri;
+  int rc;  parsed_uri_t uri;
   uri_tuple_t r;
   http_t hd;
   int c;
@@ -171,7 +219,7 @@ main (int argc, char **argv)
                  "Options:\n"
                  "  --verbose         print timings etc.\n"
                  "  --debug           flyswatter\n"
-                 "  --gnutls-debug N  use GNUTLS debug level N\n"
+                 "  --tls-debug N     use TLS debug level N\n"
                  "  --cacert FNAME    expect CA certificate in file FNAME\n"
                  "  --no-verify       do not verify the certificate\n"
                  "  --force-tls       use HTTP_FLAG_FORCE_TLS\n"
@@ -191,7 +239,7 @@ main (int argc, char **argv)
           debug++;
           argc--; argv++;
         }
-      else if (!strcmp (*argv, "--gnutls-debug"))
+      else if (!strcmp (*argv, "--tls-debug"))
         {
           argc--; argv++;
           if (argc)
@@ -248,9 +296,11 @@ main (int argc, char **argv)
   assuan_sock_init ();
 
 #if HTTP_USE_NTBTLS
-
-  (void)err;
-
+  log_info ("new session.\n");
+  err = http_session_new (&session, NULL, HTTP_FLAG_TRUST_DEF,
+                          my_http_tls_verify_cb, NULL);
+  if (err)
+    log_error ("http_session_new failed: %s\n", gpg_strerror (err));
   ntbtls_set_debug (tls_dbg, NULL, NULL);
 
 #elif HTTP_USE_GNUTLS