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