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 #ifdef HAVE_CONFIG_H 34 #include <config.h> 35 #endif 36 37 #ifdef HAVE_OPENSSL 38 #include <stdlib.h> 39 40 #include "portability.h" 41 42 #include "sslutils.h" 43 44 static const char *ssl_keyfile = ""; //!< file containing the private key in PEM format 45 static const char *ssl_certfile = ""; //!< file containing the server's certificate in PEM format 46 static const char *ssl_rootfile = ""; //!< file containing the list of CAs trusted by the client 47 // TODO: a way to set ssl_rootfile from the command line, or an envvar? 48 49 // TODO: lock? 50 static SSL_CTX *ctx; 51 52 void ssl_set_certfile(const char *certfile) 53 { 54 ssl_certfile = certfile; 55 } 56 57 void ssl_set_keyfile(const char *keyfile) 58 { 59 ssl_keyfile = keyfile; 60 } 61 62 int ssl_init_once(int is_server, int enable_compression, char *errbuf, size_t errbuflen) 63 { 64 static int inited = 0; 65 if (inited) return 0; 66 67 SSL_library_init(); 68 SSL_load_error_strings(); 69 OpenSSL_add_ssl_algorithms(); 70 if (enable_compression) 71 SSL_COMP_get_compression_methods(); 72 73 SSL_METHOD const *meth = 74 is_server ? SSLv23_server_method() : SSLv23_client_method(); 75 ctx = SSL_CTX_new(meth); 76 if (! ctx) 77 { 78 snprintf(errbuf, errbuflen, "Cannot get a new SSL context: %s", ERR_error_string(ERR_get_error(), NULL)); 79 goto die; 80 } 81 82 SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY); 83 84 if (is_server) 85 { 86 char const *certfile = ssl_certfile[0] ? ssl_certfile : "cert.pem"; 87 if (1 != SSL_CTX_use_certificate_file(ctx, certfile, SSL_FILETYPE_PEM)) 88 { 89 snprintf(errbuf, errbuflen, "Cannot read certificate file %s: %s", certfile, ERR_error_string(ERR_get_error(), NULL)); 90 goto die; 91 } 92 93 char const *keyfile = ssl_keyfile[0] ? ssl_keyfile : "key.pem"; 94 if (1 != SSL_CTX_use_PrivateKey_file(ctx, keyfile, SSL_FILETYPE_PEM)) 95 { 96 snprintf(errbuf, errbuflen, "Cannot read private key file %s: %s", keyfile, ERR_error_string(ERR_get_error(), NULL)); 97 goto die; 98 } 99 } 100 else 101 { 102 if (ssl_rootfile[0]) 103 { 104 if (! SSL_CTX_load_verify_locations(ctx, ssl_rootfile, 0)) 105 { 106 snprintf(errbuf, errbuflen, "Cannot read CA list from %s", ssl_rootfile); 107 goto die; 108 } 109 } 110 else 111 { 112 SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL); 113 } 114 } 115 116 #if 0 117 if (! RAND_load_file(RANDOM, 1024*1024)) 118 { 119 snprintf(errbuf, errbuflen, "Cannot init random"); 120 goto die; 121 } 122 123 if (is_server) 124 { 125 SSL_CTX_set_session_id_context(ctx, (void *)&s_server_session_id_context, sizeof(s_server_session_id_context)); 126 } 127 #endif 128 129 inited = 1; 130 return 0; 131 132 die: 133 return -1; 134 } 135 136 SSL *ssl_promotion(int is_server, SOCKET s, char *errbuf, size_t errbuflen) 137 { 138 if (ssl_init_once(is_server, 1, errbuf, errbuflen) < 0) { 139 return NULL; 140 } 141 142 SSL *ssl = SSL_new(ctx); // TODO: also a DTLS context 143 SSL_set_fd(ssl, (int)s); 144 145 if (is_server) { 146 if (SSL_accept(ssl) <= 0) { 147 snprintf(errbuf, errbuflen, "SSL_accept(): %s", 148 ERR_error_string(ERR_get_error(), NULL)); 149 return NULL; 150 } 151 } else { 152 if (SSL_connect(ssl) <= 0) { 153 snprintf(errbuf, errbuflen, "SSL_connect(): %s", 154 ERR_error_string(ERR_get_error(), NULL)); 155 return NULL; 156 } 157 } 158 159 return ssl; 160 } 161 162 // Finish using an SSL handle; shut down the connection and free the 163 // handle. 164 void ssl_finish(SSL *ssl) 165 { 166 // 167 // We won't be using this again, so we can just send the 168 // shutdown alert and free up the handle, and have our 169 // caller close the socket. 170 // 171 // XXX - presumably, if the connection is shut down on 172 // our side, either our peer won't have a problem sending 173 // their shutdown alert or will not treat such a problem 174 // as an error. If this causes errors to be reported, 175 // fix that as appropriate. 176 // 177 SSL_shutdown(ssl); 178 SSL_free(ssl); 179 } 180 181 // Same return value as sock_send: 182 // 0 on OK, -1 on error but closed connection (-2). 183 int ssl_send(SSL *ssl, char const *buffer, int size, char *errbuf, size_t errbuflen) 184 { 185 int status = SSL_write(ssl, buffer, size); 186 if (status > 0) 187 { 188 // "SSL_write() will only return with success, when the complete contents (...) has been written." 189 return 0; 190 } 191 else 192 { 193 int ssl_err = SSL_get_error(ssl, status); // TODO: does it pop the error? 194 if (ssl_err == SSL_ERROR_ZERO_RETURN) 195 { 196 return -2; 197 } 198 else if (ssl_err == SSL_ERROR_SYSCALL) 199 { 200 #ifndef _WIN32 201 if (errno == ECONNRESET || errno == EPIPE) return -2; 202 #endif 203 } 204 snprintf(errbuf, errbuflen, "SSL_write(): %s", 205 ERR_error_string(ERR_get_error(), NULL)); 206 return -1; 207 } 208 } 209 210 // Returns the number of bytes read, or -1 on syserror, or -2 on SSL error. 211 int ssl_recv(SSL *ssl, char *buffer, int size, char *errbuf, size_t errbuflen) 212 { 213 int status = SSL_read(ssl, buffer, size); 214 if (status <= 0) 215 { 216 int ssl_err = SSL_get_error(ssl, status); 217 if (ssl_err == SSL_ERROR_ZERO_RETURN) 218 { 219 return 0; 220 } 221 else if (ssl_err == SSL_ERROR_SYSCALL) 222 { 223 return -1; 224 } 225 else 226 { 227 // Should not happen 228 snprintf(errbuf, errbuflen, "SSL_read(): %s", 229 ERR_error_string(ERR_get_error(), NULL)); 230 return -2; 231 } 232 } 233 else 234 { 235 return status; 236 } 237 } 238 239 #endif // HAVE_OPENSSL 240