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