From 1dbefa75bed1bc068695ae0187c41ed1e33bd893 Mon Sep 17 00:00:00 2001 From: Howard Chu Date: Mon, 12 Apr 2010 02:44:28 +0000 Subject: [PATCH] ITS#6432 updated MozNSS context and PEM support --- libraries/libldap/tls_m.c | 208 +++++++++++++++++++++++++++++--------- 1 file changed, 162 insertions(+), 46 deletions(-) diff --git a/libraries/libldap/tls_m.c b/libraries/libldap/tls_m.c index 918c67cb6a..3f45f20169 100644 --- a/libraries/libldap/tls_m.c +++ b/libraries/libldap/tls_m.c @@ -64,6 +64,16 @@ #include #include +/* NSS 3.12.5 and later have NSS_InitContext */ +#if NSS_VMAJOR <= 3 && NSS_VMINOR <= 12 && NSS_VPATCH < 5 +/* do nothing */ +#else +#define HAVE_NSS_INITCONTEXT 1 +#endif + +/* InitContext does not currently work in server mode */ +/* #define INITCONTEXT_HACK 1 */ + typedef struct tlsm_ctx { PRFileDesc *tc_model; int tc_refcnt; @@ -77,6 +87,11 @@ typedef struct tlsm_ctx { PRCallOnceType tc_callonce; PRBool tc_using_pem; char *tc_slotname; /* if using pem */ +#ifdef HAVE_NSS_INITCONTEXT + NSSInitContext *tc_initctx; /* the NSS context */ +#endif + PK11GenericObject **tc_pem_objs; /* array of objects to free */ + int tc_n_pem_objs; /* number of objects */ #ifdef LDAP_R_COMPILE ldap_pvt_thread_mutex_t tc_refmutex; #endif @@ -88,10 +103,9 @@ static PRDescIdentity tlsm_layer_id; static const PRIOMethods tlsm_PR_methods; -static int tlsm_did_init; - static const char* pem_library = "nsspem"; -static SECMODModule* pemMod = NULL; +static const char *pem_mod_name = "PEM"; +static SECMODModule* pem_module; #define DEFAULT_TOKEN_NAME "default" /* sprintf format used to create token name */ @@ -925,12 +939,29 @@ tlsm_init_tokens( tlsm_ctx *ctx ) slotList = PK11_GetAllTokens( CKM_INVALID_MECHANISM, PR_FALSE, PR_TRUE, NULL ); for ( listEntry = PK11_GetFirstSafe( slotList ); !rc && listEntry; - listEntry = listEntry->next) { + listEntry = PK11_GetNextSafe( slotList, listEntry, PR_FALSE ) ) { PK11SlotInfo *slot = listEntry->slot; rc = tlsm_authenticate_to_slot( ctx, slot ); - PK11_FreeSlot(slot); } + PK11_FreeSlotList( slotList ); + + return rc; +} + +static SECStatus +tlsm_nss_shutdown_cb( void *appData, void *nssData ) +{ + SECStatus rc = SECSuccess; + + SSL_ShutdownServerSessionIDCache(); + SSL_ClearSessionCache(); + + if ( pem_module ) { + SECMOD_UnloadUserModule( pem_module ); + SECMOD_DestroyModule( pem_module ); + pem_module = NULL; + } return rc; } @@ -941,19 +972,24 @@ tlsm_init_pem_module( void ) char *fullname = NULL; char *configstring = NULL; + if ( pem_module ) { + return rc; + } + + /* not loaded - load it */ /* get the system dependent library name */ fullname = PR_GetLibraryName( NULL, pem_library ); /* Load our PKCS#11 module */ - configstring = PR_smprintf( "library=%s name=PEM parameters=\"\"", fullname ); - PR_smprintf_free( fullname ); + configstring = PR_smprintf( "library=%s name=%s parameters=\"\"", fullname, pem_mod_name ); + PL_strfree( fullname ); - pemMod = SECMOD_LoadUserModule( configstring, NULL, PR_FALSE ); + pem_module = SECMOD_LoadUserModule( configstring, NULL, PR_FALSE ); PR_smprintf_free( configstring ); - if ( !pemMod || !pemMod->loaded ) { - if ( pemMod ) { - SECMOD_DestroyModule( pemMod ); - pemMod = NULL; + if ( !pem_module || !pem_module->loaded ) { + if ( pem_module ) { + SECMOD_DestroyModule( pem_module ); + pem_module = NULL; } rc = -1; } @@ -961,6 +997,29 @@ tlsm_init_pem_module( void ) return rc; } +static void +tlsm_add_pem_obj( tlsm_ctx *ctx, PK11GenericObject *obj ) +{ + int idx = ctx->tc_n_pem_objs; + ctx->tc_n_pem_objs++; + ctx->tc_pem_objs = (PK11GenericObject **) + PORT_Realloc( ctx->tc_pem_objs, ctx->tc_n_pem_objs * sizeof( PK11GenericObject * ) ); + ctx->tc_pem_objs[idx] = obj; +} + +static void +tlsm_free_pem_objs( tlsm_ctx *ctx ) +{ + /* free in reverse order of allocation */ + while ( ctx->tc_n_pem_objs-- ) { + PK11_DestroyGenericObject( ctx->tc_pem_objs[ctx->tc_n_pem_objs] ); + ctx->tc_pem_objs[ctx->tc_n_pem_objs] = NULL; + } + PORT_Free(ctx->tc_pem_objs); + ctx->tc_pem_objs = NULL; + ctx->tc_n_pem_objs = 0; +} + static int tlsm_add_cert_from_file( tlsm_ctx *ctx, const char *filename, PRBool isca ) { @@ -1032,6 +1091,8 @@ tlsm_add_cert_from_file( tlsm_ctx *ctx, const char *filename, PRBool isca ) return -1; } + tlsm_add_pem_obj( ctx, rv ); + return 0; } @@ -1079,13 +1140,16 @@ tlsm_add_key_from_file( tlsm_ctx *ctx, const char *filename ) } else { /* 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( pemMod, 0, 0 ); + SECMOD_WaitForAnyTokenEvent( pem_module, 0, 0 ); PK11_IsPresent( slot ); retcode = 0; } PK11_FreeSlot( slot ); + if ( !retcode ) { + tlsm_add_pem_obj( ctx, rv ); + } return retcode; } @@ -1178,11 +1242,20 @@ tlsm_deferred_init( void *arg ) int ii; int nn; PRErrorCode errcode = 1; +#ifdef HAVE_NSS_INITCONTEXT + NSSInitParameters initParams; + NSSInitContext *initctx = NULL; +#endif + SECStatus rc; - /* NSS support for multi-init is coming */ -#ifndef NSS_MULTI_INIT +#ifdef HAVE_NSS_INITCONTEXT + memset( &initParams, 0, sizeof( initParams ) ); + initParams.length = sizeof( initParams ); +#endif /* HAVE_NSS_INITCONTEXT */ + +#ifndef HAVE_NSS_INITCONTEXT if ( !NSS_IsInitialized() ) { -#endif /* NSS_MULTI_INIT */ +#endif /* HAVE_NSS_INITCONTEXT */ /* MOZNSS_DIR will override everything else - you can always set MOZNSS_DIR to force the use of this @@ -1197,12 +1270,30 @@ tlsm_deferred_init( void *arg ) securitydirs[nn++] = PR_GetEnv( "MOZNSS_DIR" ); securitydirs[nn++] = lt->lt_cacertdir; securitydirs[nn++] = PR_GetEnv( "DEFAULT_MOZNSS_DIR" ); - for (ii = 0; ii < nn; ++ii) { + for ( ii = 0; ii < nn; ++ii ) { const char *securitydir = securitydirs[ii]; if ( NULL == securitydir ) { continue; } - if ( NSS_Initialize( securitydir, "", "", SECMOD_DB, NSS_INIT_READONLY ) ) { +#ifdef HAVE_NSS_INITCONTEXT +#ifdef INITCONTEXT_HACK + if ( !NSS_IsInitialized() && ctx->tc_is_server ) { + rc = NSS_Initialize( securitydir, "", "", SECMOD_DB, NSS_INIT_READONLY ); + } else { + initctx = NSS_InitContext( securitydir, "", "", SECMOD_DB, + &initParams, NSS_INIT_READONLY ); + rc = (initctx == NULL) ? SECFailure : SECSuccess; + } +#else + initctx = NSS_InitContext( securitydir, "", "", SECMOD_DB, + &initParams, NSS_INIT_READONLY ); + rc = (initctx == NULL) ? SECFailure : SECSuccess; +#endif +#else + rc = NSS_Initialize( securitydir, "", "", SECMOD_DB, NSS_INIT_READONLY ); +#endif + + if ( rc != SECSuccess ) { errcode = PORT_GetError(); Debug( LDAP_DEBUG_TRACE, "TLS: could not initialize moznss using security dir %s - error %d:%s.\n", @@ -1217,7 +1308,25 @@ tlsm_deferred_init( void *arg ) } if ( errcode ) { /* no moznss db found, or not using moznss db */ - if ( NSS_NoDB_Init( NULL ) ) { +#ifdef HAVE_NSS_INITCONTEXT + int flags = NSS_INIT_READONLY|NSS_INIT_NOCERTDB|NSS_INIT_NOMODDB; +#ifdef INITCONTEXT_HACK + if ( !NSS_IsInitialized() && ctx->tc_is_server ) { + rc = NSS_NoDB_Init( NULL ); + } else { + initctx = NSS_InitContext( "", "", "", SECMOD_DB, + &initParams, flags ); + rc = (initctx == NULL) ? SECFailure : SECSuccess; + } +#else + initctx = NSS_InitContext( "", "", "", SECMOD_DB, + &initParams, flags ); + rc = (initctx == NULL) ? SECFailure : SECSuccess; +#endif +#else + rc = NSS_NoDB_Init( NULL ); +#endif + if ( rc != SECSuccess ) { errcode = PORT_GetError(); Debug( LDAP_DEBUG_ANY, "TLS: could not initialize moznss - error %d:%s.\n", @@ -1225,6 +1334,10 @@ tlsm_deferred_init( void *arg ) return -1; } +#ifdef HAVE_NSS_INITCONTEXT + ctx->tc_initctx = initctx; +#endif + /* initialize the PEM module */ if ( tlsm_init_pem_module() ) { errcode = PORT_GetError(); @@ -1241,6 +1354,12 @@ tlsm_deferred_init( void *arg ) ctx->tc_using_pem = PR_TRUE; } +#ifdef HAVE_NSS_INITCONTEXT + if ( !ctx->tc_initctx ) { + ctx->tc_initctx = initctx; + } +#endif + NSS_SetDomesticPolicy(); PK11_SetPasswordFunc( tlsm_pin_prompt ); @@ -1249,10 +1368,14 @@ tlsm_deferred_init( void *arg ) return -1; } - tlsm_did_init = 1; /* we did the init - we should also clean up */ -#ifndef NSS_MULTI_INIT + /* register cleanup function */ + /* delete the old one, if any */ + NSS_UnregisterShutdown( tlsm_nss_shutdown_cb, NULL ); + NSS_RegisterShutdown( tlsm_nss_shutdown_cb, NULL ); + +#ifndef HAVE_NSS_INITCONTEXT } -#endif /* NSS_MULTI_INIT */ +#endif /* HAVE_NSS_INITCONTEXT */ return 0; } @@ -1420,22 +1543,19 @@ tlsm_get_client_auth_data( void *arg, PRFileDesc *fd, * the database */ static int -tlsm_clientauth_init( tlsm_ctx *ctx, const char *certname ) +tlsm_clientauth_init( tlsm_ctx *ctx ) { SECStatus status = SECFailure; int rc; - PL_strfree( ctx->tc_certname ); - rc = tlsm_find_and_verify_cert_key( ctx, ctx->tc_model, certname, 0, NULL, NULL ); + rc = tlsm_find_and_verify_cert_key( ctx, ctx->tc_model, ctx->tc_certname, 0, NULL, NULL ); if ( rc ) { Debug( LDAP_DEBUG_ANY, "TLS: error: unable to set up client certificate authentication for " - "certificate named %s\n", certname, 0, 0 ); + "certificate named %s\n", ctx->tc_certname, 0, 0 ); return -1; } - ctx->tc_certname = PL_strdup( certname ); - status = SSL_GetClientAuthDataHook( ctx->tc_model, tlsm_get_client_auth_data, (void *)ctx ); @@ -1449,21 +1569,6 @@ tlsm_clientauth_init( tlsm_ctx *ctx, const char *certname ) static void tlsm_destroy( void ) { - if (pemMod) { - SECMOD_DestroyModule(pemMod); - pemMod = NULL; - } - - /* Only if we did the actual initialization */ - if ( tlsm_did_init ) { - tlsm_did_init = 0; - - SSL_ShutdownServerSessionIDCache(); - SSL_ClearSessionCache(); - NSS_Shutdown(); - } - - PR_Cleanup(); } static tls_ctx * @@ -1487,6 +1592,11 @@ tlsm_ctx_new ( struct ldapoptions *lo ) 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 */ + ctx->tc_pem_objs = NULL; + ctx->tc_n_pem_objs = 0; } return (tls_ctx *)ctx; } @@ -1528,7 +1638,13 @@ tlsm_ctx_free ( tls_ctx *ctx ) c->tc_certname = NULL; PL_strfree( c->tc_pin_file ); c->tc_pin_file = NULL; - PL_strfree( c->tc_slotname ); + PL_strfree( c->tc_slotname ); + tlsm_free_pem_objs( c ); +#ifdef HAVE_NSS_INITCONTEXT + if (c->tc_initctx) + NSS_ShutdownContext( c->tc_initctx ); + c->tc_initctx = NULL; +#endif /* HAVE_NSS_INITCONTEXT */ #ifdef LDAP_R_COMPILE ldap_pvt_thread_mutex_destroy( &c->tc_refmutex ); #endif @@ -1566,7 +1682,7 @@ tlsm_deferred_ctx_init( void *arg ) return -1; } - ctx->tc_certdb = CERT_GetDefaultCertDB(); /* replace with multi-init db call */ + ctx->tc_certdb = CERT_GetDefaultCertDB(); /* If there is ever a per-context db, change this */ fd = PR_CreateIOLayerStub( tlsm_layer_id, &tlsm_PR_methods ); if ( fd ) { @@ -1731,7 +1847,7 @@ tlsm_deferred_ctx_init( void *arg ) ctx->tc_certname, 0, 0 ); return -1; } - if ( tlsm_clientauth_init( ctx, ctx->tc_certname ) ) { + 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 ); -- 2.39.5