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