try to select client certificate automatically when not specified

This commit is contained in:
Kamil Dudka 2009-07-22 08:48:25 +00:00
parent e8184abdd5
commit f672f48c69
3 changed files with 366 additions and 7 deletions

304
curl-7.19.5-cc.patch Normal file
View File

@ -0,0 +1,304 @@
diff -ruNp curl-7.19.5.orig/lib/nss.c curl-7.19.5/lib/nss.c
--- curl-7.19.5.orig/lib/nss.c 2009-07-22 10:30:03.010106586 +0200
+++ curl-7.19.5/lib/nss.c 2009-07-22 10:30:54.069293169 +0200
@@ -585,48 +585,6 @@ static char * nss_get_password(PK11SlotI
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;
@@ -692,15 +650,37 @@ static SECStatus HandshakeCallback(PRFil
return SECSuccess;
}
+static void display_cert_info(struct SessionHandle *data, CERTCertificate *cert) {
+ char *subject, *issuer, *common_name;
+ PRExplodedTime printableTime;
+ char timeString[256];
+ PRTime notBefore, notAfter;
+
+ subject = CERT_NameToAscii(&cert->subject);
+ issuer = CERT_NameToAscii(&cert->issuer);
+ common_name = CERT_GetCommonName(&cert->subject);
+ infof(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(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(data, "\texpire date: %s\n", timeString);
+ infof(data, "\tcommon name: %s\n", common_name);
+ infof(data, "\tissuer: %s\n", issuer);
+
+ PR_Free(subject);
+ PR_Free(issuer);
+ PR_Free(common_name);
+}
+
static void display_conn_info(struct connectdata *conn, PRFileDesc *sock)
{
SSLChannelInfo channel;
SSLCipherSuiteInfo suite;
CERTCertificate *cert;
- char *subject, *issuer, *common_name;
- PRExplodedTime printableTime;
- char timeString[256];
- PRTime notBefore, notAfter;
if(SSL_GetChannelInfo(sock, &channel, sizeof channel) ==
SECSuccess && channel.length == sizeof channel &&
@@ -714,25 +694,7 @@ static void display_conn_info(struct con
infof(conn->data, "Server certificate:\n");
cert = SSL_PeerCertificate(sock);
- 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);
-
+ display_cert_info(conn->data, cert);
CERT_DestroyCertificate(cert);
return;
@@ -786,48 +748,71 @@ static SECStatus SelectClientCert(void *
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;
+ static const char pem_nickname[] = "PEM Token #1";
+ const char *pem_slotname = pem_nickname;
- proto_win = SSL_RevealPinArg(sock);
+ struct ssl_connect_data *connssl = (struct ssl_connect_data *)arg;
+ struct SessionHandle *data = connssl->data;
+ const char *nickname = connssl->client_nickname;
- if(!nickname)
- return secStatus;
+ if (mod && nickname &&
+ 0 == strncmp(nickname, pem_nickname, /* length of "PEM Token" */ 9)) {
- 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;
- }
+ /* use the cert/key provided by PEM reader */
+ PK11SlotInfo *slot;
+ void *proto_win = SSL_RevealPinArg(sock);
+ *pRetKey = NULL;
+
+ *pRetCert = PK11_FindCertFromNickname(nickname, proto_win);
+ if (NULL == *pRetCert) {
+ failf(data, "NSS: client certificate not found: %s", nickname);
+ return SECFailure;
}
- else {
- privKey = PK11_FindKeyByAnyCert(cert, proto_win);
- if(privKey)
- secStatus = SECSuccess;
+
+ slot = PK11_FindSlotByName(pem_slotname);
+ if (NULL == slot) {
+ failf(data, "NSS: PK11 slot not found: %s", pem_slotname);
+ return SECFailure;
+ }
+
+ *pRetKey = PK11_FindPrivateKeyFromCert(slot, *pRetCert, NULL);
+ PK11_FreeSlot(slot);
+ if (NULL == *pRetKey) {
+ failf(data, "NSS: private key not found for certificate: %s", nickname);
+ return SECFailure;
}
+
+ infof(data, "NSS: Client client certificate: %s\n", nickname);
+ display_cert_info(data, *pRetCert);
+ return SECSuccess;
}
- *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
- */
+ /* use the default NSS hook */
+ if (SECSuccess != NSS_GetClientAuthData((void *)nickname, sock, caNames,
+ pRetCert, pRetKey)
+ || NULL == *pRetCert) {
- return secStatus;
+ if (NULL == nickname)
+ failf(data, "NSS: client certificate not found (nickname not specified)");
+ else
+ failf(data, "NSS: client certificate not found: %s", nickname);
+
+ return SECFailure;
+ }
+
+ /* get certificate nickname if any */
+ nickname = (*pRetCert)->nickname;
+ if (NULL == nickname)
+ nickname = "[unknown]";
+
+ if (NULL == *pRetKey) {
+ failf(data, "NSS: private key not found for certificate: %s", nickname);
+ return SECFailure;
+ }
+
+ infof(data, "NSS: using client certificate: %s\n", nickname);
+ display_cert_info(data, *pRetCert);
+ return SECSuccess;
}
/**
@@ -955,6 +940,8 @@ CURLcode Curl_nss_connect(struct connect
if (connssl->state == ssl_connection_complete)
return CURLE_OK;
+ connssl->data = data;
+
#ifdef HAVE_PK11_CREATEGENERICOBJECT
connssl->cacert[0] = NULL;
connssl->cacert[1] = NULL;
@@ -1017,6 +1004,9 @@ CURLcode Curl_nss_connect(struct connect
}
}
#endif
+
+ PK11_SetPasswordFunc(nss_get_password);
+
}
PR_Unlock(nss_initlock);
@@ -1164,11 +1154,7 @@ CURLcode Curl_nss_connect(struct connect
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() */
@@ -1183,16 +1169,15 @@ CURLcode Curl_nss_connect(struct connect
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(SSL_GetClientAuthDataHook(model, SelectClientCert,
+ (void *)connssl) != SECSuccess) {
+ curlerr = CURLE_SSL_CERTPROBLEM;
+ goto error;
+ }
/* Import our model socket onto the existing file descriptor */
connssl->handle = PR_ImportTCPSocket(sockfd);
@@ -1201,6 +1186,11 @@ CURLcode Curl_nss_connect(struct connect
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);
diff -ruNp curl-7.19.5.orig/lib/urldata.h curl-7.19.5/lib/urldata.h
--- curl-7.19.5.orig/lib/urldata.h 2009-07-22 10:30:03.007106061 +0200
+++ curl-7.19.5/lib/urldata.h 2009-07-22 10:30:54.070293354 +0200
@@ -211,6 +211,7 @@ struct ssl_connect_data {
#ifdef USE_NSS
PRFileDesc *handle;
char *client_nickname;
+ struct SessionHandle *data;
#ifdef HAVE_PK11_CREATEGENERICOBJECT
PK11GenericObject *key;
PK11GenericObject *cacert[2];

View File

@ -1,7 +1,7 @@
diff -ruNp curl-7.19.5.orig/lib/nss.c curl-7.19.5/lib/nss.c
--- curl-7.19.5.orig/lib/nss.c 2009-07-10 14:41:55.890168660 +0200
+++ curl-7.19.5/lib/nss.c 2009-07-10 14:42:18.966293110 +0200
@@ -857,8 +857,15 @@ void Curl_nss_cleanup(void)
--- curl-7.19.5.orig/lib/nss.c 2009-07-22 10:28:01.254355601 +0200
+++ curl-7.19.5/lib/nss.c 2009-07-22 10:29:02.437231090 +0200
@@ -857,9 +857,15 @@ void Curl_nss_cleanup(void)
*/
PR_Lock(nss_initlock);
if (initialized) {
@ -11,10 +11,58 @@ diff -ruNp curl-7.19.5.orig/lib/nss.c curl-7.19.5/lib/nss.c
+ * the certificates. */
+ SSL_ClearSessionCache();
+
+ if(mod) {
+ SECMOD_UnloadUserModule(mod);
+ if(mod && SECSuccess == SECMOD_UnloadUserModule(mod)) {
SECMOD_DestroyModule(mod);
- mod = NULL;
+ mod = NULL;
+ }
mod = NULL;
NSS_Shutdown();
}
PR_Unlock(nss_initlock);
@@ -940,9 +946,6 @@ CURLcode Curl_nss_connect(struct connect
curl_socket_t sockfd = conn->sock[sockindex];
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
SECStatus rv;
-#ifdef HAVE_PK11_CREATEGENERICOBJECT
- char *configstring = NULL;
-#endif
char *certDir = NULL;
int curlerr;
const int *cipher_to_enable;
@@ -995,21 +998,23 @@ CURLcode Curl_nss_connect(struct connect
NSS_SetDomesticPolicy();
#ifdef HAVE_PK11_CREATEGENERICOBJECT
- configstring = aprintf("library=%s name=PEM", pem_library);
- if(!configstring) {
- PR_Unlock(nss_initlock);
- goto error;
- }
- mod = SECMOD_LoadUserModule(configstring, NULL, PR_FALSE);
- free(configstring);
+ if(!mod) {
+ char *configstring = aprintf("library=%s name=PEM", pem_library);
+ if(!configstring) {
+ PR_Unlock(nss_initlock);
+ goto error;
+ }
+ mod = SECMOD_LoadUserModule(configstring, NULL, PR_FALSE);
+ free(configstring);
- if(!mod || !mod->loaded) {
- if(mod) {
- SECMOD_DestroyModule(mod);
- mod = NULL;
+ 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);
}
- infof(data, "WARNING: failed to load NSS PEM library %s. Using OpenSSL "
- "PEM certificates will not work.\n", pem_library);
}
#endif
}

View File

@ -1,7 +1,7 @@
Summary: A utility for getting files from remote servers (FTP, HTTP, and others)
Name: curl
Version: 7.19.5
Release: 7%{?dist}
Release: 8%{?dist}
License: MIT
Group: Applications/Internet
Source: http://curl.haxx.se/download/%{name}-%{version}.tar.bz2
@ -12,6 +12,7 @@ Patch3: curl-7.17.1-badsocket.patch
Patch4: curl-7.19.4-debug.patch
Patch5: curl-7.19.5-cc_refcnt-1.patch
Patch6: curl-7.19.5-cc_refcnt-2.patch
Patch7: curl-7.19.5-cc.patch
Provides: webclient
URL: http://curl.haxx.se/
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
@ -58,6 +59,7 @@ use cURL's capabilities internally.
%patch4 -p1
%patch5 -p1
%patch6 -p1
%patch7 -p1
# Convert docs to UTF-8
for f in CHANGES README; do
@ -140,6 +142,11 @@ rm -rf $RPM_BUILD_ROOT
%{_datadir}/aclocal/libcurl.m4
%changelog
* Wed Jul 22 2009 Kamil Dudka <kdudka@redhat.com> 7.19.5-8
- do not pre-login to all PKCS11 slots, it causes problems with HW tokens
- try to select client certificate automatically when not specified, thanks
to Claes Jakobsson
* Fri Jul 10 2009 Kamil Dudka <kdudka@redhat.com> 7.19.5-7
- fix SIGSEGV when using NSS client certificates, thanks to Claes Jakobsson