/* This file is part of the YAZ toolkit.
- * Copyright (C) 1995-2011 Index Data
+ * Copyright (C) 1995-2013 Index Data
* See the file LICENSE for details.
*/
/**
p->f_addrstr = tcpip_addrstr;
p->f_straddr = tcpip_straddr;
p->f_set_blocking = tcpip_set_blocking;
- p->max_recv_bytes = 5000000;
+ p->max_recv_bytes = 128 * 1024 * 1024;
p->state = s < 0 ? CS_ST_UNBND : CS_ST_IDLE; /* state of line */
p->event = CS_NONE;
const char *port = "210";
struct addrinfo *ai = 0;
if (h->protocol == PROTO_HTTP)
- port = "80";
+ {
+ if (h->type == ssl_type)
+ port = "443";
+ else
+ port = "80";
+ }
if (!tcpip_init())
return 0;
return 0;
assert(ai);
h->iofile = s;
-
+
if (!tcpip_set_blocking(h, h->flags))
return 0;
}
tcpip_state *sp = (tcpip_state *)h->cprivate;
int port = 210;
if (h->protocol == PROTO_HTTP)
- port = 80;
+ {
+ if (h->type == ssl_type)
+ port = 443;
+ else
+ port = 80;
+ }
if (!tcpip_init())
return 0;
int tcpip_more(COMSTACK h)
{
tcpip_state *sp = (tcpip_state *)h->cprivate;
-
+
return sp->altlen && (*sp->complete)(sp->altbuf, sp->altlen);
}
#if HAVE_GNUTLS_H
if (h->type == ssl_type && !sp->session)
{
- int res;
gnutls_global_init();
-
tcpip_create_cred(h);
-
gnutls_init(&sp->session, GNUTLS_CLIENT);
gnutls_set_default_priority(sp->session);
gnutls_credentials_set (sp->session, GNUTLS_CRD_CERTIFICATE,
sp->cred_ptr->xcred);
-
/* cast to intermediate size_t to avoid GCC warning. */
- gnutls_transport_set_ptr(sp->session,
- (gnutls_transport_ptr_t)
+ gnutls_transport_set_ptr(sp->session,
+ (gnutls_transport_ptr_t)
(size_t) h->iofile);
- res = gnutls_handshake(sp->session);
+ }
+ if (sp->session)
+ {
+ int res = gnutls_handshake(sp->session);
if (res < 0)
{
if (ssl_check_error(h, sp, res))
{
int r;
tcpip_state *sp = (tcpip_state *)h->cprivate;
-#if HAVE_GETADDRINFO
- struct addrinfo *ai = (struct addrinfo *) address;
+#if HAVE_GETADDRINFO
+ struct addrinfo *ai = (struct addrinfo *) address;
#else
struct sockaddr *addr = (struct sockaddr *)address;
#endif
tcpip_create_cred(h);
- res = gnutls_certificate_set_x509_key_file(sp->cred_ptr->xcred,
+ res = gnutls_certificate_set_x509_key_file(sp->cred_ptr->xcred,
sp->cert_fname,
sp->cert_fname,
GNUTLS_X509_FMT_PEM);
TRC(fprintf(stderr, "tcpip_bind\n"));
#endif
#ifndef WIN32
- if (setsockopt(h->iofile, SOL_SOCKET, SO_REUSEADDR, (char*)
+ if (setsockopt(h->iofile, SOL_SOCKET, SO_REUSEADDR, (char*)
&one, sizeof(one)) < 0)
{
h->cerrno = CSYSERR;
#ifdef WIN32
WSAGetLastError() == WSAEWOULDBLOCK
#else
- yaz_errno() == EWOULDBLOCK
+ yaz_errno() == EWOULDBLOCK
#ifdef EAGAIN
#if EAGAIN != EWOULDBLOCK
|| yaz_errno() == EAGAIN
#endif
cnew->state = CS_ST_ACCEPT;
h->state = CS_ST_IDLE;
-
+
#if HAVE_GNUTLS_H
state->cred_ptr = st->cred_ptr;
state->session = 0;
return 0;
}
res = gnutls_credentials_set(state->session,
- GNUTLS_CRD_CERTIFICATE,
+ GNUTLS_CRD_CERTIFICATE,
st->cred_ptr->xcred);
if (res != GNUTLS_E_SUCCESS)
{
return 0;
}
/* cast to intermediate size_t to avoid GCC warning. */
- gnutls_transport_set_ptr(state->session,
+ gnutls_transport_set_ptr(state->session,
(gnutls_transport_ptr_t)
(size_t) cnew->iofile);
}
TRC(fprintf(stderr, " recv res=%d, hasread=%d\n", res, hasread));
if (res < 0)
{
- TRC(fprintf(stderr, " recv errno=%d, (%s)\n", yaz_errno(),
+ TRC(fprintf(stderr, " recv errno=%d, (%s)\n", yaz_errno(),
strerror(yaz_errno())));
#ifdef WIN32
if (WSAGetLastError() == WSAEWOULDBLOCK)
return -1;
}
#else
- if (yaz_errno() == EWOULDBLOCK
-#ifdef EAGAIN
+ if (yaz_errno() == EWOULDBLOCK
+#ifdef EAGAIN
#if EAGAIN != EWOULDBLOCK
|| yaz_errno() == EAGAIN
#endif
#if HAVE_GNUTLS_H
res = gnutls_record_recv(sp->session, *buf + hasread,
CS_TCPIP_BUFCHUNK);
- if (res < 0)
+ if (res == 0)
+ {
+ TRC(fprintf(stderr, "gnutls_record_recv returned 0\n"));
+ return 0;
+ }
+ else if (res < 0)
{
if (ssl_check_error(h, sp, res))
break;
{
if ((res =
send(h->iofile, buf + state->written, size -
- state->written,
+ state->written,
#ifdef MSG_NOSIGNAL
MSG_NOSIGNAL
#else
#ifdef WIN32
WSAGetLastError() == WSAEWOULDBLOCK
#else
- yaz_errno() == EWOULDBLOCK
+ yaz_errno() == EWOULDBLOCK
#ifdef EAGAIN
#if EAGAIN != EWOULDBLOCK
|| yaz_errno() == EAGAIN
while (state->towrite > state->written)
{
#if HAVE_GNUTLS_H
- res = gnutls_record_send(state->session, buf + state->written,
+ res = gnutls_record_send(state->session, buf + state->written,
size - state->written);
if (res <= 0)
{
return -1;
}
#else
- res = SSL_write(state->ssl, buf + state->written,
+ res = SSL_write(state->ssl, buf + state->written,
size - state->written);
if (res <= 0)
{
if (--(sp->cred_ptr->ref) == 0)
{
- TRC(fprintf(stderr, "Removed credentials %p pid=%d\n",
+ TRC(fprintf(stderr, "Removed credentials %p pid=%d\n",
sp->cred_ptr->xcred, getpid()));
gnutls_certificate_free_credentials(sp->cred_ptr->xcred);
xfree(sp->cred_ptr);
char host[120];
struct sockaddr_storage addr;
YAZ_SOCKLEN_T len = sizeof(addr);
-
+
if (getpeername(h->iofile, (struct sockaddr *)&addr, &len) < 0)
{
h->cerrno = CSYSERR;
return 0;
}
- if (getnameinfo((struct sockaddr *) &addr, len, host, sizeof(host)-1,
- 0, 0,
+ if (getnameinfo((struct sockaddr *) &addr, len, host, sizeof(host)-1,
+ 0, 0,
(h->flags & CS_FLAGS_NUMERICHOST) ? NI_NUMERICHOST : 0))
{
r = "unknown";
}
else
r = host;
-
+
#else
struct sockaddr_in addr;
YAZ_SOCKLEN_T len = sizeof(addr);
struct hostent *host;
-
+
if (getpeername(h->iofile, (struct sockaddr*) &addr, &len) < 0)
{
h->cerrno = CSYSERR;
r = (char*) host->h_name;
}
if (!r)
- r = inet_ntoa(addr.sin_addr);
+ r = inet_ntoa(addr.sin_addr);
#endif
if (h->protocol == PROTO_HTTP)
static int tcpip_set_blocking(COMSTACK p, int flags)
{
unsigned long flag;
-
+
#ifdef WIN32
flag = (flags & CS_FLAGS_BLOCKING) ? 0 : 1;
if (ioctlsocket(p->iofile, FIONBIO, &flag) < 0)
return 1;
}
+
+#if HAVE_GNUTLS_H
+/* gnutls_x509_crt_print appeared in 1.7.6. Memory leaks were fixed in 1.7.9.
+ GNUTLS_CRT_PRINT_FULL appeared in 2.4.0. */
+#if GNUTLS_VERSION_NUMBER >= 0x020400
+#define USE_GNUTLS_X509_CRT_PRINT 1
+#else
+#define USE_GNUTLS_X509_CRT_PRINT 0
+#endif
+
+
+#if USE_GNUTLS_X509_CRT_PRINT
+#else
+static const char *bin2hex(const void *bin, size_t bin_size)
+{
+ static char printable[110];
+ const unsigned char *_bin = bin;
+ char *print;
+ size_t i;
+ if (bin_size > 50)
+ bin_size = 50;
+ print = printable;
+ for (i = 0; i < bin_size; i++)
+ {
+ sprintf(print, "%.2x ", _bin[i]);
+ print += 2;
+ }
+ return printable;
+}
+
+static void x509_crt_print(gnutls_x509_crt_t cert)
+{
+ time_t expiration_time, activation_time;
+ size_t size;
+ char serial[40];
+ char dn[256];
+ unsigned int algo, bits;
+
+ expiration_time = gnutls_x509_crt_get_expiration_time(cert);
+ activation_time = gnutls_x509_crt_get_activation_time(cert);
+
+ printf("\tCertificate is valid since: %s", ctime(&activation_time));
+ printf("\tCertificate expires: %s", ctime(&expiration_time));
+
+ /* Print the serial number of the certificate. */
+ size = sizeof(serial);
+ gnutls_x509_crt_get_serial(cert, serial, &size);
+
+ printf("\tCertificate serial number: %s\n", bin2hex(serial, size));
+
+ /* Extract some of the public key algorithm's parameters
+ */
+ algo = gnutls_x509_crt_get_pk_algorithm(cert, &bits);
+
+ printf("Certificate public key: %s", gnutls_pk_algorithm_get_name(algo));
+
+ /* Print the version of the X.509 certificate. */
+ printf("\tCertificate version: #%d\n", gnutls_x509_crt_get_version(cert));
+
+ size = sizeof(dn);
+ gnutls_x509_crt_get_dn(cert, dn, &size);
+ printf("\tDN: %s\n", dn);
+
+ size = sizeof(dn);
+ gnutls_x509_crt_get_issuer_dn(cert, dn, &size);
+ printf("\tIssuer's DN: %s\n", dn);
+}
+#endif
+#endif
+
void cs_print_session_info(COMSTACK cs)
{
#if HAVE_GNUTLS_H
struct tcpip_state *sp = (struct tcpip_state *) cs->cprivate;
- if (sp->session)
+ if (cs->type == ssl_type && sp->session)
{
+ const gnutls_datum_t *cert_list;
+ unsigned i, cert_list_size;
if (gnutls_certificate_type_get(sp->session) != GNUTLS_CRT_X509)
return;
printf("X509 certificate\n");
+ cert_list = gnutls_certificate_get_peers(sp->session,
+ &cert_list_size);
+ printf("Peer provided %u certificates\n", cert_list_size);
+ for (i = 0; i < cert_list_size; i++)
+ {
+ gnutls_x509_crt_t cert;
+#if USE_GNUTLS_X509_CRT_PRINT
+ int ret;
+ gnutls_datum_t cinfo;
+#endif
+ gnutls_x509_crt_init(&cert);
+ gnutls_x509_crt_import(cert, &cert_list[i], GNUTLS_X509_FMT_DER);
+ printf("Certificate info %d:\n", i + 1);
+#if USE_GNUTLS_X509_CRT_PRINT
+ ret = gnutls_x509_crt_print(cert, GNUTLS_CRT_PRINT_FULL,
+ &cinfo);
+ if (ret == 0)
+ {
+ printf("\t%s\n", cinfo.data);
+ gnutls_free(cinfo.data);
+ }
+#else
+ x509_crt_print(cert);
+#endif
+ gnutls_x509_crt_deinit(cert);
+
+ }
}
#elif HAVE_OPENSSL_SSL_H
- struct tcpip_state *sp = (struct tcpip_state *) cs->cprivate;
- SSL *ssl = (SSL *) sp->ssl;
- if (ssl)
+ if (cs->type == ssl_type)
{
- X509 *server_cert = SSL_get_peer_certificate(ssl);
-
- if (server_cert)
+ struct tcpip_state *sp = (struct tcpip_state *) cs->cprivate;
+ SSL *ssl = (SSL *) sp->ssl;
+ if (ssl)
{
- char *pem_buf;
- int pem_len;
- BIO *bio = BIO_new(BIO_s_mem());
+ X509 *server_cert = SSL_get_peer_certificate(ssl);
+ if (server_cert)
+ {
+ char *pem_buf;
+ int pem_len;
+ BIO *bio = BIO_new(BIO_s_mem());
- /* get PEM buffer in memory */
- PEM_write_bio_X509(bio, server_cert);
- pem_len = BIO_get_mem_data(bio, &pem_buf);
- fwrite(pem_buf, pem_len, 1, stdout);
+ /* get PEM buffer in memory */
+ PEM_write_bio_X509(bio, server_cert);
+ pem_len = BIO_get_mem_data(bio, &pem_buf);
+ fwrite(pem_buf, pem_len, 1, stdout);
- /* print all info on screen .. */
- X509_print_fp(stdout, server_cert);
- BIO_free(bio);
+ /* print all info on screen .. */
+ X509_print_fp(stdout, server_cert);
+ BIO_free(bio);
- X509_free(server_cert);
+ X509_free(server_cert);
+ }
}
}
#endif
if (cs && cs->type == ssl_type)
{
struct tcpip_state *sp = (struct tcpip_state *) cs->cprivate;
- return sp->ssl;
+ return sp->ssl;
}
#endif
return 0;
struct tcpip_state *state = (struct tcpip_state *)h->cprivate;
int r;
- r = tcpip_get(h, &state->connect_response_buf,
+ r = tcpip_get(h, &state->connect_response_buf,
&state->connect_response_len);
if (r < 1)
return r;