16f9cba8fSJoseph Mingrone /* 26f9cba8fSJoseph Mingrone * Copyright (c) 2002 - 2003 36f9cba8fSJoseph Mingrone * NetGroup, Politecnico di Torino (Italy) 46f9cba8fSJoseph Mingrone * All rights reserved. 56f9cba8fSJoseph Mingrone * 66f9cba8fSJoseph Mingrone * Redistribution and use in source and binary forms, with or without 76f9cba8fSJoseph Mingrone * modification, are permitted provided that the following conditions 86f9cba8fSJoseph Mingrone * are met: 96f9cba8fSJoseph Mingrone * 106f9cba8fSJoseph Mingrone * 1. Redistributions of source code must retain the above copyright 116f9cba8fSJoseph Mingrone * notice, this list of conditions and the following disclaimer. 126f9cba8fSJoseph Mingrone * 2. Redistributions in binary form must reproduce the above copyright 136f9cba8fSJoseph Mingrone * notice, this list of conditions and the following disclaimer in the 146f9cba8fSJoseph Mingrone * documentation and/or other materials provided with the distribution. 156f9cba8fSJoseph Mingrone * 3. Neither the name of the Politecnico di Torino nor the names of its 166f9cba8fSJoseph Mingrone * contributors may be used to endorse or promote products derived from 176f9cba8fSJoseph Mingrone * this software without specific prior written permission. 186f9cba8fSJoseph Mingrone * 196f9cba8fSJoseph Mingrone * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 206f9cba8fSJoseph Mingrone * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 216f9cba8fSJoseph Mingrone * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 226f9cba8fSJoseph Mingrone * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 236f9cba8fSJoseph Mingrone * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 246f9cba8fSJoseph Mingrone * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 256f9cba8fSJoseph Mingrone * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 266f9cba8fSJoseph Mingrone * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 276f9cba8fSJoseph Mingrone * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 286f9cba8fSJoseph Mingrone * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 296f9cba8fSJoseph Mingrone * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 306f9cba8fSJoseph Mingrone * 316f9cba8fSJoseph Mingrone */ 326f9cba8fSJoseph Mingrone 336f9cba8fSJoseph Mingrone #include <config.h> 346f9cba8fSJoseph Mingrone 356f9cba8fSJoseph Mingrone #ifdef HAVE_OPENSSL 366f9cba8fSJoseph Mingrone #include <stdlib.h> 376f9cba8fSJoseph Mingrone 386f9cba8fSJoseph Mingrone #include "portability.h" 396f9cba8fSJoseph Mingrone 406f9cba8fSJoseph Mingrone #include "sslutils.h" 416f9cba8fSJoseph Mingrone 426f9cba8fSJoseph Mingrone static const char *ssl_keyfile = ""; //!< file containing the private key in PEM format 436f9cba8fSJoseph Mingrone static const char *ssl_certfile = ""; //!< file containing the server's certificate in PEM format 446f9cba8fSJoseph Mingrone static const char *ssl_rootfile = ""; //!< file containing the list of CAs trusted by the client 456f9cba8fSJoseph Mingrone // TODO: a way to set ssl_rootfile from the command line, or an envvar? 466f9cba8fSJoseph Mingrone 476f9cba8fSJoseph Mingrone // TODO: lock? 486f9cba8fSJoseph Mingrone static SSL_CTX *ctx; 496f9cba8fSJoseph Mingrone 506f9cba8fSJoseph Mingrone void ssl_set_certfile(const char *certfile) 516f9cba8fSJoseph Mingrone { 526f9cba8fSJoseph Mingrone ssl_certfile = certfile; 536f9cba8fSJoseph Mingrone } 546f9cba8fSJoseph Mingrone 556f9cba8fSJoseph Mingrone void ssl_set_keyfile(const char *keyfile) 566f9cba8fSJoseph Mingrone { 576f9cba8fSJoseph Mingrone ssl_keyfile = keyfile; 586f9cba8fSJoseph Mingrone } 596f9cba8fSJoseph Mingrone 606f9cba8fSJoseph Mingrone int ssl_init_once(int is_server, int enable_compression, char *errbuf, size_t errbuflen) 616f9cba8fSJoseph Mingrone { 626f9cba8fSJoseph Mingrone static int inited = 0; 636f9cba8fSJoseph Mingrone if (inited) return 0; 646f9cba8fSJoseph Mingrone 656f9cba8fSJoseph Mingrone SSL_library_init(); 666f9cba8fSJoseph Mingrone SSL_load_error_strings(); 676f9cba8fSJoseph Mingrone OpenSSL_add_ssl_algorithms(); 686f9cba8fSJoseph Mingrone if (enable_compression) 696f9cba8fSJoseph Mingrone SSL_COMP_get_compression_methods(); 706f9cba8fSJoseph Mingrone 716f9cba8fSJoseph Mingrone SSL_METHOD const *meth = 726f9cba8fSJoseph Mingrone is_server ? SSLv23_server_method() : SSLv23_client_method(); 736f9cba8fSJoseph Mingrone ctx = SSL_CTX_new(meth); 746f9cba8fSJoseph Mingrone if (! ctx) 756f9cba8fSJoseph Mingrone { 766f9cba8fSJoseph Mingrone snprintf(errbuf, errbuflen, "Cannot get a new SSL context: %s", ERR_error_string(ERR_get_error(), NULL)); 776f9cba8fSJoseph Mingrone goto die; 786f9cba8fSJoseph Mingrone } 796f9cba8fSJoseph Mingrone 806f9cba8fSJoseph Mingrone SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY); 816f9cba8fSJoseph Mingrone 826f9cba8fSJoseph Mingrone if (is_server) 836f9cba8fSJoseph Mingrone { 846f9cba8fSJoseph Mingrone char const *certfile = ssl_certfile[0] ? ssl_certfile : "cert.pem"; 856f9cba8fSJoseph Mingrone if (1 != SSL_CTX_use_certificate_file(ctx, certfile, SSL_FILETYPE_PEM)) 866f9cba8fSJoseph Mingrone { 876f9cba8fSJoseph Mingrone snprintf(errbuf, errbuflen, "Cannot read certificate file %s: %s", certfile, ERR_error_string(ERR_get_error(), NULL)); 886f9cba8fSJoseph Mingrone goto die; 896f9cba8fSJoseph Mingrone } 906f9cba8fSJoseph Mingrone 916f9cba8fSJoseph Mingrone char const *keyfile = ssl_keyfile[0] ? ssl_keyfile : "key.pem"; 926f9cba8fSJoseph Mingrone if (1 != SSL_CTX_use_PrivateKey_file(ctx, keyfile, SSL_FILETYPE_PEM)) 936f9cba8fSJoseph Mingrone { 946f9cba8fSJoseph Mingrone snprintf(errbuf, errbuflen, "Cannot read private key file %s: %s", keyfile, ERR_error_string(ERR_get_error(), NULL)); 956f9cba8fSJoseph Mingrone goto die; 966f9cba8fSJoseph Mingrone } 976f9cba8fSJoseph Mingrone } 986f9cba8fSJoseph Mingrone else 996f9cba8fSJoseph Mingrone { 1006f9cba8fSJoseph Mingrone if (ssl_rootfile[0]) 1016f9cba8fSJoseph Mingrone { 1026f9cba8fSJoseph Mingrone if (! SSL_CTX_load_verify_locations(ctx, ssl_rootfile, 0)) 1036f9cba8fSJoseph Mingrone { 1046f9cba8fSJoseph Mingrone snprintf(errbuf, errbuflen, "Cannot read CA list from %s", ssl_rootfile); 1056f9cba8fSJoseph Mingrone goto die; 1066f9cba8fSJoseph Mingrone } 1076f9cba8fSJoseph Mingrone } 1086f9cba8fSJoseph Mingrone else 1096f9cba8fSJoseph Mingrone { 1106f9cba8fSJoseph Mingrone SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL); 1116f9cba8fSJoseph Mingrone } 1126f9cba8fSJoseph Mingrone } 1136f9cba8fSJoseph Mingrone 1146f9cba8fSJoseph Mingrone #if 0 1156f9cba8fSJoseph Mingrone if (! RAND_load_file(RANDOM, 1024*1024)) 1166f9cba8fSJoseph Mingrone { 1176f9cba8fSJoseph Mingrone snprintf(errbuf, errbuflen, "Cannot init random"); 1186f9cba8fSJoseph Mingrone goto die; 1196f9cba8fSJoseph Mingrone } 1206f9cba8fSJoseph Mingrone 1216f9cba8fSJoseph Mingrone if (is_server) 1226f9cba8fSJoseph Mingrone { 1236f9cba8fSJoseph Mingrone SSL_CTX_set_session_id_context(ctx, (void *)&s_server_session_id_context, sizeof(s_server_session_id_context)); 1246f9cba8fSJoseph Mingrone } 1256f9cba8fSJoseph Mingrone #endif 1266f9cba8fSJoseph Mingrone 1276f9cba8fSJoseph Mingrone inited = 1; 1286f9cba8fSJoseph Mingrone return 0; 1296f9cba8fSJoseph Mingrone 1306f9cba8fSJoseph Mingrone die: 1316f9cba8fSJoseph Mingrone return -1; 1326f9cba8fSJoseph Mingrone } 1336f9cba8fSJoseph Mingrone 134*afdbf109SJoseph Mingrone SSL *ssl_promotion(int is_server, PCAP_SOCKET s, char *errbuf, size_t errbuflen) 1356f9cba8fSJoseph Mingrone { 1366f9cba8fSJoseph Mingrone if (ssl_init_once(is_server, 1, errbuf, errbuflen) < 0) { 1376f9cba8fSJoseph Mingrone return NULL; 1386f9cba8fSJoseph Mingrone } 1396f9cba8fSJoseph Mingrone 1406f9cba8fSJoseph Mingrone SSL *ssl = SSL_new(ctx); // TODO: also a DTLS context 1416f9cba8fSJoseph Mingrone SSL_set_fd(ssl, (int)s); 1426f9cba8fSJoseph Mingrone 1436f9cba8fSJoseph Mingrone if (is_server) { 1446f9cba8fSJoseph Mingrone if (SSL_accept(ssl) <= 0) { 1456f9cba8fSJoseph Mingrone snprintf(errbuf, errbuflen, "SSL_accept(): %s", 1466f9cba8fSJoseph Mingrone ERR_error_string(ERR_get_error(), NULL)); 1476f9cba8fSJoseph Mingrone return NULL; 1486f9cba8fSJoseph Mingrone } 1496f9cba8fSJoseph Mingrone } else { 1506f9cba8fSJoseph Mingrone if (SSL_connect(ssl) <= 0) { 1516f9cba8fSJoseph Mingrone snprintf(errbuf, errbuflen, "SSL_connect(): %s", 1526f9cba8fSJoseph Mingrone ERR_error_string(ERR_get_error(), NULL)); 1536f9cba8fSJoseph Mingrone return NULL; 1546f9cba8fSJoseph Mingrone } 1556f9cba8fSJoseph Mingrone } 1566f9cba8fSJoseph Mingrone 1576f9cba8fSJoseph Mingrone return ssl; 1586f9cba8fSJoseph Mingrone } 1596f9cba8fSJoseph Mingrone 1606f9cba8fSJoseph Mingrone // Finish using an SSL handle; shut down the connection and free the 1616f9cba8fSJoseph Mingrone // handle. 1626f9cba8fSJoseph Mingrone void ssl_finish(SSL *ssl) 1636f9cba8fSJoseph Mingrone { 1646f9cba8fSJoseph Mingrone // 1656f9cba8fSJoseph Mingrone // We won't be using this again, so we can just send the 1666f9cba8fSJoseph Mingrone // shutdown alert and free up the handle, and have our 1676f9cba8fSJoseph Mingrone // caller close the socket. 1686f9cba8fSJoseph Mingrone // 1696f9cba8fSJoseph Mingrone // XXX - presumably, if the connection is shut down on 1706f9cba8fSJoseph Mingrone // our side, either our peer won't have a problem sending 1716f9cba8fSJoseph Mingrone // their shutdown alert or will not treat such a problem 1726f9cba8fSJoseph Mingrone // as an error. If this causes errors to be reported, 1736f9cba8fSJoseph Mingrone // fix that as appropriate. 1746f9cba8fSJoseph Mingrone // 1756f9cba8fSJoseph Mingrone SSL_shutdown(ssl); 1766f9cba8fSJoseph Mingrone SSL_free(ssl); 1776f9cba8fSJoseph Mingrone } 1786f9cba8fSJoseph Mingrone 1796f9cba8fSJoseph Mingrone // Same return value as sock_send: 1806f9cba8fSJoseph Mingrone // 0 on OK, -1 on error but closed connection (-2). 1816f9cba8fSJoseph Mingrone int ssl_send(SSL *ssl, char const *buffer, int size, char *errbuf, size_t errbuflen) 1826f9cba8fSJoseph Mingrone { 1836f9cba8fSJoseph Mingrone int status = SSL_write(ssl, buffer, size); 1846f9cba8fSJoseph Mingrone if (status > 0) 1856f9cba8fSJoseph Mingrone { 1866f9cba8fSJoseph Mingrone // "SSL_write() will only return with success, when the complete contents (...) has been written." 1876f9cba8fSJoseph Mingrone return 0; 1886f9cba8fSJoseph Mingrone } 1896f9cba8fSJoseph Mingrone else 1906f9cba8fSJoseph Mingrone { 1916f9cba8fSJoseph Mingrone int ssl_err = SSL_get_error(ssl, status); // TODO: does it pop the error? 1926f9cba8fSJoseph Mingrone if (ssl_err == SSL_ERROR_ZERO_RETURN) 1936f9cba8fSJoseph Mingrone { 1946f9cba8fSJoseph Mingrone return -2; 1956f9cba8fSJoseph Mingrone } 1966f9cba8fSJoseph Mingrone else if (ssl_err == SSL_ERROR_SYSCALL) 1976f9cba8fSJoseph Mingrone { 1986f9cba8fSJoseph Mingrone #ifndef _WIN32 1996f9cba8fSJoseph Mingrone if (errno == ECONNRESET || errno == EPIPE) return -2; 2006f9cba8fSJoseph Mingrone #endif 2016f9cba8fSJoseph Mingrone } 2026f9cba8fSJoseph Mingrone snprintf(errbuf, errbuflen, "SSL_write(): %s", 2036f9cba8fSJoseph Mingrone ERR_error_string(ERR_get_error(), NULL)); 2046f9cba8fSJoseph Mingrone return -1; 2056f9cba8fSJoseph Mingrone } 2066f9cba8fSJoseph Mingrone } 2076f9cba8fSJoseph Mingrone 2086f9cba8fSJoseph Mingrone // Returns the number of bytes read, or -1 on syserror, or -2 on SSL error. 2096f9cba8fSJoseph Mingrone int ssl_recv(SSL *ssl, char *buffer, int size, char *errbuf, size_t errbuflen) 2106f9cba8fSJoseph Mingrone { 2116f9cba8fSJoseph Mingrone int status = SSL_read(ssl, buffer, size); 2126f9cba8fSJoseph Mingrone if (status <= 0) 2136f9cba8fSJoseph Mingrone { 2146f9cba8fSJoseph Mingrone int ssl_err = SSL_get_error(ssl, status); 2156f9cba8fSJoseph Mingrone if (ssl_err == SSL_ERROR_ZERO_RETURN) 2166f9cba8fSJoseph Mingrone { 2176f9cba8fSJoseph Mingrone return 0; 2186f9cba8fSJoseph Mingrone } 2196f9cba8fSJoseph Mingrone else if (ssl_err == SSL_ERROR_SYSCALL) 2206f9cba8fSJoseph Mingrone { 2216f9cba8fSJoseph Mingrone return -1; 2226f9cba8fSJoseph Mingrone } 2236f9cba8fSJoseph Mingrone else 2246f9cba8fSJoseph Mingrone { 2256f9cba8fSJoseph Mingrone // Should not happen 2266f9cba8fSJoseph Mingrone snprintf(errbuf, errbuflen, "SSL_read(): %s", 2276f9cba8fSJoseph Mingrone ERR_error_string(ERR_get_error(), NULL)); 2286f9cba8fSJoseph Mingrone return -2; 2296f9cba8fSJoseph Mingrone } 2306f9cba8fSJoseph Mingrone } 2316f9cba8fSJoseph Mingrone else 2326f9cba8fSJoseph Mingrone { 2336f9cba8fSJoseph Mingrone return status; 2346f9cba8fSJoseph Mingrone } 2356f9cba8fSJoseph Mingrone } 2366f9cba8fSJoseph Mingrone 2376f9cba8fSJoseph Mingrone #endif // HAVE_OPENSSL 238