~ubuntu-branches/ubuntu/lucid/curl/lucid-201101212007

« back to all changes in this revision

Viewing changes to lib/nss.c

  • Committer: Bazaar Package Importer
  • Author(s): Bhavani Shankar
  • Date: 2009-05-26 18:58:51 UTC
  • mfrom: (3.3.1 squeeze)
  • Revision ID: james.westby@ubuntu.com-20090526185851-t1gun9nboi5kbd9u
Tags: 7.19.5-1ubuntu1
* Merge from Debian unstable (LP: #380281), remaining changes:
  - Drop build dependencies: stunnel, libdb4.6-dev, libssh2-1-dev
  - Add build-dependency on openssh-server
  - Drop libssh2-1-dev from libcurl4-openssl-dev's Depends.
  - Call automake-1.9 with --add-missing --copy --force
* Fixes LP: #379477

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.41 2009-02-27 08:53:10 bagder Exp $
 
21
 * $Id: nss.c,v 1.47 2009-05-11 09:13:49 bagder Exp $
22
22
 ***************************************************************************/
23
23
 
24
24
/*
64
64
#include <secport.h>
65
65
#include <certdb.h>
66
66
 
67
 
#include "memory.h"
 
67
#include "curl_memory.h"
68
68
#include "rawstr.h"
69
69
#include "easyif.h" /* for Curl_convert_from_utf8 prototype */
70
70
 
85
85
#define HANDSHAKE_TIMEOUT 30
86
86
 
87
87
typedef struct {
88
 
  PRInt32 retryCount;
89
 
  struct SessionHandle *data;
90
 
} pphrase_arg_t;
91
 
 
92
 
typedef struct {
93
88
  const char *name;
94
89
  int num;
95
90
  PRInt32 version; /* protocol version valid for this cipher */
162
157
#endif
163
158
};
164
159
 
 
160
/* following ciphers are new in NSS 3.4 and not enabled by default, therefor
 
161
   they are enabled explicitly */
 
162
static const int enable_ciphers_by_default[] = {
 
163
  TLS_DHE_DSS_WITH_AES_128_CBC_SHA,
 
164
  TLS_DHE_DSS_WITH_AES_256_CBC_SHA,
 
165
  TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
 
166
  TLS_DHE_RSA_WITH_AES_256_CBC_SHA,
 
167
  TLS_RSA_WITH_AES_128_CBC_SHA,
 
168
  TLS_RSA_WITH_AES_256_CBC_SHA,
 
169
  SSL_NULL_WITH_NULL_NULL
 
170
};
 
171
 
165
172
#ifdef HAVE_PK11_CREATEGENERICOBJECT
166
173
static const char* pem_library = "libnsspem.so";
167
174
#endif
270
277
  return 0;
271
278
}
272
279
 
273
 
static int
274
 
nss_load_cert(const char *filename, PRBool cacert)
 
280
static int nss_load_cert(struct ssl_connect_data *ssl,
 
281
                         const char *filename, PRBool cacert)
275
282
{
276
283
#ifdef HAVE_PK11_CREATEGENERICOBJECT
277
284
  CK_SLOT_ID slotID;
278
285
  PK11SlotInfo * slot = NULL;
279
 
  PK11GenericObject *rv;
280
286
  CK_ATTRIBUTE *attrs;
281
287
  CK_ATTRIBUTE theTemplate[20];
282
288
  CK_BBOOL cktrue = CK_TRUE;
351
357
  /* This load the certificate in our PEM module into the appropriate
352
358
   * slot.
353
359
   */
354
 
  rv = PK11_CreateGenericObject(slot, theTemplate, 4, PR_FALSE /* isPerm */);
 
360
  ssl->cacert[slotID] = PK11_CreateGenericObject(slot, theTemplate, 4,
 
361
                                         PR_FALSE /* isPerm */);
355
362
 
356
363
  PK11_FreeSlot(slot);
357
364
 
358
 
  if(rv == NULL) {
 
365
  if(ssl->cacert[slotID] == NULL) {
359
366
    free(nickname);
360
367
    return 0;
361
368
  }
462
469
  return 1;
463
470
}
464
471
 
465
 
static int nss_load_key(struct connectdata *conn, char *key_file)
 
472
static int nss_load_key(struct connectdata *conn, int sockindex, char *key_file)
466
473
{
467
474
#ifdef HAVE_PK11_CREATEGENERICOBJECT
468
475
  PK11SlotInfo * slot = NULL;
469
 
  PK11GenericObject *rv;
470
476
  CK_ATTRIBUTE *attrs;
471
477
  CK_ATTRIBUTE theTemplate[20];
472
478
  CK_BBOOL cktrue = CK_TRUE;
473
479
  CK_OBJECT_CLASS objClass = CKO_PRIVATE_KEY;
474
480
  CK_SLOT_ID slotID;
475
 
  pphrase_arg_t *parg = NULL;
476
481
  char slotname[SLOTSIZE];
 
482
  struct ssl_connect_data *sslconn = &conn->ssl[sockindex];
477
483
 
478
484
  attrs = theTemplate;
479
485
 
493
499
                strlen(key_file)+1); attrs++;
494
500
 
495
501
  /* 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) {
 
502
  sslconn->key = PK11_CreateGenericObject(slot, theTemplate, 3,
 
503
                                          PR_FALSE /* isPerm */);
 
504
  if(sslconn->key == NULL) {
498
505
    PR_SetError(SEC_ERROR_BAD_KEY, 0);
499
506
    return 0;
500
507
  }
503
510
  SECMOD_WaitForAnyTokenEvent(mod, 0, 0);
504
511
  PK11_IsPresent(slot);
505
512
 
506
 
  parg = malloc(sizeof(pphrase_arg_t));
507
 
  if(!parg)
508
 
    return 0;
509
 
  parg->retryCount = 0;
510
 
  parg->data = conn->data;
511
513
  /* parg is initialized in nss_Init_Tokens() */
512
 
  if(PK11_Authenticate(slot, PR_TRUE, parg) != SECSuccess) {
513
 
    free(parg);
 
514
  if(PK11_Authenticate(slot, PR_TRUE,
 
515
                       conn->data->set.str[STRING_KEY_PASSWD]) != SECSuccess) {
 
516
 
 
517
    PK11_FreeSlot(slot);
514
518
    return 0;
515
519
  }
516
 
  free(parg);
 
520
  PK11_FreeSlot(slot);
517
521
 
518
522
  return 1;
519
523
#else
542
546
  return 0; /* The caller will print a generic error */
543
547
}
544
548
 
545
 
static int cert_stuff(struct connectdata *conn, char *cert_file, char *key_file)
 
549
static int cert_stuff(struct connectdata *conn,
 
550
                      int sockindex, char *cert_file, char *key_file)
546
551
{
547
552
  struct SessionHandle *data = conn->data;
548
553
  int rv = 0;
549
554
 
550
555
  if(cert_file) {
551
 
    rv = nss_load_cert(cert_file, PR_FALSE);
 
556
    rv = nss_load_cert(&conn->ssl[sockindex], cert_file, PR_FALSE);
552
557
    if(!rv) {
553
558
      if(!display_error(conn, PR_GetError(), cert_file))
554
559
        failf(data, "Unable to load client cert %d.", PR_GetError());
557
562
  }
558
563
  if(key_file || (is_file(cert_file))) {
559
564
    if(key_file)
560
 
      rv = nss_load_key(conn, key_file);
 
565
      rv = nss_load_key(conn, sockindex, key_file);
561
566
    else
562
567
      /* In case the cert file also has the key */
563
 
      rv = nss_load_key(conn, cert_file);
 
568
      rv = nss_load_key(conn, sockindex, cert_file);
564
569
    if(!rv) {
565
570
      if(!display_error(conn, PR_GetError(), key_file))
566
571
        failf(data, "Unable to load client key %d.", PR_GetError());
573
578
 
574
579
static char * nss_get_password(PK11SlotInfo * slot, PRBool retry, void *arg)
575
580
{
576
 
  pphrase_arg_t *parg;
577
 
  parg = (pphrase_arg_t *) arg;
578
 
 
579
581
  (void)slot; /* unused */
580
 
  if(retry > 2)
 
582
  if(retry || NULL == arg)
581
583
    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
584
  else
585
 
    return NULL;
586
 
}
587
 
 
588
 
/* No longer ask for the password, parg has been freed */
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;
 
585
    return (char *)PORT_Strdup((char *)arg);
595
586
}
596
587
 
597
588
static SECStatus nss_Init_Tokens(struct connectdata * conn)
599
590
  PK11SlotList *slotList;
600
591
  PK11SlotListElement *listEntry;
601
592
  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
593
 
611
594
  PK11_SetPasswordFunc(nss_get_password);
612
595
 
629
612
      continue;
630
613
    }
631
614
 
632
 
    ret = PK11_Authenticate(slot, PR_TRUE, parg);
 
615
    ret = PK11_Authenticate(slot, PR_TRUE,
 
616
                            conn->data->set.str[STRING_KEY_PASSWD]);
633
617
    if(SECSuccess != ret) {
634
618
      if(PR_GetError() == SEC_ERROR_BAD_PASSWORD)
635
619
        infof(conn->data, "The password for token '%s' is incorrect\n",
637
621
      status = SECFailure;
638
622
      break;
639
623
    }
640
 
    parg->retryCount = 0; /* reset counter to 0 for the next token */
641
624
    PK11_FreeSlot(slot);
642
625
  }
643
626
 
644
 
  free(parg);
645
 
 
646
627
  return status;
647
628
}
648
629
 
805
786
                                  struct CERTCertificateStr **pRetCert,
806
787
                                  struct SECKEYPrivateKeyStr **pRetKey)
807
788
{
808
 
  CERTCertificate *cert;
809
789
  SECKEYPrivateKey *privKey;
810
 
  char *nickname = (char *)arg;
 
790
  struct ssl_connect_data *connssl = (struct ssl_connect_data *) arg;
 
791
  char *nickname = connssl->client_nickname;
811
792
  void *proto_win = NULL;
812
793
  SECStatus secStatus = SECFailure;
813
794
  PK11SlotInfo *slot;
818
799
  if(!nickname)
819
800
    return secStatus;
820
801
 
821
 
  cert = PK11_FindCertFromNickname(nickname, proto_win);
822
 
  if(cert) {
 
802
  connssl->client_cert = PK11_FindCertFromNickname(nickname, proto_win);
 
803
  if(connssl->client_cert) {
823
804
 
824
805
    if(!strncmp(nickname, "PEM Token", 9)) {
825
806
      CK_SLOT_ID slotID = 1; /* hardcoded for now */
826
807
      char slotname[SLOTSIZE];
827
808
      snprintf(slotname, SLOTSIZE, "PEM Token #%ld", slotID);
828
809
      slot = PK11_FindSlotByName(slotname);
829
 
      privKey = PK11_FindPrivateKeyFromCert(slot, cert, NULL);
 
810
      privKey = PK11_FindPrivateKeyFromCert(slot, connssl->client_cert, NULL);
830
811
      PK11_FreeSlot(slot);
831
812
      if(privKey) {
832
813
        secStatus = SECSuccess;
833
814
      }
834
815
    }
835
816
    else {
836
 
      privKey = PK11_FindKeyByAnyCert(cert, proto_win);
 
817
      privKey = PK11_FindKeyByAnyCert(connssl->client_cert, proto_win);
837
818
      if(privKey)
838
819
        secStatus = SECSuccess;
839
820
    }
840
821
  }
841
822
 
842
823
  if(secStatus == SECSuccess) {
843
 
    *pRetCert = cert;
 
824
    *pRetCert = connssl->client_cert;
844
825
    *pRetKey = privKey;
845
826
  }
846
827
  else {
847
 
    if(cert)
848
 
      CERT_DestroyCertificate(cert);
 
828
    if(connssl->client_cert)
 
829
      CERT_DestroyCertificate(connssl->client_cert);
 
830
    connssl->client_cert = NULL;
849
831
  }
850
832
 
851
833
  return secStatus;
877
859
   * as a safety feature.
878
860
   */
879
861
  PR_Lock(nss_initlock);
880
 
  if (initialized)
 
862
  if (initialized) {
 
863
    if(mod)
 
864
      SECMOD_DestroyModule(mod);
 
865
    mod = NULL;
881
866
    NSS_Shutdown();
 
867
  }
882
868
  PR_Unlock(nss_initlock);
883
869
 
884
870
  PR_DestroyLock(nss_initlock);
926
912
      free(connssl->client_nickname);
927
913
      connssl->client_nickname = NULL;
928
914
    }
 
915
    if(connssl->client_cert)
 
916
      CERT_DestroyCertificate(connssl->client_cert);
 
917
    if(connssl->key)
 
918
      (void)PK11_DestroyGenericObject(connssl->key);
 
919
    if(connssl->cacert[1])
 
920
      (void)PK11_DestroyGenericObject(connssl->cacert[1]);
 
921
    if(connssl->cacert[0])
 
922
      (void)PK11_DestroyGenericObject(connssl->cacert[0]);
929
923
    connssl->handle = NULL;
930
924
  }
931
925
}
954
948
#endif
955
949
  char *certDir = NULL;
956
950
  int curlerr;
 
951
  const int *cipher_to_enable;
957
952
 
958
953
  curlerr = CURLE_SSL_CONNECT_ERROR;
959
954
 
960
955
  if (connssl->state == ssl_connection_complete)
961
956
    return CURLE_OK;
962
957
 
 
958
  connssl->client_cert = NULL;
 
959
  connssl->cacert[0] = NULL;
 
960
  connssl->cacert[1] = NULL;
 
961
  connssl->key = NULL;
 
962
 
963
963
  /* FIXME. NSS doesn't support multiple databases open at the same time. */
964
964
  PR_Lock(nss_initlock);
965
965
  if(!initialized) {
1057
1057
  if(SSL_OptionSet(model, SSL_V2_COMPATIBLE_HELLO, ssl2) != SECSuccess)
1058
1058
    goto error;
1059
1059
 
 
1060
  /* enable all ciphers from enable_ciphers_by_default */
 
1061
  cipher_to_enable = enable_ciphers_by_default;
 
1062
  while (SSL_NULL_WITH_NULL_NULL != *cipher_to_enable) {
 
1063
    if (SSL_CipherPrefSet(model, *cipher_to_enable, PR_TRUE) != SECSuccess) {
 
1064
      curlerr = CURLE_SSL_CIPHER;
 
1065
      goto error;
 
1066
    }
 
1067
    cipher_to_enable++;
 
1068
  }
 
1069
 
1060
1070
  if(data->set.ssl.cipher_list) {
1061
1071
    if(set_ciphers(data, model, data->set.ssl.cipher_list) != SECSuccess) {
1062
1072
      curlerr = CURLE_SSL_CIPHER;
1077
1087
    /* skip the verifying of the peer */
1078
1088
    ;
1079
1089
  else if(data->set.ssl.CAfile) {
1080
 
    int rc = nss_load_cert(data->set.ssl.CAfile, PR_TRUE);
 
1090
    int rc = nss_load_cert(&conn->ssl[sockindex], data->set.ssl.CAfile,
 
1091
                           PR_TRUE);
1081
1092
    if(!rc) {
1082
1093
      curlerr = CURLE_SSL_CACERT_BADFILE;
1083
1094
      goto error;
1105
1116
 
1106
1117
          snprintf(fullpath, sizeof(fullpath), "%s/%s", data->set.ssl.CApath,
1107
1118
                   entry->name);
1108
 
          rc = nss_load_cert(fullpath, PR_TRUE);
 
1119
          rc = nss_load_cert(&conn->ssl[sockindex], fullpath, PR_TRUE);
1109
1120
          /* FIXME: check this return value! */
1110
1121
        }
1111
1122
        /* This is purposefully tolerant of errors so non-PEM files
1155
1166
        free(nickname);
1156
1167
      goto error;
1157
1168
    }
1158
 
    if(!cert_stuff(conn, data->set.str[STRING_CERT],
 
1169
    if(!cert_stuff(conn, sockindex, data->set.str[STRING_CERT],
1159
1170
                    data->set.str[STRING_KEY])) {
1160
1171
      /* failf() is already done in cert_stuff() */
1161
1172
      if(nickname_alloc)
1171
1182
 
1172
1183
    if(SSL_GetClientAuthDataHook(model,
1173
1184
                                 (SSLGetClientAuthData) SelectClientCert,
1174
 
                                 (void *)connssl->client_nickname) !=
1175
 
       SECSuccess) {
 
1185
                                 (void *)connssl) != SECSuccess) {
1176
1186
      curlerr = CURLE_SSL_CERTPROBLEM;
1177
1187
      goto error;
1178
1188
    }
1179
 
 
1180
 
    PK11_SetPasswordFunc(nss_no_password);
1181
1189
  }
1182
1190
  else
1183
1191
    connssl->client_nickname = NULL;