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