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, ¬Before, ¬After);
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