1*ea16f64eSAntonio Huete Jimenez /* 2*ea16f64eSAntonio Huete Jimenez * Copyright (c) 2002 - 2003 3*ea16f64eSAntonio Huete Jimenez * NetGroup, Politecnico di Torino (Italy) 4*ea16f64eSAntonio Huete Jimenez * All rights reserved. 5*ea16f64eSAntonio Huete Jimenez * 6*ea16f64eSAntonio Huete Jimenez * Redistribution and use in source and binary forms, with or without 7*ea16f64eSAntonio Huete Jimenez * modification, are permitted provided that the following conditions 8*ea16f64eSAntonio Huete Jimenez * are met: 9*ea16f64eSAntonio Huete Jimenez * 10*ea16f64eSAntonio Huete Jimenez * 1. Redistributions of source code must retain the above copyright 11*ea16f64eSAntonio Huete Jimenez * notice, this list of conditions and the following disclaimer. 12*ea16f64eSAntonio Huete Jimenez * 2. Redistributions in binary form must reproduce the above copyright 13*ea16f64eSAntonio Huete Jimenez * notice, this list of conditions and the following disclaimer in the 14*ea16f64eSAntonio Huete Jimenez * documentation and/or other materials provided with the distribution. 15*ea16f64eSAntonio Huete Jimenez * 3. Neither the name of the Politecnico di Torino nor the names of its 16*ea16f64eSAntonio Huete Jimenez * contributors may be used to endorse or promote products derived from 17*ea16f64eSAntonio Huete Jimenez * this software without specific prior written permission. 18*ea16f64eSAntonio Huete Jimenez * 19*ea16f64eSAntonio Huete Jimenez * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20*ea16f64eSAntonio Huete Jimenez * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21*ea16f64eSAntonio Huete Jimenez * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22*ea16f64eSAntonio Huete Jimenez * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23*ea16f64eSAntonio Huete Jimenez * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24*ea16f64eSAntonio Huete Jimenez * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25*ea16f64eSAntonio Huete Jimenez * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26*ea16f64eSAntonio Huete Jimenez * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27*ea16f64eSAntonio Huete Jimenez * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28*ea16f64eSAntonio Huete Jimenez * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29*ea16f64eSAntonio Huete Jimenez * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30*ea16f64eSAntonio Huete Jimenez * 31*ea16f64eSAntonio Huete Jimenez */ 32*ea16f64eSAntonio Huete Jimenez 33*ea16f64eSAntonio Huete Jimenez #ifdef HAVE_CONFIG_H 34*ea16f64eSAntonio Huete Jimenez #include <config.h> 35*ea16f64eSAntonio Huete Jimenez #endif 36*ea16f64eSAntonio Huete Jimenez 37*ea16f64eSAntonio Huete Jimenez #ifdef HAVE_OPENSSL 38*ea16f64eSAntonio Huete Jimenez #include <stdlib.h> 39*ea16f64eSAntonio Huete Jimenez 40*ea16f64eSAntonio Huete Jimenez #include "portability.h" 41*ea16f64eSAntonio Huete Jimenez 42*ea16f64eSAntonio Huete Jimenez #include "sslutils.h" 43*ea16f64eSAntonio Huete Jimenez 44*ea16f64eSAntonio Huete Jimenez static const char *ssl_keyfile = ""; //!< file containing the private key in PEM format 45*ea16f64eSAntonio Huete Jimenez static const char *ssl_certfile = ""; //!< file containing the server's certificate in PEM format 46*ea16f64eSAntonio Huete Jimenez static const char *ssl_rootfile = ""; //!< file containing the list of CAs trusted by the client 47*ea16f64eSAntonio Huete Jimenez // TODO: a way to set ssl_rootfile from the command line, or an envvar? 48*ea16f64eSAntonio Huete Jimenez 49*ea16f64eSAntonio Huete Jimenez // TODO: lock? 50*ea16f64eSAntonio Huete Jimenez static SSL_CTX *ctx; 51*ea16f64eSAntonio Huete Jimenez 52*ea16f64eSAntonio Huete Jimenez void ssl_set_certfile(const char *certfile) 53*ea16f64eSAntonio Huete Jimenez { 54*ea16f64eSAntonio Huete Jimenez ssl_certfile = certfile; 55*ea16f64eSAntonio Huete Jimenez } 56*ea16f64eSAntonio Huete Jimenez 57*ea16f64eSAntonio Huete Jimenez void ssl_set_keyfile(const char *keyfile) 58*ea16f64eSAntonio Huete Jimenez { 59*ea16f64eSAntonio Huete Jimenez ssl_keyfile = keyfile; 60*ea16f64eSAntonio Huete Jimenez } 61*ea16f64eSAntonio Huete Jimenez 62*ea16f64eSAntonio Huete Jimenez int ssl_init_once(int is_server, int enable_compression, char *errbuf, size_t errbuflen) 63*ea16f64eSAntonio Huete Jimenez { 64*ea16f64eSAntonio Huete Jimenez static int inited = 0; 65*ea16f64eSAntonio Huete Jimenez if (inited) return 0; 66*ea16f64eSAntonio Huete Jimenez 67*ea16f64eSAntonio Huete Jimenez SSL_library_init(); 68*ea16f64eSAntonio Huete Jimenez SSL_load_error_strings(); 69*ea16f64eSAntonio Huete Jimenez OpenSSL_add_ssl_algorithms(); 70*ea16f64eSAntonio Huete Jimenez if (enable_compression) 71*ea16f64eSAntonio Huete Jimenez SSL_COMP_get_compression_methods(); 72*ea16f64eSAntonio Huete Jimenez 73*ea16f64eSAntonio Huete Jimenez SSL_METHOD const *meth = 74*ea16f64eSAntonio Huete Jimenez is_server ? SSLv23_server_method() : SSLv23_client_method(); 75*ea16f64eSAntonio Huete Jimenez ctx = SSL_CTX_new(meth); 76*ea16f64eSAntonio Huete Jimenez if (! ctx) 77*ea16f64eSAntonio Huete Jimenez { 78*ea16f64eSAntonio Huete Jimenez snprintf(errbuf, errbuflen, "Cannot get a new SSL context: %s", ERR_error_string(ERR_get_error(), NULL)); 79*ea16f64eSAntonio Huete Jimenez goto die; 80*ea16f64eSAntonio Huete Jimenez } 81*ea16f64eSAntonio Huete Jimenez 82*ea16f64eSAntonio Huete Jimenez SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY); 83*ea16f64eSAntonio Huete Jimenez 84*ea16f64eSAntonio Huete Jimenez if (is_server) 85*ea16f64eSAntonio Huete Jimenez { 86*ea16f64eSAntonio Huete Jimenez char const *certfile = ssl_certfile[0] ? ssl_certfile : "cert.pem"; 87*ea16f64eSAntonio Huete Jimenez if (1 != SSL_CTX_use_certificate_file(ctx, certfile, SSL_FILETYPE_PEM)) 88*ea16f64eSAntonio Huete Jimenez { 89*ea16f64eSAntonio Huete Jimenez snprintf(errbuf, errbuflen, "Cannot read certificate file %s: %s", certfile, ERR_error_string(ERR_get_error(), NULL)); 90*ea16f64eSAntonio Huete Jimenez goto die; 91*ea16f64eSAntonio Huete Jimenez } 92*ea16f64eSAntonio Huete Jimenez 93*ea16f64eSAntonio Huete Jimenez char const *keyfile = ssl_keyfile[0] ? ssl_keyfile : "key.pem"; 94*ea16f64eSAntonio Huete Jimenez if (1 != SSL_CTX_use_PrivateKey_file(ctx, keyfile, SSL_FILETYPE_PEM)) 95*ea16f64eSAntonio Huete Jimenez { 96*ea16f64eSAntonio Huete Jimenez snprintf(errbuf, errbuflen, "Cannot read private key file %s: %s", keyfile, ERR_error_string(ERR_get_error(), NULL)); 97*ea16f64eSAntonio Huete Jimenez goto die; 98*ea16f64eSAntonio Huete Jimenez } 99*ea16f64eSAntonio Huete Jimenez } 100*ea16f64eSAntonio Huete Jimenez else 101*ea16f64eSAntonio Huete Jimenez { 102*ea16f64eSAntonio Huete Jimenez if (ssl_rootfile[0]) 103*ea16f64eSAntonio Huete Jimenez { 104*ea16f64eSAntonio Huete Jimenez if (! SSL_CTX_load_verify_locations(ctx, ssl_rootfile, 0)) 105*ea16f64eSAntonio Huete Jimenez { 106*ea16f64eSAntonio Huete Jimenez snprintf(errbuf, errbuflen, "Cannot read CA list from %s", ssl_rootfile); 107*ea16f64eSAntonio Huete Jimenez goto die; 108*ea16f64eSAntonio Huete Jimenez } 109*ea16f64eSAntonio Huete Jimenez } 110*ea16f64eSAntonio Huete Jimenez else 111*ea16f64eSAntonio Huete Jimenez { 112*ea16f64eSAntonio Huete Jimenez SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL); 113*ea16f64eSAntonio Huete Jimenez } 114*ea16f64eSAntonio Huete Jimenez } 115*ea16f64eSAntonio Huete Jimenez 116*ea16f64eSAntonio Huete Jimenez #if 0 117*ea16f64eSAntonio Huete Jimenez if (! RAND_load_file(RANDOM, 1024*1024)) 118*ea16f64eSAntonio Huete Jimenez { 119*ea16f64eSAntonio Huete Jimenez snprintf(errbuf, errbuflen, "Cannot init random"); 120*ea16f64eSAntonio Huete Jimenez goto die; 121*ea16f64eSAntonio Huete Jimenez } 122*ea16f64eSAntonio Huete Jimenez 123*ea16f64eSAntonio Huete Jimenez if (is_server) 124*ea16f64eSAntonio Huete Jimenez { 125*ea16f64eSAntonio Huete Jimenez SSL_CTX_set_session_id_context(ctx, (void *)&s_server_session_id_context, sizeof(s_server_session_id_context)); 126*ea16f64eSAntonio Huete Jimenez } 127*ea16f64eSAntonio Huete Jimenez #endif 128*ea16f64eSAntonio Huete Jimenez 129*ea16f64eSAntonio Huete Jimenez inited = 1; 130*ea16f64eSAntonio Huete Jimenez return 0; 131*ea16f64eSAntonio Huete Jimenez 132*ea16f64eSAntonio Huete Jimenez die: 133*ea16f64eSAntonio Huete Jimenez return -1; 134*ea16f64eSAntonio Huete Jimenez } 135*ea16f64eSAntonio Huete Jimenez 136*ea16f64eSAntonio Huete Jimenez SSL *ssl_promotion(int is_server, SOCKET s, char *errbuf, size_t errbuflen) 137*ea16f64eSAntonio Huete Jimenez { 138*ea16f64eSAntonio Huete Jimenez if (ssl_init_once(is_server, 1, errbuf, errbuflen) < 0) { 139*ea16f64eSAntonio Huete Jimenez return NULL; 140*ea16f64eSAntonio Huete Jimenez } 141*ea16f64eSAntonio Huete Jimenez 142*ea16f64eSAntonio Huete Jimenez SSL *ssl = SSL_new(ctx); // TODO: also a DTLS context 143*ea16f64eSAntonio Huete Jimenez SSL_set_fd(ssl, (int)s); 144*ea16f64eSAntonio Huete Jimenez 145*ea16f64eSAntonio Huete Jimenez if (is_server) { 146*ea16f64eSAntonio Huete Jimenez if (SSL_accept(ssl) <= 0) { 147*ea16f64eSAntonio Huete Jimenez snprintf(errbuf, errbuflen, "SSL_accept(): %s", 148*ea16f64eSAntonio Huete Jimenez ERR_error_string(ERR_get_error(), NULL)); 149*ea16f64eSAntonio Huete Jimenez return NULL; 150*ea16f64eSAntonio Huete Jimenez } 151*ea16f64eSAntonio Huete Jimenez } else { 152*ea16f64eSAntonio Huete Jimenez if (SSL_connect(ssl) <= 0) { 153*ea16f64eSAntonio Huete Jimenez snprintf(errbuf, errbuflen, "SSL_connect(): %s", 154*ea16f64eSAntonio Huete Jimenez ERR_error_string(ERR_get_error(), NULL)); 155*ea16f64eSAntonio Huete Jimenez return NULL; 156*ea16f64eSAntonio Huete Jimenez } 157*ea16f64eSAntonio Huete Jimenez } 158*ea16f64eSAntonio Huete Jimenez 159*ea16f64eSAntonio Huete Jimenez return ssl; 160*ea16f64eSAntonio Huete Jimenez } 161*ea16f64eSAntonio Huete Jimenez 162*ea16f64eSAntonio Huete Jimenez // Finish using an SSL handle; shut down the connection and free the 163*ea16f64eSAntonio Huete Jimenez // handle. 164*ea16f64eSAntonio Huete Jimenez void ssl_finish(SSL *ssl) 165*ea16f64eSAntonio Huete Jimenez { 166*ea16f64eSAntonio Huete Jimenez // 167*ea16f64eSAntonio Huete Jimenez // We won't be using this again, so we can just send the 168*ea16f64eSAntonio Huete Jimenez // shutdown alert and free up the handle, and have our 169*ea16f64eSAntonio Huete Jimenez // caller close the socket. 170*ea16f64eSAntonio Huete Jimenez // 171*ea16f64eSAntonio Huete Jimenez // XXX - presumably, if the connection is shut down on 172*ea16f64eSAntonio Huete Jimenez // our side, either our peer won't have a problem sending 173*ea16f64eSAntonio Huete Jimenez // their shutdown alert or will not treat such a problem 174*ea16f64eSAntonio Huete Jimenez // as an error. If this causes errors to be reported, 175*ea16f64eSAntonio Huete Jimenez // fix that as appropriate. 176*ea16f64eSAntonio Huete Jimenez // 177*ea16f64eSAntonio Huete Jimenez SSL_shutdown(ssl); 178*ea16f64eSAntonio Huete Jimenez SSL_free(ssl); 179*ea16f64eSAntonio Huete Jimenez } 180*ea16f64eSAntonio Huete Jimenez 181*ea16f64eSAntonio Huete Jimenez // Same return value as sock_send: 182*ea16f64eSAntonio Huete Jimenez // 0 on OK, -1 on error but closed connection (-2). 183*ea16f64eSAntonio Huete Jimenez int ssl_send(SSL *ssl, char const *buffer, int size, char *errbuf, size_t errbuflen) 184*ea16f64eSAntonio Huete Jimenez { 185*ea16f64eSAntonio Huete Jimenez int status = SSL_write(ssl, buffer, size); 186*ea16f64eSAntonio Huete Jimenez if (status > 0) 187*ea16f64eSAntonio Huete Jimenez { 188*ea16f64eSAntonio Huete Jimenez // "SSL_write() will only return with success, when the complete contents (...) has been written." 189*ea16f64eSAntonio Huete Jimenez return 0; 190*ea16f64eSAntonio Huete Jimenez } 191*ea16f64eSAntonio Huete Jimenez else 192*ea16f64eSAntonio Huete Jimenez { 193*ea16f64eSAntonio Huete Jimenez int ssl_err = SSL_get_error(ssl, status); // TODO: does it pop the error? 194*ea16f64eSAntonio Huete Jimenez if (ssl_err == SSL_ERROR_ZERO_RETURN) 195*ea16f64eSAntonio Huete Jimenez { 196*ea16f64eSAntonio Huete Jimenez return -2; 197*ea16f64eSAntonio Huete Jimenez } 198*ea16f64eSAntonio Huete Jimenez else if (ssl_err == SSL_ERROR_SYSCALL) 199*ea16f64eSAntonio Huete Jimenez { 200*ea16f64eSAntonio Huete Jimenez #ifndef _WIN32 201*ea16f64eSAntonio Huete Jimenez if (errno == ECONNRESET || errno == EPIPE) return -2; 202*ea16f64eSAntonio Huete Jimenez #endif 203*ea16f64eSAntonio Huete Jimenez } 204*ea16f64eSAntonio Huete Jimenez snprintf(errbuf, errbuflen, "SSL_write(): %s", 205*ea16f64eSAntonio Huete Jimenez ERR_error_string(ERR_get_error(), NULL)); 206*ea16f64eSAntonio Huete Jimenez return -1; 207*ea16f64eSAntonio Huete Jimenez } 208*ea16f64eSAntonio Huete Jimenez } 209*ea16f64eSAntonio Huete Jimenez 210*ea16f64eSAntonio Huete Jimenez // Returns the number of bytes read, or -1 on syserror, or -2 on SSL error. 211*ea16f64eSAntonio Huete Jimenez int ssl_recv(SSL *ssl, char *buffer, int size, char *errbuf, size_t errbuflen) 212*ea16f64eSAntonio Huete Jimenez { 213*ea16f64eSAntonio Huete Jimenez int status = SSL_read(ssl, buffer, size); 214*ea16f64eSAntonio Huete Jimenez if (status <= 0) 215*ea16f64eSAntonio Huete Jimenez { 216*ea16f64eSAntonio Huete Jimenez int ssl_err = SSL_get_error(ssl, status); 217*ea16f64eSAntonio Huete Jimenez if (ssl_err == SSL_ERROR_ZERO_RETURN) 218*ea16f64eSAntonio Huete Jimenez { 219*ea16f64eSAntonio Huete Jimenez return 0; 220*ea16f64eSAntonio Huete Jimenez } 221*ea16f64eSAntonio Huete Jimenez else if (ssl_err == SSL_ERROR_SYSCALL) 222*ea16f64eSAntonio Huete Jimenez { 223*ea16f64eSAntonio Huete Jimenez return -1; 224*ea16f64eSAntonio Huete Jimenez } 225*ea16f64eSAntonio Huete Jimenez else 226*ea16f64eSAntonio Huete Jimenez { 227*ea16f64eSAntonio Huete Jimenez // Should not happen 228*ea16f64eSAntonio Huete Jimenez snprintf(errbuf, errbuflen, "SSL_read(): %s", 229*ea16f64eSAntonio Huete Jimenez ERR_error_string(ERR_get_error(), NULL)); 230*ea16f64eSAntonio Huete Jimenez return -2; 231*ea16f64eSAntonio Huete Jimenez } 232*ea16f64eSAntonio Huete Jimenez } 233*ea16f64eSAntonio Huete Jimenez else 234*ea16f64eSAntonio Huete Jimenez { 235*ea16f64eSAntonio Huete Jimenez return status; 236*ea16f64eSAntonio Huete Jimenez } 237*ea16f64eSAntonio Huete Jimenez } 238*ea16f64eSAntonio Huete Jimenez 239*ea16f64eSAntonio Huete Jimenez #endif // HAVE_OPENSSL 240