security/nss/lib/softoken/lgglue.c

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     1 /* This Source Code Form is subject to the terms of the Mozilla Public
     2  * License, v. 2.0. If a copy of the MPL was not distributed with this
     3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     4 /* 
     5  *  The following code handles the storage of PKCS 11 modules used by the
     6  * NSS. This file is written to abstract away how the modules are
     7  * stored so we can deside that later.
     8  */
     9 #include "sftkdb.h"
    10 #include "sftkdbti.h"
    11 #include "sdb.h"
    12 #include "prsystem.h"
    13 #include "prprf.h"
    14 #include "prenv.h"
    15 #include "lgglue.h"
    16 #include "secerr.h"
    17 #include "softoken.h"
    19 static LGOpenFunc legacy_glue_open = NULL;
    20 static LGReadSecmodFunc legacy_glue_readSecmod = NULL;
    21 static LGReleaseSecmodFunc legacy_glue_releaseSecmod = NULL;
    22 static LGDeleteSecmodFunc legacy_glue_deleteSecmod = NULL;
    23 static LGAddSecmodFunc legacy_glue_addSecmod = NULL;
    24 static LGShutdownFunc legacy_glue_shutdown = NULL;
    26 /*
    27  * The following 3 functions duplicate the work done by bl_LoadLibrary.
    28  * We should make bl_LoadLibrary a global and replace the call to
    29  * sftkdb_LoadLibrary(const char *libname) with it.
    30  */
    31 #ifdef XP_UNIX
    32 #include <unistd.h>
    33 #define LG_MAX_LINKS 20
    34 static char *
    35 sftkdb_resolvePath(const char *orig)
    36 {
    37     int count = 0;
    38     int len =0;
    39     int ret = -1;
    40     char *resolved = NULL;
    41     char *source = NULL;
    43     len = 1025; /* MAX PATH +1*/
    44     if (strlen(orig)+1 > len) {
    45 	/* PATH TOO LONG */
    46 	return NULL;
    47     }
    48     resolved = PORT_Alloc(len);
    49     if (!resolved) {
    50 	return NULL;
    51     }
    52     source = PORT_Alloc(len);
    53     if (!source) {
    54 	goto loser;
    55     }
    56     PORT_Strcpy(source, orig);
    57     /* Walk down all the links */
    58     while ( count++ < LG_MAX_LINKS) {
    59 	char *tmp;
    60 	/* swap our previous sorce out with resolved */
    61 	/* read it */
    62 	ret = readlink(source, resolved, len-1);
    63 	if (ret  < 0) {
    64 	    break;
    65  	}
    66 	resolved[ret] = 0;
    67 	tmp = source; source = resolved; resolved = tmp;
    68     }
    69     if (count > 1) {
    70 	ret = 0;
    71     }
    72 loser:
    73     if (resolved) {
    74 	PORT_Free(resolved);
    75     }
    76     if (ret < 0) {
    77 	if (source) {
    78 	    PORT_Free(source);
    79 	    source = NULL;
    80 	}
    81     }
    82     return source;
    83 }
    85 #endif
    87 static PRLibrary *
    88 sftkdb_LoadFromPath(const char *path, const char *libname)
    89 {
    90     char *c;
    91     int pathLen, nameLen, fullPathLen;
    92     char *fullPathName = NULL;
    93     PRLibSpec libSpec;
    94     PRLibrary *lib = NULL;
    97     /* strip of our parent's library name */ 
    98     c = strrchr(path, PR_GetDirectorySeparator());
    99     if (!c) {
   100 	return NULL; /* invalid path */
   101     }
   102     pathLen = (c-path)+1;
   103     nameLen = strlen(libname);
   104     fullPathLen = pathLen + nameLen +1;
   105     fullPathName = (char *)PORT_Alloc(fullPathLen);
   106     if (fullPathName == NULL) {
   107 	return NULL; /* memory allocation error */
   108     }
   109     PORT_Memcpy(fullPathName, path, pathLen);
   110     PORT_Memcpy(fullPathName+pathLen, libname, nameLen);
   111     fullPathName[fullPathLen-1] = 0;
   113     libSpec.type = PR_LibSpec_Pathname;
   114     libSpec.value.pathname = fullPathName;
   115     lib = PR_LoadLibraryWithFlags(libSpec, PR_LD_NOW | PR_LD_LOCAL);
   116     PORT_Free(fullPathName);
   117     return lib;
   118 }
   121 static PRLibrary *
   122 sftkdb_LoadLibrary(const char *libname)
   123 {
   124     PRLibrary *lib = NULL;
   125     PRFuncPtr fn_addr;
   126     char *parentLibPath = NULL;
   128     fn_addr  = (PRFuncPtr) &sftkdb_LoadLibrary;
   129     parentLibPath = PR_GetLibraryFilePathname(SOFTOKEN_LIB_NAME, fn_addr);
   131     if (!parentLibPath) {
   132 	goto done;
   133     }
   135     lib = sftkdb_LoadFromPath(parentLibPath, libname);
   136 #ifdef XP_UNIX
   137     /* handle symbolic link case */
   138     if (!lib) {
   139 	char *trueParentLibPath = sftkdb_resolvePath(parentLibPath);
   140 	if (!trueParentLibPath) {
   141 	    goto done;
   142 	}
   143     	lib = sftkdb_LoadFromPath(trueParentLibPath, libname);
   144 	PORT_Free(trueParentLibPath);
   145     }
   146 #endif
   148 done:
   149     if (parentLibPath) {
   150 	PORT_Free(parentLibPath);
   151     }
   153     /* still couldn't load it, try the generic path */
   154     if (!lib) {
   155 	PRLibSpec libSpec;
   156 	libSpec.type = PR_LibSpec_Pathname;
   157 	libSpec.value.pathname = libname;
   158 	lib = PR_LoadLibraryWithFlags(libSpec, PR_LD_NOW | PR_LD_LOCAL);
   159     }
   161     return lib;
   162 }
   164 /*
   165  * stub files for legacy db's to be able to encrypt and decrypt
   166  * various keys and attributes.
   167  */
   168 static SECStatus
   169 sftkdb_encrypt_stub(PLArenaPool *arena, SDB *sdb, SECItem *plainText,
   170 		    SECItem **cipherText)
   171 {
   172     SFTKDBHandle *handle = sdb->app_private;
   173     SECStatus rv;
   175     if (handle == NULL) {
   176 	return SECFailure;
   177     }
   179     /* if we aren't the key handle, try the other handle */
   180     if (handle->type != SFTK_KEYDB_TYPE) {
   181 	handle = handle->peerDB;
   182     }
   184     /* not a key handle */
   185     if (handle == NULL || handle->passwordLock == NULL) {
   186 	return SECFailure;
   187     }
   189     PZ_Lock(handle->passwordLock);
   190     if (handle->passwordKey.data == NULL) {
   191 	PZ_Unlock(handle->passwordLock);
   192 	/* PORT_SetError */
   193 	return SECFailure;
   194     }
   196     rv = sftkdb_EncryptAttribute(arena, 
   197 	handle->newKey?handle->newKey:&handle->passwordKey, 
   198 	plainText, cipherText);
   199     PZ_Unlock(handle->passwordLock);
   201     return rv;
   202 }
   204 /*
   205  * stub files for legacy db's to be able to encrypt and decrypt
   206  * various keys and attributes.
   207  */
   208 static SECStatus
   209 sftkdb_decrypt_stub(SDB *sdb, SECItem *cipherText, SECItem **plainText) 
   210 {
   211     SFTKDBHandle *handle = sdb->app_private;
   212     SECStatus rv;
   213     SECItem *oldKey = NULL;
   215     if (handle == NULL) {
   216 	return SECFailure;
   217     }
   219     /* if we aren't th handle, try the other handle */
   220     oldKey = handle->oldKey;
   221     if (handle->type != SFTK_KEYDB_TYPE) {
   222 	handle = handle->peerDB;
   223     }
   225     /* not a key handle */
   226     if (handle == NULL || handle->passwordLock == NULL) {
   227 	return SECFailure;
   228     }
   230     PZ_Lock(handle->passwordLock);
   231     if (handle->passwordKey.data == NULL) {
   232 	PZ_Unlock(handle->passwordLock);
   233 	/* PORT_SetError */
   234 	return SECFailure;
   235     }
   236     rv = sftkdb_DecryptAttribute( oldKey ? oldKey : &handle->passwordKey,
   237 		cipherText, plainText);
   238     PZ_Unlock(handle->passwordLock);
   240     return rv;
   241 }
   243 static const char *LEGACY_LIB_NAME = 
   244 	SHLIB_PREFIX"nssdbm"SHLIB_VERSION"."SHLIB_SUFFIX;
   245 /*
   246  * 2 bools to tell us if we've check the legacy library successfully or
   247  * not. Initialize on startup to false by the C BSS segment;
   248  */
   249 static PRBool legacy_glue_libCheckFailed;    /* set if we failed the check */
   250 static PRBool legacy_glue_libCheckSucceeded; /* set if we passed the check */
   251 static PRLibrary *legacy_glue_lib = NULL;
   252 static SECStatus 
   253 sftkdbLoad_Legacy(PRBool isFIPS)
   254 {
   255     PRLibrary *lib = NULL;
   256     LGSetCryptFunc setCryptFunction = NULL;
   258     if (legacy_glue_lib) {
   259 	/* this check is necessary because it's possible we loaded the
   260 	 * legacydb to read secmod.db, which told us whether we were in
   261 	 * FIPS mode or not. */
   262 	if (isFIPS && !legacy_glue_libCheckSucceeded) {
   263 	    if (legacy_glue_libCheckFailed || 
   264 		!BLAPI_SHVerify(LEGACY_LIB_NAME,(PRFuncPtr)legacy_glue_open)) {
   265     	    	legacy_glue_libCheckFailed = PR_TRUE;
   266 		/* don't clobber legacy glue to avoid race. just let it
   267 		 * get cleared in shutdown */
   268 		return SECFailure;
   269 	    }
   270     	    legacy_glue_libCheckSucceeded = PR_TRUE;
   271 	} 
   272 	return SECSuccess;
   273     }
   275     lib = sftkdb_LoadLibrary(LEGACY_LIB_NAME);
   276     if (lib == NULL) {
   277 	return SECFailure;
   278     }
   280     legacy_glue_open = (LGOpenFunc)PR_FindFunctionSymbol(lib, "legacy_Open");
   281     legacy_glue_readSecmod = (LGReadSecmodFunc) PR_FindFunctionSymbol(lib,
   282 						 "legacy_ReadSecmodDB");
   283     legacy_glue_releaseSecmod = (LGReleaseSecmodFunc) PR_FindFunctionSymbol(lib,
   284 					 	 "legacy_ReleaseSecmodDBData");
   285     legacy_glue_deleteSecmod = (LGDeleteSecmodFunc) PR_FindFunctionSymbol(lib,
   286 						 "legacy_DeleteSecmodDB");
   287     legacy_glue_addSecmod = (LGAddSecmodFunc)PR_FindFunctionSymbol(lib, 
   288 						 "legacy_AddSecmodDB");
   289     legacy_glue_shutdown = (LGShutdownFunc) PR_FindFunctionSymbol(lib, 
   290 						"legacy_Shutdown");
   291     setCryptFunction = (LGSetCryptFunc) PR_FindFunctionSymbol(lib, 
   292 						"legacy_SetCryptFunctions");
   294     if (!legacy_glue_open || !legacy_glue_readSecmod || 
   295 	    !legacy_glue_releaseSecmod || !legacy_glue_deleteSecmod || 
   296 	    !legacy_glue_addSecmod || !setCryptFunction) {
   297 	PR_UnloadLibrary(lib);
   298 	return SECFailure;
   299     }
   301     /* verify the loaded library if we are in FIPS mode */
   302     if (isFIPS) {
   303 	if (!BLAPI_SHVerify(LEGACY_LIB_NAME,(PRFuncPtr)legacy_glue_open)) {
   304 	    PR_UnloadLibrary(lib);
   305 	    return SECFailure;
   306 	}
   307     	legacy_glue_libCheckSucceeded = PR_TRUE;
   308     } 
   310     setCryptFunction(sftkdb_encrypt_stub,sftkdb_decrypt_stub);
   311     legacy_glue_lib = lib;
   312     return SECSuccess;
   313 }
   315 CK_RV
   316 sftkdbCall_open(const char *dir, const char *certPrefix, const char *keyPrefix, 
   317 		int certVersion, int keyVersion, int flags, PRBool isFIPS,
   318 		SDB **certDB, SDB **keyDB)
   319 {
   320     SECStatus rv;
   322     rv = sftkdbLoad_Legacy(isFIPS);
   323     if (rv != SECSuccess) {
   324 	return CKR_GENERAL_ERROR;
   325     }
   326     if (!legacy_glue_open) {
   327 	PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
   328 	return SECFailure;
   329     }
   330     return (*legacy_glue_open)(dir, certPrefix, keyPrefix, 
   331 				certVersion, keyVersion,
   332 				flags, certDB, keyDB);
   333 }
   335 char **
   336 sftkdbCall_ReadSecmodDB(const char *appName, const char *filename, 
   337 			const char *dbname, char *params, PRBool rw)
   338 {
   339     SECStatus rv;
   341     rv = sftkdbLoad_Legacy(PR_FALSE);
   342     if (rv != SECSuccess) {
   343 	return NULL;
   344     }
   345     if (!legacy_glue_readSecmod) {
   346 	PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
   347 	return NULL;
   348     }
   349     return (*legacy_glue_readSecmod)(appName, filename, dbname, params, rw);
   350 }
   352 SECStatus
   353 sftkdbCall_ReleaseSecmodDBData(const char *appName, 
   354 			const char *filename, const char *dbname, 
   355 			char **moduleSpecList, PRBool rw)
   356 {
   357     SECStatus rv;
   359     rv = sftkdbLoad_Legacy(PR_FALSE);
   360     if (rv != SECSuccess) {
   361 	return rv;
   362     }
   363     if (!legacy_glue_releaseSecmod) {
   364 	PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
   365 	return SECFailure;
   366     }
   367     return (*legacy_glue_releaseSecmod)(appName, filename, dbname, 
   368 					  moduleSpecList, rw);
   369 }
   371 SECStatus
   372 sftkdbCall_DeleteSecmodDB(const char *appName, 
   373 		      const char *filename, const char *dbname, 
   374 		      char *args, PRBool rw)
   375 {
   376     SECStatus rv;
   378     rv = sftkdbLoad_Legacy(PR_FALSE);
   379     if (rv != SECSuccess) {
   380 	return rv;
   381     }
   382     if (!legacy_glue_deleteSecmod) {
   383 	PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
   384 	return SECFailure;
   385     }
   386     return (*legacy_glue_deleteSecmod)(appName, filename, dbname, args, rw);
   387 }
   389 SECStatus
   390 sftkdbCall_AddSecmodDB(const char *appName, 
   391 		   const char *filename, const char *dbname, 
   392 		   char *module, PRBool rw)
   393 {
   394     SECStatus rv;
   396     rv = sftkdbLoad_Legacy(PR_FALSE);
   397     if (rv != SECSuccess) {
   398 	return rv;
   399     }
   400     if (!legacy_glue_addSecmod) {
   401 	PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
   402 	return SECFailure;
   403     }
   404     return (*legacy_glue_addSecmod)(appName, filename, dbname, module, rw);
   405 }
   407 CK_RV
   408 sftkdbCall_Shutdown(void)
   409 {
   410     CK_RV crv = CKR_OK;
   411     char *disableUnload = NULL;
   412     if (!legacy_glue_lib) {
   413 	return CKR_OK;
   414     }
   415     if (legacy_glue_shutdown) {
   416 #ifdef NO_FORK_CHECK
   417 	PRBool parentForkedAfterC_Initialize = PR_FALSE;
   418 #endif
   419 	crv = (*legacy_glue_shutdown)(parentForkedAfterC_Initialize);
   420     }
   421     disableUnload = PR_GetEnv("NSS_DISABLE_UNLOAD");
   422     if (!disableUnload) {
   423         PR_UnloadLibrary(legacy_glue_lib);
   424     }
   425     legacy_glue_lib = NULL;
   426     legacy_glue_open = NULL;
   427     legacy_glue_readSecmod = NULL;
   428     legacy_glue_releaseSecmod = NULL;
   429     legacy_glue_deleteSecmod = NULL;
   430     legacy_glue_addSecmod = NULL;
   431     legacy_glue_libCheckFailed    = PR_FALSE;
   432     legacy_glue_libCheckSucceeded = PR_FALSE;
   433     return crv;
   434 }

mercurial