nss: prevent NSS from crashing on client auth hook failure

Although it is not explicitly stated in the documentation, NSS uses
*pRetCert and *pRetKey even if the client authentication hook returns
a failure.  Namely, if we destroy *pRetCert without clearing *pRetCert
afterwards, NSS destroys the certificate once again, which causes a
double free.

Reported by: Bob Relyea
This commit is contained in:
Kamil Dudka 2012-12-03 13:17:50 +01:00
parent 2ecdd48683
commit 68d2830ee9
2 changed files with 13 additions and 8 deletions

View File

@ -13,7 +13,7 @@ This release includes the following changes:
This release includes the following bugfixes:
o
o nss: prevent NSS from crashing on client auth hook failure
This release includes the following known bugs:
@ -28,4 +28,4 @@ advice from friends like these:
References to bug reports and discussions on issues:

View File

@ -757,6 +757,8 @@ static SECStatus SelectClientCert(void *arg, PRFileDesc *sock,
static const char pem_slotname[] = "PEM Token #1";
SECItem cert_der = { 0, NULL, 0 };
void *proto_win = SSL_RevealPinArg(sock);
struct CERTCertificateStr *cert;
struct SECKEYPrivateKeyStr *key;
PK11SlotInfo *slot = PK11_FindSlotByName(pem_slotname);
if(NULL == slot) {
@ -771,24 +773,27 @@ static SECStatus SelectClientCert(void *arg, PRFileDesc *sock,
return SECFailure;
}
*pRetCert = PK11_FindCertFromDERCertItem(slot, &cert_der, proto_win);
cert = PK11_FindCertFromDERCertItem(slot, &cert_der, proto_win);
SECITEM_FreeItem(&cert_der, PR_FALSE);
if(NULL == *pRetCert) {
if(NULL == cert) {
failf(data, "NSS: client certificate from file not found");
PK11_FreeSlot(slot);
return SECFailure;
}
*pRetKey = PK11_FindPrivateKeyFromCert(slot, *pRetCert, NULL);
key = PK11_FindPrivateKeyFromCert(slot, cert, NULL);
PK11_FreeSlot(slot);
if(NULL == *pRetKey) {
if(NULL == key) {
failf(data, "NSS: private key from file not found");
CERT_DestroyCertificate(*pRetCert);
CERT_DestroyCertificate(cert);
return SECFailure;
}
infof(data, "NSS: client certificate from file\n");
display_cert_info(data, *pRetCert);
display_cert_info(data, cert);
*pRetCert = cert;
*pRetKey = key;
return SECSuccess;
}