initialization and connection related funcs has been added;
This commit is contained in:
parent
d176ce7b9a
commit
f6e850b8f2
164
src/tls.c
164
src/tls.c
@ -19,6 +19,170 @@
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/select.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…
x
Reference in New Issue
Block a user