4141
4242#include <stdbool.h>
4343#include <stdlib.h>
44+ #include <assert.h>
45+ #include <signal.h>
4446
4547#include <errno.h>
4648#include <netdb.h>
5759#include <stdio.h>
5860#include <strings.h>
5961
62+ #include <openssl/ssl.h>
63+ #include <openssl/err.h>
64+
6065/**
6166 * \brief Check that a pointer is not null. Otherwise returns #SISO_ERR
6267 * \param[in] ptr Pointer to check
7176 * \brief Get the lass error message
7277 */
7378#define PERROR_LAST strerror(errno)
79+ /**
80+ * @brief Get the last global OpenSSL error message
81+ */
82+ #define TLS_LAST_ERROR tls_code_error(ERR_get_error())
83+ /**
84+ * @brief Get the last OpenSSL error message for SSL connection.
85+ */
86+ #define TLS_LAST_SSL_ERROR (ssl , ret ) tls_code_error(SSL_get_error((ssl), (ret)))
7487/** Maximum message size that can be send over UDP */
7588#define SISO_UDP_MAX 65000
7689/**
@@ -86,6 +99,7 @@ enum siso_conn_type {
8699 SC_UDP ,
87100 SC_TCP ,
88101 SC_SCTP ,
102+ SC_TLS ,
89103 SC_UNKNOWN ,
90104};
91105
@@ -109,26 +123,32 @@ static const char *siso_messages[] = {
109123static const char * siso_sc_types [] = {
110124 [SC_UDP ] = "UDP" ,
111125 [SC_TCP ] = "TCP" ,
112- [SC_SCTP ] = "SCTP"
126+ [SC_SCTP ] = "SCTP" ,
127+ [SC_TLS ] = "TLS" ,
113128};
114129
130+ /** Buffer for error messages. */
131+ static char sisco_err_msg_buf [256 ] = { 0 };
132+
115133/**
116134 * \brief Main sisolib structure
117135 */
118136struct sisoconf_s {
119137 const char * last_error ; /**< last error message */
120- enum siso_conn_type type ; /**< UDP/TCP/SCTP */
138+ enum siso_conn_type type ; /**< UDP/TCP/SCTP/TLS */
121139 struct addrinfo * servinfo ; /**< server information */
122140 int sockfd ; /**< socket descriptor */
123141 uint64_t max_speed ; /**< max sending speed */
124142 uint64_t act_speed ; /**< actual speed */
125143 struct timeval begin , end ; /**< start/end time for limited transfers */
144+ SSL_CTX * ssl_ctx ; /**< context for creating TLS connecitons */
145+ SSL * ssl ; /**< TLS connection */
126146};
127147
128148/**
129149 * \brief Constructor
130150 */
131- sisoconf * siso_create ()
151+ sisoconf * siso_create (void )
132152{
133153 /* allocate memory */
134154 sisoconf * conf = (sisoconf * ) calloc (1 , sizeof (sisoconf ));
@@ -154,6 +174,11 @@ void siso_destroy(sisoconf *conf)
154174 freeaddrinfo (conf -> servinfo );
155175 }
156176
177+ if (conf -> ssl_ctx ) {
178+ SSL_CTX_free (conf -> ssl_ctx );
179+ conf -> ssl_ctx = NULL ;
180+ }
181+
157182 free (conf );
158183}
159184
@@ -256,6 +281,7 @@ int siso_getaddrinfo(sisoconf *conf, const char *ip, const char *port)
256281 hints .ai_socktype = SOCK_DGRAM ;
257282 hints .ai_protocol = IPPROTO_UDP ;
258283 break ;
284+ case SC_TLS :
259285 case SC_TCP :
260286 hints .ai_socktype = SOCK_STREAM ;
261287 hints .ai_protocol = IPPROTO_TCP ;
@@ -281,6 +307,115 @@ int siso_getaddrinfo(sisoconf *conf, const char *ip, const char *port)
281307 return SISO_OK ;
282308}
283309
310+ /**
311+ * @brief Get OpenSSL error message for the given code
312+ */
313+ static inline const char * tls_code_error (unsigned long code )
314+ {
315+ ERR_error_string_n (code , sisco_err_msg_buf , sizeof (sisco_err_msg_buf ));
316+ return & sisco_err_msg_buf [0 ];
317+ }
318+
319+ /**
320+ * @brief Get SSL_CTX. Initialize it if it is not initialized.
321+ * @return NULL on failure.
322+ */
323+ SSL_CTX * siso_get_ssl_ctx (sisoconf * conf )
324+ {
325+ if (conf -> ssl_ctx ) {
326+ return conf -> ssl_ctx ;
327+ }
328+
329+ SSL_load_error_strings ();
330+
331+ SSL_CTX * ctx = SSL_CTX_new (TLS_client_method ());
332+ if (!ctx ) {
333+ conf -> last_error = TLS_LAST_ERROR ;
334+ return NULL ;
335+ }
336+
337+ SSL_CTX_set_verify (ctx , SSL_VERIFY_PEER , NULL );
338+
339+ if (!SSL_CTX_set_default_verify_paths (ctx )) {
340+ conf -> last_error = TLS_LAST_ERROR ;
341+ SSL_CTX_free (ctx );
342+ return NULL ;
343+ }
344+
345+ if (!SSL_CTX_set_min_proto_version (ctx , TLS1_2_VERSION )) {
346+ conf -> last_error = TLS_LAST_ERROR ;
347+ SSL_CTX_free (ctx );
348+ return NULL ;
349+ }
350+
351+ SSL_CTX_set_mode (ctx , SSL_MODE_ENABLE_PARTIAL_WRITE );
352+
353+ // There is no way to pass MSG_SIGIGN when writing using OpenSSL without
354+ // creating custom BIO. So we can just ignore SIGPIPE which can occur if
355+ // peer closes the file descriptor.
356+ signal (SIGPIPE , SIG_IGN );
357+
358+ return conf -> ssl_ctx = ctx ;
359+ }
360+
361+ int siso_load_cert (sisoconf * conf , const char * cert_file ) {
362+ SSL_CTX * ctx = siso_get_ssl_ctx (conf );
363+
364+ if (SSL_CTX_use_certificate_chain_file (ctx , cert_file ) <= 0 ) {
365+ conf -> last_error = TLS_LAST_ERROR ;
366+ return SISO_ERR ;
367+ }
368+
369+ if (SSL_CTX_use_PrivateKey_file (ctx , cert_file , SSL_FILETYPE_PEM ) <= 0 ) {
370+ conf -> last_error = TLS_LAST_ERROR ;
371+ return SISO_ERR ;
372+ }
373+
374+ return SISO_OK ;
375+ }
376+
377+ int siso_tls_connect (sisoconf * conf , int new_fd )
378+ {
379+ assert (!conf -> ssl );
380+
381+ SSL_CTX * ctx = siso_get_ssl_ctx (conf );
382+ if (!ctx ) {
383+ return SISO_ERR ;
384+ }
385+
386+ SSL * ssl = SSL_new (ctx );
387+ if (!ssl ) {
388+ conf -> last_error = TLS_LAST_ERROR ;
389+ return SISO_ERR ;
390+ }
391+
392+ BIO * bio = BIO_new (BIO_s_socket ());
393+ if (!bio ) {
394+ conf -> last_error = TLS_LAST_ERROR ;
395+ SSL_free (ssl );
396+ return SISO_ERR ;
397+ }
398+
399+ BIO_set_fd (bio , new_fd , BIO_NOCLOSE );
400+ SSL_set_bio (ssl , bio , bio );
401+
402+ int res = SSL_connect (ssl );
403+ if (res <= 0 ) {
404+ // Get the best error message.
405+ long vres = SSL_get_verify_result (ssl );
406+ if (vres == X509_V_OK ) {
407+ conf -> last_error = TLS_LAST_SSL_ERROR (ssl , res );
408+ } else {
409+ conf -> last_error = X509_verify_cert_error_string (vres );
410+ }
411+ SSL_free (ssl );
412+ return SISO_ERR ;
413+ }
414+
415+ conf -> ssl = ssl ;
416+ return SISO_OK ;
417+ }
418+
284419/**
285420 * \brief Create new socket
286421 */
@@ -309,6 +444,11 @@ int siso_create_socket(sisoconf *conf)
309444 return SISO_ERR ;
310445 }
311446
447+ if (conf -> type == SC_TLS && siso_tls_connect (conf , new_fd ) != SISO_OK ) {
448+ close (new_fd );
449+ return SISO_ERR ;
450+ }
451+
312452 conf -> sockfd = new_fd ;
313453 return SISO_OK ;
314454}
@@ -345,7 +485,16 @@ int siso_create_connection(sisoconf* conf, const char* ip, const char *port, con
345485 */
346486void siso_close_connection (sisoconf * conf )
347487{
348- if (conf && conf -> sockfd > 0 ) {
488+ if (!conf ) {
489+ return ;
490+ }
491+
492+ if (conf -> ssl ) {
493+ SSL_free (conf -> ssl );
494+ conf -> ssl = NULL ;
495+ }
496+
497+ if (conf -> sockfd > 0 ) {
349498 close (conf -> sockfd );
350499 conf -> sockfd = -1 ;
351500 }
@@ -375,6 +524,7 @@ int siso_send(sisoconf *conf, const char *data, ssize_t length)
375524
376525 // data sent per cycle
377526 ssize_t sent_now = 0 ;
527+ int ret_code = 1 ;
378528
379529 // Size of remaining data
380530 ssize_t todo = length ;
@@ -390,12 +540,25 @@ int siso_send(sisoconf *conf, const char *data, ssize_t length)
390540 case SC_SCTP :
391541 sent_now = send (conf -> sockfd , ptr , todo , MSG_NOSIGNAL );
392542 break ;
543+ case SC_TLS :
544+ ret_code = SSL_write_ex (conf -> ssl , ptr , todo , (size_t * )& sent_now );
545+ break ;
393546 default :
394547 break ;
395548 }
396549
397550 // Check for errors
398- if (sent_now == -1 ) {
551+ if (ret_code <= 0 ) {
552+ int err_code = SSL_get_error (conf -> ssl , ret_code );
553+ if (err_code != SSL_ERROR_WANT_READ && err_code != SSL_ERROR_WANT_WRITE ) {
554+ // Connection is broken, close...
555+ conf -> last_error = tls_code_error (err_code );
556+ siso_close_connection (conf );
557+ return SISO_ERR ;
558+ }
559+
560+ // Don't use continue here, the write may be partial.
561+ } else if (sent_now == -1 ) {
399562 if (errno != EAGAIN && errno != EWOULDBLOCK ) {
400563 // Connection broken, close...
401564 conf -> last_error = PERROR_LAST ;
0 commit comments