PageRenderTime 73ms CodeModel.GetById 18ms app.highlight 46ms RepoModel.GetById 1ms app.codeStats 0ms

/security/nss/lib/softoken/sftkpwd.c

http://github.com/zpao/v8monkey
C | 1309 lines | 852 code | 146 blank | 311 comment | 223 complexity | 15f61d591c97af3a2408162757da1b0f MD5 | raw file
   1/* ***** BEGIN LICENSE BLOCK *****
   2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
   3 *
   4 * The contents of this file are subject to the Mozilla Public License Version
   5 * 1.1 (the "License"); you may not use this file except in compliance with
   6 * the License. You may obtain a copy of the License at
   7 * http://www.mozilla.org/MPL/
   8 *
   9 * Software distributed under the License is distributed on an "AS IS" basis,
  10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  11 * for the specific language governing rights and limitations under the
  12 * License.
  13 *
  14 * The Original Code is the Netscape security libraries.
  15 *
  16 * The Initial Developer of the Original Code is
  17 * Netscape Communications Corporation.
  18 * Portions created by the Initial Developer are Copyright (C) 1994-2007
  19 * the Initial Developer. All Rights Reserved.
  20 *
  21 * Contributor(s):
  22 *
  23 * Alternatively, the contents of this file may be used under the terms of
  24 * either the GNU General Public License Version 2 or later (the "GPL"), or
  25 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  26 * in which case the provisions of the GPL or the LGPL are applicable instead
  27 * of those above. If you wish to allow use of your version of this file only
  28 * under the terms of either the GPL or the LGPL, and not to allow others to
  29 * use your version of this file under the terms of the MPL, indicate your
  30 * decision by deleting the provisions above and replace them with the notice
  31 * and other provisions required by the GPL or the LGPL. If you do not delete
  32 * the provisions above, a recipient may use your version of this file under
  33 * the terms of any one of the MPL, the GPL or the LGPL.
  34 *
  35 * ***** END LICENSE BLOCK ***** */
  36/* 
  37 *  The following code handles the storage of PKCS 11 modules used by the
  38 * NSS. For the rest of NSS, only one kind of database handle exists:
  39 *
  40 *     SFTKDBHandle
  41 *
  42 * There is one SFTKDBHandle for the each key database and one for each cert 
  43 * database. These databases are opened as associated pairs, one pair per
  44 * slot. SFTKDBHandles are reference counted objects.
  45 *
  46 * Each SFTKDBHandle points to a low level database handle (SDB). This handle
  47 * represents the underlying physical database. These objects are not 
  48 * reference counted, an are 'owned' by their respective SFTKDBHandles.
  49 *
  50 *  
  51 */
  52#include "sftkdb.h"
  53#include "sftkdbti.h"
  54#include "pkcs11t.h"
  55#include "pkcs11i.h"
  56#include "sdb.h"
  57#include "prprf.h" 
  58#include "secmodt.h"
  59#include "sftkpars.h"
  60#include "pratom.h"
  61#include "blapi.h"
  62#include "secoid.h"
  63#include "sechash.h"
  64#include "lowpbe.h"
  65#include "secdert.h"
  66#include "prsystem.h"
  67#include "lgglue.h"
  68#include "secerr.h"
  69#include "softoken.h"
  70  
  71/******************************************************************
  72 * 
  73 * Key DB password handling functions
  74 *
  75 * These functions manage the key db password (set, reset, initialize, use).
  76 *
  77 * The key is managed on 'this side' of the database. All private data is
  78 * encrypted before it is sent to the database itself. Besides PBE's, the
  79 * database management code can also mix in various fixed keys so the data
  80 * in the database is no longer considered 'plain text'.
  81 */
  82
  83
  84/* take string password and turn it into a key. The key is dependent
  85 * on a global salt entry acquired from the database. This salted
  86 * value will be based to a pkcs5 pbe function before it is used
  87 * in an actual encryption */
  88static SECStatus
  89sftkdb_passwordToKey(SFTKDBHandle *keydb, SECItem *salt,
  90			const char *pw, SECItem *key)
  91{
  92    SHA1Context *cx = NULL;
  93    SECStatus rv = SECFailure;
  94
  95    key->data = PORT_Alloc(SHA1_LENGTH);
  96    if (key->data == NULL) {
  97	goto loser;
  98    }
  99    key->len = SHA1_LENGTH;
 100
 101    cx = SHA1_NewContext();
 102    if ( cx == NULL) {
 103	goto loser;
 104    }
 105    SHA1_Begin(cx);
 106    if (salt  && salt->data ) {
 107	SHA1_Update(cx, salt->data, salt->len);
 108    }
 109    SHA1_Update(cx, (unsigned char *)pw, PORT_Strlen(pw));
 110    SHA1_End(cx, key->data, &key->len, key->len);
 111    rv = SECSuccess;
 112    
 113loser:
 114    if (cx) {
 115	SHA1_DestroyContext(cx, PR_TRUE);
 116    }
 117    if (rv != SECSuccess) {
 118	if (key->data != NULL) {
 119	    PORT_ZFree(key->data,key->len);
 120	}
 121	key->data = NULL;
 122    }
 123    return rv;
 124}
 125
 126/*
 127 * Cipher text stored in the database contains 3 elements:
 128 * 1) an identifier describing the encryption algorithm.
 129 * 2) an entry specific salt value.
 130 * 3) the encrypted value.
 131 *
 132 * The following data structure represents the encrypted data in a decoded
 133 * (but still encrypted) form.
 134 */
 135typedef struct sftkCipherValueStr sftkCipherValue;
 136struct sftkCipherValueStr {
 137    PLArenaPool *arena;
 138    SECOidTag  alg;
 139    NSSPKCS5PBEParameter *param;
 140    SECItem    salt;
 141    SECItem    value;
 142};
 143
 144#define SFTK_CIPHERTEXT_VERSION 3
 145
 146struct SFTKDBEncryptedDataInfoStr {
 147    SECAlgorithmID algorithm;
 148    SECItem encryptedData;
 149};
 150typedef struct SFTKDBEncryptedDataInfoStr SFTKDBEncryptedDataInfo;
 151
 152SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate)
 153
 154const SEC_ASN1Template sftkdb_EncryptedDataInfoTemplate[] = {
 155    { SEC_ASN1_SEQUENCE,
 156        0, NULL, sizeof(SFTKDBEncryptedDataInfo) },
 157    { SEC_ASN1_INLINE | SEC_ASN1_XTRN ,
 158        offsetof(SFTKDBEncryptedDataInfo,algorithm),
 159        SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
 160    { SEC_ASN1_OCTET_STRING,
 161        offsetof(SFTKDBEncryptedDataInfo,encryptedData) },
 162    { 0 }
 163};
 164
 165/*
 166 * This parses the cipherText into cipher value. NOTE: cipherValue will point
 167 * to data in cipherText, if cipherText is freed, cipherValue will be invalid.
 168 */
 169static SECStatus
 170sftkdb_decodeCipherText(SECItem *cipherText, sftkCipherValue *cipherValue)
 171{
 172    PLArenaPool *arena = NULL;
 173    SFTKDBEncryptedDataInfo edi;
 174    SECStatus rv;
 175
 176    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
 177    if (arena == NULL) {
 178	return SECFailure;
 179    }
 180    cipherValue->arena = NULL;
 181    cipherValue->param = NULL;
 182
 183    rv = SEC_QuickDERDecodeItem(arena, &edi, sftkdb_EncryptedDataInfoTemplate,
 184                            cipherText);
 185    if (rv != SECSuccess) {
 186	goto loser;
 187    }
 188    cipherValue->alg = SECOID_GetAlgorithmTag(&edi.algorithm);
 189    cipherValue->param = nsspkcs5_AlgidToParam(&edi.algorithm);
 190    if (cipherValue->param == NULL) {
 191	goto loser;
 192    }
 193    cipherValue->value = edi.encryptedData;
 194    cipherValue->arena = arena;
 195
 196    return SECSuccess;
 197loser:
 198    if (cipherValue->param) {
 199	nsspkcs5_DestroyPBEParameter(cipherValue->param);
 200	cipherValue->param = NULL;
 201    }
 202    if (arena) {
 203	PORT_FreeArena(arena,PR_FALSE);
 204    }
 205    return SECFailure;
 206}
 207
 208
 209
 210/* 
 211 * unlike decode, Encode actually allocates a SECItem the caller must free
 212 * The caller can pass an optional arena to to indicate where to place
 213 * the resultant cipherText.
 214 */
 215static SECStatus
 216sftkdb_encodeCipherText(PLArenaPool *arena, sftkCipherValue *cipherValue, 
 217                        SECItem **cipherText)
 218{
 219    SFTKDBEncryptedDataInfo edi;
 220    SECAlgorithmID *algid;
 221    SECStatus rv;
 222    PLArenaPool *localArena = NULL;
 223
 224
 225    localArena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
 226    if (localArena == NULL) {
 227	return SECFailure;
 228    }
 229
 230    algid = nsspkcs5_CreateAlgorithmID(localArena, cipherValue->alg, 
 231					cipherValue->param);
 232    if (algid == NULL) {
 233	rv = SECFailure;
 234	goto loser;
 235    }
 236    rv = SECOID_CopyAlgorithmID(localArena, &edi.algorithm, algid);
 237    SECOID_DestroyAlgorithmID(algid, PR_TRUE);
 238    if (rv != SECSuccess) {
 239	goto loser;
 240    }
 241    edi.encryptedData = cipherValue->value;
 242
 243    *cipherText = SEC_ASN1EncodeItem(arena, NULL, &edi, 
 244				    sftkdb_EncryptedDataInfoTemplate);
 245    if (*cipherText == NULL) {
 246	rv = SECFailure;
 247    }
 248
 249loser:
 250    if (localArena) {
 251	PORT_FreeArena(localArena,PR_FALSE);
 252    }
 253
 254    return rv;
 255}
 256
 257
 258/*
 259 * Use our key to decode a cipherText block from the database.
 260 *
 261 * plain text is allocated by nsspkcs5_CipherData and must be freed
 262 * with SECITEM_FreeItem by the caller.
 263 */
 264SECStatus
 265sftkdb_DecryptAttribute(SECItem *passKey, SECItem *cipherText, SECItem **plain) 
 266{
 267    SECStatus rv;
 268    sftkCipherValue cipherValue;
 269
 270    /* First get the cipher type */
 271    rv = sftkdb_decodeCipherText(cipherText, &cipherValue);
 272    if (rv != SECSuccess) {
 273	goto loser;
 274    }
 275
 276    *plain = nsspkcs5_CipherData(cipherValue.param, passKey, &cipherValue.value, 
 277				    PR_FALSE, NULL);
 278    if (*plain == NULL) {
 279	rv = SECFailure;
 280	goto loser;
 281    } 
 282
 283loser:
 284    if (cipherValue.param) {
 285	nsspkcs5_DestroyPBEParameter(cipherValue.param);
 286    }
 287    if (cipherValue.arena) {
 288	PORT_FreeArena(cipherValue.arena,PR_FALSE);
 289    }
 290    return rv;
 291}
 292
 293/*
 294 * encrypt a block. This function returned the encrypted ciphertext which
 295 * the caller must free. If the caller provides an arena, cipherText will
 296 * be allocated out of that arena. This also generated the per entry
 297 * salt automatically.
 298 */
 299SECStatus
 300sftkdb_EncryptAttribute(PLArenaPool *arena, SECItem *passKey, 
 301		SECItem *plainText, SECItem **cipherText) 
 302{
 303    SECStatus rv;
 304    sftkCipherValue cipherValue;
 305    SECItem *cipher = NULL;
 306    NSSPKCS5PBEParameter *param = NULL;
 307    unsigned char saltData[HASH_LENGTH_MAX];
 308
 309    cipherValue.alg = SEC_OID_PKCS12_PBE_WITH_SHA1_AND_TRIPLE_DES_CBC;
 310    cipherValue.salt.len = SHA1_LENGTH;
 311    cipherValue.salt.data = saltData;
 312    RNG_GenerateGlobalRandomBytes(saltData,cipherValue.salt.len);
 313
 314    param = nsspkcs5_NewParam(cipherValue.alg, &cipherValue.salt, 1);
 315    if (param == NULL) {
 316	rv = SECFailure;
 317	goto loser;
 318    }
 319    cipher = nsspkcs5_CipherData(param, passKey, plainText, PR_TRUE, NULL);
 320    if (cipher == NULL) {
 321	rv = SECFailure;
 322	goto loser;
 323    } 
 324    cipherValue.value = *cipher;
 325    cipherValue.param = param;
 326
 327    rv = sftkdb_encodeCipherText(arena, &cipherValue, cipherText);
 328    if (rv != SECSuccess) {
 329	goto loser;
 330    }
 331
 332loser:
 333    if (cipher) {
 334	SECITEM_FreeItem(cipher, PR_TRUE);
 335    }
 336    if (param) {
 337	nsspkcs5_DestroyPBEParameter(param);
 338    }
 339    return rv;
 340}
 341
 342/*
 343 * use the password and the pbe parameters to generate an HMAC for the
 344 * given plain text data. This is used by sftkdb_VerifyAttribute and
 345 * sftkdb_SignAttribute. Signature is returned in signData. The caller
 346 * must preallocate the space in the secitem.
 347 */
 348static SECStatus
 349sftkdb_pbehash(SECOidTag sigOid, SECItem *passKey, 
 350	       NSSPKCS5PBEParameter *param,
 351	       CK_OBJECT_HANDLE objectID, CK_ATTRIBUTE_TYPE attrType,
 352	       SECItem *plainText, SECItem *signData)
 353{
 354    SECStatus rv = SECFailure;
 355    SECItem *key = NULL;
 356    HMACContext *hashCx = NULL;
 357    HASH_HashType hashType = HASH_AlgNULL;
 358    const SECHashObject *hashObj;
 359    unsigned char addressData[SDB_ULONG_SIZE];
 360
 361    hashType = HASH_FromHMACOid(param->encAlg);
 362    if (hashType == HASH_AlgNULL) {
 363	PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
 364	return SECFailure;
 365    }
 366
 367    hashObj = HASH_GetRawHashObject(hashType);
 368    if (hashObj == NULL) {
 369	goto loser;
 370    }
 371
 372    key = nsspkcs5_ComputeKeyAndIV(param, passKey, NULL, PR_FALSE);
 373    if (!key) {
 374	goto loser;
 375    }
 376
 377    hashCx = HMAC_Create(hashObj, key->data, key->len, PR_TRUE);
 378    if (!hashCx) {
 379	goto loser;
 380    }
 381    HMAC_Begin(hashCx);
 382    /* Tie this value to a particular object. This is most important for
 383     * the trust attributes, where and attacker could copy a value for
 384     * 'validCA' from another cert in the database */
 385    sftk_ULong2SDBULong(addressData, objectID);
 386    HMAC_Update(hashCx, addressData, SDB_ULONG_SIZE);
 387    sftk_ULong2SDBULong(addressData, attrType);
 388    HMAC_Update(hashCx, addressData, SDB_ULONG_SIZE);
 389
 390    HMAC_Update(hashCx, plainText->data, plainText->len);
 391    rv = HMAC_Finish(hashCx, signData->data, &signData->len, signData->len);
 392
 393loser:
 394    if (hashCx) {
 395	HMAC_Destroy(hashCx, PR_TRUE);
 396    }
 397    if (key) {
 398	SECITEM_FreeItem(key,PR_TRUE);
 399    }
 400    return rv;
 401}
 402
 403/*
 404 * Use our key to verify a signText block from the database matches
 405 * the plainText from the database. The signText is a PKCS 5 v2 pbe.
 406 * plainText is the plainText of the attribute.
 407 */
 408SECStatus
 409sftkdb_VerifyAttribute(SECItem *passKey, CK_OBJECT_HANDLE objectID, 
 410	     CK_ATTRIBUTE_TYPE attrType, 
 411	     SECItem *plainText, SECItem *signText) 
 412{
 413    SECStatus rv;
 414    sftkCipherValue signValue;
 415    SECItem signature;
 416    unsigned char signData[HASH_LENGTH_MAX];
 417    
 418
 419    /* First get the cipher type */
 420    rv = sftkdb_decodeCipherText(signText, &signValue);
 421    if (rv != SECSuccess) {
 422	goto loser;
 423    }
 424    signature.data = signData;
 425    signature.len = sizeof(signData);
 426
 427    rv = sftkdb_pbehash(signValue.alg, passKey, signValue.param, 
 428			objectID, attrType, plainText, &signature);
 429    if (rv != SECSuccess) {
 430	goto loser;
 431    }
 432    if (SECITEM_CompareItem(&signValue.value,&signature) != 0) {
 433	PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
 434	rv = SECFailure;
 435    }
 436
 437loser:
 438    if (signValue.param) {
 439	nsspkcs5_DestroyPBEParameter(signValue.param);
 440    }
 441    if (signValue.arena) {
 442	PORT_FreeArena(signValue.arena,PR_FALSE);
 443    }
 444    return rv;
 445}
 446
 447/*
 448 * Use our key to create a signText block the plain text of an
 449 * attribute. The signText is a PKCS 5 v2 pbe.
 450 */
 451SECStatus
 452sftkdb_SignAttribute(PLArenaPool *arena, SECItem *passKey, 
 453	 CK_OBJECT_HANDLE objectID, CK_ATTRIBUTE_TYPE attrType, 
 454	 SECItem *plainText, SECItem **signature) 
 455{
 456    SECStatus rv;
 457    sftkCipherValue signValue;
 458    NSSPKCS5PBEParameter *param = NULL;
 459    unsigned char saltData[HASH_LENGTH_MAX];
 460    unsigned char signData[HASH_LENGTH_MAX];
 461    SECOidTag hmacAlg = SEC_OID_HMAC_SHA256; /* hash for authentication */
 462    SECOidTag prfAlg = SEC_OID_HMAC_SHA256;  /* hash for pb key generation */
 463    HASH_HashType prfType;
 464    unsigned int hmacLength;
 465    unsigned int prfLength;
 466
 467    /* this code allows us to fetch the lengths and hashes on the fly
 468     * by simply changing the OID above */
 469    prfType = HASH_FromHMACOid(prfAlg);
 470    PORT_Assert(prfType != HASH_AlgNULL);
 471    prfLength = HASH_GetRawHashObject(prfType)->length;
 472    PORT_Assert(prfLength <= HASH_LENGTH_MAX);
 473
 474    hmacLength = HASH_GetRawHashObject(HASH_FromHMACOid(hmacAlg))->length;
 475    PORT_Assert(hmacLength <= HASH_LENGTH_MAX);
 476
 477    /* initialize our CipherValue structure */
 478    signValue.alg = SEC_OID_PKCS5_PBMAC1;
 479    signValue.salt.len = prfLength;
 480    signValue.salt.data = saltData;
 481    signValue.value.data = signData;
 482    signValue.value.len = hmacLength;
 483    RNG_GenerateGlobalRandomBytes(saltData,prfLength);
 484
 485    /* initialize our pkcs5 parameter */
 486    param = nsspkcs5_NewParam(signValue.alg, &signValue.salt, 1);
 487    if (param == NULL) {
 488	rv = SECFailure;
 489	goto loser;
 490    }
 491    param->keyID = pbeBitGenIntegrityKey;
 492    /* set the PKCS 5 v2 parameters, not extractable from the
 493     * data passed into nsspkcs5_NewParam */
 494    param->encAlg = hmacAlg;
 495    param->hashType = prfType;
 496    param->keyLen = hmacLength;
 497    rv = SECOID_SetAlgorithmID(param->poolp, &param->prfAlg, prfAlg, NULL);
 498    if (rv != SECSuccess) {
 499	goto loser;
 500    }
 501
 502
 503    /* calculate the mac */
 504    rv = sftkdb_pbehash(signValue.alg, passKey, param, objectID, attrType,
 505			plainText, &signValue.value);
 506    if (rv != SECSuccess) {
 507	goto loser;
 508    }
 509    signValue.param = param;
 510
 511    /* write it out */
 512    rv = sftkdb_encodeCipherText(arena, &signValue, signature);
 513    if (rv != SECSuccess) {
 514	goto loser;
 515    }
 516
 517loser:
 518    if (param) {
 519	nsspkcs5_DestroyPBEParameter(param);
 520    }
 521    return rv;
 522}
 523
 524/*
 525 * safely swith the passed in key for the one caches in the keydb handle
 526 * 
 527 * A key attached to the handle tells us the the token is logged in.
 528 * We can used the key attached to the handle in sftkdb_EncryptAttribute 
 529 *  and sftkdb_DecryptAttribute calls.
 530 */  
 531static void 
 532sftkdb_switchKeys(SFTKDBHandle *keydb, SECItem *passKey)
 533{
 534    unsigned char *data;
 535    int len;
 536
 537    if (keydb->passwordLock == NULL) {
 538	PORT_Assert(keydb->type != SFTK_KEYDB_TYPE);
 539	return;
 540    }
 541
 542    /* an atomic pointer set would be nice */
 543    SKIP_AFTER_FORK(PZ_Lock(keydb->passwordLock));
 544    data = keydb->passwordKey.data;
 545    len = keydb->passwordKey.len;
 546    keydb->passwordKey.data = passKey->data;
 547    keydb->passwordKey.len = passKey->len;
 548    passKey->data = data;
 549    passKey->len = len;
 550    SKIP_AFTER_FORK(PZ_Unlock(keydb->passwordLock));
 551}
 552
 553/*
 554 * returns true if we are in a middle of a merge style update.
 555 */
 556PRBool
 557sftkdb_InUpdateMerge(SFTKDBHandle *keydb)
 558{
 559    return keydb->updateID ? PR_TRUE : PR_FALSE;
 560}
 561
 562/*
 563 * returns true if we are looking for the password for the user's old source
 564 * database as part of a merge style update.
 565 */
 566PRBool
 567sftkdb_NeedUpdateDBPassword(SFTKDBHandle *keydb)
 568{
 569    if (!sftkdb_InUpdateMerge(keydb)) {
 570	return PR_FALSE;
 571    }
 572    if (keydb->updateDBIsInit && !keydb->updatePasswordKey) {
 573	return PR_TRUE;
 574    }
 575    return PR_FALSE;
 576}
 577
 578/*
 579 * fetch an update password key from a handle.
 580 */
 581SECItem *
 582sftkdb_GetUpdatePasswordKey(SFTKDBHandle *handle)
 583{
 584    SECItem *key = NULL;
 585
 586    /* if we're a cert db, fetch it from our peer key db */
 587    if (handle->type == SFTK_CERTDB_TYPE) {
 588	handle = handle->peerDB;
 589    }
 590
 591    /* don't have one */
 592    if (!handle) {
 593	return NULL;
 594    }
 595
 596    PZ_Lock(handle->passwordLock);
 597    if (handle->updatePasswordKey) {
 598	key = SECITEM_DupItem(handle->updatePasswordKey);
 599    }
 600    PZ_Unlock(handle->passwordLock);
 601
 602    return key;
 603}
 604
 605/*
 606 * free the update password key from a handle.
 607 */
 608void
 609sftkdb_FreeUpdatePasswordKey(SFTKDBHandle *handle)
 610{
 611    SECItem *key = NULL;
 612
 613    /* don't have one */
 614    if (!handle) {
 615	return;
 616    }
 617
 618    /* if we're a cert db, we don't have one */
 619    if (handle->type == SFTK_CERTDB_TYPE) {
 620	return;
 621    }
 622
 623    PZ_Lock(handle->passwordLock);
 624    if (handle->updatePasswordKey) {
 625	key = handle->updatePasswordKey;
 626	handle->updatePasswordKey = NULL;
 627    }
 628    PZ_Unlock(handle->passwordLock);
 629
 630    if (key) {
 631	SECITEM_ZfreeItem(key, PR_TRUE);
 632    }
 633
 634    return;
 635}
 636
 637/*
 638 * what password db we use depends heavily on the update state machine
 639 * 
 640 *  1) no update db, return the normal database.
 641 *  2) update db and no merge return the update db.
 642 *  3) update db and in merge: 
 643 *      return the update db if we need the update db's password, 
 644 *      otherwise return our normal datbase.
 645 */
 646static SDB *
 647sftk_getPWSDB(SFTKDBHandle *keydb)
 648{
 649    if (!keydb->update) {
 650	return keydb->db;
 651    }
 652    if (!sftkdb_InUpdateMerge(keydb)) {
 653	return keydb->update;
 654    }
 655    if (sftkdb_NeedUpdateDBPassword(keydb)) {
 656	return keydb->update;
 657    }
 658    return keydb->db;
 659}
 660
 661/*
 662 * return success if we have a valid password entry.
 663 * This is will show up outside of PKCS #11 as CKF_USER_PIN_INIT
 664 * in the token flags.
 665 */
 666SECStatus 
 667sftkdb_HasPasswordSet(SFTKDBHandle *keydb)
 668{
 669    SECItem salt, value;
 670    unsigned char saltData[SDB_MAX_META_DATA_LEN];
 671    unsigned char valueData[SDB_MAX_META_DATA_LEN];
 672    CK_RV crv;
 673    SDB *db;
 674
 675    if (keydb == NULL) {
 676	return SECFailure;
 677    }
 678
 679    db = sftk_getPWSDB(keydb);
 680    if (db == NULL) {
 681	return SECFailure;
 682    }
 683
 684    salt.data = saltData;
 685    salt.len = sizeof(saltData);
 686    value.data = valueData;
 687    value.len = sizeof(valueData);
 688    crv = (*db->sdb_GetMetaData)(db, "password", &salt, &value);
 689
 690    /* If no password is set, we can update right away */
 691    if (((keydb->db->sdb_flags & SDB_RDONLY) == 0) && keydb->update 
 692	&& crv != CKR_OK) {
 693	/* update the peer certdb if it exists */
 694	if (keydb->peerDB) {
 695	    sftkdb_Update(keydb->peerDB, NULL);
 696	}
 697	sftkdb_Update(keydb, NULL);
 698    }
 699    return (crv == CKR_OK) ? SECSuccess : SECFailure;
 700}
 701
 702#define SFTK_PW_CHECK_STRING "password-check"
 703#define SFTK_PW_CHECK_LEN 14
 704
 705/*
 706 * check if the supplied password is valid
 707 */
 708SECStatus  
 709sftkdb_CheckPassword(SFTKDBHandle *keydb, const char *pw, PRBool *tokenRemoved)
 710{
 711    SECStatus rv;
 712    SECItem salt, value;
 713    unsigned char saltData[SDB_MAX_META_DATA_LEN];
 714    unsigned char valueData[SDB_MAX_META_DATA_LEN];
 715    SECItem key;
 716    SECItem *result = NULL;
 717    SDB *db;
 718    CK_RV crv;
 719
 720    if (keydb == NULL) {
 721	return SECFailure;
 722    }
 723
 724    db = sftk_getPWSDB(keydb);
 725    if (db == NULL) {
 726	return SECFailure;
 727    }
 728
 729    key.data = NULL;
 730    key.len = 0;
 731
 732    if (pw == NULL) pw="";
 733
 734    /* get the entry from the database */
 735    salt.data = saltData;
 736    salt.len = sizeof(saltData);
 737    value.data = valueData;
 738    value.len = sizeof(valueData);
 739    crv = (*db->sdb_GetMetaData)(db, "password", &salt, &value);
 740    if (crv != CKR_OK) {
 741	rv = SECFailure;
 742	goto done;
 743    }
 744
 745    /* get our intermediate key based on the entry salt value */
 746    rv = sftkdb_passwordToKey(keydb, &salt, pw, &key);
 747    if (rv != SECSuccess) {
 748	goto done;
 749    }
 750
 751    /* decrypt the entry value */
 752    rv = sftkdb_DecryptAttribute(&key, &value, &result);
 753    if (rv != SECSuccess) {
 754	goto done;
 755    }
 756
 757    /* if it's what we expect, update our key in the database handle and
 758     * return Success */
 759    if ((result->len == SFTK_PW_CHECK_LEN) &&
 760      PORT_Memcmp(result->data, SFTK_PW_CHECK_STRING, SFTK_PW_CHECK_LEN) == 0){
 761	/*
 762	 * We have a password, now lets handle any potential update cases..
 763	 * 
 764	 * First, the normal case: no update. In this case we only need the
 765	 *  the password for our only DB, which we now have, we switch 
 766	 *  the keys and fall through.
 767	 * Second regular (non-merge) update: The target DB does not yet have
 768	 *  a password initialized, we now have the password for the source DB,
 769	 *  so we can switch the keys and simply update the target database.
 770	 * Merge update case: This one is trickier.
 771	 *   1) If we need the source DB password, then we just got it here.
 772	 *       We need to save that password,
 773	 *       then we need to check to see if we need or have the target 
 774	 *         database password.
 775	 *       If we have it (it's the same as the source), or don't need 
 776	 *         it (it's not set or is ""), we can start the update now.
 777	 *       If we don't have it, we need the application to get it from 
 778	 *         the user. Clear our sessions out to simulate a token 
 779	 *         removal. C_GetTokenInfo will change the token description 
 780	 *         and the token will still appear to be logged out.
 781	 *   2) If we already have the source DB  password, this password is 
 782	 *         for the target database. We can now move forward with the 
 783	 *         update, as we now have both required passwords.
 784	 *
 785	 */
 786        PZ_Lock(keydb->passwordLock);
 787	if (sftkdb_NeedUpdateDBPassword(keydb)) {
 788	    /* Squirrel this special key away.
 789	     * This has the side effect of turning sftkdb_NeedLegacyPW off,
 790	     * as well as changing which database is returned from 
 791	     * SFTK_GET_PW_DB (thus effecting both sftkdb_CheckPassword()
 792	     * and sftkdb_HasPasswordSet()) */
 793	    keydb->updatePasswordKey = SECITEM_DupItem(&key);
 794	    PZ_Unlock(keydb->passwordLock);
 795	    if (keydb->updatePasswordKey == NULL) {
 796		/* PORT_Error set by SECITEM_DupItem */
 797		rv = SECFailure;
 798		goto done;
 799	    }
 800
 801	    /* Simulate a token removal -- we need to do this any
 802             * any case at this point so the token name is correct. */
 803	    *tokenRemoved = PR_TRUE;
 804
 805	    /* 
 806	     * OK, we got the update DB password, see if we need a password
 807	     * for the target...
 808	     */
 809	    if (sftkdb_HasPasswordSet(keydb) == SECSuccess) {
 810		/* We have a password, do we know what the password is?
 811		 *  check 1) for the password the user supplied for the 
 812		 *           update DB,
 813		 *    and 2) for the null password.
 814		 *
 815		 * RECURSION NOTE: we are calling ourselves here. This means
 816		 *  any updates, switchKeys, etc will have been completed
 817		 *  if these functions return successfully, in those cases
 818		 *  just exit returning Success. We don't recurse infinitely
 819		 *  because we are making this call from a NeedUpdateDBPassword
 820		 *  block and we've already set that update password at this
 821		 *  point.  */
 822		rv = sftkdb_CheckPassword(keydb, pw, tokenRemoved);
 823		if (rv == SECSuccess) {
 824		    /* source and target databases have the same password, we 
 825		     * are good to go */
 826		    goto done;
 827		}
 828		sftkdb_CheckPassword(keydb, "", tokenRemoved);
 829
 830		/*
 831		 * Important 'NULL' code here. At this point either we 
 832		 * succeeded in logging in with "" or we didn't.
 833                 *
 834                 *  If we did succeed at login, our machine state will be set
 835		 * to logged in appropriately. The application will find that 
 836		 * it's logged in as soon as it opens a new session. We have 
 837		 * also completed the update. Life is good.
 838		 * 
 839		 *  If we did not succeed, well the user still successfully
 840		 * logged into the update database, since we faked the token 
 841		 * removal it's just like the user logged into his smart card 
 842		 * then removed it. the actual login work, so we report that 
 843		 * success back to the user, but we won't actually be
 844		 * logged in. The application will find this out when it
 845		 * checks it's login state, thus triggering another password
 846		 * prompt so we can get the real target DB password.
 847		 *
 848		 * summary, we exit from here with SECSuccess no matter what.
 849		 */
 850		rv = SECSuccess;
 851		goto done;
 852	    } else {
 853		/* there is no password, just fall through to update.
 854		 * update will write the source DB's password record
 855		 * into the target DB just like it would in a non-merge
 856		 * update case. */
 857	    }
 858	} else {
 859	    PZ_Unlock(keydb->passwordLock);
 860	}
 861	/* load the keys, so the keydb can parse it's key set */
 862	sftkdb_switchKeys(keydb, &key);
 863
 864	/* we need to update, do it now */
 865	if (((keydb->db->sdb_flags & SDB_RDONLY) == 0) && keydb->update) {
 866	    /* update the peer certdb if it exists */
 867	    if (keydb->peerDB) {
 868		sftkdb_Update(keydb->peerDB, &key);
 869	    }
 870	    sftkdb_Update(keydb, &key);
 871	}
 872    } else {
 873        rv = SECFailure;
 874	/*PORT_SetError( bad password); */
 875    }
 876
 877done:
 878    if (key.data) {
 879	PORT_ZFree(key.data,key.len);
 880    }
 881    if (result) {
 882	SECITEM_FreeItem(result,PR_TRUE);
 883    }
 884    return rv;
 885}
 886
 887/*
 888 * return Success if the there is a cached password key.
 889 */
 890SECStatus
 891sftkdb_PWCached(SFTKDBHandle *keydb)
 892{
 893    return keydb->passwordKey.data ? SECSuccess : SECFailure;
 894}
 895
 896
 897static CK_RV
 898sftk_updateMacs(PLArenaPool *arena, SFTKDBHandle *handle,
 899		       CK_OBJECT_HANDLE id, SECItem *newKey)
 900{
 901    CK_RV crv = CKR_OK;
 902    CK_RV crv2;
 903    CK_ATTRIBUTE authAttrs[] = {
 904	{CKA_MODULUS, NULL, 0},
 905	{CKA_PUBLIC_EXPONENT, NULL, 0},
 906	{CKA_CERT_SHA1_HASH, NULL, 0},
 907	{CKA_CERT_MD5_HASH, NULL, 0},
 908	{CKA_TRUST_SERVER_AUTH, NULL, 0},
 909	{CKA_TRUST_CLIENT_AUTH, NULL, 0},
 910	{CKA_TRUST_EMAIL_PROTECTION, NULL, 0},
 911	{CKA_TRUST_CODE_SIGNING, NULL, 0},
 912	{CKA_TRUST_STEP_UP_APPROVED, NULL, 0},
 913	{CKA_NSS_OVERRIDE_EXTENSIONS, NULL, 0},
 914    };
 915    CK_ULONG authAttrCount = sizeof(authAttrs)/sizeof(CK_ATTRIBUTE);
 916    int i, count;
 917    SFTKDBHandle *keyHandle = handle;
 918    SDB *keyTarget = NULL;
 919
 920    id &= SFTK_OBJ_ID_MASK;
 921
 922    if (handle->type != SFTK_KEYDB_TYPE) {
 923	keyHandle = handle->peerDB;
 924    }
 925
 926    if (keyHandle == NULL) {
 927	return CKR_OK;
 928    }
 929
 930    /* old DB's don't have meta data, finished with MACs */
 931    keyTarget = SFTK_GET_SDB(keyHandle);
 932    if ((keyTarget->sdb_flags &SDB_HAS_META) == 0) {
 933	return CKR_OK;
 934    }
 935
 936    /*
 937     * STEP 1: find the MACed attributes of this object 
 938     */
 939    crv2 = sftkdb_GetAttributeValue(handle, id, authAttrs, authAttrCount);
 940    count = 0;
 941    /* allocate space for the attributes */
 942    for (i=0; i < authAttrCount; i++) {
 943	if ((authAttrs[i].ulValueLen == -1) || (authAttrs[i].ulValueLen == 0)){
 944	    continue;
 945	}
 946	count++;
 947        authAttrs[i].pValue = PORT_ArenaAlloc(arena,authAttrs[i].ulValueLen);
 948	if (authAttrs[i].pValue == NULL) {
 949	    crv = CKR_HOST_MEMORY;
 950	    break;
 951	}
 952    }
 953
 954    /* if count was zero, none were found, finished with MACs */
 955    if (count == 0) {
 956	return CKR_OK;
 957    }
 958
 959    crv = sftkdb_GetAttributeValue(handle, id, authAttrs, authAttrCount);
 960    /* ignore error code, we expect some possible errors */
 961
 962    /* GetAttributeValue just verified the old macs, safe to write
 963     * them out then... */
 964    for (i=0; i < authAttrCount; i++) {
 965	SECItem *signText;
 966	SECItem plainText;
 967	SECStatus rv;
 968
 969	if ((authAttrs[i].ulValueLen == -1) || (authAttrs[i].ulValueLen == 0)){
 970	    continue;
 971	}
 972
 973	plainText.data = authAttrs[i].pValue;
 974	plainText.len = authAttrs[i].ulValueLen;
 975	rv = sftkdb_SignAttribute(arena, newKey, id, 
 976			authAttrs[i].type, &plainText, &signText);
 977	if (rv != SECSuccess) {
 978	    return CKR_GENERAL_ERROR;
 979	}
 980	rv = sftkdb_PutAttributeSignature(handle, keyTarget, id, 
 981				authAttrs[i].type, signText);
 982	if (rv != SECSuccess) {
 983	    return CKR_GENERAL_ERROR;
 984	}
 985    }
 986
 987    return CKR_OK;
 988}
 989	
 990static CK_RV
 991sftk_updateEncrypted(PLArenaPool *arena, SFTKDBHandle *keydb,
 992		       CK_OBJECT_HANDLE id, SECItem *newKey)
 993{
 994    CK_RV crv = CKR_OK;
 995    CK_RV crv2;
 996    CK_ATTRIBUTE *first, *last;
 997    CK_ATTRIBUTE privAttrs[] = {
 998	{CKA_VALUE, NULL, 0},
 999	{CKA_PRIVATE_EXPONENT, NULL, 0},
1000	{CKA_PRIME_1, NULL, 0},
1001	{CKA_PRIME_2, NULL, 0},
1002	{CKA_EXPONENT_1, NULL, 0},
1003	{CKA_EXPONENT_2, NULL, 0},
1004	{CKA_COEFFICIENT, NULL, 0} };
1005    CK_ULONG privAttrCount = sizeof(privAttrs)/sizeof(CK_ATTRIBUTE);
1006    int i, count;
1007
1008    /*
1009     * STEP 1. Read the old attributes in the clear.
1010     */
1011
1012    /* Get the attribute sizes.
1013     *  ignore the error code, we will have unknown attributes here */
1014    crv2 = sftkdb_GetAttributeValue(keydb, id, privAttrs, privAttrCount);
1015
1016    /*
1017     * find the valid block of attributes and fill allocate space for
1018     * their data */
1019    first = last = NULL;
1020    for (i=0; i < privAttrCount; i++) {
1021         /* find the block of attributes that are appropriate for this 
1022          * objects. There should only be once contiguous block, if not 
1023          * there's an error.
1024          *
1025          * find the first and last good entry.
1026          */
1027	if ((privAttrs[i].ulValueLen == -1) || (privAttrs[i].ulValueLen == 0)){
1028	    if (!first) continue;
1029	    if (!last) {
1030		/* previous entry was last good entry */
1031		last= &privAttrs[i-1];
1032	    }
1033	    continue;
1034	}
1035	if (!first) {
1036	    first = &privAttrs[i];
1037	}
1038	if (last) {
1039	   /* OOPS, we've found another good entry beyond the end of the
1040	    * last good entry, we need to fail here. */
1041	   crv = CKR_GENERAL_ERROR;
1042	   break;
1043	}
1044        privAttrs[i].pValue = PORT_ArenaAlloc(arena,privAttrs[i].ulValueLen);
1045	if (privAttrs[i].pValue == NULL) {
1046	    crv = CKR_HOST_MEMORY;
1047	    break;
1048	}
1049    }
1050    if (first == NULL) {
1051	/* no valid entries found, return error based on crv2 */
1052	return crv2;
1053    }
1054    if (last == NULL) {
1055	last = &privAttrs[privAttrCount-1];
1056    }
1057    if (crv != CKR_OK) {
1058	return crv;
1059    }
1060    /* read the attributes */
1061    count = (last-first)+1;
1062    crv = sftkdb_GetAttributeValue(keydb, id, first, count);
1063    if (crv != CKR_OK) {
1064	return crv;
1065    }
1066
1067    /*
1068     * STEP 2: read the encrypt the attributes with the new key.
1069     */
1070    for (i=0; i < count; i++) {
1071	SECItem plainText;
1072	SECItem *result;
1073	SECStatus rv;
1074
1075	plainText.data = first[i].pValue;
1076	plainText.len = first[i].ulValueLen;
1077    	rv = sftkdb_EncryptAttribute(arena, newKey, &plainText, &result);
1078	if (rv != SECSuccess) {
1079	   return CKR_GENERAL_ERROR;
1080	}
1081	first[i].pValue = result->data;
1082	first[i].ulValueLen = result->len;
1083	/* clear our sensitive data out */
1084	PORT_Memset(plainText.data, 0, plainText.len);
1085    }
1086
1087
1088    /*
1089     * STEP 3: write the newly encrypted attributes out directly
1090     */
1091    id &= SFTK_OBJ_ID_MASK;
1092    keydb->newKey = newKey;
1093    crv = (*keydb->db->sdb_SetAttributeValue)(keydb->db, id, first, count);
1094    keydb->newKey = NULL;
1095
1096    return crv;
1097}
1098	
1099static CK_RV
1100sftk_convertAttributes(SFTKDBHandle *handle, 
1101			CK_OBJECT_HANDLE id, SECItem *newKey)
1102{
1103    CK_RV crv = CKR_OK;
1104    PLArenaPool *arena = NULL;
1105
1106    /* get a new arena to simplify cleanup */
1107    arena = PORT_NewArena(1024);
1108    if (!arena) {
1109	return CKR_HOST_MEMORY;
1110    }
1111
1112    /*
1113     * first handle the MACS
1114     */
1115    crv = sftk_updateMacs(arena, handle, id, newKey);
1116    if (crv != CKR_OK) {
1117	goto loser;
1118    }
1119
1120    if (handle->type == SFTK_KEYDB_TYPE) {
1121	crv = sftk_updateEncrypted(arena, handle, id, newKey);
1122	if (crv != CKR_OK) {
1123	    goto loser;
1124	}
1125    }
1126
1127    /* free up our mess */
1128    /* NOTE: at this point we know we've cleared out any unencrypted data */
1129    PORT_FreeArena(arena, PR_FALSE);
1130    return CKR_OK;
1131
1132loser:
1133    /* there may be unencrypted data, clear it out down */
1134    PORT_FreeArena(arena, PR_TRUE);
1135    return crv;
1136}
1137
1138
1139/*
1140 * must be called with the old key active.
1141 */
1142CK_RV
1143sftkdb_convertObjects(SFTKDBHandle *handle, CK_ATTRIBUTE *template, 
1144			CK_ULONG count, SECItem *newKey)
1145{
1146    SDBFind *find = NULL;
1147    CK_ULONG idCount = SFTK_MAX_IDS;
1148    CK_OBJECT_HANDLE ids[SFTK_MAX_IDS];
1149    CK_RV crv, crv2;
1150    int i;
1151
1152    crv = sftkdb_FindObjectsInit(handle, template, count, &find);
1153
1154    if (crv != CKR_OK) {
1155	return crv;
1156    }
1157    while ((crv == CKR_OK) && (idCount == SFTK_MAX_IDS)) {
1158	crv = sftkdb_FindObjects(handle, find, ids, SFTK_MAX_IDS, &idCount);
1159	for (i=0; (crv == CKR_OK) && (i < idCount); i++) {
1160	    crv = sftk_convertAttributes(handle, ids[i], newKey);
1161	}
1162    }
1163    crv2 = sftkdb_FindObjectsFinal(handle, find);
1164    if (crv == CKR_OK) crv = crv2;
1165
1166    return crv;
1167}
1168
1169
1170/*
1171 * change the database password.
1172 */
1173SECStatus
1174sftkdb_ChangePassword(SFTKDBHandle *keydb, 
1175                      char *oldPin, char *newPin, PRBool *tokenRemoved)
1176{
1177    SECStatus rv = SECSuccess;
1178    SECItem plainText;
1179    SECItem newKey;
1180    SECItem *result = NULL;
1181    SECItem salt, value;
1182    SFTKDBHandle *certdb;
1183    unsigned char saltData[SDB_MAX_META_DATA_LEN];
1184    unsigned char valueData[SDB_MAX_META_DATA_LEN];
1185    CK_RV crv;
1186    SDB *db;
1187
1188    if (keydb == NULL) {
1189	return SECFailure;
1190    }
1191
1192    db = SFTK_GET_SDB(keydb);
1193    if (db == NULL) {
1194	return SECFailure;
1195    }
1196
1197    newKey.data = NULL;
1198
1199    /* make sure we have a valid old pin */
1200    crv = (*keydb->db->sdb_Begin)(keydb->db);
1201    if (crv != CKR_OK) {
1202	rv = SECFailure;
1203	goto loser;
1204    }
1205    salt.data = saltData;
1206    salt.len = sizeof(saltData);
1207    value.data = valueData;
1208    value.len = sizeof(valueData);
1209    crv = (*db->sdb_GetMetaData)(db, "password", &salt, &value);
1210    if (crv == CKR_OK) {
1211	rv = sftkdb_CheckPassword(keydb, oldPin, tokenRemoved);
1212	if (rv == SECFailure) {
1213	    goto loser;
1214	}
1215    } else {
1216	salt.len = SHA1_LENGTH;
1217    	RNG_GenerateGlobalRandomBytes(salt.data,salt.len);
1218    }
1219
1220    rv = sftkdb_passwordToKey(keydb, &salt, newPin, &newKey);
1221    if (rv != SECSuccess) {
1222	goto loser;
1223    }
1224
1225
1226    /*
1227     * convert encrypted entries here.
1228     */
1229    crv = sftkdb_convertObjects(keydb, NULL, 0, &newKey);
1230    if (crv != CKR_OK) {
1231	rv = SECFailure;
1232	goto loser;
1233    }
1234    /* fix up certdb macs */
1235    certdb = keydb->peerDB;
1236    if (certdb) {
1237	CK_ATTRIBUTE objectType = { CKA_CLASS, 0, sizeof(CK_OBJECT_CLASS) };
1238	CK_OBJECT_CLASS myClass = CKO_NETSCAPE_TRUST;
1239
1240	objectType.pValue = &myClass;
1241	crv = sftkdb_convertObjects(certdb, &objectType, 1, &newKey);
1242	if (crv != CKR_OK) {
1243	    rv = SECFailure;
1244	    goto loser;
1245	}
1246	myClass = CKO_PUBLIC_KEY;
1247	crv = sftkdb_convertObjects(certdb, &objectType, 1, &newKey);
1248	if (crv != CKR_OK) {
1249	    rv = SECFailure;
1250	    goto loser;
1251	}
1252    }
1253
1254
1255    plainText.data = (unsigned char *)SFTK_PW_CHECK_STRING;
1256    plainText.len = SFTK_PW_CHECK_LEN;
1257
1258    rv = sftkdb_EncryptAttribute(NULL, &newKey, &plainText, &result);
1259    if (rv != SECSuccess) {
1260	goto loser;
1261    }
1262    value.data = result->data;
1263    value.len = result->len;
1264    crv = (*keydb->db->sdb_PutMetaData)(keydb->db, "password", &salt, &value);
1265    if (crv != CKR_OK) {
1266	rv = SECFailure;
1267	goto loser;
1268    }
1269    crv = (*keydb->db->sdb_Commit)(keydb->db);
1270    if (crv != CKR_OK) {
1271	rv = SECFailure;
1272	goto loser;
1273    }
1274
1275    keydb->newKey = NULL;
1276
1277    sftkdb_switchKeys(keydb, &newKey);
1278
1279loser:
1280    if (newKey.data) {
1281	PORT_ZFree(newKey.data,newKey.len);
1282    }
1283    if (result) {
1284	SECITEM_FreeItem(result, PR_FALSE);
1285    }
1286    if (rv != SECSuccess) {
1287        (*keydb->db->sdb_Abort)(keydb->db);
1288    }
1289    
1290    return rv;
1291}
1292
1293/*
1294 * lose our cached password
1295 */
1296SECStatus
1297sftkdb_ClearPassword(SFTKDBHandle *keydb)
1298{
1299    SECItem oldKey;
1300    oldKey.data = NULL;
1301    oldKey.len = 0;
1302    sftkdb_switchKeys(keydb, &oldKey);
1303    if (oldKey.data) {
1304	PORT_ZFree(oldKey.data, oldKey.len);
1305    }
1306    return SECSuccess;
1307}
1308
1309