1/***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al.
9 *
10 * This software is licensed as described in the file COPYING, which
11 * you should have received as part of this distribution. The terms
12 * are also available at https://curl.se/docs/copyright.html.
13 *
14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15 * copies of the Software, and permit persons to whom the Software is
16 * furnished to do so, under the terms of the COPYING file.
17 *
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
20 *
21 ***************************************************************************/
22
23/*
24 * Source file for all NSS-specific code for the TLS/SSL layer. No code
25 * but vtls.c should ever call or use these functions.
26 */
27
28#include "curl_setup.h"
29
30#ifdef USE_NSS
31
32#include "urldata.h"
33#include "sendf.h"
34#include "formdata.h" /* for the boundary function */
35#include "url.h" /* for the ssl config check function */
36#include "connect.h"
37#include "strcase.h"
38#include "select.h"
39#include "vtls.h"
40#include "llist.h"
41#include "multiif.h"
42#include "curl_printf.h"
43#include "nssg.h"
44#include <nspr.h>
45#include <nss.h>
46#include <ssl.h>
47#include <sslerr.h>
48#include <secerr.h>
49#include <secmod.h>
50#include <sslproto.h>
51#include <prtypes.h>
52#include <pk11pub.h>
53#include <prio.h>
54#include <secitem.h>
55#include <secport.h>
56#include <certdb.h>
57#include <base64.h>
58#include <cert.h>
59#include <prerror.h>
60#include <keyhi.h> /* for SECKEY_DestroyPublicKey() */
61#include <private/pprio.h> /* for PR_ImportTCPSocket */
62
63#define NSSVERNUM ((NSS_VMAJOR<<16)|(NSS_VMINOR<<8)|NSS_VPATCH)
64
65#if NSSVERNUM >= 0x030f00 /* 3.15.0 */
66#include <ocsp.h>
67#endif
68
69#include "strcase.h"
70#include "warnless.h"
71#include "x509asn1.h"
72
73/* The last #include files should be: */
74#include "curl_memory.h"
75#include "memdebug.h"
76
77#define SSL_DIR "/etc/pki/nssdb"
78
79/* enough to fit the string "PEM Token #[0|1]" */
80#define SLOTSIZE 13
81
82struct ssl_backend_data {
83 PRFileDesc *handle;
84 char *client_nickname;
85 struct Curl_easy *data;
86 struct Curl_llist obj_list;
87 PK11GenericObject *obj_clicert;
88};
89
90static PRLock *nss_initlock = NULL;
91static PRLock *nss_crllock = NULL;
92static PRLock *nss_findslot_lock = NULL;
93static PRLock *nss_trustload_lock = NULL;
94static struct Curl_llist nss_crl_list;
95static NSSInitContext *nss_context = NULL;
96static volatile int initialized = 0;
97
98/* type used to wrap pointers as list nodes */
99struct ptr_list_wrap {
100 void *ptr;
101 struct Curl_llist_element node;
102};
103
104struct cipher_s {
105 const char *name;
106 int num;
107};
108
109#define PK11_SETATTRS(_attr, _idx, _type, _val, _len) do { \
110 CK_ATTRIBUTE *ptr = (_attr) + ((_idx)++); \
111 ptr->type = (_type); \
112 ptr->pValue = (_val); \
113 ptr->ulValueLen = (_len); \
114} while(0)
115
116#define CERT_NewTempCertificate __CERT_NewTempCertificate
117
118#define NUM_OF_CIPHERS sizeof(cipherlist)/sizeof(cipherlist[0])
119static const struct cipher_s cipherlist[] = {
120 /* SSL2 cipher suites */
121 {"rc4", SSL_EN_RC4_128_WITH_MD5},
122 {"rc4-md5", SSL_EN_RC4_128_WITH_MD5},
123 {"rc4export", SSL_EN_RC4_128_EXPORT40_WITH_MD5},
124 {"rc2", SSL_EN_RC2_128_CBC_WITH_MD5},
125 {"rc2export", SSL_EN_RC2_128_CBC_EXPORT40_WITH_MD5},
126 {"des", SSL_EN_DES_64_CBC_WITH_MD5},
127 {"desede3", SSL_EN_DES_192_EDE3_CBC_WITH_MD5},
128 /* SSL3/TLS cipher suites */
129 {"rsa_rc4_128_md5", SSL_RSA_WITH_RC4_128_MD5},
130 {"rsa_rc4_128_sha", SSL_RSA_WITH_RC4_128_SHA},
131 {"rsa_3des_sha", SSL_RSA_WITH_3DES_EDE_CBC_SHA},
132 {"rsa_des_sha", SSL_RSA_WITH_DES_CBC_SHA},
133 {"rsa_rc4_40_md5", SSL_RSA_EXPORT_WITH_RC4_40_MD5},
134 {"rsa_rc2_40_md5", SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5},
135 {"rsa_null_md5", SSL_RSA_WITH_NULL_MD5},
136 {"rsa_null_sha", SSL_RSA_WITH_NULL_SHA},
137 {"fips_3des_sha", SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA},
138 {"fips_des_sha", SSL_RSA_FIPS_WITH_DES_CBC_SHA},
139 {"fortezza", SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA},
140 {"fortezza_rc4_128_sha", SSL_FORTEZZA_DMS_WITH_RC4_128_SHA},
141 {"fortezza_null", SSL_FORTEZZA_DMS_WITH_NULL_SHA},
142 {"dhe_rsa_3des_sha", SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA},
143 {"dhe_dss_3des_sha", SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA},
144 {"dhe_rsa_des_sha", SSL_DHE_RSA_WITH_DES_CBC_SHA},
145 {"dhe_dss_des_sha", SSL_DHE_DSS_WITH_DES_CBC_SHA},
146 /* TLS 1.0: Exportable 56-bit Cipher Suites. */
147 {"rsa_des_56_sha", TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA},
148 {"rsa_rc4_56_sha", TLS_RSA_EXPORT1024_WITH_RC4_56_SHA},
149 /* Ephemeral DH with RC4 bulk encryption */
150 {"dhe_dss_rc4_128_sha", TLS_DHE_DSS_WITH_RC4_128_SHA},
151 /* AES ciphers. */
152 {"dhe_dss_aes_128_cbc_sha", TLS_DHE_DSS_WITH_AES_128_CBC_SHA},
153 {"dhe_dss_aes_256_cbc_sha", TLS_DHE_DSS_WITH_AES_256_CBC_SHA},
154 {"dhe_rsa_aes_128_cbc_sha", TLS_DHE_RSA_WITH_AES_128_CBC_SHA},
155 {"dhe_rsa_aes_256_cbc_sha", TLS_DHE_RSA_WITH_AES_256_CBC_SHA},
156 {"rsa_aes_128_sha", TLS_RSA_WITH_AES_128_CBC_SHA},
157 {"rsa_aes_256_sha", TLS_RSA_WITH_AES_256_CBC_SHA},
158 /* ECC ciphers. */
159 {"ecdh_ecdsa_null_sha", TLS_ECDH_ECDSA_WITH_NULL_SHA},
160 {"ecdh_ecdsa_rc4_128_sha", TLS_ECDH_ECDSA_WITH_RC4_128_SHA},
161 {"ecdh_ecdsa_3des_sha", TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA},
162 {"ecdh_ecdsa_aes_128_sha", TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA},
163 {"ecdh_ecdsa_aes_256_sha", TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA},
164 {"ecdhe_ecdsa_null_sha", TLS_ECDHE_ECDSA_WITH_NULL_SHA},
165 {"ecdhe_ecdsa_rc4_128_sha", TLS_ECDHE_ECDSA_WITH_RC4_128_SHA},
166 {"ecdhe_ecdsa_3des_sha", TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA},
167 {"ecdhe_ecdsa_aes_128_sha", TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA},
168 {"ecdhe_ecdsa_aes_256_sha", TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA},
169 {"ecdh_rsa_null_sha", TLS_ECDH_RSA_WITH_NULL_SHA},
170 {"ecdh_rsa_128_sha", TLS_ECDH_RSA_WITH_RC4_128_SHA},
171 {"ecdh_rsa_3des_sha", TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA},
172 {"ecdh_rsa_aes_128_sha", TLS_ECDH_RSA_WITH_AES_128_CBC_SHA},
173 {"ecdh_rsa_aes_256_sha", TLS_ECDH_RSA_WITH_AES_256_CBC_SHA},
174 {"ecdhe_rsa_null", TLS_ECDHE_RSA_WITH_NULL_SHA},
175 {"ecdhe_rsa_rc4_128_sha", TLS_ECDHE_RSA_WITH_RC4_128_SHA},
176 {"ecdhe_rsa_3des_sha", TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA},
177 {"ecdhe_rsa_aes_128_sha", TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
178 {"ecdhe_rsa_aes_256_sha", TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA},
179 {"ecdh_anon_null_sha", TLS_ECDH_anon_WITH_NULL_SHA},
180 {"ecdh_anon_rc4_128sha", TLS_ECDH_anon_WITH_RC4_128_SHA},
181 {"ecdh_anon_3des_sha", TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA},
182 {"ecdh_anon_aes_128_sha", TLS_ECDH_anon_WITH_AES_128_CBC_SHA},
183 {"ecdh_anon_aes_256_sha", TLS_ECDH_anon_WITH_AES_256_CBC_SHA},
184#ifdef TLS_RSA_WITH_NULL_SHA256
185 /* new HMAC-SHA256 cipher suites specified in RFC */
186 {"rsa_null_sha_256", TLS_RSA_WITH_NULL_SHA256},
187 {"rsa_aes_128_cbc_sha_256", TLS_RSA_WITH_AES_128_CBC_SHA256},
188 {"rsa_aes_256_cbc_sha_256", TLS_RSA_WITH_AES_256_CBC_SHA256},
189 {"dhe_rsa_aes_128_cbc_sha_256", TLS_DHE_RSA_WITH_AES_128_CBC_SHA256},
190 {"dhe_rsa_aes_256_cbc_sha_256", TLS_DHE_RSA_WITH_AES_256_CBC_SHA256},
191 {"ecdhe_ecdsa_aes_128_cbc_sha_256", TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256},
192 {"ecdhe_rsa_aes_128_cbc_sha_256", TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256},
193#endif
194#ifdef TLS_RSA_WITH_AES_128_GCM_SHA256
195 /* AES GCM cipher suites in RFC 5288 and RFC 5289 */
196 {"rsa_aes_128_gcm_sha_256", TLS_RSA_WITH_AES_128_GCM_SHA256},
197 {"dhe_rsa_aes_128_gcm_sha_256", TLS_DHE_RSA_WITH_AES_128_GCM_SHA256},
198 {"dhe_dss_aes_128_gcm_sha_256", TLS_DHE_DSS_WITH_AES_128_GCM_SHA256},
199 {"ecdhe_ecdsa_aes_128_gcm_sha_256", TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
200 {"ecdh_ecdsa_aes_128_gcm_sha_256", TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256},
201 {"ecdhe_rsa_aes_128_gcm_sha_256", TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
202 {"ecdh_rsa_aes_128_gcm_sha_256", TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256},
203#endif
204#ifdef TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
205 /* cipher suites using SHA384 */
206 {"rsa_aes_256_gcm_sha_384", TLS_RSA_WITH_AES_256_GCM_SHA384},
207 {"dhe_rsa_aes_256_gcm_sha_384", TLS_DHE_RSA_WITH_AES_256_GCM_SHA384},
208 {"dhe_dss_aes_256_gcm_sha_384", TLS_DHE_DSS_WITH_AES_256_GCM_SHA384},
209 {"ecdhe_ecdsa_aes_256_sha_384", TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384},
210 {"ecdhe_rsa_aes_256_sha_384", TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384},
211 {"ecdhe_ecdsa_aes_256_gcm_sha_384", TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384},
212 {"ecdhe_rsa_aes_256_gcm_sha_384", TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384},
213#endif
214#ifdef TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256
215 /* chacha20-poly1305 cipher suites */
216 {"ecdhe_rsa_chacha20_poly1305_sha_256",
217 TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256},
218 {"ecdhe_ecdsa_chacha20_poly1305_sha_256",
219 TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256},
220 {"dhe_rsa_chacha20_poly1305_sha_256",
221 TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256},
222#endif
223#ifdef TLS_AES_256_GCM_SHA384
224 {"aes_128_gcm_sha_256", TLS_AES_128_GCM_SHA256},
225 {"aes_256_gcm_sha_384", TLS_AES_256_GCM_SHA384},
226 {"chacha20_poly1305_sha_256", TLS_CHACHA20_POLY1305_SHA256},
227#endif
228#ifdef TLS_DHE_DSS_WITH_AES_128_CBC_SHA256
229 /* AES CBC cipher suites in RFC 5246. Introduced in NSS release 3.20 */
230 {"dhe_dss_aes_128_sha_256", TLS_DHE_DSS_WITH_AES_128_CBC_SHA256},
231 {"dhe_dss_aes_256_sha_256", TLS_DHE_DSS_WITH_AES_256_CBC_SHA256},
232#endif
233#ifdef TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA
234 /* Camellia cipher suites in RFC 4132/5932.
235 Introduced in NSS release 3.12 */
236 {"dhe_rsa_camellia_128_sha", TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA},
237 {"dhe_dss_camellia_128_sha", TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA},
238 {"dhe_rsa_camellia_256_sha", TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA},
239 {"dhe_dss_camellia_256_sha", TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA},
240 {"rsa_camellia_128_sha", TLS_RSA_WITH_CAMELLIA_128_CBC_SHA},
241 {"rsa_camellia_256_sha", TLS_RSA_WITH_CAMELLIA_256_CBC_SHA},
242#endif
243#ifdef TLS_RSA_WITH_SEED_CBC_SHA
244 /* SEED cipher suite in RFC 4162. Introduced in NSS release 3.12.3 */
245 {"rsa_seed_sha", TLS_RSA_WITH_SEED_CBC_SHA},
246#endif
247};
248
249#if defined(WIN32)
250static const char *pem_library = "nsspem.dll";
251static const char *trust_library = "nssckbi.dll";
252#elif defined(__APPLE__)
253static const char *pem_library = "libnsspem.dylib";
254static const char *trust_library = "libnssckbi.dylib";
255#else
256static const char *pem_library = "libnsspem.so";
257static const char *trust_library = "libnssckbi.so";
258#endif
259
260static SECMODModule *pem_module = NULL;
261static SECMODModule *trust_module = NULL;
262
263/* NSPR I/O layer we use to detect blocking direction during SSL handshake */
264static PRDescIdentity nspr_io_identity = PR_INVALID_IO_LAYER;
265static PRIOMethods nspr_io_methods;
266
267static const char *nss_error_to_name(PRErrorCode code)
268{
269 const char *name = PR_ErrorToName(code);
270 if(name)
271 return name;
272
273 return "unknown error";
274}
275
276static void nss_print_error_message(struct Curl_easy *data, PRUint32 err)
277{
278 failf(data, "%s", PR_ErrorToString(err, PR_LANGUAGE_I_DEFAULT));
279}
280
281static char *nss_sslver_to_name(PRUint16 nssver)
282{
283 switch(nssver) {
284 case SSL_LIBRARY_VERSION_2:
285 return strdup("SSLv2");
286 case SSL_LIBRARY_VERSION_3_0:
287 return strdup("SSLv3");
288 case SSL_LIBRARY_VERSION_TLS_1_0:
289 return strdup("TLSv1.0");
290#ifdef SSL_LIBRARY_VERSION_TLS_1_1
291 case SSL_LIBRARY_VERSION_TLS_1_1:
292 return strdup("TLSv1.1");
293#endif
294#ifdef SSL_LIBRARY_VERSION_TLS_1_2
295 case SSL_LIBRARY_VERSION_TLS_1_2:
296 return strdup("TLSv1.2");
297#endif
298#ifdef SSL_LIBRARY_VERSION_TLS_1_3
299 case SSL_LIBRARY_VERSION_TLS_1_3:
300 return strdup("TLSv1.3");
301#endif
302 default:
303 return curl_maprintf("0x%04x", nssver);
304 }
305}
306
307static SECStatus set_ciphers(struct Curl_easy *data, PRFileDesc * model,
308 char *cipher_list)
309{
310 unsigned int i;
311 PRBool cipher_state[NUM_OF_CIPHERS];
312 PRBool found;
313 char *cipher;
314
315 /* use accessors to avoid dynamic linking issues after an update of NSS */
316 const PRUint16 num_implemented_ciphers = SSL_GetNumImplementedCiphers();
317 const PRUint16 *implemented_ciphers = SSL_GetImplementedCiphers();
318 if(!implemented_ciphers)
319 return SECFailure;
320
321 /* First disable all ciphers. This uses a different max value in case
322 * NSS adds more ciphers later we don't want them available by
323 * accident
324 */
325 for(i = 0; i < num_implemented_ciphers; i++) {
326 SSL_CipherPrefSet(model, implemented_ciphers[i], PR_FALSE);
327 }
328
329 /* Set every entry in our list to false */
330 for(i = 0; i < NUM_OF_CIPHERS; i++) {
331 cipher_state[i] = PR_FALSE;
332 }
333
334 cipher = cipher_list;
335
336 while(cipher_list && (cipher_list[0])) {
337 while((*cipher) && (ISSPACE(*cipher)))
338 ++cipher;
339
340 cipher_list = strpbrk(cipher, ":, ");
341 if(cipher_list) {
342 *cipher_list++ = '\0';
343 }
344
345 found = PR_FALSE;
346
347 for(i = 0; i<NUM_OF_CIPHERS; i++) {
348 if(strcasecompare(cipher, cipherlist[i].name)) {
349 cipher_state[i] = PR_TRUE;
350 found = PR_TRUE;
351 break;
352 }
353 }
354
355 if(found == PR_FALSE) {
356 failf(data, "Unknown cipher in list: %s", cipher);
357 return SECFailure;
358 }
359
360 if(cipher_list) {
361 cipher = cipher_list;
362 }
363 }
364
365 /* Finally actually enable the selected ciphers */
366 for(i = 0; i<NUM_OF_CIPHERS; i++) {
367 if(!cipher_state[i])
368 continue;
369
370 if(SSL_CipherPrefSet(model, cipherlist[i].num, PR_TRUE) != SECSuccess) {
371 failf(data, "cipher-suite not supported by NSS: %s", cipherlist[i].name);
372 return SECFailure;
373 }
374 }
375
376 return SECSuccess;
377}
378
379/*
380 * Return true if at least one cipher-suite is enabled. Used to determine
381 * if we need to call NSS_SetDomesticPolicy() to enable the default ciphers.
382 */
383static bool any_cipher_enabled(void)
384{
385 unsigned int i;
386
387 for(i = 0; i<NUM_OF_CIPHERS; i++) {
388 PRInt32 policy = 0;
389 SSL_CipherPolicyGet(cipherlist[i].num, &policy);
390 if(policy)
391 return TRUE;
392 }
393
394 return FALSE;
395}
396
397/*
398 * Determine whether the nickname passed in is a filename that needs to
399 * be loaded as a PEM or a regular NSS nickname.
400 *
401 * returns 1 for a file
402 * returns 0 for not a file (NSS nickname)
403 */
404static int is_file(const char *filename)
405{
406 struct_stat st;
407
408 if(!filename)
409 return 0;
410
411 if(stat(filename, &st) == 0)
412 if(S_ISREG(st.st_mode) || S_ISFIFO(st.st_mode) || S_ISCHR(st.st_mode))
413 return 1;
414
415 return 0;
416}
417
418/* Check if the given string is filename or nickname of a certificate. If the
419 * given string is recognized as filename, return NULL. If the given string is
420 * recognized as nickname, return a duplicated string. The returned string
421 * should be later deallocated using free(). If the OOM failure occurs, we
422 * return NULL, too.
423 */
424static char *dup_nickname(struct Curl_easy *data, const char *str)
425{
426 const char *n;
427
428 if(!is_file(str))
429 /* no such file exists, use the string as nickname */
430 return strdup(str);
431
432 /* search the first slash; we require at least one slash in a file name */
433 n = strchr(str, '/');
434 if(!n) {
435 infof(data, "warning: certificate file name \"%s\" handled as nickname; "
436 "please use \"./%s\" to force file name", str, str);
437 return strdup(str);
438 }
439
440 /* we'll use the PEM reader to read the certificate from file */
441 return NULL;
442}
443
444/* Lock/unlock wrapper for PK11_FindSlotByName() to work around race condition
445 * in nssSlot_IsTokenPresent() causing spurious SEC_ERROR_NO_TOKEN. For more
446 * details, go to <https://bugzilla.mozilla.org/1297397>.
447 */
448static PK11SlotInfo* nss_find_slot_by_name(const char *slot_name)
449{
450 PK11SlotInfo *slot;
451 PR_Lock(nss_findslot_lock);
452 slot = PK11_FindSlotByName(slot_name);
453 PR_Unlock(nss_findslot_lock);
454 return slot;
455}
456
457/* wrap 'ptr' as list node and tail-insert into 'list' */
458static CURLcode insert_wrapped_ptr(struct Curl_llist *list, void *ptr)
459{
460 struct ptr_list_wrap *wrap = malloc(sizeof(*wrap));
461 if(!wrap)
462 return CURLE_OUT_OF_MEMORY;
463
464 wrap->ptr = ptr;
465 Curl_llist_insert_next(list, list->tail, wrap, &wrap->node);
466 return CURLE_OK;
467}
468
469/* Call PK11_CreateGenericObject() with the given obj_class and filename. If
470 * the call succeeds, append the object handle to the list of objects so that
471 * the object can be destroyed in nss_close(). */
472static CURLcode nss_create_object(struct ssl_connect_data *connssl,
473 CK_OBJECT_CLASS obj_class,
474 const char *filename, bool cacert)
475{
476 PK11SlotInfo *slot;
477 PK11GenericObject *obj;
478 CK_BBOOL cktrue = CK_TRUE;
479 CK_BBOOL ckfalse = CK_FALSE;
480 CK_ATTRIBUTE attrs[/* max count of attributes */ 4];
481 int attr_cnt = 0;
482 CURLcode result = (cacert)
483 ? CURLE_SSL_CACERT_BADFILE
484 : CURLE_SSL_CERTPROBLEM;
485
486 const int slot_id = (cacert) ? 0 : 1;
487 char *slot_name = aprintf("PEM Token #%d", slot_id);
488 struct ssl_backend_data *backend = connssl->backend;
489 if(!slot_name)
490 return CURLE_OUT_OF_MEMORY;
491
492 slot = nss_find_slot_by_name(slot_name);
493 free(slot_name);
494 if(!slot)
495 return result;
496
497 PK11_SETATTRS(attrs, attr_cnt, CKA_CLASS, &obj_class, sizeof(obj_class));
498 PK11_SETATTRS(attrs, attr_cnt, CKA_TOKEN, &cktrue, sizeof(CK_BBOOL));
499 PK11_SETATTRS(attrs, attr_cnt, CKA_LABEL, (unsigned char *)filename,
500 (CK_ULONG)strlen(filename) + 1);
501
502 if(CKO_CERTIFICATE == obj_class) {
503 CK_BBOOL *pval = (cacert) ? (&cktrue) : (&ckfalse);
504 PK11_SETATTRS(attrs, attr_cnt, CKA_TRUST, pval, sizeof(*pval));
505 }
506
507 /* PK11_CreateManagedGenericObject() was introduced in NSS 3.34 because
508 * PK11_DestroyGenericObject() does not release resources allocated by
509 * PK11_CreateGenericObject() early enough. */
510 obj =
511#ifdef HAVE_PK11_CREATEMANAGEDGENERICOBJECT
512 PK11_CreateManagedGenericObject
513#else
514 PK11_CreateGenericObject
515#endif
516 (slot, attrs, attr_cnt, PR_FALSE);
517
518 PK11_FreeSlot(slot);
519 if(!obj)
520 return result;
521
522 if(insert_wrapped_ptr(&backend->obj_list, obj) != CURLE_OK) {
523 PK11_DestroyGenericObject(obj);
524 return CURLE_OUT_OF_MEMORY;
525 }
526
527 if(!cacert && CKO_CERTIFICATE == obj_class)
528 /* store reference to a client certificate */
529 backend->obj_clicert = obj;
530
531 return CURLE_OK;
532}
533
534/* Destroy the NSS object whose handle is given by ptr. This function is
535 * a callback of Curl_llist_alloc() used by Curl_llist_destroy() to destroy
536 * NSS objects in nss_close() */
537static void nss_destroy_object(void *user, void *ptr)
538{
539 struct ptr_list_wrap *wrap = (struct ptr_list_wrap *) ptr;
540 PK11GenericObject *obj = (PK11GenericObject *) wrap->ptr;
541 (void) user;
542 PK11_DestroyGenericObject(obj);
543 free(wrap);
544}
545
546/* same as nss_destroy_object() but for CRL items */
547static void nss_destroy_crl_item(void *user, void *ptr)
548{
549 struct ptr_list_wrap *wrap = (struct ptr_list_wrap *) ptr;
550 SECItem *crl_der = (SECItem *) wrap->ptr;
551 (void) user;
552 SECITEM_FreeItem(crl_der, PR_TRUE);
553 free(wrap);
554}
555
556static CURLcode nss_load_cert(struct ssl_connect_data *ssl,
557 const char *filename, PRBool cacert)
558{
559 CURLcode result = (cacert)
560 ? CURLE_SSL_CACERT_BADFILE
561 : CURLE_SSL_CERTPROBLEM;
562
563 /* libnsspem.so leaks memory if the requested file does not exist. For more
564 * details, go to <https://bugzilla.redhat.com/734760>. */
565 if(is_file(filename))
566 result = nss_create_object(ssl, CKO_CERTIFICATE, filename, cacert);
567
568 if(!result && !cacert) {
569 /* we have successfully loaded a client certificate */
570 char *nickname = NULL;
571 char *n = strrchr(filename, '/');
572 if(n)
573 n++;
574
575 /* The following undocumented magic helps to avoid a SIGSEGV on call
576 * of PK11_ReadRawAttribute() from SelectClientCert() when using an
577 * immature version of libnsspem.so. For more details, go to
578 * <https://bugzilla.redhat.com/733685>. */
579 nickname = aprintf("PEM Token #1:%s", n);
580 if(nickname) {
581 CERTCertificate *cert = PK11_FindCertFromNickname(nickname, NULL);
582 if(cert)
583 CERT_DestroyCertificate(cert);
584
585 free(nickname);
586 }
587 }
588
589 return result;
590}
591
592/* add given CRL to cache if it is not already there */
593static CURLcode nss_cache_crl(SECItem *crl_der)
594{
595 CERTCertDBHandle *db = CERT_GetDefaultCertDB();
596 CERTSignedCrl *crl = SEC_FindCrlByDERCert(db, crl_der, 0);
597 if(crl) {
598 /* CRL already cached */
599 SEC_DestroyCrl(crl);
600 SECITEM_FreeItem(crl_der, PR_TRUE);
601 return CURLE_OK;
602 }
603
604 /* acquire lock before call of CERT_CacheCRL() and accessing nss_crl_list */
605 PR_Lock(nss_crllock);
606
607 if(SECSuccess != CERT_CacheCRL(db, crl_der)) {
608 /* unable to cache CRL */
609 SECITEM_FreeItem(crl_der, PR_TRUE);
610 PR_Unlock(nss_crllock);
611 return CURLE_SSL_CRL_BADFILE;
612 }
613
614 /* store the CRL item so that we can free it in nss_cleanup() */
615 if(insert_wrapped_ptr(&nss_crl_list, crl_der) != CURLE_OK) {
616 if(SECSuccess == CERT_UncacheCRL(db, crl_der))
617 SECITEM_FreeItem(crl_der, PR_TRUE);
618 PR_Unlock(nss_crllock);
619 return CURLE_OUT_OF_MEMORY;
620 }
621
622 /* we need to clear session cache, so that the CRL could take effect */
623 SSL_ClearSessionCache();
624 PR_Unlock(nss_crllock);
625 return CURLE_OK;
626}
627
628static CURLcode nss_load_crl(const char *crlfilename)
629{
630 PRFileDesc *infile;
631 PRFileInfo info;
632 SECItem filedata = { 0, NULL, 0 };
633 SECItem *crl_der = NULL;
634 char *body;
635
636 infile = PR_Open(crlfilename, PR_RDONLY, 0);
637 if(!infile)
638 return CURLE_SSL_CRL_BADFILE;
639
640 if(PR_SUCCESS != PR_GetOpenFileInfo(infile, &info))
641 goto fail;
642
643 if(!SECITEM_AllocItem(NULL, &filedata, info.size + /* zero ended */ 1))
644 goto fail;
645
646 if(info.size != PR_Read(infile, filedata.data, info.size))
647 goto fail;
648
649 crl_der = SECITEM_AllocItem(NULL, NULL, 0U);
650 if(!crl_der)
651 goto fail;
652
653 /* place a trailing zero right after the visible data */
654 body = (char *)filedata.data;
655 body[--filedata.len] = '\0';
656
657 body = strstr(body, "-----BEGIN");
658 if(body) {
659 /* assume ASCII */
660 char *trailer;
661 char *begin = PORT_Strchr(body, '\n');
662 if(!begin)
663 begin = PORT_Strchr(body, '\r');
664 if(!begin)
665 goto fail;
666
667 trailer = strstr(++begin, "-----END");
668 if(!trailer)
669 goto fail;
670
671 /* retrieve DER from ASCII */
672 *trailer = '\0';
673 if(ATOB_ConvertAsciiToItem(crl_der, begin))
674 goto fail;
675
676 SECITEM_FreeItem(&filedata, PR_FALSE);
677 }
678 else
679 /* assume DER */
680 *crl_der = filedata;
681
682 PR_Close(infile);
683 return nss_cache_crl(crl_der);
684
685fail:
686 PR_Close(infile);
687 SECITEM_FreeItem(crl_der, PR_TRUE);
688 SECITEM_FreeItem(&filedata, PR_FALSE);
689 return CURLE_SSL_CRL_BADFILE;
690}
691
692static CURLcode nss_load_key(struct Curl_easy *data, struct connectdata *conn,
693 int sockindex, char *key_file)
694{
695 PK11SlotInfo *slot, *tmp;
696 SECStatus status;
697 CURLcode result;
698 struct ssl_connect_data *ssl = conn->ssl;
699
700 (void)sockindex; /* unused */
701
702 result = nss_create_object(ssl, CKO_PRIVATE_KEY, key_file, FALSE);
703 if(result) {
704 PR_SetError(SEC_ERROR_BAD_KEY, 0);
705 return result;
706 }
707
708 slot = nss_find_slot_by_name("PEM Token #1");
709 if(!slot)
710 return CURLE_SSL_CERTPROBLEM;
711
712 /* This will force the token to be seen as re-inserted */
713 tmp = SECMOD_WaitForAnyTokenEvent(pem_module, 0, 0);
714 if(tmp)
715 PK11_FreeSlot(tmp);
716 if(!PK11_IsPresent(slot)) {
717 PK11_FreeSlot(slot);
718 return CURLE_SSL_CERTPROBLEM;
719 }
720
721 status = PK11_Authenticate(slot, PR_TRUE, SSL_SET_OPTION(key_passwd));
722 PK11_FreeSlot(slot);
723
724 return (SECSuccess == status) ? CURLE_OK : CURLE_SSL_CERTPROBLEM;
725}
726
727static int display_error(struct Curl_easy *data, PRInt32 err,
728 const char *filename)
729{
730 switch(err) {
731 case SEC_ERROR_BAD_PASSWORD:
732 failf(data, "Unable to load client key: Incorrect password");
733 return 1;
734 case SEC_ERROR_UNKNOWN_CERT:
735 failf(data, "Unable to load certificate %s", filename);
736 return 1;
737 default:
738 break;
739 }
740 return 0; /* The caller will print a generic error */
741}
742
743static CURLcode cert_stuff(struct Curl_easy *data, struct connectdata *conn,
744 int sockindex, char *cert_file, char *key_file)
745{
746 CURLcode result;
747
748 if(cert_file) {
749 result = nss_load_cert(&conn->ssl[sockindex], cert_file, PR_FALSE);
750 if(result) {
751 const PRErrorCode err = PR_GetError();
752 if(!display_error(data, err, cert_file)) {
753 const char *err_name = nss_error_to_name(err);
754 failf(data, "unable to load client cert: %d (%s)", err, err_name);
755 }
756
757 return result;
758 }
759 }
760
761 if(key_file || (is_file(cert_file))) {
762 if(key_file)
763 result = nss_load_key(data, conn, sockindex, key_file);
764 else
765 /* In case the cert file also has the key */
766 result = nss_load_key(data, conn, sockindex, cert_file);
767 if(result) {
768 const PRErrorCode err = PR_GetError();
769 if(!display_error(data, err, key_file)) {
770 const char *err_name = nss_error_to_name(err);
771 failf(data, "unable to load client key: %d (%s)", err, err_name);
772 }
773
774 return result;
775 }
776 }
777
778 return CURLE_OK;
779}
780
781static char *nss_get_password(PK11SlotInfo *slot, PRBool retry, void *arg)
782{
783 (void)slot; /* unused */
784
785 if(retry || NULL == arg)
786 return NULL;
787 else
788 return (char *)PORT_Strdup((char *)arg);
789}
790
791/* bypass the default SSL_AuthCertificate() hook in case we do not want to
792 * verify peer */
793static SECStatus nss_auth_cert_hook(void *arg, PRFileDesc *fd, PRBool checksig,
794 PRBool isServer)
795{
796 struct Curl_easy *data = (struct Curl_easy *)arg;
797 struct connectdata *conn = data->conn;
798
799#ifdef SSL_ENABLE_OCSP_STAPLING
800 if(SSL_CONN_CONFIG(verifystatus)) {
801 SECStatus cacheResult;
802
803 const SECItemArray *csa = SSL_PeerStapledOCSPResponses(fd);
804 if(!csa) {
805 failf(data, "Invalid OCSP response");
806 return SECFailure;
807 }
808
809 if(csa->len == 0) {
810 failf(data, "No OCSP response received");
811 return SECFailure;
812 }
813
814 cacheResult = CERT_CacheOCSPResponseFromSideChannel(
815 CERT_GetDefaultCertDB(), SSL_PeerCertificate(fd),
816 PR_Now(), &csa->items[0], arg
817 );
818
819 if(cacheResult != SECSuccess) {
820 failf(data, "Invalid OCSP response");
821 return cacheResult;
822 }
823 }
824#endif
825
826 if(!SSL_CONN_CONFIG(verifypeer)) {
827 infof(data, "skipping SSL peer certificate verification");
828 return SECSuccess;
829 }
830
831 return SSL_AuthCertificate(CERT_GetDefaultCertDB(), fd, checksig, isServer);
832}
833
834/**
835 * Inform the application that the handshake is complete.
836 */
837static void HandshakeCallback(PRFileDesc *sock, void *arg)
838{
839 struct Curl_easy *data = (struct Curl_easy *)arg;
840 struct connectdata *conn = data->conn;
841 unsigned int buflenmax = 50;
842 unsigned char buf[50];
843 unsigned int buflen;
844 SSLNextProtoState state;
845
846 if(!conn->bits.tls_enable_npn && !conn->bits.tls_enable_alpn) {
847 return;
848 }
849
850 if(SSL_GetNextProto(sock, &state, buf, &buflen, buflenmax) == SECSuccess) {
851
852 switch(state) {
853#if NSSVERNUM >= 0x031a00 /* 3.26.0 */
854 /* used by NSS internally to implement 0-RTT */
855 case SSL_NEXT_PROTO_EARLY_VALUE:
856 /* fall through! */
857#endif
858 case SSL_NEXT_PROTO_NO_SUPPORT:
859 case SSL_NEXT_PROTO_NO_OVERLAP:
860 infof(data, "ALPN/NPN, server did not agree to a protocol");
861 return;
862#ifdef SSL_ENABLE_ALPN
863 case SSL_NEXT_PROTO_SELECTED:
864 infof(data, "ALPN, server accepted to use %.*s", buflen, buf);
865 break;
866#endif
867 case SSL_NEXT_PROTO_NEGOTIATED:
868 infof(data, "NPN, server accepted to use %.*s", buflen, buf);
869 break;
870 }
871
872#ifdef USE_NGHTTP2
873 if(buflen == ALPN_H2_LENGTH &&
874 !memcmp(ALPN_H2, buf, ALPN_H2_LENGTH)) {
875 conn->negnpn = CURL_HTTP_VERSION_2;
876 }
877 else
878#endif
879 if(buflen == ALPN_HTTP_1_1_LENGTH &&
880 !memcmp(ALPN_HTTP_1_1, buf, ALPN_HTTP_1_1_LENGTH)) {
881 conn->negnpn = CURL_HTTP_VERSION_1_1;
882 }
883 Curl_multiuse_state(data, conn->negnpn == CURL_HTTP_VERSION_2 ?
884 BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE);
885 }
886}
887
888#if NSSVERNUM >= 0x030f04 /* 3.15.4 */
889static SECStatus CanFalseStartCallback(PRFileDesc *sock, void *client_data,
890 PRBool *canFalseStart)
891{
892 struct Curl_easy *data = (struct Curl_easy *)client_data;
893
894 SSLChannelInfo channelInfo;
895 SSLCipherSuiteInfo cipherInfo;
896
897 SECStatus rv;
898 PRBool negotiatedExtension;
899
900 *canFalseStart = PR_FALSE;
901
902 if(SSL_GetChannelInfo(sock, &channelInfo, sizeof(channelInfo)) != SECSuccess)
903 return SECFailure;
904
905 if(SSL_GetCipherSuiteInfo(channelInfo.cipherSuite, &cipherInfo,
906 sizeof(cipherInfo)) != SECSuccess)
907 return SECFailure;
908
909 /* Prevent version downgrade attacks from TLS 1.2, and avoid False Start for
910 * TLS 1.3 and later. See https://bugzilla.mozilla.org/show_bug.cgi?id=861310
911 */
912 if(channelInfo.protocolVersion != SSL_LIBRARY_VERSION_TLS_1_2)
913 goto end;
914
915 /* Only allow ECDHE key exchange algorithm.
916 * See https://bugzilla.mozilla.org/show_bug.cgi?id=952863 */
917 if(cipherInfo.keaType != ssl_kea_ecdh)
918 goto end;
919
920 /* Prevent downgrade attacks on the symmetric cipher. We do not allow CBC
921 * mode due to BEAST, POODLE, and other attacks on the MAC-then-Encrypt
922 * design. See https://bugzilla.mozilla.org/show_bug.cgi?id=1109766 */
923 if(cipherInfo.symCipher != ssl_calg_aes_gcm)
924 goto end;
925
926 /* Enforce ALPN or NPN to do False Start, as an indicator of server
927 * compatibility. */
928 rv = SSL_HandshakeNegotiatedExtension(sock, ssl_app_layer_protocol_xtn,
929 &negotiatedExtension);
930 if(rv != SECSuccess || !negotiatedExtension) {
931 rv = SSL_HandshakeNegotiatedExtension(sock, ssl_next_proto_nego_xtn,
932 &negotiatedExtension);
933 }
934
935 if(rv != SECSuccess || !negotiatedExtension)
936 goto end;
937
938 *canFalseStart = PR_TRUE;
939
940 infof(data, "Trying TLS False Start");
941
942end:
943 return SECSuccess;
944}
945#endif
946
947static void display_cert_info(struct Curl_easy *data,
948 CERTCertificate *cert)
949{
950 char *subject, *issuer, *common_name;
951 PRExplodedTime printableTime;
952 char timeString[256];
953 PRTime notBefore, notAfter;
954
955 subject = CERT_NameToAscii(&cert->subject);
956 issuer = CERT_NameToAscii(&cert->issuer);
957 common_name = CERT_GetCommonName(&cert->subject);
958 infof(data, "subject: %s\n", subject);
959
960 CERT_GetCertTimes(cert, &notBefore, &notAfter);
961 PR_ExplodeTime(notBefore, PR_GMTParameters, &printableTime);
962 PR_FormatTime(timeString, 256, "%b %d %H:%M:%S %Y GMT", &printableTime);
963 infof(data, " start date: %s", timeString);
964 PR_ExplodeTime(notAfter, PR_GMTParameters, &printableTime);
965 PR_FormatTime(timeString, 256, "%b %d %H:%M:%S %Y GMT", &printableTime);
966 infof(data, " expire date: %s", timeString);
967 infof(data, " common name: %s", common_name);
968 infof(data, " issuer: %s", issuer);
969
970 PR_Free(subject);
971 PR_Free(issuer);
972 PR_Free(common_name);
973}
974
975static CURLcode display_conn_info(struct Curl_easy *data, PRFileDesc *sock)
976{
977 CURLcode result = CURLE_OK;
978 SSLChannelInfo channel;
979 SSLCipherSuiteInfo suite;
980 CERTCertificate *cert;
981 CERTCertificate *cert2;
982 CERTCertificate *cert3;
983 PRTime now;
984
985 if(SSL_GetChannelInfo(sock, &channel, sizeof(channel)) ==
986 SECSuccess && channel.length == sizeof(channel) &&
987 channel.cipherSuite) {
988 if(SSL_GetCipherSuiteInfo(channel.cipherSuite,
989 &suite, sizeof(suite)) == SECSuccess) {
990 infof(data, "SSL connection using %s", suite.cipherSuiteName);
991 }
992 }
993
994 cert = SSL_PeerCertificate(sock);
995 if(cert) {
996 infof(data, "Server certificate:");
997
998 if(!data->set.ssl.certinfo) {
999 display_cert_info(data, cert);
1000 CERT_DestroyCertificate(cert);
1001 }
1002 else {
1003 /* Count certificates in chain. */
1004 int i = 1;
1005 now = PR_Now();
1006 if(!cert->isRoot) {
1007 cert2 = CERT_FindCertIssuer(cert, now, certUsageSSLCA);
1008 while(cert2) {
1009 i++;
1010 if(cert2->isRoot) {
1011 CERT_DestroyCertificate(cert2);
1012 break;
1013 }
1014 cert3 = CERT_FindCertIssuer(cert2, now, certUsageSSLCA);
1015 CERT_DestroyCertificate(cert2);
1016 cert2 = cert3;
1017 }
1018 }
1019
1020 result = Curl_ssl_init_certinfo(data, i);
1021 if(!result) {
1022 for(i = 0; cert; cert = cert2) {
1023 result = Curl_extract_certinfo(data, i++, (char *)cert->derCert.data,
1024 (char *)cert->derCert.data +
1025 cert->derCert.len);
1026 if(result)
1027 break;
1028
1029 if(cert->isRoot) {
1030 CERT_DestroyCertificate(cert);
1031 break;
1032 }
1033
1034 cert2 = CERT_FindCertIssuer(cert, now, certUsageSSLCA);
1035 CERT_DestroyCertificate(cert);
1036 }
1037 }
1038 }
1039 }
1040
1041 return result;
1042}
1043
1044static SECStatus BadCertHandler(void *arg, PRFileDesc *sock)
1045{
1046 struct Curl_easy *data = (struct Curl_easy *)arg;
1047 struct connectdata *conn = data->conn;
1048 PRErrorCode err = PR_GetError();
1049 CERTCertificate *cert;
1050
1051 /* remember the cert verification result */
1052 SSL_SET_OPTION_LVALUE(certverifyresult) = err;
1053
1054 if(err == SSL_ERROR_BAD_CERT_DOMAIN && !SSL_CONN_CONFIG(verifyhost))
1055 /* we are asked not to verify the host name */
1056 return SECSuccess;
1057
1058 /* print only info about the cert, the error is printed off the callback */
1059 cert = SSL_PeerCertificate(sock);
1060 if(cert) {
1061 infof(data, "Server certificate:");
1062 display_cert_info(data, cert);
1063 CERT_DestroyCertificate(cert);
1064 }
1065
1066 return SECFailure;
1067}
1068
1069/**
1070 *
1071 * Check that the Peer certificate's issuer certificate matches the one found
1072 * by issuer_nickname. This is not exactly the way OpenSSL and GNU TLS do the
1073 * issuer check, so we provide comments that mimic the OpenSSL
1074 * X509_check_issued function (in x509v3/v3_purp.c)
1075 */
1076static SECStatus check_issuer_cert(PRFileDesc *sock,
1077 char *issuer_nickname)
1078{
1079 CERTCertificate *cert, *cert_issuer, *issuer;
1080 SECStatus res = SECSuccess;
1081 void *proto_win = NULL;
1082
1083 cert = SSL_PeerCertificate(sock);
1084 cert_issuer = CERT_FindCertIssuer(cert, PR_Now(), certUsageObjectSigner);
1085
1086 proto_win = SSL_RevealPinArg(sock);
1087 issuer = PK11_FindCertFromNickname(issuer_nickname, proto_win);
1088
1089 if((!cert_issuer) || (!issuer))
1090 res = SECFailure;
1091 else if(SECITEM_CompareItem(&cert_issuer->derCert,
1092 &issuer->derCert) != SECEqual)
1093 res = SECFailure;
1094
1095 CERT_DestroyCertificate(cert);
1096 CERT_DestroyCertificate(issuer);
1097 CERT_DestroyCertificate(cert_issuer);
1098 return res;
1099}
1100
1101static CURLcode cmp_peer_pubkey(struct ssl_connect_data *connssl,
1102 const char *pinnedpubkey)
1103{
1104 CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH;
1105 struct ssl_backend_data *backend = connssl->backend;
1106 struct Curl_easy *data = backend->data;
1107 CERTCertificate *cert;
1108
1109 if(!pinnedpubkey)
1110 /* no pinned public key specified */
1111 return CURLE_OK;
1112
1113 /* get peer certificate */
1114 cert = SSL_PeerCertificate(backend->handle);
1115 if(cert) {
1116 /* extract public key from peer certificate */
1117 SECKEYPublicKey *pubkey = CERT_ExtractPublicKey(cert);
1118 if(pubkey) {
1119 /* encode the public key as DER */
1120 SECItem *cert_der = PK11_DEREncodePublicKey(pubkey);
1121 if(cert_der) {
1122 /* compare the public key with the pinned public key */
1123 result = Curl_pin_peer_pubkey(data, pinnedpubkey, cert_der->data,
1124 cert_der->len);
1125 SECITEM_FreeItem(cert_der, PR_TRUE);
1126 }
1127 SECKEY_DestroyPublicKey(pubkey);
1128 }
1129 CERT_DestroyCertificate(cert);
1130 }
1131
1132 /* report the resulting status */
1133 switch(result) {
1134 case CURLE_OK:
1135 infof(data, "pinned public key verified successfully!");
1136 break;
1137 case CURLE_SSL_PINNEDPUBKEYNOTMATCH:
1138 failf(data, "failed to verify pinned public key");
1139 break;
1140 default:
1141 /* OOM, etc. */
1142 break;
1143 }
1144
1145 return result;
1146}
1147
1148/**
1149 *
1150 * Callback to pick the SSL client certificate.
1151 */
1152static SECStatus SelectClientCert(void *arg, PRFileDesc *sock,
1153 struct CERTDistNamesStr *caNames,
1154 struct CERTCertificateStr **pRetCert,
1155 struct SECKEYPrivateKeyStr **pRetKey)
1156{
1157 struct ssl_connect_data *connssl = (struct ssl_connect_data *)arg;
1158 struct ssl_backend_data *backend = connssl->backend;
1159 struct Curl_easy *data = backend->data;
1160 const char *nickname = backend->client_nickname;
1161 static const char pem_slotname[] = "PEM Token #1";
1162
1163 if(backend->obj_clicert) {
1164 /* use the cert/key provided by PEM reader */
1165 SECItem cert_der = { 0, NULL, 0 };
1166 void *proto_win = SSL_RevealPinArg(sock);
1167 struct CERTCertificateStr *cert;
1168 struct SECKEYPrivateKeyStr *key;
1169
1170 PK11SlotInfo *slot = nss_find_slot_by_name(pem_slotname);
1171 if(NULL == slot) {
1172 failf(data, "NSS: PK11 slot not found: %s", pem_slotname);
1173 return SECFailure;
1174 }
1175
1176 if(PK11_ReadRawAttribute(PK11_TypeGeneric, backend->obj_clicert, CKA_VALUE,
1177 &cert_der) != SECSuccess) {
1178 failf(data, "NSS: CKA_VALUE not found in PK11 generic object");
1179 PK11_FreeSlot(slot);
1180 return SECFailure;
1181 }
1182
1183 cert = PK11_FindCertFromDERCertItem(slot, &cert_der, proto_win);
1184 SECITEM_FreeItem(&cert_der, PR_FALSE);
1185 if(NULL == cert) {
1186 failf(data, "NSS: client certificate from file not found");
1187 PK11_FreeSlot(slot);
1188 return SECFailure;
1189 }
1190
1191 key = PK11_FindPrivateKeyFromCert(slot, cert, NULL);
1192 PK11_FreeSlot(slot);
1193 if(NULL == key) {
1194 failf(data, "NSS: private key from file not found");
1195 CERT_DestroyCertificate(cert);
1196 return SECFailure;
1197 }
1198
1199 infof(data, "NSS: client certificate from file");
1200 display_cert_info(data, cert);
1201
1202 *pRetCert = cert;
1203 *pRetKey = key;
1204 return SECSuccess;
1205 }
1206
1207 /* use the default NSS hook */
1208 if(SECSuccess != NSS_GetClientAuthData((void *)nickname, sock, caNames,
1209 pRetCert, pRetKey)
1210 || NULL == *pRetCert) {
1211
1212 if(NULL == nickname)
1213 failf(data, "NSS: client certificate not found (nickname not "
1214 "specified)");
1215 else
1216 failf(data, "NSS: client certificate not found: %s", nickname);
1217
1218 return SECFailure;
1219 }
1220
1221 /* get certificate nickname if any */
1222 nickname = (*pRetCert)->nickname;
1223 if(NULL == nickname)
1224 nickname = "[unknown]";
1225
1226 if(!strncmp(nickname, pem_slotname, sizeof(pem_slotname) - 1U)) {
1227 failf(data, "NSS: refusing previously loaded certificate from file: %s",
1228 nickname);
1229 return SECFailure;
1230 }
1231
1232 if(NULL == *pRetKey) {
1233 failf(data, "NSS: private key not found for certificate: %s", nickname);
1234 return SECFailure;
1235 }
1236
1237 infof(data, "NSS: using client certificate: %s", nickname);
1238 display_cert_info(data, *pRetCert);
1239 return SECSuccess;
1240}
1241
1242/* update blocking direction in case of PR_WOULD_BLOCK_ERROR */
1243static void nss_update_connecting_state(ssl_connect_state state, void *secret)
1244{
1245 struct ssl_connect_data *connssl = (struct ssl_connect_data *)secret;
1246 if(PR_GetError() != PR_WOULD_BLOCK_ERROR)
1247 /* an unrelated error is passing by */
1248 return;
1249
1250 switch(connssl->connecting_state) {
1251 case ssl_connect_2:
1252 case ssl_connect_2_reading:
1253 case ssl_connect_2_writing:
1254 break;
1255 default:
1256 /* we are not called from an SSL handshake */
1257 return;
1258 }
1259
1260 /* update the state accordingly */
1261 connssl->connecting_state = state;
1262}
1263
1264/* recv() wrapper we use to detect blocking direction during SSL handshake */
1265static PRInt32 nspr_io_recv(PRFileDesc *fd, void *buf, PRInt32 amount,
1266 PRIntn flags, PRIntervalTime timeout)
1267{
1268 const PRRecvFN recv_fn = fd->lower->methods->recv;
1269 const PRInt32 rv = recv_fn(fd->lower, buf, amount, flags, timeout);
1270 if(rv < 0)
1271 /* check for PR_WOULD_BLOCK_ERROR and update blocking direction */
1272 nss_update_connecting_state(ssl_connect_2_reading, fd->secret);
1273 return rv;
1274}
1275
1276/* send() wrapper we use to detect blocking direction during SSL handshake */
1277static PRInt32 nspr_io_send(PRFileDesc *fd, const void *buf, PRInt32 amount,
1278 PRIntn flags, PRIntervalTime timeout)
1279{
1280 const PRSendFN send_fn = fd->lower->methods->send;
1281 const PRInt32 rv = send_fn(fd->lower, buf, amount, flags, timeout);
1282 if(rv < 0)
1283 /* check for PR_WOULD_BLOCK_ERROR and update blocking direction */
1284 nss_update_connecting_state(ssl_connect_2_writing, fd->secret);
1285 return rv;
1286}
1287
1288/* close() wrapper to avoid assertion failure due to fd->secret != NULL */
1289static PRStatus nspr_io_close(PRFileDesc *fd)
1290{
1291 const PRCloseFN close_fn = PR_GetDefaultIOMethods()->close;
1292 fd->secret = NULL;
1293 return close_fn(fd);
1294}
1295
1296/* load a PKCS #11 module */
1297static CURLcode nss_load_module(SECMODModule **pmod, const char *library,
1298 const char *name)
1299{
1300 char *config_string;
1301 SECMODModule *module = *pmod;
1302 if(module)
1303 /* already loaded */
1304 return CURLE_OK;
1305
1306 config_string = aprintf("library=%s name=%s", library, name);
1307 if(!config_string)
1308 return CURLE_OUT_OF_MEMORY;
1309
1310 module = SECMOD_LoadUserModule(config_string, NULL, PR_FALSE);
1311 free(config_string);
1312
1313 if(module && module->loaded) {
1314 /* loaded successfully */
1315 *pmod = module;
1316 return CURLE_OK;
1317 }
1318
1319 if(module)
1320 SECMOD_DestroyModule(module);
1321 return CURLE_FAILED_INIT;
1322}
1323
1324/* unload a PKCS #11 module */
1325static void nss_unload_module(SECMODModule **pmod)
1326{
1327 SECMODModule *module = *pmod;
1328 if(!module)
1329 /* not loaded */
1330 return;
1331
1332 if(SECMOD_UnloadUserModule(module) != SECSuccess)
1333 /* unload failed */
1334 return;
1335
1336 SECMOD_DestroyModule(module);
1337 *pmod = NULL;
1338}
1339
1340/* data might be NULL */
1341static CURLcode nss_init_core(struct Curl_easy *data, const char *cert_dir)
1342{
1343 NSSInitParameters initparams;
1344 PRErrorCode err;
1345 const char *err_name;
1346
1347 if(nss_context != NULL)
1348 return CURLE_OK;
1349
1350 memset((void *) &initparams, '\0', sizeof(initparams));
1351 initparams.length = sizeof(initparams);
1352
1353 if(cert_dir) {
1354 char *certpath = aprintf("sql:%s", cert_dir);
1355 if(!certpath)
1356 return CURLE_OUT_OF_MEMORY;
1357
1358 infof(data, "Initializing NSS with certpath: %s", certpath);
1359 nss_context = NSS_InitContext(certpath, "", "", "", &initparams,
1360 NSS_INIT_READONLY | NSS_INIT_PK11RELOAD);
1361 free(certpath);
1362
1363 if(nss_context != NULL)
1364 return CURLE_OK;
1365
1366 err = PR_GetError();
1367 err_name = nss_error_to_name(err);
1368 infof(data, "Unable to initialize NSS database: %d (%s)", err, err_name);
1369 }
1370
1371 infof(data, "Initializing NSS with certpath: none");
1372 nss_context = NSS_InitContext("", "", "", "", &initparams, NSS_INIT_READONLY
1373 | NSS_INIT_NOCERTDB | NSS_INIT_NOMODDB | NSS_INIT_FORCEOPEN
1374 | NSS_INIT_NOROOTINIT | NSS_INIT_OPTIMIZESPACE | NSS_INIT_PK11RELOAD);
1375 if(nss_context != NULL)
1376 return CURLE_OK;
1377
1378 err = PR_GetError();
1379 err_name = nss_error_to_name(err);
1380 failf(data, "Unable to initialize NSS: %d (%s)", err, err_name);
1381 return CURLE_SSL_CACERT_BADFILE;
1382}
1383
1384/* data might be NULL */
1385static CURLcode nss_setup(struct Curl_easy *data)
1386{
1387 char *cert_dir;
1388 struct_stat st;
1389 CURLcode result;
1390
1391 if(initialized)
1392 return CURLE_OK;
1393
1394 /* list of all CRL items we need to destroy in nss_cleanup() */
1395 Curl_llist_init(&nss_crl_list, nss_destroy_crl_item);
1396
1397 /* First we check if $SSL_DIR points to a valid dir */
1398 cert_dir = getenv("SSL_DIR");
1399 if(cert_dir) {
1400 if((stat(cert_dir, &st) != 0) ||
1401 (!S_ISDIR(st.st_mode))) {
1402 cert_dir = NULL;
1403 }
1404 }
1405
1406 /* Now we check if the default location is a valid dir */
1407 if(!cert_dir) {
1408 if((stat(SSL_DIR, &st) == 0) &&
1409 (S_ISDIR(st.st_mode))) {
1410 cert_dir = (char *)SSL_DIR;
1411 }
1412 }
1413
1414 if(nspr_io_identity == PR_INVALID_IO_LAYER) {
1415 /* allocate an identity for our own NSPR I/O layer */
1416 nspr_io_identity = PR_GetUniqueIdentity("libcurl");
1417 if(nspr_io_identity == PR_INVALID_IO_LAYER)
1418 return CURLE_OUT_OF_MEMORY;
1419
1420 /* the default methods just call down to the lower I/O layer */
1421 memcpy(&nspr_io_methods, PR_GetDefaultIOMethods(),
1422 sizeof(nspr_io_methods));
1423
1424 /* override certain methods in the table by our wrappers */
1425 nspr_io_methods.recv = nspr_io_recv;
1426 nspr_io_methods.send = nspr_io_send;
1427 nspr_io_methods.close = nspr_io_close;
1428 }
1429
1430 result = nss_init_core(data, cert_dir);
1431 if(result)
1432 return result;
1433
1434 if(!any_cipher_enabled())
1435 NSS_SetDomesticPolicy();
1436
1437 initialized = 1;
1438
1439 return CURLE_OK;
1440}
1441
1442/**
1443 * Global SSL init
1444 *
1445 * @retval 0 error initializing SSL
1446 * @retval 1 SSL initialized successfully
1447 */
1448static int nss_init(void)
1449{
1450 /* curl_global_init() is not thread-safe so this test is ok */
1451 if(!nss_initlock) {
1452 PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
1453 nss_initlock = PR_NewLock();
1454 nss_crllock = PR_NewLock();
1455 nss_findslot_lock = PR_NewLock();
1456 nss_trustload_lock = PR_NewLock();
1457 }
1458
1459 /* We will actually initialize NSS later */
1460
1461 return 1;
1462}
1463
1464/* data might be NULL */
1465CURLcode Curl_nss_force_init(struct Curl_easy *data)
1466{
1467 CURLcode result;
1468 if(!nss_initlock) {
1469 if(data)
1470 failf(data, "unable to initialize NSS, curl_global_init() should have "
1471 "been called with CURL_GLOBAL_SSL or CURL_GLOBAL_ALL");
1472 return CURLE_FAILED_INIT;
1473 }
1474
1475 PR_Lock(nss_initlock);
1476 result = nss_setup(data);
1477 PR_Unlock(nss_initlock);
1478
1479 return result;
1480}
1481
1482/* Global cleanup */
1483static void nss_cleanup(void)
1484{
1485 /* This function isn't required to be threadsafe and this is only done
1486 * as a safety feature.
1487 */
1488 PR_Lock(nss_initlock);
1489 if(initialized) {
1490 /* Free references to client certificates held in the SSL session cache.
1491 * Omitting this hampers destruction of the security module owning
1492 * the certificates. */
1493 SSL_ClearSessionCache();
1494
1495 nss_unload_module(&pem_module);
1496 nss_unload_module(&trust_module);
1497 NSS_ShutdownContext(nss_context);
1498 nss_context = NULL;
1499 }
1500
1501 /* destroy all CRL items */
1502 Curl_llist_destroy(&nss_crl_list, NULL);
1503
1504 PR_Unlock(nss_initlock);
1505
1506 PR_DestroyLock(nss_initlock);
1507 PR_DestroyLock(nss_crllock);
1508 PR_DestroyLock(nss_findslot_lock);
1509 PR_DestroyLock(nss_trustload_lock);
1510 nss_initlock = NULL;
1511
1512 initialized = 0;
1513}
1514
1515/*
1516 * This function uses SSL_peek to determine connection status.
1517 *
1518 * Return codes:
1519 * 1 means the connection is still in place
1520 * 0 means the connection has been closed
1521 * -1 means the connection status is unknown
1522 */
1523static int nss_check_cxn(struct connectdata *conn)
1524{
1525 struct ssl_connect_data *connssl = &conn->ssl[FIRSTSOCKET];
1526 struct ssl_backend_data *backend = connssl->backend;
1527 int rc;
1528 char buf;
1529
1530 rc =
1531 PR_Recv(backend->handle, (void *)&buf, 1, PR_MSG_PEEK,
1532 PR_SecondsToInterval(1));
1533 if(rc > 0)
1534 return 1; /* connection still in place */
1535
1536 if(rc == 0)
1537 return 0; /* connection has been closed */
1538
1539 return -1; /* connection status unknown */
1540}
1541
1542static void close_one(struct ssl_connect_data *connssl)
1543{
1544 /* before the cleanup, check whether we are using a client certificate */
1545 struct ssl_backend_data *backend = connssl->backend;
1546 const bool client_cert = (backend->client_nickname != NULL)
1547 || (backend->obj_clicert != NULL);
1548
1549 if(backend->handle) {
1550 char buf[32];
1551 /* Maybe the server has already sent a close notify alert.
1552 Read it to avoid an RST on the TCP connection. */
1553 (void)PR_Recv(backend->handle, buf, (int)sizeof(buf), 0,
1554 PR_INTERVAL_NO_WAIT);
1555 }
1556
1557 free(backend->client_nickname);
1558 backend->client_nickname = NULL;
1559
1560 /* destroy all NSS objects in order to avoid failure of NSS shutdown */
1561 Curl_llist_destroy(&backend->obj_list, NULL);
1562 backend->obj_clicert = NULL;
1563
1564 if(backend->handle) {
1565 if(client_cert)
1566 /* A server might require different authentication based on the
1567 * particular path being requested by the client. To support this
1568 * scenario, we must ensure that a connection will never reuse the
1569 * authentication data from a previous connection. */
1570 SSL_InvalidateSession(backend->handle);
1571
1572 PR_Close(backend->handle);
1573 backend->handle = NULL;
1574 }
1575}
1576
1577/*
1578 * This function is called when an SSL connection is closed.
1579 */
1580static void nss_close(struct Curl_easy *data, struct connectdata *conn,
1581 int sockindex)
1582{
1583 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
1584#ifndef CURL_DISABLE_PROXY
1585 struct ssl_connect_data *connssl_proxy = &conn->proxy_ssl[sockindex];
1586#endif
1587 struct ssl_backend_data *backend = connssl->backend;
1588
1589 (void)data;
1590 if(backend->handle
1591#ifndef CURL_DISABLE_PROXY
1592 || connssl_proxy->backend->handle
1593#endif
1594 ) {
1595 /* NSS closes the socket we previously handed to it, so we must mark it
1596 as closed to avoid double close */
1597 fake_sclose(conn->sock[sockindex]);
1598 conn->sock[sockindex] = CURL_SOCKET_BAD;
1599 }
1600
1601#ifndef CURL_DISABLE_PROXY
1602 if(backend->handle)
1603 /* nss_close(connssl) will transitively close also
1604 connssl_proxy->backend->handle if both are used. Clear it to avoid
1605 a double close leading to crash. */
1606 connssl_proxy->backend->handle = NULL;
1607
1608 close_one(connssl_proxy);
1609#endif
1610 close_one(connssl);
1611}
1612
1613/* return true if NSS can provide error code (and possibly msg) for the
1614 error */
1615static bool is_nss_error(CURLcode err)
1616{
1617 switch(err) {
1618 case CURLE_PEER_FAILED_VERIFICATION:
1619 case CURLE_SSL_CERTPROBLEM:
1620 case CURLE_SSL_CONNECT_ERROR:
1621 case CURLE_SSL_ISSUER_ERROR:
1622 return true;
1623
1624 default:
1625 return false;
1626 }
1627}
1628
1629/* return true if the given error code is related to a client certificate */
1630static bool is_cc_error(PRInt32 err)
1631{
1632 switch(err) {
1633 case SSL_ERROR_BAD_CERT_ALERT:
1634 case SSL_ERROR_EXPIRED_CERT_ALERT:
1635 case SSL_ERROR_REVOKED_CERT_ALERT:
1636 return true;
1637
1638 default:
1639 return false;
1640 }
1641}
1642
1643static Curl_recv nss_recv;
1644static Curl_send nss_send;
1645
1646static CURLcode nss_load_ca_certificates(struct Curl_easy *data,
1647 struct connectdata *conn,
1648 int sockindex)
1649{
1650 const char *cafile = SSL_CONN_CONFIG(CAfile);
1651 const char *capath = SSL_CONN_CONFIG(CApath);
1652 bool use_trust_module;
1653 CURLcode result = CURLE_OK;
1654
1655 /* treat empty string as unset */
1656 if(cafile && !cafile[0])
1657 cafile = NULL;
1658 if(capath && !capath[0])
1659 capath = NULL;
1660
1661 infof(data, " CAfile: %s", cafile ? cafile : "none");
1662 infof(data, " CApath: %s", capath ? capath : "none");
1663
1664 /* load libnssckbi.so if no other trust roots were specified */
1665 use_trust_module = !cafile && !capath;
1666
1667 PR_Lock(nss_trustload_lock);
1668 if(use_trust_module && !trust_module) {
1669 /* libnssckbi.so needed but not yet loaded --> load it! */
1670 result = nss_load_module(&trust_module, trust_library, "trust");
1671 infof(data, "%s %s", (result) ? "failed to load" : "loaded",
1672 trust_library);
1673 if(result == CURLE_FAILED_INIT)
1674 /* If libnssckbi.so is not available (or fails to load), one can still
1675 use CA certificates stored in NSS database. Ignore the failure. */
1676 result = CURLE_OK;
1677 }
1678 else if(!use_trust_module && trust_module) {
1679 /* libnssckbi.so not needed but already loaded --> unload it! */
1680 infof(data, "unloading %s", trust_library);
1681 nss_unload_module(&trust_module);
1682 }
1683 PR_Unlock(nss_trustload_lock);
1684
1685 if(cafile)
1686 result = nss_load_cert(&conn->ssl[sockindex], cafile, PR_TRUE);
1687
1688 if(result)
1689 return result;
1690
1691 if(capath) {
1692 struct_stat st;
1693 if(stat(capath, &st) == -1)
1694 return CURLE_SSL_CACERT_BADFILE;
1695
1696 if(S_ISDIR(st.st_mode)) {
1697 PRDirEntry *entry;
1698 PRDir *dir = PR_OpenDir(capath);
1699 if(!dir)
1700 return CURLE_SSL_CACERT_BADFILE;
1701
1702 while((entry =
1703 PR_ReadDir(dir, (PRDirFlags)(PR_SKIP_BOTH | PR_SKIP_HIDDEN)))) {
1704 char *fullpath = aprintf("%s/%s", capath, entry->name);
1705 if(!fullpath) {
1706 PR_CloseDir(dir);
1707 return CURLE_OUT_OF_MEMORY;
1708 }
1709
1710 if(CURLE_OK != nss_load_cert(&conn->ssl[sockindex], fullpath, PR_TRUE))
1711 /* This is purposefully tolerant of errors so non-PEM files can
1712 * be in the same directory */
1713 infof(data, "failed to load '%s' from CURLOPT_CAPATH", fullpath);
1714
1715 free(fullpath);
1716 }
1717
1718 PR_CloseDir(dir);
1719 }
1720 else
1721 infof(data, "warning: CURLOPT_CAPATH not a directory (%s)", capath);
1722 }
1723
1724 return CURLE_OK;
1725}
1726
1727static CURLcode nss_sslver_from_curl(PRUint16 *nssver, long version)
1728{
1729 switch(version) {
1730 case CURL_SSLVERSION_SSLv2:
1731 *nssver = SSL_LIBRARY_VERSION_2;
1732 return CURLE_OK;
1733
1734 case CURL_SSLVERSION_SSLv3:
1735 return CURLE_NOT_BUILT_IN;
1736
1737 case CURL_SSLVERSION_TLSv1_0:
1738 *nssver = SSL_LIBRARY_VERSION_TLS_1_0;
1739 return CURLE_OK;
1740
1741 case CURL_SSLVERSION_TLSv1_1:
1742#ifdef SSL_LIBRARY_VERSION_TLS_1_1
1743 *nssver = SSL_LIBRARY_VERSION_TLS_1_1;
1744 return CURLE_OK;
1745#else
1746 return CURLE_SSL_CONNECT_ERROR;
1747#endif
1748
1749 case CURL_SSLVERSION_TLSv1_2:
1750#ifdef SSL_LIBRARY_VERSION_TLS_1_2
1751 *nssver = SSL_LIBRARY_VERSION_TLS_1_2;
1752 return CURLE_OK;
1753#else
1754 return CURLE_SSL_CONNECT_ERROR;
1755#endif
1756
1757 case CURL_SSLVERSION_TLSv1_3:
1758#ifdef SSL_LIBRARY_VERSION_TLS_1_3
1759 *nssver = SSL_LIBRARY_VERSION_TLS_1_3;
1760 return CURLE_OK;
1761#else
1762 return CURLE_SSL_CONNECT_ERROR;
1763#endif
1764
1765 default:
1766 return CURLE_SSL_CONNECT_ERROR;
1767 }
1768}
1769
1770static CURLcode nss_init_sslver(SSLVersionRange *sslver,
1771 struct Curl_easy *data,
1772 struct connectdata *conn)
1773{
1774 CURLcode result;
1775 const long min = SSL_CONN_CONFIG(version);
1776 const long max = SSL_CONN_CONFIG(version_max);
1777 SSLVersionRange vrange;
1778
1779 switch(min) {
1780 case CURL_SSLVERSION_TLSv1:
1781 case CURL_SSLVERSION_DEFAULT:
1782 /* Bump our minimum TLS version if NSS has stricter requirements. */
1783 if(SSL_VersionRangeGetDefault(ssl_variant_stream, &vrange) != SECSuccess)
1784 return CURLE_SSL_CONNECT_ERROR;
1785 if(sslver->min < vrange.min)
1786 sslver->min = vrange.min;
1787 break;
1788 default:
1789 result = nss_sslver_from_curl(&sslver->min, min);
1790 if(result) {
1791 failf(data, "unsupported min version passed via CURLOPT_SSLVERSION");
1792 return result;
1793 }
1794 }
1795
1796 switch(max) {
1797 case CURL_SSLVERSION_MAX_NONE:
1798 case CURL_SSLVERSION_MAX_DEFAULT:
1799 break;
1800 default:
1801 result = nss_sslver_from_curl(&sslver->max, max >> 16);
1802 if(result) {
1803 failf(data, "unsupported max version passed via CURLOPT_SSLVERSION");
1804 return result;
1805 }
1806 }
1807
1808 return CURLE_OK;
1809}
1810
1811static CURLcode nss_fail_connect(struct ssl_connect_data *connssl,
1812 struct Curl_easy *data,
1813 CURLcode curlerr)
1814{
1815 struct ssl_backend_data *backend = connssl->backend;
1816
1817 if(is_nss_error(curlerr)) {
1818 /* read NSPR error code */
1819 PRErrorCode err = PR_GetError();
1820 if(is_cc_error(err))
1821 curlerr = CURLE_SSL_CERTPROBLEM;
1822
1823 /* print the error number and error string */
1824 infof(data, "NSS error %d (%s)", err, nss_error_to_name(err));
1825
1826 /* print a human-readable message describing the error if available */
1827 nss_print_error_message(data, err);
1828 }
1829
1830 /* cleanup on connection failure */
1831 Curl_llist_destroy(&backend->obj_list, NULL);
1832
1833 return curlerr;
1834}
1835
1836/* Switch the SSL socket into blocking or non-blocking mode. */
1837static CURLcode nss_set_blocking(struct ssl_connect_data *connssl,
1838 struct Curl_easy *data,
1839 bool blocking)
1840{
1841 PRSocketOptionData sock_opt;
1842 struct ssl_backend_data *backend = connssl->backend;
1843 sock_opt.option = PR_SockOpt_Nonblocking;
1844 sock_opt.value.non_blocking = !blocking;
1845
1846 if(PR_SetSocketOption(backend->handle, &sock_opt) != PR_SUCCESS)
1847 return nss_fail_connect(connssl, data, CURLE_SSL_CONNECT_ERROR);
1848
1849 return CURLE_OK;
1850}
1851
1852static CURLcode nss_setup_connect(struct Curl_easy *data,
1853 struct connectdata *conn, int sockindex)
1854{
1855 PRFileDesc *model = NULL;
1856 PRFileDesc *nspr_io = NULL;
1857 PRFileDesc *nspr_io_stub = NULL;
1858 PRBool ssl_no_cache;
1859 PRBool ssl_cbc_random_iv;
1860 curl_socket_t sockfd = conn->sock[sockindex];
1861 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
1862 struct ssl_backend_data *backend = connssl->backend;
1863 CURLcode result;
1864 bool second_layer = FALSE;
1865 SSLVersionRange sslver_supported;
1866
1867 SSLVersionRange sslver = {
1868 SSL_LIBRARY_VERSION_TLS_1_0, /* min */
1869#ifdef SSL_LIBRARY_VERSION_TLS_1_3
1870 SSL_LIBRARY_VERSION_TLS_1_3 /* max */
1871#elif defined SSL_LIBRARY_VERSION_TLS_1_2
1872 SSL_LIBRARY_VERSION_TLS_1_2
1873#elif defined SSL_LIBRARY_VERSION_TLS_1_1
1874 SSL_LIBRARY_VERSION_TLS_1_1
1875#else
1876 SSL_LIBRARY_VERSION_TLS_1_0
1877#endif
1878 };
1879
1880 backend->data = data;
1881
1882 /* list of all NSS objects we need to destroy in nss_do_close() */
1883 Curl_llist_init(&backend->obj_list, nss_destroy_object);
1884
1885 PR_Lock(nss_initlock);
1886 result = nss_setup(data);
1887 if(result) {
1888 PR_Unlock(nss_initlock);
1889 goto error;
1890 }
1891
1892 PK11_SetPasswordFunc(nss_get_password);
1893
1894 result = nss_load_module(&pem_module, pem_library, "PEM");
1895 PR_Unlock(nss_initlock);
1896 if(result == CURLE_FAILED_INIT)
1897 infof(data, "WARNING: failed to load NSS PEM library %s. Using "
1898 "OpenSSL PEM certificates will not work.", pem_library);
1899 else if(result)
1900 goto error;
1901
1902 result = CURLE_SSL_CONNECT_ERROR;
1903
1904 model = PR_NewTCPSocket();
1905 if(!model)
1906 goto error;
1907 model = SSL_ImportFD(NULL, model);
1908
1909 if(SSL_OptionSet(model, SSL_SECURITY, PR_TRUE) != SECSuccess)
1910 goto error;
1911 if(SSL_OptionSet(model, SSL_HANDSHAKE_AS_SERVER, PR_FALSE) != SECSuccess)
1912 goto error;
1913 if(SSL_OptionSet(model, SSL_HANDSHAKE_AS_CLIENT, PR_TRUE) != SECSuccess)
1914 goto error;
1915
1916 /* do not use SSL cache if disabled or we are not going to verify peer */
1917 ssl_no_cache = (SSL_SET_OPTION(primary.sessionid)
1918 && SSL_CONN_CONFIG(verifypeer)) ? PR_FALSE : PR_TRUE;
1919 if(SSL_OptionSet(model, SSL_NO_CACHE, ssl_no_cache) != SECSuccess)
1920 goto error;
1921
1922 /* enable/disable the requested SSL version(s) */
1923 if(nss_init_sslver(&sslver, data, conn) != CURLE_OK)
1924 goto error;
1925 if(SSL_VersionRangeGetSupported(ssl_variant_stream,
1926 &sslver_supported) != SECSuccess)
1927 goto error;
1928 if(sslver_supported.max < sslver.max && sslver_supported.max >= sslver.min) {
1929 char *sslver_req_str, *sslver_supp_str;
1930 sslver_req_str = nss_sslver_to_name(sslver.max);
1931 sslver_supp_str = nss_sslver_to_name(sslver_supported.max);
1932 if(sslver_req_str && sslver_supp_str)
1933 infof(data, "Falling back from %s to max supported SSL version (%s)",
1934 sslver_req_str, sslver_supp_str);
1935 free(sslver_req_str);
1936 free(sslver_supp_str);
1937 sslver.max = sslver_supported.max;
1938 }
1939 if(SSL_VersionRangeSet(model, &sslver) != SECSuccess)
1940 goto error;
1941
1942 ssl_cbc_random_iv = !SSL_SET_OPTION(enable_beast);
1943#ifdef SSL_CBC_RANDOM_IV
1944 /* unless the user explicitly asks to allow the protocol vulnerability, we
1945 use the work-around */
1946 if(SSL_OptionSet(model, SSL_CBC_RANDOM_IV, ssl_cbc_random_iv) != SECSuccess)
1947 infof(data, "warning: failed to set SSL_CBC_RANDOM_IV = %d",
1948 ssl_cbc_random_iv);
1949#else
1950 if(ssl_cbc_random_iv)
1951 infof(data, "warning: support for SSL_CBC_RANDOM_IV not compiled in");
1952#endif
1953
1954 if(SSL_CONN_CONFIG(cipher_list)) {
1955 if(set_ciphers(data, model, SSL_CONN_CONFIG(cipher_list)) != SECSuccess) {
1956 result = CURLE_SSL_CIPHER;
1957 goto error;
1958 }
1959 }
1960
1961 if(!SSL_CONN_CONFIG(verifypeer) && SSL_CONN_CONFIG(verifyhost))
1962 infof(data, "warning: ignoring value of ssl.verifyhost");
1963
1964 /* bypass the default SSL_AuthCertificate() hook in case we do not want to
1965 * verify peer */
1966 if(SSL_AuthCertificateHook(model, nss_auth_cert_hook, data) != SECSuccess)
1967 goto error;
1968
1969 /* not checked yet */
1970 SSL_SET_OPTION_LVALUE(certverifyresult) = 0;
1971
1972 if(SSL_BadCertHook(model, BadCertHandler, data) != SECSuccess)
1973 goto error;
1974
1975 if(SSL_HandshakeCallback(model, HandshakeCallback, data) != SECSuccess)
1976 goto error;
1977
1978 {
1979 const CURLcode rv = nss_load_ca_certificates(data, conn, sockindex);
1980 if((rv == CURLE_SSL_CACERT_BADFILE) && !SSL_CONN_CONFIG(verifypeer))
1981 /* not a fatal error because we are not going to verify the peer */
1982 infof(data, "warning: CA certificates failed to load");
1983 else if(rv) {
1984 result = rv;
1985 goto error;
1986 }
1987 }
1988
1989 if(SSL_SET_OPTION(CRLfile)) {
1990 const CURLcode rv = nss_load_crl(SSL_SET_OPTION(CRLfile));
1991 if(rv) {
1992 result = rv;
1993 goto error;
1994 }
1995 infof(data, " CRLfile: %s", SSL_SET_OPTION(CRLfile));
1996 }
1997
1998 if(SSL_SET_OPTION(primary.clientcert)) {
1999 char *nickname = dup_nickname(data, SSL_SET_OPTION(primary.clientcert));
2000 if(nickname) {
2001 /* we are not going to use libnsspem.so to read the client cert */
2002 backend->obj_clicert = NULL;
2003 }
2004 else {
2005 CURLcode rv = cert_stuff(data, conn, sockindex,
2006 SSL_SET_OPTION(primary.clientcert),
2007 SSL_SET_OPTION(key));
2008 if(rv) {
2009 /* failf() is already done in cert_stuff() */
2010 result = rv;
2011 goto error;
2012 }
2013 }
2014
2015 /* store the nickname for SelectClientCert() called during handshake */
2016 backend->client_nickname = nickname;
2017 }
2018 else
2019 backend->client_nickname = NULL;
2020
2021 if(SSL_GetClientAuthDataHook(model, SelectClientCert,
2022 (void *)connssl) != SECSuccess) {
2023 result = CURLE_SSL_CERTPROBLEM;
2024 goto error;
2025 }
2026
2027#ifndef CURL_DISABLE_PROXY
2028 if(conn->proxy_ssl[sockindex].use) {
2029 DEBUGASSERT(ssl_connection_complete == conn->proxy_ssl[sockindex].state);
2030 DEBUGASSERT(conn->proxy_ssl[sockindex].backend->handle != NULL);
2031 nspr_io = conn->proxy_ssl[sockindex].backend->handle;
2032 second_layer = TRUE;
2033 }
2034#endif
2035 else {
2036 /* wrap OS file descriptor by NSPR's file descriptor abstraction */
2037 nspr_io = PR_ImportTCPSocket(sockfd);
2038 if(!nspr_io)
2039 goto error;
2040 }
2041
2042 /* create our own NSPR I/O layer */
2043 nspr_io_stub = PR_CreateIOLayerStub(nspr_io_identity, &nspr_io_methods);
2044 if(!nspr_io_stub) {
2045 if(!second_layer)
2046 PR_Close(nspr_io);
2047 goto error;
2048 }
2049
2050 /* make the per-connection data accessible from NSPR I/O callbacks */
2051 nspr_io_stub->secret = (void *)connssl;
2052
2053 /* push our new layer to the NSPR I/O stack */
2054 if(PR_PushIOLayer(nspr_io, PR_TOP_IO_LAYER, nspr_io_stub) != PR_SUCCESS) {
2055 if(!second_layer)
2056 PR_Close(nspr_io);
2057 PR_Close(nspr_io_stub);
2058 goto error;
2059 }
2060
2061 /* import our model socket onto the current I/O stack */
2062 backend->handle = SSL_ImportFD(model, nspr_io);
2063 if(!backend->handle) {
2064 if(!second_layer)
2065 PR_Close(nspr_io);
2066 goto error;
2067 }
2068
2069 PR_Close(model); /* We don't need this any more */
2070 model = NULL;
2071
2072 /* This is the password associated with the cert that we're using */
2073 if(SSL_SET_OPTION(key_passwd)) {
2074 SSL_SetPKCS11PinArg(backend->handle, SSL_SET_OPTION(key_passwd));
2075 }
2076
2077#ifdef SSL_ENABLE_OCSP_STAPLING
2078 if(SSL_CONN_CONFIG(verifystatus)) {
2079 if(SSL_OptionSet(backend->handle, SSL_ENABLE_OCSP_STAPLING, PR_TRUE)
2080 != SECSuccess)
2081 goto error;
2082 }
2083#endif
2084
2085#ifdef SSL_ENABLE_NPN
2086 if(SSL_OptionSet(backend->handle, SSL_ENABLE_NPN, conn->bits.tls_enable_npn
2087 ? PR_TRUE : PR_FALSE) != SECSuccess)
2088 goto error;
2089#endif
2090
2091#ifdef SSL_ENABLE_ALPN
2092 if(SSL_OptionSet(backend->handle, SSL_ENABLE_ALPN, conn->bits.tls_enable_alpn
2093 ? PR_TRUE : PR_FALSE) != SECSuccess)
2094 goto error;
2095#endif
2096
2097#if NSSVERNUM >= 0x030f04 /* 3.15.4 */
2098 if(data->set.ssl.falsestart) {
2099 if(SSL_OptionSet(backend->handle, SSL_ENABLE_FALSE_START, PR_TRUE)
2100 != SECSuccess)
2101 goto error;
2102
2103 if(SSL_SetCanFalseStartCallback(backend->handle, CanFalseStartCallback,
2104 data) != SECSuccess)
2105 goto error;
2106 }
2107#endif
2108
2109#if defined(SSL_ENABLE_NPN) || defined(SSL_ENABLE_ALPN)
2110 if(conn->bits.tls_enable_npn || conn->bits.tls_enable_alpn) {
2111 int cur = 0;
2112 unsigned char protocols[128];
2113
2114#ifdef USE_HTTP2
2115 if(data->state.httpwant >= CURL_HTTP_VERSION_2
2116#ifndef CURL_DISABLE_PROXY
2117 && (!SSL_IS_PROXY() || !conn->bits.tunnel_proxy)
2118#endif
2119 ) {
2120 protocols[cur++] = ALPN_H2_LENGTH;
2121 memcpy(&protocols[cur], ALPN_H2, ALPN_H2_LENGTH);
2122 cur += ALPN_H2_LENGTH;
2123 }
2124#endif
2125 protocols[cur++] = ALPN_HTTP_1_1_LENGTH;
2126 memcpy(&protocols[cur], ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH);
2127 cur += ALPN_HTTP_1_1_LENGTH;
2128
2129 if(SSL_SetNextProtoNego(backend->handle, protocols, cur) != SECSuccess)
2130 goto error;
2131 }
2132#endif
2133
2134
2135 /* Force handshake on next I/O */
2136 if(SSL_ResetHandshake(backend->handle, /* asServer */ PR_FALSE)
2137 != SECSuccess)
2138 goto error;
2139
2140 /* propagate hostname to the TLS layer */
2141 if(SSL_SetURL(backend->handle, SSL_HOST_NAME()) != SECSuccess)
2142 goto error;
2143
2144 /* prevent NSS from re-using the session for a different hostname */
2145 if(SSL_SetSockPeerID(backend->handle, SSL_HOST_NAME()) != SECSuccess)
2146 goto error;
2147
2148 return CURLE_OK;
2149
2150error:
2151 if(model)
2152 PR_Close(model);
2153
2154 return nss_fail_connect(connssl, data, result);
2155}
2156
2157static CURLcode nss_do_connect(struct Curl_easy *data,
2158 struct connectdata *conn, int sockindex)
2159{
2160 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
2161 struct ssl_backend_data *backend = connssl->backend;
2162 CURLcode result = CURLE_SSL_CONNECT_ERROR;
2163 PRUint32 timeout;
2164
2165 /* check timeout situation */
2166 const timediff_t time_left = Curl_timeleft(data, NULL, TRUE);
2167 if(time_left < 0) {
2168 failf(data, "timed out before SSL handshake");
2169 result = CURLE_OPERATION_TIMEDOUT;
2170 goto error;
2171 }
2172
2173 /* Force the handshake now */
2174 timeout = PR_MillisecondsToInterval((PRUint32) time_left);
2175 if(SSL_ForceHandshakeWithTimeout(backend->handle, timeout) != SECSuccess) {
2176 if(PR_GetError() == PR_WOULD_BLOCK_ERROR)
2177 /* blocking direction is updated by nss_update_connecting_state() */
2178 return CURLE_AGAIN;
2179 else if(SSL_SET_OPTION(certverifyresult) == SSL_ERROR_BAD_CERT_DOMAIN)
2180 result = CURLE_PEER_FAILED_VERIFICATION;
2181 else if(SSL_SET_OPTION(certverifyresult) != 0)
2182 result = CURLE_PEER_FAILED_VERIFICATION;
2183 goto error;
2184 }
2185
2186 result = display_conn_info(data, backend->handle);
2187 if(result)
2188 goto error;
2189
2190 if(SSL_CONN_CONFIG(issuercert)) {
2191 SECStatus ret = SECFailure;
2192 char *nickname = dup_nickname(data, SSL_CONN_CONFIG(issuercert));
2193 if(nickname) {
2194 /* we support only nicknames in case of issuercert for now */
2195 ret = check_issuer_cert(backend->handle, nickname);
2196 free(nickname);
2197 }
2198
2199 if(SECFailure == ret) {
2200 infof(data, "SSL certificate issuer check failed");
2201 result = CURLE_SSL_ISSUER_ERROR;
2202 goto error;
2203 }
2204 else {
2205 infof(data, "SSL certificate issuer check ok");
2206 }
2207 }
2208
2209 result = cmp_peer_pubkey(connssl, SSL_PINNED_PUB_KEY());
2210 if(result)
2211 /* status already printed */
2212 goto error;
2213
2214 return CURLE_OK;
2215
2216error:
2217 return nss_fail_connect(connssl, data, result);
2218}
2219
2220static CURLcode nss_connect_common(struct Curl_easy *data,
2221 struct connectdata *conn, int sockindex,
2222 bool *done)
2223{
2224 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
2225 const bool blocking = (done == NULL);
2226 CURLcode result;
2227
2228 if(connssl->state == ssl_connection_complete) {
2229 if(!blocking)
2230 *done = TRUE;
2231 return CURLE_OK;
2232 }
2233
2234 if(connssl->connecting_state == ssl_connect_1) {
2235 result = nss_setup_connect(data, conn, sockindex);
2236 if(result)
2237 /* we do not expect CURLE_AGAIN from nss_setup_connect() */
2238 return result;
2239
2240 connssl->connecting_state = ssl_connect_2;
2241 }
2242
2243 /* enable/disable blocking mode before handshake */
2244 result = nss_set_blocking(connssl, data, blocking);
2245 if(result)
2246 return result;
2247
2248 result = nss_do_connect(data, conn, sockindex);
2249 switch(result) {
2250 case CURLE_OK:
2251 break;
2252 case CURLE_AGAIN:
2253 if(!blocking)
2254 /* CURLE_AGAIN in non-blocking mode is not an error */
2255 return CURLE_OK;
2256 /* FALLTHROUGH */
2257 default:
2258 return result;
2259 }
2260
2261 if(blocking) {
2262 /* in blocking mode, set NSS non-blocking mode _after_ SSL handshake */
2263 result = nss_set_blocking(connssl, data, /* blocking */ FALSE);
2264 if(result)
2265 return result;
2266 }
2267 else
2268 /* signal completed SSL handshake */
2269 *done = TRUE;
2270
2271 connssl->state = ssl_connection_complete;
2272 conn->recv[sockindex] = nss_recv;
2273 conn->send[sockindex] = nss_send;
2274
2275 /* ssl_connect_done is never used outside, go back to the initial state */
2276 connssl->connecting_state = ssl_connect_1;
2277
2278 return CURLE_OK;
2279}
2280
2281static CURLcode nss_connect(struct Curl_easy *data, struct connectdata *conn,
2282 int sockindex)
2283{
2284 return nss_connect_common(data, conn, sockindex, /* blocking */ NULL);
2285}
2286
2287static CURLcode nss_connect_nonblocking(struct Curl_easy *data,
2288 struct connectdata *conn,
2289 int sockindex, bool *done)
2290{
2291 return nss_connect_common(data, conn, sockindex, done);
2292}
2293
2294static ssize_t nss_send(struct Curl_easy *data, /* transfer */
2295 int sockindex, /* socketindex */
2296 const void *mem, /* send this data */
2297 size_t len, /* amount to write */
2298 CURLcode *curlcode)
2299{
2300 struct connectdata *conn = data->conn;
2301 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
2302 struct ssl_backend_data *backend = connssl->backend;
2303 ssize_t rc;
2304
2305 /* The SelectClientCert() hook uses this for infof() and failf() but the
2306 handle stored in nss_setup_connect() could have already been freed. */
2307 backend->data = data;
2308
2309 rc = PR_Send(backend->handle, mem, (int)len, 0, PR_INTERVAL_NO_WAIT);
2310 if(rc < 0) {
2311 PRInt32 err = PR_GetError();
2312 if(err == PR_WOULD_BLOCK_ERROR)
2313 *curlcode = CURLE_AGAIN;
2314 else {
2315 /* print the error number and error string */
2316 const char *err_name = nss_error_to_name(err);
2317 infof(data, "SSL write: error %d (%s)", err, err_name);
2318
2319 /* print a human-readable message describing the error if available */
2320 nss_print_error_message(data, err);
2321
2322 *curlcode = (is_cc_error(err))
2323 ? CURLE_SSL_CERTPROBLEM
2324 : CURLE_SEND_ERROR;
2325 }
2326
2327 return -1;
2328 }
2329
2330 return rc; /* number of bytes */
2331}
2332
2333static ssize_t nss_recv(struct Curl_easy *data, /* transfer */
2334 int sockindex, /* socketindex */
2335 char *buf, /* store read data here */
2336 size_t buffersize, /* max amount to read */
2337 CURLcode *curlcode)
2338{
2339 struct connectdata *conn = data->conn;
2340 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
2341 struct ssl_backend_data *backend = connssl->backend;
2342 ssize_t nread;
2343
2344 /* The SelectClientCert() hook uses this for infof() and failf() but the
2345 handle stored in nss_setup_connect() could have already been freed. */
2346 backend->data = data;
2347
2348 nread = PR_Recv(backend->handle, buf, (int)buffersize, 0,
2349 PR_INTERVAL_NO_WAIT);
2350 if(nread < 0) {
2351 /* failed SSL read */
2352 PRInt32 err = PR_GetError();
2353
2354 if(err == PR_WOULD_BLOCK_ERROR)
2355 *curlcode = CURLE_AGAIN;
2356 else {
2357 /* print the error number and error string */
2358 const char *err_name = nss_error_to_name(err);
2359 infof(data, "SSL read: errno %d (%s)", err, err_name);
2360
2361 /* print a human-readable message describing the error if available */
2362 nss_print_error_message(data, err);
2363
2364 *curlcode = (is_cc_error(err))
2365 ? CURLE_SSL_CERTPROBLEM
2366 : CURLE_RECV_ERROR;
2367 }
2368
2369 return -1;
2370 }
2371
2372 return nread;
2373}
2374
2375static size_t nss_version(char *buffer, size_t size)
2376{
2377 return msnprintf(buffer, size, "NSS/%s", NSS_GetVersion());
2378}
2379
2380/* data might be NULL */
2381static int Curl_nss_seed(struct Curl_easy *data)
2382{
2383 /* make sure that NSS is initialized */
2384 return !!Curl_nss_force_init(data);
2385}
2386
2387/* data might be NULL */
2388static CURLcode nss_random(struct Curl_easy *data,
2389 unsigned char *entropy,
2390 size_t length)
2391{
2392 Curl_nss_seed(data); /* Initiate the seed if not already done */
2393
2394 if(SECSuccess != PK11_GenerateRandom(entropy, curlx_uztosi(length)))
2395 /* signal a failure */
2396 return CURLE_FAILED_INIT;
2397
2398 return CURLE_OK;
2399}
2400
2401static CURLcode nss_sha256sum(const unsigned char *tmp, /* input */
2402 size_t tmplen,
2403 unsigned char *sha256sum, /* output */
2404 size_t sha256len)
2405{
2406 PK11Context *SHA256pw = PK11_CreateDigestContext(SEC_OID_SHA256);
2407 unsigned int SHA256out;
2408
2409 if(!SHA256pw)
2410 return CURLE_NOT_BUILT_IN;
2411
2412 PK11_DigestOp(SHA256pw, tmp, curlx_uztoui(tmplen));
2413 PK11_DigestFinal(SHA256pw, sha256sum, &SHA256out, curlx_uztoui(sha256len));
2414 PK11_DestroyContext(SHA256pw, PR_TRUE);
2415
2416 return CURLE_OK;
2417}
2418
2419static bool nss_cert_status_request(void)
2420{
2421#ifdef SSL_ENABLE_OCSP_STAPLING
2422 return TRUE;
2423#else
2424 return FALSE;
2425#endif
2426}
2427
2428static bool nss_false_start(void)
2429{
2430#if NSSVERNUM >= 0x030f04 /* 3.15.4 */
2431 return TRUE;
2432#else
2433 return FALSE;
2434#endif
2435}
2436
2437static void *nss_get_internals(struct ssl_connect_data *connssl,
2438 CURLINFO info UNUSED_PARAM)
2439{
2440 struct ssl_backend_data *backend = connssl->backend;
2441 (void)info;
2442 return backend->handle;
2443}
2444
2445const struct Curl_ssl Curl_ssl_nss = {
2446 { CURLSSLBACKEND_NSS, "nss" }, /* info */
2447
2448 SSLSUPP_CA_PATH |
2449 SSLSUPP_CERTINFO |
2450 SSLSUPP_PINNEDPUBKEY |
2451 SSLSUPP_HTTPS_PROXY,
2452
2453 sizeof(struct ssl_backend_data),
2454
2455 nss_init, /* init */
2456 nss_cleanup, /* cleanup */
2457 nss_version, /* version */
2458 nss_check_cxn, /* check_cxn */
2459 /* NSS has no shutdown function provided and thus always fail */
2460 Curl_none_shutdown, /* shutdown */
2461 Curl_none_data_pending, /* data_pending */
2462 nss_random, /* random */
2463 nss_cert_status_request, /* cert_status_request */
2464 nss_connect, /* connect */
2465 nss_connect_nonblocking, /* connect_nonblocking */
2466 Curl_ssl_getsock, /* getsock */
2467 nss_get_internals, /* get_internals */
2468 nss_close, /* close_one */
2469 Curl_none_close_all, /* close_all */
2470 /* NSS has its own session ID cache */
2471 Curl_none_session_free, /* session_free */
2472 Curl_none_set_engine, /* set_engine */
2473 Curl_none_set_engine_default, /* set_engine_default */
2474 Curl_none_engines_list, /* engines_list */
2475 nss_false_start, /* false_start */
2476 nss_sha256sum, /* sha256sum */
2477 NULL, /* associate_connection */
2478 NULL /* disassociate_connection */
2479};
2480
2481#endif /* USE_NSS */
2482