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