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