1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/nss/lib/softoken/sftkdb.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,2737 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 +/* 1.8 + * The following code handles the storage of PKCS 11 modules used by the 1.9 + * NSS. For the rest of NSS, only one kind of database handle exists: 1.10 + * 1.11 + * SFTKDBHandle 1.12 + * 1.13 + * There is one SFTKDBHandle for the each key database and one for each cert 1.14 + * database. These databases are opened as associated pairs, one pair per 1.15 + * slot. SFTKDBHandles are reference counted objects. 1.16 + * 1.17 + * Each SFTKDBHandle points to a low level database handle (SDB). This handle 1.18 + * represents the underlying physical database. These objects are not 1.19 + * reference counted, an are 'owned' by their respective SFTKDBHandles. 1.20 + * 1.21 + * 1.22 + */ 1.23 +#include "sftkdb.h" 1.24 +#include "sftkdbti.h" 1.25 +#include "pkcs11t.h" 1.26 +#include "pkcs11i.h" 1.27 +#include "sdb.h" 1.28 +#include "prprf.h" 1.29 +#include "pratom.h" 1.30 +#include "lgglue.h" 1.31 +#include "utilpars.h" 1.32 +#include "secerr.h" 1.33 +#include "softoken.h" 1.34 + 1.35 +/* 1.36 + * We want all databases to have the same binary representation independent of 1.37 + * endianness or length of the host architecture. In general PKCS #11 attributes 1.38 + * are endian/length independent except those attributes that pass CK_ULONG. 1.39 + * 1.40 + * The following functions fixes up the CK_ULONG type attributes so that the data 1.41 + * base sees a machine independent view. CK_ULONGs are stored as 4 byte network 1.42 + * byte order values (big endian). 1.43 + */ 1.44 +#define BBP 8 1.45 + 1.46 +static PRBool 1.47 +sftkdb_isULONGAttribute(CK_ATTRIBUTE_TYPE type) 1.48 +{ 1.49 + switch(type) { 1.50 + case CKA_CERTIFICATE_CATEGORY: 1.51 + case CKA_CERTIFICATE_TYPE: 1.52 + case CKA_CLASS: 1.53 + case CKA_JAVA_MIDP_SECURITY_DOMAIN: 1.54 + case CKA_KEY_GEN_MECHANISM: 1.55 + case CKA_KEY_TYPE: 1.56 + case CKA_MECHANISM_TYPE: 1.57 + case CKA_MODULUS_BITS: 1.58 + case CKA_PRIME_BITS: 1.59 + case CKA_SUBPRIME_BITS: 1.60 + case CKA_VALUE_BITS: 1.61 + case CKA_VALUE_LEN: 1.62 + 1.63 + case CKA_TRUST_DIGITAL_SIGNATURE: 1.64 + case CKA_TRUST_NON_REPUDIATION: 1.65 + case CKA_TRUST_KEY_ENCIPHERMENT: 1.66 + case CKA_TRUST_DATA_ENCIPHERMENT: 1.67 + case CKA_TRUST_KEY_AGREEMENT: 1.68 + case CKA_TRUST_KEY_CERT_SIGN: 1.69 + case CKA_TRUST_CRL_SIGN: 1.70 + 1.71 + case CKA_TRUST_SERVER_AUTH: 1.72 + case CKA_TRUST_CLIENT_AUTH: 1.73 + case CKA_TRUST_CODE_SIGNING: 1.74 + case CKA_TRUST_EMAIL_PROTECTION: 1.75 + case CKA_TRUST_IPSEC_END_SYSTEM: 1.76 + case CKA_TRUST_IPSEC_TUNNEL: 1.77 + case CKA_TRUST_IPSEC_USER: 1.78 + case CKA_TRUST_TIME_STAMPING: 1.79 + case CKA_TRUST_STEP_UP_APPROVED: 1.80 + return PR_TRUE; 1.81 + default: 1.82 + break; 1.83 + } 1.84 + return PR_FALSE; 1.85 + 1.86 +} 1.87 + 1.88 +/* are the attributes private? */ 1.89 +static PRBool 1.90 +sftkdb_isPrivateAttribute(CK_ATTRIBUTE_TYPE type) 1.91 +{ 1.92 + switch(type) { 1.93 + case CKA_VALUE: 1.94 + case CKA_PRIVATE_EXPONENT: 1.95 + case CKA_PRIME_1: 1.96 + case CKA_PRIME_2: 1.97 + case CKA_EXPONENT_1: 1.98 + case CKA_EXPONENT_2: 1.99 + case CKA_COEFFICIENT: 1.100 + return PR_TRUE; 1.101 + default: 1.102 + break; 1.103 + } 1.104 + return PR_FALSE; 1.105 +} 1.106 + 1.107 +/* These attributes must be authenticated with an hmac. */ 1.108 +static PRBool 1.109 +sftkdb_isAuthenticatedAttribute(CK_ATTRIBUTE_TYPE type) 1.110 +{ 1.111 + switch(type) { 1.112 + case CKA_MODULUS: 1.113 + case CKA_PUBLIC_EXPONENT: 1.114 + case CKA_CERT_SHA1_HASH: 1.115 + case CKA_CERT_MD5_HASH: 1.116 + case CKA_TRUST_SERVER_AUTH: 1.117 + case CKA_TRUST_CLIENT_AUTH: 1.118 + case CKA_TRUST_EMAIL_PROTECTION: 1.119 + case CKA_TRUST_CODE_SIGNING: 1.120 + case CKA_TRUST_STEP_UP_APPROVED: 1.121 + case CKA_NSS_OVERRIDE_EXTENSIONS: 1.122 + return PR_TRUE; 1.123 + default: 1.124 + break; 1.125 + } 1.126 + return PR_FALSE; 1.127 +} 1.128 + 1.129 +/* 1.130 + * convert a native ULONG to a database ulong. Database ulong's 1.131 + * are all 4 byte big endian values. 1.132 + */ 1.133 +void 1.134 +sftk_ULong2SDBULong(unsigned char *data, CK_ULONG value) 1.135 +{ 1.136 + int i; 1.137 + 1.138 + for (i=0; i < SDB_ULONG_SIZE; i++) { 1.139 + data[i] = (value >> (SDB_ULONG_SIZE-1-i)*BBP) & 0xff; 1.140 + } 1.141 +} 1.142 + 1.143 +/* 1.144 + * convert a database ulong back to a native ULONG. (reverse of the above 1.145 + * function. 1.146 + */ 1.147 +static CK_ULONG 1.148 +sftk_SDBULong2ULong(unsigned char *data) 1.149 +{ 1.150 + int i; 1.151 + CK_ULONG value = 0; 1.152 + 1.153 + for (i=0; i < SDB_ULONG_SIZE; i++) { 1.154 + value |= (((CK_ULONG)data[i]) << (SDB_ULONG_SIZE-1-i)*BBP); 1.155 + } 1.156 + return value; 1.157 +} 1.158 + 1.159 +/* 1.160 + * fix up the input templates. Our fixed up ints are stored in data and must 1.161 + * be freed by the caller. The new template must also be freed. If there are no 1.162 + * CK_ULONG attributes, the orignal template is passed in as is. 1.163 + */ 1.164 +static CK_ATTRIBUTE * 1.165 +sftkdb_fixupTemplateIn(const CK_ATTRIBUTE *template, int count, 1.166 + unsigned char **dataOut) 1.167 +{ 1.168 + int i; 1.169 + int ulongCount = 0; 1.170 + unsigned char *data; 1.171 + CK_ATTRIBUTE *ntemplate; 1.172 + 1.173 + *dataOut = NULL; 1.174 + 1.175 + /* first count the number of CK_ULONG attributes */ 1.176 + for (i=0; i < count; i++) { 1.177 + /* Don't 'fixup' NULL values */ 1.178 + if (!template[i].pValue) { 1.179 + continue; 1.180 + } 1.181 + if (template[i].ulValueLen == sizeof (CK_ULONG)) { 1.182 + if ( sftkdb_isULONGAttribute(template[i].type)) { 1.183 + ulongCount++; 1.184 + } 1.185 + } 1.186 + } 1.187 + /* no attributes to fixup, just call on through */ 1.188 + if (ulongCount == 0) { 1.189 + return (CK_ATTRIBUTE *)template; 1.190 + } 1.191 + 1.192 + /* allocate space for new ULONGS */ 1.193 + data = (unsigned char *)PORT_Alloc(SDB_ULONG_SIZE*ulongCount); 1.194 + if (!data) { 1.195 + return NULL; 1.196 + } 1.197 + 1.198 + /* allocate new template */ 1.199 + ntemplate = PORT_NewArray(CK_ATTRIBUTE,count); 1.200 + if (!ntemplate) { 1.201 + PORT_Free(data); 1.202 + return NULL; 1.203 + } 1.204 + *dataOut = data; 1.205 + /* copy the old template, fixup the actual ulongs */ 1.206 + for (i=0; i < count; i++) { 1.207 + ntemplate[i] = template[i]; 1.208 + /* Don't 'fixup' NULL values */ 1.209 + if (!template[i].pValue) { 1.210 + continue; 1.211 + } 1.212 + if (template[i].ulValueLen == sizeof (CK_ULONG)) { 1.213 + if ( sftkdb_isULONGAttribute(template[i].type) ) { 1.214 + CK_ULONG value = *(CK_ULONG *) template[i].pValue; 1.215 + sftk_ULong2SDBULong(data, value); 1.216 + ntemplate[i].pValue = data; 1.217 + ntemplate[i].ulValueLen = SDB_ULONG_SIZE; 1.218 + data += SDB_ULONG_SIZE; 1.219 + } 1.220 + } 1.221 + } 1.222 + return ntemplate; 1.223 +} 1.224 + 1.225 + 1.226 +static const char SFTKDB_META_SIG_TEMPLATE[] = "sig_%s_%08x_%08x"; 1.227 + 1.228 +/* 1.229 + * return a string describing the database type (key or cert) 1.230 + */ 1.231 +const char * 1.232 +sftkdb_TypeString(SFTKDBHandle *handle) 1.233 +{ 1.234 + return (handle->type == SFTK_KEYDB_TYPE) ? "key" : "cert"; 1.235 +} 1.236 + 1.237 +/* 1.238 + * Some attributes are signed with an Hmac and a pbe key generated from 1.239 + * the password. This signature is stored indexed by object handle and 1.240 + * attribute type in the meta data table in the key database. 1.241 + * 1.242 + * Signature entries are indexed by the string 1.243 + * sig_[cert/key]_{ObjectID}_{Attribute} 1.244 + * 1.245 + * This function fetches that pkcs5 signature. Caller supplies a SECItem 1.246 + * pre-allocated to the appropriate size if the SECItem is too small the 1.247 + * function will fail with CKR_BUFFER_TOO_SMALL. 1.248 + */ 1.249 +static CK_RV 1.250 +sftkdb_getAttributeSignature(SFTKDBHandle *handle, SFTKDBHandle *keyHandle, 1.251 + CK_OBJECT_HANDLE objectID, CK_ATTRIBUTE_TYPE type, 1.252 + SECItem *signText) 1.253 +{ 1.254 + SDB *db; 1.255 + char id[30]; 1.256 + CK_RV crv; 1.257 + 1.258 + db = SFTK_GET_SDB(keyHandle); 1.259 + 1.260 + sprintf(id, SFTKDB_META_SIG_TEMPLATE, 1.261 + sftkdb_TypeString(handle), 1.262 + (unsigned int)objectID, (unsigned int)type); 1.263 + 1.264 + crv = (*db->sdb_GetMetaData)(db, id, signText, NULL); 1.265 + return crv; 1.266 +} 1.267 + 1.268 +/* 1.269 + * Some attributes are signed with an Hmac and a pbe key generated from 1.270 + * the password. This signature is stored indexed by object handle and 1.271 + * attribute type in the meta data table in the key database. 1.272 + * 1.273 + * Signature entries are indexed by the string 1.274 + * sig_[cert/key]_{ObjectID}_{Attribute} 1.275 + * 1.276 + * This function stores that pkcs5 signature. 1.277 + */ 1.278 +CK_RV 1.279 +sftkdb_PutAttributeSignature(SFTKDBHandle *handle, SDB *keyTarget, 1.280 + CK_OBJECT_HANDLE objectID, CK_ATTRIBUTE_TYPE type, 1.281 + SECItem *signText) 1.282 +{ 1.283 + char id[30]; 1.284 + CK_RV crv; 1.285 + 1.286 + sprintf(id, SFTKDB_META_SIG_TEMPLATE, 1.287 + sftkdb_TypeString(handle), 1.288 + (unsigned int)objectID, (unsigned int)type); 1.289 + 1.290 + crv = (*keyTarget->sdb_PutMetaData)(keyTarget, id, signText, NULL); 1.291 + return crv; 1.292 +} 1.293 + 1.294 +/* 1.295 + * fix up returned data. NOTE: sftkdb_fixupTemplateIn has already allocated 1.296 + * separate data sections for the database ULONG values. 1.297 + */ 1.298 +static CK_RV 1.299 +sftkdb_fixupTemplateOut(CK_ATTRIBUTE *template, CK_OBJECT_HANDLE objectID, 1.300 + CK_ATTRIBUTE *ntemplate, int count, SFTKDBHandle *handle) 1.301 +{ 1.302 + int i; 1.303 + CK_RV crv = CKR_OK; 1.304 + SFTKDBHandle *keyHandle; 1.305 + PRBool checkSig = PR_TRUE; 1.306 + PRBool checkEnc = PR_TRUE; 1.307 + 1.308 + PORT_Assert(handle); 1.309 + 1.310 + /* find the key handle */ 1.311 + keyHandle = handle; 1.312 + if (handle->type != SFTK_KEYDB_TYPE) { 1.313 + checkEnc = PR_FALSE; 1.314 + keyHandle = handle->peerDB; 1.315 + } 1.316 + 1.317 + if ((keyHandle == NULL) || 1.318 + ((SFTK_GET_SDB(keyHandle)->sdb_flags & SDB_HAS_META) == 0) || 1.319 + (keyHandle->passwordKey.data == NULL)) { 1.320 + checkSig = PR_FALSE; 1.321 + } 1.322 + 1.323 + for (i=0; i < count; i++) { 1.324 + CK_ULONG length = template[i].ulValueLen; 1.325 + template[i].ulValueLen = ntemplate[i].ulValueLen; 1.326 + /* fixup ulongs */ 1.327 + if (ntemplate[i].ulValueLen == SDB_ULONG_SIZE) { 1.328 + if (sftkdb_isULONGAttribute(template[i].type)) { 1.329 + if (template[i].pValue) { 1.330 + CK_ULONG value; 1.331 + unsigned char *data; 1.332 + 1.333 + data = (unsigned char *)ntemplate[i].pValue; 1.334 + value = sftk_SDBULong2ULong(ntemplate[i].pValue); 1.335 + if (length < sizeof(CK_ULONG)) { 1.336 + template[i].ulValueLen = -1; 1.337 + crv = CKR_BUFFER_TOO_SMALL; 1.338 + continue; 1.339 + } 1.340 + PORT_Memcpy(template[i].pValue,&value,sizeof(CK_ULONG)); 1.341 + } 1.342 + template[i].ulValueLen = sizeof(CK_ULONG); 1.343 + } 1.344 + } 1.345 + 1.346 + /* if no data was retrieved, no need to process encrypted or signed 1.347 + * attributes */ 1.348 + if ((template[i].pValue == NULL) || (template[i].ulValueLen == -1)) { 1.349 + continue; 1.350 + } 1.351 + 1.352 + /* fixup private attributes */ 1.353 + if (checkEnc && sftkdb_isPrivateAttribute(ntemplate[i].type)) { 1.354 + /* we have a private attribute */ 1.355 + /* This code depends on the fact that the cipherText is bigger 1.356 + * than the plain text */ 1.357 + SECItem cipherText; 1.358 + SECItem *plainText; 1.359 + SECStatus rv; 1.360 + 1.361 + cipherText.data = ntemplate[i].pValue; 1.362 + cipherText.len = ntemplate[i].ulValueLen; 1.363 + PZ_Lock(handle->passwordLock); 1.364 + if (handle->passwordKey.data == NULL) { 1.365 + PZ_Unlock(handle->passwordLock); 1.366 + template[i].ulValueLen = -1; 1.367 + crv = CKR_USER_NOT_LOGGED_IN; 1.368 + continue; 1.369 + } 1.370 + rv = sftkdb_DecryptAttribute(&handle->passwordKey, 1.371 + &cipherText, &plainText); 1.372 + PZ_Unlock(handle->passwordLock); 1.373 + if (rv != SECSuccess) { 1.374 + PORT_Memset(template[i].pValue, 0, template[i].ulValueLen); 1.375 + template[i].ulValueLen = -1; 1.376 + crv = CKR_GENERAL_ERROR; 1.377 + continue; 1.378 + } 1.379 + PORT_Assert(template[i].ulValueLen >= plainText->len); 1.380 + if (template[i].ulValueLen < plainText->len) { 1.381 + SECITEM_FreeItem(plainText,PR_TRUE); 1.382 + PORT_Memset(template[i].pValue, 0, template[i].ulValueLen); 1.383 + template[i].ulValueLen = -1; 1.384 + crv = CKR_GENERAL_ERROR; 1.385 + continue; 1.386 + } 1.387 + 1.388 + /* copy the plain text back into the template */ 1.389 + PORT_Memcpy(template[i].pValue, plainText->data, plainText->len); 1.390 + template[i].ulValueLen = plainText->len; 1.391 + SECITEM_FreeItem(plainText,PR_TRUE); 1.392 + } 1.393 + /* make sure signed attributes are valid */ 1.394 + if (checkSig && sftkdb_isAuthenticatedAttribute(ntemplate[i].type)) { 1.395 + SECStatus rv; 1.396 + SECItem signText; 1.397 + SECItem plainText; 1.398 + unsigned char signData[SDB_MAX_META_DATA_LEN]; 1.399 + 1.400 + signText.data = signData; 1.401 + signText.len = sizeof(signData); 1.402 + 1.403 + rv = sftkdb_getAttributeSignature(handle, keyHandle, 1.404 + objectID, ntemplate[i].type, &signText); 1.405 + if (rv != SECSuccess) { 1.406 + PORT_Memset(template[i].pValue, 0, template[i].ulValueLen); 1.407 + template[i].ulValueLen = -1; 1.408 + crv = CKR_DATA_INVALID; /* better error code? */ 1.409 + continue; 1.410 + } 1.411 + 1.412 + plainText.data = ntemplate[i].pValue; 1.413 + plainText.len = ntemplate[i].ulValueLen; 1.414 + 1.415 + /* 1.416 + * we do a second check holding the lock just in case the user 1.417 + * loggout while we were trying to get the signature. 1.418 + */ 1.419 + PZ_Lock(keyHandle->passwordLock); 1.420 + if (keyHandle->passwordKey.data == NULL) { 1.421 + /* if we are no longer logged in, no use checking the other 1.422 + * Signatures either. */ 1.423 + checkSig = PR_FALSE; 1.424 + PZ_Unlock(keyHandle->passwordLock); 1.425 + continue; 1.426 + } 1.427 + 1.428 + rv = sftkdb_VerifyAttribute(&keyHandle->passwordKey, 1.429 + objectID, ntemplate[i].type, 1.430 + &plainText, &signText); 1.431 + PZ_Unlock(keyHandle->passwordLock); 1.432 + if (rv != SECSuccess) { 1.433 + PORT_Memset(template[i].pValue, 0, template[i].ulValueLen); 1.434 + template[i].ulValueLen = -1; 1.435 + crv = CKR_SIGNATURE_INVALID; /* better error code? */ 1.436 + } 1.437 + /* This Attribute is fine */ 1.438 + } 1.439 + } 1.440 + return crv; 1.441 +} 1.442 + 1.443 +/* 1.444 + * Some attributes are signed with an HMAC and a pbe key generated from 1.445 + * the password. This signature is stored indexed by object handle and 1.446 + * 1.447 + * Those attributes are: 1.448 + * 1) Trust object hashes and trust values. 1.449 + * 2) public key values. 1.450 + * 1.451 + * Certs themselves are considered properly authenticated by virtue of their 1.452 + * signature, or their matching hash with the trust object. 1.453 + * 1.454 + * These signature is only checked for objects coming from shared databases. 1.455 + * Older dbm style databases have such no signature checks. HMACs are also 1.456 + * only checked when the token is logged in, as it requires a pbe generated 1.457 + * from the password. 1.458 + * 1.459 + * Tokens which have no key database (and therefore no master password) do not 1.460 + * have any stored signature values. Signature values are stored in the key 1.461 + * database, since the signature data is tightly coupled to the key database 1.462 + * password. 1.463 + * 1.464 + * This function takes a template of attributes that were either created or 1.465 + * modified. These attributes are checked to see if the need to be signed. 1.466 + * If they do, then this function signs the attributes and writes them 1.467 + * to the meta data store. 1.468 + * 1.469 + * This function can fail if there are attributes that must be signed, but 1.470 + * the token is not logged in. 1.471 + * 1.472 + * The caller is expected to abort any transaction he was in in the 1.473 + * event of a failure of this function. 1.474 + */ 1.475 +static CK_RV 1.476 +sftk_signTemplate(PLArenaPool *arena, SFTKDBHandle *handle, 1.477 + PRBool mayBeUpdateDB, 1.478 + CK_OBJECT_HANDLE objectID, const CK_ATTRIBUTE *template, 1.479 + CK_ULONG count) 1.480 +{ 1.481 + int i; 1.482 + CK_RV crv; 1.483 + SFTKDBHandle *keyHandle = handle; 1.484 + SDB *keyTarget = NULL; 1.485 + PRBool usingPeerDB = PR_FALSE; 1.486 + PRBool inPeerDBTransaction = PR_FALSE; 1.487 + 1.488 + PORT_Assert(handle); 1.489 + 1.490 + if (handle->type != SFTK_KEYDB_TYPE) { 1.491 + keyHandle = handle->peerDB; 1.492 + usingPeerDB = PR_TRUE; 1.493 + } 1.494 + 1.495 + /* no key DB defined? then no need to sign anything */ 1.496 + if (keyHandle == NULL) { 1.497 + crv = CKR_OK; 1.498 + goto loser; 1.499 + } 1.500 + 1.501 + /* When we are in a middle of an update, we have an update database set, 1.502 + * but we want to write to the real database. The bool mayBeUpdateDB is 1.503 + * set to TRUE if it's possible that we want to write an update database 1.504 + * rather than a primary */ 1.505 + keyTarget = (mayBeUpdateDB && keyHandle->update) ? 1.506 + keyHandle->update : keyHandle->db; 1.507 + 1.508 + /* skip the the database does not support meta data */ 1.509 + if ((keyTarget->sdb_flags & SDB_HAS_META) == 0) { 1.510 + crv = CKR_OK; 1.511 + goto loser; 1.512 + } 1.513 + 1.514 + /* If we had to switch databases, we need to initialize a transaction. */ 1.515 + if (usingPeerDB) { 1.516 + crv = (*keyTarget->sdb_Begin)(keyTarget); 1.517 + if (crv != CKR_OK) { 1.518 + goto loser; 1.519 + } 1.520 + inPeerDBTransaction = PR_TRUE; 1.521 + } 1.522 + 1.523 + for (i=0; i < count; i ++) { 1.524 + if (sftkdb_isAuthenticatedAttribute(template[i].type)) { 1.525 + SECStatus rv; 1.526 + SECItem *signText; 1.527 + SECItem plainText; 1.528 + 1.529 + plainText.data = template[i].pValue; 1.530 + plainText.len = template[i].ulValueLen; 1.531 + PZ_Lock(keyHandle->passwordLock); 1.532 + if (keyHandle->passwordKey.data == NULL) { 1.533 + PZ_Unlock(keyHandle->passwordLock); 1.534 + crv = CKR_USER_NOT_LOGGED_IN; 1.535 + goto loser; 1.536 + } 1.537 + rv = sftkdb_SignAttribute(arena, &keyHandle->passwordKey, 1.538 + objectID, template[i].type, 1.539 + &plainText, &signText); 1.540 + PZ_Unlock(keyHandle->passwordLock); 1.541 + if (rv != SECSuccess) { 1.542 + crv = CKR_GENERAL_ERROR; /* better error code here? */ 1.543 + goto loser; 1.544 + } 1.545 + rv = sftkdb_PutAttributeSignature(handle, keyTarget, 1.546 + objectID, template[i].type, signText); 1.547 + if (rv != SECSuccess) { 1.548 + crv = CKR_GENERAL_ERROR; /* better error code here? */ 1.549 + goto loser; 1.550 + } 1.551 + } 1.552 + } 1.553 + crv = CKR_OK; 1.554 + 1.555 + /* If necessary, commit the transaction */ 1.556 + if (inPeerDBTransaction) { 1.557 + crv = (*keyTarget->sdb_Commit)(keyTarget); 1.558 + if (crv != CKR_OK) { 1.559 + goto loser; 1.560 + } 1.561 + inPeerDBTransaction = PR_FALSE; 1.562 + } 1.563 + 1.564 +loser: 1.565 + if (inPeerDBTransaction) { 1.566 + /* The transaction must have failed. Abort. */ 1.567 + (*keyTarget->sdb_Abort)(keyTarget); 1.568 + PORT_Assert(crv != CKR_OK); 1.569 + if (crv == CKR_OK) crv = CKR_GENERAL_ERROR; 1.570 + } 1.571 + return crv; 1.572 +} 1.573 + 1.574 +static CK_RV 1.575 +sftkdb_CreateObject(PLArenaPool *arena, SFTKDBHandle *handle, 1.576 + SDB *db, CK_OBJECT_HANDLE *objectID, 1.577 + CK_ATTRIBUTE *template, CK_ULONG count) 1.578 +{ 1.579 + PRBool inTransaction = PR_FALSE; 1.580 + CK_RV crv; 1.581 + 1.582 + inTransaction = PR_TRUE; 1.583 + 1.584 + crv = (*db->sdb_CreateObject)(db, objectID, template, count); 1.585 + if (crv != CKR_OK) { 1.586 + goto loser; 1.587 + } 1.588 + crv = sftk_signTemplate(arena, handle, (db == handle->update), 1.589 + *objectID, template, count); 1.590 +loser: 1.591 + 1.592 + return crv; 1.593 +} 1.594 + 1.595 + 1.596 +CK_ATTRIBUTE * 1.597 +sftk_ExtractTemplate(PLArenaPool *arena, SFTKObject *object, 1.598 + SFTKDBHandle *handle,CK_ULONG *pcount, 1.599 + CK_RV *crv) 1.600 +{ 1.601 + int count; 1.602 + CK_ATTRIBUTE *template; 1.603 + int i, templateIndex; 1.604 + SFTKSessionObject *sessObject = sftk_narrowToSessionObject(object); 1.605 + PRBool doEnc = PR_TRUE; 1.606 + 1.607 + *crv = CKR_OK; 1.608 + 1.609 + if (sessObject == NULL) { 1.610 + *crv = CKR_GENERAL_ERROR; /* internal programming error */ 1.611 + return NULL; 1.612 + } 1.613 + 1.614 + PORT_Assert(handle); 1.615 + /* find the key handle */ 1.616 + if (handle->type != SFTK_KEYDB_TYPE) { 1.617 + doEnc = PR_FALSE; 1.618 + } 1.619 + 1.620 + PZ_Lock(sessObject->attributeLock); 1.621 + count = 0; 1.622 + for (i=0; i < sessObject->hashSize; i++) { 1.623 + SFTKAttribute *attr; 1.624 + for (attr=sessObject->head[i]; attr; attr=attr->next) { 1.625 + count++; 1.626 + } 1.627 + } 1.628 + template = PORT_ArenaNewArray(arena, CK_ATTRIBUTE, count); 1.629 + if (template == NULL) { 1.630 + PZ_Unlock(sessObject->attributeLock); 1.631 + *crv = CKR_HOST_MEMORY; 1.632 + return NULL; 1.633 + } 1.634 + templateIndex = 0; 1.635 + for (i=0; i < sessObject->hashSize; i++) { 1.636 + SFTKAttribute *attr; 1.637 + for (attr=sessObject->head[i]; attr; attr=attr->next) { 1.638 + CK_ATTRIBUTE *tp = &template[templateIndex++]; 1.639 + /* copy the attribute */ 1.640 + *tp = attr->attrib; 1.641 + 1.642 + /* fixup ULONG s */ 1.643 + if ((tp->ulValueLen == sizeof (CK_ULONG)) && 1.644 + (sftkdb_isULONGAttribute(tp->type)) ) { 1.645 + CK_ULONG value = *(CK_ULONG *) tp->pValue; 1.646 + unsigned char *data; 1.647 + 1.648 + tp->pValue = PORT_ArenaAlloc(arena, SDB_ULONG_SIZE); 1.649 + data = (unsigned char *)tp->pValue; 1.650 + if (data == NULL) { 1.651 + *crv = CKR_HOST_MEMORY; 1.652 + break; 1.653 + } 1.654 + sftk_ULong2SDBULong(data, value); 1.655 + tp->ulValueLen = SDB_ULONG_SIZE; 1.656 + } 1.657 + 1.658 + /* encrypt private attributes */ 1.659 + if (doEnc && sftkdb_isPrivateAttribute(tp->type)) { 1.660 + /* we have a private attribute */ 1.661 + SECItem *cipherText; 1.662 + SECItem plainText; 1.663 + SECStatus rv; 1.664 + 1.665 + plainText.data = tp->pValue; 1.666 + plainText.len = tp->ulValueLen; 1.667 + PZ_Lock(handle->passwordLock); 1.668 + if (handle->passwordKey.data == NULL) { 1.669 + PZ_Unlock(handle->passwordLock); 1.670 + *crv = CKR_USER_NOT_LOGGED_IN; 1.671 + break; 1.672 + } 1.673 + rv = sftkdb_EncryptAttribute(arena, &handle->passwordKey, 1.674 + &plainText, &cipherText); 1.675 + PZ_Unlock(handle->passwordLock); 1.676 + if (rv == SECSuccess) { 1.677 + tp->pValue = cipherText->data; 1.678 + tp->ulValueLen = cipherText->len; 1.679 + } else { 1.680 + *crv = CKR_GENERAL_ERROR; /* better error code here? */ 1.681 + break; 1.682 + } 1.683 + PORT_Memset(plainText.data, 0, plainText.len); 1.684 + } 1.685 + } 1.686 + } 1.687 + PORT_Assert(templateIndex <= count); 1.688 + PZ_Unlock(sessObject->attributeLock); 1.689 + 1.690 + if (*crv != CKR_OK) { 1.691 + return NULL; 1.692 + } 1.693 + if (pcount) { 1.694 + *pcount = count; 1.695 + } 1.696 + return template; 1.697 + 1.698 +} 1.699 + 1.700 +/* 1.701 + * return a pointer to the attribute in the give template. 1.702 + * The return value is not const, as the caller may modify 1.703 + * the given attribute value, but such modifications will 1.704 + * modify the actual value in the template. 1.705 + */ 1.706 +static CK_ATTRIBUTE * 1.707 +sftkdb_getAttributeFromTemplate(CK_ATTRIBUTE_TYPE attribute, 1.708 + CK_ATTRIBUTE *ptemplate, CK_ULONG len) 1.709 +{ 1.710 + CK_ULONG i; 1.711 + 1.712 + for (i=0; i < len; i++) { 1.713 + if (attribute == ptemplate[i].type) { 1.714 + return &ptemplate[i]; 1.715 + } 1.716 + } 1.717 + return NULL; 1.718 +} 1.719 + 1.720 +static const CK_ATTRIBUTE * 1.721 +sftkdb_getAttributeFromConstTemplate(CK_ATTRIBUTE_TYPE attribute, 1.722 + const CK_ATTRIBUTE *ptemplate, CK_ULONG len) 1.723 +{ 1.724 + CK_ULONG i; 1.725 + 1.726 + for (i=0; i < len; i++) { 1.727 + if (attribute == ptemplate[i].type) { 1.728 + return &ptemplate[i]; 1.729 + } 1.730 + } 1.731 + return NULL; 1.732 +} 1.733 + 1.734 + 1.735 +/* 1.736 + * fetch a template which identifies 'unique' entries based on object type 1.737 + */ 1.738 +static CK_RV 1.739 +sftkdb_getFindTemplate(CK_OBJECT_CLASS objectType, unsigned char *objTypeData, 1.740 + CK_ATTRIBUTE *findTemplate, CK_ULONG *findCount, 1.741 + CK_ATTRIBUTE *ptemplate, int len) 1.742 +{ 1.743 + CK_ATTRIBUTE *attr; 1.744 + CK_ULONG count = 1; 1.745 + 1.746 + sftk_ULong2SDBULong(objTypeData, objectType); 1.747 + findTemplate[0].type = CKA_CLASS; 1.748 + findTemplate[0].pValue = objTypeData; 1.749 + findTemplate[0].ulValueLen = SDB_ULONG_SIZE; 1.750 + 1.751 + switch (objectType) { 1.752 + case CKO_CERTIFICATE: 1.753 + case CKO_NSS_TRUST: 1.754 + attr = sftkdb_getAttributeFromTemplate(CKA_ISSUER, ptemplate, len); 1.755 + if (attr == NULL) { 1.756 + return CKR_TEMPLATE_INCOMPLETE; 1.757 + } 1.758 + findTemplate[1] = *attr; 1.759 + attr = sftkdb_getAttributeFromTemplate(CKA_SERIAL_NUMBER, 1.760 + ptemplate, len); 1.761 + if (attr == NULL) { 1.762 + return CKR_TEMPLATE_INCOMPLETE; 1.763 + } 1.764 + findTemplate[2] = *attr; 1.765 + count = 3; 1.766 + break; 1.767 + 1.768 + case CKO_PRIVATE_KEY: 1.769 + case CKO_PUBLIC_KEY: 1.770 + case CKO_SECRET_KEY: 1.771 + attr = sftkdb_getAttributeFromTemplate(CKA_ID, ptemplate, len); 1.772 + if (attr == NULL) { 1.773 + return CKR_TEMPLATE_INCOMPLETE; 1.774 + } 1.775 + if (attr->ulValueLen == 0) { 1.776 + /* key is too generic to determine that it's unique, usually 1.777 + * happens in the key gen case */ 1.778 + return CKR_OBJECT_HANDLE_INVALID; 1.779 + } 1.780 + 1.781 + findTemplate[1] = *attr; 1.782 + count = 2; 1.783 + break; 1.784 + 1.785 + case CKO_NSS_CRL: 1.786 + attr = sftkdb_getAttributeFromTemplate(CKA_SUBJECT, ptemplate, len); 1.787 + if (attr == NULL) { 1.788 + return CKR_TEMPLATE_INCOMPLETE; 1.789 + } 1.790 + findTemplate[1] = *attr; 1.791 + count = 2; 1.792 + break; 1.793 + 1.794 + case CKO_NSS_SMIME: 1.795 + attr = sftkdb_getAttributeFromTemplate(CKA_SUBJECT, ptemplate, len); 1.796 + if (attr == NULL) { 1.797 + return CKR_TEMPLATE_INCOMPLETE; 1.798 + } 1.799 + findTemplate[1] = *attr; 1.800 + attr = sftkdb_getAttributeFromTemplate(CKA_NSS_EMAIL, ptemplate, len); 1.801 + if (attr == NULL) { 1.802 + return CKR_TEMPLATE_INCOMPLETE; 1.803 + } 1.804 + findTemplate[2] = *attr; 1.805 + count = 3; 1.806 + break; 1.807 + default: 1.808 + attr = sftkdb_getAttributeFromTemplate(CKA_VALUE, ptemplate, len); 1.809 + if (attr == NULL) { 1.810 + return CKR_TEMPLATE_INCOMPLETE; 1.811 + } 1.812 + findTemplate[1] = *attr; 1.813 + count = 2; 1.814 + break; 1.815 + } 1.816 + *findCount = count; 1.817 + 1.818 + return CKR_OK; 1.819 +} 1.820 + 1.821 +/* 1.822 + * look to see if this object already exists and return its object ID if 1.823 + * it does. 1.824 + */ 1.825 +static CK_RV 1.826 +sftkdb_lookupObject(SDB *db, CK_OBJECT_CLASS objectType, 1.827 + CK_OBJECT_HANDLE *id, CK_ATTRIBUTE *ptemplate, CK_ULONG len) 1.828 +{ 1.829 + CK_ATTRIBUTE findTemplate[3]; 1.830 + CK_ULONG count = 1; 1.831 + CK_ULONG objCount = 0; 1.832 + SDBFind *find = NULL; 1.833 + unsigned char objTypeData[SDB_ULONG_SIZE]; 1.834 + CK_RV crv; 1.835 + 1.836 + *id = CK_INVALID_HANDLE; 1.837 + if (objectType == CKO_NSS_CRL) { 1.838 + return CKR_OK; 1.839 + } 1.840 + crv = sftkdb_getFindTemplate(objectType, objTypeData, 1.841 + findTemplate, &count, ptemplate, len); 1.842 + 1.843 + if (crv == CKR_OBJECT_HANDLE_INVALID) { 1.844 + /* key is too generic to determine that it's unique, usually 1.845 + * happens in the key gen case, tell the caller to go ahead 1.846 + * and just create it */ 1.847 + return CKR_OK; 1.848 + } 1.849 + if (crv != CKR_OK) { 1.850 + return crv; 1.851 + } 1.852 + 1.853 + /* use the raw find, so we get the correct database */ 1.854 + crv = (*db->sdb_FindObjectsInit)(db, findTemplate, count, &find); 1.855 + if (crv != CKR_OK) { 1.856 + return crv; 1.857 + } 1.858 + (*db->sdb_FindObjects)(db, find, id, 1, &objCount); 1.859 + (*db->sdb_FindObjectsFinal)(db, find); 1.860 + 1.861 + if (objCount == 0) { 1.862 + *id = CK_INVALID_HANDLE; 1.863 + } 1.864 + return CKR_OK; 1.865 +} 1.866 + 1.867 + 1.868 +/* 1.869 + * check to see if this template conflicts with others in our current database. 1.870 + */ 1.871 +static CK_RV 1.872 +sftkdb_checkConflicts(SDB *db, CK_OBJECT_CLASS objectType, 1.873 + const CK_ATTRIBUTE *ptemplate, CK_ULONG len, 1.874 + CK_OBJECT_HANDLE sourceID) 1.875 +{ 1.876 + CK_ATTRIBUTE findTemplate[2]; 1.877 + unsigned char objTypeData[SDB_ULONG_SIZE]; 1.878 + /* we may need to allocate some temporaries. Keep track of what was 1.879 + * allocated so we can free it in the end */ 1.880 + unsigned char *temp1 = NULL; 1.881 + unsigned char *temp2 = NULL; 1.882 + CK_ULONG objCount = 0; 1.883 + SDBFind *find = NULL; 1.884 + CK_OBJECT_HANDLE id; 1.885 + const CK_ATTRIBUTE *attr, *attr2; 1.886 + CK_RV crv; 1.887 + CK_ATTRIBUTE subject; 1.888 + 1.889 + /* Currently the only conflict is with nicknames pointing to the same 1.890 + * subject when creating or modifying a certificate. */ 1.891 + /* If the object is not a cert, no problem. */ 1.892 + if (objectType != CKO_CERTIFICATE) { 1.893 + return CKR_OK; 1.894 + } 1.895 + /* if not setting a nickname then there's still no problem */ 1.896 + attr = sftkdb_getAttributeFromConstTemplate(CKA_LABEL, ptemplate, len); 1.897 + if ((attr == NULL) || (attr->ulValueLen == 0)) { 1.898 + return CKR_OK; 1.899 + } 1.900 + /* fetch the subject of the source. For creation and merge, this should 1.901 + * be found in the template */ 1.902 + attr2 = sftkdb_getAttributeFromConstTemplate(CKA_SUBJECT, ptemplate, len); 1.903 + if (sourceID == CK_INVALID_HANDLE) { 1.904 + if ((attr2 == NULL) || ((CK_LONG)attr2->ulValueLen < 0)) { 1.905 + crv = CKR_TEMPLATE_INCOMPLETE; 1.906 + goto done; 1.907 + } 1.908 + } else if ((attr2 == NULL) || ((CK_LONG)attr2->ulValueLen <= 0)) { 1.909 + /* sourceID is set if we are trying to modify an existing entry instead 1.910 + * of creating a new one. In this case the subject may not be (probably 1.911 + * isn't) in the template, we have to read it from the database */ 1.912 + subject.type = CKA_SUBJECT; 1.913 + subject.pValue = NULL; 1.914 + subject.ulValueLen = 0; 1.915 + crv = (*db->sdb_GetAttributeValue)(db, sourceID, &subject, 1); 1.916 + if (crv != CKR_OK) { 1.917 + goto done; 1.918 + } 1.919 + if ((CK_LONG)subject.ulValueLen < 0) { 1.920 + crv = CKR_DEVICE_ERROR; /* closest pkcs11 error to corrupted DB */ 1.921 + goto done; 1.922 + } 1.923 + temp1 = subject.pValue = PORT_Alloc(++subject.ulValueLen); 1.924 + if (temp1 == NULL) { 1.925 + crv = CKR_HOST_MEMORY; 1.926 + goto done; 1.927 + } 1.928 + crv = (*db->sdb_GetAttributeValue)(db, sourceID, &subject, 1); 1.929 + if (crv != CKR_OK) { 1.930 + goto done; 1.931 + } 1.932 + attr2 = &subject; 1.933 + } 1.934 + 1.935 + /* check for another cert in the database with the same nickname */ 1.936 + sftk_ULong2SDBULong(objTypeData, objectType); 1.937 + findTemplate[0].type = CKA_CLASS; 1.938 + findTemplate[0].pValue = objTypeData; 1.939 + findTemplate[0].ulValueLen = SDB_ULONG_SIZE; 1.940 + findTemplate[1] = *attr; 1.941 + 1.942 + crv = (*db->sdb_FindObjectsInit)(db, findTemplate, 2, &find); 1.943 + if (crv != CKR_OK) { 1.944 + goto done; 1.945 + } 1.946 + (*db->sdb_FindObjects)(db, find, &id, 1, &objCount); 1.947 + (*db->sdb_FindObjectsFinal)(db, find); 1.948 + 1.949 + /* object count == 0 means no conflicting certs found, 1.950 + * go on with the operation */ 1.951 + if (objCount == 0) { 1.952 + crv = CKR_OK; 1.953 + goto done; 1.954 + } 1.955 + 1.956 + /* There is a least one cert that shares the nickname, make sure it also 1.957 + * matches the subject. */ 1.958 + findTemplate[0] = *attr2; 1.959 + /* we know how big the source subject was. Use that length to create the 1.960 + * space for the target. If it's not enough space, then it means the 1.961 + * source subject is too big, and therefore not a match. GetAttributeValue 1.962 + * will return CKR_BUFFER_TOO_SMALL. Otherwise it should be exactly enough 1.963 + * space (or enough space to be able to compare the result. */ 1.964 + temp2 = findTemplate[0].pValue = PORT_Alloc(++findTemplate[0].ulValueLen); 1.965 + if (temp2 == NULL) { 1.966 + crv = CKR_HOST_MEMORY; 1.967 + goto done; 1.968 + } 1.969 + crv = (*db->sdb_GetAttributeValue)(db, id, findTemplate, 1); 1.970 + if (crv != CKR_OK) { 1.971 + if (crv == CKR_BUFFER_TOO_SMALL) { 1.972 + /* if our buffer is too small, then the Subjects clearly do 1.973 + * not match */ 1.974 + crv = CKR_ATTRIBUTE_VALUE_INVALID; 1.975 + goto loser; 1.976 + } 1.977 + /* otherwise we couldn't get the value, just fail */ 1.978 + goto done; 1.979 + } 1.980 + 1.981 + /* Ok, we have both subjects, make sure they are the same. 1.982 + * Compare the subjects */ 1.983 + if ((findTemplate[0].ulValueLen != attr2->ulValueLen) || 1.984 + (attr2->ulValueLen > 0 && 1.985 + PORT_Memcmp(findTemplate[0].pValue, attr2->pValue, attr2->ulValueLen) 1.986 + != 0)) { 1.987 + crv = CKR_ATTRIBUTE_VALUE_INVALID; 1.988 + goto loser; 1.989 + } 1.990 + crv = CKR_OK; 1.991 + 1.992 +done: 1.993 + /* If we've failed for some other reason than a conflict, make sure we 1.994 + * return an error code other than CKR_ATTRIBUTE_VALUE_INVALID. 1.995 + * (NOTE: neither sdb_FindObjectsInit nor sdb_GetAttributeValue should 1.996 + * return CKR_ATTRIBUTE_VALUE_INVALID, so the following is paranoia). 1.997 + */ 1.998 + if (crv == CKR_ATTRIBUTE_VALUE_INVALID) { 1.999 + crv = CKR_GENERAL_ERROR; /* clearly a programming error */ 1.1000 + } 1.1001 + 1.1002 + /* exit point if we found a conflict */ 1.1003 +loser: 1.1004 + PORT_Free(temp1); 1.1005 + PORT_Free(temp2); 1.1006 + return crv; 1.1007 +} 1.1008 + 1.1009 +/* 1.1010 + * try to update the template to fix any errors. This is only done 1.1011 + * during update. 1.1012 + * 1.1013 + * NOTE: we must update the template or return an error, or the update caller 1.1014 + * will loop forever! 1.1015 + * 1.1016 + * Two copies of the source code for this algorithm exist in NSS. 1.1017 + * Changes must be made in both copies. 1.1018 + * The other copy is in pk11_IncrementNickname() in pk11wrap/pk11merge.c. 1.1019 + * 1.1020 + */ 1.1021 +static CK_RV 1.1022 +sftkdb_resolveConflicts(PLArenaPool *arena, CK_OBJECT_CLASS objectType, 1.1023 + CK_ATTRIBUTE *ptemplate, CK_ULONG *plen) 1.1024 +{ 1.1025 + CK_ATTRIBUTE *attr; 1.1026 + char *nickname, *newNickname; 1.1027 + int end, digit; 1.1028 + 1.1029 + /* sanity checks. We should never get here with these errors */ 1.1030 + if (objectType != CKO_CERTIFICATE) { 1.1031 + return CKR_GENERAL_ERROR; /* shouldn't happen */ 1.1032 + } 1.1033 + attr = sftkdb_getAttributeFromTemplate(CKA_LABEL, ptemplate, *plen); 1.1034 + if ((attr == NULL) || (attr->ulValueLen == 0)) { 1.1035 + return CKR_GENERAL_ERROR; /* shouldn't happen */ 1.1036 + } 1.1037 + 1.1038 + /* update the nickname */ 1.1039 + /* is there a number at the end of the nickname already? 1.1040 + * if so just increment that number */ 1.1041 + nickname = (char *)attr->pValue; 1.1042 + 1.1043 + /* does nickname end with " #n*" ? */ 1.1044 + for (end = attr->ulValueLen - 1; 1.1045 + end >= 2 && (digit = nickname[end]) <= '9' && digit >= '0'; 1.1046 + end--) /* just scan */ ; 1.1047 + if (attr->ulValueLen >= 3 && 1.1048 + end < (attr->ulValueLen - 1) /* at least one digit */ && 1.1049 + nickname[end] == '#' && 1.1050 + nickname[end - 1] == ' ') { 1.1051 + /* Already has a suitable suffix string */ 1.1052 + } else { 1.1053 + /* ... append " #2" to the name */ 1.1054 + static const char num2[] = " #2"; 1.1055 + newNickname = PORT_ArenaAlloc(arena, attr->ulValueLen + sizeof(num2)); 1.1056 + if (!newNickname) { 1.1057 + return CKR_HOST_MEMORY; 1.1058 + } 1.1059 + PORT_Memcpy(newNickname, nickname, attr->ulValueLen); 1.1060 + PORT_Memcpy(&newNickname[attr->ulValueLen], num2, sizeof(num2)); 1.1061 + attr->pValue = newNickname; /* modifies ptemplate */ 1.1062 + attr->ulValueLen += 3; /* 3 is strlen(num2) */ 1.1063 + return CKR_OK; 1.1064 + } 1.1065 + 1.1066 + for (end = attr->ulValueLen - 1; 1.1067 + end >= 0 && (digit = nickname[end]) <= '9' && digit >= '0'; 1.1068 + end--) { 1.1069 + if (digit < '9') { 1.1070 + nickname[end]++; 1.1071 + return CKR_OK; 1.1072 + } 1.1073 + nickname[end] = '0'; 1.1074 + } 1.1075 + 1.1076 + /* we overflowed, insert a new '1' for a carry in front of the number */ 1.1077 + newNickname = PORT_ArenaAlloc(arena, attr->ulValueLen + 1); 1.1078 + if (!newNickname) { 1.1079 + return CKR_HOST_MEMORY; 1.1080 + } 1.1081 + /* PORT_Memcpy should handle len of '0' */ 1.1082 + PORT_Memcpy(newNickname, nickname, ++end); 1.1083 + newNickname[end] = '1'; 1.1084 + PORT_Memset(&newNickname[end+1],'0',attr->ulValueLen - end); 1.1085 + attr->pValue = newNickname; 1.1086 + attr->ulValueLen++; 1.1087 + return CKR_OK; 1.1088 +} 1.1089 + 1.1090 +/* 1.1091 + * set an attribute and sign it if necessary 1.1092 + */ 1.1093 +static CK_RV 1.1094 +sftkdb_setAttributeValue(PLArenaPool *arena, SFTKDBHandle *handle, 1.1095 + SDB *db, CK_OBJECT_HANDLE objectID, const CK_ATTRIBUTE *template, 1.1096 + CK_ULONG count) 1.1097 +{ 1.1098 + CK_RV crv; 1.1099 + crv = (*db->sdb_SetAttributeValue)(db, objectID, template, count); 1.1100 + if (crv != CKR_OK) { 1.1101 + return crv; 1.1102 + } 1.1103 + crv = sftk_signTemplate(arena, handle, db == handle->update, 1.1104 + objectID, template, count); 1.1105 + return crv; 1.1106 +} 1.1107 + 1.1108 +/* 1.1109 + * write a softoken object out to the database. 1.1110 + */ 1.1111 +CK_RV 1.1112 +sftkdb_write(SFTKDBHandle *handle, SFTKObject *object, 1.1113 + CK_OBJECT_HANDLE *objectID) 1.1114 +{ 1.1115 + CK_ATTRIBUTE *template; 1.1116 + PLArenaPool *arena; 1.1117 + CK_ULONG count; 1.1118 + CK_RV crv; 1.1119 + SDB *db; 1.1120 + PRBool inTransaction = PR_FALSE; 1.1121 + CK_OBJECT_HANDLE id; 1.1122 + 1.1123 + *objectID = CK_INVALID_HANDLE; 1.1124 + 1.1125 + if (handle == NULL) { 1.1126 + return CKR_TOKEN_WRITE_PROTECTED; 1.1127 + } 1.1128 + db = SFTK_GET_SDB(handle); 1.1129 + 1.1130 + /* 1.1131 + * we have opened a new database, but we have not yet updated it. We are 1.1132 + * still running pointing to the old database (so the application can 1.1133 + * still read). We don't want to write to the old database at this point, 1.1134 + * however, since it leads to user confusion. So at this point we simply 1.1135 + * require a user login. Let NSS know this so it can prompt the user. 1.1136 + */ 1.1137 + if (db == handle->update) { 1.1138 + return CKR_USER_NOT_LOGGED_IN; 1.1139 + } 1.1140 + 1.1141 + arena = PORT_NewArena(256); 1.1142 + if (arena == NULL) { 1.1143 + return CKR_HOST_MEMORY; 1.1144 + } 1.1145 + 1.1146 + template = sftk_ExtractTemplate(arena, object, handle, &count, &crv); 1.1147 + if (!template) { 1.1148 + goto loser; 1.1149 + } 1.1150 + 1.1151 + crv = (*db->sdb_Begin)(db); 1.1152 + if (crv != CKR_OK) { 1.1153 + goto loser; 1.1154 + } 1.1155 + inTransaction = PR_TRUE; 1.1156 + 1.1157 + /* 1.1158 + * We want to make the base database as free from object specific knowledge 1.1159 + * as possible. To maintain compatibility, keep some of the desirable 1.1160 + * object specific semantics of the old database. 1.1161 + * 1.1162 + * These were 2 fold: 1.1163 + * 1) there were certain conflicts (like trying to set the same nickname 1.1164 + * on two different subjects) that would return an error. 1.1165 + * 2) Importing the 'same' object would silently update that object. 1.1166 + * 1.1167 + * The following 2 functions mimic the desirable effects of these two 1.1168 + * semantics without pushing any object knowledge to the underlying database 1.1169 + * code. 1.1170 + */ 1.1171 + 1.1172 + /* make sure we don't have attributes that conflict with the existing DB */ 1.1173 + crv = sftkdb_checkConflicts(db, object->objclass, template, count, 1.1174 + CK_INVALID_HANDLE); 1.1175 + if (crv != CKR_OK) { 1.1176 + goto loser; 1.1177 + } 1.1178 + /* Find any copies that match this particular object */ 1.1179 + crv = sftkdb_lookupObject(db, object->objclass, &id, template, count); 1.1180 + if (crv != CKR_OK) { 1.1181 + goto loser; 1.1182 + } 1.1183 + if (id == CK_INVALID_HANDLE) { 1.1184 + crv = sftkdb_CreateObject(arena, handle, db, objectID, template, count); 1.1185 + } else { 1.1186 + /* object already exists, modify it's attributes */ 1.1187 + *objectID = id; 1.1188 + crv = sftkdb_setAttributeValue(arena, handle, db, id, template, count); 1.1189 + } 1.1190 + if (crv != CKR_OK) { 1.1191 + goto loser; 1.1192 + } 1.1193 + 1.1194 + crv = (*db->sdb_Commit)(db); 1.1195 + inTransaction = PR_FALSE; 1.1196 + 1.1197 +loser: 1.1198 + if (inTransaction) { 1.1199 + (*db->sdb_Abort)(db); 1.1200 + /* It is trivial to show the following code cannot 1.1201 + * happen unless something is horribly wrong with our compilier or 1.1202 + * hardware */ 1.1203 + PORT_Assert(crv != CKR_OK); 1.1204 + if (crv == CKR_OK) crv = CKR_GENERAL_ERROR; 1.1205 + } 1.1206 + 1.1207 + if (arena) { 1.1208 + PORT_FreeArena(arena,PR_FALSE); 1.1209 + } 1.1210 + if (crv == CKR_OK) { 1.1211 + *objectID |= (handle->type | SFTK_TOKEN_TYPE); 1.1212 + } 1.1213 + return crv; 1.1214 +} 1.1215 + 1.1216 + 1.1217 +CK_RV 1.1218 +sftkdb_FindObjectsInit(SFTKDBHandle *handle, const CK_ATTRIBUTE *template, 1.1219 + CK_ULONG count, SDBFind **find) 1.1220 +{ 1.1221 + unsigned char *data = NULL; 1.1222 + CK_ATTRIBUTE *ntemplate = NULL; 1.1223 + CK_RV crv; 1.1224 + SDB *db; 1.1225 + 1.1226 + if (handle == NULL) { 1.1227 + return CKR_OK; 1.1228 + } 1.1229 + db = SFTK_GET_SDB(handle); 1.1230 + 1.1231 + if (count != 0) { 1.1232 + ntemplate = sftkdb_fixupTemplateIn(template, count, &data); 1.1233 + if (ntemplate == NULL) { 1.1234 + return CKR_HOST_MEMORY; 1.1235 + } 1.1236 + } 1.1237 + 1.1238 + crv = (*db->sdb_FindObjectsInit)(db, ntemplate, 1.1239 + count, find); 1.1240 + if (data) { 1.1241 + PORT_Free(ntemplate); 1.1242 + PORT_Free(data); 1.1243 + } 1.1244 + return crv; 1.1245 +} 1.1246 + 1.1247 +CK_RV 1.1248 +sftkdb_FindObjects(SFTKDBHandle *handle, SDBFind *find, 1.1249 + CK_OBJECT_HANDLE *ids, int arraySize, CK_ULONG *count) 1.1250 +{ 1.1251 + CK_RV crv; 1.1252 + SDB *db; 1.1253 + 1.1254 + if (handle == NULL) { 1.1255 + *count = 0; 1.1256 + return CKR_OK; 1.1257 + } 1.1258 + db = SFTK_GET_SDB(handle); 1.1259 + 1.1260 + crv = (*db->sdb_FindObjects)(db, find, ids, 1.1261 + arraySize, count); 1.1262 + if (crv == CKR_OK) { 1.1263 + int i; 1.1264 + for (i=0; i < *count; i++) { 1.1265 + ids[i] |= (handle->type | SFTK_TOKEN_TYPE); 1.1266 + } 1.1267 + } 1.1268 + return crv; 1.1269 +} 1.1270 + 1.1271 +CK_RV sftkdb_FindObjectsFinal(SFTKDBHandle *handle, SDBFind *find) 1.1272 +{ 1.1273 + SDB *db; 1.1274 + if (handle == NULL) { 1.1275 + return CKR_OK; 1.1276 + } 1.1277 + db = SFTK_GET_SDB(handle); 1.1278 + return (*db->sdb_FindObjectsFinal)(db, find); 1.1279 +} 1.1280 + 1.1281 +CK_RV 1.1282 +sftkdb_GetAttributeValue(SFTKDBHandle *handle, CK_OBJECT_HANDLE objectID, 1.1283 + CK_ATTRIBUTE *template, CK_ULONG count) 1.1284 +{ 1.1285 + CK_RV crv,crv2; 1.1286 + CK_ATTRIBUTE *ntemplate; 1.1287 + unsigned char *data = NULL; 1.1288 + SDB *db; 1.1289 + 1.1290 + if (handle == NULL) { 1.1291 + return CKR_GENERAL_ERROR; 1.1292 + } 1.1293 + 1.1294 + /* short circuit common attributes */ 1.1295 + if (count == 1 && 1.1296 + (template[0].type == CKA_TOKEN || 1.1297 + template[0].type == CKA_PRIVATE || 1.1298 + template[0].type == CKA_SENSITIVE)) { 1.1299 + CK_BBOOL boolVal = CK_TRUE; 1.1300 + 1.1301 + if (template[0].pValue == NULL) { 1.1302 + template[0].ulValueLen = sizeof(CK_BBOOL); 1.1303 + return CKR_OK; 1.1304 + } 1.1305 + if (template[0].ulValueLen < sizeof(CK_BBOOL)) { 1.1306 + template[0].ulValueLen = -1; 1.1307 + return CKR_BUFFER_TOO_SMALL; 1.1308 + } 1.1309 + 1.1310 + if ((template[0].type == CKA_PRIVATE) && 1.1311 + (handle->type != SFTK_KEYDB_TYPE)) { 1.1312 + boolVal = CK_FALSE; 1.1313 + } 1.1314 + if ((template[0].type == CKA_SENSITIVE) && 1.1315 + (handle->type != SFTK_KEYDB_TYPE)) { 1.1316 + boolVal = CK_FALSE; 1.1317 + } 1.1318 + *(CK_BBOOL *)template[0].pValue = boolVal; 1.1319 + template[0].ulValueLen = sizeof(CK_BBOOL); 1.1320 + return CKR_OK; 1.1321 + } 1.1322 + 1.1323 + db = SFTK_GET_SDB(handle); 1.1324 + /* nothing to do */ 1.1325 + if (count == 0) { 1.1326 + return CKR_OK; 1.1327 + } 1.1328 + ntemplate = sftkdb_fixupTemplateIn(template, count, &data); 1.1329 + if (ntemplate == NULL) { 1.1330 + return CKR_HOST_MEMORY; 1.1331 + } 1.1332 + objectID &= SFTK_OBJ_ID_MASK; 1.1333 + crv = (*db->sdb_GetAttributeValue)(db, objectID, 1.1334 + ntemplate, count); 1.1335 + crv2 = sftkdb_fixupTemplateOut(template, objectID, ntemplate, 1.1336 + count, handle); 1.1337 + if (crv == CKR_OK) crv = crv2; 1.1338 + if (data) { 1.1339 + PORT_Free(ntemplate); 1.1340 + PORT_Free(data); 1.1341 + } 1.1342 + return crv; 1.1343 + 1.1344 +} 1.1345 + 1.1346 +CK_RV 1.1347 +sftkdb_SetAttributeValue(SFTKDBHandle *handle, SFTKObject *object, 1.1348 + const CK_ATTRIBUTE *template, CK_ULONG count) 1.1349 +{ 1.1350 + CK_ATTRIBUTE *ntemplate; 1.1351 + unsigned char *data = NULL; 1.1352 + PLArenaPool *arena = NULL; 1.1353 + SDB *db; 1.1354 + CK_RV crv = CKR_OK; 1.1355 + CK_OBJECT_HANDLE objectID = (object->handle & SFTK_OBJ_ID_MASK); 1.1356 + PRBool inTransaction = PR_FALSE; 1.1357 + 1.1358 + if (handle == NULL) { 1.1359 + return CKR_TOKEN_WRITE_PROTECTED; 1.1360 + } 1.1361 + 1.1362 + db = SFTK_GET_SDB(handle); 1.1363 + /* nothing to do */ 1.1364 + if (count == 0) { 1.1365 + return CKR_OK; 1.1366 + } 1.1367 + /* 1.1368 + * we have opened a new database, but we have not yet updated it. We are 1.1369 + * still running pointing to the old database (so the application can 1.1370 + * still read). We don't want to write to the old database at this point, 1.1371 + * however, since it leads to user confusion. So at this point we simply 1.1372 + * require a user login. Let NSS know this so it can prompt the user. 1.1373 + */ 1.1374 + if (db == handle->update) { 1.1375 + return CKR_USER_NOT_LOGGED_IN; 1.1376 + } 1.1377 + 1.1378 + ntemplate = sftkdb_fixupTemplateIn(template, count, &data); 1.1379 + if (ntemplate == NULL) { 1.1380 + return CKR_HOST_MEMORY; 1.1381 + } 1.1382 + 1.1383 + /* make sure we don't have attributes that conflict with the existing DB */ 1.1384 + crv = sftkdb_checkConflicts(db, object->objclass, template, count, objectID); 1.1385 + if (crv != CKR_OK) { 1.1386 + goto loser; 1.1387 + } 1.1388 + 1.1389 + arena = PORT_NewArena(256); 1.1390 + if (arena == NULL) { 1.1391 + crv = CKR_HOST_MEMORY; 1.1392 + goto loser; 1.1393 + } 1.1394 + 1.1395 + crv = (*db->sdb_Begin)(db); 1.1396 + if (crv != CKR_OK) { 1.1397 + goto loser; 1.1398 + } 1.1399 + inTransaction = PR_TRUE; 1.1400 + crv = sftkdb_setAttributeValue(arena, handle, db, 1.1401 + objectID, template, count); 1.1402 + if (crv != CKR_OK) { 1.1403 + goto loser; 1.1404 + } 1.1405 + crv = (*db->sdb_Commit)(db); 1.1406 +loser: 1.1407 + if (crv != CKR_OK && inTransaction) { 1.1408 + (*db->sdb_Abort)(db); 1.1409 + } 1.1410 + if (data) { 1.1411 + PORT_Free(ntemplate); 1.1412 + PORT_Free(data); 1.1413 + } 1.1414 + if (arena) { 1.1415 + PORT_FreeArena(arena, PR_FALSE); 1.1416 + } 1.1417 + return crv; 1.1418 +} 1.1419 + 1.1420 +CK_RV 1.1421 +sftkdb_DestroyObject(SFTKDBHandle *handle, CK_OBJECT_HANDLE objectID) 1.1422 +{ 1.1423 + CK_RV crv = CKR_OK; 1.1424 + SDB *db; 1.1425 + 1.1426 + if (handle == NULL) { 1.1427 + return CKR_TOKEN_WRITE_PROTECTED; 1.1428 + } 1.1429 + db = SFTK_GET_SDB(handle); 1.1430 + objectID &= SFTK_OBJ_ID_MASK; 1.1431 + crv = (*db->sdb_Begin)(db); 1.1432 + if (crv != CKR_OK) { 1.1433 + goto loser; 1.1434 + } 1.1435 + crv = (*db->sdb_DestroyObject)(db, objectID); 1.1436 + if (crv != CKR_OK) { 1.1437 + goto loser; 1.1438 + } 1.1439 + crv = (*db->sdb_Commit)(db); 1.1440 +loser: 1.1441 + if (crv != CKR_OK) { 1.1442 + (*db->sdb_Abort)(db); 1.1443 + } 1.1444 + return crv; 1.1445 +} 1.1446 + 1.1447 +CK_RV 1.1448 +sftkdb_CloseDB(SFTKDBHandle *handle) 1.1449 +{ 1.1450 +#ifdef NO_FORK_CHECK 1.1451 + PRBool parentForkedAfterC_Initialize = PR_FALSE; 1.1452 +#endif 1.1453 + if (handle == NULL) { 1.1454 + return CKR_OK; 1.1455 + } 1.1456 + if (handle->update) { 1.1457 + if (handle->db->sdb_SetForkState) { 1.1458 + (*handle->db->sdb_SetForkState)(parentForkedAfterC_Initialize); 1.1459 + } 1.1460 + (*handle->update->sdb_Close)(handle->update); 1.1461 + } 1.1462 + if (handle->db) { 1.1463 + if (handle->db->sdb_SetForkState) { 1.1464 + (*handle->db->sdb_SetForkState)(parentForkedAfterC_Initialize); 1.1465 + } 1.1466 + (*handle->db->sdb_Close)(handle->db); 1.1467 + } 1.1468 + if (handle->passwordKey.data) { 1.1469 + PORT_ZFree(handle->passwordKey.data, handle->passwordKey.len); 1.1470 + } 1.1471 + if (handle->passwordLock) { 1.1472 + SKIP_AFTER_FORK(PZ_DestroyLock(handle->passwordLock)); 1.1473 + } 1.1474 + if (handle->updatePasswordKey) { 1.1475 + SECITEM_FreeItem(handle->updatePasswordKey, PR_TRUE); 1.1476 + } 1.1477 + if (handle->updateID) { 1.1478 + PORT_Free(handle->updateID); 1.1479 + } 1.1480 + PORT_Free(handle); 1.1481 + return CKR_OK; 1.1482 +} 1.1483 + 1.1484 +/* 1.1485 + * reset a database to it's uninitialized state. 1.1486 + */ 1.1487 +static CK_RV 1.1488 +sftkdb_ResetDB(SFTKDBHandle *handle) 1.1489 +{ 1.1490 + CK_RV crv = CKR_OK; 1.1491 + SDB *db; 1.1492 + if (handle == NULL) { 1.1493 + return CKR_TOKEN_WRITE_PROTECTED; 1.1494 + } 1.1495 + db = SFTK_GET_SDB(handle); 1.1496 + crv = (*db->sdb_Begin)(db); 1.1497 + if (crv != CKR_OK) { 1.1498 + goto loser; 1.1499 + } 1.1500 + crv = (*db->sdb_Reset)(db); 1.1501 + if (crv != CKR_OK) { 1.1502 + goto loser; 1.1503 + } 1.1504 + crv = (*db->sdb_Commit)(db); 1.1505 +loser: 1.1506 + if (crv != CKR_OK) { 1.1507 + (*db->sdb_Abort)(db); 1.1508 + } 1.1509 + return crv; 1.1510 +} 1.1511 + 1.1512 + 1.1513 +CK_RV 1.1514 +sftkdb_Begin(SFTKDBHandle *handle) 1.1515 +{ 1.1516 + CK_RV crv = CKR_OK; 1.1517 + SDB *db; 1.1518 + 1.1519 + if (handle == NULL) { 1.1520 + return CKR_OK; 1.1521 + } 1.1522 + db = SFTK_GET_SDB(handle); 1.1523 + if (db) { 1.1524 + crv = (*db->sdb_Begin)(db); 1.1525 + } 1.1526 + return crv; 1.1527 +} 1.1528 + 1.1529 +CK_RV 1.1530 +sftkdb_Commit(SFTKDBHandle *handle) 1.1531 +{ 1.1532 + CK_RV crv = CKR_OK; 1.1533 + SDB *db; 1.1534 + 1.1535 + if (handle == NULL) { 1.1536 + return CKR_OK; 1.1537 + } 1.1538 + db = SFTK_GET_SDB(handle); 1.1539 + if (db) { 1.1540 + (*db->sdb_Commit)(db); 1.1541 + } 1.1542 + return crv; 1.1543 +} 1.1544 + 1.1545 +CK_RV 1.1546 +sftkdb_Abort(SFTKDBHandle *handle) 1.1547 +{ 1.1548 + CK_RV crv = CKR_OK; 1.1549 + SDB *db; 1.1550 + 1.1551 + if (handle == NULL) { 1.1552 + return CKR_OK; 1.1553 + } 1.1554 + db = SFTK_GET_SDB(handle); 1.1555 + if (db) { 1.1556 + crv = (db->sdb_Abort)(db); 1.1557 + } 1.1558 + return crv; 1.1559 +} 1.1560 + 1.1561 + 1.1562 +/* 1.1563 + * functions to update the database from an old database 1.1564 + */ 1.1565 + 1.1566 +/* 1.1567 + * known attributes 1.1568 + */ 1.1569 +static const CK_ATTRIBUTE_TYPE known_attributes[] = { 1.1570 + CKA_CLASS, CKA_TOKEN, CKA_PRIVATE, CKA_LABEL, CKA_APPLICATION, 1.1571 + CKA_VALUE, CKA_OBJECT_ID, CKA_CERTIFICATE_TYPE, CKA_ISSUER, 1.1572 + CKA_SERIAL_NUMBER, CKA_AC_ISSUER, CKA_OWNER, CKA_ATTR_TYPES, CKA_TRUSTED, 1.1573 + CKA_CERTIFICATE_CATEGORY, CKA_JAVA_MIDP_SECURITY_DOMAIN, CKA_URL, 1.1574 + CKA_HASH_OF_SUBJECT_PUBLIC_KEY, CKA_HASH_OF_ISSUER_PUBLIC_KEY, 1.1575 + CKA_CHECK_VALUE, CKA_KEY_TYPE, CKA_SUBJECT, CKA_ID, CKA_SENSITIVE, 1.1576 + CKA_ENCRYPT, CKA_DECRYPT, CKA_WRAP, CKA_UNWRAP, CKA_SIGN, CKA_SIGN_RECOVER, 1.1577 + CKA_VERIFY, CKA_VERIFY_RECOVER, CKA_DERIVE, CKA_START_DATE, CKA_END_DATE, 1.1578 + CKA_MODULUS, CKA_MODULUS_BITS, CKA_PUBLIC_EXPONENT, CKA_PRIVATE_EXPONENT, 1.1579 + CKA_PRIME_1, CKA_PRIME_2, CKA_EXPONENT_1, CKA_EXPONENT_2, CKA_COEFFICIENT, 1.1580 + CKA_PRIME, CKA_SUBPRIME, CKA_BASE, CKA_PRIME_BITS, 1.1581 + CKA_SUB_PRIME_BITS, CKA_VALUE_BITS, CKA_VALUE_LEN, CKA_EXTRACTABLE, 1.1582 + CKA_LOCAL, CKA_NEVER_EXTRACTABLE, CKA_ALWAYS_SENSITIVE, 1.1583 + CKA_KEY_GEN_MECHANISM, CKA_MODIFIABLE, CKA_EC_PARAMS, 1.1584 + CKA_EC_POINT, CKA_SECONDARY_AUTH, CKA_AUTH_PIN_FLAGS, 1.1585 + CKA_ALWAYS_AUTHENTICATE, CKA_WRAP_WITH_TRUSTED, CKA_WRAP_TEMPLATE, 1.1586 + CKA_UNWRAP_TEMPLATE, CKA_HW_FEATURE_TYPE, CKA_RESET_ON_INIT, 1.1587 + CKA_HAS_RESET, CKA_PIXEL_X, CKA_PIXEL_Y, CKA_RESOLUTION, CKA_CHAR_ROWS, 1.1588 + CKA_CHAR_COLUMNS, CKA_COLOR, CKA_BITS_PER_PIXEL, CKA_CHAR_SETS, 1.1589 + CKA_ENCODING_METHODS, CKA_MIME_TYPES, CKA_MECHANISM_TYPE, 1.1590 + CKA_REQUIRED_CMS_ATTRIBUTES, CKA_DEFAULT_CMS_ATTRIBUTES, 1.1591 + CKA_SUPPORTED_CMS_ATTRIBUTES, CKA_NSS_URL, CKA_NSS_EMAIL, 1.1592 + CKA_NSS_SMIME_INFO, CKA_NSS_SMIME_TIMESTAMP, 1.1593 + CKA_NSS_PKCS8_SALT, CKA_NSS_PASSWORD_CHECK, CKA_NSS_EXPIRES, 1.1594 + CKA_NSS_KRL, CKA_NSS_PQG_COUNTER, CKA_NSS_PQG_SEED, 1.1595 + CKA_NSS_PQG_H, CKA_NSS_PQG_SEED_BITS, CKA_NSS_MODULE_SPEC, 1.1596 + CKA_TRUST_DIGITAL_SIGNATURE, CKA_TRUST_NON_REPUDIATION, 1.1597 + CKA_TRUST_KEY_ENCIPHERMENT, CKA_TRUST_DATA_ENCIPHERMENT, 1.1598 + CKA_TRUST_KEY_AGREEMENT, CKA_TRUST_KEY_CERT_SIGN, CKA_TRUST_CRL_SIGN, 1.1599 + CKA_TRUST_SERVER_AUTH, CKA_TRUST_CLIENT_AUTH, CKA_TRUST_CODE_SIGNING, 1.1600 + CKA_TRUST_EMAIL_PROTECTION, CKA_TRUST_IPSEC_END_SYSTEM, 1.1601 + CKA_TRUST_IPSEC_TUNNEL, CKA_TRUST_IPSEC_USER, CKA_TRUST_TIME_STAMPING, 1.1602 + CKA_TRUST_STEP_UP_APPROVED, CKA_CERT_SHA1_HASH, CKA_CERT_MD5_HASH, 1.1603 + CKA_NETSCAPE_DB, CKA_NETSCAPE_TRUST, CKA_NSS_OVERRIDE_EXTENSIONS 1.1604 +}; 1.1605 + 1.1606 +static int known_attributes_size= sizeof(known_attributes)/ 1.1607 + sizeof(known_attributes[0]); 1.1608 + 1.1609 +static CK_RV 1.1610 +sftkdb_GetObjectTemplate(SDB *source, CK_OBJECT_HANDLE id, 1.1611 + CK_ATTRIBUTE *ptemplate, CK_ULONG *max) 1.1612 +{ 1.1613 + int i,j; 1.1614 + CK_RV crv; 1.1615 + 1.1616 + if (*max < known_attributes_size) { 1.1617 + *max = known_attributes_size; 1.1618 + return CKR_BUFFER_TOO_SMALL; 1.1619 + } 1.1620 + for (i=0; i < known_attributes_size; i++) { 1.1621 + ptemplate[i].type = known_attributes[i]; 1.1622 + ptemplate[i].pValue = NULL; 1.1623 + ptemplate[i].ulValueLen = 0; 1.1624 + } 1.1625 + 1.1626 + crv = (*source->sdb_GetAttributeValue)(source, id, 1.1627 + ptemplate, known_attributes_size); 1.1628 + 1.1629 + if ((crv != CKR_OK) && (crv != CKR_ATTRIBUTE_TYPE_INVALID)) { 1.1630 + return crv; 1.1631 + } 1.1632 + 1.1633 + for (i=0, j=0; i < known_attributes_size; i++, j++) { 1.1634 + while (i < known_attributes_size && (ptemplate[i].ulValueLen == -1)) { 1.1635 + i++; 1.1636 + } 1.1637 + if (i >= known_attributes_size) { 1.1638 + break; 1.1639 + } 1.1640 + /* cheap optimization */ 1.1641 + if (i == j) { 1.1642 + continue; 1.1643 + } 1.1644 + ptemplate[j] = ptemplate[i]; 1.1645 + } 1.1646 + *max = j; 1.1647 + return CKR_OK; 1.1648 +} 1.1649 + 1.1650 +static const char SFTKDB_META_UPDATE_TEMPLATE[] = "upd_%s_%s"; 1.1651 + 1.1652 +/* 1.1653 + * check to see if we have already updated this database. 1.1654 + * a NULL updateID means we are trying to do an in place 1.1655 + * single database update. In that case we have already 1.1656 + * determined that an update was necessary. 1.1657 + */ 1.1658 +static PRBool 1.1659 +sftkdb_hasUpdate(const char *typeString, SDB *db, const char *updateID) 1.1660 +{ 1.1661 + char *id; 1.1662 + CK_RV crv; 1.1663 + SECItem dummy = { 0, NULL, 0 }; 1.1664 + unsigned char dummyData[SDB_MAX_META_DATA_LEN]; 1.1665 + 1.1666 + if (!updateID) { 1.1667 + return PR_FALSE; 1.1668 + } 1.1669 + id = PR_smprintf(SFTKDB_META_UPDATE_TEMPLATE, typeString, updateID); 1.1670 + if (id == NULL) { 1.1671 + return PR_FALSE; 1.1672 + } 1.1673 + dummy.data = dummyData; 1.1674 + dummy.len = sizeof(dummyData); 1.1675 + 1.1676 + crv = (*db->sdb_GetMetaData)(db, id, &dummy, NULL); 1.1677 + PR_smprintf_free(id); 1.1678 + return crv == CKR_OK ? PR_TRUE : PR_FALSE; 1.1679 +} 1.1680 + 1.1681 +/* 1.1682 + * we just completed an update, store the update id 1.1683 + * so we don't need to do it again. If non was given, 1.1684 + * there is nothing to do. 1.1685 + */ 1.1686 +static CK_RV 1.1687 +sftkdb_putUpdate(const char *typeString, SDB *db, const char *updateID) 1.1688 +{ 1.1689 + char *id; 1.1690 + CK_RV crv; 1.1691 + SECItem dummy = { 0, NULL, 0 }; 1.1692 + 1.1693 + /* if no id was given, nothing to do */ 1.1694 + if (updateID == NULL) { 1.1695 + return CKR_OK; 1.1696 + } 1.1697 + 1.1698 + dummy.data = (unsigned char *)updateID; 1.1699 + dummy.len = PORT_Strlen(updateID); 1.1700 + 1.1701 + id = PR_smprintf(SFTKDB_META_UPDATE_TEMPLATE, typeString, updateID); 1.1702 + if (id == NULL) { 1.1703 + return PR_FALSE; 1.1704 + } 1.1705 + 1.1706 + crv = (*db->sdb_PutMetaData)(db, id, &dummy, NULL); 1.1707 + PR_smprintf_free(id); 1.1708 + return crv; 1.1709 +} 1.1710 + 1.1711 +/* 1.1712 + * get a ULong attribute from a template: 1.1713 + * NOTE: this is a raw templated stored in database order! 1.1714 + */ 1.1715 +static CK_ULONG 1.1716 +sftkdb_getULongFromTemplate(CK_ATTRIBUTE_TYPE type, 1.1717 + CK_ATTRIBUTE *ptemplate, CK_ULONG len) 1.1718 +{ 1.1719 + CK_ATTRIBUTE *attr = sftkdb_getAttributeFromTemplate(type, 1.1720 + ptemplate, len); 1.1721 + 1.1722 + if (attr && attr->pValue && attr->ulValueLen == SDB_ULONG_SIZE) { 1.1723 + return sftk_SDBULong2ULong(attr->pValue); 1.1724 + } 1.1725 + return (CK_ULONG)-1; 1.1726 +} 1.1727 + 1.1728 +/* 1.1729 + * we need to find a unique CKA_ID. 1.1730 + * The basic idea is to just increment the lowest byte. 1.1731 + * This code also handles the following corner cases: 1.1732 + * 1) the single byte overflows. On overflow we increment the next byte up 1.1733 + * and so forth until we have overflowed the entire CKA_ID. 1.1734 + * 2) If we overflow the entire CKA_ID we expand it by one byte. 1.1735 + * 3) the CKA_ID is non-existant, we create a new one with one byte. 1.1736 + * This means no matter what CKA_ID is passed, the result of this function 1.1737 + * is always a new CKA_ID, and this function will never return the same 1.1738 + * CKA_ID the it has returned in the passed. 1.1739 + */ 1.1740 +static CK_RV 1.1741 +sftkdb_incrementCKAID(PLArenaPool *arena, CK_ATTRIBUTE *ptemplate) 1.1742 +{ 1.1743 + unsigned char *buf = ptemplate->pValue; 1.1744 + CK_ULONG len = ptemplate->ulValueLen; 1.1745 + 1.1746 + if (buf == NULL || len == (CK_ULONG)-1) { 1.1747 + /* we have no valid CKAID, we'll create a basic one byte CKA_ID below */ 1.1748 + len = 0; 1.1749 + } else { 1.1750 + CK_ULONG i; 1.1751 + 1.1752 + /* walk from the back to front, incrementing 1.1753 + * the CKA_ID until we no longer have a carry, 1.1754 + * or have hit the front of the id. */ 1.1755 + for (i=len; i != 0; i--) { 1.1756 + buf[i-1]++; 1.1757 + if (buf[i-1] != 0) { 1.1758 + /* no more carries, the increment is complete */ 1.1759 + return CKR_OK; 1.1760 + } 1.1761 + } 1.1762 + /* we've now overflowed, fall through and expand the CKA_ID by 1.1763 + * one byte */ 1.1764 + } 1.1765 + buf = PORT_ArenaAlloc(arena, len+1); 1.1766 + if (!buf) { 1.1767 + return CKR_HOST_MEMORY; 1.1768 + } 1.1769 + if (len > 0) { 1.1770 + PORT_Memcpy(buf, ptemplate->pValue, len); 1.1771 + } 1.1772 + buf[len] = 0; 1.1773 + ptemplate->pValue = buf; 1.1774 + ptemplate->ulValueLen = len+1; 1.1775 + return CKR_OK; 1.1776 +} 1.1777 + 1.1778 +/* 1.1779 + * drop an attribute from a template. 1.1780 + */ 1.1781 +void 1.1782 +sftkdb_dropAttribute(CK_ATTRIBUTE *attr, CK_ATTRIBUTE *ptemplate, 1.1783 + CK_ULONG *plen) 1.1784 +{ 1.1785 + CK_ULONG count = *plen; 1.1786 + CK_ULONG i; 1.1787 + 1.1788 + for (i=0; i < count; i++) { 1.1789 + if (attr->type == ptemplate[i].type) { 1.1790 + break; 1.1791 + } 1.1792 + } 1.1793 + 1.1794 + if (i == count) { 1.1795 + /* attribute not found */ 1.1796 + return; 1.1797 + } 1.1798 + 1.1799 + /* copy the remaining attributes up */ 1.1800 + for ( i++; i < count; i++) { 1.1801 + ptemplate[i-1] = ptemplate[i]; 1.1802 + } 1.1803 + 1.1804 + /* decrement the template size */ 1.1805 + *plen = count -1; 1.1806 +} 1.1807 + 1.1808 +/* 1.1809 + * create some defines for the following functions to document the meaning 1.1810 + * of true/false. (make's it easier to remember what means what. 1.1811 + */ 1.1812 +typedef enum { 1.1813 + SFTKDB_DO_NOTHING = 0, 1.1814 + SFTKDB_ADD_OBJECT, 1.1815 + SFTKDB_MODIFY_OBJECT, 1.1816 + SFTKDB_DROP_ATTRIBUTE 1.1817 +} sftkdbUpdateStatus; 1.1818 + 1.1819 +/* 1.1820 + * helper function to reconcile a single trust entry. 1.1821 + * Identify which trust entry we want to keep. 1.1822 + * If we don't need to do anything (the records are already equal). 1.1823 + * return SFTKDB_DO_NOTHING. 1.1824 + * If we want to use the source version, 1.1825 + * return SFTKDB_MODIFY_OBJECT 1.1826 + * If we want to use the target version, 1.1827 + * return SFTKDB_DROP_ATTRIBUTE 1.1828 + * 1.1829 + * In the end the caller will remove any attributes in the source 1.1830 + * template when SFTKDB_DROP_ATTRIBUTE is specified, then use do a 1.1831 + * set attributes with that template on the target if we received 1.1832 + * any SFTKDB_MODIFY_OBJECT returns. 1.1833 + */ 1.1834 +sftkdbUpdateStatus 1.1835 +sftkdb_reconcileTrustEntry(PLArenaPool *arena, CK_ATTRIBUTE *target, 1.1836 + CK_ATTRIBUTE *source) 1.1837 +{ 1.1838 + CK_ULONG targetTrust = sftkdb_getULongFromTemplate(target->type, 1.1839 + target, 1); 1.1840 + CK_ULONG sourceTrust = sftkdb_getULongFromTemplate(target->type, 1.1841 + source, 1); 1.1842 + 1.1843 + /* 1.1844 + * try to pick the best solution between the source and the 1.1845 + * target. Update the source template if we want the target value 1.1846 + * to win out. Prefer cases where we don't actually update the 1.1847 + * trust entry. 1.1848 + */ 1.1849 + 1.1850 + /* they are the same, everything is already kosher */ 1.1851 + if (targetTrust == sourceTrust) { 1.1852 + return SFTKDB_DO_NOTHING; 1.1853 + } 1.1854 + 1.1855 + /* handle the case where the source Trust attribute may be a bit 1.1856 + * flakey */ 1.1857 + if (sourceTrust == (CK_ULONG)-1) { 1.1858 + /* 1.1859 + * The source Trust is invalid. We know that the target Trust 1.1860 + * must be valid here, otherwise the above 1.1861 + * targetTrust == sourceTrust check would have succeeded. 1.1862 + */ 1.1863 + return SFTKDB_DROP_ATTRIBUTE; 1.1864 + } 1.1865 + 1.1866 + /* target is invalid, use the source's idea of the trust value */ 1.1867 + if (targetTrust == (CK_ULONG)-1) { 1.1868 + /* overwriting the target in this case is OK */ 1.1869 + return SFTKDB_MODIFY_OBJECT; 1.1870 + } 1.1871 + 1.1872 + /* at this point we know that both attributes exist and have the 1.1873 + * appropriate length (SDB_ULONG_SIZE). We no longer need to check 1.1874 + * ulValueLen for either attribute. 1.1875 + */ 1.1876 + if (sourceTrust == CKT_NSS_TRUST_UNKNOWN) { 1.1877 + return SFTKDB_DROP_ATTRIBUTE; 1.1878 + } 1.1879 + 1.1880 + /* target has no idea, use the source's idea of the trust value */ 1.1881 + if (targetTrust == CKT_NSS_TRUST_UNKNOWN) { 1.1882 + /* overwriting the target in this case is OK */ 1.1883 + return SFTKDB_MODIFY_OBJECT; 1.1884 + } 1.1885 + 1.1886 + /* so both the target and the source have some idea of what this 1.1887 + * trust attribute should be, and neither agree exactly. 1.1888 + * At this point, we prefer 'hard' attributes over 'soft' ones. 1.1889 + * 'hard' ones are CKT_NSS_TRUSTED, CKT_NSS_TRUSTED_DELEGATOR, and 1.1890 + * CKT_NSS_NOT_TRUTED. Soft ones are ones which don't change the 1.1891 + * actual trust of the cert (CKT_MUST_VERIFY_TRUST, 1.1892 + * CKT_NSS_VALID_DELEGATOR). 1.1893 + */ 1.1894 + if ((sourceTrust == CKT_NSS_MUST_VERIFY_TRUST) 1.1895 + || (sourceTrust == CKT_NSS_VALID_DELEGATOR)) { 1.1896 + return SFTKDB_DROP_ATTRIBUTE; 1.1897 + } 1.1898 + if ((targetTrust == CKT_NSS_MUST_VERIFY_TRUST) 1.1899 + || (targetTrust == CKT_NSS_VALID_DELEGATOR)) { 1.1900 + /* again, overwriting the target in this case is OK */ 1.1901 + return SFTKDB_MODIFY_OBJECT; 1.1902 + } 1.1903 + 1.1904 + /* both have hard attributes, we have a conflict, let the target win. */ 1.1905 + return SFTKDB_DROP_ATTRIBUTE; 1.1906 +} 1.1907 + 1.1908 +const CK_ATTRIBUTE_TYPE sftkdb_trustList[] = 1.1909 + { CKA_TRUST_SERVER_AUTH, CKA_TRUST_CLIENT_AUTH, 1.1910 + CKA_TRUST_CODE_SIGNING, CKA_TRUST_EMAIL_PROTECTION, 1.1911 + CKA_TRUST_IPSEC_TUNNEL, CKA_TRUST_IPSEC_USER, 1.1912 + CKA_TRUST_TIME_STAMPING }; 1.1913 + 1.1914 +#define SFTK_TRUST_TEMPLATE_COUNT \ 1.1915 + (sizeof(sftkdb_trustList)/sizeof(sftkdb_trustList[0])) 1.1916 +/* 1.1917 + * Run through the list of known trust types, and reconcile each trust 1.1918 + * entry one by one. Keep track of we really need to write out the source 1.1919 + * trust object (overwriting the existing one). 1.1920 + */ 1.1921 +static sftkdbUpdateStatus 1.1922 +sftkdb_reconcileTrust(PLArenaPool *arena, SDB *db, CK_OBJECT_HANDLE id, 1.1923 + CK_ATTRIBUTE *ptemplate, CK_ULONG *plen) 1.1924 +{ 1.1925 + CK_ATTRIBUTE trustTemplate[SFTK_TRUST_TEMPLATE_COUNT]; 1.1926 + unsigned char trustData[SFTK_TRUST_TEMPLATE_COUNT*SDB_ULONG_SIZE]; 1.1927 + sftkdbUpdateStatus update = SFTKDB_DO_NOTHING; 1.1928 + CK_ULONG i; 1.1929 + CK_RV crv; 1.1930 + 1.1931 + 1.1932 + for (i=0; i < SFTK_TRUST_TEMPLATE_COUNT; i++) { 1.1933 + trustTemplate[i].type = sftkdb_trustList[i]; 1.1934 + trustTemplate[i].pValue = &trustData[i*SDB_ULONG_SIZE]; 1.1935 + trustTemplate[i].ulValueLen = SDB_ULONG_SIZE; 1.1936 + } 1.1937 + crv = (*db->sdb_GetAttributeValue)(db, id, 1.1938 + trustTemplate, SFTK_TRUST_TEMPLATE_COUNT); 1.1939 + if ((crv != CKR_OK) && (crv != CKR_ATTRIBUTE_TYPE_INVALID)) { 1.1940 + /* target trust has some problems, update it */ 1.1941 + update = SFTKDB_MODIFY_OBJECT; 1.1942 + goto done; 1.1943 + } 1.1944 + 1.1945 + for (i=0; i < SFTK_TRUST_TEMPLATE_COUNT; i++) { 1.1946 + CK_ATTRIBUTE *attr = sftkdb_getAttributeFromTemplate( 1.1947 + trustTemplate[i].type, ptemplate, *plen); 1.1948 + sftkdbUpdateStatus status; 1.1949 + 1.1950 + 1.1951 + /* if target trust value doesn't exist, nothing to merge */ 1.1952 + if (trustTemplate[i].ulValueLen == (CK_ULONG)-1) { 1.1953 + /* if the source exists, then we want the source entry, 1.1954 + * go ahead and update */ 1.1955 + if (attr && attr->ulValueLen != (CK_ULONG)-1) { 1.1956 + update = SFTKDB_MODIFY_OBJECT; 1.1957 + } 1.1958 + continue; 1.1959 + } 1.1960 + 1.1961 + /* 1.1962 + * the source doesn't have the attribute, go to the next attribute 1.1963 + */ 1.1964 + if (attr == NULL) { 1.1965 + continue; 1.1966 + 1.1967 + } 1.1968 + status = sftkdb_reconcileTrustEntry(arena, &trustTemplate[i], attr); 1.1969 + if (status == SFTKDB_MODIFY_OBJECT) { 1.1970 + update = SFTKDB_MODIFY_OBJECT; 1.1971 + } else if (status == SFTKDB_DROP_ATTRIBUTE) { 1.1972 + /* drop the source copy of the attribute, we are going with 1.1973 + * the target's version */ 1.1974 + sftkdb_dropAttribute(attr, ptemplate, plen); 1.1975 + } 1.1976 + } 1.1977 + 1.1978 + /* finally manage stepup */ 1.1979 + if (update == SFTKDB_MODIFY_OBJECT) { 1.1980 + CK_BBOOL stepUpBool = CK_FALSE; 1.1981 + /* if we are going to write from the source, make sure we don't 1.1982 + * overwrite the stepup bit if it's on*/ 1.1983 + trustTemplate[0].type = CKA_TRUST_STEP_UP_APPROVED; 1.1984 + trustTemplate[0].pValue = &stepUpBool; 1.1985 + trustTemplate[0].ulValueLen = sizeof(stepUpBool); 1.1986 + crv = (*db->sdb_GetAttributeValue)(db, id, trustTemplate, 1); 1.1987 + if ((crv == CKR_OK) && (stepUpBool == CK_TRUE)) { 1.1988 + sftkdb_dropAttribute(trustTemplate, ptemplate, plen); 1.1989 + } 1.1990 + } else { 1.1991 + /* we currently aren't going to update. If the source stepup bit is 1.1992 + * on however, do an update so the target gets it as well */ 1.1993 + CK_ATTRIBUTE *attr; 1.1994 + 1.1995 + attr = sftkdb_getAttributeFromTemplate(CKA_TRUST_STEP_UP_APPROVED, 1.1996 + ptemplate, *plen); 1.1997 + if (attr && (attr->ulValueLen == sizeof(CK_BBOOL)) && 1.1998 + (*(CK_BBOOL *)(attr->pValue) == CK_TRUE)) { 1.1999 + update = SFTKDB_MODIFY_OBJECT; 1.2000 + } 1.2001 + } 1.2002 + 1.2003 +done: 1.2004 + return update; 1.2005 +} 1.2006 + 1.2007 +static sftkdbUpdateStatus 1.2008 +sftkdb_handleIDAndName(PLArenaPool *arena, SDB *db, CK_OBJECT_HANDLE id, 1.2009 + CK_ATTRIBUTE *ptemplate, CK_ULONG *plen) 1.2010 +{ 1.2011 + sftkdbUpdateStatus update = SFTKDB_DO_NOTHING; 1.2012 + CK_ATTRIBUTE *attr1, *attr2; 1.2013 + CK_ATTRIBUTE ttemplate[2] = { 1.2014 + {CKA_ID, NULL, 0}, 1.2015 + {CKA_LABEL, NULL, 0} 1.2016 + }; 1.2017 + CK_RV crv; 1.2018 + 1.2019 + attr1 = sftkdb_getAttributeFromTemplate(CKA_LABEL, ptemplate, *plen); 1.2020 + attr2 = sftkdb_getAttributeFromTemplate(CKA_ID, ptemplate, *plen); 1.2021 + 1.2022 + /* if the source has neither an id nor label, don't bother updating */ 1.2023 + if ( (!attr1 || attr1->ulValueLen == 0) && 1.2024 + (! attr2 || attr2->ulValueLen == 0) ) { 1.2025 + return SFTKDB_DO_NOTHING; 1.2026 + } 1.2027 + 1.2028 + /* the source has either an id or a label, see what the target has */ 1.2029 + crv = (*db->sdb_GetAttributeValue)(db, id, ttemplate, 2); 1.2030 + 1.2031 + /* if the target has neither, update from the source */ 1.2032 + if ( ((ttemplate[0].ulValueLen == 0) || 1.2033 + (ttemplate[0].ulValueLen == (CK_ULONG)-1)) && 1.2034 + ((ttemplate[1].ulValueLen == 0) || 1.2035 + (ttemplate[1].ulValueLen == (CK_ULONG)-1)) ) { 1.2036 + return SFTKDB_MODIFY_OBJECT; 1.2037 + } 1.2038 + 1.2039 + /* check the CKA_ID */ 1.2040 + if ((ttemplate[0].ulValueLen != 0) && 1.2041 + (ttemplate[0].ulValueLen != (CK_ULONG)-1)) { 1.2042 + /* we have a CKA_ID in the target, don't overwrite 1.2043 + * the target with an empty CKA_ID from the source*/ 1.2044 + if (attr1 && attr1->ulValueLen == 0) { 1.2045 + sftkdb_dropAttribute(attr1, ptemplate, plen); 1.2046 + } 1.2047 + } else if (attr1 && attr1->ulValueLen != 0) { 1.2048 + /* source has a CKA_ID, but the target doesn't, update the target */ 1.2049 + update = SFTKDB_MODIFY_OBJECT; 1.2050 + } 1.2051 + 1.2052 + 1.2053 + /* check the nickname */ 1.2054 + if ((ttemplate[1].ulValueLen != 0) && 1.2055 + (ttemplate[1].ulValueLen != (CK_ULONG)-1)) { 1.2056 + 1.2057 + /* we have a nickname in the target, and we don't have to update 1.2058 + * the CKA_ID. We are done. NOTE: if we add addition attributes 1.2059 + * in this check, this shortcut can only go on the last of them. */ 1.2060 + if (update == SFTKDB_DO_NOTHING) { 1.2061 + return update; 1.2062 + } 1.2063 + /* we have a nickname in the target, don't overwrite 1.2064 + * the target with an empty nickname from the source */ 1.2065 + if (attr2 && attr2->ulValueLen == 0) { 1.2066 + sftkdb_dropAttribute(attr2, ptemplate, plen); 1.2067 + } 1.2068 + } else if (attr2 && attr2->ulValueLen != 0) { 1.2069 + /* source has a nickname, but the target doesn't, update the target */ 1.2070 + update = SFTKDB_MODIFY_OBJECT; 1.2071 + } 1.2072 + 1.2073 + return update; 1.2074 +} 1.2075 + 1.2076 + 1.2077 + 1.2078 +/* 1.2079 + * This function updates the template before we write the object out. 1.2080 + * 1.2081 + * If we are going to skip updating this object, return PR_FALSE. 1.2082 + * If it should be updated we return PR_TRUE. 1.2083 + * To help readability, these have been defined 1.2084 + * as SFTK_DONT_UPDATE and SFTK_UPDATE respectively. 1.2085 + */ 1.2086 +static PRBool 1.2087 +sftkdb_updateObjectTemplate(PLArenaPool *arena, SDB *db, 1.2088 + CK_OBJECT_CLASS objectType, 1.2089 + CK_ATTRIBUTE *ptemplate, CK_ULONG *plen, 1.2090 + CK_OBJECT_HANDLE *targetID) 1.2091 +{ 1.2092 + PRBool done; /* should we repeat the loop? */ 1.2093 + CK_OBJECT_HANDLE id; 1.2094 + CK_RV crv = CKR_OK; 1.2095 + 1.2096 + do { 1.2097 + crv = sftkdb_checkConflicts(db, objectType, ptemplate, 1.2098 + *plen, CK_INVALID_HANDLE); 1.2099 + if (crv != CKR_ATTRIBUTE_VALUE_INVALID) { 1.2100 + break; 1.2101 + } 1.2102 + crv = sftkdb_resolveConflicts(arena, objectType, ptemplate, plen); 1.2103 + } while (crv == CKR_OK); 1.2104 + 1.2105 + if (crv != CKR_OK) { 1.2106 + return SFTKDB_DO_NOTHING; 1.2107 + } 1.2108 + 1.2109 + do { 1.2110 + done = PR_TRUE; 1.2111 + crv = sftkdb_lookupObject(db, objectType, &id, ptemplate, *plen); 1.2112 + if (crv != CKR_OK) { 1.2113 + return SFTKDB_DO_NOTHING; 1.2114 + } 1.2115 + 1.2116 + /* This object already exists, merge it, don't update */ 1.2117 + if (id != CK_INVALID_HANDLE) { 1.2118 + CK_ATTRIBUTE *attr = NULL; 1.2119 + /* special post processing for attributes */ 1.2120 + switch (objectType) { 1.2121 + case CKO_CERTIFICATE: 1.2122 + case CKO_PUBLIC_KEY: 1.2123 + case CKO_PRIVATE_KEY: 1.2124 + /* update target's CKA_ID and labels if they don't already 1.2125 + * exist */ 1.2126 + *targetID = id; 1.2127 + return sftkdb_handleIDAndName(arena, db, id, ptemplate, plen); 1.2128 + case CKO_NSS_TRUST: 1.2129 + /* if we have conflicting trust object types, 1.2130 + * we need to reconcile them */ 1.2131 + *targetID = id; 1.2132 + return sftkdb_reconcileTrust(arena, db, id, ptemplate, plen); 1.2133 + case CKO_SECRET_KEY: 1.2134 + /* secret keys in the old database are all sdr keys, 1.2135 + * unfortunately they all appear to have the same CKA_ID, 1.2136 + * even though they are truly different keys, so we always 1.2137 + * want to update these keys, but we need to 1.2138 + * give them a new CKA_ID */ 1.2139 + /* NOTE: this changes ptemplate */ 1.2140 + attr = sftkdb_getAttributeFromTemplate(CKA_ID,ptemplate,*plen); 1.2141 + crv = attr ? sftkdb_incrementCKAID(arena, attr) 1.2142 + : CKR_HOST_MEMORY; 1.2143 + /* in the extremely rare event that we needed memory and 1.2144 + * couldn't get it, just drop the key */ 1.2145 + if (crv != CKR_OK) { 1.2146 + return SFTKDB_DO_NOTHING; 1.2147 + } 1.2148 + done = PR_FALSE; /* repeat this find loop */ 1.2149 + break; 1.2150 + default: 1.2151 + /* for all other objects, if we found the equivalent object, 1.2152 + * don't update it */ 1.2153 + return SFTKDB_DO_NOTHING; 1.2154 + } 1.2155 + } 1.2156 + } while (!done); 1.2157 + 1.2158 + /* this object doesn't exist, update it */ 1.2159 + return SFTKDB_ADD_OBJECT; 1.2160 +} 1.2161 + 1.2162 + 1.2163 +#define MAX_ATTRIBUTES 500 1.2164 +static CK_RV 1.2165 +sftkdb_mergeObject(SFTKDBHandle *handle, CK_OBJECT_HANDLE id, 1.2166 + SECItem *key) 1.2167 +{ 1.2168 + CK_ATTRIBUTE template[MAX_ATTRIBUTES]; 1.2169 + CK_ATTRIBUTE *ptemplate; 1.2170 + CK_ULONG max_attributes = MAX_ATTRIBUTES; 1.2171 + CK_OBJECT_CLASS objectType; 1.2172 + SDB *source = handle->update; 1.2173 + SDB *target = handle->db; 1.2174 + int i; 1.2175 + CK_RV crv; 1.2176 + PLArenaPool *arena = NULL; 1.2177 + 1.2178 + arena = PORT_NewArena(256); 1.2179 + if (arena == NULL) { 1.2180 + return CKR_HOST_MEMORY; 1.2181 + } 1.2182 + 1.2183 + ptemplate = &template[0]; 1.2184 + id &= SFTK_OBJ_ID_MASK; 1.2185 + crv = sftkdb_GetObjectTemplate(source, id, ptemplate, &max_attributes); 1.2186 + if (crv == CKR_BUFFER_TOO_SMALL) { 1.2187 + ptemplate = PORT_ArenaNewArray(arena, CK_ATTRIBUTE, max_attributes); 1.2188 + if (ptemplate == NULL) { 1.2189 + crv = CKR_HOST_MEMORY; 1.2190 + } else { 1.2191 + crv = sftkdb_GetObjectTemplate(source, id, 1.2192 + ptemplate, &max_attributes); 1.2193 + } 1.2194 + } 1.2195 + if (crv != CKR_OK) { 1.2196 + goto loser; 1.2197 + } 1.2198 + 1.2199 + for (i=0; i < max_attributes; i++) { 1.2200 + ptemplate[i].pValue = PORT_ArenaAlloc(arena,ptemplate[i].ulValueLen); 1.2201 + if (ptemplate[i].pValue == NULL) { 1.2202 + crv = CKR_HOST_MEMORY; 1.2203 + goto loser; 1.2204 + } 1.2205 + } 1.2206 + crv = (*source->sdb_GetAttributeValue)(source, id, 1.2207 + ptemplate, max_attributes); 1.2208 + if (crv != CKR_OK) { 1.2209 + goto loser; 1.2210 + } 1.2211 + 1.2212 + objectType = sftkdb_getULongFromTemplate(CKA_CLASS, ptemplate, 1.2213 + max_attributes); 1.2214 + 1.2215 + /* 1.2216 + * Update Object updates the object template if necessary then returns 1.2217 + * whether or not we need to actually write the object out to our target 1.2218 + * database. 1.2219 + */ 1.2220 + if (!handle->updateID) { 1.2221 + crv = sftkdb_CreateObject(arena, handle, target, &id, 1.2222 + ptemplate, max_attributes); 1.2223 + } else { 1.2224 + sftkdbUpdateStatus update_status; 1.2225 + update_status = sftkdb_updateObjectTemplate(arena, target, 1.2226 + objectType, ptemplate, &max_attributes, &id); 1.2227 + switch (update_status) { 1.2228 + case SFTKDB_ADD_OBJECT: 1.2229 + crv = sftkdb_CreateObject(arena, handle, target, &id, 1.2230 + ptemplate, max_attributes); 1.2231 + break; 1.2232 + case SFTKDB_MODIFY_OBJECT: 1.2233 + crv = sftkdb_setAttributeValue(arena, handle, target, 1.2234 + id, ptemplate, max_attributes); 1.2235 + break; 1.2236 + case SFTKDB_DO_NOTHING: 1.2237 + case SFTKDB_DROP_ATTRIBUTE: 1.2238 + break; 1.2239 + } 1.2240 + } 1.2241 + 1.2242 +loser: 1.2243 + if (arena) { 1.2244 + PORT_FreeArena(arena,PR_TRUE); 1.2245 + } 1.2246 + return crv; 1.2247 +} 1.2248 + 1.2249 + 1.2250 +#define MAX_IDS 10 1.2251 +/* 1.2252 + * update a new database from an old one, now that we have the key 1.2253 + */ 1.2254 +CK_RV 1.2255 +sftkdb_Update(SFTKDBHandle *handle, SECItem *key) 1.2256 +{ 1.2257 + SDBFind *find = NULL; 1.2258 + CK_ULONG idCount = MAX_IDS; 1.2259 + CK_OBJECT_HANDLE ids[MAX_IDS]; 1.2260 + SECItem *updatePasswordKey = NULL; 1.2261 + CK_RV crv, crv2; 1.2262 + PRBool inTransaction = PR_FALSE; 1.2263 + int i; 1.2264 + 1.2265 + if (handle == NULL) { 1.2266 + return CKR_OK; 1.2267 + } 1.2268 + if (handle->update == NULL) { 1.2269 + return CKR_OK; 1.2270 + } 1.2271 + 1.2272 + /* 1.2273 + * put the whole update under a transaction. This allows us to handle 1.2274 + * any possible race conditions between with the updateID check. 1.2275 + */ 1.2276 + crv = (*handle->db->sdb_Begin)(handle->db); 1.2277 + if (crv != CKR_OK) { 1.2278 + goto loser; 1.2279 + } 1.2280 + inTransaction = PR_TRUE; 1.2281 + 1.2282 + /* some one else has already updated this db */ 1.2283 + if (sftkdb_hasUpdate(sftkdb_TypeString(handle), 1.2284 + handle->db, handle->updateID)) { 1.2285 + crv = CKR_OK; 1.2286 + goto done; 1.2287 + } 1.2288 + 1.2289 + updatePasswordKey = sftkdb_GetUpdatePasswordKey(handle); 1.2290 + if (updatePasswordKey) { 1.2291 + /* pass the source DB key to the legacy code, 1.2292 + * so it can decrypt things */ 1.2293 + handle->oldKey = updatePasswordKey; 1.2294 + } 1.2295 + 1.2296 + /* find all the objects */ 1.2297 + crv = sftkdb_FindObjectsInit(handle, NULL, 0, &find); 1.2298 + 1.2299 + if (crv != CKR_OK) { 1.2300 + goto loser; 1.2301 + } 1.2302 + while ((crv == CKR_OK) && (idCount == MAX_IDS)) { 1.2303 + crv = sftkdb_FindObjects(handle, find, ids, MAX_IDS, &idCount); 1.2304 + for (i=0; (crv == CKR_OK) && (i < idCount); i++) { 1.2305 + crv = sftkdb_mergeObject(handle, ids[i], key); 1.2306 + } 1.2307 + } 1.2308 + crv2 = sftkdb_FindObjectsFinal(handle, find); 1.2309 + if (crv == CKR_OK) crv = crv2; 1.2310 + 1.2311 +loser: 1.2312 + /* no longer need the old key value */ 1.2313 + handle->oldKey = NULL; 1.2314 + 1.2315 + /* update the password - even if we didn't update objects */ 1.2316 + if (handle->type == SFTK_KEYDB_TYPE) { 1.2317 + SECItem item1, item2; 1.2318 + unsigned char data1[SDB_MAX_META_DATA_LEN]; 1.2319 + unsigned char data2[SDB_MAX_META_DATA_LEN]; 1.2320 + 1.2321 + item1.data = data1; 1.2322 + item1.len = sizeof(data1); 1.2323 + item2.data = data2; 1.2324 + item2.len = sizeof(data2); 1.2325 + 1.2326 + /* if the target db already has a password, skip this. */ 1.2327 + crv = (*handle->db->sdb_GetMetaData)(handle->db, "password", 1.2328 + &item1, &item2); 1.2329 + if (crv == CKR_OK) { 1.2330 + goto done; 1.2331 + } 1.2332 + 1.2333 + 1.2334 + /* nope, update it from the source */ 1.2335 + crv = (*handle->update->sdb_GetMetaData)(handle->update, "password", 1.2336 + &item1, &item2); 1.2337 + if (crv != CKR_OK) { 1.2338 + goto done; 1.2339 + } 1.2340 + crv = (*handle->db->sdb_PutMetaData)(handle->db, "password", &item1, 1.2341 + &item2); 1.2342 + if (crv != CKR_OK) { 1.2343 + goto done; 1.2344 + } 1.2345 + } 1.2346 + 1.2347 +done: 1.2348 + /* finally mark this up to date db up to date */ 1.2349 + /* some one else has already updated this db */ 1.2350 + if (crv == CKR_OK) { 1.2351 + crv = sftkdb_putUpdate(sftkdb_TypeString(handle), 1.2352 + handle->db, handle->updateID); 1.2353 + } 1.2354 + 1.2355 + if (inTransaction) { 1.2356 + if (crv == CKR_OK) { 1.2357 + crv = (*handle->db->sdb_Commit)(handle->db); 1.2358 + } else { 1.2359 + (*handle->db->sdb_Abort)(handle->db); 1.2360 + } 1.2361 + } 1.2362 + if (handle->update) { 1.2363 + (*handle->update->sdb_Close)(handle->update); 1.2364 + handle->update = NULL; 1.2365 + } 1.2366 + if (handle->updateID) { 1.2367 + PORT_Free(handle->updateID); 1.2368 + handle->updateID = NULL; 1.2369 + } 1.2370 + sftkdb_FreeUpdatePasswordKey(handle); 1.2371 + if (updatePasswordKey) { 1.2372 + SECITEM_ZfreeItem(updatePasswordKey, PR_TRUE); 1.2373 + } 1.2374 + handle->updateDBIsInit = PR_FALSE; 1.2375 + return crv; 1.2376 +} 1.2377 + 1.2378 +/****************************************************************** 1.2379 + * DB handle managing functions. 1.2380 + * 1.2381 + * These functions are called by softoken to initialize, acquire, 1.2382 + * and release database handles. 1.2383 + */ 1.2384 + 1.2385 +const char * 1.2386 +sftkdb_GetUpdateID(SFTKDBHandle *handle) 1.2387 +{ 1.2388 + return handle->updateID; 1.2389 +} 1.2390 + 1.2391 +/* release a database handle */ 1.2392 +void 1.2393 +sftk_freeDB(SFTKDBHandle *handle) 1.2394 +{ 1.2395 + PRInt32 ref; 1.2396 + 1.2397 + if (!handle) return; 1.2398 + ref = PR_ATOMIC_DECREMENT(&handle->ref); 1.2399 + if (ref == 0) { 1.2400 + sftkdb_CloseDB(handle); 1.2401 + } 1.2402 + return; 1.2403 +} 1.2404 + 1.2405 + 1.2406 +/* 1.2407 + * acquire a database handle for a certificate db 1.2408 + * (database for public objects) 1.2409 + */ 1.2410 +SFTKDBHandle * 1.2411 +sftk_getCertDB(SFTKSlot *slot) 1.2412 +{ 1.2413 + SFTKDBHandle *dbHandle; 1.2414 + 1.2415 + PZ_Lock(slot->slotLock); 1.2416 + dbHandle = slot->certDB; 1.2417 + if (dbHandle) { 1.2418 + PR_ATOMIC_INCREMENT(&dbHandle->ref); 1.2419 + } 1.2420 + PZ_Unlock(slot->slotLock); 1.2421 + return dbHandle; 1.2422 +} 1.2423 + 1.2424 +/* 1.2425 + * acquire a database handle for a key database 1.2426 + * (database for private objects) 1.2427 + */ 1.2428 +SFTKDBHandle * 1.2429 +sftk_getKeyDB(SFTKSlot *slot) 1.2430 +{ 1.2431 + SFTKDBHandle *dbHandle; 1.2432 + 1.2433 + SKIP_AFTER_FORK(PZ_Lock(slot->slotLock)); 1.2434 + dbHandle = slot->keyDB; 1.2435 + if (dbHandle) { 1.2436 + PR_ATOMIC_INCREMENT(&dbHandle->ref); 1.2437 + } 1.2438 + SKIP_AFTER_FORK(PZ_Unlock(slot->slotLock)); 1.2439 + return dbHandle; 1.2440 +} 1.2441 + 1.2442 +/* 1.2443 + * acquire the database for a specific object. NOTE: objectID must point 1.2444 + * to a Token object! 1.2445 + */ 1.2446 +SFTKDBHandle * 1.2447 +sftk_getDBForTokenObject(SFTKSlot *slot, CK_OBJECT_HANDLE objectID) 1.2448 +{ 1.2449 + SFTKDBHandle *dbHandle; 1.2450 + 1.2451 + PZ_Lock(slot->slotLock); 1.2452 + dbHandle = objectID & SFTK_KEYDB_TYPE ? slot->keyDB : slot->certDB; 1.2453 + if (dbHandle) { 1.2454 + PR_ATOMIC_INCREMENT(&dbHandle->ref); 1.2455 + } 1.2456 + PZ_Unlock(slot->slotLock); 1.2457 + return dbHandle; 1.2458 +} 1.2459 + 1.2460 +/* 1.2461 + * initialize a new database handle 1.2462 + */ 1.2463 +static SFTKDBHandle * 1.2464 +sftk_NewDBHandle(SDB *sdb, int type) 1.2465 +{ 1.2466 + SFTKDBHandle *handle = PORT_New(SFTKDBHandle); 1.2467 + handle->ref = 1; 1.2468 + handle->db = sdb; 1.2469 + handle->update = NULL; 1.2470 + handle->peerDB = NULL; 1.2471 + handle->newKey = NULL; 1.2472 + handle->oldKey = NULL; 1.2473 + handle->updatePasswordKey = NULL; 1.2474 + handle->updateID = NULL; 1.2475 + handle->type = type; 1.2476 + handle->passwordKey.data = NULL; 1.2477 + handle->passwordKey.len = 0; 1.2478 + handle->passwordLock = NULL; 1.2479 + if (type == SFTK_KEYDB_TYPE) { 1.2480 + handle->passwordLock = PZ_NewLock(nssILockAttribute); 1.2481 + } 1.2482 + sdb->app_private = handle; 1.2483 + return handle; 1.2484 +} 1.2485 + 1.2486 +/* 1.2487 + * reset the key database to it's uninitialized state. This call 1.2488 + * will clear all the key entried. 1.2489 + */ 1.2490 +SECStatus 1.2491 +sftkdb_ResetKeyDB(SFTKDBHandle *handle) 1.2492 +{ 1.2493 + CK_RV crv; 1.2494 + 1.2495 + /* only rest the key db */ 1.2496 + if (handle->type != SFTK_KEYDB_TYPE) { 1.2497 + return SECFailure; 1.2498 + } 1.2499 + crv = sftkdb_ResetDB(handle); 1.2500 + if (crv != CKR_OK) { 1.2501 + /* set error */ 1.2502 + return SECFailure; 1.2503 + } 1.2504 + return SECSuccess; 1.2505 +} 1.2506 + 1.2507 +static PRBool 1.2508 +sftk_oldVersionExists(const char *dir, int version) 1.2509 +{ 1.2510 + int i; 1.2511 + PRStatus exists = PR_FAILURE; 1.2512 + char *file = NULL; 1.2513 + 1.2514 + for (i=version; i > 1 ; i--) { 1.2515 + file = PR_smprintf("%s%d.db",dir,i); 1.2516 + if (file == NULL) { 1.2517 + continue; 1.2518 + } 1.2519 + exists = PR_Access(file, PR_ACCESS_EXISTS); 1.2520 + PR_smprintf_free(file); 1.2521 + if (exists == PR_SUCCESS) { 1.2522 + return PR_TRUE; 1.2523 + } 1.2524 + } 1.2525 + return PR_FALSE; 1.2526 +} 1.2527 + 1.2528 +static PRBool 1.2529 +sftk_hasLegacyDB(const char *confdir, const char *certPrefix, 1.2530 + const char *keyPrefix, int certVersion, int keyVersion) 1.2531 +{ 1.2532 + char *dir; 1.2533 + PRBool exists; 1.2534 + 1.2535 + if (certPrefix == NULL) { 1.2536 + certPrefix = ""; 1.2537 + } 1.2538 + 1.2539 + if (keyPrefix == NULL) { 1.2540 + keyPrefix = ""; 1.2541 + } 1.2542 + 1.2543 + dir= PR_smprintf("%s/%scert", confdir, certPrefix); 1.2544 + if (dir == NULL) { 1.2545 + return PR_FALSE; 1.2546 + } 1.2547 + 1.2548 + exists = sftk_oldVersionExists(dir, certVersion); 1.2549 + PR_smprintf_free(dir); 1.2550 + if (exists) { 1.2551 + return PR_TRUE; 1.2552 + } 1.2553 + 1.2554 + dir= PR_smprintf("%s/%skey", confdir, keyPrefix); 1.2555 + if (dir == NULL) { 1.2556 + return PR_FALSE; 1.2557 + } 1.2558 + 1.2559 + exists = sftk_oldVersionExists(dir, keyVersion); 1.2560 + PR_smprintf_free(dir); 1.2561 + return exists; 1.2562 +} 1.2563 + 1.2564 +/* 1.2565 + * initialize certificate and key database handles as a pair. 1.2566 + * 1.2567 + * This function figures out what type of database we are opening and 1.2568 + * calls the appropriate low level function to open the database. 1.2569 + * It also figures out whether or not to setup up automatic update. 1.2570 + */ 1.2571 +CK_RV 1.2572 +sftk_DBInit(const char *configdir, const char *certPrefix, 1.2573 + const char *keyPrefix, const char *updatedir, 1.2574 + const char *updCertPrefix, const char *updKeyPrefix, 1.2575 + const char *updateID, PRBool readOnly, PRBool noCertDB, 1.2576 + PRBool noKeyDB, PRBool forceOpen, PRBool isFIPS, 1.2577 + SFTKDBHandle **certDB, SFTKDBHandle **keyDB) 1.2578 +{ 1.2579 + const char *confdir; 1.2580 + NSSDBType dbType = NSS_DB_TYPE_NONE; 1.2581 + char *appName = NULL; 1.2582 + SDB *keySDB, *certSDB; 1.2583 + CK_RV crv = CKR_OK; 1.2584 + int flags = SDB_RDONLY; 1.2585 + PRBool newInit = PR_FALSE; 1.2586 + PRBool needUpdate = PR_FALSE; 1.2587 + 1.2588 + if (!readOnly) { 1.2589 + flags = SDB_CREATE; 1.2590 + } 1.2591 + 1.2592 + *certDB = NULL; 1.2593 + *keyDB = NULL; 1.2594 + 1.2595 + if (noKeyDB && noCertDB) { 1.2596 + return CKR_OK; 1.2597 + } 1.2598 + confdir = _NSSUTIL_EvaluateConfigDir(configdir, &dbType, &appName); 1.2599 + 1.2600 + /* 1.2601 + * now initialize the appropriate database 1.2602 + */ 1.2603 + switch (dbType) { 1.2604 + case NSS_DB_TYPE_LEGACY: 1.2605 + crv = sftkdbCall_open(confdir, certPrefix, keyPrefix, 8, 3, flags, 1.2606 + isFIPS, noCertDB? NULL : &certSDB, noKeyDB ? NULL: &keySDB); 1.2607 + break; 1.2608 + case NSS_DB_TYPE_MULTIACCESS: 1.2609 + crv = sftkdbCall_open(configdir, certPrefix, keyPrefix, 8, 3, flags, 1.2610 + isFIPS, noCertDB? NULL : &certSDB, noKeyDB ? NULL: &keySDB); 1.2611 + break; 1.2612 + case NSS_DB_TYPE_SQL: 1.2613 + case NSS_DB_TYPE_EXTERN: /* SHOULD open a loadable db */ 1.2614 + crv = s_open(confdir, certPrefix, keyPrefix, 9, 4, flags, 1.2615 + noCertDB? NULL : &certSDB, noKeyDB ? NULL : &keySDB, &newInit); 1.2616 + 1.2617 + /* 1.2618 + * if we failed to open the DB's read only, use the old ones if 1.2619 + * the exists. 1.2620 + */ 1.2621 + if (crv != CKR_OK) { 1.2622 + if ((flags == SDB_RDONLY) && 1.2623 + sftk_hasLegacyDB(confdir, certPrefix, keyPrefix, 8, 3)) { 1.2624 + /* we have legacy databases, if we failed to open the new format 1.2625 + * DB's read only, just use the legacy ones */ 1.2626 + crv = sftkdbCall_open(confdir, certPrefix, 1.2627 + keyPrefix, 8, 3, flags, isFIPS, 1.2628 + noCertDB? NULL : &certSDB, noKeyDB ? NULL : &keySDB); 1.2629 + } 1.2630 + /* Handle the database merge case. 1.2631 + * 1.2632 + * For the merge case, we need help from the application. Only 1.2633 + * the application knows where the old database is, and what unique 1.2634 + * identifier it has associated with it. 1.2635 + * 1.2636 + * If the client supplies these values, we use them to determine 1.2637 + * if we need to update. 1.2638 + */ 1.2639 + } else if ( 1.2640 + /* both update params have been supplied */ 1.2641 + updatedir && *updatedir && updateID && *updateID 1.2642 + /* old dbs exist? */ 1.2643 + && sftk_hasLegacyDB(updatedir, updCertPrefix, updKeyPrefix, 8, 3) 1.2644 + /* and they have not yet been updated? */ 1.2645 + && ((noKeyDB || !sftkdb_hasUpdate("key", keySDB, updateID)) 1.2646 + || (noCertDB || !sftkdb_hasUpdate("cert", certSDB, updateID)))) { 1.2647 + /* we need to update */ 1.2648 + confdir = updatedir; 1.2649 + certPrefix = updCertPrefix; 1.2650 + keyPrefix = updKeyPrefix; 1.2651 + needUpdate = PR_TRUE; 1.2652 + } else if (newInit) { 1.2653 + /* if the new format DB was also a newly created DB, and we 1.2654 + * succeeded, then need to update that new database with data 1.2655 + * from the existing legacy DB */ 1.2656 + if (sftk_hasLegacyDB(confdir, certPrefix, keyPrefix, 8, 3)) { 1.2657 + needUpdate = PR_TRUE; 1.2658 + } 1.2659 + } 1.2660 + break; 1.2661 + default: 1.2662 + crv = CKR_GENERAL_ERROR; /* can't happen, EvaluationConfigDir MUST 1.2663 + * return one of the types we already 1.2664 + * specified. */ 1.2665 + } 1.2666 + if (crv != CKR_OK) { 1.2667 + goto done; 1.2668 + } 1.2669 + if (!noCertDB) { 1.2670 + *certDB = sftk_NewDBHandle(certSDB, SFTK_CERTDB_TYPE); 1.2671 + } else { 1.2672 + *certDB = NULL; 1.2673 + } 1.2674 + if (!noKeyDB) { 1.2675 + *keyDB = sftk_NewDBHandle(keySDB, SFTK_KEYDB_TYPE); 1.2676 + } else { 1.2677 + *keyDB = NULL; 1.2678 + } 1.2679 + 1.2680 + /* link them together */ 1.2681 + if (*certDB) { 1.2682 + (*certDB)->peerDB = *keyDB; 1.2683 + } 1.2684 + if (*keyDB) { 1.2685 + (*keyDB)->peerDB = *certDB; 1.2686 + } 1.2687 + 1.2688 + /* 1.2689 + * if we need to update, open the legacy database and 1.2690 + * mark the handle as needing update. 1.2691 + */ 1.2692 + if (needUpdate) { 1.2693 + SDB *updateCert = NULL; 1.2694 + SDB *updateKey = NULL; 1.2695 + CK_RV crv2; 1.2696 + 1.2697 + crv2 = sftkdbCall_open(confdir, certPrefix, keyPrefix, 8, 3, flags, 1.2698 + isFIPS, noCertDB ? NULL : &updateCert, 1.2699 + noKeyDB ? NULL : &updateKey); 1.2700 + if (crv2 == CKR_OK) { 1.2701 + if (*certDB) { 1.2702 + (*certDB)->update = updateCert; 1.2703 + (*certDB)->updateID = updateID && *updateID 1.2704 + ? PORT_Strdup(updateID) : NULL; 1.2705 + updateCert->app_private = (*certDB); 1.2706 + } 1.2707 + if (*keyDB) { 1.2708 + PRBool tokenRemoved = PR_FALSE; 1.2709 + (*keyDB)->update = updateKey; 1.2710 + (*keyDB)->updateID = updateID && *updateID ? 1.2711 + PORT_Strdup(updateID) : NULL; 1.2712 + updateKey->app_private = (*keyDB); 1.2713 + (*keyDB)->updateDBIsInit = PR_TRUE; 1.2714 + (*keyDB)->updateDBIsInit = 1.2715 + (sftkdb_HasPasswordSet(*keyDB) == SECSuccess) ? 1.2716 + PR_TRUE : PR_FALSE; 1.2717 + /* if the password on the key db is NULL, kick off our update 1.2718 + * chain of events */ 1.2719 + sftkdb_CheckPassword((*keyDB), "", &tokenRemoved); 1.2720 + } else { 1.2721 + /* we don't have a key DB, update the certificate DB now */ 1.2722 + sftkdb_Update(*certDB, NULL); 1.2723 + } 1.2724 + } 1.2725 + } 1.2726 +done: 1.2727 + if (appName) { 1.2728 + PORT_Free(appName); 1.2729 + } 1.2730 + return forceOpen ? CKR_OK : crv; 1.2731 +} 1.2732 + 1.2733 +CK_RV 1.2734 +sftkdb_Shutdown(void) 1.2735 +{ 1.2736 + s_shutdown(); 1.2737 + sftkdbCall_Shutdown(); 1.2738 + return CKR_OK; 1.2739 +} 1.2740 +