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