mirror of
git://git.gnupg.org/gnupg.git
synced 2025-01-03 12:11:33 +01:00
http: Revamp TLS API.
* configure.ac (NEED_GNUTLS_VERSION): New. (HTTP_USE_GNUTLS, LIBGNUTLS_CFLAGS, LIBGNUTLS_LIBS): New ac_subst. * common/http.h (http_session_t): New. * common/http.c: Remove compatibility for gnutls < 3.0. (http_session_s): New. (cookie_s): Replace gnutls_session_t by http_session_t. (tls_callback, tls_ca_certlist): New variables. (my_socket_unref): Add preclose args. (my_npth_read, my_npth_write): New. (make_header_line): Fix bug using int* instead of char*. (http_register_tls_callback): New. (http_register_tls_ca): New. (http_session_new): New. (http_session_release): New. (http_get_header_names): New. (escape_data): Add hack to escape in forms mode. (send_request) [HTTP_USE_GNUTLS]: Support SNI. (send_request) [HTTP_USE_GNUTLS]: Fix use of make_header_line. (send_gnutls_bye): New. (cookie_close): Make use of preclose feature. (http_verify_server_credentials): New. (main) [TEST]: Remove test code. * common/t-http.c: New. * common/tls-ca.pem: New. * common/Makefile.am (tls_sources): New. Move http code to here. (libcommontls_a_SOURCES): New. (libcommontlsnpth_a_SOURCES): New. (EXTRA_DIST): Add tls-ca.pem (module_maint_tests): Add t-http. (t_http_SOURCES, t_http_CFLAGS, t_http_LDADD): New. * dirmngr/Makefile.am (dirmngr_LDADD): Add libcommontlsnpth. -- This new TLS API for http.c is much more flexible than the crude old hack.
This commit is contained in:
parent
84289e85c7
commit
8412a5825c
@ -75,3 +75,5 @@ resource_objs =
|
|||||||
# Convenience macros
|
# Convenience macros
|
||||||
libcommon = ../common/libcommon.a
|
libcommon = ../common/libcommon.a
|
||||||
libcommonpth = ../common/libcommonpth.a
|
libcommonpth = ../common/libcommonpth.a
|
||||||
|
libcommontls = ../common/libcommontls.a
|
||||||
|
libcommontlsnpth = ../common/libcommontlsnpth.a
|
||||||
|
@ -20,9 +20,10 @@
|
|||||||
|
|
||||||
EXTRA_DIST = mkstrtable.awk exaudit.awk exstatus.awk ChangeLog-2011 \
|
EXTRA_DIST = mkstrtable.awk exaudit.awk exstatus.awk ChangeLog-2011 \
|
||||||
audit-events.h status-codes.h README.jnlib ChangeLog.jnlib \
|
audit-events.h status-codes.h README.jnlib ChangeLog.jnlib \
|
||||||
ChangeLog-2011.include w32info-rc.h.in gnupg.ico
|
ChangeLog-2011.include w32info-rc.h.in gnupg.ico tls-ca.pem
|
||||||
|
|
||||||
noinst_LIBRARIES = libcommon.a libcommonpth.a libgpgrl.a
|
noinst_LIBRARIES = libcommon.a libcommonpth.a libgpgrl.a \
|
||||||
|
libcommontls.a libcommontlsnpth.a
|
||||||
if !HAVE_W32CE_SYSTEM
|
if !HAVE_W32CE_SYSTEM
|
||||||
noinst_LIBRARIES += libsimple-pwquery.a
|
noinst_LIBRARIES += libsimple-pwquery.a
|
||||||
endif
|
endif
|
||||||
@ -88,7 +89,6 @@ common_sources = \
|
|||||||
srv.h \
|
srv.h \
|
||||||
dns-cert.c dns-cert.h \
|
dns-cert.c dns-cert.h \
|
||||||
pka.c pka.h \
|
pka.c pka.h \
|
||||||
http.c http.h \
|
|
||||||
localename.c \
|
localename.c \
|
||||||
session-env.c session-env.h \
|
session-env.c session-env.h \
|
||||||
userids.c userids.h \
|
userids.c userids.h \
|
||||||
@ -97,6 +97,12 @@ common_sources = \
|
|||||||
agent-opt.c \
|
agent-opt.c \
|
||||||
helpfile.c
|
helpfile.c
|
||||||
|
|
||||||
|
# Sources possible requiring a TLS library are put into a separate
|
||||||
|
# conveince library.
|
||||||
|
tls_sources = \
|
||||||
|
http.c http.h
|
||||||
|
|
||||||
|
|
||||||
# To make the code easier to read we have split home some code into
|
# To make the code easier to read we have split home some code into
|
||||||
# separate source files.
|
# separate source files.
|
||||||
if HAVE_W32_SYSTEM
|
if HAVE_W32_SYSTEM
|
||||||
@ -126,6 +132,12 @@ libcommonpth_a_SOURCES += srv.c
|
|||||||
endif
|
endif
|
||||||
libcommonpth_a_CFLAGS = $(AM_CFLAGS) $(LIBASSUAN_CFLAGS) $(NPTH_CFLAGS)
|
libcommonpth_a_CFLAGS = $(AM_CFLAGS) $(LIBASSUAN_CFLAGS) $(NPTH_CFLAGS)
|
||||||
|
|
||||||
|
libcommontls_a_SOURCES = $(tls_sources)
|
||||||
|
libcommontls_a_CFLAGS = $(AM_CFLAGS) $(LIBGNUTLS_CFLAGS) -DWITHOUT_NPTH=1
|
||||||
|
|
||||||
|
libcommontlsnpth_a_SOURCES = $(tls_sources)
|
||||||
|
libcommontlsnpth_a_CFLAGS = $(AM_CFLAGS) $(LIBGNUTLS_CFLAGS) $(NPTH_CFLAGS)
|
||||||
|
|
||||||
if !HAVE_W32CE_SYSTEM
|
if !HAVE_W32CE_SYSTEM
|
||||||
libsimple_pwquery_a_SOURCES = \
|
libsimple_pwquery_a_SOURCES = \
|
||||||
simple-pwquery.c simple-pwquery.h asshelp.c asshelp.h
|
simple-pwquery.c simple-pwquery.h asshelp.c asshelp.h
|
||||||
@ -170,11 +182,12 @@ module_tests = t-convert t-percent t-gettime t-sysutils t-sexputil \
|
|||||||
if !HAVE_W32CE_SYSTEM
|
if !HAVE_W32CE_SYSTEM
|
||||||
module_tests += t-exechelp
|
module_tests += t-exechelp
|
||||||
endif
|
endif
|
||||||
module_maint_tests = t-helpfile t-b64
|
module_maint_tests = t-helpfile t-b64 t-http
|
||||||
|
|
||||||
|
|
||||||
t_common_ldadd = libcommon.a ../gl/libgnu.a \
|
t_common_ldadd = libcommon.a ../gl/libgnu.a \
|
||||||
$(LIBGCRYPT_LIBS) $(LIBASSUAN_LIBS) $(GPG_ERROR_LIBS) $(LIBINTL) $(LIBICONV)
|
$(LIBGCRYPT_LIBS) $(LIBASSUAN_LIBS) $(GPG_ERROR_LIBS) \
|
||||||
|
$(LIBINTL) $(LIBICONV)
|
||||||
|
|
||||||
# jnlib tests
|
# jnlib tests
|
||||||
t_stringhelp_SOURCES = t-stringhelp.c $(t_jnlib_src)
|
t_stringhelp_SOURCES = t-stringhelp.c $(t_jnlib_src)
|
||||||
@ -203,3 +216,8 @@ t_ssh_utils_LDADD = $(t_common_ldadd)
|
|||||||
t_dns_cert_LDADD = $(t_common_ldadd) $(DNSLIBS)
|
t_dns_cert_LDADD = $(t_common_ldadd) $(DNSLIBS)
|
||||||
t_mapstrings_LDADD = $(t_common_ldadd)
|
t_mapstrings_LDADD = $(t_common_ldadd)
|
||||||
t_zb32_LDADD = $(t_common_ldadd)
|
t_zb32_LDADD = $(t_common_ldadd)
|
||||||
|
|
||||||
|
# http tests
|
||||||
|
t_http_SOURCES = t-http.c
|
||||||
|
t_http_CFLAGS = $(t_common_cflags) $(LIBGNUTLS_CFLAGS)
|
||||||
|
t_http_LDADD = $(libcommontls) $(t_common_ldadd) $(LIBGNUTLS_LIBS) $(DNSLIBS)
|
||||||
|
621
common/http.c
621
common/http.c
@ -39,8 +39,9 @@
|
|||||||
- fixme: list other requirements.
|
- fixme: list other requirements.
|
||||||
|
|
||||||
|
|
||||||
- With HTTP_USE_GNUTLS support for https is provided (this also
|
- With HTTP_USE_GNUTLS or HTTP_USE_POLARSSL support for https is
|
||||||
requires estream).
|
provided (this also requires estream).
|
||||||
|
|
||||||
- With HTTP_NO_WSASTARTUP the socket initialization is not done
|
- With HTTP_NO_WSASTARTUP the socket initialization is not done
|
||||||
under Windows. This is useful if the socket layer has already
|
under Windows. This is useful if the socket layer has already
|
||||||
been initialized elsewhere. This also avoids the installation of
|
been initialized elsewhere. This also avoids the installation of
|
||||||
@ -81,20 +82,19 @@
|
|||||||
# include <npth.h>
|
# include <npth.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined (HTTP_USE_GNUTLS) && defined (HTTP_USE_POLARSSL)
|
||||||
|
# error Both, HTTP_USE_GNUTLS and HTTP_USE_POLARSSL, are defined.
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef HTTP_USE_GNUTLS
|
#ifdef HTTP_USE_GNUTLS
|
||||||
# include <gnutls/gnutls.h>
|
# include <gnutls/gnutls.h>
|
||||||
/* For non-understandable reasons GNUTLS dropped the _t suffix from
|
# include <gnutls/x509.h>
|
||||||
all types. yes, ISO-C might be read as this but there are still
|
|
||||||
other name space conflicts and using _t is actually a Good
|
|
||||||
Thing. */
|
|
||||||
typedef gnutls_session gnutls_session_t;
|
|
||||||
typedef gnutls_transport_ptr gnutls_transport_ptr_t;
|
|
||||||
#endif /*HTTP_USE_GNUTLS*/
|
#endif /*HTTP_USE_GNUTLS*/
|
||||||
|
#ifdef HTTP_USE_POLARSSL
|
||||||
#ifdef TEST
|
# error Support for PolarSSL has not yet been added
|
||||||
# undef USE_DNS_SRV
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "i18n.h"
|
#include "i18n.h"
|
||||||
#include "http.h"
|
#include "http.h"
|
||||||
@ -204,22 +204,36 @@ struct cookie_s
|
|||||||
/* Socket object or NULL if already closed. */
|
/* Socket object or NULL if already closed. */
|
||||||
my_socket_t sock;
|
my_socket_t sock;
|
||||||
|
|
||||||
/* TLS session context or NULL if not used. */
|
/* The session object or NULL if not used. */
|
||||||
gnutls_session_t tls_session;
|
http_session_t session;
|
||||||
|
|
||||||
|
/* True if TLS is to be used. */
|
||||||
|
int use_tls;
|
||||||
|
|
||||||
/* The remaining content length and a flag telling whether to use
|
/* The remaining content length and a flag telling whether to use
|
||||||
the content length. */
|
the content length. */
|
||||||
longcounter_t content_length;
|
longcounter_t content_length;
|
||||||
unsigned int content_length_valid:1;
|
unsigned int content_length_valid:1;
|
||||||
|
|
||||||
/* Flag to communicate with the close handler. */
|
|
||||||
unsigned int keep_socket:1;
|
|
||||||
};
|
};
|
||||||
typedef struct cookie_s *cookie_t;
|
typedef struct cookie_s *cookie_t;
|
||||||
|
|
||||||
|
/* The session object. */
|
||||||
|
struct http_session_s
|
||||||
|
{
|
||||||
#ifdef HTTP_USE_GNUTLS
|
#ifdef HTTP_USE_GNUTLS
|
||||||
static gpg_error_t (*tls_callback) (http_t, gnutls_session_t, int);
|
gnutls_certificate_credentials_t certcred;
|
||||||
#endif /*HTTP_USE_GNUTLS*/
|
gnutls_session_t tls_session;
|
||||||
|
struct {
|
||||||
|
int done; /* Verifciation has been done. */
|
||||||
|
int rc; /* GnuTLS verification return code. */
|
||||||
|
unsigned int status; /* Verification status. */
|
||||||
|
} verify;
|
||||||
|
char *servername; /* Malloced server name. */
|
||||||
|
#else
|
||||||
|
int dummy;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* An object to save header lines. */
|
/* An object to save header lines. */
|
||||||
@ -243,7 +257,7 @@ struct http_context_s
|
|||||||
estream_t fp_write;
|
estream_t fp_write;
|
||||||
void *write_cookie;
|
void *write_cookie;
|
||||||
void *read_cookie;
|
void *read_cookie;
|
||||||
void *tls_context;
|
http_session_t session;
|
||||||
parsed_uri_t uri;
|
parsed_uri_t uri;
|
||||||
http_req_t req_type;
|
http_req_t req_type;
|
||||||
char *buffer; /* Line buffer. */
|
char *buffer; /* Line buffer. */
|
||||||
@ -253,6 +267,12 @@ struct http_context_s
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* The global callback for the verification fucntion. */
|
||||||
|
static gpg_error_t (*tls_callback) (http_t, http_session_t, int);
|
||||||
|
|
||||||
|
/* The list of files with trusted CA certificates. */
|
||||||
|
static strlist_t tls_ca_certlist;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#if defined(HAVE_W32_SYSTEM) && !defined(HTTP_NO_WSASTARTUP)
|
#if defined(HAVE_W32_SYSTEM) && !defined(HTTP_NO_WSASTARTUP)
|
||||||
@ -340,7 +360,7 @@ my_socket_ref (my_socket_t so)
|
|||||||
has no more references, close the socket and release the
|
has no more references, close the socket and release the
|
||||||
object. */
|
object. */
|
||||||
static void
|
static void
|
||||||
my_socket_unref (my_socket_t so)
|
my_socket_unref (my_socket_t so, void (*preclose)(void*), void *preclosearg)
|
||||||
{
|
{
|
||||||
if (so)
|
if (so)
|
||||||
{
|
{
|
||||||
@ -349,6 +369,8 @@ my_socket_unref (my_socket_t so)
|
|||||||
/* lnr, so, so->fd, so->refcount); */
|
/* lnr, so, so->fd, so->refcount); */
|
||||||
if (!so->refcount)
|
if (!so->refcount)
|
||||||
{
|
{
|
||||||
|
if (preclose)
|
||||||
|
preclose (preclosearg);
|
||||||
sock_close (so->fd);
|
sock_close (so->fd);
|
||||||
xfree (so);
|
xfree (so);
|
||||||
}
|
}
|
||||||
@ -357,6 +379,21 @@ my_socket_unref (my_socket_t so)
|
|||||||
/* #define my_socket_unref(a) _my_socket_unref ((a),__LINE__) */
|
/* #define my_socket_unref(a) _my_socket_unref ((a),__LINE__) */
|
||||||
|
|
||||||
|
|
||||||
|
#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);
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
#endif /*USE_NPTH && HTTP_USE_GNUTLS*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* This notification function is called by estream whenever stream is
|
/* This notification function is called by estream whenever stream is
|
||||||
closed. Its purpose is to mark the closing in the handle so
|
closed. Its purpose is to mark the closing in the handle so
|
||||||
@ -383,13 +420,13 @@ fp_onclose_notification (estream_t stream, void *opaque)
|
|||||||
*/
|
*/
|
||||||
static char *
|
static char *
|
||||||
make_header_line (const char *prefix, const char *suffix,
|
make_header_line (const char *prefix, const char *suffix,
|
||||||
const void *data, size_t len )
|
const void *data, size_t len )
|
||||||
{
|
{
|
||||||
static unsigned char bintoasc[] =
|
static unsigned char bintoasc[] =
|
||||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||||
"abcdefghijklmnopqrstuvwxyz"
|
"abcdefghijklmnopqrstuvwxyz"
|
||||||
"0123456789+/";
|
"0123456789+/";
|
||||||
const unsigned int *s = data;
|
const unsigned char *s = data;
|
||||||
char *buffer, *p;
|
char *buffer, *p;
|
||||||
|
|
||||||
buffer = xtrymalloc (strlen (prefix) + (len+2)/3*4 + strlen (suffix) + 1);
|
buffer = xtrymalloc (strlen (prefix) + (len+2)/3*4 + strlen (suffix) + 1);
|
||||||
@ -402,6 +439,7 @@ make_header_line (const char *prefix, const char *suffix,
|
|||||||
*p++ = bintoasc[(((s[0] <<4)&060)|((s[1] >> 4)&017))&077];
|
*p++ = bintoasc[(((s[0] <<4)&060)|((s[1] >> 4)&017))&077];
|
||||||
*p++ = bintoasc[(((s[1]<<2)&074)|((s[2]>>6)&03))&077];
|
*p++ = bintoasc[(((s[1]<<2)&074)|((s[2]>>6)&03))&077];
|
||||||
*p++ = bintoasc[s[2]&077];
|
*p++ = bintoasc[s[2]&077];
|
||||||
|
*p = 0;
|
||||||
}
|
}
|
||||||
if ( len == 2 )
|
if ( len == 2 )
|
||||||
{
|
{
|
||||||
@ -417,6 +455,7 @@ make_header_line (const char *prefix, const char *suffix,
|
|||||||
*p++ = '=';
|
*p++ = '=';
|
||||||
*p++ = '=';
|
*p++ = '=';
|
||||||
}
|
}
|
||||||
|
*p = 0;
|
||||||
strcpy (p, suffix);
|
strcpy (p, suffix);
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
@ -424,17 +463,132 @@ make_header_line (const char *prefix, const char *suffix,
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Register the global TLS callback fucntion. */
|
||||||
void
|
void
|
||||||
http_register_tls_callback ( gpg_error_t (*cb) (http_t, void *, int) )
|
http_register_tls_callback (gpg_error_t (*cb)(http_t, http_session_t, int))
|
||||||
{
|
{
|
||||||
#ifdef HTTP_USE_GNUTLS
|
tls_callback = cb;
|
||||||
tls_callback = (gpg_error_t (*) (http_t, gnutls_session_t, int))cb;
|
|
||||||
#else
|
|
||||||
(void)cb;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* 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" */
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Create a new session object which is currently used to enable TLS
|
||||||
|
support. It may eventually allow reusing existing connections. */
|
||||||
|
gpg_error_t
|
||||||
|
http_session_new (http_session_t *r_session, const char *tls_priority)
|
||||||
|
{
|
||||||
|
gpg_error_t err;
|
||||||
|
http_session_t sess;
|
||||||
|
|
||||||
|
*r_session = NULL;
|
||||||
|
|
||||||
|
sess = xtrycalloc (1, sizeof *sess);
|
||||||
|
if (!sess)
|
||||||
|
return gpg_error_from_syserror ();
|
||||||
|
|
||||||
|
#ifdef HTTP_USE_GNUTLS
|
||||||
|
{
|
||||||
|
const char *errpos;
|
||||||
|
int rc;
|
||||||
|
strlist_t sl;
|
||||||
|
|
||||||
|
rc = gnutls_certificate_allocate_credentials (&sess->certcred);
|
||||||
|
if (rc < 0)
|
||||||
|
{
|
||||||
|
log_error ("gnutls_certificate_allocate_credentials failed: %s\n",
|
||||||
|
gnutls_strerror (rc));
|
||||||
|
err = gpg_error (GPG_ERR_GENERAL);
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (sl = tls_ca_certlist; sl; sl = sl->next)
|
||||||
|
{
|
||||||
|
rc = gnutls_certificate_set_x509_trust_file
|
||||||
|
(sess->certcred, sl->d,
|
||||||
|
(sl->flags & 1)? GNUTLS_X509_FMT_PEM : GNUTLS_X509_FMT_DER);
|
||||||
|
if (rc < 0)
|
||||||
|
log_info ("setting CA from file '%s' failed: %s\n",
|
||||||
|
sl->d, gnutls_strerror (rc));
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = gnutls_init (&sess->tls_session, GNUTLS_CLIENT);
|
||||||
|
if (rc < 0)
|
||||||
|
{
|
||||||
|
log_error ("gnutls_init failed: %s\n", gnutls_strerror (rc));
|
||||||
|
err = gpg_error (GPG_ERR_GENERAL);
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
rc = gnutls_priority_set_direct (sess->tls_session,
|
||||||
|
tls_priority? tls_priority : "NORMAL",
|
||||||
|
&errpos);
|
||||||
|
if (rc < 0)
|
||||||
|
{
|
||||||
|
log_error ("gnutls_priority_set_direct failed at '%s': %s\n",
|
||||||
|
errpos, gnutls_strerror (rc));
|
||||||
|
err = gpg_error (GPG_ERR_GENERAL);
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = gnutls_credentials_set (sess->tls_session,
|
||||||
|
GNUTLS_CRD_CERTIFICATE, sess->certcred);
|
||||||
|
if (rc < 0)
|
||||||
|
{
|
||||||
|
log_error ("gnutls_credentials_set failed: %s\n", gnutls_strerror (rc));
|
||||||
|
err = gpg_error (GPG_ERR_GENERAL);
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#else /*!HTTP_USE_GNUTLS*/
|
||||||
|
(void)tls_priority;
|
||||||
|
#endif /*!HTTP_USE_GNUTLS*/
|
||||||
|
|
||||||
|
err = 0;
|
||||||
|
|
||||||
|
#ifdef HTTP_USE_GNUTLS
|
||||||
|
leave:
|
||||||
|
#endif /*HTTP_USE_GNUTLS*/
|
||||||
|
if (err)
|
||||||
|
http_session_release (sess);
|
||||||
|
else
|
||||||
|
*r_session = sess;
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* 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)
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Start a HTTP retrieval and return on success in R_HD a context
|
/* Start a HTTP retrieval and return on success in R_HD a context
|
||||||
pointer for completing the the request and to wait for the
|
pointer for completing the the request and to wait for the
|
||||||
@ -442,7 +596,7 @@ http_register_tls_callback ( gpg_error_t (*cb) (http_t, void *, int) )
|
|||||||
gpg_error_t
|
gpg_error_t
|
||||||
http_open (http_t *r_hd, http_req_t reqtype, const char *url,
|
http_open (http_t *r_hd, http_req_t reqtype, const char *url,
|
||||||
const char *auth, unsigned int flags, const char *proxy,
|
const char *auth, unsigned int flags, const char *proxy,
|
||||||
void *tls_context, const char *srvtag, strlist_t headers)
|
http_session_t session, const char *srvtag, strlist_t headers)
|
||||||
{
|
{
|
||||||
gpg_error_t err;
|
gpg_error_t err;
|
||||||
http_t hd;
|
http_t hd;
|
||||||
@ -458,7 +612,7 @@ http_open (http_t *r_hd, http_req_t reqtype, const char *url,
|
|||||||
return gpg_error_from_syserror ();
|
return gpg_error_from_syserror ();
|
||||||
hd->req_type = reqtype;
|
hd->req_type = reqtype;
|
||||||
hd->flags = flags;
|
hd->flags = flags;
|
||||||
hd->tls_context = tls_context;
|
hd->session = session;
|
||||||
|
|
||||||
err = http_parse_uri (&hd->uri, url, 0);
|
err = http_parse_uri (&hd->uri, url, 0);
|
||||||
if (!err)
|
if (!err)
|
||||||
@ -466,7 +620,7 @@ http_open (http_t *r_hd, http_req_t reqtype, const char *url,
|
|||||||
|
|
||||||
if (err)
|
if (err)
|
||||||
{
|
{
|
||||||
my_socket_unref (hd->sock);
|
my_socket_unref (hd->sock, NULL, NULL);
|
||||||
if (hd->fp_read)
|
if (hd->fp_read)
|
||||||
es_fclose (hd->fp_read);
|
es_fclose (hd->fp_read);
|
||||||
if (hd->fp_write)
|
if (hd->fp_write)
|
||||||
@ -531,7 +685,7 @@ http_raw_connect (http_t *r_hd, const char *server, unsigned short port,
|
|||||||
if (!hd->fp_write)
|
if (!hd->fp_write)
|
||||||
{
|
{
|
||||||
err = gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
|
err = gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
|
||||||
my_socket_unref (cookie->sock);
|
my_socket_unref (cookie->sock, NULL, NULL);
|
||||||
xfree (cookie);
|
xfree (cookie);
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
@ -548,7 +702,7 @@ http_raw_connect (http_t *r_hd, const char *server, unsigned short port,
|
|||||||
if (!hd->fp_read)
|
if (!hd->fp_read)
|
||||||
{
|
{
|
||||||
err = gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
|
err = gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
|
||||||
my_socket_unref (cookie->sock);
|
my_socket_unref (cookie->sock, NULL, NULL);
|
||||||
xfree (cookie);
|
xfree (cookie);
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
@ -567,7 +721,7 @@ http_raw_connect (http_t *r_hd, const char *server, unsigned short port,
|
|||||||
es_fclose (hd->fp_read);
|
es_fclose (hd->fp_read);
|
||||||
if (hd->fp_write)
|
if (hd->fp_write)
|
||||||
es_fclose (hd->fp_write);
|
es_fclose (hd->fp_write);
|
||||||
my_socket_unref (hd->sock);
|
my_socket_unref (hd->sock, NULL, NULL);
|
||||||
xfree (hd);
|
xfree (hd);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -624,15 +778,15 @@ http_wait_response (http_t hd)
|
|||||||
if (!cookie)
|
if (!cookie)
|
||||||
return gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
|
return gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
|
||||||
cookie->sock = my_socket_ref (hd->sock);
|
cookie->sock = my_socket_ref (hd->sock);
|
||||||
if (hd->uri->use_tls)
|
cookie->session = hd->session;
|
||||||
cookie->tls_session = hd->tls_context;
|
cookie->use_tls = hd->uri->use_tls;
|
||||||
|
|
||||||
hd->read_cookie = cookie;
|
hd->read_cookie = cookie;
|
||||||
hd->fp_read = es_fopencookie (cookie, "r", cookie_functions);
|
hd->fp_read = es_fopencookie (cookie, "r", cookie_functions);
|
||||||
if (!hd->fp_read)
|
if (!hd->fp_read)
|
||||||
{
|
{
|
||||||
err = gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
|
err = gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
|
||||||
my_socket_unref (cookie->sock);
|
my_socket_unref (cookie->sock, NULL, NULL);
|
||||||
xfree (cookie);
|
xfree (cookie);
|
||||||
hd->read_cookie = NULL;
|
hd->read_cookie = NULL;
|
||||||
return err;
|
return err;
|
||||||
@ -654,12 +808,13 @@ http_wait_response (http_t hd)
|
|||||||
gpg_error_t
|
gpg_error_t
|
||||||
http_open_document (http_t *r_hd, const char *document,
|
http_open_document (http_t *r_hd, const char *document,
|
||||||
const char *auth, unsigned int flags, const char *proxy,
|
const char *auth, unsigned int flags, const char *proxy,
|
||||||
void *tls_context, const char *srvtag, strlist_t headers)
|
http_session_t session,
|
||||||
|
const char *srvtag, strlist_t headers)
|
||||||
{
|
{
|
||||||
gpg_error_t err;
|
gpg_error_t err;
|
||||||
|
|
||||||
err = http_open (r_hd, HTTP_REQ_GET, document, auth, flags,
|
err = http_open (r_hd, HTTP_REQ_GET, document, auth, flags,
|
||||||
proxy, tls_context, srvtag, headers);
|
proxy, session, srvtag, headers);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
@ -684,7 +839,7 @@ http_close (http_t hd, int keep_read_stream)
|
|||||||
es_onclose (hd->fp_write, 0, fp_onclose_notification, hd);
|
es_onclose (hd->fp_write, 0, fp_onclose_notification, hd);
|
||||||
|
|
||||||
/* Now we can close the streams. */
|
/* Now we can close the streams. */
|
||||||
my_socket_unref (hd->sock);
|
my_socket_unref (hd->sock, NULL, NULL);
|
||||||
if (hd->fp_read && !keep_read_stream)
|
if (hd->fp_read && !keep_read_stream)
|
||||||
es_fclose (hd->fp_read);
|
es_fclose (hd->fp_read);
|
||||||
if (hd->fp_write)
|
if (hd->fp_write)
|
||||||
@ -962,16 +1117,41 @@ remove_escapes (char *string)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* If SPECIAL is NULL this function escapes in forms mode. */
|
||||||
static size_t
|
static size_t
|
||||||
escape_data (char *buffer, const void *data, size_t datalen,
|
escape_data (char *buffer, const void *data, size_t datalen,
|
||||||
const char *special)
|
const char *special)
|
||||||
{
|
{
|
||||||
|
int forms = !special;
|
||||||
const unsigned char *s;
|
const unsigned char *s;
|
||||||
size_t n = 0;
|
size_t n = 0;
|
||||||
|
|
||||||
|
if (forms)
|
||||||
|
special = "%;?&=";
|
||||||
|
|
||||||
for (s = data; datalen; s++, datalen--)
|
for (s = data; datalen; s++, datalen--)
|
||||||
{
|
{
|
||||||
if (strchr (VALID_URI_CHARS, *s) && !strchr (special, *s))
|
if (forms && *s == ' ')
|
||||||
|
{
|
||||||
|
if (buffer)
|
||||||
|
*buffer++ = '+';
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
else if (forms && *s == '\n')
|
||||||
|
{
|
||||||
|
if (buffer)
|
||||||
|
memcpy (buffer, "%0D%0A", 6);
|
||||||
|
n += 6;
|
||||||
|
}
|
||||||
|
else if (forms && *s == '\r' && datalen > 1 && s[1] == '\n')
|
||||||
|
{
|
||||||
|
if (buffer)
|
||||||
|
memcpy (buffer, "%0D%0A", 6);
|
||||||
|
n += 6;
|
||||||
|
s++;
|
||||||
|
datalen--;
|
||||||
|
}
|
||||||
|
else if (strchr (VALID_URI_CHARS, *s) && !strchr (special, *s))
|
||||||
{
|
{
|
||||||
if (buffer)
|
if (buffer)
|
||||||
*(unsigned char*)buffer++ = *s;
|
*(unsigned char*)buffer++ = *s;
|
||||||
@ -1003,7 +1183,8 @@ insert_escapes (char *buffer, const char *string,
|
|||||||
well as escaping of characters given in SPECIALS. A common pattern
|
well as escaping of characters given in SPECIALS. A common pattern
|
||||||
for SPECIALS is "%;?&=". However it depends on the needs, for
|
for SPECIALS is "%;?&=". However it depends on the needs, for
|
||||||
example "+" and "/: often needs to be escaped too. Returns NULL on
|
example "+" and "/: often needs to be escaped too. Returns NULL on
|
||||||
failure and sets ERRNO. */
|
failure and sets ERRNO. If SPECIAL is NULL a dedicated forms
|
||||||
|
encoding mode is used. */
|
||||||
char *
|
char *
|
||||||
http_escape_string (const char *string, const char *specials)
|
http_escape_string (const char *string, const char *specials)
|
||||||
{
|
{
|
||||||
@ -1024,7 +1205,8 @@ http_escape_string (const char *string, const char *specials)
|
|||||||
escaping as well as escaping of characters given in SPECIALS. A
|
escaping as well as escaping of characters given in SPECIALS. A
|
||||||
common pattern for SPECIALS is "%;?&=". However it depends on the
|
common pattern for SPECIALS is "%;?&=". However it depends on the
|
||||||
needs, for example "+" and "/: often needs to be escaped too.
|
needs, for example "+" and "/: often needs to be escaped too.
|
||||||
Returns NULL on failure and sets ERRNO. */
|
Returns NULL on failure and sets ERRNO. If SPECIAL is NULL a
|
||||||
|
dedicated forms encoding mode is used. */
|
||||||
char *
|
char *
|
||||||
http_escape_data (const void *data, size_t datalen, const char *specials)
|
http_escape_data (const void *data, size_t datalen, const char *specials)
|
||||||
{
|
{
|
||||||
@ -1042,7 +1224,6 @@ http_escape_data (const void *data, size_t datalen, const char *specials)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static uri_tuple_t
|
static uri_tuple_t
|
||||||
parse_tuple (char *string)
|
parse_tuple (char *string)
|
||||||
{
|
{
|
||||||
@ -1089,7 +1270,6 @@ static gpg_error_t
|
|||||||
send_request (http_t hd, const char *auth,
|
send_request (http_t hd, const char *auth,
|
||||||
const char *proxy, const char *srvtag, strlist_t headers)
|
const char *proxy, const char *srvtag, strlist_t headers)
|
||||||
{
|
{
|
||||||
gnutls_session_t tls_session;
|
|
||||||
gpg_error_t err;
|
gpg_error_t err;
|
||||||
const char *server;
|
const char *server;
|
||||||
char *request, *p;
|
char *request, *p;
|
||||||
@ -1100,16 +1280,44 @@ send_request (http_t hd, const char *auth,
|
|||||||
int sock;
|
int sock;
|
||||||
int hnf;
|
int hnf;
|
||||||
|
|
||||||
tls_session = hd->tls_context;
|
if (hd->uri->use_tls && !hd->session)
|
||||||
if (hd->uri->use_tls && !tls_session)
|
|
||||||
{
|
{
|
||||||
log_error ("TLS requested but no GNUTLS context provided\n");
|
log_error ("TLS requested but no session object provided\n");
|
||||||
return gpg_err_make (default_errsource, GPG_ERR_INTERNAL);
|
return gpg_err_make (default_errsource, GPG_ERR_INTERNAL);
|
||||||
}
|
}
|
||||||
|
#ifdef HTTP_USE_GNUTLS
|
||||||
|
if (hd->uri->use_tls && !hd->session->tls_session)
|
||||||
|
{
|
||||||
|
log_error ("TLS requested but no GNUTLS context available\n");
|
||||||
|
return gpg_err_make (default_errsource, GPG_ERR_INTERNAL);
|
||||||
|
}
|
||||||
|
#endif /*HTTP_USE_GNUTLS*/
|
||||||
|
|
||||||
server = *hd->uri->host ? hd->uri->host : "localhost";
|
server = *hd->uri->host ? hd->uri->host : "localhost";
|
||||||
port = hd->uri->port ? hd->uri->port : 80;
|
port = hd->uri->port ? hd->uri->port : 80;
|
||||||
|
|
||||||
|
/* Try to use SNI. */
|
||||||
|
#ifdef HTTP_USE_GNUTLS
|
||||||
|
if (hd->uri->use_tls)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
xfree (hd->session->servername);
|
||||||
|
hd->session->servername = xtrystrdup (server);
|
||||||
|
if (!hd->session->servername)
|
||||||
|
{
|
||||||
|
err = gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = gnutls_server_name_set (hd->session->tls_session,
|
||||||
|
GNUTLS_NAME_DNS,
|
||||||
|
server, strlen (server));
|
||||||
|
if (rc < 0)
|
||||||
|
log_info ("gnutls_server_name_set failed: %s\n", gnutls_strerror (rc));
|
||||||
|
}
|
||||||
|
#endif /*HTTP_USE_GNUTLS*/
|
||||||
|
|
||||||
if ( (proxy && *proxy)
|
if ( (proxy && *proxy)
|
||||||
|| ( (hd->flags & HTTP_FLAG_TRY_PROXY)
|
|| ( (hd->flags & HTTP_FLAG_TRY_PROXY)
|
||||||
&& (http_proxy = getenv (HTTP_PROXY_ENV))
|
&& (http_proxy = getenv (HTTP_PROXY_ENV))
|
||||||
@ -1179,11 +1387,22 @@ send_request (http_t hd, const char *auth,
|
|||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
my_socket_ref (hd->sock);
|
my_socket_ref (hd->sock);
|
||||||
gnutls_transport_set_ptr (tls_session,
|
#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));
|
(gnutls_transport_ptr_t)(hd->sock->fd));
|
||||||
|
#endif
|
||||||
|
#ifdef USE_NPTH
|
||||||
|
gnutls_transport_set_pull_function (hd->session->tls_session,
|
||||||
|
my_npth_read);
|
||||||
|
gnutls_transport_set_push_function (hd->session->tls_session,
|
||||||
|
my_npth_write);
|
||||||
|
#endif
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
rc = gnutls_handshake (tls_session);
|
rc = gnutls_handshake (hd->session->tls_session);
|
||||||
}
|
}
|
||||||
while (rc == GNUTLS_E_INTERRUPTED || rc == GNUTLS_E_AGAIN);
|
while (rc == GNUTLS_E_INTERRUPTED || rc == GNUTLS_E_AGAIN);
|
||||||
if (rc < 0)
|
if (rc < 0)
|
||||||
@ -1195,7 +1414,8 @@ send_request (http_t hd, const char *auth,
|
|||||||
|
|
||||||
if (tls_callback)
|
if (tls_callback)
|
||||||
{
|
{
|
||||||
err = tls_callback (hd, tls_session, 0);
|
hd->session->verify.done = 0;
|
||||||
|
err = tls_callback (hd, hd->session, 0);
|
||||||
if (err)
|
if (err)
|
||||||
{
|
{
|
||||||
log_info ("TLS connection authentication failed: %s\n",
|
log_info ("TLS connection authentication failed: %s\n",
|
||||||
@ -1227,7 +1447,7 @@ send_request (http_t hd, const char *auth,
|
|||||||
myauth = hd->uri->auth;
|
myauth = hd->uri->auth;
|
||||||
}
|
}
|
||||||
|
|
||||||
authstr = make_header_line ("Authorization: Basic %s", "\r\n",
|
authstr = make_header_line ("Authorization: Basic ", "\r\n",
|
||||||
myauth, strlen (myauth));
|
myauth, strlen (myauth));
|
||||||
if (auth)
|
if (auth)
|
||||||
xfree (myauth);
|
xfree (myauth);
|
||||||
@ -1281,6 +1501,7 @@ send_request (http_t hd, const char *auth,
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* log_debug ("request:\n%s\nEND request\n", request); */
|
||||||
|
|
||||||
/* First setup estream so that we can write even the first line
|
/* First setup estream so that we can write even the first line
|
||||||
using estream. This is also required for the sake of gnutls. */
|
using estream. This is also required for the sake of gnutls. */
|
||||||
@ -1295,14 +1516,14 @@ send_request (http_t hd, const char *auth,
|
|||||||
}
|
}
|
||||||
cookie->sock = my_socket_ref (hd->sock);
|
cookie->sock = my_socket_ref (hd->sock);
|
||||||
hd->write_cookie = cookie;
|
hd->write_cookie = cookie;
|
||||||
if (hd->uri->use_tls)
|
cookie->use_tls = hd->uri->use_tls;
|
||||||
cookie->tls_session = tls_session;
|
cookie->session = hd->session;
|
||||||
|
|
||||||
hd->fp_write = es_fopencookie (cookie, "w", cookie_functions);
|
hd->fp_write = es_fopencookie (cookie, "w", cookie_functions);
|
||||||
if (!hd->fp_write)
|
if (!hd->fp_write)
|
||||||
{
|
{
|
||||||
err = gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
|
err = gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
|
||||||
my_socket_unref (cookie->sock);
|
my_socket_unref (cookie->sock, NULL, NULL);
|
||||||
xfree (cookie);
|
xfree (cookie);
|
||||||
hd->write_cookie = NULL;
|
hd->write_cookie = NULL;
|
||||||
}
|
}
|
||||||
@ -1491,8 +1712,8 @@ store_header (http_t hd, char *line)
|
|||||||
|
|
||||||
|
|
||||||
/* Return the header NAME from the last response. The returned value
|
/* Return the header NAME from the last response. The returned value
|
||||||
is valid as along as HD has not been closed and no othe request has
|
is valid as along as HD has not been closed and no other request
|
||||||
been send. If the header was not found, NULL is returned. Name
|
has been send. If the header was not found, NULL is returned. NAME
|
||||||
must be canonicalized, that is the first letter of each dash
|
must be canonicalized, that is the first letter of each dash
|
||||||
delimited part must be uppercase and all other letters lowercase. */
|
delimited part must be uppercase and all other letters lowercase. */
|
||||||
const char *
|
const char *
|
||||||
@ -1507,6 +1728,29 @@ http_get_header (http_t hd, const char *name)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Return a newly allocated and NULL terminated array with pointers to
|
||||||
|
header names. The array must be released with xfree() and its
|
||||||
|
content is only values as long as no other request has been
|
||||||
|
send. */
|
||||||
|
const char **
|
||||||
|
http_get_header_names (http_t hd)
|
||||||
|
{
|
||||||
|
const char **array;
|
||||||
|
size_t n;
|
||||||
|
header_t h;
|
||||||
|
|
||||||
|
for (n=0, h = hd->headers; h; h = h->next)
|
||||||
|
n++;
|
||||||
|
array = xtrycalloc (n+1, sizeof *array);
|
||||||
|
if (array)
|
||||||
|
{
|
||||||
|
for (n=0, h = hd->headers; h; h = h->next)
|
||||||
|
array[n++] = h->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Parse the response from a server.
|
* Parse the response from a server.
|
||||||
@ -1960,10 +2204,10 @@ cookie_read (void *cookie, void *buffer, size_t size)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HTTP_USE_GNUTLS
|
#ifdef HTTP_USE_GNUTLS
|
||||||
if (c->tls_session)
|
if (c->use_tls && c->session && c->session->tls_session)
|
||||||
{
|
{
|
||||||
again:
|
again:
|
||||||
nread = gnutls_record_recv (c->tls_session, buffer, size);
|
nread = gnutls_record_recv (c->session->tls_session, buffer, size);
|
||||||
if (nread < 0)
|
if (nread < 0)
|
||||||
{
|
{
|
||||||
if (nread == GNUTLS_E_INTERRUPTED)
|
if (nread == GNUTLS_E_INTERRUPTED)
|
||||||
@ -2014,18 +2258,20 @@ cookie_read (void *cookie, void *buffer, size_t size)
|
|||||||
|
|
||||||
/* Write handler for estream. */
|
/* Write handler for estream. */
|
||||||
static ssize_t
|
static ssize_t
|
||||||
cookie_write (void *cookie, const void *buffer, size_t size)
|
cookie_write (void *cookie, const void *buffer_arg, size_t size)
|
||||||
{
|
{
|
||||||
|
const char *buffer = buffer_arg;
|
||||||
cookie_t c = cookie;
|
cookie_t c = cookie;
|
||||||
int nwritten = 0;
|
int nwritten = 0;
|
||||||
|
|
||||||
#ifdef HTTP_USE_GNUTLS
|
#ifdef HTTP_USE_GNUTLS
|
||||||
if (c->tls_session)
|
if (c->use_tls && c->session && c->session->tls_session)
|
||||||
{
|
{
|
||||||
int nleft = size;
|
int nleft = size;
|
||||||
while (nleft > 0)
|
while (nleft > 0)
|
||||||
{
|
{
|
||||||
nwritten = gnutls_record_send (c->tls_session, buffer, nleft);
|
nwritten = gnutls_record_send (c->session->tls_session,
|
||||||
|
buffer, nleft);
|
||||||
if (nwritten <= 0)
|
if (nwritten <= 0)
|
||||||
{
|
{
|
||||||
if (nwritten == GNUTLS_E_INTERRUPTED)
|
if (nwritten == GNUTLS_E_INTERRUPTED)
|
||||||
@ -2063,6 +2309,18 @@ cookie_write (void *cookie, const void *buffer, size_t size)
|
|||||||
return nwritten;
|
return nwritten;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef HTTP_USE_GNUTLS
|
||||||
|
/* Wrapper for gnutls_bye used by my_socket_unref. */
|
||||||
|
static void
|
||||||
|
send_gnutls_bye (void *opaque)
|
||||||
|
{
|
||||||
|
gnutls_session_t tls_session = opaque;
|
||||||
|
|
||||||
|
gnutls_bye (tls_session, GNUTLS_SHUT_RDWR);
|
||||||
|
}
|
||||||
|
#endif /*HTTP_USE_GNUTLS*/
|
||||||
|
|
||||||
/* Close handler for estream. */
|
/* Close handler for estream. */
|
||||||
static int
|
static int
|
||||||
cookie_close (void *cookie)
|
cookie_close (void *cookie)
|
||||||
@ -2073,182 +2331,117 @@ cookie_close (void *cookie)
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
#ifdef HTTP_USE_GNUTLS
|
#ifdef HTTP_USE_GNUTLS
|
||||||
if (c->tls_session && !c->keep_socket)
|
if (c->use_tls && c->session && c->session->tls_session)
|
||||||
{
|
my_socket_unref (c->sock, send_gnutls_bye, c->session->tls_session);
|
||||||
gnutls_bye (c->tls_session, GNUTLS_SHUT_RDWR);
|
else
|
||||||
my_socket_unref (c->sock);
|
|
||||||
}
|
|
||||||
#endif /*HTTP_USE_GNUTLS*/
|
#endif /*HTTP_USE_GNUTLS*/
|
||||||
if (c->sock && !c->keep_socket)
|
if (c->sock)
|
||||||
my_socket_unref (c->sock);
|
my_socket_unref (c->sock, NULL, NULL);
|
||||||
|
|
||||||
xfree (c);
|
xfree (c);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**** Test code ****/
|
/* Verify the credentials of the server. Returns 0 on success and
|
||||||
#ifdef TEST
|
store the result in the session object. */
|
||||||
|
gpg_error_t
|
||||||
|
http_verify_server_credentials (http_session_t sess)
|
||||||
|
{
|
||||||
#ifdef HTTP_USE_GNUTLS
|
#ifdef HTTP_USE_GNUTLS
|
||||||
static gpg_error_t
|
static const char const errprefix[] = "TLS verification of peer failed";
|
||||||
verify_callback (http_t hd, void *tls_context, int reserved)
|
|
||||||
{
|
|
||||||
log_info ("verification of certificates skipped\n");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#endif /*HTTP_USE_GNUTLS*/
|
|
||||||
|
|
||||||
|
|
||||||
/* static void */
|
|
||||||
/* my_gnutls_log (int level, const char *text) */
|
|
||||||
/* { */
|
|
||||||
/* fprintf (stderr, "gnutls:L%d: %s", level, text); */
|
|
||||||
/* } */
|
|
||||||
|
|
||||||
int
|
|
||||||
main (int argc, char **argv)
|
|
||||||
{
|
|
||||||
int rc;
|
int rc;
|
||||||
parsed_uri_t uri;
|
unsigned int status;
|
||||||
uri_tuple_t r;
|
const char *hostname;
|
||||||
http_t hd;
|
const gnutls_datum_t *certlist;
|
||||||
int c;
|
unsigned int certlistlen;
|
||||||
gnutls_session_t tls_session = NULL;
|
gnutls_x509_crt_t cert;
|
||||||
#ifdef HTTP_USE_GNUTLS
|
|
||||||
gnutls_certificate_credentials certcred;
|
|
||||||
const int certprio[] = { GNUTLS_CRT_X509, 0 };
|
|
||||||
#endif /*HTTP_USE_GNUTLS*/
|
|
||||||
header_t hdr;
|
|
||||||
|
|
||||||
es_init ();
|
sess->verify.done = 1;
|
||||||
log_set_prefix ("http-test", 1 | 4);
|
sess->verify.status = 0;
|
||||||
if (argc == 1)
|
sess->verify.rc = GNUTLS_E_CERTIFICATE_ERROR;
|
||||||
|
|
||||||
|
if (gnutls_certificate_type_get (sess->tls_session) != GNUTLS_CRT_X509)
|
||||||
{
|
{
|
||||||
/*start_server (); */
|
log_error ("%s: %s\n", errprefix, "not an X.509 certificate");
|
||||||
return 0;
|
sess->verify.rc = GNUTLS_E_UNSUPPORTED_CERTIFICATE_TYPE;
|
||||||
|
return gpg_error (GPG_ERR_GENERAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (argc != 2)
|
rc = gnutls_certificate_verify_peers2 (sess->tls_session, &status);
|
||||||
{
|
|
||||||
fprintf (stderr, "usage: http-test uri\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
argc--;
|
|
||||||
argv++;
|
|
||||||
|
|
||||||
#ifdef HTTP_USE_GNUTLS
|
|
||||||
rc = gnutls_global_init ();
|
|
||||||
if (rc)
|
|
||||||
log_error ("gnutls_global_init failed: %s\n", gnutls_strerror (rc));
|
|
||||||
rc = gnutls_certificate_allocate_credentials (&certcred);
|
|
||||||
if (rc)
|
|
||||||
log_error ("gnutls_certificate_allocate_credentials failed: %s\n",
|
|
||||||
gnutls_strerror (rc));
|
|
||||||
/* rc = gnutls_certificate_set_x509_trust_file */
|
|
||||||
/* (certcred, "ca.pem", GNUTLS_X509_FMT_PEM); */
|
|
||||||
/* if (rc) */
|
|
||||||
/* log_error ("gnutls_certificate_set_x509_trust_file failed: %s\n", */
|
|
||||||
/* gnutls_strerror (rc)); */
|
|
||||||
rc = gnutls_init (&tls_session, GNUTLS_CLIENT);
|
|
||||||
if (rc)
|
|
||||||
log_error ("gnutls_init failed: %s\n", gnutls_strerror (rc));
|
|
||||||
rc = gnutls_set_default_priority (tls_session);
|
|
||||||
if (rc)
|
|
||||||
log_error ("gnutls_set_default_priority failed: %s\n",
|
|
||||||
gnutls_strerror (rc));
|
|
||||||
rc = gnutls_certificate_type_set_priority (tls_session, certprio);
|
|
||||||
if (rc)
|
|
||||||
log_error ("gnutls_certificate_type_set_priority failed: %s\n",
|
|
||||||
gnutls_strerror (rc));
|
|
||||||
rc = gnutls_credentials_set (tls_session, GNUTLS_CRD_CERTIFICATE, certcred);
|
|
||||||
if (rc)
|
|
||||||
log_error ("gnutls_credentials_set failed: %s\n", gnutls_strerror (rc));
|
|
||||||
/* gnutls_global_set_log_function (my_gnutls_log); */
|
|
||||||
/* gnutls_global_set_log_level (4); */
|
|
||||||
|
|
||||||
http_register_tls_callback (verify_callback);
|
|
||||||
#endif /*HTTP_USE_GNUTLS*/
|
|
||||||
|
|
||||||
rc = http_parse_uri (&uri, *argv, 1);
|
|
||||||
if (rc)
|
if (rc)
|
||||||
{
|
{
|
||||||
log_error ("'%s': %s\n", *argv, gpg_strerror (rc));
|
log_error ("%s: %s\n", errprefix, gnutls_strerror (rc));
|
||||||
return 1;
|
return gpg_error (GPG_ERR_GENERAL);
|
||||||
}
|
}
|
||||||
|
if (status)
|
||||||
printf ("Scheme: %s\n", uri->scheme);
|
|
||||||
if (uri->opaque)
|
|
||||||
printf ("Value : %s\n", uri->path);
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
printf ("Auth : %s\n", uri->auth? uri->auth:"[none]");
|
log_error ("%s: status=0x%04x\n", errprefix, status);
|
||||||
printf ("Host : %s\n", uri->host);
|
sess->verify.status = status;
|
||||||
printf ("Port : %u\n", uri->port);
|
return gpg_error (GPG_ERR_GENERAL);
|
||||||
printf ("Path : %s\n", uri->path);
|
|
||||||
for (r = uri->params; r; r = r->next)
|
|
||||||
{
|
|
||||||
printf ("Params: %s", r->name);
|
|
||||||
if (!r->no_value)
|
|
||||||
{
|
|
||||||
printf ("=%s", r->value);
|
|
||||||
if (strlen (r->value) != r->valuelen)
|
|
||||||
printf (" [real length=%d]", (int) r->valuelen);
|
|
||||||
}
|
|
||||||
putchar ('\n');
|
|
||||||
}
|
|
||||||
for (r = uri->query; r; r = r->next)
|
|
||||||
{
|
|
||||||
printf ("Query : %s", r->name);
|
|
||||||
if (!r->no_value)
|
|
||||||
{
|
|
||||||
printf ("=%s", r->value);
|
|
||||||
if (strlen (r->value) != r->valuelen)
|
|
||||||
printf (" [real length=%d]", (int) r->valuelen);
|
|
||||||
}
|
|
||||||
putchar ('\n');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
http_release_parsed_uri (uri);
|
|
||||||
uri = NULL;
|
|
||||||
|
|
||||||
rc = http_open_document (&hd, *argv, NULL, 0, NULL, tls_session, NULL, NULL);
|
hostname = sess->servername;
|
||||||
if (rc)
|
if (!hostname || !strchr (hostname, '.'))
|
||||||
{
|
{
|
||||||
log_error ("can't get '%s': %s\n", *argv, gpg_strerror (rc));
|
log_error ("%s: %s\n", errprefix, "hostname missing");
|
||||||
return 1;
|
return gpg_error (GPG_ERR_GENERAL);
|
||||||
}
|
}
|
||||||
log_info ("open_http_document succeeded; status=%u\n",
|
|
||||||
http_get_status_code (hd));
|
certlist = gnutls_certificate_get_peers (sess->tls_session, &certlistlen);
|
||||||
for (hdr = hd->headers; hdr; hdr = hdr->next)
|
if (!certlistlen)
|
||||||
printf ("HDR: %s: %s\n", hdr->name, hdr->value);
|
|
||||||
switch (http_get_status_code (hd))
|
|
||||||
{
|
{
|
||||||
case 200:
|
log_error ("%s: %s\n", errprefix, "server did not send a certificate");
|
||||||
while ((c = es_getc (http_get_read_ptr (hd))) != EOF)
|
return gpg_error (GPG_ERR_GENERAL);
|
||||||
putchar (c);
|
|
||||||
break;
|
|
||||||
case 301:
|
|
||||||
case 302:
|
|
||||||
printf ("Redirected to '%s'\n", http_get_header (hd, "Location"));
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
http_close (hd, 0);
|
|
||||||
|
|
||||||
#ifdef HTTP_USE_GNUTLS
|
/* log_debug ("Server sent %u certs\n", certlistlen); */
|
||||||
gnutls_deinit (tls_session);
|
/* { */
|
||||||
gnutls_certificate_free_credentials (certcred);
|
/* int i; */
|
||||||
gnutls_global_deinit ();
|
/* char fname[50]; */
|
||||||
#endif /*HTTP_USE_GNUTLS*/
|
/* FILE *fp; */
|
||||||
|
|
||||||
return 0;
|
/* for (i=0; i < certlistlen; i++) */
|
||||||
|
/* { */
|
||||||
|
/* snprintf (fname, sizeof fname, "xc_%d.der", i); */
|
||||||
|
/* fp = fopen (fname, "wb"); */
|
||||||
|
/* if (!fp) */
|
||||||
|
/* log_fatal ("Failed to create '%s'\n", fname); */
|
||||||
|
/* if (fwrite (certlist[i].data, certlist[i].size, 1, fp) != 1) */
|
||||||
|
/* log_fatal ("Error writing to '%s'\n", fname); */
|
||||||
|
/* fclose (fp); */
|
||||||
|
/* } */
|
||||||
|
/* } */
|
||||||
|
|
||||||
|
rc = gnutls_x509_crt_init (&cert);
|
||||||
|
if (rc < 0)
|
||||||
|
{
|
||||||
|
return gpg_error (GPG_ERR_GENERAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = gnutls_x509_crt_import (cert, &certlist[0], GNUTLS_X509_FMT_DER);
|
||||||
|
if (rc < 0)
|
||||||
|
{
|
||||||
|
log_error ("%s: %s: %s\n", errprefix, "error importing certificate",
|
||||||
|
gnutls_strerror (rc));
|
||||||
|
gnutls_x509_crt_deinit (cert);
|
||||||
|
return gpg_error (GPG_ERR_GENERAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!gnutls_x509_crt_check_hostname (cert, hostname))
|
||||||
|
{
|
||||||
|
log_error ("%s: %s\n", errprefix, "hostname does not match");
|
||||||
|
gnutls_x509_crt_deinit (cert);
|
||||||
|
return gpg_error (GPG_ERR_GENERAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
gnutls_x509_crt_deinit (cert);
|
||||||
|
sess->verify.rc = 0;
|
||||||
|
return 0; /* Verification succeeded. */
|
||||||
|
#else /*!HTTP_USE_GNUTLS*/
|
||||||
|
(void)sess;
|
||||||
|
return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
#endif /*TEST*/
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
Local Variables:
|
|
||||||
compile-command: "gcc -I.. -I../gl -DTEST -DHAVE_CONFIG_H -Wall -O2 -g -o http-test http.c -L. -lcommon -lgcrypt -lpth -lgnutls"
|
|
||||||
End:
|
|
||||||
*/
|
|
||||||
|
@ -82,10 +82,20 @@ enum
|
|||||||
HTTP_FLAG_IGNORE_IPv6 = 128 /* Do not use IPv6. */
|
HTTP_FLAG_IGNORE_IPv6 = 128 /* Do not use IPv6. */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct http_session_s;
|
||||||
|
typedef struct http_session_s *http_session_t;
|
||||||
|
|
||||||
struct http_context_s;
|
struct http_context_s;
|
||||||
typedef struct http_context_s *http_t;
|
typedef struct http_context_s *http_t;
|
||||||
|
|
||||||
void http_register_tls_callback (gpg_error_t (*cb) (http_t, void *, int));
|
void http_register_tls_callback (gpg_error_t (*cb)(http_t,http_session_t,int));
|
||||||
|
void http_register_tls_ca (const char *fname);
|
||||||
|
|
||||||
|
gpg_error_t http_session_new (http_session_t *r_session,
|
||||||
|
const char *tls_priority);
|
||||||
|
void http_session_release (http_session_t sess);
|
||||||
|
|
||||||
|
|
||||||
gpg_error_t http_parse_uri (parsed_uri_t *ret_uri, const char *uri,
|
gpg_error_t http_parse_uri (parsed_uri_t *ret_uri, const char *uri,
|
||||||
int no_scheme_check);
|
int no_scheme_check);
|
||||||
@ -101,7 +111,7 @@ gpg_error_t http_open (http_t *r_hd, http_req_t reqtype,
|
|||||||
const char *auth,
|
const char *auth,
|
||||||
unsigned int flags,
|
unsigned int flags,
|
||||||
const char *proxy,
|
const char *proxy,
|
||||||
void *tls_context,
|
http_session_t session,
|
||||||
const char *srvtag,
|
const char *srvtag,
|
||||||
strlist_t headers);
|
strlist_t headers);
|
||||||
|
|
||||||
@ -116,7 +126,7 @@ gpg_error_t http_open_document (http_t *r_hd,
|
|||||||
const char *auth,
|
const char *auth,
|
||||||
unsigned int flags,
|
unsigned int flags,
|
||||||
const char *proxy,
|
const char *proxy,
|
||||||
void *tls_context,
|
http_session_t session,
|
||||||
const char *srvtag,
|
const char *srvtag,
|
||||||
strlist_t headers);
|
strlist_t headers);
|
||||||
|
|
||||||
@ -124,6 +134,8 @@ estream_t http_get_read_ptr (http_t hd);
|
|||||||
estream_t http_get_write_ptr (http_t hd);
|
estream_t http_get_write_ptr (http_t hd);
|
||||||
unsigned int http_get_status_code (http_t hd);
|
unsigned int http_get_status_code (http_t hd);
|
||||||
const char *http_get_header (http_t hd, const char *name);
|
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);
|
||||||
|
|
||||||
char *http_escape_string (const char *string, const char *specials);
|
char *http_escape_string (const char *string, const char *specials);
|
||||||
char *http_escape_data (const void *data, size_t datalen, const char *specials);
|
char *http_escape_data (const void *data, size_t datalen, const char *specials);
|
||||||
|
269
common/t-http.c
Normal file
269
common/t-http.c
Normal file
@ -0,0 +1,269 @@
|
|||||||
|
/* t-http.c
|
||||||
|
* Copyright (C) 1999, 2001, 2002, 2003, 2004, 2006, 2009, 2010,
|
||||||
|
* 2011 Free Software Foundation, Inc.
|
||||||
|
* Copyright (C) 2014 Werner Koch
|
||||||
|
*
|
||||||
|
* This file is part of GnuPG.
|
||||||
|
*
|
||||||
|
* This file is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of either
|
||||||
|
*
|
||||||
|
* - the GNU Lesser General Public License as published by the Free
|
||||||
|
* Software Foundation; either version 3 of the License, or (at
|
||||||
|
* your option) any later version.
|
||||||
|
*
|
||||||
|
* or
|
||||||
|
*
|
||||||
|
* - the GNU General Public License as published by the Free
|
||||||
|
* Software Foundation; either version 2 of the License, or (at
|
||||||
|
* your option) any later version.
|
||||||
|
*
|
||||||
|
* or both in parallel, as here.
|
||||||
|
*
|
||||||
|
* This file 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <config.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "util.h"
|
||||||
|
#include "logging.h"
|
||||||
|
#include "http.h"
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef HTTP_USE_GNUTLS
|
||||||
|
# include <gnutls/gnutls.h> /* For init, logging, and deinit. */
|
||||||
|
#endif /*HTTP_USE_GNUTLS*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* static void */
|
||||||
|
/* read_dh_params (const char *fname) */
|
||||||
|
/* { */
|
||||||
|
/* gpg_error_t err; */
|
||||||
|
/* int rc; */
|
||||||
|
/* FILE *fp; */
|
||||||
|
/* struct stat st; */
|
||||||
|
/* char *buf; */
|
||||||
|
/* size_t buflen; */
|
||||||
|
/* gnutls_datum_t datum; */
|
||||||
|
|
||||||
|
/* fp = fopen (fname, "rb"); */
|
||||||
|
/* if (!fp) */
|
||||||
|
/* { */
|
||||||
|
/* err = gpg_error_from_syserror (); */
|
||||||
|
/* log_fatal ("can't open '%s': %s\n", fname, gpg_strerror (err)); */
|
||||||
|
/* } */
|
||||||
|
|
||||||
|
/* if (fstat (fileno(fp), &st)) */
|
||||||
|
/* { */
|
||||||
|
/* err = gpg_error_from_syserror (); */
|
||||||
|
/* log_fatal ("can't stat '%s': %s\n", fname, gpg_strerror (err)); */
|
||||||
|
/* } */
|
||||||
|
|
||||||
|
/* buflen = st.st_size; */
|
||||||
|
/* buf = xmalloc (buflen+1); */
|
||||||
|
/* if (fread (buf, buflen, 1, fp) != 1) */
|
||||||
|
/* { */
|
||||||
|
/* err = gpg_error_from_syserror (); */
|
||||||
|
/* log_fatal ("error reading '%s': %s\n", fname, gpg_strerror (err)); */
|
||||||
|
/* } */
|
||||||
|
/* fclose (fp); */
|
||||||
|
|
||||||
|
/* datum.size = buflen; */
|
||||||
|
/* datum.data = buf; */
|
||||||
|
|
||||||
|
/* rc = gnutls_dh_params_import_pkcs3 (dh_params, &datum, GNUTLS_X509_FMT_PEM); */
|
||||||
|
/* if (rc < 0) */
|
||||||
|
/* log_fatal ("gnutls_dh_param_import failed: %s\n", gnutls_strerror (rc)); */
|
||||||
|
|
||||||
|
/* xfree (buf); */
|
||||||
|
/* } */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static gpg_error_t
|
||||||
|
verify_callback (http_t hd, http_session_t session, int reserved)
|
||||||
|
{
|
||||||
|
(void)hd;
|
||||||
|
(void)reserved;
|
||||||
|
return http_verify_server_credentials (session);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
my_gnutls_log (int level, const char *text)
|
||||||
|
{
|
||||||
|
fprintf (stderr, "gnutls:L%d: %s", level, text);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Prepend FNAME with the srcdir environment variable's value and
|
||||||
|
return an allocated filename. */
|
||||||
|
static char *
|
||||||
|
prepend_srcdir (const char *fname)
|
||||||
|
{
|
||||||
|
static const char *srcdir;
|
||||||
|
char *result;
|
||||||
|
|
||||||
|
if (!srcdir && !(srcdir = getenv ("srcdir")))
|
||||||
|
srcdir = ".";
|
||||||
|
|
||||||
|
result = xmalloc (strlen (srcdir) + 1 + strlen (fname) + 1);
|
||||||
|
strcpy (result, srcdir);
|
||||||
|
strcat (result, "/");
|
||||||
|
strcat (result, fname);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
main (int argc, char **argv)
|
||||||
|
{
|
||||||
|
gpg_error_t err;
|
||||||
|
int rc;
|
||||||
|
parsed_uri_t uri;
|
||||||
|
uri_tuple_t r;
|
||||||
|
http_t hd;
|
||||||
|
int c;
|
||||||
|
http_session_t session = NULL;
|
||||||
|
|
||||||
|
es_init ();
|
||||||
|
log_set_prefix ("t-http", 1 | 4);
|
||||||
|
if (argc != 2)
|
||||||
|
{
|
||||||
|
fprintf (stderr, "usage: t-http uri\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
argc--;
|
||||||
|
argv++;
|
||||||
|
|
||||||
|
#ifdef HTTP_USE_GNUTLS
|
||||||
|
rc = gnutls_global_init ();
|
||||||
|
if (rc)
|
||||||
|
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"));
|
||||||
|
|
||||||
|
err = http_session_new (&session, NULL);
|
||||||
|
if (err)
|
||||||
|
log_error ("http_session_new failed: %s\n", gpg_strerror (err));
|
||||||
|
|
||||||
|
/* rc = gnutls_dh_params_init(&dh_params); */
|
||||||
|
/* if (rc) */
|
||||||
|
/* log_error ("gnutls_dh_params_init failed: %s\n", gnutls_strerror (rc)); */
|
||||||
|
/* read_dh_params ("dh_param.pem"); */
|
||||||
|
|
||||||
|
/* rc = gnutls_certificate_set_x509_trust_file */
|
||||||
|
/* (certcred, "ca.pem", GNUTLS_X509_FMT_PEM); */
|
||||||
|
/* if (rc) */
|
||||||
|
/* log_error ("gnutls_certificate_set_x509_trust_file failed: %s\n", */
|
||||||
|
/* gnutls_strerror (rc)); */
|
||||||
|
|
||||||
|
/* gnutls_certificate_set_dh_params (certcred, dh_params); */
|
||||||
|
|
||||||
|
gnutls_global_set_log_function (my_gnutls_log);
|
||||||
|
/* gnutls_global_set_log_level (2); */
|
||||||
|
|
||||||
|
#endif /*HTTP_USE_GNUTLS*/
|
||||||
|
|
||||||
|
rc = http_parse_uri (&uri, *argv, 1);
|
||||||
|
if (rc)
|
||||||
|
{
|
||||||
|
log_error ("'%s': %s\n", *argv, gpg_strerror (rc));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf ("Scheme: %s\n", uri->scheme);
|
||||||
|
if (uri->opaque)
|
||||||
|
printf ("Value : %s\n", uri->path);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf ("Auth : %s\n", uri->auth? uri->auth:"[none]");
|
||||||
|
printf ("Host : %s\n", uri->host);
|
||||||
|
printf ("Port : %u\n", uri->port);
|
||||||
|
printf ("Path : %s\n", uri->path);
|
||||||
|
for (r = uri->params; r; r = r->next)
|
||||||
|
{
|
||||||
|
printf ("Params: %s", r->name);
|
||||||
|
if (!r->no_value)
|
||||||
|
{
|
||||||
|
printf ("=%s", r->value);
|
||||||
|
if (strlen (r->value) != r->valuelen)
|
||||||
|
printf (" [real length=%d]", (int) r->valuelen);
|
||||||
|
}
|
||||||
|
putchar ('\n');
|
||||||
|
}
|
||||||
|
for (r = uri->query; r; r = r->next)
|
||||||
|
{
|
||||||
|
printf ("Query : %s", r->name);
|
||||||
|
if (!r->no_value)
|
||||||
|
{
|
||||||
|
printf ("=%s", r->value);
|
||||||
|
if (strlen (r->value) != r->valuelen)
|
||||||
|
printf (" [real length=%d]", (int) r->valuelen);
|
||||||
|
}
|
||||||
|
putchar ('\n');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
http_release_parsed_uri (uri);
|
||||||
|
uri = NULL;
|
||||||
|
|
||||||
|
rc = http_open_document (&hd, *argv, NULL, 0, NULL, session, NULL, NULL);
|
||||||
|
if (rc)
|
||||||
|
{
|
||||||
|
log_error ("can't get '%s': %s\n", *argv, gpg_strerror (rc));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
log_info ("open_http_document succeeded; status=%u\n",
|
||||||
|
http_get_status_code (hd));
|
||||||
|
|
||||||
|
{
|
||||||
|
const char **names;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
names = http_get_header_names (hd);
|
||||||
|
if (!names)
|
||||||
|
log_fatal ("http_get_header_names failed: %s\n",
|
||||||
|
gpg_strerror (gpg_error_from_syserror ()));
|
||||||
|
for (i = 0; names[i]; i++)
|
||||||
|
printf ("HDR: %s: %s\n", names[i], http_get_header (hd, names[i]));
|
||||||
|
xfree (names);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (http_get_status_code (hd))
|
||||||
|
{
|
||||||
|
case 200:
|
||||||
|
case 400:
|
||||||
|
case 401:
|
||||||
|
case 403:
|
||||||
|
case 404:
|
||||||
|
while ((c = es_getc (http_get_read_ptr (hd))) != EOF)
|
||||||
|
putchar (c);
|
||||||
|
break;
|
||||||
|
case 301:
|
||||||
|
case 302:
|
||||||
|
printf ("Redirected to '%s'\n", http_get_header (hd, "Location"));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
http_close (hd, 0);
|
||||||
|
|
||||||
|
http_session_release (session);
|
||||||
|
#ifdef HTTP_USE_GNUTLS
|
||||||
|
gnutls_global_deinit ();
|
||||||
|
#endif /*HTTP_USE_GNUTLS*/
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
30
common/tls-ca.pem
Normal file
30
common/tls-ca.pem
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
Issuer ...: /CN=UTN-USERFirst-Hardware/OU=http:\x2f\x2fwww.usertrust.com/O=The USERTRUST Network/L=Salt Lake City/ST=UT/C=US
|
||||||
|
Serial ...: 44BE0C8B500024B411D3362AFE650AFD
|
||||||
|
Subject ..: /CN=UTN-USERFirst-Hardware/OU=http:\x2f\x2fwww.usertrust.com/O=The USERTRUST Network/L=Salt Lake City/ST=UT/C=US
|
||||||
|
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIEdDCCA1ygAwIBAgIQRL4Mi1AAJLQR0zYq/mUK/TANBgkqhkiG9w0BAQUFADCB
|
||||||
|
lzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug
|
||||||
|
Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho
|
||||||
|
dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3Qt
|
||||||
|
SGFyZHdhcmUwHhcNOTkwNzA5MTgxMDQyWhcNMTkwNzA5MTgxOTIyWjCBlzELMAkG
|
||||||
|
A1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEe
|
||||||
|
MBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8v
|
||||||
|
d3d3LnVzZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3QtSGFyZHdh
|
||||||
|
cmUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCx98M4P7Sof885glFn
|
||||||
|
0G2f0v9Y8+efK+wNiVSZuTiZFvfgIXlIwrthdBKWHTxqctU8EGc6Oe0rE81m65UJ
|
||||||
|
M6Rsl7HoxuzBdXmcRl6Nq9Bq/bkqVRcQVLMZ8Jr28bFdtqdt++BxF2uiiPsA3/4a
|
||||||
|
MXcMmgF6sTLjKwEHOG7DpV4jvEWbe1DByTCP2+UretNb+zNAHqDVmBe8i4fDidNd
|
||||||
|
oI6yqqr2jmmIBsX6iSHzCJ1pLgkzmykNRg+MzEk0sGlRvfkGzWitZky8PqxhvQqI
|
||||||
|
DsjfPe58BEydCl5rkdbux+0ojatNh4lz0G6k0B4WixThdkQDf2Os5M1JnMWS9Ksy
|
||||||
|
oUhbAgMBAAGjgbkwgbYwCwYDVR0PBAQDAgHGMA8GA1UdEwEB/wQFMAMBAf8wHQYD
|
||||||
|
VR0OBBYEFKFyXyYbKJhDlV0HN9WFlp1L0sNFMEQGA1UdHwQ9MDswOaA3oDWGM2h0
|
||||||
|
dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VVE4tVVNFUkZpcnN0LUhhcmR3YXJlLmNy
|
||||||
|
bDAxBgNVHSUEKjAoBggrBgEFBQcDAQYIKwYBBQUHAwUGCCsGAQUFBwMGBggrBgEF
|
||||||
|
BQcDBzANBgkqhkiG9w0BAQUFAAOCAQEARxkP3nTGmZev/K0oXnWO6y1n7k57K9cM
|
||||||
|
//bey1WiCuFMVGWTYGufEpytXoMs61quwOQt9ABjHbjAbPLPSbtNk28Gpgoiskli
|
||||||
|
CE7/yMgUsogWXecB5BKV5UU0s4tpvc+0hY91UZ59Ojg6FEgSxvunOxqNDYJAB+gE
|
||||||
|
CJChicsZUN/KHAG8HQQZexB2lzvukJDKxA4fFm517zP4029bHpbj4HR3dHuKom4t
|
||||||
|
3XbWOTCC8KucUvIqx69JXn7HaOWCgchqJ/kniCrVWFCVH/A7HFe7fRQ5YiuayZSS
|
||||||
|
KqMiDP+JJn1fIytH1xUdqWqeUQ0qUZ6B+dQ7XnASfxAynB67nfhmqA==
|
||||||
|
-----END CERTIFICATE-----
|
24
configure.ac
24
configure.ac
@ -58,6 +58,8 @@ NEED_KSBA_VERSION=1.2.0
|
|||||||
NEED_NPTH_API=1
|
NEED_NPTH_API=1
|
||||||
NEED_NPTH_VERSION=0.91
|
NEED_NPTH_VERSION=0.91
|
||||||
|
|
||||||
|
NEED_GNUTLS_VERSION=3.0
|
||||||
|
|
||||||
|
|
||||||
development_version=mym4_isgit
|
development_version=mym4_isgit
|
||||||
PACKAGE=$PACKAGE_NAME
|
PACKAGE=$PACKAGE_NAME
|
||||||
@ -912,6 +914,26 @@ else
|
|||||||
***]])
|
***]])
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
#
|
||||||
|
# Check whether GNUTLS is available
|
||||||
|
#
|
||||||
|
PKG_CHECK_MODULES([LIBGNUTLS], [gnutls >= $NEED_GNUTLS_VERSION],
|
||||||
|
[have_gnutls=yes],
|
||||||
|
[have_gnutls=no])
|
||||||
|
if test "$have_gnutls" = "yes"; then
|
||||||
|
AC_SUBST([LIBGNUTLS_CFLAGS])
|
||||||
|
AC_SUBST([LIBGNUTLS_LIBS])
|
||||||
|
AC_DEFINE(HTTP_USE_GNUTLS, 1, [Enable GNUTLS support in http.c])
|
||||||
|
else
|
||||||
|
tmp=$(echo "$LIBGNUTLS_PKG_ERRORS" | tr '\n' '\v' | sed 's/\v/\n*** /g')
|
||||||
|
AC_MSG_WARN([[
|
||||||
|
***
|
||||||
|
*** Building without GNUTLS - no TLS access to keyservers.
|
||||||
|
***
|
||||||
|
*** $tmp]])
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
AC_MSG_NOTICE([checking for networking options])
|
AC_MSG_NOTICE([checking for networking options])
|
||||||
|
|
||||||
@ -1867,6 +1889,8 @@ echo "
|
|||||||
Use standard socket: $use_standard_socket
|
Use standard socket: $use_standard_socket
|
||||||
Dirmngr auto start: $dirmngr_auto_start
|
Dirmngr auto start: $dirmngr_auto_start
|
||||||
Readline support: $gnupg_cv_have_readline
|
Readline support: $gnupg_cv_have_readline
|
||||||
|
DNS SRV support: $use_dns_srv
|
||||||
|
TLS support: $have_gnutls
|
||||||
"
|
"
|
||||||
if test x"$use_regex" != xyes ; then
|
if test x"$use_regex" != xyes ; then
|
||||||
echo "
|
echo "
|
||||||
|
@ -60,8 +60,10 @@ dirmngr_SOURCES += ldap-wrapper-ce.c dirmngr_ldap.c
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
|
|
||||||
dirmngr_LDADD = $(libcommonpth) ../gl/libgnu.a $(DNSLIBS) $(LIBASSUAN_LIBS) \
|
dirmngr_LDADD = $(libcommontlsnpth) $(libcommonpth) \
|
||||||
$(LIBGCRYPT_LIBS) $(KSBA_LIBS) $(NPTH_LIBS) $(LIBINTL) $(LIBICONV)
|
../gl/libgnu.a $(DNSLIBS) $(LIBASSUAN_LIBS) \
|
||||||
|
$(LIBGCRYPT_LIBS) $(KSBA_LIBS) $(NPTH_LIBS) \
|
||||||
|
$(LIBGNUTLS_LIBS) $(LIBINTL) $(LIBICONV)
|
||||||
if !USE_LDAPWRAPPER
|
if !USE_LDAPWRAPPER
|
||||||
dirmngr_LDADD += $(LDAPLIBS)
|
dirmngr_LDADD += $(LDAPLIBS)
|
||||||
endif
|
endif
|
||||||
@ -79,8 +81,7 @@ endif
|
|||||||
dirmngr_client_SOURCES = dirmngr-client.c
|
dirmngr_client_SOURCES = dirmngr-client.c
|
||||||
dirmngr_client_LDADD = $(libcommon) no-libgcrypt.o \
|
dirmngr_client_LDADD = $(libcommon) no-libgcrypt.o \
|
||||||
../gl/libgnu.a $(LIBASSUAN_LIBS) \
|
../gl/libgnu.a $(LIBASSUAN_LIBS) \
|
||||||
$(GPG_ERROR_LIBS) $(LIBINTL) \
|
$(GPG_ERROR_LIBS) $(NETLIBS) $(LIBINTL) $(LIBICONV)
|
||||||
$(LIBICONV)
|
|
||||||
dirmngr_client_LDFLAGS = $(extra_bin_ldflags)
|
dirmngr_client_LDFLAGS = $(extra_bin_ldflags)
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user