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