sftkdb.c (106706B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 /* 5 * The following code handles the storage of PKCS 11 modules used by the 6 * NSS. For the rest of NSS, only one kind of database handle exists: 7 * 8 * SFTKDBHandle 9 * 10 * There is one SFTKDBHandle for the each key database and one for each cert 11 * database. These databases are opened as associated pairs, one pair per 12 * slot. SFTKDBHandles are reference counted objects. 13 * 14 * Each SFTKDBHandle points to a low level database handle (SDB). This handle 15 * represents the underlying physical database. These objects are not 16 * reference counted, an are 'owned' by their respective SFTKDBHandles. 17 * 18 * 19 */ 20 #include "sftkdb.h" 21 #include "sftkdbti.h" 22 #include "pkcs11t.h" 23 #include "pkcs11i.h" 24 #include "sdb.h" 25 #include "prprf.h" 26 #include "pratom.h" 27 #include "lgglue.h" 28 #include "utilpars.h" 29 #include "secerr.h" 30 #include "softoken.h" 31 #if defined(_WIN32) 32 #include <windows.h> 33 #endif 34 35 /* 36 * We want all databases to have the same binary representation independent of 37 * endianness or length of the host architecture. In general PKCS #11 attributes 38 * are endian/length independent except those attributes that pass CK_ULONG. 39 * 40 * The following functions fixes up the CK_ULONG type attributes so that the data 41 * base sees a machine independent view. CK_ULONGs are stored as 4 byte network 42 * byte order values (big endian). 43 */ 44 #define BBP 8 45 46 PRBool 47 sftkdb_isULONGAttribute(CK_ATTRIBUTE_TYPE type) 48 { 49 switch (type) { 50 case CKA_CERTIFICATE_CATEGORY: 51 case CKA_CERTIFICATE_TYPE: 52 case CKA_CLASS: 53 case CKA_JAVA_MIDP_SECURITY_DOMAIN: 54 case CKA_KEY_GEN_MECHANISM: 55 case CKA_KEY_TYPE: 56 case CKA_MECHANISM_TYPE: 57 case CKA_MODULUS_BITS: 58 case CKA_PRIME_BITS: 59 case CKA_SUBPRIME_BITS: 60 case CKA_VALUE_BITS: 61 case CKA_VALUE_LEN: 62 63 case CKA_PKCS_TRUST_SERVER_AUTH: 64 case CKA_PKCS_TRUST_CLIENT_AUTH: 65 case CKA_PKCS_TRUST_CODE_SIGNING: 66 case CKA_PKCS_TRUST_EMAIL_PROTECTION: 67 case CKA_TRUST_IPSEC_IKE: 68 case CKA_PKCS_TRUST_TIME_STAMPING: 69 case CKA_NAME_HASH_ALGORITHM: 70 71 case CKA_NSS_TRUST_DIGITAL_SIGNATURE: 72 case CKA_NSS_TRUST_NON_REPUDIATION: 73 case CKA_NSS_TRUST_KEY_ENCIPHERMENT: 74 case CKA_NSS_TRUST_DATA_ENCIPHERMENT: 75 case CKA_NSS_TRUST_KEY_AGREEMENT: 76 case CKA_NSS_TRUST_KEY_CERT_SIGN: 77 case CKA_NSS_TRUST_CRL_SIGN: 78 79 case CKA_NSS_TRUST_SERVER_AUTH: 80 case CKA_NSS_TRUST_CLIENT_AUTH: 81 case CKA_NSS_TRUST_CODE_SIGNING: 82 case CKA_NSS_TRUST_EMAIL_PROTECTION: 83 case CKA_NSS_TRUST_IPSEC_END_SYSTEM: 84 case CKA_NSS_TRUST_IPSEC_TUNNEL: 85 case CKA_NSS_TRUST_IPSEC_USER: 86 case CKA_NSS_TRUST_TIME_STAMPING: 87 case CKA_NSS_TRUST_STEP_UP_APPROVED: 88 return PR_TRUE; 89 default: 90 break; 91 } 92 return PR_FALSE; 93 } 94 95 /* are the attributes private? */ 96 static PRBool 97 sftkdb_isPrivateAttribute(CK_ATTRIBUTE_TYPE type) 98 { 99 switch (type) { 100 case CKA_VALUE: 101 case CKA_SEED: 102 case CKA_PRIVATE_EXPONENT: 103 case CKA_PRIME_1: 104 case CKA_PRIME_2: 105 case CKA_EXPONENT_1: 106 case CKA_EXPONENT_2: 107 case CKA_COEFFICIENT: 108 return PR_TRUE; 109 default: 110 break; 111 } 112 return PR_FALSE; 113 } 114 115 /* These attributes must be authenticated with an hmac. */ 116 static PRBool 117 sftkdb_isAuthenticatedAttribute(CK_ATTRIBUTE_TYPE type) 118 { 119 switch (type) { 120 case CKA_MODULUS: 121 case CKA_PUBLIC_EXPONENT: 122 case CKA_NSS_CERT_SHA1_HASH: 123 case CKA_NSS_CERT_MD5_HASH: 124 case CKA_NSS_TRUST_SERVER_AUTH: 125 case CKA_NSS_TRUST_CLIENT_AUTH: 126 case CKA_NSS_TRUST_EMAIL_PROTECTION: 127 case CKA_NSS_TRUST_CODE_SIGNING: 128 case CKA_NSS_TRUST_STEP_UP_APPROVED: 129 case CKA_HASH_OF_CERTIFICATE: 130 case CKA_NAME_HASH_ALGORITHM: 131 case CKA_PKCS_TRUST_SERVER_AUTH: 132 case CKA_PKCS_TRUST_CLIENT_AUTH: 133 case CKA_PKCS_TRUST_EMAIL_PROTECTION: 134 case CKA_PKCS_TRUST_CODE_SIGNING: 135 case CKA_NSS_OVERRIDE_EXTENSIONS: 136 return PR_TRUE; 137 default: 138 break; 139 } 140 return PR_FALSE; 141 } 142 /* 143 * convert a native ULONG to a database ulong. Database ulong's 144 * are all 4 byte big endian values. 145 */ 146 void 147 sftk_ULong2SDBULong(unsigned char *data, CK_ULONG value) 148 { 149 int i; 150 151 for (i = 0; i < SDB_ULONG_SIZE; i++) { 152 data[i] = (value >> (SDB_ULONG_SIZE - 1 - i) * BBP) & 0xff; 153 } 154 } 155 156 /* 157 * convert a database ulong back to a native ULONG. (reverse of the above 158 * function). 159 */ 160 static CK_ULONG 161 sftk_SDBULong2ULong(unsigned char *data) 162 { 163 int i; 164 CK_ULONG value = 0; 165 166 for (i = 0; i < SDB_ULONG_SIZE; i++) { 167 value |= (((CK_ULONG)data[i]) << (SDB_ULONG_SIZE - 1 - i) * BBP); 168 } 169 return value; 170 } 171 172 /* certain trust records are default values, which are the values 173 * returned if the signature check fails anyway. 174 * In those cases, we can skip the signature check. */ 175 PRBool 176 sftkdb_isNullTrust(const CK_ATTRIBUTE *template) 177 { 178 switch (template->type) { 179 case CKA_NSS_TRUST_SERVER_AUTH: 180 case CKA_NSS_TRUST_CLIENT_AUTH: 181 case CKA_NSS_TRUST_EMAIL_PROTECTION: 182 case CKA_NSS_TRUST_CODE_SIGNING: 183 if (template->ulValueLen != SDB_ULONG_SIZE) { 184 break; 185 } 186 if (sftk_SDBULong2ULong(template->pValue) == 187 CKT_NSS_TRUST_UNKNOWN) { 188 return PR_TRUE; 189 } 190 break; 191 case CKA_PKCS_TRUST_SERVER_AUTH: 192 case CKA_PKCS_TRUST_CLIENT_AUTH: 193 case CKA_PKCS_TRUST_EMAIL_PROTECTION: 194 case CKA_PKCS_TRUST_CODE_SIGNING: 195 if (template->ulValueLen != SDB_ULONG_SIZE) { 196 break; 197 } 198 if (sftk_SDBULong2ULong(template->pValue) == 199 CKT_TRUST_UNKNOWN) { 200 return PR_TRUE; 201 } 202 break; 203 case CKA_NSS_TRUST_STEP_UP_APPROVED: 204 if (template->ulValueLen != 1) { 205 break; 206 } 207 if (*((unsigned char *)(template->pValue)) == 0) { 208 return PR_TRUE; 209 } 210 break; 211 default: 212 break; 213 } 214 return PR_FALSE; 215 } 216 217 /* 218 * fix up the input templates. Our fixed up ints are stored in data and must 219 * be freed by the caller. The new template must also be freed. If there are no 220 * CK_ULONG attributes, the orignal template is passed in as is. 221 */ 222 static CK_ATTRIBUTE * 223 sftkdb_fixupTemplateIn(const CK_ATTRIBUTE *template, int count, 224 unsigned char **dataOut, int *dataOutSize) 225 { 226 int i; 227 int ulongCount = 0; 228 unsigned char *data; 229 CK_ATTRIBUTE *ntemplate; 230 231 *dataOut = NULL; 232 *dataOutSize = 0; 233 234 /* first count the number of CK_ULONG attributes */ 235 for (i = 0; i < count; i++) { 236 /* Don't 'fixup' NULL values */ 237 if (!template[i].pValue) { 238 continue; 239 } 240 if (template[i].ulValueLen == sizeof(CK_ULONG)) { 241 if (sftkdb_isULONGAttribute(template[i].type)) { 242 ulongCount++; 243 } 244 } 245 } 246 /* no attributes to fixup, just call on through */ 247 if (ulongCount == 0) { 248 return (CK_ATTRIBUTE *)template; 249 } 250 251 /* allocate space for new ULONGS */ 252 data = (unsigned char *)PORT_Alloc(SDB_ULONG_SIZE * ulongCount); 253 if (!data) { 254 return NULL; 255 } 256 257 /* allocate new template */ 258 ntemplate = PORT_NewArray(CK_ATTRIBUTE, count); 259 if (!ntemplate) { 260 PORT_Free(data); 261 return NULL; 262 } 263 *dataOut = data; 264 *dataOutSize = SDB_ULONG_SIZE * ulongCount; 265 /* copy the old template, fixup the actual ulongs */ 266 for (i = 0; i < count; i++) { 267 ntemplate[i] = template[i]; 268 /* Don't 'fixup' NULL values */ 269 if (!template[i].pValue) { 270 continue; 271 } 272 if (template[i].ulValueLen == sizeof(CK_ULONG)) { 273 if (sftkdb_isULONGAttribute(template[i].type)) { 274 CK_ULONG value = *(CK_ULONG *)template[i].pValue; 275 sftk_ULong2SDBULong(data, value); 276 ntemplate[i].pValue = data; 277 ntemplate[i].ulValueLen = SDB_ULONG_SIZE; 278 data += SDB_ULONG_SIZE; 279 } 280 } 281 } 282 return ntemplate; 283 } 284 285 static const char SFTKDB_META_SIG_TEMPLATE[] = "sig_%s_%08x_%08x"; 286 287 /* 288 * return a string describing the database type (key or cert) 289 */ 290 const char * 291 sftkdb_TypeString(SFTKDBHandle *handle) 292 { 293 return (handle->type == SFTK_KEYDB_TYPE) ? "key" : "cert"; 294 } 295 296 /* 297 * Some attributes are signed with an Hmac and a pbe key generated from 298 * the password. This signature is stored indexed by object handle and 299 * attribute type in the meta data table in the key database. 300 * 301 * Signature entries are indexed by the string 302 * sig_[cert/key]_{ObjectID}_{Attribute} 303 * 304 * This function fetches that pkcs5 signature. Caller supplies a SECItem 305 * pre-allocated to the appropriate size if the SECItem is too small the 306 * function will fail with CKR_BUFFER_TOO_SMALL. 307 */ 308 static CK_RV 309 sftkdb_getRawAttributeSignature(SFTKDBHandle *handle, SDB *db, 310 CK_OBJECT_HANDLE objectID, 311 CK_ATTRIBUTE_TYPE type, 312 SECItem *signText) 313 { 314 char id[30]; 315 CK_RV crv; 316 317 snprintf(id, sizeof(id), SFTKDB_META_SIG_TEMPLATE, 318 sftkdb_TypeString(handle), 319 (unsigned int)objectID, (unsigned int)type); 320 321 crv = (*db->sdb_GetMetaData)(db, id, signText, NULL); 322 return crv; 323 } 324 325 CK_RV 326 sftkdb_GetAttributeSignature(SFTKDBHandle *handle, SFTKDBHandle *keyHandle, 327 CK_OBJECT_HANDLE objectID, CK_ATTRIBUTE_TYPE type, 328 SECItem *signText) 329 { 330 SDB *db = SFTK_GET_SDB(keyHandle); 331 return sftkdb_getRawAttributeSignature(handle, db, objectID, type, signText); 332 } 333 334 CK_RV 335 sftkdb_DestroyAttributeSignature(SFTKDBHandle *handle, SDB *db, 336 CK_OBJECT_HANDLE objectID, 337 CK_ATTRIBUTE_TYPE type) 338 { 339 char id[30]; 340 CK_RV crv; 341 342 snprintf(id, sizeof(id), SFTKDB_META_SIG_TEMPLATE, 343 sftkdb_TypeString(handle), 344 (unsigned int)objectID, (unsigned int)type); 345 346 crv = (*db->sdb_DestroyMetaData)(db, id); 347 return crv; 348 } 349 350 /* 351 * Some attributes are signed with an Hmac and a pbe key generated from 352 * the password. This signature is stored indexed by object handle and 353 * attribute type in the meta data table in the key database. 354 * 355 * Signature entries are indexed by the string 356 * sig_[cert/key]_{ObjectID}_{Attribute} 357 * 358 * This function stores that pkcs5 signature. 359 */ 360 CK_RV 361 sftkdb_PutAttributeSignature(SFTKDBHandle *handle, SDB *keyTarget, 362 CK_OBJECT_HANDLE objectID, CK_ATTRIBUTE_TYPE type, 363 SECItem *signText) 364 { 365 char id[30]; 366 CK_RV crv; 367 368 snprintf(id, sizeof(id), SFTKDB_META_SIG_TEMPLATE, 369 sftkdb_TypeString(handle), 370 (unsigned int)objectID, (unsigned int)type); 371 372 crv = (*keyTarget->sdb_PutMetaData)(keyTarget, id, signText, NULL); 373 return crv; 374 } 375 376 /* 377 * fix up returned data. NOTE: sftkdb_fixupTemplateIn has already allocated 378 * separate data sections for the database ULONG values. 379 */ 380 static CK_RV 381 sftkdb_fixupTemplateOut(CK_ATTRIBUTE *template, CK_OBJECT_HANDLE objectID, 382 CK_ATTRIBUTE *ntemplate, int count, SFTKDBHandle *handle) 383 { 384 int i; 385 CK_RV crv = CKR_OK; 386 SFTKDBHandle *keyHandle; 387 PRBool checkSig = PR_TRUE; 388 PRBool checkEnc = PR_TRUE; 389 390 PORT_Assert(handle); 391 392 /* find the key handle */ 393 keyHandle = handle; 394 if (handle->type != SFTK_KEYDB_TYPE) { 395 checkEnc = PR_FALSE; 396 keyHandle = handle->peerDB; 397 } 398 399 if ((keyHandle == NULL) || 400 ((SFTK_GET_SDB(keyHandle)->sdb_flags & SDB_HAS_META) == 0) || 401 (sftkdb_PWCached(keyHandle) != SECSuccess)) { 402 checkSig = PR_FALSE; 403 } 404 405 for (i = 0; i < count; i++) { 406 CK_ULONG length = template[i].ulValueLen; 407 template[i].ulValueLen = ntemplate[i].ulValueLen; 408 /* fixup ulongs */ 409 if (ntemplate[i].ulValueLen == SDB_ULONG_SIZE) { 410 if (sftkdb_isULONGAttribute(template[i].type)) { 411 if (template[i].pValue) { 412 CK_ULONG value; 413 414 value = sftk_SDBULong2ULong(ntemplate[i].pValue); 415 if (length < sizeof(CK_ULONG)) { 416 template[i].ulValueLen = -1; 417 crv = CKR_BUFFER_TOO_SMALL; 418 continue; 419 } 420 PORT_Memcpy(template[i].pValue, &value, sizeof(CK_ULONG)); 421 } 422 template[i].ulValueLen = sizeof(CK_ULONG); 423 } 424 } 425 426 /* if no data was retrieved, no need to process encrypted or signed 427 * attributes */ 428 if ((template[i].pValue == NULL) || (template[i].ulValueLen == -1)) { 429 continue; 430 } 431 432 /* fixup private attributes */ 433 if (checkEnc && sftkdb_isPrivateAttribute(ntemplate[i].type)) { 434 /* we have a private attribute */ 435 /* This code depends on the fact that the cipherText is bigger 436 * than the plain text */ 437 SECItem cipherText; 438 SECItem *plainText; 439 SECStatus rv; 440 441 cipherText.data = ntemplate[i].pValue; 442 cipherText.len = ntemplate[i].ulValueLen; 443 PZ_Lock(handle->passwordLock); 444 if (handle->passwordKey.data == NULL) { 445 PZ_Unlock(handle->passwordLock); 446 template[i].ulValueLen = -1; 447 crv = CKR_USER_NOT_LOGGED_IN; 448 continue; 449 } 450 rv = sftkdb_DecryptAttribute(handle, 451 &handle->passwordKey, 452 objectID, 453 ntemplate[i].type, 454 &cipherText, &plainText); 455 PZ_Unlock(handle->passwordLock); 456 if (rv != SECSuccess) { 457 PORT_Memset(template[i].pValue, 0, template[i].ulValueLen); 458 template[i].ulValueLen = -1; 459 crv = CKR_GENERAL_ERROR; 460 continue; 461 } 462 PORT_Assert(template[i].ulValueLen >= plainText->len); 463 if (template[i].ulValueLen < plainText->len) { 464 SECITEM_ZfreeItem(plainText, PR_TRUE); 465 PORT_Memset(template[i].pValue, 0, template[i].ulValueLen); 466 template[i].ulValueLen = -1; 467 crv = CKR_GENERAL_ERROR; 468 continue; 469 } 470 471 /* copy the plain text back into the template */ 472 PORT_Memcpy(template[i].pValue, plainText->data, plainText->len); 473 template[i].ulValueLen = plainText->len; 474 SECITEM_ZfreeItem(plainText, PR_TRUE); 475 } 476 /* make sure signed attributes are valid */ 477 if (checkSig && sftkdb_isAuthenticatedAttribute(ntemplate[i].type) && !sftkdb_isNullTrust(&ntemplate[i])) { 478 SECStatus rv; 479 CK_RV local_crv; 480 SECItem signText; 481 SECItem plainText; 482 unsigned char signData[SDB_MAX_META_DATA_LEN]; 483 484 signText.data = signData; 485 signText.len = sizeof(signData); 486 487 /* Use a local variable so that we don't clobber any already 488 * set error. This function returns either CKR_OK or the last 489 * found error in the template */ 490 local_crv = sftkdb_GetAttributeSignature(handle, keyHandle, 491 objectID, 492 ntemplate[i].type, 493 &signText); 494 if (local_crv != CKR_OK) { 495 PORT_Memset(template[i].pValue, 0, template[i].ulValueLen); 496 template[i].ulValueLen = -1; 497 crv = local_crv; 498 continue; 499 } 500 501 plainText.data = ntemplate[i].pValue; 502 plainText.len = ntemplate[i].ulValueLen; 503 504 /* 505 * we do a second check holding the lock just in case the user 506 * loggout while we were trying to get the signature. 507 */ 508 PZ_Lock(keyHandle->passwordLock); 509 if (keyHandle->passwordKey.data == NULL) { 510 /* if we are no longer logged in, no use checking the other 511 * Signatures either. */ 512 checkSig = PR_FALSE; 513 PZ_Unlock(keyHandle->passwordLock); 514 continue; 515 } 516 517 rv = sftkdb_VerifyAttribute(keyHandle, 518 &keyHandle->passwordKey, 519 objectID, ntemplate[i].type, 520 &plainText, &signText); 521 PZ_Unlock(keyHandle->passwordLock); 522 if (rv != SECSuccess) { 523 PORT_Memset(template[i].pValue, 0, template[i].ulValueLen); 524 template[i].ulValueLen = -1; 525 crv = CKR_SIGNATURE_INVALID; /* better error code? */ 526 } 527 /* This Attribute is fine */ 528 } 529 } 530 return crv; 531 } 532 533 /* 534 * Some attributes are signed with an HMAC and a pbe key generated from 535 * the password. This signature is stored indexed by object handle and 536 * 537 * Those attributes are: 538 * 1) Trust object hashes and trust values. 539 * 2) public key values. 540 * 541 * Certs themselves are considered properly authenticated by virtue of their 542 * signature, or their matching hash with the trust object. 543 * 544 * These signature is only checked for objects coming from shared databases. 545 * Older dbm style databases have such no signature checks. HMACs are also 546 * only checked when the token is logged in, as it requires a pbe generated 547 * from the password. 548 * 549 * Tokens which have no key database (and therefore no master password) do not 550 * have any stored signature values. Signature values are stored in the key 551 * database, since the signature data is tightly coupled to the key database 552 * password. 553 * 554 * This function takes a template of attributes that were either created or 555 * modified. These attributes are checked to see if the need to be signed. 556 * If they do, then this function signs the attributes and writes them 557 * to the meta data store. 558 * 559 * This function can fail if there are attributes that must be signed, but 560 * the token is not logged in. 561 * 562 * The caller is expected to abort any transaction he was in in the 563 * event of a failure of this function. 564 */ 565 static CK_RV 566 sftk_signTemplate(PLArenaPool *arena, SFTKDBHandle *handle, 567 PRBool mayBeUpdateDB, 568 CK_OBJECT_HANDLE objectID, const CK_ATTRIBUTE *template, 569 CK_ULONG count) 570 { 571 unsigned int i; 572 CK_RV crv; 573 SFTKDBHandle *keyHandle = handle; 574 SDB *keyTarget = NULL; 575 PRBool usingPeerDB = PR_FALSE; 576 PRBool inPeerDBTransaction = PR_FALSE; 577 578 PORT_Assert(handle); 579 580 if (handle->type != SFTK_KEYDB_TYPE) { 581 keyHandle = handle->peerDB; 582 usingPeerDB = PR_TRUE; 583 } 584 585 /* no key DB defined? then no need to sign anything */ 586 if (keyHandle == NULL) { 587 crv = CKR_OK; 588 goto loser; 589 } 590 591 /* When we are in a middle of an update, we have an update database set, 592 * but we want to write to the real database. The bool mayBeUpdateDB is 593 * set to TRUE if it's possible that we want to write an update database 594 * rather than a primary */ 595 keyTarget = (mayBeUpdateDB && keyHandle->update) ? keyHandle->update : keyHandle->db; 596 597 /* skip the the database does not support meta data */ 598 if ((keyTarget->sdb_flags & SDB_HAS_META) == 0) { 599 crv = CKR_OK; 600 goto loser; 601 } 602 603 /* If we had to switch databases, we need to initialize a transaction. */ 604 if (usingPeerDB) { 605 crv = (*keyTarget->sdb_Begin)(keyTarget); 606 if (crv != CKR_OK) { 607 goto loser; 608 } 609 inPeerDBTransaction = PR_TRUE; 610 } 611 612 for (i = 0; i < count; i++) { 613 if (sftkdb_isAuthenticatedAttribute(template[i].type)) { 614 SECStatus rv; 615 SECItem *signText; 616 SECItem plainText; 617 618 plainText.data = template[i].pValue; 619 plainText.len = template[i].ulValueLen; 620 PZ_Lock(keyHandle->passwordLock); 621 if (keyHandle->passwordKey.data == NULL) { 622 PZ_Unlock(keyHandle->passwordLock); 623 crv = CKR_USER_NOT_LOGGED_IN; 624 goto loser; 625 } 626 rv = sftkdb_SignAttribute(arena, keyHandle, keyTarget, 627 &keyHandle->passwordKey, 628 keyHandle->defaultIterationCount, 629 objectID, template[i].type, 630 &plainText, &signText); 631 PZ_Unlock(keyHandle->passwordLock); 632 if (rv != SECSuccess) { 633 crv = CKR_GENERAL_ERROR; /* better error code here? */ 634 goto loser; 635 } 636 crv = sftkdb_PutAttributeSignature(handle, keyTarget, objectID, 637 template[i].type, signText); 638 if (crv != CKR_OK) { 639 goto loser; 640 } 641 } 642 } 643 crv = CKR_OK; 644 645 /* If necessary, commit the transaction */ 646 if (inPeerDBTransaction) { 647 crv = (*keyTarget->sdb_Commit)(keyTarget); 648 if (crv != CKR_OK) { 649 goto loser; 650 } 651 inPeerDBTransaction = PR_FALSE; 652 } 653 654 loser: 655 if (inPeerDBTransaction) { 656 /* The transaction must have failed. Abort. */ 657 (*keyTarget->sdb_Abort)(keyTarget); 658 PORT_Assert(crv != CKR_OK); 659 if (crv == CKR_OK) 660 crv = CKR_GENERAL_ERROR; 661 } 662 return crv; 663 } 664 665 static CK_RV 666 sftkdb_CreateObject(PLArenaPool *arena, SFTKDBHandle *handle, 667 SDB *db, CK_OBJECT_HANDLE *objectID, 668 CK_ATTRIBUTE *template, CK_ULONG count) 669 { 670 CK_RV crv; 671 672 crv = (*db->sdb_CreateObject)(db, objectID, template, count); 673 if (crv != CKR_OK) { 674 goto loser; 675 } 676 crv = sftk_signTemplate(arena, handle, (db == handle->update), 677 *objectID, template, count); 678 loser: 679 680 return crv; 681 } 682 683 static CK_RV 684 sftkdb_fixupSignatures(SFTKDBHandle *handle, 685 SDB *db, CK_OBJECT_HANDLE oldID, CK_OBJECT_HANDLE newID, 686 CK_ATTRIBUTE *ptemplate, CK_ULONG max_attributes) 687 { 688 unsigned int i; 689 CK_RV crv = CKR_OK; 690 691 /* if we don't have a meta table, we didn't write any signature objects */ 692 if ((db->sdb_flags & SDB_HAS_META) == 0) { 693 return CKR_OK; 694 } 695 for (i = 0; i < max_attributes; i++) { 696 CK_ATTRIBUTE *att = &ptemplate[i]; 697 CK_ATTRIBUTE_TYPE type = att->type; 698 if (sftkdb_isPrivateAttribute(type)) { 699 /* move the signature from one object handle to another and delete 700 * the old entry */ 701 SECItem signature; 702 unsigned char signData[SDB_MAX_META_DATA_LEN]; 703 704 signature.data = signData; 705 signature.len = sizeof(signData); 706 crv = sftkdb_getRawAttributeSignature(handle, db, oldID, type, 707 &signature); 708 if (crv != CKR_OK) { 709 /* NOTE: if we ever change our default write from AES_CBC 710 * to AES_KW, We'll need to change this to a continue as 711 * we won't need the integrity record for AES_KW */ 712 break; 713 } 714 crv = sftkdb_PutAttributeSignature(handle, db, newID, type, 715 &signature); 716 if (crv != CKR_OK) { 717 break; 718 } 719 /* now get rid of the old one */ 720 crv = sftkdb_DestroyAttributeSignature(handle, db, oldID, type); 721 if (crv != CKR_OK) { 722 break; 723 } 724 } 725 } 726 return crv; 727 } 728 729 CK_ATTRIBUTE * 730 sftk_ExtractTemplate(PLArenaPool *arena, SFTKObject *object, 731 SFTKDBHandle *handle, CK_OBJECT_HANDLE objectID, 732 SDB *db, CK_ULONG *pcount, CK_RV *crv) 733 { 734 unsigned int count; 735 CK_ATTRIBUTE *template; 736 unsigned int i, templateIndex; 737 SFTKSessionObject *sessObject = sftk_narrowToSessionObject(object); 738 PRBool doEnc = PR_TRUE; 739 740 *crv = CKR_OK; 741 742 if (sessObject == NULL) { 743 *crv = CKR_GENERAL_ERROR; /* internal programming error */ 744 return NULL; 745 } 746 747 PORT_Assert(handle); 748 /* find the key handle */ 749 if (handle->type != SFTK_KEYDB_TYPE) { 750 doEnc = PR_FALSE; 751 } 752 753 PZ_Lock(sessObject->attributeLock); 754 count = 0; 755 for (i = 0; i < sessObject->hashSize; i++) { 756 SFTKAttribute *attr; 757 for (attr = sessObject->head[i]; attr; attr = attr->next) { 758 count++; 759 } 760 } 761 template = PORT_ArenaNewArray(arena, CK_ATTRIBUTE, count); 762 if (template == NULL) { 763 PZ_Unlock(sessObject->attributeLock); 764 *crv = CKR_HOST_MEMORY; 765 return NULL; 766 } 767 templateIndex = 0; 768 for (i = 0; i < sessObject->hashSize; i++) { 769 SFTKAttribute *attr; 770 for (attr = sessObject->head[i]; attr; attr = attr->next) { 771 CK_ATTRIBUTE *tp = &template[templateIndex++]; 772 /* copy the attribute */ 773 *tp = attr->attrib; 774 775 /* fixup ULONG s */ 776 if ((tp->ulValueLen == sizeof(CK_ULONG)) && 777 (sftkdb_isULONGAttribute(tp->type))) { 778 CK_ULONG value = *(CK_ULONG *)tp->pValue; 779 unsigned char *data; 780 781 tp->pValue = PORT_ArenaAlloc(arena, SDB_ULONG_SIZE); 782 data = (unsigned char *)tp->pValue; 783 if (data == NULL) { 784 *crv = CKR_HOST_MEMORY; 785 break; 786 } 787 sftk_ULong2SDBULong(data, value); 788 tp->ulValueLen = SDB_ULONG_SIZE; 789 } 790 791 /* encrypt private attributes */ 792 if (doEnc && sftkdb_isPrivateAttribute(tp->type)) { 793 /* we have a private attribute */ 794 SECItem *cipherText; 795 SECItem plainText; 796 SECStatus rv; 797 798 plainText.data = tp->pValue; 799 plainText.len = tp->ulValueLen; 800 PZ_Lock(handle->passwordLock); 801 if (handle->passwordKey.data == NULL) { 802 PZ_Unlock(handle->passwordLock); 803 *crv = CKR_USER_NOT_LOGGED_IN; 804 break; 805 } 806 rv = sftkdb_EncryptAttribute(arena, handle, db, 807 &handle->passwordKey, 808 handle->defaultIterationCount, 809 objectID, 810 tp->type, 811 &plainText, &cipherText); 812 PZ_Unlock(handle->passwordLock); 813 if (rv == SECSuccess) { 814 tp->pValue = cipherText->data; 815 tp->ulValueLen = cipherText->len; 816 } else { 817 *crv = CKR_GENERAL_ERROR; /* better error code here? */ 818 break; 819 } 820 PORT_Memset(plainText.data, 0, plainText.len); 821 } 822 } 823 } 824 PORT_Assert(templateIndex <= count); 825 PZ_Unlock(sessObject->attributeLock); 826 827 if (*crv != CKR_OK) { 828 return NULL; 829 } 830 if (pcount) { 831 *pcount = count; 832 } 833 return template; 834 } 835 836 /* 837 * return a pointer to the attribute in the give template. 838 * The return value is not const, as the caller may modify 839 * the given attribute value, but such modifications will 840 * modify the actual value in the template. 841 */ 842 static CK_ATTRIBUTE * 843 sftkdb_getAttributeFromTemplate(CK_ATTRIBUTE_TYPE attribute, 844 CK_ATTRIBUTE *ptemplate, CK_ULONG len) 845 { 846 CK_ULONG i; 847 848 for (i = 0; i < len; i++) { 849 if (attribute == ptemplate[i].type) { 850 return &ptemplate[i]; 851 } 852 } 853 return NULL; 854 } 855 856 static const CK_ATTRIBUTE * 857 sftkdb_getAttributeFromConstTemplate(CK_ATTRIBUTE_TYPE attribute, 858 const CK_ATTRIBUTE *ptemplate, CK_ULONG len) 859 { 860 CK_ULONG i; 861 862 for (i = 0; i < len; i++) { 863 if (attribute == ptemplate[i].type) { 864 return &ptemplate[i]; 865 } 866 } 867 return NULL; 868 } 869 870 /* 871 * fetch a template which identifies 'unique' entries based on object type 872 */ 873 static CK_RV 874 sftkdb_getFindTemplate(CK_OBJECT_CLASS objectType, unsigned char *objTypeData, 875 CK_ATTRIBUTE *findTemplate, CK_ULONG *findCount, 876 CK_ATTRIBUTE *ptemplate, int len) 877 { 878 CK_ATTRIBUTE *attr; 879 CK_ULONG count = 1; 880 881 sftk_ULong2SDBULong(objTypeData, objectType); 882 findTemplate[0].type = CKA_CLASS; 883 findTemplate[0].pValue = objTypeData; 884 findTemplate[0].ulValueLen = SDB_ULONG_SIZE; 885 886 switch (objectType) { 887 case CKO_CERTIFICATE: 888 case CKO_NSS_TRUST: 889 case CKO_TRUST: 890 attr = sftkdb_getAttributeFromTemplate(CKA_ISSUER, ptemplate, len); 891 if (attr == NULL) { 892 return CKR_TEMPLATE_INCOMPLETE; 893 } 894 findTemplate[1] = *attr; 895 attr = sftkdb_getAttributeFromTemplate(CKA_SERIAL_NUMBER, 896 ptemplate, len); 897 if (attr == NULL) { 898 return CKR_TEMPLATE_INCOMPLETE; 899 } 900 findTemplate[2] = *attr; 901 count = 3; 902 break; 903 904 case CKO_PRIVATE_KEY: 905 case CKO_PUBLIC_KEY: 906 case CKO_SECRET_KEY: 907 attr = sftkdb_getAttributeFromTemplate(CKA_ID, ptemplate, len); 908 if (attr == NULL) { 909 return CKR_TEMPLATE_INCOMPLETE; 910 } 911 if (attr->ulValueLen == 0) { 912 /* key is too generic to determine that it's unique, usually 913 * happens in the key gen case */ 914 return CKR_OBJECT_HANDLE_INVALID; 915 } 916 findTemplate[1] = *attr; 917 attr = sftkdb_getAttributeFromTemplate(CKA_KEY_TYPE, 918 ptemplate, len); 919 if (attr != NULL) { 920 findTemplate[2] = *attr; 921 count = 3; 922 } else { 923 count = 2; 924 } 925 break; 926 927 case CKO_NSS_CRL: 928 attr = sftkdb_getAttributeFromTemplate(CKA_SUBJECT, ptemplate, len); 929 if (attr == NULL) { 930 return CKR_TEMPLATE_INCOMPLETE; 931 } 932 findTemplate[1] = *attr; 933 count = 2; 934 break; 935 936 case CKO_NSS_SMIME: 937 attr = sftkdb_getAttributeFromTemplate(CKA_SUBJECT, ptemplate, len); 938 if (attr == NULL) { 939 return CKR_TEMPLATE_INCOMPLETE; 940 } 941 findTemplate[1] = *attr; 942 attr = sftkdb_getAttributeFromTemplate(CKA_NSS_EMAIL, ptemplate, len); 943 if (attr == NULL) { 944 return CKR_TEMPLATE_INCOMPLETE; 945 } 946 findTemplate[2] = *attr; 947 count = 3; 948 break; 949 default: 950 attr = sftkdb_getAttributeFromTemplate(CKA_VALUE, ptemplate, len); 951 if (attr == NULL) { 952 return CKR_TEMPLATE_INCOMPLETE; 953 } 954 findTemplate[1] = *attr; 955 count = 2; 956 break; 957 } 958 *findCount = count; 959 960 return CKR_OK; 961 } 962 963 /* 964 * look to see if this object already exists and return its object ID if 965 * it does. 966 */ 967 static CK_RV 968 sftkdb_lookupObject(SDB *db, CK_OBJECT_CLASS objectType, 969 CK_OBJECT_HANDLE *id, CK_ATTRIBUTE *ptemplate, CK_ULONG len) 970 { 971 CK_ATTRIBUTE findTemplate[3]; 972 CK_ULONG count = 1; 973 CK_ULONG objCount = 0; 974 SDBFind *find = NULL; 975 unsigned char objTypeData[SDB_ULONG_SIZE]; 976 CK_RV crv; 977 978 *id = CK_INVALID_HANDLE; 979 if (objectType == CKO_NSS_CRL) { 980 return CKR_OK; 981 } 982 crv = sftkdb_getFindTemplate(objectType, objTypeData, 983 findTemplate, &count, ptemplate, len); 984 985 if (crv == CKR_OBJECT_HANDLE_INVALID) { 986 /* key is too generic to determine that it's unique, usually 987 * happens in the key gen case, tell the caller to go ahead 988 * and just create it */ 989 return CKR_OK; 990 } 991 if (crv != CKR_OK) { 992 return crv; 993 } 994 995 /* use the raw find, so we get the correct database */ 996 crv = (*db->sdb_FindObjectsInit)(db, findTemplate, count, &find); 997 if (crv != CKR_OK) { 998 return crv; 999 } 1000 (*db->sdb_FindObjects)(db, find, id, 1, &objCount); 1001 (*db->sdb_FindObjectsFinal)(db, find); 1002 1003 if (objCount == 0) { 1004 *id = CK_INVALID_HANDLE; 1005 } 1006 return CKR_OK; 1007 } 1008 1009 /* 1010 * check to see if this template conflicts with others in our current database. 1011 */ 1012 static CK_RV 1013 sftkdb_checkConflicts(SDB *db, CK_OBJECT_CLASS objectType, 1014 const CK_ATTRIBUTE *ptemplate, CK_ULONG len, 1015 CK_OBJECT_HANDLE sourceID) 1016 { 1017 CK_ATTRIBUTE findTemplate[2]; 1018 unsigned char objTypeData[SDB_ULONG_SIZE]; 1019 /* we may need to allocate some temporaries. Keep track of what was 1020 * allocated so we can free it in the end */ 1021 unsigned char *temp1 = NULL; 1022 unsigned char *temp2 = NULL; 1023 CK_ULONG objCount = 0; 1024 SDBFind *find = NULL; 1025 CK_OBJECT_HANDLE id; 1026 const CK_ATTRIBUTE *attr, *attr2; 1027 CK_RV crv; 1028 CK_ATTRIBUTE subject; 1029 1030 /* Currently the only conflict is with nicknames pointing to the same 1031 * subject when creating or modifying a certificate. */ 1032 /* If the object is not a cert, no problem. */ 1033 if (objectType != CKO_CERTIFICATE) { 1034 return CKR_OK; 1035 } 1036 /* if not setting a nickname then there's still no problem */ 1037 attr = sftkdb_getAttributeFromConstTemplate(CKA_LABEL, ptemplate, len); 1038 if ((attr == NULL) || (attr->ulValueLen == 0)) { 1039 return CKR_OK; 1040 } 1041 /* fetch the subject of the source. For creation and merge, this should 1042 * be found in the template */ 1043 attr2 = sftkdb_getAttributeFromConstTemplate(CKA_SUBJECT, ptemplate, len); 1044 if (sourceID == CK_INVALID_HANDLE) { 1045 if ((attr2 == NULL) || ((CK_LONG)attr2->ulValueLen < 0)) { 1046 crv = CKR_TEMPLATE_INCOMPLETE; 1047 goto done; 1048 } 1049 } else if ((attr2 == NULL) || ((CK_LONG)attr2->ulValueLen <= 0)) { 1050 /* sourceID is set if we are trying to modify an existing entry instead 1051 * of creating a new one. In this case the subject may not be (probably 1052 * isn't) in the template, we have to read it from the database */ 1053 subject.type = CKA_SUBJECT; 1054 subject.pValue = NULL; 1055 subject.ulValueLen = 0; 1056 crv = (*db->sdb_GetAttributeValue)(db, sourceID, &subject, 1); 1057 if (crv != CKR_OK) { 1058 goto done; 1059 } 1060 if ((CK_LONG)subject.ulValueLen < 0) { 1061 crv = CKR_DEVICE_ERROR; /* closest pkcs11 error to corrupted DB */ 1062 goto done; 1063 } 1064 temp1 = subject.pValue = PORT_Alloc(++subject.ulValueLen); 1065 if (temp1 == NULL) { 1066 crv = CKR_HOST_MEMORY; 1067 goto done; 1068 } 1069 crv = (*db->sdb_GetAttributeValue)(db, sourceID, &subject, 1); 1070 if (crv != CKR_OK) { 1071 goto done; 1072 } 1073 attr2 = &subject; 1074 } 1075 1076 /* check for another cert in the database with the same nickname */ 1077 sftk_ULong2SDBULong(objTypeData, objectType); 1078 findTemplate[0].type = CKA_CLASS; 1079 findTemplate[0].pValue = objTypeData; 1080 findTemplate[0].ulValueLen = SDB_ULONG_SIZE; 1081 findTemplate[1] = *attr; 1082 1083 crv = (*db->sdb_FindObjectsInit)(db, findTemplate, 2, &find); 1084 if (crv != CKR_OK) { 1085 goto done; 1086 } 1087 (*db->sdb_FindObjects)(db, find, &id, 1, &objCount); 1088 (*db->sdb_FindObjectsFinal)(db, find); 1089 1090 /* object count == 0 means no conflicting certs found, 1091 * go on with the operation */ 1092 if (objCount == 0) { 1093 crv = CKR_OK; 1094 goto done; 1095 } 1096 1097 /* There is a least one cert that shares the nickname, make sure it also 1098 * matches the subject. */ 1099 findTemplate[0] = *attr2; 1100 /* we know how big the source subject was. Use that length to create the 1101 * space for the target. If it's not enough space, then it means the 1102 * source subject is too big, and therefore not a match. GetAttributeValue 1103 * will return CKR_BUFFER_TOO_SMALL. Otherwise it should be exactly enough 1104 * space (or enough space to be able to compare the result. */ 1105 temp2 = findTemplate[0].pValue = PORT_Alloc(++findTemplate[0].ulValueLen); 1106 if (temp2 == NULL) { 1107 crv = CKR_HOST_MEMORY; 1108 goto done; 1109 } 1110 crv = (*db->sdb_GetAttributeValue)(db, id, findTemplate, 1); 1111 if (crv != CKR_OK) { 1112 if (crv == CKR_BUFFER_TOO_SMALL) { 1113 /* if our buffer is too small, then the Subjects clearly do 1114 * not match */ 1115 crv = CKR_ATTRIBUTE_VALUE_INVALID; 1116 goto loser; 1117 } 1118 /* otherwise we couldn't get the value, just fail */ 1119 goto done; 1120 } 1121 1122 /* Ok, we have both subjects, make sure they are the same. 1123 * Compare the subjects */ 1124 if ((findTemplate[0].ulValueLen != attr2->ulValueLen) || 1125 (attr2->ulValueLen > 0 && 1126 PORT_Memcmp(findTemplate[0].pValue, attr2->pValue, attr2->ulValueLen) != 0)) { 1127 crv = CKR_ATTRIBUTE_VALUE_INVALID; 1128 goto loser; 1129 } 1130 crv = CKR_OK; 1131 1132 done: 1133 /* If we've failed for some other reason than a conflict, make sure we 1134 * return an error code other than CKR_ATTRIBUTE_VALUE_INVALID. 1135 * (NOTE: neither sdb_FindObjectsInit nor sdb_GetAttributeValue should 1136 * return CKR_ATTRIBUTE_VALUE_INVALID, so the following is paranoia). 1137 */ 1138 if (crv == CKR_ATTRIBUTE_VALUE_INVALID) { 1139 crv = CKR_GENERAL_ERROR; /* clearly a programming error */ 1140 } 1141 1142 /* exit point if we found a conflict */ 1143 loser: 1144 PORT_Free(temp1); 1145 PORT_Free(temp2); 1146 return crv; 1147 } 1148 1149 /* 1150 * try to update the template to fix any errors. This is only done 1151 * during update. 1152 * 1153 * NOTE: we must update the template or return an error, or the update caller 1154 * will loop forever! 1155 * 1156 * Two copies of the source code for this algorithm exist in NSS. 1157 * Changes must be made in both copies. 1158 * The other copy is in pk11_IncrementNickname() in pk11wrap/pk11merge.c. 1159 * 1160 */ 1161 static CK_RV 1162 sftkdb_resolveConflicts(PLArenaPool *arena, CK_OBJECT_CLASS objectType, 1163 CK_ATTRIBUTE *ptemplate, CK_ULONG *plen) 1164 { 1165 CK_ATTRIBUTE *attr; 1166 char *nickname, *newNickname; 1167 unsigned int end, digit; 1168 1169 /* sanity checks. We should never get here with these errors */ 1170 if (objectType != CKO_CERTIFICATE) { 1171 return CKR_GENERAL_ERROR; /* shouldn't happen */ 1172 } 1173 attr = sftkdb_getAttributeFromTemplate(CKA_LABEL, ptemplate, *plen); 1174 if ((attr == NULL) || (attr->ulValueLen == 0)) { 1175 return CKR_GENERAL_ERROR; /* shouldn't happen */ 1176 } 1177 1178 /* update the nickname */ 1179 /* is there a number at the end of the nickname already? 1180 * if so just increment that number */ 1181 nickname = (char *)attr->pValue; 1182 1183 /* does nickname end with " #n*" ? */ 1184 for (end = attr->ulValueLen - 1; 1185 end >= 2 && (digit = nickname[end]) <= '9' && digit >= '0'; 1186 end--) /* just scan */ 1187 ; 1188 if (attr->ulValueLen >= 3 && 1189 end < (attr->ulValueLen - 1) /* at least one digit */ && 1190 nickname[end] == '#' && 1191 nickname[end - 1] == ' ') { 1192 /* Already has a suitable suffix string */ 1193 } else { 1194 /* ... append " #2" to the name */ 1195 static const char num2[] = " #2"; 1196 newNickname = PORT_ArenaAlloc(arena, attr->ulValueLen + sizeof(num2)); 1197 if (!newNickname) { 1198 return CKR_HOST_MEMORY; 1199 } 1200 PORT_Memcpy(newNickname, nickname, attr->ulValueLen); 1201 PORT_Memcpy(&newNickname[attr->ulValueLen], num2, sizeof(num2)); 1202 attr->pValue = newNickname; /* modifies ptemplate */ 1203 attr->ulValueLen += 3; /* 3 is strlen(num2) */ 1204 return CKR_OK; 1205 } 1206 1207 for (end = attr->ulValueLen; end-- > 0;) { 1208 digit = nickname[end]; 1209 if (digit > '9' || digit < '0') { 1210 break; 1211 } 1212 if (digit < '9') { 1213 nickname[end]++; 1214 return CKR_OK; 1215 } 1216 nickname[end] = '0'; 1217 } 1218 1219 /* we overflowed, insert a new '1' for a carry in front of the number */ 1220 newNickname = PORT_ArenaAlloc(arena, attr->ulValueLen + 1); 1221 if (!newNickname) { 1222 return CKR_HOST_MEMORY; 1223 } 1224 /* PORT_Memcpy should handle len of '0' */ 1225 PORT_Memcpy(newNickname, nickname, ++end); 1226 newNickname[end] = '1'; 1227 PORT_Memset(&newNickname[end + 1], '0', attr->ulValueLen - end); 1228 attr->pValue = newNickname; 1229 attr->ulValueLen++; 1230 return CKR_OK; 1231 } 1232 1233 /* 1234 * set an attribute and sign it if necessary 1235 */ 1236 static CK_RV 1237 sftkdb_setAttributeValue(PLArenaPool *arena, SFTKDBHandle *handle, 1238 SDB *db, CK_OBJECT_HANDLE objectID, const CK_ATTRIBUTE *template, 1239 CK_ULONG count) 1240 { 1241 CK_RV crv; 1242 crv = (*db->sdb_SetAttributeValue)(db, objectID, template, count); 1243 if (crv != CKR_OK) { 1244 return crv; 1245 } 1246 crv = sftk_signTemplate(arena, handle, db == handle->update, 1247 objectID, template, count); 1248 return crv; 1249 } 1250 1251 /* 1252 * write a softoken object out to the database. 1253 */ 1254 CK_RV 1255 sftkdb_write(SFTKDBHandle *handle, SFTKObject *object, 1256 CK_OBJECT_HANDLE *objectID) 1257 { 1258 CK_ATTRIBUTE *template; 1259 PLArenaPool *arena; 1260 CK_ULONG count; 1261 CK_RV crv; 1262 SDB *db; 1263 PRBool inTransaction = PR_FALSE; 1264 CK_OBJECT_HANDLE id, candidateID; 1265 1266 *objectID = CK_INVALID_HANDLE; 1267 1268 if (handle == NULL) { 1269 return CKR_TOKEN_WRITE_PROTECTED; 1270 } 1271 db = SFTK_GET_SDB(handle); 1272 1273 /* 1274 * we have opened a new database, but we have not yet updated it. We are 1275 * still running pointing to the old database (so the application can 1276 * still read). We don't want to write to the old database at this point, 1277 * however, since it leads to user confusion. So at this point we simply 1278 * require a user login. Let NSS know this so it can prompt the user. 1279 */ 1280 if (db == handle->update) { 1281 return CKR_USER_NOT_LOGGED_IN; 1282 } 1283 1284 arena = PORT_NewArena(256); 1285 if (arena == NULL) { 1286 return CKR_HOST_MEMORY; 1287 } 1288 1289 crv = (*db->sdb_Begin)(db); 1290 if (crv != CKR_OK) { 1291 goto loser; 1292 } 1293 inTransaction = PR_TRUE; 1294 1295 crv = (*db->sdb_GetNewObjectID)(db, &candidateID); 1296 if (crv != CKR_OK) { 1297 goto loser; 1298 } 1299 1300 template = sftk_ExtractTemplate(arena, object, handle, candidateID, db, &count, &crv); 1301 if (!template) { 1302 goto loser; 1303 } 1304 1305 /* 1306 * We want to make the base database as free from object specific knowledge 1307 * as possible. To maintain compatibility, keep some of the desirable 1308 * object specific semantics of the old database. 1309 * 1310 * These were 2 fold: 1311 * 1) there were certain conflicts (like trying to set the same nickname 1312 * on two different subjects) that would return an error. 1313 * 2) Importing the 'same' object would silently update that object. 1314 * 1315 * The following 2 functions mimic the desirable effects of these two 1316 * semantics without pushing any object knowledge to the underlying database 1317 * code. 1318 */ 1319 1320 /* make sure we don't have attributes that conflict with the existing DB */ 1321 crv = sftkdb_checkConflicts(db, object->objclass, template, count, 1322 CK_INVALID_HANDLE); 1323 if (crv != CKR_OK) { 1324 goto loser; 1325 } 1326 /* Find any copies that match this particular object */ 1327 crv = sftkdb_lookupObject(db, object->objclass, &id, template, count); 1328 if (crv != CKR_OK) { 1329 goto loser; 1330 } 1331 if (id == CK_INVALID_HANDLE) { 1332 *objectID = candidateID; 1333 crv = sftkdb_CreateObject(arena, handle, db, objectID, template, count); 1334 } else { 1335 /* object already exists, modify it's attributes */ 1336 *objectID = id; 1337 /* The object ID changed from our candidate, we need to move any 1338 * signature attribute signatures to the new object ID. */ 1339 crv = sftkdb_fixupSignatures(handle, db, candidateID, id, 1340 template, count); 1341 if (crv != CKR_OK) { 1342 goto loser; 1343 } 1344 crv = sftkdb_setAttributeValue(arena, handle, db, id, template, count); 1345 } 1346 if (crv != CKR_OK) { 1347 goto loser; 1348 } 1349 crv = (*db->sdb_Commit)(db); 1350 inTransaction = PR_FALSE; 1351 1352 loser: 1353 if (inTransaction) { 1354 (*db->sdb_Abort)(db); 1355 /* It is trivial to show the following code cannot 1356 * happen unless something is horribly wrong with our compilier or 1357 * hardware */ 1358 PORT_Assert(crv != CKR_OK); 1359 if (crv == CKR_OK) 1360 crv = CKR_GENERAL_ERROR; 1361 } 1362 1363 if (arena) { 1364 PORT_FreeArena(arena, PR_TRUE); 1365 } 1366 if (crv == CKR_OK) { 1367 *objectID |= (handle->type | SFTK_TOKEN_TYPE); 1368 } 1369 return crv; 1370 } 1371 1372 CK_RV 1373 sftkdb_FindObjectsInit(SFTKDBHandle *handle, const CK_ATTRIBUTE *template, 1374 CK_ULONG count, SDBFind **find) 1375 { 1376 unsigned char *data = NULL; 1377 CK_ATTRIBUTE *ntemplate = NULL; 1378 CK_RV crv; 1379 int dataSize; 1380 SDB *db; 1381 1382 if (handle == NULL) { 1383 return CKR_OK; 1384 } 1385 db = SFTK_GET_SDB(handle); 1386 1387 if (count != 0) { 1388 ntemplate = sftkdb_fixupTemplateIn(template, count, &data, &dataSize); 1389 if (ntemplate == NULL) { 1390 return CKR_HOST_MEMORY; 1391 } 1392 } 1393 1394 crv = (*db->sdb_FindObjectsInit)(db, ntemplate, 1395 count, find); 1396 if (data) { 1397 PORT_Free(ntemplate); 1398 PORT_ZFree(data, dataSize); 1399 } 1400 return crv; 1401 } 1402 1403 CK_RV 1404 sftkdb_FindObjects(SFTKDBHandle *handle, SDBFind *find, 1405 CK_OBJECT_HANDLE *ids, int arraySize, CK_ULONG *count) 1406 { 1407 CK_RV crv; 1408 SDB *db; 1409 1410 if (handle == NULL) { 1411 *count = 0; 1412 return CKR_OK; 1413 } 1414 db = SFTK_GET_SDB(handle); 1415 1416 crv = (*db->sdb_FindObjects)(db, find, ids, 1417 arraySize, count); 1418 if (crv == CKR_OK) { 1419 unsigned int i; 1420 for (i = 0; i < *count; i++) { 1421 ids[i] |= (handle->type | SFTK_TOKEN_TYPE); 1422 } 1423 } 1424 return crv; 1425 } 1426 1427 CK_RV 1428 sftkdb_FindObjectsFinal(SFTKDBHandle *handle, SDBFind *find) 1429 { 1430 SDB *db; 1431 if (handle == NULL) { 1432 return CKR_OK; 1433 } 1434 db = SFTK_GET_SDB(handle); 1435 return (*db->sdb_FindObjectsFinal)(db, find); 1436 } 1437 1438 CK_RV 1439 sftkdb_GetAttributeValue(SFTKDBHandle *handle, CK_OBJECT_HANDLE objectID, 1440 CK_ATTRIBUTE *template, CK_ULONG count) 1441 { 1442 CK_RV crv, crv2; 1443 CK_ATTRIBUTE *ntemplate; 1444 unsigned char *data = NULL; 1445 int dataSize = 0; 1446 SDB *db; 1447 1448 if (handle == NULL) { 1449 return CKR_GENERAL_ERROR; 1450 } 1451 1452 /* short circuit common attributes */ 1453 if (count == 1 && 1454 (template[0].type == CKA_TOKEN || 1455 template[0].type == CKA_PRIVATE || 1456 template[0].type == CKA_SENSITIVE)) { 1457 CK_BBOOL boolVal = CK_TRUE; 1458 1459 if (template[0].pValue == NULL) { 1460 template[0].ulValueLen = sizeof(CK_BBOOL); 1461 return CKR_OK; 1462 } 1463 if (template[0].ulValueLen < sizeof(CK_BBOOL)) { 1464 template[0].ulValueLen = -1; 1465 return CKR_BUFFER_TOO_SMALL; 1466 } 1467 1468 if ((template[0].type == CKA_PRIVATE) && 1469 (handle->type != SFTK_KEYDB_TYPE)) { 1470 boolVal = CK_FALSE; 1471 } 1472 if ((template[0].type == CKA_SENSITIVE) && 1473 (handle->type != SFTK_KEYDB_TYPE)) { 1474 boolVal = CK_FALSE; 1475 } 1476 *(CK_BBOOL *)template[0].pValue = boolVal; 1477 template[0].ulValueLen = sizeof(CK_BBOOL); 1478 return CKR_OK; 1479 } 1480 1481 db = SFTK_GET_SDB(handle); 1482 /* nothing to do */ 1483 if (count == 0) { 1484 return CKR_OK; 1485 } 1486 ntemplate = sftkdb_fixupTemplateIn(template, count, &data, &dataSize); 1487 if (ntemplate == NULL) { 1488 return CKR_HOST_MEMORY; 1489 } 1490 objectID &= SFTK_OBJ_ID_MASK; 1491 crv = (*db->sdb_GetAttributeValue)(db, objectID, 1492 ntemplate, count); 1493 crv2 = sftkdb_fixupTemplateOut(template, objectID, ntemplate, 1494 count, handle); 1495 if (crv == CKR_OK) 1496 crv = crv2; 1497 if (data) { 1498 PORT_Free(ntemplate); 1499 PORT_ZFree(data, dataSize); 1500 } 1501 return crv; 1502 } 1503 1504 CK_RV 1505 sftkdb_SetAttributeValue(SFTKDBHandle *handle, SFTKObject *object, 1506 const CK_ATTRIBUTE *template, CK_ULONG count) 1507 { 1508 CK_ATTRIBUTE *ntemplate; 1509 unsigned char *data = NULL; 1510 PLArenaPool *arena = NULL; 1511 SDB *db; 1512 CK_RV crv = CKR_OK; 1513 CK_OBJECT_HANDLE objectID = (object->handle & SFTK_OBJ_ID_MASK); 1514 PRBool inTransaction = PR_FALSE; 1515 int dataSize; 1516 1517 if (handle == NULL) { 1518 return CKR_TOKEN_WRITE_PROTECTED; 1519 } 1520 1521 db = SFTK_GET_SDB(handle); 1522 /* nothing to do */ 1523 if (count == 0) { 1524 return CKR_OK; 1525 } 1526 /* 1527 * we have opened a new database, but we have not yet updated it. We are 1528 * still running pointing to the old database (so the application can 1529 * still read). We don't want to write to the old database at this point, 1530 * however, since it leads to user confusion. So at this point we simply 1531 * require a user login. Let NSS know this so it can prompt the user. 1532 */ 1533 if (db == handle->update) { 1534 return CKR_USER_NOT_LOGGED_IN; 1535 } 1536 1537 ntemplate = sftkdb_fixupTemplateIn(template, count, &data, &dataSize); 1538 if (ntemplate == NULL) { 1539 return CKR_HOST_MEMORY; 1540 } 1541 1542 /* make sure we don't have attributes that conflict with the existing DB */ 1543 crv = sftkdb_checkConflicts(db, object->objclass, ntemplate, count, 1544 objectID); 1545 if (crv != CKR_OK) { 1546 goto loser; 1547 } 1548 1549 arena = PORT_NewArena(256); 1550 if (arena == NULL) { 1551 crv = CKR_HOST_MEMORY; 1552 goto loser; 1553 } 1554 1555 crv = (*db->sdb_Begin)(db); 1556 if (crv != CKR_OK) { 1557 goto loser; 1558 } 1559 inTransaction = PR_TRUE; 1560 crv = sftkdb_setAttributeValue(arena, handle, db, objectID, ntemplate, 1561 count); 1562 if (crv != CKR_OK) { 1563 goto loser; 1564 } 1565 crv = (*db->sdb_Commit)(db); 1566 loser: 1567 if (crv != CKR_OK && inTransaction) { 1568 (*db->sdb_Abort)(db); 1569 } 1570 if (data) { 1571 PORT_Free(ntemplate); 1572 PORT_ZFree(data, dataSize); 1573 } 1574 if (arena) { 1575 PORT_FreeArena(arena, PR_FALSE); 1576 } 1577 return crv; 1578 } 1579 1580 CK_RV 1581 sftkdb_DestroyObject(SFTKDBHandle *handle, CK_OBJECT_HANDLE objectID, 1582 CK_OBJECT_CLASS objclass) 1583 { 1584 CK_RV crv = CKR_OK; 1585 SDB *db; 1586 1587 if (handle == NULL) { 1588 return CKR_TOKEN_WRITE_PROTECTED; 1589 } 1590 db = SFTK_GET_SDB(handle); 1591 objectID &= SFTK_OBJ_ID_MASK; 1592 1593 crv = (*db->sdb_Begin)(db); 1594 if (crv != CKR_OK) { 1595 return crv; 1596 } 1597 crv = (*db->sdb_DestroyObject)(db, objectID); 1598 if (crv != CKR_OK) { 1599 goto loser; 1600 } 1601 /* if the database supports meta data, delete any old signatures 1602 * that we may have added */ 1603 if ((db->sdb_flags & SDB_HAS_META) == SDB_HAS_META) { 1604 SDB *keydb = db; 1605 if (handle->type == SFTK_KEYDB_TYPE) { 1606 /* delete any private attribute signatures that might exist */ 1607 (void)sftkdb_DestroyAttributeSignature(handle, keydb, objectID, 1608 CKA_VALUE); 1609 (void)sftkdb_DestroyAttributeSignature(handle, keydb, objectID, 1610 CKA_PRIVATE_EXPONENT); 1611 (void)sftkdb_DestroyAttributeSignature(handle, keydb, objectID, 1612 CKA_PRIME_1); 1613 (void)sftkdb_DestroyAttributeSignature(handle, keydb, objectID, 1614 CKA_PRIME_2); 1615 (void)sftkdb_DestroyAttributeSignature(handle, keydb, objectID, 1616 CKA_EXPONENT_1); 1617 (void)sftkdb_DestroyAttributeSignature(handle, keydb, objectID, 1618 CKA_EXPONENT_2); 1619 (void)sftkdb_DestroyAttributeSignature(handle, keydb, objectID, 1620 CKA_COEFFICIENT); 1621 } else { 1622 keydb = SFTK_GET_SDB(handle->peerDB); 1623 } 1624 /* now destroy any authenticated attributes that may exist */ 1625 (void)sftkdb_DestroyAttributeSignature(handle, keydb, objectID, 1626 CKA_MODULUS); 1627 (void)sftkdb_DestroyAttributeSignature(handle, keydb, objectID, 1628 CKA_PUBLIC_EXPONENT); 1629 (void)sftkdb_DestroyAttributeSignature(handle, keydb, objectID, 1630 CKA_NSS_CERT_SHA1_HASH); 1631 (void)sftkdb_DestroyAttributeSignature(handle, keydb, objectID, 1632 CKA_NSS_CERT_MD5_HASH); 1633 (void)sftkdb_DestroyAttributeSignature(handle, keydb, objectID, 1634 CKA_HASH_OF_CERTIFICATE); 1635 (void)sftkdb_DestroyAttributeSignature(handle, keydb, objectID, 1636 CKA_NAME_HASH_ALGORITHM); 1637 (void)sftkdb_DestroyAttributeSignature(handle, keydb, objectID, 1638 CKA_NSS_TRUST_SERVER_AUTH); 1639 (void)sftkdb_DestroyAttributeSignature(handle, keydb, objectID, 1640 CKA_NSS_TRUST_CLIENT_AUTH); 1641 (void)sftkdb_DestroyAttributeSignature(handle, keydb, objectID, 1642 CKA_NSS_TRUST_EMAIL_PROTECTION); 1643 (void)sftkdb_DestroyAttributeSignature(handle, keydb, objectID, 1644 CKA_NSS_TRUST_CODE_SIGNING); 1645 (void)sftkdb_DestroyAttributeSignature(handle, keydb, objectID, 1646 CKA_NSS_TRUST_STEP_UP_APPROVED); 1647 (void)sftkdb_DestroyAttributeSignature(handle, keydb, objectID, 1648 CKA_PKCS_TRUST_SERVER_AUTH); 1649 (void)sftkdb_DestroyAttributeSignature(handle, keydb, objectID, 1650 CKA_PKCS_TRUST_CLIENT_AUTH); 1651 (void)sftkdb_DestroyAttributeSignature(handle, keydb, objectID, 1652 CKA_PKCS_TRUST_EMAIL_PROTECTION); 1653 (void)sftkdb_DestroyAttributeSignature(handle, keydb, objectID, 1654 CKA_PKCS_TRUST_CODE_SIGNING); 1655 (void)sftkdb_DestroyAttributeSignature(handle, keydb, objectID, 1656 CKA_NSS_OVERRIDE_EXTENSIONS); 1657 } 1658 crv = (*db->sdb_Commit)(db); 1659 loser: 1660 if (crv != CKR_OK) { 1661 (*db->sdb_Abort)(db); 1662 } 1663 return crv; 1664 } 1665 1666 CK_RV 1667 sftkdb_CloseDB(SFTKDBHandle *handle) 1668 { 1669 #ifdef NO_FORK_CHECK 1670 PRBool parentForkedAfterC_Initialize = PR_FALSE; 1671 #endif 1672 if (handle == NULL) { 1673 return CKR_OK; 1674 } 1675 if (handle->update) { 1676 if (handle->db->sdb_SetForkState) { 1677 (*handle->db->sdb_SetForkState)(parentForkedAfterC_Initialize); 1678 } 1679 (*handle->update->sdb_Close)(handle->update); 1680 } 1681 if (handle->db) { 1682 if (handle->db->sdb_SetForkState) { 1683 (*handle->db->sdb_SetForkState)(parentForkedAfterC_Initialize); 1684 } 1685 (*handle->db->sdb_Close)(handle->db); 1686 } 1687 if (handle->passwordLock) { 1688 PZ_Lock(handle->passwordLock); 1689 } 1690 if (handle->passwordKey.data) { 1691 SECITEM_ZfreeItem(&handle->passwordKey, PR_FALSE); 1692 } 1693 if (handle->passwordLock) { 1694 PZ_Unlock(handle->passwordLock); 1695 SKIP_AFTER_FORK(PZ_DestroyLock(handle->passwordLock)); 1696 } 1697 if (handle->updatePasswordKey) { 1698 SECITEM_ZfreeItem(handle->updatePasswordKey, PR_TRUE); 1699 } 1700 if (handle->updateID) { 1701 PORT_Free(handle->updateID); 1702 } 1703 PORT_Free(handle); 1704 return CKR_OK; 1705 } 1706 1707 /* 1708 * reset a database to it's uninitialized state. 1709 */ 1710 static CK_RV 1711 sftkdb_ResetDB(SFTKDBHandle *handle) 1712 { 1713 CK_RV crv = CKR_OK; 1714 SDB *db; 1715 if (handle == NULL) { 1716 return CKR_TOKEN_WRITE_PROTECTED; 1717 } 1718 db = SFTK_GET_SDB(handle); 1719 crv = (*db->sdb_Begin)(db); 1720 if (crv != CKR_OK) { 1721 goto loser; 1722 } 1723 crv = (*db->sdb_Reset)(db); 1724 if (crv != CKR_OK) { 1725 goto loser; 1726 } 1727 crv = (*db->sdb_Commit)(db); 1728 loser: 1729 if (crv != CKR_OK) { 1730 (*db->sdb_Abort)(db); 1731 } 1732 return crv; 1733 } 1734 1735 CK_RV 1736 sftkdb_Begin(SFTKDBHandle *handle) 1737 { 1738 CK_RV crv = CKR_OK; 1739 SDB *db; 1740 1741 if (handle == NULL) { 1742 return CKR_OK; 1743 } 1744 db = SFTK_GET_SDB(handle); 1745 if (db) { 1746 crv = (*db->sdb_Begin)(db); 1747 } 1748 return crv; 1749 } 1750 1751 CK_RV 1752 sftkdb_Commit(SFTKDBHandle *handle) 1753 { 1754 CK_RV crv = CKR_OK; 1755 SDB *db; 1756 1757 if (handle == NULL) { 1758 return CKR_OK; 1759 } 1760 db = SFTK_GET_SDB(handle); 1761 if (db) { 1762 (*db->sdb_Commit)(db); 1763 } 1764 return crv; 1765 } 1766 1767 CK_RV 1768 sftkdb_Abort(SFTKDBHandle *handle) 1769 { 1770 CK_RV crv = CKR_OK; 1771 SDB *db; 1772 1773 if (handle == NULL) { 1774 return CKR_OK; 1775 } 1776 db = SFTK_GET_SDB(handle); 1777 if (db) { 1778 crv = (db->sdb_Abort)(db); 1779 } 1780 return crv; 1781 } 1782 1783 /* 1784 * functions to update the database from an old database 1785 */ 1786 1787 static CK_RV 1788 sftkdb_GetObjectTemplate(SDB *source, CK_OBJECT_HANDLE id, 1789 CK_ATTRIBUTE *ptemplate, CK_ULONG *max) 1790 { 1791 unsigned int i, j; 1792 CK_RV crv; 1793 1794 if (*max < sftkdb_known_attributes_size) { 1795 *max = sftkdb_known_attributes_size; 1796 return CKR_BUFFER_TOO_SMALL; 1797 } 1798 for (i = 0; i < sftkdb_known_attributes_size; i++) { 1799 ptemplate[i].type = sftkdb_known_attributes[i]; 1800 ptemplate[i].pValue = NULL; 1801 ptemplate[i].ulValueLen = 0; 1802 } 1803 1804 crv = (*source->sdb_GetAttributeValue)(source, id, 1805 ptemplate, sftkdb_known_attributes_size); 1806 1807 if ((crv != CKR_OK) && (crv != CKR_ATTRIBUTE_TYPE_INVALID)) { 1808 return crv; 1809 } 1810 1811 for (i = 0, j = 0; i < sftkdb_known_attributes_size; i++, j++) { 1812 while (i < sftkdb_known_attributes_size && (ptemplate[i].ulValueLen == -1)) { 1813 i++; 1814 } 1815 if (i >= sftkdb_known_attributes_size) { 1816 break; 1817 } 1818 /* cheap optimization */ 1819 if (i == j) { 1820 continue; 1821 } 1822 ptemplate[j] = ptemplate[i]; 1823 } 1824 *max = j; 1825 return CKR_OK; 1826 } 1827 1828 static const char SFTKDB_META_UPDATE_TEMPLATE[] = "upd_%s_%s"; 1829 1830 /* 1831 * check to see if we have already updated this database. 1832 * a NULL updateID means we are trying to do an in place 1833 * single database update. In that case we have already 1834 * determined that an update was necessary. 1835 */ 1836 static PRBool 1837 sftkdb_hasUpdate(const char *typeString, SDB *db, const char *updateID) 1838 { 1839 char *id; 1840 CK_RV crv; 1841 SECItem dummy = { 0, NULL, 0 }; 1842 unsigned char dummyData[SDB_MAX_META_DATA_LEN]; 1843 1844 if (!updateID) { 1845 return PR_FALSE; 1846 } 1847 id = PR_smprintf(SFTKDB_META_UPDATE_TEMPLATE, typeString, updateID); 1848 if (id == NULL) { 1849 return PR_FALSE; 1850 } 1851 dummy.data = dummyData; 1852 dummy.len = sizeof(dummyData); 1853 1854 crv = (*db->sdb_GetMetaData)(db, id, &dummy, NULL); 1855 PR_smprintf_free(id); 1856 return crv == CKR_OK ? PR_TRUE : PR_FALSE; 1857 } 1858 1859 /* 1860 * we just completed an update, store the update id 1861 * so we don't need to do it again. If non was given, 1862 * there is nothing to do. 1863 */ 1864 static CK_RV 1865 sftkdb_putUpdate(const char *typeString, SDB *db, const char *updateID) 1866 { 1867 char *id; 1868 CK_RV crv; 1869 SECItem dummy = { 0, NULL, 0 }; 1870 1871 /* if no id was given, nothing to do */ 1872 if (updateID == NULL) { 1873 return CKR_OK; 1874 } 1875 1876 dummy.data = (unsigned char *)updateID; 1877 dummy.len = PORT_Strlen(updateID); 1878 1879 id = PR_smprintf(SFTKDB_META_UPDATE_TEMPLATE, typeString, updateID); 1880 if (id == NULL) { 1881 return PR_FALSE; 1882 } 1883 1884 crv = (*db->sdb_PutMetaData)(db, id, &dummy, NULL); 1885 PR_smprintf_free(id); 1886 return crv; 1887 } 1888 1889 /* 1890 * get a ULong attribute from a template: 1891 * NOTE: this is a raw templated stored in database order! 1892 */ 1893 static CK_ULONG 1894 sftkdb_getULongFromTemplate(CK_ATTRIBUTE_TYPE type, 1895 CK_ATTRIBUTE *ptemplate, CK_ULONG len) 1896 { 1897 CK_ATTRIBUTE *attr = sftkdb_getAttributeFromTemplate(type, 1898 ptemplate, len); 1899 1900 if (attr && attr->pValue && attr->ulValueLen == SDB_ULONG_SIZE) { 1901 return sftk_SDBULong2ULong(attr->pValue); 1902 } 1903 return (CK_ULONG)-1; 1904 } 1905 1906 static CK_RV 1907 sftkdb_setULongInTemplate(CK_ATTRIBUTE *ptemplate, CK_ULONG value) 1908 { 1909 if ((ptemplate->ulValueLen < SDB_ULONG_SIZE) || !ptemplate->pValue) { 1910 return CKR_TEMPLATE_INCOMPLETE; 1911 } 1912 ptemplate->ulValueLen = SDB_ULONG_SIZE; 1913 sftk_ULong2SDBULong(ptemplate->pValue, value); 1914 return CKR_OK; 1915 } 1916 1917 /* 1918 * we need to find a unique CKA_ID. 1919 * The basic idea is to just increment the lowest byte. 1920 * This code also handles the following corner cases: 1921 * 1) the single byte overflows. On overflow we increment the next byte up 1922 * and so forth until we have overflowed the entire CKA_ID. 1923 * 2) If we overflow the entire CKA_ID we expand it by one byte. 1924 * 3) the CKA_ID is non-existant, we create a new one with one byte. 1925 * This means no matter what CKA_ID is passed, the result of this function 1926 * is always a new CKA_ID, and this function will never return the same 1927 * CKA_ID the it has returned in the passed. 1928 */ 1929 static CK_RV 1930 sftkdb_incrementCKAID(PLArenaPool *arena, CK_ATTRIBUTE *ptemplate) 1931 { 1932 unsigned char *buf = ptemplate->pValue; 1933 CK_ULONG len = ptemplate->ulValueLen; 1934 1935 if (buf == NULL || len == (CK_ULONG)-1) { 1936 /* we have no valid CKAID, we'll create a basic one byte CKA_ID below */ 1937 len = 0; 1938 } else { 1939 CK_ULONG i; 1940 1941 /* walk from the back to front, incrementing 1942 * the CKA_ID until we no longer have a carry, 1943 * or have hit the front of the id. */ 1944 for (i = len; i != 0; i--) { 1945 buf[i - 1]++; 1946 if (buf[i - 1] != 0) { 1947 /* no more carries, the increment is complete */ 1948 return CKR_OK; 1949 } 1950 } 1951 /* we've now overflowed, fall through and expand the CKA_ID by 1952 * one byte */ 1953 } 1954 buf = PORT_ArenaAlloc(arena, len + 1); 1955 if (!buf) { 1956 return CKR_HOST_MEMORY; 1957 } 1958 if (len > 0) { 1959 PORT_Memcpy(buf, ptemplate->pValue, len); 1960 } 1961 buf[len] = 0; 1962 ptemplate->pValue = buf; 1963 ptemplate->ulValueLen = len + 1; 1964 return CKR_OK; 1965 } 1966 1967 /* 1968 * drop an attribute from a template. 1969 */ 1970 void 1971 sftkdb_dropAttribute(CK_ATTRIBUTE *attr, CK_ATTRIBUTE *ptemplate, 1972 CK_ULONG *plen) 1973 { 1974 CK_ULONG count = *plen; 1975 CK_ULONG i; 1976 1977 for (i = 0; i < count; i++) { 1978 if (attr->type == ptemplate[i].type) { 1979 break; 1980 } 1981 } 1982 1983 if (i == count) { 1984 /* attribute not found */ 1985 return; 1986 } 1987 1988 /* copy the remaining attributes up */ 1989 for (i++; i < count; i++) { 1990 ptemplate[i - 1] = ptemplate[i]; 1991 } 1992 1993 /* decrement the template size */ 1994 *plen = count - 1; 1995 } 1996 1997 /* 1998 * create some defines for the following functions to document the meaning 1999 * of true/false. (make's it easier to remember what means what. 2000 */ 2001 typedef enum { 2002 SFTKDB_DO_NOTHING = 0, 2003 SFTKDB_ADD_OBJECT, 2004 SFTKDB_MODIFY_OBJECT, 2005 SFTKDB_DROP_ATTRIBUTE 2006 } sftkdbUpdateStatus; 2007 2008 /* 2009 * helper function to reconcile a single trust entry. 2010 * Identify which trust entry we want to keep. 2011 * If we don't need to do anything (the records are already equal). 2012 * return SFTKDB_DO_NOTHING. 2013 * If we want to use the source version, 2014 * return SFTKDB_MODIFY_OBJECT 2015 * If we want to use the target version, 2016 * return SFTKDB_DROP_ATTRIBUTE 2017 * 2018 * In the end the caller will remove any attributes in the source 2019 * template when SFTKDB_DROP_ATTRIBUTE is specified, then use do a 2020 * set attributes with that template on the target if we received 2021 * any SFTKDB_MODIFY_OBJECT returns. 2022 */ 2023 sftkdbUpdateStatus 2024 sftkdb_reconcileTrustEntry(PLArenaPool *arena, CK_ATTRIBUTE *target, 2025 CK_ATTRIBUTE *source) 2026 { 2027 CK_ULONG targetTrust = sftkdb_getULongFromTemplate(target->type, 2028 target, 1); 2029 CK_ULONG sourceTrust = sftkdb_getULongFromTemplate(target->type, 2030 source, 1); 2031 2032 /* 2033 * try to pick the best solution between the source and the 2034 * target. Update the source template if we want the target value 2035 * to win out. Prefer cases where we don't actually update the 2036 * trust entry. 2037 */ 2038 2039 /* they are the same, everything is already kosher */ 2040 if (targetTrust == sourceTrust) { 2041 return SFTKDB_DO_NOTHING; 2042 } 2043 2044 /* handle the case where the source Trust attribute may be a bit 2045 * flakey */ 2046 if (sourceTrust == (CK_ULONG)-1) { 2047 /* 2048 * The source Trust is invalid. We know that the target Trust 2049 * must be valid here, otherwise the above 2050 * targetTrust == sourceTrust check would have succeeded. 2051 */ 2052 return SFTKDB_DROP_ATTRIBUTE; 2053 } 2054 2055 /* target is invalid, use the source's idea of the trust value */ 2056 if (targetTrust == (CK_ULONG)-1) { 2057 /* overwriting the target in this case is OK */ 2058 return SFTKDB_MODIFY_OBJECT; 2059 } 2060 2061 /* at this point we know that both attributes exist and have the 2062 * appropriate length (SDB_ULONG_SIZE). We no longer need to check 2063 * ulValueLen for either attribute. 2064 */ 2065 if (sourceTrust == CKT_TRUST_UNKNOWN) { 2066 return SFTKDB_DROP_ATTRIBUTE; 2067 } 2068 2069 /* target has no idea, use the source's idea of the trust value */ 2070 if (targetTrust == CKT_TRUST_UNKNOWN) { 2071 /* overwriting the target in this case is OK */ 2072 return SFTKDB_MODIFY_OBJECT; 2073 } 2074 2075 /* so both the target and the source have some idea of what this 2076 * trust attribute should be, and neither agree exactly. 2077 * At this point, we prefer 'hard' attributes over 'soft' ones. 2078 * 'hard' ones are CKT_TRUSTED, CKT_TRUST_ANCHOR, and 2079 * CKT_NSS_NOT_TRUTED. Soft ones are ones which don't change the 2080 * actual trust of the cert (CKT_TRUST_MUST_VERIFY_TRUST). 2081 */ 2082 if (sourceTrust == CKT_TRUST_MUST_VERIFY_TRUST) { 2083 return SFTKDB_DROP_ATTRIBUTE; 2084 } 2085 if (targetTrust == CKT_TRUST_MUST_VERIFY_TRUST) { 2086 /* again, overwriting the target in this case is OK */ 2087 return SFTKDB_MODIFY_OBJECT; 2088 } 2089 2090 /* both have hard attributes, we have a conflict, let the target win. */ 2091 return SFTKDB_DROP_ATTRIBUTE; 2092 } 2093 2094 /* map the attribute types */ 2095 CK_TRUST 2096 sftkdb_mapNSSTrustValueToPKCS11TrustValue(CK_TRUST trust) 2097 { 2098 switch (trust) { 2099 case CKT_NSS_TRUSTED: 2100 return CKT_TRUSTED; 2101 case CKT_NSS_TRUSTED_DELEGATOR: 2102 return CKT_TRUST_ANCHOR; 2103 case CKT_NSS_VALID_DELEGATOR: 2104 case CKT_NSS_MUST_VERIFY_TRUST: 2105 return CKT_TRUST_MUST_VERIFY_TRUST; 2106 case CKT_NSS_NOT_TRUSTED: 2107 return CKT_NOT_TRUSTED; 2108 case CKT_NSS_TRUST_UNKNOWN: 2109 return CKT_TRUST_UNKNOWN; 2110 default: 2111 break; 2112 } 2113 return CKT_TRUST_UNKNOWN; /* everything else, just copy */ 2114 } 2115 2116 /* map the attribute types */ 2117 CK_ATTRIBUTE_TYPE 2118 sftkdb_mapNSSTrustAttributeTypeToTrustAttributeType(CK_ATTRIBUTE_TYPE type) 2119 { 2120 switch (type) { 2121 case CKA_NSS_CERT_SHA1_HASH: 2122 return CKA_HASH_OF_CERTIFICATE; 2123 case CKA_NSS_TRUST_SERVER_AUTH: 2124 return CKA_PKCS_TRUST_SERVER_AUTH; 2125 case CKA_NSS_TRUST_CLIENT_AUTH: 2126 return CKA_PKCS_TRUST_CLIENT_AUTH; 2127 case CKA_NSS_TRUST_CODE_SIGNING: 2128 return CKA_PKCS_TRUST_CODE_SIGNING; 2129 case CKA_NSS_TRUST_EMAIL_PROTECTION: 2130 return CKA_PKCS_TRUST_EMAIL_PROTECTION; 2131 case CKA_NSS_TRUST_IPSEC_TUNNEL: 2132 return CKA_TRUST_IPSEC_IKE; 2133 case CKA_NSS_TRUST_TIME_STAMPING: 2134 return CKA_PKCS_TRUST_TIME_STAMPING; 2135 default: 2136 break; 2137 } 2138 return type; /* everything else, just copy */ 2139 } 2140 2141 /* these attributes have no mappings, just drop them */ 2142 PRBool 2143 sftkdb_dropTrustAttribute(CK_ATTRIBUTE_TYPE type) 2144 { 2145 switch (type) { 2146 case CKA_NSS_CERT_MD5_HASH: 2147 case CKA_NSS_TRUST_DIGITAL_SIGNATURE: 2148 case CKA_NSS_TRUST_NON_REPUDIATION: 2149 case CKA_NSS_TRUST_KEY_ENCIPHERMENT: 2150 case CKA_NSS_TRUST_DATA_ENCIPHERMENT: 2151 case CKA_NSS_TRUST_KEY_AGREEMENT: 2152 case CKA_NSS_TRUST_KEY_CERT_SIGN: 2153 case CKA_NSS_TRUST_CRL_SIGN: 2154 case CKA_NSS_TRUST_IPSEC_END_SYSTEM: 2155 case CKA_NSS_TRUST_IPSEC_USER: 2156 case CKA_NSS_TRUST_STEP_UP_APPROVED: 2157 return PR_TRUE; 2158 } 2159 return PR_FALSE; 2160 } 2161 2162 CK_RV 2163 sftkdb_mapTrustAttribute(CK_ATTRIBUTE *attr) 2164 { 2165 CK_ATTRIBUTE_TYPE oldType = attr->type; 2166 attr->type = sftkdb_mapNSSTrustAttributeTypeToTrustAttributeType(attr->type); 2167 if ((attr->type != oldType) && (attr->ulValueLen == SDB_ULONG_SIZE)) { 2168 CK_TRUST oldTrust = sftkdb_getULongFromTemplate(attr->type, attr, 1); 2169 CK_TRUST newTrust = sftkdb_mapNSSTrustValueToPKCS11TrustValue(oldTrust); 2170 return sftkdb_setULongInTemplate(attr, newTrust); 2171 } 2172 return CKR_OK; 2173 } 2174 2175 /* 2176 * take an NSS vendor specific trust object and map it to the 2177 * standard PKCS trust object. If the template includes attributes 2178 * that have not be mapped to PKCS then those attributes may be dropped. 2179 */ 2180 CK_RV 2181 sftkdb_mapNSSTrustToPKCS11Trust(CK_ATTRIBUTE *trustTemplate, 2182 CK_ULONG *templateCountPtr) 2183 { 2184 CK_ULONG i; 2185 CK_ULONG originalCount = *templateCountPtr; 2186 void *space = NULL; 2187 int hasCertificateHash = 0; 2188 CK_RV crv; 2189 2190 for (i = 0; i < *templateCountPtr; i++) { 2191 CK_ATTRIBUTE *attr = &trustTemplate[i]; 2192 if (sftkdb_dropTrustAttribute(attr->type)) { 2193 /* if there's a enough space to store a ulong, hang 2194 * onto it. We will probably need it tostore 2195 * CKA_NAME_HASH_ALGORITHM */ 2196 if (!space && attr->ulValueLen >= SDB_ULONG_SIZE) { 2197 space = attr->pValue; 2198 } 2199 sftkdb_dropAttribute(attr, trustTemplate, templateCountPtr); 2200 continue; 2201 } 2202 crv = sftkdb_mapTrustAttribute(attr); 2203 if (crv != CKR_OK) { 2204 return crv; 2205 } 2206 if (attr->type == CKA_HASH_OF_CERTIFICATE) { 2207 hasCertificateHash++; 2208 } 2209 } 2210 /* if we have CKA_HASH_OF_CERTIFICATE, then we need to add 2211 * CKA_NAME_HASH_ALGORITHM. We can only do that if we have dropped 2212 * an attribute because we can't expand the template. This shouldn't 2213 * be a problem because in a normal template we'll have a CKA_CERT_HASH_MD5 2214 * attribute and a CKA_NSS_TRUST_STEP_UP_APPROVED attribute */ 2215 if (hasCertificateHash) { 2216 if ((*templateCountPtr >= originalCount) || !space) { 2217 return CKR_TEMPLATE_INCOMPLETE; 2218 } 2219 i = (*templateCountPtr)++; 2220 trustTemplate[i].type = CKA_NAME_HASH_ALGORITHM; 2221 trustTemplate[i].pValue = space; 2222 trustTemplate[i].ulValueLen = SDB_ULONG_SIZE; 2223 return sftkdb_setULongInTemplate(&trustTemplate[i], CKM_SHA_1); 2224 } 2225 return CKR_OK; 2226 } 2227 2228 const CK_ATTRIBUTE_TYPE sftkdb_nssTrustList[] = { CKA_NSS_TRUST_SERVER_AUTH, 2229 CKA_NSS_TRUST_CLIENT_AUTH, 2230 CKA_NSS_TRUST_CODE_SIGNING, 2231 CKA_NSS_TRUST_EMAIL_PROTECTION, 2232 CKA_NSS_TRUST_IPSEC_TUNNEL, 2233 CKA_NSS_TRUST_TIME_STAMPING }; 2234 2235 const CK_ATTRIBUTE_TYPE sftkdb_trustList[] = { CKA_PKCS_TRUST_SERVER_AUTH, 2236 CKA_PKCS_TRUST_CLIENT_AUTH, 2237 CKA_PKCS_TRUST_CODE_SIGNING, 2238 CKA_PKCS_TRUST_EMAIL_PROTECTION, 2239 CKA_TRUST_IPSEC_IKE, 2240 CKA_PKCS_TRUST_TIME_STAMPING }; 2241 2242 #define SFTK_TRUST_TEMPLATE_COUNT \ 2243 (sizeof(sftkdb_trustList) / sizeof(sftkdb_trustList[0])) 2244 /* 2245 * Run through the list of known trust types, and reconcile each trust 2246 * entry one by one. Keep track of we really need to write out the source 2247 * trust object (overwriting the existing one). 2248 */ 2249 static sftkdbUpdateStatus 2250 sftkdb_reconcileTrust(PLArenaPool *arena, SDB *db, CK_OBJECT_HANDLE id, 2251 PRBool useLegacy, CK_ATTRIBUTE *ptemplate, 2252 CK_ULONG *plen) 2253 { 2254 CK_ATTRIBUTE trustTemplate[SFTK_TRUST_TEMPLATE_COUNT]; 2255 unsigned char trustData[SFTK_TRUST_TEMPLATE_COUNT * SDB_ULONG_SIZE]; 2256 sftkdbUpdateStatus update = useLegacy ? SFTKDB_DO_NOTHING 2257 : SFTKDB_MODIFY_OBJECT; 2258 const CK_ULONG templateCount = PR_ARRAY_SIZE(sftkdb_trustList); 2259 CK_ULONG i; 2260 CK_RV crv; 2261 2262 /* make sure the two arrays are the same size */ 2263 PR_STATIC_ASSERT(PR_ARRAY_SIZE(sftkdb_trustList) == PR_ARRAY_SIZE(sftkdb_nssTrustList)); 2264 for (i = 0; i < SFTK_TRUST_TEMPLATE_COUNT; i++) { 2265 trustTemplate[i].type = useLegacy ? sftkdb_nssTrustList[i] 2266 : sftkdb_trustList[i]; 2267 trustTemplate[i].pValue = &trustData[i * SDB_ULONG_SIZE]; 2268 trustTemplate[i].ulValueLen = SDB_ULONG_SIZE; 2269 } 2270 crv = (*db->sdb_GetAttributeValue)(db, id, 2271 trustTemplate, templateCount); 2272 if ((crv != CKR_OK) && (crv != CKR_ATTRIBUTE_TYPE_INVALID)) { 2273 /* target trust has some problems, update it */ 2274 update = SFTKDB_MODIFY_OBJECT; 2275 goto done; 2276 } 2277 2278 if (useLegacy) { 2279 CK_ULONG count = templateCount; 2280 crv = sftkdb_mapNSSTrustToPKCS11Trust(trustTemplate, &count); 2281 PORT_Assert((count == templateCount) && (crv != CKR_OK)); 2282 if ((count == templateCount) && (crv != CKR_OK)) { 2283 return SFTKDB_DO_NOTHING; 2284 } 2285 } 2286 2287 for (i = 0; i < templateCount; i++) { 2288 CK_ATTRIBUTE *attr = sftkdb_getAttributeFromTemplate( 2289 trustTemplate[i].type, ptemplate, *plen); 2290 sftkdbUpdateStatus status; 2291 2292 /* if target trust value doesn't exist, nothing to merge */ 2293 if (trustTemplate[i].ulValueLen == (CK_ULONG)-1) { 2294 /* if the source exists, then we want the source entry, 2295 * go ahead and update */ 2296 if (attr && attr->ulValueLen != (CK_ULONG)-1) { 2297 update = SFTKDB_MODIFY_OBJECT; 2298 } 2299 continue; 2300 } 2301 2302 /* 2303 * the source doesn't have the attribute, go to the next attribute 2304 */ 2305 if (attr == NULL) { 2306 continue; 2307 } 2308 status = sftkdb_reconcileTrustEntry(arena, &trustTemplate[i], attr); 2309 if (useLegacy) { 2310 /* in the legacy case we are always modifying the object because 2311 * we are updating to the new attribute type */ 2312 if (status == SFTKDB_DROP_ATTRIBUTE) { 2313 /* rather than drop the attribute, we need to copy the 2314 * updated destination attribute */ 2315 *attr = trustTemplate[i]; 2316 } 2317 /* SFTKDB_MODIFY_OBJECT - we are already modifying the object, 2318 * do nothing */ 2319 /* SFTKDB_NO_NOTHING, both source and target already have the 2320 * correct attribute, so no need to copy */ 2321 } else { 2322 /* not legacy, so the target will be updated in place 2323 * if necessary */ 2324 if (status == SFTKDB_MODIFY_OBJECT) { 2325 /* we need to write the source version of this attribute 2326 * to the target, we need to modify the object */ 2327 update = SFTKDB_MODIFY_OBJECT; 2328 } else if (status == SFTKDB_DROP_ATTRIBUTE) { 2329 /* drop the source copy of the attribute, we are going with 2330 * the target's version. This allows us to modify other 2331 * attributes if we need to. */ 2332 sftkdb_dropAttribute(attr, ptemplate, plen); 2333 } 2334 /* SFTKDB_NO_NOTHING, both source and target already have the 2335 * correct attribute, so no need to or drop anything */ 2336 } 2337 } 2338 2339 /* we don't support step-up in the PKCS version, so don't do anything with 2340 * step-up */ 2341 2342 done: 2343 return update; 2344 } 2345 2346 static sftkdbUpdateStatus 2347 sftkdb_handleIDAndName(PLArenaPool *arena, SDB *db, CK_OBJECT_HANDLE id, 2348 CK_ATTRIBUTE *ptemplate, CK_ULONG *plen) 2349 { 2350 sftkdbUpdateStatus update = SFTKDB_DO_NOTHING; 2351 CK_ATTRIBUTE *attr1, *attr2; 2352 CK_ATTRIBUTE ttemplate[2] = { 2353 { CKA_ID, NULL, 0 }, 2354 { CKA_LABEL, NULL, 0 } 2355 }; 2356 2357 attr1 = sftkdb_getAttributeFromTemplate(CKA_LABEL, ptemplate, *plen); 2358 attr2 = sftkdb_getAttributeFromTemplate(CKA_ID, ptemplate, *plen); 2359 2360 /* if the source has neither an id nor label, don't bother updating */ 2361 if ((!attr1 || attr1->ulValueLen == 0) && 2362 (!attr2 || attr2->ulValueLen == 0)) { 2363 return SFTKDB_DO_NOTHING; 2364 } 2365 2366 /* the source has either an id or a label, see what the target has */ 2367 (void)(*db->sdb_GetAttributeValue)(db, id, ttemplate, 2); 2368 2369 /* if the target has neither, update from the source */ 2370 if (((ttemplate[0].ulValueLen == 0) || 2371 (ttemplate[0].ulValueLen == (CK_ULONG)-1)) && 2372 ((ttemplate[1].ulValueLen == 0) || 2373 (ttemplate[1].ulValueLen == (CK_ULONG)-1))) { 2374 return SFTKDB_MODIFY_OBJECT; 2375 } 2376 2377 /* check the CKA_ID */ 2378 if ((ttemplate[0].ulValueLen != 0) && 2379 (ttemplate[0].ulValueLen != (CK_ULONG)-1)) { 2380 /* we have a CKA_ID in the target, don't overwrite 2381 * the target with an empty CKA_ID from the source*/ 2382 if (attr1 && attr1->ulValueLen == 0) { 2383 sftkdb_dropAttribute(attr1, ptemplate, plen); 2384 } 2385 } else if (attr1 && attr1->ulValueLen != 0) { 2386 /* source has a CKA_ID, but the target doesn't, update the target */ 2387 update = SFTKDB_MODIFY_OBJECT; 2388 } 2389 2390 /* check the nickname */ 2391 if ((ttemplate[1].ulValueLen != 0) && 2392 (ttemplate[1].ulValueLen != (CK_ULONG)-1)) { 2393 2394 /* we have a nickname in the target, and we don't have to update 2395 * the CKA_ID. We are done. NOTE: if we add addition attributes 2396 * in this check, this shortcut can only go on the last of them. */ 2397 if (update == SFTKDB_DO_NOTHING) { 2398 return update; 2399 } 2400 /* we have a nickname in the target, don't overwrite 2401 * the target with an empty nickname from the source */ 2402 if (attr2 && attr2->ulValueLen == 0) { 2403 sftkdb_dropAttribute(attr2, ptemplate, plen); 2404 } 2405 } else if (attr2 && attr2->ulValueLen != 0) { 2406 /* source has a nickname, but the target doesn't, update the target */ 2407 update = SFTKDB_MODIFY_OBJECT; 2408 } 2409 2410 return update; 2411 } 2412 2413 /* 2414 * This function updates the template before we write the object out. 2415 * 2416 * If we are going to skip updating this object, return PR_FALSE. 2417 * If it should be updated we return PR_TRUE. 2418 * To help readability, these have been defined 2419 * as SFTK_DONT_UPDATE and SFTK_UPDATE respectively. 2420 */ 2421 static PRBool 2422 sftkdb_updateObjectTemplate(PLArenaPool *arena, SDB *db, 2423 CK_OBJECT_CLASS objectType, 2424 CK_ATTRIBUTE *ptemplate, CK_ULONG *plen, 2425 CK_OBJECT_HANDLE *targetID) 2426 { 2427 PRBool done; /* should we repeat the loop? */ 2428 CK_OBJECT_HANDLE id; 2429 CK_RV crv = CKR_OK; 2430 2431 do { 2432 crv = sftkdb_checkConflicts(db, objectType, ptemplate, 2433 *plen, CK_INVALID_HANDLE); 2434 if (crv != CKR_ATTRIBUTE_VALUE_INVALID) { 2435 break; 2436 } 2437 crv = sftkdb_resolveConflicts(arena, objectType, ptemplate, plen); 2438 } while (crv == CKR_OK); 2439 2440 if (crv != CKR_OK) { 2441 return SFTKDB_DO_NOTHING; 2442 } 2443 2444 if (objectType == CKO_NSS_TRUST) { 2445 sftkdb_mapNSSTrustToPKCS11Trust(ptemplate, plen); 2446 objectType = CKO_TRUST; 2447 } 2448 2449 do { 2450 done = PR_TRUE; 2451 crv = sftkdb_lookupObject(db, objectType, &id, ptemplate, *plen); 2452 if (crv != CKR_OK) { 2453 if (objectType == CKO_TRUST && id == CK_INVALID_HANDLE) { 2454 objectType = CKO_NSS_TRUST; 2455 /* didn't find a new PKCS #11 Trust object, look for 2456 * and NSS Vendor specific Trust Object */ 2457 crv = sftkdb_lookupObject(db, CKO_NSS_TRUST, &id, 2458 ptemplate, *plen); 2459 } 2460 if (crv != CKR_OK) { 2461 return SFTKDB_DO_NOTHING; 2462 } 2463 } 2464 2465 /* This object already exists, merge it, don't update */ 2466 if (id != CK_INVALID_HANDLE) { 2467 CK_ATTRIBUTE *attr = NULL; 2468 /* special post processing for attributes */ 2469 switch (objectType) { 2470 case CKO_CERTIFICATE: 2471 case CKO_PUBLIC_KEY: 2472 case CKO_PRIVATE_KEY: 2473 /* update target's CKA_ID and labels if they don't already 2474 * exist */ 2475 *targetID = id; 2476 return sftkdb_handleIDAndName(arena, db, id, ptemplate, plen); 2477 case CKO_NSS_TRUST: 2478 /* if we have conflicting trust object types, 2479 * we need to reconcile them */ 2480 *targetID = id; 2481 return sftkdb_reconcileTrust(arena, db, id, PR_TRUE, 2482 ptemplate, plen); 2483 case CKO_TRUST: 2484 /* if we have conflicting trust object types, 2485 * we need to reconcile them */ 2486 *targetID = id; 2487 return sftkdb_reconcileTrust(arena, db, id, PR_FALSE, 2488 ptemplate, plen); 2489 case CKO_SECRET_KEY: 2490 /* secret keys in the old database are all sdr keys, 2491 * unfortunately they all appear to have the same CKA_ID, 2492 * even though they are truly different keys, so we always 2493 * want to update these keys, but we need to 2494 * give them a new CKA_ID */ 2495 /* NOTE: this changes ptemplate */ 2496 attr = sftkdb_getAttributeFromTemplate(CKA_ID, ptemplate, *plen); 2497 crv = attr ? sftkdb_incrementCKAID(arena, attr) 2498 : CKR_HOST_MEMORY; 2499 /* in the extremely rare event that we needed memory and 2500 * couldn't get it, just drop the key */ 2501 if (crv != CKR_OK) { 2502 return SFTKDB_DO_NOTHING; 2503 } 2504 done = PR_FALSE; /* repeat this find loop */ 2505 break; 2506 default: 2507 /* for all other objects, if we found the equivalent object, 2508 * don't update it */ 2509 return SFTKDB_DO_NOTHING; 2510 } 2511 } 2512 } while (!done); 2513 2514 /* this object doesn't exist, update it */ 2515 return SFTKDB_ADD_OBJECT; 2516 } 2517 2518 static CK_RV 2519 sftkdb_updateIntegrity(PLArenaPool *arena, SFTKDBHandle *handle, 2520 SDB *source, CK_OBJECT_HANDLE sourceID, 2521 SDB *target, CK_OBJECT_HANDLE targetID, 2522 CK_ATTRIBUTE *ptemplate, CK_ULONG max_attributes) 2523 { 2524 unsigned int i; 2525 CK_RV global_crv = CKR_OK; 2526 2527 /* if the target doesn't have META data, don't need to do anything */ 2528 if ((target->sdb_flags & SDB_HAS_META) == 0) { 2529 return CKR_OK; 2530 } 2531 /* if the source doesn't have meta data, then the record won't require 2532 * integrity */ 2533 if ((source->sdb_flags & SDB_HAS_META) == 0) { 2534 return CKR_OK; 2535 } 2536 for (i = 0; i < max_attributes; i++) { 2537 CK_ATTRIBUTE *att = &ptemplate[i]; 2538 CK_ATTRIBUTE_TYPE type = att->type; 2539 if (sftkdb_isPrivateAttribute(type)) { 2540 /* copy integrity signatures associated with this record (if any) */ 2541 SECItem signature; 2542 unsigned char signData[SDB_MAX_META_DATA_LEN]; 2543 CK_RV crv; 2544 2545 signature.data = signData; 2546 signature.len = sizeof(signData); 2547 crv = sftkdb_getRawAttributeSignature(handle, source, sourceID, type, 2548 &signature); 2549 if (crv != CKR_OK) { 2550 /* old databases don't have signature IDs because they are 2551 * 3DES encrypted. Since we know not to look for integrity 2552 * for 3DES records it's OK not to find one here. A new record 2553 * will be created when we reencrypt using AES CBC */ 2554 continue; 2555 } 2556 crv = sftkdb_PutAttributeSignature(handle, target, targetID, type, 2557 &signature); 2558 if (crv != CKR_OK) { 2559 /* we had a signature in the source db, but we couldn't store 2560 * it in the target, remember the error so we can report it. */ 2561 global_crv = crv; 2562 } 2563 } 2564 } 2565 return global_crv; 2566 } 2567 2568 #define MAX_ATTRIBUTES 500 2569 static CK_RV 2570 sftkdb_mergeObject(SFTKDBHandle *handle, CK_OBJECT_HANDLE id, 2571 SECItem *key) 2572 { 2573 CK_ATTRIBUTE template[MAX_ATTRIBUTES]; 2574 CK_ATTRIBUTE *ptemplate; 2575 CK_ULONG max_attributes = MAX_ATTRIBUTES; 2576 CK_OBJECT_CLASS objectType; 2577 SDB *source = handle->update; 2578 SDB *target = handle->db; 2579 unsigned int i; 2580 CK_OBJECT_HANDLE newID = CK_INVALID_HANDLE; 2581 CK_RV crv; 2582 PLArenaPool *arena = NULL; 2583 2584 arena = PORT_NewArena(256); 2585 if (arena == NULL) { 2586 return CKR_HOST_MEMORY; 2587 } 2588 2589 ptemplate = &template[0]; 2590 id &= SFTK_OBJ_ID_MASK; 2591 crv = sftkdb_GetObjectTemplate(source, id, ptemplate, &max_attributes); 2592 if (crv == CKR_BUFFER_TOO_SMALL) { 2593 ptemplate = PORT_ArenaNewArray(arena, CK_ATTRIBUTE, max_attributes); 2594 if (ptemplate == NULL) { 2595 crv = CKR_HOST_MEMORY; 2596 } else { 2597 crv = sftkdb_GetObjectTemplate(source, id, 2598 ptemplate, &max_attributes); 2599 } 2600 } 2601 if (crv != CKR_OK) { 2602 goto loser; 2603 } 2604 2605 for (i = 0; i < max_attributes; i++) { 2606 ptemplate[i].pValue = PORT_ArenaAlloc(arena, ptemplate[i].ulValueLen); 2607 if (ptemplate[i].pValue == NULL) { 2608 crv = CKR_HOST_MEMORY; 2609 goto loser; 2610 } 2611 } 2612 crv = (*source->sdb_GetAttributeValue)(source, id, 2613 ptemplate, max_attributes); 2614 if (crv != CKR_OK) { 2615 goto loser; 2616 } 2617 2618 objectType = sftkdb_getULongFromTemplate(CKA_CLASS, ptemplate, 2619 max_attributes); 2620 /* 2621 * Update Object updates the object template if necessary then returns 2622 * whether or not we need to actually write the object out to our target 2623 * database. 2624 */ 2625 if (!handle->updateID) { 2626 crv = sftkdb_CreateObject(arena, handle, target, &newID, 2627 ptemplate, max_attributes); 2628 } else { 2629 sftkdbUpdateStatus update_status; 2630 update_status = sftkdb_updateObjectTemplate(arena, target, 2631 objectType, ptemplate, &max_attributes, &newID); 2632 switch (update_status) { 2633 case SFTKDB_ADD_OBJECT: 2634 crv = sftkdb_CreateObject(arena, handle, target, &newID, 2635 ptemplate, max_attributes); 2636 break; 2637 case SFTKDB_MODIFY_OBJECT: 2638 crv = sftkdb_setAttributeValue(arena, handle, target, 2639 newID, ptemplate, max_attributes); 2640 break; 2641 case SFTKDB_DO_NOTHING: 2642 case SFTKDB_DROP_ATTRIBUTE: 2643 break; 2644 } 2645 } 2646 2647 /* if keyDB copy any meta data hashes to target, Update for the new 2648 * object ID */ 2649 if (crv == CKR_OK) { 2650 crv = sftkdb_updateIntegrity(arena, handle, source, id, target, newID, 2651 ptemplate, max_attributes); 2652 } 2653 2654 loser: 2655 if (arena) { 2656 PORT_FreeArena(arena, PR_TRUE); 2657 } 2658 return crv; 2659 } 2660 2661 #define MAX_IDS 10 2662 /* 2663 * update a new database from an old one, now that we have the key 2664 */ 2665 CK_RV 2666 sftkdb_Update(SFTKDBHandle *handle, SECItem *key) 2667 { 2668 SDBFind *find = NULL; 2669 CK_ULONG idCount = MAX_IDS; 2670 CK_OBJECT_HANDLE ids[MAX_IDS]; 2671 SECItem *updatePasswordKey = NULL; 2672 CK_RV crv, crv2; 2673 PRBool inTransaction = PR_FALSE; 2674 unsigned int i; 2675 2676 if (handle == NULL) { 2677 return CKR_OK; 2678 } 2679 if (handle->update == NULL) { 2680 return CKR_OK; 2681 } 2682 /* 2683 * put the whole update under a transaction. This allows us to handle 2684 * any possible race conditions between with the updateID check. 2685 */ 2686 crv = (*handle->db->sdb_Begin)(handle->db); 2687 if (crv != CKR_OK) { 2688 return crv; 2689 } 2690 inTransaction = PR_TRUE; 2691 2692 /* some one else has already updated this db */ 2693 if (sftkdb_hasUpdate(sftkdb_TypeString(handle), 2694 handle->db, handle->updateID)) { 2695 crv = CKR_OK; 2696 goto done; 2697 } 2698 2699 updatePasswordKey = sftkdb_GetUpdatePasswordKey(handle); 2700 if (updatePasswordKey) { 2701 /* pass the source DB key to the legacy code, 2702 * so it can decrypt things */ 2703 handle->oldKey = updatePasswordKey; 2704 } 2705 2706 /* find all the objects */ 2707 crv = sftkdb_FindObjectsInit(handle, NULL, 0, &find); 2708 2709 if (crv != CKR_OK) { 2710 goto loser; 2711 } 2712 while ((crv == CKR_OK) && (idCount == MAX_IDS)) { 2713 crv = sftkdb_FindObjects(handle, find, ids, MAX_IDS, &idCount); 2714 for (i = 0; (crv == CKR_OK) && (i < idCount); i++) { 2715 crv = sftkdb_mergeObject(handle, ids[i], key); 2716 } 2717 } 2718 crv2 = sftkdb_FindObjectsFinal(handle, find); 2719 if (crv == CKR_OK) 2720 crv = crv2; 2721 2722 loser: 2723 /* no longer need the old key value */ 2724 handle->oldKey = NULL; 2725 2726 /* update the password - even if we didn't update objects */ 2727 if (handle->type == SFTK_KEYDB_TYPE) { 2728 SECItem item1, item2; 2729 unsigned char data1[SDB_MAX_META_DATA_LEN]; 2730 unsigned char data2[SDB_MAX_META_DATA_LEN]; 2731 2732 item1.data = data1; 2733 item1.len = sizeof(data1); 2734 item2.data = data2; 2735 item2.len = sizeof(data2); 2736 2737 /* if the target db already has a password, skip this. */ 2738 crv = (*handle->db->sdb_GetMetaData)(handle->db, "password", 2739 &item1, &item2); 2740 if (crv == CKR_OK) { 2741 goto done; 2742 } 2743 2744 /* nope, update it from the source */ 2745 crv = (*handle->update->sdb_GetMetaData)(handle->update, "password", 2746 &item1, &item2); 2747 if (crv != CKR_OK) { 2748 /* if we get here, neither the source, nor the target has been initialized 2749 * with a password entry. Create a metadata table now so that we don't 2750 * mistake this for a partially updated database */ 2751 item1.data[0] = 0; 2752 item2.data[0] = 0; 2753 item1.len = item2.len = 1; 2754 crv = (*handle->db->sdb_PutMetaData)(handle->db, "empty", &item1, &item2); 2755 goto done; 2756 } 2757 crv = (*handle->db->sdb_PutMetaData)(handle->db, "password", &item1, 2758 &item2); 2759 if (crv != CKR_OK) { 2760 goto done; 2761 } 2762 } 2763 2764 done: 2765 /* finally mark this up to date db up to date */ 2766 /* some one else has already updated this db */ 2767 if (crv == CKR_OK) { 2768 crv = sftkdb_putUpdate(sftkdb_TypeString(handle), 2769 handle->db, handle->updateID); 2770 } 2771 2772 if (inTransaction) { 2773 if (crv == CKR_OK) { 2774 crv = (*handle->db->sdb_Commit)(handle->db); 2775 } else { 2776 (*handle->db->sdb_Abort)(handle->db); 2777 } 2778 } 2779 if (handle->update) { 2780 (*handle->update->sdb_Close)(handle->update); 2781 handle->update = NULL; 2782 } 2783 if (handle->updateID) { 2784 PORT_Free(handle->updateID); 2785 handle->updateID = NULL; 2786 } 2787 sftkdb_FreeUpdatePasswordKey(handle); 2788 if (updatePasswordKey) { 2789 SECITEM_ZfreeItem(updatePasswordKey, PR_TRUE); 2790 } 2791 handle->updateDBIsInit = PR_FALSE; 2792 return crv; 2793 } 2794 2795 /****************************************************************** 2796 * DB handle managing functions. 2797 * 2798 * These functions are called by softoken to initialize, acquire, 2799 * and release database handles. 2800 */ 2801 2802 const char * 2803 sftkdb_GetUpdateID(SFTKDBHandle *handle) 2804 { 2805 return handle->updateID; 2806 } 2807 2808 /* release a database handle */ 2809 void 2810 sftk_freeDB(SFTKDBHandle *handle) 2811 { 2812 PRInt32 ref; 2813 2814 if (!handle) 2815 return; 2816 ref = PR_ATOMIC_DECREMENT(&handle->ref); 2817 if (ref == 0) { 2818 sftkdb_CloseDB(handle); 2819 } 2820 return; 2821 } 2822 2823 /* 2824 * acquire a database handle for a certificate db 2825 * (database for public objects) 2826 */ 2827 SFTKDBHandle * 2828 sftk_getCertDB(SFTKSlot *slot) 2829 { 2830 SFTKDBHandle *dbHandle; 2831 2832 PZ_Lock(slot->slotLock); 2833 dbHandle = slot->certDB; 2834 if (dbHandle) { 2835 (void)PR_ATOMIC_INCREMENT(&dbHandle->ref); 2836 } 2837 PZ_Unlock(slot->slotLock); 2838 return dbHandle; 2839 } 2840 2841 /* 2842 * acquire a database handle for a key database 2843 * (database for private objects) 2844 */ 2845 SFTKDBHandle * 2846 sftk_getKeyDB(SFTKSlot *slot) 2847 { 2848 SFTKDBHandle *dbHandle; 2849 2850 SKIP_AFTER_FORK(PZ_Lock(slot->slotLock)); 2851 dbHandle = slot->keyDB; 2852 if (dbHandle) { 2853 (void)PR_ATOMIC_INCREMENT(&dbHandle->ref); 2854 } 2855 SKIP_AFTER_FORK(PZ_Unlock(slot->slotLock)); 2856 return dbHandle; 2857 } 2858 2859 /* 2860 * acquire the database for a specific object. NOTE: objectID must point 2861 * to a Token object! 2862 */ 2863 SFTKDBHandle * 2864 sftk_getDBForTokenObject(SFTKSlot *slot, CK_OBJECT_HANDLE objectID) 2865 { 2866 SFTKDBHandle *dbHandle; 2867 2868 PZ_Lock(slot->slotLock); 2869 dbHandle = objectID & SFTK_KEYDB_TYPE ? slot->keyDB : slot->certDB; 2870 if (dbHandle) { 2871 (void)PR_ATOMIC_INCREMENT(&dbHandle->ref); 2872 } 2873 PZ_Unlock(slot->slotLock); 2874 return dbHandle; 2875 } 2876 2877 /* 2878 * initialize a new database handle 2879 */ 2880 static SFTKDBHandle * 2881 sftk_NewDBHandle(SDB *sdb, int type, PRBool legacy) 2882 { 2883 SFTKDBHandle *handle = PORT_New(SFTKDBHandle); 2884 handle->ref = 1; 2885 handle->db = sdb; 2886 handle->update = NULL; 2887 handle->peerDB = NULL; 2888 handle->newKey = NULL; 2889 handle->oldKey = NULL; 2890 handle->updatePasswordKey = NULL; 2891 handle->updateID = NULL; 2892 handle->type = type; 2893 handle->usesLegacyStorage = legacy; 2894 handle->passwordKey.data = NULL; 2895 handle->passwordKey.len = 0; 2896 handle->passwordLock = NULL; 2897 if (type == SFTK_KEYDB_TYPE) { 2898 handle->passwordLock = PZ_NewLock(nssILockAttribute); 2899 } 2900 sdb->app_private = handle; 2901 return handle; 2902 } 2903 2904 /* 2905 * reset the key database to it's uninitialized state. This call 2906 * will clear all the key entried. 2907 */ 2908 SECStatus 2909 sftkdb_ResetKeyDB(SFTKDBHandle *handle) 2910 { 2911 CK_RV crv; 2912 2913 /* only rest the key db */ 2914 if (handle->type != SFTK_KEYDB_TYPE) { 2915 return SECFailure; 2916 } 2917 crv = sftkdb_ResetDB(handle); 2918 if (crv != CKR_OK) { 2919 /* set error */ 2920 return SECFailure; 2921 } 2922 PZ_Lock(handle->passwordLock); 2923 if (handle->passwordKey.data) { 2924 SECITEM_ZfreeItem(&handle->passwordKey, PR_FALSE); 2925 handle->passwordKey.data = NULL; 2926 } 2927 PZ_Unlock(handle->passwordLock); 2928 return SECSuccess; 2929 } 2930 2931 #ifndef NSS_DISABLE_DBM 2932 static PRBool 2933 sftk_oldVersionExists(const char *dir, int version) 2934 { 2935 int i; 2936 PRStatus exists = PR_FAILURE; 2937 char *file = NULL; 2938 2939 for (i = version; i > 1; i--) { 2940 file = PR_smprintf("%s%d.db", dir, i); 2941 if (file == NULL) { 2942 continue; 2943 } 2944 exists = PR_Access(file, PR_ACCESS_EXISTS); 2945 PR_smprintf_free(file); 2946 if (exists == PR_SUCCESS) { 2947 return PR_TRUE; 2948 } 2949 } 2950 return PR_FALSE; 2951 } 2952 2953 #if defined(_WIN32) 2954 /* 2955 * Convert an sdb path (encoded in UTF-8) to a legacy path (encoded in the 2956 * current system codepage). Fails if the path contains a character outside 2957 * the current system codepage. 2958 */ 2959 static char * 2960 sftk_legacyPathFromSDBPath(const char *confdir) 2961 { 2962 wchar_t *confdirWide; 2963 DWORD size; 2964 char *nconfdir; 2965 BOOL unmappable; 2966 2967 if (!confdir) { 2968 return NULL; 2969 } 2970 confdirWide = _NSSUTIL_UTF8ToWide(confdir); 2971 if (!confdirWide) { 2972 return NULL; 2973 } 2974 2975 size = WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, confdirWide, -1, 2976 NULL, 0, NULL, &unmappable); 2977 if (size == 0 || unmappable) { 2978 PORT_Free(confdirWide); 2979 return NULL; 2980 } 2981 nconfdir = PORT_Alloc(sizeof(char) * size); 2982 if (!nconfdir) { 2983 PORT_Free(confdirWide); 2984 return NULL; 2985 } 2986 size = WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, confdirWide, -1, 2987 nconfdir, size, NULL, &unmappable); 2988 PORT_Free(confdirWide); 2989 if (size == 0 || unmappable) { 2990 PORT_Free(nconfdir); 2991 return NULL; 2992 } 2993 2994 return nconfdir; 2995 } 2996 #else 2997 #define sftk_legacyPathFromSDBPath(confdir) PORT_Strdup((confdir)) 2998 #endif 2999 3000 static PRBool 3001 sftk_hasLegacyDB(const char *confdir, const char *certPrefix, 3002 const char *keyPrefix, int certVersion, int keyVersion) 3003 { 3004 char *dir; 3005 PRBool exists; 3006 3007 if (certPrefix == NULL) { 3008 certPrefix = ""; 3009 } 3010 3011 if (keyPrefix == NULL) { 3012 keyPrefix = ""; 3013 } 3014 3015 dir = PR_smprintf("%s/%scert", confdir, certPrefix); 3016 if (dir == NULL) { 3017 return PR_FALSE; 3018 } 3019 3020 exists = sftk_oldVersionExists(dir, certVersion); 3021 PR_smprintf_free(dir); 3022 if (exists) { 3023 return PR_TRUE; 3024 } 3025 3026 dir = PR_smprintf("%s/%skey", confdir, keyPrefix); 3027 if (dir == NULL) { 3028 return PR_FALSE; 3029 } 3030 3031 exists = sftk_oldVersionExists(dir, keyVersion); 3032 PR_smprintf_free(dir); 3033 return exists; 3034 } 3035 #endif /* NSS_DISABLE_DBM */ 3036 3037 /* 3038 * initialize certificate and key database handles as a pair. 3039 * 3040 * This function figures out what type of database we are opening and 3041 * calls the appropriate low level function to open the database. 3042 * It also figures out whether or not to setup up automatic update. 3043 */ 3044 CK_RV 3045 sftk_DBInit(const char *configdir, const char *certPrefix, 3046 const char *keyPrefix, const char *updatedir, 3047 const char *updCertPrefix, const char *updKeyPrefix, 3048 const char *updateID, PRBool readOnly, PRBool noCertDB, 3049 PRBool noKeyDB, PRBool forceOpen, PRBool isFIPS, 3050 SFTKDBHandle **certDB, SFTKDBHandle **keyDB) 3051 { 3052 const char *confdir; 3053 NSSDBType dbType = NSS_DB_TYPE_NONE; 3054 char *appName = NULL; 3055 SDB *keySDB, *certSDB; 3056 CK_RV crv = CKR_OK; 3057 int flags = SDB_RDONLY; 3058 PRBool newInit = PR_FALSE; 3059 #ifndef NSS_DISABLE_DBM 3060 PRBool needUpdate = PR_FALSE; 3061 #endif /* NSS_DISABLE_DBM */ 3062 char *nconfdir = NULL; 3063 PRBool legacy = PR_TRUE; 3064 3065 if (!readOnly) { 3066 flags = SDB_CREATE; 3067 } 3068 if (isFIPS) { 3069 flags |= SDB_FIPS; 3070 } 3071 3072 *certDB = NULL; 3073 *keyDB = NULL; 3074 3075 if (noKeyDB && noCertDB) { 3076 return CKR_OK; 3077 } 3078 confdir = _NSSUTIL_EvaluateConfigDir(configdir, &dbType, &appName); 3079 3080 /* 3081 * now initialize the appropriate database 3082 */ 3083 switch (dbType) { 3084 #ifndef NSS_DISABLE_DBM 3085 case NSS_DB_TYPE_LEGACY: 3086 crv = sftkdbCall_open(confdir, certPrefix, keyPrefix, 8, 3, flags, 3087 noCertDB ? NULL : &certSDB, noKeyDB ? NULL : &keySDB); 3088 break; 3089 case NSS_DB_TYPE_MULTIACCESS: 3090 crv = sftkdbCall_open(configdir, certPrefix, keyPrefix, 8, 3, flags, 3091 noCertDB ? NULL : &certSDB, noKeyDB ? NULL : &keySDB); 3092 break; 3093 #endif /* NSS_DISABLE_DBM */ 3094 case NSS_DB_TYPE_SQL: 3095 case NSS_DB_TYPE_EXTERN: /* SHOULD open a loadable db */ 3096 crv = s_open(confdir, certPrefix, keyPrefix, 9, 4, flags, 3097 noCertDB ? NULL : &certSDB, noKeyDB ? NULL : &keySDB, &newInit); 3098 legacy = PR_FALSE; 3099 3100 #ifndef NSS_DISABLE_DBM 3101 /* 3102 * if we failed to open the DB's read only, use the old ones if 3103 * the exists. 3104 */ 3105 if (crv != CKR_OK) { 3106 legacy = PR_TRUE; 3107 if ((flags & SDB_RDONLY) == SDB_RDONLY) { 3108 nconfdir = sftk_legacyPathFromSDBPath(confdir); 3109 } 3110 if (nconfdir && 3111 sftk_hasLegacyDB(nconfdir, certPrefix, keyPrefix, 8, 3)) { 3112 /* we have legacy databases, if we failed to open the new format 3113 * DB's read only, just use the legacy ones */ 3114 crv = sftkdbCall_open(nconfdir, certPrefix, 3115 keyPrefix, 8, 3, flags, 3116 noCertDB ? NULL : &certSDB, noKeyDB ? NULL : &keySDB); 3117 } 3118 /* Handle the database merge case. 3119 * 3120 * For the merge case, we need help from the application. Only 3121 * the application knows where the old database is, and what unique 3122 * identifier it has associated with it. 3123 * 3124 * If the client supplies these values, we use them to determine 3125 * if we need to update. 3126 */ 3127 } else if ( 3128 /* both update params have been supplied */ 3129 updatedir && *updatedir && updateID && *updateID 3130 /* old dbs exist? */ 3131 && sftk_hasLegacyDB(updatedir, updCertPrefix, updKeyPrefix, 8, 3) 3132 /* and they have not yet been updated? */ 3133 && ((noKeyDB || !sftkdb_hasUpdate("key", keySDB, updateID)) || (noCertDB || !sftkdb_hasUpdate("cert", certSDB, updateID)))) { 3134 /* we need to update */ 3135 confdir = updatedir; 3136 certPrefix = updCertPrefix; 3137 keyPrefix = updKeyPrefix; 3138 needUpdate = PR_TRUE; 3139 } else if (newInit) { 3140 /* if the new format DB was also a newly created DB, and we 3141 * succeeded, then need to update that new database with data 3142 * from the existing legacy DB */ 3143 nconfdir = sftk_legacyPathFromSDBPath(confdir); 3144 if (nconfdir && 3145 sftk_hasLegacyDB(nconfdir, certPrefix, keyPrefix, 8, 3)) { 3146 confdir = nconfdir; 3147 needUpdate = PR_TRUE; 3148 } 3149 } 3150 #endif /* NSS_DISABLE_DBM */ 3151 break; 3152 default: 3153 crv = CKR_GENERAL_ERROR; /* can't happen, EvaluationConfigDir MUST 3154 * return one of the types we already 3155 * specified. */ 3156 } 3157 if (crv != CKR_OK) { 3158 goto done; 3159 } 3160 if (!noCertDB) { 3161 *certDB = sftk_NewDBHandle(certSDB, SFTK_CERTDB_TYPE, legacy); 3162 } else { 3163 *certDB = NULL; 3164 } 3165 if (!noKeyDB) { 3166 *keyDB = sftk_NewDBHandle(keySDB, SFTK_KEYDB_TYPE, legacy); 3167 } else { 3168 *keyDB = NULL; 3169 } 3170 3171 /* link them together */ 3172 if (*certDB) { 3173 (*certDB)->peerDB = *keyDB; 3174 } 3175 if (*keyDB) { 3176 (*keyDB)->peerDB = *certDB; 3177 } 3178 3179 #ifndef NSS_DISABLE_DBM 3180 /* 3181 * if we need to update, open the legacy database and 3182 * mark the handle as needing update. 3183 */ 3184 if (needUpdate) { 3185 SDB *updateCert = NULL; 3186 SDB *updateKey = NULL; 3187 CK_RV crv2; 3188 3189 crv2 = sftkdbCall_open(confdir, certPrefix, keyPrefix, 8, 3, flags, 3190 noCertDB ? NULL : &updateCert, 3191 noKeyDB ? NULL : &updateKey); 3192 if (crv2 == CKR_OK) { 3193 if (*certDB) { 3194 (*certDB)->update = updateCert; 3195 (*certDB)->updateID = updateID && *updateID 3196 ? PORT_Strdup(updateID) 3197 : NULL; 3198 updateCert->app_private = (*certDB); 3199 } 3200 if (*keyDB) { 3201 PRBool tokenRemoved = PR_FALSE; 3202 (*keyDB)->update = updateKey; 3203 (*keyDB)->updateID = updateID && *updateID ? PORT_Strdup(updateID) : NULL; 3204 updateKey->app_private = (*keyDB); 3205 (*keyDB)->updateDBIsInit = PR_TRUE; 3206 (*keyDB)->updateDBIsInit = 3207 (sftkdb_HasPasswordSet(*keyDB) == SECSuccess) ? PR_TRUE : PR_FALSE; 3208 /* if the password on the key db is NULL, kick off our update 3209 * chain of events */ 3210 sftkdb_CheckPasswordNull((*keyDB), &tokenRemoved); 3211 } else { 3212 /* we don't have a key DB, update the certificate DB now */ 3213 sftkdb_Update(*certDB, NULL); 3214 } 3215 } 3216 } 3217 #endif /* NSS_DISABLE_DBM */ 3218 3219 done: 3220 if (appName) { 3221 PORT_Free(appName); 3222 } 3223 if (nconfdir) { 3224 PORT_Free(nconfdir); 3225 } 3226 return forceOpen ? CKR_OK : crv; 3227 } 3228 3229 CK_RV 3230 sftkdb_Shutdown(void) 3231 { 3232 s_shutdown(); 3233 #ifndef NSS_DISABLE_DBM 3234 sftkdbCall_Shutdown(); 3235 #endif /* NSS_DISABLE_DBM */ 3236 return CKR_OK; 3237 }