/* This Source Code Form is subject to the terms of the Mozilla Public *License,v.2.0.IfacopyoftheMPLwasnotdistributedwiththis
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ /* *ThefollowingcodehandlesthestorageofPKCS11modulesusedbythe *NSS.FortherestofNSS,onlyonekindofdatabasehandleexists: * *SFTKDBHandle * *ThereisoneSFTKDBHandlefortheeachkeydatabaseandoneforeachcert *database.Thesedatabasesareopenedasassociatedpairs,onepairper *slot.SFTKDBHandlesarereferencecountedobjects. * *EachSFTKDBHandlepointstoalowleveldatabasehandle(SDB).Thishandle *representstheunderlyingphysicaldatabase.Theseobjectsarenot *referencecounted,anare'owned'bytheirrespectiveSFTKDBHandles. * *
*/ #include"sftkdb.h" #include"sftkdbti.h" #include"pkcs11t.h" #include"pkcs11i.h" #include"sdb.h" #include"prprf.h" #include"pratom.h" #include"lgglue.h" #include"utilpars.h" #include"secerr.h" #include"softoken.h" #ifdefined(_WIN32) #include <windows.h> #endif
PRBool
sftkdb_isULONGAttribute(CK_ATTRIBUTE_TYPE type)
{ switch (type) { case CKA_CERTIFICATE_CATEGORY: case CKA_CERTIFICATE_TYPE: case CKA_CLASS: case CKA_JAVA_MIDP_SECURITY_DOMAIN: case CKA_KEY_GEN_MECHANISM: case CKA_KEY_TYPE: case CKA_MECHANISM_TYPE: case CKA_MODULUS_BITS: case CKA_PRIME_BITS: case CKA_SUBPRIME_BITS: case CKA_VALUE_BITS: case CKA_VALUE_LEN: case CKA_PARAMETER_SET: case CKA_NSS_PARAMETER_SET:
case CKA_PKCS_TRUST_SERVER_AUTH: case CKA_PKCS_TRUST_CLIENT_AUTH: case CKA_PKCS_TRUST_CODE_SIGNING: case CKA_PKCS_TRUST_EMAIL_PROTECTION: case CKA_TRUST_IPSEC_IKE: case CKA_PKCS_TRUST_TIME_STAMPING: case CKA_NAME_HASH_ALGORITHM:
case CKA_NSS_TRUST_DIGITAL_SIGNATURE: case CKA_NSS_TRUST_NON_REPUDIATION: case CKA_NSS_TRUST_KEY_ENCIPHERMENT: case CKA_NSS_TRUST_DATA_ENCIPHERMENT: case CKA_NSS_TRUST_KEY_AGREEMENT: case CKA_NSS_TRUST_KEY_CERT_SIGN: case CKA_NSS_TRUST_CRL_SIGN:
case CKA_NSS_TRUST_SERVER_AUTH: case CKA_NSS_TRUST_CLIENT_AUTH: case CKA_NSS_TRUST_CODE_SIGNING: case CKA_NSS_TRUST_EMAIL_PROTECTION: case CKA_NSS_TRUST_IPSEC_END_SYSTEM: case CKA_NSS_TRUST_IPSEC_TUNNEL: case CKA_NSS_TRUST_IPSEC_USER: case CKA_NSS_TRUST_TIME_STAMPING: case CKA_NSS_TRUST_STEP_UP_APPROVED: return PR_TRUE; default: break;
} return PR_FALSE;
}
/* are the attributes private? */ static PRBool
sftkdb_isPrivateAttribute(CK_ATTRIBUTE_TYPE type)
{ switch (type) { case CKA_VALUE: case CKA_SEED: case CKA_PRIVATE_EXPONENT: case CKA_PRIME_1: case CKA_PRIME_2: case CKA_EXPONENT_1: case CKA_EXPONENT_2: case CKA_COEFFICIENT: return PR_TRUE; default: break;
} return PR_FALSE;
}
/* These attributes must be authenticated with an hmac. */ static PRBool
sftkdb_isAuthenticatedAttribute(CK_ATTRIBUTE_TYPE type)
{ switch (type) { case CKA_MODULUS: case CKA_PUBLIC_EXPONENT: case CKA_NSS_CERT_SHA1_HASH: case CKA_NSS_CERT_MD5_HASH: case CKA_NSS_TRUST_SERVER_AUTH: case CKA_NSS_TRUST_CLIENT_AUTH: case CKA_NSS_TRUST_EMAIL_PROTECTION: case CKA_NSS_TRUST_CODE_SIGNING: case CKA_NSS_TRUST_STEP_UP_APPROVED: case CKA_HASH_OF_CERTIFICATE: case CKA_NAME_HASH_ALGORITHM: case CKA_PKCS_TRUST_SERVER_AUTH: case CKA_PKCS_TRUST_CLIENT_AUTH: case CKA_PKCS_TRUST_EMAIL_PROTECTION: case CKA_PKCS_TRUST_CODE_SIGNING: case CKA_NSS_OVERRIDE_EXTENSIONS: return PR_TRUE; default: break;
} return PR_FALSE;
} /* *convertanativeULONGtoadatabaseulong.Databaseulong's *areall4bytebigendianvalues.
*/ void
sftk_ULong2SDBULong(unsignedchar *data, CK_ULONG value)
{ int i;
for (i = 0; i < SDB_ULONG_SIZE; i++) {
data[i] = (value >> (SDB_ULONG_SIZE - 1 - i) * BBP) & 0xff;
}
}
/* *convertadatabaseulongbacktoanativeULONG.(reverseoftheabove *function).
*/ static CK_ULONG
sftk_SDBULong2ULong(unsignedchar *data)
{ int i;
CK_ULONG value = 0;
for (i = 0; i < SDB_ULONG_SIZE; i++) {
value |= (((CK_ULONG)data[i]) << (SDB_ULONG_SIZE - 1 - i) * BBP);
} return value;
}
/* certain trust records are default values, which are the values *returnedifthesignaturecheckfailsanyway.
* In those cases, we can skip the signature check. */
PRBool
sftkdb_isNullTrust(const CK_ATTRIBUTE *template)
{ switch (template->type) { case CKA_NSS_TRUST_SERVER_AUTH: case CKA_NSS_TRUST_CLIENT_AUTH: case CKA_NSS_TRUST_EMAIL_PROTECTION: case CKA_NSS_TRUST_CODE_SIGNING: if (template->ulValueLen != SDB_ULONG_SIZE) { break;
} if (sftk_SDBULong2ULong(template->pValue) ==
CKT_NSS_TRUST_UNKNOWN) { return PR_TRUE;
} break; case CKA_PKCS_TRUST_SERVER_AUTH: case CKA_PKCS_TRUST_CLIENT_AUTH: case CKA_PKCS_TRUST_EMAIL_PROTECTION: case CKA_PKCS_TRUST_CODE_SIGNING: if (template->ulValueLen != SDB_ULONG_SIZE) { break;
} if (sftk_SDBULong2ULong(template->pValue) ==
CKT_TRUST_UNKNOWN) { return PR_TRUE;
} break; case CKA_NSS_TRUST_STEP_UP_APPROVED: if (template->ulValueLen != 1) { break;
} if (*((unsignedchar *)(template->pValue)) == 0) { return PR_TRUE;
} break; default: break;
} return PR_FALSE;
}
/* *fixuptheinputtemplates.Ourfixedupintsarestoredindataandmust *befreedbythecaller.Thenewtemplatemustalsobefreed.Ifthereareno *CK_ULONGattributes,theorignaltemplateispassedinasis.
*/ static CK_ATTRIBUTE *
sftkdb_fixupTemplateIn(const CK_ATTRIBUTE *template, int count, unsignedchar **dataOut, int *dataOutSize)
{ int i; int ulongCount = 0; unsignedchar *data;
CK_ATTRIBUTE *ntemplate;
*dataOut = NULL;
*dataOutSize = 0;
/* first count the number of CK_ULONG attributes */ for (i = 0; i < count; i++) { /* Don't 'fixup' NULL values */ if (!template[i].pValue) { continue;
} if (template[i].ulValueLen == sizeof(CK_ULONG)) { if (sftkdb_isULONGAttribute(template[i].type)) {
ulongCount++;
}
}
} /* no attributes to fixup, just call on through */ if (ulongCount == 0) { return (CK_ATTRIBUTE *)template;
}
/* allocate space for new ULONGS */
data = (unsignedchar *)PORT_Alloc(SDB_ULONG_SIZE * ulongCount); if (!data) { return NULL;
}
/* allocate new template */
ntemplate = PORT_NewArray(CK_ATTRIBUTE, count); if (!ntemplate) {
PORT_Free(data); return NULL;
}
*dataOut = data;
*dataOutSize = SDB_ULONG_SIZE * ulongCount; /* copy the old template, fixup the actual ulongs */ for (i = 0; i < count; i++) {
ntemplate[i] = template[i]; /* Don't 'fixup' NULL values */ if (!template[i].pValue) { continue;
} if (template[i].ulValueLen == sizeof(CK_ULONG)) { if (sftkdb_isULONGAttribute(template[i].type)) {
CK_ULONG value = *(CK_ULONG *)template[i].pValue;
sftk_ULong2SDBULong(data, value);
ntemplate[i].pValue = data;
ntemplate[i].ulValueLen = SDB_ULONG_SIZE;
data += SDB_ULONG_SIZE;
}
}
} return ntemplate;
}
for (i = 0; i < count; i++) {
CK_ULONG length = template[i].ulValueLen; template[i].ulValueLen = ntemplate[i].ulValueLen; /* fixup ulongs */ if (ntemplate[i].ulValueLen == SDB_ULONG_SIZE) { if (sftkdb_isULONGAttribute(template[i].type)) { if (template[i].pValue) {
CK_ULONG value;
value = sftk_SDBULong2ULong(ntemplate[i].pValue); if (length < sizeof(CK_ULONG)) { template[i].ulValueLen = -1;
crv = CKR_BUFFER_TOO_SMALL; continue;
} /* handle the case where the CKA_PARAMETER_SET was
* incorrectly encoded */ if ((value > 0xff) &&
(template[i].type == CKA_PARAMETER_SET)) {
PORT_Memcpy(template[i].pValue, ntemplate[i].pValue,
ntemplate[i].ulValueLen);
} else {
PORT_Memcpy(template[i].pValue, &value, sizeof(CK_ULONG));
}
} template[i].ulValueLen = sizeof(CK_ULONG);
}
}
/* if no data was retrieved, no need to process encrypted or signed
* attributes */ if ((template[i].pValue == NULL) || (template[i].ulValueLen == -1)) { continue;
}
/* fixup private attributes */ if (checkEnc && sftkdb_isPrivateAttribute(ntemplate[i].type)) { /* we have a private attribute */ /* This code depends on the fact that the cipherText is bigger
* than the plain text */
SECItem cipherText;
SECItem *plainText;
SECStatus rv;
/* copy the plain text back into the template */
PORT_Memcpy(template[i].pValue, plainText->data, plainText->len); template[i].ulValueLen = plainText->len;
SECITEM_ZfreeItem(plainText, PR_TRUE);
} /* make sure signed attributes are valid */ if (checkSig && sftkdb_isAuthenticatedAttribute(ntemplate[i].type) && !sftkdb_isNullTrust(&ntemplate[i])) {
SECStatus rv;
CK_RV local_crv;
SECItem signText;
SECItem plainText; unsignedchar signData[SDB_MAX_META_DATA_LEN];
/* Use a local variable so that we don't clobber any already *seterror.ThisfunctionreturnseitherCKR_OKorthelast
* found error in the template */
local_crv = sftkdb_GetAttributeSignature(handle, keyHandle,
objectID,
ntemplate[i].type,
&signText); if (local_crv != CKR_OK) {
PORT_Memset(template[i].pValue, 0, template[i].ulValueLen); template[i].ulValueLen = -1;
crv = local_crv; continue;
}
/* *wedoasecondcheckholdingthelockjustincasetheuser *loggoutwhileweweretryingtogetthesignature.
*/
PR_Lock(keyHandle->passwordLock); if (keyHandle->passwordKey.data == NULL) { /* if we are no longer logged in, no use checking the other
* Signatures either. */
checkSig = PR_FALSE;
PR_Unlock(keyHandle->passwordLock); continue;
}
rv = sftkdb_VerifyAttribute(keyHandle,
&keyHandle->passwordKey,
objectID, ntemplate[i].type,
&plainText, &signText);
PR_Unlock(keyHandle->passwordLock); if (rv != SECSuccess) {
PORT_Memset(template[i].pValue, 0, template[i].ulValueLen); template[i].ulValueLen = -1;
crv = CKR_SIGNATURE_INVALID; /* better error code? */
} /* This Attribute is fine */
}
} return crv;
}
/* no key DB defined? then no need to sign anything */ if (keyHandle == NULL) {
crv = CKR_OK; goto loser;
}
/* When we are in a middle of an update, we have an update database set, *butwewanttowritetotherealdatabase.TheboolmayBeUpdateDBis *settoTRUEifit'spossiblethatwewanttowriteanupdatedatabase
* rather than a primary */
keyTarget = (mayBeUpdateDB && keyHandle->update) ? keyHandle->update : keyHandle->db;
/* skip the the database does not support meta data */ if ((keyTarget->sdb_flags & SDB_HAS_META) == 0) {
crv = CKR_OK; goto loser;
}
/* If we had to switch databases, we need to initialize a transaction. */ if (usingPeerDB) {
crv = (*keyTarget->sdb_Begin)(keyTarget); if (crv != CKR_OK) { goto loser;
}
inPeerDBTransaction = PR_TRUE;
}
for (i = 0; i < count; i++) { if (sftkdb_isAuthenticatedAttribute(template[i].type)) {
SECStatus rv;
SECItem *signText;
SECItem plainText;
/* if we don't have a meta table, we didn't write any signature objects */ if ((db->sdb_flags & SDB_HAS_META) == 0) { return CKR_OK;
} for (i = 0; i < max_attributes; i++) {
CK_ATTRIBUTE *att = &ptemplate[i];
CK_ATTRIBUTE_TYPE type = att->type; if (sftkdb_isPrivateAttribute(type)) { /* move the signature from one object handle to another and delete
* the old entry */
SECItem signature; unsignedchar signData[SDB_MAX_META_DATA_LEN];
signature.data = signData;
signature.len = sizeof(signData);
crv = sftkdb_getRawAttributeSignature(handle, db, oldID, type,
&signature); if (crv != CKR_OK) { /* NOTE: if we ever change our default write from AES_CBC *toAES_KW,We'llneedtochangethistoacontinueas
* we won't need the integrity record for AES_KW */ break;
}
crv = sftkdb_PutAttributeSignature(handle, db, newID, type,
&signature); if (crv != CKR_OK) { break;
} /* now get rid of the old one */
crv = sftkdb_DestroyAttributeSignature(handle, db, oldID, type); if (crv != CKR_OK) { break;
}
}
} return crv;
}
switch (objectType) { case CKO_CERTIFICATE: case CKO_NSS_TRUST: case CKO_TRUST:
attr = sftkdb_getAttributeFromTemplate(CKA_ISSUER, ptemplate, len); if (attr == NULL) { return CKR_TEMPLATE_INCOMPLETE;
}
findTemplate[1] = *attr;
attr = sftkdb_getAttributeFromTemplate(CKA_SERIAL_NUMBER,
ptemplate, len); if (attr == NULL) { return CKR_TEMPLATE_INCOMPLETE;
}
findTemplate[2] = *attr;
count = 3; break;
case CKO_PRIVATE_KEY: case CKO_PUBLIC_KEY: case CKO_SECRET_KEY:
attr = sftkdb_getAttributeFromTemplate(CKA_ID, ptemplate, len); if (attr == NULL) { return CKR_TEMPLATE_INCOMPLETE;
} if (attr->ulValueLen == 0) { /* key is too generic to determine that it's unique, usually
* happens in the key gen case */ return CKR_OBJECT_HANDLE_INVALID;
}
findTemplate[1] = *attr;
attr = sftkdb_getAttributeFromTemplate(CKA_KEY_TYPE,
ptemplate, len); if (attr != NULL) {
findTemplate[2] = *attr;
count = 3;
} else {
count = 2;
} break;
if (crv == CKR_OBJECT_HANDLE_INVALID) { /* key is too generic to determine that it's unique, usually *happensinthekeygencase,tellthecallertogoahead
* and just create it */ return CKR_OK;
} if (crv != CKR_OK) { return crv;
}
/* use the raw find, so we get the correct database */
crv = (*db->sdb_FindObjectsInit)(db, findTemplate, count, &find); if (crv != CKR_OK) { return crv;
}
(*db->sdb_FindObjects)(db, find, id, 1, &objCount);
(*db->sdb_FindObjectsFinal)(db, find);
/* *checktoseeifthistemplateconflictswithothersinourcurrentdatabase.
*/ static CK_RV
sftkdb_checkConflicts(SDB *db, CK_OBJECT_CLASS objectType, const CK_ATTRIBUTE *ptemplate, CK_ULONG len,
CK_OBJECT_HANDLE sourceID)
{
CK_ATTRIBUTE findTemplate[2]; unsignedchar objTypeData[SDB_ULONG_SIZE]; /* we may need to allocate some temporaries. Keep track of what was
* allocated so we can free it in the end */ unsignedchar *temp1 = NULL; unsignedchar *temp2 = NULL;
CK_ULONG objCount = 0;
SDBFind *find = NULL;
CK_OBJECT_HANDLE id; const CK_ATTRIBUTE *attr, *attr2;
CK_RV crv;
CK_ATTRIBUTE subject;
/* Currently the only conflict is with nicknames pointing to the same
* subject when creating or modifying a certificate. */ /* If the object is not a cert, no problem. */ if (objectType != CKO_CERTIFICATE) { return CKR_OK;
} /* if not setting a nickname then there's still no problem */
attr = sftkdb_getAttributeFromConstTemplate(CKA_LABEL, ptemplate, len); if ((attr == NULL) || (attr->ulValueLen == 0)) { return CKR_OK;
} /* fetch the subject of the source. For creation and merge, this should
* be found in the template */
attr2 = sftkdb_getAttributeFromConstTemplate(CKA_SUBJECT, ptemplate, len); if (sourceID == CK_INVALID_HANDLE) { if ((attr2 == NULL) || ((CK_LONG)attr2->ulValueLen < 0)) {
crv = CKR_TEMPLATE_INCOMPLETE; goto done;
}
} elseif ((attr2 == NULL) || ((CK_LONG)attr2->ulValueLen <= 0)) { /* sourceID is set if we are trying to modify an existing entry instead *ofcreatinganewone.Inthiscasethesubjectmaynotbe(probably
* isn't) in the template, we have to read it from the database */
subject.type = CKA_SUBJECT;
subject.pValue = NULL;
subject.ulValueLen = 0;
crv = (*db->sdb_GetAttributeValue)(db, sourceID, &subject, 1); if (crv != CKR_OK) { goto done;
} if ((CK_LONG)subject.ulValueLen < 0) {
crv = CKR_DEVICE_ERROR; /* closest pkcs11 error to corrupted DB */ goto done;
}
temp1 = subject.pValue = PORT_Alloc(++subject.ulValueLen); if (temp1 == NULL) {
crv = CKR_HOST_MEMORY; goto done;
}
crv = (*db->sdb_GetAttributeValue)(db, sourceID, &subject, 1); if (crv != CKR_OK) { goto done;
}
attr2 = &subject;
}
/* check for another cert in the database with the same nickname */
sftk_ULong2SDBULong(objTypeData, objectType);
findTemplate[0].type = CKA_CLASS;
findTemplate[0].pValue = objTypeData;
findTemplate[0].ulValueLen = SDB_ULONG_SIZE;
findTemplate[1] = *attr;
/* object count == 0 means no conflicting certs found,
* go on with the operation */ if (objCount == 0) {
crv = CKR_OK; goto done;
}
/* There is a least one cert that shares the nickname, make sure it also
* matches the subject. */
findTemplate[0] = *attr2; /* we know how big the source subject was. Use that length to create the *spaceforthetarget.Ifit'snotenoughspace,thenitmeansthe *sourcesubjectistoobig,andthereforenotamatch.GetAttributeValue *willreturnCKR_BUFFER_TOO_SMALL.Otherwiseitshouldbeexactlyenough
* space (or enough space to be able to compare the result. */
temp2 = findTemplate[0].pValue = PORT_Alloc(++findTemplate[0].ulValueLen); if (temp2 == NULL) {
crv = CKR_HOST_MEMORY; goto done;
}
crv = (*db->sdb_GetAttributeValue)(db, id, findTemplate, 1); if (crv != CKR_OK) { if (crv == CKR_BUFFER_TOO_SMALL) { /* if our buffer is too small, then the Subjects clearly do
* not match */
crv = CKR_ATTRIBUTE_VALUE_INVALID; goto loser;
} /* otherwise we couldn't get the value, just fail */ goto done;
}
/* Ok, we have both subjects, make sure they are the same.
* Compare the subjects */ if ((findTemplate[0].ulValueLen != attr2->ulValueLen) ||
(attr2->ulValueLen > 0 &&
PORT_Memcmp(findTemplate[0].pValue, attr2->pValue, attr2->ulValueLen) != 0)) {
crv = CKR_ATTRIBUTE_VALUE_INVALID; goto loser;
}
crv = CKR_OK;
done: /* If we've failed for some other reason than a conflict, make sure we *returnanerrorcodeotherthanCKR_ATTRIBUTE_VALUE_INVALID. *(NOTE:neithersdb_FindObjectsInitnorsdb_GetAttributeValueshould *returnCKR_ATTRIBUTE_VALUE_INVALID,sothefollowingisparanoia).
*/ if (crv == CKR_ATTRIBUTE_VALUE_INVALID) {
crv = CKR_GENERAL_ERROR; /* clearly a programming error */
}
/* exit point if we found a conflict */
loser:
PORT_Free(temp1);
PORT_Free(temp2); return crv;
}
/* sanity checks. We should never get here with these errors */ if (objectType != CKO_CERTIFICATE) { return CKR_GENERAL_ERROR; /* shouldn't happen */
}
attr = sftkdb_getAttributeFromTemplate(CKA_LABEL, ptemplate, *plen); if ((attr == NULL) || (attr->ulValueLen == 0)) { return CKR_GENERAL_ERROR; /* shouldn't happen */
}
/* update the nickname */ /* is there a number at the end of the nickname already?
* if so just increment that number */
nickname = (char *)attr->pValue;
/* does nickname end with " #n*" ? */ for (end = attr->ulValueLen - 1;
end >= 2 && (digit = nickname[end]) <= '9' && digit >= '0';
end--) /* just scan */
; if (attr->ulValueLen >= 3 &&
end < (attr->ulValueLen - 1) /* at least one digit */ &&
nickname[end] == '#' &&
nickname[end - 1] == ' ') { /* Already has a suitable suffix string */
} else { /* ... append " #2" to the name */ staticconstchar num2[] = " #2";
newNickname = PORT_ArenaAlloc(arena, attr->ulValueLen + sizeof(num2)); if (!newNickname) { return CKR_HOST_MEMORY;
}
PORT_Memcpy(newNickname, nickname, attr->ulValueLen);
PORT_Memcpy(&newNickname[attr->ulValueLen], num2, sizeof(num2));
attr->pValue = newNickname; /* modifies ptemplate */
attr->ulValueLen += 3; /* 3 is strlen(num2) */ return CKR_OK;
}
/* we overflowed, insert a new '1' for a carry in front of the number */
newNickname = PORT_ArenaAlloc(arena, attr->ulValueLen + 1); if (!newNickname) { return CKR_HOST_MEMORY;
} /* PORT_Memcpy should handle len of '0' */
PORT_Memcpy(newNickname, nickname, ++end);
newNickname[end] = '1';
PORT_Memset(&newNickname[end + 1], '0', attr->ulValueLen - end);
attr->pValue = newNickname;
attr->ulValueLen++; return CKR_OK;
}
/* make sure we don't have attributes that conflict with the existing DB */
crv = sftkdb_checkConflicts(db, object->objclass, template, count,
CK_INVALID_HANDLE); if (crv != CKR_OK) { goto loser;
} /* Find any copies that match this particular object */
crv = sftkdb_lookupObject(db, object->objclass, &id, template, count); if (crv != CKR_OK) { goto loser;
} if (id == CK_INVALID_HANDLE) {
*objectID = candidateID;
crv = sftkdb_CreateObject(arena, handle, db, objectID, template, count);
} else { /* object already exists, modify it's attributes */
*objectID = id; /* The object ID changed from our candidate, we need to move any
* signature attribute signatures to the new object ID. */
crv = sftkdb_fixupSignatures(handle, db, candidateID, id, template, count); if (crv != CKR_OK) { goto loser;
}
crv = sftkdb_setAttributeValue(arena, handle, db, id, template, count);
} if (crv != CKR_OK) { goto loser;
}
crv = (*db->sdb_Commit)(db);
inTransaction = PR_FALSE;
loser: if (inTransaction) {
(*db->sdb_Abort)(db); /* It is trivial to show the following code cannot *happenunlesssomethingishorriblywrongwithourcompilieror
* hardware */
PORT_Assert(crv != CKR_OK); if (crv == CKR_OK)
crv = CKR_GENERAL_ERROR;
}
if (arena) {
PORT_FreeArena(arena, PR_TRUE);
} if (crv == CKR_OK) {
*objectID |= (handle->type | SFTK_TOKEN_TYPE);
} return crv;
}
/* make sure we don't have attributes that conflict with the existing DB */
crv = sftkdb_checkConflicts(db, object->objclass, ntemplate, count,
objectID); if (crv != CKR_OK) { goto loser;
}
if (buf == NULL || len == (CK_ULONG)-1) { /* we have no valid CKAID, we'll create a basic one byte CKA_ID below */
len = 0;
} else {
CK_ULONG i;
/* walk from the back to front, incrementing *theCKA_IDuntilwenolongerhaveacarry,
* or have hit the front of the id. */ for (i = len; i != 0; i--) {
buf[i - 1]++; if (buf[i - 1] != 0) { /* no more carries, the increment is complete */ return CKR_OK;
}
} /* we've now overflowed, fall through and expand the CKA_ID by
* one byte */
}
buf = PORT_ArenaAlloc(arena, len + 1); if (!buf) { return CKR_HOST_MEMORY;
} if (len > 0) {
PORT_Memcpy(buf, ptemplate->pValue, len);
}
buf[len] = 0;
ptemplate->pValue = buf;
ptemplate->ulValueLen = len + 1; return CKR_OK;
}
/* they are the same, everything is already kosher */ if (targetTrust == sourceTrust) { return SFTKDB_DO_NOTHING;
}
/* handle the case where the source Trust attribute may be a bit
* flakey */ if (sourceTrust == (CK_ULONG)-1) { /* *ThesourceTrustisinvalid.WeknowthatthetargetTrust *mustbevalidhere,otherwisetheabove *targetTrust==sourceTrustcheckwouldhavesucceeded.
*/ return SFTKDB_DROP_ATTRIBUTE;
}
/* target is invalid, use the source's idea of the trust value */ if (targetTrust == (CK_ULONG)-1) { /* overwriting the target in this case is OK */ return SFTKDB_MODIFY_OBJECT;
}
/* at this point we know that both attributes exist and have the *appropriatelength(SDB_ULONG_SIZE).Wenolongerneedtocheck *ulValueLenforeitherattribute.
*/ if (sourceTrust == CKT_TRUST_UNKNOWN) { return SFTKDB_DROP_ATTRIBUTE;
}
/* target has no idea, use the source's idea of the trust value */ if (targetTrust == CKT_TRUST_UNKNOWN) { /* overwriting the target in this case is OK */ return SFTKDB_MODIFY_OBJECT;
}
/* so both the target and the source have some idea of what this *trustattributeshouldbe,andneitheragreeexactly. *Atthispoint,weprefer'hard'attributesover'soft'ones. *'hard'onesareCKT_TRUSTED,CKT_TRUST_ANCHOR,and *CKT_NSS_NOT_TRUTED.Softonesareoneswhichdon'tchangethe *actualtrustofthecert(CKT_TRUST_MUST_VERIFY_TRUST).
*/ if (sourceTrust == CKT_TRUST_MUST_VERIFY_TRUST) { return SFTKDB_DROP_ATTRIBUTE;
} if (targetTrust == CKT_TRUST_MUST_VERIFY_TRUST) { /* again, overwriting the target in this case is OK */ return SFTKDB_MODIFY_OBJECT;
}
/* both have hard attributes, we have a conflict, let the target win. */ return SFTKDB_DROP_ATTRIBUTE;
}
/* map the attribute types */
CK_TRUST
sftkdb_mapNSSTrustValueToPKCS11TrustValue(CK_TRUST trust)
{ switch (trust) { case CKT_NSS_TRUSTED: return CKT_TRUSTED; case CKT_NSS_TRUSTED_DELEGATOR: return CKT_TRUST_ANCHOR; case CKT_NSS_VALID_DELEGATOR: case CKT_NSS_MUST_VERIFY_TRUST: return CKT_TRUST_MUST_VERIFY_TRUST; case CKT_NSS_NOT_TRUSTED: return CKT_NOT_TRUSTED; case CKT_NSS_TRUST_UNKNOWN: return CKT_TRUST_UNKNOWN; default: break;
} return CKT_TRUST_UNKNOWN; /* everything else, just copy */
}
/* map the attribute types */
CK_ATTRIBUTE_TYPE
sftkdb_mapNSSTrustAttributeTypeToTrustAttributeType(CK_ATTRIBUTE_TYPE type)
{ switch (type) { case CKA_NSS_CERT_SHA1_HASH: return CKA_HASH_OF_CERTIFICATE; case CKA_NSS_TRUST_SERVER_AUTH: return CKA_PKCS_TRUST_SERVER_AUTH; case CKA_NSS_TRUST_CLIENT_AUTH: return CKA_PKCS_TRUST_CLIENT_AUTH; case CKA_NSS_TRUST_CODE_SIGNING: return CKA_PKCS_TRUST_CODE_SIGNING; case CKA_NSS_TRUST_EMAIL_PROTECTION: return CKA_PKCS_TRUST_EMAIL_PROTECTION; case CKA_NSS_TRUST_IPSEC_TUNNEL: return CKA_TRUST_IPSEC_IKE; case CKA_NSS_TRUST_TIME_STAMPING: return CKA_PKCS_TRUST_TIME_STAMPING; default: break;
} return type; /* everything else, just copy */
}
/* these attributes have no mappings, just drop them */
PRBool
sftkdb_dropTrustAttribute(CK_ATTRIBUTE_TYPE type)
{ switch (type) { case CKA_NSS_CERT_MD5_HASH: case CKA_NSS_TRUST_DIGITAL_SIGNATURE: case CKA_NSS_TRUST_NON_REPUDIATION: case CKA_NSS_TRUST_KEY_ENCIPHERMENT: case CKA_NSS_TRUST_DATA_ENCIPHERMENT: case CKA_NSS_TRUST_KEY_AGREEMENT: case CKA_NSS_TRUST_KEY_CERT_SIGN: case CKA_NSS_TRUST_CRL_SIGN: case CKA_NSS_TRUST_IPSEC_END_SYSTEM: case CKA_NSS_TRUST_IPSEC_USER: case CKA_NSS_TRUST_STEP_UP_APPROVED: return PR_TRUE;
} return PR_FALSE;
}
for (i = 0; i < *templateCountPtr; i++) {
CK_ATTRIBUTE *attr = &trustTemplate[i]; if (sftkdb_dropTrustAttribute(attr->type)) { /* if there's a enough space to store a ulong, hang *ontoit.Wewillprobablyneedittostore
* CKA_NAME_HASH_ALGORITHM */ if (!space && attr->ulValueLen >= SDB_ULONG_SIZE) {
space = attr->pValue;
}
sftkdb_dropAttribute(attr, trustTemplate, templateCountPtr); continue;
}
crv = sftkdb_mapTrustAttribute(attr); if (crv != CKR_OK) { return crv;
} if (attr->type == CKA_HASH_OF_CERTIFICATE) {
hasCertificateHash++;
}
} /* if we have CKA_HASH_OF_CERTIFICATE, then we need to add *CKA_NAME_HASH_ALGORITHM.Wecanonlydothatifwehavedropped *anattributebecausewecan'texpandthetemplate.Thisshouldn't *beaproblembecauseinanormaltemplatewe'llhaveaCKA_CERT_HASH_MD5
* attribute and a CKA_NSS_TRUST_STEP_UP_APPROVED attribute */ if (hasCertificateHash) { if ((*templateCountPtr >= originalCount) || !space) { return CKR_TEMPLATE_INCOMPLETE;
}
i = (*templateCountPtr)++;
trustTemplate[i].type = CKA_NAME_HASH_ALGORITHM;
trustTemplate[i].pValue = space;
trustTemplate[i].ulValueLen = SDB_ULONG_SIZE; return sftkdb_setULongInTemplate(&trustTemplate[i], CKM_SHA_1);
} return CKR_OK;
}
for (i = 0; i < templateCount; i++) {
CK_ATTRIBUTE *attr = sftkdb_getAttributeFromTemplate(
trustTemplate[i].type, ptemplate, *plen);
sftkdbUpdateStatus status;
/* if target trust value doesn't exist, nothing to merge */ if (trustTemplate[i].ulValueLen == (CK_ULONG)-1) { /* if the source exists, then we want the source entry,
* go ahead and update */ if (attr && attr->ulValueLen != (CK_ULONG)-1) {
update = SFTKDB_MODIFY_OBJECT;
} continue;
}
/* *thesourcedoesn'thavetheattribute,gotothenextattribute
*/ if (attr == NULL) { continue;
}
status = sftkdb_reconcileTrustEntry(arena, &trustTemplate[i], attr); if (useLegacy) { /* in the legacy case we are always modifying the object because
* we are updating to the new attribute type */ if (status == SFTKDB_DROP_ATTRIBUTE) { /* rather than drop the attribute, we need to copy the
* updated destination attribute */
*attr = trustTemplate[i];
} /* SFTKDB_MODIFY_OBJECT - we are already modifying the object,
* do nothing */ /* SFTKDB_NO_NOTHING, both source and target already have the
* correct attribute, so no need to copy */
} else { /* not legacy, so the target will be updated in place
* if necessary */ if (status == SFTKDB_MODIFY_OBJECT) { /* we need to write the source version of this attribute
* to the target, we need to modify the object */
update = SFTKDB_MODIFY_OBJECT;
} elseif (status == SFTKDB_DROP_ATTRIBUTE) { /* drop the source copy of the attribute, we are going with *thetarget'sversion.Thisallowsustomodifyother
* attributes if we need to. */
sftkdb_dropAttribute(attr, ptemplate, plen);
} /* SFTKDB_NO_NOTHING, both source and target already have the
* correct attribute, so no need to or drop anything */
}
}
/* we don't support step-up in the PKCS version, so don't do anything with
* step-up */
/* if the source has neither an id nor label, don't bother updating */ if ((!attr1 || attr1->ulValueLen == 0) &&
(!attr2 || attr2->ulValueLen == 0)) { return SFTKDB_DO_NOTHING;
}
/* the source has either an id or a label, see what the target has */
(void)(*db->sdb_GetAttributeValue)(db, id, ttemplate, 2);
/* if the target has neither, update from the source */ if (((ttemplate[0].ulValueLen == 0) ||
(ttemplate[0].ulValueLen == (CK_ULONG)-1)) &&
((ttemplate[1].ulValueLen == 0) ||
(ttemplate[1].ulValueLen == (CK_ULONG)-1))) { return SFTKDB_MODIFY_OBJECT;
}
/* check the CKA_ID */ if ((ttemplate[0].ulValueLen != 0) &&
(ttemplate[0].ulValueLen != (CK_ULONG)-1)) { /* we have a CKA_ID in the target, don't overwrite
* the target with an empty CKA_ID from the source*/ if (attr1 && attr1->ulValueLen == 0) {
sftkdb_dropAttribute(attr1, ptemplate, plen);
}
} elseif (attr1 && attr1->ulValueLen != 0) { /* source has a CKA_ID, but the target doesn't, update the target */
update = SFTKDB_MODIFY_OBJECT;
}
/* check the nickname */ if ((ttemplate[1].ulValueLen != 0) &&
(ttemplate[1].ulValueLen != (CK_ULONG)-1)) {
/* we have a nickname in the target, and we don't have to update *theCKA_ID.Wearedone.NOTE:ifweaddadditionattributes
* in this check, this shortcut can only go on the last of them. */ if (update == SFTKDB_DO_NOTHING) { return update;
} /* we have a nickname in the target, don't overwrite
* the target with an empty nickname from the source */ if (attr2 && attr2->ulValueLen == 0) {
sftkdb_dropAttribute(attr2, ptemplate, plen);
}
} elseif (attr2 && attr2->ulValueLen != 0) { /* source has a nickname, but the target doesn't, update the target */
update = SFTKDB_MODIFY_OBJECT;
}
do {
done = PR_TRUE;
crv = sftkdb_lookupObject(db, objectType, &id, ptemplate, *plen); if (crv != CKR_OK) { if (objectType == CKO_TRUST && id == CK_INVALID_HANDLE) {
objectType = CKO_NSS_TRUST; /* didn't find a new PKCS #11 Trust object, look for
* and NSS Vendor specific Trust Object */
crv = sftkdb_lookupObject(db, CKO_NSS_TRUST, &id,
ptemplate, *plen);
} if (crv != CKR_OK) { return SFTKDB_DO_NOTHING;
}
}
/* This object already exists, merge it, don't update */ if (id != CK_INVALID_HANDLE) {
CK_ATTRIBUTE *attr = NULL; /* special post processing for attributes */ switch (objectType) { case CKO_CERTIFICATE: case CKO_PUBLIC_KEY: case CKO_PRIVATE_KEY: /* update target's CKA_ID and labels if they don't already
* exist */
*targetID = id; return sftkdb_handleIDAndName(arena, db, id, ptemplate, plen); case CKO_NSS_TRUST: /* if we have conflicting trust object types,
* we need to reconcile them */
*targetID = id; return sftkdb_reconcileTrust(arena, db, id, PR_TRUE,
ptemplate, plen); case CKO_TRUST: /* if we have conflicting trust object types,
* we need to reconcile them */
*targetID = id; return sftkdb_reconcileTrust(arena, db, id, PR_FALSE,
ptemplate, plen); case CKO_SECRET_KEY: /* secret keys in the old database are all sdr keys, *unfortunatelytheyallappeartohavethesameCKA_ID, *eventhoughtheyaretrulydifferentkeys,sowealways *wanttoupdatethesekeys,butweneedto
* give them a new CKA_ID */ /* NOTE: this changes ptemplate */
attr = sftkdb_getAttributeFromTemplate(CKA_ID, ptemplate, *plen);
crv = attr ? sftkdb_incrementCKAID(arena, attr)
: CKR_HOST_MEMORY; /* in the extremely rare event that we needed memory and
* couldn't get it, just drop the key */ if (crv != CKR_OK) { return SFTKDB_DO_NOTHING;
}
done = PR_FALSE; /* repeat this find loop */ break; default: /* for all other objects, if we found the equivalent object,
* don't update it */ return SFTKDB_DO_NOTHING;
}
}
} while (!done);
/* this object doesn't exist, update it */ return SFTKDB_ADD_OBJECT;
}
/* if the target doesn't have META data, don't need to do anything */ if ((target->sdb_flags & SDB_HAS_META) == 0) { return CKR_OK;
} /* if the source doesn't have meta data, then the record won't require
* integrity */ if ((source->sdb_flags & SDB_HAS_META) == 0) { return CKR_OK;
} for (i = 0; i < max_attributes; i++) {
CK_ATTRIBUTE *att = &ptemplate[i];
CK_ATTRIBUTE_TYPE type = att->type; if (sftkdb_isPrivateAttribute(type)) { /* copy integrity signatures associated with this record (if any) */
SECItem signature; unsignedchar signData[SDB_MAX_META_DATA_LEN];
CK_RV crv;
signature.data = signData;
signature.len = sizeof(signData);
crv = sftkdb_getRawAttributeSignature(handle, source, sourceID, type,
&signature); if (crv != CKR_OK) { /* old databases don't have signature IDs because they are *3DESencrypted.Sinceweknownottolookforintegrity *for3DESrecordsit'sOKnottofindonehere.Anewrecord
* will be created when we reencrypt using AES CBC */ continue;
}
crv = sftkdb_PutAttributeSignature(handle, target, targetID, type,
&signature); if (crv != CKR_OK) { /* we had a signature in the source db, but we couldn't store
* it in the target, remember the error so we can report it. */
global_crv = crv;
}
}
} return global_crv;
}
/* if keyDB copy any meta data hashes to target, Update for the new
* object ID */ if (crv == CKR_OK) {
crv = sftkdb_updateIntegrity(arena, handle, source, id, target, newID,
ptemplate, max_attributes);
}
loser: if (arena) {
PORT_FreeArena(arena, PR_TRUE);
} return crv;
}
/* some one else has already updated this db */ if (sftkdb_hasUpdate(sftkdb_TypeString(handle),
handle->db, handle->updateID)) {
crv = CKR_OK; goto done;
}
updatePasswordKey = sftkdb_GetUpdatePasswordKey(handle); if (updatePasswordKey) { /* pass the source DB key to the legacy code,
* so it can decrypt things */
handle->oldKey = updatePasswordKey;
}
/* find all the objects */
crv = sftkdb_FindObjectsInit(handle, NULL, 0, &find);
if (crv != CKR_OK) { goto loser;
} while ((crv == CKR_OK) && (idCount == MAX_IDS)) {
crv = sftkdb_FindObjects(handle, find, ids, MAX_IDS, &idCount); for (i = 0; (crv == CKR_OK) && (i < idCount); i++) {
crv = sftkdb_mergeObject(handle, ids[i], key);
}
}
crv2 = sftkdb_FindObjectsFinal(handle, find); if (crv == CKR_OK)
crv = crv2;
loser: /* no longer need the old key value */
handle->oldKey = NULL;
/* update the password - even if we didn't update objects */ if (handle->type == SFTK_KEYDB_TYPE) {
SECItem item1, item2; unsignedchar data1[SDB_MAX_META_DATA_LEN]; unsignedchar data2[SDB_MAX_META_DATA_LEN];
/* if the target db already has a password, skip this. */
crv = (*handle->db->sdb_GetMetaData)(handle->db, "password",
&item1, &item2); if (crv == CKR_OK) { goto done;
}
/* nope, update it from the source */
crv = (*handle->update->sdb_GetMetaData)(handle->update, "password",
&item1, &item2); if (crv != CKR_OK) { /* if we get here, neither the source, nor the target has been initialized *withapasswordentry.Createametadatatablenowsothatwedon't
* mistake this for a partially updated database */
item1.data[0] = 0;
item2.data[0] = 0;
item1.len = item2.len = 1;
crv = (*handle->db->sdb_PutMetaData)(handle->db, "empty", &item1, &item2); goto done;
}
crv = (*handle->db->sdb_PutMetaData)(handle->db, "password", &item1,
&item2); if (crv != CKR_OK) { goto done;
}
}
done: /* finally mark this up to date db up to date */ /* some one else has already updated this db */ if (crv == CKR_OK) {
crv = sftkdb_putUpdate(sftkdb_TypeString(handle),
handle->db, handle->updateID);
}
if (inTransaction) { if (crv == CKR_OK) {
crv = (*handle->db->sdb_Commit)(handle->db);
} else {
(*handle->db->sdb_Abort)(handle->db);
}
} if (handle->update) {
(*handle->update->sdb_Close)(handle->update);
handle->update = NULL;
} if (handle->updateID) {
PORT_Free(handle->updateID);
handle->updateID = NULL;
}
sftkdb_FreeUpdatePasswordKey(handle); if (updatePasswordKey) {
SECITEM_ZfreeItem(updatePasswordKey, PR_TRUE);
}
handle->updateDBIsInit = PR_FALSE; return crv;
}
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.125Bemerkung:
(Wie Sie bei der Firma Beratungs- und Dienstleistungen beauftragen können 2026-09-29)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.