From f6e850b8f21abc35f0ab6615831db1562c64b42e Mon Sep 17 00:00:00 2001 From: Alexander Vdolainen Date: Thu, 18 Mar 2021 21:25:12 +0200 Subject: [PATCH] initialization and connection related funcs has been added; --- src/tls.c | 164 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 164 insertions(+) diff --git a/src/tls.c b/src/tls.c index 1dccf90..b015b8a 100644 --- a/src/tls.c +++ b/src/tls.c @@ -19,6 +19,170 @@ */ #include +#include #include #include +#include +#include +#include +#include #include +#include +#include +#include + +#include + +int ssllib_init(void) +{ + /* init the ssl library internl stuff */ + SSL_load_error_strings(); + SSL_library_init(); + + return 0; +} + +int ssllib_free(void) +{ + ERR_free_strings(); + + EVP_cleanup(); + return 0; +} + +int tls_connect(const char *hostname, const char *service, struct tlsport *p) +{ + struct addrinfo *host = NULL, *rh = NULL; + struct addrinfo hint; + int r = 0, sock, sel_read = 0, sel_write = 0; + SSL_CTX *sslctx; + SSL *sslc; + fd_set readfd, writefd; + + /* get host by hostname first */ + /* set hints for search */ + memset(&hint, 0, sizeof(struct addrinfo)); + hint.ai_family = AF_UNSPEC; /* ipv4 and ipv6 support from the first step */ + hint.ai_socktype = SOCK_STREAM; + r = getaddrinfo(hostname, service, &hint, &host); + if(r) return -1; /* TODO: error report */ + + for(rh = host; rh != NULL; rh = rh->ai_next) { + sock = socket(rh->ai_family, rh->ai_socktype, rh->ai_protocol); + if(sock == -1) continue; + if(connect(sock, rh->ai_addr, rh->ai_addrlen) != -1) break; /* got it */ + else close(sock); + } + + if(!rh) { + freeaddrinfo(host); + return -1; /* TODO: error report */ + } else freeaddrinfo(host); + + /* time to do a tls handshake */ + sslctx = SSL_CTX_new(SSLv23_client_method()); + if(!sslctx) { + ssllib_error0: + close(sock); + return -1; /* TODO: error report */ + } + /* disable old insecure SSLv3 */ + SSL_CTX_set_options(sslctx, SSL_OP_NO_SSLv3); + /* create a new ssl connection context */ + sslc = SSL_new(sslctx); + if(!sslc) { + ssllib_error1: + SSL_CTX_free(sslctx); /* TODO: error report */ + goto ssllib_error0; + } else { + SSL_set_fd(sslc, sock); + SSL_set_connect_state(sslc); /* tls connection is going from client */ + } + + ssllib_connect: + sel_read = sel_write = 0; + do { + r = SSL_connect(sslc); + switch(SSL_get_error(sslc, r)) { + case SSL_ERROR_NONE: + r = SSL_ERROR_NONE; /* connected! */ + p->fd = sock; + p->ssl = sslc; + p->sslctx = sslctx; + return 0; + break; + case SSL_ERROR_WANT_READ: + sel_read = 1; /* is required to wait during read */ break; + case SSL_ERROR_WANT_WRITE: + sel_write = 1; /* is required to wait during write */ break; + case SSL_ERROR_SYSCALL: + if(errno == EAGAIN || errno == EINTR) break; + case SSL_ERROR_SSL: + case SSL_ERROR_ZERO_RETURN: /* expected close */ + default: + SSL_free(sslc); /* TODO: error report */ + goto ssllib_error1; + break; + } + } while(SSL_pending(sslc) && !sel_read); + + /* wait to read */ + if(r != SSL_ERROR_NONE && sel_read) { + FD_ZERO(&readfd); + FD_SET(sock, &readfd); + + read_select: + r = select(sock + 1, &readfd, NULL, NULL, NULL); + if(r <= 0) { + if(errno == EAGAIN || errno == EINTR) goto read_select; + else goto ssllib_error2; + } else if(FD_ISSET(sock, &readfd)) goto ssllib_connect; + } + + /* wait to write */ + if(r != SSL_ERROR_NONE && sel_write) { + FD_ZERO(&readfd); + FD_ZERO(&writefd); + FD_SET(sock, &readfd); + FD_SET(sock, &writefd); + + r = select(sock + 1, &readfd, &writefd, NULL, NULL); + if(r && FD_ISSET(sock, &writefd)) goto ssllib_connect; + } + + ssllib_error2: + SSL_free(sslc); + SSL_CTX_free(sslctx); + close(sock); + + return -1; +} + +int tls_close(struct tlsport *p) +{ + int r, e = 0; + + do { + r = SSL_shutdown(p->ssl); + if(r == 1) break; + + switch(SSL_get_error(p->ssl, r)) { + case SSL_ERROR_WANT_READ: + case SSL_ERROR_WANT_WRITE: + break; + case SSL_ERROR_SYSCALL: + if(errno == EAGAIN || errno == EINTR) break; + case SSL_ERROR_SSL: + case SSL_ERROR_ZERO_RETURN: /* expected close */ + default: + e = -1; + break; + } + } while(SSL_pending(p->ssl) && !e); + + SSL_free(p->ssl); + SSL_CTX_free(p->sslctx); + close(p->fd); + + return e; +}