• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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, &notBefore, &notAfter);
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