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