[git] GnuPG - branch, master, updated. gnupg-2.1.0beta3-405-g60e2fc7

by Werner Koch cvs at cvs.gnupg.org
Mon May 5 16:22:40 CEST 2014


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "The GNU Privacy Guard".

The branch, master has been updated
       via  60e2fc7d38d8b37d1de944cf230e410c2ce37d5e (commit)
       via  ea0f5481f01eacedff264bf08144164aa989ec4d (commit)
       via  0e59195642eb26263b8e0b9200290538631d35cd (commit)
      from  2def230231abd34f6012df284ab468321ffedc10 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 60e2fc7d38d8b37d1de944cf230e410c2ce37d5e
Author: Werner Koch <wk at gnupg.org>
Date:   Mon May 5 16:09:45 2014 +0200

    dirmngr: Add support for hkps keyservers.
    
    * dirmngr/dirmngr.c: Include gnutls.h.
    (opts): Add --gnutls-debug and --hkp-cacert.
    (opt_gnutls_debug, my_gnutls_log): New.
    (set_debug): Set gnutls log level.
    (parse_rereadable_options): Register a CA file.
    (main): Init GNUTLS.
    * dirmngr/ks-engine-hkp.c (ks_hkp_help): Support hkps.
    (send_request): Ditto.

diff --git a/dirmngr/dirmngr.c b/dirmngr/dirmngr.c
index 81da029..8f85e48 100644
--- a/dirmngr/dirmngr.c
+++ b/dirmngr/dirmngr.c
@@ -40,6 +40,9 @@
 # include <signal.h>
 #endif
 #include <npth.h>
+#ifdef HTTP_USE_GNUTLS
+# include <gnutls/gnutls.h>
+#endif /*HTTP_USE_GNUTLS*/
 
 
 #define JNLIB_NEED_LOG_LOGV
@@ -92,6 +95,7 @@ enum cmd_and_opt_values {
   oDebugAll,
   oDebugWait,
   oDebugLevel,
+  oGnutlsDebug,
   oNoGreeting,
   oNoOptions,
   oHomedir,
@@ -116,6 +120,7 @@ enum cmd_and_opt_values {
   oOCSPMaxPeriod,
   oOCSPCurrentPeriod,
   oMaxReplies,
+  oHkpCaCert,
   oFakedSystemTime,
   oForce,
   oAllowOCSP,
@@ -195,11 +200,16 @@ static ARGPARSE_OPTS opts[] = {
   ARGPARSE_s_i (oMaxReplies, "max-replies",
                 N_("|N|do not return more than N items in one query")),
 
+  ARGPARSE_s_s (oHkpCaCert, "hkp-cacert",
+                N_("|FILE|use the CA certifciates in FILE for HKP over TLS")),
+
+
   ARGPARSE_s_s (oSocketName, "socket-name", "@"),  /* Only for debugging.  */
 
   ARGPARSE_s_u (oFakedSystemTime, "faked-system-time", "@"), /*(epoch time)*/
   ARGPARSE_p_u (oDebug,    "debug", "@"),
   ARGPARSE_s_n (oDebugAll, "debug-all", "@"),
+  ARGPARSE_s_i (oGnutlsDebug, "gnutls-debug", "@"),
   ARGPARSE_s_i (oDebugWait, "debug-wait", "@"),
   ARGPARSE_s_n (oNoGreeting, "no-greeting", "@"),
   ARGPARSE_s_s (oHomedir, "homedir", "@"),
@@ -234,6 +244,9 @@ static char *current_logfile;
 /* Helper to implement --debug-level. */
 static const char *debug_level;
 
+/* Helper to set the GNUTLS log level.  */
+static int opt_gnutls_debug = -1;
+
 /* Flag indicating that a shutdown has been requested.  */
 static volatile int shutdown_pending;
 
@@ -331,6 +344,20 @@ my_ksba_hash_buffer (void *arg, const char *oid,
 }
 
 
+/* GNUTLS log function callback.  */
+static void
+my_gnutls_log (int level, const char *text)
+{
+  int n;
+
+  n = strlen (text);
+  while (n && text[n-1] == '\n')
+    n--;
+
+  log_debug ("gnutls:L%d: %.*s\n", level, n, text);
+}
+
+
 /* Setup the debugging.  With a LEVEL of NULL only the active debug
    flags are propagated to the subsystems.  With LEVEL set, a specific
    set of debug flags is set; thus overriding all flags already
@@ -382,6 +409,14 @@ set_debug (void)
 
   if (opt.debug & DBG_CRYPTO_VALUE )
     gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1);
+
+#ifdef HTTP_USE_GNUTLS
+  if (opt_gnutls_debug >= 0)
+    {
+      gnutls_global_set_log_function (my_gnutls_log);
+      gnutls_global_set_log_level (opt_gnutls_debug);
+    }
+#endif /*HTTP_USE_GNUTLS*/
 }
 
 
@@ -439,6 +474,7 @@ parse_rereadable_options (ARGPARSE_ARGS *pargs, int reread)
           opt.ocsp_signer = tmp;
         }
       FREE_STRLIST (opt.ignored_cert_extensions);
+      http_register_tls_ca (NULL);
       return 1;
     }
 
@@ -449,6 +485,7 @@ parse_rereadable_options (ARGPARSE_ARGS *pargs, int reread)
     case oDebug:   opt.debug |= pargs->r.ret_ulong; break;
     case oDebugAll: opt.debug = ~0; break;
     case oDebugLevel: debug_level = pargs->r.ret_str; break;
+    case oGnutlsDebug: opt_gnutls_debug = pargs->r.ret_int; break;
 
     case oLogFile:
       if (!reread)
@@ -490,6 +527,10 @@ parse_rereadable_options (ARGPARSE_ARGS *pargs, int reread)
 
     case oMaxReplies: opt.max_replies = pargs->r.ret_int; break;
 
+    case oHkpCaCert:
+      http_register_tls_ca (pargs->r.ret_str);
+      break;
+
     case oIgnoreCertExtension:
       add_to_strlist (&opt.ignored_cert_extensions, pargs->r.ret_str);
       break;
@@ -628,6 +669,12 @@ main (int argc, char **argv)
   ksba_set_malloc_hooks (gcry_malloc, gcry_realloc, gcry_free );
   ksba_set_hash_buffer_function (my_ksba_hash_buffer, NULL);
 
+  /* Init GNUTLS.  */
+#ifdef HTTP_USE_GNUTLS
+  rc = gnutls_global_init ();
+  if (rc)
+    log_fatal ("gnutls_global_init failed: %s\n", gnutls_strerror (rc));
+#endif /*HTTP_USE_GNUTLS*/
 
   /* Init Assuan. */
   malloc_hooks.malloc = gcry_malloc;
diff --git a/dirmngr/ks-engine-hkp.c b/dirmngr/ks-engine-hkp.c
index fa616a0..c115cf5 100644
--- a/dirmngr/ks-engine-hkp.c
+++ b/dirmngr/ks-engine-hkp.c
@@ -628,12 +628,14 @@ ks_hkp_help (ctrl_t ctrl, parsed_uri_t uri)
   const char const data[] =
     "Handler for HKP URLs:\n"
     "  hkp://\n"
+    "  hkps://\n"
     "Supported methods: search, get, put\n";
   gpg_error_t err;
 
   if (!uri)
-    err = ks_print_help (ctrl, "  hkp");
-  else if (uri->is_http && !strcmp (uri->scheme, "hkp"))
+    err = ks_print_help (ctrl, "  hkp\n  hkps");
+  else if (uri->is_http && (!strcmp (uri->scheme, "hkp")
+                            || !strcmp (uri->scheme, "hkps")))
     err = ks_print_help (ctrl, data);
   else
     err = 0;
@@ -747,6 +749,7 @@ send_request (ctrl_t ctrl, const char *request, const char *hostportstr,
               estream_t *r_fp)
 {
   gpg_error_t err;
+  http_session_t session = NULL;
   http_t http = NULL;
   int redirects_left = MAX_REDIRECTS;
   estream_t fp = NULL;
@@ -754,6 +757,10 @@ send_request (ctrl_t ctrl, const char *request, const char *hostportstr,
 
   *r_fp = NULL;
 
+  err = http_session_new (&session, NULL);
+  if (err)
+    goto leave;
+
  once_more:
   err = http_open (&http,
                    post_cb? HTTP_REQ_POST : HTTP_REQ_GET,
@@ -761,7 +768,8 @@ send_request (ctrl_t ctrl, const char *request, const char *hostportstr,
                    /* fixme: AUTH */ NULL,
                    httpflags,
                    /* fixme: proxy*/ NULL,
-                   NULL, NULL,
+                   session,
+                   NULL,
                    /*FIXME curl->srvtag*/NULL);
   if (!err)
     {
@@ -798,6 +806,13 @@ send_request (ctrl_t ctrl, const char *request, const char *hostportstr,
       goto leave;
     }
 
+  if (http_get_tls_info (http, NULL))
+    {
+      /* Update the httpflags so that a redirect won't fallback to an
+         unencrypted connection.  */
+      httpflags |= HTTP_FLAG_FORCE_TLS;
+    }
+
   switch (http_get_status_code (http))
     {
     case 200:
@@ -806,6 +821,7 @@ send_request (ctrl_t ctrl, const char *request, const char *hostportstr,
 
     case 301:
     case 302:
+    case 307:
       {
         const char *s = http_get_header (http, "Location");
 
@@ -837,6 +853,10 @@ send_request (ctrl_t ctrl, const char *request, const char *hostportstr,
       goto leave;
     }
 
+  /* FIXME: We should register a permanent redirection and whether a
+     host has ever used TLS so that future calls will always use
+     TLS. */
+
   fp = http_get_read_ptr (http);
   if (!fp)
     {
@@ -851,6 +871,7 @@ send_request (ctrl_t ctrl, const char *request, const char *hostportstr,
 
  leave:
   http_close (http, 0);
+  http_session_release (session);
   xfree (request_buffer);
   return err;
 }
diff --git a/dirmngr/sks-keyservers.netCA.pem b/dirmngr/sks-keyservers.netCA.pem
new file mode 100644
index 0000000..24a2ad2
--- /dev/null
+++ b/dirmngr/sks-keyservers.netCA.pem
@@ -0,0 +1,32 @@
+-----BEGIN CERTIFICATE-----
+MIIFizCCA3OgAwIBAgIJAK9zyLTPn4CPMA0GCSqGSIb3DQEBBQUAMFwxCzAJBgNV
+BAYTAk5PMQ0wCwYDVQQIDARPc2xvMR4wHAYDVQQKDBVza3Mta2V5c2VydmVycy5u
+ZXQgQ0ExHjAcBgNVBAMMFXNrcy1rZXlzZXJ2ZXJzLm5ldCBDQTAeFw0xMjEwMDkw
+MDMzMzdaFw0yMjEwMDcwMDMzMzdaMFwxCzAJBgNVBAYTAk5PMQ0wCwYDVQQIDARP
+c2xvMR4wHAYDVQQKDBVza3Mta2V5c2VydmVycy5uZXQgQ0ExHjAcBgNVBAMMFXNr
+cy1rZXlzZXJ2ZXJzLm5ldCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC
+ggIBANdsWy4PXWNUCkS3L//nrd0GqN3dVwoBGZ6w94Tw2jPDPifegwxQozFXkG6I
+6A4TK1CJLXPvfz0UP0aBYyPmTNadDinaB9T4jIwd4rnxl+59GiEmqkN3IfPsv5Jj
+MkKUmJnvOT0DEVlEaO1UZIwx5WpfprB3mR81/qm4XkAgmYrmgnLXd/pJDAMk7y1F
+45b5zWofiD5l677lplcIPRbFhpJ6kDTODXh/XEdtF71EAeaOdEGOvyGDmCO0GWqS
+FDkMMPTlieLA/0rgFTcz4xwUYj/cD5e0ZBuSkYsYFAU3hd1cGfBue0cPZaQH2HYx
+Qk4zXD8S3F4690fRhr+tki5gyG6JDR67aKp3BIGLqm7f45WkX1hYp+YXywmEziM4
+aSbGYhx8hoFGfq9UcfPEvp2aoc8u5sdqjDslhyUzM1v3m3ZGbhwEOnVjljY6JJLx
+MxagxnZZSAY424ZZ3t71E/Mn27dm2w+xFRuoy8JEjv1d+BT3eChM5KaNwrj0IO/y
+u8kFIgWYA1vZ/15qMT+tyJTfyrNVV/7Df7TNeWyNqjJ5rBmt0M6NpHG7CrUSkBy9
+p8JhimgjP5r0FlEkgg+lyD+V79H98gQfVgP3pbJICz0SpBQf2F/2tyS4rLm+49rP
+fcOajiXEuyhpcmzgusAj/1FjrtlynH1r9mnNaX4e+rLWzvU5AgMBAAGjUDBOMB0G
+A1UdDgQWBBTkwyoJFGfYTVISTpM8E+igjdq28zAfBgNVHSMEGDAWgBTkwyoJFGfY
+TVISTpM8E+igjdq28zAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4ICAQAR
+OXnYwu3g1ZjHyley3fZI5aLPsaE17cOImVTehC8DcIphm2HOMR/hYTTL+V0G4P+u
+gH+6xeRLKSHMHZTtSBIa6GDL03434y9CBuwGvAFCMU2GV8w92/Z7apkAhdLToZA/
+X/iWP2jeaVJhxgEcH8uPrnSlqoPBcKC9PrgUzQYfSZJkLmB+3jEa3HKruy1abJP5
+gAdQvwvcPpvYRnIzUc9fZODsVmlHVFBCl2dlu/iHh2h4GmL4Da2rRkUMlbVTdioB
+UYIvMycdOkpH5wJftzw7cpjsudGas0PARDXCFfGyKhwBRFY7Xp7lbjtU5Rz0Gc04
+lPrhDf0pFE98Aw4jJRpFeWMjpXUEaG1cq7D641RpgcMfPFvOHY47rvDTS7XJOaUT
+BwRjmDt896s6vMDcaG/uXJbQjuzmmx3W2Idyh3s5SI0GTHb0IwMKYb4eBUIpQOnB
+cE77VnCYqKvN1NVYAqhWjXbY7XasZvszCRcOG+W3FqNaHOK/n/0ueb0uijdLan+U
+f4p1bjbAox8eAOQS/8a3bzkJzdyBNUKGx1BIK2IBL9bn/HravSDOiNRSnZ/R3l9G
+ZauX0tu7IIDlRCILXSyeazu0aj/vdT3YFQXPcvt5Fkf5wiNTo53f72/jYEJd6qph
+WrpoKqrwGwTpRUCMhYIUt65hsTxCiJJ5nKe39h46sg==
+-----END CERTIFICATE-----
diff --git a/doc/dirmngr.texi b/doc/dirmngr.texi
index e626487..7b2f92c 100644
--- a/doc/dirmngr.texi
+++ b/doc/dirmngr.texi
@@ -18,7 +18,7 @@
 @mansect synopsis
 @ifset manverb
 .B  dirmngr
-.RI [ options ]  
+.RI [ options ]
 .I command
 .RI [ args ]
 @end ifset
@@ -32,7 +32,7 @@ system daemon through the @command{dirmngr-client} tool.
 
 If @command{dirmngr} is started in system daemon mode, it uses a
 directory layout as common for system daemons and does not make use of
-the default @file{~/.gnupg} directory.  
+the default @file{~/.gnupg} directory.
 
 
 @manpause
@@ -175,7 +175,7 @@ numeric value or by a keyword:
 @item none
 No debugging at all.  A value of less than 1 may be used instead of
 the keyword.
- at item basic  
+ at item basic
 Some basic debug messages.  A value between 1 and 2 may be used
 instead of the keyword.
 @item advanced
@@ -204,6 +204,10 @@ usual C-Syntax.
 @opindex debug-all
 Same as @code{--debug=0xffffffff}
 
+ at item --gnutls-debug @var{level}
+ at opindex gnutls-debug
+Enable debugging of GNUTLS at @var{level}.
+
 @item --debug-wait @var{n}
 @opindex debug-wait
 When running in server mode, wait @var{n} seconds before entering the
@@ -247,12 +251,12 @@ scheme are ignored when looking for a suitable DP.
 @item --ignore-ldap-dp
 @opindex ignore-ldap-dp
 This is similar to @option{--ignore-http-dp} but ignores entries using
-the @acronym{LDAP} scheme.  Both options may be combined resulting in 
+the @acronym{LDAP} scheme.  Both options may be combined resulting in
 ignoring DPs entirely.
 
 @item --ignore-ocsp-service-url
 @opindex ignore-ocsp-service-url
-Ignore all OCSP URLs contained in the certificate.  The effect is to 
+Ignore all OCSP URLs contained in the certificate.  The effect is to
 force the use of the default responder.
 
 @item --honor-http-proxy
@@ -284,7 +288,7 @@ configured LDAP server if the connection using the "proxy" failed.
 @item --ldapserverlist-file @var{file}
 @opindex ldapserverlist-file
 Read the list of LDAP servers to consult for CRLs and certificates from
-file instead of the default per-user ldap server list file. The default 
+file instead of the default per-user ldap server list file. The default
 value for @var{file} is @file{dirmngr_ldapservers.conf} or
 @file{ldapservers.conf} when running in @option{--daemon} mode.
 
@@ -328,7 +332,7 @@ Note: The current version of dirmngr has this option disabled by default.
 
 @item --allow-ocsp
 @opindex allow-ocsp
-This option enables OCSP support if requested by the client.  
+This option enables OCSP support if requested by the client.
 
 OCSP requests are rejected by default because they may violate the
 privacy of the user; for example it is possible to track the time when
@@ -395,10 +399,17 @@ won't be rejected due to an unknown critical extension.  Use this
 option with care because extensions are usually flagged as critical
 for a reason.
 
+ at item --hkp-cacert @var{file}
+Use the root certificates in @var{file} for verification of the TLS
+certificates used with @code{hkps} (keyserver access over TLS).  If
+the file is in PEM format a suffix of @code{.pem} is expected for
+ at var{file}.  This option may be given multiple times to add more
+root certificates.
+
 @end table
 
 
- at c 
+ at c
 @c Dirmngr Configuration
 @c
 @mansect files
@@ -472,7 +483,7 @@ Please ignore the output; it is not needed anymore.  Check the log file
 to see whether all trusted root certificates have been loaded correctly.
 
 
- at c 
+ at c
 @c Dirmngr Signals
 @c
 @mansect signals
@@ -480,7 +491,7 @@ to see whether all trusted root certificates have been loaded correctly.
 @section Use of signals.
 
 A running @command{dirmngr} may be controlled by signals, i.e. using
-the @command{kill} command to send a signal to the process. 
+the @command{kill} command to send a signal to the process.
 
 Here is a list of supported signals:
 
@@ -522,7 +533,7 @@ This prints some caching statistics to the log file.
 Dirmngr is supposed to be used as a system wide daemon, it should be
 started like:
 
- at example 
+ at example
   dirmngr --daemon
 @end example
 
@@ -613,7 +624,7 @@ local lookup will be done in this case.
 
 Check whether the certificate described by the @var{certid} has been
 revoked.  Due to caching, the Dirmngr is able to answer immediately in
-most cases.  
+most cases.
 
 The @var{certid} is a hex encoded string consisting of two parts,
 delimited by a single dot.  The first part is the SHA-1 hash of the
@@ -642,7 +653,7 @@ us that it has been revoked.
 
 @item GPG_ERR_NO_CRL_KNOWN
 No CRL is known for this certificate or the CRL is not valid or out of
-date. 
+date.
 
 @item GPG_ERR_NO_DATA
 The OCSP responder returned an ``unknown'' status.  This means that it
@@ -690,7 +701,7 @@ given or the certificate is not know, the function inquires the
 certificate using:
 
 @example
-  S: INQUIRE TARGETCERT 
+  S: INQUIRE TARGETCERT
   C: D <DER encoded certificate>
   C: END
 @end example
@@ -720,7 +731,7 @@ certificate is not known by Dirmngr, the function inquires the
 certificate using:
 
 @example
-  S: INQUIRE TARGETCERT 
+  S: INQUIRE TARGETCERT
   C: D <DER encoded certificate>
   C: END
 @end example
@@ -751,13 +762,13 @@ helpful for debugging.  To get the actual certificate, this command
 immediately inquires it using
 
 @example
-  S: INQUIRE TARGETCERT 
+  S: INQUIRE TARGETCERT
   C: D <DER encoded certificate>
   C: END
 @end example
 
 Thus the caller is expected to return the certificate for the request
-as a binary blob. 
+as a binary blob.
 
 @noindent
 The return code is 0 for success; i.e. the certificate has not been
@@ -771,45 +782,45 @@ internally by dirmngr.  This command is only useful for debugging.  To
 get the actual certificate, this command immediately inquires it using
 
 @example
-  S: INQUIRE TARGETCERT 
+  S: INQUIRE TARGETCERT
   C: D <DER encoded certificate>
   C: END
 @end example
 
 Thus the caller is expected to return the certificate for the request
-as a binary blob. 
+as a binary blob.
 
 
 @mansect see also
 @ifset isman
- at command{gpgsm}(1), 
+ at command{gpgsm}(1),
 @command{dirmngr-client}(1)
 @end ifset
 @include see-also-note.texi
 
- at c 
+ at c
 @c !!! UNDER CONSTRUCTION !!!
- at c 
- at c 
+ at c
+ at c
 @c @section Verifying a Certificate
- at c 
+ at c
 @c There are several ways to request services from Dirmngr.  Almost all of
 @c them are done using the Assuan protocol.  What we describe here is the
 @c Assuan command CHECKCRL as used for example by the dirmnr-client tool if
 @c invoked as
- at c 
+ at c
 @c @example
 @c   dirmngr-client foo.crt
 @c @end example
- at c 
+ at c
 @c This command will send an Assuan request to an already running Dirmngr
 @c instance.  foo.crt is expected to be a standard X.509 certificate and
 @c dirmngr will receive the Assuan command
- at c 
+ at c
 @c @example
 @c    CHECKCRL @var [{fingerprint}]
 @c @end example
- at c 
+ at c
 @c @var{fingerprint} is optional and expected to be the SHA-1 has of the
 @c DER encoding of the certificate under question.  It is to be HEX
 @c encoded.  The rationale for sending the fingerprint is that it allows
@@ -817,15 +828,15 @@ as a binary blob.
 @c this is not the case and no certificate has been found in dirmngr's
 @c internal certificate storage, dirmngr will request the certificate using
 @c the Assuan inquiry
- at c 
+ at c
 @c @example
 @c       INQUIRE TARGETCERT
 @c @end example
- at c 
+ at c
 @c The caller (in our example dirmngr-client) is then expected to return
 @c the certificate for the request (which should match @var{fingerprint})
 @c as a binary blob.
- at c 
+ at c
 @c Dirmngr now passes control to @code{crl_cache_cert_isvalid}.  This
 @c function checks whether a CRL item exists for target certificate.  These
 @c CRL items are kept in a database of already loaded and verified CRLs.
@@ -837,25 +848,25 @@ as a binary blob.
 @c listed in the CRL or @code{GPG_ERR_NO_CRL_KNOWN} in cases where no CRL or no
 @c information is available.  The first two codes are immediatly returned to
 @c the caller and the processing of this request has been done.
- at c 
+ at c
 @c Only the @code{GPG_ERR_NO_CRL_KNOWN} needs more attention: Dirmngr now
 @c calls @code{clr_cache_reload_crl} and if this succeeds calls
 @c @code{crl_cache_cert_isvald) once more.  All further errors are
 @c immediately returned to the caller.
- at c 
+ at c
 @c @code{crl_cache_reload_crl} is the actual heart of the CRL management.
 @c It locates the corresponding CRL for the target certificate, reads and
 @c verifies this CRL and stores it in the CRL cache.  It works like this:
- at c 
+ at c
 @c * Loop over all crlDPs in the target certificate.
 @c     * If the crlDP is invalid immediately terminate the loop.
 @c     * Loop over all names in the current crlDP.
- at c         * If the URL scheme is unknown or not enabled 
+ at c         * If the URL scheme is unknown or not enabled
 @c           (--ignore-http-dp, --ignore-ldap-dp) continues with
 @c           the next name.
 @c         * @code{crl_fetch} is called to actually retrieve the CRL.
 @c           In case of problems this name is ignore and we continue with
- at c           the next name.  Note that @code{crl_fetch} does only return 
+ at c           the next name.  Note that @code{crl_fetch} does only return
 @c           a descriptor for the CRL for further reading so does the CRL
 @c           does not yet end up in memory.
 @c         * @code{crl_cache_insert} is called with that descriptor to
@@ -873,16 +884,16 @@ as a binary blob.
 @c     * @code(crl_cache_insert) is then used to actually insert the CRL
 @c       into the cache.  If this failed we give up immediatley without
 @c       checking the rest of the servers from the first step.
- at c * Ready. 
- at c 
- at c 
+ at c * Ready.
+ at c
+ at c
 @c The @code{crl_cache_insert} function takes care of reading the bulk of
 @c the CRL, parsing it and checking the signature.  It works like this: A
 @c new database file is created using a temporary file name.  The CRL
 @c parsing machinery is started and all items of the CRL are put into
 @c this database file.  At the end the issuer certificate of the CRL
 @c needs to be retrieved.  Three cases are to be distinguished:
- at c 
+ at c
 @c  a) An authorityKeyIdentifier with an issuer and serialno exits: The
 @c     certificate is retrieved using @code{find_cert_bysn}.  If
 @c     the certificate is in the certificate cache, it is directly
@@ -899,7 +910,7 @@ as a binary blob.
 @c     certificate to match the requested issuer and seriano (This is
 @c     needed because the LDAP layer may return several certificates as
 @c     LDAP as no standard way to retrieve by serial number).
- at c 
+ at c
 @c  b) An authorityKeyIdentifier with a key ID exists: The certificate is
 @c     retrieved using @code{find_cert_bysubject}.  If the certificate is
 @c     in the certificate cache, it is directly returned.  Then the
@@ -913,7 +924,7 @@ as a binary blob.
 @c     external resources.  This is done using the @code{ca_cert_fetch}
 @c     and @code{fetch_next_ksba_cert} and comparing the returned
 @c     certificate to match the requested subject and key ID.
- at c 
+ at c
 @c  c) No authorityKeyIdentifier exits: The certificate is retrieved
 @c     using @code{find_cert_bysubject} without the key ID argument.  If
 @c     the certificate is in the certificate cache the first one with a
@@ -930,12 +941,12 @@ as a binary blob.
 @c     and @code{fetch_next_ksba_cert} and comparing the returned
 @c     certificate to match the requested subject; the first certificate
 @c     with a matching subject is then returned.
- at c 
+ at c
 @c If no certificate was found, the function returns with the error
 @c GPG_ERR_MISSING_CERT.  Now the signature is verified.  If this fails,
 @c the erro is returned.  On success the @code{validate_cert_chain} is
- at c used to verify that the certificate is actually valid. 
- at c 
+ at c used to verify that the certificate is actually valid.
+ at c
 @c Here we may encounter a recursive situation:
 @c @code{validate_cert_chain} needs to look at other certificates and
 @c also at CRLs to check whether tehse other certificates and well, the
@@ -944,7 +955,7 @@ as a binary blob.
 @c are currently processing. This would be a catch-22 and may indicate a
 @c broken PKI.  However, due to overlapping expiring times and imprecise
 @c clocks thsi may actually happen.
- at c     
+ at c
 @c For historical reasons the Assuan command ISVALID is a bit different
 @c to CHECKCRL but this is mainly due to different calling conventions.
 @c In the end the same fucntionality is used, albeit hidden by a couple
@@ -952,44 +963,44 @@ as a binary blob.
 @c ingetrages OCSP checking depending on options are the way it is
 @c called.  GPGSM still uses this command but might eventuall switch over
 @c to CHECKCRL and CHECKOCSP so that ISVALID can be retired.
- at c   
- at c 
+ at c
+ at c
 @c @section Validating a certificate
- at c 
+ at c
 @c We describe here how the internal function @code{validate_cert_chain}
 @c works. Note that mainly testing purposes this functionality may be
 @c called directly using @cmd{dirmngr-client --validate @file{foo.crt}}.
- at c 
+ at c
 @c For backward compatibility this function returns success if Dirmngr is
 @c not used as a system daemon.  Thus not validating the certicates at
 @c all. FIXME:  This is definitely not correct and should be fixed ASAP.
- at c 
+ at c
 @c The function takes the target certificate and a mode argument as
 @c parameters and returns an error code and optionally the closes
 @c expiration time of all certificates in the chain.
- at c 
+ at c
 @c We first check that the certificate may be used for the requested
 @c purpose (i.e. OCSP or CRL signing).  If this is not the case
 @c GPG_ERR_WRONG_KEY_USAGE is returned.
- at c 
+ at c
 @c The next step is to find the trust anchor (root certificate) and to
 @c assemble the chain in memory: Starting with the target certificate,
 @c the expiration time is checked against the current date, unknown
 @c critical extensions are detected and certificate policies are matched
 @c (We only allow 2.289.9.9 but I have no clue about that OID and from
 @c where I got it - it does not even seem to be assigned - debug cruft?).
- at c 
+ at c
 @c Now if this certificate is a self-signed one, we have reached the
 @c trust anchor.  In this case we check that the signature is good, the
 @c certificate is allowed to act as a CA, that it is a trusted one (by
 @c checking whether it is has been put into the trusted-certs
 @c configuration directory) and finally prepend into to our list
 @c representing the certificate chain.  This steps ends then.
- at c 
+ at c
 @c If it is not a self-signed certificate, we check that the chain won't
 @c get too long (current limit is 100), if this is the case we terminate
 @c with the error GPG_ERR_BAD_CERT_CHAIN.
- at c 
+ at c
 @c Now the issuer's certificate is looked up: If an
 @c authorityKeyIdentifier is available, this one is used to locate the
 @c certificate either using issuer and serialnumber or subject DN
@@ -1002,7 +1013,7 @@ as a binary blob.
 @c that a matching certificate has explicitly been put into the
 @c certificate cache.  If the issuer's certificate could not be found,
 @c the validation terminates with the error code @code{GPG_ERR_MISSING_CERT}.
- at c 
+ at c
 @c If the issuer's certificate has been found, the signature of the
 @c actual certificate is checked and in case this fails the error
 @c #code{GPG_ERR_BAD_CERT_CHAIN} is returned.  If the signature checks out, the
@@ -1011,13 +1022,13 @@ as a binary blob.
 @c certificate signing).  Then the certificate is prepended to our list
 @c representing the certificate chain.  Finally the loop is continued now
 @c with the issuer's certificate as the current certificate.
- at c 
+ at c
 @c After the end of the loop and if no error as been encountered
 @c (i.e. the certificate chain has been assempled correctly), a check is
 @c done whether any certificate expired or a critical policy has not been
 @c met.  In any of these cases the validation terminates with an
- at c appropriate error. 
- at c 
+ at c appropriate error.
+ at c
 @c Finally the function @code{check_revocations} is called to verify no
 @c certificate in the assempled chain has been revoked: This is an
 @c recursive process because a CRL has to be checked for each certificate
@@ -1025,16 +1036,16 @@ as a binary blob.
 @c that it is trusted and we avoid checking a CRL here due to common
 @c setup problems and the assumption that a revoked root certifcate has
 @c been removed from the list of trusted certificates.
- at c 
- at c 
- at c 
- at c 
+ at c
+ at c
+ at c
+ at c
 @c @section Looking up certificates through LDAP.
- at c 
+ at c
 @c This describes the LDAP layer to retrieve certificates.
 @c the functions @code{ca_cert_fetch} and @code{fetch_next_ksba_cert} are
 @c used for this.  The first one starts a search and the second one is
 @c used to retrieve certificate after certificate.
- at c 
+ at c
+
 
-  
diff --git a/doc/gpg.texi b/doc/gpg.texi
index 1a81010..bc12cbc 100644
--- a/doc/gpg.texi
+++ b/doc/gpg.texi
@@ -1630,16 +1630,29 @@ are available for all keyserver types, some common options are:
   program uses internally (libcurl, openldap, etc).
 
   @item check-cert
+ at ifset gpgtwoone
+  This option has no more function since GnuPG 2.1.  Use the
+  @code{dirmngr} configuration options instead.
+ at end ifset
+ at ifclear gpgtwoone
   Enable certificate checking if the keyserver presents one (for hkps or
   ldaps).  Defaults to on.
+ at end ifclear
 
   @item ca-cert-file
+ at ifset gpgtwoone
+  This option has no more function since GnuPG 2.1.  Use the
+  @code{dirmngr} configuration options instead.
+ at end ifset
+ at ifclear gpgtwoone
   Provide a certificate store to override the system default.  Only
   necessary if check-cert is enabled, and the keyserver is using a
   certificate that is not present in a system default certificate list.
 
   Note that depending on the SSL library that the keyserver helper is
   built with, this may actually be a directory or a file.
+ at end ifclear
+
 @end table
 
 @item --completes-needed @code{n}

commit ea0f5481f01eacedff264bf08144164aa989ec4d
Author: Werner Koch <wk at gnupg.org>
Date:   Mon May 5 16:06:42 2014 +0200

    http: Add reference counting to the session object.
    
    * common/http.c (http_session_t): Add field "refcount".
    (_my_socket_new, _my_socket_ref, _my_socket_unref): Add debug code.
    (send_request, my_npth_read, my_npth_write): Use SOCK object for the
    transport ptr.
    (http_session_release): Factor all code out to ...
    (session_unref): here.  Deref SOCK.
    (http_session_new): Init refcount and transport ptr.
    (http_session_ref): New.  Ref and unref all assignments.
    --
    
    Having the reference counted session objects makes it easier for the
    application to pass around only an estream.  Without that the
    application would need to implement an es_onclose machinery for the
    session object.

diff --git a/common/http.c b/common/http.c
index 590893d..eb95dcb 100644
--- a/common/http.c
+++ b/common/http.c
@@ -222,6 +222,7 @@ typedef struct cookie_s *cookie_t;
 /* The session object. */
 struct http_session_s
 {
+  int refcount;    /* Number of references to this object.  */
 #ifdef HTTP_USE_GNUTLS
   gnutls_certificate_credentials_t certcred;
   gnutls_session_t tls_session;
@@ -231,9 +232,7 @@ struct http_session_s
     unsigned int status; /* Verification status.  */
   } verify;
   char *servername; /* Malloced server name.  */
-#else
-  int dummy;
-#endif
+#endif /*HTTP_USE_GNUTLS*/
 };
 
 
@@ -327,7 +326,7 @@ init_sockets (void)
 /* Create a new socket object.  Returns NULL and closes FD if not
    enough memory is available.  */
 static my_socket_t
-my_socket_new (int fd)
+_my_socket_new (int lnr, int fd)
 {
   my_socket_t so;
 
@@ -341,34 +340,39 @@ my_socket_new (int fd)
     }
   so->fd = fd;
   so->refcount = 1;
-  /* log_debug ("my_socket_new(%d): object %p for fd %d created\n", */
+  /* log_debug ("http.c:socket_new(%d): object %p for fd %d created\n", */
   /*            lnr, so, so->fd); */
+  (void)lnr;
   return so;
 }
-/* #define my_socket_new(a) _my_socket_new ((a),__LINE__) */
+#define my_socket_new(a) _my_socket_new (__LINE__, (a))
 
 /* Bump up the reference counter for the socket object SO.  */
 static my_socket_t
-my_socket_ref (my_socket_t so)
+_my_socket_ref (int lnr, my_socket_t so)
 {
   so->refcount++;
-  /* log_debug ("my_socket_ref(%d): object %p for fd %d refcount now %d\n", */
+  /* log_debug ("http.c:socket_ref(%d) object %p for fd %d refcount now %d\n", */
   /*            lnr, so, so->fd, so->refcount); */
+  (void)lnr;
   return so;
 }
-/* #define my_socket_ref(a) _my_socket_ref ((a),__LINE__) */
+#define my_socket_ref(a) _my_socket_ref (__LINE__,(a))
+
 
 /* Bump down the reference counter for the socket object SO.  If SO
    has no more references, close the socket and release the
    object.  */
 static void
-my_socket_unref (my_socket_t so, void (*preclose)(void*), void *preclosearg)
+_my_socket_unref (int lnr, my_socket_t so,
+                  void (*preclose)(void*), void *preclosearg)
 {
   if (so)
     {
       so->refcount--;
-      /* log_debug ("my_socket_unref(%d): object %p for fd %d ref now %d\n", */
+      /* log_debug ("http.c:socket_unref(%d): object %p for fd %d ref now %d\n", */
       /*            lnr, so, so->fd, so->refcount); */
+      (void)lnr;
       if (!so->refcount)
         {
           if (preclose)
@@ -378,19 +382,21 @@ my_socket_unref (my_socket_t so, void (*preclose)(void*), void *preclosearg)
         }
     }
 }
-/* #define my_socket_unref(a) _my_socket_unref ((a),__LINE__) */
+#define my_socket_unref(a,b,c) _my_socket_unref (__LINE__,(a),(b),(c))
 
 
 #if defined (USE_NPTH) && defined(HTTP_USE_GNUTLS)
 static ssize_t
 my_npth_read (gnutls_transport_ptr_t ptr, void *buffer, size_t size)
 {
-  return npth_read ((int)(unsigned long)ptr, buffer, size);
+  my_socket_t sock = ptr;
+  return npth_read (sock->fd, buffer, size);
 }
 static ssize_t
 my_npth_write (gnutls_transport_ptr_t ptr, const void *buffer, size_t size)
 {
-  return npth_write ((int)(unsigned long)ptr, buffer, size);
+  my_socket_t sock = ptr;
+  return npth_write (sock->fd, buffer, size);
 }
 #endif /*USE_NPTH && HTTP_USE_GNUTLS*/
 
@@ -498,6 +504,44 @@ http_register_tls_ca (const char *fname)
 }
 
 
+/* Release a session.  Take care not to release it while it is being
+   used by a http context object.  */
+static void
+session_unref (int lnr, http_session_t sess)
+{
+  if (!sess)
+    return;
+
+  sess->refcount--;
+  /* log_debug ("http.c:session_unref(%d): sess %p ref now %d\n", */
+  /*            lnr, sess, sess->refcount); */
+  (void)lnr;
+  if (sess->refcount)
+    return;
+
+#ifdef HTTP_USE_GNUTLS
+  if (sess->tls_session)
+    {
+      my_socket_t sock = gnutls_transport_get_ptr (sess->tls_session);
+      my_socket_unref (sock, NULL, NULL);
+      gnutls_deinit (sess->tls_session);
+    }
+  if (sess->certcred)
+    gnutls_certificate_free_credentials (sess->certcred);
+  xfree (sess->servername);
+#endif /*HTTP_USE_GNUTLS*/
+
+  xfree (sess);
+}
+#define http_session_unref(a) session_unref (__LINE__, (a))
+
+void
+http_session_release (http_session_t sess)
+{
+  http_session_unref (sess);
+}
+
+
 /* Create a new session object which is currently used to enable TLS
    support.  It may eventually allow reusing existing connections.  */
 gpg_error_t
@@ -511,6 +555,7 @@ http_session_new (http_session_t *r_session, const char *tls_priority)
   sess = xtrycalloc (1, sizeof *sess);
   if (!sess)
     return gpg_error_from_syserror ();
+  sess->refcount = 1;
 
 #ifdef HTTP_USE_GNUTLS
   {
@@ -544,6 +589,10 @@ http_session_new (http_session_t *r_session, const char *tls_priority)
         err = gpg_error (GPG_ERR_GENERAL);
         goto leave;
       }
+    /* A new session has the transport ptr set to (void*(-1), we need
+       it to be NULL.  */
+    gnutls_transport_set_ptr (sess->tls_session, NULL);
+
     rc = gnutls_priority_set_direct (sess->tls_session,
                                      tls_priority? tls_priority : "NORMAL",
                                      &errpos);
@@ -569,13 +618,14 @@ http_session_new (http_session_t *r_session, const char *tls_priority)
   (void)tls_priority;
 #endif /*!HTTP_USE_GNUTLS*/
 
+  /* log_debug ("http.c:session_new: sess %p created\n", sess); */
   err = 0;
 
 #ifdef HTTP_USE_GNUTLS
  leave:
 #endif /*HTTP_USE_GNUTLS*/
   if (err)
-    http_session_release (sess);
+    http_session_unref (sess);
   else
     *r_session = sess;
 
@@ -583,23 +633,13 @@ http_session_new (http_session_t *r_session, const char *tls_priority)
 }
 
 
-/* Release a session.  Take care not to release it while it is beeing
-   used by a http contect object.  */
-void
-http_session_release (http_session_t sess)
+/* Increment the reference count for session SESS.  */
+http_session_t
+http_session_ref (http_session_t sess)
 {
-  if (!sess)
-    return;
-
-#ifdef HTTP_USE_GNUTLS
-  if (sess->tls_session)
-    gnutls_deinit (sess->tls_session);
-  if (sess->certcred)
-    gnutls_certificate_free_credentials (sess->certcred);
-  xfree (sess->servername);
-#endif /*HTTP_USE_GNUTLS*/
-
-  xfree (sess);
+  sess->refcount++;
+  /* log_debug ("http.c:session_ref: sess %p ref now %d\n", sess, sess->refcount); */
+  return sess;
 }
 
 
@@ -625,7 +665,7 @@ http_open (http_t *r_hd, http_req_t reqtype, const char *url,
     return gpg_error_from_syserror ();
   hd->req_type = reqtype;
   hd->flags = flags;
-  hd->session = session;
+  hd->session = http_session_ref (session);
 
   err = parse_uri (&hd->uri, url, 0, !!(flags & HTTP_FLAG_FORCE_TLS));
   if (!err)
@@ -638,6 +678,7 @@ http_open (http_t *r_hd, http_req_t reqtype, const char *url,
         es_fclose (hd->fp_read);
       if (hd->fp_write)
         es_fclose (hd->fp_write);
+      http_session_unref (hd->session);
       xfree (hd);
     }
   else
@@ -791,7 +832,7 @@ http_wait_response (http_t hd)
   if (!cookie)
     return gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
   cookie->sock = my_socket_ref (hd->sock);
-  cookie->session = hd->session;
+  cookie->session = http_session_ref (hd->session);
   cookie->use_tls = hd->uri->use_tls;
 
   hd->read_cookie = cookie;
@@ -800,6 +841,7 @@ http_wait_response (http_t hd)
     {
       err = gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
       my_socket_unref (cookie->sock, NULL, NULL);
+      http_session_unref (cookie->session);
       xfree (cookie);
       hd->read_cookie = NULL;
       return err;
@@ -857,6 +899,7 @@ http_close (http_t hd, int keep_read_stream)
     es_fclose (hd->fp_read);
   if (hd->fp_write)
     es_fclose (hd->fp_write);
+  http_session_unref (hd->session);
   http_release_parsed_uri (hd->uri);
   while (hd->headers)
     {
@@ -1431,12 +1474,7 @@ send_request (http_t hd, const char *auth,
       int rc;
 
       my_socket_ref (hd->sock);
-#if GNUTLS_VERSION_NUMBER >= 0x030109
-      gnutls_transport_set_int (hd->session->tls_session, hd->sock->fd);
-#else
-      gnutls_transport_set_ptr (hd->session->tls_session,
-                                (gnutls_transport_ptr_t)(hd->sock->fd));
-#endif
+      gnutls_transport_set_ptr (hd->session->tls_session, hd->sock);
 #ifdef USE_NPTH
       gnutls_transport_set_pull_function (hd->session->tls_session,
                                           my_npth_read);
@@ -1561,7 +1599,7 @@ send_request (http_t hd, const char *auth,
     cookie->sock = my_socket_ref (hd->sock);
     hd->write_cookie = cookie;
     cookie->use_tls = hd->uri->use_tls;
-    cookie->session = hd->session;
+    cookie->session = http_session_ref (hd->session);
 
     hd->fp_write = es_fopencookie (cookie, "w", cookie_functions);
     if (!hd->fp_write)
@@ -2382,6 +2420,8 @@ cookie_close (void *cookie)
     if (c->sock)
       my_socket_unref (c->sock, NULL, NULL);
 
+  if (c->session)
+    http_session_unref (c->session);
   xfree (c);
   return 0;
 }
diff --git a/common/http.h b/common/http.h
index fa73b6e..b6471b6 100644
--- a/common/http.h
+++ b/common/http.h
@@ -95,6 +95,7 @@ void http_register_tls_ca (const char *fname);
 
 gpg_error_t http_session_new (http_session_t *r_session,
                               const char *tls_priority);
+http_session_t http_session_ref (http_session_t sess);
 void http_session_release (http_session_t sess);
 
 
diff --git a/common/t-http.c b/common/t-http.c
index 0191e85..7b9c744 100644
--- a/common/t-http.c
+++ b/common/t-http.c
@@ -144,6 +144,7 @@ main (int argc, char **argv)
   int c;
   unsigned int my_http_flags = 0;
   int no_out = 0;
+  int tls_dbg = 0;
   const char *cafile = NULL;
   http_session_t session = NULL;
 
@@ -163,12 +164,13 @@ main (int argc, char **argv)
         {
           fputs ("usage: " PGM " URL\n"
                  "Options:\n"
-                 "  --verbose       print timings etc.\n"
-                 "  --debug         flyswatter\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"
-                 "  --no-out        do not print the content\n",
+                 "  --verbose         print timings etc.\n"
+                 "  --debug           flyswatter\n"
+                 "  --gnutls-debug N  use GNUTLS 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"
+                 "  --no-out          do not print the content\n",
                  stdout);
           exit (0);
         }
@@ -183,6 +185,15 @@ main (int argc, char **argv)
           debug++;
           argc--; argv++;
         }
+      else if (!strcmp (*argv, "--gnutls-debug"))
+        {
+          argc--; argv++;
+          if (argc)
+            {
+              tls_dbg = atoi (*argv);
+              argc--; argv++;
+            }
+        }
       else if (!strcmp (*argv, "--cacert"))
         {
           argc--; argv++;
@@ -248,7 +259,8 @@ main (int argc, char **argv)
   /* gnutls_certificate_set_dh_params (certcred, dh_params); */
 
   gnutls_global_set_log_function (my_gnutls_log);
-  /* gnutls_global_set_log_level (2); */
+  if (tls_dbg)
+    gnutls_global_set_log_level (tls_dbg);
 
 #endif /*HTTP_USE_GNUTLS*/
 

commit 0e59195642eb26263b8e0b9200290538631d35cd
Author: Werner Koch <wk at gnupg.org>
Date:   Fri May 2 15:37:02 2014 +0200

    http: Add HTTP_FLAG_FORCE_TLS and http_get_tls_info.
    
    * common/http.c (http_parse_uri): Factor code out to ...
    (parse_uri): here.  Add arg FORCE_TLS.
    (do_parse_uri): Ditto.  Implement flag.
    (http_get_tls_info): New.
    (http_register_tls_ca): Allow clearing of the list.
    (send_request): Use a default verification function.
    * common/http.h (HTTP_FLAG_FORCE_TLS): New.
    * common/t-http.c (main): Add several command line options.

diff --git a/common/http.c b/common/http.c
index e5516e8..590893d 100644
--- a/common/http.c
+++ b/common/http.c
@@ -161,7 +161,9 @@ typedef void * gnutls_session_t;
 #endif
 
 static gpg_err_code_t do_parse_uri (parsed_uri_t uri, int only_local_part,
-                                    int no_scheme_check);
+                                    int no_scheme_check, int force_tls);
+static gpg_error_t parse_uri (parsed_uri_t *ret_uri, const char *uri,
+                              int no_scheme_check, int force_tls);
 static int remove_escapes (char *string);
 static int insert_escapes (char *buffer, const char *string,
                            const char *special);
@@ -463,7 +465,9 @@ make_header_line (const char *prefix, const char *suffix,
 
 
 

-/* Register the global TLS callback fucntion.  */
+/* Register a non-standard global TLS callback function.  If no
+   verification is desired a callback needs to be registered which
+   always returns NULL.  */
 void
 http_register_tls_callback (gpg_error_t (*cb)(http_t, http_session_t, int))
 {
@@ -473,15 +477,24 @@ http_register_tls_callback (gpg_error_t (*cb)(http_t, http_session_t, int))
 
 /* Register a CA certificate for future use.  The certificate is
    expected to be in FNAME.  PEM format is assume if FNAME has a
-   suffix of ".pem" */
+   suffix of ".pem".  If FNAME is NULL the list of CA files is
+   removed.  */
 void
 http_register_tls_ca (const char *fname)
 {
   strlist_t sl;
 
-  sl = add_to_strlist (&tls_ca_certlist, fname);
-  if (*sl->d && !strcmp (sl->d + strlen (sl->d) - 4, ".pem"))
-    sl->flags = 1;
+  if (!fname)
+    {
+      free_strlist (tls_ca_certlist);
+      tls_ca_certlist = NULL;
+    }
+  else
+    {
+      sl = add_to_strlist (&tls_ca_certlist, fname);
+      if (*sl->d && !strcmp (sl->d + strlen (sl->d) - 4, ".pem"))
+        sl->flags = 1;
+    }
 }
 
 
@@ -614,7 +627,7 @@ http_open (http_t *r_hd, http_req_t reqtype, const char *url,
   hd->flags = flags;
   hd->session = session;
 
-  err = http_parse_uri (&hd->uri, url, 0);
+  err = parse_uri (&hd->uri, url, 0, !!(flags & HTTP_FLAG_FORCE_TLS));
   if (!err)
     err = send_request (hd, auth, proxy, srvtag, headers);
 
@@ -875,17 +888,29 @@ http_get_status_code (http_t hd)
   return hd?hd->status_code:0;
 }
 
+/* Return information pertaining to TLS.  If TLS is not in use for HD,
+   NULL is returned.  WHAT is used ask for specific information:
 
-

-/*
- * Parse an URI and put the result into the newly allocated RET_URI.
- * On success the caller must use release_parsed_uri() to releases the
- * resources.  If NO_SCHEME_CHECK is set, the function tries to parse
- * the URL in the same way it would do for an HTTP style URI.
+     (NULL) := Only check whether TLS is is use.  Returns an
+               unspecified string if TLS is in use.  That string may
+               even be the empty string.
  */
-gpg_error_t
-http_parse_uri (parsed_uri_t *ret_uri, const char *uri,
-                int no_scheme_check)
+const char *
+http_get_tls_info (http_t hd, const char *what)
+{
+  (void)what;
+
+  if (!hd)
+    return NULL;
+
+  return hd->uri->use_tls? "":NULL;
+}
+
+
+

+static gpg_error_t
+parse_uri (parsed_uri_t *ret_uri, const char *uri,
+           int no_scheme_check, int force_tls)
 {
   gpg_err_code_t ec;
 
@@ -893,7 +918,7 @@ http_parse_uri (parsed_uri_t *ret_uri, const char *uri,
   if (!*ret_uri)
     return gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
   strcpy ((*ret_uri)->buffer, uri);
-  ec = do_parse_uri (*ret_uri, 0, no_scheme_check);
+  ec = do_parse_uri (*ret_uri, 0, no_scheme_check, force_tls);
   if (ec)
     {
       xfree (*ret_uri);
@@ -902,6 +927,21 @@ http_parse_uri (parsed_uri_t *ret_uri, const char *uri,
   return gpg_err_make (default_errsource, ec);
 }
 
+
+/*
+ * Parse an URI and put the result into the newly allocated RET_URI.
+ * On success the caller must use release_parsed_uri() to releases the
+ * resources.  If NO_SCHEME_CHECK is set, the function tries to parse
+ * the URL in the same way it would do for an HTTP style URI.
+ */
+gpg_error_t
+http_parse_uri (parsed_uri_t *ret_uri, const char *uri,
+                int no_scheme_check)
+{
+  return parse_uri (ret_uri, uri, no_scheme_check, 0);
+}
+
+
 void
 http_release_parsed_uri (parsed_uri_t uri)
 {
@@ -920,7 +960,8 @@ http_release_parsed_uri (parsed_uri_t uri)
 
 
 static gpg_err_code_t
-do_parse_uri (parsed_uri_t uri, int only_local_part, int no_scheme_check)
+do_parse_uri (parsed_uri_t uri, int only_local_part,
+              int no_scheme_check, int force_tls)
 {
   uri_tuple_t *tail;
   char *p, *p2, *p3, *pp;
@@ -951,18 +992,20 @@ do_parse_uri (parsed_uri_t uri, int only_local_part, int no_scheme_check)
       for (pp=p; *pp; pp++)
        *pp = tolower (*(unsigned char*)pp);
       uri->scheme = p;
-      if (!strcmp (uri->scheme, "http"))
+      if (!strcmp (uri->scheme, "http") && !force_tls)
         {
           uri->port = 80;
           uri->is_http = 1;
         }
-      else if (!strcmp (uri->scheme, "hkp"))
+      else if (!strcmp (uri->scheme, "hkp") && !force_tls)
         {
           uri->port = 11371;
           uri->is_http = 1;
         }
 #ifdef HTTP_USE_GNUTLS
-      else if (!strcmp (uri->scheme, "https") || !strcmp (uri->scheme,"hkps"))
+      else if (!strcmp (uri->scheme, "https") || !strcmp (uri->scheme,"hkps")
+               || (force_tls && (!strcmp (uri->scheme, "http")
+                                 || !strcmp (uri->scheme,"hkp"))))
         {
           uri->port = 443;
           uri->is_http = 1;
@@ -1329,7 +1372,8 @@ send_request (http_t hd, const char *auth,
       if (proxy)
 	http_proxy = proxy;
 
-      err = http_parse_uri (&uri, http_proxy, 0);
+      err = parse_uri (&uri, http_proxy, 0,
+                       !!(hd->flags & HTTP_FLAG_FORCE_TLS));
       if (err)
 	{
 	  log_error ("invalid HTTP proxy (%s): %s\n",
@@ -1412,17 +1456,17 @@ send_request (http_t hd, const char *auth,
           return gpg_err_make (default_errsource, GPG_ERR_NETWORK);
         }
 
+      hd->session->verify.done = 0;
       if (tls_callback)
+        err = tls_callback (hd, hd->session, 0);
+      else
+        err = http_verify_server_credentials (hd->session);
+      if (err)
         {
-          hd->session->verify.done = 0;
-          err = tls_callback (hd, hd->session, 0);
-          if (err)
-            {
-              log_info ("TLS connection authentication failed: %s\n",
-                        gpg_strerror (err));
-              xfree (proxy_authstr);
-              return err;
-            }
+          log_info ("TLS connection authentication failed: %s\n",
+                    gpg_strerror (err));
+          xfree (proxy_authstr);
+          return err;
         }
     }
 #endif /*HTTP_USE_GNUTLS*/
diff --git a/common/http.h b/common/http.h
index e38fadc..fa73b6e 100644
--- a/common/http.h
+++ b/common/http.h
@@ -77,6 +77,7 @@ enum
     HTTP_FLAG_TRY_PROXY = 1,     /* Try to use a proxy.  */
     HTTP_FLAG_SHUTDOWN = 2,      /* Close sending end after the request.  */
     HTTP_FLAG_LOG_RESP = 8,      /* Log the server respone.  */
+    HTTP_FLAG_FORCE_TLS = 16,    /* Force the use opf TLS.  */
     HTTP_FLAG_IGNORE_CL = 32,    /* Ignore content-length.  */
     HTTP_FLAG_IGNORE_IPv4 = 64,  /* Do not use IPv4.  */
     HTTP_FLAG_IGNORE_IPv6 = 128  /* Do not use IPv6.  */
@@ -133,6 +134,7 @@ gpg_error_t http_open_document (http_t *r_hd,
 estream_t http_get_read_ptr (http_t hd);
 estream_t http_get_write_ptr (http_t hd);
 unsigned int http_get_status_code (http_t hd);
+const char *http_get_tls_info (http_t hd, const char *what);
 const char *http_get_header (http_t hd, const char *name);
 const char **http_get_header_names (http_t hd);
 gpg_error_t http_verify_server_credentials (http_session_t sess);
diff --git a/common/t-http.c b/common/t-http.c
index f515287..0191e85 100644
--- a/common/t-http.c
+++ b/common/t-http.c
@@ -46,7 +46,11 @@
 # include <gnutls/gnutls.h>  /* For init, logging, and deinit.  */
 #endif /*HTTP_USE_GNUTLS*/
 
+#define PGM "t-http"
 
+static int verbose;
+static int debug;
+static int no_verify;
 
 /* static void */
 /* read_dh_params (const char *fname) */
@@ -98,7 +102,7 @@ verify_callback (http_t hd, http_session_t session, int reserved)
 {
   (void)hd;
   (void)reserved;
-  return http_verify_server_credentials (session);
+  return no_verify? 0 : http_verify_server_credentials (session);
 }
 
 
@@ -131,23 +135,92 @@ prepend_srcdir (const char *fname)
 int
 main (int argc, char **argv)
 {
+  int last_argc = -1;
   gpg_error_t err;
   int rc;
   parsed_uri_t uri;
   uri_tuple_t r;
   http_t hd;
   int c;
+  unsigned int my_http_flags = 0;
+  int no_out = 0;
+  const char *cafile = NULL;
   http_session_t session = NULL;
 
   es_init ();
-  log_set_prefix ("t-http", 1 | 4);
-  if (argc != 2)
+  log_set_prefix (PGM, 1 | 4);
+  if (argc)
+    { argc--; argv++; }
+  while (argc && last_argc != argc )
     {
-      fprintf (stderr, "usage: t-http uri\n");
-      return 1;
+      last_argc = argc;
+      if (!strcmp (*argv, "--"))
+        {
+          argc--; argv++;
+          break;
+        }
+      else if (!strcmp (*argv, "--help"))
+        {
+          fputs ("usage: " PGM " URL\n"
+                 "Options:\n"
+                 "  --verbose       print timings etc.\n"
+                 "  --debug         flyswatter\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"
+                 "  --no-out        do not print the content\n",
+                 stdout);
+          exit (0);
+        }
+      else if (!strcmp (*argv, "--verbose"))
+        {
+          verbose++;
+          argc--; argv++;
+        }
+      else if (!strcmp (*argv, "--debug"))
+        {
+          verbose += 2;
+          debug++;
+          argc--; argv++;
+        }
+      else if (!strcmp (*argv, "--cacert"))
+        {
+          argc--; argv++;
+          if (argc)
+            {
+              cafile = *argv;
+              argc--; argv++;
+            }
+        }
+      else if (!strcmp (*argv, "--no-verify"))
+        {
+          no_verify = 1;
+          argc--; argv++;
+        }
+      else if (!strcmp (*argv, "--force-tls"))
+        {
+          my_http_flags |= HTTP_FLAG_FORCE_TLS;
+          argc--; argv++;
+        }
+      else if (!strcmp (*argv, "--no-out"))
+        {
+          no_out = 1;
+          argc--; argv++;
+        }
+      else if (!strncmp (*argv, "--", 2))
+        {
+          fprintf (stderr, PGM ": unknown option '%s'\n", *argv);
+          exit (1);
+        }
+    }
+  if (argc != 1)
+    {
+      fprintf (stderr, PGM ": no or roo many URLS given\n");
+      exit (1);
     }
-  argc--;
-  argv++;
+
+  if (!cafile)
+    cafile = prepend_srcdir ("tls-ca.pem");
 
 #ifdef HTTP_USE_GNUTLS
   rc = gnutls_global_init ();
@@ -155,7 +228,7 @@ main (int argc, char **argv)
     log_error ("gnutls_global_init failed: %s\n", gnutls_strerror (rc));
 
   http_register_tls_callback (verify_callback);
-  http_register_tls_ca (prepend_srcdir ("tls-ca.pem"));
+  http_register_tls_ca (cafile);
 
   err = http_session_new (&session, NULL);
   if (err)
@@ -217,11 +290,17 @@ main (int argc, char **argv)
             }
           putchar ('\n');
         }
+      printf ("TLS   : %s\n",
+              uri->use_tls? "yes":
+              (my_http_flags&HTTP_FLAG_FORCE_TLS)? "forced" : "no");
+
     }
+  fflush (stdout);
   http_release_parsed_uri (uri);
   uri = NULL;
 
-  rc = http_open_document (&hd, *argv, NULL, 0, NULL, session, NULL, NULL);
+  rc = http_open_document (&hd, *argv, NULL, my_http_flags,
+                           NULL, session, NULL, NULL);
   if (rc)
     {
       log_error ("can't get '%s': %s\n", *argv, gpg_strerror (rc));
@@ -242,6 +321,7 @@ main (int argc, char **argv)
       printf ("HDR: %s: %s\n", names[i], http_get_header (hd, names[i]));
     xfree (names);
   }
+  fflush (stdout);
 
   switch (http_get_status_code (hd))
     {
@@ -250,12 +330,21 @@ main (int argc, char **argv)
     case 401:
     case 403:
     case 404:
-      while ((c = es_getc (http_get_read_ptr (hd))) != EOF)
-        putchar (c);
+      {
+        unsigned long count = 0;
+        while ((c = es_getc (http_get_read_ptr (hd))) != EOF)
+          {
+            count++;
+            if (!no_out)
+              putchar (c);
+          }
+        log_info ("Received bytes: %lu\n", count);
+      }
       break;
     case 301:
     case 302:
-      printf ("Redirected to '%s'\n", http_get_header (hd, "Location"));
+    case 307:
+      log_info ("Redirected to: %s\n", http_get_header (hd, "Location"));
       break;
     }
   http_close (hd, 0);

-----------------------------------------------------------------------

Summary of changes:
 common/http.c                    |  226 ++++++++++++++++++++++++++------------
 common/http.h                    |    3 +
 common/t-http.c                  |  127 ++++++++++++++++++---
 dirmngr/dirmngr.c                |   47 ++++++++
 dirmngr/ks-engine-hkp.c          |   27 ++++-
 dirmngr/sks-keyservers.netCA.pem |   32 ++++++
 doc/dirmngr.texi                 |  145 +++++++++++++-----------
 doc/gpg.texi                     |   13 +++
 8 files changed, 466 insertions(+), 154 deletions(-)
 create mode 100644 dirmngr/sks-keyservers.netCA.pem


hooks/post-receive
-- 
The GNU Privacy Guard
http://git.gnupg.org




More information about the Gnupg-commits mailing list