From 7eae41a2eff8c4ab3f94afe01e608895e1ec33ec Mon Sep 17 00:00:00 2001
From: Jan Vcelak <jvcelak@redhat.com>
Date: Mon, 5 Mar 2012 17:04:51 +0100
Subject: [PATCH 2/5] MozNSS: store certificate object instead of nickname in
 in ctx

PEM certificates should not be referenced by nicknames, because the
nicknames are derived from basename of the cerificate file and in
general are not easy-predictable.

The code of Mozilla NSS backend depends on some aspects of PEM module
and tries to guess the nicknames correctly. In some cases the guessing
is wrong.

This patch changes this approach and the PEM certificates are no longer
referenced by nicknames. DER value of the certificate is extracted when
the PEM file is loaded into the database and this DER value is then
used to retrieve the certificate object. When certificate database is
used (not PEM), certificates are retrieved using nickname as before.

The retrieved certificate objects (and associated private keys) are now
stored directly in the tlsm_ctx structure and the nickname (certname)
disappears.

The changes are quite broad, but the code was simplified on many places.

This approach was recommended by Mozilla NSS developers and was recently
implemented for example in CURL.
---
 libraries/libldap/tls_m.c |  450 +++++++++++++++++----------------------------
 1 file changed, 165 insertions(+), 285 deletions(-)

diff --git a/libraries/libldap/tls_m.c b/libraries/libldap/tls_m.c
index 83e2474..767cea2 100644
--- a/libraries/libldap/tls_m.c
+++ b/libraries/libldap/tls_m.c
@@ -85,14 +85,14 @@ typedef struct tlsm_ctx {
 	PRBool tc_verify_cert;
 	CERTCertDBHandle *tc_certdb;
 	PK11SlotInfo *tc_certdb_slot;
-	char *tc_certname;
+	CERTCertificate *tc_certificate;
+	SECKEYPrivateKey *tc_private_key;
 	char *tc_pin_file;
 	struct ldaptls *tc_config;
 	int tc_is_server;
 	int tc_require_cert;
 	PRCallOnceType tc_callonce;
 	PRBool tc_using_pem;
-	char *tc_slotname; /* if using pem */
 #ifdef HAVE_NSS_INITCONTEXT
 	NSSInitContext *tc_initctx; /* the NSS context */
 #endif
@@ -125,13 +125,11 @@ static const PRIOMethods tlsm_PR_methods;
 static SECMODModule *pem_module;
 
 #define DEFAULT_TOKEN_NAME "default"
-/* sprintf format used to create token name */
-#define TLSM_PEM_TOKEN_FMT "PEM Token #%ld"
+#define TLSM_PEM_SLOT_CACERTS "PEM Token #0"
+#define TLSM_PEM_SLOT_CERTS "PEM Token #1"
 
-static int tlsm_slot_count;
-
-#define PK11_SETATTRS(x,id,v,l) (x)->type = (id); \
-                (x)->pValue=(v); (x)->ulValueLen = (l);
+#define PK11_SETATTRS(x,id,v,l) (x).type = (id); \
+                (x).pValue=(v); (x).ulValueLen = (l);
 
 /* forward declaration */
 static int tlsm_init( void );
@@ -947,6 +945,15 @@ tlsm_pin_prompt(PK11SlotInfo *slot, PRBool retry, void *arg)
 	return tlsm_get_pin( slot, retry, ctx );
 }
 
+static char *
+tlsm_ctx_subject_name(tlsm_ctx *ctx)
+{
+	if (!ctx || !ctx->tc_certificate)
+		return "(unknown)";
+
+	return ctx->tc_certificate->subjectName;
+}
+
 static SECStatus
 tlsm_get_basic_constraint_extension( CERTCertificate *cert,
 									 CERTBasicConstraints *cbcval )
@@ -1211,22 +1218,18 @@ tlsm_free_pem_objs( tlsm_ctx *ctx )
 }
 
 static int
-tlsm_add_cert_from_file( tlsm_ctx *ctx, const char *filename, PRBool isca, PRBool istrusted )
+tlsm_add_cert_from_file( tlsm_ctx *ctx, const char *filename, PRBool isca )
 {
-	CK_SLOT_ID slotID;
-	PK11SlotInfo *slot = NULL;
-	PK11GenericObject *rv;
-	CK_ATTRIBUTE *attrs;
-	CK_ATTRIBUTE theTemplate[20];
+	PK11SlotInfo *slot;
+	PK11GenericObject *cert;
+	CK_ATTRIBUTE attrs[4];
 	CK_BBOOL cktrue = CK_TRUE;
 	CK_BBOOL ckfalse = CK_FALSE;
 	CK_OBJECT_CLASS objClass = CKO_CERTIFICATE;
-	char tmpslotname[64];
-	char *slotname = NULL;
-	const char *ptr = NULL;
-	char sep = PR_GetDirectorySeparator();
+	char *slotname;
 	PRFileInfo fi;
 	PRStatus status;
+	SECItem certDER = { 0, NULL, 0 };
 
 	memset( &fi, 0, sizeof(fi) );
 	status = PR_GetFileInfo( filename, &fi );
@@ -1247,87 +1250,96 @@ tlsm_add_cert_from_file( tlsm_ctx *ctx, const char *filename, PRBool isca, PRBoo
 		return -1;
 	}
 
-	attrs = theTemplate;
+	slotname = isca ? TLSM_PEM_SLOT_CACERTS : TLSM_PEM_SLOT_CERTS;
+	slot = PK11_FindSlotByName( slotname );
 
-	if ( isca ) {
-		slotID = 0; /* CA and trust objects use slot 0 */
-		PR_snprintf( tmpslotname, sizeof(tmpslotname), TLSM_PEM_TOKEN_FMT, slotID );
-		slotname = tmpslotname;
-		istrusted = PR_TRUE;
-	} else {
-		if ( ctx->tc_slotname == NULL ) { /* need new slot */
-			if ( istrusted ) {
-				slotID = 0;
-			} else {
-				slotID = ++tlsm_slot_count;
-			}
-			ctx->tc_slotname = PR_smprintf( TLSM_PEM_TOKEN_FMT, slotID );
-		}
-		slotname = ctx->tc_slotname;
-
-		if ( ( ptr = PL_strrchr( filename, sep ) ) ) {
-			PL_strfree( ctx->tc_certname );
-			++ptr;
-			if ( istrusted ) {
-				/* pemnss conflates trusted certs with CA certs - since there can
-				   be more than one CA cert in a file (e.g. ca-bundle.crt) pemnss
-				   numbers each trusted cert - in the case of a server cert, there will be
-				   only one, so it will be number 0 */
-				ctx->tc_certname = PR_smprintf( "%s:%s - 0", slotname, ptr );
-			} else {
-				ctx->tc_certname = PR_smprintf( "%s:%s", slotname, ptr );
-			}
-		}
+	if ( !slot ) {
+		PRErrorCode errcode = PR_GetError();
+		Debug( LDAP_DEBUG_ANY,
+			   "TLS: could not find the slot for the certificate '%s' - error %d:%s.\n",
+			   filename, errcode, PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
+		return -1;
 	}
 
-	slot = PK11_FindSlotByName( slotname );
+	PK11_SETATTRS( attrs[0], CKA_CLASS, &objClass, sizeof(objClass) );
+	PK11_SETATTRS( attrs[1], CKA_TOKEN, &cktrue, sizeof(CK_BBOOL) );
+	PK11_SETATTRS( attrs[2], CKA_LABEL, (unsigned char *)filename, strlen(filename)+1 );
+	PK11_SETATTRS( attrs[3], CKA_TRUST, isca ? &cktrue : &ckfalse, sizeof(CK_BBOOL) );
 
-	if ( !slot ) {
+	cert = PK11_CreateGenericObject( slot, attrs, 4, PR_FALSE /* isPerm */ );
+
+	if ( !cert ) {
 		PRErrorCode errcode = PR_GetError();
 		Debug( LDAP_DEBUG_ANY,
-			   "TLS: could not find the slot for certificate %s - error %d:%s.\n",
-			   ctx->tc_certname, errcode,
-			   PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
+			   "TLS: could not add the certificate '%s' - error %d:%s.\n",
+			   filename, errcode, PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
+		PK11_FreeSlot( slot );
 		return -1;
 	}
 
-	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 ( istrusted ) {
-		PK11_SETATTRS( attrs, CKA_TRUST, &cktrue, sizeof(CK_BBOOL) ); attrs++;
-	} else {
-		PK11_SETATTRS( attrs, CKA_TRUST, &ckfalse, sizeof(CK_BBOOL) ); attrs++;
+	/* if not CA, we store the certificate in ctx->tc_certificate */
+	if ( !isca ) {
+		if ( PK11_ReadRawAttribute( PK11_TypeGeneric, cert, CKA_VALUE, &certDER ) != SECSuccess ) {
+			PRErrorCode errcode = PR_GetError();
+			Debug( LDAP_DEBUG_ANY,
+					"TLS: could not get DER of the '%s' certificate - error %d:%s.\n",
+					filename, errcode, PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
+			PK11_DestroyGenericObject( cert );
+			PK11_FreeSlot( slot );
+			return -1;
+		}
+
+		ctx->tc_certificate = PK11_FindCertFromDERCertItem( slot, &certDER, NULL );
+		SECITEM_FreeItem( &certDER, PR_FALSE );
+
+		if ( !ctx->tc_certificate ) {
+			PRErrorCode errcode = PR_GetError();
+			Debug( LDAP_DEBUG_ANY,
+					"TLS: could not get certificate '%s' using DER - error %d:%s.\n",
+					filename, errcode, PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
+			PK11_DestroyGenericObject( cert );
+			PK11_FreeSlot( slot );
+			return -1;
+		}
 	}
-	/* This loads the certificate in our PEM module into the appropriate
-	 * slot.
-	 */
-	rv = PK11_CreateGenericObject( slot, theTemplate, 4, PR_FALSE /* isPerm */ );
+
+	tlsm_add_pem_obj( ctx, cert );
 
 	PK11_FreeSlot( slot );
 
-	if ( !rv ) {
+	return 0;
+}
+
+static int
+tlsm_ctx_load_private_key(tlsm_ctx *ctx)
+{
+	if (!ctx->tc_certificate)
+		return -1;
+
+	if (ctx->tc_private_key)
+		return 0;
+
+	void *pin_arg = SSL_RevealPinArg(ctx->tc_model);
+
+	ctx->tc_private_key = PK11_FindKeyByAnyCert(ctx->tc_certificate, pin_arg);
+	if (!ctx->tc_private_key) {
 		PRErrorCode errcode = PR_GetError();
-		Debug( LDAP_DEBUG_ANY,
-			   "TLS: could not add the certificate %s - error %d:%s.\n",
-			   ctx->tc_certname, errcode,
-			   PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
+		Debug(LDAP_DEBUG_ANY,
+				"TLS: cannot find private key for certificate '%s' (error %d: %s)",
+				tlsm_ctx_subject_name(ctx), errcode,
+				PR_ErrorToString(errcode, PR_LANGUAGE_I_DEFAULT));
 		return -1;
 	}
 
-	tlsm_add_pem_obj( ctx, rv );
-
 	return 0;
 }
 
 static int
 tlsm_add_key_from_file( tlsm_ctx *ctx, const char *filename )
 {
-	CK_SLOT_ID slotID;
 	PK11SlotInfo * slot = NULL;
-	PK11GenericObject *rv;
-	CK_ATTRIBUTE *attrs;
-	CK_ATTRIBUTE theTemplate[20];
+	PK11GenericObject *key;
+	CK_ATTRIBUTE attrs[3];
 	CK_BBOOL cktrue = CK_TRUE;
 	CK_OBJECT_CLASS objClass = CKO_PRIVATE_KEY;
 	int retcode = 0;
@@ -1353,48 +1365,40 @@ tlsm_add_key_from_file( tlsm_ctx *ctx, const char *filename )
 		return -1;
 	}
 
-	attrs = theTemplate;
-
-	if ( ctx->tc_slotname == NULL ) { /* need new slot */
-		slotID = ++tlsm_slot_count;
-		ctx->tc_slotname = PR_smprintf( TLSM_PEM_TOKEN_FMT, slotID );
-	}
-	slot = PK11_FindSlotByName( ctx->tc_slotname );
+	slot = PK11_FindSlotByName( TLSM_PEM_SLOT_CERTS );
 
 	if ( !slot ) {
 		PRErrorCode errcode = PR_GetError();
 		Debug( LDAP_DEBUG_ANY,
-			   "TLS: could not find the slot %s for the private key - error %d:%s.\n",
-			   ctx->tc_slotname, errcode,
-			   PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
+			   "TLS: could not find the slot for the private key '%s' - error %d:%s.\n",
+			   filename, errcode, PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
 		return -1;
 	}
 
-	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++;
-	rv = PK11_CreateGenericObject( slot, theTemplate, 3, PR_FALSE /* isPerm */ );
+	PK11_SETATTRS( attrs[0], CKA_CLASS, &objClass, sizeof(objClass) );
+	PK11_SETATTRS( attrs[1], CKA_TOKEN, &cktrue, sizeof(CK_BBOOL) );
+	PK11_SETATTRS( attrs[2], CKA_LABEL, (unsigned char *)filename, strlen(filename)+1 );
+
+	key = PK11_CreateGenericObject( slot, attrs, 3, PR_FALSE /* isPerm */ );
 
-	if ( !rv ) {
+	if ( !key ) {
 		PRErrorCode errcode = PR_GetError();
 		Debug( LDAP_DEBUG_ANY,
-			   "TLS: could not add the certificate %s - error %d:%s.\n",
-			   ctx->tc_certname, errcode,
-			   PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
+			   "TLS: could not add the private key '%s' - error %d:%s.\n",
+			   filename, errcode, PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
 		retcode = -1;
 	} else {
+		tlsm_add_pem_obj( ctx, key );
+		retcode = 0;
+
 		/* When adding an encrypted key the PKCS#11 will be set as removed */
 		/* This will force the token to be seen as re-inserted */
 		SECMOD_WaitForAnyTokenEvent( pem_module, 0, 0 );
 		PK11_IsPresent( slot );
-		retcode = 0;
 	}
 
 	PK11_FreeSlot( slot );
 
-	if ( !retcode ) {
-		tlsm_add_pem_obj( ctx, rv );
-	}
 	return retcode;
 }
 
@@ -1411,7 +1415,7 @@ tlsm_init_ca_certs( tlsm_ctx *ctx, const char *cacertfile, const char *cacertdir
 	}
 
 	if ( cacertfile ) {
-		int rc = tlsm_add_cert_from_file( ctx, cacertfile, isca, PR_TRUE );
+		int rc = tlsm_add_cert_from_file( ctx, cacertfile, isca );
 		if ( rc ) {
 			errcode = PR_GetError();
 			Debug( LDAP_DEBUG_ANY,
@@ -1485,7 +1489,7 @@ tlsm_init_ca_certs( tlsm_ctx *ctx, const char *cacertfile, const char *cacertdir
 					continue;
 				}
 				fullpath = PR_smprintf( "%s/%s", cacertdir, entry->name );
-				if ( !tlsm_add_cert_from_file( ctx, fullpath, isca, PR_TRUE ) ) {
+				if ( !tlsm_add_cert_from_file( ctx, fullpath, isca ) ) {
 					Debug( LDAP_DEBUG_TRACE,
 						   "TLS: loaded CA certificate file %s from CA certificate directory %s.\n",
 						   fullpath, cacertdir, 0 );
@@ -1828,137 +1832,34 @@ tlsm_deferred_init( void *arg )
 	return 0;
 }
 
-static int
-tlsm_authenticate( tlsm_ctx *ctx, const char *certname, const char *pininfo )
-{
-	const char *colon = NULL;
-	char *token_name = NULL;
-	PK11SlotInfo *slot = NULL;
-	int rc = -1;
-
-	if ( !certname || !*certname ) {
-		return 0;
-	}
-
-	if ( ( colon = PL_strchr( certname, ':' ) ) ) {
-		token_name = PL_strndup( certname, colon-certname );
-	}
-
-	if ( token_name ) {
-		slot = PK11_FindSlotByName( token_name );
-	} else {
-		slot = PK11_GetInternalKeySlot();
-	}
-
-	if ( !slot ) {
-		PRErrorCode errcode = PR_GetError();
-		Debug( LDAP_DEBUG_ANY,
-			   "TLS: could not find the slot for security token %s - error %d:%s.\n",
-			   token_name ? token_name : DEFAULT_TOKEN_NAME, errcode,
-			   PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
-		goto done;
-	}
-
-	rc = tlsm_authenticate_to_slot( ctx, slot );
-
-done:
-	PL_strfree( token_name );
-	if ( slot ) {
-		PK11_FreeSlot( slot );
-	}
-
-	return rc;
-}
-
 /*
  * Find and verify the certificate.
- * Either fd is given, in which case the cert will be taken from it via SSL_PeerCertificate
- * or certname is given, and it will be searched for by name
+ * The key is loaded and stored in ctx->tc_private_key
  */
 static int
-tlsm_find_and_verify_cert_key(tlsm_ctx *ctx, PRFileDesc *fd, const char *certname, int isServer, CERTCertificate **pRetCert, SECKEYPrivateKey **pRetKey)
+tlsm_find_and_verify_cert_key(tlsm_ctx *ctx)
 {
-	CERTCertificate *cert = NULL;
-	int rc = -1;
-	void *pin_arg = NULL;
-	SECKEYPrivateKey *key = NULL;
-
-	pin_arg = SSL_RevealPinArg( fd );
-	if ( certname ) {
-		cert = PK11_FindCertFromNickname( certname, pin_arg );
-		if ( !cert ) {
-			PRErrorCode errcode = PR_GetError();
-			Debug( LDAP_DEBUG_ANY,
-				   "TLS: error: the certificate %s could not be found in the database - error %d:%s\n",
-				   certname, errcode, PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
-			return -1;
-		}
-	} else {
-		/* we are verifying the peer cert
-		   we also need to swap the isServer meaning */
-		cert = SSL_PeerCertificate( fd );
-		if ( !cert ) {
-			PRErrorCode errcode = PR_GetError();
-			Debug( LDAP_DEBUG_ANY,
-				   "TLS: error: could not get the certificate from the peer connection - error %d:%s\n",
-				   errcode, PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ), NULL );
-			return -1;
-		}
-		isServer = !isServer; /* verify the peer's cert instead */
-	}
-
-	if ( ctx->tc_slotname ) {
-		PK11SlotInfo *slot = PK11_FindSlotByName( ctx->tc_slotname );
-		key = PK11_FindPrivateKeyFromCert( slot, cert, NULL );
-		PK11_FreeSlot( slot );
-	} else {
-		key = PK11_FindKeyByAnyCert( cert, pin_arg );
-	}
+	SECCertificateUsage certUsage;
+	PRBool checkSig;
+	SECStatus status;
+	int errorToIgnore;
+	void *pin_arg;
 
-	if (key) {
-		SECCertificateUsage certUsage;
-		PRBool checkSig = PR_TRUE;
-		SECStatus status;
-		/* may not have a CA cert - ok - ignore SEC_ERROR_UNKNOWN_ISSUER */
-		int errorToIgnore = SEC_ERROR_UNKNOWN_ISSUER;
+	if (tlsm_ctx_load_private_key(ctx))
+		return -1;
 
-		if ( pRetKey ) {
-			*pRetKey = key; /* caller will deal with this */
-		} else {
-			SECKEY_DestroyPrivateKey( key );
-		}
-		if ( isServer ) {
-			certUsage = certificateUsageSSLServer;
-		} else {
-			certUsage = certificateUsageSSLClient;
-		}
-		if ( ctx->tc_verify_cert ) {
-			checkSig = PR_TRUE;
-		} else {
-			checkSig = PR_FALSE;
-		}
-		if ( ctx->tc_warn_only ) {
-			errorToIgnore = -1;
-		}
-		status = tlsm_verify_cert( ctx->tc_certdb, cert, pin_arg,
-								   checkSig, certUsage, errorToIgnore );
-		if ( status == SECSuccess ) {
-			rc = 0;
-		}
-	} else {
-		PRErrorCode errcode = PR_GetError();
-		Debug( LDAP_DEBUG_ANY,
-			   "TLS: error: could not find the private key for certificate %s - error %d:%s\n",
-			   certname, errcode, PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
-	}
+	pin_arg = SSL_RevealPinArg(ctx->tc_model);
+	certUsage = ctx->tc_is_server ? certificateUsageSSLServer : certificateUsageSSLClient;
+	checkSig = ctx->tc_verify_cert ? PR_TRUE : PR_FALSE;
+	if ( ctx->tc_warn_only )
+		errorToIgnore = -1;
+	else
+		errorToIgnore = SEC_ERROR_UNKNOWN_ISSUER; /* may not have a CA cert */
 
-	if ( pRetCert ) {
-		*pRetCert = cert; /* caller will deal with this */
-	} else {
-		CERT_DestroyCertificate( cert );
-	}
+	status = tlsm_verify_cert( ctx->tc_certdb, ctx->tc_certificate, pin_arg,
+							   checkSig, certUsage, errorToIgnore );
 
-    return rc;
+	return status == SECSuccess ? 0 : -1;
 }
 
 static int
@@ -1967,39 +1868,18 @@ tlsm_get_client_auth_data( void *arg, PRFileDesc *fd,
 						   SECKEYPrivateKey **pRetKey )
 {
 	tlsm_ctx *ctx = (tlsm_ctx *)arg;
-	int rc;
-	PRBool saveval;
 
-	/* don't need caNames - this function will call CERT_VerifyCertificateNow
-	   which will verify the cert against the known CAs */
-	saveval = ctx->tc_warn_only;
-	ctx->tc_warn_only = PR_TRUE;
-	rc = tlsm_find_and_verify_cert_key( ctx, fd, ctx->tc_certname, 0, pRetCert, pRetKey );
-	ctx->tc_warn_only = saveval;
-	if ( rc ) {
-		Debug( LDAP_DEBUG_ANY,
-			   "TLS: error: unable to perform client certificate authentication for "
-			   "certificate named %s\n", ctx->tc_certname, 0, 0 );
-		if ( pRetKey && *pRetKey ) {
-			SECKEY_DestroyPrivateKey( *pRetKey );
-			*pRetKey = NULL;
-		}
-		if ( pRetCert && *pRetCert ) {
-			CERT_DestroyCertificate( *pRetCert );
-			*pRetCert = NULL;
-		}
-		return SECFailure;
-	}
+	if (pRetCert)
+		*pRetCert = CERT_DupCertificate(ctx->tc_certificate);
+
+	if (pRetKey)
+		*pRetKey = SECKEY_CopyPrivateKey(ctx->tc_private_key);
 
 	return SECSuccess;
 }
 
 /*
  * ctx must have a tc_model that is valid
- * certname is in the form [<tokenname>:]<certnickname>
- * where <tokenname> is the name of the PKCS11 token
- * and <certnickname> is the nickname of the cert/key in
- * the database
 */
 static int
 tlsm_clientauth_init( tlsm_ctx *ctx )
@@ -2010,12 +1890,12 @@ tlsm_clientauth_init( tlsm_ctx *ctx )
 
 	saveval = ctx->tc_warn_only;
 	ctx->tc_warn_only = PR_TRUE;
-	rc = tlsm_find_and_verify_cert_key( ctx, ctx->tc_model, ctx->tc_certname, 0, NULL, NULL );
+	rc = tlsm_find_and_verify_cert_key(ctx);
 	ctx->tc_warn_only = saveval;
 	if ( rc ) {
 		Debug( LDAP_DEBUG_ANY,
 			   "TLS: error: unable to set up client certificate authentication for "
-			   "certificate named %s\n", ctx->tc_certname, 0, 0 );
+			   "certificate named %s\n", tlsm_ctx_subject_name(ctx), 0, 0 );
 		return -1;
 	}
 
@@ -2116,14 +1996,14 @@ tlsm_ctx_new ( struct ldapoptions *lo )
 		ctx->tc_config = NULL; /* populated later by tlsm_ctx_init */
 		ctx->tc_certdb = NULL;
 		ctx->tc_certdb_slot = NULL;
-		ctx->tc_certname = NULL;
+		ctx->tc_certificate = NULL;
+		ctx->tc_private_key = NULL;
 		ctx->tc_pin_file = NULL;
 		ctx->tc_model = NULL;
 		memset(&ctx->tc_callonce, 0, sizeof(ctx->tc_callonce));
 		ctx->tc_require_cert = lo->ldo_tls_require_cert;
 		ctx->tc_verify_cert = PR_FALSE;
 		ctx->tc_using_pem = PR_FALSE;
-		ctx->tc_slotname = NULL;
 #ifdef HAVE_NSS_INITCONTEXT
 		ctx->tc_initctx = NULL;
 #endif /* HAVE_NSS_INITCONTEXT */
@@ -2158,6 +2038,10 @@ tlsm_ctx_free ( tls_ctx *ctx )
 		return;
 	if ( c->tc_model )
 		PR_Close( c->tc_model );
+	if (c->tc_certificate)
+		CERT_DestroyCertificate(c->tc_certificate);
+	if (c->tc_private_key)
+		SECKEY_DestroyPrivateKey(c->tc_private_key);
 	c->tc_certdb = NULL; /* if not the default, may have to clean up */
 	if ( c->tc_certdb_slot ) {
 		if ( SECMOD_CloseUserDB( c->tc_certdb_slot ) ) {
@@ -2167,11 +2051,8 @@ tlsm_ctx_free ( tls_ctx *ctx )
 				   errcode, PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ), 0 );
 		}
 	}
-	PL_strfree( c->tc_certname );
-	c->tc_certname = NULL;
 	PL_strfree( c->tc_pin_file );
 	c->tc_pin_file = NULL;
-	PL_strfree( c->tc_slotname );		
 	tlsm_free_pem_objs( c );
 #ifdef HAVE_NSS_INITCONTEXT
 	if ( c->tc_initctx ) {
@@ -2361,8 +2242,8 @@ tlsm_deferred_ctx_init( void *arg )
 		/* if using the PEM module, load the PEM file specified by lt_certfile */
 		/* otherwise, assume this is the name of a cert already in the db */
 		if ( ctx->tc_using_pem ) {
-			/* this sets ctx->tc_certname to the correct value */
-			int rc = tlsm_add_cert_from_file( ctx, lt->lt_certfile, PR_FALSE, PR_TRUE );
+			/* this sets ctx->tc_certificate to the correct value */
+			int rc = tlsm_add_cert_from_file( ctx, lt->lt_certfile, PR_FALSE );
 			if ( rc ) {
 				return rc;
 			}
@@ -2371,10 +2252,19 @@ tlsm_deferred_ctx_init( void *arg )
 
 			if (ctx->tc_certdb_slot) {
 				tmp_certname = PR_smprintf(TLSM_CERTDB_DESC_FMT ":%s", ctx->tc_unique, lt->lt_certfile);
-				ctx->tc_certname = PL_strdup( tmp_certname );
-				PR_smprintf_free(tmp_certname);
 			} else {
-				ctx->tc_certname = PL_strdup( lt->lt_certfile );
+				tmp_certname = PR_smprintf("%s", lt->lt_certfile);
+			}
+
+			ctx->tc_certificate = PK11_FindCertFromNickname(tmp_certname, SSL_RevealPinArg(ctx->tc_model));
+			PR_smprintf_free(tmp_certname);
+
+			if (!ctx->tc_certificate) {
+				PRErrorCode errcode = PR_GetError();
+				Debug( LDAP_DEBUG_ANY,
+					   "TLS: error: the certificate '%s' could not be found in the database - error %d:%s.\n",
+					   lt->lt_certfile, errcode, PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
+				return -1;
 			}
 		}
 	}
@@ -2383,7 +2273,6 @@ tlsm_deferred_ctx_init( void *arg )
 		/* if using the PEM module, load the PEM file specified by lt_keyfile */
 		/* otherwise, assume this is the pininfo for the key */
 		if ( ctx->tc_using_pem ) {
-			/* this sets ctx->tc_certname to the correct value */
 			int rc = tlsm_add_key_from_file( ctx, lt->lt_keyfile );
 			if ( rc ) {
 				return rc;
@@ -2415,28 +2304,26 @@ tlsm_deferred_ctx_init( void *arg )
 		/* 
 		   since a cert has been specified, assume the client wants to do cert auth
 		*/
-		if ( ctx->tc_certname ) {
-			if ( tlsm_authenticate( ctx, ctx->tc_certname, ctx->tc_pin_file ) ) {
+		if ( ctx->tc_certificate ) {
+			if ( tlsm_authenticate_to_slot( ctx, ctx->tc_certificate->slot ) ) {
 				Debug( LDAP_DEBUG_ANY, 
-				       "TLS: error: unable to authenticate to the security device for certificate %s\n",
-				       ctx->tc_certname, 0, 0 );
+				       "TLS: error: unable to authenticate to the security device for certificate '%s'\n",
+				       tlsm_ctx_subject_name(ctx), 0, 0 );
 				return -1;
 			}
 			if ( tlsm_clientauth_init( ctx ) ) {
 				Debug( LDAP_DEBUG_ANY, 
-				       "TLS: error: unable to set up client certificate authentication using %s\n",
-				       ctx->tc_certname, 0, 0 );
+				       "TLS: error: unable to set up client certificate authentication using '%s'\n",
+				       tlsm_ctx_subject_name(ctx), 0, 0 );
 				return -1;
 			}
 		}
 	} else { /* set up secure server */
 		SSLKEAType certKEA;
-		CERTCertificate *serverCert = NULL;
-		SECKEYPrivateKey *serverKey = NULL;
 		SECStatus status;
 
 		/* must have a certificate for the server to use */
-		if ( !ctx->tc_certname ) {
+		if ( !ctx->tc_certificate ) {
 			Debug( LDAP_DEBUG_ANY, 
 			       "TLS: error: no server certificate: must specify a certificate for the server to use\n",
 			       0, 0, 0 );
@@ -2445,36 +2332,29 @@ tlsm_deferred_ctx_init( void *arg )
 
 		/* authenticate to the server's token - this will do nothing
 		   if the key/cert db is not password protected */
-		if ( tlsm_authenticate( ctx, ctx->tc_certname, ctx->tc_pin_file ) ) {
+		if ( tlsm_authenticate_to_slot( ctx, ctx->tc_certificate->slot ) ) {
 			Debug( LDAP_DEBUG_ANY, 
-			       "TLS: error: unable to authenticate to the security device for certificate %s\n",
-			       ctx->tc_certname, 0, 0 );
+				   "TLS: error: unable to authenticate to the security device for certificate '%s'\n",
+				   tlsm_ctx_subject_name(ctx), 0, 0 );
 			return -1;
 		}
 
-		/* get the server's key and cert */
-		if ( tlsm_find_and_verify_cert_key( ctx, ctx->tc_model, ctx->tc_certname, ctx->tc_is_server,
-						    &serverCert, &serverKey ) ) {
+		if (tlsm_find_and_verify_cert_key(ctx)) {
 			Debug( LDAP_DEBUG_ANY, 
 			       "TLS: error: unable to find and verify server's cert and key for certificate %s\n",
-			       ctx->tc_certname, 0, 0 );
-			CERT_DestroyCertificate( serverCert );
-			SECKEY_DestroyPrivateKey( serverKey );
+			       tlsm_ctx_subject_name(ctx), 0, 0 );
 			return -1;
 		}
 
-		certKEA = NSS_FindCertKEAType( serverCert );
 		/* configure the socket to be a secure server socket */
-		status = SSL_ConfigSecureServer( ctx->tc_model, serverCert, serverKey, certKEA );
-		/* SSL_ConfigSecureServer copies these */
-		CERT_DestroyCertificate( serverCert );
-		SECKEY_DestroyPrivateKey( serverKey );
+		certKEA = NSS_FindCertKEAType( ctx->tc_certificate );
+		status = SSL_ConfigSecureServer( ctx->tc_model, ctx->tc_certificate, ctx->tc_private_key, certKEA );
 
 		if ( SECSuccess != status ) {
 			PRErrorCode err = PR_GetError();
 			Debug( LDAP_DEBUG_ANY, 
-			       "TLS: error: unable to configure secure server using certificate %s - error %d:%s\n",
-			       ctx->tc_certname, err, PR_ErrorToString( err, PR_LANGUAGE_I_DEFAULT ) );
+			       "TLS: error: unable to configure secure server using certificate '%s' - error %d:%s\n",
+			       tlsm_ctx_subject_name(ctx), err, PR_ErrorToString( err, PR_LANGUAGE_I_DEFAULT ) );
 			return -1;
 		}
 	}
-- 
1.7.10.4

