tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

sftkdb.c (106706B)


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