curl/curl-7.16.4-nsspem.patch

741 lines
21 KiB
Diff

diff -up curl-7.16.4/configure.nsspem curl-7.16.4/configure
--- curl-7.16.4/configure.nsspem 2007-06-25 11:18:41.000000000 +0200
+++ curl-7.16.4/configure 2007-09-06 08:35:31.000000000 +0200
@@ -26760,7 +26760,7 @@ echo "$as_me: WARNING: Use --with-ssl, -
fi
-if test X"$USE_GNUTLS$OPENSSL_ENABLED" != "X"; then
+if test X"$USE_NSS$USE_GNUTLS$OPENSSL_ENABLED" != "X"; then
{ echo "$as_me:$LINENO: checking CA cert bundle install path" >&5
echo $ECHO_N "checking CA cert bundle install path... $ECHO_C" >&6; }
diff -up curl-7.16.4/configure.ac.nsspem curl-7.16.4/configure.ac
--- curl-7.16.4/configure.ac.nsspem 2007-06-12 23:39:21.000000000 +0200
+++ curl-7.16.4/configure.ac 2007-09-06 08:35:31.000000000 +0200
@@ -1468,7 +1468,7 @@ dnl ************************************
dnl Check for the CA bundle
dnl **********************************************************************
-if test X"$USE_GNUTLS$OPENSSL_ENABLED" != "X"; then
+if test X"$USE_NSS$USE_GNUTLS$OPENSSL_ENABLED" != "X"; then
AC_MSG_CHECKING([CA cert bundle install path])
diff -up curl-7.16.4/lib/nss.c.nsspem curl-7.16.4/lib/nss.c
--- curl-7.16.4/lib/nss.c.nsspem 2007-05-25 23:56:27.000000000 +0200
+++ curl-7.16.4/lib/nss.c 2007-09-06 09:26:39.000000000 +0200
@@ -55,6 +55,7 @@
#include <ssl.h>
#include <sslerr.h>
#include <secerr.h>
+#include <secmod.h>
#include <sslproto.h>
#include <prtypes.h>
#include <pk11pub.h>
@@ -69,10 +70,19 @@
#define min(a, b) ((a) < (b) ? (a) : (b))
#endif
+#define SSL_DIR "/etc/pki/nssdb"
+
+/* enough to fit the string "PEM Token #[0|1]" */
+#define SLOTSIZE 13
+
PRFileDesc *PR_ImportTCPSocket(PRInt32 osfd);
static int initialized = 0;
-static int noverify = 0;
+static int verify_done = 0;
+char * select_nickname = NULL;
+
+/* Global so our callbacks can update as appropriate */
+static int curlerr;
#define HANDSHAKE_TIMEOUT 30
@@ -87,15 +97,25 @@ typedef struct {
PRInt32 version; /* protocol version valid for this cipher */
} cipher_s;
-/* the table itself is defined in nss_engine_init.c */
#ifdef NSS_ENABLE_ECC
#define ciphernum 48
#else
#define ciphernum 23
#endif
+#define PK11_SETATTRS(x,id,v,l) \
+ do { \
+ (x)->type = (id); \
+ (x)->pValue=(v); \
+ (x)->ulValueLen = (l); \
+ } while (0)
+
+#define CERT_NewTempCertificate __CERT_NewTempCertificate
+
enum sslversion { SSL2 = 1, SSL3 = 2, TLS = 4 };
+pphrase_arg_t *parg = NULL;
+
cipher_s cipherlist[ciphernum] = {
/* SSL2 cipher suites */
{"rc4", SSL_EN_RC4_128_WITH_MD5, SSL2},
@@ -154,6 +174,9 @@ cipher_s cipherlist[ciphernum] = {
#endif
};
+const char* pem_library = "libnsspem.so";
+static SECMODModule* mod = NULL;
+
static SECStatus set_ciphers(struct SessionHandle *data, PRFileDesc * model,
char *cipher_list)
{
@@ -197,9 +220,7 @@ static SECStatus set_ciphers(struct Sess
}
if(found == PR_FALSE) {
- char buf[1024];
- snprintf(buf, 1024, "Unknown cipher in list: %s", cipher);
- failf(data, buf);
+ failf(data, "Unknown cipher in list: %s", cipher);
return SECFailure;
}
@@ -220,27 +241,240 @@ static SECStatus set_ciphers(struct Sess
return SECSuccess;
}
+/*
+ * Determine whether the nickname passed in is a filename that needs to
+ * be loaded as a PEM or a regular NSS nickname.
+ *
+ * returns 1 for a file
+ * returns 0 for not a file (NSS nickname)
+ */
+static int is_file(const char *filename) {
+ struct stat st;
+
+ if (filename == NULL)
+ return 0;
+
+ if (stat(filename, &st) == 0) {
+ if (S_ISREG(st.st_mode))
+ return 1;
+ }
+ return 0;
+}
+
+static int
+nss_load_cert(struct SessionHandle *data, const char *filename, PRBool cacert)
+{
+ CERTCertificate *cert;
+ void *proto_win = NULL;
+ CK_SLOT_ID slotID;
+ PK11SlotInfo * slot = NULL;
+ PK11GenericObject *rv;
+ CK_ATTRIBUTE *attrs;
+ CK_ATTRIBUTE theTemplate[20];
+ CK_BBOOL cktrue = CK_TRUE;
+ CK_BBOOL ckfalse = CK_FALSE;
+ CK_OBJECT_CLASS objClass = CKO_CERTIFICATE;
+ char *nickname = NULL;
+ char *slotname = NULL;
+ char *n;
+
+ /* If there is no slash in the filename it is assumed to be a regular
+ * NSS nickname.
+ */
+ if (is_file(filename)) {
+ n = strrchr(filename, '/');
+ if (n)
+ n++;
+ } else {
+ /* A nickname from the NSS internal database */
+ nickname = strdup(filename);
+ goto done;
+ }
+
+ attrs = theTemplate;
+
+ /* All CA and trust objects go into slot 0. Other slots are used
+ * for storing certificates. With each new user certificate we increment
+ * the slot count. We only support 1 user certificate right now.
+ */
+ if (cacert) {
+ slotID = 0;
+ } else {
+ slotID = 1;
+ }
+
+ slotname = (char *)malloc(SLOTSIZE);
+ nickname = (char *)malloc(PATH_MAX);
+ snprintf(slotname, SLOTSIZE, "PEM Token #%ld", slotID);
+ snprintf(nickname, PATH_MAX, "PEM Token #%ld:%s", slotID, n);
+
+ slot = PK11_FindSlotByName(slotname);
+
+ if (!slot) {
+ free(slotname);
+ free(nickname);
+ return 0;
+ }
+
+ PK11_SETATTRS(attrs, CKA_CLASS, &objClass, sizeof(objClass) ); attrs++;
+ PK11_SETATTRS(attrs, CKA_TOKEN, &cktrue, sizeof(CK_BBOOL) ); attrs++;
+ PK11_SETATTRS(attrs, CKA_LABEL, (unsigned char *)filename, strlen(filename)+1); attrs++;
+ if (cacert) {
+ PK11_SETATTRS(attrs, CKA_TRUST, &cktrue, sizeof(CK_BBOOL) ); attrs++;
+ } else {
+ PK11_SETATTRS(attrs, CKA_TRUST, &ckfalse, sizeof(CK_BBOOL) ); attrs++;
+ }
+
+ /* This load the certificate in our PEM module into the appropriate
+ * slot.
+ */
+ rv = PK11_CreateGenericObject(slot, theTemplate, 4, PR_FALSE /* isPerm */);
+
+ PK11_FreeSlot(slot);
+
+ free(slotname);
+ if (rv == NULL) {
+ free(nickname);
+ return 0;
+ }
+
+done:
+ /* Double-check that the certificate or nickname requested exists in
+ * either the token or the NSS certificate database.
+ */
+ if (!cacert) {
+ cert = PK11_FindCertFromNickname((char *)nickname, proto_win);
+
+ /* An invalid nickname was passed in */
+ if (cert == NULL) {
+ PR_SetError(SEC_ERROR_UNKNOWN_CERT, 0);
+ return 0;
+ }
+
+ CERT_DestroyCertificate(cert);
+ }
+ free(nickname);
+
+ return 1;
+}
+
+static int nss_load_key(char *key_file)
+{
+ PK11SlotInfo * slot = NULL;
+ PK11GenericObject *rv;
+ CK_ATTRIBUTE *attrs;
+ CK_ATTRIBUTE theTemplate[20];
+ CK_BBOOL cktrue = CK_TRUE;
+ CK_OBJECT_CLASS objClass = CKO_PRIVATE_KEY;
+ CK_SLOT_ID slotID;
+ char *slotname = NULL;
+
+ attrs = theTemplate;
+
+ /* FIXME: grok the various file types */
+
+ /* FIXME: shouldn't be hardcoded */
+ slotID = 1;
+
+ slotname = (char *)malloc(SLOTSIZE);
+ snprintf(slotname, SLOTSIZE, "PEM Token #%ld", slotID);
+
+ slot = PK11_FindSlotByName(slotname);
+ free(slotname);
+
+ if (!slot) {
+ return 0;
+ }
+
+ PK11_SETATTRS(attrs, CKA_CLASS, &objClass, sizeof(objClass) ); attrs++;
+ PK11_SETATTRS(attrs, CKA_TOKEN, &cktrue, sizeof(CK_BBOOL) ); attrs++;
+ PK11_SETATTRS(attrs, CKA_LABEL, (unsigned char *)key_file, strlen(key_file)+1); attrs++;
+
+ /* When adding an encrypted key the PKCS#11 will be set as removed */
+ rv = PK11_CreateGenericObject(slot, theTemplate, 3, PR_FALSE /* isPerm */);
+ if (rv == NULL) {
+ PR_SetError(SEC_ERROR_BAD_KEY, 0);
+ return 0;
+ }
+
+ /* This will force the token to be seen as re-inserted */
+ PK11_IsPresent(slot);
+
+ parg->retryCount = 0;
+ /* parg is initialized in nss_Init_Tokens() */
+ if (PK11_Authenticate(slot, PR_TRUE, parg) != SECSuccess) {
+ return 0;
+ }
+
+ return 1;
+}
+
+static int display_error(struct connectdata *conn, PRInt32 err, const char *filename) {
+ switch(err) {
+ case SEC_ERROR_BAD_PASSWORD:
+ failf(conn->data, "Unable to load client key: Incorrect password\n");
+ return 1;
+ case SEC_ERROR_UNKNOWN_CERT:
+ failf(conn->data, "Unable to load certificate %s\n", filename);
+ return 1;
+ }
+ return 0; /* The caller will print a generic error */
+}
+
+static int cert_stuff(struct connectdata *conn, char *cert_file, char *key_file)
+{
+ struct SessionHandle *data = conn->data;
+ int rv = 0;
+
+ if (cert_file)
+ rv = nss_load_cert(data, cert_file, PR_FALSE);
+ if (!rv) {
+ if (!display_error(conn, PR_GetError(), cert_file))
+ failf(data, "Unable to load client cert %d.", PR_GetError());
+ return 0;
+ }
+ if (key_file || (is_file(cert_file) )) {
+ if (key_file)
+ rv = nss_load_key(key_file);
+ else
+ rv = nss_load_key(cert_file);
+ if (!rv) {
+ if (!display_error(conn, PR_GetError(), key_file))
+ failf(data, "Unable to load client key %d.", PR_GetError());
+
+ return 0;
+ }
+ }
+ return 1;
+}
+
static char * nss_get_password(PK11SlotInfo * slot, PRBool retry, void *arg)
{
pphrase_arg_t *parg = (pphrase_arg_t *) arg;
- (void)slot; /* unused */
- (void)retry; /* unused */
+ parg->retryCount++;
+ if (parg->retryCount > 2)
+ return NULL;
if(parg->data->set.key_passwd)
return (char *)PORT_Strdup((char *)parg->data->set.key_passwd);
else
return NULL;
}
-static SECStatus nss_Init_Tokens(struct connectdata * conn)
+static char * nss_no_password(PK11SlotInfo *slot, PRBool retry, void *arg)
+{
+ return NULL;
+}
+
+static SECStatus nss_Init_Tokens(struct SessionHandle *data)
{
PK11SlotList *slotList;
PK11SlotListElement *listEntry;
SECStatus ret, status = SECSuccess;
- pphrase_arg_t *parg;
- parg = (pphrase_arg_t *) malloc(sizeof(*parg));
+ if (!parg)
+ parg = (pphrase_arg_t *) malloc(sizeof(*parg));
parg->retryCount = 0;
- parg->data = conn->data;
+ parg->data = data;
PK11_SetPasswordFunc(nss_get_password);
@@ -253,10 +487,10 @@ static SECStatus nss_Init_Tokens(struct
if(PK11_NeedLogin(slot) && PK11_NeedUserInit(slot)) {
if(slot == PK11_GetInternalKeySlot()) {
- failf(conn->data, "The NSS database has not been initialized.\n");
+ failf(data, "The NSS database has not been initialized.\n");
}
else {
- failf(conn->data, "The token %s has not been initialized.",
+ failf(data, "The token %s has not been initialized.",
PK11_GetTokenName(slot));
}
PK11_FreeSlot(slot);
@@ -265,6 +499,8 @@ static SECStatus nss_Init_Tokens(struct
ret = PK11_Authenticate(slot, PR_TRUE, parg);
if(SECSuccess != ret) {
+ if (PR_GetError() == SEC_ERROR_BAD_PASSWORD)
+ infof(data, "The password for token '%s' is incorrect\n", PK11_GetTokenName(slot));
status = SECFailure;
break;
}
@@ -272,15 +508,59 @@ static SECStatus nss_Init_Tokens(struct
PK11_FreeSlot(slot);
}
- free(parg);
return status;
}
static SECStatus BadCertHandler(void *arg, PRFileDesc * socket)
{
SECStatus success = SECSuccess;
- (void)arg;
- (void)socket;
+ struct connectdata *conn = (struct connectdata *)arg;
+ PRErrorCode err = PR_GetError();
+ CERTCertificate *cert = NULL;
+ char *subject, *issuer;
+
+ if (verify_done)
+ return success;
+
+ verify_done = 1;
+ cert = SSL_PeerCertificate(socket);
+ subject = CERT_NameToAscii(&cert->subject);
+ issuer = CERT_NameToAscii(&cert->issuer);
+ CERT_DestroyCertificate(cert);
+
+ switch(err) {
+ case SEC_ERROR_CA_CERT_INVALID:
+ infof(conn->data, "Issuer certificate is invalid: '%s'\n", issuer);
+ if (conn->data->set.ssl.verifypeer)
+ success = SECFailure;
+ break;
+ case SEC_ERROR_UNTRUSTED_ISSUER:
+ if (conn->data->set.ssl.verifypeer)
+ success = SECFailure;
+ infof(conn->data, "Certificate is signed by an untrusted issuer: '%s'\n", issuer);
+ break;
+ case SSL_ERROR_BAD_CERT_DOMAIN:
+ if (conn->data->set.ssl.verifypeer)
+ success = SECFailure;
+ infof(conn->data, "common name: %s (does not match '%s')\n",
+ subject, conn->host.dispname);
+ break;
+ case SEC_ERROR_EXPIRED_CERTIFICATE:
+ if (conn->data->set.ssl.verifypeer)
+ success = SECFailure;
+ infof(conn->data, "Remote Certificate has expired.\n");
+ break;
+ default:
+ if (conn->data->set.ssl.verifypeer)
+ success = SECFailure;
+ infof(conn->data, "Bad certificate received. Subject = '%s', Issuer = '%s'\n", subject, issuer);
+ break;
+ }
+ if (success == SECSuccess)
+ infof(conn->data, "SSL certificate verify ok.\n");
+ PR_Free(subject);
+ PR_Free(issuer);
+ curlerr = CURLE_SSL_CACERT;
return success;
}
@@ -295,6 +575,52 @@ static SECStatus HandshakeCallback(PRFil
return SECSuccess;
}
+static void display_conn_info(struct connectdata *conn, PRFileDesc * socket)
+{
+ SSLChannelInfo channel;
+ SSLCipherSuiteInfo suite;
+ CERTCertificate *cert;
+ char *subject, *issuer, *common_name;
+ PRExplodedTime printableTime;
+ char timeString[256];
+ PRTime notBefore, notAfter;
+
+ if (SSL_GetChannelInfo(socket, &channel, sizeof channel) ==
+ SECSuccess && channel.length == sizeof channel &&
+ channel.cipherSuite) {
+ if (SSL_GetCipherSuiteInfo(channel.cipherSuite,
+ &suite, sizeof suite) == SECSuccess) {
+ infof(conn->data, "SSL connection using %s\n", suite.cipherSuiteName);
+ }
+ }
+
+ infof(conn->data, "Server certificate:\n");
+
+ cert = SSL_PeerCertificate(socket);
+ subject = CERT_NameToAscii(&cert->subject);
+ issuer = CERT_NameToAscii(&cert->issuer);
+ common_name = CERT_GetCommonName(&cert->subject);
+ infof(conn->data, "\tsubject: %s\n", subject);
+
+ CERT_GetCertTimes(cert, &notBefore, &notAfter);
+ PR_ExplodeTime(notBefore, PR_GMTParameters, &printableTime);
+ PR_FormatTime(timeString, 256, "%b %d %H:%M:%S %Y GMT", &printableTime);
+ infof(conn->data, "\tstart date: %s\n", timeString);
+ PR_ExplodeTime(notAfter, PR_GMTParameters, &printableTime);
+ PR_FormatTime(timeString, 256, "%b %d %H:%M:%S %Y GMT", &printableTime);
+ infof(conn->data, "\texpire date: %s\n", timeString);
+ infof(conn->data, "\tcommon name: %s\n", common_name);
+ infof(conn->data, "\tissuer: %s\n", issuer);
+
+ PR_Free(subject);
+ PR_Free(issuer);
+ PR_Free(common_name);
+
+ CERT_DestroyCertificate(cert);
+
+ return;
+}
+
/**
*
* Callback to pick the SSL client certificate.
@@ -309,24 +635,42 @@ static SECStatus SelectClientCert(void *
char *nickname = (char *)arg;
void *proto_win = NULL;
SECStatus secStatus = SECFailure;
+ PK11SlotInfo *slot;
(void)caNames;
proto_win = SSL_RevealPinArg(socket);
+ if (!nickname)
+ return secStatus;
+
cert = PK11_FindCertFromNickname(nickname, proto_win);
if(cert) {
- privKey = PK11_FindKeyByAnyCert(cert, proto_win);
- if(privKey) {
- secStatus = SECSuccess;
- }
- else {
- CERT_DestroyCertificate(cert);
+
+ if (!strncmp(nickname, "PEM Token", 9)) {
+ CK_SLOT_ID slotID = 1; /* hardcoded for now */
+ char * slotname = (char *)malloc(SLOTSIZE);
+ snprintf(slotname, SLOTSIZE, "PEM Token #%ld", slotID);
+ slot = PK11_FindSlotByName(slotname);
+ privKey = PK11_FindPrivateKeyFromCert(slot, cert, NULL);
+ PK11_FreeSlot(slot);
+ free(slotname);
+ if(privKey) {
+ secStatus = SECSuccess;
+ }
+ } else {
+ privKey = PK11_FindKeyByAnyCert(cert, proto_win);
+ if(privKey) {
+ secStatus = SECSuccess;
+ }
}
}
if(secStatus == SECSuccess) {
*pRetCert = cert;
*pRetKey = privKey;
+ } else {
+ if (cert)
+ CERT_DestroyCertificate(cert);
}
return secStatus;
@@ -397,6 +741,8 @@ void Curl_nss_close(struct connectdata *
}
connssl->use = FALSE; /* get back to ordinary socket usage */
}
+ if (select_nickname)
+ free(select_nickname);
}
/*
@@ -418,31 +764,52 @@ CURLcode Curl_nss_connect(struct connect
curl_socket_t sockfd = conn->sock[sockindex];
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
SECStatus rv;
- int curlerr = CURLE_SSL_CONNECT_ERROR;
+ char *configstring = NULL;
+ char *certDir = NULL;
+
+ curlerr = CURLE_SSL_CONNECT_ERROR;
+ certDir = getenv("SSL_DIR"); /* Look in $SSL_DIR */
+
+ if (!certDir) {
+ struct stat st;
+
+ if (stat(SSL_DIR, &st) == 0)
+ if (S_ISDIR(st.st_mode)) {
+ certDir = "/etc/pki/nssdb";
+ }
+ }
/* FIXME. NSS doesn't support multiple databases open at the same time. */
if(!initialized) {
- if(!data->set.ssl.CAfile) {
- if(data->set.ssl.verifypeer) {
- failf(data, "No NSS cacert database specified.");
- return CURLE_SSL_CACERT_BADFILE;
- }
- else {
- rv = NSS_NoDB_Init(NULL);
- noverify = 1;
- }
+ if(!certDir) {
+ rv = NSS_NoDB_Init(NULL);
}
else {
- rv = NSS_Initialize(data->set.ssl.CAfile, NULL, NULL, "secmod.db",
+ rv = NSS_Initialize(certDir, NULL, NULL, "secmod.db",
NSS_INIT_READONLY);
}
if(rv != SECSuccess) {
curlerr = CURLE_SSL_CACERT_BADFILE;
goto error;
}
- }
+ configstring = (char *)malloc(4096);
+
+ NSS_SetDomesticPolicy();
- NSS_SetDomesticPolicy();
+ PR_snprintf(configstring, 4096, "library=%s name=PEM", pem_library);
+// PR_snprintf(configstring, 4096, "library=%s name=PEM parameters=\"NSS=\"trustorder=75\"\"", pem_library);
+// PR_snprintf(configstring, 4096, "library=/usr/lib/libnsspem.so name=PEM parameters=\"/etc/pki/tls/certs/ca-bundle.crt\" NSS=\"trustorder=75\"");
+
+ mod = SECMOD_LoadUserModule(configstring, NULL, PR_FALSE);
+ if (!mod || !mod->loaded) {
+ if (mod) {
+ SECMOD_DestroyModule(mod);
+ mod = NULL;
+ }
+ infof(data, "WARNING: failed to load NSS PEM library %s. Using OpenSSL PEM certificates will not work.\n", pem_library);
+ }
+ free(configstring);
+ }
model = PR_NewTCPSocket();
if(!model)
@@ -482,26 +849,92 @@ CURLcode Curl_nss_connect(struct connect
goto error;
if(data->set.ssl.cipher_list) {
- if(set_ciphers(data, model, data->set.ssl.cipher_list) != SECSuccess)
+ if(set_ciphers(data, model, data->set.ssl.cipher_list) != SECSuccess) {
+ curlerr = CURLE_SSL_CIPHER;
goto error;
+ }
}
- if(SSL_BadCertHook(model, (SSLBadCertHandler) BadCertHandler, NULL)
- != SECSuccess)
+ if(SSL_BadCertHook(model, (SSLBadCertHandler) BadCertHandler, conn)
+ != SECSuccess) {
goto error;
+ }
if(SSL_HandshakeCallback(model, (SSLHandshakeCallback) HandshakeCallback,
NULL) != SECSuccess)
goto error;
+ if (mod && data->set.ssl.CAfile) {
+ rv = nss_load_cert(data, data->set.ssl.CAfile, PR_TRUE);
+ } else if (data->set.ssl.CApath) {
+ struct stat st;
+ PRDir *dir;
+ PRDirEntry *entry;
+
+ if (stat(data->set.ssl.CApath, &st) == -1)
+ curlerr = CURLE_SSL_CACERT_BADFILE;
+ goto error;
+
+ if (S_ISDIR(st.st_mode)) {
+ dir = PR_OpenDir(data->set.ssl.CApath);
+ int rv;
+ do {
+ entry = PR_ReadDir(dir, PR_SKIP_BOTH | PR_SKIP_HIDDEN);
+
+ if (entry) {
+ char fullpath[PATH_MAX];
+
+ snprintf(fullpath, sizeof(fullpath), "%s/%s", data->set.ssl.CApath, entry->name);
+ rv = nss_load_cert(data, fullpath, PR_TRUE);
+ }
+ /* This is purposefully tolerant of errors so non-PEM files
+ * can be in the same directory */
+ } while (entry != NULL);
+ PR_CloseDir(dir);
+ }
+ }
+ infof(data,
+ " CAfile: %s\n"
+ " CApath: %s\n",
+ data->set.ssl.CAfile ? data->set.ssl.CAfile : "none",
+ data->set.ssl.CApath ? data->set.ssl.CApath : "none");
+
if(data->set.cert) {
+ char * n;
+ char * nickname;
+
+ nickname = (char *)malloc(PATH_MAX);
+ if (is_file(data->set.cert)) {
+ n = strrchr(data->set.cert, '/');
+ if (n) {
+ n++; /* skip last slash */
+ snprintf(nickname, PATH_MAX, "PEM Token #%ld:%s", 1, n);
+ }
+ } else {
+ strncpy(nickname, data->set.cert, PATH_MAX);
+ }
+ if(nss_Init_Tokens(conn->data) != SECSuccess) {
+ free(nickname);
+ goto error;
+ }
+ if (!cert_stuff(conn, data->set.cert, data->set.key)) {
+ /* failf() is already done in cert_stuff() */
+ free(nickname);
+ return CURLE_SSL_CERTPROBLEM;
+ }
+
+ select_nickname = strdup(nickname);
if(SSL_GetClientAuthDataHook(model,
(SSLGetClientAuthData) SelectClientCert,
- (void *)data->set.cert) != SECSuccess) {
+ (void *)select_nickname) != SECSuccess) {
curlerr = CURLE_SSL_CERTPROBLEM;
goto error;
}
- if(nss_Init_Tokens(conn) != SECSuccess)
- goto error;
+
+ free(nickname);
+ free(parg);
+
+ /* No longer return the password, lets us free parg */
+ PK11_SetPasswordFunc(nss_no_password);
}
/* Import our model socket onto the existing file descriptor */
@@ -509,6 +942,7 @@ CURLcode Curl_nss_connect(struct connect
connssl->handle = SSL_ImportFD(model, connssl->handle);
if(!connssl->handle)
goto error;
+ PR_Close(model); /* We don't need this any more */
/* Force handshake on next I/O */
SSL_ResetHandshake(connssl->handle, /* asServer */ PR_FALSE);
@@ -518,14 +952,17 @@ CURLcode Curl_nss_connect(struct connect
/* Force the handshake now */
if (SSL_ForceHandshakeWithTimeout(connssl->handle,
PR_SecondsToInterval(HANDSHAKE_TIMEOUT))
- != SECSuccess)
+ != SECSuccess) {
goto error;
+ }
+
+ display_conn_info(conn, connssl->handle);
return CURLE_OK;
error:
err = PR_GetError();
- failf(data, "NSS error %d", err);
+ infof(data, "NSS error %d\n", err);
if(model)
PR_Close(model);
return curlerr;