initialization and connection related funcs has been added;

master
Alexander Vdolainen 4 years ago
parent d176ce7b9a
commit f6e850b8f2

@ -19,6 +19,170 @@
*/ */
#include <stdio.h> #include <stdio.h>
#include <stdlib.h>
#include <stdint.h> #include <stdint.h>
#include <unistd.h> #include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/select.h>
#include <errno.h> #include <errno.h>
#include <netdb.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <tlsport.h>
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;
}

Loading…
Cancel
Save