security/nss/lib/softoken/legacydb/keydb.c

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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 #include "lowkeyi.h"
michael@0 6 #include "secasn1.h"
michael@0 7 #include "secder.h"
michael@0 8 #include "secoid.h"
michael@0 9 #include "blapi.h"
michael@0 10 #include "secitem.h"
michael@0 11 #include "pcert.h"
michael@0 12 #include "mcom_db.h"
michael@0 13 #include "secerr.h"
michael@0 14
michael@0 15 #include "keydbi.h"
michael@0 16 #include "lgdb.h"
michael@0 17
michael@0 18 /*
michael@0 19 * Record keys for keydb
michael@0 20 */
michael@0 21 #define SALT_STRING "global-salt"
michael@0 22 #define VERSION_STRING "Version"
michael@0 23 #define KEYDB_PW_CHECK_STRING "password-check"
michael@0 24 #define KEYDB_PW_CHECK_LEN 14
michael@0 25 #define KEYDB_FAKE_PW_CHECK_STRING "fake-password-check"
michael@0 26 #define KEYDB_FAKE_PW_CHECK_LEN 19
michael@0 27
michael@0 28 /* Size of the global salt for key database */
michael@0 29 #define SALT_LENGTH 16
michael@0 30
michael@0 31 SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate)
michael@0 32
michael@0 33 const SEC_ASN1Template nsslowkey_EncryptedPrivateKeyInfoTemplate[] = {
michael@0 34 { SEC_ASN1_SEQUENCE,
michael@0 35 0, NULL, sizeof(NSSLOWKEYEncryptedPrivateKeyInfo) },
michael@0 36 { SEC_ASN1_INLINE | SEC_ASN1_XTRN,
michael@0 37 offsetof(NSSLOWKEYEncryptedPrivateKeyInfo,algorithm),
michael@0 38 SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
michael@0 39 { SEC_ASN1_OCTET_STRING,
michael@0 40 offsetof(NSSLOWKEYEncryptedPrivateKeyInfo,encryptedData) },
michael@0 41 { 0 }
michael@0 42 };
michael@0 43
michael@0 44 const SEC_ASN1Template nsslowkey_PointerToEncryptedPrivateKeyInfoTemplate[] = {
michael@0 45 { SEC_ASN1_POINTER, 0, nsslowkey_EncryptedPrivateKeyInfoTemplate }
michael@0 46 };
michael@0 47
michael@0 48
michael@0 49 /* ====== Default key databse encryption algorithm ====== */
michael@0 50 static void
michael@0 51 sec_destroy_dbkey(NSSLOWKEYDBKey *dbkey)
michael@0 52 {
michael@0 53 if ( dbkey && dbkey->arena ) {
michael@0 54 PORT_FreeArena(dbkey->arena, PR_FALSE);
michael@0 55 }
michael@0 56 }
michael@0 57
michael@0 58 static void
michael@0 59 free_dbt(DBT *dbt)
michael@0 60 {
michael@0 61 if ( dbt ) {
michael@0 62 PORT_Free(dbt->data);
michael@0 63 PORT_Free(dbt);
michael@0 64 }
michael@0 65
michael@0 66 return;
michael@0 67 }
michael@0 68
michael@0 69 static int keydb_Get(NSSLOWKEYDBHandle *db, DBT *key, DBT *data,
michael@0 70 unsigned int flags);
michael@0 71 static int keydb_Put(NSSLOWKEYDBHandle *db, DBT *key, DBT *data,
michael@0 72 unsigned int flags);
michael@0 73 static int keydb_Sync(NSSLOWKEYDBHandle *db, unsigned int flags);
michael@0 74 static int keydb_Del(NSSLOWKEYDBHandle *db, DBT *key, unsigned int flags);
michael@0 75 static int keydb_Seq(NSSLOWKEYDBHandle *db, DBT *key, DBT *data,
michael@0 76 unsigned int flags);
michael@0 77 static void keydb_Close(NSSLOWKEYDBHandle *db);
michael@0 78
michael@0 79 /*
michael@0 80 * format of key database entries for version 3 of database:
michael@0 81 * byte offset field
michael@0 82 * ----------- -----
michael@0 83 * 0 version
michael@0 84 * 1 salt-len
michael@0 85 * 2 nn-len
michael@0 86 * 3.. salt-data
michael@0 87 * ... nickname
michael@0 88 * ... encrypted-key-data
michael@0 89 */
michael@0 90 static DBT *
michael@0 91 encode_dbkey(NSSLOWKEYDBKey *dbkey,unsigned char version)
michael@0 92 {
michael@0 93 DBT *bufitem = NULL;
michael@0 94 unsigned char *buf;
michael@0 95 int nnlen;
michael@0 96 char *nn;
michael@0 97
michael@0 98 bufitem = (DBT *)PORT_ZAlloc(sizeof(DBT));
michael@0 99 if ( bufitem == NULL ) {
michael@0 100 goto loser;
michael@0 101 }
michael@0 102
michael@0 103 if ( dbkey->nickname ) {
michael@0 104 nn = dbkey->nickname;
michael@0 105 nnlen = PORT_Strlen(nn) + 1;
michael@0 106 } else {
michael@0 107 nn = "";
michael@0 108 nnlen = 1;
michael@0 109 }
michael@0 110
michael@0 111 /* compute the length of the record */
michael@0 112 /* 1 + 1 + 1 == version number header + salt length + nn len */
michael@0 113 bufitem->size = dbkey->salt.len + nnlen + dbkey->derPK.len + 1 + 1 + 1;
michael@0 114
michael@0 115 bufitem->data = (void *)PORT_ZAlloc(bufitem->size);
michael@0 116 if ( bufitem->data == NULL ) {
michael@0 117 goto loser;
michael@0 118 }
michael@0 119
michael@0 120 buf = (unsigned char *)bufitem->data;
michael@0 121
michael@0 122 /* set version number */
michael@0 123 buf[0] = version;
michael@0 124
michael@0 125 /* set length of salt */
michael@0 126 PORT_Assert(dbkey->salt.len < 256);
michael@0 127 buf[1] = dbkey->salt.len;
michael@0 128
michael@0 129 /* set length of nickname */
michael@0 130 PORT_Assert(nnlen < 256);
michael@0 131 buf[2] = nnlen;
michael@0 132
michael@0 133 /* copy salt */
michael@0 134 PORT_Memcpy(&buf[3], dbkey->salt.data, dbkey->salt.len);
michael@0 135
michael@0 136 /* copy nickname */
michael@0 137 PORT_Memcpy(&buf[3 + dbkey->salt.len], nn, nnlen);
michael@0 138
michael@0 139 /* copy encrypted key */
michael@0 140 PORT_Memcpy(&buf[3 + dbkey->salt.len + nnlen], dbkey->derPK.data,
michael@0 141 dbkey->derPK.len);
michael@0 142
michael@0 143 return(bufitem);
michael@0 144
michael@0 145 loser:
michael@0 146 if ( bufitem ) {
michael@0 147 free_dbt(bufitem);
michael@0 148 }
michael@0 149
michael@0 150 return(NULL);
michael@0 151 }
michael@0 152
michael@0 153 static NSSLOWKEYDBKey *
michael@0 154 decode_dbkey(DBT *bufitem, int expectedVersion)
michael@0 155 {
michael@0 156 NSSLOWKEYDBKey *dbkey;
michael@0 157 PLArenaPool *arena = NULL;
michael@0 158 unsigned char *buf;
michael@0 159 int version;
michael@0 160 int keyoff;
michael@0 161 int nnlen;
michael@0 162 int saltoff;
michael@0 163
michael@0 164 buf = (unsigned char *)bufitem->data;
michael@0 165
michael@0 166 version = buf[0];
michael@0 167
michael@0 168 if ( version != expectedVersion ) {
michael@0 169 goto loser;
michael@0 170 }
michael@0 171
michael@0 172 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
michael@0 173 if ( arena == NULL ) {
michael@0 174 goto loser;
michael@0 175 }
michael@0 176
michael@0 177 dbkey = (NSSLOWKEYDBKey *)PORT_ArenaZAlloc(arena, sizeof(NSSLOWKEYDBKey));
michael@0 178 if ( dbkey == NULL ) {
michael@0 179 goto loser;
michael@0 180 }
michael@0 181
michael@0 182 dbkey->arena = arena;
michael@0 183 dbkey->salt.data = NULL;
michael@0 184 dbkey->derPK.data = NULL;
michael@0 185
michael@0 186 dbkey->salt.len = buf[1];
michael@0 187 dbkey->salt.data = (unsigned char *)PORT_ArenaZAlloc(arena, dbkey->salt.len);
michael@0 188 if ( dbkey->salt.data == NULL ) {
michael@0 189 goto loser;
michael@0 190 }
michael@0 191
michael@0 192 saltoff = 2;
michael@0 193 keyoff = 2 + dbkey->salt.len;
michael@0 194
michael@0 195 if ( expectedVersion >= 3 ) {
michael@0 196 nnlen = buf[2];
michael@0 197 if ( nnlen ) {
michael@0 198 dbkey->nickname = (char *)PORT_ArenaZAlloc(arena, nnlen + 1);
michael@0 199 if ( dbkey->nickname ) {
michael@0 200 PORT_Memcpy(dbkey->nickname, &buf[keyoff+1], nnlen);
michael@0 201 }
michael@0 202 }
michael@0 203 keyoff += ( nnlen + 1 );
michael@0 204 saltoff = 3;
michael@0 205 }
michael@0 206
michael@0 207 PORT_Memcpy(dbkey->salt.data, &buf[saltoff], dbkey->salt.len);
michael@0 208
michael@0 209 dbkey->derPK.len = bufitem->size - keyoff;
michael@0 210 dbkey->derPK.data = (unsigned char *)PORT_ArenaZAlloc(arena,dbkey->derPK.len);
michael@0 211 if ( dbkey->derPK.data == NULL ) {
michael@0 212 goto loser;
michael@0 213 }
michael@0 214
michael@0 215 PORT_Memcpy(dbkey->derPK.data, &buf[keyoff], dbkey->derPK.len);
michael@0 216
michael@0 217 return(dbkey);
michael@0 218
michael@0 219 loser:
michael@0 220
michael@0 221 if ( arena ) {
michael@0 222 PORT_FreeArena(arena, PR_FALSE);
michael@0 223 }
michael@0 224
michael@0 225 return(NULL);
michael@0 226 }
michael@0 227
michael@0 228 static NSSLOWKEYDBKey *
michael@0 229 get_dbkey(NSSLOWKEYDBHandle *handle, DBT *index)
michael@0 230 {
michael@0 231 NSSLOWKEYDBKey *dbkey;
michael@0 232 DBT entry;
michael@0 233 int ret;
michael@0 234
michael@0 235 /* get it from the database */
michael@0 236 ret = keydb_Get(handle, index, &entry, 0);
michael@0 237 if ( ret ) {
michael@0 238 PORT_SetError(SEC_ERROR_BAD_DATABASE);
michael@0 239 return NULL;
michael@0 240 }
michael@0 241
michael@0 242 /* set up dbkey struct */
michael@0 243
michael@0 244 dbkey = decode_dbkey(&entry, handle->version);
michael@0 245
michael@0 246 return(dbkey);
michael@0 247 }
michael@0 248
michael@0 249 static SECStatus
michael@0 250 put_dbkey(NSSLOWKEYDBHandle *handle, DBT *index, NSSLOWKEYDBKey *dbkey, PRBool update)
michael@0 251 {
michael@0 252 DBT *keydata = NULL;
michael@0 253 int status;
michael@0 254
michael@0 255 keydata = encode_dbkey(dbkey, handle->version);
michael@0 256 if ( keydata == NULL ) {
michael@0 257 goto loser;
michael@0 258 }
michael@0 259
michael@0 260 /* put it in the database */
michael@0 261 if ( update ) {
michael@0 262 status = keydb_Put(handle, index, keydata, 0);
michael@0 263 } else {
michael@0 264 status = keydb_Put(handle, index, keydata, R_NOOVERWRITE);
michael@0 265 }
michael@0 266
michael@0 267 if ( status ) {
michael@0 268 goto loser;
michael@0 269 }
michael@0 270
michael@0 271 /* sync the database */
michael@0 272 status = keydb_Sync(handle, 0);
michael@0 273 if ( status ) {
michael@0 274 goto loser;
michael@0 275 }
michael@0 276
michael@0 277 free_dbt(keydata);
michael@0 278 return(SECSuccess);
michael@0 279
michael@0 280 loser:
michael@0 281 if ( keydata ) {
michael@0 282 free_dbt(keydata);
michael@0 283 }
michael@0 284
michael@0 285 return(SECFailure);
michael@0 286 }
michael@0 287
michael@0 288 SECStatus
michael@0 289 nsslowkey_TraverseKeys(NSSLOWKEYDBHandle *handle,
michael@0 290 SECStatus (* keyfunc)(DBT *k, DBT *d, void *pdata),
michael@0 291 void *udata )
michael@0 292 {
michael@0 293 DBT data;
michael@0 294 DBT key;
michael@0 295 SECStatus status;
michael@0 296 int ret;
michael@0 297
michael@0 298 if (handle == NULL) {
michael@0 299 return(SECFailure);
michael@0 300 }
michael@0 301
michael@0 302 ret = keydb_Seq(handle, &key, &data, R_FIRST);
michael@0 303 if ( ret ) {
michael@0 304 return(SECFailure);
michael@0 305 }
michael@0 306
michael@0 307 do {
michael@0 308 /* skip version record */
michael@0 309 if ( data.size > 1 ) {
michael@0 310 if ( key.size == ( sizeof(SALT_STRING) - 1 ) ) {
michael@0 311 if ( PORT_Memcmp(key.data, SALT_STRING, key.size) == 0 ) {
michael@0 312 continue;
michael@0 313 }
michael@0 314 }
michael@0 315
michael@0 316 /* skip password check */
michael@0 317 if ( key.size == KEYDB_PW_CHECK_LEN ) {
michael@0 318 if ( PORT_Memcmp(key.data, KEYDB_PW_CHECK_STRING,
michael@0 319 KEYDB_PW_CHECK_LEN) == 0 ) {
michael@0 320 continue;
michael@0 321 }
michael@0 322 }
michael@0 323
michael@0 324 status = (* keyfunc)(&key, &data, udata);
michael@0 325 if (status != SECSuccess) {
michael@0 326 return(status);
michael@0 327 }
michael@0 328 }
michael@0 329 } while ( keydb_Seq(handle, &key, &data, R_NEXT) == 0 );
michael@0 330
michael@0 331 return(SECSuccess);
michael@0 332 }
michael@0 333
michael@0 334 #ifdef notdef
michael@0 335 typedef struct keyNode {
michael@0 336 struct keyNode *next;
michael@0 337 DBT key;
michael@0 338 } keyNode;
michael@0 339
michael@0 340 typedef struct {
michael@0 341 PLArenaPool *arena;
michael@0 342 keyNode *head;
michael@0 343 } keyList;
michael@0 344
michael@0 345 static SECStatus
michael@0 346 sec_add_key_to_list(DBT *key, DBT *data, void *arg)
michael@0 347 {
michael@0 348 keyList *keylist;
michael@0 349 keyNode *node;
michael@0 350 void *keydata;
michael@0 351
michael@0 352 keylist = (keyList *)arg;
michael@0 353
michael@0 354 /* allocate the node struct */
michael@0 355 node = (keyNode*)PORT_ArenaZAlloc(keylist->arena, sizeof(keyNode));
michael@0 356 if ( node == NULL ) {
michael@0 357 return(SECFailure);
michael@0 358 }
michael@0 359
michael@0 360 /* allocate room for key data */
michael@0 361 keydata = PORT_ArenaZAlloc(keylist->arena, key->size);
michael@0 362 if ( keydata == NULL ) {
michael@0 363 return(SECFailure);
michael@0 364 }
michael@0 365
michael@0 366 /* link node into list */
michael@0 367 node->next = keylist->head;
michael@0 368 keylist->head = node;
michael@0 369
michael@0 370 /* copy key into node */
michael@0 371 PORT_Memcpy(keydata, key->data, key->size);
michael@0 372 node->key.size = key->size;
michael@0 373 node->key.data = keydata;
michael@0 374
michael@0 375 return(SECSuccess);
michael@0 376 }
michael@0 377 #endif
michael@0 378
michael@0 379 static SECItem *
michael@0 380 decodeKeyDBGlobalSalt(DBT *saltData)
michael@0 381 {
michael@0 382 SECItem *saltitem;
michael@0 383
michael@0 384 saltitem = (SECItem *)PORT_ZAlloc(sizeof(SECItem));
michael@0 385 if ( saltitem == NULL ) {
michael@0 386 return(NULL);
michael@0 387 }
michael@0 388
michael@0 389 saltitem->data = (unsigned char *)PORT_ZAlloc(saltData->size);
michael@0 390 if ( saltitem->data == NULL ) {
michael@0 391 PORT_Free(saltitem);
michael@0 392 return(NULL);
michael@0 393 }
michael@0 394
michael@0 395 saltitem->len = saltData->size;
michael@0 396 PORT_Memcpy(saltitem->data, saltData->data, saltitem->len);
michael@0 397
michael@0 398 return(saltitem);
michael@0 399 }
michael@0 400
michael@0 401 static SECItem *
michael@0 402 GetKeyDBGlobalSalt(NSSLOWKEYDBHandle *handle)
michael@0 403 {
michael@0 404 DBT saltKey;
michael@0 405 DBT saltData;
michael@0 406 int ret;
michael@0 407
michael@0 408 saltKey.data = SALT_STRING;
michael@0 409 saltKey.size = sizeof(SALT_STRING) - 1;
michael@0 410
michael@0 411 ret = keydb_Get(handle, &saltKey, &saltData, 0);
michael@0 412 if ( ret ) {
michael@0 413 return(NULL);
michael@0 414 }
michael@0 415
michael@0 416 return(decodeKeyDBGlobalSalt(&saltData));
michael@0 417 }
michael@0 418
michael@0 419 static SECStatus
michael@0 420 StoreKeyDBGlobalSalt(NSSLOWKEYDBHandle *handle, SECItem *salt)
michael@0 421 {
michael@0 422 DBT saltKey;
michael@0 423 DBT saltData;
michael@0 424 int status;
michael@0 425
michael@0 426 saltKey.data = SALT_STRING;
michael@0 427 saltKey.size = sizeof(SALT_STRING) - 1;
michael@0 428
michael@0 429 saltData.data = (void *)salt->data;
michael@0 430 saltData.size = salt->len;
michael@0 431
michael@0 432 /* put global salt into the database now */
michael@0 433 status = keydb_Put(handle, &saltKey, &saltData, 0);
michael@0 434 if ( status ) {
michael@0 435 return(SECFailure);
michael@0 436 }
michael@0 437
michael@0 438 return(SECSuccess);
michael@0 439 }
michael@0 440
michael@0 441 static SECStatus
michael@0 442 makeGlobalVersion(NSSLOWKEYDBHandle *handle)
michael@0 443 {
michael@0 444 unsigned char version;
michael@0 445 DBT versionData;
michael@0 446 DBT versionKey;
michael@0 447 int status;
michael@0 448
michael@0 449 version = NSSLOWKEY_DB_FILE_VERSION;
michael@0 450 versionData.data = &version;
michael@0 451 versionData.size = 1;
michael@0 452 versionKey.data = VERSION_STRING;
michael@0 453 versionKey.size = sizeof(VERSION_STRING)-1;
michael@0 454
michael@0 455 /* put version string into the database now */
michael@0 456 status = keydb_Put(handle, &versionKey, &versionData, 0);
michael@0 457 if ( status ) {
michael@0 458 return(SECFailure);
michael@0 459 }
michael@0 460 handle->version = version;
michael@0 461
michael@0 462 return(SECSuccess);
michael@0 463 }
michael@0 464
michael@0 465
michael@0 466 static SECStatus
michael@0 467 makeGlobalSalt(NSSLOWKEYDBHandle *handle)
michael@0 468 {
michael@0 469 DBT saltKey;
michael@0 470 DBT saltData;
michael@0 471 unsigned char saltbuf[16];
michael@0 472 int status;
michael@0 473
michael@0 474 saltKey.data = SALT_STRING;
michael@0 475 saltKey.size = sizeof(SALT_STRING) - 1;
michael@0 476
michael@0 477 saltData.data = (void *)saltbuf;
michael@0 478 saltData.size = sizeof(saltbuf);
michael@0 479 RNG_GenerateGlobalRandomBytes(saltbuf, sizeof(saltbuf));
michael@0 480
michael@0 481 /* put global salt into the database now */
michael@0 482 status = keydb_Put(handle, &saltKey, &saltData, 0);
michael@0 483 if ( status ) {
michael@0 484 return(SECFailure);
michael@0 485 }
michael@0 486
michael@0 487 return(SECSuccess);
michael@0 488 }
michael@0 489
michael@0 490 static SECStatus
michael@0 491 encodePWCheckEntry(PLArenaPool *arena, SECItem *entry, SECOidTag alg,
michael@0 492 SECItem *encCheck);
michael@0 493
michael@0 494 static unsigned char
michael@0 495 nsslowkey_version(NSSLOWKEYDBHandle *handle)
michael@0 496 {
michael@0 497 DBT versionKey;
michael@0 498 DBT versionData;
michael@0 499 int ret;
michael@0 500 versionKey.data = VERSION_STRING;
michael@0 501 versionKey.size = sizeof(VERSION_STRING)-1;
michael@0 502
michael@0 503 if (handle->db == NULL) {
michael@0 504 return 255;
michael@0 505 }
michael@0 506
michael@0 507 /* lookup version string in database */
michael@0 508 ret = keydb_Get( handle, &versionKey, &versionData, 0 );
michael@0 509
michael@0 510 /* error accessing the database */
michael@0 511 if ( ret < 0 ) {
michael@0 512 return 255;
michael@0 513 }
michael@0 514
michael@0 515 if ( ret >= 1 ) {
michael@0 516 return 0;
michael@0 517 }
michael@0 518 return *( (unsigned char *)versionData.data);
michael@0 519 }
michael@0 520
michael@0 521 static PRBool
michael@0 522 seckey_HasAServerKey(NSSLOWKEYDBHandle *handle)
michael@0 523 {
michael@0 524 DBT key;
michael@0 525 DBT data;
michael@0 526 int ret;
michael@0 527 PRBool found = PR_FALSE;
michael@0 528
michael@0 529 ret = keydb_Seq(handle, &key, &data, R_FIRST);
michael@0 530 if ( ret ) {
michael@0 531 return PR_FALSE;
michael@0 532 }
michael@0 533
michael@0 534 do {
michael@0 535 /* skip version record */
michael@0 536 if ( data.size > 1 ) {
michael@0 537 /* skip salt */
michael@0 538 if ( key.size == ( sizeof(SALT_STRING) - 1 ) ) {
michael@0 539 if ( PORT_Memcmp(key.data, SALT_STRING, key.size) == 0 ) {
michael@0 540 continue;
michael@0 541 }
michael@0 542 }
michael@0 543 /* skip pw check entry */
michael@0 544 if ( key.size == KEYDB_PW_CHECK_LEN ) {
michael@0 545 if ( PORT_Memcmp(key.data, KEYDB_PW_CHECK_STRING,
michael@0 546 KEYDB_PW_CHECK_LEN) == 0 ) {
michael@0 547 continue;
michael@0 548 }
michael@0 549 }
michael@0 550
michael@0 551 /* keys stored by nickname will have 0 as the last byte of the
michael@0 552 * db key. Other keys must be stored by modulus. We will not
michael@0 553 * update those because they are left over from a keygen that
michael@0 554 * never resulted in a cert.
michael@0 555 */
michael@0 556 if ( ((unsigned char *)key.data)[key.size-1] != 0 ) {
michael@0 557 continue;
michael@0 558 }
michael@0 559
michael@0 560 if (PORT_Strcmp(key.data,"Server-Key") == 0) {
michael@0 561 found = PR_TRUE;
michael@0 562 break;
michael@0 563 }
michael@0 564
michael@0 565 }
michael@0 566 } while ( keydb_Seq(handle, &key, &data, R_NEXT) == 0 );
michael@0 567
michael@0 568 return found;
michael@0 569 }
michael@0 570
michael@0 571 /* forward declare local create function */
michael@0 572 static NSSLOWKEYDBHandle * nsslowkey_NewHandle(DB *dbHandle);
michael@0 573
michael@0 574 /*
michael@0 575 * currently updates key database from v2 to v3
michael@0 576 */
michael@0 577 static SECStatus
michael@0 578 nsslowkey_UpdateKeyDBPass1(NSSLOWKEYDBHandle *handle)
michael@0 579 {
michael@0 580 SECStatus rv;
michael@0 581 DBT checkKey;
michael@0 582 DBT checkData;
michael@0 583 DBT saltKey;
michael@0 584 DBT saltData;
michael@0 585 DBT key;
michael@0 586 DBT data;
michael@0 587 unsigned char version;
michael@0 588 NSSLOWKEYDBKey *dbkey = NULL;
michael@0 589 NSSLOWKEYDBHandle *update = NULL;
michael@0 590 SECItem *oldSalt = NULL;
michael@0 591 int ret;
michael@0 592 SECItem checkitem;
michael@0 593
michael@0 594 if ( handle->updatedb == NULL ) {
michael@0 595 return SECSuccess;
michael@0 596 }
michael@0 597
michael@0 598 /* create a full DB Handle for our update so we
michael@0 599 * can use the correct locks for the db primatives */
michael@0 600 update = nsslowkey_NewHandle(handle->updatedb);
michael@0 601 if ( update == NULL) {
michael@0 602 return SECSuccess;
michael@0 603 }
michael@0 604
michael@0 605 /* update has now inherited the database handle */
michael@0 606 handle->updatedb = NULL;
michael@0 607
michael@0 608 /*
michael@0 609 * check the version record
michael@0 610 */
michael@0 611 version = nsslowkey_version(update);
michael@0 612 if (version != 2) {
michael@0 613 goto done;
michael@0 614 }
michael@0 615
michael@0 616 saltKey.data = SALT_STRING;
michael@0 617 saltKey.size = sizeof(SALT_STRING) - 1;
michael@0 618
michael@0 619 ret = keydb_Get(update, &saltKey, &saltData, 0);
michael@0 620 if ( ret ) {
michael@0 621 /* no salt in old db, so it is corrupted */
michael@0 622 goto done;
michael@0 623 }
michael@0 624
michael@0 625 oldSalt = decodeKeyDBGlobalSalt(&saltData);
michael@0 626 if ( oldSalt == NULL ) {
michael@0 627 /* bad salt in old db, so it is corrupted */
michael@0 628 goto done;
michael@0 629 }
michael@0 630
michael@0 631 /*
michael@0 632 * look for a pw check entry
michael@0 633 */
michael@0 634 checkKey.data = KEYDB_PW_CHECK_STRING;
michael@0 635 checkKey.size = KEYDB_PW_CHECK_LEN;
michael@0 636
michael@0 637 ret = keydb_Get(update, &checkKey, &checkData, 0 );
michael@0 638 if (ret) {
michael@0 639 /*
michael@0 640 * if we have a key, but no KEYDB_PW_CHECK_STRING, then this must
michael@0 641 * be an old server database, and it does have a password associated
michael@0 642 * with it. Put a fake entry in so we can identify this db when we do
michael@0 643 * get the password for it.
michael@0 644 */
michael@0 645 if (seckey_HasAServerKey(update)) {
michael@0 646 DBT fcheckKey;
michael@0 647 DBT fcheckData;
michael@0 648
michael@0 649 /*
michael@0 650 * include a fake string
michael@0 651 */
michael@0 652 fcheckKey.data = KEYDB_FAKE_PW_CHECK_STRING;
michael@0 653 fcheckKey.size = KEYDB_FAKE_PW_CHECK_LEN;
michael@0 654 fcheckData.data = "1";
michael@0 655 fcheckData.size = 1;
michael@0 656 /* put global salt into the new database now */
michael@0 657 ret = keydb_Put( handle, &saltKey, &saltData, 0);
michael@0 658 if ( ret ) {
michael@0 659 goto done;
michael@0 660 }
michael@0 661 ret = keydb_Put( handle, &fcheckKey, &fcheckData, 0);
michael@0 662 if ( ret ) {
michael@0 663 goto done;
michael@0 664 }
michael@0 665 } else {
michael@0 666 goto done;
michael@0 667 }
michael@0 668 } else {
michael@0 669 /* put global salt into the new database now */
michael@0 670 ret = keydb_Put( handle, &saltKey, &saltData, 0);
michael@0 671 if ( ret ) {
michael@0 672 goto done;
michael@0 673 }
michael@0 674
michael@0 675 dbkey = decode_dbkey(&checkData, 2);
michael@0 676 if ( dbkey == NULL ) {
michael@0 677 goto done;
michael@0 678 }
michael@0 679 checkitem = dbkey->derPK;
michael@0 680 dbkey->derPK.data = NULL;
michael@0 681
michael@0 682 /* format the new pw check entry */
michael@0 683 rv = encodePWCheckEntry(NULL, &dbkey->derPK, SEC_OID_RC4, &checkitem);
michael@0 684 if ( rv != SECSuccess ) {
michael@0 685 goto done;
michael@0 686 }
michael@0 687
michael@0 688 rv = put_dbkey(handle, &checkKey, dbkey, PR_TRUE);
michael@0 689 if ( rv != SECSuccess ) {
michael@0 690 goto done;
michael@0 691 }
michael@0 692
michael@0 693 /* free the dbkey */
michael@0 694 sec_destroy_dbkey(dbkey);
michael@0 695 dbkey = NULL;
michael@0 696 }
michael@0 697
michael@0 698
michael@0 699 /* now traverse the database */
michael@0 700 ret = keydb_Seq(update, &key, &data, R_FIRST);
michael@0 701 if ( ret ) {
michael@0 702 goto done;
michael@0 703 }
michael@0 704
michael@0 705 do {
michael@0 706 /* skip version record */
michael@0 707 if ( data.size > 1 ) {
michael@0 708 /* skip salt */
michael@0 709 if ( key.size == ( sizeof(SALT_STRING) - 1 ) ) {
michael@0 710 if ( PORT_Memcmp(key.data, SALT_STRING, key.size) == 0 ) {
michael@0 711 continue;
michael@0 712 }
michael@0 713 }
michael@0 714 /* skip pw check entry */
michael@0 715 if ( key.size == checkKey.size ) {
michael@0 716 if ( PORT_Memcmp(key.data, checkKey.data, key.size) == 0 ) {
michael@0 717 continue;
michael@0 718 }
michael@0 719 }
michael@0 720
michael@0 721 /* keys stored by nickname will have 0 as the last byte of the
michael@0 722 * db key. Other keys must be stored by modulus. We will not
michael@0 723 * update those because they are left over from a keygen that
michael@0 724 * never resulted in a cert.
michael@0 725 */
michael@0 726 if ( ((unsigned char *)key.data)[key.size-1] != 0 ) {
michael@0 727 continue;
michael@0 728 }
michael@0 729
michael@0 730 dbkey = decode_dbkey(&data, 2);
michael@0 731 if ( dbkey == NULL ) {
michael@0 732 continue;
michael@0 733 }
michael@0 734
michael@0 735 /* This puts the key into the new database with the same
michael@0 736 * index (nickname) that it had before. The second pass
michael@0 737 * of the update will have the password. It will decrypt
michael@0 738 * and re-encrypt the entries using a new algorithm.
michael@0 739 */
michael@0 740 dbkey->nickname = (char *)key.data;
michael@0 741 rv = put_dbkey(handle, &key, dbkey, PR_FALSE);
michael@0 742 dbkey->nickname = NULL;
michael@0 743
michael@0 744 sec_destroy_dbkey(dbkey);
michael@0 745 }
michael@0 746 } while ( keydb_Seq(update, &key, &data, R_NEXT) == 0 );
michael@0 747
michael@0 748 dbkey = NULL;
michael@0 749
michael@0 750 done:
michael@0 751 /* sync the database */
michael@0 752 ret = keydb_Sync(handle, 0);
michael@0 753
michael@0 754 nsslowkey_CloseKeyDB(update);
michael@0 755
michael@0 756 if ( oldSalt ) {
michael@0 757 SECITEM_FreeItem(oldSalt, PR_TRUE);
michael@0 758 }
michael@0 759
michael@0 760 if ( dbkey ) {
michael@0 761 sec_destroy_dbkey(dbkey);
michael@0 762 }
michael@0 763
michael@0 764 return(SECSuccess);
michael@0 765 }
michael@0 766
michael@0 767 static SECStatus
michael@0 768 openNewDB(const char *appName, const char *prefix, const char *dbname,
michael@0 769 NSSLOWKEYDBHandle *handle, NSSLOWKEYDBNameFunc namecb, void *cbarg)
michael@0 770 {
michael@0 771 SECStatus rv = SECFailure;
michael@0 772 int status = RDB_FAIL;
michael@0 773 char *updname = NULL;
michael@0 774 DB *updatedb = NULL;
michael@0 775 PRBool updated = PR_FALSE;
michael@0 776 int ret;
michael@0 777
michael@0 778 if (appName) {
michael@0 779 handle->db = rdbopen( appName, prefix, "key", NO_CREATE, &status);
michael@0 780 } else {
michael@0 781 handle->db = dbopen( dbname, NO_CREATE, 0600, DB_HASH, 0 );
michael@0 782 }
michael@0 783 /* if create fails then we lose */
michael@0 784 if ( handle->db == NULL ) {
michael@0 785 return (status == RDB_RETRY) ? SECWouldBlock: SECFailure;
michael@0 786 }
michael@0 787
michael@0 788 /* force a transactional read, which will verify that one and only one
michael@0 789 * process attempts the update. */
michael@0 790 if (nsslowkey_version(handle) == NSSLOWKEY_DB_FILE_VERSION) {
michael@0 791 /* someone else has already updated the database for us */
michael@0 792 db_InitComplete(handle->db);
michael@0 793 return SECSuccess;
michael@0 794 }
michael@0 795
michael@0 796 /*
michael@0 797 * if we are creating a multiaccess database, see if there is a
michael@0 798 * local database we can update from.
michael@0 799 */
michael@0 800 if (appName) {
michael@0 801 NSSLOWKEYDBHandle *updateHandle;
michael@0 802 updatedb = dbopen( dbname, NO_RDONLY, 0600, DB_HASH, 0 );
michael@0 803 if (!updatedb) {
michael@0 804 goto noupdate;
michael@0 805 }
michael@0 806
michael@0 807 /* nsslowkey_version needs a full handle because it calls
michael@0 808 * the kdb_Get() function, which needs to lock.
michael@0 809 */
michael@0 810 updateHandle = nsslowkey_NewHandle(updatedb);
michael@0 811 if (!updateHandle) {
michael@0 812 updatedb->close(updatedb);
michael@0 813 goto noupdate;
michael@0 814 }
michael@0 815
michael@0 816 handle->version = nsslowkey_version(updateHandle);
michael@0 817 if (handle->version != NSSLOWKEY_DB_FILE_VERSION) {
michael@0 818 nsslowkey_CloseKeyDB(updateHandle);
michael@0 819 goto noupdate;
michael@0 820 }
michael@0 821
michael@0 822 /* copy the new DB from the old one */
michael@0 823 db_Copy(handle->db, updatedb);
michael@0 824 nsslowkey_CloseKeyDB(updateHandle);
michael@0 825 db_InitComplete(handle->db);
michael@0 826 return SECSuccess;
michael@0 827 }
michael@0 828 noupdate:
michael@0 829
michael@0 830 /* update the version number */
michael@0 831 rv = makeGlobalVersion(handle);
michael@0 832 if ( rv != SECSuccess ) {
michael@0 833 goto loser;
michael@0 834 }
michael@0 835
michael@0 836 /*
michael@0 837 * try to update from v2 db
michael@0 838 */
michael@0 839 updname = (*namecb)(cbarg, 2);
michael@0 840 if ( updname != NULL ) {
michael@0 841 handle->updatedb = dbopen( updname, NO_RDONLY, 0600, DB_HASH, 0 );
michael@0 842 PORT_Free( updname );
michael@0 843
michael@0 844 if ( handle->updatedb ) {
michael@0 845 /*
michael@0 846 * Try to update the db using a null password. If the db
michael@0 847 * doesn't have a password, then this will work. If it does
michael@0 848 * have a password, then this will fail and we will do the
michael@0 849 * update later
michael@0 850 */
michael@0 851 rv = nsslowkey_UpdateKeyDBPass1(handle);
michael@0 852 if ( rv == SECSuccess ) {
michael@0 853 updated = PR_TRUE;
michael@0 854 }
michael@0 855 }
michael@0 856
michael@0 857 }
michael@0 858
michael@0 859 /* we are using the old salt if we updated from an old db */
michael@0 860 if ( ! updated ) {
michael@0 861 rv = makeGlobalSalt(handle);
michael@0 862 if ( rv != SECSuccess ) {
michael@0 863 goto loser;
michael@0 864 }
michael@0 865 }
michael@0 866
michael@0 867 /* sync the database */
michael@0 868 ret = keydb_Sync(handle, 0);
michael@0 869 if ( ret ) {
michael@0 870 rv = SECFailure;
michael@0 871 goto loser;
michael@0 872 }
michael@0 873 rv = SECSuccess;
michael@0 874
michael@0 875 loser:
michael@0 876 db_InitComplete(handle->db);
michael@0 877 return rv;
michael@0 878 }
michael@0 879
michael@0 880
michael@0 881 static DB *
michael@0 882 openOldDB(const char *appName, const char *prefix, const char *dbname,
michael@0 883 PRBool openflags) {
michael@0 884 DB *db = NULL;
michael@0 885
michael@0 886 if (appName) {
michael@0 887 db = rdbopen( appName, prefix, "key", openflags, NULL);
michael@0 888 } else {
michael@0 889 db = dbopen( dbname, openflags, 0600, DB_HASH, 0 );
michael@0 890 }
michael@0 891
michael@0 892 return db;
michael@0 893 }
michael@0 894
michael@0 895 /* check for correct version number */
michael@0 896 static PRBool
michael@0 897 verifyVersion(NSSLOWKEYDBHandle *handle)
michael@0 898 {
michael@0 899 int version = nsslowkey_version(handle);
michael@0 900
michael@0 901 handle->version = version;
michael@0 902 if (version != NSSLOWKEY_DB_FILE_VERSION ) {
michael@0 903 if (handle->db) {
michael@0 904 keydb_Close(handle);
michael@0 905 handle->db = NULL;
michael@0 906 }
michael@0 907 }
michael@0 908 return handle->db != NULL;
michael@0 909 }
michael@0 910
michael@0 911 static NSSLOWKEYDBHandle *
michael@0 912 nsslowkey_NewHandle(DB *dbHandle)
michael@0 913 {
michael@0 914 NSSLOWKEYDBHandle *handle;
michael@0 915 handle = (NSSLOWKEYDBHandle *)PORT_ZAlloc (sizeof(NSSLOWKEYDBHandle));
michael@0 916 if (handle == NULL) {
michael@0 917 PORT_SetError (SEC_ERROR_NO_MEMORY);
michael@0 918 return NULL;
michael@0 919 }
michael@0 920
michael@0 921 handle->appname = NULL;
michael@0 922 handle->dbname = NULL;
michael@0 923 handle->global_salt = NULL;
michael@0 924 handle->updatedb = NULL;
michael@0 925 handle->db = dbHandle;
michael@0 926 handle->ref = 1;
michael@0 927 handle->lock = PZ_NewLock(nssILockKeyDB);
michael@0 928
michael@0 929 return handle;
michael@0 930 }
michael@0 931
michael@0 932 NSSLOWKEYDBHandle *
michael@0 933 nsslowkey_OpenKeyDB(PRBool readOnly, const char *appName, const char *prefix,
michael@0 934 NSSLOWKEYDBNameFunc namecb, void *cbarg)
michael@0 935 {
michael@0 936 NSSLOWKEYDBHandle *handle = NULL;
michael@0 937 SECStatus rv;
michael@0 938 int openflags;
michael@0 939 char *dbname = NULL;
michael@0 940
michael@0 941
michael@0 942 handle = nsslowkey_NewHandle(NULL);
michael@0 943
michael@0 944 openflags = readOnly ? NO_RDONLY : NO_RDWR;
michael@0 945
michael@0 946
michael@0 947 dbname = (*namecb)(cbarg, NSSLOWKEY_DB_FILE_VERSION);
michael@0 948 if ( dbname == NULL ) {
michael@0 949 goto loser;
michael@0 950 }
michael@0 951 handle->appname = appName ? PORT_Strdup(appName) : NULL ;
michael@0 952 handle->dbname = (appName == NULL) ? PORT_Strdup(dbname) :
michael@0 953 (prefix ? PORT_Strdup(prefix) : NULL);
michael@0 954 handle->readOnly = readOnly;
michael@0 955
michael@0 956
michael@0 957
michael@0 958 handle->db = openOldDB(appName, prefix, dbname, openflags);
michael@0 959 if (handle->db) {
michael@0 960 verifyVersion(handle);
michael@0 961 if (handle->version == 255) {
michael@0 962 goto loser;
michael@0 963 }
michael@0 964 }
michael@0 965
michael@0 966 /* if first open fails, try to create a new DB */
michael@0 967 if ( handle->db == NULL ) {
michael@0 968 if ( readOnly ) {
michael@0 969 goto loser;
michael@0 970 }
michael@0 971
michael@0 972 rv = openNewDB(appName, prefix, dbname, handle, namecb, cbarg);
michael@0 973 /* two processes started to initialize the database at the same time.
michael@0 974 * The multiprocess code blocked the second one, then had it retry to
michael@0 975 * see if it can just open the database normally */
michael@0 976 if (rv == SECWouldBlock) {
michael@0 977 handle->db = openOldDB(appName,prefix,dbname, openflags);
michael@0 978 verifyVersion(handle);
michael@0 979 if (handle->db == NULL) {
michael@0 980 goto loser;
michael@0 981 }
michael@0 982 } else if (rv != SECSuccess) {
michael@0 983 goto loser;
michael@0 984 }
michael@0 985 }
michael@0 986
michael@0 987 handle->global_salt = GetKeyDBGlobalSalt(handle);
michael@0 988 if ( dbname )
michael@0 989 PORT_Free( dbname );
michael@0 990 return handle;
michael@0 991
michael@0 992 loser:
michael@0 993
michael@0 994 if ( dbname )
michael@0 995 PORT_Free( dbname );
michael@0 996 PORT_SetError(SEC_ERROR_BAD_DATABASE);
michael@0 997 nsslowkey_CloseKeyDB(handle);
michael@0 998 return NULL;
michael@0 999 }
michael@0 1000
michael@0 1001 /*
michael@0 1002 * Close the database
michael@0 1003 */
michael@0 1004 void
michael@0 1005 nsslowkey_CloseKeyDB(NSSLOWKEYDBHandle *handle)
michael@0 1006 {
michael@0 1007 if (handle != NULL) {
michael@0 1008 if (handle->db != NULL) {
michael@0 1009 keydb_Close(handle);
michael@0 1010 }
michael@0 1011 if (handle->updatedb) {
michael@0 1012 handle->updatedb->close(handle->updatedb);
michael@0 1013 }
michael@0 1014 if (handle->dbname) PORT_Free(handle->dbname);
michael@0 1015 if (handle->appname) PORT_Free(handle->appname);
michael@0 1016 if (handle->global_salt) {
michael@0 1017 SECITEM_FreeItem(handle->global_salt,PR_TRUE);
michael@0 1018 }
michael@0 1019 if (handle->lock != NULL) {
michael@0 1020 SKIP_AFTER_FORK(PZ_DestroyLock(handle->lock));
michael@0 1021 }
michael@0 1022
michael@0 1023 PORT_Free(handle);
michael@0 1024 }
michael@0 1025 }
michael@0 1026
michael@0 1027 /* Get the key database version */
michael@0 1028 int
michael@0 1029 nsslowkey_GetKeyDBVersion(NSSLOWKEYDBHandle *handle)
michael@0 1030 {
michael@0 1031 PORT_Assert(handle != NULL);
michael@0 1032
michael@0 1033 return handle->version;
michael@0 1034 }
michael@0 1035
michael@0 1036 /*
michael@0 1037 * Delete a private key that was stored in the database
michael@0 1038 */
michael@0 1039 SECStatus
michael@0 1040 nsslowkey_DeleteKey(NSSLOWKEYDBHandle *handle, const SECItem *pubkey)
michael@0 1041 {
michael@0 1042 DBT namekey;
michael@0 1043 int ret;
michael@0 1044
michael@0 1045 if (handle == NULL) {
michael@0 1046 PORT_SetError(SEC_ERROR_BAD_DATABASE);
michael@0 1047 return(SECFailure);
michael@0 1048 }
michael@0 1049
michael@0 1050 /* set up db key and data */
michael@0 1051 namekey.data = pubkey->data;
michael@0 1052 namekey.size = pubkey->len;
michael@0 1053
michael@0 1054 /* delete it from the database */
michael@0 1055 ret = keydb_Del(handle, &namekey, 0);
michael@0 1056 if ( ret ) {
michael@0 1057 PORT_SetError(SEC_ERROR_BAD_DATABASE);
michael@0 1058 return(SECFailure);
michael@0 1059 }
michael@0 1060
michael@0 1061 /* sync the database */
michael@0 1062 ret = keydb_Sync(handle, 0);
michael@0 1063 if ( ret ) {
michael@0 1064 PORT_SetError(SEC_ERROR_BAD_DATABASE);
michael@0 1065 return(SECFailure);
michael@0 1066 }
michael@0 1067
michael@0 1068 return(SECSuccess);
michael@0 1069 }
michael@0 1070
michael@0 1071 /*
michael@0 1072 * Store a key in the database, indexed by its public key modulus.(value!)
michael@0 1073 */
michael@0 1074 SECStatus
michael@0 1075 nsslowkey_StoreKeyByPublicKey(NSSLOWKEYDBHandle *handle,
michael@0 1076 NSSLOWKEYPrivateKey *privkey,
michael@0 1077 SECItem *pubKeyData,
michael@0 1078 char *nickname,
michael@0 1079 SDB *sdb)
michael@0 1080 {
michael@0 1081 return nsslowkey_StoreKeyByPublicKeyAlg(handle, privkey, pubKeyData,
michael@0 1082 nickname, sdb, PR_FALSE);
michael@0 1083 }
michael@0 1084
michael@0 1085 SECStatus
michael@0 1086 nsslowkey_UpdateNickname(NSSLOWKEYDBHandle *handle,
michael@0 1087 NSSLOWKEYPrivateKey *privkey,
michael@0 1088 SECItem *pubKeyData,
michael@0 1089 char *nickname,
michael@0 1090 SDB *sdb)
michael@0 1091 {
michael@0 1092 return nsslowkey_StoreKeyByPublicKeyAlg(handle, privkey, pubKeyData,
michael@0 1093 nickname, sdb, PR_TRUE);
michael@0 1094 }
michael@0 1095
michael@0 1096 /* see if the symetric CKA_ID already Exists.
michael@0 1097 */
michael@0 1098 PRBool
michael@0 1099 nsslowkey_KeyForIDExists(NSSLOWKEYDBHandle *handle, SECItem *id)
michael@0 1100 {
michael@0 1101 DBT namekey;
michael@0 1102 DBT dummy;
michael@0 1103 int status;
michael@0 1104
michael@0 1105 namekey.data = (char *)id->data;
michael@0 1106 namekey.size = id->len;
michael@0 1107 status = keydb_Get(handle, &namekey, &dummy, 0);
michael@0 1108 if ( status ) {
michael@0 1109 return PR_FALSE;
michael@0 1110 }
michael@0 1111
michael@0 1112 return PR_TRUE;
michael@0 1113 }
michael@0 1114
michael@0 1115 /* see if the public key for this cert is in the database filed
michael@0 1116 * by modulus
michael@0 1117 */
michael@0 1118 PRBool
michael@0 1119 nsslowkey_KeyForCertExists(NSSLOWKEYDBHandle *handle, NSSLOWCERTCertificate *cert)
michael@0 1120 {
michael@0 1121 NSSLOWKEYPublicKey *pubkey = NULL;
michael@0 1122 DBT namekey;
michael@0 1123 DBT dummy;
michael@0 1124 int status;
michael@0 1125
michael@0 1126 /* get cert's public key */
michael@0 1127 pubkey = nsslowcert_ExtractPublicKey(cert);
michael@0 1128 if ( pubkey == NULL ) {
michael@0 1129 return PR_FALSE;
michael@0 1130 }
michael@0 1131
michael@0 1132 /* TNH - make key from NSSLOWKEYPublicKey */
michael@0 1133 switch (pubkey->keyType) {
michael@0 1134 case NSSLOWKEYRSAKey:
michael@0 1135 namekey.data = pubkey->u.rsa.modulus.data;
michael@0 1136 namekey.size = pubkey->u.rsa.modulus.len;
michael@0 1137 break;
michael@0 1138 case NSSLOWKEYDSAKey:
michael@0 1139 namekey.data = pubkey->u.dsa.publicValue.data;
michael@0 1140 namekey.size = pubkey->u.dsa.publicValue.len;
michael@0 1141 break;
michael@0 1142 case NSSLOWKEYDHKey:
michael@0 1143 namekey.data = pubkey->u.dh.publicValue.data;
michael@0 1144 namekey.size = pubkey->u.dh.publicValue.len;
michael@0 1145 break;
michael@0 1146 #ifndef NSS_DISABLE_ECC
michael@0 1147 case NSSLOWKEYECKey:
michael@0 1148 namekey.data = pubkey->u.ec.publicValue.data;
michael@0 1149 namekey.size = pubkey->u.ec.publicValue.len;
michael@0 1150 break;
michael@0 1151 #endif /* NSS_DISABLE_ECC */
michael@0 1152 default:
michael@0 1153 /* XXX We don't do Fortezza or DH yet. */
michael@0 1154 return PR_FALSE;
michael@0 1155 }
michael@0 1156
michael@0 1157 if (handle->version != 3) {
michael@0 1158 unsigned char buf[SHA1_LENGTH];
michael@0 1159 SHA1_HashBuf(buf,namekey.data,namekey.size);
michael@0 1160 /* NOTE: don't use pubkey after this! it's now thrashed */
michael@0 1161 PORT_Memcpy(namekey.data,buf,sizeof(buf));
michael@0 1162 namekey.size = sizeof(buf);
michael@0 1163 }
michael@0 1164
michael@0 1165 status = keydb_Get(handle, &namekey, &dummy, 0);
michael@0 1166 /* some databases have the key stored as a signed value */
michael@0 1167 if (status) {
michael@0 1168 unsigned char *buf = (unsigned char *)PORT_Alloc(namekey.size+1);
michael@0 1169 if (buf) {
michael@0 1170 PORT_Memcpy(&buf[1], namekey.data, namekey.size);
michael@0 1171 buf[0] = 0;
michael@0 1172 namekey.data = buf;
michael@0 1173 namekey.size ++;
michael@0 1174 status = keydb_Get(handle, &namekey, &dummy, 0);
michael@0 1175 PORT_Free(buf);
michael@0 1176 }
michael@0 1177 }
michael@0 1178 lg_nsslowkey_DestroyPublicKey(pubkey);
michael@0 1179 if ( status ) {
michael@0 1180 return PR_FALSE;
michael@0 1181 }
michael@0 1182
michael@0 1183 return PR_TRUE;
michael@0 1184 }
michael@0 1185
michael@0 1186 typedef struct NSSLowPasswordDataParamStr {
michael@0 1187 SECItem salt;
michael@0 1188 SECItem iter;
michael@0 1189 } NSSLowPasswordDataParam;
michael@0 1190
michael@0 1191 static const SEC_ASN1Template NSSLOWPasswordParamTemplate[] =
michael@0 1192 {
michael@0 1193 {SEC_ASN1_SEQUENCE, 0, NULL, sizeof(NSSLowPasswordDataParam) },
michael@0 1194 {SEC_ASN1_OCTET_STRING, offsetof(NSSLowPasswordDataParam, salt) },
michael@0 1195 {SEC_ASN1_INTEGER, offsetof(NSSLowPasswordDataParam, iter) },
michael@0 1196 {0}
michael@0 1197 };
michael@0 1198 struct LGEncryptedDataInfoStr {
michael@0 1199 SECAlgorithmID algorithm;
michael@0 1200 SECItem encryptedData;
michael@0 1201 };
michael@0 1202 typedef struct LGEncryptedDataInfoStr LGEncryptedDataInfo;
michael@0 1203
michael@0 1204 const SEC_ASN1Template lg_EncryptedDataInfoTemplate[] = {
michael@0 1205 { SEC_ASN1_SEQUENCE,
michael@0 1206 0, NULL, sizeof(LGEncryptedDataInfo) },
michael@0 1207 { SEC_ASN1_INLINE | SEC_ASN1_XTRN,
michael@0 1208 offsetof(LGEncryptedDataInfo,algorithm),
michael@0 1209 SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
michael@0 1210 { SEC_ASN1_OCTET_STRING,
michael@0 1211 offsetof(LGEncryptedDataInfo,encryptedData) },
michael@0 1212 { 0 }
michael@0 1213 };
michael@0 1214
michael@0 1215 static SECItem *
michael@0 1216 nsslowkey_EncodePW(SECOidTag alg, const SECItem *salt, SECItem *data)
michael@0 1217 {
michael@0 1218 NSSLowPasswordDataParam param;
michael@0 1219 LGEncryptedDataInfo edi;
michael@0 1220 PLArenaPool *arena;
michael@0 1221 unsigned char one = 1;
michael@0 1222 SECItem *epw = NULL;
michael@0 1223 SECItem *encParam;
michael@0 1224 SECStatus rv;
michael@0 1225
michael@0 1226 param.salt = *salt;
michael@0 1227 param.iter.type = siBuffer; /* encode as signed integer */
michael@0 1228 param.iter.data = &one;
michael@0 1229 param.iter.len = 1;
michael@0 1230 edi.encryptedData = *data;
michael@0 1231
michael@0 1232 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
michael@0 1233 if (arena == NULL) {
michael@0 1234 return NULL;
michael@0 1235 }
michael@0 1236
michael@0 1237 encParam = SEC_ASN1EncodeItem(arena, NULL, &param,
michael@0 1238 NSSLOWPasswordParamTemplate);
michael@0 1239 if (encParam == NULL) {
michael@0 1240 goto loser;
michael@0 1241 }
michael@0 1242 rv = SECOID_SetAlgorithmID(arena, &edi.algorithm, alg, encParam);
michael@0 1243 if (rv != SECSuccess) {
michael@0 1244 goto loser;
michael@0 1245 }
michael@0 1246 epw = SEC_ASN1EncodeItem(NULL, NULL, &edi, lg_EncryptedDataInfoTemplate);
michael@0 1247
michael@0 1248 loser:
michael@0 1249 PORT_FreeArena(arena, PR_FALSE);
michael@0 1250 return epw;
michael@0 1251 }
michael@0 1252
michael@0 1253 static SECItem *
michael@0 1254 nsslowkey_DecodePW(const SECItem *derData, SECOidTag *alg, SECItem *salt)
michael@0 1255 {
michael@0 1256 NSSLowPasswordDataParam param;
michael@0 1257 LGEncryptedDataInfo edi;
michael@0 1258 PLArenaPool *arena;
michael@0 1259 SECItem *pwe = NULL;
michael@0 1260 SECStatus rv;
michael@0 1261
michael@0 1262 salt->data = NULL;
michael@0 1263 param.iter.type = siBuffer; /* decode as signed integer */
michael@0 1264
michael@0 1265 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
michael@0 1266 if (arena == NULL) {
michael@0 1267 return NULL;
michael@0 1268 }
michael@0 1269
michael@0 1270 rv = SEC_QuickDERDecodeItem(arena, &edi, lg_EncryptedDataInfoTemplate,
michael@0 1271 derData);
michael@0 1272 if (rv != SECSuccess) {
michael@0 1273 goto loser;
michael@0 1274 }
michael@0 1275 *alg = SECOID_GetAlgorithmTag(&edi.algorithm);
michael@0 1276 rv = SEC_QuickDERDecodeItem(arena, &param, NSSLOWPasswordParamTemplate,
michael@0 1277 &edi.algorithm.parameters);
michael@0 1278 if (rv != SECSuccess) {
michael@0 1279 goto loser;
michael@0 1280 }
michael@0 1281 rv = SECITEM_CopyItem(NULL, salt, &param.salt);
michael@0 1282 if (rv != SECSuccess) {
michael@0 1283 goto loser;
michael@0 1284 }
michael@0 1285 pwe = SECITEM_DupItem(&edi.encryptedData);
michael@0 1286
michael@0 1287 loser:
michael@0 1288 if (!pwe && salt->data) {
michael@0 1289 PORT_Free(salt->data);
michael@0 1290 salt->data = NULL;
michael@0 1291 }
michael@0 1292 PORT_FreeArena(arena, PR_FALSE);
michael@0 1293 return pwe;
michael@0 1294 }
michael@0 1295
michael@0 1296
michael@0 1297 /*
michael@0 1298 * check to see if the user has a password
michael@0 1299 */
michael@0 1300 static SECStatus
michael@0 1301 nsslowkey_GetPWCheckEntry(NSSLOWKEYDBHandle *handle,NSSLOWKEYPasswordEntry *entry)
michael@0 1302 {
michael@0 1303 DBT checkkey; /*, checkdata; */
michael@0 1304 NSSLOWKEYDBKey *dbkey = NULL;
michael@0 1305 SECItem *global_salt = NULL;
michael@0 1306 SECItem *item = NULL;
michael@0 1307 SECItem entryData, oid;
michael@0 1308 SECItem none = { siBuffer, NULL, 0 };
michael@0 1309 SECStatus rv = SECFailure;
michael@0 1310 SECOidTag algorithm;
michael@0 1311
michael@0 1312 if (handle == NULL) {
michael@0 1313 /* PORT_SetError */
michael@0 1314 return(SECFailure);
michael@0 1315 }
michael@0 1316
michael@0 1317 global_salt = GetKeyDBGlobalSalt(handle);
michael@0 1318 if (!global_salt) {
michael@0 1319 global_salt = &none;
michael@0 1320 }
michael@0 1321 if (global_salt->len > sizeof(entry->data)) {
michael@0 1322 /* PORT_SetError */
michael@0 1323 goto loser;
michael@0 1324 }
michael@0 1325
michael@0 1326 PORT_Memcpy(entry->data, global_salt->data, global_salt->len);
michael@0 1327 entry->salt.data = entry->data;
michael@0 1328 entry->salt.len = global_salt->len;
michael@0 1329 entry->value.data = &entry->data[entry->salt.len];
michael@0 1330
michael@0 1331 checkkey.data = KEYDB_PW_CHECK_STRING;
michael@0 1332 checkkey.size = KEYDB_PW_CHECK_LEN;
michael@0 1333 dbkey = get_dbkey(handle, &checkkey);
michael@0 1334 if (dbkey == NULL) {
michael@0 1335 /* handle 'FAKE' check here */
michael@0 1336 goto loser;
michael@0 1337 }
michael@0 1338
michael@0 1339 oid.len = dbkey->derPK.data[0];
michael@0 1340 oid.data = &dbkey->derPK.data[1];
michael@0 1341
michael@0 1342 if (dbkey->derPK.len < (KEYDB_PW_CHECK_LEN + 1 +oid.len)) {
michael@0 1343 goto loser;
michael@0 1344 }
michael@0 1345 algorithm = SECOID_FindOIDTag(&oid);
michael@0 1346 entryData.type = siBuffer;
michael@0 1347 entryData.len = dbkey->derPK.len - (oid.len+1);
michael@0 1348 entryData.data = &dbkey->derPK.data[oid.len+1];
michael@0 1349
michael@0 1350 item = nsslowkey_EncodePW(algorithm, &dbkey->salt, &entryData);
michael@0 1351 if (!item || (item->len + entry->salt.len) > sizeof(entry->data)) {
michael@0 1352 goto loser;
michael@0 1353 }
michael@0 1354 PORT_Memcpy(entry->value.data, item->data, item->len);
michael@0 1355 entry->value.len = item->len;
michael@0 1356 rv = SECSuccess;
michael@0 1357
michael@0 1358 loser:
michael@0 1359 if (item) {
michael@0 1360 SECITEM_FreeItem(item, PR_TRUE);
michael@0 1361 }
michael@0 1362 if (dbkey) {
michael@0 1363 sec_destroy_dbkey(dbkey);
michael@0 1364 }
michael@0 1365 if (global_salt != &none) {
michael@0 1366 SECITEM_FreeItem(global_salt,PR_TRUE);
michael@0 1367 }
michael@0 1368 return rv;
michael@0 1369 }
michael@0 1370
michael@0 1371 /*
michael@0 1372 * check to see if the user has a password
michael@0 1373 */
michael@0 1374 static SECStatus
michael@0 1375 nsslowkey_PutPWCheckEntry(NSSLOWKEYDBHandle *handle,NSSLOWKEYPasswordEntry *entry)
michael@0 1376 {
michael@0 1377 DBT checkkey;
michael@0 1378 NSSLOWKEYDBKey *dbkey = NULL;
michael@0 1379 SECItem *item = NULL;
michael@0 1380 SECItem salt;
michael@0 1381 SECOidTag algid;
michael@0 1382 SECStatus rv = SECFailure;
michael@0 1383 PLArenaPool *arena;
michael@0 1384 int ret;
michael@0 1385
michael@0 1386 if (handle == NULL) {
michael@0 1387 /* PORT_SetError */
michael@0 1388 return(SECFailure);
michael@0 1389 }
michael@0 1390
michael@0 1391 checkkey.data = KEYDB_PW_CHECK_STRING;
michael@0 1392 checkkey.size = KEYDB_PW_CHECK_LEN;
michael@0 1393
michael@0 1394 salt.data = NULL;
michael@0 1395 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
michael@0 1396 if (arena == NULL) {
michael@0 1397 return SECFailure;
michael@0 1398 }
michael@0 1399
michael@0 1400 item = nsslowkey_DecodePW(&entry->value, &algid, &salt);
michael@0 1401 if (item == NULL) {
michael@0 1402 goto loser;
michael@0 1403 }
michael@0 1404
michael@0 1405 dbkey = PORT_ArenaZNew(arena, NSSLOWKEYDBKey);
michael@0 1406 if (dbkey == NULL) {
michael@0 1407 goto loser;
michael@0 1408 }
michael@0 1409
michael@0 1410 dbkey->arena = arena;
michael@0 1411
michael@0 1412 rv = SECITEM_CopyItem(arena, &dbkey->salt, &salt);
michael@0 1413 if (rv != SECSuccess) {
michael@0 1414 goto loser;
michael@0 1415 }
michael@0 1416
michael@0 1417 rv = encodePWCheckEntry(arena, &dbkey->derPK, algid, item);
michael@0 1418 if (rv != SECSuccess) {
michael@0 1419 goto loser;
michael@0 1420 }
michael@0 1421
michael@0 1422 rv = put_dbkey(handle, &checkkey, dbkey, PR_TRUE);
michael@0 1423 if (rv != SECSuccess) {
michael@0 1424 goto loser;
michael@0 1425 }
michael@0 1426
michael@0 1427 if (handle->global_salt) {
michael@0 1428 SECITEM_FreeItem(handle->global_salt, PR_TRUE);
michael@0 1429 handle->global_salt = NULL;
michael@0 1430 }
michael@0 1431 rv = StoreKeyDBGlobalSalt(handle, &entry->salt);
michael@0 1432 if (rv != SECSuccess) {
michael@0 1433 goto loser;
michael@0 1434 }
michael@0 1435 ret = keydb_Sync(handle, 0);
michael@0 1436 if ( ret ) {
michael@0 1437 rv = SECFailure;
michael@0 1438 goto loser;
michael@0 1439 }
michael@0 1440 handle->global_salt = GetKeyDBGlobalSalt(handle);
michael@0 1441
michael@0 1442 loser:
michael@0 1443 if (item) {
michael@0 1444 SECITEM_FreeItem(item, PR_TRUE);
michael@0 1445 }
michael@0 1446 if (arena) {
michael@0 1447 PORT_FreeArena(arena, PR_TRUE);
michael@0 1448 }
michael@0 1449 if (salt.data) {
michael@0 1450 PORT_Free(salt.data);
michael@0 1451 }
michael@0 1452 return rv;
michael@0 1453 }
michael@0 1454
michael@0 1455 #ifdef EC_DEBUG
michael@0 1456 #define SEC_PRINT(str1, str2, num, sitem) \
michael@0 1457 printf("pkcs11c.c:%s:%s (keytype=%d) [len=%d]\n", \
michael@0 1458 str1, str2, num, sitem->len); \
michael@0 1459 for (i = 0; i < sitem->len; i++) { \
michael@0 1460 printf("%02x:", sitem->data[i]); \
michael@0 1461 } \
michael@0 1462 printf("\n")
michael@0 1463 #else
michael@0 1464 #define SEC_PRINT(a, b, c, d)
michael@0 1465 #endif /* EC_DEBUG */
michael@0 1466
michael@0 1467
michael@0 1468 SECStatus
michael@0 1469 seckey_encrypt_private_key( PLArenaPool *permarena, NSSLOWKEYPrivateKey *pk,
michael@0 1470 SDB *sdbpw, SECItem *result)
michael@0 1471 {
michael@0 1472 NSSLOWKEYPrivateKeyInfo *pki = NULL;
michael@0 1473 SECStatus rv = SECFailure;
michael@0 1474 PLArenaPool *temparena = NULL;
michael@0 1475 SECItem *der_item = NULL;
michael@0 1476 SECItem *cipherText = NULL;
michael@0 1477 SECItem *dummy = NULL;
michael@0 1478 #ifndef NSS_DISABLE_ECC
michael@0 1479 SECItem *fordebug = NULL;
michael@0 1480 int savelen;
michael@0 1481 #endif
michael@0 1482
michael@0 1483 temparena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
michael@0 1484 if(temparena == NULL)
michael@0 1485 goto loser;
michael@0 1486
michael@0 1487 /* allocate structures */
michael@0 1488 pki = (NSSLOWKEYPrivateKeyInfo *)PORT_ArenaZAlloc(temparena,
michael@0 1489 sizeof(NSSLOWKEYPrivateKeyInfo));
michael@0 1490 der_item = (SECItem *)PORT_ArenaZAlloc(temparena, sizeof(SECItem));
michael@0 1491 if((pki == NULL) || (der_item == NULL))
michael@0 1492 goto loser;
michael@0 1493
michael@0 1494
michael@0 1495 /* setup private key info */
michael@0 1496 dummy = SEC_ASN1EncodeInteger(temparena, &(pki->version),
michael@0 1497 NSSLOWKEY_PRIVATE_KEY_INFO_VERSION);
michael@0 1498 if(dummy == NULL)
michael@0 1499 goto loser;
michael@0 1500
michael@0 1501 /* Encode the key, and set the algorithm (with params) */
michael@0 1502 switch (pk->keyType) {
michael@0 1503 case NSSLOWKEYRSAKey:
michael@0 1504 lg_prepare_low_rsa_priv_key_for_asn1(pk);
michael@0 1505 dummy = SEC_ASN1EncodeItem(temparena, &(pki->privateKey), pk,
michael@0 1506 lg_nsslowkey_RSAPrivateKeyTemplate);
michael@0 1507 if (dummy == NULL) {
michael@0 1508 rv = SECFailure;
michael@0 1509 goto loser;
michael@0 1510 }
michael@0 1511
michael@0 1512 rv = SECOID_SetAlgorithmID(temparena, &(pki->algorithm),
michael@0 1513 SEC_OID_PKCS1_RSA_ENCRYPTION, 0);
michael@0 1514 if (rv == SECFailure) {
michael@0 1515 goto loser;
michael@0 1516 }
michael@0 1517
michael@0 1518 break;
michael@0 1519 case NSSLOWKEYDSAKey:
michael@0 1520 lg_prepare_low_dsa_priv_key_for_asn1(pk);
michael@0 1521 dummy = SEC_ASN1EncodeItem(temparena, &(pki->privateKey), pk,
michael@0 1522 lg_nsslowkey_DSAPrivateKeyTemplate);
michael@0 1523 if (dummy == NULL) {
michael@0 1524 rv = SECFailure;
michael@0 1525 goto loser;
michael@0 1526 }
michael@0 1527
michael@0 1528 lg_prepare_low_pqg_params_for_asn1(&pk->u.dsa.params);
michael@0 1529 dummy = SEC_ASN1EncodeItem(temparena, NULL, &pk->u.dsa.params,
michael@0 1530 lg_nsslowkey_PQGParamsTemplate);
michael@0 1531 if (dummy == NULL) {
michael@0 1532 rv = SECFailure;
michael@0 1533 goto loser;
michael@0 1534 }
michael@0 1535
michael@0 1536 rv = SECOID_SetAlgorithmID(temparena, &(pki->algorithm),
michael@0 1537 SEC_OID_ANSIX9_DSA_SIGNATURE, dummy);
michael@0 1538 if (rv == SECFailure) {
michael@0 1539 goto loser;
michael@0 1540 }
michael@0 1541
michael@0 1542 break;
michael@0 1543 case NSSLOWKEYDHKey:
michael@0 1544 lg_prepare_low_dh_priv_key_for_asn1(pk);
michael@0 1545 dummy = SEC_ASN1EncodeItem(temparena, &(pki->privateKey), pk,
michael@0 1546 lg_nsslowkey_DHPrivateKeyTemplate);
michael@0 1547 if (dummy == NULL) {
michael@0 1548 rv = SECFailure;
michael@0 1549 goto loser;
michael@0 1550 }
michael@0 1551
michael@0 1552 rv = SECOID_SetAlgorithmID(temparena, &(pki->algorithm),
michael@0 1553 SEC_OID_X942_DIFFIE_HELMAN_KEY, dummy);
michael@0 1554 if (rv == SECFailure) {
michael@0 1555 goto loser;
michael@0 1556 }
michael@0 1557 break;
michael@0 1558 #ifndef NSS_DISABLE_ECC
michael@0 1559 case NSSLOWKEYECKey:
michael@0 1560 lg_prepare_low_ec_priv_key_for_asn1(pk);
michael@0 1561 /* Public value is encoded as a bit string so adjust length
michael@0 1562 * to be in bits before ASN encoding and readjust
michael@0 1563 * immediately after.
michael@0 1564 *
michael@0 1565 * Since the SECG specification recommends not including the
michael@0 1566 * parameters as part of ECPrivateKey, we zero out the curveOID
michael@0 1567 * length before encoding and restore it later.
michael@0 1568 */
michael@0 1569 pk->u.ec.publicValue.len <<= 3;
michael@0 1570 savelen = pk->u.ec.ecParams.curveOID.len;
michael@0 1571 pk->u.ec.ecParams.curveOID.len = 0;
michael@0 1572 dummy = SEC_ASN1EncodeItem(temparena, &(pki->privateKey), pk,
michael@0 1573 lg_nsslowkey_ECPrivateKeyTemplate);
michael@0 1574 pk->u.ec.ecParams.curveOID.len = savelen;
michael@0 1575 pk->u.ec.publicValue.len >>= 3;
michael@0 1576
michael@0 1577 if (dummy == NULL) {
michael@0 1578 rv = SECFailure;
michael@0 1579 goto loser;
michael@0 1580 }
michael@0 1581
michael@0 1582 dummy = &pk->u.ec.ecParams.DEREncoding;
michael@0 1583
michael@0 1584 /* At this point dummy should contain the encoded params */
michael@0 1585 rv = SECOID_SetAlgorithmID(temparena, &(pki->algorithm),
michael@0 1586 SEC_OID_ANSIX962_EC_PUBLIC_KEY, dummy);
michael@0 1587
michael@0 1588 if (rv == SECFailure) {
michael@0 1589 goto loser;
michael@0 1590 }
michael@0 1591
michael@0 1592 fordebug = &(pki->privateKey);
michael@0 1593 SEC_PRINT("seckey_encrypt_private_key()", "PrivateKey",
michael@0 1594 pk->keyType, fordebug);
michael@0 1595
michael@0 1596 break;
michael@0 1597 #endif /* NSS_DISABLE_ECC */
michael@0 1598 default:
michael@0 1599 /* We don't support DH or Fortezza private keys yet */
michael@0 1600 PORT_Assert(PR_FALSE);
michael@0 1601 break;
michael@0 1602 }
michael@0 1603
michael@0 1604 /* setup encrypted private key info */
michael@0 1605 dummy = SEC_ASN1EncodeItem(temparena, der_item, pki,
michael@0 1606 lg_nsslowkey_PrivateKeyInfoTemplate);
michael@0 1607
michael@0 1608 SEC_PRINT("seckey_encrypt_private_key()", "PrivateKeyInfo",
michael@0 1609 pk->keyType, der_item);
michael@0 1610
michael@0 1611 if(dummy == NULL) {
michael@0 1612 rv = SECFailure;
michael@0 1613 goto loser;
michael@0 1614 }
michael@0 1615
michael@0 1616 rv = lg_util_encrypt(temparena, sdbpw, dummy, &cipherText);
michael@0 1617 if (rv != SECSuccess) {
michael@0 1618 goto loser;
michael@0 1619 }
michael@0 1620
michael@0 1621 rv = SECITEM_CopyItem ( permarena, result, cipherText);
michael@0 1622
michael@0 1623 loser:
michael@0 1624
michael@0 1625 if(temparena != NULL)
michael@0 1626 PORT_FreeArena(temparena, PR_TRUE);
michael@0 1627
michael@0 1628 return rv;
michael@0 1629 }
michael@0 1630
michael@0 1631 static SECStatus
michael@0 1632 seckey_put_private_key(NSSLOWKEYDBHandle *keydb, DBT *index, SDB *sdbpw,
michael@0 1633 NSSLOWKEYPrivateKey *pk, char *nickname, PRBool update)
michael@0 1634 {
michael@0 1635 NSSLOWKEYDBKey *dbkey = NULL;
michael@0 1636 PLArenaPool *arena = NULL;
michael@0 1637 SECStatus rv = SECFailure;
michael@0 1638
michael@0 1639 if((keydb == NULL) || (index == NULL) || (sdbpw == NULL) ||
michael@0 1640 (pk == NULL))
michael@0 1641 return SECFailure;
michael@0 1642
michael@0 1643 arena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
michael@0 1644 if(arena == NULL)
michael@0 1645 return SECFailure;
michael@0 1646
michael@0 1647 dbkey = (NSSLOWKEYDBKey *)PORT_ArenaZAlloc(arena, sizeof(NSSLOWKEYDBKey));
michael@0 1648 if(dbkey == NULL)
michael@0 1649 goto loser;
michael@0 1650 dbkey->arena = arena;
michael@0 1651 dbkey->nickname = nickname;
michael@0 1652
michael@0 1653 rv = seckey_encrypt_private_key(arena, pk, sdbpw, &dbkey->derPK);
michael@0 1654 if(rv != SECSuccess)
michael@0 1655 goto loser;
michael@0 1656
michael@0 1657 rv = put_dbkey(keydb, index, dbkey, update);
michael@0 1658
michael@0 1659 /* let success fall through */
michael@0 1660 loser:
michael@0 1661 if(arena != NULL)
michael@0 1662 PORT_FreeArena(arena, PR_TRUE);
michael@0 1663
michael@0 1664 return rv;
michael@0 1665 }
michael@0 1666
michael@0 1667 /*
michael@0 1668 * Store a key in the database, indexed by its public key modulus.
michael@0 1669 * Note that the nickname is optional. It was only used by keyutil.
michael@0 1670 */
michael@0 1671 SECStatus
michael@0 1672 nsslowkey_StoreKeyByPublicKeyAlg(NSSLOWKEYDBHandle *handle,
michael@0 1673 NSSLOWKEYPrivateKey *privkey,
michael@0 1674 SECItem *pubKeyData,
michael@0 1675 char *nickname,
michael@0 1676 SDB *sdbpw,
michael@0 1677 PRBool update)
michael@0 1678 {
michael@0 1679 DBT namekey;
michael@0 1680 SECStatus rv;
michael@0 1681
michael@0 1682 if (handle == NULL) {
michael@0 1683 PORT_SetError(SEC_ERROR_BAD_DATABASE);
michael@0 1684 return(SECFailure);
michael@0 1685 }
michael@0 1686
michael@0 1687 /* set up db key and data */
michael@0 1688 namekey.data = pubKeyData->data;
michael@0 1689 namekey.size = pubKeyData->len;
michael@0 1690
michael@0 1691 /* encrypt the private key */
michael@0 1692 rv = seckey_put_private_key(handle, &namekey, sdbpw, privkey, nickname,
michael@0 1693 update);
michael@0 1694
michael@0 1695 return(rv);
michael@0 1696 }
michael@0 1697
michael@0 1698 static NSSLOWKEYPrivateKey *
michael@0 1699 seckey_decrypt_private_key(SECItem*epki,
michael@0 1700 SDB *sdbpw)
michael@0 1701 {
michael@0 1702 NSSLOWKEYPrivateKey *pk = NULL;
michael@0 1703 NSSLOWKEYPrivateKeyInfo *pki = NULL;
michael@0 1704 SECStatus rv = SECFailure;
michael@0 1705 PLArenaPool *temparena = NULL, *permarena = NULL;
michael@0 1706 SECItem *dest = NULL;
michael@0 1707 #ifndef NSS_DISABLE_ECC
michael@0 1708 SECItem *fordebug = NULL;
michael@0 1709 #endif
michael@0 1710
michael@0 1711 if((epki == NULL) || (sdbpw == NULL))
michael@0 1712 goto loser;
michael@0 1713
michael@0 1714 temparena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
michael@0 1715 permarena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
michael@0 1716 if((temparena == NULL) || (permarena == NULL))
michael@0 1717 goto loser;
michael@0 1718
michael@0 1719 /* allocate temporary items */
michael@0 1720 pki = (NSSLOWKEYPrivateKeyInfo *)PORT_ArenaZAlloc(temparena,
michael@0 1721 sizeof(NSSLOWKEYPrivateKeyInfo));
michael@0 1722
michael@0 1723 /* allocate permanent arena items */
michael@0 1724 pk = (NSSLOWKEYPrivateKey *)PORT_ArenaZAlloc(permarena,
michael@0 1725 sizeof(NSSLOWKEYPrivateKey));
michael@0 1726
michael@0 1727 if((pk == NULL) || (pki == NULL))
michael@0 1728 goto loser;
michael@0 1729
michael@0 1730 pk->arena = permarena;
michael@0 1731
michael@0 1732 rv = lg_util_decrypt(sdbpw, epki, &dest);
michael@0 1733 if (rv != SECSuccess) {
michael@0 1734 goto loser;
michael@0 1735 }
michael@0 1736
michael@0 1737 if(dest != NULL)
michael@0 1738 {
michael@0 1739 SECItem newPrivateKey;
michael@0 1740 SECItem newAlgParms;
michael@0 1741
michael@0 1742 SEC_PRINT("seckey_decrypt_private_key()", "PrivateKeyInfo", -1,
michael@0 1743 dest);
michael@0 1744
michael@0 1745 rv = SEC_QuickDERDecodeItem(temparena, pki,
michael@0 1746 lg_nsslowkey_PrivateKeyInfoTemplate, dest);
michael@0 1747 if(rv == SECSuccess)
michael@0 1748 {
michael@0 1749 switch(SECOID_GetAlgorithmTag(&pki->algorithm)) {
michael@0 1750 case SEC_OID_X500_RSA_ENCRYPTION:
michael@0 1751 case SEC_OID_PKCS1_RSA_ENCRYPTION:
michael@0 1752 pk->keyType = NSSLOWKEYRSAKey;
michael@0 1753 lg_prepare_low_rsa_priv_key_for_asn1(pk);
michael@0 1754 if (SECSuccess != SECITEM_CopyItem(permarena, &newPrivateKey,
michael@0 1755 &pki->privateKey) ) break;
michael@0 1756 rv = SEC_QuickDERDecodeItem(permarena, pk,
michael@0 1757 lg_nsslowkey_RSAPrivateKeyTemplate,
michael@0 1758 &newPrivateKey);
michael@0 1759 if (rv == SECSuccess) {
michael@0 1760 break;
michael@0 1761 }
michael@0 1762 /* Try decoding with the alternative template, but only allow
michael@0 1763 * a zero-length modulus for a secret key object.
michael@0 1764 * See bug 715073.
michael@0 1765 */
michael@0 1766 rv = SEC_QuickDERDecodeItem(permarena, pk,
michael@0 1767 lg_nsslowkey_RSAPrivateKeyTemplate2,
michael@0 1768 &newPrivateKey);
michael@0 1769 /* A publicExponent of 0 is the defining property of a secret
michael@0 1770 * key disguised as an RSA key. When decoding with the
michael@0 1771 * alternative template, only accept a secret key with an
michael@0 1772 * improperly encoded modulus and a publicExponent of 0.
michael@0 1773 */
michael@0 1774 if (rv == SECSuccess) {
michael@0 1775 if (pk->u.rsa.modulus.len == 2 &&
michael@0 1776 pk->u.rsa.modulus.data[0] == SEC_ASN1_INTEGER &&
michael@0 1777 pk->u.rsa.modulus.data[1] == 0 &&
michael@0 1778 pk->u.rsa.publicExponent.len == 1 &&
michael@0 1779 pk->u.rsa.publicExponent.data[0] == 0) {
michael@0 1780 /* Fix the zero-length integer by setting it to 0. */
michael@0 1781 pk->u.rsa.modulus.data = pk->u.rsa.publicExponent.data;
michael@0 1782 pk->u.rsa.modulus.len = pk->u.rsa.publicExponent.len;
michael@0 1783 } else {
michael@0 1784 PORT_SetError(SEC_ERROR_BAD_DER);
michael@0 1785 rv = SECFailure;
michael@0 1786 }
michael@0 1787 }
michael@0 1788 break;
michael@0 1789 case SEC_OID_ANSIX9_DSA_SIGNATURE:
michael@0 1790 pk->keyType = NSSLOWKEYDSAKey;
michael@0 1791 lg_prepare_low_dsa_priv_key_for_asn1(pk);
michael@0 1792 if (SECSuccess != SECITEM_CopyItem(permarena, &newPrivateKey,
michael@0 1793 &pki->privateKey) ) break;
michael@0 1794 rv = SEC_QuickDERDecodeItem(permarena, pk,
michael@0 1795 lg_nsslowkey_DSAPrivateKeyTemplate,
michael@0 1796 &newPrivateKey);
michael@0 1797 if (rv != SECSuccess)
michael@0 1798 goto loser;
michael@0 1799 lg_prepare_low_pqg_params_for_asn1(&pk->u.dsa.params);
michael@0 1800 if (SECSuccess != SECITEM_CopyItem(permarena, &newAlgParms,
michael@0 1801 &pki->algorithm.parameters) ) break;
michael@0 1802 rv = SEC_QuickDERDecodeItem(permarena, &pk->u.dsa.params,
michael@0 1803 lg_nsslowkey_PQGParamsTemplate,
michael@0 1804 &newAlgParms);
michael@0 1805 break;
michael@0 1806 case SEC_OID_X942_DIFFIE_HELMAN_KEY:
michael@0 1807 pk->keyType = NSSLOWKEYDHKey;
michael@0 1808 lg_prepare_low_dh_priv_key_for_asn1(pk);
michael@0 1809 if (SECSuccess != SECITEM_CopyItem(permarena, &newPrivateKey,
michael@0 1810 &pki->privateKey) ) break;
michael@0 1811 rv = SEC_QuickDERDecodeItem(permarena, pk,
michael@0 1812 lg_nsslowkey_DHPrivateKeyTemplate,
michael@0 1813 &newPrivateKey);
michael@0 1814 break;
michael@0 1815 #ifndef NSS_DISABLE_ECC
michael@0 1816 case SEC_OID_ANSIX962_EC_PUBLIC_KEY:
michael@0 1817 pk->keyType = NSSLOWKEYECKey;
michael@0 1818 lg_prepare_low_ec_priv_key_for_asn1(pk);
michael@0 1819
michael@0 1820 fordebug = &pki->privateKey;
michael@0 1821 SEC_PRINT("seckey_decrypt_private_key()", "PrivateKey",
michael@0 1822 pk->keyType, fordebug);
michael@0 1823 if (SECSuccess != SECITEM_CopyItem(permarena, &newPrivateKey,
michael@0 1824 &pki->privateKey) ) break;
michael@0 1825 rv = SEC_QuickDERDecodeItem(permarena, pk,
michael@0 1826 lg_nsslowkey_ECPrivateKeyTemplate,
michael@0 1827 &newPrivateKey);
michael@0 1828 if (rv != SECSuccess)
michael@0 1829 goto loser;
michael@0 1830
michael@0 1831 lg_prepare_low_ecparams_for_asn1(&pk->u.ec.ecParams);
michael@0 1832
michael@0 1833 rv = SECITEM_CopyItem(permarena,
michael@0 1834 &pk->u.ec.ecParams.DEREncoding,
michael@0 1835 &pki->algorithm.parameters);
michael@0 1836
michael@0 1837 if (rv != SECSuccess)
michael@0 1838 goto loser;
michael@0 1839
michael@0 1840 /* Fill out the rest of EC params */
michael@0 1841 rv = LGEC_FillParams(permarena, &pk->u.ec.ecParams.DEREncoding,
michael@0 1842 &pk->u.ec.ecParams);
michael@0 1843
michael@0 1844 if (rv != SECSuccess)
michael@0 1845 goto loser;
michael@0 1846
michael@0 1847 if (pk->u.ec.publicValue.len != 0) {
michael@0 1848 pk->u.ec.publicValue.len >>= 3;
michael@0 1849 }
michael@0 1850
michael@0 1851 break;
michael@0 1852 #endif /* NSS_DISABLE_ECC */
michael@0 1853 default:
michael@0 1854 rv = SECFailure;
michael@0 1855 break;
michael@0 1856 }
michael@0 1857 }
michael@0 1858 else if(PORT_GetError() == SEC_ERROR_BAD_DER)
michael@0 1859 {
michael@0 1860 PORT_SetError(SEC_ERROR_BAD_PASSWORD);
michael@0 1861 goto loser;
michael@0 1862 }
michael@0 1863 }
michael@0 1864
michael@0 1865 /* let success fall through */
michael@0 1866 loser:
michael@0 1867 if(temparena != NULL)
michael@0 1868 PORT_FreeArena(temparena, PR_TRUE);
michael@0 1869 if(dest != NULL)
michael@0 1870 SECITEM_ZfreeItem(dest, PR_TRUE);
michael@0 1871
michael@0 1872 if(rv != SECSuccess)
michael@0 1873 {
michael@0 1874 if(permarena != NULL)
michael@0 1875 PORT_FreeArena(permarena, PR_TRUE);
michael@0 1876 pk = NULL;
michael@0 1877 }
michael@0 1878
michael@0 1879 return pk;
michael@0 1880 }
michael@0 1881
michael@0 1882 static NSSLOWKEYPrivateKey *
michael@0 1883 seckey_decode_encrypted_private_key(NSSLOWKEYDBKey *dbkey, SDB *sdbpw)
michael@0 1884 {
michael@0 1885 if( ( dbkey == NULL ) || ( sdbpw == NULL ) ) {
michael@0 1886 return NULL;
michael@0 1887 }
michael@0 1888
michael@0 1889 return seckey_decrypt_private_key(&(dbkey->derPK), sdbpw);
michael@0 1890 }
michael@0 1891
michael@0 1892 static NSSLOWKEYPrivateKey *
michael@0 1893 seckey_get_private_key(NSSLOWKEYDBHandle *keydb, DBT *index, char **nickname,
michael@0 1894 SDB *sdbpw)
michael@0 1895 {
michael@0 1896 NSSLOWKEYDBKey *dbkey = NULL;
michael@0 1897 NSSLOWKEYPrivateKey *pk = NULL;
michael@0 1898
michael@0 1899 if( ( keydb == NULL ) || ( index == NULL ) || ( sdbpw == NULL ) ) {
michael@0 1900 return NULL;
michael@0 1901 }
michael@0 1902
michael@0 1903 dbkey = get_dbkey(keydb, index);
michael@0 1904 if(dbkey == NULL) {
michael@0 1905 goto loser;
michael@0 1906 }
michael@0 1907
michael@0 1908 if ( nickname ) {
michael@0 1909 if ( dbkey->nickname && ( dbkey->nickname[0] != 0 ) ) {
michael@0 1910 *nickname = PORT_Strdup(dbkey->nickname);
michael@0 1911 } else {
michael@0 1912 *nickname = NULL;
michael@0 1913 }
michael@0 1914 }
michael@0 1915
michael@0 1916 pk = seckey_decode_encrypted_private_key(dbkey, sdbpw);
michael@0 1917
michael@0 1918 /* let success fall through */
michael@0 1919 loser:
michael@0 1920
michael@0 1921 if ( dbkey != NULL ) {
michael@0 1922 sec_destroy_dbkey(dbkey);
michael@0 1923 }
michael@0 1924
michael@0 1925 return pk;
michael@0 1926 }
michael@0 1927
michael@0 1928 /*
michael@0 1929 * Find a key in the database, indexed by its public key modulus
michael@0 1930 * This is used to find keys that have been stored before their
michael@0 1931 * certificate arrives. Once the certificate arrives the key
michael@0 1932 * is looked up by the public modulus in the certificate, and the
michael@0 1933 * re-stored by its nickname.
michael@0 1934 */
michael@0 1935 NSSLOWKEYPrivateKey *
michael@0 1936 nsslowkey_FindKeyByPublicKey(NSSLOWKEYDBHandle *handle, SECItem *modulus,
michael@0 1937 SDB *sdbpw)
michael@0 1938 {
michael@0 1939 DBT namekey;
michael@0 1940 NSSLOWKEYPrivateKey *pk = NULL;
michael@0 1941
michael@0 1942 if (handle == NULL) {
michael@0 1943 PORT_SetError(SEC_ERROR_BAD_DATABASE);
michael@0 1944 return NULL;
michael@0 1945 }
michael@0 1946
michael@0 1947 /* set up db key */
michael@0 1948 namekey.data = modulus->data;
michael@0 1949 namekey.size = modulus->len;
michael@0 1950
michael@0 1951 pk = seckey_get_private_key(handle, &namekey, NULL, sdbpw);
michael@0 1952
michael@0 1953 /* no need to free dbkey, since its on the stack, and the data it
michael@0 1954 * points to is owned by the database
michael@0 1955 */
michael@0 1956 return(pk);
michael@0 1957 }
michael@0 1958
michael@0 1959 char *
michael@0 1960 nsslowkey_FindKeyNicknameByPublicKey(NSSLOWKEYDBHandle *handle,
michael@0 1961 SECItem *modulus, SDB *sdbpw)
michael@0 1962 {
michael@0 1963 DBT namekey;
michael@0 1964 NSSLOWKEYPrivateKey *pk = NULL;
michael@0 1965 char *nickname = NULL;
michael@0 1966
michael@0 1967 if (handle == NULL) {
michael@0 1968 PORT_SetError(SEC_ERROR_BAD_DATABASE);
michael@0 1969 return NULL;
michael@0 1970 }
michael@0 1971
michael@0 1972 /* set up db key */
michael@0 1973 namekey.data = modulus->data;
michael@0 1974 namekey.size = modulus->len;
michael@0 1975
michael@0 1976 pk = seckey_get_private_key(handle, &namekey, &nickname, sdbpw);
michael@0 1977 if (pk) {
michael@0 1978 lg_nsslowkey_DestroyPrivateKey(pk);
michael@0 1979 }
michael@0 1980
michael@0 1981 /* no need to free dbkey, since its on the stack, and the data it
michael@0 1982 * points to is owned by the database
michael@0 1983 */
michael@0 1984 return(nickname);
michael@0 1985 }
michael@0 1986 /* ===== ENCODING ROUTINES ===== */
michael@0 1987
michael@0 1988 static SECStatus
michael@0 1989 encodePWCheckEntry(PLArenaPool *arena, SECItem *entry, SECOidTag alg,
michael@0 1990 SECItem *encCheck)
michael@0 1991 {
michael@0 1992 SECOidData *oidData;
michael@0 1993 SECStatus rv;
michael@0 1994
michael@0 1995 oidData = SECOID_FindOIDByTag(alg);
michael@0 1996 if ( oidData == NULL ) {
michael@0 1997 rv = SECFailure;
michael@0 1998 goto loser;
michael@0 1999 }
michael@0 2000
michael@0 2001 entry->len = 1 + oidData->oid.len + encCheck->len;
michael@0 2002 if ( arena ) {
michael@0 2003 entry->data = (unsigned char *)PORT_ArenaAlloc(arena, entry->len);
michael@0 2004 } else {
michael@0 2005 entry->data = (unsigned char *)PORT_Alloc(entry->len);
michael@0 2006 }
michael@0 2007
michael@0 2008 if ( entry->data == NULL ) {
michael@0 2009 goto loser;
michael@0 2010 }
michael@0 2011
michael@0 2012 /* first length of oid */
michael@0 2013 entry->data[0] = (unsigned char)oidData->oid.len;
michael@0 2014 /* next oid itself */
michael@0 2015 PORT_Memcpy(&entry->data[1], oidData->oid.data, oidData->oid.len);
michael@0 2016 /* finally the encrypted check string */
michael@0 2017 PORT_Memcpy(&entry->data[1+oidData->oid.len], encCheck->data,
michael@0 2018 encCheck->len);
michael@0 2019
michael@0 2020 return(SECSuccess);
michael@0 2021
michael@0 2022 loser:
michael@0 2023 return(SECFailure);
michael@0 2024 }
michael@0 2025
michael@0 2026
michael@0 2027 #define MAX_DB_SIZE 0xffff
michael@0 2028 /*
michael@0 2029 * Clear out all the keys in the existing database
michael@0 2030 */
michael@0 2031 static SECStatus
michael@0 2032 nsslowkey_ResetKeyDB(NSSLOWKEYDBHandle *handle)
michael@0 2033 {
michael@0 2034 SECStatus rv;
michael@0 2035 int ret;
michael@0 2036 int errors = 0;
michael@0 2037
michael@0 2038 if ( handle->db == NULL ) {
michael@0 2039 return(SECSuccess);
michael@0 2040 }
michael@0 2041
michael@0 2042 if (handle->readOnly) {
michael@0 2043 /* set an error code */
michael@0 2044 return SECFailure;
michael@0 2045 }
michael@0 2046
michael@0 2047 if (handle->appname == NULL && handle->dbname == NULL) {
michael@0 2048 return SECFailure;
michael@0 2049 }
michael@0 2050
michael@0 2051 keydb_Close(handle);
michael@0 2052 if (handle->appname) {
michael@0 2053 handle->db=
michael@0 2054 rdbopen(handle->appname, handle->dbname, "key", NO_CREATE, NULL);
michael@0 2055 } else {
michael@0 2056 handle->db = dbopen( handle->dbname, NO_CREATE, 0600, DB_HASH, 0 );
michael@0 2057 }
michael@0 2058 if (handle->db == NULL) {
michael@0 2059 /* set an error code */
michael@0 2060 return SECFailure;
michael@0 2061 }
michael@0 2062
michael@0 2063 rv = makeGlobalVersion(handle);
michael@0 2064 if ( rv != SECSuccess ) {
michael@0 2065 errors++;
michael@0 2066 goto done;
michael@0 2067 }
michael@0 2068
michael@0 2069 if (handle->global_salt) {
michael@0 2070 rv = StoreKeyDBGlobalSalt(handle, handle->global_salt);
michael@0 2071 } else {
michael@0 2072 rv = makeGlobalSalt(handle);
michael@0 2073 if ( rv == SECSuccess ) {
michael@0 2074 handle->global_salt = GetKeyDBGlobalSalt(handle);
michael@0 2075 }
michael@0 2076 }
michael@0 2077 if ( rv != SECSuccess ) {
michael@0 2078 errors++;
michael@0 2079 }
michael@0 2080
michael@0 2081 done:
michael@0 2082 /* sync the database */
michael@0 2083 ret = keydb_Sync(handle, 0);
michael@0 2084 db_InitComplete(handle->db);
michael@0 2085
michael@0 2086 return (errors == 0 ? SECSuccess : SECFailure);
michael@0 2087 }
michael@0 2088
michael@0 2089 static int
michael@0 2090 keydb_Get(NSSLOWKEYDBHandle *kdb, DBT *key, DBT *data, unsigned int flags)
michael@0 2091 {
michael@0 2092 PRStatus prstat;
michael@0 2093 int ret;
michael@0 2094 PRLock *kdbLock = kdb->lock;
michael@0 2095 DB *db = kdb->db;
michael@0 2096
michael@0 2097 PORT_Assert(kdbLock != NULL);
michael@0 2098 PZ_Lock(kdbLock);
michael@0 2099
michael@0 2100 ret = (* db->get)(db, key, data, flags);
michael@0 2101
michael@0 2102 prstat = PZ_Unlock(kdbLock);
michael@0 2103
michael@0 2104 return(ret);
michael@0 2105 }
michael@0 2106
michael@0 2107 static int
michael@0 2108 keydb_Put(NSSLOWKEYDBHandle *kdb, DBT *key, DBT *data, unsigned int flags)
michael@0 2109 {
michael@0 2110 PRStatus prstat;
michael@0 2111 int ret = 0;
michael@0 2112 PRLock *kdbLock = kdb->lock;
michael@0 2113 DB *db = kdb->db;
michael@0 2114
michael@0 2115 PORT_Assert(kdbLock != NULL);
michael@0 2116 PZ_Lock(kdbLock);
michael@0 2117
michael@0 2118 ret = (* db->put)(db, key, data, flags);
michael@0 2119
michael@0 2120 prstat = PZ_Unlock(kdbLock);
michael@0 2121
michael@0 2122 return(ret);
michael@0 2123 }
michael@0 2124
michael@0 2125 static int
michael@0 2126 keydb_Sync(NSSLOWKEYDBHandle *kdb, unsigned int flags)
michael@0 2127 {
michael@0 2128 PRStatus prstat;
michael@0 2129 int ret;
michael@0 2130 PRLock *kdbLock = kdb->lock;
michael@0 2131 DB *db = kdb->db;
michael@0 2132
michael@0 2133 PORT_Assert(kdbLock != NULL);
michael@0 2134 PZ_Lock(kdbLock);
michael@0 2135
michael@0 2136 ret = (* db->sync)(db, flags);
michael@0 2137
michael@0 2138 prstat = PZ_Unlock(kdbLock);
michael@0 2139
michael@0 2140 return(ret);
michael@0 2141 }
michael@0 2142
michael@0 2143 static int
michael@0 2144 keydb_Del(NSSLOWKEYDBHandle *kdb, DBT *key, unsigned int flags)
michael@0 2145 {
michael@0 2146 PRStatus prstat;
michael@0 2147 int ret;
michael@0 2148 PRLock *kdbLock = kdb->lock;
michael@0 2149 DB *db = kdb->db;
michael@0 2150
michael@0 2151 PORT_Assert(kdbLock != NULL);
michael@0 2152 PZ_Lock(kdbLock);
michael@0 2153
michael@0 2154 ret = (* db->del)(db, key, flags);
michael@0 2155
michael@0 2156 prstat = PZ_Unlock(kdbLock);
michael@0 2157
michael@0 2158 return(ret);
michael@0 2159 }
michael@0 2160
michael@0 2161 static int
michael@0 2162 keydb_Seq(NSSLOWKEYDBHandle *kdb, DBT *key, DBT *data, unsigned int flags)
michael@0 2163 {
michael@0 2164 PRStatus prstat;
michael@0 2165 int ret;
michael@0 2166 PRLock *kdbLock = kdb->lock;
michael@0 2167 DB *db = kdb->db;
michael@0 2168
michael@0 2169 PORT_Assert(kdbLock != NULL);
michael@0 2170 PZ_Lock(kdbLock);
michael@0 2171
michael@0 2172 ret = (* db->seq)(db, key, data, flags);
michael@0 2173
michael@0 2174 prstat = PZ_Unlock(kdbLock);
michael@0 2175
michael@0 2176 return(ret);
michael@0 2177 }
michael@0 2178
michael@0 2179 static void
michael@0 2180 keydb_Close(NSSLOWKEYDBHandle *kdb)
michael@0 2181 {
michael@0 2182 PRStatus prstat;
michael@0 2183 PRLock *kdbLock = kdb->lock;
michael@0 2184 DB *db = kdb->db;
michael@0 2185
michael@0 2186 PORT_Assert(kdbLock != NULL);
michael@0 2187 SKIP_AFTER_FORK(PZ_Lock(kdbLock));
michael@0 2188
michael@0 2189 (* db->close)(db);
michael@0 2190
michael@0 2191 SKIP_AFTER_FORK(prstat = PZ_Unlock(kdbLock));
michael@0 2192
michael@0 2193 return;
michael@0 2194 }
michael@0 2195
michael@0 2196 /*
michael@0 2197 * SDB Entry Points for the Key DB
michael@0 2198 */
michael@0 2199
michael@0 2200 CK_RV
michael@0 2201 lg_GetMetaData(SDB *sdb, const char *id, SECItem *item1, SECItem *item2)
michael@0 2202 {
michael@0 2203 NSSLOWKEYDBHandle *keydb;
michael@0 2204 NSSLOWKEYPasswordEntry entry;
michael@0 2205 SECStatus rv;
michael@0 2206
michael@0 2207 keydb = lg_getKeyDB(sdb);
michael@0 2208 if (keydb == NULL) {
michael@0 2209 return CKR_TOKEN_WRITE_PROTECTED;
michael@0 2210 }
michael@0 2211 if (PORT_Strcmp(id,"password") != 0) {
michael@0 2212 /* shouldn't happen */
michael@0 2213 return CKR_GENERAL_ERROR; /* no extra data stored */
michael@0 2214 }
michael@0 2215 rv = nsslowkey_GetPWCheckEntry(keydb, &entry);
michael@0 2216 if (rv != SECSuccess) {
michael@0 2217 return CKR_GENERAL_ERROR;
michael@0 2218 }
michael@0 2219 item1->len = entry.salt.len;
michael@0 2220 PORT_Memcpy(item1->data, entry.salt.data, item1->len);
michael@0 2221 item2->len = entry.value.len;
michael@0 2222 PORT_Memcpy(item2->data, entry.value.data, item2->len);
michael@0 2223 return CKR_OK;
michael@0 2224 }
michael@0 2225
michael@0 2226 CK_RV
michael@0 2227 lg_PutMetaData(SDB *sdb, const char *id,
michael@0 2228 const SECItem *item1, const SECItem *item2)
michael@0 2229 {
michael@0 2230 NSSLOWKEYDBHandle *keydb;
michael@0 2231 NSSLOWKEYPasswordEntry entry;
michael@0 2232 SECStatus rv;
michael@0 2233
michael@0 2234 keydb = lg_getKeyDB(sdb);
michael@0 2235 if (keydb == NULL) {
michael@0 2236 return CKR_TOKEN_WRITE_PROTECTED;
michael@0 2237 }
michael@0 2238 if (PORT_Strcmp(id,"password") != 0) {
michael@0 2239 /* shouldn't happen */
michael@0 2240 return CKR_GENERAL_ERROR; /* no extra data stored */
michael@0 2241 }
michael@0 2242 entry.salt = *item1;
michael@0 2243 entry.value = *item2;
michael@0 2244 rv = nsslowkey_PutPWCheckEntry(keydb, &entry);
michael@0 2245 if (rv != SECSuccess) {
michael@0 2246 return CKR_GENERAL_ERROR;
michael@0 2247 }
michael@0 2248 return CKR_OK;
michael@0 2249 }
michael@0 2250
michael@0 2251 CK_RV
michael@0 2252 lg_Reset(SDB *sdb)
michael@0 2253 {
michael@0 2254 NSSLOWKEYDBHandle *keydb;
michael@0 2255 SECStatus rv;
michael@0 2256
michael@0 2257 keydb = lg_getKeyDB(sdb);
michael@0 2258 if (keydb == NULL) {
michael@0 2259 return CKR_TOKEN_WRITE_PROTECTED;
michael@0 2260 }
michael@0 2261 rv = nsslowkey_ResetKeyDB(keydb);
michael@0 2262 if (rv != SECSuccess) {
michael@0 2263 return CKR_GENERAL_ERROR;
michael@0 2264 }
michael@0 2265 return CKR_OK;
michael@0 2266 }
michael@0 2267

mercurial