xref: /lighttpd1.4/src/mod_wolfssl.c (revision 82a26c1b)
1 /*
2  * mod_wolfssl - wolfSSL support for lighttpd
3  *
4  * Copyright(c) 2020 Glenn Strauss gstrauss()gluelogic.com  All rights reserved
5  * License: BSD 3-clause (same as lighttpd)
6  */
7 /*
8  * Note: If session tickets are -not- disabled with
9  *     ssl.openssl.ssl-conf-cmd = ("Options" => "-SessionTicket")
10  *   mod_wolfssl rotates server ticket encryption key (STEK) every 8 hours
11  *   and keeps the prior two STEKs around, so ticket lifetime is 24 hours.
12  *   This is fine for use with a single lighttpd instance, but with multiple
13  *   lighttpd workers, no coordinated STEK (server ticket encryption key)
14  *   rotation occurs unless ssl.stek-file is defined and maintained (preferred),
15  *   or if some external job restarts lighttpd.  Restarting lighttpd generates a
16  *   new key that is shared by lighttpd workers for the lifetime of the new key.
17  *   If the rotation period expires and lighttpd has not been restarted, and if
18  *   ssl.stek-file is not in use, then lighttpd workers will generate new
19  *   independent keys, making session tickets less effective for session
20  *   resumption, since clients have a lower chance for future connections to
21  *   reach the same lighttpd worker.  However, things will still work, and a new
22  *   session will be created if session resumption fails.  Admins should plan to
23  *   restart lighttpd at least every 8 hours if session tickets are enabled and
24  *   multiple lighttpd workers are configured.  Since that is likely disruptive,
25  *   if multiple lighttpd workers are configured, ssl.stek-file should be
26  *   defined and the file maintained externally.
27  */
28 #include "first.h"
29 
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include <errno.h>
33 #include <fcntl.h>
34 #include <stdint.h>
35 #include <stdlib.h>
36 #include <string.h>
37 
38 /*
39  * Note: mod_wolfssl.c is forked from mod_openssl.c
40  * Many internal symbol names in mod_wolfssl.c retain the mod_openssl_* prefix
41  * (wolfSSL provides an OpenSSL compatibility layer)
42  */
43 
44 /* wolfSSL needs to be built with ./configure --enable-lighty for lighttpd.
45  * Doing so defines OPENSSL_EXTRA and HAVE_LIGHTY in <wolfssl/options.h>, and
46  * these defines are necessary for wolfSSL headers to expose sufficient openssl
47  * compatibility layer for wolfSSL to be able to provide an openssl substitute
48  * for use by lighttpd */
49 
50 /* workaround fragile code in wolfssl/wolfcrypto/types.h */
51 #if !defined(SIZEOF_LONG) || !defined(SIZEOF_LONG_LONG)
52 #undef SIZEOF_LONG
53 #undef SIZEOF_LONG_LONG
54 #endif
55 
56 #include <wolfssl/options.h>
57 #include <wolfssl/ssl.h>
58 #ifdef HAVE_OCSP
59 #include <wolfssl/ocsp.h>
60 #endif
61 
62 static char global_err_buf[WOLFSSL_MAX_ERROR_SZ];
63 #undef ERR_error_string
64 #define ERR_error_string(e,b) \
65         (wolfSSL_ERR_error_string_n((e),global_err_buf,WOLFSSL_MAX_ERROR_SZ), \
66          global_err_buf)
67 
68 #if 0 /* symbols and definitions requires WolfSSL built with -DOPENSSL_EXTRA */
69 #define SSL_TLSEXT_ERR_OK               0
70 #define SSL_TLSEXT_ERR_ALERT_FATAL      alert_fatal
71 #define SSL_TLSEXT_ERR_NOACK            alert_warning
72 
73 WOLFSSL_API void wolfSSL_set_verify_depth(WOLFSSL *ssl,int depth);
74 
75 WOLFSSL_API void wolfSSL_X509_NAME_free(WOLFSSL_X509_NAME* name);
76 WOLFSSL_API int wolfSSL_X509_NAME_cmp(const WOLFSSL_X509_NAME* x, const WOLFSSL_X509_NAME* y);
77 WOLFSSL_API WOLFSSL_X509_NAME* wolfSSL_X509_NAME_dup(WOLFSSL_X509_NAME*);
78 WOLFSSL_API char* wolfSSL_X509_get_name_oneline(WOLFSSL_X509_NAME*, char*, int);
79 
80 WOLFSSL_API const char* wolfSSL_OBJ_nid2sn(int n);
81 WOLFSSL_API int wolfSSL_OBJ_obj2nid(const WOLFSSL_ASN1_OBJECT *o);
82 WOLFSSL_API WOLFSSL_ASN1_OBJECT * wolfSSL_X509_NAME_ENTRY_get_object(WOLFSSL_X509_NAME_ENTRY *ne);
83 WOLFSSL_API WOLFSSL_X509_NAME_ENTRY *wolfSSL_X509_NAME_get_entry(WOLFSSL_X509_NAME *name, int loc);
84 #endif
85 
86 #if LIBWOLFSSL_VERSION_HEX < 0x04005000
87 #if !defined(OPENSSL_ALL) || LIBWOLFSSL_VERSION_HEX < 0x04002000
88 /*(invalid; but centralize making these calls no-ops)*/
89 #define wolfSSL_sk_X509_NAME_num(a)          0
90 #define wolfSSL_sk_X509_NAME_push(a, b)      0
91 #define wolfSSL_sk_X509_NAME_pop_free(a, b)  do { } while (0)
92 #define wolfSSL_sk_X509_NAME_free(a)         do { } while (0)
93 #define wolfSSL_X509_get_subject_name(ca) \
94         ((WOLFSSL_X509_NAME *)1) /* ! NULL */
95 #define wolfSSL_sk_X509_NAME_new(a) \
96         ((WOLF_STACK_OF(WOLFSSL_X509_NAME) *)1) /* ! NULL */
97 #endif
98 #endif
99 
100 #if LIBWOLFSSL_VERSION_HEX < 0x04006000 || defined(WOLFSSL_NO_FORCE_ZERO)
101 #define wolfSSL_OPENSSL_cleanse(x,sz) ck_memzero((x),(sz))
102 #endif
103 
104 #if LIBWOLFSSL_VERSION_HEX < 0x04002000 /*(exact version needed not checked)*/
105 #ifndef STACK_OF
106 #define STACK_OF(x) WOLFSSL_STACK
107 #endif
108 #endif
109 
110 #include "base.h"
111 #include "ck.h"
112 #include "fdevent.h"
113 #include "http_header.h"
114 #include "http_kv.h"
115 #include "log.h"
116 #include "plugin.h"
117 
118 typedef struct {
119     /* SNI per host: with COMP_SERVER_SOCKET, COMP_HTTP_SCHEME, COMP_HTTP_HOST */
120     buffer *ssl_pemfile_pkey;
121     buffer *ssl_pemfile_x509;
122     buffer **ssl_pemfile_chain;
123     buffer *ssl_stapling;
124     const buffer *ssl_pemfile;
125     const buffer *ssl_privkey;
126     const buffer *ssl_stapling_file;
127     unix_time64_t ssl_stapling_loadts;
128     unix_time64_t ssl_stapling_nextts;
129     char must_staple;
130 } plugin_cert;
131 
132 typedef struct {
133     WOLFSSL_CTX *ssl_ctx;
134 } plugin_ssl_ctx;
135 
136 typedef struct {
137     STACK_OF(X509_NAME) *names;
138     X509_STORE *certs;
139 } plugin_cacerts;
140 
141 typedef struct {
142     WOLFSSL_CTX *ssl_ctx; /* output from network_init_ssl() */
143 
144     /*(used only during startup; not patched)*/
145     unsigned char ssl_enabled; /* only interesting for setting up listening sockets. don't use at runtime */
146     unsigned char ssl_honor_cipher_order; /* determine SSL cipher in server-preferred order, not client-order */
147     const buffer *ssl_cipher_list;
148     array *ssl_conf_cmd;
149 
150     /*(copied from plugin_data for socket ssl_ctx config)*/
151     const plugin_cert *pc;
152     const plugin_cacerts *ssl_ca_file;
153     STACK_OF(X509_NAME) *ssl_ca_dn_file;
154     const buffer *ssl_ca_crl_file;
155     unsigned char ssl_verifyclient;
156     unsigned char ssl_verifyclient_enforce;
157     unsigned char ssl_verifyclient_depth;
158     unsigned char ssl_read_ahead;
159 } plugin_config_socket; /*(used at startup during configuration)*/
160 
161 typedef struct {
162     /* SNI per host: w/ COMP_SERVER_SOCKET, COMP_HTTP_SCHEME, COMP_HTTP_HOST */
163     plugin_cert *pc;
164     const plugin_cacerts *ssl_ca_file;
165     STACK_OF(X509_NAME) *ssl_ca_dn_file;
166     const buffer *ssl_ca_crl_file;
167 
168     unsigned char ssl_verifyclient;
169     unsigned char ssl_verifyclient_enforce;
170     unsigned char ssl_verifyclient_depth;
171     unsigned char ssl_verifyclient_export_cert;
172     unsigned char ssl_read_ahead;
173     unsigned char ssl_log_noise;
174     const buffer *ssl_verifyclient_username;
175     const buffer *ssl_acme_tls_1;
176 } plugin_config;
177 
178 typedef struct {
179     PLUGIN_DATA;
180     plugin_ssl_ctx *ssl_ctxs;
181     plugin_config defaults;
182     server *srv;
183     array *cafiles;
184     const char *ssl_stek_file;
185 } plugin_data;
186 
187 static int ssl_is_init;
188 /* need assigned p->id for deep access of module handler_ctx for connection
189  *   i.e. handler_ctx *hctx = con->plugin_ctx[plugin_data_singleton->id]; */
190 static plugin_data *plugin_data_singleton;
191 #define LOCAL_SEND_BUFSIZE (16 * 1024)
192 static char *local_send_buffer;
193 
194 typedef struct {
195     WOLFSSL *ssl;
196     request_st *r;
197     connection *con;
198     short renegotiations; /* count of SSL_CB_HANDSHAKE_START */
199     short close_notify;
200     unsigned short alpn;
201     plugin_config conf;
202     buffer *tmp_buf;
203     log_error_st *errh;
204 } handler_ctx;
205 
206 
207 static handler_ctx *
handler_ctx_init(void)208 handler_ctx_init (void)
209 {
210     return ck_calloc(1, sizeof(handler_ctx));
211 }
212 
213 
214 static void
handler_ctx_free(handler_ctx * hctx)215 handler_ctx_free (handler_ctx *hctx)
216 {
217     if (hctx->ssl) SSL_free(hctx->ssl);
218     free(hctx);
219 }
220 
221 
222 #ifdef HAVE_SESSION_TICKET
223 /* ssl/ssl_local.h */
224 #define TLSEXT_KEYNAME_LENGTH  16
225 #define TLSEXT_TICK_KEY_LENGTH 32
226 
227 /* openssl has a huge number of interfaces, but not the most useful;
228  * construct our own session ticket encryption key structure */
229 typedef struct tlsext_ticket_key_st {
230     unix_time64_t active_ts; /* tickets not issued w/ key until activation ts*/
231     unix_time64_t expire_ts; /* key not valid after expiration timestamp */
232     unsigned char tick_key_name[TLSEXT_KEYNAME_LENGTH];
233     unsigned char tick_hmac_key[TLSEXT_TICK_KEY_LENGTH];
234     unsigned char tick_aes_key[TLSEXT_TICK_KEY_LENGTH];
235 } tlsext_ticket_key_t;
236 
237 static tlsext_ticket_key_t session_ticket_keys[4];
238 static unix_time64_t stek_rotate_ts;
239 
240 
241 static int
mod_openssl_session_ticket_key_generate(unix_time64_t active_ts,unix_time64_t expire_ts)242 mod_openssl_session_ticket_key_generate (unix_time64_t active_ts, unix_time64_t expire_ts)
243 {
244     /* openssl RAND_*bytes() functions are called multiple times since the
245      * funcs might have a 32-byte limit on number of bytes returned each call
246      *
247      * (Note: session ticket encryption key generation is not expected to fail)
248      *
249      * 3 keys are stored in session_ticket_keys[]
250      * The 4th element of session_ticket_keys[] is used for STEK construction
251      */
252     /*(RAND_priv_bytes() not in openssl 1.1.0; introduced in openssl 1.1.1)*/
253   #define RAND_priv_bytes(x,sz) RAND_bytes((x),(sz))
254     if (RAND_bytes(session_ticket_keys[3].tick_key_name,
255                    TLSEXT_KEYNAME_LENGTH) <= 0
256         || RAND_priv_bytes(session_ticket_keys[3].tick_hmac_key,
257                            TLSEXT_TICK_KEY_LENGTH) <= 0
258         || RAND_priv_bytes(session_ticket_keys[3].tick_aes_key,
259                            TLSEXT_TICK_KEY_LENGTH) <= 0)
260         return 0;
261     session_ticket_keys[3].active_ts = active_ts;
262     session_ticket_keys[3].expire_ts = expire_ts;
263     return 1;
264 }
265 
266 
267 static void
mod_openssl_session_ticket_key_rotate(void)268 mod_openssl_session_ticket_key_rotate (void)
269 {
270     /* discard oldest key (session_ticket_keys[2]) and put newest key first
271      * 3 keys are stored in session_ticket_keys[0], [1], [2]
272      * session_ticket_keys[3] is used to construct and pass new STEK */
273 
274     session_ticket_keys[2] = session_ticket_keys[1];
275     session_ticket_keys[1] = session_ticket_keys[0];
276     /*memmove(session_ticket_keys+1,
277               session_ticket_keys+0, sizeof(tlsext_ticket_key_t)*2);*/
278     session_ticket_keys[0] = session_ticket_keys[3];
279 
280     wolfSSL_OPENSSL_cleanse(session_ticket_keys+3, sizeof(tlsext_ticket_key_t));
281 }
282 
283 
284 static tlsext_ticket_key_t *
tlsext_ticket_key_get(void)285 tlsext_ticket_key_get (void)
286 {
287     const unix_time64_t cur_ts = log_epoch_secs;
288     const int e = sizeof(session_ticket_keys)/sizeof(*session_ticket_keys) - 1;
289     for (int i = 0; i < e; ++i) {
290         if (session_ticket_keys[i].active_ts > cur_ts) continue;
291         if (session_ticket_keys[i].expire_ts < cur_ts) continue;
292         return &session_ticket_keys[i];
293     }
294     return NULL;
295 }
296 
297 
298 static tlsext_ticket_key_t *
tlsext_ticket_key_find(unsigned char key_name[16],int * refresh)299 tlsext_ticket_key_find (unsigned char key_name[16], int *refresh)
300 {
301     *refresh = 0;
302     const unix_time64_t cur_ts = log_epoch_secs;
303     const int e = sizeof(session_ticket_keys)/sizeof(*session_ticket_keys) - 1;
304     for (int i = 0; i < e; ++i) {
305         if (session_ticket_keys[i].expire_ts < cur_ts) continue;
306         if (0 == memcmp(session_ticket_keys[i].tick_key_name, key_name, 16))
307             return &session_ticket_keys[i];
308         if (session_ticket_keys[i].active_ts <= cur_ts)
309             *refresh = 1; /* newer active key is available */
310     }
311     return NULL;
312 }
313 
314 
315 static void
tlsext_ticket_wipe_expired(const unix_time64_t cur_ts)316 tlsext_ticket_wipe_expired (const unix_time64_t cur_ts)
317 {
318     const int e = sizeof(session_ticket_keys)/sizeof(*session_ticket_keys) - 1;
319     for (int i = 0; i < e; ++i) {
320         if (session_ticket_keys[i].expire_ts != 0
321             && session_ticket_keys[i].expire_ts < cur_ts)
322             wolfSSL_OPENSSL_cleanse(session_ticket_keys+i,
323                                     sizeof(tlsext_ticket_key_t));
324     }
325 }
326 
327 
328 /* based on reference implementation from openssl 1.1.1g man page
329  *   man SSL_CTX_set_tlsext_ticket_key_cb
330  * but openssl code uses EVP_aes_256_cbc() instead of EVP_aes_128_cbc()
331  */
332 #ifndef EVP_MAX_IV_LENGTH
333 #define EVP_MAX_IV_LENGTH 16
334 #endif
335 static int
ssl_tlsext_ticket_key_cb(SSL * s,unsigned char key_name[16],unsigned char iv[EVP_MAX_IV_LENGTH],EVP_CIPHER_CTX * ctx,HMAC_CTX * hctx,int enc)336 ssl_tlsext_ticket_key_cb (SSL *s, unsigned char key_name[16],
337                           unsigned char iv[EVP_MAX_IV_LENGTH],
338                           EVP_CIPHER_CTX *ctx, HMAC_CTX *hctx, int enc)
339 {
340     UNUSED(s);
341     if (enc) { /* create new session */
342         tlsext_ticket_key_t *k = tlsext_ticket_key_get();
343         if (NULL == k)
344             return 0; /* current key does not exist or is not valid */
345         memcpy(key_name, k->tick_key_name, 16);
346         if (RAND_bytes(iv, EVP_MAX_IV_LENGTH) <= 0)
347             return -1; /* insufficient random */
348         EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, k->tick_aes_key, iv);
349         HMAC_Init_ex(hctx, k->tick_hmac_key, sizeof(k->tick_hmac_key),
350                      EVP_sha256(), NULL);
351         return 1;
352     }
353     else { /* retrieve session */
354         int refresh;
355         tlsext_ticket_key_t *k = tlsext_ticket_key_find(key_name, &refresh);
356         if (NULL == k)
357             return 0;
358         HMAC_Init_ex(hctx, k->tick_hmac_key, sizeof(k->tick_hmac_key),
359                      EVP_sha256(), NULL);
360         EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, k->tick_aes_key, iv);
361         return refresh ? 2 : 1;
362         /* 'refresh' will trigger issuing new ticket for session
363          * even though the current ticket is still valid */
364     }
365 }
366 
367 
368 static int
mod_openssl_session_ticket_key_file(const char * fn)369 mod_openssl_session_ticket_key_file (const char *fn)
370 {
371     /* session ticket encryption key (STEK)
372      *
373      * STEK file should be stored in non-persistent storage,
374      *   e.g. /dev/shm/lighttpd/stek-file  (in memory)
375      * with appropriate permissions set to keep stek-file from being
376      * read by other users.  Where possible, systems should also be
377      * configured without swap.
378      *
379      * admin should schedule an independent job to periodically
380      *   generate new STEK up to 3 times during key lifetime
381      *   (lighttpd stores up to 3 keys)
382      *
383      * format of binary file is:
384      *    4-byte - format version (always 0; for use if format changes)
385      *    4-byte - activation timestamp
386      *    4-byte - expiration timestamp
387      *   16-byte - session ticket key name
388      *   32-byte - session ticket HMAC encrpytion key
389      *   32-byte - session ticket AES encrpytion key
390      *
391      * STEK file can be created with a command such as:
392      *   dd if=/dev/random bs=1 count=80 status=none | \
393      *     perl -e 'print pack("iii",0,time()+300,time()+86400),<>' \
394      *     > STEK-file.$$ && mv STEK-file.$$ STEK-file
395      *
396      * The above delays activation time by 5 mins (+300 sec) to allow file to
397      * be propagated to other machines.  (admin must handle this independently)
398      * If STEK generation is performed immediately prior to starting lighttpd,
399      * admin should activate keys immediately (without +300).
400      */
401     int buf[23]; /* 92 bytes */
402     int rc = 0; /*(will retry on next check interval upon any error)*/
403     if (0 != fdevent_load_file_bytes((char *)buf,(off_t)sizeof(buf),0,fn,NULL))
404         return rc;
405     if (buf[0] == 0) { /*(format version 0)*/
406         session_ticket_keys[3].active_ts = TIME64_CAST(buf[1]);
407         session_ticket_keys[3].expire_ts = TIME64_CAST(buf[2]);
408       #ifndef __COVERITY__ /* intentional; hide from Coverity Scan */
409         /* intentionally copy 80 bytes into consecutive arrays
410          * tick_key_name[], tick_hmac_key[], tick_aes_key[] */
411         memcpy(&session_ticket_keys[3].tick_key_name, buf+3, 80);
412       #endif
413         rc = 1;
414     }
415 
416     wolfSSL_OPENSSL_cleanse(buf, sizeof(buf));
417     return rc;
418 }
419 
420 
421 static void
mod_openssl_session_ticket_key_check(const plugin_data * p,const unix_time64_t cur_ts)422 mod_openssl_session_ticket_key_check (const plugin_data *p, const unix_time64_t cur_ts)
423 {
424     static unix_time64_t detect_retrograde_ts;
425     if (detect_retrograde_ts > cur_ts && detect_retrograde_ts - cur_ts > 28800)
426         stek_rotate_ts = 0;
427     detect_retrograde_ts = cur_ts;
428 
429     int rotate = 0;
430     if (p->ssl_stek_file) {
431         struct stat st;
432         if (0 == stat(p->ssl_stek_file, &st)
433             && TIME64_CAST(st.st_mtime) > stek_rotate_ts)
434             rotate = mod_openssl_session_ticket_key_file(p->ssl_stek_file);
435         tlsext_ticket_wipe_expired(cur_ts);
436     }
437     else if (cur_ts - 28800 >= stek_rotate_ts || 0 == stek_rotate_ts)/*(8 hrs)*/
438         rotate = mod_openssl_session_ticket_key_generate(cur_ts, cur_ts+86400);
439 
440     if (rotate) {
441         mod_openssl_session_ticket_key_rotate();
442         stek_rotate_ts = cur_ts;
443     }
444 }
445 
446 #endif /* HAVE_SESSION_TICKET */
447 
448 
449 #ifdef HAVE_OCSP
450 static int
ssl_tlsext_status_cb(SSL * ssl,void * arg)451 ssl_tlsext_status_cb(SSL *ssl, void *arg)
452 {
453   #ifdef SSL_get_tlsext_status_type
454     if (TLSEXT_STATUSTYPE_ocsp != SSL_get_tlsext_status_type(ssl))
455         return SSL_TLSEXT_ERR_NOACK; /* ignore if not client OCSP request */
456   #endif
457 
458     handler_ctx *hctx = (handler_ctx *) SSL_get_app_data(ssl);
459     if (NULL == hctx->conf.pc) return SSL_TLSEXT_ERR_NOACK;/*should not happen*/
460     buffer *ssl_stapling = hctx->conf.pc->ssl_stapling;
461     if (NULL == ssl_stapling) return SSL_TLSEXT_ERR_NOACK;
462     UNUSED(arg);
463 
464     int len = (int)buffer_clen(ssl_stapling);
465 
466     /* wolfSSL caller is going to XFREE() */
467     uint8_t *ocsp_resp = XMALLOC(len, NULL, DYNAMIC_TYPE_OPENSSL);
468     if (NULL == ocsp_resp)
469         return SSL_TLSEXT_ERR_NOACK; /* ignore OCSP request if error occurs */
470     memcpy(ocsp_resp, ssl_stapling->ptr, (uint32_t)len);
471 
472     if (!SSL_set_tlsext_status_ocsp_resp(ssl, ocsp_resp, len)) {
473         log_error(hctx->r->conf.errh, __FILE__, __LINE__,
474           "SSL: failed to set OCSP response for TLS server name %s: %s",
475           hctx->r->uri.authority.ptr, ERR_error_string(ERR_get_error(), NULL));
476         return SSL_TLSEXT_ERR_NOACK; /* ignore OCSP request if error occurs */
477         /*return SSL_TLSEXT_ERR_ALERT_FATAL;*/
478     }
479     return SSL_TLSEXT_ERR_OK;
480 }
481 #endif
482 
483 
INIT_FUNC(mod_openssl_init)484 INIT_FUNC(mod_openssl_init)
485 {
486     plugin_data_singleton = (plugin_data *)ck_calloc(1, sizeof(plugin_data));
487   #ifdef DEBUG_WOLFSSL
488     wolfSSL_Debugging_ON();
489   #endif
490     return plugin_data_singleton;
491 }
492 
493 
mod_openssl_init_once_openssl(server * srv)494 static int mod_openssl_init_once_openssl (server *srv)
495 {
496     if (ssl_is_init) return 1;
497 
498     if (wolfSSL_Init() != WOLFSSL_SUCCESS) {
499         log_error(srv->errh, __FILE__, __LINE__,
500           "SSL: wolfSSL_Init() failed");
501         return 0;
502     }
503     ssl_is_init = 1;
504 
505     if (0 == RAND_status()) {
506         log_error(srv->errh, __FILE__, __LINE__,
507           "SSL: not enough entropy in the pool");
508         return 0;
509     }
510 
511     local_send_buffer = ck_malloc(LOCAL_SEND_BUFSIZE);
512     return 1;
513 }
514 
515 
mod_openssl_free_openssl(void)516 static void mod_openssl_free_openssl (void)
517 {
518     if (!ssl_is_init) return;
519 
520   #ifdef HAVE_SESSION_TICKET
521     wolfSSL_OPENSSL_cleanse(session_ticket_keys, sizeof(session_ticket_keys));
522     stek_rotate_ts = 0;
523   #endif
524 
525     if (wolfSSL_Cleanup() != WOLFSSL_SUCCESS) {
526         log_error(plugin_data_singleton->srv->errh, __FILE__, __LINE__,
527           "SSL: wolfSSL_Cleanup() failed");
528     }
529 
530     free(local_send_buffer);
531     ssl_is_init = 0;
532 }
533 
534 
535 static void
mod_wolfssl_free_der_certs(buffer ** certs)536 mod_wolfssl_free_der_certs (buffer **certs)
537 {
538     if (NULL == certs) return;
539     for (int i = 0; NULL != certs[i]; ++i)
540         buffer_free(certs[i]);
541     free(certs);
542 }
543 
544 
545 static void
mod_openssl_free_config(server * srv,plugin_data * const p)546 mod_openssl_free_config (server *srv, plugin_data * const p)
547 {
548     array_free(p->cafiles);
549 
550     if (NULL != p->ssl_ctxs) {
551         SSL_CTX * const ssl_ctx_global_scope = p->ssl_ctxs->ssl_ctx;
552         /* free ssl_ctx from $SERVER["socket"] (if not copy of global scope) */
553         for (uint32_t i = 1; i < srv->config_context->used; ++i) {
554             plugin_ssl_ctx * const s = p->ssl_ctxs + i;
555             if (s->ssl_ctx && s->ssl_ctx != ssl_ctx_global_scope)
556                 SSL_CTX_free(s->ssl_ctx);
557         }
558         /* free ssl_ctx from global scope */
559         if (ssl_ctx_global_scope)
560             SSL_CTX_free(ssl_ctx_global_scope);
561         free(p->ssl_ctxs);
562     }
563 
564     if (NULL == p->cvlist) return;
565     /* (init i to 0 if global context; to 1 to skip empty global context) */
566     for (int i = !p->cvlist[0].v.u2[1], used = p->nconfig; i < used; ++i) {
567         config_plugin_value_t *cpv = p->cvlist + p->cvlist[i].v.u2[0];
568         for (; -1 != cpv->k_id; ++cpv) {
569             switch (cpv->k_id) {
570               case 0: /* ssl.pemfile */
571                 if (cpv->vtype == T_CONFIG_LOCAL) {
572                     plugin_cert *pc = cpv->v.v;
573                     wolfSSL_OPENSSL_cleanse(pc->ssl_pemfile_pkey->ptr,
574                                             pc->ssl_pemfile_pkey->size);
575                     buffer_free(pc->ssl_pemfile_pkey);
576                     /*buffer_free(pc->ssl_pemfile_x509);*//*(part of chain)*/
577                     mod_wolfssl_free_der_certs(pc->ssl_pemfile_chain);
578                     buffer_free(pc->ssl_stapling);
579                     free(pc);
580                 }
581                 break;
582               case 2: /* ssl.ca-file */
583                 if (cpv->vtype == T_CONFIG_LOCAL) {
584                     plugin_cacerts *cacerts = cpv->v.v;
585                     wolfSSL_sk_X509_NAME_pop_free(cacerts->names,
586                                                   X509_NAME_free);
587                     wolfSSL_X509_STORE_free(cacerts->certs);
588                     free(cacerts);
589                 }
590                 break;
591               case 3: /* ssl.ca-dn-file */
592                 if (cpv->vtype == T_CONFIG_LOCAL)
593                     wolfSSL_sk_X509_NAME_pop_free(cpv->v.v, X509_NAME_free);
594                 break;
595               default:
596                 break;
597             }
598         }
599     }
600 }
601 
602 
603 #if LIBWOLFSSL_VERSION_HEX >= 0x04002000
604 static int
mod_wolfssl_cert_is_active(const buffer * b)605 mod_wolfssl_cert_is_active (const buffer *b)
606 {
607     WOLFSSL_X509 *crt =
608       wolfSSL_X509_load_certificate_buffer((const unsigned char *)b->ptr,
609                                            (int)buffer_clen(b),
610                                            WOLFSSL_FILETYPE_ASN1);
611     if (NULL == crt) return 0;
612     const WOLFSSL_ASN1_TIME *notBefore = wolfSSL_X509_get_notBefore(crt);
613     const WOLFSSL_ASN1_TIME *notAfter  = wolfSSL_X509_get_notAfter(crt);
614     time_t now = (time_t)log_epoch_secs;
615     /*(wolfSSL_X509_cmp_time() might return 0 (WOLFSSL_FAILURE) on failure
616      * to convert WOLFSSL_ASN1_TIME to struct tm; should not happen but WTH?
617      * Also might return -337 (GETTIME_ERROR))*/
618     const int before_cmp = wolfSSL_X509_cmp_time(notBefore, &now);
619     const int after_cmp  = wolfSSL_X509_cmp_time(notAfter,  &now);
620     wolfSSL_X509_free(crt);
621     return ((before_cmp == -1 || before_cmp == 0) && 0 <= after_cmp);
622 }
623 #endif
624 
625 
626 /* WolfSSL OpenSSL compat API does not wipe temp mem used; write our own */
627 /* (pemfile might contain private key)*/
628 /* code here is based on similar code in mod_nss */
629 #include "base64.h"
630 
631 #define PEM_BEGIN          "-----BEGIN "
632 #define PEM_END            "-----END "
633 #define PEM_BEGIN_CERT     "-----BEGIN CERTIFICATE-----"
634 #define PEM_END_CERT       "-----END CERTIFICATE-----"
635 #define PEM_BEGIN_TRUSTED_CERT "-----BEGIN TRUSTED CERTIFICATE-----"
636 #define PEM_END_TRUSTED_CERT   "-----END TRUSTED CERTIFICATE-----"
637 #define PEM_BEGIN_PKEY     "-----BEGIN PRIVATE KEY-----"
638 #define PEM_END_PKEY       "-----END PRIVATE KEY-----"
639 #define PEM_BEGIN_EC_PKEY  "-----BEGIN EC PRIVATE KEY-----"
640 #define PEM_END_EC_PKEY    "-----END EC PRIVATE KEY-----"
641 #define PEM_BEGIN_RSA_PKEY "-----BEGIN RSA PRIVATE KEY-----"
642 #define PEM_END_RSA_PKEY   "-----END RSA PRIVATE KEY-----"
643 #define PEM_BEGIN_DSA_PKEY "-----BEGIN DSA PRIVATE KEY-----"
644 #define PEM_END_DSA_PKEY   "-----END DSA PRIVATE KEY-----"
645 #define PEM_BEGIN_ANY_PKEY "-----BEGIN ANY PRIVATE KEY-----"
646 #define PEM_END_ANY_PKEY   "-----END ANY PRIVATE KEY-----"
647 /* (not implemented: support to get password from user for encrypted key) */
648 #define PEM_BEGIN_ENCRYPTED_PKEY "-----BEGIN ENCRYPTED PRIVATE KEY-----"
649 #define PEM_END_ENCRYPTED_PKEY   "-----END ENCRYPTED PRIVATE KEY-----"
650 
651 #define PEM_BEGIN_X509_CRL "-----BEGIN X509 CRL-----"
652 #define PEM_END_X509_CRL   "-----END X509 CRL-----"
653 
654 
655 static buffer *
mod_wolfssl_load_pem_file(const char * fn,log_error_st * errh,buffer *** chain)656 mod_wolfssl_load_pem_file (const char *fn, log_error_st *errh, buffer ***chain)
657 {
658     off_t dlen = 512*1024*1024;/*(arbitrary limit: 512 MB file; expect < 1 MB)*/
659     char *data = fdevent_load_file(fn, &dlen, errh, malloc, free);
660     if (NULL == data) return NULL;
661 
662     buffer **certs = NULL;
663     int rc = -1;
664     do {
665         int count = 0;
666         char *b = data;
667         for (; (b = strstr(b, PEM_BEGIN_CERT)); b += sizeof(PEM_BEGIN_CERT)-1)
668             ++count;
669         b = data;
670         for (; (b = strstr(b, PEM_BEGIN_TRUSTED_CERT));
671                 b += sizeof(PEM_BEGIN_TRUSTED_CERT)-1)
672             ++count;
673         if (0 == count) {
674             rc = 0;
675             if (NULL == strstr(data, "-----")) {
676                 /* does not look like PEM, treat as DER format */
677                 certs = ck_malloc(2 * sizeof(buffer *));
678                 certs[0] = buffer_init();
679                 certs[1] = NULL;
680                 buffer_copy_string_len(certs[0], data, dlen);
681             }
682             break;
683         }
684 
685         certs = ck_malloc((count+1) * sizeof(buffer *));
686         certs[count] = NULL;
687         for (int i = 0; i < count; ++i)
688             certs[i] = buffer_init();
689 
690         buffer *der;
691         int i = 0;
692         for (char *e = data; (b = strstr(e, PEM_BEGIN_CERT)); ++i) {
693             b += sizeof(PEM_BEGIN_CERT)-1;
694             if (*b == '\r') ++b;
695             if (*b == '\n') ++b;
696             e = strstr(b, PEM_END_CERT);
697             if (NULL == e) break;
698             uint32_t len = (uint32_t)(e - b);
699             e += sizeof(PEM_END_CERT)-1;
700             if (i >= count) break; /*(should not happen)*/
701             der = certs[i];
702             if (NULL == buffer_append_base64_decode(der,b,len,BASE64_STANDARD))
703                 break;
704         }
705         for (char *e = data; (b = strstr(e, PEM_BEGIN_TRUSTED_CERT)); ++i) {
706             b += sizeof(PEM_BEGIN_TRUSTED_CERT)-1;
707             if (*b == '\r') ++b;
708             if (*b == '\n') ++b;
709             e = strstr(b, PEM_END_TRUSTED_CERT);
710             if (NULL == e) break;
711             uint32_t len = (uint32_t)(e - b);
712             e += sizeof(PEM_END_TRUSTED_CERT)-1;
713             if (i >= count) break; /*(should not happen)*/
714             der = certs[i];
715             if (NULL == buffer_append_base64_decode(der,b,len,BASE64_STANDARD))
716                 break;
717         }
718         if (i == count)
719             rc = 0;
720         else
721             errno = EIO;
722     } while (0);
723 
724     if (dlen) ck_memzero(data, dlen);
725     free(data);
726 
727     if (rc < 0) {
728         log_perror(errh, __FILE__, __LINE__, "error loading %s", fn);
729         mod_wolfssl_free_der_certs(certs);
730         certs = NULL;
731     }
732 
733   #if LIBWOLFSSL_VERSION_HEX >= 0x04002000
734     if (certs && !mod_wolfssl_cert_is_active(certs[0]))
735         log_error(errh, __FILE__, __LINE__,
736           "SSL: inactive/expired X509 certificate '%s'", fn);
737   #endif
738 
739     *chain = certs;
740     return certs ? certs[0] : NULL;
741 }
742 
743 
744 static buffer *
mod_wolfssl_evp_pkey_load_pem_file(const char * fn,log_error_st * errh)745 mod_wolfssl_evp_pkey_load_pem_file (const char *fn, log_error_st *errh)
746 {
747     off_t dlen = 512*1024*1024;/*(arbitrary limit: 512 MB file; expect < 1 MB)*/
748     char *data = fdevent_load_file(fn, &dlen, errh, malloc, free);
749     if (NULL == data) return NULL;
750 
751     buffer *pkey = NULL;
752     int rc = -1;
753     do {
754         /*(expecting single private key in file, so first match)*/
755         char *b, *e;
756         if ((b = strstr(data, PEM_BEGIN_PKEY))
757             && (e = strstr(b, PEM_END_PKEY)))
758             b += sizeof(PEM_BEGIN_PKEY)-1;
759         else if ((b = strstr(data, PEM_BEGIN_EC_PKEY))
760                  && (e = strstr(b, PEM_END_EC_PKEY)))
761             b += sizeof(PEM_BEGIN_EC_PKEY)-1;
762         else if ((b = strstr(data, PEM_BEGIN_RSA_PKEY))
763                  && (e = strstr(b, PEM_END_RSA_PKEY)))
764             b += sizeof(PEM_BEGIN_RSA_PKEY)-1;
765         else if ((b = strstr(data, PEM_BEGIN_DSA_PKEY))
766                  && (e = strstr(b, PEM_END_DSA_PKEY)))
767             b += sizeof(PEM_BEGIN_DSA_PKEY)-1;
768         else if ((b = strstr(data, PEM_BEGIN_ANY_PKEY))
769                  && (e = strstr(b, PEM_END_ANY_PKEY)))
770             b += sizeof(PEM_BEGIN_ANY_PKEY)-1;
771         else if (NULL == strstr(data, "-----")) {
772             /* does not look like PEM, treat as DER format */
773             pkey = buffer_init();
774             buffer_copy_string_len(pkey, data, dlen);
775             rc = 0;
776             break;
777         }
778         else
779             break;
780         if (*b == '\r') ++b;
781         if (*b == '\n') ++b;
782 
783         pkey = buffer_init();
784         size_t len = (size_t)(e - b);
785         if (NULL == buffer_append_base64_decode(pkey, b, len, BASE64_STANDARD))
786             break;
787         rc = 0;
788     } while (0);
789 
790     if (dlen) ck_memzero(data, dlen);
791     free(data);
792 
793     if (rc < 0) {
794         log_error(errh, __FILE__, __LINE__, "%s() %s", __func__, fn);
795         if (pkey) {
796             wolfSSL_OPENSSL_cleanse(pkey->ptr, pkey->size);
797             buffer_free(pkey);
798         }
799         return NULL;
800     }
801 
802     return pkey;
803 }
804 
805 
806 static int
mod_wolfssl_CTX_use_certificate_chain_file(WOLFSSL_CTX * ssl_ctx,const char * fn,log_error_st * errh)807 mod_wolfssl_CTX_use_certificate_chain_file (WOLFSSL_CTX *ssl_ctx, const char *fn, log_error_st *errh)
808 {
809     /* (While it should be possible to parse DERs from (buffer **)
810      *  s->pc->ssl_pemfile_chain, it is simpler to re-read file and use the
811      *  built-in wolfSSL_CTX_use_certificate_chain_buffer() interface) */
812     off_t dlen = 4*1024*1024;/*(arbitrary limit: 4 MB file; expect < 1 KB)*/
813     char *data = fdevent_load_file(fn, &dlen, errh, malloc, free);
814     if (NULL == data) return -1;
815 
816     int rc = (NULL != strstr(data, "-----"))
817       ? wolfSSL_CTX_use_certificate_chain_buffer(ssl_ctx, (unsigned char *)data,
818                                                  (long)dlen)
819       : wolfSSL_CTX_use_certificate_chain_buffer_format(ssl_ctx,
820                                                         (unsigned char *)data,
821                                                         (long)dlen,
822                                                         WOLFSSL_FILETYPE_ASN1);
823 
824     if (dlen) ck_memzero(data, dlen);
825     free(data);
826 
827     if (rc == WOLFSSL_SUCCESS)
828         return 1;
829 
830     log_error(errh, __FILE__, __LINE__,
831       "SSL: %s %s", ERR_error_string(rc, NULL), fn);
832     return 0;
833 }
834 
835 
STACK_OF(X509_NAME)836 static STACK_OF(X509_NAME) *
837 mod_wolfssl_load_client_CA_file (const buffer *ssl_ca_file, log_error_st *errh)
838 {
839     /* similar to wolfSSL_load_client_CA_file(), plus some processing */
840     buffer **certs = NULL;
841     if (NULL == mod_wolfssl_load_pem_file(ssl_ca_file->ptr, errh, &certs)) {
842       #if defined(__clang_analyzer__) || defined(__COVERITY__)
843         mod_wolfssl_free_der_certs(certs); /*unnecessary; quiet clang analyzer*/
844       #endif
845         return NULL;
846     }
847 
848     WOLF_STACK_OF(WOLFSSL_X509_NAME) *canames = wolfSSL_sk_X509_NAME_new(NULL);
849     if (NULL == canames) {
850         mod_wolfssl_free_der_certs(certs);
851         return NULL;
852     }
853 
854     /* wolfSSL_sk_X509_NAME_push prior to version 4.8.0 returned 0 on success.
855      * The return value was changed to WOLFSSL_SUCCESS (not 0) from 4.8.0. */
856     const int x = wolfSSL_lib_version_hex() < 0x04008000 ? 0 : WOLFSSL_SUCCESS;
857     for (int i = 0; NULL != certs[i]; ++i) {
858         WOLFSSL_X509 *ca =
859           wolfSSL_X509_load_certificate_buffer((unsigned char *)certs[i]->ptr,
860                                                (int)buffer_clen(certs[i]),
861                                                WOLFSSL_FILETYPE_ASN1);
862         WOLFSSL_X509_NAME *subj = NULL;
863         if (NULL == ca
864             || NULL == (subj = wolfSSL_X509_get_subject_name(ca))
865             || x != wolfSSL_sk_X509_NAME_push(canames,
866                                               wolfSSL_X509_NAME_dup(subj))) {
867             log_error(errh, __FILE__, __LINE__,
868               "SSL: couldn't read X509 certificates from '%s'",
869               ssl_ca_file->ptr);
870             if (subj) wolfSSL_X509_NAME_free(subj);
871             if (ca) wolfSSL_X509_free(ca);
872             wolfSSL_sk_X509_NAME_free(canames);
873             mod_wolfssl_free_der_certs(certs);
874             return NULL;
875         }
876 
877         wolfSSL_X509_free(ca);
878     }
879 
880     mod_wolfssl_free_der_certs(certs);
881     return canames;
882 }
883 
884 
885 static plugin_cacerts *
mod_wolfssl_load_cacerts(const buffer * ssl_ca_file,log_error_st * errh)886 mod_wolfssl_load_cacerts (const buffer *ssl_ca_file, log_error_st *errh)
887 {
888     /* similar to mod_wolfSSL_load_client_CA_file(), plus some processing */
889     /* similar to wolfSSL_load_client_CA_file(), plus some processing */
890     buffer **certs = NULL;
891     if (NULL == mod_wolfssl_load_pem_file(ssl_ca_file->ptr, errh, &certs)) {
892       #if defined(__clang_analyzer__) || defined(__COVERITY__)
893         mod_wolfssl_free_der_certs(certs); /*unnecessary; quiet clang analyzer*/
894       #endif
895         return NULL;
896     }
897 
898     WOLFSSL_X509_STORE *castore = wolfSSL_X509_STORE_new();
899     if (NULL == castore) {
900         mod_wolfssl_free_der_certs(certs);
901         return NULL;
902     }
903 
904     WOLF_STACK_OF(WOLFSSL_X509_NAME) *canames = wolfSSL_sk_X509_NAME_new(NULL);
905     if (NULL == canames) {
906         wolfSSL_X509_STORE_free(castore);
907         mod_wolfssl_free_der_certs(certs);
908         return NULL;
909     }
910 
911     /* wolfSSL_sk_X509_NAME_push prior to version 4.8.0 returned 0 on success.
912      * The return value was changed to WOLFSSL_SUCCESS (not 0) from 4.8.0. */
913     const int x = wolfSSL_lib_version_hex() < 0x04008000 ? 0 : WOLFSSL_SUCCESS;
914     for (int i = 0; NULL != certs[i]; ++i) {
915         WOLFSSL_X509 *ca =
916           wolfSSL_X509_load_certificate_buffer((unsigned char *)certs[i]->ptr,
917                                                (int)buffer_clen(certs[i]),
918                                                WOLFSSL_FILETYPE_ASN1);
919         WOLFSSL_X509_NAME *subj = NULL;
920         if (NULL == ca || !wolfSSL_X509_STORE_add_cert(castore, ca)
921             || NULL == (subj = wolfSSL_X509_get_subject_name(ca))
922             || x != wolfSSL_sk_X509_NAME_push(canames,
923                                               wolfSSL_X509_NAME_dup(subj))) {
924             log_error(errh, __FILE__, __LINE__,
925               "SSL: couldn't read X509 certificates from '%s'",
926               ssl_ca_file->ptr);
927             if (subj) wolfSSL_X509_NAME_free(subj);
928             if (ca) wolfSSL_X509_free(ca);
929             wolfSSL_sk_X509_NAME_free(canames);
930             wolfSSL_X509_STORE_free(castore);
931             mod_wolfssl_free_der_certs(certs);
932             return NULL;
933         }
934 
935         wolfSSL_X509_free(ca);
936     }
937 
938     mod_wolfssl_free_der_certs(certs);
939 
940     plugin_cacerts *cacerts = ck_malloc(sizeof(plugin_cacerts));
941     cacerts->names = canames;
942     cacerts->certs = castore;
943     return cacerts;
944 }
945 
946 
947 static int
mod_wolfssl_load_cacrls(WOLFSSL_CTX * ssl_ctx,const buffer * ssl_ca_crl_file,server * srv)948 mod_wolfssl_load_cacrls (WOLFSSL_CTX *ssl_ctx, const buffer *ssl_ca_crl_file, server *srv)
949 {
950   #ifdef HAVE_CRL /* <wolfssl/options.h> */
951     int rc = wolfSSL_CTX_EnableCRL(ssl_ctx,
952                                    WOLFSSL_CRL_CHECK | WOLFSSL_CRL_CHECKALL);
953     if (rc != WOLFSSL_SUCCESS) return 0;
954 
955     const char *fn = ssl_ca_crl_file->ptr;
956     off_t dlen = 512*1024*1024;/*(arbitrary limit: 512 MB file; expect < 1 MB)*/
957     char *data = fdevent_load_file(fn, &dlen, srv->errh, malloc, free);
958     if (NULL == data) return 0;
959 
960     rc = wolfSSL_CTX_LoadCRLBuffer(ssl_ctx, (byte *)data, (long)dlen,
961                                    WOLFSSL_FILETYPE_PEM);
962 
963     if (dlen) ck_memzero(data, dlen);
964     free(data);
965 
966     if (rc == WOLFSSL_SUCCESS)
967         return 1;
968 
969     log_error(srv->errh, __FILE__, __LINE__,
970       "SSL: %s %s", ERR_error_string(rc, NULL), fn);
971     return 0;
972   #else
973     UNUSED(ssl_ctx);
974     log_error(srv->errh, __FILE__, __LINE__,
975       "WolfSSL not built with CRL support; ignoring %s", ssl_ca_crl_file->ptr);
976     return WOLFSSL_FAILURE;
977   #endif
978 }
979 
980 
981 static int
mod_wolfssl_load_verify_locn(SSL_CTX * ssl_ctx,const buffer * b,server * srv)982 mod_wolfssl_load_verify_locn (SSL_CTX *ssl_ctx, const buffer *b, server *srv)
983 {
984     const char *fn = b->ptr;
985     off_t dlen = 512*1024*1024;/*(arbitrary limit: 512 MB file; expect < 1 MB)*/
986     char *data = fdevent_load_file(fn, &dlen, srv->errh, malloc, free);
987     if (NULL == data) return 0;
988 
989     int rc = wolfSSL_CTX_load_verify_buffer(ssl_ctx, (unsigned char *)data,
990                                             (long)dlen, WOLFSSL_FILETYPE_PEM);
991 
992     if (dlen) ck_memzero(data, dlen);
993     free(data);
994 
995     if (rc == WOLFSSL_SUCCESS)
996         return 1;
997 
998     log_error(srv->errh, __FILE__, __LINE__,
999       "SSL: %s %s", ERR_error_string(rc, NULL), fn);
1000     return 0;
1001 }
1002 
1003 
1004 static int
mod_wolfssl_load_ca_files(SSL_CTX * ssl_ctx,plugin_data * p,server * srv)1005 mod_wolfssl_load_ca_files (SSL_CTX *ssl_ctx, plugin_data *p, server *srv)
1006 {
1007     /* load all ssl.ca-files specified in the config into each SSL_CTX */
1008 
1009     for (uint32_t i = 0, used = p->cafiles->used; i < used; ++i) {
1010         const buffer *b = &((data_string *)p->cafiles->data[i])->value;
1011         if (!mod_wolfssl_load_verify_locn(ssl_ctx, b, srv))
1012             return 0;
1013     }
1014     return 1;
1015 }
1016 
1017 
FREE_FUNC(mod_openssl_free)1018 FREE_FUNC(mod_openssl_free)
1019 {
1020     plugin_data *p = p_d;
1021     if (NULL == p->srv) return;
1022     mod_openssl_free_config(p->srv, p);
1023     mod_openssl_free_openssl();
1024 }
1025 
1026 
1027 static void
mod_openssl_merge_config_cpv(plugin_config * const pconf,const config_plugin_value_t * const cpv)1028 mod_openssl_merge_config_cpv (plugin_config * const pconf, const config_plugin_value_t * const cpv)
1029 {
1030     switch (cpv->k_id) { /* index into static config_plugin_keys_t cpk[] */
1031       case 0: /* ssl.pemfile */
1032         if (cpv->vtype == T_CONFIG_LOCAL)
1033             pconf->pc = cpv->v.v;
1034         break;
1035       case 1: /* ssl.privkey */
1036         break;
1037       case 2: /* ssl.ca-file */
1038         if (cpv->vtype == T_CONFIG_LOCAL)
1039             pconf->ssl_ca_file = cpv->v.v;
1040         break;
1041       case 3: /* ssl.ca-dn-file */
1042         if (cpv->vtype == T_CONFIG_LOCAL)
1043             pconf->ssl_ca_dn_file = cpv->v.v;
1044         break;
1045       case 4: /* ssl.ca-crl-file */
1046         pconf->ssl_ca_crl_file = cpv->v.b;
1047         break;
1048       case 5: /* ssl.read-ahead */
1049         pconf->ssl_read_ahead = (0 != cpv->v.u);
1050         break;
1051       case 6: /* ssl.disable-client-renegotiation */
1052         /*(ignored; unsafe renegotiation disabled by default)*/
1053         break;
1054       case 7: /* ssl.verifyclient.activate */
1055         pconf->ssl_verifyclient = (0 != cpv->v.u);
1056         break;
1057       case 8: /* ssl.verifyclient.enforce */
1058         pconf->ssl_verifyclient_enforce = (0 != cpv->v.u);
1059         break;
1060       case 9: /* ssl.verifyclient.depth */
1061         pconf->ssl_verifyclient_depth = (unsigned char)cpv->v.shrt;
1062         break;
1063       case 10:/* ssl.verifyclient.username */
1064         pconf->ssl_verifyclient_username = cpv->v.b;
1065         break;
1066       case 11:/* ssl.verifyclient.exportcert */
1067         pconf->ssl_verifyclient_export_cert = (0 != cpv->v.u);
1068         break;
1069       case 12:/* ssl.acme-tls-1 */
1070         pconf->ssl_acme_tls_1 = cpv->v.b;
1071         break;
1072       case 13:/* ssl.stapling-file */
1073         break;
1074       case 14:/* debug.log-ssl-noise */
1075         pconf->ssl_log_noise = (0 != cpv->v.u);
1076         break;
1077      #if 0    /*(cpk->k_id remapped in mod_openssl_set_defaults())*/
1078       case 15:/* ssl.verifyclient.ca-file */
1079       case 16:/* ssl.verifyclient.ca-dn-file */
1080       case 17:/* ssl.verifyclient.ca-crl-file */
1081         break;
1082      #endif
1083       default:/* should not happen */
1084         return;
1085     }
1086 }
1087 
1088 
1089 static void
mod_openssl_merge_config(plugin_config * const pconf,const config_plugin_value_t * cpv)1090 mod_openssl_merge_config(plugin_config * const pconf, const config_plugin_value_t *cpv)
1091 {
1092     do {
1093         mod_openssl_merge_config_cpv(pconf, cpv);
1094     } while ((++cpv)->k_id != -1);
1095 }
1096 
1097 
1098 static void
mod_openssl_patch_config(request_st * const r,plugin_config * const pconf)1099 mod_openssl_patch_config (request_st * const r, plugin_config * const pconf)
1100 {
1101     plugin_data * const p = plugin_data_singleton;
1102     memcpy(pconf, &p->defaults, sizeof(plugin_config));
1103     for (int i = 1, used = p->nconfig; i < used; ++i) {
1104         if (config_check_cond(r, (uint32_t)p->cvlist[i].k_id))
1105             mod_openssl_merge_config(pconf, p->cvlist + p->cvlist[i].v.u2[0]);
1106     }
1107 }
1108 
1109 
1110 static int
safer_X509_NAME_oneline(X509_NAME * name,char * buf,size_t sz)1111 safer_X509_NAME_oneline(X509_NAME *name, char *buf, size_t sz)
1112 {
1113   #if LIBWOLFSSL_VERSION_HEX < 0x04004000
1114     UNUSED(name);
1115     UNUSED(sz);
1116   #else
1117     if (wolfSSL_X509_get_name_oneline(name, buf, (int)sz))
1118         return (int)strlen(buf);
1119     else
1120   #endif
1121     {
1122         buf[0] = '\0';
1123         return -1;
1124     }
1125 }
1126 
1127 
1128 static void
ssl_info_callback(const SSL * ssl,int where,int ret)1129 ssl_info_callback (const SSL *ssl, int where, int ret)
1130 {
1131     UNUSED(ret);
1132 
1133     if (0 != (where & SSL_CB_HANDSHAKE_START)) {
1134         handler_ctx *hctx = (handler_ctx *) SSL_get_app_data(ssl);
1135         if (hctx->renegotiations >= 0) ++hctx->renegotiations;
1136     }
1137     /* https://github.com/openssl/openssl/issues/5721
1138      * "TLSv1.3 unexpected InfoCallback after handshake completed" */
1139     if (0 != (where & SSL_CB_HANDSHAKE_DONE)) {
1140         /* SSL_version() is valid after initial handshake completed */
1141         SSL *ssl_nonconst;
1142         *(const SSL **)&ssl_nonconst = ssl;
1143         if (wolfSSL_GetVersion(ssl_nonconst) >= WOLFSSL_TLSV1_3) {
1144             /* https://wiki.openssl.org/index.php/TLS1.3
1145              * "Renegotiation is not possible in a TLSv1.3 connection" */
1146             handler_ctx *hctx = (handler_ctx *) SSL_get_app_data(ssl);
1147             hctx->renegotiations = -1;
1148         }
1149     }
1150 }
1151 
1152 /* https://wiki.openssl.org/index.php/Manual:SSL_CTX_set_verify(3)#EXAMPLES */
1153 static int
verify_callback(int preverify_ok,X509_STORE_CTX * ctx)1154 verify_callback(int preverify_ok, X509_STORE_CTX *ctx)
1155 {
1156     char buf[256];
1157     X509 *err_cert;
1158     int err, depth;
1159     SSL *ssl;
1160     handler_ctx *hctx;
1161 
1162     err = X509_STORE_CTX_get_error(ctx);
1163     depth = X509_STORE_CTX_get_error_depth(ctx);
1164 
1165     /*
1166      * Retrieve the pointer to the SSL of the connection currently treated
1167      * and the application specific data stored into the SSL object.
1168      */
1169     ssl = X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
1170     hctx = (handler_ctx *) SSL_get_app_data(ssl);
1171 
1172     /*
1173      * Catch a too long certificate chain. The depth limit set using
1174      * wolfSSL_CTX_set_verify_depth() is by purpose set to "limit+1" so
1175      * that whenever the "depth>verify_depth" condition is met, we
1176      * have violated the limit and want to log this error condition.
1177      * We must do it here, because the CHAIN_TOO_LONG error would not
1178      * be found explicitly; only errors introduced by cutting off the
1179      * additional certificates would be logged.
1180      */
1181     if (depth > hctx->conf.ssl_verifyclient_depth) {
1182         preverify_ok = 0;
1183         err = X509_V_ERR_CERT_CHAIN_TOO_LONG;
1184         X509_STORE_CTX_set_error(ctx, err);
1185     }
1186 
1187     if (preverify_ok && 0 == depth && NULL != hctx->conf.ssl_ca_dn_file) {
1188         /* verify that client cert is issued by CA in ssl.ca-dn-file
1189          * if both ssl.ca-dn-file and ssl.ca-file were configured */
1190         STACK_OF(X509_NAME) * const cert_names = hctx->conf.ssl_ca_dn_file;
1191         X509_NAME *issuer;
1192         err_cert = ctx->current_cert;/*wolfSSL_X509_STORE_CTX_get_current_cert*/
1193         if (NULL == err_cert) return !hctx->conf.ssl_verifyclient_enforce;
1194         issuer = X509_get_issuer_name(err_cert);
1195       #if 0 /*(?desirable/undesirable to have cert_names sorted?)*/
1196         if (-1 != sk_X509_NAME_find(cert_names, issuer))
1197             return preverify_ok; /* match */
1198       #else
1199         for (int i=0, len=wolfSSL_sk_X509_NAME_num(cert_names); i < len; ++i) {
1200             if (0 == wolfSSL_X509_NAME_cmp(sk_X509_NAME_value(cert_names, i),
1201                                            issuer))
1202                 return preverify_ok; /* match */
1203         }
1204       #endif
1205 
1206         preverify_ok = 0;
1207         err = X509_V_ERR_CERT_REJECTED;
1208         X509_STORE_CTX_set_error(ctx, err);
1209     }
1210 
1211     if (preverify_ok) {
1212         return preverify_ok;
1213     }
1214 
1215     err_cert = ctx->current_cert; /*wolfSSL_X509_STORE_CTX_get_current_cert()*/
1216     if (NULL == err_cert) return !hctx->conf.ssl_verifyclient_enforce;
1217     safer_X509_NAME_oneline(X509_get_subject_name(err_cert),buf,sizeof(buf));
1218     log_error_st *errh = hctx->r->conf.errh;
1219     log_error(errh, __FILE__, __LINE__,
1220       "SSL: verify error:num=%d:%s:depth=%d:subject=%s",
1221       err, X509_verify_cert_error_string(err), depth, buf);
1222 
1223     /*
1224      * At this point, err contains the last verification error. We can use
1225      * it for something special
1226      */
1227     if (!preverify_ok && (err == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY ||
1228                           err == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT)) {
1229         safer_X509_NAME_oneline(X509_get_issuer_name(err_cert),buf,sizeof(buf));
1230         log_error(errh, __FILE__, __LINE__, "SSL: issuer=%s", buf);
1231     }
1232 
1233     return !hctx->conf.ssl_verifyclient_enforce;
1234 }
1235 
1236 static int
mod_openssl_cert_cb(SSL * ssl,void * arg)1237 mod_openssl_cert_cb (SSL *ssl, void *arg)
1238 {
1239     handler_ctx *hctx = (handler_ctx *) SSL_get_app_data(ssl);
1240     plugin_cert *pc = hctx->conf.pc;
1241     UNUSED(arg);
1242 
1243     if (!pc || NULL == pc->ssl_pemfile_x509 || NULL == pc->ssl_pemfile_pkey) {
1244         /* x509/pkey available <=> pemfile was set <=> pemfile got patched:
1245          * so this should never happen, unless you nest $SERVER["socket"] */
1246         log_error(hctx->r->conf.errh, __FILE__, __LINE__,
1247           "SSL: no certificate/private key for TLS server name \"%s\".  "
1248           "$SERVER[\"socket\"] should not be nested in other conditions.",
1249           hctx->r->uri.authority.ptr);
1250         return 0;
1251     }
1252 
1253     /* first set certificate!
1254      * setting private key checks whether certificate matches it */
1255     buffer *cert = pc->ssl_pemfile_x509;
1256     if (1 != wolfSSL_use_certificate_ASN1(ssl, (unsigned char *)cert->ptr,
1257                                           (int)buffer_clen(cert))) {
1258         log_error(hctx->r->conf.errh, __FILE__, __LINE__,
1259           "SSL: failed to set certificate for TLS server name %s: %s",
1260           hctx->r->uri.authority.ptr, ERR_error_string(ERR_get_error(), NULL));
1261         return 0;
1262     }
1263 
1264     buffer *pkey = pc->ssl_pemfile_pkey;
1265     if (1 != wolfSSL_use_PrivateKey_buffer(ssl, (unsigned char *)pkey->ptr,
1266                                            (int)buffer_clen(pkey),
1267                                            WOLFSSL_FILETYPE_ASN1)) {
1268         log_error(hctx->r->conf.errh, __FILE__, __LINE__,
1269           "SSL: failed to set private key for TLS server name %s: %s",
1270           hctx->r->uri.authority.ptr, ERR_error_string(ERR_get_error(), NULL));
1271         return 0;
1272     }
1273 
1274     if (hctx->conf.ssl_verifyclient) {
1275         if (NULL == hctx->conf.ssl_ca_file) {
1276             log_error(hctx->r->conf.errh, __FILE__, __LINE__,
1277               "SSL: can't verify client without ssl.verifyclient.ca-file "
1278               "for TLS server name %s", hctx->r->uri.authority.ptr);
1279             return 0;
1280         }
1281         /* WolfSSL does not support setting per-session CA list;
1282          * limitation is to per-CTX CA list, and is not changed after SNI */
1283         int mode = SSL_VERIFY_PEER;
1284         if (hctx->conf.ssl_verifyclient_enforce)
1285             mode |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
1286         wolfSSL_set_verify(ssl, mode, verify_callback);
1287         wolfSSL_set_verify_depth(ssl, hctx->conf.ssl_verifyclient_depth + 1);
1288     }
1289     else {
1290         wolfSSL_set_verify(ssl, SSL_VERIFY_NONE, NULL);
1291     }
1292 
1293     return 1;
1294 }
1295 
1296 #ifdef HAVE_TLS_EXTENSIONS
1297 
1298 enum {
1299   MOD_OPENSSL_ALPN_HTTP11      = 1
1300  ,MOD_OPENSSL_ALPN_HTTP10      = 2
1301  ,MOD_OPENSSL_ALPN_H2          = 3
1302  ,MOD_OPENSSL_ALPN_ACME_TLS_1  = 4
1303 };
1304 
1305 static int
mod_openssl_SNI(handler_ctx * hctx,const char * servername,size_t len)1306 mod_openssl_SNI (handler_ctx *hctx, const char *servername, size_t len)
1307 {
1308     request_st * const r = hctx->r;
1309     if (len >= 1024) { /*(expecting < 256; TLSEXT_MAXLEN_host_name is 255)*/
1310         log_error(r->conf.errh, __FILE__, __LINE__,
1311                   "SSL: SNI name too long %.*s", (int)len, servername);
1312         return SSL_TLSEXT_ERR_ALERT_FATAL;
1313     }
1314 
1315     /* use SNI to patch mod_openssl config and then reset COMP_HTTP_HOST */
1316     buffer_copy_string_len_lc(&r->uri.authority, servername, len);
1317   #if 0
1318     /*(r->uri.authority used below for configuration before request read;
1319      * revisit for h2)*/
1320     if (0 != http_request_host_policy(&r->uri.authority,
1321                                       r->conf.http_parseopts, 443))
1322         return SSL_TLSEXT_ERR_ALERT_FATAL;
1323   #endif
1324 
1325     r->conditional_is_valid |= (1 << COMP_HTTP_SCHEME)
1326                             |  (1 << COMP_HTTP_HOST);
1327     mod_openssl_patch_config(r, &hctx->conf);
1328     /* reset COMP_HTTP_HOST so that conditions re-run after request hdrs read */
1329     /*(done in response.c:config_cond_cache_reset() after request hdrs read)*/
1330     /*config_cond_cache_reset_item(r, COMP_HTTP_HOST);*/
1331     /*buffer_clear(&r->uri.authority);*/
1332 
1333     return (mod_openssl_cert_cb(hctx->ssl, NULL) == 1)
1334       ? SSL_TLSEXT_ERR_OK
1335       : SSL_TLSEXT_ERR_ALERT_FATAL;
1336 }
1337 
1338 static int
network_ssl_servername_callback(SSL * ssl,int * al,void * srv)1339 network_ssl_servername_callback (SSL *ssl, int *al, void *srv)
1340 {
1341     handler_ctx *hctx = (handler_ctx *) SSL_get_app_data(ssl);
1342   #ifdef HAVE_ALPN
1343   #ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
1344     /*(do not repeat if acme-tls/1 creds have been set
1345      * and still in handshake (hctx->alpn not unset yet))*/
1346     if (hctx->alpn == MOD_OPENSSL_ALPN_ACME_TLS_1)
1347         return SSL_TLSEXT_ERR_OK; /*(wolfSSL might call twice in client hello)*/
1348   #endif
1349   #endif
1350     if (hctx->r->conditional_is_valid & (1 << COMP_HTTP_HOST))/*(already done)*/
1351         return SSL_TLSEXT_ERR_OK; /*(wolfSSL might call twice in client hello)*/
1352     buffer_copy_string_len(&hctx->r->uri.scheme, CONST_STR_LEN("https"));
1353     UNUSED(al);
1354     UNUSED(srv);
1355 
1356     const char *servername;
1357     size_t len = (size_t)
1358     #ifdef HAVE_SNI
1359       wolfSSL_SNI_GetRequest(ssl, WOLFSSL_SNI_HOST_NAME, (void **)&servername);
1360     #else
1361       0;
1362     #endif
1363     if (0 == len)
1364         return SSL_TLSEXT_ERR_NOACK; /* client did not provide SNI */
1365   #if 0  /* WolfSSL does not provide per-session SSL_set_read_ahead() */
1366     int read_ahead = hctx->conf.ssl_read_ahead;
1367     int rc = mod_openssl_SNI(hctx, servername, len);
1368     if (!read_ahead && hctx->conf.ssl_read_ahead)
1369         SSL_set_read_ahead(ssl, hctx->conf.ssl_read_ahead);
1370     return rc;
1371   #else
1372     return mod_openssl_SNI(hctx, servername, len);
1373   #endif
1374 }
1375 
1376 #endif /* HAVE_TLS_EXTENSIONS */
1377 
1378 
1379 #ifdef HAVE_OCSP
1380 
1381 #define OCSP_RESPONSE             OcspResponse
1382 #define OCSP_RESPONSE_free        wolfSSL_OCSP_RESPONSE_free
1383 #define d2i_OCSP_RESPONSE_bio     wolfSSL_d2i_OCSP_RESPONSE_bio
1384 #define d2i_OCSP_RESPONSE         wolfSSL_d2i_OCSP_RESPONSE
1385 #define i2d_OCSP_RESPONSE         wolfSSL_i2d_OCSP_RESPONSE
1386 #define OCSP_response_get1_basic  wolfSSL_OCSP_response_get1_basic
1387 #define OCSP_single_get0_status   wolfSSL_OCSP_single_get0_status
1388 #define OCSP_resp_get0            wolfSSL_OCSP_resp_get0
1389 #define OCSP_BASICRESP            WOLFSSL_OCSP_BASICRESP
1390 #define OCSP_BASICRESP_free       wolfSSL_OCSP_BASICRESP_free
1391 
1392 static buffer *
mod_openssl_load_stapling_file(const char * file,log_error_st * errh,buffer * b)1393 mod_openssl_load_stapling_file (const char *file, log_error_st *errh, buffer *b)
1394 {
1395     /* load stapling .der into buffer *b only if successful
1396      *
1397      * Note: for some TLS libs, the OCSP stapling response is not copied when
1398      * assigned to a session (and is reasonable since not changed frequently)
1399      * - BoringSSL SSL_set_ocsp_response()
1400      * - WolfSSL SSL_set_tlsext_status_ocsp_resp() (differs from OpenSSL API)
1401      * Therefore, there is a potential race condition if the OCSP response is
1402      * assigned to the session during the handshake and the Server Hello is
1403      * partially sent, AND (unlikely, if possible at all), the TLS library is
1404      * in the middle of reading this OSCP response buffer.  If the OCSP response
1405      * is replaced due to an updated ssl.stapling-file (checked periodically),
1406      * AND the buffer is resized, this would be a problem.  Resizing the buffer
1407      * is unlikely since updated OSCP response for same certificate are
1408      * typically the same size with the signature and dates refreshed.
1409      */
1410 
1411     /* load raw .der file */
1412     off_t dlen = 1*1024*1024;/*(arbitrary limit: 1 MB file; expect < 1 KB)*/
1413     char *data = fdevent_load_file(file, &dlen, errh, malloc, free);
1414     if (NULL == data) return NULL;
1415 
1416     if (NULL == b)
1417         b = buffer_init();
1418     else if (b->ptr)
1419         free(b->ptr);
1420     b->ptr  = data;
1421     b->used = (uint32_t)dlen;
1422     b->size = (uint32_t)dlen+1;
1423     return b;
1424 }
1425 
1426 
1427 static unix_time64_t
mod_openssl_asn1_time_to_posix(const ASN1_TIME * asn1time)1428 mod_openssl_asn1_time_to_posix (const ASN1_TIME *asn1time)
1429 {
1430   #if LIBWOLFSSL_VERSION_HEX >= 0x05000000 /*(stub func filled in v5.0.0)*/
1431     /* Note: up to at least wolfSSL 4.5.0 (current version as this is written)
1432      * wolfSSL_ASN1_TIME_diff() is a stub function which always returns 0 */
1433     /* Note: this does not check for integer overflow of time_t! */
1434     int day, sec;
1435     return wolfSSL_ASN1_TIME_diff(&day, &sec, NULL, asn1time)
1436       ? log_epoch_secs + day*86400 + sec
1437       : -1;
1438   #else
1439     UNUSED(asn1time);
1440     return -1;
1441   #endif
1442 }
1443 
1444 
1445 static unix_time64_t
mod_openssl_ocsp_next_update(plugin_cert * pc)1446 mod_openssl_ocsp_next_update (plugin_cert *pc)
1447 {
1448   #if LIBWOLFSSL_VERSION_HEX < 0x05000000
1449     UNUSED(pc);
1450     (void)mod_openssl_asn1_time_to_posix(NULL);
1451     return -1; /*(not implemented)*/
1452   #else
1453     buffer *der = pc->ssl_stapling;
1454     const unsigned char *p = (unsigned char *)der->ptr; /*(p gets modified)*/
1455     OCSP_RESPONSE *ocsp = d2i_OCSP_RESPONSE(NULL, &p, buffer_clen(der));
1456     if (NULL == ocsp) return -1;
1457     OCSP_BASICRESP *bs = OCSP_response_get1_basic(ocsp);
1458     if (NULL == bs) {
1459         OCSP_RESPONSE_free(ocsp);
1460         return -1;
1461     }
1462 
1463     /* XXX: should save and evaluate cert status returned by these calls */
1464     ASN1_TIME *nextupd = NULL;
1465    #if LIBWOLFSSL_VERSION_HEX < 0x04006000
1466     /* WolfSSL does not provide OCSP_resp_get0() OCSP_single_get0_status() */
1467     /* (inactive code path; alternative path followed in #if above for WolfSSL)
1468      * (chain not currently available in mod_openssl when used with WolfSSL)
1469      * (For WolfSSL, pc->ssl_pemfile_chain might not be filled in with actual
1470      *  chain, but is used to store (buffer **) of DER decoded from PEM certs
1471      *  read from ssl.pemfile, which may be a single cert, pc->ssl_pemfile_x509.
1472      *  The chain is not calculated or filled in if single cert, and neither are
1473      *  (X509 *), though (X509 *) could be temporarily created to calculated
1474      *  (OCSP_CERTID *), which additionally could be calculated once at startup)
1475      */
1476     OCSP_CERTID *id = (NULL != pc->ssl_pemfile_chain)
1477       ? OCSP_cert_to_id(NULL, pc->ssl_pemfile_x509,
1478                         sk_X509_value(pc->ssl_pemfile_chain, 0))
1479       : NULL;
1480     if (id == NULL) {
1481         OCSP_BASICRESP_free(bs);
1482         OCSP_RESPONSE_free(ocsp);
1483         return -1;
1484     }
1485     OCSP_resp_find_status(bs, id, NULL, NULL, NULL, NULL, &nextupd);
1486     OCSP_CERTID_free(id);
1487    #else
1488     OCSP_single_get0_status(OCSP_resp_get0(bs, 0), NULL, NULL, NULL, &nextupd);
1489    #endif
1490     unix_time64_t t = nextupd ? mod_openssl_asn1_time_to_posix(nextupd) : -1;
1491 
1492     /* Note: trust external process which creates ssl.stapling-file to verify
1493      *       (as well as to validate certificate status)
1494      * future: verify OCSP response here to double-check */
1495 
1496     OCSP_BASICRESP_free(bs);
1497     OCSP_RESPONSE_free(ocsp);
1498 
1499     return t;
1500   #endif
1501 }
1502 
1503 
1504 __attribute_cold__
1505 static void
mod_openssl_expire_stapling_file(server * srv,plugin_cert * pc)1506 mod_openssl_expire_stapling_file (server *srv, plugin_cert *pc)
1507 {
1508     if (NULL == pc->ssl_stapling) /*(previously discarded or never loaded)*/
1509         return;
1510 
1511     /* discard expired OCSP stapling response */
1512     buffer_free(pc->ssl_stapling);
1513     pc->ssl_stapling = NULL;
1514     if (pc->must_staple)
1515         log_error(srv->errh, __FILE__, __LINE__,
1516                   "certificate marked OCSP Must-Staple, "
1517                   "but OCSP response expired from ssl.stapling-file %s",
1518                   pc->ssl_stapling_file->ptr);
1519 }
1520 
1521 
1522 static int
mod_openssl_reload_stapling_file(server * srv,plugin_cert * pc,const unix_time64_t cur_ts)1523 mod_openssl_reload_stapling_file (server *srv, plugin_cert *pc, const unix_time64_t cur_ts)
1524 {
1525     buffer *b = mod_openssl_load_stapling_file(pc->ssl_stapling_file->ptr,
1526                                                srv->errh, pc->ssl_stapling);
1527     if (!b) return 0;
1528 
1529     pc->ssl_stapling = b; /*(unchanged unless orig was NULL)*/
1530     pc->ssl_stapling_loadts = cur_ts;
1531     pc->ssl_stapling_nextts = mod_openssl_ocsp_next_update(pc);
1532     if (pc->ssl_stapling_nextts == -1) {
1533         /* "Next Update" might not be provided by OCSP responder
1534          * Use 3600 sec (1 hour) in that case. */
1535         /* retry in 1 hour if unable to determine Next Update */
1536         pc->ssl_stapling_nextts = cur_ts + 3600;
1537         pc->ssl_stapling_loadts = 0;
1538     }
1539     else if (pc->ssl_stapling_nextts < cur_ts) {
1540         mod_openssl_expire_stapling_file(srv, pc);
1541         return 0;
1542     }
1543 
1544     return 1;
1545 }
1546 
1547 
1548 static int
mod_openssl_refresh_stapling_file(server * srv,plugin_cert * pc,const unix_time64_t cur_ts)1549 mod_openssl_refresh_stapling_file (server *srv, plugin_cert *pc, const unix_time64_t cur_ts)
1550 {
1551     if (pc->ssl_stapling && pc->ssl_stapling_nextts > cur_ts + 256)
1552         return 1; /* skip check for refresh unless close to expire */
1553     struct stat st;
1554     if (0 != stat(pc->ssl_stapling_file->ptr, &st)
1555         || TIME64_CAST(st.st_mtime) <= pc->ssl_stapling_loadts) {
1556         if (pc->ssl_stapling && pc->ssl_stapling_nextts < cur_ts)
1557             mod_openssl_expire_stapling_file(srv, pc);
1558         return 1;
1559     }
1560     return mod_openssl_reload_stapling_file(srv, pc, cur_ts);
1561 }
1562 
1563 
1564 static void
mod_openssl_refresh_stapling_files(server * srv,const plugin_data * p,const unix_time64_t cur_ts)1565 mod_openssl_refresh_stapling_files (server *srv, const plugin_data *p, const unix_time64_t cur_ts)
1566 {
1567     /* future: might construct array of (plugin_cert *) at startup
1568      *         to avoid the need to search for them here */
1569     /* (init i to 0 if global context; to 1 to skip empty global context) */
1570     if (NULL == p->cvlist) return;
1571     for (int i = !p->cvlist[0].v.u2[1], used = p->nconfig; i < used; ++i) {
1572         const config_plugin_value_t *cpv = p->cvlist + p->cvlist[i].v.u2[0];
1573         for (; cpv->k_id != -1; ++cpv) {
1574             if (cpv->k_id != 0) continue; /* k_id == 0 for ssl.pemfile */
1575             if (cpv->vtype != T_CONFIG_LOCAL) continue;
1576             plugin_cert *pc = cpv->v.v;
1577             if (pc->ssl_stapling_file)
1578                 mod_openssl_refresh_stapling_file(srv, pc, cur_ts);
1579         }
1580     }
1581 }
1582 
1583 
1584 static int
mod_openssl_crt_must_staple(const WOLFSSL_X509 * crt)1585 mod_openssl_crt_must_staple (const WOLFSSL_X509 *crt)
1586 {
1587   #if LIBWOLFSSL_VERSION_HEX < 0x05000000 /*(stub func filled in v5.0.0)*/
1588     /* wolfSSL_ASN1_INTEGER_get() is a stub func < v5.0.0; always returns 0 */
1589     UNUSED(crt);
1590     return 0;
1591   #else
1592     STACK_OF(ASN1_OBJECT) * const tlsf = (STACK_OF(ASN1_OBJECT)*)
1593       wolfSSL_X509_get_ext_d2i(crt, NID_tlsfeature, NULL, NULL);
1594     if (NULL == tlsf) return 0;
1595 
1596     int rc = 0;
1597 
1598     /* wolfSSL_sk_ASN1_INTEGER_num() not implemented */
1599     /* wolfSSL_sk_ASN1_INTEGER_value() not implemented */
1600     /* wolfSSL_sk_ASN1_INTEGER_pop_free() not implemented */
1601     #define wolfSSL_sk_ASN1_INTEGER_num(sk) wolfSSL_sk_num(sk)
1602     #define wolfSSL_sk_ASN1_INTEGER_value(sk, i) wolfSSL_sk_value(sk, i)
1603     #define wolfSSL_sk_ASN1_INTEGER_pop_free(sk, fn) wolfSSL_sk_pop_free(sk, fn)
1604 
1605     for (int i = 0; i < wolfSSL_sk_ASN1_INTEGER_num(tlsf); ++i) {
1606         WOLFSSL_ASN1_INTEGER *ai = wolfSSL_sk_ASN1_INTEGER_value(tlsf, i);
1607         long tlsextid = wolfSSL_ASN1_INTEGER_get(ai);
1608         if (tlsextid == 5) { /* 5 = OCSP Must-Staple */
1609             rc = 1;
1610             break;
1611         }
1612     }
1613 
1614     wolfSSL_sk_ASN1_INTEGER_pop_free(tlsf, (wolfSSL_sk_freefunc)
1615                                            wolfSSL_ASN1_INTEGER_free);
1616     return rc; /* 1 if OCSP Must-Staple found; 0 if not */
1617   #endif
1618 }
1619 
1620 #endif /* HAVE_OCSP */
1621 
1622 
1623 static plugin_cert *
network_openssl_load_pemfile(server * srv,const buffer * pemfile,const buffer * privkey,const buffer * ssl_stapling_file)1624 network_openssl_load_pemfile (server *srv, const buffer *pemfile, const buffer *privkey, const buffer *ssl_stapling_file)
1625 {
1626     if (!mod_openssl_init_once_openssl(srv)) return NULL;
1627 
1628     buffer **ssl_pemfile_chain = NULL;
1629     buffer *ssl_pemfile_x509 =
1630       mod_wolfssl_load_pem_file(pemfile->ptr, srv->errh, &ssl_pemfile_chain);
1631     if (NULL == ssl_pemfile_x509) {
1632       #if defined(__clang_analyzer__) || defined(__COVERITY__)
1633         mod_wolfssl_free_der_certs(ssl_pemfile_chain); /*unnecessary*/
1634       #endif
1635         return NULL;
1636     }
1637 
1638     buffer *ssl_pemfile_pkey =
1639       mod_wolfssl_evp_pkey_load_pem_file(privkey->ptr, srv->errh);
1640     if (NULL == ssl_pemfile_pkey) {
1641         /*buffer_free(ssl_pemfile_x509);*//*(part of chain)*/
1642         mod_wolfssl_free_der_certs(ssl_pemfile_chain);
1643         return NULL;
1644     }
1645 
1646     /* wolfSSL_X509_check_private_key() is a stub func (not implemented) in
1647      * WolfSSL prior to v4.6.0, and still no-op #ifdef NO_CHECK_PRIVATE_KEY */
1648 
1649     plugin_cert *pc = ck_malloc(sizeof(plugin_cert));
1650     pc->ssl_pemfile_pkey = ssl_pemfile_pkey;
1651     pc->ssl_pemfile_x509 = ssl_pemfile_x509;
1652     pc->ssl_pemfile_chain= ssl_pemfile_chain;
1653     pc->ssl_pemfile = pemfile;
1654     pc->ssl_privkey = privkey;
1655     pc->ssl_stapling     = NULL;
1656     pc->ssl_stapling_file= ssl_stapling_file;
1657     pc->ssl_stapling_loadts = 0;
1658     pc->ssl_stapling_nextts = 0;
1659   #ifdef HAVE_OCSP
1660     WOLFSSL_X509 *crt =
1661       wolfSSL_X509_load_certificate_buffer((const unsigned char *)
1662                                              ssl_pemfile_x509->ptr,
1663                                            (int)buffer_clen(ssl_pemfile_x509),
1664                                            WOLFSSL_FILETYPE_ASN1);
1665     pc->must_staple = mod_openssl_crt_must_staple(crt);
1666     wolfSSL_X509_free(crt);
1667   #else
1668     pc->must_staple = 0;
1669   #endif
1670 
1671     if (pc->ssl_stapling_file) {
1672       #ifdef HAVE_OCSP
1673         if (!mod_openssl_reload_stapling_file(srv, pc, log_epoch_secs)) {
1674             /* continue without OCSP response if there is an error */
1675         }
1676       #else
1677         log_error(srv->errh, __FILE__, __LINE__, "SSL:"
1678           "OCSP stapling not supported; ignoring %s",
1679           pc->ssl_stapling_file->ptr);
1680       #endif
1681     }
1682     else if (pc->must_staple) {
1683         log_error(srv->errh, __FILE__, __LINE__,
1684                   "certificate %s marked OCSP Must-Staple, "
1685                   "but ssl.stapling-file not provided", pemfile->ptr);
1686     }
1687 
1688   #if 0
1689   #if LIBWOLFSSL_VERSION_HEX >= 0x05000000 /*(stub func filled in v5.0.0)*/
1690     pc->notAfter = /*(see mod_wolfssl_cert_is_active to get X509 crt from buf)*/
1691       mod_openssl_asn1_time_to_posix(wolfSSL_X509_get_notAfter(crt));
1692   #endif
1693   #endif
1694 
1695     return pc;
1696 }
1697 
1698 
1699 #ifdef HAVE_TLS_EXTENSIONS
1700 
1701 #ifdef HAVE_ALPN
1702 #ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
1703 
1704 static int
mod_openssl_acme_tls_1(SSL * ssl,handler_ctx * hctx)1705 mod_openssl_acme_tls_1 (SSL *ssl, handler_ctx *hctx)
1706 {
1707     buffer * const b = hctx->tmp_buf;
1708     const buffer * const name = &hctx->r->uri.authority;
1709     log_error_st * const errh = hctx->r->conf.errh;
1710     buffer *ssl_pemfile_x509 = NULL;
1711     buffer *ssl_pemfile_pkey = NULL;
1712     buffer **ssl_pemfile_chain = NULL;
1713     size_t len;
1714     int rc = SSL_TLSEXT_ERR_ALERT_FATAL;
1715 
1716     /* check if acme-tls/1 protocol is enabled (path to dir of cert(s) is set)*/
1717     if (!hctx->conf.ssl_acme_tls_1)
1718         return SSL_TLSEXT_ERR_NOACK; /*(reuse value here for not-configured)*/
1719 
1720     /* check if SNI set server name (required for acme-tls/1 protocol)
1721      * and perform simple path checks for no '/'
1722      * and no leading '.' (e.g. ignore "." or ".." or anything beginning '.') */
1723     if (buffer_is_blank(name))          return rc;
1724     if (NULL != strchr(name->ptr, '/')) return rc;
1725     if (name->ptr[0] == '.')            return rc;
1726   #if 0
1727     if (0 != http_request_host_policy(name,hctx->r->conf.http_parseopts,443))
1728         return rc;
1729   #endif
1730     buffer_copy_path_len2(b, BUF_PTR_LEN(hctx->conf.ssl_acme_tls_1),
1731                              BUF_PTR_LEN(name));
1732     len = buffer_clen(b);
1733 
1734     do {
1735         buffer_append_string_len(b, CONST_STR_LEN(".crt.pem"));
1736         ssl_pemfile_x509 =
1737           mod_wolfssl_load_pem_file(b->ptr, errh, &ssl_pemfile_chain);
1738         if (NULL == ssl_pemfile_x509) {
1739             log_error(errh, __FILE__, __LINE__,
1740               "SSL: Failed to load acme-tls/1 pemfile: %s", b->ptr);
1741             break;
1742         }
1743 
1744         buffer_truncate(b, len); /*(remove ".crt.pem")*/
1745         buffer_append_string_len(b, CONST_STR_LEN(".key.pem"));
1746         ssl_pemfile_pkey = mod_wolfssl_evp_pkey_load_pem_file(b->ptr, errh);
1747         if (NULL == ssl_pemfile_pkey) {
1748             log_error(errh, __FILE__, __LINE__,
1749               "SSL: Failed to load acme-tls/1 pemfile: %s", b->ptr);
1750             break;
1751         }
1752 
1753       #if 0 /* redundant with below? */
1754         if (!X509_check_private_key(ssl_pemfile_x509, ssl_pemfile_pkey)) {
1755             log_error(errh, __FILE__, __LINE__,
1756                "SSL: Private key does not match acme-tls/1 "
1757                "certificate public key, reason: %s %s"
1758                ERR_error_string(ERR_get_error(), NULL), b->ptr);
1759             break;
1760         }
1761       #endif
1762 
1763         /* first set certificate!
1764          * setting private key checks whether certificate matches it */
1765         buffer *cert = ssl_pemfile_x509;
1766         if (1 != wolfSSL_use_certificate_ASN1(ssl, (unsigned char *)cert->ptr,
1767                                               (int)buffer_clen(cert))){
1768             log_error(errh, __FILE__, __LINE__,
1769               "SSL: failed to set acme-tls/1 certificate for TLS server "
1770               "name %s: %s", name->ptr, ERR_error_string(ERR_get_error(),NULL));
1771             break;
1772         }
1773 
1774         if (ssl_pemfile_chain) {
1775             /* WolfSSL limitation */
1776             /* WolfSSL does not support setting per-session chain;
1777              * limitation is to per-CTX chain, and so chain is not provided for
1778              * "acme-tls/1" (might be non-issue; chain might not be present) */
1779         }
1780 
1781         buffer *pkey = ssl_pemfile_pkey;
1782         if (1 != wolfSSL_use_PrivateKey_buffer(ssl, (unsigned char *)pkey->ptr,
1783                                                (int)buffer_clen(pkey),
1784                                                WOLFSSL_FILETYPE_ASN1)) {
1785             log_error(errh, __FILE__, __LINE__,
1786               "SSL: failed to set acme-tls/1 private key for TLS server "
1787               "name %s: %s", name->ptr, ERR_error_string(ERR_get_error(),NULL));
1788             break;
1789         }
1790 
1791         hctx->conf.ssl_verifyclient_enforce = 0;
1792         wolfSSL_set_verify(ssl, SSL_VERIFY_NONE, NULL);
1793         rc = SSL_TLSEXT_ERR_OK;
1794     } while (0);
1795 
1796     if (ssl_pemfile_pkey) {
1797         wolfSSL_OPENSSL_cleanse(b->ptr, b->size);
1798         buffer_free(ssl_pemfile_pkey);
1799     }
1800     /*if (ssl_pemfile_x509) buffer_free(ssl_pemfile_x509);*//*(part of chain)*/
1801     mod_wolfssl_free_der_certs(ssl_pemfile_chain);
1802 
1803     return rc;
1804 }
1805 
1806 static int
mod_openssl_alpn_h2_policy(handler_ctx * const hctx)1807 mod_openssl_alpn_h2_policy (handler_ctx * const hctx)
1808 {
1809     /*(currently called after handshake has completed)*/
1810   #if 0 /* SNI omitted by client when connecting to IP instead of to name */
1811     if (buffer_is_blank(&hctx->r->uri.authority)) {
1812         log_error(hctx->errh, __FILE__, __LINE__,
1813           "SSL: error ALPN h2 without SNI");
1814         return -1;
1815     }
1816   #endif
1817     if (wolfSSL_version(hctx->ssl) < TLS1_2_VERSION) {
1818         log_error(hctx->errh, __FILE__, __LINE__,
1819           "SSL: error ALPN h2 requires TLSv1.2 or later");
1820         return -1;
1821     }
1822 
1823     return 0;
1824 }
1825 
1826 /* https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#alpn-protocol-ids */
1827 static int
mod_openssl_alpn_select_cb(SSL * ssl,const unsigned char ** out,unsigned char * outlen,const unsigned char * in,unsigned int inlen,void * arg)1828 mod_openssl_alpn_select_cb (SSL *ssl, const unsigned char **out, unsigned char *outlen, const unsigned char *in, unsigned int inlen, void *arg)
1829 {
1830     handler_ctx *hctx = (handler_ctx *) SSL_get_app_data(ssl);
1831     unsigned short proto;
1832     UNUSED(arg);
1833 
1834     for (unsigned int i = 0, n; i < inlen; i += n) {
1835         n = in[i++];
1836         if (i+n > inlen || 0 == n) break;
1837         switch (n) {
1838           case 2:  /* "h2" */
1839             if (in[i] == 'h' && in[i+1] == '2') {
1840                 if (!hctx->r->conf.h2proto) continue;
1841                 proto = MOD_OPENSSL_ALPN_H2;
1842                 if (hctx->r->handler_module == NULL)/*(e.g. not mod_sockproxy)*/
1843                     hctx->r->http_version = HTTP_VERSION_2;
1844                 break;
1845             }
1846             continue;
1847           case 8:  /* "http/1.1" "http/1.0" */
1848             if (0 == memcmp(in+i, "http/1.", 7)) {
1849                 if (in[i+7] == '1') {
1850                     proto = MOD_OPENSSL_ALPN_HTTP11;
1851                     break;
1852                 }
1853                 if (in[i+7] == '0') {
1854                     proto = MOD_OPENSSL_ALPN_HTTP10;
1855                     break;
1856                 }
1857             }
1858             continue;
1859           case 10: /* "acme-tls/1" */
1860             if (0 == memcmp(in+i, "acme-tls/1", 10)) {
1861                 int rc = mod_openssl_acme_tls_1(ssl, hctx);
1862                 if (rc == SSL_TLSEXT_ERR_OK) {
1863                     proto = MOD_OPENSSL_ALPN_ACME_TLS_1;
1864                     break;
1865                 }
1866                 /* (use SSL_TLSEXT_ERR_NOACK for not-configured) */
1867                 if (rc == SSL_TLSEXT_ERR_NOACK) continue;
1868                 return rc;
1869             }
1870             continue;
1871           default:
1872             continue;
1873         }
1874 
1875         hctx->alpn = proto;
1876         *out = in+i;
1877         *outlen = n;
1878         return SSL_TLSEXT_ERR_OK;
1879     }
1880 
1881     return SSL_TLSEXT_ERR_NOACK;
1882 }
1883 
1884 #endif /* TLSEXT_TYPE_application_layer_protocol_negotiation */
1885 #endif /* HAVE_ALPN */
1886 
1887 #endif /* HAVE_TLS_EXTENSIONS */
1888 
1889 
1890 static int
1891 mod_openssl_ssl_conf_cmd (server *srv, plugin_config_socket *s);
1892 
1893 
1894 #ifndef NO_DH
1895 #include <wolfssl/openssl/dh.h>
1896 /* wolfSSL provides wolfSSL_DH_set0_pqg() for
1897  * Apache w/ OPENSSL_VERSION_NUMBER >= 0x10100000L
1898  * but does not provide most other openssl 1.1.0+ interfaces
1899  * and get_dh2048() might not be necessary if wolfSSL defines
1900  * HAVE_TLS_EXTENSIONS HAVE_DH_DEFAULT_PARAMS HAVE_FFDHE HAVE_SUPPORTED_CURVES*/
1901 #ifndef DH_set0_pqg /*(added in wolfssl v5.0.0)*/
1902 #define DH_set0_pqg(dh, dh_p, NULL, dh_g) \
1903         ((dh)->p = (dh_p), (dh)->g = (dh_g), (dh_p) != NULL && (dh_g) != NULL)
1904 #endif
1905 /* https://tools.ietf.org/html/rfc7919#appendix-A.1
1906  * A.1.  ffdhe2048
1907  *
1908  * https://ssl-config.mozilla.org/ffdhe2048.txt
1909  * C code generated with: openssl dhparam -C -in ffdhe2048.txt
1910  */
get_dh2048(void)1911 static DH *get_dh2048(void)
1912 {
1913     static unsigned char dhp_2048[] = {
1914         0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xAD, 0xF8,
1915         0x54, 0x58, 0xA2, 0xBB, 0x4A, 0x9A, 0xAF, 0xDC, 0x56, 0x20,
1916         0x27, 0x3D, 0x3C, 0xF1, 0xD8, 0xB9, 0xC5, 0x83, 0xCE, 0x2D,
1917         0x36, 0x95, 0xA9, 0xE1, 0x36, 0x41, 0x14, 0x64, 0x33, 0xFB,
1918         0xCC, 0x93, 0x9D, 0xCE, 0x24, 0x9B, 0x3E, 0xF9, 0x7D, 0x2F,
1919         0xE3, 0x63, 0x63, 0x0C, 0x75, 0xD8, 0xF6, 0x81, 0xB2, 0x02,
1920         0xAE, 0xC4, 0x61, 0x7A, 0xD3, 0xDF, 0x1E, 0xD5, 0xD5, 0xFD,
1921         0x65, 0x61, 0x24, 0x33, 0xF5, 0x1F, 0x5F, 0x06, 0x6E, 0xD0,
1922         0x85, 0x63, 0x65, 0x55, 0x3D, 0xED, 0x1A, 0xF3, 0xB5, 0x57,
1923         0x13, 0x5E, 0x7F, 0x57, 0xC9, 0x35, 0x98, 0x4F, 0x0C, 0x70,
1924         0xE0, 0xE6, 0x8B, 0x77, 0xE2, 0xA6, 0x89, 0xDA, 0xF3, 0xEF,
1925         0xE8, 0x72, 0x1D, 0xF1, 0x58, 0xA1, 0x36, 0xAD, 0xE7, 0x35,
1926         0x30, 0xAC, 0xCA, 0x4F, 0x48, 0x3A, 0x79, 0x7A, 0xBC, 0x0A,
1927         0xB1, 0x82, 0xB3, 0x24, 0xFB, 0x61, 0xD1, 0x08, 0xA9, 0x4B,
1928         0xB2, 0xC8, 0xE3, 0xFB, 0xB9, 0x6A, 0xDA, 0xB7, 0x60, 0xD7,
1929         0xF4, 0x68, 0x1D, 0x4F, 0x42, 0xA3, 0xDE, 0x39, 0x4D, 0xF4,
1930         0xAE, 0x56, 0xED, 0xE7, 0x63, 0x72, 0xBB, 0x19, 0x0B, 0x07,
1931         0xA7, 0xC8, 0xEE, 0x0A, 0x6D, 0x70, 0x9E, 0x02, 0xFC, 0xE1,
1932         0xCD, 0xF7, 0xE2, 0xEC, 0xC0, 0x34, 0x04, 0xCD, 0x28, 0x34,
1933         0x2F, 0x61, 0x91, 0x72, 0xFE, 0x9C, 0xE9, 0x85, 0x83, 0xFF,
1934         0x8E, 0x4F, 0x12, 0x32, 0xEE, 0xF2, 0x81, 0x83, 0xC3, 0xFE,
1935         0x3B, 0x1B, 0x4C, 0x6F, 0xAD, 0x73, 0x3B, 0xB5, 0xFC, 0xBC,
1936         0x2E, 0xC2, 0x20, 0x05, 0xC5, 0x8E, 0xF1, 0x83, 0x7D, 0x16,
1937         0x83, 0xB2, 0xC6, 0xF3, 0x4A, 0x26, 0xC1, 0xB2, 0xEF, 0xFA,
1938         0x88, 0x6B, 0x42, 0x38, 0x61, 0x28, 0x5C, 0x97, 0xFF, 0xFF,
1939         0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
1940     };
1941     static unsigned char dhg_2048[] = {
1942         0x02
1943     };
1944     DH *dh = DH_new();
1945     BIGNUM *p, *g;
1946 
1947     if (dh == NULL)
1948         return NULL;
1949     p = BN_bin2bn(dhp_2048, sizeof(dhp_2048), NULL);
1950     g = BN_bin2bn(dhg_2048, sizeof(dhg_2048), NULL);
1951     if (p == NULL || g == NULL || !DH_set0_pqg(dh, p, NULL, g)) {
1952         DH_free(dh);
1953         BN_free(p);
1954         BN_free(g);
1955         return NULL;
1956     }
1957     return dh;
1958 }
1959 #endif
1960 
1961 
1962 static int
mod_openssl_ssl_conf_dhparameters(server * srv,plugin_config_socket * s,const buffer * dhparameters)1963 mod_openssl_ssl_conf_dhparameters(server *srv, plugin_config_socket *s, const buffer *dhparameters)
1964 {
1965   #ifndef NO_DH
1966     DH *dh;
1967     /* Support for Diffie-Hellman key exchange */
1968     if (dhparameters) {
1969         const char *fn = dhparameters->ptr;
1970         off_t dlen = 1*1024*1024;/*(arbitrary limit: 1 MB; expect < 1 KB)*/
1971         char *data = fdevent_load_file(fn, &dlen, srv->errh, malloc, free);
1972         int rc = (NULL != data) ? 0 : -1;
1973         if (0 == rc)
1974             wolfSSL_CTX_SetTmpDH_buffer(s->ssl_ctx, (unsigned char *)data,
1975                                         (long)dlen, WOLFSSL_FILETYPE_PEM);
1976         if (dlen) ck_memzero(data, dlen);
1977         free(data);
1978         if (rc < 0) {
1979             log_error(srv->errh, __FILE__, __LINE__,
1980               "SSL: Unable to read DH params from file %s",
1981               dhparameters->ptr);
1982             return 0;
1983         }
1984     }
1985     else {
1986         dh = get_dh2048();
1987         if (dh == NULL) {
1988             log_error(srv->errh, __FILE__, __LINE__,
1989               "SSL: get_dh2048() failed");
1990             return 0;
1991         }
1992         SSL_CTX_set_tmp_dh(s->ssl_ctx, dh);
1993         DH_free(dh);
1994     }
1995     SSL_CTX_set_options(s->ssl_ctx, SSL_OP_SINGLE_DH_USE);
1996   #else
1997     if (dhparameters) {
1998         log_error(srv->errh, __FILE__, __LINE__,
1999           "SSL: wolfssl compiled without DH support, "
2000           "can't load parameters from %s", dhparameters->ptr);
2001     }
2002   #endif
2003 
2004     return 1;
2005 }
2006 
2007 
2008 static int
mod_openssl_ssl_conf_curves(server * srv,plugin_config_socket * s,const buffer * ssl_ec_curve)2009 mod_openssl_ssl_conf_curves(server *srv, plugin_config_socket *s, const buffer *ssl_ec_curve)
2010 {
2011     /* Support for Elliptic-Curve Diffie-Hellman key exchange */
2012     /* OpenSSL only supports the "named curves" from RFC 4492, section 5.1.1. */
2013     const char *curve = ssl_ec_curve ? ssl_ec_curve->ptr : "prime256v1";
2014     int nid = wolfSSL_OBJ_sn2nid(curve);
2015     if (nid) {
2016         EC_KEY * const ecdh = EC_KEY_new_by_curve_name(nid);
2017         if (ecdh == NULL) {
2018             log_error(srv->errh, __FILE__, __LINE__,
2019               "SSL: Unable to create curve %s", curve);
2020             return 0;
2021         }
2022         wolfSSL_SSL_CTX_set_tmp_ecdh(s->ssl_ctx, ecdh);
2023         SSL_CTX_set_options(s->ssl_ctx, SSL_OP_SINGLE_ECDH_USE);
2024         EC_KEY_free(ecdh);
2025         return 1;
2026     }
2027     else {
2028         log_error(srv->errh, __FILE__, __LINE__,
2029           "SSL: Unknown curve name %s", curve);
2030         return 0;
2031     }
2032 }
2033 
2034 
2035 static int
network_init_ssl(server * srv,plugin_config_socket * s,plugin_data * p)2036 network_init_ssl (server *srv, plugin_config_socket *s, plugin_data *p)
2037 {
2038     /* load SSL certificates */
2039 
2040       #ifndef SSL_OP_NO_COMPRESSION
2041       #define SSL_OP_NO_COMPRESSION 0
2042       #endif
2043         long ssloptions = SSL_OP_ALL
2044                         | SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION
2045                         | SSL_OP_NO_COMPRESSION;
2046 
2047       #if LIBWOLFSSL_VERSION_HEX >= 0x04002000
2048         s->ssl_ctx = SSL_CTX_new(TLS_server_method());
2049       #else
2050         s->ssl_ctx = SSL_CTX_new(SSLv23_server_method());
2051       #endif
2052         if (NULL == s->ssl_ctx) {
2053             log_error(srv->errh, __FILE__, __LINE__,
2054               "SSL: %s", ERR_error_string(ERR_get_error(), NULL));
2055             return -1;
2056         }
2057 
2058       #ifdef SSL_OP_NO_RENEGOTIATION /* openssl 1.1.0 */
2059         ssloptions |= SSL_OP_NO_RENEGOTIATION;
2060       #endif
2061 
2062         /* completely useless identifier;
2063          * required for client cert verification to work with sessions */
2064         if (0 == SSL_CTX_set_session_id_context(
2065                    s->ssl_ctx,(const unsigned char*)CONST_STR_LEN("lighttpd"))){
2066             log_error(srv->errh, __FILE__, __LINE__,
2067               "SSL: failed to set session context: %s",
2068               ERR_error_string(ERR_get_error(), NULL));
2069             return -1;
2070         }
2071 
2072       #if !defined(NO_SESSION_CACHE)
2073         const int disable_sess_cache =
2074           !config_feature_bool(srv, "ssl.session-cache", 0);
2075         if (disable_sess_cache)
2076             /* disable session cache; session tickets are preferred */
2077             SSL_CTX_set_session_cache_mode(s->ssl_ctx,
2078                                              SSL_SESS_CACHE_OFF
2079                                            | SSL_SESS_CACHE_NO_AUTO_CLEAR
2080                                            | SSL_SESS_CACHE_NO_INTERNAL);
2081       #endif
2082 
2083         SSL_CTX_set_options(s->ssl_ctx, ssloptions);
2084         SSL_CTX_set_info_callback(s->ssl_ctx, ssl_info_callback);
2085 
2086         /*(wolfSSL does not support SSLv2)*/
2087 
2088         if (0 != SSL_OP_NO_SSLv3) {
2089             /* disable SSLv3 */
2090             if ((SSL_OP_NO_SSLv3
2091                  & SSL_CTX_set_options(s->ssl_ctx, SSL_OP_NO_SSLv3))
2092                 != SSL_OP_NO_SSLv3) {
2093                 log_error(srv->errh, __FILE__, __LINE__,
2094                   "SSL: %s", ERR_error_string(ERR_get_error(), NULL));
2095                 return -1;
2096             }
2097         }
2098 
2099         if (s->ssl_cipher_list) {
2100             /* Disable support for low encryption ciphers */
2101             if (SSL_CTX_set_cipher_list(s->ssl_ctx,s->ssl_cipher_list->ptr)!=1){
2102                 log_error(srv->errh, __FILE__, __LINE__,
2103                   "SSL: %s", ERR_error_string(ERR_get_error(), NULL));
2104                 return -1;
2105             }
2106 
2107             if (s->ssl_honor_cipher_order) {
2108                 SSL_CTX_set_options(s->ssl_ctx,SSL_OP_CIPHER_SERVER_PREFERENCE);
2109             }
2110         }
2111 
2112       #ifdef SSL_OP_PRIORITIZE_CHACHA /*(openssl 1.1.1)*/
2113         if (s->ssl_honor_cipher_order)
2114             SSL_CTX_set_options(s->ssl_ctx, SSL_OP_PRIORITIZE_CHACHA);
2115       #endif
2116 
2117         if (!mod_openssl_ssl_conf_dhparameters(srv, s, NULL))
2118             return -1;
2119 
2120       #ifdef HAVE_SESSION_TICKET
2121         wolfSSL_CTX_set_tlsext_ticket_key_cb(s->ssl_ctx, ssl_tlsext_ticket_key_cb);
2122       #endif
2123 
2124       #ifdef HAVE_OCSP
2125         wolfSSL_CTX_set_tlsext_status_cb(s->ssl_ctx, ssl_tlsext_status_cb);
2126       #endif
2127 
2128         /* load all ssl.ca-files specified in the config into each SSL_CTX
2129          * XXX: This might be a bit excessive, but are all trusted CAs
2130          *      TODO: prefer to load on-demand in mod_openssl_cert_cb()
2131          *            for openssl >= 1.0.2 */
2132         if (!mod_wolfssl_load_ca_files(s->ssl_ctx, p, srv))
2133             return -1;
2134 
2135         if (s->ssl_verifyclient) {
2136             if (NULL == s->ssl_ca_file) {
2137                 log_error(srv->errh, __FILE__, __LINE__,
2138                   "SSL: You specified ssl.verifyclient.activate "
2139                   "but no ssl.verifyclient.ca-file");
2140                 return -1;
2141             }
2142           #ifndef OPENSSL_ALL
2143                 log_error(srv->errh, __FILE__, __LINE__,
2144                   "SSL: You specified ssl.verifyclient.activate "
2145                   "but wolfssl library built without necessary support");
2146                 return -1;
2147           #else
2148             /* Before wolfssl 4.6.0, wolfSSL_dup_CA_list() is a stub function
2149              * which returns NULL, so DN names in cert request are not set here.
2150              * (A patch has been submitted to WolfSSL add is part of 4.6.0)
2151              * https://github.com/wolfSSL/wolfssl/pull/3098 */
2152             STACK_OF(X509_NAME) * const cert_names = s->ssl_ca_dn_file
2153               ? s->ssl_ca_dn_file
2154               : s->ssl_ca_file->names;
2155             wolfSSL_CTX_set_client_CA_list(s->ssl_ctx,
2156                                            wolfSSL_dup_CA_list(cert_names));
2157             int mode = SSL_VERIFY_PEER;
2158             if (s->ssl_verifyclient_enforce) {
2159                 mode |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
2160             }
2161             wolfSSL_CTX_set_verify(s->ssl_ctx, mode, verify_callback);
2162             wolfSSL_CTX_set_verify_depth(s->ssl_ctx,
2163                                          s->ssl_verifyclient_depth + 1);
2164           #endif
2165             if (s->ssl_ca_crl_file) {
2166                 if (!mod_wolfssl_load_cacrls(s->ssl_ctx,s->ssl_ca_crl_file,srv))
2167                     return -1;
2168             }
2169         }
2170 
2171         if (1 != mod_wolfssl_CTX_use_certificate_chain_file(
2172                    s->ssl_ctx, s->pc->ssl_pemfile->ptr, srv->errh))
2173             return -1;
2174 
2175         buffer *k = s->pc->ssl_pemfile_pkey;
2176         if (1 != wolfSSL_CTX_use_PrivateKey_buffer(s->ssl_ctx,
2177                                                    (unsigned char *)k->ptr,
2178                                                    (int)buffer_clen(k),
2179                                                    WOLFSSL_FILETYPE_ASN1)) {
2180             log_error(srv->errh, __FILE__, __LINE__,
2181               "SSL: %s %s %s", ERR_error_string(ERR_get_error(), NULL),
2182               s->pc->ssl_pemfile->ptr, s->pc->ssl_privkey->ptr);
2183             return -1;
2184         }
2185 
2186         if (SSL_CTX_check_private_key(s->ssl_ctx) != 1) {
2187             log_error(srv->errh, __FILE__, __LINE__,
2188               "SSL: Private key does not match the certificate public key, "
2189               "reason: %s %s %s", ERR_error_string(ERR_get_error(), NULL),
2190               s->pc->ssl_pemfile->ptr, s->pc->ssl_privkey->ptr);
2191             return -1;
2192         }
2193 
2194         SSL_CTX_set_default_read_ahead(s->ssl_ctx, s->ssl_read_ahead);
2195         wolfSSL_CTX_set_mode(s->ssl_ctx,
2196                              SSL_MODE_ENABLE_PARTIAL_WRITE);
2197         wolfSSL_CTX_set_mode(s->ssl_ctx, /*(wolfSSL default mode)*/
2198                              WOLFSSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
2199       #ifdef wolfSSL_SSL_MODE_RELEASE_BUFFERS
2200         wolfSSL_CTX_set_mode(s->ssl_ctx, /*(not currently implemented)*/
2201                              wolfSSL_SSL_MODE_RELEASE_BUFFERS);
2202       #endif
2203 
2204       #ifdef HAVE_TLS_EXTENSIONS
2205         /*(wolfSSL preprocessor defines are obnoxious)*/
2206         /*(code should be HAVE_SNI, but is hidden by OPENSSL_ALL
2207          * even though the comment in wolfssl code on the #endif
2208          * says (OPENSSL_ALL
2209          *       || (OPENSSL_EXTRA
2210          *           && (HAVE_STUNNEL || WOLFSSL_NGINX || HAVE_LIGHTY)))
2211          * and sniRecvCb sniRecvCbArg are hidden by *different* set of defines
2212          * in wolfssl/internal.h)
2213          * Note: wolfSSL SNI callbacks members not present unless wolfSSL is
2214          * built OPENSSL_ALL or some additional combination of preprocessor
2215          * defines.  The following should work with more recent wolfSSL versions
2216          * (and HAVE_LIGHTY is not sufficient in wolfssl <= 4.5.0) */
2217        #if defined(OPENSSL_ALL) \
2218         || (defined(OPENSSL_EXTRA) \
2219             && (defined(HAVE_STUNNEL) \
2220                 || defined(WOLFSSL_NGINX) \
2221                 || defined(WOLFSSL_HAPROXY)))
2222        #else
2223        #undef HAVE_SNI
2224        #endif
2225        #ifdef HAVE_SNI
2226         wolfSSL_CTX_set_servername_callback(
2227             s->ssl_ctx, network_ssl_servername_callback);
2228         wolfSSL_CTX_set_servername_arg(s->ssl_ctx, srv);
2229        #else
2230         log_error(srv->errh, __FILE__, __LINE__,
2231           "SSL: WARNING: SNI callbacks *crippled* in wolfSSL library build");
2232         UNUSED(network_ssl_servername_callback);
2233        #endif
2234 
2235        #ifdef HAVE_ALPN
2236        #ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
2237         SSL_CTX_set_alpn_select_cb(s->ssl_ctx,mod_openssl_alpn_select_cb,NULL);
2238        #endif
2239        #endif
2240       #endif
2241 
2242         if (wolfSSL_CTX_SetMinVersion(s->ssl_ctx, WOLFSSL_TLSV1_2)
2243                != WOLFSSL_SUCCESS)
2244             return -1;
2245 
2246         if (s->ssl_conf_cmd && s->ssl_conf_cmd->used) {
2247             if (0 != mod_openssl_ssl_conf_cmd(srv, s)) return -1;
2248         }
2249 
2250         return 0;
2251 }
2252 
2253 
2254 /* expanded from:
2255  * $ openssl ciphers 'EECDH+AESGCM:AES256+EECDH:CHACHA20:!SHA1:!SHA256:!SHA384'
2256  */
2257 #define LIGHTTPD_DEFAULT_CIPHER_LIST \
2258 "TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256:TLS_AES_128_CCM_SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-CCM8:ECDHE-ECDSA-AES256-CCM:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-CHACHA20-POLY1305:RSA-PSK-CHACHA20-POLY1305:DHE-PSK-CHACHA20-POLY1305:ECDHE-PSK-CHACHA20-POLY1305:PSK-CHACHA20-POLY1305"
2259 
2260 
2261 static int
mod_openssl_set_defaults_sockets(server * srv,plugin_data * p)2262 mod_openssl_set_defaults_sockets(server *srv, plugin_data *p)
2263 {
2264     static const config_plugin_keys_t cpk[] = {
2265       { CONST_STR_LEN("ssl.engine"),
2266         T_CONFIG_BOOL,
2267         T_CONFIG_SCOPE_SOCKET }
2268      ,{ CONST_STR_LEN("ssl.cipher-list"),
2269         T_CONFIG_STRING,
2270         T_CONFIG_SCOPE_SOCKET }
2271      ,{ CONST_STR_LEN("ssl.openssl.ssl-conf-cmd"),
2272         T_CONFIG_ARRAY_KVSTRING,
2273         T_CONFIG_SCOPE_SOCKET }
2274      ,{ CONST_STR_LEN("ssl.pemfile"), /* included to process global scope */
2275         T_CONFIG_STRING,
2276         T_CONFIG_SCOPE_CONNECTION }
2277      ,{ CONST_STR_LEN("ssl.stek-file"),
2278         T_CONFIG_STRING,
2279         T_CONFIG_SCOPE_SERVER }
2280      ,{ NULL, 0,
2281         T_CONFIG_UNSET,
2282         T_CONFIG_SCOPE_UNSET }
2283     };
2284     static const buffer default_ssl_cipher_list =
2285       { CONST_STR_LEN(LIGHTTPD_DEFAULT_CIPHER_LIST), 0 };
2286 
2287     p->ssl_ctxs = ck_calloc(srv->config_context->used, sizeof(plugin_ssl_ctx));
2288 
2289     int rc = HANDLER_GO_ON;
2290     plugin_data_base srvplug;
2291     memset(&srvplug, 0, sizeof(srvplug));
2292     plugin_data_base * const ps = &srvplug;
2293     if (!config_plugin_values_init(srv, ps, cpk, "mod_openssl"))
2294         return HANDLER_ERROR;
2295 
2296     plugin_config_socket defaults;
2297     memset(&defaults, 0, sizeof(defaults));
2298     defaults.ssl_cipher_list = &default_ssl_cipher_list;
2299 
2300     /* process and validate config directives for global and $SERVER["socket"]
2301      * (init i to 0 if global context; to 1 to skip empty global context) */
2302     for (int i = !ps->cvlist[0].v.u2[1]; i < ps->nconfig; ++i) {
2303         config_cond_info cfginfo;
2304         config_get_config_cond_info(&cfginfo, (uint32_t)ps->cvlist[i].k_id);
2305         int is_socket_scope = (0 == i || cfginfo.comp == COMP_SERVER_SOCKET);
2306         int count_not_engine = 0;
2307 
2308         plugin_config_socket conf;
2309         memcpy(&conf, &defaults, sizeof(conf));
2310         config_plugin_value_t *cpv = ps->cvlist + ps->cvlist[i].v.u2[0];
2311         for (; -1 != cpv->k_id; ++cpv) {
2312             /* ignore ssl.pemfile (k_id=3); included to process global scope */
2313             if (!is_socket_scope && cpv->k_id != 3) {
2314                 log_error(srv->errh, __FILE__, __LINE__,
2315                   "%s is valid only in global scope or "
2316                   "$SERVER[\"socket\"] condition", cpk[cpv->k_id].k);
2317                 continue;
2318             }
2319             ++count_not_engine;
2320             switch (cpv->k_id) {
2321               case 0: /* ssl.engine */
2322                 conf.ssl_enabled = (0 != cpv->v.u);
2323                 --count_not_engine;
2324                 break;
2325               case 1: /* ssl.cipher-list */
2326                 if (!buffer_is_blank(cpv->v.b)) {
2327                     conf.ssl_cipher_list = cpv->v.b;
2328                     /*(historical use might list non-PFS ciphers)*/
2329                     conf.ssl_honor_cipher_order = 1;
2330                     log_error(srv->errh, __FILE__, __LINE__,
2331                       "%s is deprecated.  "
2332                       "Please prefer lighttpd secure TLS defaults, or use "
2333                       "ssl.openssl.ssl-conf-cmd \"CipherString\" to set custom "
2334                       "cipher list.", cpk[cpv->k_id].k);
2335                 }
2336                 break;
2337               case 2: /* ssl.openssl.ssl-conf-cmd */
2338                 *(const array **)&conf.ssl_conf_cmd = cpv->v.a;
2339                 break;
2340               case 3: /* ssl.pemfile */
2341                 /* ignore here; included to process global scope when
2342                  * ssl.pemfile is set, but ssl.engine is not "enable" */
2343                 break;
2344               case 4: /* ssl.stek-file */
2345                 if (!buffer_is_blank(cpv->v.b))
2346                     p->ssl_stek_file = cpv->v.b->ptr;
2347                 break;
2348               default:/* should not happen */
2349                 break;
2350             }
2351         }
2352         if (HANDLER_GO_ON != rc) break;
2353         if (0 == i) memcpy(&defaults, &conf, sizeof(conf));
2354 
2355         if (0 != i && !conf.ssl_enabled) continue;
2356 
2357         /* fill plugin_config_socket with global context then $SERVER["socket"]
2358          * only for directives directly in current $SERVER["socket"] condition*/
2359 
2360         /*conf.pc                     = p->defaults.pc;*/
2361         conf.ssl_ca_file              = p->defaults.ssl_ca_file;
2362         conf.ssl_ca_dn_file           = p->defaults.ssl_ca_dn_file;
2363         conf.ssl_ca_crl_file          = p->defaults.ssl_ca_crl_file;
2364         conf.ssl_verifyclient         = p->defaults.ssl_verifyclient;
2365         conf.ssl_verifyclient_enforce = p->defaults.ssl_verifyclient_enforce;
2366         conf.ssl_verifyclient_depth   = p->defaults.ssl_verifyclient_depth;
2367         conf.ssl_read_ahead           = p->defaults.ssl_read_ahead;
2368 
2369         int sidx = ps->cvlist[i].k_id;
2370         for (int j = !p->cvlist[0].v.u2[1]; j < p->nconfig; ++j) {
2371             if (p->cvlist[j].k_id != sidx) continue;
2372             /*if (0 == sidx) break;*//*(repeat to get ssl_pemfile,ssl_privkey)*/
2373             cpv = p->cvlist + p->cvlist[j].v.u2[0];
2374             for (; -1 != cpv->k_id; ++cpv) {
2375                 ++count_not_engine;
2376                 switch (cpv->k_id) {
2377                   case 0: /* ssl.pemfile */
2378                     if (cpv->vtype == T_CONFIG_LOCAL)
2379                         conf.pc = cpv->v.v;
2380                     break;
2381                   case 2: /* ssl.ca-file */
2382                     if (cpv->vtype == T_CONFIG_LOCAL)
2383                         conf.ssl_ca_file = cpv->v.v;
2384                     break;
2385                   case 3: /* ssl.ca-dn-file */
2386                     if (cpv->vtype == T_CONFIG_LOCAL)
2387                         conf.ssl_ca_dn_file = cpv->v.v;
2388                     break;
2389                   case 4: /* ssl.ca-crl-file */
2390                     if (!buffer_is_blank(cpv->v.b))
2391                         conf.ssl_ca_crl_file = cpv->v.b;
2392                     break;
2393                   case 5: /* ssl.read-ahead */
2394                     conf.ssl_read_ahead = (0 != cpv->v.u);
2395                     break;
2396                   case 6: /* ssl.disable-client-renegotiation */
2397                     /*(ignored; unsafe renegotiation disabled by default)*/
2398                     break;
2399                   case 7: /* ssl.verifyclient.activate */
2400                     conf.ssl_verifyclient = (0 != cpv->v.u);
2401                     break;
2402                   case 8: /* ssl.verifyclient.enforce */
2403                     conf.ssl_verifyclient_enforce = (0 != cpv->v.u);
2404                     break;
2405                   case 9: /* ssl.verifyclient.depth */
2406                     conf.ssl_verifyclient_depth = (unsigned char)cpv->v.shrt;
2407                     break;
2408                  #if 0    /*(cpk->k_id remapped in mod_openssl_set_defaults())*/
2409                   case 15:/* ssl.verifyclient.ca-file */
2410                   case 16:/* ssl.verifyclient.ca-dn-file */
2411                   case 17:/* ssl.verifyclient.ca-crl-file */
2412                  #endif
2413                   default:
2414                     break;
2415                 }
2416             }
2417             break;
2418         }
2419 
2420         if (NULL == conf.pc) {
2421             if (0 == i && !conf.ssl_enabled) continue;
2422             if (0 != i) {
2423                 /* inherit ssl settings from global scope
2424                  * (if only ssl.engine = "enable" and no other ssl.* settings)
2425                  * (This is for convenience when defining both IPv4 and IPv6
2426                  *  and desiring to inherit the ssl config from global context
2427                  *  without having to duplicate the directives)*/
2428                 if (count_not_engine
2429                     || (conf.ssl_enabled && NULL == p->ssl_ctxs[0].ssl_ctx)) {
2430                     log_error(srv->errh, __FILE__, __LINE__,
2431                       "ssl.pemfile has to be set in same $SERVER[\"socket\"] scope "
2432                       "as other ssl.* directives, unless only ssl.engine is set, "
2433                       "inheriting ssl.* from global scope");
2434                     rc = HANDLER_ERROR;
2435                     continue;
2436                 }
2437                 plugin_ssl_ctx * const s = p->ssl_ctxs + sidx;
2438                 *s = *p->ssl_ctxs;/*(copy struct of ssl_ctx from global scope)*/
2439                 continue;
2440             }
2441             /* PEM file is required */
2442             log_error(srv->errh, __FILE__, __LINE__,
2443               "ssl.pemfile has to be set when ssl.engine = \"enable\"");
2444             rc = HANDLER_ERROR;
2445             continue;
2446         }
2447 
2448         /* configure ssl_ctx for socket */
2449 
2450         /*conf.ssl_ctx = NULL;*//*(filled by network_init_ssl() even on error)*/
2451         if (0 == network_init_ssl(srv, &conf, p)) {
2452             plugin_ssl_ctx * const s = p->ssl_ctxs + sidx;
2453             s->ssl_ctx = conf.ssl_ctx;
2454         }
2455         else {
2456             SSL_CTX_free(conf.ssl_ctx);
2457             rc = HANDLER_ERROR;
2458         }
2459     }
2460 
2461   #ifdef HAVE_SESSION_TICKET
2462     if (rc == HANDLER_GO_ON && ssl_is_init)
2463         mod_openssl_session_ticket_key_check(p, log_epoch_secs);
2464   #endif
2465 
2466     free(srvplug.cvlist);
2467     return rc;
2468 }
2469 
2470 
SETDEFAULTS_FUNC(mod_openssl_set_defaults)2471 SETDEFAULTS_FUNC(mod_openssl_set_defaults)
2472 {
2473     static const config_plugin_keys_t cpk[] = {
2474       { CONST_STR_LEN("ssl.pemfile"),
2475         T_CONFIG_STRING,
2476         T_CONFIG_SCOPE_CONNECTION }
2477      ,{ CONST_STR_LEN("ssl.privkey"),
2478         T_CONFIG_STRING,
2479         T_CONFIG_SCOPE_CONNECTION }
2480      ,{ CONST_STR_LEN("ssl.ca-file"),
2481         T_CONFIG_STRING,
2482         T_CONFIG_SCOPE_CONNECTION }
2483      ,{ CONST_STR_LEN("ssl.ca-dn-file"),
2484         T_CONFIG_STRING,
2485         T_CONFIG_SCOPE_CONNECTION }
2486      ,{ CONST_STR_LEN("ssl.ca-crl-file"),
2487         T_CONFIG_STRING,
2488         T_CONFIG_SCOPE_CONNECTION }
2489      ,{ CONST_STR_LEN("ssl.read-ahead"),
2490         T_CONFIG_BOOL,
2491         T_CONFIG_SCOPE_CONNECTION }
2492      ,{ CONST_STR_LEN("ssl.disable-client-renegotiation"),
2493         T_CONFIG_BOOL, /*(directive ignored)*/
2494         T_CONFIG_SCOPE_CONNECTION }
2495      ,{ CONST_STR_LEN("ssl.verifyclient.activate"),
2496         T_CONFIG_BOOL,
2497         T_CONFIG_SCOPE_CONNECTION }
2498      ,{ CONST_STR_LEN("ssl.verifyclient.enforce"),
2499         T_CONFIG_BOOL,
2500         T_CONFIG_SCOPE_CONNECTION }
2501      ,{ CONST_STR_LEN("ssl.verifyclient.depth"),
2502         T_CONFIG_SHORT,
2503         T_CONFIG_SCOPE_CONNECTION }
2504      ,{ CONST_STR_LEN("ssl.verifyclient.username"),
2505         T_CONFIG_STRING,
2506         T_CONFIG_SCOPE_CONNECTION }
2507      ,{ CONST_STR_LEN("ssl.verifyclient.exportcert"),
2508         T_CONFIG_BOOL,
2509         T_CONFIG_SCOPE_CONNECTION }
2510      ,{ CONST_STR_LEN("ssl.acme-tls-1"),
2511         T_CONFIG_STRING,
2512         T_CONFIG_SCOPE_CONNECTION }
2513      ,{ CONST_STR_LEN("ssl.stapling-file"),
2514         T_CONFIG_STRING,
2515         T_CONFIG_SCOPE_CONNECTION }
2516      ,{ CONST_STR_LEN("debug.log-ssl-noise"),
2517         T_CONFIG_BOOL,
2518         T_CONFIG_SCOPE_CONNECTION }
2519      ,{ CONST_STR_LEN("ssl.verifyclient.ca-file"),
2520         T_CONFIG_STRING,
2521         T_CONFIG_SCOPE_CONNECTION }
2522      ,{ CONST_STR_LEN("ssl.verifyclient.ca-dn-file"),
2523         T_CONFIG_STRING,
2524         T_CONFIG_SCOPE_CONNECTION }
2525      ,{ CONST_STR_LEN("ssl.verifyclient.ca-crl-file"),
2526         T_CONFIG_STRING,
2527         T_CONFIG_SCOPE_CONNECTION }
2528      ,{ NULL, 0,
2529         T_CONFIG_UNSET,
2530         T_CONFIG_SCOPE_UNSET }
2531     };
2532 
2533     plugin_data * const p = p_d;
2534     p->srv = srv;
2535     p->cafiles = array_init(0);
2536     if (!config_plugin_values_init(srv, p, cpk, "mod_openssl"))
2537         return HANDLER_ERROR;
2538 
2539     const buffer *default_ssl_ca_crl_file = NULL;
2540 
2541     /* process and validate config directives
2542      * (init i to 0 if global context; to 1 to skip empty global context) */
2543     for (int i = !p->cvlist[0].v.u2[1]; i < p->nconfig; ++i) {
2544         config_plugin_value_t *cpv = p->cvlist + p->cvlist[i].v.u2[0];
2545         config_plugin_value_t *pemfile = NULL;
2546         config_plugin_value_t *privkey = NULL;
2547         const buffer *ssl_stapling_file = NULL;
2548         const buffer *ssl_ca_file = NULL;
2549         const buffer *ssl_ca_dn_file = NULL;
2550         const buffer *ssl_ca_crl_file = NULL;
2551         X509_STORE *ca_store = NULL;
2552         for (; -1 != cpv->k_id; ++cpv) {
2553             switch (cpv->k_id) {
2554               case 0: /* ssl.pemfile */
2555                 if (!buffer_is_blank(cpv->v.b)) pemfile = cpv;
2556                 break;
2557               case 1: /* ssl.privkey */
2558                 if (!buffer_is_blank(cpv->v.b)) privkey = cpv;
2559                 break;
2560               case 15:/* ssl.verifyclient.ca-file */
2561                 cpv->k_id = 2;
2562                 __attribute_fallthrough__
2563               case 2: /* ssl.ca-file */
2564                 if (buffer_is_blank(cpv->v.b)) break;
2565                 if (!mod_openssl_init_once_openssl(srv)) return HANDLER_ERROR;
2566                 ssl_ca_file = cpv->v.b;
2567                 cpv->v.v = mod_wolfssl_load_cacerts(ssl_ca_file, srv->errh);
2568                 if (NULL != cpv->v.v) {
2569                     cpv->vtype = T_CONFIG_LOCAL;
2570                     ca_store = ((plugin_cacerts *)cpv->v.v)->certs;
2571                 }
2572                 else {
2573                     log_error(srv->errh, __FILE__, __LINE__, "SSL: %s %s",
2574                       ERR_error_string(ERR_get_error(), NULL),
2575                       ssl_ca_file->ptr);
2576                     return HANDLER_ERROR;
2577                 }
2578                 break;
2579               case 16:/* ssl.verifyclient.ca-dn-file */
2580                 cpv->k_id = 3;
2581                 __attribute_fallthrough__
2582               case 3: /* ssl.ca-dn-file */
2583                 if (buffer_is_blank(cpv->v.b)) break;
2584                 if (!mod_openssl_init_once_openssl(srv)) return HANDLER_ERROR;
2585                 ssl_ca_dn_file = cpv->v.b;
2586                #ifndef OPENSSL_ALL
2587                 {
2588                     log_error(srv->errh, __FILE__, __LINE__,
2589                       "SSL: You specified %s but wolfssl library built without "
2590                       "necessary support", cpk[cpv->k_id].k);
2591                     return HANDLER_ERROR;
2592                 }
2593                #endif
2594                 cpv->v.v = mod_wolfssl_load_client_CA_file(ssl_ca_dn_file,
2595                                                            srv->errh);
2596                 if (NULL != cpv->v.v) {
2597                     cpv->vtype = T_CONFIG_LOCAL;
2598                 }
2599                 else {
2600                     log_error(srv->errh, __FILE__, __LINE__, "SSL: %s %s",
2601                       ERR_error_string(ERR_get_error(), NULL),
2602                       ssl_ca_dn_file->ptr);
2603                     return HANDLER_ERROR;
2604                 }
2605                 break;
2606               case 17:/* ssl.verifyclient.ca-crl-file */
2607                 cpv->k_id = 4;
2608                 __attribute_fallthrough__
2609               case 4: /* ssl.ca-crl-file */
2610                 if (buffer_is_blank(cpv->v.b)) break;
2611                 ssl_ca_crl_file = cpv->v.b;
2612                 if (0 == i) default_ssl_ca_crl_file = cpv->v.b;
2613                 break;
2614               case 5: /* ssl.read-ahead */
2615               case 6: /* ssl.disable-client-renegotiation */
2616                 /*(ignored; unsafe renegotiation disabled by default)*/
2617               case 7: /* ssl.verifyclient.activate */
2618               case 8: /* ssl.verifyclient.enforce */
2619                 break;
2620               case 9: /* ssl.verifyclient.depth */
2621                 if (cpv->v.shrt > 255) {
2622                     log_error(srv->errh, __FILE__, __LINE__,
2623                       "%s is absurdly large (%hu); limiting to 255",
2624                       cpk[cpv->k_id].k, cpv->v.shrt);
2625                     cpv->v.shrt = 255;
2626                 }
2627                 break;
2628               case 10:/* ssl.verifyclient.username */
2629                 if (buffer_is_blank(cpv->v.b))
2630                     cpv->v.b = NULL;
2631                 break;
2632               case 11:/* ssl.verifyclient.exportcert */
2633                 break;
2634               case 12:/* ssl.acme-tls-1 */
2635                 if (buffer_is_blank(cpv->v.b))
2636                     cpv->v.b = NULL;
2637                 break;
2638               case 13:/* ssl.stapling-file */
2639                 if (!buffer_is_blank(cpv->v.b))
2640                     ssl_stapling_file = cpv->v.b;
2641                 break;
2642               case 14:/* debug.log-ssl-noise */
2643              #if 0    /*(handled further above)*/
2644               case 15:/* ssl.verifyclient.ca-file */
2645               case 16:/* ssl.verifyclient.ca-dn-file */
2646               case 17:/* ssl.verifyclient.ca-crl-file */
2647              #endif
2648                 break;
2649               default:/* should not happen */
2650                 break;
2651             }
2652         }
2653 
2654         /* p->cafiles for legacy only */
2655         /* load all ssl.ca-files into a single chain */
2656         /*(certificate load order might matter)*/
2657         if (ssl_ca_dn_file)
2658             array_insert_value(p->cafiles, BUF_PTR_LEN(ssl_ca_dn_file));
2659         if (ssl_ca_file)
2660             array_insert_value(p->cafiles, BUF_PTR_LEN(ssl_ca_file));
2661         UNUSED(ca_store);
2662         UNUSED(ssl_ca_crl_file);
2663         UNUSED(default_ssl_ca_crl_file);
2664 
2665         if (pemfile) {
2666           #ifndef HAVE_TLS_EXTENSIONS
2667             config_cond_info cfginfo;
2668             uint32_t j = (uint32_t)p->cvlist[i].k_id;
2669             config_get_config_cond_info(&cfginfo, j);
2670             if (j > 0 && (COMP_SERVER_SOCKET != cfginfo.comp
2671                           || cfginfo.cond != CONFIG_COND_EQ)) {
2672                 if (COMP_HTTP_HOST == cfginfo.comp)
2673                     log_error(srv->errh, __FILE__, __LINE__, "SSL:"
2674                       "can't use ssl.pemfile with $HTTP[\"host\"], "
2675                       "as openssl version does not support TLS extensions");
2676                 else
2677                     log_error(srv->errh, __FILE__, __LINE__, "SSL:"
2678                       "ssl.pemfile only works in SSL socket binding context "
2679                       "as openssl version does not support TLS extensions");
2680                 return HANDLER_ERROR;
2681             }
2682           #endif
2683             if (NULL == privkey) privkey = pemfile;
2684             pemfile->v.v =
2685               network_openssl_load_pemfile(srv, pemfile->v.b, privkey->v.b,
2686                                            ssl_stapling_file);
2687             if (pemfile->v.v)
2688                 pemfile->vtype = T_CONFIG_LOCAL;
2689             else
2690                 return HANDLER_ERROR;
2691         }
2692     }
2693 
2694     p->defaults.ssl_verifyclient = 0;
2695     p->defaults.ssl_verifyclient_enforce = 1;
2696     p->defaults.ssl_verifyclient_depth = 9;
2697     p->defaults.ssl_verifyclient_export_cert = 0;
2698     p->defaults.ssl_read_ahead = 0;
2699 
2700     /* initialize p->defaults from global config context */
2701     if (p->nconfig > 0 && p->cvlist->v.u2[1]) {
2702         const config_plugin_value_t *cpv = p->cvlist + p->cvlist->v.u2[0];
2703         if (-1 != cpv->k_id)
2704             mod_openssl_merge_config(&p->defaults, cpv);
2705     }
2706 
2707     return mod_openssl_set_defaults_sockets(srv, p);
2708 }
2709 
2710 
2711     /* local_send_buffer is a static buffer of size (LOCAL_SEND_BUFSIZE)
2712      *
2713      * it has to stay at the same location all the time to satisfy the needs
2714      * of SSL_write to pass the SAME parameter in case of a _WANT_WRITE
2715      *
2716      * buffer is allocated once, is NOT realloced (note: not thread-safe)
2717      *
2718      * (Note: above restriction no longer true since SSL_CTX_set_mode() is
2719      *        called with SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER)
2720      * */
2721 
2722             /* copy small mem chunks into single large buffer before SSL_write()
2723              * to reduce number times write() called underneath SSL_write() and
2724              * potentially reduce number of packets generated if TCP_NODELAY */
2725 
2726 
2727 static int
2728 mod_openssl_close_notify(handler_ctx *hctx);
2729 
2730 
2731 static int
connection_write_cq_ssl(connection * const con,chunkqueue * const cq,off_t max_bytes)2732 connection_write_cq_ssl (connection * const con, chunkqueue * const cq, off_t max_bytes)
2733 {
2734     handler_ctx * const hctx = con->plugin_ctx[plugin_data_singleton->id];
2735     SSL * const ssl = hctx->ssl;
2736     log_error_st * const errh = hctx->errh;
2737 
2738     if (__builtin_expect( (0 != hctx->close_notify), 0))
2739         return mod_openssl_close_notify(hctx);
2740 
2741     while (max_bytes > 0 && !chunkqueue_is_empty(cq)) {
2742         char *data = local_send_buffer;
2743         uint32_t data_len = LOCAL_SEND_BUFSIZE < max_bytes
2744           ? LOCAL_SEND_BUFSIZE
2745           : (uint32_t)max_bytes;
2746         int wr;
2747 
2748         if (0 != chunkqueue_peek_data(cq, &data, &data_len, errh)) return -1;
2749         if (__builtin_expect( (0 == data_len), 0)) {
2750             chunkqueue_remove_finished_chunks(cq);
2751             continue;
2752         }
2753 
2754         /**
2755          * SSL_write man-page
2756          *
2757          * WARNING
2758          *        When an SSL_write() operation has to be repeated because of
2759          *        SSL_ERROR_WANT_READ or SSL_ERROR_WANT_WRITE, it must be
2760          *        repeated with the same arguments.
2761          */
2762 
2763         ERR_clear_error();
2764         wr = SSL_write(ssl, data, data_len);
2765 
2766         if (__builtin_expect( (hctx->renegotiations > 1), 0)) {
2767             log_error(errh, __FILE__, __LINE__,
2768               "SSL: renegotiation initiated by client, killing connection");
2769             return -1;
2770         }
2771 
2772         if (wr <= 0) {
2773             int ssl_r;
2774             unsigned long err;
2775 
2776             switch ((ssl_r = SSL_get_error(ssl, wr))) {
2777             case SSL_ERROR_WANT_READ:
2778                 con->is_readable = -1;
2779                 return 0; /* try again later */
2780             case SSL_ERROR_WANT_WRITE:
2781                 con->is_writable = -1;
2782                 return 0; /* try again later */
2783             case SSL_ERROR_SYSCALL:
2784                 /* perhaps we have error waiting in our error-queue */
2785                 if (0 != (err = ERR_get_error())) {
2786                     do {
2787                         log_error(errh, __FILE__, __LINE__,
2788                           "SSL: %d %d %s",ssl_r,wr,ERR_error_string(err,NULL));
2789                     } while((err = ERR_get_error()));
2790                 } else if (wr == -1) {
2791                     /* no, but we have errno */
2792                     switch(errno) {
2793                     case EPIPE:
2794                     case ECONNRESET:
2795                         return -2;
2796                     default:
2797                         log_perror(errh, __FILE__, __LINE__,
2798                           "SSL: %d %d", ssl_r, wr);
2799                         break;
2800                     }
2801                 } else {
2802                     /* neither error-queue nor errno ? */
2803                     log_perror(errh, __FILE__, __LINE__,
2804                       "SSL (error): %d %d", ssl_r, wr);
2805                 }
2806                 break;
2807 
2808             case SSL_ERROR_ZERO_RETURN:
2809                 /* clean shutdown on the remote side */
2810 
2811                 if (wr == 0) return -2;
2812 
2813                 __attribute_fallthrough__
2814             default:
2815                 while((err = ERR_get_error())) {
2816                     log_error(errh, __FILE__, __LINE__,
2817                       "SSL: %d %d %s", ssl_r, wr, ERR_error_string(err, NULL));
2818                 }
2819                 break;
2820             }
2821             return -1;
2822         }
2823 
2824         chunkqueue_mark_written(cq, wr);
2825         max_bytes -= wr;
2826 
2827         if ((size_t) wr < data_len) break; /* try again later */
2828     }
2829 
2830     return 0;
2831 }
2832 
2833 
2834 static int
connection_read_cq_ssl(connection * const con,chunkqueue * const cq,off_t max_bytes)2835 connection_read_cq_ssl (connection * const con, chunkqueue * const cq, off_t max_bytes)
2836 {
2837     handler_ctx * const hctx = con->plugin_ctx[plugin_data_singleton->id];
2838     int len;
2839     char *mem = NULL;
2840     size_t mem_len = 0;
2841 
2842     UNUSED(max_bytes);
2843 
2844     if (__builtin_expect( (0 != hctx->close_notify), 0))
2845         return mod_openssl_close_notify(hctx);
2846 
2847     ERR_clear_error();
2848     do {
2849         len = SSL_pending(hctx->ssl);
2850         mem_len = len < 2048 ? 2048 : (size_t)len;
2851         chunk * const ckpt = cq->last;
2852         mem = chunkqueue_get_memory(cq, &mem_len);
2853 
2854         len = SSL_read(hctx->ssl, mem, mem_len);
2855         chunkqueue_use_memory(cq, ckpt, len > 0 ? len : 0);
2856 
2857         if (hctx->renegotiations > 1) {
2858             log_error(hctx->errh, __FILE__, __LINE__,
2859               "SSL: renegotiation initiated by client, killing connection");
2860             return -1;
2861         }
2862 
2863       #ifdef HAVE_ALPN
2864       #ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
2865         if (hctx->alpn) {
2866             if (hctx->alpn == MOD_OPENSSL_ALPN_H2) {
2867                 if (0 != mod_openssl_alpn_h2_policy(hctx))
2868                     return -1;
2869             }
2870             else if (hctx->alpn == MOD_OPENSSL_ALPN_ACME_TLS_1) {
2871                 chunkqueue_reset(cq);
2872                 /* initiate handshake in order to send ServerHello.
2873                  * Once TLS handshake is complete, return -1 to result in
2874                  * CON_STATE_ERROR so that socket connection is quickly closed*/
2875                 if (1 == SSL_do_handshake(hctx->ssl)) return -1;
2876                 len = -1;
2877                 break;
2878             }
2879             hctx->alpn = 0;
2880         }
2881       #endif
2882       #endif
2883     } while (len > 0
2884              && (hctx->conf.ssl_read_ahead || SSL_pending(hctx->ssl) > 0));
2885 
2886     if (len < 0) {
2887         int oerrno = errno;
2888         int rc, ssl_err;
2889         switch ((rc = SSL_get_error(hctx->ssl, len))) {
2890         case SSL_ERROR_WANT_WRITE:
2891             con->is_writable = -1;
2892             __attribute_fallthrough__
2893         case SSL_ERROR_WANT_READ:
2894             con->is_readable = 0;
2895 
2896             /* the manual says we have to call SSL_read with the same arguments
2897              * next time.  we ignore this restriction; no one has complained
2898              * about it in 1.5 yet, so it probably works anyway.
2899              */
2900 
2901             return 0;
2902         case SSL_ERROR_SYSCALL:
2903             /**
2904              * man SSL_get_error()
2905              *
2906              * SSL_ERROR_SYSCALL
2907              *   Some I/O error occurred.  The OpenSSL error queue may contain
2908              *   more information on the error.  If the error queue is empty
2909              *   (i.e. ERR_get_error() returns 0), ret can be used to find out
2910              *   more about the error: If ret == 0, an EOF was observed that
2911              *   violates the protocol.  If ret == -1, the underlying BIO
2912              *   reported an I/O error (for socket I/O on Unix systems, consult
2913              *   errno for details).
2914              *
2915              */
2916             while((ssl_err = ERR_get_error())) {
2917                 /* get all errors from the error-queue */
2918                 log_error(hctx->errh, __FILE__, __LINE__,
2919                   "SSL: %d %s", rc, ERR_error_string(ssl_err, NULL));
2920             }
2921 
2922             switch(oerrno) {
2923             case ECONNRESET:
2924                 if (!hctx->conf.ssl_log_noise) break;
2925                 __attribute_fallthrough__
2926             default:
2927                 /* (oerrno should be something like ECONNABORTED not 0
2928                  *  if client disconnected before anything was sent
2929                  *  (e.g. TCP connection probe), but it does not appear
2930                  *  that openssl provides such notification, not even
2931                  *  something like SSL_R_SSL_HANDSHAKE_FAILURE) */
2932                 if (0==oerrno && 0==cq->bytes_in && !hctx->conf.ssl_log_noise)
2933                     break;
2934 
2935                 errno = oerrno; /*(for log_perror())*/
2936                 log_perror(hctx->errh, __FILE__, __LINE__,
2937                   "SSL: %d %d %d", len, rc, oerrno);
2938                 break;
2939             }
2940 
2941             break;
2942         case SSL_ERROR_ZERO_RETURN:
2943             /* clean shutdown on the remote side */
2944 
2945             /* future: might set flag to record that we received CLOSE_NOTIFY
2946              * TLS alert from peer, then have future calls to this func return
2947              * the equivalent of EOF, but we also want to remove read interest
2948              * on fd, perhaps by setting RDHUP.  If setting is_readable, ensure
2949              * that callers avoid spinning if we return EOF while is_readable.
2950              *
2951              * Should we treat this like len == 0 below and return -2 ? */
2952 
2953             /*__attribute_fallthrough__*/
2954         default:
2955             while((ssl_err = ERR_get_error())) {
2956                 switch (ERR_GET_REASON(ssl_err)) {
2957                 case SSL_R_SSL_HANDSHAKE_FAILURE:
2958               #ifdef SSL_R_UNEXPECTED_EOF_WHILE_READING
2959                 case SSL_R_UNEXPECTED_EOF_WHILE_READING:
2960               #endif
2961               #ifdef SSL_R_TLSV1_ALERT_UNKNOWN_CA
2962                 case SSL_R_TLSV1_ALERT_UNKNOWN_CA:
2963               #endif
2964               #ifdef SSL_R_SSLV3_ALERT_CERTIFICATE_UNKNOWN
2965                 case SSL_R_SSLV3_ALERT_CERTIFICATE_UNKNOWN:
2966               #endif
2967               #ifdef SSL_R_SSLV3_ALERT_BAD_CERTIFICATE
2968                 case SSL_R_SSLV3_ALERT_BAD_CERTIFICATE:
2969               #endif
2970                     if (!hctx->conf.ssl_log_noise) continue;
2971                     break;
2972                 default:
2973                     break;
2974                 }
2975                 /* get all errors from the error-queue */
2976                 log_error(hctx->errh, __FILE__, __LINE__,
2977                   "SSL: %d %s", rc, ERR_error_string(ssl_err, NULL));
2978             }
2979             break;
2980         }
2981         return -1;
2982     } else if (len == 0) {
2983         con->is_readable = 0;
2984         /* the other end close the connection -> KEEP-ALIVE */
2985 
2986         return -2;
2987     } else {
2988         return 0;
2989     }
2990 }
2991 
2992 
CONNECTION_FUNC(mod_openssl_handle_con_accept)2993 CONNECTION_FUNC(mod_openssl_handle_con_accept)
2994 {
2995     const server_socket *srv_sock = con->srv_socket;
2996     if (!srv_sock->is_ssl) return HANDLER_GO_ON;
2997 
2998     plugin_data *p = p_d;
2999     handler_ctx * const hctx = handler_ctx_init();
3000     request_st * const r = &con->request;
3001     hctx->r = r;
3002     hctx->con = con;
3003     hctx->tmp_buf = con->srv->tmp_buf;
3004     hctx->errh = r->conf.errh;
3005     con->plugin_ctx[p->id] = hctx;
3006     buffer_blank(&r->uri.authority);
3007 
3008     plugin_ssl_ctx * const s = p->ssl_ctxs + srv_sock->sidx;
3009     hctx->ssl = SSL_new(s->ssl_ctx);
3010     if (NULL != hctx->ssl
3011         && SSL_set_app_data(hctx->ssl, hctx)
3012         && SSL_set_fd(hctx->ssl, con->fd)) {
3013         SSL_set_accept_state(hctx->ssl);
3014         con->network_read = connection_read_cq_ssl;
3015         con->network_write = connection_write_cq_ssl;
3016         con->proto_default_port = 443; /* "https" */
3017         mod_openssl_patch_config(r, &hctx->conf);
3018         return HANDLER_GO_ON;
3019     }
3020     else {
3021         log_error(r->conf.errh, __FILE__, __LINE__,
3022           "SSL: %s", ERR_error_string(ERR_get_error(), NULL));
3023         return HANDLER_ERROR;
3024     }
3025 }
3026 
3027 
3028 static void
mod_openssl_detach(handler_ctx * hctx)3029 mod_openssl_detach(handler_ctx *hctx)
3030 {
3031     /* step aside from further SSL processing
3032      * (used after handle_connection_shut_wr hook) */
3033     /* future: might restore prior network_read and network_write fn ptrs */
3034     hctx->con->is_ssl_sock = 0;
3035     /* if called after handle_connection_shut_wr hook, shutdown SHUT_WR */
3036     if (-1 == hctx->close_notify) shutdown(hctx->con->fd, SHUT_WR);
3037     hctx->close_notify = 1;
3038 }
3039 
3040 
CONNECTION_FUNC(mod_openssl_handle_con_shut_wr)3041 CONNECTION_FUNC(mod_openssl_handle_con_shut_wr)
3042 {
3043     plugin_data *p = p_d;
3044     handler_ctx *hctx = con->plugin_ctx[p->id];
3045     if (NULL == hctx) return HANDLER_GO_ON;
3046 
3047     hctx->close_notify = -2;
3048     if (SSL_is_init_finished(hctx->ssl)) {
3049         mod_openssl_close_notify(hctx);
3050     }
3051     else {
3052         mod_openssl_detach(hctx);
3053     }
3054 
3055     return HANDLER_GO_ON;
3056 }
3057 
3058 
3059 static int
mod_openssl_close_notify(handler_ctx * hctx)3060 mod_openssl_close_notify(handler_ctx *hctx)
3061 {
3062         int ret, ssl_r;
3063         unsigned long err;
3064         log_error_st *errh;
3065 
3066         if (1 == hctx->close_notify) return -2;
3067 
3068         ERR_clear_error();
3069         switch ((ret = SSL_shutdown(hctx->ssl))) {
3070         case 1:
3071             mod_openssl_detach(hctx);
3072             return -2;
3073         case 0:
3074             /* Drain SSL read buffers in case pending records need processing.
3075              * Limit to reading next record to avoid denial of service when CPU
3076              * processing TLS is slower than arrival speed of TLS data packets.
3077              * (unless hctx->conf.ssl_read_ahead is set)
3078              *
3079              * references:
3080              *
3081              * "New session ticket breaks bidirectional shutdown of TLS 1.3 connection"
3082              * https://github.com/openssl/openssl/issues/6262
3083              *
3084              * The peer is still allowed to send data after receiving the
3085              * "close notify" event. If the peer did send data it need to be
3086              * processed by calling SSL_read() before calling SSL_shutdown() a
3087              * second time. SSL_read() will indicate the end of the peer data by
3088              * returning <= 0 and SSL_get_error() returning
3089              * SSL_ERROR_ZERO_RETURN. It is recommended to call SSL_read()
3090              * between SSL_shutdown() calls.
3091              *
3092              * Additional discussion in "Auto retry in shutdown"
3093              * https://github.com/openssl/openssl/pull/6340
3094              */
3095             ssl_r = SSL_pending(hctx->ssl);
3096             if (ssl_r) {
3097                 do {
3098                     char buf[4096];
3099                     ret = SSL_read(hctx->ssl, buf, (int)sizeof(buf));
3100                 } while (ret > 0 && (hctx->conf.ssl_read_ahead||(ssl_r-=ret)));
3101             }
3102 
3103             ERR_clear_error();
3104             switch ((ret = SSL_shutdown(hctx->ssl))) {
3105             case 1:
3106                 mod_openssl_detach(hctx);
3107                 return -2;
3108             case 0:
3109                 hctx->close_notify = -1;
3110                 return 0;
3111             default:
3112                 break;
3113             }
3114 
3115             __attribute_fallthrough__
3116         default:
3117 
3118             if (!SSL_is_init_finished(hctx->ssl)) {
3119                 mod_openssl_detach(hctx);
3120                 return -2;
3121             }
3122 
3123             switch ((ssl_r = SSL_get_error(hctx->ssl, ret))) {
3124             case SSL_ERROR_WANT_WRITE:
3125             case SSL_ERROR_WANT_READ:
3126             case SSL_ERROR_ZERO_RETURN: /*(unexpected here)*/
3127                 hctx->close_notify = -1;
3128                 return 0; /* try again later */
3129             case SSL_ERROR_SYSCALL:
3130                 if (0 == ERR_peek_error()) {
3131                     switch(errno) {
3132                     case 0: /*ssl bug (see lighttpd ticket #2213)*/
3133                     case EPIPE:
3134                     case ECONNRESET:
3135                         mod_openssl_detach(hctx);
3136                         return -2;
3137                     default:
3138                         log_perror(hctx->r->conf.errh, __FILE__, __LINE__,
3139                           "SSL (error): %d %d", ssl_r, ret);
3140                         break;
3141                     }
3142                     break;
3143                 }
3144                 __attribute_fallthrough__
3145             default:
3146                 errh = hctx->r->conf.errh;
3147                 while((err = ERR_get_error())) {
3148                     log_error(errh, __FILE__, __LINE__,
3149                       "SSL: %d %d %s", ssl_r, ret, ERR_error_string(err, NULL));
3150                 }
3151 
3152                 break;
3153             }
3154         }
3155         ERR_clear_error();
3156         hctx->close_notify = -1;
3157         return ret;
3158 }
3159 
3160 
CONNECTION_FUNC(mod_openssl_handle_con_close)3161 CONNECTION_FUNC(mod_openssl_handle_con_close)
3162 {
3163     plugin_data *p = p_d;
3164     handler_ctx *hctx = con->plugin_ctx[p->id];
3165     if (NULL != hctx) {
3166         con->plugin_ctx[p->id] = NULL;
3167         handler_ctx_free(hctx);
3168     }
3169 
3170     return HANDLER_GO_ON;
3171 }
3172 
3173 
3174 #ifndef OBJ_nid2sn
3175 #define OBJ_nid2sn  wolfSSL_OBJ_nid2sn
3176 #endif
3177 #ifndef OBJ_obj2nid
3178 #define OBJ_obj2nid wolfSSL_OBJ_obj2nid
3179 #endif
3180 #include <wolfssl/wolfcrypt/asn_public.h>
3181 
3182 
3183 static void
https_add_ssl_client_subject(request_st * const r,X509_NAME * xn)3184 https_add_ssl_client_subject (request_st * const r, X509_NAME *xn)
3185 {
3186     const size_t prelen = sizeof("SSL_CLIENT_S_DN_")-1;
3187     char key[64] = "SSL_CLIENT_S_DN_";
3188     for (int i = 0, nentries = X509_NAME_entry_count(xn); i < nentries; ++i) {
3189         int xobjnid;
3190         const char * xobjsn;
3191         X509_NAME_ENTRY *xe;
3192 
3193         if (!(xe = wolfSSL_X509_NAME_get_entry(xn, i))) {
3194             continue;
3195         }
3196         xobjnid = OBJ_obj2nid((ASN1_OBJECT*)X509_NAME_ENTRY_get_object(xe));
3197         xobjsn = OBJ_nid2sn(xobjnid);
3198         if (xobjsn) {
3199             const size_t len = strlen(xobjsn);
3200             if (prelen+len >= sizeof(key)) continue;
3201             memcpy(key+prelen, xobjsn, len); /*(not '\0'-terminated)*/
3202             http_header_env_set(r, key, prelen+len,
3203                                 (const char*)X509_NAME_ENTRY_get_data(xe)->data,
3204                                 X509_NAME_ENTRY_get_data(xe)->length);
3205         }
3206     }
3207 }
3208 
3209 
3210 __attribute_cold__
3211 static void
https_add_ssl_client_verify_err(buffer * const b,long status)3212 https_add_ssl_client_verify_err (buffer * const b, long status)
3213 {
3214     char errstr[256];
3215     ERR_error_string_n(status, errstr, sizeof(errstr));
3216     buffer_append_string(b, errstr);
3217 }
3218 
3219 
3220 __attribute_noinline__
3221 static void
https_add_ssl_client_entries(request_st * const r,handler_ctx * const hctx)3222 https_add_ssl_client_entries (request_st * const r, handler_ctx * const hctx)
3223 {
3224     X509 *xs;
3225     X509_NAME *xn;
3226     buffer *vb = http_header_env_set_ptr(r, CONST_STR_LEN("SSL_CLIENT_VERIFY"));
3227 
3228     long vr = SSL_get_verify_result(hctx->ssl);
3229     if (vr != X509_V_OK) {
3230         buffer_copy_string_len(vb, CONST_STR_LEN("FAILED:"));
3231         https_add_ssl_client_verify_err(vb, vr);
3232         return;
3233     } else if (!(xs = SSL_get_peer_certificate(hctx->ssl))) {
3234         buffer_copy_string_len(vb, CONST_STR_LEN("NONE"));
3235         return;
3236     } else {
3237         buffer_copy_string_len(vb, CONST_STR_LEN("SUCCESS"));
3238     }
3239 
3240     xn = X509_get_subject_name(xs);
3241     {
3242         char buf[256];
3243         int len = safer_X509_NAME_oneline(xn, buf, sizeof(buf));
3244         if (len > 0) {
3245             if (len >= (int)sizeof(buf)) len = (int)sizeof(buf)-1;
3246             http_header_env_set(r,
3247                                 CONST_STR_LEN("SSL_CLIENT_S_DN"),
3248                                 buf, (size_t)len);
3249         }
3250     }
3251 
3252     https_add_ssl_client_subject(r, xn);
3253 
3254     {
3255         byte buf[64];
3256         int bsz = (int)sizeof(buf);
3257         if (wolfSSL_X509_get_serial_number(xs, buf, &bsz) == WOLFSSL_SUCCESS) {
3258             buffer_append_string_encoded_hex_uc(
3259               http_header_env_set_ptr(r, CONST_STR_LEN("SSL_CLIENT_M_SERIAL")),
3260               (char *)buf, (size_t)bsz);
3261         }
3262     }
3263 
3264     if (hctx->conf.ssl_verifyclient_username) {
3265         /* pick one of the exported values as "REMOTE_USER", for example
3266          *   ssl.verifyclient.username = "SSL_CLIENT_S_DN_UID"
3267          * or
3268          *   ssl.verifyclient.username = "SSL_CLIENT_S_DN_emailAddress"
3269          */
3270         const buffer *varname = hctx->conf.ssl_verifyclient_username;
3271         vb = http_header_env_get(r, BUF_PTR_LEN(varname));
3272         if (vb) { /* same as mod_auth_api.c:http_auth_setenv() */
3273             http_header_env_set(r,
3274                                 CONST_STR_LEN("REMOTE_USER"),
3275                                 BUF_PTR_LEN(vb));
3276             http_header_env_set(r,
3277                                 CONST_STR_LEN("AUTH_TYPE"),
3278                                 CONST_STR_LEN("SSL_CLIENT_VERIFY"));
3279         }
3280     }
3281 
3282     if (hctx->conf.ssl_verifyclient_export_cert) {
3283         int dersz, pemsz;
3284         const unsigned char *der = wolfSSL_X509_get_der(xs, &dersz);
3285         pemsz = der ? wc_DerToPemEx(der, dersz, NULL, 0, NULL, CERT_TYPE) : 0;
3286         if (pemsz > 0) {
3287             vb = http_header_env_set_ptr(r, CONST_STR_LEN("SSL_CLIENT_CERT"));
3288             if (0 == wc_DerToPemEx(der, dersz,
3289                                    (byte *)buffer_string_prepare_copy(vb,pemsz),
3290                                    pemsz, NULL, CERT_TYPE))
3291                 buffer_commit(vb, (uint32_t)pemsz);
3292         }
3293     }
3294     X509_free(xs);
3295 }
3296 
3297 
3298 static void
http_cgi_ssl_env(request_st * const r,handler_ctx * const hctx)3299 http_cgi_ssl_env (request_st * const r, handler_ctx * const hctx)
3300 {
3301     const char *s;
3302     const SSL_CIPHER *cipher;
3303 
3304     s = SSL_get_version(hctx->ssl);
3305     http_header_env_set(r, CONST_STR_LEN("SSL_PROTOCOL"), s, strlen(s));
3306 
3307     if ((cipher = SSL_get_current_cipher(hctx->ssl))) {
3308         s = SSL_CIPHER_get_name(cipher);
3309         http_header_env_set(r, CONST_STR_LEN("SSL_CIPHER"), s, strlen(s));
3310         /*(wolfSSL preprocessor defines are obnoxious)*/
3311       #if defined(OPENSSL_ALL) \
3312        || (defined(OPENSSL_EXTRA) \
3313            && (defined(HAVE_STUNNEL)    || \
3314                defined(WOLFSSL_NGINX)   || defined(HAVE_LIGHTY) || \
3315                defined(WOLFSSL_HAPROXY) || defined(WOLFSSL_OPENSSH)))
3316         int usekeysize, algkeysize = 0;
3317         char buf[LI_ITOSTRING_LENGTH];
3318         usekeysize = wolfSSL_CIPHER_get_bits(cipher, &algkeysize);
3319         if (0 == algkeysize) algkeysize = usekeysize;
3320         http_header_env_set(r, CONST_STR_LEN("SSL_CIPHER_USEKEYSIZE"),
3321                             buf, li_itostrn(buf, sizeof(buf), usekeysize));
3322         http_header_env_set(r, CONST_STR_LEN("SSL_CIPHER_ALGKEYSIZE"),
3323                             buf, li_itostrn(buf, sizeof(buf), algkeysize));
3324       #endif
3325     }
3326 }
3327 
3328 
REQUEST_FUNC(mod_openssl_handle_request_env)3329 REQUEST_FUNC(mod_openssl_handle_request_env)
3330 {
3331     plugin_data *p = p_d;
3332     /* simple flag for request_env_patched */
3333     if (r->plugin_ctx[p->id]) return HANDLER_GO_ON;
3334     handler_ctx *hctx = r->con->plugin_ctx[p->id];
3335     if (NULL == hctx) return HANDLER_GO_ON;
3336     r->plugin_ctx[p->id] = (void *)(uintptr_t)1u;
3337 
3338     http_cgi_ssl_env(r, hctx);
3339     if (hctx->conf.ssl_verifyclient) {
3340         https_add_ssl_client_entries(r, hctx);
3341     }
3342 
3343     return HANDLER_GO_ON;
3344 }
3345 
3346 
REQUEST_FUNC(mod_openssl_handle_uri_raw)3347 REQUEST_FUNC(mod_openssl_handle_uri_raw)
3348 {
3349     /* mod_openssl must be loaded prior to mod_auth
3350      * if mod_openssl is configured to set REMOTE_USER based on client cert */
3351     /* mod_openssl must be loaded after mod_extforward
3352      * if mod_openssl config is based on lighttpd.conf remote IP conditional
3353      * using remote IP address set by mod_extforward, *unless* PROXY protocol
3354      * is enabled with extforward.hap-PROXY = "enable", in which case the
3355      * reverse is true: mod_extforward must be loaded after mod_openssl */
3356     plugin_data *p = p_d;
3357     handler_ctx *hctx = r->con->plugin_ctx[p->id];
3358     if (NULL == hctx) return HANDLER_GO_ON;
3359 
3360     mod_openssl_patch_config(r, &hctx->conf);
3361     if (hctx->conf.ssl_verifyclient) {
3362         mod_openssl_handle_request_env(r, p);
3363     }
3364 
3365     return HANDLER_GO_ON;
3366 }
3367 
3368 
REQUEST_FUNC(mod_openssl_handle_request_reset)3369 REQUEST_FUNC(mod_openssl_handle_request_reset)
3370 {
3371     plugin_data *p = p_d;
3372     r->plugin_ctx[p->id] = NULL; /* simple flag for request_env_patched */
3373     return HANDLER_GO_ON;
3374 }
3375 
3376 
TRIGGER_FUNC(mod_openssl_handle_trigger)3377 TRIGGER_FUNC(mod_openssl_handle_trigger) {
3378     const plugin_data * const p = p_d;
3379     const unix_time64_t cur_ts = log_epoch_secs;
3380     if (cur_ts & 0x3f) return HANDLER_GO_ON; /*(continue once each 64 sec)*/
3381     UNUSED(srv);
3382     UNUSED(p);
3383 
3384   #ifdef HAVE_SESSION_TICKET
3385     mod_openssl_session_ticket_key_check(p, cur_ts);
3386   #endif
3387 
3388   #ifdef HAVE_OCSP
3389     mod_openssl_refresh_stapling_files(srv, p, cur_ts);
3390   #endif
3391 
3392     return HANDLER_GO_ON;
3393 }
3394 
3395 
3396 __attribute_cold__
3397 int mod_wolfssl_plugin_init (plugin *p);
mod_wolfssl_plugin_init(plugin * p)3398 int mod_wolfssl_plugin_init (plugin *p)
3399 {
3400     p->version      = LIGHTTPD_VERSION_ID;
3401     p->name         = "wolfssl";
3402     p->init         = mod_openssl_init;
3403     p->cleanup      = mod_openssl_free;
3404     p->priv_defaults= mod_openssl_set_defaults;
3405 
3406     p->handle_connection_accept  = mod_openssl_handle_con_accept;
3407     p->handle_connection_shut_wr = mod_openssl_handle_con_shut_wr;
3408     p->handle_connection_close   = mod_openssl_handle_con_close;
3409     p->handle_uri_raw            = mod_openssl_handle_uri_raw;
3410     p->handle_request_env        = mod_openssl_handle_request_env;
3411     p->handle_request_reset      = mod_openssl_handle_request_reset;
3412     p->handle_trigger            = mod_openssl_handle_trigger;
3413 
3414     return 0;
3415 }
3416 
3417 
3418 static int
mod_openssl_ssl_conf_proto_val(server * srv,const buffer * b,int max)3419 mod_openssl_ssl_conf_proto_val (server *srv, const buffer *b, int max)
3420 {
3421     if (NULL == b) /* default: min TLSv1.2, max TLSv1.3 */
3422         return max ? WOLFSSL_TLSV1_3 : WOLFSSL_TLSV1_2;
3423     else if (buffer_eq_icase_slen(b, CONST_STR_LEN("None"))) /*"disable" limit*/
3424         return max ? WOLFSSL_TLSV1_3 : WOLFSSL_TLSV1;
3425     else if (buffer_eq_icase_slen(b, CONST_STR_LEN("TLSv1.0")))
3426         return WOLFSSL_TLSV1;
3427     else if (buffer_eq_icase_slen(b, CONST_STR_LEN("TLSv1.1")))
3428         return WOLFSSL_TLSV1_1;
3429     else if (buffer_eq_icase_slen(b, CONST_STR_LEN("TLSv1.2")))
3430         return WOLFSSL_TLSV1_2;
3431     else if (buffer_eq_icase_slen(b, CONST_STR_LEN("TLSv1.3")))
3432         return WOLFSSL_TLSV1_3;
3433     else {
3434         if (buffer_eq_icase_slen(b, CONST_STR_LEN("DTLSv1"))
3435             || buffer_eq_icase_slen(b, CONST_STR_LEN("DTLSv1.2")))
3436             log_error(srv->errh, __FILE__, __LINE__,
3437                       "SSL: ssl.openssl.ssl-conf-cmd %s %s ignored",
3438                       max ? "MaxProtocol" : "MinProtocol", b->ptr);
3439         else
3440             log_error(srv->errh, __FILE__, __LINE__,
3441                       "SSL: ssl.openssl.ssl-conf-cmd %s %s invalid; ignored",
3442                       max ? "MaxProtocol" : "MinProtocol", b->ptr);
3443     }
3444     return max ? WOLFSSL_TLSV1_3 : WOLFSSL_TLSV1_2;
3445 }
3446 
3447 
3448 static int
mod_openssl_ssl_conf_cmd(server * srv,plugin_config_socket * s)3449 mod_openssl_ssl_conf_cmd (server *srv, plugin_config_socket *s)
3450 {
3451     /* reference:
3452      * https://www.openssl.org/docs/man1.1.1/man3/SSL_CONF_cmd.html */
3453     int rc = 0;
3454     buffer *cipherstring = NULL;
3455     /*buffer *ciphersuites = NULL;*/
3456     buffer *minb = NULL;
3457     buffer *maxb = NULL;
3458     buffer *curves = NULL;
3459 
3460     for (size_t i = 0; i < s->ssl_conf_cmd->used; ++i) {
3461         data_string *ds = (data_string *)s->ssl_conf_cmd->data[i];
3462         if (buffer_eq_icase_slen(&ds->key, CONST_STR_LEN("CipherString")))
3463             cipherstring = &ds->value;
3464       #if 0
3465         else if (buffer_eq_icase_slen(&ds->key, CONST_STR_LEN("Ciphersuites")))
3466             ciphersuites = &ds->value;
3467       #endif
3468         else if (buffer_eq_icase_slen(&ds->key, CONST_STR_LEN("Curves"))
3469               || buffer_eq_icase_slen(&ds->key, CONST_STR_LEN("Groups")))
3470             curves = &ds->value;
3471         else if (buffer_eq_icase_slen(&ds->key, CONST_STR_LEN("DHParameters"))){
3472             if (!buffer_is_blank(&ds->value)) {
3473                 if (!mod_openssl_ssl_conf_dhparameters(srv, s, &ds->value))
3474                     rc = -1;
3475             }
3476         }
3477         else if (buffer_eq_icase_slen(&ds->key, CONST_STR_LEN("MaxProtocol")))
3478             maxb = &ds->value;
3479         else if (buffer_eq_icase_slen(&ds->key, CONST_STR_LEN("MinProtocol")))
3480             minb = &ds->value;
3481         else if (buffer_eq_icase_slen(&ds->key, CONST_STR_LEN("Protocol"))) {
3482             /* openssl config for Protocol=... is complex and deprecated */
3483             log_error(srv->errh, __FILE__, __LINE__,
3484                       "SSL: ssl.openssl.ssl-conf-cmd %s ignored; "
3485                       "use MinProtocol=... and MaxProtocol=... instead",
3486                       ds->key.ptr);
3487         }
3488         else if (buffer_eq_icase_slen(&ds->key, CONST_STR_LEN("Options"))) {
3489             for (char *v = ds->value.ptr, *e; *v; v = e) {
3490                 while (*v == ' ' || *v == '\t' || *v == ',') ++v;
3491                 int flag = 1;
3492                 if (*v == '-') {
3493                     flag = 0;
3494                     ++v;
3495                 }
3496                 else if (*v == '+')
3497                     ++v;
3498                 for (e = v; light_isalpha(*e); ++e) ;
3499                 switch ((int)(e-v)) {
3500                   case 11:
3501                     if (buffer_eq_icase_ssn(v, "Compression", 11)) {
3502                         /* (force disabled, the default, if HTTP/2 enabled) */
3503                         if (srv->srvconf.h2proto)
3504                             flag = 0;
3505                         if (flag)
3506                             SSL_CTX_clear_options(s->ssl_ctx,
3507                                                   SSL_OP_NO_COMPRESSION);
3508                         else
3509                             SSL_CTX_set_options(s->ssl_ctx,
3510                                                 SSL_OP_NO_COMPRESSION);
3511                         continue;
3512                     }
3513                     break;
3514                   case 13:
3515                     if (buffer_eq_icase_ssn(v, "SessionTicket", 13)) {
3516                         if (flag)
3517                             SSL_CTX_clear_options(s->ssl_ctx,
3518                                                   SSL_OP_NO_TICKET);
3519                         else
3520                             SSL_CTX_set_options(s->ssl_ctx,
3521                                                 SSL_OP_NO_TICKET);
3522                         continue;
3523                     }
3524                     break;
3525                   case 16:
3526                     if (buffer_eq_icase_ssn(v, "ServerPreference", 16)) {
3527                         if (flag)
3528                             SSL_CTX_set_options(s->ssl_ctx,
3529                                                SSL_OP_CIPHER_SERVER_PREFERENCE);
3530                         else
3531                             SSL_CTX_clear_options(s->ssl_ctx,
3532                                                SSL_OP_CIPHER_SERVER_PREFERENCE);
3533                         s->ssl_honor_cipher_order = flag;
3534                         continue;
3535                     }
3536                     break;
3537                   default:
3538                     break;
3539                 }
3540                 /* warn if not explicitly handled or ignored above */
3541                 if (!flag) --v;
3542                 log_error(srv->errh, __FILE__, __LINE__,
3543                           "SSL: ssl.openssl.ssl-conf-cmd Options %.*s "
3544                           "ignored", (int)(e-v), v);
3545             }
3546         }
3547       #if 0
3548         else if (buffer_eq_icase_slen(&ds->key, CONST_STR_LEN("..."))) {
3549         }
3550       #endif
3551         else {
3552             /* warn if not explicitly handled or ignored above */
3553             log_error(srv->errh, __FILE__, __LINE__,
3554                       "SSL: ssl.openssl.ssl-conf-cmd %s ignored",
3555                       ds->key.ptr);
3556         }
3557 
3558     }
3559 
3560     if (minb) {
3561         int n = mod_openssl_ssl_conf_proto_val(srv, minb, 0);
3562         if (wolfSSL_CTX_SetMinVersion(s->ssl_ctx, n) != WOLFSSL_SUCCESS)
3563             rc = -1;
3564     }
3565 
3566     if (maxb) {
3567         /* WolfSSL max ver is set at WolfSSL compile-time */
3568       #if LIBWOLFSSL_VERSION_HEX >= 0x04002000
3569         /*(could use SSL_OP_NO_* before 4.2.0)*/
3570         /*(wolfSSL_CTX_set_max_proto_version() 4.6.0 uses different defines)*/
3571         int n = mod_openssl_ssl_conf_proto_val(srv, maxb, 1);
3572         switch (n) {
3573           case WOLFSSL_SSLV3:
3574             wolfSSL_CTX_set_options(s->ssl_ctx, WOLFSSL_OP_NO_TLSv1);
3575             __attribute_fallthrough__
3576           case WOLFSSL_TLSV1:
3577             wolfSSL_CTX_set_options(s->ssl_ctx, WOLFSSL_OP_NO_TLSv1_1);
3578             __attribute_fallthrough__
3579           case WOLFSSL_TLSV1_1:
3580             wolfSSL_CTX_set_options(s->ssl_ctx, WOLFSSL_OP_NO_TLSv1_2);
3581             __attribute_fallthrough__
3582           case WOLFSSL_TLSV1_2:
3583             wolfSSL_CTX_set_options(s->ssl_ctx, WOLFSSL_OP_NO_TLSv1_3);
3584             __attribute_fallthrough__
3585           case WOLFSSL_TLSV1_3:
3586           default:
3587             break;
3588         }
3589       #endif
3590     }
3591 
3592     if (cipherstring && !buffer_is_blank(cipherstring)) {
3593         /* Disable support for low encryption ciphers */
3594         buffer_append_string_len(cipherstring,
3595                                  CONST_STR_LEN(":!aNULL:!eNULL:!EXP"));
3596         if (SSL_CTX_set_cipher_list(s->ssl_ctx, cipherstring->ptr) != 1) {
3597             log_error(srv->errh, __FILE__, __LINE__,
3598               "SSL: %s", ERR_error_string(ERR_get_error(), NULL));
3599             rc = -1;
3600         }
3601 
3602         if (s->ssl_honor_cipher_order)
3603             SSL_CTX_set_options(s->ssl_ctx, SSL_OP_CIPHER_SERVER_PREFERENCE);
3604     }
3605 
3606     if (curves && !buffer_is_blank(curves)) {
3607         if (!mod_openssl_ssl_conf_curves(srv, s, curves))
3608             rc = -1;
3609     }
3610 
3611     return rc;
3612 }
3613