]>
Commit | Line | Data |
---|---|---|
7460295f | 1 | // ssl.c -- Support functions that find and load SSL support, if available |
bc83b450 | 2 | // Copyright (C) 2008-2010 Markus Gutschke <markus@shellinabox.com> |
7460295f MG |
3 | // |
4 | // This program is free software; you can redistribute it and/or modify | |
5 | // it under the terms of the GNU General Public License version 2 as | |
6 | // published by the Free Software Foundation. | |
7 | // | |
8 | // This program is distributed in the hope that it will be useful, | |
9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of | |
10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
11 | // GNU General Public License for more details. | |
12 | // | |
13 | // You should have received a copy of the GNU General Public License along | |
14 | // with this program; if not, write to the Free Software Foundation, Inc., | |
15 | // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |
16 | // | |
17 | // In addition to these license terms, the author grants the following | |
18 | // additional rights: | |
19 | // | |
20 | // If you modify this program, or any covered work, by linking or | |
21 | // combining it with the OpenSSL project's OpenSSL library (or a | |
22 | // modified version of that library), containing parts covered by the | |
23 | // terms of the OpenSSL or SSLeay licenses, the author | |
24 | // grants you additional permission to convey the resulting work. | |
25 | // Corresponding Source for a non-source form of such a combination | |
26 | // shall include the source code for the parts of OpenSSL used as well | |
27 | // as that of the covered work. | |
28 | // | |
29 | // You may at your option choose to remove this additional permission from | |
30 | // the work, or from any part of it. | |
31 | // | |
32 | // It is possible to build this program in a way that it loads OpenSSL | |
33 | // libraries at run-time. If doing so, the following notices are required | |
34 | // by the OpenSSL and SSLeay licenses: | |
35 | // | |
36 | // This product includes software developed by the OpenSSL Project | |
37 | // for use in the OpenSSL Toolkit. (http://www.openssl.org/) | |
38 | // | |
39 | // This product includes cryptographic software written by Eric Young | |
40 | // (eay@cryptsoft.com) | |
41 | // | |
42 | // | |
43 | // The most up-to-date version of this program is always available from | |
44 | // http://shellinabox.com | |
45 | ||
46 | #define _GNU_SOURCE | |
bdd01e84 | 47 | #include "config.h" |
7460295f | 48 | |
c593cf68 MG |
49 | #define pthread_once x_pthread_once |
50 | #define pthread_sigmask x_pthread_sigmask | |
51 | ||
7460295f MG |
52 | #include <dlfcn.h> |
53 | #include <errno.h> | |
ad24d9a9 | 54 | #include <fcntl.h> |
7460295f MG |
55 | #include <netdb.h> |
56 | #include <signal.h> | |
57 | #include <stdlib.h> | |
58 | #include <string.h> | |
ad24d9a9 MG |
59 | #include <sys/types.h> |
60 | #include <sys/stat.h> | |
38388d32 | 61 | #include <sys/wait.h> |
7460295f MG |
62 | #include <unistd.h> |
63 | ||
64 | #include "libhttp/ssl.h" | |
65 | #include "libhttp/httpconnection.h" | |
66 | #include "logging/logging.h" | |
67 | ||
242e6c5b MG |
68 | #ifdef HAVE_UNUSED |
69 | #defined ATTR_UNUSED __attribute__((unused)) | |
70 | #defined UNUSED(x) do { } while (0) | |
71 | #else | |
72 | #define ATTR_UNUSED | |
73 | #define UNUSED(x) do { (void)(x); } while (0) | |
74 | #endif | |
75 | ||
c593cf68 MG |
76 | #undef pthread_once |
77 | #undef pthread_sigmask | |
78 | ||
bdd01e84 MG |
79 | #if defined(HAVE_OPENSSL) && !defined(OPENSSL_NO_TLSEXT) && \ |
80 | defined(TLSEXT_NAMETYPE_host_name) && defined(SSL_TLSEXT_ERR_OK) | |
d04f7ca7 MG |
81 | #define HAVE_TLSEXT |
82 | #endif | |
83 | ||
7460295f MG |
84 | #if defined(HAVE_PTHREAD_H) |
85 | // Pthread support is optional. Only enable it, if the library has been | |
86 | // linked into the program | |
87 | #include <pthread.h> | |
bf1ec4d2 | 88 | #if defined(__linux__) |
7460295f | 89 | extern int pthread_once(pthread_once_t *, void (*)(void))__attribute__((weak)); |
bf1ec4d2 | 90 | #endif |
7460295f MG |
91 | extern int pthread_sigmask(int, const sigset_t *, sigset_t *) |
92 | __attribute__((weak)); | |
93 | ||
94 | #endif | |
95 | ||
bf1ec4d2 | 96 | #if defined(HAVE_DLOPEN) |
7460295f | 97 | // SSL support is optional. Only enable it, if the library can be loaded. |
03cd76e1 MG |
98 | long (*BIO_ctrl)(BIO *, int, long, void *); |
99 | BIO_METHOD * (*BIO_f_buffer)(void); | |
100 | void (*BIO_free_all)(BIO *); | |
101 | BIO * (*BIO_new)(BIO_METHOD *); | |
102 | BIO * (*BIO_new_socket)(int, int); | |
103 | BIO * (*BIO_pop)(BIO *); | |
104 | BIO * (*BIO_push)(BIO *, BIO *); | |
105 | void (*ERR_clear_error)(void); | |
106 | void (*ERR_clear_error)(void); | |
107 | unsigned long (*ERR_peek_error)(void); | |
108 | unsigned long (*ERR_peek_error)(void); | |
109 | long (*SSL_CTX_callback_ctrl)(SSL_CTX *, int, void (*)(void)); | |
110 | int (*SSL_CTX_check_private_key)(const SSL_CTX *); | |
111 | long (*SSL_CTX_ctrl)(SSL_CTX *, int, long, void *); | |
112 | void (*SSL_CTX_free)(SSL_CTX *); | |
113 | SSL_CTX * (*SSL_CTX_new)(SSL_METHOD *); | |
114 | int (*SSL_CTX_use_PrivateKey_file)(SSL_CTX *, const char *, int); | |
dc6575f2 MG |
115 | int (*SSL_CTX_use_PrivateKey_ASN1)(int, SSL_CTX *, |
116 | const unsigned char *, long); | |
03cd76e1 | 117 | int (*SSL_CTX_use_certificate_file)(SSL_CTX *, const char *, int); |
dc6575f2 MG |
118 | int (*SSL_CTX_use_certificate_ASN1)(SSL_CTX *, long, |
119 | const unsigned char *); | |
03cd76e1 MG |
120 | long (*SSL_ctrl)(SSL *, int, long, void *); |
121 | void (*SSL_free)(SSL *); | |
122 | int (*SSL_get_error)(const SSL *, int); | |
123 | void * (*SSL_get_ex_data)(const SSL *, int); | |
124 | BIO * (*SSL_get_rbio)(const SSL *); | |
125 | const char * (*SSL_get_servername)(const SSL *, int); | |
126 | BIO * (*SSL_get_wbio)(const SSL *); | |
127 | int (*SSL_library_init)(void); | |
128 | SSL * (*SSL_new)(SSL_CTX *); | |
129 | int (*SSL_read)(SSL *, void *, int); | |
130 | SSL_CTX * (*SSL_set_SSL_CTX)(SSL *, SSL_CTX *); | |
131 | void (*SSL_set_accept_state)(SSL *); | |
132 | void (*SSL_set_bio)(SSL *, BIO *, BIO *); | |
133 | int (*SSL_set_ex_data)(SSL *, int, void *); | |
134 | int (*SSL_shutdown)(SSL *); | |
135 | int (*SSL_write)(SSL *, const void *, int); | |
136 | SSL_METHOD * (*SSLv23_server_method)(void); | |
ad24d9a9 MG |
137 | X509 * (*d2i_X509)(X509 **px, const unsigned char **in, int len); |
138 | void (*X509_free)(X509 *a); | |
bf1ec4d2 | 139 | #endif |
7460295f MG |
140 | |
141 | static void sslDestroyCachedContext(void *ssl_, char *context_) { | |
142 | struct SSLSupport *ssl = (struct SSLSupport *)ssl_; | |
143 | SSL_CTX *context = (SSL_CTX *)context_; | |
03cd76e1 | 144 | #if defined(HAVE_OPENSSL) |
7460295f MG |
145 | if (context != ssl->sslContext) { |
146 | SSL_CTX_free(context); | |
147 | } | |
03cd76e1 MG |
148 | #else |
149 | check(!context); | |
150 | check(!ssl->sslContext); | |
151 | #endif | |
7460295f MG |
152 | } |
153 | ||
154 | struct SSLSupport *newSSL(void) { | |
155 | struct SSLSupport *ssl; | |
156 | check(ssl = malloc(sizeof(struct SSLSupport))); | |
157 | initSSL(ssl); | |
158 | return ssl; | |
159 | } | |
160 | ||
161 | void initSSL(struct SSLSupport *ssl) { | |
162 | ssl->enabled = serverSupportsSSL(); | |
163 | ssl->sslContext = NULL; | |
164 | ssl->sniCertificatePattern = NULL; | |
165 | ssl->generateMissing = 0; | |
166 | initTrie(&ssl->sniContexts, sslDestroyCachedContext, ssl); | |
167 | } | |
168 | ||
169 | void destroySSL(struct SSLSupport *ssl) { | |
170 | if (ssl) { | |
171 | free(ssl->sniCertificatePattern); | |
172 | destroyTrie(&ssl->sniContexts); | |
03cd76e1 | 173 | #if defined(HAVE_OPENSSL) |
7460295f MG |
174 | if (ssl->sslContext) { |
175 | dcheck(!ERR_peek_error()); | |
176 | SSL_CTX_free(ssl->sslContext); | |
177 | } | |
03cd76e1 MG |
178 | #else |
179 | check(!ssl->sslContext); | |
180 | #endif | |
7460295f MG |
181 | } |
182 | } | |
183 | ||
184 | void deleteSSL(struct SSLSupport *ssl) { | |
185 | destroySSL(ssl); | |
186 | free(ssl); | |
187 | } | |
188 | ||
bf1ec4d2 | 189 | #if defined(HAVE_OPENSSL) && defined(HAVE_DLOPEN) |
10d0a6b0 MG |
190 | static int maybeLoadCrypto(void) { |
191 | // Some operating systems cannot automatically load dependent dynamic | |
192 | // libraries. As libssl.so can depend on libcrypto.so, we try to load | |
193 | // it, iff we haven't tried loading it before and iff libssl.so does not | |
194 | // work by itself. | |
195 | static int crypto; | |
196 | if (!crypto++) { | |
197 | #ifdef RTLD_NOLOAD | |
198 | if (dlopen("libcrypto.so", RTLD_LAZY|RTLD_GLOBAL|RTLD_NOLOAD)) | |
199 | return 1; | |
200 | else | |
201 | #endif | |
202 | if (dlopen("libcrypto.so", RTLD_LAZY|RTLD_GLOBAL)) | |
203 | return 1; | |
204 | } | |
205 | return 0; | |
206 | } | |
207 | ||
7460295f | 208 | static void *loadSymbol(const char *lib, const char *fn) { |
10d0a6b0 MG |
209 | int err = NOINTR(dup(2)); |
210 | if (err > 2) { | |
211 | int null = NOINTR(open("/dev/null", O_WRONLY)); | |
212 | if (null >= 0) { | |
213 | NOINTR(dup2(null, 2)); | |
214 | NOINTR(close(null)); | |
215 | } | |
216 | } | |
7460295f MG |
217 | void *dl = RTLD_DEFAULT; |
218 | void *rc = dlsym(dl, fn); | |
219 | if (!rc) { | |
10d0a6b0 | 220 | for (int i = 0; i < 2; i++) { |
47e62a9c | 221 | #ifdef RTLD_NOLOAD |
10d0a6b0 | 222 | dl = dlopen(lib, RTLD_LAZY|RTLD_GLOBAL|RTLD_NOLOAD); |
47e62a9c | 223 | #else |
10d0a6b0 | 224 | dl = NULL; |
47e62a9c | 225 | #endif |
10d0a6b0 MG |
226 | if (dl == NULL) { |
227 | dl = dlopen(lib, RTLD_LAZY|RTLD_GLOBAL); | |
228 | } | |
229 | if (dl != NULL || !maybeLoadCrypto()) { | |
230 | break; | |
231 | } | |
7460295f MG |
232 | } |
233 | if (dl != NULL) { | |
10d0a6b0 MG |
234 | rc = dlsym(RTLD_DEFAULT, fn); |
235 | if (rc == NULL && maybeLoadCrypto()) { | |
236 | rc = dlsym(RTLD_DEFAULT, fn); | |
237 | } | |
7460295f MG |
238 | } |
239 | } | |
10d0a6b0 MG |
240 | if (err > 2) { |
241 | NOINTR(dup2(err, 2)); | |
242 | } | |
243 | NOINTR(close(err)); | |
7460295f MG |
244 | return rc; |
245 | } | |
246 | ||
247 | static void loadSSL(void) { | |
248 | check(!SSL_library_init); | |
249 | struct { | |
88b579e2 MG |
250 | union { |
251 | void *avoid_gcc_warning_about_type_punning; | |
252 | void **var; | |
253 | }; | |
7460295f MG |
254 | const char *fn; |
255 | } symbols[] = { | |
03cd76e1 MG |
256 | { { &BIO_ctrl }, "BIO_ctrl" }, |
257 | { { &BIO_f_buffer }, "BIO_f_buffer" }, | |
258 | { { &BIO_free_all }, "BIO_free_all" }, | |
259 | { { &BIO_new }, "BIO_new" }, | |
260 | { { &BIO_new_socket }, "BIO_new_socket" }, | |
261 | { { &BIO_pop }, "BIO_pop" }, | |
262 | { { &BIO_push }, "BIO_push" }, | |
263 | { { &ERR_clear_error }, "ERR_clear_error" }, | |
264 | { { &ERR_clear_error }, "ERR_clear_error" }, | |
265 | { { &ERR_peek_error }, "ERR_peek_error" }, | |
266 | { { &ERR_peek_error }, "ERR_peek_error" }, | |
267 | { { &SSL_CTX_callback_ctrl }, "SSL_CTX_callback_ctrl" }, | |
268 | { { &SSL_CTX_check_private_key }, "SSL_CTX_check_private_key" }, | |
269 | { { &SSL_CTX_ctrl }, "SSL_CTX_ctrl" }, | |
270 | { { &SSL_CTX_free }, "SSL_CTX_free" }, | |
271 | { { &SSL_CTX_new }, "SSL_CTX_new" }, | |
272 | { { &SSL_CTX_use_PrivateKey_file }, "SSL_CTX_use_PrivateKey_file" }, | |
dc6575f2 | 273 | { { &SSL_CTX_use_PrivateKey_ASN1 }, "SSL_CTX_use_PrivateKey_ASN1" }, |
03cd76e1 | 274 | { { &SSL_CTX_use_certificate_file },"SSL_CTX_use_certificate_file"}, |
dc6575f2 | 275 | { { &SSL_CTX_use_certificate_ASN1 },"SSL_CTX_use_certificate_ASN1"}, |
03cd76e1 MG |
276 | { { &SSL_ctrl }, "SSL_ctrl" }, |
277 | { { &SSL_free }, "SSL_free" }, | |
278 | { { &SSL_get_error }, "SSL_get_error" }, | |
279 | { { &SSL_get_ex_data }, "SSL_get_ex_data" }, | |
280 | { { &SSL_get_rbio }, "SSL_get_rbio" }, | |
d04f7ca7 | 281 | #ifdef HAVE_TLSEXT |
03cd76e1 | 282 | { { &SSL_get_servername }, "SSL_get_servername" }, |
a42d111c | 283 | #endif |
03cd76e1 MG |
284 | { { &SSL_get_wbio }, "SSL_get_wbio" }, |
285 | { { &SSL_library_init }, "SSL_library_init" }, | |
286 | { { &SSL_new }, "SSL_new" }, | |
287 | { { &SSL_read }, "SSL_read" }, | |
d04f7ca7 | 288 | #ifdef HAVE_TLSEXT |
03cd76e1 | 289 | { { &SSL_set_SSL_CTX }, "SSL_set_SSL_CTX" }, |
a42d111c | 290 | #endif |
03cd76e1 MG |
291 | { { &SSL_set_accept_state }, "SSL_set_accept_state" }, |
292 | { { &SSL_set_bio }, "SSL_set_bio" }, | |
293 | { { &SSL_set_ex_data }, "SSL_set_ex_data" }, | |
294 | { { &SSL_shutdown }, "SSL_shutdown" }, | |
295 | { { &SSL_write }, "SSL_write" }, | |
ad24d9a9 MG |
296 | { { &SSLv23_server_method }, "SSLv23_server_method" }, |
297 | { { &d2i_X509 }, "d2i_X509" }, | |
298 | { { &X509_free }, "X509_free" } | |
7460295f | 299 | }; |
bc83b450 | 300 | for (unsigned i = 0; i < sizeof(symbols)/sizeof(symbols[0]); i++) { |
7460295f MG |
301 | if (!(*symbols[i].var = loadSymbol("libssl.so", symbols[i].fn))) { |
302 | debug("Failed to load SSL support. Could not find \"%s\"", | |
303 | symbols[i].fn); | |
bc83b450 | 304 | for (unsigned j = 0; j < sizeof(symbols)/sizeof(symbols[0]); j++) { |
7460295f MG |
305 | *symbols[j].var = NULL; |
306 | } | |
307 | return; | |
308 | } | |
309 | } | |
310 | SSL_library_init(); | |
311 | dcheck(!ERR_peek_error()); | |
312 | debug("Loaded SSL suppport"); | |
313 | } | |
314 | #endif | |
315 | ||
316 | int serverSupportsSSL(void) { | |
bf1ec4d2 MG |
317 | #if defined(HAVE_OPENSSL) && !defined(HAVE_DLOPEN) |
318 | return SSL_library_init(); | |
319 | #else | |
7460295f MG |
320 | #if defined(HAVE_OPENSSL) |
321 | // We want to call loadSSL() exactly once. For single-threaded applications, | |
322 | // this is straight-forward. For threaded applications, we need to call | |
323 | // pthread_once(), instead. We perform run-time checks for whether we are | |
324 | // single- or multi-threaded, so that the same code can be used. | |
a3876a41 | 325 | // This currently only works on Linux. |
9d758d39 | 326 | #if defined(HAVE_PTHREAD_H) && defined(__linux__) && defined(__i386__) |
7460295f MG |
327 | if (!!&pthread_once) { |
328 | static pthread_once_t once = PTHREAD_ONCE_INIT; | |
329 | pthread_once(&once, loadSSL); | |
330 | } else | |
331 | #endif | |
332 | { | |
333 | static int initialized; | |
334 | if (!initialized) { | |
335 | initialized = 1; | |
336 | loadSSL(); | |
337 | } | |
338 | } | |
339 | return !!SSL_library_init; | |
340 | #else | |
341 | return 0; | |
342 | #endif | |
bf1ec4d2 | 343 | #endif |
7460295f MG |
344 | } |
345 | ||
bdd01e84 | 346 | #if defined(HAVE_OPENSSL) |
39e8401e MG |
347 | static void sslGenerateCertificate(const char *certificate, |
348 | const char *serverName) { | |
7460295f MG |
349 | debug("Auto-generating missing certificate \"%s\" for \"%s\"", |
350 | certificate, serverName); | |
38388d32 AK |
351 | |
352 | pid_t pid = fork(); | |
353 | if (pid == -1) { | |
7460295f | 354 | warn("Failed to generate self-signed certificate \"%s\"", certificate); |
38388d32 AK |
355 | } else if (pid == 0) { |
356 | int fd = NOINTR(open("/dev/null", O_RDONLY)); | |
357 | check(fd != -1); | |
358 | check(NOINTR(dup2(fd, STDERR_FILENO)) == STDERR_FILENO); | |
359 | check(NOINTR(close(fd)) == 0); | |
360 | fd = NOINTR(open("/dev/null", O_WRONLY)); | |
361 | check(fd != -1); | |
362 | check(NOINTR(dup2(fd, STDIN_FILENO)) == STDIN_FILENO); | |
363 | check(NOINTR(close(fd)) == 0); | |
364 | umask(077); | |
365 | check(setenv("PATH", "/usr/bin:/usr/sbin", 1) == 0); | |
366 | execlp("openssl", "openssl", "req", "-x509", "-nodes", "-days", "7300", | |
6ddcf799 | 367 | "-newkey", "rsa:2048", "-keyout", certificate, "-out", certificate, |
38388d32 AK |
368 | "-subj", stringPrintf(NULL, "/CN=%s/", serverName), |
369 | (char *)NULL); | |
370 | check(0); | |
371 | } else { | |
372 | int status; | |
373 | check(NOINTR(waitpid(pid, &status, 0)) == pid); | |
374 | if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) | |
375 | warn("Failed to generate self-signed certificate \"%s\"", certificate); | |
7460295f | 376 | } |
7460295f | 377 | } |
ad24d9a9 MG |
378 | |
379 | static const unsigned char *sslSecureReadASCIIFileToMem(int fd) { | |
380 | size_t inc = 16384; | |
381 | size_t bufSize = inc; | |
382 | size_t len = 0; | |
383 | unsigned char *buf; | |
384 | check((buf = malloc(bufSize)) != NULL); | |
385 | for (;;) { | |
386 | check(len < bufSize - 1); | |
bc83b450 | 387 | ssize_t readLen = bufSize - len - 1; |
ad24d9a9 MG |
388 | ssize_t bytesRead = NOINTR(read(fd, buf + len, readLen)); |
389 | if (bytesRead > 0) { | |
390 | len += bytesRead; | |
391 | } | |
392 | if (bytesRead != readLen) { | |
393 | break; | |
394 | } | |
395 | ||
396 | // Instead of calling realloc(), allocate a new buffer, copy the data, | |
397 | // and then clear the old buffer. This way, we are not accidentally | |
398 | // leaving key material in memory. | |
399 | unsigned char *newBuf; | |
400 | check((newBuf = malloc(bufSize + inc)) != NULL); | |
401 | memcpy(newBuf, buf, len); | |
402 | memset(buf, 0, bufSize); | |
403 | free(buf); | |
404 | buf = newBuf; | |
405 | bufSize += inc; | |
406 | } | |
407 | check(len < bufSize); | |
408 | buf[len] = '\000'; | |
409 | return buf; | |
410 | } | |
411 | ||
412 | static const unsigned char *sslPEMtoASN1(const unsigned char *pem, | |
413 | const char *record, | |
414 | long *size, | |
415 | const unsigned char **eor) { | |
416 | if (eor) { | |
417 | *eor = NULL; | |
418 | } | |
419 | *size = 0; | |
420 | char *marker; | |
421 | check((marker = stringPrintf(NULL, "-----BEGIN %s-----",record))!=NULL); | |
422 | unsigned char *ptr = (unsigned char *)strstr((char *)pem, marker); | |
423 | if (!ptr) { | |
424 | free(marker); | |
425 | return NULL; | |
426 | } else { | |
427 | ptr += strlen(marker); | |
428 | } | |
429 | *marker = '\000'; | |
430 | check((marker = stringPrintf(marker, "-----END %s-----",record))!=NULL); | |
431 | unsigned char *end = (unsigned char *)strstr((char *)ptr, marker); | |
432 | if (eor) { | |
433 | *eor = end + strlen(marker); | |
434 | } | |
435 | free(marker); | |
436 | if (!end) { | |
437 | return NULL; | |
438 | } | |
439 | unsigned char *ret; | |
bc83b450 | 440 | ssize_t maxSize = (((end - ptr)*6)+7)/8; |
ad24d9a9 MG |
441 | check((ret = malloc(maxSize)) != NULL); |
442 | unsigned char *out = ret; | |
443 | unsigned bits = 0; | |
444 | int count = 0; | |
445 | while (ptr < end) { | |
446 | unsigned char ch = *ptr++; | |
447 | if (ch >= 'A' && ch <= 'Z') { | |
448 | ch -= 'A'; | |
449 | } else if (ch >= 'a' && ch <= 'z') { | |
450 | ch -= 'a' - 26; | |
451 | } else if (ch >= '0' && ch <= '9') { | |
452 | ch += 52 - '0'; | |
453 | } else if (ch == '+') { | |
454 | ch += 62 - '+'; | |
455 | } else if (ch == '/') { | |
456 | ch += 63 - '/'; | |
457 | } else if (ch == '=') { | |
458 | while (ptr < end) { | |
459 | if ((ch = *ptr++) != '=' && ch > ' ') { | |
460 | goto err; | |
461 | } | |
462 | } | |
463 | break; | |
464 | } else if (ch <= ' ') { | |
465 | continue; | |
466 | } else { | |
467 | err: | |
468 | free(ret); | |
469 | return NULL; | |
470 | } | |
471 | check(ch <= 63); | |
472 | check(count >= 0); | |
473 | check(count <= 6); | |
474 | bits = (bits << 6) | ch; | |
475 | count += 6; | |
476 | if (count >= 8) { | |
477 | *out++ = (bits >> (count -= 8)) & 0xFF; | |
478 | } | |
479 | } | |
480 | check(out - ret <= maxSize); | |
481 | *size = out - ret; | |
482 | return ret; | |
483 | } | |
484 | ||
485 | static int sslSetCertificateFromFd(SSL_CTX *context, int fd) { | |
486 | int rc = 0; | |
487 | check(serverSupportsSSL()); | |
488 | check(fd >= 0); | |
489 | const unsigned char *data = sslSecureReadASCIIFileToMem(fd); | |
490 | check(!NOINTR(close(fd))); | |
491 | long dataSize = (long)strlen((const char *)data); | |
28ff61e1 | 492 | long certSize, rsaSize, dsaSize, ecSize, notypeSize; |
ad24d9a9 MG |
493 | const unsigned char *record; |
494 | const unsigned char *cert = sslPEMtoASN1(data, "CERTIFICATE", &certSize, | |
495 | &record); | |
496 | const unsigned char *rsa = sslPEMtoASN1(data, "RSA PRIVATE KEY",&rsaSize, | |
497 | NULL); | |
498 | const unsigned char *dsa = sslPEMtoASN1(data, "DSA PRIVATE KEY",&dsaSize, | |
499 | NULL); | |
500 | const unsigned char *ec = sslPEMtoASN1(data, "EC PRIVATE KEY", &ecSize, | |
501 | NULL); | |
28ff61e1 JW |
502 | const unsigned char *notype = sslPEMtoASN1(data, "PRIVATE KEY", ¬ypeSize, |
503 | NULL); | |
ad24d9a9 MG |
504 | if (certSize && (rsaSize || dsaSize |
505 | #ifdef EVP_PKEY_EC | |
506 | || ecSize | |
507 | #endif | |
28ff61e1 | 508 | || notypeSize) && |
ad24d9a9 MG |
509 | SSL_CTX_use_certificate_ASN1(context, certSize, cert) && |
510 | (!rsaSize || | |
511 | SSL_CTX_use_PrivateKey_ASN1(EVP_PKEY_RSA, context, rsa, rsaSize)) && | |
512 | (!dsaSize || | |
28ff61e1 | 513 | SSL_CTX_use_PrivateKey_ASN1(EVP_PKEY_DSA, context, dsa, dsaSize)) && |
ad24d9a9 | 514 | #ifdef EVP_PKEY_EC |
ad24d9a9 | 515 | (!ecSize || |
28ff61e1 | 516 | SSL_CTX_use_PrivateKey_ASN1(EVP_PKEY_EC, context, ec, ecSize)) && |
ad24d9a9 | 517 | #endif |
28ff61e1 JW |
518 | // Assume a private key is RSA if the header does not specify a type. |
519 | // (e.g. BEGIN PRIVATE KEY) | |
520 | (!notypeSize || | |
521 | SSL_CTX_use_PrivateKey_ASN1(EVP_PKEY_RSA, context, notype, notypeSize)) | |
ad24d9a9 MG |
522 | ) { |
523 | memset((char *)cert, 0, certSize); | |
524 | free((char *)cert); | |
525 | while (record) { | |
526 | cert = sslPEMtoASN1(record, "CERTIFICATE", &certSize, | |
527 | &record); | |
528 | if (cert) { | |
529 | X509 *x509; | |
530 | const unsigned char *c = cert; | |
531 | check(x509 = d2i_X509(NULL, &c, certSize)); | |
532 | memset((char *)cert, 0, certSize); | |
533 | free((char *)cert); | |
534 | if (!SSL_CTX_add_extra_chain_cert(context, x509)) { | |
535 | X509_free(x509); | |
536 | break; | |
537 | } | |
538 | } | |
539 | } | |
540 | if (!record && SSL_CTX_check_private_key(context)) { | |
541 | rc = 1; | |
542 | } | |
543 | dcheck(!ERR_peek_error()); | |
544 | ERR_clear_error(); | |
545 | } else { | |
546 | memset((char *)cert, 0, certSize); | |
547 | free((char *)cert); | |
548 | } | |
549 | memset((char *)data, 0, dataSize); | |
550 | free((char *)data); | |
551 | memset((char *)rsa, 0, rsaSize); | |
552 | free((char *)rsa); | |
553 | memset((char *)dsa, 0, dsaSize); | |
554 | free((char *)dsa); | |
555 | memset((char *)ec, 0, ecSize); | |
556 | free((char *)ec); | |
28ff61e1 JW |
557 | memset((char *)notype, 0, notypeSize); |
558 | free((char *)notype); | |
ad24d9a9 MG |
559 | return rc; |
560 | } | |
561 | ||
562 | static int sslSetCertificateFromFile(SSL_CTX *context, | |
563 | const char *filename) { | |
564 | int fd = open(filename, O_RDONLY); | |
565 | if (fd < 0) { | |
566 | return -1; | |
567 | } | |
568 | int rc = sslSetCertificateFromFd(context, fd); | |
ad24d9a9 MG |
569 | return rc; |
570 | } | |
bdd01e84 | 571 | #endif |
7460295f | 572 | |
d04f7ca7 | 573 | #ifdef HAVE_TLSEXT |
242e6c5b MG |
574 | static int sslSNICallback(SSL *sslHndl, int *al ATTR_UNUSED, |
575 | struct SSLSupport *ssl) { | |
576 | UNUSED(al); | |
7460295f MG |
577 | check(!ERR_peek_error()); |
578 | const char *name = SSL_get_servername(sslHndl, | |
579 | TLSEXT_NAMETYPE_host_name); | |
580 | if (name == NULL || !*name) { | |
581 | return SSL_TLSEXT_ERR_OK; | |
582 | } | |
583 | struct HttpConnection *http = | |
584 | (struct HttpConnection *)SSL_get_app_data(sslHndl); | |
585 | debug("Received SNI callback for virtual host \"%s\" from \"%s:%d\"", | |
586 | name, httpGetPeerName(http), httpGetPort(http)); | |
587 | char *serverName; | |
588 | check(serverName = malloc(strlen(name)+2)); | |
589 | serverName[0] = '-'; | |
590 | for (int i = 0;;) { | |
591 | char ch = name[i]; | |
592 | if (ch >= 'A' && ch <= 'Z') { | |
593 | ch |= 0x20; | |
594 | } else if (ch != '\000' && ch != '.' && ch != '-' && | |
595 | (ch < '0' ||(ch > '9' && ch < 'A') || (ch > 'Z' && | |
596 | ch < 'a')|| ch > 'z')) { | |
8059075f AK |
597 | free(serverName); |
598 | return SSL_TLSEXT_ERR_OK; | |
7460295f MG |
599 | } |
600 | serverName[++i] = ch; | |
601 | if (!ch) { | |
602 | break; | |
603 | } | |
604 | } | |
7460295f MG |
605 | SSL_CTX *context = (SSL_CTX *)getFromTrie(&ssl->sniContexts, |
606 | serverName+1, | |
607 | NULL); | |
608 | if (context == NULL) { | |
609 | check(context = SSL_CTX_new(SSLv23_server_method())); | |
610 | check(ssl->sniCertificatePattern); | |
9b850878 MG |
611 | char *certificate = stringPrintfUnchecked(NULL, |
612 | ssl->sniCertificatePattern, | |
613 | serverName); | |
ad24d9a9 | 614 | if (sslSetCertificateFromFile(context, certificate) < 0) { |
7460295f MG |
615 | if (ssl->generateMissing) { |
616 | sslGenerateCertificate(certificate, serverName + 1); | |
ad24d9a9 MG |
617 | |
618 | // No need to check the certificate. If we fail to set it, we will use | |
619 | // the default certificate, instead. | |
620 | sslSetCertificateFromFile(context, certificate); | |
7460295f | 621 | } else { |
7460295f MG |
622 | warn("Could not find matching certificate \"%s\" for \"%s\"", |
623 | certificate, serverName + 1); | |
624 | SSL_CTX_free(context); | |
625 | context = ssl->sslContext; | |
626 | } | |
627 | } | |
628 | ERR_clear_error(); | |
629 | free(certificate); | |
630 | addToTrie(&ssl->sniContexts, serverName+1, (char *)context); | |
631 | } | |
632 | free(serverName); | |
633 | if (context != ssl->sslContext) { | |
bc83b450 | 634 | check(SSL_set_SSL_CTX(sslHndl, context)); |
7460295f MG |
635 | } |
636 | check(!ERR_peek_error()); | |
637 | return SSL_TLSEXT_ERR_OK; | |
638 | } | |
639 | #endif | |
640 | ||
4101fea2 | 641 | #if defined(HAVE_OPENSSL) && !defined(HAVE_GETHOSTBYNAME_R) |
572ac014 MG |
642 | // This is a not-thread-safe replacement for gethostbyname_r() |
643 | #define gethostbyname_r x_gethostbyname_r | |
644 | static int gethostbyname_r(const char *name, struct hostent *ret, | |
242e6c5b | 645 | char *buf ATTR_UNUSED, size_t buflen ATTR_UNUSED, |
572ac014 | 646 | struct hostent **result, int *h_errnop) { |
242e6c5b MG |
647 | UNUSED(buf); |
648 | UNUSED(buflen); | |
572ac014 MG |
649 | if (result) { |
650 | *result = NULL; | |
651 | } | |
652 | if (h_errnop) { | |
653 | *h_errnop = ERANGE; | |
654 | } | |
655 | if (!ret) { | |
656 | return -1; | |
657 | } | |
658 | struct hostent *he = gethostbyname(name); | |
4101fea2 MG |
659 | if (he) { |
660 | *ret = *he; | |
661 | if (result) { | |
662 | *result = ret; | |
663 | } | |
572ac014 MG |
664 | } |
665 | if (h_errnop) { | |
666 | *h_errnop = h_errno; | |
667 | } | |
4101fea2 | 668 | return he ? 0 : -1; |
572ac014 MG |
669 | } |
670 | #endif | |
671 | ||
7460295f MG |
672 | void sslSetCertificate(struct SSLSupport *ssl, const char *filename, |
673 | int autoGenerateMissing) { | |
674 | #if defined(HAVE_OPENSSL) | |
675 | check(serverSupportsSSL()); | |
676 | ||
677 | char *defaultCertificate; | |
678 | check(defaultCertificate = strdup(filename)); | |
679 | char *ptr = strchr(defaultCertificate, '%'); | |
680 | if (ptr != NULL) { | |
681 | check(!strchr(ptr+1, '%')); | |
682 | check(ptr[1] == 's'); | |
683 | memmove(ptr, ptr + 2, strlen(ptr)-1); | |
684 | } | |
685 | ||
ad24d9a9 | 686 | // Try to set the default certificate. If necessary, (re-)generate it. |
7460295f MG |
687 | check(ssl->sslContext = SSL_CTX_new(SSLv23_server_method())); |
688 | if (autoGenerateMissing) { | |
ad24d9a9 | 689 | if (sslSetCertificateFromFile(ssl->sslContext, defaultCertificate) < 0) { |
7460295f MG |
690 | char hostname[256], buf[4096]; |
691 | check(!gethostname(hostname, sizeof(hostname))); | |
692 | struct hostent he_buf, *he; | |
06513c67 JW |
693 | int h_err = 0; |
694 | int ret = gethostbyname_r(hostname, &he_buf, buf, sizeof(buf), &he, &h_err); | |
695 | if (!ret && he && he->h_name) { | |
7460295f | 696 | sslGenerateCertificate(defaultCertificate, he->h_name); |
06513c67 JW |
697 | } else { |
698 | if (h_err) { | |
699 | warn("Error getting host information: \"%s\".", hstrerror(h_err)); | |
700 | } | |
701 | sslGenerateCertificate(defaultCertificate, hostname); | |
7460295f MG |
702 | } |
703 | } else { | |
704 | goto valid_certificate; | |
705 | } | |
706 | } | |
ad24d9a9 | 707 | if (sslSetCertificateFromFile(ssl->sslContext, defaultCertificate) < 0) { |
7460295f MG |
708 | fatal("Cannot read valid certificate from \"%s\". " |
709 | "Check file permissions and file format.", defaultCertificate); | |
710 | } | |
711 | valid_certificate: | |
712 | free(defaultCertificate); | |
713 | ||
ad24d9a9 MG |
714 | // Enable SNI support so that we can set a different certificate, if the |
715 | // client asked for it. | |
d04f7ca7 | 716 | #ifdef HAVE_TLSEXT |
7460295f MG |
717 | if (ptr != NULL) { |
718 | check(ssl->sniCertificatePattern = strdup(filename)); | |
719 | check(SSL_CTX_set_tlsext_servername_callback(ssl->sslContext, | |
720 | sslSNICallback)); | |
721 | check(SSL_CTX_set_tlsext_servername_arg(ssl->sslContext, ssl)); | |
722 | } | |
723 | #endif | |
724 | dcheck(!ERR_peek_error()); | |
725 | ERR_clear_error(); | |
726 | ||
727 | ssl->generateMissing = autoGenerateMissing; | |
728 | #endif | |
729 | } | |
730 | ||
ad24d9a9 MG |
731 | // Convert the file descriptor to a human-readable format. Attempts to |
732 | // retrieve the original file name where possible. | |
dc6575f2 | 733 | #ifdef HAVE_OPENSSL |
ad24d9a9 MG |
734 | static char *sslFdToFilename(int fd) { |
735 | char *proc, *buf; | |
736 | int len = 128; | |
737 | check(proc = stringPrintf(NULL, "/proc/self/fd/%d", fd)); | |
738 | check(buf = malloc(len)); | |
dc6575f2 | 739 | for (;;) { |
ad24d9a9 MG |
740 | ssize_t i; |
741 | if ((i = readlink(proc, buf + 1, len-3)) < 0) { | |
742 | free(proc); | |
743 | free(buf); | |
744 | check(buf = stringPrintf(NULL, "fd %d", fd)); | |
745 | return buf; | |
746 | } else if (i >= len-3) { | |
747 | len += 512; | |
748 | check(buf = realloc(buf, len)); | |
dc6575f2 | 749 | } else { |
ad24d9a9 MG |
750 | free(proc); |
751 | check(i >= 0 && i < len); | |
752 | buf[i+1] = '\000'; | |
753 | struct stat sb; | |
754 | if (!stat(buf + 1, &sb) && S_ISREG(sb.st_mode)) { | |
755 | *buf = '"'; | |
756 | buf[i + 1] = '"'; | |
757 | buf[i + 2] = '\000'; | |
758 | return buf; | |
759 | } else { | |
760 | free(buf); | |
761 | check(buf = stringPrintf(NULL, "fd %d", fd)); | |
762 | return buf; | |
763 | } | |
dc6575f2 MG |
764 | } |
765 | } | |
dc6575f2 MG |
766 | } |
767 | #endif | |
768 | ||
769 | void sslSetCertificateFd(struct SSLSupport *ssl, int fd) { | |
770 | #ifdef HAVE_OPENSSL | |
ad24d9a9 | 771 | check(ssl->sslContext = SSL_CTX_new(SSLv23_server_method())); |
48f25965 | 772 | char *filename = sslFdToFilename(fd); |
ad24d9a9 MG |
773 | if (!sslSetCertificateFromFd(ssl->sslContext, fd)) { |
774 | fatal("Cannot read valid certificate from %s. Check file format.", | |
48f25965 | 775 | filename); |
dc6575f2 | 776 | } |
48f25965 | 777 | free(filename); |
ad24d9a9 | 778 | ssl->generateMissing = 0; |
dc6575f2 MG |
779 | #endif |
780 | } | |
781 | ||
7460295f MG |
782 | int sslEnable(struct SSLSupport *ssl, int enabled) { |
783 | int old = ssl->enabled; | |
784 | ssl->enabled = enabled; | |
785 | return old; | |
786 | } | |
787 | ||
788 | void sslBlockSigPipe(void) { | |
789 | sigset_t set; | |
790 | sigemptyset(&set); | |
791 | sigaddset(&set, SIGPIPE); | |
9d758d39 | 792 | #if defined(HAVE_PTHREAD_H) && defined(__linux__) && defined(__i386__) |
c593cf68 MG |
793 | if (&pthread_sigmask) { |
794 | dcheck(!pthread_sigmask(SIG_BLOCK, &set, NULL)); | |
9d758d39 MG |
795 | } else |
796 | #endif | |
797 | { | |
c593cf68 MG |
798 | dcheck(!sigprocmask(SIG_BLOCK, &set, NULL)); |
799 | } | |
7460295f MG |
800 | } |
801 | ||
572ac014 MG |
802 | #ifndef HAVE_SIGWAIT |
803 | // This is a non-thread-safe replacement for sigwait() | |
804 | static int dummysignalno; | |
805 | static void dummysignal(int signo) { | |
806 | dummysignalno = signo; | |
807 | } | |
808 | ||
809 | #define sigwait x_sigwait | |
810 | static int sigwait(const sigset_t *set, int *sig) { | |
811 | sigset_t mask, old_mask; | |
812 | sigfillset(&mask); | |
9d758d39 | 813 | #if defined(HAVE_PTHREAD_H) && defined(__linux__) && defined(__i386__) |
572ac014 MG |
814 | if (&pthread_sigmask) { |
815 | dcheck(!pthread_sigmask(SIG_BLOCK, &mask, &old_mask)); | |
9d758d39 MG |
816 | } else |
817 | #endif | |
818 | { | |
572ac014 MG |
819 | dcheck(!sigprocmask(SIG_BLOCK, &mask, &old_mask)); |
820 | } | |
821 | #ifndef NSIG | |
822 | #define NSIG 32 | |
823 | #endif | |
824 | struct sigaction sa[NSIG]; | |
825 | memset(sa, 0, sizeof(sa)); | |
826 | sa->sa_handler = dummysignal; | |
827 | for (int i = 1; i <= NSIG; i++) { | |
828 | if (sigismember(set, i)) { | |
829 | sigdelset(&mask, i); | |
830 | sigaction(i, sa, sa + i); | |
831 | } | |
832 | } | |
833 | dummysignalno = -1; | |
834 | sigsuspend(&mask); | |
9d758d39 | 835 | #if defined(HAVE_PTHREAD_H) && defined(__linux__) && defined(__i386__) |
572ac014 MG |
836 | if (&pthread_sigmask) { |
837 | dcheck(!pthread_sigmask(SIG_SETMASK, &old_mask, NULL)); | |
9d758d39 MG |
838 | } else |
839 | #endif | |
840 | { | |
572ac014 MG |
841 | dcheck(!sigprocmask(SIG_BLOCK, &old_mask, NULL)); |
842 | } | |
843 | return dummysignalno; | |
844 | } | |
845 | #endif | |
846 | ||
7460295f MG |
847 | int sslUnblockSigPipe(void) { |
848 | int signum = 0; | |
849 | sigset_t set; | |
850 | check(!sigpending(&set)); | |
851 | if (sigismember(&set, SIGPIPE)) { | |
852 | sigwait(&set, &signum); | |
853 | } | |
854 | sigemptyset(&set); | |
855 | sigaddset(&set, SIGPIPE); | |
9d758d39 | 856 | #if defined(HAVE_PTHREAD_H) && defined(__linux__) && defined(__i386__) |
c593cf68 MG |
857 | if (&pthread_sigmask) { |
858 | dcheck(!pthread_sigmask(SIG_UNBLOCK, &set, NULL)); | |
9d758d39 MG |
859 | } else |
860 | #endif | |
861 | { | |
c593cf68 MG |
862 | dcheck(!sigprocmask(SIG_UNBLOCK, &set, NULL)); |
863 | } | |
7460295f MG |
864 | return signum; |
865 | } | |
866 | ||
867 | int sslPromoteToSSL(struct SSLSupport *ssl, SSL **sslHndl, int fd, | |
868 | const char *buf, int len) { | |
869 | #if defined(HAVE_OPENSSL) | |
870 | sslBlockSigPipe(); | |
871 | int rc = 0; | |
872 | check(!*sslHndl); | |
873 | dcheck(!ERR_peek_error()); | |
874 | dcheck(*sslHndl = SSL_new(ssl->sslContext)); | |
875 | if (*sslHndl == NULL) { | |
876 | ERR_clear_error(); | |
877 | errno = EINVAL; | |
878 | rc = -1; | |
879 | } else { | |
880 | SSL_set_mode(*sslHndl, SSL_MODE_ENABLE_PARTIAL_WRITE); | |
881 | BIO *writeBIO = BIO_new_socket(fd, 0); | |
882 | BIO *readBIO = writeBIO; | |
883 | if (len > 0) { | |
884 | readBIO = BIO_new(BIO_f_buffer()); | |
885 | BIO_push(readBIO, writeBIO); | |
886 | check(BIO_set_buffer_read_data(readBIO, (char *)buf, len)); | |
887 | } | |
888 | SSL_set_bio(*sslHndl, readBIO, writeBIO); | |
889 | SSL_set_accept_state(*sslHndl); | |
890 | dcheck(!ERR_peek_error()); | |
891 | } | |
892 | sslUnblockSigPipe(); | |
893 | return rc; | |
894 | #else | |
895 | errno = EINVAL; | |
896 | return -1; | |
897 | #endif | |
898 | } | |
899 | ||
900 | void sslFreeHndl(SSL **sslHndl) { | |
901 | #if defined(HAVE_OPENSSL) | |
902 | if (*sslHndl) { | |
903 | // OpenSSL does not always correctly perform reference counting for stacked | |
904 | // BIOs. This is particularly a problem if an SSL connection has two | |
905 | // different BIOs for the read and the write end, with one being a stacked | |
906 | // derivative of the other. Unfortunately, this is exactly the scenario | |
907 | // that we set up. | |
908 | // As a work-around, we un-stack the BIOs prior to freeing the SSL | |
909 | // connection. | |
910 | ERR_clear_error(); | |
911 | BIO *writeBIO, *readBIO; | |
912 | check(writeBIO = SSL_get_wbio(*sslHndl)); | |
913 | check(readBIO = SSL_get_rbio(*sslHndl)); | |
914 | if (writeBIO != readBIO) { | |
915 | if (readBIO->next_bio == writeBIO) { | |
916 | // OK, that's exactly the bug we are looking for. We know how to | |
917 | // fix it. | |
918 | check(BIO_pop(readBIO) == writeBIO); | |
919 | check(readBIO->references == 1); | |
920 | check(writeBIO->references == 1); | |
921 | check(!readBIO->next_bio); | |
922 | check(!writeBIO->prev_bio); | |
923 | } else if (readBIO->next_bio == writeBIO->next_bio && | |
924 | writeBIO->next_bio->prev_bio == writeBIO) { | |
925 | // Things get even more confused, if the SSL handshake is aborted | |
926 | // prematurely. | |
927 | // OpenSSL appears to internally stack a BIO onto the read end that | |
928 | // does not get removed afterwards. We end up with the original | |
929 | // socket BIO having two different BIOs prepended to it (one for | |
930 | // reading and one for writing). In this case, not only is the | |
931 | // reference count wrong, but the chain of next_bio/prev_bio pairs | |
932 | // is corrupted, too. | |
933 | BIO *sockBIO; | |
934 | check(sockBIO = BIO_pop(readBIO)); | |
935 | check(sockBIO == BIO_pop(writeBIO)); | |
936 | check(readBIO->references == 1); | |
937 | check(writeBIO->references == 1); | |
938 | check(sockBIO->references == 1); | |
939 | check(!readBIO->next_bio); | |
940 | check(!writeBIO->next_bio); | |
941 | check(!sockBIO->prev_bio); | |
942 | BIO_free_all(sockBIO); | |
943 | } else { | |
944 | // We do not know, how to fix this situation. Something must have | |
945 | // changed in the OpenSSL internals. Either, this is a new bug, or | |
946 | // somebody fixed the code in a way that we did not anticipate. | |
947 | fatal("Unexpected corruption of OpenSSL data structures"); | |
948 | } | |
949 | } | |
950 | SSL_free(*sslHndl); | |
951 | dcheck(!ERR_peek_error()); | |
952 | } | |
953 | #endif | |
954 | *sslHndl = NULL; | |
955 | } |