1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2009, 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 http://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  * $Id: nss.c,v 1.41 2009-02-27 08:53:10 bagder Exp $
22  ***************************************************************************/
23 
24 /*
25  * Source file for all NSS-specific code for the TLS/SSL layer. No code
26  * but sslgen.c should ever call or use these functions.
27  */
28 
29 #include "setup.h"
30 
31 #include <string.h>
32 #include <stdlib.h>
33 #include <ctype.h>
34 #ifdef HAVE_SYS_SOCKET_H
35 #include <sys/socket.h>
36 #endif
37 
38 #include "urldata.h"
39 #include "sendf.h"
40 #include "formdata.h" /* for the boundary function */
41 #include "url.h" /* for the ssl config check function */
42 #include "connect.h"
43 #include "strequal.h"
44 #include "select.h"
45 #include "sslgen.h"
46 
47 #define _MPRINTF_REPLACE /* use the internal *printf() functions */
48 #include <curl/mprintf.h>
49 
50 #ifdef USE_NSS
51 
52 #include "nssg.h"
53 #include <nspr.h>
54 #include <nss.h>
55 #include <ssl.h>
56 #include <sslerr.h>
57 #include <secerr.h>
58 #include <secmod.h>
59 #include <sslproto.h>
60 #include <prtypes.h>
61 #include <pk11pub.h>
62 #include <prio.h>
63 #include <secitem.h>
64 #include <secport.h>
65 #include <certdb.h>
66 
67 #include "memory.h"
68 #include "rawstr.h"
69 #include "easyif.h" /* for Curl_convert_from_utf8 prototype */
70 
71 /* The last #include file should be: */
72 #include "memdebug.h"
73 
74 #define SSL_DIR "/etc/pki/nssdb"
75 
76 /* enough to fit the string "PEM Token #[0|1]" */
77 #define SLOTSIZE 13
78 
79 PRFileDesc *PR_ImportTCPSocket(PRInt32 osfd);
80 
81 PRLock * nss_initlock = NULL;
82 
83 volatile int initialized = 0;
84 
85 #define HANDSHAKE_TIMEOUT 30
86 
87 typedef struct {
88   PRInt32 retryCount;
89   struct SessionHandle *data;
90 } pphrase_arg_t;
91 
92 typedef struct {
93   const char *name;
94   int num;
95   PRInt32 version; /* protocol version valid for this cipher */
96 } cipher_s;
97 
98 #define PK11_SETATTRS(x,id,v,l) (x)->type = (id); \
99                      (x)->pValue=(v); (x)->ulValueLen = (l)
100 
101 #define CERT_NewTempCertificate __CERT_NewTempCertificate
102 
103 enum sslversion { SSL2 = 1, SSL3 = 2, TLS = 4 };
104 
105 #define NUM_OF_CIPHERS sizeof(cipherlist)/sizeof(cipherlist[0])
106 static const cipher_s cipherlist[] = {
107   /* SSL2 cipher suites */
108   {"rc4", SSL_EN_RC4_128_WITH_MD5, SSL2},
109   {"rc4-md5", SSL_EN_RC4_128_WITH_MD5, SSL2},
110   {"rc4export", SSL_EN_RC4_128_EXPORT40_WITH_MD5, SSL2},
111   {"rc2", SSL_EN_RC2_128_CBC_WITH_MD5, SSL2},
112   {"rc2export", SSL_EN_RC2_128_CBC_EXPORT40_WITH_MD5, SSL2},
113   {"des", SSL_EN_DES_64_CBC_WITH_MD5, SSL2},
114   {"desede3", SSL_EN_DES_192_EDE3_CBC_WITH_MD5, SSL2},
115   /* SSL3/TLS cipher suites */
116   {"rsa_rc4_128_md5", SSL_RSA_WITH_RC4_128_MD5, SSL3 | TLS},
117   {"rsa_rc4_128_sha", SSL_RSA_WITH_RC4_128_SHA, SSL3 | TLS},
118   {"rsa_3des_sha", SSL_RSA_WITH_3DES_EDE_CBC_SHA, SSL3 | TLS},
119   {"rsa_des_sha", SSL_RSA_WITH_DES_CBC_SHA, SSL3 | TLS},
120   {"rsa_rc4_40_md5", SSL_RSA_EXPORT_WITH_RC4_40_MD5, SSL3 | TLS},
121   {"rsa_rc2_40_md5", SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5, SSL3 | TLS},
122   {"rsa_null_md5", SSL_RSA_WITH_NULL_MD5, SSL3 | TLS},
123   {"rsa_null_sha", SSL_RSA_WITH_NULL_SHA, SSL3 | TLS},
124   {"fips_3des_sha", SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA, SSL3 | TLS},
125   {"fips_des_sha", SSL_RSA_FIPS_WITH_DES_CBC_SHA, SSL3 | TLS},
126   {"fortezza", SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA, SSL3 | TLS},
127   {"fortezza_rc4_128_sha", SSL_FORTEZZA_DMS_WITH_RC4_128_SHA, SSL3 | TLS},
128   {"fortezza_null", SSL_FORTEZZA_DMS_WITH_NULL_SHA, SSL3 | TLS},
129   /* TLS 1.0: Exportable 56-bit Cipher Suites. */
130   {"rsa_des_56_sha", TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA, SSL3 | TLS},
131   {"rsa_rc4_56_sha", TLS_RSA_EXPORT1024_WITH_RC4_56_SHA, SSL3 | TLS},
132   /* AES ciphers. */
133   {"rsa_aes_128_sha", TLS_RSA_WITH_AES_128_CBC_SHA, SSL3 | TLS},
134   {"rsa_aes_256_sha", TLS_RSA_WITH_AES_256_CBC_SHA, SSL3 | TLS},
135 #ifdef NSS_ENABLE_ECC
136   /* ECC ciphers. */
137   {"ecdh_ecdsa_null_sha", TLS_ECDH_ECDSA_WITH_NULL_SHA, TLS},
138   {"ecdh_ecdsa_rc4_128_sha", TLS_ECDH_ECDSA_WITH_RC4_128_SHA, TLS},
139   {"ecdh_ecdsa_3des_sha", TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, TLS},
140   {"ecdh_ecdsa_aes_128_sha", TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, TLS},
141   {"ecdh_ecdsa_aes_256_sha", TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, TLS},
142   {"ecdhe_ecdsa_null_sha", TLS_ECDHE_ECDSA_WITH_NULL_SHA, TLS},
143   {"ecdhe_ecdsa_rc4_128_sha", TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, TLS},
144   {"ecdhe_ecdsa_3des_sha", TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, TLS},
145   {"ecdhe_ecdsa_aes_128_sha", TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, TLS},
146   {"ecdhe_ecdsa_aes_256_sha", TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, TLS},
147   {"ecdh_rsa_null_sha", TLS_ECDH_RSA_WITH_NULL_SHA, TLS},
148   {"ecdh_rsa_128_sha", TLS_ECDH_RSA_WITH_RC4_128_SHA, TLS},
149   {"ecdh_rsa_3des_sha", TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, TLS},
150   {"ecdh_rsa_aes_128_sha", TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, TLS},
151   {"ecdh_rsa_aes_256_sha", TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, TLS},
152   {"echde_rsa_null", TLS_ECDHE_RSA_WITH_NULL_SHA, TLS},
153   {"ecdhe_rsa_rc4_128_sha", TLS_ECDHE_RSA_WITH_RC4_128_SHA, TLS},
154   {"ecdhe_rsa_3des_sha", TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, TLS},
155   {"ecdhe_rsa_aes_128_sha", TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, TLS},
156   {"ecdhe_rsa_aes_256_sha", TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, TLS},
157   {"ecdh_anon_null_sha", TLS_ECDH_anon_WITH_NULL_SHA, TLS},
158   {"ecdh_anon_rc4_128sha", TLS_ECDH_anon_WITH_RC4_128_SHA, TLS},
159   {"ecdh_anon_3des_sha", TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA, TLS},
160   {"ecdh_anon_aes_128_sha", TLS_ECDH_anon_WITH_AES_128_CBC_SHA, TLS},
161   {"ecdh_anon_aes_256_sha", TLS_ECDH_anon_WITH_AES_256_CBC_SHA, TLS},
162 #endif
163 };
164 
165 #ifdef HAVE_PK11_CREATEGENERICOBJECT
166 static const char* pem_library = "libnsspem.so";
167 #endif
168 SECMODModule* mod = NULL;
169 
set_ciphers(struct SessionHandle * data,PRFileDesc * model,char * cipher_list)170 static SECStatus set_ciphers(struct SessionHandle *data, PRFileDesc * model,
171                              char *cipher_list)
172 {
173   unsigned int i;
174   PRBool cipher_state[NUM_OF_CIPHERS];
175   PRBool found;
176   char *cipher;
177   SECStatus rv;
178 
179   /* First disable all ciphers. This uses a different max value in case
180    * NSS adds more ciphers later we don't want them available by
181    * accident
182    */
183   for(i=0; i<SSL_NumImplementedCiphers; i++) {
184     SSL_CipherPrefSet(model, SSL_ImplementedCiphers[i], SSL_NOT_ALLOWED);
185   }
186 
187   /* Set every entry in our list to false */
188   for(i=0; i<NUM_OF_CIPHERS; i++) {
189     cipher_state[i] = PR_FALSE;
190   }
191 
192   cipher = cipher_list;
193 
194   while(cipher_list && (cipher_list[0])) {
195     while((*cipher) && (ISSPACE(*cipher)))
196       ++cipher;
197 
198     if((cipher_list = strchr(cipher, ','))) {
199       *cipher_list++ = '\0';
200     }
201 
202     found = PR_FALSE;
203 
204     for(i=0; i<NUM_OF_CIPHERS; i++) {
205       if(Curl_raw_equal(cipher, cipherlist[i].name)) {
206         cipher_state[i] = PR_TRUE;
207         found = PR_TRUE;
208         break;
209       }
210     }
211 
212     if(found == PR_FALSE) {
213       failf(data, "Unknown cipher in list: %s", cipher);
214       return SECFailure;
215     }
216 
217     if(cipher_list) {
218       cipher = cipher_list;
219     }
220   }
221 
222   /* Finally actually enable the selected ciphers */
223   for(i=0; i<NUM_OF_CIPHERS; i++) {
224     rv = SSL_CipherPrefSet(model, cipherlist[i].num, cipher_state[i]);
225     if(rv != SECSuccess) {
226       failf(data, "Unknown cipher in cipher list");
227       return SECFailure;
228     }
229   }
230 
231   return SECSuccess;
232 }
233 
234 /*
235  * Get the number of ciphers that are enabled. We use this to determine
236  * if we need to call NSS_SetDomesticPolicy() to enable the default ciphers.
237  */
num_enabled_ciphers(void)238 static int num_enabled_ciphers(void)
239 {
240   PRInt32 policy = 0;
241   int count = 0;
242   unsigned int i;
243 
244   for(i=0; i<NUM_OF_CIPHERS; i++) {
245     SSL_CipherPolicyGet(cipherlist[i].num, &policy);
246     if(policy)
247       count++;
248   }
249   return count;
250 }
251 
252 /*
253  * Determine whether the nickname passed in is a filename that needs to
254  * be loaded as a PEM or a regular NSS nickname.
255  *
256  * returns 1 for a file
257  * returns 0 for not a file (NSS nickname)
258  */
is_file(const char * filename)259 static int is_file(const char *filename)
260 {
261   struct stat st;
262 
263   if(filename == NULL)
264     return 0;
265 
266   if(stat(filename, &st) == 0)
267     if(S_ISREG(st.st_mode))
268       return 1;
269 
270   return 0;
271 }
272 
273 static int
nss_load_cert(const char * filename,PRBool cacert)274 nss_load_cert(const char *filename, PRBool cacert)
275 {
276 #ifdef HAVE_PK11_CREATEGENERICOBJECT
277   CK_SLOT_ID slotID;
278   PK11SlotInfo * slot = NULL;
279   PK11GenericObject *rv;
280   CK_ATTRIBUTE *attrs;
281   CK_ATTRIBUTE theTemplate[20];
282   CK_BBOOL cktrue = CK_TRUE;
283   CK_BBOOL ckfalse = CK_FALSE;
284   CK_OBJECT_CLASS objClass = CKO_CERTIFICATE;
285   char slotname[SLOTSIZE];
286 #endif
287   CERTCertificate *cert;
288   char *nickname = NULL;
289   char *n = NULL;
290 
291   /* If there is no slash in the filename it is assumed to be a regular
292    * NSS nickname.
293    */
294   if(is_file(filename)) {
295     n = strrchr(filename, '/');
296     if(n)
297       n++;
298     if(!mod)
299       return 1;
300   }
301   else {
302     /* A nickname from the NSS internal database */
303     if(cacert)
304       return 0; /* You can't specify an NSS CA nickname this way */
305     nickname = strdup(filename);
306     if(!nickname)
307       return 0;
308     goto done;
309   }
310 
311 #ifdef HAVE_PK11_CREATEGENERICOBJECT
312   attrs = theTemplate;
313 
314   /* All CA and trust objects go into slot 0. Other slots are used
315    * for storing certificates. With each new user certificate we increment
316    * the slot count. We only support 1 user certificate right now.
317    */
318   if(cacert)
319     slotID = 0;
320   else
321     slotID = 1;
322 
323   snprintf(slotname, SLOTSIZE, "PEM Token #%ld", slotID);
324 
325   nickname = aprintf("PEM Token #%ld:%s", slotID, n);
326   if(!nickname)
327     return 0;
328 
329   slot = PK11_FindSlotByName(slotname);
330 
331   if(!slot) {
332     free(nickname);
333     return 0;
334   }
335 
336   PK11_SETATTRS(attrs, CKA_CLASS, &objClass, sizeof(objClass) );
337   attrs++;
338   PK11_SETATTRS(attrs, CKA_TOKEN, &cktrue, sizeof(CK_BBOOL) );
339   attrs++;
340   PK11_SETATTRS(attrs, CKA_LABEL, (unsigned char *)filename,
341                 strlen(filename)+1);
342   attrs++;
343   if(cacert) {
344     PK11_SETATTRS(attrs, CKA_TRUST, &cktrue, sizeof(CK_BBOOL) );
345   }
346   else {
347     PK11_SETATTRS(attrs, CKA_TRUST, &ckfalse, sizeof(CK_BBOOL) );
348   }
349   attrs++;
350 
351   /* This load the certificate in our PEM module into the appropriate
352    * slot.
353    */
354   rv = PK11_CreateGenericObject(slot, theTemplate, 4, PR_FALSE /* isPerm */);
355 
356   PK11_FreeSlot(slot);
357 
358   if(rv == NULL) {
359     free(nickname);
360     return 0;
361   }
362 #else
363   /* We don't have PK11_CreateGenericObject but a file-based cert was passed
364    * in. We need to fail.
365    */
366   return 0;
367 #endif
368 
369 done:
370   /* Double-check that the certificate or nickname requested exists in
371    * either the token or the NSS certificate database.
372    */
373   if(!cacert) {
374     cert = PK11_FindCertFromNickname((char *)nickname, NULL);
375 
376     /* An invalid nickname was passed in */
377     if(cert == NULL) {
378       free(nickname);
379       PR_SetError(SEC_ERROR_UNKNOWN_CERT, 0);
380       return 0;
381     }
382 
383     CERT_DestroyCertificate(cert);
384   }
385 
386   free(nickname);
387 
388   return 1;
389 }
390 
nss_load_crl(const char * crlfilename,PRBool ascii)391 static int nss_load_crl(const char* crlfilename, PRBool ascii)
392 {
393   PRFileDesc *infile;
394   PRStatus    prstat;
395   PRFileInfo  info;
396   PRInt32     nb;
397   int rv;
398   SECItem crlDER;
399   CERTSignedCrl *crl=NULL;
400   PK11SlotInfo *slot=NULL;
401 
402   infile = PR_Open(crlfilename,PR_RDONLY,0);
403   if (!infile) {
404     return 0;
405   }
406   crlDER.data = NULL;
407   prstat = PR_GetOpenFileInfo(infile,&info);
408   if (prstat!=PR_SUCCESS)
409     return 0;
410   if (ascii) {
411     SECItem filedata;
412     char *asc,*body;
413     filedata.data = NULL;
414     if (!SECITEM_AllocItem(NULL,&filedata,info.size))
415       return 0;
416     nb = PR_Read(infile,filedata.data,info.size);
417     if (nb!=info.size)
418       return 0;
419     asc = (char*)filedata.data;
420     if (!asc)
421       return 0;
422 
423     body=strstr(asc,"-----BEGIN");
424     if (body != NULL) {
425       char *trailer=NULL;
426       asc = body;
427       body = PORT_Strchr(asc,'\n');
428       if (!body)
429         body = PORT_Strchr(asc,'\r');
430       if (body)
431         trailer = strstr(++body,"-----END");
432       if (trailer!=NULL)
433         *trailer='\0';
434       else
435         return 0;
436     }
437     else {
438       body = asc;
439     }
440     rv = ATOB_ConvertAsciiToItem(&crlDER,body);
441     PORT_Free(filedata.data);
442     if (rv)
443       return 0;
444   }
445   else {
446     if (!SECITEM_AllocItem(NULL,&crlDER,info.size))
447       return 0;
448     nb = PR_Read(infile,crlDER.data,info.size);
449     if (nb!=info.size)
450       return 0;
451   }
452 
453   slot = PK11_GetInternalKeySlot();
454   crl  = PK11_ImportCRL(slot,&crlDER,
455                         NULL,SEC_CRL_TYPE,
456                         NULL,CRL_IMPORT_DEFAULT_OPTIONS,
457                         NULL,(CRL_DECODE_DEFAULT_OPTIONS|
458                               CRL_DECODE_DONT_COPY_DER));
459   if (slot) PK11_FreeSlot(slot);
460   if (!crl) return 0;
461   SEC_DestroyCrl(crl);
462   return 1;
463 }
464 
nss_load_key(struct connectdata * conn,char * key_file)465 static int nss_load_key(struct connectdata *conn, char *key_file)
466 {
467 #ifdef HAVE_PK11_CREATEGENERICOBJECT
468   PK11SlotInfo * slot = NULL;
469   PK11GenericObject *rv;
470   CK_ATTRIBUTE *attrs;
471   CK_ATTRIBUTE theTemplate[20];
472   CK_BBOOL cktrue = CK_TRUE;
473   CK_OBJECT_CLASS objClass = CKO_PRIVATE_KEY;
474   CK_SLOT_ID slotID;
475   pphrase_arg_t *parg = NULL;
476   char slotname[SLOTSIZE];
477 
478   attrs = theTemplate;
479 
480   /* FIXME: grok the various file types */
481 
482   slotID = 1; /* hardcoded for now */
483 
484   snprintf(slotname, sizeof(slotname), "PEM Token #%ld", slotID);
485   slot = PK11_FindSlotByName(slotname);
486 
487   if(!slot)
488     return 0;
489 
490   PK11_SETATTRS(attrs, CKA_CLASS, &objClass, sizeof(objClass) ); attrs++;
491   PK11_SETATTRS(attrs, CKA_TOKEN, &cktrue, sizeof(CK_BBOOL) ); attrs++;
492   PK11_SETATTRS(attrs, CKA_LABEL, (unsigned char *)key_file,
493                 strlen(key_file)+1); attrs++;
494 
495   /* When adding an encrypted key the PKCS#11 will be set as removed */
496   rv = PK11_CreateGenericObject(slot, theTemplate, 3, PR_FALSE /* isPerm */);
497   if(rv == NULL) {
498     PR_SetError(SEC_ERROR_BAD_KEY, 0);
499     return 0;
500   }
501 
502   /* This will force the token to be seen as re-inserted */
503   SECMOD_WaitForAnyTokenEvent(mod, 0, 0);
504   PK11_IsPresent(slot);
505 
506   parg = malloc(sizeof(pphrase_arg_t));
507   if(!parg)
508     return 0;
509   parg->retryCount = 0;
510   parg->data = conn->data;
511   /* parg is initialized in nss_Init_Tokens() */
512   if(PK11_Authenticate(slot, PR_TRUE, parg) != SECSuccess) {
513     free(parg);
514     return 0;
515   }
516   free(parg);
517 
518   return 1;
519 #else
520   /* If we don't have PK11_CreateGenericObject then we can't load a file-based
521    * key.
522    */
523   (void)conn; /* unused */
524   (void)key_file; /* unused */
525   return 0;
526 #endif
527 }
528 
display_error(struct connectdata * conn,PRInt32 err,const char * filename)529 static int display_error(struct connectdata *conn, PRInt32 err,
530                          const char *filename)
531 {
532   switch(err) {
533   case SEC_ERROR_BAD_PASSWORD:
534     failf(conn->data, "Unable to load client key: Incorrect password");
535     return 1;
536   case SEC_ERROR_UNKNOWN_CERT:
537     failf(conn->data, "Unable to load certificate %s", filename);
538     return 1;
539   default:
540     break;
541   }
542   return 0; /* The caller will print a generic error */
543 }
544 
cert_stuff(struct connectdata * conn,char * cert_file,char * key_file)545 static int cert_stuff(struct connectdata *conn, char *cert_file, char *key_file)
546 {
547   struct SessionHandle *data = conn->data;
548   int rv = 0;
549 
550   if(cert_file) {
551     rv = nss_load_cert(cert_file, PR_FALSE);
552     if(!rv) {
553       if(!display_error(conn, PR_GetError(), cert_file))
554         failf(data, "Unable to load client cert %d.", PR_GetError());
555       return 0;
556     }
557   }
558   if(key_file || (is_file(cert_file))) {
559     if(key_file)
560       rv = nss_load_key(conn, key_file);
561     else
562       /* In case the cert file also has the key */
563       rv = nss_load_key(conn, cert_file);
564     if(!rv) {
565       if(!display_error(conn, PR_GetError(), key_file))
566         failf(data, "Unable to load client key %d.", PR_GetError());
567 
568       return 0;
569     }
570   }
571   return 1;
572 }
573 
nss_get_password(PK11SlotInfo * slot,PRBool retry,void * arg)574 static char * nss_get_password(PK11SlotInfo * slot, PRBool retry, void *arg)
575 {
576   pphrase_arg_t *parg;
577   parg = (pphrase_arg_t *) arg;
578 
579   (void)slot; /* unused */
580   if(retry > 2)
581     return NULL;
582   if(parg->data->set.str[STRING_KEY_PASSWD])
583     return (char *)PORT_Strdup((char *)parg->data->set.str[STRING_KEY_PASSWD]);
584   else
585     return NULL;
586 }
587 
588 /* No longer ask for the password, parg has been freed */
nss_no_password(PK11SlotInfo * slot,PRBool retry,void * arg)589 static char * nss_no_password(PK11SlotInfo *slot, PRBool retry, void *arg)
590 {
591   (void)slot; /* unused */
592   (void)retry; /* unused */
593   (void)arg; /* unused */
594   return NULL;
595 }
596 
nss_Init_Tokens(struct connectdata * conn)597 static SECStatus nss_Init_Tokens(struct connectdata * conn)
598 {
599   PK11SlotList *slotList;
600   PK11SlotListElement *listEntry;
601   SECStatus ret, status = SECSuccess;
602   pphrase_arg_t *parg = NULL;
603 
604   parg = malloc(sizeof(pphrase_arg_t));
605   if(!parg)
606     return SECFailure;
607 
608   parg->retryCount = 0;
609   parg->data = conn->data;
610 
611   PK11_SetPasswordFunc(nss_get_password);
612 
613   slotList =
614     PK11_GetAllTokens(CKM_INVALID_MECHANISM, PR_FALSE, PR_TRUE, NULL);
615 
616   for(listEntry = PK11_GetFirstSafe(slotList);
617       listEntry; listEntry = listEntry->next) {
618     PK11SlotInfo *slot = listEntry->slot;
619 
620     if(PK11_NeedLogin(slot) && PK11_NeedUserInit(slot)) {
621       if(slot == PK11_GetInternalKeySlot()) {
622         failf(conn->data, "The NSS database has not been initialized");
623       }
624       else {
625         failf(conn->data, "The token %s has not been initialized",
626               PK11_GetTokenName(slot));
627       }
628       PK11_FreeSlot(slot);
629       continue;
630     }
631 
632     ret = PK11_Authenticate(slot, PR_TRUE, parg);
633     if(SECSuccess != ret) {
634       if(PR_GetError() == SEC_ERROR_BAD_PASSWORD)
635         infof(conn->data, "The password for token '%s' is incorrect\n",
636               PK11_GetTokenName(slot));
637       status = SECFailure;
638       break;
639     }
640     parg->retryCount = 0; /* reset counter to 0 for the next token */
641     PK11_FreeSlot(slot);
642   }
643 
644   free(parg);
645 
646   return status;
647 }
648 
BadCertHandler(void * arg,PRFileDesc * sock)649 static SECStatus BadCertHandler(void *arg, PRFileDesc *sock)
650 {
651   SECStatus success = SECSuccess;
652   struct connectdata *conn = (struct connectdata *)arg;
653   PRErrorCode err = PR_GetError();
654   CERTCertificate *cert = NULL;
655   char *subject, *issuer;
656 
657   if(conn->data->set.ssl.certverifyresult!=0)
658     return success;
659 
660   conn->data->set.ssl.certverifyresult=err;
661   cert = SSL_PeerCertificate(sock);
662   subject = CERT_NameToAscii(&cert->subject);
663   issuer = CERT_NameToAscii(&cert->issuer);
664   CERT_DestroyCertificate(cert);
665 
666   switch(err) {
667   case SEC_ERROR_CA_CERT_INVALID:
668     infof(conn->data, "Issuer certificate is invalid: '%s'\n", issuer);
669     if(conn->data->set.ssl.verifypeer)
670       success = SECFailure;
671     break;
672   case SEC_ERROR_UNTRUSTED_ISSUER:
673     if(conn->data->set.ssl.verifypeer)
674       success = SECFailure;
675     infof(conn->data, "Certificate is signed by an untrusted issuer: '%s'\n",
676           issuer);
677     break;
678   case SSL_ERROR_BAD_CERT_DOMAIN:
679     if(conn->data->set.ssl.verifypeer)
680       success = SECFailure;
681     infof(conn->data, "common name: %s (does not match '%s')\n",
682           subject, conn->host.dispname);
683     break;
684   case SEC_ERROR_EXPIRED_CERTIFICATE:
685     if(conn->data->set.ssl.verifypeer)
686       success = SECFailure;
687     infof(conn->data, "Remote Certificate has expired.\n");
688     break;
689   default:
690     if(conn->data->set.ssl.verifypeer)
691       success = SECFailure;
692     infof(conn->data, "Bad certificate received. Subject = '%s', "
693           "Issuer = '%s'\n", subject, issuer);
694     break;
695   }
696   if(success == SECSuccess)
697     infof(conn->data, "SSL certificate verify ok.\n");
698   PR_Free(subject);
699   PR_Free(issuer);
700 
701   return success;
702 }
703 
704 /**
705  * Inform the application that the handshake is complete.
706  */
HandshakeCallback(PRFileDesc * sock,void * arg)707 static SECStatus HandshakeCallback(PRFileDesc *sock, void *arg)
708 {
709   (void)sock;
710   (void)arg;
711   return SECSuccess;
712 }
713 
display_conn_info(struct connectdata * conn,PRFileDesc * sock)714 static void display_conn_info(struct connectdata *conn, PRFileDesc *sock)
715 {
716   SSLChannelInfo channel;
717   SSLCipherSuiteInfo suite;
718   CERTCertificate *cert;
719   char *subject, *issuer, *common_name;
720   PRExplodedTime printableTime;
721   char timeString[256];
722   PRTime notBefore, notAfter;
723 
724   if(SSL_GetChannelInfo(sock, &channel, sizeof channel) ==
725      SECSuccess && channel.length == sizeof channel &&
726      channel.cipherSuite) {
727     if(SSL_GetCipherSuiteInfo(channel.cipherSuite,
728                               &suite, sizeof suite) == SECSuccess) {
729       infof(conn->data, "SSL connection using %s\n", suite.cipherSuiteName);
730     }
731   }
732 
733   infof(conn->data, "Server certificate:\n");
734 
735   cert = SSL_PeerCertificate(sock);
736   subject = CERT_NameToAscii(&cert->subject);
737   issuer = CERT_NameToAscii(&cert->issuer);
738   common_name = CERT_GetCommonName(&cert->subject);
739   infof(conn->data, "\tsubject: %s\n", subject);
740 
741   CERT_GetCertTimes(cert, &notBefore, &notAfter);
742   PR_ExplodeTime(notBefore, PR_GMTParameters, &printableTime);
743   PR_FormatTime(timeString, 256, "%b %d %H:%M:%S %Y GMT", &printableTime);
744   infof(conn->data, "\tstart date: %s\n", timeString);
745   PR_ExplodeTime(notAfter, PR_GMTParameters, &printableTime);
746   PR_FormatTime(timeString, 256, "%b %d %H:%M:%S %Y GMT", &printableTime);
747   infof(conn->data, "\texpire date: %s\n", timeString);
748   infof(conn->data, "\tcommon name: %s\n", common_name);
749   infof(conn->data, "\tissuer: %s\n", issuer);
750 
751   PR_Free(subject);
752   PR_Free(issuer);
753   PR_Free(common_name);
754 
755   CERT_DestroyCertificate(cert);
756 
757   return;
758 }
759 
760 /**
761  *
762  * Check that the Peer certificate's issuer certificate matches the one found
763  * by issuer_nickname.  This is not exactly the way OpenSSL and GNU TLS do the
764  * issuer check, so we provide comments that mimic the OpenSSL
765  * X509_check_issued function (in x509v3/v3_purp.c)
766  */
check_issuer_cert(PRFileDesc * sock,char * issuer_nickname)767 static SECStatus check_issuer_cert(PRFileDesc *sock,
768                                    char *issuer_nickname)
769 {
770   CERTCertificate *cert,*cert_issuer,*issuer;
771   SECStatus res=SECSuccess;
772   void *proto_win = NULL;
773 
774   /*
775   PRArenaPool   *tmpArena = NULL;
776   CERTAuthKeyID *authorityKeyID = NULL;
777   SECITEM       *caname = NULL;
778   */
779 
780   cert = SSL_PeerCertificate(sock);
781   cert_issuer = CERT_FindCertIssuer(cert,PR_Now(),certUsageObjectSigner);
782 
783   proto_win = SSL_RevealPinArg(sock);
784   issuer = NULL;
785   issuer = PK11_FindCertFromNickname(issuer_nickname, proto_win);
786 
787   if ((!cert_issuer) || (!issuer))
788     res = SECFailure;
789   else if (SECITEM_CompareItem(&cert_issuer->derCert,
790                                &issuer->derCert)!=SECEqual)
791     res = SECFailure;
792 
793   CERT_DestroyCertificate(cert);
794   CERT_DestroyCertificate(issuer);
795   CERT_DestroyCertificate(cert_issuer);
796   return res;
797 }
798 
799 /**
800  *
801  * Callback to pick the SSL client certificate.
802  */
SelectClientCert(void * arg,PRFileDesc * sock,struct CERTDistNamesStr * caNames,struct CERTCertificateStr ** pRetCert,struct SECKEYPrivateKeyStr ** pRetKey)803 static SECStatus SelectClientCert(void *arg, PRFileDesc *sock,
804                                   struct CERTDistNamesStr *caNames,
805                                   struct CERTCertificateStr **pRetCert,
806                                   struct SECKEYPrivateKeyStr **pRetKey)
807 {
808   CERTCertificate *cert;
809   SECKEYPrivateKey *privKey;
810   char *nickname = (char *)arg;
811   void *proto_win = NULL;
812   SECStatus secStatus = SECFailure;
813   PK11SlotInfo *slot;
814   (void)caNames;
815 
816   proto_win = SSL_RevealPinArg(sock);
817 
818   if(!nickname)
819     return secStatus;
820 
821   cert = PK11_FindCertFromNickname(nickname, proto_win);
822   if(cert) {
823 
824     if(!strncmp(nickname, "PEM Token", 9)) {
825       CK_SLOT_ID slotID = 1; /* hardcoded for now */
826       char slotname[SLOTSIZE];
827       snprintf(slotname, SLOTSIZE, "PEM Token #%ld", slotID);
828       slot = PK11_FindSlotByName(slotname);
829       privKey = PK11_FindPrivateKeyFromCert(slot, cert, NULL);
830       PK11_FreeSlot(slot);
831       if(privKey) {
832         secStatus = SECSuccess;
833       }
834     }
835     else {
836       privKey = PK11_FindKeyByAnyCert(cert, proto_win);
837       if(privKey)
838         secStatus = SECSuccess;
839     }
840   }
841 
842   if(secStatus == SECSuccess) {
843     *pRetCert = cert;
844     *pRetKey = privKey;
845   }
846   else {
847     if(cert)
848       CERT_DestroyCertificate(cert);
849   }
850 
851   return secStatus;
852 }
853 
854 /**
855  * Global SSL init
856  *
857  * @retval 0 error initializing SSL
858  * @retval 1 SSL initialized successfully
859  */
Curl_nss_init(void)860 int Curl_nss_init(void)
861 {
862   /* curl_global_init() is not thread-safe so this test is ok */
863   if (nss_initlock == NULL) {
864     PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 256);
865     nss_initlock = PR_NewLock();
866   }
867 
868   /* We will actually initialize NSS later */
869 
870   return 1;
871 }
872 
873 /* Global cleanup */
Curl_nss_cleanup(void)874 void Curl_nss_cleanup(void)
875 {
876   /* This function isn't required to be threadsafe and this is only done
877    * as a safety feature.
878    */
879   PR_Lock(nss_initlock);
880   if (initialized)
881     NSS_Shutdown();
882   PR_Unlock(nss_initlock);
883 
884   PR_DestroyLock(nss_initlock);
885   nss_initlock = NULL;
886 
887   initialized = 0;
888 }
889 
890 /*
891  * This function uses SSL_peek to determine connection status.
892  *
893  * Return codes:
894  *     1 means the connection is still in place
895  *     0 means the connection has been closed
896  *    -1 means the connection status is unknown
897  */
898 int
Curl_nss_check_cxn(struct connectdata * conn)899 Curl_nss_check_cxn(struct connectdata *conn)
900 {
901   int rc;
902   char buf;
903 
904   rc =
905     PR_Recv(conn->ssl[FIRSTSOCKET].handle, (void *)&buf, 1, PR_MSG_PEEK,
906             PR_SecondsToInterval(1));
907   if(rc > 0)
908     return 1; /* connection still in place */
909 
910   if(rc == 0)
911     return 0; /* connection has been closed */
912 
913   return -1;  /* connection status unknown */
914 }
915 
916 /*
917  * This function is called when an SSL connection is closed.
918  */
Curl_nss_close(struct connectdata * conn,int sockindex)919 void Curl_nss_close(struct connectdata *conn, int sockindex)
920 {
921   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
922 
923   if(connssl->handle) {
924     PR_Close(connssl->handle);
925     if(connssl->client_nickname != NULL) {
926       free(connssl->client_nickname);
927       connssl->client_nickname = NULL;
928     }
929     connssl->handle = NULL;
930   }
931 }
932 
933 /*
934  * This function is called when the 'data' struct is going away. Close
935  * down everything and free all resources!
936  */
Curl_nss_close_all(struct SessionHandle * data)937 int Curl_nss_close_all(struct SessionHandle *data)
938 {
939   (void)data;
940   return 0;
941 }
942 
Curl_nss_connect(struct connectdata * conn,int sockindex)943 CURLcode Curl_nss_connect(struct connectdata *conn, int sockindex)
944 {
945   PRInt32 err;
946   PRFileDesc *model = NULL;
947   PRBool ssl2, ssl3, tlsv1;
948   struct SessionHandle *data = conn->data;
949   curl_socket_t sockfd = conn->sock[sockindex];
950   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
951   SECStatus rv;
952 #ifdef HAVE_PK11_CREATEGENERICOBJECT
953   char *configstring = NULL;
954 #endif
955   char *certDir = NULL;
956   int curlerr;
957 
958   curlerr = CURLE_SSL_CONNECT_ERROR;
959 
960   if (connssl->state == ssl_connection_complete)
961     return CURLE_OK;
962 
963   /* FIXME. NSS doesn't support multiple databases open at the same time. */
964   PR_Lock(nss_initlock);
965   if(!initialized) {
966 
967     certDir = getenv("SSL_DIR"); /* Look in $SSL_DIR */
968 
969     if(!certDir) {
970       struct stat st;
971 
972       if(stat(SSL_DIR, &st) == 0)
973         if(S_ISDIR(st.st_mode)) {
974           certDir = (char *)SSL_DIR;
975         }
976     }
977 
978     if (!NSS_IsInitialized()) {
979       initialized = 1;
980       if(!certDir) {
981         rv = NSS_NoDB_Init(NULL);
982       }
983       else {
984         rv = NSS_Initialize(certDir, NULL, NULL, "secmod.db",
985                             NSS_INIT_READONLY);
986       }
987       if(rv != SECSuccess) {
988         infof(conn->data, "Unable to initialize NSS database\n");
989         curlerr = CURLE_SSL_CACERT_BADFILE;
990         initialized = 0;
991         PR_Unlock(nss_initlock);
992         goto error;
993       }
994     }
995 
996     if(num_enabled_ciphers() == 0)
997       NSS_SetDomesticPolicy();
998 
999 #ifdef HAVE_PK11_CREATEGENERICOBJECT
1000     configstring = aprintf("library=%s name=PEM", pem_library);
1001     if(!configstring) {
1002       PR_Unlock(nss_initlock);
1003       goto error;
1004     }
1005     mod = SECMOD_LoadUserModule(configstring, NULL, PR_FALSE);
1006     free(configstring);
1007 
1008     if(!mod || !mod->loaded) {
1009       if(mod) {
1010         SECMOD_DestroyModule(mod);
1011         mod = NULL;
1012       }
1013       infof(data, "WARNING: failed to load NSS PEM library %s. Using OpenSSL "
1014             "PEM certificates will not work.\n", pem_library);
1015     }
1016 #endif
1017   }
1018   PR_Unlock(nss_initlock);
1019 
1020   model = PR_NewTCPSocket();
1021   if(!model)
1022     goto error;
1023   model = SSL_ImportFD(NULL, model);
1024 
1025   if(SSL_OptionSet(model, SSL_SECURITY, PR_TRUE) != SECSuccess)
1026     goto error;
1027   if(SSL_OptionSet(model, SSL_HANDSHAKE_AS_SERVER, PR_FALSE) != SECSuccess)
1028     goto error;
1029   if(SSL_OptionSet(model, SSL_HANDSHAKE_AS_CLIENT, PR_TRUE) != SECSuccess)
1030     goto error;
1031 
1032   ssl2 = ssl3 = tlsv1 = PR_FALSE;
1033 
1034   switch (data->set.ssl.version) {
1035   default:
1036   case CURL_SSLVERSION_DEFAULT:
1037     ssl3 = tlsv1 = PR_TRUE;
1038     break;
1039   case CURL_SSLVERSION_TLSv1:
1040     tlsv1 = PR_TRUE;
1041     break;
1042   case CURL_SSLVERSION_SSLv2:
1043     ssl2 = PR_TRUE;
1044     break;
1045   case CURL_SSLVERSION_SSLv3:
1046     ssl3 = PR_TRUE;
1047     break;
1048   }
1049 
1050   if(SSL_OptionSet(model, SSL_ENABLE_SSL2, ssl2) != SECSuccess)
1051     goto error;
1052   if(SSL_OptionSet(model, SSL_ENABLE_SSL3, ssl3) != SECSuccess)
1053     goto error;
1054   if(SSL_OptionSet(model, SSL_ENABLE_TLS, tlsv1) != SECSuccess)
1055     goto error;
1056 
1057   if(SSL_OptionSet(model, SSL_V2_COMPATIBLE_HELLO, ssl2) != SECSuccess)
1058     goto error;
1059 
1060   if(data->set.ssl.cipher_list) {
1061     if(set_ciphers(data, model, data->set.ssl.cipher_list) != SECSuccess) {
1062       curlerr = CURLE_SSL_CIPHER;
1063       goto error;
1064     }
1065   }
1066 
1067   data->set.ssl.certverifyresult=0; /* not checked yet */
1068   if(SSL_BadCertHook(model, (SSLBadCertHandler) BadCertHandler, conn)
1069      != SECSuccess) {
1070     goto error;
1071   }
1072   if(SSL_HandshakeCallback(model, (SSLHandshakeCallback) HandshakeCallback,
1073                            NULL) != SECSuccess)
1074     goto error;
1075 
1076   if(!data->set.ssl.verifypeer)
1077     /* skip the verifying of the peer */
1078     ;
1079   else if(data->set.ssl.CAfile) {
1080     int rc = nss_load_cert(data->set.ssl.CAfile, PR_TRUE);
1081     if(!rc) {
1082       curlerr = CURLE_SSL_CACERT_BADFILE;
1083       goto error;
1084     }
1085   }
1086   else if(data->set.ssl.CApath) {
1087     struct stat st;
1088     PRDir      *dir;
1089     PRDirEntry *entry;
1090 
1091     if(stat(data->set.ssl.CApath, &st) == -1) {
1092       curlerr = CURLE_SSL_CACERT_BADFILE;
1093       goto error;
1094     }
1095 
1096     if(S_ISDIR(st.st_mode)) {
1097       int rc;
1098 
1099       dir = PR_OpenDir(data->set.ssl.CApath);
1100       do {
1101         entry = PR_ReadDir(dir, PR_SKIP_BOTH | PR_SKIP_HIDDEN);
1102 
1103         if(entry) {
1104           char fullpath[PATH_MAX];
1105 
1106           snprintf(fullpath, sizeof(fullpath), "%s/%s", data->set.ssl.CApath,
1107                    entry->name);
1108           rc = nss_load_cert(fullpath, PR_TRUE);
1109           /* FIXME: check this return value! */
1110         }
1111         /* This is purposefully tolerant of errors so non-PEM files
1112          * can be in the same directory */
1113       } while(entry != NULL);
1114       PR_CloseDir(dir);
1115     }
1116   }
1117   infof(data,
1118         "  CAfile: %s\n"
1119         "  CApath: %s\n",
1120         data->set.ssl.CAfile ? data->set.ssl.CAfile : "none",
1121         data->set.ssl.CApath ? data->set.ssl.CApath : "none");
1122 
1123   if (data->set.ssl.CRLfile) {
1124     int rc = nss_load_crl(data->set.ssl.CRLfile, PR_FALSE);
1125     if (!rc) {
1126       curlerr = CURLE_SSL_CRL_BADFILE;
1127       goto error;
1128     }
1129     infof(data,
1130           "  CRLfile: %s\n",
1131           data->set.ssl.CRLfile ? data->set.ssl.CRLfile : "none");
1132   }
1133 
1134   if(data->set.str[STRING_CERT]) {
1135     char *n;
1136     char *nickname;
1137     bool nickname_alloc = FALSE;
1138 
1139     if(is_file(data->set.str[STRING_CERT])) {
1140       n = strrchr(data->set.str[STRING_CERT], '/');
1141       if(n) {
1142         n++; /* skip last slash */
1143         nickname = aprintf("PEM Token #%d:%s", 1, n);
1144         if(!nickname)
1145           return CURLE_OUT_OF_MEMORY;
1146 
1147         nickname_alloc = TRUE;
1148       }
1149     }
1150     else {
1151       nickname = data->set.str[STRING_CERT];
1152     }
1153     if(nss_Init_Tokens(conn) != SECSuccess) {
1154       if(nickname_alloc)
1155         free(nickname);
1156       goto error;
1157     }
1158     if(!cert_stuff(conn, data->set.str[STRING_CERT],
1159                     data->set.str[STRING_KEY])) {
1160       /* failf() is already done in cert_stuff() */
1161       if(nickname_alloc)
1162         free(nickname);
1163       return CURLE_SSL_CERTPROBLEM;
1164     }
1165 
1166     /* this "takes over" the pointer to the allocated name or makes a
1167        dup of it */
1168     connssl->client_nickname = nickname_alloc?nickname:strdup(nickname);
1169     if(!connssl->client_nickname)
1170       return CURLE_OUT_OF_MEMORY;
1171 
1172     if(SSL_GetClientAuthDataHook(model,
1173                                  (SSLGetClientAuthData) SelectClientCert,
1174                                  (void *)connssl->client_nickname) !=
1175        SECSuccess) {
1176       curlerr = CURLE_SSL_CERTPROBLEM;
1177       goto error;
1178     }
1179 
1180     PK11_SetPasswordFunc(nss_no_password);
1181   }
1182   else
1183     connssl->client_nickname = NULL;
1184 
1185 
1186   /* Import our model socket  onto the existing file descriptor */
1187   connssl->handle = PR_ImportTCPSocket(sockfd);
1188   connssl->handle = SSL_ImportFD(model, connssl->handle);
1189   if(!connssl->handle)
1190     goto error;
1191   PR_Close(model); /* We don't need this any more */
1192 
1193   /* Force handshake on next I/O */
1194   SSL_ResetHandshake(connssl->handle, /* asServer */ PR_FALSE);
1195 
1196   SSL_SetURL(connssl->handle, conn->host.name);
1197 
1198   /* Force the handshake now */
1199   if(SSL_ForceHandshakeWithTimeout(connssl->handle,
1200                                     PR_SecondsToInterval(HANDSHAKE_TIMEOUT))
1201       != SECSuccess) {
1202     if(conn->data->set.ssl.certverifyresult!=0)
1203       curlerr = CURLE_SSL_CACERT;
1204     goto error;
1205   }
1206 
1207   connssl->state = ssl_connection_complete;
1208 
1209   display_conn_info(conn, connssl->handle);
1210 
1211   if (data->set.str[STRING_SSL_ISSUERCERT]) {
1212     char *n;
1213     char *nickname;
1214     bool nickname_alloc = FALSE;
1215     SECStatus ret;
1216 
1217     if(is_file(data->set.str[STRING_SSL_ISSUERCERT])) {
1218       n = strrchr(data->set.str[STRING_SSL_ISSUERCERT], '/');
1219       if (n) {
1220         n++; /* skip last slash */
1221         nickname = aprintf("PEM Token #%d:%s", 1, n);
1222         if(!nickname)
1223           return CURLE_OUT_OF_MEMORY;
1224         nickname_alloc = TRUE;
1225       }
1226     }
1227     else
1228       nickname = data->set.str[STRING_SSL_ISSUERCERT];
1229 
1230     ret = check_issuer_cert(connssl->handle, nickname);
1231 
1232     if(nickname_alloc)
1233       free(nickname);
1234 
1235     if(SECFailure == ret) {
1236       infof(data,"SSL certificate issuer check failed\n");
1237       curlerr = CURLE_SSL_ISSUER_ERROR;
1238       goto error;
1239     }
1240     else {
1241       infof(data, "SSL certificate issuer check ok\n");
1242     }
1243   }
1244 
1245   return CURLE_OK;
1246 
1247 error:
1248   err = PR_GetError();
1249   infof(data, "NSS error %d\n", err);
1250   if(model)
1251     PR_Close(model);
1252   return curlerr;
1253 }
1254 
1255 /* return number of sent (non-SSL) bytes */
Curl_nss_send(struct connectdata * conn,int sockindex,const void * mem,size_t len)1256 int Curl_nss_send(struct connectdata *conn,  /* connection data */
1257                   int sockindex,             /* socketindex */
1258                   const void *mem,           /* send this data */
1259                   size_t len)                /* amount to write */
1260 {
1261   PRInt32 err;
1262   struct SessionHandle *data = conn->data;
1263   PRInt32 timeout;
1264   int rc;
1265 
1266   if(data->set.timeout)
1267     timeout = PR_MillisecondsToInterval(data->set.timeout);
1268   else
1269     timeout = PR_MillisecondsToInterval(DEFAULT_CONNECT_TIMEOUT);
1270 
1271   rc = PR_Send(conn->ssl[sockindex].handle, mem, (int)len, 0, timeout);
1272 
1273   if(rc < 0) {
1274     err = PR_GetError();
1275 
1276     if(err == PR_IO_TIMEOUT_ERROR) {
1277       failf(data, "SSL connection timeout");
1278       return CURLE_OPERATION_TIMEDOUT;
1279     }
1280 
1281     failf(conn->data, "SSL write: error %d", err);
1282     return -1;
1283   }
1284   return rc; /* number of bytes */
1285 }
1286 
1287 /*
1288  * If the read would block we return -1 and set 'wouldblock' to TRUE.
1289  * Otherwise we return the amount of data read. Other errors should return -1
1290  * and set 'wouldblock' to FALSE.
1291  */
Curl_nss_recv(struct connectdata * conn,int num,char * buf,size_t buffersize,bool * wouldblock)1292 ssize_t Curl_nss_recv(struct connectdata * conn, /* connection data */
1293                       int num,                   /* socketindex */
1294                       char *buf,                 /* store read data here */
1295                       size_t buffersize,         /* max amount to read */
1296                       bool * wouldblock)
1297 {
1298   ssize_t nread;
1299   struct SessionHandle *data = conn->data;
1300   PRInt32 timeout;
1301 
1302   if(data->set.timeout)
1303     timeout = PR_SecondsToInterval(data->set.timeout);
1304   else
1305     timeout = PR_MillisecondsToInterval(DEFAULT_CONNECT_TIMEOUT);
1306 
1307   nread = PR_Recv(conn->ssl[num].handle, buf, (int)buffersize, 0, timeout);
1308   *wouldblock = FALSE;
1309   if(nread < 0) {
1310     /* failed SSL read */
1311     PRInt32 err = PR_GetError();
1312 
1313     if(err == PR_WOULD_BLOCK_ERROR) {
1314       *wouldblock = TRUE;
1315       return -1; /* basically EWOULDBLOCK */
1316     }
1317     if(err == PR_IO_TIMEOUT_ERROR) {
1318       failf(data, "SSL connection timeout");
1319       return CURLE_OPERATION_TIMEDOUT;
1320     }
1321     failf(conn->data, "SSL read: errno %d", err);
1322     return -1;
1323   }
1324   return nread;
1325 }
1326 
Curl_nss_version(char * buffer,size_t size)1327 size_t Curl_nss_version(char *buffer, size_t size)
1328 {
1329   return snprintf(buffer, size, "NSS/%s", NSS_VERSION);
1330 }
1331 #endif /* USE_NSS */
1332