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

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

mercurial