? curl-cc_auth_hook.patch
Index: lib/nss.c
===================================================================
RCS file: /cvsroot/curl/curl/lib/nss.c,v
retrieving revision 1.50
diff -u -r1.50 nss.c
--- lib/nss.c	8 Jun 2009 21:25:17 -0000	1.50
+++ lib/nss.c	10 Jul 2009 19:54:44 -0000
@@ -585,48 +585,6 @@
     return (char *)PORT_Strdup((char *)arg);
 }
 
-static SECStatus nss_Init_Tokens(struct connectdata * conn)
-{
-  PK11SlotList *slotList;
-  PK11SlotListElement *listEntry;
-  SECStatus ret, status = SECSuccess;
-
-  PK11_SetPasswordFunc(nss_get_password);
-
-  slotList =
-    PK11_GetAllTokens(CKM_INVALID_MECHANISM, PR_FALSE, PR_TRUE, NULL);
-
-  for(listEntry = PK11_GetFirstSafe(slotList);
-      listEntry; listEntry = listEntry->next) {
-    PK11SlotInfo *slot = listEntry->slot;
-
-    if(PK11_NeedLogin(slot) && PK11_NeedUserInit(slot)) {
-      if(slot == PK11_GetInternalKeySlot()) {
-        failf(conn->data, "The NSS database has not been initialized");
-      }
-      else {
-        failf(conn->data, "The token %s has not been initialized",
-              PK11_GetTokenName(slot));
-      }
-      PK11_FreeSlot(slot);
-      continue;
-    }
-
-    ret = PK11_Authenticate(slot, PR_TRUE,
-                            conn->data->set.str[STRING_KEY_PASSWD]);
-    if(SECSuccess != ret) {
-      if(PR_GetError() == SEC_ERROR_BAD_PASSWORD)
-        infof(conn->data, "The password for token '%s' is incorrect\n",
-              PK11_GetTokenName(slot));
-      status = SECFailure;
-      break;
-    }
-    PK11_FreeSlot(slot);
-  }
-
-  return status;
-}
-
 static SECStatus BadCertHandler(void *arg, PRFileDesc *sock)
 {
   SECStatus success = SECSuccess;
@@ -786,48 +744,28 @@
                                   struct CERTCertificateStr **pRetCert,
                                   struct SECKEYPrivateKeyStr **pRetKey)
 {
-  SECKEYPrivateKey *privKey = NULL;
-  CERTCertificate *cert;
-  struct ssl_connect_data *connssl = (struct ssl_connect_data *) arg;
-  char *nickname = connssl->client_nickname;
-  void *proto_win = NULL;
-  SECStatus secStatus = SECFailure;
-  PK11SlotInfo *slot;
-  (void)caNames;
+  const char *nickname = (const char *)arg;
 
-  proto_win = SSL_RevealPinArg(sock);
+  *pRetCert = NULL;
+  *pRetKey = NULL;
 
-  if(!nickname)
-    return secStatus;
+  if (nickname && 0 == strncmp(nickname, "PEM Token", 9)) {
+    /* use the cert/key provided by PEM reader */
 
-  cert = PK11_FindCertFromNickname(nickname, proto_win);
-  if(cert) {
-    if(!strncmp(nickname, "PEM Token", 9)) {
-      CK_SLOT_ID slotID = 1; /* hardcoded for now */
-      char slotname[SLOTSIZE];
-      snprintf(slotname, SLOTSIZE, "PEM Token #%ld", slotID);
-      slot = PK11_FindSlotByName(slotname);
-      privKey = PK11_FindPrivateKeyFromCert(slot, cert, NULL);
-      PK11_FreeSlot(slot);
-      if(privKey) {
-        secStatus = SECSuccess;
-      }
-    }
-    else {
-      privKey = PK11_FindKeyByAnyCert(cert, proto_win);
-      if(privKey)
-        secStatus = SECSuccess;
-    }
-  }
+    void *proto_win = SSL_RevealPinArg(sock);
+    *pRetCert = PK11_FindCertFromNickname(nickname, proto_win);
+    if (NULL == *pRetCert)
+      return SECFailure;
 
-  *pRetCert = cert;
-  *pRetKey = privKey;
-  
-  /* There's no need to destroy either cert or privKey as 
-   * NSS will do that for us even if returning SECFailure
-   */
+    PK11SlotInfo *slot = PK11_FindSlotByName("PEM Token #1");
+    *pRetKey = PK11_FindPrivateKeyFromCert(slot, *pRetCert, NULL);
+    PK11_FreeSlot(slot);
 
-  return secStatus;
+    return (NULL == *pRetKey) ? SECFailure : SECSuccess;
+  }
+
+  /* use the default NSS hook */
+  return NSS_GetClientAuthData(arg, sock, caNames, pRetCert, pRetKey);
 }
 
 /**
@@ -946,7 +884,7 @@
   char *certDir = NULL;
   int curlerr;
   const int *cipher_to_enable;
-
+  SSLGetClientAuthData clientAuthHook = NSS_GetClientAuthData;
   curlerr = CURLE_SSL_CONNECT_ERROR;
 
   if (connssl->state == ssl_connection_complete)
@@ -1012,6 +950,9 @@
             "PEM certificates will not work.\n", pem_library);
     }
 #endif
+
+    PK11_SetPasswordFunc(nss_get_password);
+
   }
   PR_Unlock(nss_initlock);
 
@@ -1159,11 +1100,7 @@
     else {
       nickname = data->set.str[STRING_CERT];
     }
-    if(nss_Init_Tokens(conn) != SECSuccess) {
-      if(nickname_alloc)
-        free(nickname);
-      goto error;
-    }
+
     if(!cert_stuff(conn, sockindex, data->set.str[STRING_CERT],
                     data->set.str[STRING_KEY])) {
       /* failf() is already done in cert_stuff() */
@@ -1178,16 +1115,19 @@
     if(!connssl->client_nickname)
       return CURLE_OUT_OF_MEMORY;
 
-    if(SSL_GetClientAuthDataHook(model,
-                                 (SSLGetClientAuthData) SelectClientCert,
-                                 (void *)connssl) != SECSuccess) {
-      curlerr = CURLE_SSL_CERTPROBLEM;
-      goto error;
-    }
   }
   else
     connssl->client_nickname = NULL;
 
+  if (mod)
+    /* special hook for PEM reader */
+    clientAuthHook = SelectClientCert;
+
+  if(SSL_GetClientAuthDataHook(model, clientAuthHook,
+                               connssl->client_nickname) != SECSuccess) {
+    curlerr = CURLE_SSL_CERTPROBLEM;
+    goto error;
+  }
 
   /* Import our model socket  onto the existing file descriptor */
   connssl->handle = PR_ImportTCPSocket(sockfd);
@@ -1196,6 +1136,11 @@
     goto error;
   PR_Close(model); /* We don't need this any more */
 
+  /* This is the password associated with the cert that we're using */
+  if (data->set.str[STRING_KEY_PASSWD]) {
+      SSL_SetPKCS11PinArg(connssl->handle, data->set.str[STRING_KEY_PASSWD]);
+  }
+
   /* Force handshake on next I/O */
   SSL_ResetHandshake(connssl->handle, /* asServer */ PR_FALSE);
 

