|
|
@ -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;
|
|
|
|
|
|
|
|
}
|
|
|
|