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