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
82 struct 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
90 static PRLock *nss_initlock = NULL;
91 static PRLock *nss_crllock = NULL;
92 static PRLock *nss_findslot_lock = NULL;
93 static PRLock *nss_trustload_lock = NULL;
94 static struct Curl_llist nss_crl_list;
95 static NSSInitContext *nss_context = NULL;
96 static volatile int initialized = 0;
97
98 /* type used to wrap pointers as list nodes */
99 struct ptr_list_wrap {
100 void *ptr;
101 struct Curl_llist_element node;
102 };
103
104 struct 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])
119 static 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)
250 static const char *pem_library = "nsspem.dll";
251 static const char *trust_library = "nssckbi.dll";
252 #elif defined(__APPLE__)
253 static const char *pem_library = "libnsspem.dylib";
254 static const char *trust_library = "libnssckbi.dylib";
255 #else
256 static const char *pem_library = "libnsspem.so";
257 static const char *trust_library = "libnssckbi.so";
258 #endif
259
260 static SECMODModule *pem_module = NULL;
261 static SECMODModule *trust_module = NULL;
262
263 /* NSPR I/O layer we use to detect blocking direction during SSL handshake */
264 static PRDescIdentity nspr_io_identity = PR_INVALID_IO_LAYER;
265 static PRIOMethods nspr_io_methods;
266
nss_error_to_name(PRErrorCode code)267 static 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
nss_print_error_message(struct Curl_easy * data,PRUint32 err)276 static 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
nss_sslver_to_name(PRUint16 nssver)281 static 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
set_ciphers(struct Curl_easy * data,PRFileDesc * model,char * cipher_list)307 static 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 */
any_cipher_enabled(void)383 static 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 */
is_file(const char * filename)404 static 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 */
dup_nickname(struct Curl_easy * data,const char * str)424 static 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 */
nss_find_slot_by_name(const char * slot_name)448 static 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' */
insert_wrapped_ptr(struct Curl_llist * list,void * ptr)458 static 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(). */
nss_create_object(struct ssl_connect_data * connssl,CK_OBJECT_CLASS obj_class,const char * filename,bool cacert)472 static 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() */
nss_destroy_object(void * user,void * ptr)537 static 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 */
nss_destroy_crl_item(void * user,void * ptr)547 static 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
nss_load_cert(struct ssl_connect_data * ssl,const char * filename,PRBool cacert)556 static 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 */
nss_cache_crl(SECItem * crl_der)593 static 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
nss_load_crl(const char * crlfilename)628 static 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
685 fail:
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
nss_load_key(struct Curl_easy * data,struct connectdata * conn,int sockindex,char * key_file)692 static 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
display_error(struct Curl_easy * data,PRInt32 err,const char * filename)727 static 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
cert_stuff(struct Curl_easy * data,struct connectdata * conn,int sockindex,char * cert_file,char * key_file)743 static 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
nss_get_password(PK11SlotInfo * slot,PRBool retry,void * arg)781 static 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 */
nss_auth_cert_hook(void * arg,PRFileDesc * fd,PRBool checksig,PRBool isServer)793 static 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 */
HandshakeCallback(PRFileDesc * sock,void * arg)837 static 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 */
CanFalseStartCallback(PRFileDesc * sock,void * client_data,PRBool * canFalseStart)889 static 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
942 end:
943 return SECSuccess;
944 }
945 #endif
946
display_cert_info(struct Curl_easy * data,CERTCertificate * cert)947 static 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, ¬Before, ¬After);
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
975 /* A number of certs that will never occur in a real server handshake */
976 #define TOO_MANY_CERTS 300
977
display_conn_info(struct Curl_easy * data,PRFileDesc * sock)978 static CURLcode display_conn_info(struct Curl_easy *data, PRFileDesc *sock)
979 {
980 CURLcode result = CURLE_OK;
981 SSLChannelInfo channel;
982 SSLCipherSuiteInfo suite;
983 CERTCertificate *cert;
984 CERTCertificate *cert2;
985 CERTCertificate *cert3;
986 PRTime now;
987
988 if(SSL_GetChannelInfo(sock, &channel, sizeof(channel)) ==
989 SECSuccess && channel.length == sizeof(channel) &&
990 channel.cipherSuite) {
991 if(SSL_GetCipherSuiteInfo(channel.cipherSuite,
992 &suite, sizeof(suite)) == SECSuccess) {
993 infof(data, "SSL connection using %s", suite.cipherSuiteName);
994 }
995 }
996
997 cert = SSL_PeerCertificate(sock);
998 if(cert) {
999 infof(data, "Server certificate:");
1000
1001 if(!data->set.ssl.certinfo) {
1002 display_cert_info(data, cert);
1003 CERT_DestroyCertificate(cert);
1004 }
1005 else {
1006 /* Count certificates in chain. */
1007 int i = 1;
1008 now = PR_Now();
1009 if(!cert->isRoot) {
1010 cert2 = CERT_FindCertIssuer(cert, now, certUsageSSLCA);
1011 while(cert2) {
1012 i++;
1013 if(i >= TOO_MANY_CERTS) {
1014 CERT_DestroyCertificate(cert2);
1015 failf(data, "certificate loop");
1016 return CURLE_SSL_CERTPROBLEM;
1017 }
1018 if(cert2->isRoot) {
1019 CERT_DestroyCertificate(cert2);
1020 break;
1021 }
1022 cert3 = CERT_FindCertIssuer(cert2, now, certUsageSSLCA);
1023 CERT_DestroyCertificate(cert2);
1024 cert2 = cert3;
1025 }
1026 }
1027
1028 result = Curl_ssl_init_certinfo(data, i);
1029 if(!result) {
1030 for(i = 0; cert; cert = cert2) {
1031 result = Curl_extract_certinfo(data, i++, (char *)cert->derCert.data,
1032 (char *)cert->derCert.data +
1033 cert->derCert.len);
1034 if(result)
1035 break;
1036
1037 if(cert->isRoot) {
1038 CERT_DestroyCertificate(cert);
1039 break;
1040 }
1041
1042 cert2 = CERT_FindCertIssuer(cert, now, certUsageSSLCA);
1043 CERT_DestroyCertificate(cert);
1044 }
1045 }
1046 }
1047 }
1048
1049 return result;
1050 }
1051
BadCertHandler(void * arg,PRFileDesc * sock)1052 static SECStatus BadCertHandler(void *arg, PRFileDesc *sock)
1053 {
1054 struct Curl_easy *data = (struct Curl_easy *)arg;
1055 struct connectdata *conn = data->conn;
1056 PRErrorCode err = PR_GetError();
1057 CERTCertificate *cert;
1058
1059 /* remember the cert verification result */
1060 SSL_SET_OPTION_LVALUE(certverifyresult) = err;
1061
1062 if(err == SSL_ERROR_BAD_CERT_DOMAIN && !SSL_CONN_CONFIG(verifyhost))
1063 /* we are asked not to verify the host name */
1064 return SECSuccess;
1065
1066 /* print only info about the cert, the error is printed off the callback */
1067 cert = SSL_PeerCertificate(sock);
1068 if(cert) {
1069 infof(data, "Server certificate:");
1070 display_cert_info(data, cert);
1071 CERT_DestroyCertificate(cert);
1072 }
1073
1074 return SECFailure;
1075 }
1076
1077 /**
1078 *
1079 * Check that the Peer certificate's issuer certificate matches the one found
1080 * by issuer_nickname. This is not exactly the way OpenSSL and GNU TLS do the
1081 * issuer check, so we provide comments that mimic the OpenSSL
1082 * X509_check_issued function (in x509v3/v3_purp.c)
1083 */
check_issuer_cert(PRFileDesc * sock,char * issuer_nickname)1084 static SECStatus check_issuer_cert(PRFileDesc *sock,
1085 char *issuer_nickname)
1086 {
1087 CERTCertificate *cert, *cert_issuer, *issuer;
1088 SECStatus res = SECSuccess;
1089 void *proto_win = NULL;
1090
1091 cert = SSL_PeerCertificate(sock);
1092 cert_issuer = CERT_FindCertIssuer(cert, PR_Now(), certUsageObjectSigner);
1093
1094 proto_win = SSL_RevealPinArg(sock);
1095 issuer = PK11_FindCertFromNickname(issuer_nickname, proto_win);
1096
1097 if((!cert_issuer) || (!issuer))
1098 res = SECFailure;
1099 else if(SECITEM_CompareItem(&cert_issuer->derCert,
1100 &issuer->derCert) != SECEqual)
1101 res = SECFailure;
1102
1103 CERT_DestroyCertificate(cert);
1104 CERT_DestroyCertificate(issuer);
1105 CERT_DestroyCertificate(cert_issuer);
1106 return res;
1107 }
1108
cmp_peer_pubkey(struct ssl_connect_data * connssl,const char * pinnedpubkey)1109 static CURLcode cmp_peer_pubkey(struct ssl_connect_data *connssl,
1110 const char *pinnedpubkey)
1111 {
1112 CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH;
1113 struct ssl_backend_data *backend = connssl->backend;
1114 struct Curl_easy *data = backend->data;
1115 CERTCertificate *cert;
1116
1117 if(!pinnedpubkey)
1118 /* no pinned public key specified */
1119 return CURLE_OK;
1120
1121 /* get peer certificate */
1122 cert = SSL_PeerCertificate(backend->handle);
1123 if(cert) {
1124 /* extract public key from peer certificate */
1125 SECKEYPublicKey *pubkey = CERT_ExtractPublicKey(cert);
1126 if(pubkey) {
1127 /* encode the public key as DER */
1128 SECItem *cert_der = PK11_DEREncodePublicKey(pubkey);
1129 if(cert_der) {
1130 /* compare the public key with the pinned public key */
1131 result = Curl_pin_peer_pubkey(data, pinnedpubkey, cert_der->data,
1132 cert_der->len);
1133 SECITEM_FreeItem(cert_der, PR_TRUE);
1134 }
1135 SECKEY_DestroyPublicKey(pubkey);
1136 }
1137 CERT_DestroyCertificate(cert);
1138 }
1139
1140 /* report the resulting status */
1141 switch(result) {
1142 case CURLE_OK:
1143 infof(data, "pinned public key verified successfully!");
1144 break;
1145 case CURLE_SSL_PINNEDPUBKEYNOTMATCH:
1146 failf(data, "failed to verify pinned public key");
1147 break;
1148 default:
1149 /* OOM, etc. */
1150 break;
1151 }
1152
1153 return result;
1154 }
1155
1156 /**
1157 *
1158 * Callback to pick the SSL client certificate.
1159 */
SelectClientCert(void * arg,PRFileDesc * sock,struct CERTDistNamesStr * caNames,struct CERTCertificateStr ** pRetCert,struct SECKEYPrivateKeyStr ** pRetKey)1160 static SECStatus SelectClientCert(void *arg, PRFileDesc *sock,
1161 struct CERTDistNamesStr *caNames,
1162 struct CERTCertificateStr **pRetCert,
1163 struct SECKEYPrivateKeyStr **pRetKey)
1164 {
1165 struct ssl_connect_data *connssl = (struct ssl_connect_data *)arg;
1166 struct ssl_backend_data *backend = connssl->backend;
1167 struct Curl_easy *data = backend->data;
1168 const char *nickname = backend->client_nickname;
1169 static const char pem_slotname[] = "PEM Token #1";
1170
1171 if(backend->obj_clicert) {
1172 /* use the cert/key provided by PEM reader */
1173 SECItem cert_der = { 0, NULL, 0 };
1174 void *proto_win = SSL_RevealPinArg(sock);
1175 struct CERTCertificateStr *cert;
1176 struct SECKEYPrivateKeyStr *key;
1177
1178 PK11SlotInfo *slot = nss_find_slot_by_name(pem_slotname);
1179 if(NULL == slot) {
1180 failf(data, "NSS: PK11 slot not found: %s", pem_slotname);
1181 return SECFailure;
1182 }
1183
1184 if(PK11_ReadRawAttribute(PK11_TypeGeneric, backend->obj_clicert, CKA_VALUE,
1185 &cert_der) != SECSuccess) {
1186 failf(data, "NSS: CKA_VALUE not found in PK11 generic object");
1187 PK11_FreeSlot(slot);
1188 return SECFailure;
1189 }
1190
1191 cert = PK11_FindCertFromDERCertItem(slot, &cert_der, proto_win);
1192 SECITEM_FreeItem(&cert_der, PR_FALSE);
1193 if(NULL == cert) {
1194 failf(data, "NSS: client certificate from file not found");
1195 PK11_FreeSlot(slot);
1196 return SECFailure;
1197 }
1198
1199 key = PK11_FindPrivateKeyFromCert(slot, cert, NULL);
1200 PK11_FreeSlot(slot);
1201 if(NULL == key) {
1202 failf(data, "NSS: private key from file not found");
1203 CERT_DestroyCertificate(cert);
1204 return SECFailure;
1205 }
1206
1207 infof(data, "NSS: client certificate from file");
1208 display_cert_info(data, cert);
1209
1210 *pRetCert = cert;
1211 *pRetKey = key;
1212 return SECSuccess;
1213 }
1214
1215 /* use the default NSS hook */
1216 if(SECSuccess != NSS_GetClientAuthData((void *)nickname, sock, caNames,
1217 pRetCert, pRetKey)
1218 || NULL == *pRetCert) {
1219
1220 if(NULL == nickname)
1221 failf(data, "NSS: client certificate not found (nickname not "
1222 "specified)");
1223 else
1224 failf(data, "NSS: client certificate not found: %s", nickname);
1225
1226 return SECFailure;
1227 }
1228
1229 /* get certificate nickname if any */
1230 nickname = (*pRetCert)->nickname;
1231 if(NULL == nickname)
1232 nickname = "[unknown]";
1233
1234 if(!strncmp(nickname, pem_slotname, sizeof(pem_slotname) - 1U)) {
1235 failf(data, "NSS: refusing previously loaded certificate from file: %s",
1236 nickname);
1237 return SECFailure;
1238 }
1239
1240 if(NULL == *pRetKey) {
1241 failf(data, "NSS: private key not found for certificate: %s", nickname);
1242 return SECFailure;
1243 }
1244
1245 infof(data, "NSS: using client certificate: %s", nickname);
1246 display_cert_info(data, *pRetCert);
1247 return SECSuccess;
1248 }
1249
1250 /* update blocking direction in case of PR_WOULD_BLOCK_ERROR */
nss_update_connecting_state(ssl_connect_state state,void * secret)1251 static void nss_update_connecting_state(ssl_connect_state state, void *secret)
1252 {
1253 struct ssl_connect_data *connssl = (struct ssl_connect_data *)secret;
1254 if(PR_GetError() != PR_WOULD_BLOCK_ERROR)
1255 /* an unrelated error is passing by */
1256 return;
1257
1258 switch(connssl->connecting_state) {
1259 case ssl_connect_2:
1260 case ssl_connect_2_reading:
1261 case ssl_connect_2_writing:
1262 break;
1263 default:
1264 /* we are not called from an SSL handshake */
1265 return;
1266 }
1267
1268 /* update the state accordingly */
1269 connssl->connecting_state = state;
1270 }
1271
1272 /* recv() wrapper we use to detect blocking direction during SSL handshake */
nspr_io_recv(PRFileDesc * fd,void * buf,PRInt32 amount,PRIntn flags,PRIntervalTime timeout)1273 static PRInt32 nspr_io_recv(PRFileDesc *fd, void *buf, PRInt32 amount,
1274 PRIntn flags, PRIntervalTime timeout)
1275 {
1276 const PRRecvFN recv_fn = fd->lower->methods->recv;
1277 const PRInt32 rv = recv_fn(fd->lower, buf, amount, flags, timeout);
1278 if(rv < 0)
1279 /* check for PR_WOULD_BLOCK_ERROR and update blocking direction */
1280 nss_update_connecting_state(ssl_connect_2_reading, fd->secret);
1281 return rv;
1282 }
1283
1284 /* send() wrapper we use to detect blocking direction during SSL handshake */
nspr_io_send(PRFileDesc * fd,const void * buf,PRInt32 amount,PRIntn flags,PRIntervalTime timeout)1285 static PRInt32 nspr_io_send(PRFileDesc *fd, const void *buf, PRInt32 amount,
1286 PRIntn flags, PRIntervalTime timeout)
1287 {
1288 const PRSendFN send_fn = fd->lower->methods->send;
1289 const PRInt32 rv = send_fn(fd->lower, buf, amount, flags, timeout);
1290 if(rv < 0)
1291 /* check for PR_WOULD_BLOCK_ERROR and update blocking direction */
1292 nss_update_connecting_state(ssl_connect_2_writing, fd->secret);
1293 return rv;
1294 }
1295
1296 /* close() wrapper to avoid assertion failure due to fd->secret != NULL */
nspr_io_close(PRFileDesc * fd)1297 static PRStatus nspr_io_close(PRFileDesc *fd)
1298 {
1299 const PRCloseFN close_fn = PR_GetDefaultIOMethods()->close;
1300 fd->secret = NULL;
1301 return close_fn(fd);
1302 }
1303
1304 /* load a PKCS #11 module */
nss_load_module(SECMODModule ** pmod,const char * library,const char * name)1305 static CURLcode nss_load_module(SECMODModule **pmod, const char *library,
1306 const char *name)
1307 {
1308 char *config_string;
1309 SECMODModule *module = *pmod;
1310 if(module)
1311 /* already loaded */
1312 return CURLE_OK;
1313
1314 config_string = aprintf("library=%s name=%s", library, name);
1315 if(!config_string)
1316 return CURLE_OUT_OF_MEMORY;
1317
1318 module = SECMOD_LoadUserModule(config_string, NULL, PR_FALSE);
1319 free(config_string);
1320
1321 if(module && module->loaded) {
1322 /* loaded successfully */
1323 *pmod = module;
1324 return CURLE_OK;
1325 }
1326
1327 if(module)
1328 SECMOD_DestroyModule(module);
1329 return CURLE_FAILED_INIT;
1330 }
1331
1332 /* unload a PKCS #11 module */
nss_unload_module(SECMODModule ** pmod)1333 static void nss_unload_module(SECMODModule **pmod)
1334 {
1335 SECMODModule *module = *pmod;
1336 if(!module)
1337 /* not loaded */
1338 return;
1339
1340 if(SECMOD_UnloadUserModule(module) != SECSuccess)
1341 /* unload failed */
1342 return;
1343
1344 SECMOD_DestroyModule(module);
1345 *pmod = NULL;
1346 }
1347
1348 /* data might be NULL */
nss_init_core(struct Curl_easy * data,const char * cert_dir)1349 static CURLcode nss_init_core(struct Curl_easy *data, const char *cert_dir)
1350 {
1351 NSSInitParameters initparams;
1352 PRErrorCode err;
1353 const char *err_name;
1354
1355 if(nss_context != NULL)
1356 return CURLE_OK;
1357
1358 memset((void *) &initparams, '\0', sizeof(initparams));
1359 initparams.length = sizeof(initparams);
1360
1361 if(cert_dir) {
1362 char *certpath = aprintf("sql:%s", cert_dir);
1363 if(!certpath)
1364 return CURLE_OUT_OF_MEMORY;
1365
1366 infof(data, "Initializing NSS with certpath: %s", certpath);
1367 nss_context = NSS_InitContext(certpath, "", "", "", &initparams,
1368 NSS_INIT_READONLY | NSS_INIT_PK11RELOAD);
1369 free(certpath);
1370
1371 if(nss_context != NULL)
1372 return CURLE_OK;
1373
1374 err = PR_GetError();
1375 err_name = nss_error_to_name(err);
1376 infof(data, "Unable to initialize NSS database: %d (%s)", err, err_name);
1377 }
1378
1379 infof(data, "Initializing NSS with certpath: none");
1380 nss_context = NSS_InitContext("", "", "", "", &initparams, NSS_INIT_READONLY
1381 | NSS_INIT_NOCERTDB | NSS_INIT_NOMODDB | NSS_INIT_FORCEOPEN
1382 | NSS_INIT_NOROOTINIT | NSS_INIT_OPTIMIZESPACE | NSS_INIT_PK11RELOAD);
1383 if(nss_context != NULL)
1384 return CURLE_OK;
1385
1386 err = PR_GetError();
1387 err_name = nss_error_to_name(err);
1388 failf(data, "Unable to initialize NSS: %d (%s)", err, err_name);
1389 return CURLE_SSL_CACERT_BADFILE;
1390 }
1391
1392 /* data might be NULL */
nss_setup(struct Curl_easy * data)1393 static CURLcode nss_setup(struct Curl_easy *data)
1394 {
1395 char *cert_dir;
1396 struct_stat st;
1397 CURLcode result;
1398
1399 if(initialized)
1400 return CURLE_OK;
1401
1402 /* list of all CRL items we need to destroy in nss_cleanup() */
1403 Curl_llist_init(&nss_crl_list, nss_destroy_crl_item);
1404
1405 /* First we check if $SSL_DIR points to a valid dir */
1406 cert_dir = getenv("SSL_DIR");
1407 if(cert_dir) {
1408 if((stat(cert_dir, &st) != 0) ||
1409 (!S_ISDIR(st.st_mode))) {
1410 cert_dir = NULL;
1411 }
1412 }
1413
1414 /* Now we check if the default location is a valid dir */
1415 if(!cert_dir) {
1416 if((stat(SSL_DIR, &st) == 0) &&
1417 (S_ISDIR(st.st_mode))) {
1418 cert_dir = (char *)SSL_DIR;
1419 }
1420 }
1421
1422 if(nspr_io_identity == PR_INVALID_IO_LAYER) {
1423 /* allocate an identity for our own NSPR I/O layer */
1424 nspr_io_identity = PR_GetUniqueIdentity("libcurl");
1425 if(nspr_io_identity == PR_INVALID_IO_LAYER)
1426 return CURLE_OUT_OF_MEMORY;
1427
1428 /* the default methods just call down to the lower I/O layer */
1429 memcpy(&nspr_io_methods, PR_GetDefaultIOMethods(),
1430 sizeof(nspr_io_methods));
1431
1432 /* override certain methods in the table by our wrappers */
1433 nspr_io_methods.recv = nspr_io_recv;
1434 nspr_io_methods.send = nspr_io_send;
1435 nspr_io_methods.close = nspr_io_close;
1436 }
1437
1438 result = nss_init_core(data, cert_dir);
1439 if(result)
1440 return result;
1441
1442 if(!any_cipher_enabled())
1443 NSS_SetDomesticPolicy();
1444
1445 initialized = 1;
1446
1447 return CURLE_OK;
1448 }
1449
1450 /**
1451 * Global SSL init
1452 *
1453 * @retval 0 error initializing SSL
1454 * @retval 1 SSL initialized successfully
1455 */
nss_init(void)1456 static int nss_init(void)
1457 {
1458 /* curl_global_init() is not thread-safe so this test is ok */
1459 if(!nss_initlock) {
1460 PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
1461 nss_initlock = PR_NewLock();
1462 nss_crllock = PR_NewLock();
1463 nss_findslot_lock = PR_NewLock();
1464 nss_trustload_lock = PR_NewLock();
1465 }
1466
1467 /* We will actually initialize NSS later */
1468
1469 return 1;
1470 }
1471
1472 /* data might be NULL */
Curl_nss_force_init(struct Curl_easy * data)1473 CURLcode Curl_nss_force_init(struct Curl_easy *data)
1474 {
1475 CURLcode result;
1476 if(!nss_initlock) {
1477 if(data)
1478 failf(data, "unable to initialize NSS, curl_global_init() should have "
1479 "been called with CURL_GLOBAL_SSL or CURL_GLOBAL_ALL");
1480 return CURLE_FAILED_INIT;
1481 }
1482
1483 PR_Lock(nss_initlock);
1484 result = nss_setup(data);
1485 PR_Unlock(nss_initlock);
1486
1487 return result;
1488 }
1489
1490 /* Global cleanup */
nss_cleanup(void)1491 static void nss_cleanup(void)
1492 {
1493 /* This function isn't required to be threadsafe and this is only done
1494 * as a safety feature.
1495 */
1496 PR_Lock(nss_initlock);
1497 if(initialized) {
1498 /* Free references to client certificates held in the SSL session cache.
1499 * Omitting this hampers destruction of the security module owning
1500 * the certificates. */
1501 SSL_ClearSessionCache();
1502
1503 nss_unload_module(&pem_module);
1504 nss_unload_module(&trust_module);
1505 NSS_ShutdownContext(nss_context);
1506 nss_context = NULL;
1507 }
1508
1509 /* destroy all CRL items */
1510 Curl_llist_destroy(&nss_crl_list, NULL);
1511
1512 PR_Unlock(nss_initlock);
1513
1514 PR_DestroyLock(nss_initlock);
1515 PR_DestroyLock(nss_crllock);
1516 PR_DestroyLock(nss_findslot_lock);
1517 PR_DestroyLock(nss_trustload_lock);
1518 nss_initlock = NULL;
1519
1520 initialized = 0;
1521 }
1522
1523 /*
1524 * This function uses SSL_peek to determine connection status.
1525 *
1526 * Return codes:
1527 * 1 means the connection is still in place
1528 * 0 means the connection has been closed
1529 * -1 means the connection status is unknown
1530 */
nss_check_cxn(struct connectdata * conn)1531 static int nss_check_cxn(struct connectdata *conn)
1532 {
1533 struct ssl_connect_data *connssl = &conn->ssl[FIRSTSOCKET];
1534 struct ssl_backend_data *backend = connssl->backend;
1535 int rc;
1536 char buf;
1537
1538 rc =
1539 PR_Recv(backend->handle, (void *)&buf, 1, PR_MSG_PEEK,
1540 PR_SecondsToInterval(1));
1541 if(rc > 0)
1542 return 1; /* connection still in place */
1543
1544 if(rc == 0)
1545 return 0; /* connection has been closed */
1546
1547 return -1; /* connection status unknown */
1548 }
1549
close_one(struct ssl_connect_data * connssl)1550 static void close_one(struct ssl_connect_data *connssl)
1551 {
1552 /* before the cleanup, check whether we are using a client certificate */
1553 struct ssl_backend_data *backend = connssl->backend;
1554 const bool client_cert = (backend->client_nickname != NULL)
1555 || (backend->obj_clicert != NULL);
1556
1557 if(backend->handle) {
1558 char buf[32];
1559 /* Maybe the server has already sent a close notify alert.
1560 Read it to avoid an RST on the TCP connection. */
1561 (void)PR_Recv(backend->handle, buf, (int)sizeof(buf), 0,
1562 PR_INTERVAL_NO_WAIT);
1563 }
1564
1565 free(backend->client_nickname);
1566 backend->client_nickname = NULL;
1567
1568 /* destroy all NSS objects in order to avoid failure of NSS shutdown */
1569 Curl_llist_destroy(&backend->obj_list, NULL);
1570 backend->obj_clicert = NULL;
1571
1572 if(backend->handle) {
1573 if(client_cert)
1574 /* A server might require different authentication based on the
1575 * particular path being requested by the client. To support this
1576 * scenario, we must ensure that a connection will never reuse the
1577 * authentication data from a previous connection. */
1578 SSL_InvalidateSession(backend->handle);
1579
1580 PR_Close(backend->handle);
1581 backend->handle = NULL;
1582 }
1583 }
1584
1585 /*
1586 * This function is called when an SSL connection is closed.
1587 */
nss_close(struct Curl_easy * data,struct connectdata * conn,int sockindex)1588 static void nss_close(struct Curl_easy *data, struct connectdata *conn,
1589 int sockindex)
1590 {
1591 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
1592 #ifndef CURL_DISABLE_PROXY
1593 struct ssl_connect_data *connssl_proxy = &conn->proxy_ssl[sockindex];
1594 #endif
1595 struct ssl_backend_data *backend = connssl->backend;
1596
1597 (void)data;
1598 if(backend->handle
1599 #ifndef CURL_DISABLE_PROXY
1600 || connssl_proxy->backend->handle
1601 #endif
1602 ) {
1603 /* NSS closes the socket we previously handed to it, so we must mark it
1604 as closed to avoid double close */
1605 fake_sclose(conn->sock[sockindex]);
1606 conn->sock[sockindex] = CURL_SOCKET_BAD;
1607 }
1608
1609 #ifndef CURL_DISABLE_PROXY
1610 if(backend->handle)
1611 /* nss_close(connssl) will transitively close also
1612 connssl_proxy->backend->handle if both are used. Clear it to avoid
1613 a double close leading to crash. */
1614 connssl_proxy->backend->handle = NULL;
1615
1616 close_one(connssl_proxy);
1617 #endif
1618 close_one(connssl);
1619 }
1620
1621 /* return true if NSS can provide error code (and possibly msg) for the
1622 error */
is_nss_error(CURLcode err)1623 static bool is_nss_error(CURLcode err)
1624 {
1625 switch(err) {
1626 case CURLE_PEER_FAILED_VERIFICATION:
1627 case CURLE_SSL_CERTPROBLEM:
1628 case CURLE_SSL_CONNECT_ERROR:
1629 case CURLE_SSL_ISSUER_ERROR:
1630 return true;
1631
1632 default:
1633 return false;
1634 }
1635 }
1636
1637 /* return true if the given error code is related to a client certificate */
is_cc_error(PRInt32 err)1638 static bool is_cc_error(PRInt32 err)
1639 {
1640 switch(err) {
1641 case SSL_ERROR_BAD_CERT_ALERT:
1642 case SSL_ERROR_EXPIRED_CERT_ALERT:
1643 case SSL_ERROR_REVOKED_CERT_ALERT:
1644 return true;
1645
1646 default:
1647 return false;
1648 }
1649 }
1650
1651 static Curl_recv nss_recv;
1652 static Curl_send nss_send;
1653
nss_load_ca_certificates(struct Curl_easy * data,struct connectdata * conn,int sockindex)1654 static CURLcode nss_load_ca_certificates(struct Curl_easy *data,
1655 struct connectdata *conn,
1656 int sockindex)
1657 {
1658 const char *cafile = SSL_CONN_CONFIG(CAfile);
1659 const char *capath = SSL_CONN_CONFIG(CApath);
1660 bool use_trust_module;
1661 CURLcode result = CURLE_OK;
1662
1663 /* treat empty string as unset */
1664 if(cafile && !cafile[0])
1665 cafile = NULL;
1666 if(capath && !capath[0])
1667 capath = NULL;
1668
1669 infof(data, " CAfile: %s", cafile ? cafile : "none");
1670 infof(data, " CApath: %s", capath ? capath : "none");
1671
1672 /* load libnssckbi.so if no other trust roots were specified */
1673 use_trust_module = !cafile && !capath;
1674
1675 PR_Lock(nss_trustload_lock);
1676 if(use_trust_module && !trust_module) {
1677 /* libnssckbi.so needed but not yet loaded --> load it! */
1678 result = nss_load_module(&trust_module, trust_library, "trust");
1679 infof(data, "%s %s", (result) ? "failed to load" : "loaded",
1680 trust_library);
1681 if(result == CURLE_FAILED_INIT)
1682 /* If libnssckbi.so is not available (or fails to load), one can still
1683 use CA certificates stored in NSS database. Ignore the failure. */
1684 result = CURLE_OK;
1685 }
1686 else if(!use_trust_module && trust_module) {
1687 /* libnssckbi.so not needed but already loaded --> unload it! */
1688 infof(data, "unloading %s", trust_library);
1689 nss_unload_module(&trust_module);
1690 }
1691 PR_Unlock(nss_trustload_lock);
1692
1693 if(cafile)
1694 result = nss_load_cert(&conn->ssl[sockindex], cafile, PR_TRUE);
1695
1696 if(result)
1697 return result;
1698
1699 if(capath) {
1700 struct_stat st;
1701 if(stat(capath, &st) == -1)
1702 return CURLE_SSL_CACERT_BADFILE;
1703
1704 if(S_ISDIR(st.st_mode)) {
1705 PRDirEntry *entry;
1706 PRDir *dir = PR_OpenDir(capath);
1707 if(!dir)
1708 return CURLE_SSL_CACERT_BADFILE;
1709
1710 while((entry =
1711 PR_ReadDir(dir, (PRDirFlags)(PR_SKIP_BOTH | PR_SKIP_HIDDEN)))) {
1712 char *fullpath = aprintf("%s/%s", capath, entry->name);
1713 if(!fullpath) {
1714 PR_CloseDir(dir);
1715 return CURLE_OUT_OF_MEMORY;
1716 }
1717
1718 if(CURLE_OK != nss_load_cert(&conn->ssl[sockindex], fullpath, PR_TRUE))
1719 /* This is purposefully tolerant of errors so non-PEM files can
1720 * be in the same directory */
1721 infof(data, "failed to load '%s' from CURLOPT_CAPATH", fullpath);
1722
1723 free(fullpath);
1724 }
1725
1726 PR_CloseDir(dir);
1727 }
1728 else
1729 infof(data, "warning: CURLOPT_CAPATH not a directory (%s)", capath);
1730 }
1731
1732 return CURLE_OK;
1733 }
1734
nss_sslver_from_curl(PRUint16 * nssver,long version)1735 static CURLcode nss_sslver_from_curl(PRUint16 *nssver, long version)
1736 {
1737 switch(version) {
1738 case CURL_SSLVERSION_SSLv2:
1739 *nssver = SSL_LIBRARY_VERSION_2;
1740 return CURLE_OK;
1741
1742 case CURL_SSLVERSION_SSLv3:
1743 return CURLE_NOT_BUILT_IN;
1744
1745 case CURL_SSLVERSION_TLSv1_0:
1746 *nssver = SSL_LIBRARY_VERSION_TLS_1_0;
1747 return CURLE_OK;
1748
1749 case CURL_SSLVERSION_TLSv1_1:
1750 #ifdef SSL_LIBRARY_VERSION_TLS_1_1
1751 *nssver = SSL_LIBRARY_VERSION_TLS_1_1;
1752 return CURLE_OK;
1753 #else
1754 return CURLE_SSL_CONNECT_ERROR;
1755 #endif
1756
1757 case CURL_SSLVERSION_TLSv1_2:
1758 #ifdef SSL_LIBRARY_VERSION_TLS_1_2
1759 *nssver = SSL_LIBRARY_VERSION_TLS_1_2;
1760 return CURLE_OK;
1761 #else
1762 return CURLE_SSL_CONNECT_ERROR;
1763 #endif
1764
1765 case CURL_SSLVERSION_TLSv1_3:
1766 #ifdef SSL_LIBRARY_VERSION_TLS_1_3
1767 *nssver = SSL_LIBRARY_VERSION_TLS_1_3;
1768 return CURLE_OK;
1769 #else
1770 return CURLE_SSL_CONNECT_ERROR;
1771 #endif
1772
1773 default:
1774 return CURLE_SSL_CONNECT_ERROR;
1775 }
1776 }
1777
nss_init_sslver(SSLVersionRange * sslver,struct Curl_easy * data,struct connectdata * conn)1778 static CURLcode nss_init_sslver(SSLVersionRange *sslver,
1779 struct Curl_easy *data,
1780 struct connectdata *conn)
1781 {
1782 CURLcode result;
1783 const long min = SSL_CONN_CONFIG(version);
1784 const long max = SSL_CONN_CONFIG(version_max);
1785 SSLVersionRange vrange;
1786
1787 switch(min) {
1788 case CURL_SSLVERSION_TLSv1:
1789 case CURL_SSLVERSION_DEFAULT:
1790 /* Bump our minimum TLS version if NSS has stricter requirements. */
1791 if(SSL_VersionRangeGetDefault(ssl_variant_stream, &vrange) != SECSuccess)
1792 return CURLE_SSL_CONNECT_ERROR;
1793 if(sslver->min < vrange.min)
1794 sslver->min = vrange.min;
1795 break;
1796 default:
1797 result = nss_sslver_from_curl(&sslver->min, min);
1798 if(result) {
1799 failf(data, "unsupported min version passed via CURLOPT_SSLVERSION");
1800 return result;
1801 }
1802 }
1803
1804 switch(max) {
1805 case CURL_SSLVERSION_MAX_NONE:
1806 case CURL_SSLVERSION_MAX_DEFAULT:
1807 break;
1808 default:
1809 result = nss_sslver_from_curl(&sslver->max, max >> 16);
1810 if(result) {
1811 failf(data, "unsupported max version passed via CURLOPT_SSLVERSION");
1812 return result;
1813 }
1814 }
1815
1816 return CURLE_OK;
1817 }
1818
nss_fail_connect(struct ssl_connect_data * connssl,struct Curl_easy * data,CURLcode curlerr)1819 static CURLcode nss_fail_connect(struct ssl_connect_data *connssl,
1820 struct Curl_easy *data,
1821 CURLcode curlerr)
1822 {
1823 struct ssl_backend_data *backend = connssl->backend;
1824
1825 if(is_nss_error(curlerr)) {
1826 /* read NSPR error code */
1827 PRErrorCode err = PR_GetError();
1828 if(is_cc_error(err))
1829 curlerr = CURLE_SSL_CERTPROBLEM;
1830
1831 /* print the error number and error string */
1832 infof(data, "NSS error %d (%s)", err, nss_error_to_name(err));
1833
1834 /* print a human-readable message describing the error if available */
1835 nss_print_error_message(data, err);
1836 }
1837
1838 /* cleanup on connection failure */
1839 Curl_llist_destroy(&backend->obj_list, NULL);
1840
1841 return curlerr;
1842 }
1843
1844 /* Switch the SSL socket into blocking or non-blocking mode. */
nss_set_blocking(struct ssl_connect_data * connssl,struct Curl_easy * data,bool blocking)1845 static CURLcode nss_set_blocking(struct ssl_connect_data *connssl,
1846 struct Curl_easy *data,
1847 bool blocking)
1848 {
1849 PRSocketOptionData sock_opt;
1850 struct ssl_backend_data *backend = connssl->backend;
1851 sock_opt.option = PR_SockOpt_Nonblocking;
1852 sock_opt.value.non_blocking = !blocking;
1853
1854 if(PR_SetSocketOption(backend->handle, &sock_opt) != PR_SUCCESS)
1855 return nss_fail_connect(connssl, data, CURLE_SSL_CONNECT_ERROR);
1856
1857 return CURLE_OK;
1858 }
1859
nss_setup_connect(struct Curl_easy * data,struct connectdata * conn,int sockindex)1860 static CURLcode nss_setup_connect(struct Curl_easy *data,
1861 struct connectdata *conn, int sockindex)
1862 {
1863 PRFileDesc *model = NULL;
1864 PRFileDesc *nspr_io = NULL;
1865 PRFileDesc *nspr_io_stub = NULL;
1866 PRBool ssl_no_cache;
1867 PRBool ssl_cbc_random_iv;
1868 curl_socket_t sockfd = conn->sock[sockindex];
1869 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
1870 struct ssl_backend_data *backend = connssl->backend;
1871 CURLcode result;
1872 bool second_layer = FALSE;
1873 SSLVersionRange sslver_supported;
1874
1875 SSLVersionRange sslver = {
1876 SSL_LIBRARY_VERSION_TLS_1_0, /* min */
1877 #ifdef SSL_LIBRARY_VERSION_TLS_1_3
1878 SSL_LIBRARY_VERSION_TLS_1_3 /* max */
1879 #elif defined SSL_LIBRARY_VERSION_TLS_1_2
1880 SSL_LIBRARY_VERSION_TLS_1_2
1881 #elif defined SSL_LIBRARY_VERSION_TLS_1_1
1882 SSL_LIBRARY_VERSION_TLS_1_1
1883 #else
1884 SSL_LIBRARY_VERSION_TLS_1_0
1885 #endif
1886 };
1887
1888 backend->data = data;
1889
1890 /* list of all NSS objects we need to destroy in nss_do_close() */
1891 Curl_llist_init(&backend->obj_list, nss_destroy_object);
1892
1893 PR_Lock(nss_initlock);
1894 result = nss_setup(data);
1895 if(result) {
1896 PR_Unlock(nss_initlock);
1897 goto error;
1898 }
1899
1900 PK11_SetPasswordFunc(nss_get_password);
1901
1902 result = nss_load_module(&pem_module, pem_library, "PEM");
1903 PR_Unlock(nss_initlock);
1904 if(result == CURLE_FAILED_INIT)
1905 infof(data, "WARNING: failed to load NSS PEM library %s. Using "
1906 "OpenSSL PEM certificates will not work.", pem_library);
1907 else if(result)
1908 goto error;
1909
1910 result = CURLE_SSL_CONNECT_ERROR;
1911
1912 model = PR_NewTCPSocket();
1913 if(!model)
1914 goto error;
1915 model = SSL_ImportFD(NULL, model);
1916
1917 if(SSL_OptionSet(model, SSL_SECURITY, PR_TRUE) != SECSuccess)
1918 goto error;
1919 if(SSL_OptionSet(model, SSL_HANDSHAKE_AS_SERVER, PR_FALSE) != SECSuccess)
1920 goto error;
1921 if(SSL_OptionSet(model, SSL_HANDSHAKE_AS_CLIENT, PR_TRUE) != SECSuccess)
1922 goto error;
1923
1924 /* do not use SSL cache if disabled or we are not going to verify peer */
1925 ssl_no_cache = (SSL_SET_OPTION(primary.sessionid)
1926 && SSL_CONN_CONFIG(verifypeer)) ? PR_FALSE : PR_TRUE;
1927 if(SSL_OptionSet(model, SSL_NO_CACHE, ssl_no_cache) != SECSuccess)
1928 goto error;
1929
1930 /* enable/disable the requested SSL version(s) */
1931 if(nss_init_sslver(&sslver, data, conn) != CURLE_OK)
1932 goto error;
1933 if(SSL_VersionRangeGetSupported(ssl_variant_stream,
1934 &sslver_supported) != SECSuccess)
1935 goto error;
1936 if(sslver_supported.max < sslver.max && sslver_supported.max >= sslver.min) {
1937 char *sslver_req_str, *sslver_supp_str;
1938 sslver_req_str = nss_sslver_to_name(sslver.max);
1939 sslver_supp_str = nss_sslver_to_name(sslver_supported.max);
1940 if(sslver_req_str && sslver_supp_str)
1941 infof(data, "Falling back from %s to max supported SSL version (%s)",
1942 sslver_req_str, sslver_supp_str);
1943 free(sslver_req_str);
1944 free(sslver_supp_str);
1945 sslver.max = sslver_supported.max;
1946 }
1947 if(SSL_VersionRangeSet(model, &sslver) != SECSuccess)
1948 goto error;
1949
1950 ssl_cbc_random_iv = !SSL_SET_OPTION(enable_beast);
1951 #ifdef SSL_CBC_RANDOM_IV
1952 /* unless the user explicitly asks to allow the protocol vulnerability, we
1953 use the work-around */
1954 if(SSL_OptionSet(model, SSL_CBC_RANDOM_IV, ssl_cbc_random_iv) != SECSuccess)
1955 infof(data, "warning: failed to set SSL_CBC_RANDOM_IV = %d",
1956 ssl_cbc_random_iv);
1957 #else
1958 if(ssl_cbc_random_iv)
1959 infof(data, "warning: support for SSL_CBC_RANDOM_IV not compiled in");
1960 #endif
1961
1962 if(SSL_CONN_CONFIG(cipher_list)) {
1963 if(set_ciphers(data, model, SSL_CONN_CONFIG(cipher_list)) != SECSuccess) {
1964 result = CURLE_SSL_CIPHER;
1965 goto error;
1966 }
1967 }
1968
1969 if(!SSL_CONN_CONFIG(verifypeer) && SSL_CONN_CONFIG(verifyhost))
1970 infof(data, "warning: ignoring value of ssl.verifyhost");
1971
1972 /* bypass the default SSL_AuthCertificate() hook in case we do not want to
1973 * verify peer */
1974 if(SSL_AuthCertificateHook(model, nss_auth_cert_hook, data) != SECSuccess)
1975 goto error;
1976
1977 /* not checked yet */
1978 SSL_SET_OPTION_LVALUE(certverifyresult) = 0;
1979
1980 if(SSL_BadCertHook(model, BadCertHandler, data) != SECSuccess)
1981 goto error;
1982
1983 if(SSL_HandshakeCallback(model, HandshakeCallback, data) != SECSuccess)
1984 goto error;
1985
1986 {
1987 const CURLcode rv = nss_load_ca_certificates(data, conn, sockindex);
1988 if((rv == CURLE_SSL_CACERT_BADFILE) && !SSL_CONN_CONFIG(verifypeer))
1989 /* not a fatal error because we are not going to verify the peer */
1990 infof(data, "warning: CA certificates failed to load");
1991 else if(rv) {
1992 result = rv;
1993 goto error;
1994 }
1995 }
1996
1997 if(SSL_SET_OPTION(primary.CRLfile)) {
1998 const CURLcode rv = nss_load_crl(SSL_SET_OPTION(primary.CRLfile));
1999 if(rv) {
2000 result = rv;
2001 goto error;
2002 }
2003 infof(data, " CRLfile: %s", SSL_SET_OPTION(primary.CRLfile));
2004 }
2005
2006 if(SSL_SET_OPTION(primary.clientcert)) {
2007 char *nickname = dup_nickname(data, SSL_SET_OPTION(primary.clientcert));
2008 if(nickname) {
2009 /* we are not going to use libnsspem.so to read the client cert */
2010 backend->obj_clicert = NULL;
2011 }
2012 else {
2013 CURLcode rv = cert_stuff(data, conn, sockindex,
2014 SSL_SET_OPTION(primary.clientcert),
2015 SSL_SET_OPTION(key));
2016 if(rv) {
2017 /* failf() is already done in cert_stuff() */
2018 result = rv;
2019 goto error;
2020 }
2021 }
2022
2023 /* store the nickname for SelectClientCert() called during handshake */
2024 backend->client_nickname = nickname;
2025 }
2026 else
2027 backend->client_nickname = NULL;
2028
2029 if(SSL_GetClientAuthDataHook(model, SelectClientCert,
2030 (void *)connssl) != SECSuccess) {
2031 result = CURLE_SSL_CERTPROBLEM;
2032 goto error;
2033 }
2034
2035 #ifndef CURL_DISABLE_PROXY
2036 if(conn->proxy_ssl[sockindex].use) {
2037 DEBUGASSERT(ssl_connection_complete == conn->proxy_ssl[sockindex].state);
2038 DEBUGASSERT(conn->proxy_ssl[sockindex].backend->handle != NULL);
2039 nspr_io = conn->proxy_ssl[sockindex].backend->handle;
2040 second_layer = TRUE;
2041 }
2042 #endif
2043 else {
2044 /* wrap OS file descriptor by NSPR's file descriptor abstraction */
2045 nspr_io = PR_ImportTCPSocket(sockfd);
2046 if(!nspr_io)
2047 goto error;
2048 }
2049
2050 /* create our own NSPR I/O layer */
2051 nspr_io_stub = PR_CreateIOLayerStub(nspr_io_identity, &nspr_io_methods);
2052 if(!nspr_io_stub) {
2053 if(!second_layer)
2054 PR_Close(nspr_io);
2055 goto error;
2056 }
2057
2058 /* make the per-connection data accessible from NSPR I/O callbacks */
2059 nspr_io_stub->secret = (void *)connssl;
2060
2061 /* push our new layer to the NSPR I/O stack */
2062 if(PR_PushIOLayer(nspr_io, PR_TOP_IO_LAYER, nspr_io_stub) != PR_SUCCESS) {
2063 if(!second_layer)
2064 PR_Close(nspr_io);
2065 PR_Close(nspr_io_stub);
2066 goto error;
2067 }
2068
2069 /* import our model socket onto the current I/O stack */
2070 backend->handle = SSL_ImportFD(model, nspr_io);
2071 if(!backend->handle) {
2072 if(!second_layer)
2073 PR_Close(nspr_io);
2074 goto error;
2075 }
2076
2077 PR_Close(model); /* We don't need this any more */
2078 model = NULL;
2079
2080 /* This is the password associated with the cert that we're using */
2081 if(SSL_SET_OPTION(key_passwd)) {
2082 SSL_SetPKCS11PinArg(backend->handle, SSL_SET_OPTION(key_passwd));
2083 }
2084
2085 #ifdef SSL_ENABLE_OCSP_STAPLING
2086 if(SSL_CONN_CONFIG(verifystatus)) {
2087 if(SSL_OptionSet(backend->handle, SSL_ENABLE_OCSP_STAPLING, PR_TRUE)
2088 != SECSuccess)
2089 goto error;
2090 }
2091 #endif
2092
2093 #ifdef SSL_ENABLE_NPN
2094 if(SSL_OptionSet(backend->handle, SSL_ENABLE_NPN, conn->bits.tls_enable_npn
2095 ? PR_TRUE : PR_FALSE) != SECSuccess)
2096 goto error;
2097 #endif
2098
2099 #ifdef SSL_ENABLE_ALPN
2100 if(SSL_OptionSet(backend->handle, SSL_ENABLE_ALPN, conn->bits.tls_enable_alpn
2101 ? PR_TRUE : PR_FALSE) != SECSuccess)
2102 goto error;
2103 #endif
2104
2105 #if NSSVERNUM >= 0x030f04 /* 3.15.4 */
2106 if(data->set.ssl.falsestart) {
2107 if(SSL_OptionSet(backend->handle, SSL_ENABLE_FALSE_START, PR_TRUE)
2108 != SECSuccess)
2109 goto error;
2110
2111 if(SSL_SetCanFalseStartCallback(backend->handle, CanFalseStartCallback,
2112 data) != SECSuccess)
2113 goto error;
2114 }
2115 #endif
2116
2117 #if defined(SSL_ENABLE_NPN) || defined(SSL_ENABLE_ALPN)
2118 if(conn->bits.tls_enable_npn || conn->bits.tls_enable_alpn) {
2119 int cur = 0;
2120 unsigned char protocols[128];
2121
2122 #ifdef USE_HTTP2
2123 if(data->state.httpwant >= CURL_HTTP_VERSION_2
2124 #ifndef CURL_DISABLE_PROXY
2125 && (!SSL_IS_PROXY() || !conn->bits.tunnel_proxy)
2126 #endif
2127 ) {
2128 protocols[cur++] = ALPN_H2_LENGTH;
2129 memcpy(&protocols[cur], ALPN_H2, ALPN_H2_LENGTH);
2130 cur += ALPN_H2_LENGTH;
2131 }
2132 #endif
2133 protocols[cur++] = ALPN_HTTP_1_1_LENGTH;
2134 memcpy(&protocols[cur], ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH);
2135 cur += ALPN_HTTP_1_1_LENGTH;
2136
2137 if(SSL_SetNextProtoNego(backend->handle, protocols, cur) != SECSuccess)
2138 goto error;
2139 }
2140 #endif
2141
2142
2143 /* Force handshake on next I/O */
2144 if(SSL_ResetHandshake(backend->handle, /* asServer */ PR_FALSE)
2145 != SECSuccess)
2146 goto error;
2147
2148 /* propagate hostname to the TLS layer */
2149 if(SSL_SetURL(backend->handle, SSL_HOST_NAME()) != SECSuccess)
2150 goto error;
2151
2152 /* prevent NSS from re-using the session for a different hostname */
2153 if(SSL_SetSockPeerID(backend->handle, SSL_HOST_NAME()) != SECSuccess)
2154 goto error;
2155
2156 return CURLE_OK;
2157
2158 error:
2159 if(model)
2160 PR_Close(model);
2161
2162 return nss_fail_connect(connssl, data, result);
2163 }
2164
nss_do_connect(struct Curl_easy * data,struct connectdata * conn,int sockindex)2165 static CURLcode nss_do_connect(struct Curl_easy *data,
2166 struct connectdata *conn, int sockindex)
2167 {
2168 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
2169 struct ssl_backend_data *backend = connssl->backend;
2170 CURLcode result = CURLE_SSL_CONNECT_ERROR;
2171 PRUint32 timeout;
2172
2173 /* check timeout situation */
2174 const timediff_t time_left = Curl_timeleft(data, NULL, TRUE);
2175 if(time_left < 0) {
2176 failf(data, "timed out before SSL handshake");
2177 result = CURLE_OPERATION_TIMEDOUT;
2178 goto error;
2179 }
2180
2181 /* Force the handshake now */
2182 timeout = PR_MillisecondsToInterval((PRUint32) time_left);
2183 if(SSL_ForceHandshakeWithTimeout(backend->handle, timeout) != SECSuccess) {
2184 if(PR_GetError() == PR_WOULD_BLOCK_ERROR)
2185 /* blocking direction is updated by nss_update_connecting_state() */
2186 return CURLE_AGAIN;
2187 else if(SSL_SET_OPTION(certverifyresult) == SSL_ERROR_BAD_CERT_DOMAIN)
2188 result = CURLE_PEER_FAILED_VERIFICATION;
2189 else if(SSL_SET_OPTION(certverifyresult) != 0)
2190 result = CURLE_PEER_FAILED_VERIFICATION;
2191 goto error;
2192 }
2193
2194 result = display_conn_info(data, backend->handle);
2195 if(result)
2196 goto error;
2197
2198 if(SSL_CONN_CONFIG(issuercert)) {
2199 SECStatus ret = SECFailure;
2200 char *nickname = dup_nickname(data, SSL_CONN_CONFIG(issuercert));
2201 if(nickname) {
2202 /* we support only nicknames in case of issuercert for now */
2203 ret = check_issuer_cert(backend->handle, nickname);
2204 free(nickname);
2205 }
2206
2207 if(SECFailure == ret) {
2208 infof(data, "SSL certificate issuer check failed");
2209 result = CURLE_SSL_ISSUER_ERROR;
2210 goto error;
2211 }
2212 else {
2213 infof(data, "SSL certificate issuer check ok");
2214 }
2215 }
2216
2217 result = cmp_peer_pubkey(connssl, SSL_PINNED_PUB_KEY());
2218 if(result)
2219 /* status already printed */
2220 goto error;
2221
2222 return CURLE_OK;
2223
2224 error:
2225 return nss_fail_connect(connssl, data, result);
2226 }
2227
nss_connect_common(struct Curl_easy * data,struct connectdata * conn,int sockindex,bool * done)2228 static CURLcode nss_connect_common(struct Curl_easy *data,
2229 struct connectdata *conn, int sockindex,
2230 bool *done)
2231 {
2232 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
2233 const bool blocking = (done == NULL);
2234 CURLcode result;
2235
2236 if(connssl->state == ssl_connection_complete) {
2237 if(!blocking)
2238 *done = TRUE;
2239 return CURLE_OK;
2240 }
2241
2242 if(connssl->connecting_state == ssl_connect_1) {
2243 result = nss_setup_connect(data, conn, sockindex);
2244 if(result)
2245 /* we do not expect CURLE_AGAIN from nss_setup_connect() */
2246 return result;
2247
2248 connssl->connecting_state = ssl_connect_2;
2249 }
2250
2251 /* enable/disable blocking mode before handshake */
2252 result = nss_set_blocking(connssl, data, blocking);
2253 if(result)
2254 return result;
2255
2256 result = nss_do_connect(data, conn, sockindex);
2257 switch(result) {
2258 case CURLE_OK:
2259 break;
2260 case CURLE_AGAIN:
2261 if(!blocking)
2262 /* CURLE_AGAIN in non-blocking mode is not an error */
2263 return CURLE_OK;
2264 /* FALLTHROUGH */
2265 default:
2266 return result;
2267 }
2268
2269 if(blocking) {
2270 /* in blocking mode, set NSS non-blocking mode _after_ SSL handshake */
2271 result = nss_set_blocking(connssl, data, /* blocking */ FALSE);
2272 if(result)
2273 return result;
2274 }
2275 else
2276 /* signal completed SSL handshake */
2277 *done = TRUE;
2278
2279 connssl->state = ssl_connection_complete;
2280 conn->recv[sockindex] = nss_recv;
2281 conn->send[sockindex] = nss_send;
2282
2283 /* ssl_connect_done is never used outside, go back to the initial state */
2284 connssl->connecting_state = ssl_connect_1;
2285
2286 return CURLE_OK;
2287 }
2288
nss_connect(struct Curl_easy * data,struct connectdata * conn,int sockindex)2289 static CURLcode nss_connect(struct Curl_easy *data, struct connectdata *conn,
2290 int sockindex)
2291 {
2292 return nss_connect_common(data, conn, sockindex, /* blocking */ NULL);
2293 }
2294
nss_connect_nonblocking(struct Curl_easy * data,struct connectdata * conn,int sockindex,bool * done)2295 static CURLcode nss_connect_nonblocking(struct Curl_easy *data,
2296 struct connectdata *conn,
2297 int sockindex, bool *done)
2298 {
2299 return nss_connect_common(data, conn, sockindex, done);
2300 }
2301
nss_send(struct Curl_easy * data,int sockindex,const void * mem,size_t len,CURLcode * curlcode)2302 static ssize_t nss_send(struct Curl_easy *data, /* transfer */
2303 int sockindex, /* socketindex */
2304 const void *mem, /* send this data */
2305 size_t len, /* amount to write */
2306 CURLcode *curlcode)
2307 {
2308 struct connectdata *conn = data->conn;
2309 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
2310 struct ssl_backend_data *backend = connssl->backend;
2311 ssize_t rc;
2312
2313 /* The SelectClientCert() hook uses this for infof() and failf() but the
2314 handle stored in nss_setup_connect() could have already been freed. */
2315 backend->data = data;
2316
2317 rc = PR_Send(backend->handle, mem, (int)len, 0, PR_INTERVAL_NO_WAIT);
2318 if(rc < 0) {
2319 PRInt32 err = PR_GetError();
2320 if(err == PR_WOULD_BLOCK_ERROR)
2321 *curlcode = CURLE_AGAIN;
2322 else {
2323 /* print the error number and error string */
2324 const char *err_name = nss_error_to_name(err);
2325 infof(data, "SSL write: error %d (%s)", err, err_name);
2326
2327 /* print a human-readable message describing the error if available */
2328 nss_print_error_message(data, err);
2329
2330 *curlcode = (is_cc_error(err))
2331 ? CURLE_SSL_CERTPROBLEM
2332 : CURLE_SEND_ERROR;
2333 }
2334
2335 return -1;
2336 }
2337
2338 return rc; /* number of bytes */
2339 }
2340
nss_recv(struct Curl_easy * data,int sockindex,char * buf,size_t buffersize,CURLcode * curlcode)2341 static ssize_t nss_recv(struct Curl_easy *data, /* transfer */
2342 int sockindex, /* socketindex */
2343 char *buf, /* store read data here */
2344 size_t buffersize, /* max amount to read */
2345 CURLcode *curlcode)
2346 {
2347 struct connectdata *conn = data->conn;
2348 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
2349 struct ssl_backend_data *backend = connssl->backend;
2350 ssize_t nread;
2351
2352 /* The SelectClientCert() hook uses this for infof() and failf() but the
2353 handle stored in nss_setup_connect() could have already been freed. */
2354 backend->data = data;
2355
2356 nread = PR_Recv(backend->handle, buf, (int)buffersize, 0,
2357 PR_INTERVAL_NO_WAIT);
2358 if(nread < 0) {
2359 /* failed SSL read */
2360 PRInt32 err = PR_GetError();
2361
2362 if(err == PR_WOULD_BLOCK_ERROR)
2363 *curlcode = CURLE_AGAIN;
2364 else {
2365 /* print the error number and error string */
2366 const char *err_name = nss_error_to_name(err);
2367 infof(data, "SSL read: errno %d (%s)", err, err_name);
2368
2369 /* print a human-readable message describing the error if available */
2370 nss_print_error_message(data, err);
2371
2372 *curlcode = (is_cc_error(err))
2373 ? CURLE_SSL_CERTPROBLEM
2374 : CURLE_RECV_ERROR;
2375 }
2376
2377 return -1;
2378 }
2379
2380 return nread;
2381 }
2382
nss_version(char * buffer,size_t size)2383 static size_t nss_version(char *buffer, size_t size)
2384 {
2385 return msnprintf(buffer, size, "NSS/%s", NSS_GetVersion());
2386 }
2387
2388 /* data might be NULL */
Curl_nss_seed(struct Curl_easy * data)2389 static int Curl_nss_seed(struct Curl_easy *data)
2390 {
2391 /* make sure that NSS is initialized */
2392 return !!Curl_nss_force_init(data);
2393 }
2394
2395 /* data might be NULL */
nss_random(struct Curl_easy * data,unsigned char * entropy,size_t length)2396 static CURLcode nss_random(struct Curl_easy *data,
2397 unsigned char *entropy,
2398 size_t length)
2399 {
2400 Curl_nss_seed(data); /* Initiate the seed if not already done */
2401
2402 if(SECSuccess != PK11_GenerateRandom(entropy, curlx_uztosi(length)))
2403 /* signal a failure */
2404 return CURLE_FAILED_INIT;
2405
2406 return CURLE_OK;
2407 }
2408
nss_sha256sum(const unsigned char * tmp,size_t tmplen,unsigned char * sha256sum,size_t sha256len)2409 static CURLcode nss_sha256sum(const unsigned char *tmp, /* input */
2410 size_t tmplen,
2411 unsigned char *sha256sum, /* output */
2412 size_t sha256len)
2413 {
2414 PK11Context *SHA256pw = PK11_CreateDigestContext(SEC_OID_SHA256);
2415 unsigned int SHA256out;
2416
2417 if(!SHA256pw)
2418 return CURLE_NOT_BUILT_IN;
2419
2420 PK11_DigestOp(SHA256pw, tmp, curlx_uztoui(tmplen));
2421 PK11_DigestFinal(SHA256pw, sha256sum, &SHA256out, curlx_uztoui(sha256len));
2422 PK11_DestroyContext(SHA256pw, PR_TRUE);
2423
2424 return CURLE_OK;
2425 }
2426
nss_cert_status_request(void)2427 static bool nss_cert_status_request(void)
2428 {
2429 #ifdef SSL_ENABLE_OCSP_STAPLING
2430 return TRUE;
2431 #else
2432 return FALSE;
2433 #endif
2434 }
2435
nss_false_start(void)2436 static bool nss_false_start(void)
2437 {
2438 #if NSSVERNUM >= 0x030f04 /* 3.15.4 */
2439 return TRUE;
2440 #else
2441 return FALSE;
2442 #endif
2443 }
2444
nss_get_internals(struct ssl_connect_data * connssl,CURLINFO info UNUSED_PARAM)2445 static void *nss_get_internals(struct ssl_connect_data *connssl,
2446 CURLINFO info UNUSED_PARAM)
2447 {
2448 struct ssl_backend_data *backend = connssl->backend;
2449 (void)info;
2450 return backend->handle;
2451 }
2452
2453 const struct Curl_ssl Curl_ssl_nss = {
2454 { CURLSSLBACKEND_NSS, "nss" }, /* info */
2455
2456 SSLSUPP_CA_PATH |
2457 SSLSUPP_CERTINFO |
2458 SSLSUPP_PINNEDPUBKEY |
2459 SSLSUPP_HTTPS_PROXY,
2460
2461 sizeof(struct ssl_backend_data),
2462
2463 nss_init, /* init */
2464 nss_cleanup, /* cleanup */
2465 nss_version, /* version */
2466 nss_check_cxn, /* check_cxn */
2467 /* NSS has no shutdown function provided and thus always fail */
2468 Curl_none_shutdown, /* shutdown */
2469 Curl_none_data_pending, /* data_pending */
2470 nss_random, /* random */
2471 nss_cert_status_request, /* cert_status_request */
2472 nss_connect, /* connect */
2473 nss_connect_nonblocking, /* connect_nonblocking */
2474 Curl_ssl_getsock, /* getsock */
2475 nss_get_internals, /* get_internals */
2476 nss_close, /* close_one */
2477 Curl_none_close_all, /* close_all */
2478 /* NSS has its own session ID cache */
2479 Curl_none_session_free, /* session_free */
2480 Curl_none_set_engine, /* set_engine */
2481 Curl_none_set_engine_default, /* set_engine_default */
2482 Curl_none_engines_list, /* engines_list */
2483 nss_false_start, /* false_start */
2484 nss_sha256sum, /* sha256sum */
2485 NULL, /* associate_connection */
2486 NULL /* disassociate_connection */
2487 };
2488
2489 #endif /* USE_NSS */
2490