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.
This commit is contained in:
Werner Koch 2014-05-05 16:09:45 +02:00
parent ea0f5481f0
commit 60e2fc7d38
5 changed files with 194 additions and 70 deletions

View File

@ -40,6 +40,9 @@
# include <signal.h> # include <signal.h>
#endif #endif
#include <npth.h> #include <npth.h>
#ifdef HTTP_USE_GNUTLS
# include <gnutls/gnutls.h>
#endif /*HTTP_USE_GNUTLS*/
#define JNLIB_NEED_LOG_LOGV #define JNLIB_NEED_LOG_LOGV
@ -92,6 +95,7 @@ enum cmd_and_opt_values {
oDebugAll, oDebugAll,
oDebugWait, oDebugWait,
oDebugLevel, oDebugLevel,
oGnutlsDebug,
oNoGreeting, oNoGreeting,
oNoOptions, oNoOptions,
oHomedir, oHomedir,
@ -116,6 +120,7 @@ enum cmd_and_opt_values {
oOCSPMaxPeriod, oOCSPMaxPeriod,
oOCSPCurrentPeriod, oOCSPCurrentPeriod,
oMaxReplies, oMaxReplies,
oHkpCaCert,
oFakedSystemTime, oFakedSystemTime,
oForce, oForce,
oAllowOCSP, oAllowOCSP,
@ -195,11 +200,16 @@ static ARGPARSE_OPTS opts[] = {
ARGPARSE_s_i (oMaxReplies, "max-replies", ARGPARSE_s_i (oMaxReplies, "max-replies",
N_("|N|do not return more than N items in one query")), 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_s (oSocketName, "socket-name", "@"), /* Only for debugging. */
ARGPARSE_s_u (oFakedSystemTime, "faked-system-time", "@"), /*(epoch time)*/ ARGPARSE_s_u (oFakedSystemTime, "faked-system-time", "@"), /*(epoch time)*/
ARGPARSE_p_u (oDebug, "debug", "@"), ARGPARSE_p_u (oDebug, "debug", "@"),
ARGPARSE_s_n (oDebugAll, "debug-all", "@"), ARGPARSE_s_n (oDebugAll, "debug-all", "@"),
ARGPARSE_s_i (oGnutlsDebug, "gnutls-debug", "@"),
ARGPARSE_s_i (oDebugWait, "debug-wait", "@"), ARGPARSE_s_i (oDebugWait, "debug-wait", "@"),
ARGPARSE_s_n (oNoGreeting, "no-greeting", "@"), ARGPARSE_s_n (oNoGreeting, "no-greeting", "@"),
ARGPARSE_s_s (oHomedir, "homedir", "@"), ARGPARSE_s_s (oHomedir, "homedir", "@"),
@ -234,6 +244,9 @@ static char *current_logfile;
/* Helper to implement --debug-level. */ /* Helper to implement --debug-level. */
static const char *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. */ /* Flag indicating that a shutdown has been requested. */
static volatile int shutdown_pending; 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 /* Setup the debugging. With a LEVEL of NULL only the active debug
flags are propagated to the subsystems. With LEVEL set, a specific flags are propagated to the subsystems. With LEVEL set, a specific
set of debug flags is set; thus overriding all flags already set of debug flags is set; thus overriding all flags already
@ -382,6 +409,14 @@ set_debug (void)
if (opt.debug & DBG_CRYPTO_VALUE ) if (opt.debug & DBG_CRYPTO_VALUE )
gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1); 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; opt.ocsp_signer = tmp;
} }
FREE_STRLIST (opt.ignored_cert_extensions); FREE_STRLIST (opt.ignored_cert_extensions);
http_register_tls_ca (NULL);
return 1; return 1;
} }
@ -449,6 +485,7 @@ parse_rereadable_options (ARGPARSE_ARGS *pargs, int reread)
case oDebug: opt.debug |= pargs->r.ret_ulong; break; case oDebug: opt.debug |= pargs->r.ret_ulong; break;
case oDebugAll: opt.debug = ~0; break; case oDebugAll: opt.debug = ~0; break;
case oDebugLevel: debug_level = pargs->r.ret_str; break; case oDebugLevel: debug_level = pargs->r.ret_str; break;
case oGnutlsDebug: opt_gnutls_debug = pargs->r.ret_int; break;
case oLogFile: case oLogFile:
if (!reread) 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 oMaxReplies: opt.max_replies = pargs->r.ret_int; break;
case oHkpCaCert:
http_register_tls_ca (pargs->r.ret_str);
break;
case oIgnoreCertExtension: case oIgnoreCertExtension:
add_to_strlist (&opt.ignored_cert_extensions, pargs->r.ret_str); add_to_strlist (&opt.ignored_cert_extensions, pargs->r.ret_str);
break; break;
@ -628,6 +669,12 @@ main (int argc, char **argv)
ksba_set_malloc_hooks (gcry_malloc, gcry_realloc, gcry_free ); ksba_set_malloc_hooks (gcry_malloc, gcry_realloc, gcry_free );
ksba_set_hash_buffer_function (my_ksba_hash_buffer, NULL); 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. */ /* Init Assuan. */
malloc_hooks.malloc = gcry_malloc; malloc_hooks.malloc = gcry_malloc;

View File

@ -628,12 +628,14 @@ ks_hkp_help (ctrl_t ctrl, parsed_uri_t uri)
const char const data[] = const char const data[] =
"Handler for HKP URLs:\n" "Handler for HKP URLs:\n"
" hkp://\n" " hkp://\n"
" hkps://\n"
"Supported methods: search, get, put\n"; "Supported methods: search, get, put\n";
gpg_error_t err; gpg_error_t err;
if (!uri) if (!uri)
err = ks_print_help (ctrl, " hkp"); err = ks_print_help (ctrl, " hkp\n hkps");
else if (uri->is_http && !strcmp (uri->scheme, "hkp")) else if (uri->is_http && (!strcmp (uri->scheme, "hkp")
|| !strcmp (uri->scheme, "hkps")))
err = ks_print_help (ctrl, data); err = ks_print_help (ctrl, data);
else else
err = 0; err = 0;
@ -747,6 +749,7 @@ send_request (ctrl_t ctrl, const char *request, const char *hostportstr,
estream_t *r_fp) estream_t *r_fp)
{ {
gpg_error_t err; gpg_error_t err;
http_session_t session = NULL;
http_t http = NULL; http_t http = NULL;
int redirects_left = MAX_REDIRECTS; int redirects_left = MAX_REDIRECTS;
estream_t fp = NULL; estream_t fp = NULL;
@ -754,6 +757,10 @@ send_request (ctrl_t ctrl, const char *request, const char *hostportstr,
*r_fp = NULL; *r_fp = NULL;
err = http_session_new (&session, NULL);
if (err)
goto leave;
once_more: once_more:
err = http_open (&http, err = http_open (&http,
post_cb? HTTP_REQ_POST : HTTP_REQ_GET, 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, /* fixme: AUTH */ NULL,
httpflags, httpflags,
/* fixme: proxy*/ NULL, /* fixme: proxy*/ NULL,
NULL, NULL, session,
NULL,
/*FIXME curl->srvtag*/NULL); /*FIXME curl->srvtag*/NULL);
if (!err) if (!err)
{ {
@ -798,6 +806,13 @@ send_request (ctrl_t ctrl, const char *request, const char *hostportstr,
goto leave; 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)) switch (http_get_status_code (http))
{ {
case 200: case 200:
@ -806,6 +821,7 @@ send_request (ctrl_t ctrl, const char *request, const char *hostportstr,
case 301: case 301:
case 302: case 302:
case 307:
{ {
const char *s = http_get_header (http, "Location"); 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; 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); fp = http_get_read_ptr (http);
if (!fp) if (!fp)
{ {
@ -851,6 +871,7 @@ send_request (ctrl_t ctrl, const char *request, const char *hostportstr,
leave: leave:
http_close (http, 0); http_close (http, 0);
http_session_release (session);
xfree (request_buffer); xfree (request_buffer);
return err; return err;
} }

View File

@ -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-----

View File

@ -204,6 +204,10 @@ usual C-Syntax.
@opindex debug-all @opindex debug-all
Same as @code{--debug=0xffffffff} Same as @code{--debug=0xffffffff}
@item --gnutls-debug @var{level}
@opindex gnutls-debug
Enable debugging of GNUTLS at @var{level}.
@item --debug-wait @var{n} @item --debug-wait @var{n}
@opindex debug-wait @opindex debug-wait
When running in server mode, wait @var{n} seconds before entering the When running in server mode, wait @var{n} seconds before entering the
@ -395,6 +399,13 @@ won't be rejected due to an unknown critical extension. Use this
option with care because extensions are usually flagged as critical option with care because extensions are usually flagged as critical
for a reason. for a reason.
@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
@var{file}. This option may be given multiple times to add more
root certificates.
@end table @end table

View File

@ -1630,16 +1630,29 @@ are available for all keyserver types, some common options are:
program uses internally (libcurl, openldap, etc). program uses internally (libcurl, openldap, etc).
@item check-cert @item check-cert
@ifset gpgtwoone
This option has no more function since GnuPG 2.1. Use the
@code{dirmngr} configuration options instead.
@end ifset
@ifclear gpgtwoone
Enable certificate checking if the keyserver presents one (for hkps or Enable certificate checking if the keyserver presents one (for hkps or
ldaps). Defaults to on. ldaps). Defaults to on.
@end ifclear
@item ca-cert-file @item ca-cert-file
@ifset gpgtwoone
This option has no more function since GnuPG 2.1. Use the
@code{dirmngr} configuration options instead.
@end ifset
@ifclear gpgtwoone
Provide a certificate store to override the system default. Only Provide a certificate store to override the system default. Only
necessary if check-cert is enabled, and the keyserver is using a necessary if check-cert is enabled, and the keyserver is using a
certificate that is not present in a system default certificate list. certificate that is not present in a system default certificate list.
Note that depending on the SSL library that the keyserver helper is Note that depending on the SSL library that the keyserver helper is
built with, this may actually be a directory or a file. built with, this may actually be a directory or a file.
@end ifclear
@end table @end table
@item --completes-needed @code{n} @item --completes-needed @code{n}