PageRenderTime 98ms CodeModel.GetById 12ms app.highlight 71ms RepoModel.GetById 1ms app.codeStats 1ms

/security/nss/lib/softoken/sftkdb.c

http://github.com/zpao/v8monkey
C | 2770 lines | 1950 code | 275 blank | 545 comment | 574 complexity | 2cfb7015beb67e3f5fbe9ba30de64a93 MD5 | raw file

Large files files are truncated, but you can click here to view the full 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 "pratom.h"
  60#include "lgglue.h"
  61#include "sftkpars.h"
  62#include "secerr.h"
  63#include "softoken.h"
  64
  65/*
  66 * We want all databases to have the same binary representation independent of
  67 * endianness or length of the host architecture. In general PKCS #11 attributes
  68 * are endian/length independent except those attributes that pass CK_ULONG.
  69 *
  70 * The following functions fixes up the CK_ULONG type attributes so that the data
  71 * base sees a machine independent view. CK_ULONGs are stored as 4 byte network
  72 * byte order values (big endian).
  73 */
  74#define BBP 8
  75
  76static PRBool
  77sftkdb_isULONGAttribute(CK_ATTRIBUTE_TYPE type) 
  78{
  79    switch(type) {
  80    case CKA_CERTIFICATE_CATEGORY:
  81    case CKA_CERTIFICATE_TYPE:
  82    case CKA_CLASS:
  83    case CKA_JAVA_MIDP_SECURITY_DOMAIN:
  84    case CKA_KEY_GEN_MECHANISM:
  85    case CKA_KEY_TYPE:
  86    case CKA_MECHANISM_TYPE:
  87    case CKA_MODULUS_BITS:
  88    case CKA_PRIME_BITS:
  89    case CKA_SUBPRIME_BITS:
  90    case CKA_VALUE_BITS:
  91    case CKA_VALUE_LEN:
  92
  93    case CKA_TRUST_DIGITAL_SIGNATURE:
  94    case CKA_TRUST_NON_REPUDIATION:
  95    case CKA_TRUST_KEY_ENCIPHERMENT:
  96    case CKA_TRUST_DATA_ENCIPHERMENT:
  97    case CKA_TRUST_KEY_AGREEMENT:
  98    case CKA_TRUST_KEY_CERT_SIGN:
  99    case CKA_TRUST_CRL_SIGN:
 100
 101    case CKA_TRUST_SERVER_AUTH:
 102    case CKA_TRUST_CLIENT_AUTH:
 103    case CKA_TRUST_CODE_SIGNING:
 104    case CKA_TRUST_EMAIL_PROTECTION:
 105    case CKA_TRUST_IPSEC_END_SYSTEM:
 106    case CKA_TRUST_IPSEC_TUNNEL:
 107    case CKA_TRUST_IPSEC_USER:
 108    case CKA_TRUST_TIME_STAMPING:
 109    case CKA_TRUST_STEP_UP_APPROVED:
 110	return PR_TRUE;
 111    default:
 112	break;
 113    }
 114    return PR_FALSE;
 115    
 116}
 117
 118/* are the attributes private? */
 119static PRBool
 120sftkdb_isPrivateAttribute(CK_ATTRIBUTE_TYPE type) 
 121{
 122    switch(type) {
 123    case CKA_VALUE:
 124    case CKA_PRIVATE_EXPONENT:
 125    case CKA_PRIME_1:
 126    case CKA_PRIME_2:
 127    case CKA_EXPONENT_1:
 128    case CKA_EXPONENT_2:
 129    case CKA_COEFFICIENT:
 130	return PR_TRUE;
 131    default:
 132	break;
 133    }
 134    return PR_FALSE;
 135}
 136
 137/* These attributes must be authenticated with an hmac. */
 138static PRBool
 139sftkdb_isAuthenticatedAttribute(CK_ATTRIBUTE_TYPE type) 
 140{
 141    switch(type) {
 142    case CKA_MODULUS:
 143    case CKA_PUBLIC_EXPONENT:
 144    case CKA_CERT_SHA1_HASH:
 145    case CKA_CERT_MD5_HASH:
 146    case CKA_TRUST_SERVER_AUTH:
 147    case CKA_TRUST_CLIENT_AUTH:
 148    case CKA_TRUST_EMAIL_PROTECTION:
 149    case CKA_TRUST_CODE_SIGNING:
 150    case CKA_TRUST_STEP_UP_APPROVED:
 151    case CKA_NSS_OVERRIDE_EXTENSIONS:
 152	return PR_TRUE;
 153    default:
 154	break;
 155    }
 156    return PR_FALSE;
 157}
 158
 159/*
 160 * convert a native ULONG to a database ulong. Database ulong's
 161 * are all 4 byte big endian values.
 162 */
 163void
 164sftk_ULong2SDBULong(unsigned char *data, CK_ULONG value)
 165{ 
 166    int i;
 167
 168    for (i=0; i < SDB_ULONG_SIZE; i++) {
 169	data[i] = (value >> (SDB_ULONG_SIZE-1-i)*BBP) & 0xff;
 170    }
 171}
 172
 173/*
 174 * convert a database ulong back to a native ULONG. (reverse of the above
 175 * function.
 176 */
 177static CK_ULONG
 178sftk_SDBULong2ULong(unsigned char *data)
 179{
 180    int i;
 181    CK_ULONG value = 0;
 182
 183    for (i=0; i < SDB_ULONG_SIZE; i++) {
 184	value |= (((CK_ULONG)data[i]) << (SDB_ULONG_SIZE-1-i)*BBP);
 185    }
 186    return value;
 187}
 188
 189/*
 190 * fix up the input templates. Our fixed up ints are stored in data and must
 191 * be freed by the caller. The new template must also be freed. If there are no
 192 * CK_ULONG attributes, the orignal template is passed in as is.
 193 */
 194static CK_ATTRIBUTE *
 195sftkdb_fixupTemplateIn(const CK_ATTRIBUTE *template, int count, 
 196			unsigned char **dataOut)
 197{
 198    int i;
 199    int ulongCount = 0;
 200    unsigned char *data;
 201    CK_ATTRIBUTE *ntemplate;
 202
 203    *dataOut = NULL;
 204
 205    /* first count the number of CK_ULONG attributes */
 206    for (i=0; i < count; i++) {
 207	/* Don't 'fixup' NULL values */
 208	if (!template[i].pValue) {
 209	    continue;
 210	}
 211	if (template[i].ulValueLen == sizeof (CK_ULONG)) {
 212	    if ( sftkdb_isULONGAttribute(template[i].type)) {
 213		ulongCount++;
 214	    }
 215	}
 216    }
 217    /* no attributes to fixup, just call on through */
 218    if (ulongCount == 0) {
 219	return (CK_ATTRIBUTE *)template;
 220    }
 221
 222    /* allocate space for new ULONGS */
 223    data = (unsigned char *)PORT_Alloc(SDB_ULONG_SIZE*ulongCount);
 224    if (!data) {
 225	return NULL;
 226    }
 227
 228    /* allocate new template */
 229    ntemplate = PORT_NewArray(CK_ATTRIBUTE,count);
 230    if (!ntemplate) {
 231	PORT_Free(data);
 232	return NULL;
 233    }
 234    *dataOut = data;
 235    /* copy the old template, fixup the actual ulongs */
 236    for (i=0; i < count; i++) {
 237	ntemplate[i] = template[i];
 238	/* Don't 'fixup' NULL values */
 239	if (!template[i].pValue) {
 240	    continue;
 241	}
 242	if (template[i].ulValueLen == sizeof (CK_ULONG)) {
 243	    if ( sftkdb_isULONGAttribute(template[i].type) ) {
 244		CK_ULONG value = *(CK_ULONG *) template[i].pValue;
 245		sftk_ULong2SDBULong(data, value);
 246		ntemplate[i].pValue = data;
 247		ntemplate[i].ulValueLen = SDB_ULONG_SIZE;
 248		data += SDB_ULONG_SIZE;
 249	    }
 250	}
 251    }
 252    return ntemplate;
 253}
 254
 255
 256static const char SFTKDB_META_SIG_TEMPLATE[] = "sig_%s_%08x_%08x";
 257
 258/*
 259 * return a string describing the database type (key or cert)
 260 */
 261const char *
 262sftkdb_TypeString(SFTKDBHandle *handle)
 263{
 264   return (handle->type == SFTK_KEYDB_TYPE) ? "key" : "cert";
 265}
 266
 267/*
 268 * Some attributes are signed with an Hmac and a pbe key generated from
 269 * the password. This signature is stored indexed by object handle and
 270 * attribute type in the meta data table in the key database.
 271 *
 272 * Signature entries are indexed by the string
 273 * sig_[cert/key]_{ObjectID}_{Attribute}
 274 *
 275 * This function fetches that pkcs5 signature. Caller supplies a SECItem
 276 * pre-allocated to the appropriate size if the SECItem is too small the
 277 * function will fail with CKR_BUFFER_TOO_SMALL.
 278 */
 279static CK_RV
 280sftkdb_getAttributeSignature(SFTKDBHandle *handle, SFTKDBHandle *keyHandle, 
 281		CK_OBJECT_HANDLE objectID, CK_ATTRIBUTE_TYPE type,
 282		SECItem *signText)
 283{
 284    SDB *db;
 285    char id[30];
 286    CK_RV crv;
 287
 288    db = SFTK_GET_SDB(keyHandle);
 289
 290    sprintf(id, SFTKDB_META_SIG_TEMPLATE,
 291	sftkdb_TypeString(handle),
 292	(unsigned int)objectID, (unsigned int)type);
 293
 294    crv = (*db->sdb_GetMetaData)(db, id, signText, NULL);
 295    return crv;
 296}
 297
 298/*
 299 * Some attributes are signed with an Hmac and a pbe key generated from
 300 * the password. This signature is stored indexed by object handle and
 301 * attribute type in the meta data table in the key database.
 302 *
 303 * Signature entries are indexed by the string
 304 * sig_[cert/key]_{ObjectID}_{Attribute}
 305 *
 306 * This function stores that pkcs5 signature.
 307 */
 308CK_RV
 309sftkdb_PutAttributeSignature(SFTKDBHandle *handle, SDB *keyTarget, 
 310		CK_OBJECT_HANDLE objectID, CK_ATTRIBUTE_TYPE type,
 311		SECItem *signText)
 312{
 313    char id[30];
 314    CK_RV crv;
 315
 316    sprintf(id, SFTKDB_META_SIG_TEMPLATE,
 317	sftkdb_TypeString(handle),
 318	(unsigned int)objectID, (unsigned int)type);
 319
 320    crv = (*keyTarget->sdb_PutMetaData)(keyTarget, id, signText, NULL);
 321    return crv;
 322}
 323
 324/*
 325 * fix up returned data. NOTE: sftkdb_fixupTemplateIn has already allocated
 326 * separate data sections for the database ULONG values.
 327 */
 328static CK_RV
 329sftkdb_fixupTemplateOut(CK_ATTRIBUTE *template, CK_OBJECT_HANDLE objectID,
 330		CK_ATTRIBUTE *ntemplate, int count, SFTKDBHandle *handle)
 331{
 332    int i;
 333    CK_RV crv = CKR_OK;
 334    SFTKDBHandle *keyHandle;
 335    PRBool checkSig = PR_TRUE;
 336    PRBool checkEnc = PR_TRUE;
 337
 338    PORT_Assert(handle);
 339
 340    /* find the key handle */
 341    keyHandle = handle;
 342    if (handle->type != SFTK_KEYDB_TYPE) {
 343	checkEnc = PR_FALSE;
 344	keyHandle = handle->peerDB;
 345    }
 346
 347    if ((keyHandle == NULL) || 
 348	((SFTK_GET_SDB(keyHandle)->sdb_flags & SDB_HAS_META) == 0)  ||
 349	(keyHandle->passwordKey.data == NULL)) {
 350	checkSig = PR_FALSE;
 351    }
 352
 353    for (i=0; i < count; i++) {
 354	CK_ULONG length = template[i].ulValueLen;
 355	template[i].ulValueLen = ntemplate[i].ulValueLen;
 356	/* fixup ulongs */
 357	if (ntemplate[i].ulValueLen == SDB_ULONG_SIZE) {
 358	    if (sftkdb_isULONGAttribute(template[i].type)) {
 359		if (template[i].pValue) {
 360		    CK_ULONG value;
 361		    unsigned char *data;
 362
 363		    data = (unsigned char *)ntemplate[i].pValue;
 364		    value = sftk_SDBULong2ULong(ntemplate[i].pValue);
 365		    if (length < sizeof(CK_ULONG)) {
 366			template[i].ulValueLen = -1;
 367			crv = CKR_BUFFER_TOO_SMALL;
 368			continue;
 369		    } 
 370		    PORT_Memcpy(template[i].pValue,&value,sizeof(CK_ULONG));
 371		}
 372		template[i].ulValueLen = sizeof(CK_ULONG);
 373	    }
 374	}
 375
 376	/* if no data was retrieved, no need to process encrypted or signed
 377	 * attributes */
 378	if ((template[i].pValue == NULL) || (template[i].ulValueLen == -1)) {
 379	    continue;
 380	}
 381
 382	/* fixup private attributes */
 383	if (checkEnc && sftkdb_isPrivateAttribute(ntemplate[i].type)) {
 384	    /* we have a private attribute */
 385	    /* This code depends on the fact that the cipherText is bigger
 386	     * than the plain text */
 387	    SECItem cipherText;
 388	    SECItem *plainText;
 389	    SECStatus rv;
 390
 391	    cipherText.data = ntemplate[i].pValue;
 392	    cipherText.len = ntemplate[i].ulValueLen;
 393    	    PZ_Lock(handle->passwordLock);
 394	    if (handle->passwordKey.data == NULL) {
 395		PZ_Unlock(handle->passwordLock);
 396		template[i].ulValueLen = -1;
 397		crv = CKR_USER_NOT_LOGGED_IN;
 398		continue;
 399	    }
 400	    rv = sftkdb_DecryptAttribute(&handle->passwordKey, 
 401					&cipherText, &plainText);
 402	    PZ_Unlock(handle->passwordLock);
 403	    if (rv != SECSuccess) {
 404		PORT_Memset(template[i].pValue, 0, template[i].ulValueLen);
 405		template[i].ulValueLen = -1;
 406		crv = CKR_GENERAL_ERROR;
 407		continue;
 408	    }
 409	    PORT_Assert(template[i].ulValueLen >= plainText->len);
 410	    if (template[i].ulValueLen < plainText->len) {
 411		SECITEM_FreeItem(plainText,PR_TRUE);
 412		PORT_Memset(template[i].pValue, 0, template[i].ulValueLen);
 413		template[i].ulValueLen = -1;
 414		crv = CKR_GENERAL_ERROR;
 415		continue;
 416	    }
 417		
 418	    /* copy the plain text back into the template */
 419	    PORT_Memcpy(template[i].pValue, plainText->data, plainText->len);
 420	    template[i].ulValueLen = plainText->len;
 421	    SECITEM_FreeItem(plainText,PR_TRUE);
 422	}
 423	/* make sure signed attributes are valid */
 424	if (checkSig && sftkdb_isAuthenticatedAttribute(ntemplate[i].type)) {
 425	    SECStatus rv;
 426	    SECItem signText;
 427	    SECItem plainText;
 428	    unsigned char signData[SDB_MAX_META_DATA_LEN];
 429
 430	    signText.data = signData;
 431	    signText.len = sizeof(signData);
 432
 433	    rv = sftkdb_getAttributeSignature(handle, keyHandle, 
 434				objectID, ntemplate[i].type, &signText);
 435	    if (rv != SECSuccess) {
 436		PORT_Memset(template[i].pValue, 0, template[i].ulValueLen);
 437		template[i].ulValueLen = -1;
 438		crv = CKR_DATA_INVALID; /* better error code? */
 439		continue;
 440	    }
 441
 442	    plainText.data = ntemplate[i].pValue;
 443	    plainText.len = ntemplate[i].ulValueLen;
 444
 445	    /*
 446	     * we do a second check holding the lock just in case the user
 447	     * loggout while we were trying to get the signature.
 448	     */
 449    	    PZ_Lock(keyHandle->passwordLock);
 450	    if (keyHandle->passwordKey.data == NULL) {
 451		/* if we are no longer logged in, no use checking the other
 452		 * Signatures either. */
 453		checkSig = PR_FALSE; 
 454		PZ_Unlock(keyHandle->passwordLock);
 455		continue;
 456	    }
 457
 458	    rv = sftkdb_VerifyAttribute(&keyHandle->passwordKey, 
 459				objectID, ntemplate[i].type,
 460				&plainText, &signText);
 461	    PZ_Unlock(keyHandle->passwordLock);
 462	    if (rv != SECSuccess) {
 463		PORT_Memset(template[i].pValue, 0, template[i].ulValueLen);
 464		template[i].ulValueLen = -1;
 465		crv = CKR_SIGNATURE_INVALID; /* better error code? */
 466	    }
 467	    /* This Attribute is fine */
 468	}
 469    }
 470    return crv;
 471}
 472
 473/*
 474 * Some attributes are signed with an HMAC and a pbe key generated from
 475 * the password. This signature is stored indexed by object handle and
 476 *
 477 * Those attributes are:
 478 * 1) Trust object hashes and trust values.
 479 * 2) public key values.
 480 *
 481 * Certs themselves are considered properly authenticated by virtue of their
 482 * signature, or their matching hash with the trust object.
 483 *
 484 * These signature is only checked for objects coming from shared databases. 
 485 * Older dbm style databases have such no signature checks. HMACs are also 
 486 * only checked when the token is logged in, as it requires a pbe generated 
 487 * from the password.
 488 *
 489 * Tokens which have no key database (and therefore no master password) do not
 490 * have any stored signature values. Signature values are stored in the key
 491 * database, since the signature data is tightly coupled to the key database
 492 * password. 
 493 *
 494 * This function takes a template of attributes that were either created or
 495 * modified. These attributes are checked to see if the need to be signed.
 496 * If they do, then this function signs the attributes and writes them
 497 * to the meta data store.
 498 *
 499 * This function can fail if there are attributes that must be signed, but
 500 * the token is not logged in.
 501 *
 502 * The caller is expected to abort any transaction he was in in the
 503 * event of a failure of this function.
 504 */
 505static CK_RV
 506sftk_signTemplate(PLArenaPool *arena, SFTKDBHandle *handle, 
 507		  PRBool mayBeUpdateDB,
 508		  CK_OBJECT_HANDLE objectID, const CK_ATTRIBUTE *template,
 509		  CK_ULONG count)
 510{
 511    int i;
 512    CK_RV crv;
 513    SFTKDBHandle *keyHandle = handle;
 514    SDB *keyTarget = NULL;
 515    PRBool usingPeerDB = PR_FALSE;
 516    PRBool inPeerDBTransaction = PR_FALSE;
 517
 518    PORT_Assert(handle);
 519
 520    if (handle->type != SFTK_KEYDB_TYPE) {
 521	keyHandle = handle->peerDB;
 522	usingPeerDB = PR_TRUE;
 523    }
 524
 525    /* no key DB defined? then no need to sign anything */
 526    if (keyHandle == NULL) {
 527	crv = CKR_OK;
 528	goto loser;
 529    }
 530
 531    /* When we are in a middle of an update, we have an update database set, 
 532     * but we want to write to the real database. The bool mayBeUpdateDB is
 533     * set to TRUE if it's possible that we want to write an update database
 534     * rather than a primary */
 535    keyTarget = (mayBeUpdateDB && keyHandle->update) ? 
 536		keyHandle->update : keyHandle->db;
 537
 538    /* skip the the database does not support meta data */
 539    if ((keyTarget->sdb_flags & SDB_HAS_META) == 0) {
 540	crv = CKR_OK;
 541	goto loser;
 542    }
 543
 544    /* If we had to switch databases, we need to initialize a transaction. */
 545    if (usingPeerDB) {
 546	crv = (*keyTarget->sdb_Begin)(keyTarget);
 547	if (crv != CKR_OK) {
 548	    goto loser;
 549	}
 550	inPeerDBTransaction = PR_TRUE;
 551    }
 552
 553    for (i=0; i < count; i ++) {
 554	if (sftkdb_isAuthenticatedAttribute(template[i].type)) {
 555	    SECStatus rv;
 556	    SECItem *signText;
 557	    SECItem plainText;
 558
 559	    plainText.data = template[i].pValue;
 560	    plainText.len = template[i].ulValueLen;
 561	    PZ_Lock(keyHandle->passwordLock);
 562	    if (keyHandle->passwordKey.data == NULL) {
 563		PZ_Unlock(keyHandle->passwordLock);
 564		crv = CKR_USER_NOT_LOGGED_IN;
 565		goto loser;
 566	    }
 567	    rv = sftkdb_SignAttribute(arena, &keyHandle->passwordKey, 
 568				objectID, template[i].type,
 569				&plainText, &signText);
 570	    PZ_Unlock(keyHandle->passwordLock);
 571	    if (rv != SECSuccess) {
 572		crv = CKR_GENERAL_ERROR; /* better error code here? */
 573		goto loser;
 574	    }
 575	    rv = sftkdb_PutAttributeSignature(handle, keyTarget, 
 576				objectID, template[i].type, signText);
 577	    if (rv != SECSuccess) {
 578		crv = CKR_GENERAL_ERROR; /* better error code here? */
 579		goto loser;
 580	    }
 581	}
 582    }
 583    crv = CKR_OK;
 584
 585    /* If necessary, commit the transaction */
 586    if (inPeerDBTransaction) {
 587	crv = (*keyTarget->sdb_Commit)(keyTarget);
 588	if (crv != CKR_OK) {
 589	    goto loser;
 590	}
 591	inPeerDBTransaction = PR_FALSE;
 592    }
 593
 594loser:
 595    if (inPeerDBTransaction) {
 596	/* The transaction must have failed. Abort. */
 597	(*keyTarget->sdb_Abort)(keyTarget);
 598	PORT_Assert(crv != CKR_OK);
 599	if (crv == CKR_OK) crv = CKR_GENERAL_ERROR;
 600    }
 601    return crv;
 602}
 603
 604static CK_RV
 605sftkdb_CreateObject(PRArenaPool *arena, SFTKDBHandle *handle, 
 606	SDB *db, CK_OBJECT_HANDLE *objectID,
 607        CK_ATTRIBUTE *template, CK_ULONG count)
 608{
 609    PRBool inTransaction = PR_FALSE;
 610    CK_RV crv;
 611
 612    inTransaction = PR_TRUE;
 613    
 614    crv = (*db->sdb_CreateObject)(db, objectID, template, count);
 615    if (crv != CKR_OK) {
 616	goto loser;
 617    }
 618    crv = sftk_signTemplate(arena, handle, (db == handle->update),
 619					*objectID, template, count);
 620loser:
 621
 622    return crv;
 623}
 624
 625
 626CK_ATTRIBUTE * 
 627sftk_ExtractTemplate(PLArenaPool *arena, SFTKObject *object, 
 628		     SFTKDBHandle *handle,CK_ULONG *pcount, 
 629		     CK_RV *crv)
 630{
 631    int count;
 632    CK_ATTRIBUTE *template;
 633    int i, templateIndex;
 634    SFTKSessionObject *sessObject = sftk_narrowToSessionObject(object);
 635    PRBool doEnc = PR_TRUE;
 636
 637    *crv = CKR_OK;
 638
 639    if (sessObject == NULL) {
 640	*crv = CKR_GENERAL_ERROR; /* internal programming error */
 641	return NULL;
 642    }
 643
 644    PORT_Assert(handle);
 645    /* find the key handle */
 646    if (handle->type != SFTK_KEYDB_TYPE) {
 647	doEnc = PR_FALSE;
 648    }
 649
 650    PZ_Lock(sessObject->attributeLock);
 651    count = 0;
 652    for (i=0; i < sessObject->hashSize; i++) {
 653	SFTKAttribute *attr;
 654   	for (attr=sessObject->head[i]; attr; attr=attr->next) {
 655	    count++;
 656	}
 657    }
 658    template = PORT_ArenaNewArray(arena, CK_ATTRIBUTE, count);
 659    if (template == NULL) {
 660        PZ_Unlock(sessObject->attributeLock);
 661	*crv = CKR_HOST_MEMORY;
 662	return NULL;
 663    }
 664    templateIndex = 0;
 665    for (i=0; i < sessObject->hashSize; i++) {
 666	SFTKAttribute *attr;
 667   	for (attr=sessObject->head[i]; attr; attr=attr->next) {
 668	    CK_ATTRIBUTE *tp = &template[templateIndex++];
 669	    /* copy the attribute */
 670	    *tp = attr->attrib;
 671
 672	    /* fixup  ULONG s */
 673	    if ((tp->ulValueLen == sizeof (CK_ULONG)) &&
 674		(sftkdb_isULONGAttribute(tp->type)) ) {
 675		CK_ULONG value = *(CK_ULONG *) tp->pValue;
 676		unsigned char *data;
 677
 678		tp->pValue = PORT_ArenaAlloc(arena, SDB_ULONG_SIZE);
 679		data = (unsigned char *)tp->pValue;
 680		if (data == NULL) {
 681		    *crv = CKR_HOST_MEMORY;
 682		    break;
 683		}
 684		sftk_ULong2SDBULong(data, value);
 685		tp->ulValueLen = SDB_ULONG_SIZE;
 686	    }
 687
 688	    /* encrypt private attributes */
 689	    if (doEnc && sftkdb_isPrivateAttribute(tp->type)) {
 690		/* we have a private attribute */
 691		SECItem *cipherText;
 692		SECItem plainText;
 693		SECStatus rv;
 694
 695		plainText.data = tp->pValue;
 696		plainText.len = tp->ulValueLen;
 697		PZ_Lock(handle->passwordLock);
 698		if (handle->passwordKey.data == NULL) {
 699		    PZ_Unlock(handle->passwordLock);
 700		    *crv = CKR_USER_NOT_LOGGED_IN;
 701		    break;
 702		}
 703		rv = sftkdb_EncryptAttribute(arena, &handle->passwordKey, 
 704						&plainText, &cipherText);
 705		PZ_Unlock(handle->passwordLock);
 706		if (rv == SECSuccess) {
 707		    tp->pValue = cipherText->data;
 708		    tp->ulValueLen = cipherText->len;
 709		} else {
 710		    *crv = CKR_GENERAL_ERROR; /* better error code here? */
 711		    break;
 712		}
 713		PORT_Memset(plainText.data, 0, plainText.len);
 714	    }
 715	}
 716    }
 717    PORT_Assert(templateIndex <= count);
 718    PZ_Unlock(sessObject->attributeLock);
 719
 720    if (*crv != CKR_OK) {
 721	return NULL;
 722    }
 723    if (pcount) {
 724	*pcount = count;
 725    }
 726    return template;
 727
 728}
 729
 730/*
 731 * return a pointer to the attribute in the give template.
 732 * The return value is not const, as the caller may modify
 733 * the given attribute value, but such modifications will
 734 * modify the actual value in the template.
 735 */
 736static CK_ATTRIBUTE *
 737sftkdb_getAttributeFromTemplate(CK_ATTRIBUTE_TYPE attribute, 
 738			    CK_ATTRIBUTE *ptemplate, CK_ULONG len)
 739{
 740    CK_ULONG i;
 741
 742    for (i=0; i < len; i++) {
 743	if (attribute == ptemplate[i].type) {
 744	    return &ptemplate[i];
 745	}
 746    }
 747    return NULL;
 748}
 749
 750static const CK_ATTRIBUTE *
 751sftkdb_getAttributeFromConstTemplate(CK_ATTRIBUTE_TYPE attribute, 
 752				const CK_ATTRIBUTE *ptemplate, CK_ULONG len)
 753{
 754    CK_ULONG i;
 755
 756    for (i=0; i < len; i++) {
 757	if (attribute == ptemplate[i].type) {
 758	    return &ptemplate[i];
 759	}
 760    }
 761    return NULL;
 762}
 763
 764
 765/*
 766 * fetch a template which identifies 'unique' entries based on object type
 767 */
 768static CK_RV
 769sftkdb_getFindTemplate(CK_OBJECT_CLASS objectType, unsigned char *objTypeData,
 770			CK_ATTRIBUTE *findTemplate, CK_ULONG *findCount,
 771			CK_ATTRIBUTE *ptemplate, int len)
 772{
 773    CK_ATTRIBUTE *attr;
 774    CK_ULONG count = 1;
 775
 776    sftk_ULong2SDBULong(objTypeData, objectType);
 777    findTemplate[0].type = CKA_CLASS;
 778    findTemplate[0].pValue = objTypeData;
 779    findTemplate[0].ulValueLen = SDB_ULONG_SIZE;
 780
 781    switch (objectType) {
 782    case CKO_CERTIFICATE:
 783    case CKO_NSS_TRUST:
 784	attr = sftkdb_getAttributeFromTemplate(CKA_ISSUER, ptemplate, len);
 785	if (attr == NULL) {
 786	    return CKR_TEMPLATE_INCOMPLETE;
 787	}
 788	findTemplate[1] = *attr;
 789	attr = sftkdb_getAttributeFromTemplate(CKA_SERIAL_NUMBER, 
 790					ptemplate, len);
 791	if (attr == NULL) {
 792	    return CKR_TEMPLATE_INCOMPLETE;
 793	}
 794	findTemplate[2] = *attr;
 795	count = 3;
 796	break;
 797	
 798    case CKO_PRIVATE_KEY:
 799    case CKO_PUBLIC_KEY:
 800    case CKO_SECRET_KEY:
 801	attr = sftkdb_getAttributeFromTemplate(CKA_ID, ptemplate, len);
 802	if (attr == NULL) {
 803	    return CKR_TEMPLATE_INCOMPLETE;
 804	}
 805	if (attr->ulValueLen == 0) {
 806	    /* key is too generic to determine that it's unique, usually
 807	     * happens in the key gen case */
 808	    return CKR_OBJECT_HANDLE_INVALID;
 809	}
 810	
 811	findTemplate[1] = *attr;
 812	count = 2;
 813	break;
 814
 815    case CKO_NSS_CRL:
 816	attr = sftkdb_getAttributeFromTemplate(CKA_SUBJECT, ptemplate, len);
 817	if (attr == NULL) {
 818	    return CKR_TEMPLATE_INCOMPLETE;
 819	}
 820	findTemplate[1] = *attr;
 821	count = 2;
 822	break;
 823
 824    case CKO_NSS_SMIME:
 825	attr = sftkdb_getAttributeFromTemplate(CKA_SUBJECT, ptemplate, len);
 826	if (attr == NULL) {
 827	    return CKR_TEMPLATE_INCOMPLETE;
 828	}
 829	findTemplate[1] = *attr;
 830	attr = sftkdb_getAttributeFromTemplate(CKA_NSS_EMAIL, ptemplate, len);
 831	if (attr == NULL) {
 832	    return CKR_TEMPLATE_INCOMPLETE;
 833	}
 834	findTemplate[2] = *attr;
 835	count = 3;
 836	break;
 837    default:
 838	attr = sftkdb_getAttributeFromTemplate(CKA_VALUE, ptemplate, len);
 839	if (attr == NULL) {
 840	    return CKR_TEMPLATE_INCOMPLETE;
 841	}
 842	findTemplate[1] = *attr;
 843	count = 2;
 844	break;
 845    }
 846    *findCount = count;
 847
 848    return CKR_OK;
 849}
 850
 851/*
 852 * look to see if this object already exists and return its object ID if
 853 * it does.
 854 */
 855static CK_RV
 856sftkdb_lookupObject(SDB *db, CK_OBJECT_CLASS objectType, 
 857		 CK_OBJECT_HANDLE *id, CK_ATTRIBUTE *ptemplate, CK_ULONG len)
 858{
 859    CK_ATTRIBUTE findTemplate[3];
 860    CK_ULONG count = 1;
 861    CK_ULONG objCount = 0;
 862    SDBFind *find = NULL;
 863    unsigned char objTypeData[SDB_ULONG_SIZE];
 864    CK_RV crv;
 865
 866    *id = CK_INVALID_HANDLE;
 867    if (objectType == CKO_NSS_CRL) {
 868	return CKR_OK;
 869    }
 870    crv = sftkdb_getFindTemplate(objectType, objTypeData,
 871			findTemplate, &count, ptemplate, len);
 872
 873    if (crv == CKR_OBJECT_HANDLE_INVALID) {
 874	/* key is too generic to determine that it's unique, usually
 875	 * happens in the key gen case, tell the caller to go ahead
 876	 * and just create it */
 877	return CKR_OK;
 878    }
 879    if (crv != CKR_OK) {
 880	return crv;
 881    }
 882
 883    /* use the raw find, so we get the correct database */
 884    crv = (*db->sdb_FindObjectsInit)(db, findTemplate, count, &find);
 885    if (crv != CKR_OK) {
 886	return crv;
 887    }
 888    (*db->sdb_FindObjects)(db, find, id, 1, &objCount);
 889    (*db->sdb_FindObjectsFinal)(db, find);
 890
 891    if (objCount == 0) {
 892	*id = CK_INVALID_HANDLE;
 893    }
 894    return CKR_OK;
 895}
 896
 897
 898/*
 899 * check to see if this template conflicts with others in our current database.
 900 */
 901static CK_RV
 902sftkdb_checkConflicts(SDB *db, CK_OBJECT_CLASS objectType, 
 903			const CK_ATTRIBUTE *ptemplate, CK_ULONG len, 
 904			CK_OBJECT_HANDLE sourceID)
 905{
 906    CK_ATTRIBUTE findTemplate[2];
 907    unsigned char objTypeData[SDB_ULONG_SIZE];
 908    /* we may need to allocate some temporaries. Keep track of what was 
 909     * allocated so we can free it in the end */
 910    unsigned char *temp1 = NULL; 
 911    unsigned char *temp2 = NULL;
 912    CK_ULONG objCount = 0;
 913    SDBFind *find = NULL;
 914    CK_OBJECT_HANDLE id;
 915    const CK_ATTRIBUTE *attr, *attr2;
 916    CK_RV crv;
 917    CK_ATTRIBUTE subject;
 918
 919    /* Currently the only conflict is with nicknames pointing to the same 
 920     * subject when creating or modifying a certificate. */
 921    /* If the object is not a cert, no problem. */
 922    if (objectType != CKO_CERTIFICATE) {
 923	return CKR_OK;
 924    }
 925    /* if not setting a nickname then there's still no problem */
 926    attr = sftkdb_getAttributeFromConstTemplate(CKA_LABEL, ptemplate, len);
 927    if ((attr == NULL) || (attr->ulValueLen == 0)) {
 928	return CKR_OK;
 929    }
 930    /* fetch the subject of the source. For creation and merge, this should
 931     * be found in the template */
 932    attr2 = sftkdb_getAttributeFromConstTemplate(CKA_SUBJECT, ptemplate, len);
 933    if (sourceID == CK_INVALID_HANDLE) {
 934	if ((attr2 == NULL) || ((CK_LONG)attr2->ulValueLen < 0)) {
 935	    crv = CKR_TEMPLATE_INCOMPLETE; 
 936	    goto done;
 937	}
 938    } else if ((attr2 == NULL) || ((CK_LONG)attr2->ulValueLen <= 0)) {
 939	/* sourceID is set if we are trying to modify an existing entry instead
 940	 * of creating a new one. In this case the subject may not be (probably
 941	 * isn't) in the template, we have to read it from the database */
 942    	subject.type = CKA_SUBJECT;
 943    	subject.pValue = NULL;
 944    	subject.ulValueLen = 0;
 945    	crv = (*db->sdb_GetAttributeValue)(db, sourceID, &subject, 1);
 946	if (crv != CKR_OK) {
 947	    goto done;
 948	}
 949	if ((CK_LONG)subject.ulValueLen < 0) {
 950	    crv = CKR_DEVICE_ERROR; /* closest pkcs11 error to corrupted DB */
 951	    goto done;
 952	}
 953	temp1 = subject.pValue = PORT_Alloc(++subject.ulValueLen);
 954	if (temp1 == NULL) {
 955	    crv = CKR_HOST_MEMORY;
 956	    goto done;
 957	}
 958    	crv = (*db->sdb_GetAttributeValue)(db, sourceID, &subject, 1);
 959	if (crv != CKR_OK) {
 960	    goto done;
 961	}
 962	attr2 = &subject;
 963    }
 964    
 965    /* check for another cert in the database with the same nickname */
 966    sftk_ULong2SDBULong(objTypeData, objectType);
 967    findTemplate[0].type = CKA_CLASS;
 968    findTemplate[0].pValue = objTypeData;
 969    findTemplate[0].ulValueLen = SDB_ULONG_SIZE;
 970    findTemplate[1] = *attr;
 971
 972    crv = (*db->sdb_FindObjectsInit)(db, findTemplate, 2, &find);
 973    if (crv != CKR_OK) {
 974	goto done;
 975    }
 976    (*db->sdb_FindObjects)(db, find, &id, 1, &objCount);
 977    (*db->sdb_FindObjectsFinal)(db, find);
 978
 979    /* object count == 0 means no conflicting certs found, 
 980     * go on with the operation */
 981    if (objCount == 0) {
 982	crv = CKR_OK;
 983	goto done;
 984    }
 985
 986    /* There is a least one cert that shares the nickname, make sure it also
 987     * matches the subject. */
 988    findTemplate[0] = *attr2;
 989    /* we know how big the source subject was. Use that length to create the 
 990     * space for the target. If it's not enough space, then it means the 
 991     * source subject is too big, and therefore not a match. GetAttributeValue 
 992     * will return CKR_BUFFER_TOO_SMALL. Otherwise it should be exactly enough 
 993     * space (or enough space to be able to compare the result. */
 994    temp2 = findTemplate[0].pValue = PORT_Alloc(++findTemplate[0].ulValueLen);
 995    if (temp2 == NULL) {
 996	crv = CKR_HOST_MEMORY;
 997	goto done;
 998    }
 999    crv = (*db->sdb_GetAttributeValue)(db, id, findTemplate, 1);
1000    if (crv != CKR_OK) {
1001	if (crv == CKR_BUFFER_TOO_SMALL) {
1002	    /* if our buffer is too small, then the Subjects clearly do 
1003	     * not match */
1004	    crv = CKR_ATTRIBUTE_VALUE_INVALID;
1005	    goto loser;
1006	}
1007	/* otherwise we couldn't get the value, just fail */
1008	goto done;
1009    }
1010	
1011    /* Ok, we have both subjects, make sure they are the same. 
1012     * Compare the subjects */
1013    if ((findTemplate[0].ulValueLen != attr2->ulValueLen) || 
1014	(attr2->ulValueLen > 0 &&
1015	 PORT_Memcmp(findTemplate[0].pValue, attr2->pValue, attr2->ulValueLen) 
1016	 != 0)) {
1017    	crv = CKR_ATTRIBUTE_VALUE_INVALID; 
1018	goto loser;
1019    }
1020    crv = CKR_OK;
1021    
1022done:
1023    /* If we've failed for some other reason than a conflict, make sure we 
1024     * return an error code other than CKR_ATTRIBUTE_VALUE_INVALID. 
1025     * (NOTE: neither sdb_FindObjectsInit nor sdb_GetAttributeValue should 
1026     * return CKR_ATTRIBUTE_VALUE_INVALID, so the following is paranoia).
1027     */
1028    if (crv == CKR_ATTRIBUTE_VALUE_INVALID) {
1029	crv = CKR_GENERAL_ERROR; /* clearly a programming error */
1030    }
1031
1032    /* exit point if we found a conflict */
1033loser:
1034    PORT_Free(temp1);
1035    PORT_Free(temp2);
1036    return crv;
1037}
1038
1039/*
1040 * try to update the template to fix any errors. This is only done 
1041 * during update.
1042 *
1043 * NOTE: we must update the template or return an error, or the update caller 
1044 * will loop forever!
1045 *
1046 * Two copies of the source code for this algorithm exist in NSS.  
1047 * Changes must be made in both copies.
1048 * The other copy is in pk11_IncrementNickname() in pk11wrap/pk11merge.c.
1049 *
1050 */
1051static CK_RV
1052sftkdb_resolveConflicts(PRArenaPool *arena, CK_OBJECT_CLASS objectType, 
1053			CK_ATTRIBUTE *ptemplate, CK_ULONG *plen)
1054{
1055    CK_ATTRIBUTE *attr;
1056    char *nickname, *newNickname;
1057    int end, digit;
1058
1059    /* sanity checks. We should never get here with these errors */
1060    if (objectType != CKO_CERTIFICATE) {
1061	return CKR_GENERAL_ERROR; /* shouldn't happen */
1062    }
1063    attr = sftkdb_getAttributeFromTemplate(CKA_LABEL, ptemplate, *plen);
1064    if ((attr == NULL) || (attr->ulValueLen == 0)) {
1065	return CKR_GENERAL_ERROR; /* shouldn't happen */
1066    }
1067
1068    /* update the nickname */
1069    /* is there a number at the end of the nickname already?
1070     * if so just increment that number  */
1071    nickname = (char *)attr->pValue;
1072
1073    /* does nickname end with " #n*" ? */
1074    for (end = attr->ulValueLen - 1; 
1075         end >= 2 && (digit = nickname[end]) <= '9' &&  digit >= '0'; 
1076	 end--)  /* just scan */ ;
1077    if (attr->ulValueLen >= 3 &&
1078        end < (attr->ulValueLen - 1) /* at least one digit */ &&
1079	nickname[end]     == '#'  && 
1080	nickname[end - 1] == ' ') {
1081    	/* Already has a suitable suffix string */
1082    } else {
1083	/* ... append " #2" to the name */
1084	static const char num2[] = " #2";
1085	newNickname = PORT_ArenaAlloc(arena, attr->ulValueLen + sizeof(num2));
1086	if (!newNickname) {
1087	    return CKR_HOST_MEMORY;
1088	}
1089	PORT_Memcpy(newNickname, nickname, attr->ulValueLen);
1090	PORT_Memcpy(&newNickname[attr->ulValueLen], num2, sizeof(num2));
1091	attr->pValue = newNickname; /* modifies ptemplate */
1092	attr->ulValueLen += 3;      /* 3 is strlen(num2)  */
1093	return CKR_OK;
1094    }
1095
1096    for (end = attr->ulValueLen - 1; 
1097	 end >= 0 && (digit = nickname[end]) <= '9' &&  digit >= '0'; 
1098	 end--) {
1099	if (digit < '9') {
1100	    nickname[end]++;
1101	    return CKR_OK;
1102	}
1103	nickname[end] = '0';
1104    }
1105
1106    /* we overflowed, insert a new '1' for a carry in front of the number */
1107    newNickname = PORT_ArenaAlloc(arena, attr->ulValueLen + 1);
1108    if (!newNickname) {
1109	return CKR_HOST_MEMORY;
1110    }
1111    /* PORT_Memcpy should handle len of '0' */
1112    PORT_Memcpy(newNickname, nickname, ++end);
1113    newNickname[end] = '1';
1114    PORT_Memset(&newNickname[end+1],'0',attr->ulValueLen - end);
1115    attr->pValue = newNickname;
1116    attr->ulValueLen++;
1117    return CKR_OK;
1118}
1119
1120/*
1121 * set an attribute and sign it if necessary
1122 */
1123static CK_RV
1124sftkdb_setAttributeValue(PRArenaPool *arena, SFTKDBHandle *handle, 
1125	SDB *db, CK_OBJECT_HANDLE objectID, const CK_ATTRIBUTE *template, 
1126	CK_ULONG count)
1127{
1128    CK_RV crv;
1129    crv = (*db->sdb_SetAttributeValue)(db, objectID, template, count);
1130    if (crv != CKR_OK) {
1131	return crv;
1132    }
1133    crv = sftk_signTemplate(arena, handle, db == handle->update, 
1134				objectID, template, count);
1135    return crv;
1136}
1137
1138/*
1139 * write a softoken object out to the database.
1140 */
1141CK_RV
1142sftkdb_write(SFTKDBHandle *handle, SFTKObject *object, 
1143	     CK_OBJECT_HANDLE *objectID)
1144{
1145    CK_ATTRIBUTE *template;
1146    PLArenaPool *arena;
1147    CK_ULONG count;
1148    CK_RV crv;
1149    SDB *db;
1150    PRBool inTransaction = PR_FALSE;
1151    CK_OBJECT_HANDLE id;
1152
1153    *objectID = CK_INVALID_HANDLE;
1154
1155    if (handle == NULL) {
1156	return  CKR_TOKEN_WRITE_PROTECTED;
1157    }
1158    db = SFTK_GET_SDB(handle);
1159
1160    /*
1161     * we have opened a new database, but we have not yet updated it. We are
1162     * still running pointing to the old database (so the application can 
1163     * still read). We don't want to write to the old database at this point,
1164     * however, since it leads to user confusion. So at this point we simply
1165     * require a user login. Let NSS know this so it can prompt the user.
1166     */
1167    if (db == handle->update) {
1168	return CKR_USER_NOT_LOGGED_IN;
1169    }
1170
1171    arena = PORT_NewArena(256);
1172    if (arena ==  NULL) {
1173	return CKR_HOST_MEMORY;
1174    }
1175
1176    template = sftk_ExtractTemplate(arena, object, handle, &count, &crv);
1177    if (!template) {
1178	goto loser;
1179    }
1180
1181    crv = (*db->sdb_Begin)(db);
1182    if (crv != CKR_OK) {
1183	goto loser;
1184    }
1185    inTransaction = PR_TRUE;
1186
1187    /*
1188     * We want to make the base database as free from object specific knowledge
1189     * as possible. To maintain compatibility, keep some of the desirable
1190     * object specific semantics of the old database.
1191     * 
1192     * These were 2 fold:
1193     *  1) there were certain conflicts (like trying to set the same nickname 
1194     * on two different subjects) that would return an error.
1195     *  2) Importing the 'same' object would silently update that object.
1196     *
1197     * The following 2 functions mimic the desirable effects of these two
1198     * semantics without pushing any object knowledge to the underlying database
1199     * code.
1200     */
1201
1202    /* make sure we don't have attributes that conflict with the existing DB */
1203    crv = sftkdb_checkConflicts(db, object->objclass, template, count,
1204				 CK_INVALID_HANDLE);
1205    if (crv != CKR_OK) {
1206	goto loser;
1207    }
1208    /* Find any copies that match this particular object */
1209    crv = sftkdb_lookupObject(db, object->objclass, &id, template, count);
1210    if (crv != CKR_OK) {
1211	goto loser;
1212    }
1213    if (id == CK_INVALID_HANDLE) {
1214        crv = sftkdb_CreateObject(arena, handle, db, objectID, template, count);
1215    } else {
1216	/* object already exists, modify it's attributes */
1217	*objectID = id;
1218        crv = sftkdb_setAttributeValue(arena, handle, db, id, template, count);
1219    }
1220    if (crv != CKR_OK) {
1221	goto loser;
1222    }
1223
1224    crv = (*db->sdb_Commit)(db);
1225    inTransaction = PR_FALSE;
1226
1227loser:
1228    if (inTransaction) {
1229	(*db->sdb_Abort)(db);
1230	/* It is trivial to show the following code cannot
1231	 * happen unless something is horribly wrong with our compilier or
1232	 * hardware */
1233	PORT_Assert(crv != CKR_OK);
1234	if (crv == CKR_OK) crv = CKR_GENERAL_ERROR;
1235    }
1236
1237    if (arena) {
1238	PORT_FreeArena(arena,PR_FALSE);
1239    }
1240    if (crv == CKR_OK) {
1241	*objectID |= (handle->type | SFTK_TOKEN_TYPE);
1242    } 
1243    return crv;
1244}
1245
1246
1247CK_RV 
1248sftkdb_FindObjectsInit(SFTKDBHandle *handle, const CK_ATTRIBUTE *template,
1249				 CK_ULONG count, SDBFind **find) 
1250{
1251    unsigned char *data = NULL;
1252    CK_ATTRIBUTE *ntemplate = NULL;
1253    CK_RV crv;
1254    SDB *db;
1255
1256    if (handle == NULL) {
1257	return CKR_OK;
1258    }
1259    db = SFTK_GET_SDB(handle);
1260
1261    if (count !=  0) {
1262	ntemplate = sftkdb_fixupTemplateIn(template, count, &data);
1263	if (ntemplate == NULL) {
1264	    return CKR_HOST_MEMORY;
1265	}
1266    }
1267	
1268    crv = (*db->sdb_FindObjectsInit)(db, ntemplate, 
1269					     count, find);
1270    if (data) {
1271	PORT_Free(ntemplate);
1272	PORT_Free(data);
1273    }
1274    return crv;
1275}
1276
1277CK_RV 
1278sftkdb_FindObjects(SFTKDBHandle *handle, SDBFind *find, 
1279			CK_OBJECT_HANDLE *ids, int arraySize, CK_ULONG *count)
1280{
1281    CK_RV crv;
1282    SDB *db;
1283
1284    if (handle == NULL) {
1285	*count = 0;
1286	return CKR_OK;
1287    }
1288    db = SFTK_GET_SDB(handle);
1289
1290    crv = (*db->sdb_FindObjects)(db, find, ids, 
1291					    arraySize, count);
1292    if (crv == CKR_OK) {
1293	int i;
1294	for (i=0; i < *count; i++) {
1295	    ids[i] |= (handle->type | SFTK_TOKEN_TYPE);
1296	}
1297    }
1298    return crv;
1299}
1300
1301CK_RV sftkdb_FindObjectsFinal(SFTKDBHandle *handle, SDBFind *find)
1302{
1303    SDB *db;
1304    if (handle == NULL) {
1305	return CKR_OK;
1306    }
1307    db = SFTK_GET_SDB(handle);
1308    return (*db->sdb_FindObjectsFinal)(db, find);
1309}
1310
1311CK_RV
1312sftkdb_GetAttributeValue(SFTKDBHandle *handle, CK_OBJECT_HANDLE objectID,
1313                                CK_ATTRIBUTE *template, CK_ULONG count)
1314{
1315    CK_RV crv,crv2;
1316    CK_ATTRIBUTE *ntemplate;
1317    unsigned char *data = NULL;
1318    SDB *db;
1319
1320    if (handle == NULL) {
1321	return CKR_GENERAL_ERROR;
1322    }
1323
1324    /* short circuit common attributes */
1325    if (count == 1 && 
1326	  (template[0].type == CKA_TOKEN || 
1327	   template[0].type == CKA_PRIVATE ||
1328	   template[0].type == CKA_SENSITIVE)) {
1329	CK_BBOOL boolVal = CK_TRUE;
1330
1331	if (template[0].pValue == NULL) {
1332	    template[0].ulValueLen = sizeof(CK_BBOOL);
1333	    return CKR_OK;
1334	}
1335	if (template[0].ulValueLen < sizeof(CK_BBOOL)) {
1336	    template[0].ulValueLen = -1;
1337	    return CKR_BUFFER_TOO_SMALL;
1338	}
1339
1340	if ((template[0].type == CKA_PRIVATE) &&
1341    				(handle->type != SFTK_KEYDB_TYPE)) {
1342	    boolVal = CK_FALSE;
1343	}
1344	if ((template[0].type == CKA_SENSITIVE) &&
1345    				(handle->type != SFTK_KEYDB_TYPE)) {
1346	    boolVal = CK_FALSE;
1347	}
1348	*(CK_BBOOL *)template[0].pValue = boolVal;
1349	template[0].ulValueLen = sizeof(CK_BBOOL);
1350	return CKR_OK;
1351    }
1352
1353    db = SFTK_GET_SDB(handle);
1354    /* nothing to do */
1355    if (count == 0) {
1356	return CKR_OK;
1357    }
1358    ntemplate = sftkdb_fixupTemplateIn(template, count, &data);
1359    if (ntemplate == NULL) {
1360	return CKR_HOST_MEMORY;
1361    }
1362    objectID &= SFTK_OBJ_ID_MASK;
1363    crv = (*db->sdb_GetAttributeValue)(db, objectID, 
1364						ntemplate, count);
1365    crv2 = sftkdb_fixupTemplateOut(template, objectID, ntemplate, 
1366						count, handle);
1367    if (crv == CKR_OK) crv = crv2;
1368    if (data) {
1369	PORT_Free(ntemplate);
1370	PORT_Free(data);
1371    }
1372    return crv;
1373
1374}
1375
1376CK_RV
1377sftkdb_SetAttributeValue(SFTKDBHandle *handle, SFTKObject *object,
1378                                const CK_ATTRIBUTE *template, CK_ULONG count)
1379{
1380    CK_ATTRIBUTE *ntemplate;
1381    unsigned char *data = NULL;
1382    PLArenaPool *arena = NULL;
1383    SDB *db;
1384    CK_RV crv = CKR_OK;
1385    CK_OBJECT_HANDLE objectID = (object->handle & SFTK_OBJ_ID_MASK);
1386    PRBool inTransaction = PR_FALSE;
1387
1388    if (handle == NULL) {
1389	return CKR_TOKEN_WRITE_PROTECTED;
1390    }
1391
1392    db = SFTK_GET_SDB(handle);
1393    /* nothing to do */
1394    if (count == 0) {
1395	return CKR_OK;
1396    }
1397    /*
1398     * we have opened a new database, but we have not yet updated it. We are
1399     * still running  pointing to the old database (so the application can 
1400     * still read). We don't want to write to the old database at this point,
1401     * however, since it leads to user confusion. So at this point we simply
1402     * require a user login. Let NSS know this so it can prompt the user.
1403     */
1404    if (db == handle->update) {
1405	return CKR_USER_NOT_LOGGED_IN;
1406    }
1407
1408    ntemplate = sftkdb_fixupTemplateIn(template, count, &data);
1409    if (ntemplate == NULL) {
1410	return CKR_HOST_MEMORY;
1411    }
1412
1413    /* make sure we don't have attributes that conflict with the existing DB */
1414    crv = sftkdb_checkConflicts(db, object->objclass, template, count, objectID);
1415    if (crv != CKR_OK) {
1416	goto loser;
1417    }
1418
1419    arena = PORT_NewArena(256);
1420    if (arena ==  NULL) {
1421	crv = CKR_HOST_MEMORY;
1422	goto loser;
1423    }
1424
1425    crv = (*db->sdb_Begin)(db);
1426    if (crv != CKR_OK) {
1427	goto loser;
1428    }
1429    inTransaction = PR_TRUE;
1430    crv = sftkdb_setAttributeValue(arena, handle, db, 
1431				   objectID, template, count);
1432    if (crv != CKR_OK) {
1433	goto loser;
1434    }
1435    crv = (*db->sdb_Commit)(db);
1436loser:
1437    if (crv != CKR_OK && inTransaction) {
1438	(*db->sdb_Abort)(db);
1439    }
1440    if (data) {
1441	PORT_Free(ntemplate);
1442	PORT_Free(data);
1443    }
1444    if (arena) {
1445	PORT_FreeArena(arena, PR_FALSE);
1446    }
1447    return crv;
1448}
1449
1450CK_RV
1451sftkdb_DestroyObject(SFTKDBHandle *handle, CK_OBJECT_HANDLE objectID)
1452{
1453    CK_RV crv = CKR_OK;
1454    SDB *db;
1455
1456    if (handle == NULL) {
1457	return CKR_TOKEN_WRITE_PROTECTED;
1458    }
1459    db = SFTK_GET_SDB(handle);
1460    objectID &= SFTK_OBJ_ID_MASK;
1461    crv = (*db->sdb_Begin)(db);
1462    if (crv != CKR_OK) {
1463	goto loser;
1464    }
1465    crv = (*db->sdb_DestroyObject)(db, objectID);
1466    if (crv != CKR_OK) {
1467	goto loser;
1468    }
1469    crv = (*db->sdb_Commit)(db);
1470loser:
1471    if (crv != CKR_OK) {
1472	(*db->sdb_Abort)(db);
1473    }
1474    return crv;
1475}
1476
1477CK_RV
1478sftkdb_CloseDB(SFTKDBHandle *handle)
1479{
1480#ifdef NO_FORK_CHECK
1481    PRBool parentForkedAfterC_Initialize = PR_FALSE;
1482#endif
1483    if (handle == NULL) {
1484	return CKR_OK;
1485    }
1486    if (handle->update) {
1487        if (handle->db->sdb_SetForkState) {
1488            (*handle->db->sdb_SetForkState)(parentForkedAfterC_Initialize);
1489        }
1490	(*handle->update->sdb_Close)(handle->update);
1491    }
1492    if (handle->db) {
1493        if (handle->db->sdb_SetForkState) {
1494            (*handle->db->sdb_SetForkState)(parentForkedAfterC_Initialize);
1495        }
1496	(*handle->db->sdb_Close)(handle->db);
1497    }
1498    if (handle->passwordKey.data) {
1499	PORT_ZFree(handle->passwordKey.data, handle->passwordKey.len);
1500    }
1501    if (handle->passwordLock) {
1502	SKIP_AFTER_FORK(PZ_DestroyLock(handle->passwordLock));
1503    }
1504    if (handle->updatePasswordKey) {
1505	SECITEM_FreeItem(handle->updatePasswordKey, PR_TRUE);
1506    }
1507    if (handle->updateID) {
1508	PORT_Free(handle->updateID);
1509    }
1510    PORT_Free(handle);
1511    return CKR_OK;
1512}
1513
1514/*
1515 * reset a database to it's uninitialized state. 
1516 */
1517static CK_RV
1518sftkdb_ResetDB(SFTKDBHandle *handle)
1519{
1520    CK_RV crv = CKR_OK;
1521    SDB *db;
1522    if (handle == NULL) {
1523	return CKR_TOKEN_WRITE_PROTECTED;
1524    }
1525    db = SFTK_GET_SDB(handle);
1526    crv = (*db->sdb_Begin)(db);
1527    if (crv != CKR_OK) {
1528	goto loser;
1529    }
1530    crv = (*db->sdb_Reset)(db);
1531    if (crv != CKR_OK) {
1532	goto loser;
1533    }
1534    crv = (*db->sdb_Commit)(db);
1535loser:
1536    if (crv != CKR_OK) {
1537	(*db->sdb_Abort)(db);
1538    }
1539    return crv;
1540}
1541
1542
1543CK_RV
1544sftkdb_Begin(SFTKDBHandle *handle)
1545{
1546    CK_RV crv = CKR_OK;
1547    SDB *db;
1548
1549    if (handle == NULL) {
1550	return CKR_OK;
1551    }
1552    db = SFTK_GET_SDB(handle);
1553    if (db) {
1554	crv = (*db->sdb_Begin)(db);
1555    }
1556    return crv;
1557}
1558
1559CK_RV
1560sftkdb_Commit(SFTKDBHandle *handle)
1561{
1562    CK_RV crv = CKR_OK;
1563    SDB *db;
1564
1565    if (handle == NULL) {
1566	return CKR_OK;
1567    }
1568    db = SFTK_GET_SDB(handle);
1569    if (db) {
1570	(*db->sdb_Commit)(db);
1571    }
1572    return crv;
1573}
1574
1575CK_RV
1576sftkdb_Abort(SFTKDBHandle *handle)
1577{
1578    CK_RV crv = CKR_OK;
1579    SDB *db;
1580
1581    if (handle == NULL) {
1582	return CKR_OK;
1583    }
1584    db = SFTK_GET_SDB(handle);
1585    if (db) {
1586	crv = (db->sdb_Abort)(db);
1587    }
1588    return crv;
1589}
1590
1591
1592/*
1593 * functions to update the database from an old database
1594 */
1595
1596/*
1597 * known attributes
1598 */
1599static const CK_ATTRIBUTE_TYPE known_attributes[] = {
1600    CKA_CLASS, CKA_TOKEN, CKA_PRIVATE, CKA_LABEL, CKA_APPLICATION,
1601    CKA_VALUE, CKA_OBJECT_ID, CKA_CERTIFICATE_TYPE, CKA_ISSUER,
1602    CKA_SERIAL_NUMBER, CKA_AC_ISSUER, CKA_OWNER, CKA_ATTR_TYPES, CKA_TRUSTED,
1603    CKA_CERTIFICATE_CATEGORY, CKA_JAVA_MIDP_SECURITY_DOMAIN, CKA_URL,
1604    CKA_HASH_OF_SUBJECT_PUBLIC_KEY, CKA_HASH_OF_ISSUER_PUBLIC_KEY,
1605    CKA_CHECK_VALUE, CKA_KEY_TYPE, CKA_SUBJECT, CKA_ID, CKA_SENSITIVE,
1606    CKA_ENCRYPT, CKA_DECRYPT, CKA_WRAP, CKA_UNWRAP, CKA_SIGN, CKA_SIGN_RECOVER,
1607    CKA_VERIFY, CKA_VERIFY_RECOVER, CKA_DERIVE, CKA_START_DATE, CKA_END_DATE,
1608    CKA_MODULUS, CKA_MODULUS_BITS, CKA_PUBLIC_EXPONENT, CKA_PRIVATE_EXPONENT,
1609    CKA_PRIME_1, CKA_PRIME_2, CKA_EXPONENT_1, CKA_EXPONENT_2, CKA_COEFFICIENT,
1610    CKA_PRIME, CKA_SUBPRIME, CKA_BASE, CKA_PRIME_BITS, 
1611    CKA_SUB_PRIME_BITS, CKA_VALUE_BITS, CKA_VALUE_LEN, CKA_EXTRACTABLE,
1612    CKA_LOCAL, CKA_NEVER_EXTRACTABLE, CKA_ALWAYS_SENSITIVE,
1613    CKA_KEY_GEN_MECHANISM, CKA_MODIFIABLE, CKA_EC_PARAMS,
1614    CKA_EC_POINT, CKA_SECONDARY_AUTH, CKA_AUTH_PIN_FLAGS,
1615    CKA_ALWAYS_AUTHENTICATE, CKA_WRAP_WITH_TRUSTED, CKA_WRAP_TEMPLATE,
1616    CKA_UNWRAP_TEMPLATE, CKA_HW_FEATURE_TYPE, CKA_RESET_ON_INIT,
1617    CKA_HAS_RESET, CKA_PIXEL_X, CKA_PIXEL_Y, CKA_RESOLUTION, CKA_CHAR_ROWS,
1618    CKA_CHAR_COLUMNS, CKA_COLOR, CKA_BITS_PER_PIXEL, CKA_CHAR_SETS,
1619    CKA_ENCODING_METHODS, CKA_MIME_TYPES, CKA_MECHANISM_TYPE,
1620    CKA_REQUIRED_CMS_ATTRIBUTES, CKA_DEFAULT_CMS_ATTRIBUTES,
1621    CKA_SUPPORTED_CMS_ATTRIBUTES, CKA_NSS_URL, CKA_NSS_EMAIL,
1622    CKA_NSS_SMIME_INFO, CKA_NSS_SMIME_TIMESTAMP,
1623    CKA_NSS_PKCS8_SALT, CKA_NSS_PASSWORD_CHECK, CKA_NSS_EXPIRES,
1624    CKA_NSS_KRL, CKA_NSS_PQG_COUNTER, CKA_NSS_PQG_SEED,
1625    CKA_NSS_PQG_H, CKA_NSS_PQG_SEED_BITS, CKA_NSS_MODULE_SPEC,
1626    CKA_TRUST_DIGITAL_SIGNATURE, CKA_TRUST_NON_REPUDIATION,
1627    CKA_TRUST_KEY_ENCIPHERMENT, CKA_TRUST_DATA_ENCIPHERMENT,
1628    CKA_TRUST_KEY_AGREEMENT, CKA_TRUST_KEY_CERT_SIGN, CKA_TRUST_CRL_SIGN,
1629    CKA_TRUST_SERVER_AUTH, CKA_TRUST_CLIENT_AUTH, CKA_TRUST_CODE_SIGNING,
1630    CKA_TRUST_EMAIL_PROTECTION, CKA_TRUST_IPSEC_END_SYSTEM,
1631    CKA_TRUST_IPSEC_TUNNEL, CKA_TRUST_IPSEC_USER, CKA_TRUST_TIME_STAMPING,
1632    CKA_TRUST_STEP_UP_APPROVED, CKA_CERT_SHA1_HASH, CKA_CERT_MD5_HASH,
1633    CKA_NETSCAPE_DB, CKA_NETSCAPE_TRUST, CKA_NSS_OVERRIDE_EXTENSIONS
1634};
1635
1636static int known_attributes_size= sizeof(known_attributes)/
1637			   sizeof(known_attributes[0]);
1638
1639static CK_RV
1640sftkdb_GetObjectTemplate(SDB *source, CK_OBJECT_HANDLE id,
1641		CK_ATTRIBUTE *ptemplate, CK_ULONG *max)
1642{
1643    int i,j;
1644    CK_RV crv;
1645
1646    if (*max < known_attributes_size) {
1647	*max = known_attributes_size;
1648	return CKR_BUFFER_TOO_SMALL;
1649    }
1650    for (i=0; i < known_attributes_size; i++) {
1651	ptemplate[i].type = known_attributes[i];
1652	ptemplate[i].pValue = NULL;
1653	ptemplate[i].ulValueLen = 0;
1654    }
1655
1656    crv = (*source->sdb_GetAttributeValue)(source, id, 
1657					ptemplate, known_attributes_size);
1658
1659    if ((crv != CKR_OK) && (crv != CKR_ATTRIBUTE_TYPE_INVALID)) {
1660	return crv;
1661    }
1662
1663    for (i=0, j=0; i < known_attributes_size; i++, j++) {
1664	while (i < known_attributes_size && (ptemplate[i].ulValueLen == -1)) {
1665	    i++;
1666	}
1667	if (i >= known_attributes_size) {
1668	    break;
1669	}
1670	/* cheap optimization */
1671	if (i == j) {
1672	   continue;
1673	}
1674	ptemplate[j] = ptemplate[i];
1675    }
1676    *max = j;
1677    return CKR_OK;
1678}
1679
1680static const char SFTKDB_META_UPDATE_TEMPLATE[] = "upd_%s_%s";
1681
1682/*
1683 * check to see if we have already updated this database.
1684 * a NULL updateID means we are trying to do an in place 
1685 * single database update. In that case we have already
1686 * determined that an update was necessary.
1687 */
1688static PRBool 
1689sftkdb_hasUpdate(const char *typeString, SDB *db, const char *updateID)
1690{
1691    char *id;
1692    CK_RV crv;
1693    SECItem dummy = { 0, NULL, 0 };
1694    unsigned char dummyData[SDB_MAX_META_DATA_LEN];
1695
1696    if (!updateID) {
1697	return PR_FALSE;
1698    }
1699    id = PR_smprintf(SFTKDB_META_UPDATE_TEMPLATE, typeString, updateID);
1700    if (id == NULL) {
1701	return PR_FALSE;
1702    }
1703    dummy.data = dummyData;
1704    dummy.len = sizeof(dummyData);
1705
1706    crv = (*db->sdb_GetMetaData)(db, id, &dummy, NULL);
1707    PR_smprintf_free(id);
1708    return crv == CKR_OK ? PR_TRUE : PR_FALSE;
1709}
1710
1711/*
1712 * we just completed an update, store the update id
1713 * so we don't need to do it again. If non was given,
1714 * there is nothing to do.
1715 */
1716static CK_RV
1717sftkdb_putUpdate(const char *typeString, SDB *db, const char *updateID)
1718{
1719    char *id;
1720    CK_RV crv;
1721    SECItem dummy = { 0, NULL, 0 };
1722
1723    /* if no id was given, nothing to do */
1724    if (updateID == NULL) {
1725	return CKR_OK;
1726    }
1727
1728    dummy.data = (unsigned char *)updateID;
1729    dummy.len = PORT_Strlen(updateID);
1730
1731    id = PR_smprintf(SFTKDB_META_UPDATE_TEMPLATE, typeString, updateID);
1732    if (id == NULL) {
1733	return PR_FALSE;
1734    }
1735
1736    crv = (*db->sdb_PutMetaData)(db, id, &dummy, NULL);
1737    PR_smprintf_free(id);
1738    return crv;
1739}
1740
1741/*
1742 * get a ULong attribute from a template:
1743 * NOTE: this is a raw templated stored in database order!
1744 */
1745static CK_ULONG
1746sftkdb_getULongFromTemplate(CK_ATTRIBUTE_TYPE type, 
1747			CK_ATTRIBUTE *ptemplate, CK_ULONG len)
1748{
1749    CK_ATTRIBUTE *attr = sftkdb_getAttributeFromTemplate(type,
1750					ptemplate, len);
1751
1752    if (attr && attr->pValue && attr->ulValueLen == SDB_ULONG_SIZE) {
1753	return sftk_SDBULong2ULong(attr->pValue);
1754    }
1755    return (CK_ULONG)-1;
1756}
1757
1758/*
1759 * we need to find a unique CKA_ID.
1760 *  The basic idea is to just increment the lowest byte.
1761 *  This code also handles the following corner cases:
1762 *   1) the single byte overflows. On overflow we increment the next byte up 
1763 *    and so forth until we have overflowed the entire CKA_ID.
1764 *   2) If we overflow the entire CKA_ID we expand it by one byte.
1765 *   3) the CKA_ID is non-existant, we create a new one with one byte.
1766 *    This means no matter what CKA_ID is passed, the result of this function 
1767 *    is always a new CKA_ID, and this function will never return the same 
1768 *    CKA_ID the it has returned in the passed.
1769 */
1770static CK_RV
1771sftkdb_incrementCKAID(PRArenaPool *arena, CK_ATTRIBUTE *ptemplate)
1772{
1773    unsigned cha

Large files files are truncated, but you can click here to view the full file