diff options
Diffstat (limited to 'src/tls.c')
-rw-r--r-- | src/tls.c | 165 |
1 files changed, 165 insertions, 0 deletions
diff --git a/src/tls.c b/src/tls.c new file mode 100644 index 0000000..6b81bd3 --- /dev/null +++ b/src/tls.c @@ -0,0 +1,165 @@ +#include <fcntl.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "tcp.h" +#include "tls.h" + +int sd = 0; +gnutls_session_t session; +gnutls_certificate_credentials_t xcred; + +void tls_init(void) +{ + gnutls_global_init(); + gnutls_certificate_allocate_credentials(&xcred); + //gnutls_certificate_set_x509_trust_file(xcred, cafile, GNUTLS_X509_FMT_PEM); + //gnutls_certificate_set_verify_function(xcred, _verify_certificate_callback); + //gnutls_certificate_set_x509_key_file (xcred, "cert.pem", "key.pem", GNUTLS_X509_FMT_PEM); + gnutls_init(&session, GNUTLS_CLIENT); + + // Only usefull if accessing a virtual hosting server + //gnutls_session_set_ptr(session, (void *) "my_host_name"); + //gnutls_server_name_set(session, GNUTLS_NAME_DNS, "my_host_name", strlen("my_host_name")); + + gnutls_set_default_priority(session); + gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, xcred); +} + +int tls_connect(const char* const host, const unsigned short port) +{ + int ret; + sd = tcp_connect(host, port); + if (sd < 0) { + tls_clean(); + exit(101); + } + + gnutls_transport_set_int(session, sd); + gnutls_handshake_set_timeout(session, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT); + + /* Perform the TLS handshake */ + do { + ret = gnutls_handshake(session); + } + while (ret < 0 && gnutls_error_is_fatal(ret) == 0); + + if (ret < 0) { + fprintf(stderr, "TLS Handshake failed\n"); + gnutls_perror(ret); + tls_clean(); + exit(102); + } else { + char *desc; + + desc = gnutls_session_get_desc(session); + printf("# TLS Session info: %s\n", desc); + gnutls_free(desc); + } + + int sf = fcntl (sd, F_GETFL, 0); + if (sf == -1) { + perror("fcntl get"); + return -1; + } + fcntl(sd, F_SETFL, sf | O_NONBLOCK); + if (sf == -1) { + perror("fcntl set"); + return -1; + } + + return sd; +} + +int tls_read(int (*input_handler_callback)(const char* const sbuf, const int len)) +{ + char sbuf[512]; /* string buffer */ + int len = 0; /* len read from the server */ + len = gnutls_record_recv(session, sbuf, sizeof(sbuf)); + if (len == 0) { + printf("Server has closed the TLS connection\n"); + tls_clean(); + return 1; + } else if (len < 0 && gnutls_error_is_fatal(len) == 0) { + fprintf(stderr, "*** Warning: %s\n", gnutls_strerror(len)); + return 3; + } else if (len < 0) { + fprintf(stderr, "*** Error: %s\n", gnutls_strerror(len)); + tls_clean(); + return 2; + } else { + if (input_handler_callback(sbuf, len) != 0) { + return 0; + } + } + return 4; +} + +void tls_send(char *buf, int len) +{ + gnutls_record_send(session, buf, len); +} + +void tls_close(void) { + gnutls_bye(session, GNUTLS_SHUT_RDWR); + tls_clean(); +} + +void tls_clean(void) +{ + tcp_close(sd); + gnutls_deinit(session); + gnutls_certificate_free_credentials(xcred); + gnutls_global_deinit(); +} + +/* This function will verify the peer's certificate, and check + * if the hostname matches, as well as the activation, expiration dates. */ +//static int _verify_certificate_callback(gnutls_session_t session) +//{ +// unsigned int status; +// int ret, type; +// const char *hostname; +// gnutls_datum_t out; +// +// /* read hostname */ +// hostname = gnutls_session_get_ptr(session); +// +// /* This verification function uses the trusted CAs in the credentials +// * structure. So you must have installed one or more CA certificates. */ +// gnutls_typed_vdata_st data[2]; +// +// memset(data, 0, sizeof(data)); +// +// data[0].type = GNUTLS_DT_DNS_HOSTNAME; +// data[0].data = (void*)hostname; +// +// data[1].type = GNUTLS_DT_KEY_PURPOSE_OID; +// data[1].data = (void*)GNUTLS_KP_TLS_WWW_SERVER; +// +// ret = gnutls_certificate_verify_peers(session, data, 2, &status); +// if (ret < 0) { +// printf("Error\n"); +// return GNUTLS_E_CERTIFICATE_ERROR; +// } +// +// type = gnutls_certificate_type_get(session); +// +// ret = gnutls_certificate_verification_status_print(status, type, &out, 0); +// if (ret < 0) { +// printf("Error\n"); +// return GNUTLS_E_CERTIFICATE_ERROR; +// } +// +// printf("%s", out.data); +// +// gnutls_free(out.data); +// +// if (status != 0) /* Certificate is not trusted */ +// return GNUTLS_E_CERTIFICATE_ERROR; +// +// /* notify gnutls to continue handshake normally */ +// return 0; +//} |