LCOV - code coverage report
Current view: top level - msus/webserver - sslops.c (source / functions) Hit Total Coverage
Test: unnamed Lines: 81 95 85.3 %
Date: 2018-01-11 Functions: 11 11 100.0 %

          Line data    Source code
       1             : /*
       2             : START OF LICENSE STUB
       3             :     DeDOS: Declarative Dispersion-Oriented Software
       4             :     Copyright (C) 2017 University of Pennsylvania, Georgetown University
       5             : 
       6             :     This program is free software: you can redistribute it and/or modify
       7             :     it under the terms of the GNU General Public License as published by
       8             :     the Free Software Foundation, either version 3 of the License, or
       9             :     (at your option) any later version.
      10             : 
      11             :     This program is distributed in the hope that it will be useful,
      12             :     but WITHOUT ANY WARRANTY; without even the implied warranty of
      13             :     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14             :     GNU General Public License for more details.
      15             : 
      16             :     You should have received a copy of the GNU General Public License
      17             :     along with this program.  If not, see <http://www.gnu.org/licenses/>.
      18             : END OF LICENSE STUB
      19             : */
      20             : #include "webserver/sslops.h"
      21             : #include "webserver/webserver.h"
      22             : #include "logging.h"
      23             : #include <pthread.h>
      24             : #include <openssl/err.h>
      25             : 
      26             : #ifdef __GNUC__
      27             : #define UNUSED __attribute__ ((unused))
      28             : #else 
      29             : #define UNUSED
      30             : #endif
      31             : 
      32             : //#define PRINT_REQUEST_ERRORS
      33             : 
      34             : #ifdef PRINT_REQUEST_ERRORS
      35             : #define print_request_error(fmt, ...)\
      36             :     log_error(fmt, ##__VA_ARGS__);
      37             : #else
      38             : #define print_request_error(...)
      39             : #endif
      40             : 
      41             : /**
      42             :  * Explains an SSL error. Written as a macro so we have traceability in the log_error statements
      43             :  */
      44             : //FIXME: calling ERR_get_error in the case SSL_ERROR_SSL breaks consistency of this function
      45             : // (which otherwise reads the stack and doesn't pop it)
      46             : #ifdef PRINT_REQUEST_ERRORS
      47             : #define print_ssl_error(ssl, rtn) { \
      48             :     int _err = SSL_get_error(ssl, rtn); \
      49             :     const char* UNUSED error_str = ERR_error_string(_err, NULL); \
      50             :     switch (_err) { \
      51             :         case SSL_ERROR_ZERO_RETURN: { \
      52             :             print_request_error("SSL_ERROR_ZERO_RETURN (%d): %s\n", _err, error_str); \
      53             :             break; \
      54             :         } \
      55             :         case SSL_ERROR_WANT_READ: { \
      56             :             print_request_error("SSL_ERROR_WANT_READ (%d): %s\n", _err, error_str);\
      57             :             break;\
      58             :         }\
      59             :         case SSL_ERROR_WANT_WRITE: {\
      60             :             print_request_error("SSL_ERROR_WANT_WRITE (%d): %s\n", _err, error_str);\
      61             :             break;\
      62             :         }\
      63             :         case SSL_ERROR_WANT_CONNECT: {\
      64             :             print_request_error("SSL_ERROR_WANT_CONNECT (%d): %s\n", _err, error_str);\
      65             :             break;\
      66             :         }\
      67             :         case SSL_ERROR_WANT_ACCEPT: {\
      68             :             print_request_error("SSL_ERROR_WANT_ACCEPT (%d): %s\n", _err, error_str);\
      69             :             break;\
      70             :         }\
      71             :         case SSL_ERROR_WANT_X509_LOOKUP: {\
      72             :             print_request_error("SSL_ERROR_WANT_X509_LOOKUP (%d): %s\n", _err, error_str);\
      73             :             break;\
      74             :         }\
      75             :         case SSL_ERROR_SYSCALL: {\
      76             :             print_request_error("SSL_ERROR_SYSCALL (%d): %s\n", _err, error_str);\
      77             :             break;\
      78             :         }\
      79             :         case SSL_ERROR_SSL: {\
      80             :             unsigned long UNUSED err2 = ERR_get_error(); \
      81             :             print_request_error("SSL_ERROR_SSL (%d, %lx): %s\n", _err, err2, error_str);\
      82             :             break;\
      83             :         }\
      84             :         default:\
      85             :             break;\
      86             :     }\
      87             : }
      88             : #else
      89             : #define print_ssl_error(ssl, rtn)
      90             : #endif
      91             : 
      92             : static pthread_mutex_t *lockarray;
      93             : 
      94     8751479 : static void crypto_locking_callback(int mode, int n,
      95             :         const char UNUSED *file, int UNUSED line) {
      96     8751479 :     if (mode & CRYPTO_LOCK) {
      97     4375655 :         pthread_mutex_lock(&(lockarray[n]));
      98             :     } else {
      99     4375824 :         pthread_mutex_unlock(&(lockarray[n]));
     100             :     }
     101     8751988 : }
     102             : 
     103      793132 : static unsigned long crypto_id_function(void) {
     104      793132 :     return (unsigned long)pthread_self();
     105             : }
     106             : 
     107         164 : void init_ssl_locks(void) {
     108             : #if defined(OPENSSL_THREADS)
     109             : #else
     110             :     log_error("no OPENSSL thread support!");
     111             : #endif
     112         164 :     lockarray = OPENSSL_malloc(CRYPTO_num_locks() * sizeof(*lockarray));
     113        6888 :     for (int i=0; i < CRYPTO_num_locks(); i++) {
     114        6724 :         pthread_mutex_init(&(lockarray[i]), NULL);
     115             :     }
     116         164 :     CRYPTO_set_id_callback(crypto_id_function);
     117         164 :     CRYPTO_set_locking_callback(crypto_locking_callback);
     118         164 : }
     119             : 
     120             : SSL_CTX *ssl_ctx = NULL;
     121             : 
     122          35 : void kill_ssl_locks(void) {
     123          35 :     CRYPTO_set_locking_callback(NULL);
     124        1470 :     for (int i=0; i<CRYPTO_num_locks(); i++) {
     125        1435 :         pthread_mutex_destroy(&(lockarray[i]));
     126             :     }
     127          35 :     if (ssl_ctx != NULL) {
     128          35 :         SSL_CTX_free(ssl_ctx);
     129          35 :         ssl_ctx = NULL;
     130             :     }
     131          35 : }
     132             : 
     133             : 
     134          40 : int init_ssl_context(void) {
     135          40 :     if (ssl_ctx != NULL) {
     136           0 :         log_warn("SSL context already initialized. Not initializing again.");
     137           0 :         return 1;
     138             :     }
     139             : 
     140          40 :     SSL_library_init();
     141          40 :     OpenSSL_add_all_algorithms();
     142          40 :     SSL_load_error_strings();
     143             : 
     144             :     /* Create new SSL context */
     145          40 :     const SSL_METHOD *method = TLSv1_2_server_method();
     146          40 :     ssl_ctx = SSL_CTX_new(method);
     147          40 :     SSL_CTX_set_session_cache_mode(ssl_ctx, SSL_SESS_CACHE_OFF);
     148          40 :     SSL_CTX_set_options(ssl_ctx, 
     149             :             SSL_OP_NO_SSLv3 | SSL_OP_NO_TICKET | SSL_OP_SINGLE_DH_USE);
     150             : 
     151          40 :     int rtn = SSL_CTX_set_cipher_list(ssl_ctx, "HIGH:!aNULL:!MD5:!RC4");
     152          40 :     if ( rtn <= 0 ) {
     153           0 :         log_error("Could not set cipger list for SSL context");
     154           0 :         return -1;
     155             :     }
     156             : 
     157          40 :     return 0;
     158             : }
     159             : 
     160          40 : int load_ssl_certificate(char *cert_file, char *key_file) {
     161             :     /* set the local certificate from CertFile */
     162          40 :     if ( SSL_CTX_use_certificate_chain_file(ssl_ctx, cert_file) <= 0 ) {
     163           0 :         return -1;
     164             :     }
     165             :     /* set the private key from KeyFile (may be the same as CertFile) */
     166          40 :     if ( SSL_CTX_use_PrivateKey_file(ssl_ctx, cert_file, SSL_FILETYPE_PEM) <= 0 ) {
     167           0 :         return -1;
     168             :     }
     169             :     /* verify private key */
     170          40 :     if ( !SSL_CTX_check_private_key(ssl_ctx) ) {
     171           0 :         return -1;
     172             :     }
     173          40 :     return 0;
     174             : }
     175             :  
     176         148 : SSL *init_ssl_connection(int fd) {
     177         148 :     SSL *ssl = SSL_new(ssl_ctx);
     178         148 :     SSL_set_fd(ssl, fd);
     179         148 :     return ssl;
     180             : }
     181             : 
     182             : #define CHECK_SSL_WANTS(ssl, rtn) \
     183             :     do { \
     184             :         int err = SSL_get_error(ssl, rtn); \
     185             :         if (err != SSL_ERROR_WANT_READ && err != SSL_ERROR_WANT_WRITE) { \
     186             :             print_ssl_error(ssl, rtn); \
     187             :             return WS_ERROR; \
     188             :         } else if ( err == SSL_ERROR_WANT_READ) { \
     189             :             return WS_INCOMPLETE_READ; \
     190             :         } else if ( err == SSL_ERROR_WANT_WRITE) { \
     191             :             return WS_INCOMPLETE_WRITE; \
     192             :         } \
     193             :     } while (0);
     194             : 
     195         294 : int accept_ssl(SSL *ssl) {
     196         294 :     ERR_clear_error();
     197         294 :     int rtn = SSL_accept(ssl);
     198         294 :     if (rtn == 0) {
     199           0 :         log_warn("The TLS/SSL handshake was not successful "
     200             :                  "but was shut down controlled and by the "
     201             :                  "specifications of the TLS/SSL protocol");
     202             :         print_ssl_error(ssl, rtn);
     203           0 :         return -1;
     204             :     }
     205         294 :     if (rtn < 0) {
     206         148 :         CHECK_SSL_WANTS(ssl, rtn);
     207             :     }
     208         146 :     return WS_COMPLETE;
     209             : }
     210             : 
     211         293 : int read_ssl(SSL *ssl, char *buf, int *buf_size) {
     212         293 :     ERR_clear_error();
     213         293 :     int num_bytes = SSL_read(ssl, buf, *buf_size);
     214         293 :     if (num_bytes > 0) {
     215         144 :         *buf_size = num_bytes;
     216         144 :         return WS_COMPLETE;
     217             :     } else {
     218         149 :         CHECK_SSL_WANTS(ssl, num_bytes);
     219             :     }
     220           0 :     log_warn("Shouldn't ever get here...");
     221           0 :     return WS_ERROR;
     222             : }
     223             : 
     224         281 : int write_ssl(SSL *ssl, char *buf, int *buf_size) {
     225         281 :     ERR_clear_error();
     226         281 :     int num_bytes = SSL_write(ssl, buf, *buf_size);
     227         281 :     if (num_bytes > 0) {
     228         280 :         if (num_bytes != *buf_size) {
     229           0 :             log_warn("Didn't write the requested amount (written: %d, requested: %d)...",
     230             :                      num_bytes, *buf_size);
     231             :         }
     232         280 :         *buf_size = num_bytes;
     233         280 :         return WS_COMPLETE;
     234             :     } else {
     235           1 :         CHECK_SSL_WANTS(ssl, num_bytes);
     236             :     }
     237           0 :     log_warn("Shouldn't ever get here...");
     238           0 :     return WS_ERROR;
     239             : }
     240             : 
     241         142 : int close_ssl(SSL *ssl) {
     242         142 :     ERR_clear_error();
     243         142 :     int rtn = SSL_get_shutdown(ssl);
     244         142 :     if (rtn >= 0) {
     245         142 :         rtn = SSL_shutdown(ssl);
     246         142 :         if (rtn == -1) {
     247           1 :             log(WS_ERROR, "Error shutting down SSL connection");
     248           1 :             SSL_free(ssl);
     249           1 :             return WS_ERROR;
     250             :         }
     251         141 :         if (rtn == 0) {
     252             :             //See the man page to understand this way of handling error on SSL_shutdown()
     253             :             //TODO: need too handle WANT_READ and WANT_WRITE on BOTH calls
     254             :             //see https://stackoverflow.com/questions/28056056/handling-ssl-shutdown-correctly
     255         141 :             rtn = SSL_shutdown(ssl);
     256         141 :             if (rtn == -1) {
     257             :         //        log_error("Error shutting down SSL connection");
     258         107 :                 SSL_free(ssl);
     259         107 :                 return WS_ERROR;
     260             :             }
     261             :         }
     262             :     }
     263             : 
     264          34 :     SSL_free(ssl);
     265          34 :     return WS_COMPLETE;
     266             : }

Generated by: LCOV version 1.10