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