xref: /lighttpd1.4/src/mod_nss.c (revision 82a26c1b)
1 /*
2  * mod_nss - Network Security Services (NSS) 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  * Portions supporting mod_nss_ssl_conf_ciphersuites() (see end of file)
8  *   Copyright 2001-2004 The Apache Software Foundation
9  */
10 /*
11  * NSS docs: https://developer.mozilla.org/en-US/docs/Mozilla/Projects/NSS
12  *
13  * NSS documentation is seriously lacking and man pages exist only for apps;
14  * be prepared to slog through organic piles of NSS library code
15  *
16  * Note: If session tickets are -not- disabled with
17  *     ssl.openssl.ssl-conf-cmd = ("Options" => "-SessionTicket")
18  *   NSS never rotates server ticket encryption key (STEK) while running.
19  *   Therefore, if session tickets are enabled, lighttpd server should be
20  *   restarted (by an external job) at least every 24 hours.  Restarting
21  *   lighttpd generates a new key that is shared by lighttpd workers.  There
22  *   is no mechanism implemented in lighttpd mod_nss to share STEK between
23  *   independent lighttpd servers.  ssl.stek-file is not used in mod_nss.
24  *
25  *   NSS provides SSL_SetSessionTicketKeyPair(pubKey, privKey) to set RSA keys.
26  *   However, to match behavior of other lighttpd TLS modules, it seems we want
27  *   to set the private struct ssl_self_encrypt_keys in lib/ssl/sslsnce.c
28  *   instead of the private struct ssl_self_encrypt_key_pair.
29  *   sslSelfEncryptKeys ssl_self_encrypt_keys contains:
30  *     PRUint8 keyName[SELF_ENCRYPT_KEY_NAME_LEN];
31  *     PK11SymKey *encKey;
32  *     PK11SymKey *macKey;
33  *   (see lib/ssl/sslsnce.c:GenerateSelfEncryptKeys())
34  *   PK11SymKey *masterSecret in ssl3CipherSpec in ssl3State in sslSessionID
35  *     is private in lib/ssl/ssl3con.c
36  *
37  *   Update: NSS developer explains:
38  *   "The way that we currently operate is to tie the session key encryption to
39  *    the server public key. Which only works if you have an RSA key configured"
40  *   https://bugzilla.mozilla.org/show_bug.cgi?id=1673254
41  *
42  * not implemented:
43  * - session ticket rotation (see comments above)
44  * - OCSP Must Staple detection
45  * - ssl.verifyclient.depth
46  * - ssl.openssl.ssl-conf-cmd Ciphersuite
47  *
48  * future:
49  * - consider SSL_AlertReceivedCallback() to set SSLAlertCallback
50  *   in order to (optionally) log alerts, and to abort connection if fatal alert
51  * - consider using experimental API for cipher suite choice in lib/ssl/sslexp.h
52  *   SSL_CipherSuiteOrderGet
53  *   SSL_CipherSuiteOrderSet
54  * - detect CLOSE_NOTIFY from client
55  * - feature options
56  *   - SSL_ENABLE_FALSE_START
57  *   - SSL_ENABLE_DELEGATED_CREDENTIALS
58  *   - SSL_ENABLE_0RTT_DATA
59  *   - SSL_SUPPRESS_END_OF_EARLY_DATA
60  * - crypto option using FreeBL
61  *   "A core element of NSS is FreeBL, a base library providing hash functions,
62  *    big number calculations, and cryptographic algorithms."
63  *   "Softoken is an NSS module that exposes most FreeBL functionality as a
64  *    PKCS#11 module."
65  *   "PR_GetRandomNoise - Produces a random value for use as a seed value for
66  *    another random number generator."
67  */
68 #include "first.h"
69 
70 #include <sys/types.h>
71 #include <sys/stat.h>
72 #include <errno.h>
73 #include <fcntl.h>
74 #include <stdarg.h>
75 #include <stdlib.h>
76 #include <stdio.h>      /* vsnprintf() */
77 #include <string.h>
78 
79 #ifdef __has_include
80 #if __has_include(<nss3/nss.h>)
81 #define NSS_VER_INCLUDE
82 #endif
83 #endif
84 
85 #ifndef NSS_VER_INCLUDE
86 #include <nspr/nspr.h>
87 #include <nspr/private/pprio.h> /* see mod_nss_io_ctor() comments */
88 #include <nss/nss.h>
89 #include <nss/nssb64.h>
90 #include <nss/keyhi.h>
91 #include <nss/pk11pub.h>
92 #include <nss/secder.h>
93 #include <nss/secerr.h>
94 #include <nss/ssl.h>
95 #include <nss/sslproto.h>
96 #else
97 #include <nspr4/nspr.h>
98 #include <nspr4/private/pprio.h> /* see mod_nss_io_ctor() comments */
99 #include <nss3/nss.h>
100 #include <nss3/nssb64.h>
101 #include <nss3/keyhi.h>
102 #include <nss3/pk11pub.h>
103 #include <nss3/secder.h>
104 #include <nss3/secerr.h>
105 #include <nss3/ssl.h>
106 #include <nss3/sslproto.h>
107 #endif
108 
109 #include "base.h"
110 #include "ck.h"
111 #include "fdevent.h"
112 #include "http_header.h"
113 #include "http_kv.h"
114 #include "log.h"
115 #include "plugin.h"
116 
117 typedef struct {
118     /* SNI per host: with COMP_SERVER_SOCKET, COMP_HTTP_SCHEME, COMP_HTTP_HOST */
119     char must_staple;
120     CERTCertificate *ssl_pemfile_x509;
121     SECKEYPrivateKey *ssl_pemfile_pkey;
122     SSLExtraServerCertData ssl_credex;
123     const buffer *ssl_stapling_file;
124     unix_time64_t ssl_stapling_loadts;
125     unix_time64_t ssl_stapling_nextts;
126     SECItemArray OCSPResponses;
127     SECItem OCSPResponse;
128 } plugin_cert;
129 
130 typedef struct {
131     PRFileDesc *model;
132     SSLVersionRange protos;
133     PRBool ssl_compression;
134     int8_t ssl_session_ticket;
135 } plugin_ssl_ctx;
136 
137 typedef struct {
138     plugin_cert *pc;
139 
140     /*(used only during startup; not patched)*/
141     unsigned char ssl_enabled; /* only interesting for setting up listening sockets. don't use at runtime */
142     unsigned char ssl_honor_cipher_order; /* determine SSL cipher in server-preferred order, not client-order */
143     const buffer *ssl_cipher_list;
144     array *ssl_conf_cmd;
145 
146     /*(copied from plugin_data for socket ssl_ctx config)*/
147     unsigned char ssl_session_ticket;
148     unsigned char ssl_verifyclient;
149     unsigned char ssl_verifyclient_enforce;
150     unsigned char ssl_verifyclient_depth;
151 
152     PRFileDesc *model;
153     SSLVersionRange protos;
154     PRBool ssl_compression;
155 } plugin_config_socket; /*(used at startup during configuration)*/
156 
157 typedef struct {
158     /* SNI per host: w/ COMP_SERVER_SOCKET, COMP_HTTP_SCHEME, COMP_HTTP_HOST */
159     plugin_cert *pc;
160     CERTCertList *ssl_ca_file;
161     CERTCertList *ssl_ca_dn_file;
162 
163     unsigned char ssl_verifyclient;
164     unsigned char ssl_verifyclient_enforce;
165     unsigned char ssl_verifyclient_depth;
166     unsigned char ssl_verifyclient_export_cert;
167     unsigned char ssl_read_ahead;
168     unsigned char ssl_log_noise;
169     const buffer *ssl_verifyclient_username;
170     const buffer *ssl_acme_tls_1;
171 } plugin_config;
172 
173 typedef struct {
174     PLUGIN_DATA;
175     plugin_ssl_ctx *ssl_ctxs;
176     plugin_config defaults;
177     server *srv;
178 } plugin_data;
179 
180 static int ssl_is_init;
181 /* need assigned p->id for deep access of module handler_ctx for connection
182  *   i.e. handler_ctx *hctx = con->plugin_ctx[plugin_data_singleton->id]; */
183 static plugin_data *plugin_data_singleton;
184 #define LOCAL_SEND_BUFSIZE 16384 /* DEFAULT_MAX_RECORD_SIZE */
185 static char *local_send_buffer;
186 
187 typedef struct {
188     PRFileDesc *ssl;
189     request_st *r;
190     connection *con;
191     int8_t close_notify;
192     uint8_t alpn;
193     int8_t ssl_session_ticket;
194     int handshake;
195     size_t pending_write;
196     plugin_config conf;
197     int verify_status;
198     buffer *tmp_buf;
199     log_error_st *errh;
200 } handler_ctx;
201 
202 
203 static handler_ctx *
handler_ctx_init(void)204 handler_ctx_init (void)
205 {
206     return ck_calloc(1, sizeof(handler_ctx));
207 }
208 
209 
210 static void mod_nss_io_dtor (PRFileDesc *ssl);
211 
212 static void
handler_ctx_free(handler_ctx * hctx)213 handler_ctx_free (handler_ctx *hctx)
214 {
215     mod_nss_io_dtor(hctx->ssl);
216     free(hctx);
217 }
218 
219 
220 __attribute_cold__
elog(log_error_st * const errh,const char * const file,const int line,const char * const msg)221 static void elog(log_error_st * const errh,
222                  const char * const file, const int line,
223                  const char * const msg)
224 {
225     /* error logging convenience function that decodes NSS result codes */
226     const PRErrorCode rc = PR_GetError();
227     const char *s = PR_ErrorToName(rc);
228     log_error(errh, file, line, "NSS: %s: (%s) %s",
229               msg, s ? s : "", PR_ErrorToString(rc, 0));
230 }
231 
232 
233 __attribute_cold__
234 __attribute_format__((__printf__, 4, 5))
elogf(log_error_st * const errh,const char * const file,const int line,const char * const fmt,...)235 static void elogf(log_error_st * const errh,
236                   const char * const file, const int line,
237                   const char * const fmt, ...)
238 {
239     char msg[1024];
240     va_list ap;
241     va_start(ap, fmt);
242     vsnprintf(msg, sizeof(msg), fmt, ap);
243     va_end(ap);
244     elog(errh, file, line, msg);
245 }
246 
247 
248 static PRFileDesc *
mod_nss_io_ctor(int fd,PRFileDesc * model,log_error_st * errh)249 mod_nss_io_ctor (int fd, PRFileDesc *model, log_error_st *errh)
250 {
251     /* WTH? Why not a public PR_ImportTCPSocket() interface from NSPR?
252      * (and PR_GetInheritedFD() is not a great replacement interface to
253      *  fudge NSPR_INHERIT_FDS in environment for each connection)
254      *
255      * #include <nspr4/private/pprio.h>
256      * Use internal routines to set up PRFileDesc.  Perform actions underlying
257      * PR_ImportTCPSocket() to avoid excess work done by PR_ImportTCPSocket(),
258      * which includes closing the fd if there is a failure.  Could pass 0 as fd
259      * to PR_AllocFileDesc() to avoid NSPR setting O_NONBLOCK since already set.
260      * Instead, employ simpler PR_CreateSocketPollFd() and change methods table,
261      * which handles _PR_ImplicitInitialization() (PR_AllocFileDesc() does not).
262      * (WTH?: PR_AllocFileDesc() has limit fd < FD_SETSIZE when XP_UNIX defined)
263      * Note: since bypassing PR_ImportTCPSocket() this might not work on Windows
264      * which expects prfd->secret->af to be set to AF_INET.
265      */
266   #if defined(_WIN32) && !defined(__CYGWIN__)
267     PRFileDesc *prfd = PR_ImportTCPSocket(fd);
268     if (NULL == prfd) {
269         elog(errh, __FILE__, __LINE__, "PR_ImportTCPSocket()");
270         return NULL;
271     }
272   #else
273     /*PRFileDesc *prfd = PR_AllocFileDesc(0, PR_GetTCPMethods());*/
274     PRFileDesc *prfd = PR_CreateSocketPollFd(fd);
275     if (NULL == prfd) {
276         elog(errh, __FILE__, __LINE__, "PR_CreateSocketPollFd()");
277         return NULL;
278     }
279     /*PR_ChangeFileDescNativeHandle(prfd, fd);*/
280     prfd->methods = PR_GetTCPMethods();
281     /*prfd->dtor    = PR_FreeFileDesc();*/ /* PR_FreeFileDesc() is private */
282   #endif
283 
284     /* set prfd->secret->nonblocking flag */
285     PRSocketOptionData data;
286     data.option = PR_SockOpt_Nonblocking;
287     data.value.non_blocking = PR_TRUE;
288     if (PR_SetSocketOption(prfd, &data) != PR_SUCCESS) {
289         elog(errh, __FILE__, __LINE__, "PR_SocketSetSocketOption()");
290         PR_DestroySocketPollFd(prfd); /* PR_FreeFileDesc() is private */
291         return NULL;
292     }
293 
294     PRFileDesc *ssl = SSL_ImportFD(model, prfd);
295     if (NULL == ssl) {
296         elog(errh, __FILE__, __LINE__, "SSL_ImportFD()");
297         PR_DestroySocketPollFd(prfd); /* PR_FreeFileDesc() is private */
298         return NULL;
299     }
300 
301     return ssl;
302 }
303 
304 
305 static void
mod_nss_io_detach(PRFileDesc * ssl)306 mod_nss_io_detach (PRFileDesc *ssl)
307 {
308   #if 0 /* PR_PopIOLayer() forbids pop of PR_NSPR_IO_LAYER */
309     PRFileDesc *prfd = PR_PopIOLayer(ssl, PR_NSPR_IO_LAYER);
310     if (prfd) {
311         PR_ChangeFileDescNativeHandle(prfd, -1);
312         PR_DestroySocketPollFd(prfd); /* PR_FreeFileDesc() is private */
313     }
314   #else
315     /*(results in close(-1) and EBADF from PR_Close() in mod_nss_io_dtor())*/
316     PRFileDesc *prfd = PR_GetIdentitiesLayer(ssl, PR_NSPR_IO_LAYER);
317     if (prfd)
318         PR_ChangeFileDescNativeHandle(prfd, -1);
319   #endif
320 }
321 
322 
323 static void
mod_nss_io_dtor(PRFileDesc * ssl)324 mod_nss_io_dtor (PRFileDesc *ssl)
325 {
326     if (NULL == ssl) return;
327     mod_nss_io_detach(ssl);
328     PR_Close(ssl);
329 }
330 
331 
332 static int
mod_nss_load_file(const char * const fn,SECItem * const d,log_error_st * errh)333 mod_nss_load_file (const char * const fn, SECItem * const d, log_error_st *errh)
334 {
335     off_t dlen = 512*1024*1024;/*(arbitrary limit: 512 MB file; expect < 1 MB)*/
336     char *data = fdevent_load_file(fn, &dlen, errh, PORT_Alloc, PORT_Free);
337     if (NULL == data) return -1;
338     d->type = siBuffer;
339     d->data = (unsigned char *)data;
340     d->len  = (unsigned int)dlen;
341     return 0;
342 }
343 
344 
345 static void
mod_nss_secitem_wipe(SECItem * const d)346 mod_nss_secitem_wipe (SECItem * const d)
347 {
348     /* safer than SECITEM_ZfreeItem() */
349     if (NULL == d) return;
350     if (d->data) {
351         if (d->len) ck_memzero(d->data, d->len); /*safer than PORT_Memset()*/
352         PORT_Free(d->data); /* ck_memzero() is safer than PORT_ZFree() */
353         d->data = NULL;
354     }
355     d->len = 0;
356 }
357 
358 
INIT_FUNC(mod_nss_init)359 INIT_FUNC(mod_nss_init)
360 {
361     plugin_data_singleton = (plugin_data *)ck_calloc(1, sizeof(plugin_data));
362     return plugin_data_singleton;
363 }
364 
365 
mod_nss_init_once_nss(void)366 static int mod_nss_init_once_nss (void)
367 {
368     if (ssl_is_init) return 1;
369     ssl_is_init = 1;
370 
371     /*PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);*//*implicit on first use*/
372 
373     if (!NSS_IsInitialized() && NSS_NoDB_Init(NULL) < 0)
374         return 0;
375 
376     if (SSL_OptionSetDefault(SSL_ENABLE_SSL2, PR_FALSE) < 0)
377         return 0;
378     if (SSL_OptionSetDefault(SSL_ENABLE_SSL3, PR_FALSE) < 0)
379         return 0;
380     /* XXX: lighttpd is single threaded and so SSL_NO_LOCKS is desirable,
381      *      but NSS crashes if SSL_NO_LOCKS option is set to PR_TRUE.
382      *      (Crash in SSL3_SendAlert() call to PR_GetMonitorEntryCount()
383      *       with NULL ptr to monitor (mon))
384      *      NSS lib/ssl/sslimpl.h macros such as ssl_HaveSSL3HandshakeLock(ss),
385      *      plus some other .c files use macros without first checking if
386      *      (!ss->opt.noLocks): PZ_InMonitor() PZ_InMonitor() PZ_InMonitor() */
387     /*if (SSL_OptionSetDefault(SSL_NO_LOCKS, PR_TRUE) < 0)*/
388     if (SSL_OptionSetDefault(SSL_NO_LOCKS, PR_FALSE) < 0)
389         return 0;
390     if (SSL_OptionSetDefault(SSL_NO_CACHE, PR_TRUE) < 0)
391         return 0;
392     if (SSL_OptionSetDefault(SSL_ENABLE_SESSION_TICKETS, PR_TRUE) < 0)
393         return 0;
394     if (SSL_OptionSetDefault(SSL_ENABLE_ALPN, PR_TRUE) < 0)
395         return 0;
396     if (SSL_OptionSetDefault(SSL_ENABLE_RENEGOTIATION,
397                              SSL_RENEGOTIATE_NEVER) < 0)
398         return 0;
399 
400     if (NSS_SetDomesticPolicy() < 0)
401         return 0;
402 
403     local_send_buffer = ck_malloc(LOCAL_SEND_BUFSIZE);
404     return 1;
405 }
406 
407 
mod_nss_free_nss(void)408 static void mod_nss_free_nss (void)
409 {
410     if (!ssl_is_init) return;
411 
412     NSS_Shutdown();
413 
414     free(local_send_buffer);
415     ssl_is_init = 0;
416 }
417 
418 
419 static int
mod_nss_cert_is_active(const CERTCertificate * crt)420 mod_nss_cert_is_active (const CERTCertificate *crt)
421 {
422     PRTime notBefore, notAfter;
423     SECStatus rc = CERT_GetCertTimes(crt, &notBefore, &notAfter);
424     const unix_time64_t now = log_epoch_secs;
425     return (rc == SECSuccess
426             && notBefore/1000000 <= now && now <= notAfter/1000000);
427 }
428 
429 
430 #define PEM_BEGIN          "-----BEGIN "
431 #define PEM_END            "-----END "
432 #define PEM_BEGIN_CERT     "-----BEGIN CERTIFICATE-----"
433 #define PEM_END_CERT       "-----END CERTIFICATE-----"
434 #define PEM_BEGIN_TRUSTED_CERT "-----BEGIN TRUSTED CERTIFICATE-----"
435 #define PEM_END_TRUSTED_CERT   "-----END TRUSTED CERTIFICATE-----"
436 #define PEM_BEGIN_PKEY     "-----BEGIN PRIVATE KEY-----"
437 #define PEM_END_PKEY       "-----END PRIVATE KEY-----"
438 #define PEM_BEGIN_EC_PKEY  "-----BEGIN EC PRIVATE KEY-----"
439 #define PEM_END_EC_PKEY    "-----END EC PRIVATE KEY-----"
440 #define PEM_BEGIN_RSA_PKEY "-----BEGIN RSA PRIVATE KEY-----"
441 #define PEM_END_RSA_PKEY   "-----END RSA PRIVATE KEY-----"
442 #define PEM_BEGIN_DSA_PKEY "-----BEGIN DSA PRIVATE KEY-----"
443 #define PEM_END_DSA_PKEY   "-----END DSA PRIVATE KEY-----"
444 #define PEM_BEGIN_ANY_PKEY "-----BEGIN ANY PRIVATE KEY-----"
445 #define PEM_END_ANY_PKEY   "-----END ANY PRIVATE KEY-----"
446 /* (not implemented: support to get password from user for encrypted key) */
447 #define PEM_BEGIN_ENCRYPTED_PKEY "-----BEGIN ENCRYPTED PRIVATE KEY-----"
448 #define PEM_END_ENCRYPTED_PKEY   "-----END ENCRYPTED PRIVATE KEY-----"
449 
450 #define PEM_BEGIN_X509_CRL "-----BEGIN X509 CRL-----"
451 #define PEM_END_X509_CRL   "-----END X509 CRL-----"
452 
453 
454 static CERTCertificateList *
mod_nss_load_pem_file(const char * fn,log_error_st * errh)455 mod_nss_load_pem_file (const char *fn, log_error_st *errh)
456 {
457     if (!mod_nss_init_once_nss()) return NULL;
458 
459     SECItem f;
460     int rc = mod_nss_load_file(fn, &f, errh);
461     if (rc < 0) return NULL;
462 
463     rc = -1;
464     CERTCertificateList *chain = NULL;
465     do {
466         int count = 0;
467         char *b = (char *)f.data;
468         for (; (b = strstr(b, PEM_BEGIN_CERT)); b += sizeof(PEM_BEGIN_CERT)-1)
469             ++count;
470         b = (char *)f.data;
471         for (; (b = strstr(b, PEM_BEGIN_TRUSTED_CERT));
472                 b += sizeof(PEM_BEGIN_TRUSTED_CERT)-1)
473             ++count;
474         if (0 == count) {
475             if (NULL != strstr((char *)f.data, "-----")) {
476                 rc = 0;
477                 break;
478             }
479             /*(fall through and treat as DER)*/
480         }
481 
482         PLArenaPool *arena = PORT_NewArena(4096);
483         if (NULL == arena)
484             break;
485 
486         chain = (CERTCertificateList *)
487           PORT_ArenaAlloc(arena, sizeof(CERTCertificateList));
488         if (NULL == chain) {
489             PORT_FreeArena(arena, PR_FALSE);
490             break;
491         }
492 
493         chain->arena = arena;
494         chain->len = count ? count : 1;
495         chain->certs = (SECItem *)PORT_ArenaZAlloc(arena,
496                                                    chain->len*sizeof(SECItem));
497         if (NULL == chain->certs)
498             break;
499 
500         if (0 == count) {
501             /* treat as DER */
502             if (NULL == SECITEM_AllocItem(arena, chain->certs+0, f.len)) {
503                 PORT_SetError(SEC_ERROR_IO);
504                 break;
505             }
506             memcpy(chain->certs[0].data, f.data, (chain->certs[0].len = f.len));
507             rc = 0;
508             break;
509         }
510 
511         int i = 0;
512         for (char *e = (char *)f.data; (b = strstr(e, PEM_BEGIN_CERT)); ++i) {
513             b += sizeof(PEM_BEGIN_CERT)-1;
514             if (*b == '\r') ++b;
515             if (*b == '\n') ++b;
516             e = strstr(b, PEM_END_CERT);
517             if (NULL == e) break;
518             uint32_t len = (uint32_t)(e - b);
519             e += sizeof(PEM_END_CERT)-1;
520             if (NULL == NSSBase64_DecodeBuffer(arena, chain->certs+i, b, len))
521                 break;
522         }
523         for (char *e=(char *)f.data; (b=strstr(e,PEM_BEGIN_TRUSTED_CERT)); ++i){
524             b += sizeof(PEM_BEGIN_TRUSTED_CERT)-1;
525             if (*b == '\r') ++b;
526             if (*b == '\n') ++b;
527             e = strstr(b, PEM_END_TRUSTED_CERT);
528             if (NULL == e) break;
529             uint32_t len = (uint32_t)(e - b);
530             e += sizeof(PEM_END_TRUSTED_CERT)-1;
531             if (NULL == NSSBase64_DecodeBuffer(arena, chain->certs+i, b, len))
532                 break;
533         }
534         if (i == count)
535             rc = 0;
536         else
537             PORT_SetError(SEC_ERROR_IO);
538     } while (0);
539 
540     mod_nss_secitem_wipe(&f);
541 
542     if (rc < 0) {
543         elogf(errh, __FILE__, __LINE__, "error loading %s", fn);
544         if (chain)
545             CERT_DestroyCertificateList(chain);
546         return NULL;
547     }
548 
549     return chain;
550 }
551 
552 
553 static CERTCertificate *
mod_nss_load_pem_crts(const char * fn,log_error_st * errh,CERTCertificateList ** pchain)554 mod_nss_load_pem_crts (const char *fn, log_error_st *errh, CERTCertificateList **pchain)
555 {
556     *pchain = mod_nss_load_pem_file(fn, errh);
557     if (NULL == *pchain) return NULL;
558 
559     CERTCertificate *cert = CERT_NewTempCertificate(NULL, (*pchain)->certs+0,
560                                                     NULL, PR_FALSE, PR_TRUE);
561     if (NULL == cert) {
562         CERT_DestroyCertificateList(*pchain);
563         *pchain = NULL;
564     }
565     else if (!mod_nss_cert_is_active(cert)) {
566         log_error(errh, __FILE__, __LINE__,
567           "NSS: inactive/expired X509 certificate '%s'", fn);
568     }
569 
570     return cert;
571 }
572 
573 static CERTCertList *
mod_nss_cert_list(CERTCertificateList * crts)574 mod_nss_cert_list (CERTCertificateList *crts)
575 {
576     SECStatus rc = SECFailure;
577     CERTCertificate *cert = NULL;
578     CERTCertList *clist = CERT_NewCertList();
579     if (NULL != clist) {
580         for (int i = 0; i < crts->len; ++i) {
581             cert = CERT_NewTempCertificate(NULL, crts->certs+i,
582                                            NULL, PR_FALSE, PR_TRUE);
583             if (NULL == cert) break;
584             rc = CERT_AddCertToListTail(clist, cert);
585             if (rc < 0) break;
586         }
587     }
588 
589     if (rc < 0 || NULL == cert) {
590         if (cert) CERT_DestroyCertificate(cert);
591         if (clist) CERT_DestroyCertList(clist);
592         PORT_SetError(SEC_ERROR_NO_MEMORY);
593         return NULL;
594     }
595 
596     return clist;
597 }
598 
599 
600 static CERTCertList *
mod_nss_load_config_crts(const char * fn,log_error_st * errh)601 mod_nss_load_config_crts (const char *fn, log_error_st *errh)
602 {
603     CERTCertificateList *crts = mod_nss_load_pem_file(fn, errh);
604     if (NULL == crts) return NULL;
605 
606     CERTCertList *clist = NULL;
607     SECStatus rc =
608       CERT_ImportCAChainTrusted(crts->certs,crts->len,certUsageUserCertImport);
609     if (rc == SECSuccess)
610         clist = mod_nss_cert_list(crts);
611     else {
612         elogf(errh, __FILE__, __LINE__, "CERT_ImportCAChainTrusted() %s", fn);
613         CERT_DestroyCertificateList(crts);
614         return NULL;
615     }
616 
617     CERT_DestroyCertificateList(crts);
618     return clist;
619 }
620 
621 
622 static CERTCertList *
mod_nss_load_config_dncrts(const char * fn,log_error_st * errh)623 mod_nss_load_config_dncrts (const char *fn, log_error_st *errh)
624 {
625     CERTCertificateList *crts = mod_nss_load_pem_file(fn, errh);
626     if (NULL == crts) return NULL;
627 
628     CERTCertList *clist = mod_nss_cert_list(crts);
629 
630     CERT_DestroyCertificateList(crts);
631     return clist;
632 }
633 
634 
635 static void
mod_nss_free_config_crls(CERTCertificateList * crls)636 mod_nss_free_config_crls (CERTCertificateList *crls)
637 {
638     if (NULL == crls) return;
639     CERTCertDBHandle * const dbhandle = CERT_GetDefaultCertDB();
640     for (int i = 0; i < crls->len; ++i)
641         CERT_UncacheCRL(dbhandle, crls->certs+i);
642     CERT_DestroyCertificateList(crls);
643 }
644 
645 
646 static CERTCertificateList *
mod_nss_load_config_crls(const char * fn,log_error_st * errh)647 mod_nss_load_config_crls (const char *fn, log_error_st *errh)
648 {
649     /*(similar start to other mod_nss_load_config_*())*/
650     if (!mod_nss_init_once_nss()) return NULL;
651 
652     SECItem f;
653     int rc = mod_nss_load_file(fn, &f, errh);
654     if (rc < 0) return NULL;
655 
656     rc = -1;
657     CERTCertificateList *chain = NULL;
658     CERTCertDBHandle * const dbhandle = CERT_GetDefaultCertDB();
659     do {
660         int count = 0;
661         char *b = (char *)f.data;
662         for (; (b = strstr(b, PEM_BEGIN_X509_CRL));
663                 b += sizeof(PEM_BEGIN_X509_CRL)-1)
664             ++count;
665         if (0 == count) {
666             rc = 0;
667             break;
668         }
669 
670         PLArenaPool *arena = PORT_NewArena(4096);
671         if (NULL == arena)
672             break;
673 
674         chain = (CERTCertificateList *)
675           PORT_ArenaAlloc(arena, sizeof(CERTCertificateList));
676         if (NULL == chain) {
677             PORT_FreeArena(arena, PR_FALSE);
678             break;
679         }
680 
681         chain->arena = arena;
682         chain->len = count;
683         chain->certs = (SECItem *)PORT_ArenaAlloc(arena, count*sizeof(SECItem));
684         if (NULL == chain->certs)
685             break;
686 
687         int i = 0;
688         for (char *e = (char *)f.data; (b = strstr(e,PEM_BEGIN_X509_CRL)); ++i){
689             b += sizeof(PEM_BEGIN_X509_CRL)-1;
690             if (*b == '\r') ++b;
691             if (*b == '\n') ++b;
692             e = strstr(b, PEM_END_X509_CRL);
693             if (NULL == e) break;
694             uint32_t len = (uint32_t)(e - b);
695             e += sizeof(PEM_END_X509_CRL)-1;
696             chain->certs[i].type = 0;
697             chain->certs[i].data = NULL;
698             chain->certs[i].len  = 0;
699             if (NULL == NSSBase64_DecodeBuffer(arena, chain->certs+i, b, len))
700                 break;
701             /* using ephemeral db, so cache CRL instead of CERT_ImportCRL() */
702             if (CERT_CacheCRL(dbhandle, chain->certs+i) < 0)
703                 break;
704         }
705         if (i == count)
706             rc = 0;
707         else
708             PORT_SetError(SEC_ERROR_IO);
709     } while (0);
710 
711     mod_nss_secitem_wipe(&f);
712 
713     if (rc < 0) {
714         elogf(errh, __FILE__, __LINE__, "error loading %s", fn);
715         if (chain)
716             CERT_DestroyCertificateList(chain);
717         return NULL;
718     }
719 
720     return chain;
721 }
722 
723 
724 static SECItem *
mod_nss_cert_get_publicValue(SECKEYPublicKey * pubKey)725 mod_nss_cert_get_publicValue (SECKEYPublicKey *pubKey)
726 {
727     /*(lib/pkcs12/p12d.c:sec_pkcs12_get_public_value_and_type() private)*/
728     /*(lib/pk11wrap/pk11akey.c:pk11_MakeIDFromPublicKey() private, hashes)*/
729     /*(lib/crmf/crmfcont.c:crmf_get_public_value() public but incomplete)*/
730     switch (pubKey->keyType) {
731       case dsaKey: return &pubKey->u.dsa.publicValue;
732       case dhKey:  return &pubKey->u.dh.publicValue;
733       case rsaKey: return &pubKey->u.rsa.modulus;
734       case ecKey:  return &pubKey->u.ec.publicValue;
735       default:     return NULL;
736     }
737 }
738 
739 
740 static SECKEYPrivateKey *
mod_nss_load_config_pkey(const char * fn,CERTCertificate * cert,log_error_st * errh)741 mod_nss_load_config_pkey (const char *fn, CERTCertificate *cert, log_error_st *errh)
742 {
743     /* NSS does not provide convenient mechanisms to read PEM or DER private key
744      * instead expecting PKCS12-format, which is not the convention used by many
745      * other TLS modules */
746 
747     /*(similar start to other mod_nss_load_config_*())*/
748     if (!mod_nss_init_once_nss()) return NULL;
749 
750     SECItem f;
751     int rc = mod_nss_load_file(fn, &f, errh);
752     if (rc < 0) return NULL;
753 
754     SECItem der = { 0, NULL, 0 };
755     PK11SlotInfo *slot = NULL;
756     SECKEYPrivateKey *pkey = NULL;
757     SECStatus src = SECFailure;
758     do {
759         /*(expecting single private key in file, so first match)*/
760         char *b, *e;
761         if ((b = strstr((char *)f.data, PEM_BEGIN_PKEY))
762             && (e = strstr(b, PEM_END_PKEY)))
763             b += sizeof(PEM_BEGIN_PKEY)-1;
764         else if ((b = strstr((char *)f.data, PEM_BEGIN_EC_PKEY))
765                  && (e = strstr(b, PEM_END_EC_PKEY)))
766             b += sizeof(PEM_BEGIN_EC_PKEY)-1;
767         else if ((b = strstr((char *)f.data, PEM_BEGIN_RSA_PKEY))
768                  && (e = strstr(b, PEM_END_RSA_PKEY)))
769             b += sizeof(PEM_BEGIN_RSA_PKEY)-1;
770         else if ((b = strstr((char *)f.data, PEM_BEGIN_DSA_PKEY))
771                  && (e = strstr(b, PEM_END_DSA_PKEY)))
772             b += sizeof(PEM_BEGIN_DSA_PKEY)-1;
773         else if ((b = strstr((char *)f.data, PEM_BEGIN_ANY_PKEY))
774                  && (e = strstr(b, PEM_END_ANY_PKEY)))
775             b += sizeof(PEM_BEGIN_ANY_PKEY)-1;
776         else if (NULL == strstr((char *)f.data, "-----")) {
777             der = f; /*(copy struct)*/
778             f.type = 0;
779             f.data = NULL;
780             f.len = 0;
781             b = (char *)der.data;
782         }
783         else
784             break;
785         if (*b == '\r') ++b;
786         if (*b == '\n') ++b;
787 
788         if (NULL == der.data
789             && NULL == NSSBase64_DecodeBuffer(NULL, &der, b, (uint32_t)(e - b)))
790             break;
791 
792         slot = PK11_GetInternalKeySlot();
793         if (NULL == slot) break;
794 
795         SECItem nickname = { 0, NULL, strlen(fn) };
796         *(const unsigned char **)&nickname.data = (unsigned char *)fn;
797         unsigned int keyUsage = KU_ALL;  /* XXX: limit to fewer flags? */
798         PRBool isPerm = PR_FALSE;
799         PRBool isPrivate = PR_TRUE;
800         SECKEYPublicKey *pubKey = CERT_ExtractPublicKey(cert);
801         SECItem *pubValue = mod_nss_cert_get_publicValue(pubKey);
802         src =
803           PK11_ImportDERPrivateKeyInfoAndReturnKey(slot, &der, &nickname,
804                                                    pubValue, isPerm, isPrivate,
805                                                    keyUsage, &pkey, NULL);
806         /* nickname attribute has reference taken to data;
807          * data must persist longer than SECKEYPrivateKey */
808         /* (pubValue data is of decoded type SEC_ASN1_INTEGER and is copied) */
809         SECKEY_DestroyPublicKey(pubKey);
810     } while (0);
811 
812     if (slot) PK11_FreeSlot(slot);
813     if (der.data) {
814         mod_nss_secitem_wipe(&der);
815         PORT_Free(der.data);
816     }
817     mod_nss_secitem_wipe(&f);
818 
819     if (src < 0) {
820         elogf(errh, __FILE__, __LINE__,
821               "PK11_ImportDERPrivateKeyInfoAndReturnKey() %s", fn);
822         return NULL;
823     }
824 
825     return pkey;
826 }
827 
828 
829 static void
mod_nss_free_config(server * srv,plugin_data * const p)830 mod_nss_free_config (server *srv, plugin_data * const p)
831 {
832     if (NULL != p->ssl_ctxs) {
833         PRFileDesc *global_model = p->ssl_ctxs->model;
834         /* free from $SERVER["socket"] (if not copy of global scope) */
835         for (uint32_t i = 1; i < srv->config_context->used; ++i) {
836             plugin_ssl_ctx * const s = p->ssl_ctxs + i;
837             if (s->model && s->model != global_model)
838                 PR_Close(s->model);
839         }
840         /* free from global scope */
841         if (global_model)
842             PR_Close(global_model);
843         free(p->ssl_ctxs);
844     }
845 
846     if (NULL == p->cvlist) return;
847     /* (init i to 0 if global context; to 1 to skip empty global context) */
848     for (int i = !p->cvlist[0].v.u2[1], used = p->nconfig; i < used; ++i) {
849         config_plugin_value_t *cpv = p->cvlist + p->cvlist[i].v.u2[0];
850         for (; -1 != cpv->k_id; ++cpv) {
851             switch (cpv->k_id) {
852               case 0: /* ssl.pemfile */
853                 if (cpv->vtype == T_CONFIG_LOCAL) {
854                     plugin_cert *pc = cpv->v.v;
855                     CERT_DestroyCertificate(pc->ssl_pemfile_x509);
856                     SECKEY_DestroyPrivateKey(pc->ssl_pemfile_pkey);
857                     CERTCertificateList *certChain;
858                     *(const CERTCertificateList **)&certChain =
859                       pc->ssl_credex.certChain;
860                     CERT_DestroyCertificateList(certChain);
861                     PORT_Free(pc->OCSPResponse.data);
862                     //CERT_Destroy...(pc->ssl_credex.signedCertTimestamps);
863                     //CERT_Destroy...(pc->ssl_credex.delegCred);
864                     //CERT_Destroy...(pc->ssl_credex.delegCredPrivKey);
865                     free(pc);
866                 }
867                 break;
868               case 2: /* ssl.ca-file */
869               case 3: /* ssl.ca-dn-file */
870                 if (cpv->vtype == T_CONFIG_LOCAL)
871                     CERT_DestroyCertList(cpv->v.v);
872                 break;
873               case 4: /* ssl.ca-crl-file */
874                 if (cpv->vtype == T_CONFIG_LOCAL)
875                     mod_nss_free_config_crls(cpv->v.v);
876                 break;
877               default:
878                 break;
879             }
880         }
881     }
882 }
883 
884 
FREE_FUNC(mod_nss_free)885 FREE_FUNC(mod_nss_free)
886 {
887     plugin_data *p = p_d;
888     if (NULL == p->srv) return;
889     mod_nss_free_config(p->srv, p);
890     mod_nss_free_nss();
891 }
892 
893 
894 static void
mod_nss_merge_config_cpv(plugin_config * const pconf,const config_plugin_value_t * const cpv)895 mod_nss_merge_config_cpv (plugin_config * const pconf, const config_plugin_value_t * const cpv)
896 {
897     switch (cpv->k_id) { /* index into static config_plugin_keys_t cpk[] */
898       case 0: /* ssl.pemfile */
899         if (cpv->vtype == T_CONFIG_LOCAL)
900             pconf->pc = cpv->v.v;
901         break;
902       case 1: /* ssl.privkey */
903         break;
904       case 2: /* ssl.ca-file */
905         if (cpv->vtype == T_CONFIG_LOCAL)
906             pconf->ssl_ca_file = cpv->v.v;
907         break;
908       case 3: /* ssl.ca-dn-file */
909         if (cpv->vtype == T_CONFIG_LOCAL)
910             pconf->ssl_ca_dn_file = cpv->v.v;
911         break;
912       case 4: /* ssl.ca-crl-file */
913         break;
914       case 5: /* ssl.read-ahead */
915         pconf->ssl_read_ahead = (0 != cpv->v.u);
916         break;
917       case 6: /* ssl.disable-client-renegotiation */
918         /*(ignored; unsafe renegotiation disabled by default)*/
919         break;
920       case 7: /* ssl.verifyclient.activate */
921         pconf->ssl_verifyclient = (0 != cpv->v.u);
922         break;
923       case 8: /* ssl.verifyclient.enforce */
924         pconf->ssl_verifyclient_enforce = (0 != cpv->v.u);
925         break;
926       case 9: /* ssl.verifyclient.depth */
927         pconf->ssl_verifyclient_depth = (unsigned char)cpv->v.shrt;
928         break;
929       case 10:/* ssl.verifyclient.username */
930         pconf->ssl_verifyclient_username = cpv->v.b;
931         break;
932       case 11:/* ssl.verifyclient.exportcert */
933         pconf->ssl_verifyclient_export_cert = (0 != cpv->v.u);
934         break;
935       case 12:/* ssl.acme-tls-1 */
936         pconf->ssl_acme_tls_1 = cpv->v.b;
937         break;
938       case 13:/* ssl.stapling-file */
939         break;
940       case 14:/* debug.log-ssl-noise */
941         pconf->ssl_log_noise = (unsigned char)cpv->v.shrt;
942         break;
943      #if 0    /*(cpk->k_id remapped in mod_nss_set_defaults())*/
944       case 15:/* ssl.verifyclient.ca-file */
945       case 16:/* ssl.verifyclient.ca-dn-file */
946       case 17:/* ssl.verifyclient.ca-crl-file */
947         break;
948      #endif
949       default:/* should not happen */
950         return;
951     }
952 }
953 
954 
955 static void
mod_nss_merge_config(plugin_config * const pconf,const config_plugin_value_t * cpv)956 mod_nss_merge_config(plugin_config * const pconf, const config_plugin_value_t *cpv)
957 {
958     do {
959         mod_nss_merge_config_cpv(pconf, cpv);
960     } while ((++cpv)->k_id != -1);
961 }
962 
963 
964 static void
mod_nss_patch_config(request_st * const r,plugin_config * const pconf)965 mod_nss_patch_config (request_st * const r, plugin_config * const pconf)
966 {
967     plugin_data * const p = plugin_data_singleton;
968     memcpy(pconf, &p->defaults, sizeof(plugin_config));
969     for (int i = 1, used = p->nconfig; i < used; ++i) {
970         if (config_check_cond(r, (uint32_t)p->cvlist[i].k_id))
971             mod_nss_merge_config(pconf, p->cvlist + p->cvlist[i].v.u2[0]);
972     }
973 }
974 
975 
976 static SECStatus
mod_nss_verify_cb(void * arg,PRFileDesc * ssl,PRBool checkSig,PRBool isServer)977 mod_nss_verify_cb (void *arg, PRFileDesc *ssl, PRBool checkSig, PRBool isServer)
978 {
979     handler_ctx * const hctx = arg;
980     if (!hctx->conf.ssl_verifyclient) return SECSuccess;
981 
982     /* Notes
983      * trusted CAs in ssl.ca-file were loaded into default cert db at startup
984      * OCSP checking (querying OCSP Responder) is disabled by default
985      *   CERT_EnableOCSPChecking()
986      *   CERT_DisableOCSPChecking()
987      * cert_VerifyCertWithFlags() is not public,
988      *   so unable to use CERT_VERIFYCERT_SKIP_OCSP
989      * hctx->verify_status is set here; not setting SSL_BadCertHook()
990      * XXX: not implemented (yet) here: hctx->conf.ssl_verifyclient_depth)
991      */
992 
993     CERTCertificate *peer = NULL;
994 
995   #if 0
996     peer = SSL_PeerCertificate(ssl);
997     if (NULL == peer)
998         return (PORT_GetError() == SSL_ERROR_NO_CERTIFICATE)
999           ? SECSuccess
1000           : SECFailure;
1001 
1002     if (CERT_VerifyCert(CERT_GetDefaultCertDB(), peer, PR_TRUE,
1003                         certUsageSSLClient, (PRInt64)log_epoch_secs * 1000000,
1004                         SSL_RevealPinArg(ssl), NULL) < 0)
1005   #else
1006     if (SSL_AuthCertificate((void *)CERT_GetDefaultCertDB(),
1007                             ssl, checkSig, isServer) < 0)
1008   #endif
1009     {
1010         hctx->verify_status = PORT_GetError();
1011         if (0 == hctx->verify_status)
1012             hctx->verify_status = SEC_ERROR_UNTRUSTED_CERT;
1013     }
1014 
1015     if (hctx->verify_status == 0 && hctx->conf.ssl_ca_dn_file) {
1016         /* verify that client cert is issued by CA in ssl.ca-dn-file
1017          * if both ssl.ca-dn-file and ssl.ca-file were configured */
1018         if (NULL == peer) peer = SSL_PeerCertificate(ssl);
1019         if (peer) {
1020             CERTCertList * const certList = hctx->conf.ssl_ca_dn_file;
1021             SECItem * const derIssuer = &peer->derIssuer;
1022             CERTCertListNode *node = CERT_LIST_HEAD(certList);
1023             for (; !CERT_LIST_END(node, certList); node = CERT_LIST_NEXT(node)){
1024                 SECItem * const derSubject = &node->cert->derSubject;
1025                 if (SECITEM_CompareItem(derIssuer, derSubject) == SECEqual)
1026                     break;
1027             }
1028             if (CERT_LIST_END(node, certList))
1029                 hctx->verify_status = SEC_ERROR_UNTRUSTED_CERT;
1030         }
1031     }
1032 
1033     if (peer) CERT_DestroyCertificate(peer);
1034 
1035     if (hctx->verify_status != 0 && hctx->conf.ssl_verifyclient_enforce) {
1036         PORT_SetError(SEC_ERROR_UNTRUSTED_CERT);
1037         return SECFailure;
1038     }
1039 
1040     return SECSuccess;
1041 }
1042 
1043 
1044 __attribute_cold__
1045 static void
mod_nss_expire_stapling_file(server * srv,plugin_cert * pc)1046 mod_nss_expire_stapling_file (server *srv, plugin_cert *pc)
1047 {
1048     /* discard expired OCSP stapling response */
1049     pc->ssl_credex.stapledOCSPResponses = NULL;
1050     if (pc->must_staple)
1051         log_error(srv->errh, __FILE__, __LINE__,
1052                   "certificate marked OCSP Must-Staple, "
1053                   "but OCSP response expired from ssl.stapling-file %s",
1054                   pc->ssl_stapling_file->ptr);
1055 }
1056 
1057 
1058 static int
mod_nss_reload_stapling_file(server * srv,plugin_cert * pc,const unix_time64_t cur_ts)1059 mod_nss_reload_stapling_file (server *srv, plugin_cert *pc, const unix_time64_t cur_ts)
1060 {
1061     SECItem f;
1062     int rc = mod_nss_load_file(pc->ssl_stapling_file->ptr, &f, srv->errh);
1063     if (rc < 0) return rc;
1064 
1065     /* NSS has the ability to include multiple OCSP responses for
1066      * certificate chain as allowed in TLSv1.3, but that is not utilized here.
1067      * If implemented, it will probably operate on a new directive,
1068      *   e.g. ssl.stapling-pemfile
1069      */
1070 
1071     /*   Note that the credentials structure should be read-only when in
1072      *   use, thus when reloading, either the credentials structure must not
1073      *   be in use by any sessions, or a new credentials structure should be
1074      *   allocated for new sessions.
1075      * XXX: lighttpd is not threaded, so this is probably not an issue (?)
1076      */
1077 
1078     PORT_Free(pc->OCSPResponse.data);
1079     pc->OCSPResponse.data   = f.data;
1080     pc->OCSPResponse.len    = f.len;
1081     pc->OCSPResponses.items = &pc->OCSPResponse;
1082     pc->OCSPResponses.len   = 1;
1083     pc->ssl_credex.stapledOCSPResponses = &pc->OCSPResponses;
1084 
1085     /* NSS does not expose CERTOCSPSingleResponse member nextUpdate
1086      * to allow getting (PRTime) of nextUpdate from the OCSP response.
1087      * (PRTime is (PRInt64) of microseconds since epoch)
1088      * e.g. DER_GeneralizedTimeToTime(&nextUpdate, single->nextUpdate);
1089      * XXX: *not* implementing our own ASN.1 DER decoder for OCSP response
1090      * ssl.stapling-file will be reloaded hourly
1091      */
1092     unix_time64_t nextupd = -1;
1093 
1094     pc->ssl_stapling_loadts = cur_ts;
1095     pc->ssl_stapling_nextts = nextupd;
1096     if (pc->ssl_stapling_nextts == -1) {
1097         /* "Next Update" might not be provided by OCSP responder
1098          * Use 3600 sec (1 hour) in that case. */
1099         /* retry in 1 hour if unable to determine Next Update */
1100         pc->ssl_stapling_nextts = cur_ts + 3600;
1101         pc->ssl_stapling_loadts = 0;
1102     }
1103     else if (pc->ssl_stapling_nextts < cur_ts)
1104         mod_nss_expire_stapling_file(srv, pc);
1105 
1106     return 0;
1107 }
1108 
1109 
1110 static int
mod_nss_refresh_stapling_file(server * srv,plugin_cert * pc,const unix_time64_t cur_ts)1111 mod_nss_refresh_stapling_file (server *srv, plugin_cert *pc, const unix_time64_t cur_ts)
1112 {
1113     if (pc->ssl_stapling_nextts > cur_ts + 256)
1114         return 0; /* skip check for refresh unless close to expire */
1115     struct stat st;
1116     if (0 != stat(pc->ssl_stapling_file->ptr, &st)
1117         || TIME64_CAST(st.st_mtime) <= pc->ssl_stapling_loadts) {
1118         if (pc->ssl_stapling_nextts < cur_ts)
1119             mod_nss_expire_stapling_file(srv, pc);
1120         return 0;
1121     }
1122     return mod_nss_reload_stapling_file(srv, pc, cur_ts);
1123 }
1124 
1125 
1126 static void
mod_nss_refresh_stapling_files(server * srv,const plugin_data * p,const unix_time64_t cur_ts)1127 mod_nss_refresh_stapling_files (server *srv, const plugin_data *p, const unix_time64_t cur_ts)
1128 {
1129     /* future: might construct array of (plugin_cert *) at startup
1130      *         to avoid the need to search for them here */
1131     /* (init i to 0 if global context; to 1 to skip empty global context) */
1132     if (NULL == p->cvlist) return;
1133     for (int i = !p->cvlist[0].v.u2[1], used = p->nconfig; i < used; ++i) {
1134         const config_plugin_value_t *cpv = p->cvlist + p->cvlist[i].v.u2[0];
1135         for (; cpv->k_id != -1; ++cpv) {
1136             if (cpv->k_id != 0) continue; /* k_id == 0 for ssl.pemfile */
1137             if (cpv->vtype != T_CONFIG_LOCAL) continue;
1138             plugin_cert *pc = cpv->v.v;
1139             if (pc->ssl_stapling_file)
1140                 mod_nss_refresh_stapling_file(srv, pc, cur_ts);
1141         }
1142     }
1143 }
1144 
1145 
1146 static int
mod_nss_crt_must_staple(CERTCertificate * crt)1147 mod_nss_crt_must_staple (CERTCertificate *crt)
1148 {
1149     /* Look for TLS features X.509 extension with value 5
1150      * RFC 7633 https://tools.ietf.org/html/rfc7633#appendix-A
1151      * 5 = OCSP Must-Staple (security mechanism)
1152      *
1153      * id-pe-tlsfeature 1.3.6.1.5.5.7.1.24
1154      * 1.3.6.1.5.5.7.1.24 = DER:30:03:02:01:05
1155      */
1156 
1157     int rc;
1158 
1159     /* XXX: not implemented */
1160     UNUSED(crt);
1161     rc = 0;
1162 
1163     return rc; /* 1 if OCSP Must-Staple found; 0 if not */
1164 }
1165 
1166 
1167 static void *
network_nss_load_pemfile(server * srv,const buffer * pemfile,const buffer * privkey,const buffer * ssl_stapling_file)1168 network_nss_load_pemfile (server *srv, const buffer *pemfile, const buffer *privkey, const buffer *ssl_stapling_file)
1169 {
1170     CERTCertificateList *ssl_pemfile_chain;
1171     CERTCertificate *ssl_pemfile_x509 =
1172       mod_nss_load_pem_crts(pemfile->ptr, srv->errh, &ssl_pemfile_chain);
1173     if (NULL == ssl_pemfile_x509)
1174         return NULL;
1175 
1176     SECKEYPrivateKey *pkey =
1177       mod_nss_load_config_pkey(privkey->ptr, ssl_pemfile_x509, srv->errh);
1178     if (NULL == pkey) {
1179         CERT_DestroyCertificate(ssl_pemfile_x509);
1180         if (ssl_pemfile_chain) CERT_DestroyCertificateList(ssl_pemfile_chain);
1181         return NULL;
1182     }
1183 
1184     if (NULL == ssl_pemfile_chain)
1185         ssl_pemfile_chain = CERT_CertChainFromCert(ssl_pemfile_x509,
1186                                                    certUsageSSLServer,
1187                                                    PR_FALSE);
1188 
1189     plugin_cert *pc = ck_calloc(1, sizeof(plugin_cert));
1190     pc->ssl_pemfile_pkey = pkey;
1191     pc->ssl_pemfile_x509 = ssl_pemfile_x509;
1192     pc->ssl_credex.certChain = ssl_pemfile_chain;
1193     pc->ssl_stapling_file= ssl_stapling_file;
1194     pc->ssl_stapling_loadts = 0;
1195     pc->ssl_stapling_nextts = 0;
1196     pc->OCSPResponse.type   = 0;
1197     pc->OCSPResponse.data   = NULL;
1198     pc->OCSPResponse.len    = 0;
1199     pc->OCSPResponses.items = NULL;
1200     pc->OCSPResponses.len   = 0;
1201     pc->must_staple = mod_nss_crt_must_staple(ssl_pemfile_x509);
1202 
1203     if (pc->ssl_stapling_file) {
1204         if (mod_nss_reload_stapling_file(srv, pc, log_epoch_secs) < 0) {
1205             /* continue without OCSP response if there is an error */
1206         }
1207     }
1208     else if (pc->must_staple) {
1209         log_error(srv->errh, __FILE__, __LINE__,
1210                   "certificate %s marked OCSP Must-Staple, "
1211                   "but ssl.stapling-file not provided", pemfile->ptr);
1212     }
1213 
1214   #if 0
1215     PRTime notBefore, notAfter;
1216     SECStatus rc = CERT_GetCertTimes(crt, &notBefore, &notAfter);
1217     pc->notAfter = (rc == SECSuccess) ? notAfter/1000000 : 0;
1218   #endif
1219 
1220     return pc;
1221 }
1222 
1223 
1224 static int
mod_nss_acme_tls_1(handler_ctx * hctx)1225 mod_nss_acme_tls_1 (handler_ctx *hctx)
1226 {
1227     buffer * const b = hctx->tmp_buf;
1228     const buffer * const name = &hctx->r->uri.authority;
1229     log_error_st * const errh = hctx->r->conf.errh;
1230 
1231     /* check if acme-tls/1 protocol is enabled (path to dir of cert(s) is set)*/
1232     if (!hctx->conf.ssl_acme_tls_1)
1233         return SECFailure; /*(should not happen)*/
1234 
1235     /* check if SNI set server name (required for acme-tls/1 protocol)
1236      * and perform simple path checks for no '/'
1237      * and no leading '.' (e.g. ignore "." or ".." or anything beginning '.') */
1238     if (buffer_is_blank(name))          return SECFailure;
1239     if (NULL != strchr(name->ptr, '/')) return SECFailure;
1240     if (name->ptr[0] == '.')            return SECFailure;
1241   #if 0
1242     if (0 != http_request_host_policy(name, hctx->r->conf.http_parseopts, 443))
1243         return SECFailure;
1244   #endif
1245     buffer_copy_path_len2(b, BUF_PTR_LEN(hctx->conf.ssl_acme_tls_1),
1246                              BUF_PTR_LEN(name));
1247 
1248     /* cert and key load is similar to network_nss_load_pemfile() */
1249 
1250     uint32_t len = buffer_clen(b);
1251     buffer_append_string_len(b, CONST_STR_LEN(".crt.pem"));
1252 
1253     CERTCertificateList *ssl_pemfile_chain;
1254     CERTCertificate *ssl_pemfile_x509 =
1255       mod_nss_load_pem_crts(b->ptr, errh, &ssl_pemfile_chain);
1256     if (NULL == ssl_pemfile_x509)
1257         return SECFailure;
1258 
1259     buffer_truncate(b, len);
1260     buffer_append_string_len(b, CONST_STR_LEN(".key.pem"));
1261 
1262     SECKEYPrivateKey *pkey =
1263       mod_nss_load_config_pkey(b->ptr, ssl_pemfile_x509, errh);
1264     if (NULL == pkey) {
1265         CERT_DestroyCertificate(ssl_pemfile_x509);
1266         if (ssl_pemfile_chain) CERT_DestroyCertificateList(ssl_pemfile_chain);
1267         return SECFailure;
1268     }
1269 
1270     /* use NSS deprecated functions to unconfigure an already-configured cert.
1271      * This is because SSL_ConfigServerCert() will replace an existing cert
1272      * of the same type, but not if an existing cert is of a different type */
1273     if (hctx->conf.pc) {
1274         SSLKEAType certType =
1275           NSS_FindCertKEAType(hctx->conf.pc->ssl_pemfile_x509);
1276         SSL_ConfigSecureServerWithCertChain(hctx->ssl,NULL,NULL,NULL,certType);
1277     }
1278 
1279     unsigned int dlen = 0;
1280     SSLExtraServerCertData *data = NULL;
1281     SSLExtraServerCertData d;
1282     if (ssl_pemfile_chain) {
1283         data = &d;
1284         dlen = sizeof(d);
1285         memset(&d, 0, sizeof(d));
1286         d.certChain = ssl_pemfile_chain;
1287     }
1288     SECStatus rc =
1289       SSL_ConfigServerCert(hctx->ssl, ssl_pemfile_x509, pkey, data, dlen);
1290 
1291     CERT_DestroyCertificate(ssl_pemfile_x509);
1292     SECKEY_DestroyPrivateKey(pkey);
1293     if (ssl_pemfile_chain) CERT_DestroyCertificateList(ssl_pemfile_chain);
1294 
1295     if (hctx->conf.ssl_verifyclient) {
1296         /*(disable client certificate verification for "acme-tls/1")*/
1297         hctx->conf.ssl_verifyclient = 0;
1298         SSL_OptionSet(hctx->ssl, SSL_REQUEST_CERTIFICATE, PR_FALSE);
1299         SSL_OptionSet(hctx->ssl, SSL_REQUIRE_CERTIFICATE, SSL_REQUIRE_NEVER);
1300     }
1301 
1302     return rc;
1303 }
1304 
1305 
1306 static int
mod_nss_alpn_h2_policy(handler_ctx * const hctx)1307 mod_nss_alpn_h2_policy (handler_ctx * const hctx)
1308 {
1309     UNUSED(hctx);
1310     /*(currently called after handshake has completed)*/
1311   #if 0 /* SNI omitted by client when connecting to IP instead of to name */
1312     if (buffer_is_blank(&hctx->r->uri.authority)) {
1313         log_error(hctx->errh, __FILE__, __LINE__,
1314           "SSL: error ALPN h2 without SNI");
1315         return -1;
1316     }
1317   #endif
1318   #if 0
1319     /* sanity check; lighttpd defaults to using TLSv1.2 or better */
1320     /* modified from http_cgi_ssl_env(); expensive, so commented out */
1321     /* (quite a bit of work just to get protocol version)
1322      * (could not find better NSS interface) */
1323     SSLChannelInfo inf;
1324     if (SSL_GetChannelInfo(ssl, &inf, sizeof(inf)) < 0
1325         || inf.protocolVersion < SSL_LIBRARY_VERSION_TLS_1_2) {
1326         log_error(hctx->errh, __FILE__, __LINE__,
1327           "SSL: error ALPN h2 requires TLSv1.2 or later");
1328         return -1;
1329     }
1330   #endif
1331 
1332     return 0;
1333 }
1334 
1335 
1336 enum {
1337   MOD_NSS_ALPN_HTTP11      = 1
1338  ,MOD_NSS_ALPN_HTTP10      = 2
1339  ,MOD_NSS_ALPN_H2          = 3
1340  ,MOD_NSS_ALPN_ACME_TLS_1  = 4
1341 };
1342 
1343 
1344 static SECStatus
mod_nss_alpn_select_cb(void * arg,PRFileDesc * ssl,const unsigned char * protos,unsigned int protosLen,unsigned char * protoOut,unsigned int * protoOutLen,unsigned int protoMaxOut)1345 mod_nss_alpn_select_cb (void *arg, PRFileDesc *ssl,
1346                         const unsigned char *protos, unsigned int protosLen,
1347                         unsigned char *protoOut, unsigned int *protoOutLen,
1348                         unsigned int protoMaxOut)
1349 {
1350     /* https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#alpn-protocol-ids */
1351     static const SECItem alpn[] = {
1352       { 0, (unsigned char *)CONST_STR_LEN("h2") }
1353      ,{ 0, (unsigned char *)CONST_STR_LEN("http/1.1") }
1354      ,{ 0, (unsigned char *)CONST_STR_LEN("http/1.0") }
1355      ,{ 0, (unsigned char *)CONST_STR_LEN("acme-tls/1") }
1356     };
1357     UNUSED(ssl);
1358     /* reference: lib/ssl/sslsock.c:ssl_NextProtoNegoCallback() */
1359     for (unsigned int i = 0; i < protosLen; i += 1 + protos[i]) {
1360         for (unsigned int j = 0; j < sizeof(alpn)/sizeof(*alpn); ++j) {
1361             if (protos[i] == alpn[j].len && i+1+protos[i] <= protosLen
1362                 && 0 == PORT_Memcmp(protos+i+1, alpn[j].data, alpn[j].len)) {
1363 
1364                 if (protoMaxOut < alpn[j].len) {
1365                     PORT_SetError(SEC_ERROR_OUTPUT_LEN);
1366                     return SECFailure;
1367                 }
1368 
1369                 handler_ctx *hctx = arg;
1370                 switch (j) { /*(must match SECItem alpn[] above)*/
1371                   case 0:
1372                     if (!hctx->r->conf.h2proto) continue;
1373                     hctx->alpn = MOD_NSS_ALPN_H2;
1374                     if (hctx->r->handler_module == NULL)/*(not mod_sockproxy)*/
1375                         hctx->r->http_version = HTTP_VERSION_2;
1376                     break;
1377                   case 1:
1378                     hctx->alpn = MOD_NSS_ALPN_HTTP11;
1379                     break;
1380                   case 2:
1381                     hctx->alpn = MOD_NSS_ALPN_HTTP10;
1382                     break;
1383                   case 3:
1384                     if (!hctx->conf.ssl_acme_tls_1)
1385                         continue;
1386                     hctx->alpn = MOD_NSS_ALPN_ACME_TLS_1;
1387                     break;
1388                   default:
1389                     break;
1390                 }
1391 
1392                 memcpy(protoOut, alpn[j].data, alpn[j].len);
1393                 *protoOutLen = alpn[j].len;
1394 
1395                 return SECSuccess;
1396             }
1397         }
1398     }
1399     return SECSuccess;
1400 }
1401 
1402 
1403 static PRInt32
mod_nss_SNI(PRFileDesc * ssl,const SECItem * srvNameArr,PRUint32 srvNameArrSize,void * arg)1404 mod_nss_SNI (PRFileDesc *ssl, const SECItem *srvNameArr, PRUint32 srvNameArrSize,
1405              void *arg)
1406 {
1407     if (0 == srvNameArrSize) /* should not happen */
1408         return SSL_SNI_CURRENT_CONFIG_IS_USED;
1409 
1410     handler_ctx * const hctx = (handler_ctx *)arg;
1411     request_st * const r = hctx->r;
1412     buffer_copy_string_len(&r->uri.scheme, CONST_STR_LEN("https"));
1413     PRUint32 i = 0; /* index into srvNameArr; always take first element */
1414     const SECItem *sn = srvNameArr+i;
1415 
1416     if (sn->len >= 1024) { /*(expecting < 256; TLSEXT_MAXLEN_host_name is 255)*/
1417         log_error(r->conf.errh, __FILE__, __LINE__,
1418                   "NSS: SNI name too long %.*s", (int)sn->len,(char *)sn->data);
1419         return SSL_SNI_SEND_ALERT;
1420     }
1421 
1422     /* use SNI to patch mod_nss config and then reset COMP_HTTP_HOST */
1423     buffer_copy_string_len_lc(&r->uri.authority,(const char *)sn->data,sn->len);
1424   #if 0
1425     /*(r->uri.authority used below for configuration before request read;
1426      * revisit for h2)*/
1427     if (0 != http_request_host_policy(&r->uri.authority,
1428                                       r->conf.http_parseopts, 443))
1429         return SSL_SNI_SEND_ALERT;
1430   #endif
1431 
1432     r->conditional_is_valid |= (1 << COMP_HTTP_SCHEME)
1433                             |  (1 << COMP_HTTP_HOST);
1434 
1435     plugin_cert *pc = hctx->conf.pc;
1436 
1437     mod_nss_patch_config(r, &hctx->conf);
1438     /* reset COMP_HTTP_HOST so that conditions re-run after request hdrs read */
1439     /*(done in configfile-glue.c:config_cond_cache_reset() after request hdrs read)*/
1440     /*config_cond_cache_reset_item(r, COMP_HTTP_HOST);*/
1441     /*buffer_clear(&r->uri.authority);*/
1442 
1443     /* XXX: it appears that ALPN callback is called before SNI callback in NSS,
1444      * so handle acme-tls/1 here, prior to and instead of setting cert below */
1445     if (hctx->alpn == MOD_NSS_ALPN_ACME_TLS_1) {
1446         if (0 == mod_nss_acme_tls_1(hctx))
1447             return (PRInt32)i;
1448         else {
1449             log_error(hctx->r->conf.errh, __FILE__, __LINE__,
1450                       "failed to set acme-tls/1 certificate for TLS"
1451                       " server name %s", hctx->r->uri.authority.ptr);
1452             return SSL_SNI_SEND_ALERT;
1453         }
1454     }
1455 
1456     if (pc == hctx->conf.pc)
1457         return SSL_SNI_CURRENT_CONFIG_IS_USED;
1458 
1459     /* use NSS deprecated functions to unconfigure an already-configured cert.
1460      * This is because SSL_ConfigServerCert() will replace an existing cert
1461      * of the same type, but not if an existing cert is of a different type */
1462     SSLKEAType certType =
1463       NSS_FindCertKEAType(hctx->conf.pc->ssl_pemfile_x509);
1464     SSL_ConfigSecureServerWithCertChain(ssl, NULL, NULL, NULL, certType);
1465     SECStatus rc =
1466       SSL_ConfigServerCert(ssl, hctx->conf.pc->ssl_pemfile_x509,
1467                            hctx->conf.pc->ssl_pemfile_pkey,
1468                            &hctx->conf.pc->ssl_credex,
1469                            sizeof(hctx->conf.pc->ssl_credex));
1470     if (rc < 0) {
1471         elogf(r->conf.errh, __FILE__, __LINE__,
1472               "failed to set SNI certificate for TLS server name %s",
1473               r->uri.authority.ptr);
1474         return SSL_SNI_SEND_ALERT;
1475     }
1476 
1477     if (hctx->conf.ssl_verifyclient) {
1478         /*(XXX: technically do not need to redo if it has not changed)*/
1479         if (SSL_AuthCertificateHook(ssl, mod_nss_verify_cb, hctx) < 0) {
1480             elog(r->conf.errh, __FILE__, __LINE__, "SSL_AuthCertificateHook");
1481             return SSL_SNI_SEND_ALERT;
1482         }
1483         CERTCertList * const certList = hctx->conf.ssl_ca_dn_file
1484                                       ? hctx->conf.ssl_ca_dn_file
1485                                       : hctx->conf.ssl_ca_file;
1486         if (NULL == certList)
1487             log_error(hctx->r->conf.errh, __FILE__, __LINE__,
1488               "NSS: can't verify client without ssl.verifyclient.ca-file "
1489               "for TLS server name %s",
1490               hctx->r->uri.authority.ptr); /*(might not be set yet if no SNI)*/
1491         if (certList && SSL_SetTrustAnchors(ssl, certList) < 0) {
1492             elog(r->conf.errh, __FILE__, __LINE__, "SSL_SetTrustAnchors");
1493             return SSL_SNI_SEND_ALERT;
1494         }
1495         SSL_OptionSet(ssl, SSL_REQUEST_CERTIFICATE, PR_TRUE);
1496         SSL_OptionSet(ssl, SSL_REQUIRE_CERTIFICATE,
1497                            hctx->conf.ssl_verifyclient_enforce
1498                              ? SSL_REQUIRE_ALWAYS
1499                              : SSL_REQUIRE_NEVER);
1500     }
1501     else {
1502         SSL_OptionSet(ssl, SSL_REQUEST_CERTIFICATE, PR_FALSE);
1503         SSL_OptionSet(ssl, SSL_REQUIRE_CERTIFICATE, SSL_REQUIRE_NEVER);
1504     }
1505 
1506     return (PRInt32)i;
1507 }
1508 
1509 
1510 static int
1511 mod_nss_ssl_conf_ciphersuites (server *srv, plugin_config_socket *s, buffer *ciphersuites, const buffer *cipherstring);
1512 
1513 
1514 static int
1515 mod_nss_ssl_conf_curves(server *srv, plugin_config_socket *s, const buffer *curvelist);
1516 
1517 
1518 static void
1519 mod_nss_ssl_conf_proto (server *srv, plugin_config_socket *s, const buffer *minb, const buffer *maxb);
1520 
1521 
1522 static int
mod_nss_ssl_conf_cmd(server * srv,plugin_config_socket * s)1523 mod_nss_ssl_conf_cmd (server *srv, plugin_config_socket *s)
1524 {
1525     /* reference:
1526      * https://www.openssl.org/docs/man1.1.1/man3/SSL_CONF_cmd.html */
1527     int rc = 0;
1528     buffer *cipherstring = NULL;
1529     buffer *ciphersuites = NULL;
1530     buffer *minb = NULL;
1531     buffer *maxb = NULL;
1532     buffer *curves = NULL;
1533 
1534     for (size_t i = 0; i < s->ssl_conf_cmd->used; ++i) {
1535         data_string *ds = (data_string *)s->ssl_conf_cmd->data[i];
1536         if (buffer_eq_icase_slen(&ds->key, CONST_STR_LEN("CipherString")))
1537             cipherstring = &ds->value;
1538         else if (buffer_eq_icase_slen(&ds->key, CONST_STR_LEN("Ciphersuites")))
1539             ciphersuites = &ds->value;
1540         else if (buffer_eq_icase_slen(&ds->key, CONST_STR_LEN("Curves"))
1541               || buffer_eq_icase_slen(&ds->key, CONST_STR_LEN("Groups")))
1542             curves = &ds->value;
1543         else if (buffer_eq_icase_slen(&ds->key, CONST_STR_LEN("MaxProtocol")))
1544             maxb = &ds->value;
1545         else if (buffer_eq_icase_slen(&ds->key, CONST_STR_LEN("MinProtocol")))
1546             minb = &ds->value;
1547         else if (buffer_eq_icase_slen(&ds->key, CONST_STR_LEN("Protocol"))) {
1548             /* openssl config for Protocol=... is complex and deprecated */
1549             log_error(srv->errh, __FILE__, __LINE__,
1550                       "NSS: ssl.openssl.ssl-conf-cmd %s ignored; "
1551                       "use MinProtocol=... and MaxProtocol=... instead",
1552                       ds->key.ptr);
1553         }
1554         else if (buffer_eq_icase_slen(&ds->key, CONST_STR_LEN("Options"))) {
1555             for (char *v = ds->value.ptr, *e; *v; v = e) {
1556                 while (*v == ' ' || *v == '\t' || *v == ',') ++v;
1557                 int flag = 1;
1558                 if (*v == '-') {
1559                     flag = 0;
1560                     ++v;
1561                 }
1562                 else if (*v == '+')
1563                     ++v;
1564                 for (e = v; light_isalpha(*e); ++e) ;
1565                 switch ((int)(e-v)) {
1566                   case 11:
1567                     if (buffer_eq_icase_ssn(v, "Compression", 11)) {
1568                         /* (force disabled, the default, if HTTP/2 enabled) */
1569                         if (srv->srvconf.h2proto)
1570                             flag = 0;
1571                         s->ssl_compression = flag;
1572                         continue;
1573                     }
1574                     break;
1575                   case 13:
1576                     if (buffer_eq_icase_ssn(v, "SessionTicket", 13)) {
1577                         /*(translates to "%NO_TICKETS" priority str if !flag)*/
1578                         s->ssl_session_ticket = flag;
1579                         continue;
1580                     }
1581                     break;
1582                   case 16:
1583                     if (buffer_eq_icase_ssn(v, "ServerPreference", 16)) {
1584                         /*(translates to "%SERVER_PRECEDENCE" priority string)*/
1585                         s->ssl_honor_cipher_order = flag;
1586                         continue;
1587                     }
1588                     break;
1589                   default:
1590                     break;
1591                 }
1592                 /* warn if not explicitly handled or ignored above */
1593                 if (!flag) --v;
1594                 log_error(srv->errh, __FILE__, __LINE__,
1595                           "NSS: ssl.openssl.ssl-conf-cmd Options %.*s "
1596                           "ignored", (int)(e-v), v);
1597             }
1598         }
1599       #if 0
1600         else if (buffer_eq_icase_slen(&ds->key, CONST_STR_LEN("..."))) {
1601         }
1602       #endif
1603         else {
1604             /* warn if not explicitly handled or ignored above */
1605             log_error(srv->errh, __FILE__, __LINE__,
1606                       "NSS: ssl.openssl.ssl-conf-cmd %s ignored",
1607                       ds->key.ptr);
1608         }
1609     }
1610 
1611     if (minb || maxb) /*(if at least one was set)*/
1612         mod_nss_ssl_conf_proto(srv, s, minb, maxb);
1613 
1614     if (!mod_nss_ssl_conf_ciphersuites(srv, s, ciphersuites, cipherstring))
1615         rc = -1;
1616 
1617     if (curves && !buffer_is_blank(curves)) {
1618         if (!mod_nss_ssl_conf_curves(srv, s, curves))
1619             rc = -1;
1620     }
1621 
1622     return rc;
1623 }
1624 
1625 
1626 static int
network_init_ssl(server * srv,plugin_config_socket * s,plugin_data * p)1627 network_init_ssl (server *srv, plugin_config_socket *s, plugin_data *p)
1628 {
1629     UNUSED(p);
1630 
1631     const int disable_sess_cache =
1632       !config_feature_bool(srv, "ssl.session-cache", 0);
1633     if (!disable_sess_cache) /* undo disable from mod_nss_init_once_nss() */
1634         SSL_OptionSetDefault(SSL_NO_CACHE, PR_FALSE);
1635 
1636     /* use PR_CreateSocketPollFd() for dummy;
1637      * PR_CreateIOLayerStub() was resulting in crashes
1638      * when SSL_ImportFD() attempted ssl_DefGetpeername() */
1639     s->model = PR_CreateSocketPollFd(-1);
1640     if (NULL == s->model) return -1;
1641     s->model->methods = PR_GetTCPMethods();
1642     PRFileDesc *model = SSL_ImportFD(NULL, s->model);
1643     if (NULL == model) return -1;
1644     s->model = model;
1645 
1646     if (s->ssl_cipher_list) {
1647         if (!mod_nss_ssl_conf_ciphersuites(srv,s,NULL,s->ssl_cipher_list))
1648             return -1;
1649     }
1650 
1651     mod_nss_ssl_conf_proto(srv, s, NULL, NULL); /* set default range */
1652 
1653     if (s->ssl_conf_cmd && s->ssl_conf_cmd->used) {
1654         if (0 != mod_nss_ssl_conf_cmd(srv, s)) return -1;
1655     }
1656 
1657     /* future: add additional configuration of s->model here
1658      *         rather than in mod_nss_handle_con_accept() */
1659 
1660     if (SSL_OptionSet(model, SSL_SECURITY, PR_TRUE) < 0) {
1661         elog(srv->errh, __FILE__, __LINE__, "SSL_SECURITY");
1662         return -1;
1663     }
1664 
1665     if (SSL_VersionRangeSet(model, &s->protos)) {
1666         elog(srv->errh, __FILE__, __LINE__, "SSL_VersionRangeSet()");
1667         return -1;
1668     }
1669 
1670     if (s->protos.min == SSL_LIBRARY_VERSION_2
1671         && SSL_OptionSet(model, SSL_ENABLE_SSL2, PR_TRUE) < 0) {
1672         elog(srv->errh, __FILE__, __LINE__, "SSL_ENABLE_SSL2");
1673         return -1;
1674     }
1675 
1676     if (s->protos.min == SSL_LIBRARY_VERSION_3_0
1677         && SSL_OptionSet(model, SSL_ENABLE_SSL3, PR_TRUE) < 0) {
1678         elog(srv->errh, __FILE__, __LINE__, "SSL_ENABLE_SSL3");
1679         return -1;
1680     }
1681 
1682     if (!s->ssl_session_ticket
1683         && SSL_OptionSet(model, SSL_ENABLE_SESSION_TICKETS, PR_FALSE) < 0) {
1684         elog(srv->errh, __FILE__, __LINE__, "!SSL_ENABLE_SESSION_TICKETS");
1685         return -1;
1686     }
1687 
1688     if (SSL_OptionSet(model, SSL_ENABLE_DEFLATE, s->ssl_compression) < 0) {
1689         elog(srv->errh, __FILE__, __LINE__, "SSL_ENABLE_DEFLATE");
1690         return HANDLER_ERROR;
1691     }
1692 
1693     SSL_OptionSet(model, SSL_REQUEST_CERTIFICATE, PR_FALSE);
1694     SSL_OptionSet(model, SSL_REQUIRE_CERTIFICATE, SSL_REQUIRE_NEVER);
1695 
1696     SECStatus rc =
1697       SSL_ConfigServerCert(model, s->pc->ssl_pemfile_x509,
1698                            s->pc->ssl_pemfile_pkey,
1699                            &s->pc->ssl_credex,
1700                            sizeof(s->pc->ssl_credex));
1701     if (rc < 0) {
1702         elogf(srv->errh, __FILE__, __LINE__,
1703               "failed to set default certificate for socket");
1704         return -1;
1705     }
1706 
1707     return 0;
1708 }
1709 
1710 
1711 #define LIGHTTPD_DEFAULT_CIPHER_LIST \
1712 "EECDH+AESGCM:AES256+EECDH:CHACHA20:!SHA1:!SHA256:!SHA384"
1713 
1714 
1715 static int
mod_nss_set_defaults_sockets(server * srv,plugin_data * p)1716 mod_nss_set_defaults_sockets(server *srv, plugin_data *p)
1717 {
1718     static const config_plugin_keys_t cpk[] = {
1719       { CONST_STR_LEN("ssl.engine"),
1720         T_CONFIG_BOOL,
1721         T_CONFIG_SCOPE_SOCKET }
1722      ,{ CONST_STR_LEN("ssl.cipher-list"),
1723         T_CONFIG_STRING,
1724         T_CONFIG_SCOPE_SOCKET }
1725      ,{ CONST_STR_LEN("ssl.openssl.ssl-conf-cmd"),
1726         T_CONFIG_ARRAY_KVSTRING,
1727         T_CONFIG_SCOPE_SOCKET }
1728      ,{ CONST_STR_LEN("ssl.pemfile"), /* included to process global scope */
1729         T_CONFIG_STRING,
1730         T_CONFIG_SCOPE_CONNECTION }
1731      ,{ CONST_STR_LEN("ssl.stek-file"),
1732         T_CONFIG_STRING,
1733         T_CONFIG_SCOPE_SERVER }
1734      ,{ NULL, 0,
1735         T_CONFIG_UNSET,
1736         T_CONFIG_SCOPE_UNSET }
1737     };
1738     static const buffer default_ssl_cipher_list =
1739       { CONST_STR_LEN(LIGHTTPD_DEFAULT_CIPHER_LIST), 0 };
1740 
1741     p->ssl_ctxs = ck_calloc(srv->config_context->used, sizeof(plugin_ssl_ctx));
1742 
1743     int rc = HANDLER_GO_ON;
1744     plugin_data_base srvplug;
1745     memset(&srvplug, 0, sizeof(srvplug));
1746     plugin_data_base * const ps = &srvplug;
1747     if (!config_plugin_values_init(srv, ps, cpk, "mod_nss"))
1748         return HANDLER_ERROR;
1749 
1750     plugin_config_socket defaults;
1751     memset(&defaults, 0, sizeof(defaults));
1752     defaults.ssl_session_ticket     = 1; /* enabled by default */
1753     defaults.ssl_compression        = 0; /* disable for security */
1754     defaults.ssl_cipher_list        = &default_ssl_cipher_list;
1755 
1756     /* process and validate config directives for global and $SERVER["socket"]
1757      * (init i to 0 if global context; to 1 to skip empty global context) */
1758     for (int i = !ps->cvlist[0].v.u2[1]; i < ps->nconfig; ++i) {
1759         config_cond_info cfginfo;
1760         config_get_config_cond_info(&cfginfo, (uint32_t)ps->cvlist[i].k_id);
1761         int is_socket_scope = (0 == i || cfginfo.comp == COMP_SERVER_SOCKET);
1762         int count_not_engine = 0;
1763 
1764         plugin_config_socket conf;
1765         memcpy(&conf, &defaults, sizeof(conf));
1766         config_plugin_value_t *cpv = ps->cvlist + ps->cvlist[i].v.u2[0];
1767         for (; -1 != cpv->k_id; ++cpv) {
1768             /* ignore ssl.pemfile (k_id=3); included to process global scope */
1769             if (!is_socket_scope && cpv->k_id != 3) {
1770                 log_error(srv->errh, __FILE__, __LINE__,
1771                   "NSS: %s is valid only in global scope or "
1772                   "$SERVER[\"socket\"] condition", cpk[cpv->k_id].k);
1773                 continue;
1774             }
1775             ++count_not_engine;
1776             switch (cpv->k_id) {
1777               case 0: /* ssl.engine */
1778                 conf.ssl_enabled = (0 != cpv->v.u);
1779                 --count_not_engine;
1780                 break;
1781               case 1: /* ssl.cipher-list */
1782                 if (!buffer_is_blank(cpv->v.b)) {
1783                     conf.ssl_cipher_list = cpv->v.b;
1784                     /*(historical use might list non-PFS ciphers)*/
1785                     conf.ssl_honor_cipher_order = 1;
1786                     log_error(srv->errh, __FILE__, __LINE__,
1787                       "%s is deprecated.  "
1788                       "Please prefer lighttpd secure TLS defaults, or use "
1789                       "ssl.openssl.ssl-conf-cmd \"CipherString\" to set custom "
1790                       "cipher list.", cpk[cpv->k_id].k);
1791                 }
1792                 break;
1793               case 2: /* ssl.openssl.ssl-conf-cmd */
1794                 *(const array **)&conf.ssl_conf_cmd = cpv->v.a;
1795                 break;
1796               case 3: /* ssl.pemfile */
1797                 /* ignore here; included to process global scope when
1798                  * ssl.pemfile is set, but ssl.engine is not "enable" */
1799                 break;
1800               case 4: /* ssl.stek-file */
1801                 log_error(srv->errh, __FILE__, __LINE__, "NSS: "
1802                   "ssl.stek-file is not supported in mod_nss; ignoring.");
1803                 break;
1804               default:/* should not happen */
1805                 break;
1806             }
1807         }
1808         if (HANDLER_GO_ON != rc) break;
1809         if (0 == i) memcpy(&defaults, &conf, sizeof(conf));
1810 
1811         if (0 != i && !conf.ssl_enabled) continue;
1812 
1813         /* fill plugin_config_socket with global context then $SERVER["socket"]
1814          * only for directives directly in current $SERVER["socket"] condition*/
1815 
1816         /*conf.pc                     = p->defaults.pc;*/
1817         conf.ssl_verifyclient         = p->defaults.ssl_verifyclient;
1818         conf.ssl_verifyclient_enforce = p->defaults.ssl_verifyclient_enforce;
1819         conf.ssl_verifyclient_depth   = p->defaults.ssl_verifyclient_depth;
1820 
1821         int sidx = ps->cvlist[i].k_id;
1822         for (int j = !p->cvlist[0].v.u2[1]; j < p->nconfig; ++j) {
1823             if (p->cvlist[j].k_id != sidx) continue;
1824             /*if (0 == sidx) break;*//*(repeat to get ssl_pemfile,ssl_privkey)*/
1825             cpv = p->cvlist + p->cvlist[j].v.u2[0];
1826             for (; -1 != cpv->k_id; ++cpv) {
1827                 ++count_not_engine;
1828                 switch (cpv->k_id) {
1829                   case 0: /* ssl.pemfile */
1830                     if (cpv->vtype == T_CONFIG_LOCAL)
1831                         conf.pc = cpv->v.v;
1832                     break;
1833                   case 7: /* ssl.verifyclient.activate */
1834                     conf.ssl_verifyclient = (0 != cpv->v.u);
1835                     break;
1836                   case 8: /* ssl.verifyclient.enforce */
1837                     conf.ssl_verifyclient_enforce = (0 != cpv->v.u);
1838                     break;
1839                   case 9: /* ssl.verifyclient.depth */
1840                     conf.ssl_verifyclient_depth = (unsigned char)cpv->v.shrt;
1841                     break;
1842                   default:
1843                     break;
1844                 }
1845             }
1846             break;
1847         }
1848 
1849         if (NULL == conf.pc) {
1850             if (0 == i && !conf.ssl_enabled) continue;
1851             if (0 != i) {
1852                 /* inherit ssl settings from global scope
1853                  * (if only ssl.engine = "enable" and no other ssl.* settings)
1854                  * (This is for convenience when defining both IPv4 and IPv6
1855                  *  and desiring to inherit the ssl config from global context
1856                  *  without having to duplicate the directives)*/
1857                 if (count_not_engine
1858                     || (conf.ssl_enabled && NULL == p->ssl_ctxs[0].model)) {
1859                     log_error(srv->errh, __FILE__, __LINE__,
1860                       "NSS: ssl.pemfile has to be set in same "
1861                       "$SERVER[\"socket\"] scope as other ssl.* directives, "
1862                       "unless only ssl.engine is set, inheriting ssl.* from "
1863                       "global scope");
1864                     rc = HANDLER_ERROR;
1865                     continue;
1866                 }
1867                 plugin_ssl_ctx * const s = p->ssl_ctxs + sidx;
1868                 *s = *p->ssl_ctxs;/*(copy struct of ssl_ctx from global scope)*/
1869                 continue;
1870             }
1871             /* PEM file is required */
1872             log_error(srv->errh, __FILE__, __LINE__,
1873               "NSS: ssl.pemfile has to be set when ssl.engine = \"enable\"");
1874             rc = HANDLER_ERROR;
1875             continue;
1876         }
1877 
1878         /* (initialize once if module enabled) */
1879         if (!mod_nss_init_once_nss()) {
1880             rc = HANDLER_ERROR;
1881             break;
1882         }
1883 
1884         /* configure ssl_ctx for socket */
1885 
1886         /*conf.ssl_ctx = NULL;*//*(filled by network_init_ssl() even on error)*/
1887         if (0 == network_init_ssl(srv, &conf, p)) {
1888             plugin_ssl_ctx * const s = p->ssl_ctxs + sidx;
1889             s->model              = conf.model;
1890             s->protos             = conf.protos;
1891             s->ssl_compression    = conf.ssl_compression;
1892             s->ssl_session_ticket = conf.ssl_session_ticket;
1893         }
1894         else {
1895             if (conf.model) PR_Close(conf.model);
1896             rc = HANDLER_ERROR;
1897         }
1898     }
1899 
1900     free(srvplug.cvlist);
1901     return rc;
1902 }
1903 
1904 
SETDEFAULTS_FUNC(mod_nss_set_defaults)1905 SETDEFAULTS_FUNC(mod_nss_set_defaults)
1906 {
1907     static const config_plugin_keys_t cpk[] = {
1908       { CONST_STR_LEN("ssl.pemfile"),
1909         T_CONFIG_STRING,
1910         T_CONFIG_SCOPE_CONNECTION }
1911      ,{ CONST_STR_LEN("ssl.privkey"),
1912         T_CONFIG_STRING,
1913         T_CONFIG_SCOPE_CONNECTION }
1914      ,{ CONST_STR_LEN("ssl.ca-file"),
1915         T_CONFIG_STRING,
1916         T_CONFIG_SCOPE_CONNECTION }
1917      ,{ CONST_STR_LEN("ssl.ca-dn-file"),
1918         T_CONFIG_STRING,
1919         T_CONFIG_SCOPE_CONNECTION }
1920      ,{ CONST_STR_LEN("ssl.ca-crl-file"),
1921         T_CONFIG_STRING,
1922         T_CONFIG_SCOPE_CONNECTION }
1923      ,{ CONST_STR_LEN("ssl.read-ahead"),
1924         T_CONFIG_BOOL,
1925         T_CONFIG_SCOPE_CONNECTION }
1926      ,{ CONST_STR_LEN("ssl.disable-client-renegotiation"),
1927         T_CONFIG_BOOL, /*(directive ignored)*/
1928         T_CONFIG_SCOPE_CONNECTION }
1929      ,{ CONST_STR_LEN("ssl.verifyclient.activate"),
1930         T_CONFIG_BOOL,
1931         T_CONFIG_SCOPE_CONNECTION }
1932      ,{ CONST_STR_LEN("ssl.verifyclient.enforce"),
1933         T_CONFIG_BOOL,
1934         T_CONFIG_SCOPE_CONNECTION }
1935      ,{ CONST_STR_LEN("ssl.verifyclient.depth"),
1936         T_CONFIG_SHORT,
1937         T_CONFIG_SCOPE_CONNECTION }
1938      ,{ CONST_STR_LEN("ssl.verifyclient.username"),
1939         T_CONFIG_STRING,
1940         T_CONFIG_SCOPE_CONNECTION }
1941      ,{ CONST_STR_LEN("ssl.verifyclient.exportcert"),
1942         T_CONFIG_BOOL,
1943         T_CONFIG_SCOPE_CONNECTION }
1944      ,{ CONST_STR_LEN("ssl.acme-tls-1"),
1945         T_CONFIG_STRING,
1946         T_CONFIG_SCOPE_CONNECTION }
1947      ,{ CONST_STR_LEN("ssl.stapling-file"),
1948         T_CONFIG_STRING,
1949         T_CONFIG_SCOPE_CONNECTION }
1950      ,{ CONST_STR_LEN("debug.log-ssl-noise"),
1951         T_CONFIG_BOOL,
1952         T_CONFIG_SCOPE_CONNECTION }
1953      ,{ CONST_STR_LEN("ssl.verifyclient.ca-file"),
1954         T_CONFIG_STRING,
1955         T_CONFIG_SCOPE_CONNECTION }
1956      ,{ CONST_STR_LEN("ssl.verifyclient.ca-dn-file"),
1957         T_CONFIG_STRING,
1958         T_CONFIG_SCOPE_CONNECTION }
1959      ,{ CONST_STR_LEN("ssl.verifyclient.ca-crl-file"),
1960         T_CONFIG_STRING,
1961         T_CONFIG_SCOPE_CONNECTION }
1962      ,{ NULL, 0,
1963         T_CONFIG_UNSET,
1964         T_CONFIG_SCOPE_UNSET }
1965     };
1966 
1967     plugin_data * const p = p_d;
1968     p->srv = srv;
1969     if (!config_plugin_values_init(srv, p, cpk, "mod_nss"))
1970         return HANDLER_ERROR;
1971 
1972     /* process and validate config directives
1973      * (init i to 0 if global context; to 1 to skip empty global context) */
1974     for (int i = !p->cvlist[0].v.u2[1]; i < p->nconfig; ++i) {
1975         config_plugin_value_t *cpv = p->cvlist + p->cvlist[i].v.u2[0];
1976         config_plugin_value_t *pemfile = NULL;
1977         config_plugin_value_t *privkey = NULL;
1978         const buffer *ssl_stapling_file = NULL;
1979         for (; -1 != cpv->k_id; ++cpv) {
1980             switch (cpv->k_id) {
1981               case 0: /* ssl.pemfile */
1982                 if (!buffer_is_blank(cpv->v.b)) pemfile = cpv;
1983                 break;
1984               case 1: /* ssl.privkey */
1985                 if (!buffer_is_blank(cpv->v.b)) privkey = cpv;
1986                 break;
1987               case 15:/* ssl.verifyclient.ca-file */
1988                 cpv->k_id = 2;
1989                 __attribute_fallthrough__
1990               case 2: /* ssl.ca-file */
1991                 if (!buffer_is_blank(cpv->v.b)) {
1992                     CERTCertList *d =
1993                       mod_nss_load_config_crts(cpv->v.b->ptr, srv->errh);
1994                     if (d != NULL) {
1995                         cpv->vtype = T_CONFIG_LOCAL;
1996                         cpv->v.v = d;
1997                     }
1998                     else {
1999                         log_error(srv->errh, __FILE__, __LINE__,
2000                                   "%s = %s", cpk[cpv->k_id].k, cpv->v.b->ptr);
2001                         return HANDLER_ERROR;
2002                     }
2003                 }
2004                 break;
2005               case 16:/* ssl.verifyclient.ca-dn-file */
2006                 cpv->k_id = 3;
2007                 __attribute_fallthrough__
2008               case 3: /* ssl.ca-dn-file */
2009                 if (!buffer_is_blank(cpv->v.b)) {
2010                     CERTCertList *d =
2011                       mod_nss_load_config_dncrts(cpv->v.b->ptr, srv->errh);
2012                     if (d != NULL) {
2013                         cpv->vtype = T_CONFIG_LOCAL;
2014                         cpv->v.v = d;
2015                     }
2016                     else {
2017                         log_error(srv->errh, __FILE__, __LINE__,
2018                                   "%s = %s", cpk[cpv->k_id].k, cpv->v.b->ptr);
2019                         return HANDLER_ERROR;
2020                     }
2021                 }
2022                 break;
2023               case 17:/* ssl.verifyclient.ca-crl-file */
2024                 cpv->k_id = 4;
2025                 __attribute_fallthrough__
2026               case 4: /* ssl.ca-crl-file */
2027                 if (!buffer_is_blank(cpv->v.b)) {
2028                     CERTCertificateList *d =
2029                       mod_nss_load_config_crls(cpv->v.b->ptr, srv->errh);
2030                     if (d != NULL) {
2031                         cpv->vtype = T_CONFIG_LOCAL;
2032                         cpv->v.v = d;
2033                     }
2034                     else {
2035                         log_error(srv->errh, __FILE__, __LINE__,
2036                                   "%s = %s", cpk[cpv->k_id].k, cpv->v.b->ptr);
2037                         return HANDLER_ERROR;
2038                     }
2039                 }
2040                 break;
2041               case 5: /* ssl.read-ahead */
2042               case 6: /* ssl.disable-client-renegotiation */
2043                 /*(ignored; unsafe renegotiation disabled by default)*/
2044               case 7: /* ssl.verifyclient.activate */
2045               case 8: /* ssl.verifyclient.enforce */
2046                 break;
2047               case 9: /* ssl.verifyclient.depth */
2048                 if (cpv->v.shrt > 255) {
2049                     log_error(srv->errh, __FILE__, __LINE__,
2050                       "NSS: %s is absurdly large (%hu); limiting to 255",
2051                       cpk[cpv->k_id].k, cpv->v.shrt);
2052                     cpv->v.shrt = 255;
2053                 }
2054                 break;
2055               case 10:/* ssl.verifyclient.username */
2056                 if (buffer_is_blank(cpv->v.b))
2057                     cpv->v.b = NULL;
2058                 break;
2059               case 11:/* ssl.verifyclient.exportcert */
2060                 break;
2061               case 12:/* ssl.acme-tls-1 */
2062                 if (buffer_is_blank(cpv->v.b))
2063                     cpv->v.b = NULL;
2064                 break;
2065               case 13:/* ssl.stapling-file */
2066                 if (!buffer_is_blank(cpv->v.b))
2067                     ssl_stapling_file = cpv->v.b;
2068                 break;
2069               case 14:/* debug.log-ssl-noise */
2070              #if 0    /*(handled further above)*/
2071               case 15:/* ssl.verifyclient.ca-file */
2072               case 16:/* ssl.verifyclient.ca-dn-file */
2073               case 17:/* ssl.verifyclient.ca-crl-file */
2074              #endif
2075                 break;
2076               default:/* should not happen */
2077                 break;
2078             }
2079         }
2080 
2081         if (pemfile) {
2082             if (NULL == privkey) privkey = pemfile;
2083             pemfile->v.v =
2084               network_nss_load_pemfile(srv, pemfile->v.b, privkey->v.b,
2085                                        ssl_stapling_file);
2086             if (pemfile->v.v)
2087                 pemfile->vtype = T_CONFIG_LOCAL;
2088             else
2089                 return HANDLER_ERROR;
2090         }
2091     }
2092 
2093     p->defaults.ssl_verifyclient = 0;
2094     p->defaults.ssl_verifyclient_enforce = 1;
2095     p->defaults.ssl_verifyclient_depth = 9;
2096     p->defaults.ssl_verifyclient_export_cert = 0;
2097     p->defaults.ssl_read_ahead = 0;
2098 
2099     /* initialize p->defaults from global config context */
2100     if (p->nconfig > 0 && p->cvlist->v.u2[1]) {
2101         const config_plugin_value_t *cpv = p->cvlist + p->cvlist->v.u2[0];
2102         if (-1 != cpv->k_id)
2103             mod_nss_merge_config(&p->defaults, cpv);
2104     }
2105 
2106     return mod_nss_set_defaults_sockets(srv, p);
2107 }
2108 
2109 
2110     /* local_send_buffer is a static buffer of size (LOCAL_SEND_BUFSIZE)
2111      *
2112      * buffer is allocated once, is NOT realloced (note: not thread-safe)
2113      * */
2114 
2115             /* copy small mem chunks into single large buffer
2116              * before PR_Write() to reduce number times write() called
2117              * underneath PR_Write() and potentially reduce number of packets
2118              * generated if TCP_NODELAY */
2119 
2120 
2121 __attribute_cold__
2122 static int
mod_nss_write_err(connection * con,handler_ctx * hctx,size_t wr_len)2123 mod_nss_write_err(connection *con, handler_ctx *hctx, size_t wr_len)
2124 {
2125     switch (PR_GetError()) {
2126       case PR_WOULD_BLOCK_ERROR:
2127       case PR_PENDING_INTERRUPT_ERROR:
2128         con->is_writable = -1;
2129         /* XXX: not handled: protocol might be blocked waiting on read */
2130         /*if (0) con->is_readable = -1;*/
2131         break; /* try again later */
2132       case PR_CONNECT_RESET_ERROR:
2133         if (!hctx->conf.ssl_log_noise) return -1;
2134         __attribute_fallthrough__
2135       default:
2136         elog(hctx->r->conf.errh, __FILE__, __LINE__, __func__);
2137         return -1;
2138     }
2139 
2140     /* partial write; save attempted wr_len */
2141     hctx->pending_write = wr_len;
2142 
2143     return 0; /* try again later */
2144 }
2145 
2146 
2147 __attribute_cold__
2148 static int
mod_nss_read_err(connection * con,handler_ctx * hctx)2149 mod_nss_read_err(connection *con, handler_ctx *hctx)
2150 {
2151     switch (PR_GetError()) {
2152       case PR_WOULD_BLOCK_ERROR:
2153       case PR_PENDING_INTERRUPT_ERROR:
2154         /* XXX: not handled: protocol might be blocked waiting on write */
2155         /*if (0) con->is_writable = -1;*/
2156         con->is_readable = 0;
2157         return 0;
2158       case PR_CONNECT_ABORTED_ERROR:
2159       case PR_CONNECT_RESET_ERROR:
2160       case PR_END_OF_FILE_ERROR:
2161         if (!hctx->conf.ssl_log_noise) return -1;
2162         __attribute_fallthrough__
2163       default:
2164         elog(hctx->errh, __FILE__, __LINE__, __func__);
2165         return -1;
2166     }
2167 }
2168 
2169 
2170 static int
2171 mod_nss_close_notify(handler_ctx *hctx);
2172 
2173 
2174 static int
connection_write_cq_ssl(connection * const con,chunkqueue * const cq,off_t max_bytes)2175 connection_write_cq_ssl (connection * const con, chunkqueue * const cq, off_t max_bytes)
2176 {
2177     handler_ctx * const hctx = con->plugin_ctx[plugin_data_singleton->id];
2178     PRFileDesc * const ssl = hctx->ssl;
2179     log_error_st * const errh = hctx->errh;
2180 
2181     if (__builtin_expect( (0 != hctx->close_notify), 0))
2182         return mod_nss_close_notify(hctx);
2183 
2184     /* future: for efficiency/performance might consider using NSS
2185      *   PR_Writev() PR_TransmitFile() PR_SendFile()
2186      */
2187 
2188     while (max_bytes > 0 && !chunkqueue_is_empty(cq)) {
2189         char *data = local_send_buffer;
2190         uint32_t data_len = LOCAL_SEND_BUFSIZE < max_bytes
2191           ? LOCAL_SEND_BUFSIZE
2192           : (uint32_t)max_bytes;
2193         int wr;
2194 
2195         if (0 != chunkqueue_peek_data(cq, &data, &data_len, errh)) return -1;
2196         if (__builtin_expect( (0 == data_len), 0)) {
2197             chunkqueue_remove_finished_chunks(cq);
2198             continue;
2199         }
2200 
2201         /*(if partial write occurred, expect that subsequent writes will have
2202          * at least that much data available from chunkqueue_peek_data(), which
2203          * is what should happen, but is not checked here)*/
2204         size_t lim = hctx->pending_write;
2205         if (lim && data_len > lim) data_len = lim;
2206         hctx->pending_write = 0;
2207 
2208         /*
2209          * XXX: above comments modified from mod_mbedtls; should be verified
2210          */
2211 
2212         int wr_total = 0;
2213         do {
2214             size_t wr_len = data_len;
2215             wr = PR_Write(ssl, data, (PRInt32)wr_len);
2216             if (wr <= 0) {
2217                 if (wr_total) chunkqueue_mark_written(cq, wr_total);
2218                 return mod_nss_write_err(con, hctx, wr_len);
2219             }
2220             wr_total += wr;
2221             data += wr;
2222         } while ((data_len -= wr));
2223         chunkqueue_mark_written(cq, wr_total);
2224         max_bytes -= wr_total;
2225     }
2226 
2227     return 0;
2228 }
2229 
2230 
2231 static void
mod_nss_SSLHandshakeCallback(PRFileDesc * fd,void * arg)2232 mod_nss_SSLHandshakeCallback (PRFileDesc *fd, void *arg)
2233 {
2234     UNUSED(fd);
2235     handler_ctx *hctx = arg;
2236     hctx->handshake = 1;
2237 }
2238 
2239 
2240 static int
connection_read_cq_ssl(connection * const con,chunkqueue * const cq,off_t max_bytes)2241 connection_read_cq_ssl (connection * const con, chunkqueue * const cq, off_t max_bytes)
2242 {
2243     handler_ctx * const hctx = con->plugin_ctx[plugin_data_singleton->id];
2244 
2245     UNUSED(max_bytes);
2246 
2247     if (__builtin_expect( (0 != hctx->close_notify), 0))
2248         return mod_nss_close_notify(hctx);
2249 
2250     PRFileDesc * const ssl = hctx->ssl;
2251     ssize_t len;
2252     char *mem = NULL;
2253     size_t mem_len = 0;
2254     do {
2255         int pend = SSL_DataPending(ssl);
2256         if (pend < 0) {
2257             len = pend;
2258             break;
2259         }
2260         mem_len = pend < 2048 ? 2048 : (uint32_t)pend;
2261         chunk * const ckpt = cq->last;
2262         mem = chunkqueue_get_memory(cq, &mem_len);
2263 
2264         len = PR_Read(ssl, mem, (PRInt32)mem_len);
2265         chunkqueue_use_memory(cq, ckpt, len > 0 ? len : 0);
2266     } while (len > 0);
2267 
2268     if (hctx->alpn && hctx->handshake) {
2269         if (hctx->alpn == MOD_NSS_ALPN_H2) {
2270             if (0 != mod_nss_alpn_h2_policy(hctx))
2271                 return -1;
2272         }
2273         else if (hctx->alpn == MOD_NSS_ALPN_ACME_TLS_1) {
2274             /* Once TLS handshake is complete, return -1 to result in
2275              * CON_STATE_ERROR so that socket connection is quickly closed */
2276             return -1;
2277         }
2278         hctx->alpn = 0;
2279     }
2280 
2281     if (len < 0) {
2282         return mod_nss_read_err(con, hctx);
2283     } else if (len == 0) {
2284         con->is_readable = 0;
2285         /* the other end closed the connection -> KEEP-ALIVE */
2286 
2287         return -2;
2288   #ifndef __COVERITY__
2289     } else {
2290         return 0;
2291   #endif
2292     }
2293 }
2294 
2295 
CONNECTION_FUNC(mod_nss_handle_con_accept)2296 CONNECTION_FUNC(mod_nss_handle_con_accept)
2297 {
2298     const server_socket *srv_sock = con->srv_socket;
2299     if (!srv_sock->is_ssl) return HANDLER_GO_ON;
2300 
2301     plugin_data *p = p_d;
2302     handler_ctx * const hctx = handler_ctx_init();
2303     request_st * const r = &con->request;
2304     hctx->r = r;
2305     hctx->con = con;
2306     hctx->tmp_buf = con->srv->tmp_buf;
2307     hctx->errh = r->conf.errh;
2308     con->plugin_ctx[p->id] = hctx;
2309     buffer_blank(&r->uri.authority);
2310 
2311     plugin_ssl_ctx * const s = p->ssl_ctxs + srv_sock->sidx;
2312     hctx->ssl_session_ticket = s->ssl_session_ticket;
2313 
2314     con->network_read = connection_read_cq_ssl;
2315     con->network_write = connection_write_cq_ssl;
2316     con->proto_default_port = 443; /* "https" */
2317     mod_nss_patch_config(r, &hctx->conf);
2318 
2319     hctx->ssl = mod_nss_io_ctor(con->fd, s->model, r->conf.errh);
2320     if (NULL == hctx->ssl)
2321         return HANDLER_ERROR;
2322 
2323     /* future: move more config from here to config model in network_init_ssl().
2324      * Callbacks need to be set here to be able to set callback arg to hctx */
2325 
2326     if (SSL_ResetHandshake(hctx->ssl, PR_TRUE) < 0) {
2327         elog(r->conf.errh, __FILE__, __LINE__, "SSL_ResetHandshake()");
2328         return HANDLER_ERROR;
2329     }
2330 
2331     if (SSL_HandshakeCallback(hctx->ssl, mod_nss_SSLHandshakeCallback, hctx)<0){
2332         elog(r->conf.errh, __FILE__, __LINE__, "SSL_HandshakeCallback()");
2333         return HANDLER_ERROR;
2334     }
2335 
2336     if (SSL_SNISocketConfigHook(hctx->ssl, mod_nss_SNI, hctx) < 0) {
2337         elog(r->conf.errh, __FILE__, __LINE__, "SSL_SNISocketConfigHook()");
2338         return HANDLER_ERROR;
2339     }
2340 
2341     if (SSL_SetNextProtoCallback(hctx->ssl, mod_nss_alpn_select_cb, hctx) < 0) {
2342         elog(r->conf.errh, __FILE__, __LINE__, "SSL_SetNextProtoCallback()");
2343         return HANDLER_ERROR;
2344     }
2345 
2346     hctx->verify_status = -1;
2347     if (hctx->conf.ssl_verifyclient) {
2348         if (SSL_AuthCertificateHook(hctx->ssl, mod_nss_verify_cb, hctx) < 0) {
2349             elog(r->conf.errh, __FILE__, __LINE__, "SSL_AuthCertificateHook()");
2350             return HANDLER_ERROR;
2351         }
2352         CERTCertList * const certList = hctx->conf.ssl_ca_dn_file
2353                                       ? hctx->conf.ssl_ca_dn_file
2354                                       : hctx->conf.ssl_ca_file;
2355         if (NULL == certList) {
2356             log_error(hctx->r->conf.errh, __FILE__, __LINE__,
2357               "NSS: can't verify client without ssl.verifyclient.ca-file "
2358               "for TLS server name %s",
2359               hctx->r->uri.authority.ptr); /*(might not be set yet if no SNI)*/
2360             return hctx->conf.ssl_verifyclient_enforce
2361               ? HANDLER_ERROR
2362               : HANDLER_GO_ON;
2363         }
2364         if (SSL_SetTrustAnchors(hctx->ssl, certList) < 0) {
2365             elog(r->conf.errh, __FILE__, __LINE__, "SSL_SetTrustAnchors()");
2366             return HANDLER_ERROR;
2367         }
2368         SSL_OptionSet(hctx->ssl, SSL_REQUEST_CERTIFICATE, PR_TRUE);
2369         SSL_OptionSet(hctx->ssl, SSL_REQUIRE_CERTIFICATE,
2370                                  hctx->conf.ssl_verifyclient_enforce
2371                                    ? SSL_REQUIRE_ALWAYS
2372                                    : SSL_REQUIRE_NEVER);
2373     }
2374     else {
2375         SSL_OptionSet(hctx->ssl, SSL_REQUEST_CERTIFICATE, PR_FALSE);
2376         SSL_OptionSet(hctx->ssl, SSL_REQUIRE_CERTIFICATE, SSL_REQUIRE_NEVER);
2377     }
2378 
2379     return HANDLER_GO_ON;
2380 }
2381 
2382 
2383 static void
mod_nss_detach(handler_ctx * hctx)2384 mod_nss_detach(handler_ctx *hctx)
2385 {
2386     /* step aside from further SSL processing
2387      * (note: additional data might be buffered/discarded by this layer)
2388      * (used after handle_connection_shut_wr hook) */
2389     /* future: might restore prior network_read and network_write fn ptrs */
2390     mod_nss_io_detach(hctx->ssl);
2391     hctx->con->is_ssl_sock = 0;
2392     /* if called after handle_connection_shut_wr hook, shutdown SHUT_WR */
2393     if (-1 == hctx->close_notify) shutdown(hctx->con->fd, SHUT_WR);
2394     hctx->close_notify = 1;
2395 }
2396 
2397 
CONNECTION_FUNC(mod_nss_handle_con_shut_wr)2398 CONNECTION_FUNC(mod_nss_handle_con_shut_wr)
2399 {
2400     plugin_data *p = p_d;
2401     handler_ctx *hctx = con->plugin_ctx[p->id];
2402     if (NULL == hctx) return HANDLER_GO_ON;
2403 
2404     hctx->close_notify = -2;
2405     if (hctx->handshake) {
2406         mod_nss_close_notify(hctx);
2407     }
2408     else {
2409         mod_nss_detach(hctx);
2410     }
2411 
2412     return HANDLER_GO_ON;
2413 }
2414 
2415 
2416 static int
mod_nss_close_notify(handler_ctx * hctx)2417 mod_nss_close_notify (handler_ctx *hctx)
2418 {
2419     if (1 == hctx->close_notify) return -2;
2420 
2421     /* note: this sends close_notify TLS alert and calls shutdown() on fd */
2422     switch (PR_Shutdown(hctx->ssl, PR_SHUTDOWN_SEND)) {
2423       case PR_SUCCESS:
2424         mod_nss_detach(hctx);
2425         return -2;
2426       case PR_FAILURE:
2427       default:
2428         if (PR_GetError() != PR_NOT_CONNECTED_ERROR)
2429             elog(hctx->r->conf.errh, __FILE__, __LINE__, "PR_Shutdown()");
2430         mod_nss_detach(hctx);
2431         return -1;
2432     }
2433 }
2434 
2435 
CONNECTION_FUNC(mod_nss_handle_con_close)2436 CONNECTION_FUNC(mod_nss_handle_con_close)
2437 {
2438     plugin_data *p = p_d;
2439     handler_ctx *hctx = con->plugin_ctx[p->id];
2440     if (NULL != hctx) {
2441         con->plugin_ctx[p->id] = NULL;
2442         if (1 != hctx->close_notify)
2443             mod_nss_close_notify(hctx); /*(one final try)*/
2444         handler_ctx_free(hctx);
2445     }
2446 
2447     return HANDLER_GO_ON;
2448 }
2449 
2450 
2451 __attribute_noinline__
2452 static void
https_add_ssl_client_cert(request_st * const r,CERTCertificate * peer)2453 https_add_ssl_client_cert (request_st * const r, CERTCertificate *peer)
2454 {
2455     char *pem = NSSBase64_EncodeItem(NULL, NULL, 0, &peer->derCert);
2456     if (NULL == pem) return;
2457     uint32_t len = 0;
2458     for (uint32_t i = 0; pem[i]; ++i) {
2459         if (pem[i] != '\r') pem[len++] = pem[i]; /*(translate \r\n to \n)*/
2460     }
2461     buffer_append_str3(
2462       http_header_env_set_ptr(r, CONST_STR_LEN("SSL_CLIENT_CERT")),
2463       CONST_STR_LEN(PEM_BEGIN_CERT"\n"),
2464       pem, len,
2465       CONST_STR_LEN("\n"PEM_END_CERT"\n"));
2466     PORT_Free(pem);
2467 }
2468 
2469 
2470 static void
https_add_ssl_client_subject(request_st * const r,CERTName * const subj)2471 https_add_ssl_client_subject (request_st * const r, CERTName * const subj)
2472 {
2473     /* add components of client Subject DN */
2474     /* not complete list; NSS does not expose enough of lib/certdb/alg1485.c
2475      * for friendly names, though we could consider using CERT_GetOidString()
2476      * and CERT_RFC1485_EscapeAndQuote() */
2477     static const
2478       struct { const char *tag; uint32_t tlen; char *(*fn)(const CERTName *); }
2479       comp[] = {
2480         { CONST_STR_LEN("CN"),           CERT_GetCommonName },
2481         { CONST_STR_LEN("ST"),           CERT_GetStateName },
2482         { CONST_STR_LEN("O"),            CERT_GetOrgName },
2483         { CONST_STR_LEN("OU"),           CERT_GetOrgUnitName },
2484         { CONST_STR_LEN("C"),            CERT_GetCountryName },
2485         { CONST_STR_LEN("L"),            CERT_GetLocalityName },
2486         { CONST_STR_LEN("UID"),          CERT_GetCertUid },
2487         { CONST_STR_LEN("emailAddress"), CERT_GetCertEmailAddress },
2488         { CONST_STR_LEN("DC"),           CERT_GetDomainComponentName },
2489       };
2490     const size_t prelen = sizeof("SSL_CLIENT_S_DN_")-1;
2491     char key[64] = "SSL_CLIENT_S_DN_";
2492     for (uint32_t i = 0; i < sizeof(comp)/sizeof(*comp); ++i) {
2493         char *s = comp[i].fn(subj);
2494         if (NULL == s) continue;
2495 
2496         unsigned int n;
2497         unsigned char c;
2498         for (n = 0; (c = ((unsigned char *)s)[n]); ++n) {
2499             if (c < 32 || c == 127) s[n] = '?';
2500         }
2501 
2502         /*if (prelen+comp[i].tlen >= sizeof(key)) continue;*//*(not possible)*/
2503         memcpy(key+prelen, comp[i].tag, comp[i].tlen); /*(not '\0'-terminated)*/
2504         http_header_env_set(r, key, prelen+comp[i].tlen, s, n);
2505 
2506         PR_Free(s);
2507     }
2508 }
2509 
2510 
2511 __attribute_cold__
2512 static void
https_add_ssl_client_verify_err(buffer * const b,unsigned int status)2513 https_add_ssl_client_verify_err (buffer * const b, unsigned int status)
2514 {
2515     const char *s = PR_ErrorToName(status);
2516     if (s)
2517         buffer_append_string_len(b, s, strlen(s));
2518     buffer_append_char(b, ':');
2519     s = PR_ErrorToString(status, PR_LANGUAGE_I_DEFAULT);
2520     buffer_append_string_len(b, s, strlen(s));
2521 }
2522 
2523 
2524 __attribute_noinline__
2525 static void
https_add_ssl_client_entries(request_st * const r,handler_ctx * const hctx)2526 https_add_ssl_client_entries (request_st * const r, handler_ctx * const hctx)
2527 {
2528     PRFileDesc *ssl = hctx->ssl;
2529     CERTCertificate *crt = NULL;
2530     buffer *vb = http_header_env_set_ptr(r, CONST_STR_LEN("SSL_CLIENT_VERIFY"));
2531 
2532     if (hctx->verify_status != -1)
2533         crt = SSL_PeerCertificate(ssl);
2534     if (NULL == crt) { /* || hctx->verify_status == -1) */
2535         /*(e.g. no cert, or verify result not available)*/
2536         buffer_copy_string_len(vb, CONST_STR_LEN("NONE"));
2537         return;
2538     }
2539     else if (0 != hctx->verify_status) {
2540         buffer_copy_string_len(vb, CONST_STR_LEN("FAILED:"));
2541         https_add_ssl_client_verify_err(vb, hctx->verify_status);
2542         CERT_DestroyCertificate(crt);
2543         return;
2544     }
2545     else {
2546         buffer_copy_string_len(vb, CONST_STR_LEN("SUCCESS"));
2547     }
2548 
2549     char *s = CERT_NameToAsciiInvertible(&crt->subject, CERT_N2A_STRICT);
2550     if (s) {
2551         http_header_env_set(r,
2552                             CONST_STR_LEN("SSL_CLIENT_S_DN"),
2553                             s, strlen(s));
2554         PR_Free(s);
2555     }
2556 
2557     https_add_ssl_client_subject(r, &crt->subject);
2558 
2559     s = (char *)crt->serialNumber.data;
2560     size_t i = 0; /* skip leading 0's per Distinguished Encoding Rules (DER) */
2561     while (i < crt->serialNumber.len && s[i] == 0) ++i;
2562     if (i == crt->serialNumber.len) --i;
2563     buffer_append_string_encoded_hex_uc(
2564       http_header_env_set_ptr(r, CONST_STR_LEN("SSL_CLIENT_M_SERIAL")),
2565       s+i, crt->serialNumber.len-i);
2566 
2567     if (hctx->conf.ssl_verifyclient_username) {
2568         /* pick one of the exported values as "REMOTE_USER", for example
2569          *   ssl.verifyclient.username = "SSL_CLIENT_S_DN_UID"
2570          * or
2571          *   ssl.verifyclient.username = "SSL_CLIENT_S_DN_emailAddress"
2572          */
2573         const buffer *varname = hctx->conf.ssl_verifyclient_username;
2574         vb = http_header_env_get(r, BUF_PTR_LEN(varname));
2575         if (vb) { /* same as mod_auth_api.c:http_auth_setenv() */
2576             http_header_env_set(r,
2577                                 CONST_STR_LEN("REMOTE_USER"),
2578                                 BUF_PTR_LEN(vb));
2579             http_header_env_set(r,
2580                                 CONST_STR_LEN("AUTH_TYPE"),
2581                                 CONST_STR_LEN("SSL_CLIENT_VERIFY"));
2582         }
2583     }
2584 
2585     if (hctx->conf.ssl_verifyclient_export_cert)
2586         https_add_ssl_client_cert(r, crt);
2587 
2588     CERT_DestroyCertificate(crt);
2589 }
2590 
2591 
2592 static void
http_cgi_ssl_env(request_st * const r,handler_ctx * const hctx)2593 http_cgi_ssl_env (request_st * const r, handler_ctx * const hctx)
2594 {
2595     PRFileDesc *ssl = hctx->ssl;
2596 
2597     /* (quite a bit of work just to get protocol version)
2598      * (could not find better NSS interface) */
2599     SSLChannelInfo inf;
2600     if (SSL_GetChannelInfo(ssl, &inf, sizeof(inf)) < 0)
2601         inf.protocolVersion = 0;
2602 
2603     size_t n;
2604     const char *s = NULL;
2605     switch (inf.protocolVersion) {
2606       case SSL_LIBRARY_VERSION_TLS_1_3: s="TLSv1.3";n=sizeof("TLSv1.3")-1;break;
2607       case SSL_LIBRARY_VERSION_TLS_1_2: s="TLSv1.2";n=sizeof("TLSv1.2")-1;break;
2608       case SSL_LIBRARY_VERSION_TLS_1_1: s="TLSv1.1";n=sizeof("TLSv1.1")-1;break;
2609       case SSL_LIBRARY_VERSION_TLS_1_0: s="TLSv1.0";n=sizeof("TLSv1.0")-1;break;
2610       default: break;
2611     }
2612     if (s) http_header_env_set(r, CONST_STR_LEN("SSL_PROTOCOL"), s, n);
2613 
2614     char *cipher;
2615     int algkeysize;
2616     int usekeysize;
2617     if (SSL_SecurityStatus(ssl, NULL, &cipher, &algkeysize, &usekeysize,
2618                            NULL, NULL) < 0)
2619         return;
2620 
2621     if (cipher) {
2622         n = strlen(cipher);
2623         http_header_env_set(r, CONST_STR_LEN("SSL_CIPHER"), cipher, n);
2624         PR_Free(cipher);
2625     }
2626 
2627     /* SSL_CIPHER_ALGKEYSIZE - Number of cipher bits (possible) */
2628     /* SSL_CIPHER_USEKEYSIZE - Number of cipher bits (actually used) */
2629     char buf[LI_ITOSTRING_LENGTH];
2630     http_header_env_set(r, CONST_STR_LEN("SSL_CIPHER_USEKEYSIZE"),
2631                         buf, li_utostrn(buf, sizeof(buf), usekeysize));
2632     http_header_env_set(r, CONST_STR_LEN("SSL_CIPHER_ALGKEYSIZE"),
2633                         buf, li_utostrn(buf, sizeof(buf), algkeysize));
2634 }
2635 
2636 
REQUEST_FUNC(mod_nss_handle_request_env)2637 REQUEST_FUNC(mod_nss_handle_request_env)
2638 {
2639     plugin_data *p = p_d;
2640     /* simple flag for request_env_patched */
2641     if (r->plugin_ctx[p->id]) return HANDLER_GO_ON;
2642     handler_ctx *hctx = r->con->plugin_ctx[p->id];
2643     if (NULL == hctx) return HANDLER_GO_ON;
2644     r->plugin_ctx[p->id] = (void *)(uintptr_t)1u;
2645 
2646     http_cgi_ssl_env(r, hctx);
2647     if (hctx->conf.ssl_verifyclient) {
2648         https_add_ssl_client_entries(r, hctx);
2649     }
2650 
2651     return HANDLER_GO_ON;
2652 }
2653 
2654 
REQUEST_FUNC(mod_nss_handle_uri_raw)2655 REQUEST_FUNC(mod_nss_handle_uri_raw)
2656 {
2657     /* mod_nss must be loaded prior to mod_auth
2658      * if mod_nss is configured to set REMOTE_USER based on client cert */
2659     /* mod_nss must be loaded after mod_extforward
2660      * if mod_nss config is based on lighttpd.conf remote IP conditional
2661      * using remote IP address set by mod_extforward, *unless* PROXY protocol
2662      * is enabled with extforward.hap-PROXY = "enable", in which case the
2663      * reverse is true: mod_extforward must be loaded after mod_nss */
2664     plugin_data *p = p_d;
2665     handler_ctx *hctx = r->con->plugin_ctx[p->id];
2666     if (NULL == hctx) return HANDLER_GO_ON;
2667 
2668     mod_nss_patch_config(r, &hctx->conf);
2669     if (hctx->conf.ssl_verifyclient) {
2670         mod_nss_handle_request_env(r, p);
2671     }
2672 
2673     return HANDLER_GO_ON;
2674 }
2675 
2676 
REQUEST_FUNC(mod_nss_handle_request_reset)2677 REQUEST_FUNC(mod_nss_handle_request_reset)
2678 {
2679     plugin_data *p = p_d;
2680     r->plugin_ctx[p->id] = NULL; /* simple flag for request_env_patched */
2681     return HANDLER_GO_ON;
2682 }
2683 
2684 
TRIGGER_FUNC(mod_nss_handle_trigger)2685 TRIGGER_FUNC(mod_nss_handle_trigger) {
2686     const plugin_data * const p = p_d;
2687     const unix_time64_t cur_ts = log_epoch_secs;
2688     if (cur_ts & 0x3f) return HANDLER_GO_ON; /*(continue once each 64 sec)*/
2689 
2690     mod_nss_refresh_stapling_files(srv, p, cur_ts);
2691 
2692     return HANDLER_GO_ON;
2693 }
2694 
2695 
2696 __attribute_cold__
2697 int mod_nss_plugin_init (plugin *p);
mod_nss_plugin_init(plugin * p)2698 int mod_nss_plugin_init (plugin *p)
2699 {
2700     p->version      = LIGHTTPD_VERSION_ID;
2701     p->name         = "nss";
2702     p->init         = mod_nss_init;
2703     p->cleanup      = mod_nss_free;
2704     p->priv_defaults= mod_nss_set_defaults;
2705 
2706     p->handle_connection_accept  = mod_nss_handle_con_accept;
2707     p->handle_connection_shut_wr = mod_nss_handle_con_shut_wr;
2708     p->handle_connection_close   = mod_nss_handle_con_close;
2709     p->handle_uri_raw            = mod_nss_handle_uri_raw;
2710     p->handle_request_env        = mod_nss_handle_request_env;
2711     p->handle_request_reset      = mod_nss_handle_request_reset;
2712     p->handle_trigger            = mod_nss_handle_trigger;
2713 
2714     return 0;
2715 }
2716 
2717 
2718 static int
mod_nss_ssl_conf_curves(server * srv,plugin_config_socket * s,const buffer * curvelist)2719 mod_nss_ssl_conf_curves(server *srv, plugin_config_socket *s, const buffer *curvelist)
2720 {
2721     log_error(srv->errh, __FILE__, __LINE__,
2722               "NSS: ignoring Curves/Groups; not implemented (%s)",
2723               curvelist->ptr);
2724     UNUSED(s);
2725     UNUSED(curvelist);
2726 
2727     /* XXX: TODO: see ssl/sslt.h enum SSLNamedGroup */
2728 
2729     return 1;
2730 }
2731 
2732 
2733 static PRUint16
mod_nss_ssl_conf_proto_val(server * srv,const buffer * b,int max)2734 mod_nss_ssl_conf_proto_val (server *srv, const buffer *b, int max)
2735 {
2736     /* use of SSL v3 should be avoided, and SSL v2 is not supported here */
2737     if (NULL == b) /* default: min TLSv1.2, max TLSv1.3 */
2738         return max ? SSL_LIBRARY_VERSION_TLS_1_3 : SSL_LIBRARY_VERSION_TLS_1_2;
2739     else if (buffer_eq_icase_slen(b, CONST_STR_LEN("None"))) /*"disable" limit*/
2740         return max ? SSL_LIBRARY_VERSION_TLS_1_3 : SSL_LIBRARY_VERSION_TLS_1_0;
2741     else if (buffer_eq_icase_slen(b, CONST_STR_LEN("TLSv1.0")))
2742         return SSL_LIBRARY_VERSION_TLS_1_0;
2743     else if (buffer_eq_icase_slen(b, CONST_STR_LEN("TLSv1.1")))
2744         return SSL_LIBRARY_VERSION_TLS_1_1;
2745     else if (buffer_eq_icase_slen(b, CONST_STR_LEN("TLSv1.2")))
2746         return SSL_LIBRARY_VERSION_TLS_1_2;
2747     else if (buffer_eq_icase_slen(b, CONST_STR_LEN("TLSv1.3")))
2748         return SSL_LIBRARY_VERSION_TLS_1_3;
2749     else {
2750         if (buffer_eq_icase_slen(b, CONST_STR_LEN("DTLSv1"))
2751             || buffer_eq_icase_slen(b, CONST_STR_LEN("DTLSv1.2")))
2752             log_error(srv->errh, __FILE__, __LINE__,
2753                       "NSS: ssl.openssl.ssl-conf-cmd %s %s ignored",
2754                       max ? "MaxProtocol" : "MinProtocol", b->ptr);
2755         else
2756             log_error(srv->errh, __FILE__, __LINE__,
2757                       "NSS: ssl.openssl.ssl-conf-cmd %s %s invalid; ignored",
2758                       max ? "MaxProtocol" : "MinProtocol", b->ptr);
2759     }
2760     return max ? SSL_LIBRARY_VERSION_TLS_1_3 : SSL_LIBRARY_VERSION_TLS_1_2;
2761 }
2762 
2763 
2764 static void
mod_nss_ssl_conf_proto(server * srv,plugin_config_socket * s,const buffer * minb,const buffer * maxb)2765 mod_nss_ssl_conf_proto (server *srv, plugin_config_socket *s, const buffer *minb, const buffer *maxb)
2766 {
2767     s->protos.min = mod_nss_ssl_conf_proto_val(srv, minb, 0);
2768     s->protos.max = mod_nss_ssl_conf_proto_val(srv, maxb, 1);
2769     /* XXX: could check values against SSL_VersionRangeGetSupported() */
2770 }
2771 
2772 
2773 /**
2774  * Apache mod_nss
2775  * https://pagure.io/mod_nss.git
2776  *
2777  * (with minor modifications to compile in lighttpd)
2778  */
2779 
2780 #define ap_log_error(APLOG_MARK, APLOG_INFO, rc, errh, ...) \
2781         log_error(errh, __FILE__, __LINE__, __VA_ARGS__)
2782 typedef log_error_st server_rec;
2783 
2784 
2785 /*
2786  * mod_nss/nss_engine_cipher.h
2787  */
2788 
2789 /* Copyright 2001-2004 The Apache Software Foundation
2790  *
2791  * Licensed under the Apache License, Version 2.0 (the "License");
2792  * you may not use this file except in compliance with the License.
2793  * You may obtain a copy of the License at
2794  *
2795  *     http://www.apache.org/licenses/LICENSE-2.0
2796  *
2797  * Unless required by applicable law or agreed to in writing, software
2798  * distributed under the License is distributed on an "AS IS" BASIS,
2799  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
2800  * See the License for the specific language governing permissions and
2801  * limitations under the License.
2802  */
2803 
2804 /*
2805  * Cipher definitions
2806  */
2807 typedef struct
2808 {
2809     const char *name;            /* The mod_nss cipher name */
2810     PRInt32 num;                 /* The cipher id */
2811     const char *openssl_name;    /* The OpenSSL cipher name */
2812     PRInt32 attr;                /* cipher attributes: algorithms, etc */
2813     PRInt32 version;             /* protocol version valid for this cipher */
2814     PRInt32 strength;            /* LOW, MEDIUM, HIGH */
2815     PRInt32 bits;                /* bits of strength */
2816     PRInt32 alg_bits;            /* bits of the algorithm */
2817     const char *alias;           /* Other names, usually typos. Right now a
2818                                     single string but could be CSV */
2819 } cipher_properties;
2820 
2821 /* OpenSSL-compatible cipher attributes */
2822 #define SSL_kRSA	0x00000001L
2823 #define SSL_aRSA	0x00000002L
2824 #define SSL_aDSS	0x00000004L
2825 #define SSL_DSS		SSL_aDSS
2826 #define SSL_eNULL	0x00000008L
2827 #define SSL_DES		0x00000010L
2828 #define SSL_3DES	0x00000020L
2829 #define SSL_RC4		0x00000040L
2830 #define SSL_RC2		0x00000080L
2831 #define SSL_MD5		0x00000200L
2832 #define SSL_SHA1	0x00000400L
2833 #define SSL_SHA		SSL_SHA1
2834 #define SSL_RSA		(SSL_kRSA)
2835 #define SSL_kEDH	0x00000800L
2836 #define SSL_EDH		(SSL_kDHE)
2837 #define SSL_aNULL	0x00001000L
2838 #define SSL_kECDHE	0x00002000L
2839 #define SSL_AECDH	0x00004000L
2840 #define SSL_aECDSA	0x00008000L
2841 #define SSL_kECDHr	0x00010000L
2842 #define SSL_kEECDH	0x00020000L
2843 #define SSL_ECDH	(SSL_kECDHE|SSL_kECDHr|SSL_kEECDH)
2844 #define SSL_EECDH	(SSL_kEECDH)
2845 #define SSL_ADH		(SSL_kEDH)
2846 #define SSL_kDHE	0x00040000L
2847 #define SSL_DHE		(SSL_kDHE)
2848 
2849 /* cipher strength */
2850 #define SSL_STRONG_NONE   0x00000001L
2851 #define SSL_NULL          0x00000002L
2852 #define SSL_EXPORT40      0x00000004L
2853 #define SSL_EXPORT56      0x00000008L
2854 #define SSL_LOW           0x00000010L
2855 #define SSL_MEDIUM        0x00000020L
2856 #define SSL_HIGH          0x00000040L
2857 
2858 #define SSL_CHACHA20POLY1305   0x00080000L
2859 #define SSL_AES128             0x00400000L
2860 #define SSL_AES256             0x00800000L
2861 #define SSL_CAMELLIA128        0x01000000L
2862 #define SSL_CAMELLIA256        0x02000000L
2863 #define SSL_AES128GCM          0x04000000L
2864 #define SSL_AES256GCM          0x08000000L
2865 #define SSL_SHA256             0x10000000L
2866 #define SSL_SHA384             0x20000000L
2867 #define SSL_AEAD               0x40000000L
2868 
2869 #define SSL_AES           (SSL_AES128|SSL_AES256|SSL_AES128GCM|SSL_AES256GCM)
2870 #define SSL_CAMELLIA      (SSL_CAMELLIA128|SSL_CAMELLIA256)
2871 
2872 /* Protocols */
2873 #define SSLV2              0x00000001L
2874 #define SSLV3              0x00000002L
2875 #define TLSV1              SSLV3
2876 #define TLSV1_2            0x00000004L
2877 #define TLSV1_3            0x00000008L
2878 
2879 #if 0
2880 /* the table itself is defined in nss_engine_cipher.c */
2881 #if 0
2882 #ifdef NSS_ENABLE_ECC
2883 # ifdef ENABLE_SHA384
2884 #  define ciphernum 54
2885 # else
2886 #  define ciphernum 49
2887 # endif
2888 #else
2889 #define ciphernum 20
2890 #endif
2891 #endif
2892 
2893 extern int ciphernum;
2894 
2895 /* function prototypes */
2896 int nss_parse_ciphers(server_rec *s, char *ciphers, PRBool cipher_list[ciphernum]);
2897 int countciphers(PRBool cipher_state[ciphernum], int version);
2898 #endif
2899 
2900 /* I chose an arbitrary cipher to test the existence for to handle older
2901  * versions of NSS, at least back to 3.15.1
2902  */
2903 #ifndef TLS_NULL_WITH_NULL_NULL
2904 #define TLS_NULL_WITH_NULL_NULL                SSL_NULL_WITH_NULL_NULL
2905 #define TLS_RSA_WITH_NULL_MD5                  SSL_RSA_WITH_NULL_MD5
2906 #define TLS_RSA_WITH_NULL_SHA                  SSL_RSA_WITH_NULL_SHA
2907 #define TLS_RSA_EXPORT_WITH_RC4_40_MD5         SSL_RSA_EXPORT_WITH_RC4_40_MD5
2908 #define TLS_RSA_WITH_RC4_128_MD5               SSL_RSA_WITH_RC4_128_MD5
2909 #define TLS_RSA_WITH_RC4_128_SHA               SSL_RSA_WITH_RC4_128_SHA
2910 #define TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5 SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5
2911 #define TLS_RSA_WITH_IDEA_CBC_SHA              SSL_RSA_WITH_IDEA_CBC_SHA
2912 #define TLS_RSA_EXPORT_WITH_DES40_CBC_SHA      SSL_RSA_EXPORT_WITH_DES40_CBC_SHA
2913 #define TLS_RSA_WITH_DES_CBC_SHA               SSL_RSA_WITH_DES_CBC_SHA
2914 #define TLS_RSA_WITH_3DES_EDE_CBC_SHA          SSL_RSA_WITH_3DES_EDE_CBC_SHA
2915 #endif
2916 
2917 
2918 /*
2919  * mod_nss/nss_engine_cipher.c
2920  */
2921 
2922 /* Copyright 2001-2004 The Apache Software Foundation
2923  *
2924  * Licensed under the Apache License, Version 2.0 (the "License");
2925  * you may not use this file except in compliance with the License.
2926  * You may obtain a copy of the License at
2927  *
2928  *     http://www.apache.org/licenses/LICENSE-2.0
2929  *
2930  * Unless required by applicable law or agreed to in writing, software
2931  * distributed under the License is distributed on an "AS IS" BASIS,
2932  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
2933  * See the License for the specific language governing permissions and
2934  * limitations under the License.
2935  */
2936 #include <sys/types.h>
2937 #include <string.h>
2938 #include <strings.h>
2939 #include <stdio.h>
2940 #include <stdlib.h>
2941 #ifndef NSS_VER_INCLUDE
2942 #include <nss/sslproto.h>
2943 #else
2944 #include <nss3/sslproto.h>
2945 #endif
2946 
2947 /* Cipher actions */
2948 #define PERMANENTLY_DISABLE_CIPHER   -1 /* !CIPHER */
2949 #define SUBTRACT_CIPHER               0 /* -CIPHER */
2950 #define ENABLE_CIPHER                 1 /* CIPHER */
2951 #define REORDER_CIPHER                2 /* +CIPHER */
2952 
2953 ///* ciphernum is defined in nss_engine_cipher.h */
2954 static const cipher_properties ciphers_def[] =
2955 {
2956     {"rsa_null_md5", TLS_RSA_WITH_NULL_MD5, "NULL-MD5", SSL_kRSA|SSL_aRSA|SSL_eNULL|SSL_MD5, SSLV3, SSL_STRONG_NONE, 0, 0, NULL},
2957     {"rsa_null_sha", TLS_RSA_WITH_NULL_SHA, "NULL-SHA", SSL_kRSA|SSL_aRSA|SSL_eNULL|SSL_SHA1, SSLV3, SSL_STRONG_NONE, 0, 0, NULL},
2958     {"rsa_rc4_40_md5", TLS_RSA_EXPORT_WITH_RC4_40_MD5, "EXP-RC4-MD5", SSL_kRSA|SSL_aRSA|SSL_RC4|SSL_MD5, SSLV3, SSL_EXPORT40, 40, 128, NULL},
2959     {"rsa_rc4_128_md5", TLS_RSA_WITH_RC4_128_MD5, "RC4-MD5", SSL_kRSA|SSL_aRSA|SSL_RC4|SSL_MD5, SSLV3, SSL_MEDIUM, 128, 128, NULL},
2960     {"rsa_rc4_128_sha", TLS_RSA_WITH_RC4_128_SHA, "RC4-SHA", SSL_kRSA|SSL_aRSA|SSL_RC4|SSL_SHA1, SSLV3, SSL_MEDIUM, 128, 128, NULL},
2961     {"rsa_rc2_40_md5", TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5, "EXP-RC2-CBC-MD5", SSL_kRSA|SSL_aRSA|SSL_RC2|SSL_MD5, SSLV3, SSL_EXPORT40, 40, 128, NULL},
2962     /* TLS_RSA_EXPORT_WITH_DES40_CBC_SHA not implemented 0x0008 */
2963     {"rsa_des_sha", TLS_RSA_WITH_DES_CBC_SHA, "DES-CBC-SHA", SSL_kRSA|SSL_aRSA|SSL_DES|SSL_SHA1, SSLV3, SSL_LOW, 56, 56, NULL},
2964     {"rsa_3des_sha", TLS_RSA_WITH_3DES_EDE_CBC_SHA, "DES-CBC3-SHA", SSL_kRSA|SSL_aRSA|SSL_3DES|SSL_SHA1, SSLV3, SSL_MEDIUM, 168, 168, NULL},
2965 //#ifdef ENABLE_SERVER_DHE
2966     {"dhe_rsa_des_sha", TLS_DHE_RSA_WITH_DES_CBC_SHA, "EDH-RSA-DES-CBC-SHA", SSL_kDHE|SSL_aRSA|SSL_DES|SSL_SHA1, SSLV3, SSL_LOW, 56, 56, NULL},
2967 //#endif
2968     {"rsa_aes_128_sha", TLS_RSA_WITH_AES_128_CBC_SHA, "AES128-SHA", SSL_kRSA|SSL_aRSA|SSL_AES128|SSL_SHA1, TLSV1, SSL_HIGH, 128, 128, NULL},
2969     {"rsa_aes_256_sha", TLS_RSA_WITH_AES_256_CBC_SHA, "AES256-SHA", SSL_kRSA|SSL_aRSA|SSL_AES256|SSL_SHA1, TLSV1, SSL_HIGH, 256, 256, NULL},
2970     {"null_sha_256", TLS_RSA_WITH_NULL_SHA256, "NULL-SHA256", SSL_kRSA|SSL_aRSA|SSL_eNULL|SSL_SHA256, TLSV1_2, SSL_STRONG_NONE, 0, 0, NULL},
2971     {"aes_128_sha_256", TLS_RSA_WITH_AES_128_CBC_SHA256, "AES128-SHA256", SSL_kRSA|SSL_aRSA|SSL_AES128|SSL_SHA256, TLSV1_2, SSL_HIGH, 128, 128, NULL},
2972     {"aes_256_sha_256", TLS_RSA_WITH_AES_256_CBC_SHA256, "AES256-SHA256", SSL_kRSA|SSL_aRSA|SSL_AES256|SSL_SHA256, TLSV1_2, SSL_HIGH, 256, 256, NULL},
2973     {"camellia_128_sha", TLS_RSA_WITH_CAMELLIA_128_CBC_SHA, "CAMELLIA128-SHA", SSL_kRSA|SSL_aRSA|SSL_CAMELLIA128|SSL_SHA1, TLSV1, SSL_HIGH, 128, 128, "camelia_128_sha"},
2974     {"rsa_des_56_sha", TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA, "EXP1024-DES-CBC-SHA", SSL_kRSA|SSL_aRSA|SSL_DES|SSL_SHA1, TLSV1, SSL_EXPORT56, 56, 56, NULL},
2975     {"rsa_rc4_56_sha", TLS_RSA_EXPORT1024_WITH_RC4_56_SHA, "EXP1024-RC4-SHA", SSL_kRSA|SSL_aRSA|SSL_RC4|SSL_SHA1, TLSV1, SSL_EXPORT56, 56, 128, NULL},
2976     {"camellia_256_sha", TLS_RSA_WITH_CAMELLIA_256_CBC_SHA, "CAMELLIA256-SHA", SSL_kRSA|SSL_aRSA|SSL_CAMELLIA256|SSL_SHA1, TLSV1, SSL_HIGH, 256, 256, "camelia_256_sha"},
2977 //#ifdef ENABLE_GCM
2978     {"rsa_aes_128_gcm_sha_256", TLS_RSA_WITH_AES_128_GCM_SHA256, "AES128-GCM-SHA256", SSL_kRSA|SSL_aRSA|SSL_AES128GCM|SSL_AEAD, TLSV1_2, SSL_HIGH, 128, 128, NULL},
2979 //#endif
2980 //#ifdef ENABLE_SHA384
2981     {"rsa_aes_256_gcm_sha_384", TLS_RSA_WITH_AES_256_GCM_SHA384, "AES256-GCM-SHA384", SSL_kRSA|SSL_aRSA|SSL_AES256GCM|SSL_AEAD, TLSV1_2, SSL_HIGH, 256, 256, NULL},
2982 //#endif
2983     {"fips_3des_sha", SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA, "FIPS-DES-CBC3-SHA", SSL_kRSA|SSL_aRSA|SSL_3DES|SSL_SHA1, SSLV3, SSL_MEDIUM, 112, 168, NULL},
2984     {"fips_des_sha", SSL_RSA_FIPS_WITH_DES_CBC_SHA, "FIPS-DES-CBC-SHA", SSL_kRSA|SSL_aRSA|SSL_DES|SSL_SHA1, SSLV3, SSL_LOW, 56, 56, NULL},
2985 //#ifdef ENABLE_SERVER_DHE
2986     {"dhe_rsa_3des_sha", TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA, "DHE-RSA-DES-CBC3-SHA", SSL_kDHE|SSL_aRSA|SSL_3DES|SSL_SHA1, TLSV1, SSL_MEDIUM, 112, 168, NULL},
2987     {"dhe_rsa_aes_128_sha", TLS_DHE_RSA_WITH_AES_128_CBC_SHA, "DHE-RSA-AES128-SHA", SSL_kDHE|SSL_aRSA|SSL_AES128|SSL_SHA1, TLSV1, SSL_HIGH, 128, 128, NULL},
2988     {"dhe_rsa_aes_256_sha", TLS_DHE_RSA_WITH_AES_256_CBC_SHA, "DHE-RSA-AES256-SHA", SSL_kDHE|SSL_aRSA|SSL_AES256|SSL_SHA1, TLSV1, SSL_HIGH, 256, 256, NULL},
2989     {"dhe_rsa_camellia_128_sha", TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA, "DHE-RSA-CAMELLIA128-SHA", SSL_kDHE|SSL_aRSA|SSL_CAMELLIA128|SSL_SHA1, TLSV1, SSL_HIGH, 128, 128, NULL},
2990     {"dhe_rsa_camellia_256_sha", TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA, "DHE-RSA-CAMELLIA256-SHA", SSL_kDHE|SSL_aRSA|SSL_CAMELLIA256|SSL_SHA1, TLSV1, SSL_HIGH, 256, 256, NULL},
2991     {"dhe_rsa_aes_128_sha_256", TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, "DHE-RSA-AES128-SHA256", SSL_kDHE|SSL_aRSA|SSL_AES128|SSL_SHA256, TLSV1_2, SSL_HIGH, 128, 128, "dhe_rsa_aes_128_sha256"},
2992     {"dhe_rsa_aes_256_sha_256", TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, "DHE-RSA-AES256-SHA256", SSL_kDHE|SSL_aRSA|SSL_AES256|SSL_SHA256, TLSV1_2, SSL_HIGH, 256, 256, "dhe_rsa_aes_256_sha256"},
2993 //#ifdef ENABLE_GCM
2994     {"dhe_rsa_aes_128_gcm_sha_256", TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, "DHE-RSA-AES128-GCM-SHA256", SSL_kDHE|SSL_aRSA|SSL_AES128GCM|SSL_AEAD, TLSV1_2, SSL_HIGH, 128, 128, NULL},
2995 //#endif
2996 //#ifdef ENABLE_SHA384
2997     {"dhe_rsa_aes_256_gcm_sha_384", TLS_DHE_RSA_WITH_AES_256_GCM_SHA384, "DHE-RSA-AES256-GCM-SHA384", SSL_kDHE|SSL_aRSA|SSL_AES256GCM|SSL_AEAD, TLSV1_2, SSL_HIGH, 256, 256, NULL},
2998 //#endif
2999 //#endif /* ENABLE_SERVER_DHE */
3000 //#ifdef NSS_ENABLE_ECC
3001     {"ecdh_ecdsa_null_sha", TLS_ECDH_ECDSA_WITH_NULL_SHA, "ECDH-ECDSA-NULL-SHA", SSL_kECDHE|SSL_AECDH|SSL_eNULL|SSL_SHA1, TLSV1, SSL_STRONG_NONE, 0, 0, NULL},
3002     {"ecdh_ecdsa_rc4_128_sha", TLS_ECDH_ECDSA_WITH_RC4_128_SHA, "ECDH-ECDSA-RC4-SHA", SSL_kECDHE|SSL_AECDH|SSL_RC4|SSL_SHA1, TLSV1, SSL_MEDIUM, 128, 128, NULL},
3003     {"ecdh_ecdsa_3des_sha", TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, "ECDH-ECDSA-DES-CBC3-SHA", SSL_kECDHE|SSL_AECDH|SSL_3DES|SSL_SHA1, TLSV1, SSL_MEDIUM, 112, 168, NULL},
3004     {"ecdh_ecdsa_aes_128_sha", TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, "ECDH-ECDSA-AES128-SHA", SSL_kECDHE|SSL_AECDH|SSL_AES128|SSL_SHA1, TLSV1, SSL_HIGH, 128, 128, NULL},
3005     {"ecdh_ecdsa_aes_256_sha", TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, "ECDH-ECDSA-AES256-SHA", SSL_kECDHE|SSL_AECDH|SSL_AES256|SSL_SHA1, TLSV1, SSL_HIGH, 256, 256, NULL},
3006     {"ecdhe_ecdsa_null_sha", TLS_ECDHE_ECDSA_WITH_NULL_SHA, "ECDHE-ECDSA-NULL-SHA", SSL_kEECDH|SSL_aECDSA|SSL_eNULL|SSL_SHA1, TLSV1, SSL_STRONG_NONE, 0, 0, NULL},
3007     {"ecdhe_ecdsa_rc4_128_sha", TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, "ECDHE-ECDSA-RC4-SHA", SSL_kEECDH|SSL_aECDSA|SSL_RC4|SSL_SHA1, TLSV1, SSL_MEDIUM, 128, 128, NULL},
3008     {"ecdhe_ecdsa_3des_sha", TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, "ECDHE-ECDSA-DES-CBC3-SHA", SSL_kEECDH|SSL_aECDSA|SSL_3DES|SSL_SHA1, TLSV1, SSL_MEDIUM, 112, 168, NULL},
3009     {"ecdhe_ecdsa_aes_128_sha", TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, "ECDHE-ECDSA-AES128-SHA", SSL_kEECDH|SSL_aECDSA|SSL_AES128|SSL_SHA1, TLSV1, SSL_HIGH, 128, 128, NULL},
3010     {"ecdhe_ecdsa_aes_256_sha", TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, "ECDHE-ECDSA-AES256-SHA", SSL_kEECDH|SSL_aECDSA|SSL_AES256|SSL_SHA1, TLSV1, SSL_HIGH, 256, 256, NULL},
3011     {"ecdh_rsa_null_sha", TLS_ECDH_RSA_WITH_NULL_SHA, "ECDH-RSA-NULL-SHA", SSL_kECDHr|SSL_AECDH|SSL_eNULL|SSL_SHA1, TLSV1, SSL_STRONG_NONE, 0, 0, NULL},
3012     {"ecdh_rsa_128_sha", TLS_ECDH_RSA_WITH_RC4_128_SHA, "ECDH-RSA-RC4-SHA", SSL_kECDHr|SSL_AECDH|SSL_RC4|SSL_SHA1, TLSV1, SSL_MEDIUM, 128, 128, NULL},
3013     {"ecdh_rsa_3des_sha", TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, "ECDH-RSA-DES-CBC3-SHA", SSL_kECDHr|SSL_AECDH|SSL_3DES|SSL_SHA1, TLSV1, SSL_MEDIUM, 112, 168, NULL},
3014     {"ecdh_rsa_aes_128_sha", TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, "ECDH-RSA-AES128-SHA", SSL_kECDHr|SSL_AECDH|SSL_AES128|SSL_SHA1, TLSV1, SSL_HIGH, 128, 128, NULL},
3015     {"ecdh_rsa_aes_256_sha", TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, "ECDH-RSA-AES256-SHA", SSL_kECDHr|SSL_AECDH|SSL_AES256|SSL_SHA1, TLSV1, SSL_HIGH, 256, 256, NULL},
3016     {"ecdhe_rsa_null", TLS_ECDHE_RSA_WITH_NULL_SHA, "ECDHE-RSA-NULL-SHA", SSL_kEECDH|SSL_aRSA|SSL_eNULL|SSL_SHA1, TLSV1, SSL_STRONG_NONE, 0, 0, NULL},
3017     {"ecdhe_rsa_rc4_128_sha", TLS_ECDHE_RSA_WITH_RC4_128_SHA, "ECDHE-RSA-RC4-SHA", SSL_kEECDH|SSL_aRSA|SSL_RC4|SSL_SHA1, TLSV1, SSL_MEDIUM, 128, 128, NULL},
3018     {"ecdhe_rsa_3des_sha", TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, "ECDHE-RSA-DES-CBC3-SHA", SSL_kEECDH|SSL_aRSA|SSL_3DES|SSL_SHA1, TLSV1, SSL_MEDIUM, 112, 168, NULL},
3019     {"ecdhe_rsa_aes_128_sha", TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, "ECDHE-RSA-AES128-SHA", SSL_kEECDH|SSL_aRSA|SSL_AES128|SSL_SHA1, TLSV1, SSL_HIGH, 128, 128, NULL},
3020     {"ecdhe_rsa_aes_256_sha", TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, "ECDHE-RSA-AES256-SHA", SSL_kEECDH|SSL_aRSA|SSL_AES256|SSL_SHA1, TLSV1, SSL_HIGH, 256, 256, NULL},
3021     {"ecdh_anon_null_sha", TLS_ECDH_anon_WITH_NULL_SHA, "AECDH-NULL-SHA", SSL_kEECDH|SSL_aNULL|SSL_eNULL|SSL_SHA1, TLSV1, SSL_STRONG_NONE, 0, 0, NULL},
3022     {"ecdh_anon_rc4_128sha", TLS_ECDH_anon_WITH_RC4_128_SHA, "AECDH-RC4-SHA", SSL_kEECDH|SSL_aNULL|SSL_RC4|SSL_SHA1, TLSV1, SSL_MEDIUM, 128, 128, NULL},
3023     {"ecdh_anon_3des_sha", TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA, "AECDH-DES-CBC3-SHA", SSL_kEECDH|SSL_aNULL|SSL_3DES|SSL_SHA1, TLSV1, SSL_MEDIUM, 112, 168, NULL},
3024     {"ecdh_anon_aes_128_sha", TLS_ECDH_anon_WITH_AES_128_CBC_SHA, "AECDH-AES128-SHA", SSL_kEECDH|SSL_aNULL|SSL_AES128|SSL_SHA1, TLSV1, SSL_HIGH, 128, 128, NULL},
3025     {"ecdh_anon_aes_256_sha", TLS_ECDH_anon_WITH_AES_256_CBC_SHA, "AECDH-AES256-SHA", SSL_kEECDH|SSL_aNULL|SSL_AES256|SSL_SHA1, TLSV1, SSL_HIGH, 256, 256, NULL},
3026     {"ecdhe_ecdsa_aes_128_sha_256", TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, "ECDHE-ECDSA-AES128-SHA256", SSL_kEECDH|SSL_aECDSA|SSL_AES128|SSL_SHA256, TLSV1_2, SSL_HIGH, 128, 128, NULL},
3027     {"ecdhe_rsa_aes_128_sha_256", TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, "ECDHE-RSA-AES128-SHA256", SSL_kEECDH|SSL_aRSA|SSL_AES128|SSL_SHA256, TLSV1_2, SSL_HIGH, 128, 128, NULL},
3028 //#ifdef ENABLE_GCM
3029     {"ecdhe_ecdsa_aes_128_gcm_sha_256", TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, "ECDHE-ECDSA-AES128-GCM-SHA256", SSL_kEECDH|SSL_aECDSA|SSL_AES128GCM|SSL_AEAD, TLSV1_2, SSL_HIGH, 128, 128, NULL},
3030 //#endif
3031 //#ifdef ENABLE_SHA384
3032     {"ecdhe_ecdsa_aes_256_sha_384", TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, "ECDHE-ECDSA-AES256-SHA384", SSL_kEECDH|SSL_aECDSA|SSL_AES256|SSL_SHA384, TLSV1_2, SSL_HIGH, 256, 256, NULL},
3033     {"ecdhe_rsa_aes_256_sha_384", TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, "ECDHE-RSA-AES256-SHA384", SSL_kEECDH|SSL_aRSA|SSL_AES256|SSL_SHA384, TLSV1_2, SSL_HIGH, 256, 256, NULL},
3034     {"ecdhe_ecdsa_aes_256_gcm_sha_384", TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, "ECDHE-ECDSA-AES256-GCM-SHA384", SSL_kEECDH|SSL_aECDSA|SSL_AES256GCM|SSL_AEAD, TLSV1_2, SSL_HIGH, 256, 256, NULL},
3035     {"ecdhe_rsa_aes_256_gcm_sha_384", TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, "ECDHE-RSA-AES256-GCM-SHA384", SSL_kEECDH|SSL_aRSA|SSL_AES256GCM|SSL_AEAD, TLSV1_2, SSL_HIGH, 256, 256, NULL},
3036 //#endif
3037 //#ifdef ENABLE_GCM
3038     {"ecdhe_rsa_aes_128_gcm_sha_256", TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, "ECDHE-RSA-AES128-GCM-SHA256", SSL_kEECDH|SSL_aRSA|SSL_AES128GCM|SSL_AEAD, TLSV1_2, SSL_HIGH, 128, 128, NULL},
3039 //#endif
3040     /* TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 is not implemented */
3041     /* TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 is not implemented */
3042     /* TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 is not implemented */
3043     /* TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 is not implemented */
3044 //#endif
3045 //#ifdef ENABLE_CHACHA20
3046     {"ecdhe_rsa_chacha20_poly1305_sha_256", TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, "ECDHE-RSA-CHACHA20-POLY1305", SSL_kEECDH|SSL_aRSA|SSL_CHACHA20POLY1305|SSL_AEAD, TLSV1_2, SSL_HIGH, 256, 256, NULL},
3047     {"ecdhe_ecdsa_chacha20_poly1305_sha_256", TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, "ECDHE-ECDSA-CHACHA20-POLY1305", SSL_kEECDH|SSL_aECDSA|SSL_CHACHA20POLY1305|SSL_AEAD, TLSV1_2, SSL_HIGH, 256, 256, NULL},
3048     {"dhe_rsa_chacha20_poly1305_sha_256", TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256, "DHE-RSA-CHACHA20-POLY1305", SSL_kDHE|SSL_aRSA|SSL_CHACHA20POLY1305|SSL_AEAD, TLSV1_2, SSL_HIGH, 256, 256, NULL},
3049 //#endif
3050 //#ifdef NSS_SUPPORTS_TLS_1_3
3051   #ifdef TLS_AES_128_GCM_SHA256
3052     /* Special TLS 1.3 cipher suites that really just specify AEAD
3053      * TLS 1.3 ciphers don't specify key exchange and authentication.
3054      */
3055     {"aes_128_gcm_sha_256", TLS_AES_128_GCM_SHA256, "TLS-AES-128-GCM-SHA256", SSL_AES128GCM|SSL_AEAD, TLSV1_3, SSL_HIGH, 128, 128, NULL},
3056     {"aes_256_gcm_sha_384", TLS_AES_256_GCM_SHA384, "TLS-AES-256-GCM-SHA384", SSL_AES256GCM|SSL_AEAD, TLSV1_3, SSL_HIGH, 256, 256, NULL},
3057     {"chacha20_poly1305_sha_256", TLS_CHACHA20_POLY1305_SHA256, "TLS-CHACHA20-POLY1305_SHA256", SSL_CHACHA20POLY1305|SSL_AEAD, TLSV1_3, SSL_HIGH, 256, 256, NULL},
3058   #endif
3059 //#endif
3060 };
3061 
3062 #define CIPHERNUM sizeof(ciphers_def) / sizeof(cipher_properties)
3063 //static const int ciphernum = CIPHERNUM;
3064 #define ciphernum ((int)(CIPHERNUM))
3065 
3066 /* Some ciphers are optionally enabled in OpenSSL. For safety sake assume
3067  * they are not available.
3068  */
3069 static const int skip_ciphers = 4;
3070 static const int ciphers_not_in_openssl[] = {
3071     SSL_RSA_FIPS_WITH_DES_CBC_SHA,
3072     SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA,
3073     TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA,
3074     TLS_RSA_EXPORT1024_WITH_RC4_56_SHA,
3075 };
3076 
3077 static int parse_nss_ciphers(server_rec *s, char *ciphers, PRBool cipher_list[ciphernum]);
3078 static int parse_openssl_ciphers(server_rec *s, char *ciphers, PRBool cipher_list[ciphernum]);
3079 
3080 static
countciphers(PRBool cipher_state[ciphernum],int version)3081 int countciphers(PRBool cipher_state[ciphernum], int version) {
3082     int ciphercount = 0;
3083     int i = 0;
3084 
3085     for (i = 0; i < ciphernum; i++)
3086     {
3087         if ((cipher_state[i] == PR_TRUE) &&
3088             (ciphers_def[i].version & version)) {
3089             ciphercount++;
3090         }
3091     }
3092 
3093     return ciphercount;
3094 }
3095 
3096 
3097 static
nss_parse_ciphers(server_rec * s,char * ciphers,PRBool cipher_list[ciphernum])3098 int nss_parse_ciphers(server_rec *s, char *ciphers, PRBool cipher_list[ciphernum])
3099 {
3100     UNUSED(s);
3101     int rv = 0;
3102 
3103     /* If the string has a colon we use the OpenSSL style. If it has a
3104      * comma then NSS. If it has neither we try both. */
3105     if (strchr(ciphers, ':')) {
3106         rv = parse_openssl_ciphers(s, ciphers, cipher_list);
3107     } else if (strchr(ciphers, ',')) {
3108         rv = parse_nss_ciphers(s, ciphers, cipher_list);
3109     } else {
3110         rv = parse_openssl_ciphers(s, ciphers, cipher_list);
3111         if (rv == 0 && 0 == countciphers(cipher_list, SSLV3|TLSV1|TLSV1_2|TLSV1_3)) {
3112             rv = parse_nss_ciphers(s, ciphers, cipher_list);
3113         }
3114     }
3115     if (0 == countciphers(cipher_list, SSLV3|TLSV1|TLSV1_2|TLSV1_3)) {
3116         ap_log_error(APLOG_MARK, APLOG_INFO, 0, s,
3117                      "no cipher match");
3118     }
3119 
3120     return rv;
3121 }
3122 
3123 
3124 /* Given a set of ciphers perform a given action on the indexed value.
3125  *
3126  * This is needed because the + action doesn't do anything in the NSS
3127  * context. In OpenSSL it will re-order the cipher list.
3128  */
set_cipher_value(PRBool cipher_list[ciphernum],int index,int action)3129 static void set_cipher_value(PRBool cipher_list[ciphernum], int index, int action)
3130 {
3131     int i;
3132 
3133     if (action == REORDER_CIPHER)
3134         /* NSS doesn't allow ordering so do nothing */
3135         return;
3136 
3137     for (i = 0; i < skip_ciphers; i++) {
3138         if (ciphers_def[index].num == ciphers_not_in_openssl[i]) {
3139             cipher_list[index] = PERMANENTLY_DISABLE_CIPHER;
3140             return;
3141         }
3142     }
3143 
3144     if (cipher_list[index] != PERMANENTLY_DISABLE_CIPHER)
3145         cipher_list[index] = action;
3146 }
3147 
3148 
parse_openssl_ciphers(server_rec * s,char * ciphers,PRBool cipher_list[ciphernum])3149 static int parse_openssl_ciphers(server_rec *s, char *ciphers, PRBool cipher_list[ciphernum])
3150 {
3151     UNUSED(s);
3152     char * cipher;
3153     int i, action;
3154     PRBool merge = PR_FALSE;
3155     PRBool found = PR_FALSE;
3156     PRBool first = PR_TRUE;
3157 
3158     cipher = ciphers;
3159     while (ciphers && (strlen(ciphers)))
3160     {
3161         while ((*cipher) && (isspace(*(uint8_t *)cipher)))
3162             ++cipher;
3163 
3164         action = ENABLE_CIPHER; /* default to enable */
3165         switch(*cipher)
3166         {
3167             case '+':
3168                 /* Cipher ordering is not supported in NSS */
3169                 action = REORDER_CIPHER;
3170                 cipher++;
3171                 break;
3172             case '-':
3173                 action = SUBTRACT_CIPHER;
3174                 cipher++;
3175                 break;
3176             case '!':
3177                 action = PERMANENTLY_DISABLE_CIPHER;
3178                 cipher++;
3179                 break;
3180             default:
3181                 /* Add the cipher */
3182                 break;
3183         }
3184 
3185         if ((ciphers = strchr(cipher, ':'))) {
3186             *ciphers++ = '\0';
3187             merge = PR_FALSE;
3188             found = PR_FALSE;
3189         }
3190 
3191         if (!strcmp(cipher, "ALL")) {
3192             found = PR_TRUE;
3193             for (i=0; i<ciphernum; i++) {
3194                 if (!(ciphers_def[i].attr & SSL_eNULL))
3195                     set_cipher_value(cipher_list, i, action);
3196             }
3197         } else if (!strcmp(cipher, "COMPLEMENTOFALL")) {
3198             found = PR_TRUE;
3199             for (i=0; i<ciphernum; i++) {
3200                 if ((ciphers_def[i].attr & SSL_eNULL))
3201                     set_cipher_value(cipher_list, i, action);
3202             }
3203         } else if (!strcmp(cipher, "DEFAULT")) {
3204             /* In OpenSSL the default cipher list is
3205              *    ALL:!aNULL:!eNULL:!SSLv2
3206              * So we need to disable all the NULL ciphers too.
3207              */
3208             int mask = SSL_aNULL | SSL_eNULL;
3209             found = PR_TRUE;
3210             for (i=0; i < ciphernum; i++) {
3211                 if (cipher_list[i] != PERMANENTLY_DISABLE_CIPHER)
3212                     SSL_CipherPrefGetDefault(ciphers_def[i].num,
3213                                              &cipher_list[i]);
3214                 if (PR_TRUE == first) {
3215                     if (ciphers_def[i].attr & mask) {
3216                         set_cipher_value(cipher_list, i,
3217                                          PERMANENTLY_DISABLE_CIPHER);
3218                     }
3219                 }
3220             }
3221         } else if (!strcmp(cipher, "COMPLEMENTOFDEFAULT")) {
3222             found = PR_TRUE;
3223             /* no-op. In OpenSSL this is the ADH ciphers */
3224         } else if (!strcmp(cipher, "@STRENGTH")) {
3225             /* No cipher ordering in NSS */
3226             ap_log_error(APLOG_MARK, APLOG_INFO, 0, s,
3227                          "Cipher ordering is not supported in NSS");
3228             return -1;
3229         } else {
3230             int amask = 0;
3231             int amaskaction = 0;
3232             int mask = 0;
3233             int strength = 0;
3234             int protocol = 0;
3235             char *c;
3236             PRBool candidate_list[ciphernum];
3237             PRBool temp_list[ciphernum];
3238 
3239             for (i = 0; i < ciphernum; i++) {
3240                 candidate_list[i] = 1;
3241             }
3242 
3243             c = cipher;
3244             while (c && (strlen(c))) {
3245                 amask = 0;
3246                 amaskaction = 0;
3247                 mask = 0;
3248                 strength = 0;
3249                 protocol = 0;
3250                 for (i = 0; i < ciphernum; i++) {
3251                     temp_list[i] = 0;
3252                 }
3253 
3254                 if ((c = strchr(cipher, '+'))) {
3255                     *c++ = '\0';
3256                 }
3257 
3258                 if (!strcmp(cipher, "RSA")) {
3259                     mask |= SSL_RSA;
3260                 } else if (!strcmp(cipher, "kRSA")) {
3261                     mask |= SSL_kRSA;
3262                 } else if (!strcmp(cipher, "aRSA")) {
3263                     mask |= SSL_aRSA;
3264                 } else if (!strcmp(cipher, "EDH")) {
3265                     /* Normally this is kEDH:-ADH but since we don't
3266                      * support ADH this is sufficient.
3267                      */
3268                     mask |= SSL_kEDH;
3269                 } else if (!strcmp(cipher, "DH")) {
3270                     /* non-ephemeral DH. The ciphers are defined
3271                      * but not implemented in OpenSSL so manage
3272                      * this here.
3273                      */
3274                     mask |= SSL_kDHE;
3275 #if 0
3276                 } else if (!strcmp(cipher, "ADH")) {
3277                     mask |= SSL_ADH;
3278 #endif
3279                 } else if (!strcmp(cipher, "ECDH")) {
3280                     mask |= SSL_ECDH;
3281                 } else if (!strcmp(cipher, "EECDH")) {
3282                     mask |= SSL_kEECDH;
3283                     amask = SSL_aNULL;
3284                     amaskaction = 1; /* filter anonymous out */
3285                 } else if (!strcmp(cipher, "AECDH")) {
3286                     mask |= SSL_kEECDH;
3287                     amask = SSL_aNULL; /* require anonymous */
3288                     amaskaction = 0; /* keep these */
3289                 } else if (!strcmp(cipher, "kECDH")) {
3290                     mask |= SSL_kECDHE | SSL_kECDHr;
3291                 } else if (!strcmp(cipher, "kECDHE")) {
3292                     mask |= SSL_kECDHE;
3293                 } else if (!strcmp(cipher, "kECDHr")) {
3294                     mask |= SSL_kECDHr;
3295                 } else if (!strcmp(cipher, "kEECDH")) {
3296                     mask |= SSL_kEECDH;
3297                 } else if (!strcmp(cipher, "AECDH")) {
3298                     mask |= SSL_AECDH;
3299                 } else if (!strcmp(cipher, "ECDSA")) {
3300                     mask |= SSL_aECDSA;
3301                 } else if (!strcmp(cipher, "aECDSA")) {
3302                     mask |= SSL_aECDSA;
3303                 } else if ((!strcmp(cipher, "NULL")) || (!strcmp(cipher, "eNULL"))) {
3304                     mask |= SSL_eNULL;
3305                 } else if (!strcmp(cipher, "aNULL")) {
3306                     mask |= SSL_aNULL;
3307                 } else if (!strcmp(cipher, "AES")) {
3308                     mask |= SSL_AES;
3309                 } else if (!strcmp(cipher, "AESGCM")) {
3310                     mask |= SSL_AES128GCM|SSL_AES256GCM;
3311                 } else if (!strcmp(cipher, "AES128")) {
3312                     mask |= SSL_AES128|SSL_AES128GCM;
3313                 } else if (!strcmp(cipher, "AES256")) {
3314                     mask |= SSL_AES256|SSL_AES256GCM;
3315                 } else if (!strcmp(cipher, "CHACHA20")) {
3316                     mask |= SSL_CHACHA20POLY1305;
3317                 } else if (!strcmp(cipher, "CAMELLIA")) {
3318                     mask |= SSL_CAMELLIA128|SSL_CAMELLIA256;
3319                 } else if (!strcmp(cipher, "CAMELLIA128")) {
3320                     mask |= SSL_CAMELLIA128;
3321                 } else if (!strcmp(cipher, "CAMELLIA256")) {
3322                     mask |= SSL_CAMELLIA256;
3323                 } else if (!strcmp(cipher, "3DES")) {
3324                     mask |= SSL_3DES;
3325                 } else if (!strcmp(cipher, "DES")) {
3326                     mask |= SSL_DES;
3327                 } else if (!strcmp(cipher, "RC4")) {
3328                     mask |= SSL_RC4;
3329                 } else if (!strcmp(cipher, "RC2")) {
3330                     mask |= SSL_RC2;
3331                 } else if (!strcmp(cipher, "MD5")) {
3332                     mask |= SSL_MD5;
3333                 } else if ((!strcmp(cipher, "SHA")) || (!strcmp(cipher, "SHA1"))) {
3334                     mask |= SSL_SHA1;
3335                 } else if (!strcmp(cipher, "SHA256")) {
3336                     mask |= SSL_SHA256;
3337                 } else if (!strcmp(cipher, "SHA384")) {
3338                     mask |= SSL_SHA384;
3339                 } else if (!strcmp(cipher, "SSLv2")) {
3340                     /* no-op */
3341                 } else if (!strcmp(cipher, "SSLv3")) {
3342                     protocol |= SSLV3;
3343                 } else if (!strcmp(cipher, "TLSv1")) {
3344                     protocol |= TLSV1;
3345                 } else if (!strcmp(cipher, "TLSv1.2")) {
3346                     protocol |= TLSV1_2;
3347                 } else if (!strcmp(cipher, "TLSv1.3")) {
3348                     protocol |= TLSV1_3;
3349                 } else if (!strcmp(cipher, "HIGH")) {
3350                     strength |= SSL_HIGH;
3351                 } else if (!strcmp(cipher, "MEDIUM")) {
3352                     strength |= SSL_MEDIUM;
3353                 } else if (!strcmp(cipher, "LOW")) {
3354                     strength |= SSL_LOW;
3355                 } else if ((!strcmp(cipher, "EXPORT")) || (!strcmp(cipher, "EXP"))) {
3356                     strength |= SSL_EXPORT40|SSL_EXPORT56;
3357                 } else if (!strcmp(cipher, "EXPORT40")) {
3358                     strength |= SSL_EXPORT40;
3359                 } else if (!strcmp(cipher, "EXPORT56")) {
3360                     strength |= SSL_EXPORT56;
3361                 }
3362 
3363                 if (c)
3364                     cipher = c;
3365 
3366                 /* If we have a mask, apply it. If not then perhaps they
3367                  * provided a specific cipher to enable.
3368                  */
3369                 if (mask || strength || protocol) {
3370                     merge = PR_TRUE;
3371                     found = PR_TRUE;
3372                     for (i=0; i<ciphernum; i++) {
3373                         if (((ciphers_def[i].attr & mask) ||
3374                          (ciphers_def[i].strength & strength) ||
3375                          (ciphers_def[i].version & protocol)) &&
3376                          (cipher_list[i] != PERMANENTLY_DISABLE_CIPHER)) {
3377                             if (amask != 0) {
3378                                 PRBool match = PR_FALSE;
3379                                 if (ciphers_def[i].attr & amask) {
3380                                     match = PR_TRUE;
3381                                 }
3382                                 if (amaskaction && match)
3383                                     continue;
3384                                 if (!amaskaction && !match)
3385                                     continue;
3386                             }
3387 #if 0
3388                             /* Enable the NULL ciphers only if explicity
3389                              * requested */
3390                             if (ciphers_def[i].attr & SSL_eNULL) {
3391                                 if (mask & SSL_eNULL)
3392                                     temp_list[i] = 1;
3393                             } else
3394 #endif
3395                                 temp_list[i] = 1;
3396                             }
3397                     }
3398                     /* Merge the temp list into the candidate list */
3399                     for (i=0; i<ciphernum; i++) {
3400                         if (!(candidate_list[i] & temp_list[i])) {
3401                             candidate_list[i] = 0;
3402                         }
3403                     }
3404                 } else if (!strcmp(cipher, "FIPS")) {
3405                         SSLCipherSuiteInfo suite;
3406                     for (i=0; i<ciphernum;i++) {
3407                         if (SSL_GetCipherSuiteInfo(ciphers_def[i].num,
3408                             &suite, sizeof suite) == SECSuccess) {
3409                             if (suite.isFIPS)
3410                                 set_cipher_value(cipher_list, i, action);
3411                         }
3412                     }
3413                 } else {
3414                     for (i=0; i<ciphernum; i++) {
3415                         if (!strcmp(ciphers_def[i].openssl_name, cipher))
3416                             set_cipher_value(cipher_list, i, action);
3417                     }
3418                 }
3419             } /* while */
3420             if (PR_TRUE == merge) {
3421                 first = PR_FALSE;
3422                 /* Merge the candidate list into the cipher list */
3423                 for (i=0; i<ciphernum; i++) {
3424                     if (candidate_list[i])
3425                         set_cipher_value(cipher_list, i, action);
3426                 }
3427                 merge = PR_FALSE;
3428                 found = PR_FALSE;
3429             }
3430         }
3431 
3432         if (ciphers)
3433             cipher = ciphers;
3434 
3435     }
3436     if (found && 0 == countciphers(cipher_list, SSLV3|TLSV1|TLSV1_2|TLSV1_3))
3437         return 1; /* no matching ciphers */
3438     return 0;
3439 }
3440 
3441 
parse_nss_ciphers(server_rec * s,char * ciphers,PRBool cipher_list[ciphernum])3442 static int parse_nss_ciphers(server_rec *s, char *ciphers, PRBool cipher_list[ciphernum])
3443 {
3444     UNUSED(s);
3445     char * cipher;
3446     PRBool found;
3447     int i, active;
3448 
3449     cipher = ciphers;
3450 
3451     while (ciphers && (strlen(ciphers)))
3452     {
3453         while ((*cipher) && (isspace(*(uint8_t *)cipher)))
3454            ++cipher;
3455 
3456         switch(*cipher++)
3457         {
3458             case '+':
3459                 active = PR_TRUE;
3460                 break;
3461             case '-':
3462                 active = PR_FALSE;
3463                 break;
3464             default:
3465                 ap_log_error(APLOG_MARK, APLOG_INFO, 0, s,
3466                              "invalid cipher string %s. Format is +cipher1,-cipher2...", cipher - 1);
3467             return -1;
3468         }
3469 
3470         if ((ciphers = strchr(cipher, ','))) {
3471             *ciphers++ = '\0';
3472         }
3473 
3474         found = PR_FALSE;
3475 
3476         for (i = 0; i < ciphernum; i++)
3477         {
3478             if (!strcasecmp(cipher, ciphers_def[i].name))
3479             {
3480                 cipher_list[i] = active;
3481                 found = PR_TRUE;
3482                 break;
3483             } else if ((ciphers_def[i].alias != NULL) &&
3484                 (!strcasecmp(cipher, ciphers_def[i].alias)))
3485             {
3486                 cipher_list[i] = active;
3487                 found = PR_TRUE;
3488                 ap_log_error(APLOG_MARK, APLOG_INFO, 0, s,
3489                              "Deprecated cipher name %s, use %s instead.",
3490                              cipher, ciphers_def[i].name);
3491                 break;
3492             }
3493         }
3494 
3495         if (found == PR_FALSE) {
3496             ap_log_error(APLOG_MARK, APLOG_INFO, 0, s,
3497                          "Unknown cipher %s\n", cipher);
3498         }
3499 
3500         if (ciphers) {
3501             cipher = ciphers;
3502         }
3503     }
3504 
3505     return 0;
3506 }
3507 
3508 
3509 static int
mod_nss_ssl_conf_ciphersuites(server * srv,plugin_config_socket * s,buffer * ciphersuites,const buffer * cipherstring)3510 mod_nss_ssl_conf_ciphersuites (server *srv, plugin_config_socket *s, buffer *ciphersuites, const buffer *cipherstring)
3511 {
3512     if (ciphersuites)
3513         /* XXX: not implemented;
3514          *      could manually add support for short list of TLSv1.3 suites */
3515         log_error(srv->errh, __FILE__, __LINE__,
3516                   "Ciphersuite support not implemented for %s",
3517                   ciphersuites->ptr);
3518 
3519     if (!cipherstring || buffer_is_blank(cipherstring))
3520         return 1; /* nothing to do */
3521 
3522     /*
3523      * Apache mod_nss
3524      * https://pagure.io/mod_nss.git
3525      *
3526      * modified from mod_nss/nss_engine_init.c:nss_init_ctx_cipher_suite()
3527      */
3528 
3529     PRBool cipher_state[ciphernum];
3530 
3531     /* Disable all NSS supported cipher suites. This is to prevent any new
3532      * NSS cipher suites from getting automatically and unintentionally
3533      * enabled as a result of the NSS_SetDomesticPolicy() call. This way,
3534      * only the ciphers explicitly specified in the server configuration can
3535      * ever be enabled.
3536      */
3537     for (int i = 0; i < SSL_NumImplementedCiphers; ++i)
3538         SSL_CipherPrefSet(s->model, SSL_ImplementedCiphers[i], SSL_NOT_ALLOWED);
3539 
3540     /* initialize all known ciphers to false */
3541     for (int i = 0; i < ciphernum; ++i)
3542         cipher_state[i] = PR_FALSE;
3543 
3544     char *ciphers = strdup(cipherstring->ptr);/*(string modified during parse)*/
3545     if (NULL == ciphers) return 0;
3546 
3547     int rc = nss_parse_ciphers(srv->errh, ciphers, cipher_state);
3548     free(ciphers);
3549     if (-1 == rc) return 0;
3550 
3551     if (s->protos.min && s->protos.min <= SSL_LIBRARY_VERSION_3_0
3552         && countciphers(cipher_state, SSLV3) == 0) {
3553         ap_log_error(APLOG_MARK, APLOG_ERR, 0, srv->errh,
3554           "NSSCipherSuite: SSL3 is enabled but no SSL3 ciphers are enabled.");
3555         return 0;
3556     }
3557 
3558     if (s->protos.max >= SSL_LIBRARY_VERSION_TLS_1_0
3559         && countciphers(cipher_state, TLSV1|TLSV1_2|TLSV1_3) == 0) {
3560         ap_log_error(APLOG_MARK, APLOG_ERR, 0, srv->errh,
3561           "NSSCipherSuite: TLS is enabled but no TLS ciphers are enabled.");
3562         return 0;
3563     }
3564 
3565     /* Finally actually enable the selected ciphers */
3566     for (int i = 0; i < ciphernum; ++i)
3567         SSL_CipherPrefSet(s->model, ciphers_def[i].num,
3568                           cipher_state[i] == ENABLE_CIPHER
3569                             ? SSL_ALLOWED
3570                             : SSL_NOT_ALLOWED);
3571 
3572     return 1;
3573 }
3574