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