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