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