~ubuntu-branches/ubuntu/hardy/curl/hardy-updates

« back to all changes in this revision

Viewing changes to lib/nss.c

  • Committer: Bazaar Package Importer
  • Author(s): Matthias Klose
  • Date: 2007-12-04 01:09:30 UTC
  • mfrom: (1.1.9 upstream)
  • Revision ID: james.westby@ubuntu.com-20071204010930-he4zlo7f3qdaz3qz
Tags: 7.17.1-1ubuntu1
* Merge with Debian; remaining changes:
  - Drop the stunnel build dependency.
* Drop the build-dependency on libdb4.5-dev, add build-dependency on
  openssh-server.

Show diffs side-by-side

added added

removed removed

Lines of Context:
18
18
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19
19
 * KIND, either express or implied.
20
20
 *
21
 
 * $Id: nss.c,v 1.5 2007-05-25 21:56:27 bagder Exp $
 
21
 * $Id: nss.c,v 1.13 2007-10-25 21:08:55 bagder Exp $
22
22
 ***************************************************************************/
23
23
 
24
24
/*
55
55
#include <ssl.h>
56
56
#include <sslerr.h>
57
57
#include <secerr.h>
 
58
#include <secmod.h>
58
59
#include <sslproto.h>
59
60
#include <prtypes.h>
60
61
#include <pk11pub.h>
69
70
#define min(a, b)   ((a) < (b) ? (a) : (b))
70
71
#endif
71
72
 
 
73
#define SSL_DIR "/etc/pki/nssdb"
 
74
 
 
75
/* enough to fit the string "PEM Token #[0|1]" */
 
76
#define SLOTSIZE 13
 
77
 
72
78
PRFileDesc *PR_ImportTCPSocket(PRInt32 osfd);
73
79
 
74
 
static int initialized = 0;
75
 
static int noverify = 0;
 
80
int initialized = 0;
76
81
 
77
82
#define HANDSHAKE_TIMEOUT 30
78
83
 
87
92
  PRInt32 version; /* protocol version valid for this cipher */
88
93
} cipher_s;
89
94
 
90
 
/* the table itself is defined in nss_engine_init.c */
91
95
#ifdef NSS_ENABLE_ECC
92
96
#define ciphernum 48
93
97
#else
94
98
#define ciphernum 23
95
99
#endif
96
100
 
 
101
#define PK11_SETATTRS(x,id,v,l) (x)->type = (id); \
 
102
                     (x)->pValue=(v); (x)->ulValueLen = (l)
 
103
 
 
104
#define CERT_NewTempCertificate __CERT_NewTempCertificate
 
105
 
97
106
enum sslversion { SSL2 = 1, SSL3 = 2, TLS = 4 };
98
107
 
99
 
cipher_s cipherlist[ciphernum] = {
 
108
static const cipher_s cipherlist[ciphernum] = {
100
109
  /* SSL2 cipher suites */
101
110
  {"rc4", SSL_EN_RC4_128_WITH_MD5, SSL2},
102
111
  {"rc4export", SSL_EN_RC4_128_EXPORT40_WITH_MD5, SSL2},
154
163
#endif
155
164
};
156
165
 
 
166
#ifdef HAVE_PK11_CREATEGENERICOBJECT
 
167
static const char* pem_library = "libnsspem.so";
 
168
#endif
 
169
SECMODModule* mod = NULL;
 
170
 
157
171
static SECStatus set_ciphers(struct SessionHandle *data, PRFileDesc * model,
158
172
                             char *cipher_list)
159
173
{
197
211
    }
198
212
 
199
213
    if(found == PR_FALSE) {
200
 
      char buf[1024];
201
 
      snprintf(buf, 1024, "Unknown cipher in list: %s", cipher);
202
 
      failf(data, buf);
 
214
      failf(data, "Unknown cipher in list: %s", cipher);
203
215
      return SECFailure;
204
216
    }
205
217
 
220
232
  return SECSuccess;
221
233
}
222
234
 
 
235
/*
 
236
 * Determine whether the nickname passed in is a filename that needs to
 
237
 * be loaded as a PEM or a regular NSS nickname.
 
238
 *
 
239
 * returns 1 for a file
 
240
 * returns 0 for not a file (NSS nickname)
 
241
 */
 
242
static int is_file(const char *filename)
 
243
{
 
244
  struct stat st;
 
245
 
 
246
  if(filename == NULL)
 
247
    return 0;
 
248
 
 
249
  if(stat(filename, &st) == 0)
 
250
    if(S_ISREG(st.st_mode))
 
251
      return 1;
 
252
 
 
253
  return 0;
 
254
}
 
255
 
 
256
static int
 
257
nss_load_cert(const char *filename, PRBool cacert)
 
258
{
 
259
#ifdef HAVE_PK11_CREATEGENERICOBJECT
 
260
  CK_SLOT_ID slotID;
 
261
  PK11SlotInfo * slot = NULL;
 
262
  PK11GenericObject *rv;
 
263
  CK_ATTRIBUTE *attrs;
 
264
  CK_ATTRIBUTE theTemplate[20];
 
265
  CK_BBOOL cktrue = CK_TRUE;
 
266
  CK_BBOOL ckfalse = CK_FALSE;
 
267
  CK_OBJECT_CLASS objClass = CKO_CERTIFICATE;
 
268
  char *slotname = NULL;
 
269
#endif
 
270
  CERTCertificate *cert;
 
271
  char *nickname = NULL;
 
272
  char *n = NULL;
 
273
 
 
274
  /* If there is no slash in the filename it is assumed to be a regular
 
275
   * NSS nickname.
 
276
   */
 
277
  if(is_file(filename)) {
 
278
    n = strrchr(filename, '/');
 
279
    if(n)
 
280
      n++;
 
281
    if(!mod)
 
282
      return 1;
 
283
  }
 
284
  else {
 
285
    /* A nickname from the NSS internal database */
 
286
    if (cacert)
 
287
      return 0; /* You can't specify an NSS CA nickname this way */
 
288
    nickname = strdup(filename);
 
289
    goto done;
 
290
  }
 
291
 
 
292
#ifdef HAVE_PK11_CREATEGENERICOBJECT
 
293
  attrs = theTemplate;
 
294
 
 
295
  /* All CA and trust objects go into slot 0. Other slots are used
 
296
   * for storing certificates. With each new user certificate we increment
 
297
   * the slot count. We only support 1 user certificate right now.
 
298
   */
 
299
  if (cacert)
 
300
    slotID = 0;
 
301
  else
 
302
    slotID = 1;
 
303
 
 
304
  slotname = (char *)malloc(SLOTSIZE);
 
305
  nickname = (char *)malloc(PATH_MAX);
 
306
  snprintf(slotname, SLOTSIZE, "PEM Token #%ld", slotID);
 
307
  snprintf(nickname, PATH_MAX, "PEM Token #%ld:%s", slotID, n);
 
308
 
 
309
  slot = PK11_FindSlotByName(slotname);
 
310
 
 
311
  if (!slot) {
 
312
    free(slotname);
 
313
    free(nickname);
 
314
    return 0;
 
315
  }
 
316
 
 
317
  PK11_SETATTRS(attrs, CKA_CLASS, &objClass, sizeof(objClass) ); attrs++;
 
318
  PK11_SETATTRS(attrs, CKA_TOKEN, &cktrue, sizeof(CK_BBOOL) ); attrs++;
 
319
  PK11_SETATTRS(attrs, CKA_LABEL, (unsigned char *)filename,
 
320
                strlen(filename)+1); attrs++;
 
321
  if (cacert) {
 
322
    PK11_SETATTRS(attrs, CKA_TRUST, &cktrue, sizeof(CK_BBOOL) ); attrs++;
 
323
  }
 
324
  else {
 
325
    PK11_SETATTRS(attrs, CKA_TRUST, &ckfalse, sizeof(CK_BBOOL) ); attrs++;
 
326
  }
 
327
 
 
328
  /* This load the certificate in our PEM module into the appropriate
 
329
   * slot.
 
330
   */
 
331
  rv = PK11_CreateGenericObject(slot, theTemplate, 4, PR_FALSE /* isPerm */);
 
332
 
 
333
  PK11_FreeSlot(slot);
 
334
 
 
335
  free(slotname);
 
336
  if(rv == NULL) {
 
337
    free(nickname);
 
338
    return 0;
 
339
  }
 
340
#else
 
341
  /* We don't have PK11_CreateGenericObject but a file-based cert was passed
 
342
   * in. We need to fail.
 
343
   */
 
344
  return 0;
 
345
#endif
 
346
 
 
347
done:
 
348
  /* Double-check that the certificate or nickname requested exists in
 
349
   * either the token or the NSS certificate database.
 
350
   */
 
351
  if (!cacert) {
 
352
    cert = PK11_FindCertFromNickname((char *)nickname, NULL);
 
353
 
 
354
    /* An invalid nickname was passed in */
 
355
    if (cert == NULL) {
 
356
      free(nickname);
 
357
      PR_SetError(SEC_ERROR_UNKNOWN_CERT, 0);
 
358
      return 0;
 
359
    }
 
360
 
 
361
    CERT_DestroyCertificate(cert);
 
362
  }
 
363
 
 
364
  free(nickname);
 
365
 
 
366
  return 1;
 
367
}
 
368
 
 
369
static int nss_load_key(struct connectdata *conn, char *key_file)
 
370
{
 
371
#ifdef HAVE_PK11_CREATEGENERICOBJECT
 
372
  PK11SlotInfo * slot = NULL;
 
373
  PK11GenericObject *rv;
 
374
  CK_ATTRIBUTE *attrs;
 
375
  CK_ATTRIBUTE theTemplate[20];
 
376
  CK_BBOOL cktrue = CK_TRUE;
 
377
  CK_OBJECT_CLASS objClass = CKO_PRIVATE_KEY;
 
378
  CK_SLOT_ID slotID;
 
379
  char *slotname = NULL;
 
380
  pphrase_arg_t *parg = NULL;
 
381
 
 
382
  attrs = theTemplate;
 
383
 
 
384
  /* FIXME: grok the various file types */
 
385
 
 
386
  slotID = 1; /* hardcoded for now */
 
387
 
 
388
  slotname = (char *)malloc(SLOTSIZE);
 
389
  snprintf(slotname, SLOTSIZE, "PEM Token #%ld", slotID);
 
390
 
 
391
  slot = PK11_FindSlotByName(slotname);
 
392
  free(slotname);
 
393
 
 
394
  if(!slot)
 
395
    return 0;
 
396
 
 
397
  PK11_SETATTRS(attrs, CKA_CLASS, &objClass, sizeof(objClass) ); attrs++;
 
398
  PK11_SETATTRS(attrs, CKA_TOKEN, &cktrue, sizeof(CK_BBOOL) ); attrs++;
 
399
  PK11_SETATTRS(attrs, CKA_LABEL, (unsigned char *)key_file,
 
400
                strlen(key_file)+1); attrs++;
 
401
 
 
402
  /* When adding an encrypted key the PKCS#11 will be set as removed */
 
403
  rv = PK11_CreateGenericObject(slot, theTemplate, 3, PR_FALSE /* isPerm */);
 
404
  if(rv == NULL) {
 
405
    PR_SetError(SEC_ERROR_BAD_KEY, 0);
 
406
    return 0;
 
407
  }
 
408
 
 
409
  /* This will force the token to be seen as re-inserted */
 
410
  SECMOD_WaitForAnyTokenEvent(mod, 0, 0);
 
411
  PK11_IsPresent(slot);
 
412
 
 
413
  parg = (pphrase_arg_t *) malloc(sizeof(*parg));
 
414
  parg->retryCount = 0;
 
415
  parg->data = conn->data;
 
416
  /* parg is initialized in nss_Init_Tokens() */
 
417
  if(PK11_Authenticate(slot, PR_TRUE, parg) != SECSuccess) {
 
418
    free(parg);
 
419
    return 0;
 
420
  }
 
421
  free(parg);
 
422
 
 
423
  return 1;
 
424
#else
 
425
  /* If we don't have PK11_CreateGenericObject then we can't load a file-based
 
426
   * key.
 
427
   */
 
428
  (void)conn; /* unused */
 
429
  (void)key_file; /* unused */
 
430
  return 0;
 
431
#endif
 
432
}
 
433
 
 
434
static int display_error(struct connectdata *conn, PRInt32 err,
 
435
                         const char *filename)
 
436
{
 
437
  switch(err) {
 
438
  case SEC_ERROR_BAD_PASSWORD:
 
439
    failf(conn->data, "Unable to load client key: Incorrect password\n");
 
440
    return 1;
 
441
  case SEC_ERROR_UNKNOWN_CERT:
 
442
    failf(conn->data, "Unable to load certificate %s\n", filename);
 
443
    return 1;
 
444
  default:
 
445
    break;
 
446
  }
 
447
  return 0; /* The caller will print a generic error */
 
448
}
 
449
 
 
450
static int cert_stuff(struct connectdata *conn, char *cert_file, char *key_file)
 
451
{
 
452
  struct SessionHandle *data = conn->data;
 
453
  int rv = 0;
 
454
 
 
455
  if(cert_file) {
 
456
    rv = nss_load_cert(cert_file, PR_FALSE);
 
457
    if(!rv) {
 
458
      if(!display_error(conn, PR_GetError(), cert_file))
 
459
        failf(data, "Unable to load client cert %d.", PR_GetError());
 
460
      return 0;
 
461
    }
 
462
  }
 
463
  if(key_file || (is_file(cert_file))) {
 
464
    if(key_file)
 
465
      rv = nss_load_key(conn, key_file);
 
466
    else
 
467
      /* In case the cert file also has the key */
 
468
      rv = nss_load_key(conn, cert_file);
 
469
    if(!rv) {
 
470
      if(!display_error(conn, PR_GetError(), key_file))
 
471
        failf(data, "Unable to load client key %d.", PR_GetError());
 
472
 
 
473
      return 0;
 
474
    }
 
475
  }
 
476
  return 1;
 
477
}
 
478
 
223
479
static char * nss_get_password(PK11SlotInfo * slot, PRBool retry, void *arg)
224
480
{
225
 
  pphrase_arg_t *parg = (pphrase_arg_t *) arg;
 
481
  pphrase_arg_t *parg;
 
482
  parg = (pphrase_arg_t *) arg;
 
483
 
 
484
  (void)slot; /* unused */
 
485
  if(retry > 2)
 
486
    return NULL;
 
487
  if(parg->data->set.str[STRING_KEY_PASSWD])
 
488
    return (char *)PORT_Strdup((char *)parg->data->set.str[STRING_KEY_PASSWD]);
 
489
  else
 
490
    return NULL;
 
491
}
 
492
 
 
493
/* No longer ask for the password, parg has been freed */
 
494
static char * nss_no_password(PK11SlotInfo *slot, PRBool retry, void *arg)
 
495
{
226
496
  (void)slot; /* unused */
227
497
  (void)retry; /* unused */
228
 
  if(parg->data->set.key_passwd)
229
 
    return (char *)PORT_Strdup((char *)parg->data->set.key_passwd);
230
 
  else
231
 
    return NULL;
 
498
  (void)arg; /* unused */
 
499
  return NULL;
232
500
}
233
501
 
234
502
static SECStatus nss_Init_Tokens(struct connectdata * conn)
236
504
  PK11SlotList *slotList;
237
505
  PK11SlotListElement *listEntry;
238
506
  SECStatus ret, status = SECSuccess;
239
 
  pphrase_arg_t *parg;
 
507
  pphrase_arg_t *parg = NULL;
240
508
 
241
509
  parg = (pphrase_arg_t *) malloc(sizeof(*parg));
242
510
  parg->retryCount = 0;
265
533
 
266
534
    ret = PK11_Authenticate(slot, PR_TRUE, parg);
267
535
    if(SECSuccess != ret) {
 
536
      if (PR_GetError() == SEC_ERROR_BAD_PASSWORD)
 
537
        infof(conn->data, "The password for token '%s' is incorrect\n",
 
538
              PK11_GetTokenName(slot));
268
539
      status = SECFailure;
269
540
      break;
270
541
    }
273
544
  }
274
545
 
275
546
  free(parg);
 
547
 
276
548
  return status;
277
549
}
278
550
 
279
 
static SECStatus BadCertHandler(void *arg, PRFileDesc * socket)
 
551
static SECStatus BadCertHandler(void *arg, PRFileDesc *sock)
280
552
{
281
553
  SECStatus success = SECSuccess;
282
 
  (void)arg;
283
 
  (void)socket;
 
554
  struct connectdata *conn = (struct connectdata *)arg;
 
555
  PRErrorCode err = PR_GetError();
 
556
  CERTCertificate *cert = NULL;
 
557
  char *subject, *issuer;
 
558
 
 
559
  if (conn->data->set.ssl.certverifyresult!=0)
 
560
    return success;
 
561
 
 
562
  conn->data->set.ssl.certverifyresult=err;
 
563
  cert = SSL_PeerCertificate(sock);
 
564
  subject = CERT_NameToAscii(&cert->subject);
 
565
  issuer = CERT_NameToAscii(&cert->issuer);
 
566
  CERT_DestroyCertificate(cert);
 
567
 
 
568
  switch(err) {
 
569
  case SEC_ERROR_CA_CERT_INVALID:
 
570
    infof(conn->data, "Issuer certificate is invalid: '%s'\n", issuer);
 
571
    if (conn->data->set.ssl.verifypeer)
 
572
      success = SECFailure;
 
573
    break;
 
574
  case SEC_ERROR_UNTRUSTED_ISSUER:
 
575
    if (conn->data->set.ssl.verifypeer)
 
576
      success = SECFailure;
 
577
    infof(conn->data, "Certificate is signed by an untrusted issuer: '%s'\n",
 
578
          issuer);
 
579
    break;
 
580
  case SSL_ERROR_BAD_CERT_DOMAIN:
 
581
    if (conn->data->set.ssl.verifypeer)
 
582
      success = SECFailure;
 
583
    infof(conn->data, "common name: %s (does not match '%s')\n",
 
584
          subject, conn->host.dispname);
 
585
    break;
 
586
  case SEC_ERROR_EXPIRED_CERTIFICATE:
 
587
    if (conn->data->set.ssl.verifypeer)
 
588
      success = SECFailure;
 
589
    infof(conn->data, "Remote Certificate has expired.\n");
 
590
    break;
 
591
  default:
 
592
    if (conn->data->set.ssl.verifypeer)
 
593
      success = SECFailure;
 
594
    infof(conn->data, "Bad certificate received. Subject = '%s', "
 
595
          "Issuer = '%s'\n", subject, issuer);
 
596
    break;
 
597
  }
 
598
  if (success == SECSuccess)
 
599
    infof(conn->data, "SSL certificate verify ok.\n");
 
600
  PR_Free(subject);
 
601
  PR_Free(issuer);
284
602
 
285
603
  return success;
286
604
}
288
606
/**
289
607
 * Inform the application that the handshake is complete.
290
608
 */
291
 
static SECStatus HandshakeCallback(PRFileDesc * socket, void *arg)
 
609
static SECStatus HandshakeCallback(PRFileDesc *sock, void *arg)
292
610
{
293
 
  (void)socket;
 
611
  (void)sock;
294
612
  (void)arg;
295
613
  return SECSuccess;
296
614
}
297
615
 
 
616
static void display_conn_info(struct connectdata *conn, PRFileDesc *sock)
 
617
{
 
618
  SSLChannelInfo channel;
 
619
  SSLCipherSuiteInfo suite;
 
620
  CERTCertificate *cert;
 
621
  char *subject, *issuer, *common_name;
 
622
  PRExplodedTime printableTime;
 
623
  char timeString[256];
 
624
  PRTime notBefore, notAfter;
 
625
 
 
626
  if (SSL_GetChannelInfo(sock, &channel, sizeof channel) ==
 
627
    SECSuccess && channel.length == sizeof channel &&
 
628
    channel.cipherSuite) {
 
629
    if (SSL_GetCipherSuiteInfo(channel.cipherSuite,
 
630
      &suite, sizeof suite) == SECSuccess) {
 
631
      infof(conn->data, "SSL connection using %s\n", suite.cipherSuiteName);
 
632
    }
 
633
  }
 
634
 
 
635
  infof(conn->data, "Server certificate:\n");
 
636
 
 
637
  cert = SSL_PeerCertificate(sock);
 
638
  subject = CERT_NameToAscii(&cert->subject);
 
639
  issuer = CERT_NameToAscii(&cert->issuer);
 
640
  common_name = CERT_GetCommonName(&cert->subject);
 
641
  infof(conn->data, "\tsubject: %s\n", subject);
 
642
 
 
643
  CERT_GetCertTimes(cert, &notBefore, &notAfter);
 
644
  PR_ExplodeTime(notBefore, PR_GMTParameters, &printableTime);
 
645
  PR_FormatTime(timeString, 256, "%b %d %H:%M:%S %Y GMT", &printableTime);
 
646
  infof(conn->data, "\tstart date: %s\n", timeString);
 
647
  PR_ExplodeTime(notAfter, PR_GMTParameters, &printableTime);
 
648
  PR_FormatTime(timeString, 256, "%b %d %H:%M:%S %Y GMT", &printableTime);
 
649
  infof(conn->data, "\texpire date: %s\n", timeString);
 
650
  infof(conn->data, "\tcommon name: %s\n", common_name);
 
651
  infof(conn->data, "\tissuer: %s\n", issuer);
 
652
 
 
653
  PR_Free(subject);
 
654
  PR_Free(issuer);
 
655
  PR_Free(common_name);
 
656
 
 
657
  CERT_DestroyCertificate(cert);
 
658
 
 
659
  return;
 
660
}
 
661
 
298
662
/**
299
663
 *
300
664
 * Callback to pick the SSL client certificate.
301
665
 */
302
 
static SECStatus SelectClientCert(void *arg, PRFileDesc * socket,
303
 
                                  struct CERTDistNamesStr * caNames,
304
 
                                  struct CERTCertificateStr ** pRetCert,
305
 
                                  struct SECKEYPrivateKeyStr ** pRetKey)
 
666
static SECStatus SelectClientCert(void *arg, PRFileDesc *sock,
 
667
                                  struct CERTDistNamesStr *caNames,
 
668
                                  struct CERTCertificateStr **pRetCert,
 
669
                                  struct SECKEYPrivateKeyStr **pRetKey)
306
670
{
307
671
  CERTCertificate *cert;
308
672
  SECKEYPrivateKey *privKey;
309
673
  char *nickname = (char *)arg;
310
674
  void *proto_win = NULL;
311
675
  SECStatus secStatus = SECFailure;
 
676
  PK11SlotInfo *slot;
312
677
  (void)caNames;
313
678
 
314
 
  proto_win = SSL_RevealPinArg(socket);
 
679
  proto_win = SSL_RevealPinArg(sock);
 
680
 
 
681
  if (!nickname)
 
682
    return secStatus;
315
683
 
316
684
  cert = PK11_FindCertFromNickname(nickname, proto_win);
317
685
  if(cert) {
318
 
    privKey = PK11_FindKeyByAnyCert(cert, proto_win);
319
 
    if(privKey) {
320
 
      secStatus = SECSuccess;
 
686
 
 
687
    if(!strncmp(nickname, "PEM Token", 9)) {
 
688
      CK_SLOT_ID slotID = 1; /* hardcoded for now */
 
689
      char * slotname = (char *)malloc(SLOTSIZE);
 
690
      snprintf(slotname, SLOTSIZE, "PEM Token #%ld", slotID);
 
691
      slot = PK11_FindSlotByName(slotname);
 
692
      privKey = PK11_FindPrivateKeyFromCert(slot, cert, NULL);
 
693
      PK11_FreeSlot(slot);
 
694
      free(slotname);
 
695
      if(privKey) {
 
696
        secStatus = SECSuccess;
 
697
      }
321
698
    }
322
699
    else {
323
 
      CERT_DestroyCertificate(cert);
 
700
      privKey = PK11_FindKeyByAnyCert(cert, proto_win);
 
701
      if(privKey)
 
702
        secStatus = SECSuccess;
324
703
    }
325
704
  }
326
705
 
328
707
    *pRetCert = cert;
329
708
    *pRetKey = privKey;
330
709
  }
 
710
  else {
 
711
    if (cert)
 
712
      CERT_DestroyCertificate(cert);
 
713
  }
331
714
 
332
715
  return secStatus;
333
716
}
384
767
/*
385
768
 * This function is called when an SSL connection is closed.
386
769
 */
387
 
void Curl_nss_close(struct connectdata *conn)
 
770
void Curl_nss_close(struct connectdata *conn, int sockindex)
388
771
{
389
 
  int i;
390
 
 
391
 
  for(i=0; i<2; i++) {
392
 
    struct ssl_connect_data *connssl = &conn->ssl[i];
393
 
 
394
 
    if(connssl->handle) {
395
 
      PR_Close(connssl->handle);
396
 
      connssl->handle = NULL;
 
772
  struct ssl_connect_data *connssl = &conn->ssl[sockindex];
 
773
 
 
774
  if(connssl->handle) {
 
775
    PR_Close(connssl->handle);
 
776
    if(connssl->client_nickname != NULL) {
 
777
      free(connssl->client_nickname);
 
778
      connssl->client_nickname = NULL;
397
779
    }
398
 
    connssl->use = FALSE; /* get back to ordinary socket usage */
 
780
    connssl->handle = NULL;
399
781
  }
400
782
}
401
783
 
418
800
  curl_socket_t sockfd = conn->sock[sockindex];
419
801
  struct ssl_connect_data *connssl = &conn->ssl[sockindex];
420
802
  SECStatus rv;
421
 
  int curlerr = CURLE_SSL_CONNECT_ERROR;
 
803
#ifdef HAVE_PK11_CREATEGENERICOBJECT
 
804
  char *configstring = NULL;
 
805
#endif
 
806
  char *certDir = NULL;
 
807
  int curlerr;
 
808
 
 
809
  curlerr = CURLE_SSL_CONNECT_ERROR;
422
810
 
423
811
  /* FIXME. NSS doesn't support multiple databases open at the same time. */
424
812
  if(!initialized) {
425
 
    if(!data->set.ssl.CAfile) {
426
 
      if(data->set.ssl.verifypeer) {
427
 
        failf(data, "No NSS cacert database specified.");
428
 
        return CURLE_SSL_CACERT_BADFILE;
429
 
      }
430
 
      else {
431
 
        rv = NSS_NoDB_Init(NULL);
432
 
        noverify = 1;
433
 
      }
 
813
    initialized = 1;
 
814
 
 
815
    certDir = getenv("SSL_DIR"); /* Look in $SSL_DIR */
 
816
 
 
817
    if (!certDir) {
 
818
      struct stat st;
 
819
 
 
820
      if (stat(SSL_DIR, &st) == 0)
 
821
        if (S_ISDIR(st.st_mode)) {
 
822
          certDir = (char *)SSL_DIR;
 
823
        }
 
824
    }
 
825
 
 
826
    if(!certDir) {
 
827
      rv = NSS_NoDB_Init(NULL);
434
828
    }
435
829
    else {
436
 
      rv = NSS_Initialize(data->set.ssl.CAfile, NULL, NULL, "secmod.db",
 
830
      rv = NSS_Initialize(certDir, NULL, NULL, "secmod.db",
437
831
                          NSS_INIT_READONLY);
438
832
    }
439
833
    if(rv != SECSuccess) {
 
834
      infof(conn->data, "Unable to initialize NSS database\n");
440
835
      curlerr = CURLE_SSL_CACERT_BADFILE;
441
836
      goto error;
442
837
    }
 
838
 
 
839
    NSS_SetDomesticPolicy();
 
840
 
 
841
#ifdef HAVE_PK11_CREATEGENERICOBJECT
 
842
    configstring = (char *)malloc(PATH_MAX);
 
843
 
 
844
    PR_snprintf(configstring, PATH_MAX, "library=%s name=PEM", pem_library);
 
845
 
 
846
    mod = SECMOD_LoadUserModule(configstring, NULL, PR_FALSE);
 
847
    free(configstring);
 
848
    if (!mod || !mod->loaded) {
 
849
      if (mod) {
 
850
        SECMOD_DestroyModule(mod);
 
851
        mod = NULL;
 
852
      }
 
853
      infof(data, "WARNING: failed to load NSS PEM library %s. Using OpenSSL "
 
854
            "PEM certificates will not work.\n", pem_library);
 
855
    }
 
856
#endif
443
857
  }
444
858
 
445
 
  NSS_SetDomesticPolicy();
446
 
 
447
859
  model = PR_NewTCPSocket();
448
860
  if(!model)
449
861
    goto error;
482
894
    goto error;
483
895
 
484
896
  if(data->set.ssl.cipher_list) {
485
 
    if(set_ciphers(data, model, data->set.ssl.cipher_list) != SECSuccess)
 
897
    if(set_ciphers(data, model, data->set.ssl.cipher_list) != SECSuccess) {
 
898
      curlerr = CURLE_SSL_CIPHER;
486
899
      goto error;
 
900
    }
487
901
  }
488
902
 
489
 
  if(SSL_BadCertHook(model, (SSLBadCertHandler) BadCertHandler, NULL)
490
 
     != SECSuccess)
 
903
  data->set.ssl.certverifyresult=0; /* not checked yet */
 
904
  if(SSL_BadCertHook(model, (SSLBadCertHandler) BadCertHandler, conn)
 
905
     != SECSuccess) {
491
906
    goto error;
 
907
  }
492
908
  if(SSL_HandshakeCallback(model, (SSLHandshakeCallback) HandshakeCallback,
493
909
                           NULL) != SECSuccess)
494
910
    goto error;
495
911
 
496
 
  if(data->set.cert) {
 
912
  if(!data->set.ssl.verifypeer)
 
913
    /* skip the verifying of the peer */
 
914
    ;
 
915
  else if (data->set.ssl.CAfile) {
 
916
    int rc = nss_load_cert(data->set.ssl.CAfile, PR_TRUE);
 
917
    if (!rc) {
 
918
      curlerr = CURLE_SSL_CACERT_BADFILE;
 
919
      goto error;
 
920
    }
 
921
  }
 
922
  else if (data->set.ssl.CApath) {
 
923
    struct stat st;
 
924
    PRDir      *dir;
 
925
    PRDirEntry *entry;
 
926
 
 
927
    if (stat(data->set.ssl.CApath, &st) == -1) {
 
928
      curlerr = CURLE_SSL_CACERT_BADFILE;
 
929
      goto error;
 
930
    }
 
931
 
 
932
    if (S_ISDIR(st.st_mode)) {
 
933
      int rc;
 
934
 
 
935
      dir = PR_OpenDir(data->set.ssl.CApath);
 
936
      do {
 
937
        entry = PR_ReadDir(dir, PR_SKIP_BOTH | PR_SKIP_HIDDEN);
 
938
 
 
939
        if (entry) {
 
940
          char fullpath[PATH_MAX];
 
941
 
 
942
          snprintf(fullpath, sizeof(fullpath), "%s/%s", data->set.ssl.CApath,
 
943
                   entry->name);
 
944
          rc = nss_load_cert(fullpath, PR_TRUE);
 
945
          /* FIXME: check this return value! */
 
946
        }
 
947
      /* This is purposefully tolerant of errors so non-PEM files
 
948
       * can be in the same directory */
 
949
      } while (entry != NULL);
 
950
      PR_CloseDir(dir);
 
951
    }
 
952
  }
 
953
  infof(data,
 
954
        "  CAfile: %s\n"
 
955
        "  CApath: %s\n",
 
956
        data->set.ssl.CAfile ? data->set.ssl.CAfile : "none",
 
957
        data->set.ssl.CApath ? data->set.ssl.CApath : "none");
 
958
 
 
959
  if(data->set.str[STRING_CERT]) {
 
960
    char *n;
 
961
    char *nickname;
 
962
 
 
963
    nickname = (char *)malloc(PATH_MAX);
 
964
    if(is_file(data->set.str[STRING_CERT])) {
 
965
      n = strrchr(data->set.str[STRING_CERT], '/');
 
966
      if (n) {
 
967
        n++; /* skip last slash */
 
968
        snprintf(nickname, PATH_MAX, "PEM Token #%ld:%s", 1, n);
 
969
      }
 
970
    }
 
971
    else {
 
972
      strncpy(nickname, data->set.str[STRING_CERT], PATH_MAX);
 
973
    }
 
974
    if(nss_Init_Tokens(conn) != SECSuccess) {
 
975
      free(nickname);
 
976
      goto error;
 
977
    }
 
978
    if (!cert_stuff(conn, data->set.str[STRING_CERT],
 
979
                    data->set.str[STRING_KEY])) {
 
980
      /* failf() is already done in cert_stuff() */
 
981
      free(nickname);
 
982
      return CURLE_SSL_CERTPROBLEM;
 
983
    }
 
984
 
 
985
    connssl->client_nickname = strdup(nickname);
497
986
    if(SSL_GetClientAuthDataHook(model,
498
987
                                 (SSLGetClientAuthData) SelectClientCert,
499
 
                                 (void *)data->set.cert) != SECSuccess) {
 
988
                                 (void *)connssl->client_nickname) !=
 
989
       SECSuccess) {
500
990
      curlerr = CURLE_SSL_CERTPROBLEM;
501
991
      goto error;
502
992
    }
503
 
    if(nss_Init_Tokens(conn) != SECSuccess)
504
 
      goto error;
 
993
 
 
994
    free(nickname);
 
995
 
 
996
    PK11_SetPasswordFunc(nss_no_password);
505
997
  }
 
998
  else
 
999
    connssl->client_nickname = NULL;
506
1000
 
507
1001
  /* Import our model socket  onto the existing file descriptor */
508
1002
  connssl->handle = PR_ImportTCPSocket(sockfd);
509
1003
  connssl->handle = SSL_ImportFD(model, connssl->handle);
510
1004
  if(!connssl->handle)
511
1005
    goto error;
 
1006
  PR_Close(model); /* We don't need this any more */
512
1007
 
513
1008
  /* Force handshake on next I/O */
514
1009
  SSL_ResetHandshake(connssl->handle, /* asServer */ PR_FALSE);
518
1013
  /* Force the handshake now */
519
1014
  if (SSL_ForceHandshakeWithTimeout(connssl->handle,
520
1015
                                    PR_SecondsToInterval(HANDSHAKE_TIMEOUT))
521
 
      != SECSuccess)
 
1016
      != SECSuccess) {
 
1017
    if (conn->data->set.ssl.certverifyresult!=0)
 
1018
      curlerr = CURLE_SSL_CACERT;
522
1019
    goto error;
 
1020
  }
 
1021
 
 
1022
  display_conn_info(conn, connssl->handle);
523
1023
 
524
1024
  return CURLE_OK;
525
1025
 
526
1026
error:
527
1027
  err = PR_GetError();
528
 
  failf(data, "NSS error %d", err);
 
1028
  infof(data, "NSS error %d\n", err);
529
1029
  if(model)
530
1030
    PR_Close(model);
531
1031
  return curlerr;
554
1054
 
555
1055
    if(err == PR_IO_TIMEOUT_ERROR) {
556
1056
      failf(data, "SSL connection timeout");
557
 
      return CURLE_OPERATION_TIMEOUTED;
 
1057
      return CURLE_OPERATION_TIMEDOUT;
558
1058
    }
559
1059
 
560
1060
    failf(conn->data, "SSL write: error %d\n", err);
595
1095
    }
596
1096
    if(err == PR_IO_TIMEOUT_ERROR) {
597
1097
      failf(data, "SSL connection timeout");
598
 
      return CURLE_OPERATION_TIMEOUTED;
 
1098
      return CURLE_OPERATION_TIMEDOUT;
599
1099
    }
600
1100
    failf(conn->data, "SSL read: errno %d", err);
601
1101
    return -1;
605
1105
 
606
1106
size_t Curl_nss_version(char *buffer, size_t size)
607
1107
{
608
 
  return snprintf(buffer, size, " NSS/%s", NSS_VERSION);
 
1108
  return snprintf(buffer, size, "NSS/%s", NSS_VERSION);
609
1109
}
610
1110
#endif /* USE_NSS */