From 9b6930990d3fb6251033570dbb5da247f8b3cad2 Mon Sep 17 00:00:00 2001 From: ketmar Date: Tue, 27 Jul 2021 03:37:27 +0000 Subject: [PATCH] it is now possible to build Syren with GnuTLS (and GnuTLS will be used by default if found) FossilOrigin-Name: bd5d0cea319054fa7cb18de021a2b4f35e8e7ef3b5f20c825c2e6e3beda97495 --- Jamrules | 1 + Jamrules.configure | 6 +- src/Jamfile | 4 +- src/sylib/syren_dloader.c | 2 +- src/sylib/syren_tcp.c | 186 ++++++++++++++++++++++++++++++++++++++++------ src/sylib/syren_tcp.h | 5 +- src/syren/Jamfile | 10 ++- 7 files changed, 185 insertions(+), 29 deletions(-) diff --git a/Jamrules b/Jamrules index 3a85e88..b010d03 100644 --- a/Jamrules +++ b/Jamrules @@ -38,6 +38,7 @@ DEFINES += _FILE_OFFSET_BITS=64 ; if $(USE_HTTPS) { DEFINES += SYOPT_ALLOW_HTTPS ; } +if $(USE_GNUTLS) { DEFINES += SY_USE_GNUTLS ; } softinclude $(TOP)/Jamrules.local ; diff --git a/Jamrules.configure b/Jamrules.configure index 58b07fa..e8f9670 100644 --- a/Jamrules.configure +++ b/Jamrules.configure @@ -4,7 +4,8 @@ PROJECT_NAME = syren ; # "": disabled by default, show '--enable-xxx' # non-empty string: enabled by default, show '--disable-xxx' -configure-enable-disable-vars- += - "https" USE_HTTPS "tan" "disable HTTPS support" + "https" USE_HTTPS "tan" "disable HTTPS support" + "gnutls" USE_GNUTLS "auto" "use GnuTLS instead of built-in PolarSSL fork" ; @@ -18,6 +19,9 @@ rule -configure-options-install-man- { INSTALL_MAN = tan ; } rule -configure- { + if $(USE_HTTPS) = "ona" { USE_GNUTLS = "ona" ; } + -configure-pkg-config-var- USE_GNUTLS : "GnuTLS" : "gnutls" : "USE_GNUTLS = tan ;" : "USE_GNUTLS = ;" ; + -configure-add-line- "USE_HTTPS =" "$(USE_HTTPS)" ";" ; -configure-add-line- "INSTALL_MAN =" "$(INSTALL_MAN)" ";" ; } diff --git a/src/Jamfile b/src/Jamfile index c1f5117..4ffd81c 100644 --- a/src/Jamfile +++ b/src/Jamfile @@ -1,6 +1,8 @@ SubDir TOP src ; -SubInclude TOP src libpolarssl ; +if ! $(USE_GNUTLS) && ! $(NO_HTTPS) { + SubInclude TOP src libpolarssl ; +} SubInclude TOP src sylib ; SubInclude TOP src syren ; diff --git a/src/sylib/syren_dloader.c b/src/sylib/syren_dloader.c index 4eacbcc..5535c47 100644 --- a/src/sylib/syren_dloader.c +++ b/src/sylib/syren_dloader.c @@ -372,7 +372,7 @@ TSyResult SyBegin (TSyState *state) { SY_CHECK_BREAK0 } if (url->proto == SY_PROTO_HTTPS) { - if (SyTCPInitSSL(&state->fd, state->ioTimeout) != SY_OK) break; + if (SyTCPInitSSL(&state->fd, url->host, state->ioTimeout, state->pfn) != SY_OK) break; } #endif diff --git a/src/sylib/syren_tcp.c b/src/sylib/syren_tcp.c index ba7610d..b837de5 100644 --- a/src/sylib/syren_tcp.c +++ b/src/sylib/syren_tcp.c @@ -41,9 +41,44 @@ #ifdef SYOPT_ALLOW_HTTPS -#include "libpolarssl/ssl.h" -#include "libpolarssl/entropy.h" -#include "libpolarssl/ctr_drbg.h" +#ifdef SY_USE_GNUTLS +# include +# include + +#define SSL_MAX_CONTENT_LEN (32768) +static int gnutlsInited = 0; + + +typedef struct { + gnutls_certificate_credentials_t xcred; + gnutls_session_t session; + //int handshakeComplete; +} TSySSLInfo; + +static int SyTCP_SSLSend (TSySSLInfo *si, const void *buf, size_t len) { + if (len < 1) return 0; + for (;;) { + int res = (int)gnutls_record_send(si->session, buf, len); + //if (res < 0) fprintf(stderr, "GnuTLS: error sending %d bytes (%d) :%s\n", (int)len, res, gnutls_strerror(res)); + //if (res != GNUTLS_E_INTERRUPTED && res != GNUTLS_E_AGAIN) return res; + if (res >= 0 || gnutls_error_is_fatal(res)) return res; + } +} + +static int SyTCP_SSLRecv (TSySSLInfo *si, void *buf, size_t len) { + if (len < 1) return 0; + for (;;) { + int res = (int)gnutls_record_recv(si->session, buf, len); + //if (res < 0) fprintf(stderr, "GnuTLS: error receiving %d bytes (%d) (fatal=%d) :%s\n", (int)len, res, gnutls_error_is_fatal(res), gnutls_strerror(res)); + //if (res != GNUTLS_E_INTERRUPTED && res != GNUTLS_E_AGAIN) return res; + if (res >= 0 || gnutls_error_is_fatal(res)) return res; + } +} + +#else +# include "libpolarssl/ssl.h" +# include "libpolarssl/entropy.h" +# include "libpolarssl/ctr_drbg.h" typedef struct { //havege_state hs; @@ -77,6 +112,8 @@ static int SyTCP_SSLRecv (void *sock, unsigned char *buf, size_t len) { if (!res) res = -666; return res; } +#endif /* polarssl */ + #endif @@ -161,19 +198,85 @@ TSyResult SyTCPInitSocket (TSySocket *fd) { #ifdef SYOPT_ALLOW_HTTPS -TSyResult SyTCPInitSSL (TSySocket *fd, int timeout) { +TSyResult SyTCPInitSSL (TSySocket *fd, const char *hostname, int timeout, const TSyPrintStr *pfn) { TSySSLInfo *si; - static const char *pers0 = "fuckme"; - //static const char *pers1 = "fuckhim"; fd->errCode = 0; if (fd->fd < 0) return SY_ERROR; if (fd->usessl) return SY_ERROR; + if (!fd->sslinfo) { fd->sslinfo = calloc(1, sizeof(TSySSLInfo)); if (!fd->sslinfo) return SY_ERROR; } si = fd->sslinfo; + +#ifdef SY_USE_GNUTLS + if (!gnutlsInited) { + if (gnutls_global_init() < 0) return SY_ERROR; + gnutlsInited = 1; + } + + if (gnutls_certificate_allocate_credentials(&si->xcred) < 0) return SY_ERROR; + + // initialize TLS session + if (gnutls_init(&si->session, GNUTLS_CLIENT) < 0) { + gnutls_certificate_free_credentials(si->xcred); + return SY_ERROR; + } + + fd->usessl = 1; + + #if 0 + const char *err = NULL; + //if (gnutls_priority_set_direct(si->session, "PERFORMANCE", &err) < 0) return SY_ERROR; + if (gnutls_priority_set_direct(si->session, "SECURE256", &err) < 0) return SY_ERROR; + #else + if (gnutls_set_default_priority(si->session) < 0) return SY_ERROR; + gnutls_session_enable_compatibility_mode(si->session); + #endif + + if (hostname) { + int res = gnutls_server_name_set(si->session, GNUTLS_NAME_DNS, hostname, strlen(hostname)); + if (res < 0) { + SyMessage(pfn, SY_MSG_ERROR, " GnuTLS error (while setting hostname '%s') %d: %s", res, hostname, gnutls_strerror(res)); + return SY_ERROR; + } + } + + // put the x509 credentials to the current session + if (gnutls_credentials_set(si->session, GNUTLS_CRD_CERTIFICATE, si->xcred) < 0) return SY_ERROR; + + // pass the socket handle off to gnutls + gnutls_transport_set_int(si->session, fd->fd); + + gnutls_handshake_set_timeout(si->session, (timeout < 0 ? GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT : timeout*1000)); + + // perform the TLS handshake + for (;;) { + int res = gnutls_handshake(si->session); + //fprintf(stderr, "...handshacking: res=%d (%d) (to=%d)\n", res, gnutls_error_is_fatal(res), timeout); + if (res >= 0) break; + if (gnutls_error_is_fatal(res)) { + SyMessage(pfn, SY_MSG_ERROR, " GnuTLS error %d: %s", res, gnutls_strerror(res)); + if (res == GNUTLS_E_WARNING_ALERT_RECEIVED || res == GNUTLS_E_FATAL_ALERT_RECEIVED) { + gnutls_alert_description_t alt = gnutls_alert_get(si->session); + const char *astr = gnutls_alert_get_name(alt); + SyMessage(pfn, SY_MSG_ERROR, " GnuTLS alert: %s", astr); + } + return SY_ERROR; + } + } + + { + char *desc = gnutls_session_get_desc(si->session); + SyMessage(pfn, SY_MSG_NOTICE, " GnuTLS session info: %s", desc); + gnutls_free(desc); + } +#else + const char *pers0 = "fuckme"; + //static const char *pers1 = "fuckhim"; + //havege_init(&(si->hs)); memset(&(si->ssn), 0, sizeof(ssl_session)); @@ -194,6 +297,7 @@ TSyResult SyTCPInitSSL (TSySocket *fd, int timeout) { //ssl_set_ciphers(&(si->ssl), ssl_default_ciphers); //ssl_set_session(&(si->ssl), 1, timeout, &(si->ssn)); +#endif fd->usessl = 1; return SY_OK; @@ -202,20 +306,27 @@ TSyResult SyTCPInitSSL (TSySocket *fd, int timeout) { TSyResult SyTCPCloseSocket (TSySocket *fd) { -#ifdef SYOPT_ALLOW_HTTPS - TSySSLInfo *si; -#endif - if (fd->fd >= 0) { #ifdef SYOPT_ALLOW_HTTPS if (fd->usessl && fd->sslinfo) { - si = fd->sslinfo; + TSySSLInfo *si = fd->sslinfo; + #ifdef SY_USE_GNUTLS + if (fd->usessl) { + gnutls_deinit(si->session); + gnutls_certificate_free_credentials(si->xcred); + } + #else if (fd->usessl > 1) ssl_close_notify(&(si->ssl)); ssl_free(&(si->ssl)); memset(&(si->ssl), 0, sizeof(si->ssl)); - fd->usessl = 0; + #endif + } + fd->usessl = 0; + if (fd->sslinfo) { + memset(fd->sslinfo, 0, sizeof(TSySSLInfo)); + free(fd->sslinfo); + fd->sslinfo = NULL; } - if (fd->sslinfo) free(fd->sslinfo); #endif SySocketClose(fd->fd); fd->fd = -1; @@ -302,6 +413,7 @@ TSyResult SyTCPConnect (TSySocket *fd, char *hostname, int port, const char *ifa } + TSyResult SyTCPSend (TSySocket *fd, const void *buf, int bufSize) { const char *c = (char *)buf; @@ -311,13 +423,21 @@ TSyResult SyTCPSend (TSySocket *fd, const void *buf, int bufSize) { #ifdef SYOPT_ALLOW_HTTPS int wr, tosend; if (fd->usessl) { - tosend = bufSize>SSL_MAX_CONTENT_LEN?SSL_MAX_CONTENT_LEN:bufSize; + tosend = (bufSize > SSL_MAX_CONTENT_LEN ? SSL_MAX_CONTENT_LEN : bufSize); + #ifdef SY_USE_GNUTLS + wr = SyTCP_SSLSend((TSySSLInfo *)fd->sslinfo, buf, tosend); + #else wr = ssl_write(&(((TSySSLInfo *)fd->sslinfo)->ssl), (void *)buf, tosend); if (wr == -666) wr = 0; if (wr != POLARSSL_ERR_NET_WANT_WRITE) { if (wr >= 0) fd->usessl = 2; - } else wr = -1; - } else wr = send(fd->fd, c, bufSize, SY_SOCK_MSG_NO_SIGNAL); + } else { + wr = -1; + } + #endif + } else { + wr = send(fd->fd, c, bufSize, SY_SOCK_MSG_NO_SIGNAL); + } #else int wr = send(fd->fd, c, bufSize, SY_SOCK_MSG_NO_SIGNAL); #endif @@ -350,15 +470,23 @@ int SyTCPReceiveEx (TSySocket *fd, void *buf, int bufSize, int allowPartial) { #ifdef SYOPT_ALLOW_HTTPS int rd, toread; if (fd->usessl) { - toread = bufSize>SSL_MAX_CONTENT_LEN?SSL_MAX_CONTENT_LEN:bufSize; + toread = (bufSize > SSL_MAX_CONTENT_LEN ? SSL_MAX_CONTENT_LEN : bufSize); /*fprintf(stderr, "\r*** reading: %i \n", toread);*/ + #ifdef SY_USE_GNUTLS + rd = SyTCP_SSLRecv((TSySSLInfo *)fd->sslinfo, buf, toread); + #else rd = ssl_read(&(((TSySSLInfo *)fd->sslinfo)->ssl), buf, toread); /*fprintf(stderr, "\r*** rd=%i \n", rd);*/ if (rd == -666) rd = 0; if (rd != POLARSSL_ERR_NET_WANT_READ) { if (rd >= 0) fd->usessl = 2; - } else rd = -1; - } else rd = recv(fd->fd, c, bufSize, 0); + } else { + rd = -1; + } + #endif + } else { + rd = recv(fd->fd, c, bufSize, 0); + } #else int rd = recv(fd->fd, c, bufSize, 0); #endif @@ -425,15 +553,23 @@ char *SyTCPReceiveStrEx (TSySocket *fd, int maxSize, char *dest) { rcv = 1; #ifdef SYOPT_ALLOW_HTTPS if (fd->usessl) { + #ifdef SY_USE_GNUTLS + rd = SyTCP_SSLRecv((TSySSLInfo *)fd->sslinfo, d, 1); + #else rd = ssl_read(&(((TSySSLInfo *)fd->sslinfo)->ssl), (void *)d, 1); if (rd == -666) rd = 0; if (rd != POLARSSL_ERR_NET_WANT_READ) { if (rd >= 0) fd->usessl = 2; - } else rd = -1; + } else { + rd = -1; + } + #endif } else #endif rd = recv(fd->fd, d, 1, 0); - } else rcv = 0; + } else { + rcv = 0; + } if (rd <= 0) fd->errCode = SyTCPLastError(); if (rd < 0) return NULL; if (rd == 0) break; /* connection closed */ @@ -502,11 +638,17 @@ char *SyTCPReceiveHdrs (TSySocket *fd, int maxSize) { rcv = 1; #ifdef SYOPT_ALLOW_HTTPS if (fd->usessl) { + #ifdef SY_USE_GNUTLS + rd = SyTCP_SSLRecv((TSySSLInfo *)fd->sslinfo, d, 1); + #else rd = ssl_read(&(((TSySSLInfo *)fd->sslinfo)->ssl), (void *)d, 1); if (rd == -666) rd = 0; if (rd != POLARSSL_ERR_NET_WANT_READ) { if (rd >= 0) fd->usessl = 2; - } else rd = -1; + } else { + rd = -1; + } + #endif } else #endif rd = recv(fd->fd, d, 1, 0); diff --git a/src/sylib/syren_tcp.h b/src/sylib/syren_tcp.h index dfd23a8..ed173ec 100644 --- a/src/sylib/syren_tcp.h +++ b/src/sylib/syren_tcp.h @@ -58,11 +58,12 @@ TSyResult SyGetIFIP (char *ip, const char *iface); /* initialize socket */ TSyResult SyTCPInitSocket (TSySocket *fd); #ifdef SYOPT_ALLOW_HTTPS -TSyResult SyTCPInitSSL (TSySocket *fd, int timeout); +/* timeout in seconds */ +TSyResult SyTCPInitSSL (TSySocket *fd, const char *hostname, int timeout, const TSyPrintStr *pfn); #endif TSyResult SyTCPCloseSocket (TSySocket *fd); -/* create a TCP connection; fd must not be initialized */ +/* create a TCP connection; fd must not be initialized; timeout in seconds */ TSyResult SyTCPConnect (TSySocket *fd, char *hostname, int port, const char *iface, int timeout, const TSyPrintStr *pfn); TSyResult SyTCPSend (TSySocket *fd, const void *buf, int bufSize); TSyResult SyTCPSendStr (TSySocket *fd, const char *str); diff --git a/src/syren/Jamfile b/src/syren/Jamfile index 4dac521..f7dd6c7 100644 --- a/src/syren/Jamfile +++ b/src/syren/Jamfile @@ -3,7 +3,11 @@ SubDir TOP src syren ; if $(NO_HTTPS) { libpolarssl = ; } else { - libpolarssl = libpolarssl.a ; + if ! $(USE_GNUTLS) { + libpolarssl = libpolarssl.a ; + } else { + libpolarssl = ; + } } Main syren : syren.c syren_script.c ; @@ -11,5 +15,7 @@ LinkLibraries syren : libsyrendl.a $(libpolarssl) ; LINKLIBS on syren += -lm ; -SubInclude TOP src libpolarssl ; +if ! $(USE_GNUTLS) && ! $(NO_HTTPS) { + SubInclude TOP src libpolarssl ; +} SubInclude TOP src sylib ; -- 2.11.4.GIT