tor-browser

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

pk11merge.c (52656B)


      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 /*
      6 * Merge the source token into the target token.
      7 */
      8 
      9 #include "secmod.h"
     10 #include "secmodi.h"
     11 #include "secmodti.h"
     12 #include "pk11pub.h"
     13 #include "pk11priv.h"
     14 #include "pkcs11.h"
     15 #include "seccomon.h"
     16 #include "secerr.h"
     17 #include "keyhi.h"
     18 #include "hasht.h"
     19 #include "cert.h"
     20 #include "certdb.h"
     21 
     22 /*************************************************************************
     23 *
     24 *             short utilities to aid in the merge
     25 *
     26 *************************************************************************/
     27 
     28 /*
     29 * write a bunch of attributes out to an existing object.
     30 */
     31 static SECStatus
     32 pk11_setAttributes(PK11SlotInfo *slot, CK_OBJECT_HANDLE id,
     33                   CK_ATTRIBUTE *setTemplate, CK_ULONG setTemplCount)
     34 {
     35    CK_RV crv;
     36    CK_SESSION_HANDLE rwsession;
     37 
     38    rwsession = PK11_GetRWSession(slot);
     39    if (rwsession == CK_INVALID_HANDLE) {
     40        PORT_SetError(SEC_ERROR_BAD_DATA);
     41        return SECFailure;
     42    }
     43    crv = PK11_GETTAB(slot)->C_SetAttributeValue(rwsession, id,
     44                                                 setTemplate, setTemplCount);
     45    PK11_RestoreROSession(slot, rwsession);
     46    if (crv != CKR_OK) {
     47        PORT_SetError(PK11_MapError(crv));
     48        return SECFailure;
     49    }
     50    return SECSuccess;
     51 }
     52 
     53 /*
     54 * copy a template of attributes from a source object to a target object.
     55 * if target object is not given, create it.
     56 */
     57 static SECStatus
     58 pk11_copyAttributes(PLArenaPool *arena,
     59                    PK11SlotInfo *targetSlot, CK_OBJECT_HANDLE targetID,
     60                    PK11SlotInfo *sourceSlot, CK_OBJECT_HANDLE sourceID,
     61                    CK_ATTRIBUTE *copyTemplate, CK_ULONG copyTemplateCount)
     62 {
     63    SECStatus rv;
     64    CK_ATTRIBUTE *newTemplate = NULL;
     65    CK_RV crv;
     66 
     67    crv = PK11_GetAttributes(arena, sourceSlot, sourceID,
     68                             copyTemplate, copyTemplateCount);
     69    /* if we have missing attributes, just skip them and create the object */
     70    if (crv == CKR_ATTRIBUTE_TYPE_INVALID) {
     71        CK_ULONG i, j;
     72        newTemplate = PORT_NewArray(CK_ATTRIBUTE, copyTemplateCount);
     73        if (!newTemplate) {
     74            return SECFailure;
     75        }
     76        /* remove the unknown attributes. If we don't have enough attributes
     77         * PK11_CreateNewObject() will fail */
     78        for (i = 0, j = 0; i < copyTemplateCount; i++) {
     79            if (copyTemplate[i].ulValueLen != -1) {
     80                newTemplate[j] = copyTemplate[i];
     81                j++;
     82            }
     83        }
     84        copyTemplate = newTemplate;
     85        copyTemplateCount = j;
     86        crv = PK11_GetAttributes(arena, sourceSlot, sourceID,
     87                                 copyTemplate, copyTemplateCount);
     88    }
     89    if (crv != CKR_OK) {
     90        PORT_SetError(PK11_MapError(crv));
     91        PORT_Free(newTemplate);
     92        return SECFailure;
     93    }
     94    if (targetID == CK_INVALID_HANDLE) {
     95        /* we need to create the object */
     96        rv = PK11_CreateNewObject(targetSlot, CK_INVALID_HANDLE,
     97                                  copyTemplate, copyTemplateCount, PR_TRUE, &targetID);
     98    } else {
     99        /* update the existing object with the new attributes */
    100        rv = pk11_setAttributes(targetSlot, targetID,
    101                                copyTemplate, copyTemplateCount);
    102    }
    103    if (newTemplate) {
    104        PORT_Free(newTemplate);
    105    }
    106    return rv;
    107 }
    108 
    109 static CK_OBJECT_CLASS
    110 pk11_getClassFromTemplate(CK_ATTRIBUTE *template, CK_ULONG tsize)
    111 {
    112    CK_ULONG i;
    113    for (i = 0; i < tsize; i++) {
    114        if ((template[i].type == CKA_CLASS) &&
    115            template[i].ulValueLen == sizeof(CK_OBJECT_CLASS)) {
    116            return *(CK_OBJECT_CLASS *)template[i].pValue;
    117        }
    118    }
    119    return CK_INVALID_HANDLE;
    120 }
    121 
    122 static void
    123 pk11_setClassInTemplate(CK_ATTRIBUTE *template, CK_ULONG tsize,
    124                        CK_OBJECT_CLASS objClass)
    125 {
    126    CK_ULONG i;
    127    for (i = 0; i < tsize; i++) {
    128        if ((template[i].type == CKA_CLASS) &&
    129            template[i].ulValueLen == sizeof(objClass)) {
    130            PORT_Memcpy(template[i].pValue, &objClass, sizeof(objClass));
    131        }
    132    }
    133 }
    134 
    135 /*
    136 * look for a matching object across tokens.
    137 */
    138 static SECStatus
    139 pk11_matchAcrossTokens(PLArenaPool *arena, PK11SlotInfo *targetSlot,
    140                       PK11SlotInfo *sourceSlot,
    141                       CK_ATTRIBUTE *template, CK_ULONG tsize,
    142                       CK_OBJECT_HANDLE id, CK_OBJECT_HANDLE *peer)
    143 {
    144 
    145    CK_RV crv;
    146    CK_OBJECT_CLASS objclass = CK_INVALID_HANDLE;
    147    *peer = CK_INVALID_HANDLE;
    148 
    149    crv = PK11_GetAttributes(arena, sourceSlot, id, template, tsize);
    150    if (crv != CKR_OK) {
    151        PORT_SetError(PK11_MapError(crv));
    152        goto loser;
    153    }
    154 
    155    if (template[0].ulValueLen == -1) {
    156        crv = CKR_ATTRIBUTE_TYPE_INVALID;
    157        PORT_SetError(PK11_MapError(crv));
    158        goto loser;
    159    }
    160 
    161    /* if the source is a CKO_NSS_TRUST, first look to see if the target
    162     * has a CKO_TRUST object */
    163    objclass = pk11_getClassFromTemplate(template, tsize);
    164    if (objclass == CKO_NSS_TRUST) {
    165        pk11_setClassInTemplate(template, tsize, CKO_TRUST);
    166        objclass = CKO_TRUST;
    167    }
    168 
    169    *peer = pk11_FindObjectByTemplate(targetSlot, template, tsize);
    170    /* if we coun't find a CKO_TRUST object, look for a CKO_NSS_TRUST object */
    171    if ((*peer == CK_INVALID_HANDLE && objclass == CKO_TRUST)) {
    172        pk11_setClassInTemplate(template, tsize, CKO_NSS_TRUST);
    173        *peer = pk11_FindObjectByTemplate(targetSlot, template, tsize);
    174    }
    175    return SECSuccess;
    176 
    177 loser:
    178    return SECFailure;
    179 }
    180 
    181 /*
    182 * Encrypt using key and parameters
    183 */
    184 SECStatus
    185 pk11_encrypt(PK11SymKey *symKey, CK_MECHANISM_TYPE mechType, SECItem *param,
    186             SECItem *input, SECItem **output)
    187 {
    188    PK11Context *ctxt = NULL;
    189    SECStatus rv = SECSuccess;
    190 
    191    if (*output) {
    192        SECITEM_FreeItem(*output, PR_TRUE);
    193    }
    194    *output = SECITEM_AllocItem(NULL, NULL, input->len + 20 /*slop*/);
    195    if (!*output) {
    196        rv = SECFailure;
    197        goto done;
    198    }
    199 
    200    ctxt = PK11_CreateContextBySymKey(mechType, CKA_ENCRYPT, symKey, param);
    201    if (ctxt == NULL) {
    202        rv = SECFailure;
    203        goto done;
    204    }
    205 
    206    rv = PK11_CipherOp(ctxt, (*output)->data,
    207                       (int *)&((*output)->len),
    208                       (*output)->len, input->data, input->len);
    209 
    210 done:
    211    if (ctxt) {
    212        PK11_Finalize(ctxt);
    213        PK11_DestroyContext(ctxt, PR_TRUE);
    214    }
    215    if (rv != SECSuccess) {
    216        if (*output) {
    217            SECITEM_FreeItem(*output, PR_TRUE);
    218            *output = NULL;
    219        }
    220    }
    221    return rv;
    222 }
    223 
    224 /*************************************************************************
    225 *
    226 *            Private Keys
    227 *
    228 *************************************************************************/
    229 
    230 /*
    231 * Fetch the key usage based on the pkcs #11 flags
    232 */
    233 unsigned int
    234 pk11_getPrivateKeyUsage(PK11SlotInfo *slot, CK_OBJECT_HANDLE id)
    235 {
    236    unsigned int usage = 0;
    237 
    238    if ((PK11_HasAttributeSet(slot, id, CKA_UNWRAP, PR_FALSE) ||
    239         PK11_HasAttributeSet(slot, id, CKA_DECRYPT, PR_FALSE))) {
    240        usage |= KU_KEY_ENCIPHERMENT;
    241    }
    242    if (PK11_HasAttributeSet(slot, id, CKA_DERIVE, PR_FALSE)) {
    243        usage |= KU_KEY_AGREEMENT;
    244    }
    245    if ((PK11_HasAttributeSet(slot, id, CKA_SIGN_RECOVER, PR_FALSE) ||
    246         PK11_HasAttributeSet(slot, id, CKA_SIGN, PR_FALSE))) {
    247        usage |= KU_DIGITAL_SIGNATURE;
    248    }
    249    return usage;
    250 }
    251 
    252 /*
    253 * merge a private key,
    254 *
    255 * Private keys are merged using PBE wrapped keys with a random
    256 * value as the 'password'. Once the base key is moved, The remaining
    257 * attributes (SUBJECT) is copied.
    258 */
    259 static SECStatus
    260 pk11_mergePrivateKey(PK11SlotInfo *targetSlot, PK11SlotInfo *sourceSlot,
    261                     CK_OBJECT_HANDLE id, void *targetPwArg, void *sourcePwArg)
    262 {
    263    SECKEYPrivateKey *sourceKey = NULL;
    264    CK_OBJECT_HANDLE targetKeyID;
    265    SECKEYEncryptedPrivateKeyInfo *epki = NULL;
    266    char *nickname = NULL;
    267    SECItem nickItem;
    268    SECItem pwitem;
    269    SECItem publicValue;
    270    PLArenaPool *arena = NULL;
    271    SECStatus rv = SECSuccess;
    272    unsigned int keyUsage;
    273    unsigned char randomData[SHA1_LENGTH];
    274    SECOidTag algTag = SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_3KEY_TRIPLE_DES_CBC;
    275    CK_ATTRIBUTE privTemplate[] = {
    276        { CKA_ID, NULL, 0 },
    277        { CKA_CLASS, NULL, 0 }
    278    };
    279    CK_ULONG privTemplateCount = sizeof(privTemplate) / sizeof(privTemplate[0]);
    280    CK_ATTRIBUTE privCopyTemplate[] = {
    281        { CKA_SUBJECT, NULL, 0 }
    282    };
    283    CK_ULONG privCopyTemplateCount =
    284        sizeof(privCopyTemplate) / sizeof(privCopyTemplate[0]);
    285 
    286    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
    287    if (arena == NULL) {
    288        rv = SECFailure;
    289        goto done;
    290    }
    291 
    292    /* check to see if the key is already in the target slot */
    293    rv = pk11_matchAcrossTokens(arena, targetSlot, sourceSlot, privTemplate,
    294                                privTemplateCount, id, &targetKeyID);
    295    if (rv != SECSuccess) {
    296        goto done;
    297    }
    298 
    299    if (targetKeyID != CK_INVALID_HANDLE) {
    300        /* match found,  not an error ... */
    301        goto done;
    302    }
    303 
    304    /* get an NSS representation of our source key */
    305    sourceKey = PK11_MakePrivKey(sourceSlot, nullKey, PR_FALSE,
    306                                 id, sourcePwArg);
    307    if (sourceKey == NULL) {
    308        rv = SECFailure;
    309        goto done;
    310    }
    311 
    312    /* Load the private key */
    313    /* generate a random pwitem */
    314    rv = PK11_GenerateRandom(randomData, sizeof(randomData));
    315    if (rv != SECSuccess) {
    316        goto done;
    317    }
    318    pwitem.data = randomData;
    319    pwitem.len = sizeof(randomData);
    320    /* fetch the private key encrypted */
    321    epki = PK11_ExportEncryptedPrivKeyInfo(sourceSlot, algTag, &pwitem,
    322                                           sourceKey, 1, sourcePwArg);
    323    if (epki == NULL) {
    324        rv = SECFailure;
    325        goto done;
    326    }
    327    nickname = PK11_GetObjectNickname(sourceSlot, id);
    328    /* NULL nickanme is fine (in fact is often normal) */
    329    if (nickname) {
    330        nickItem.data = (unsigned char *)nickname;
    331        nickItem.len = PORT_Strlen(nickname);
    332    }
    333    keyUsage = pk11_getPrivateKeyUsage(sourceSlot, id);
    334    /* pass in the CKA_ID */
    335    publicValue.data = privTemplate[0].pValue;
    336    publicValue.len = privTemplate[0].ulValueLen;
    337    rv = PK11_ImportEncryptedPrivateKeyInfo(targetSlot, epki, &pwitem,
    338                                            nickname ? &nickItem : NULL, &publicValue,
    339                                            PR_TRUE, PR_TRUE, sourceKey->keyType, keyUsage,
    340                                            targetPwArg);
    341    if (rv != SECSuccess) {
    342        goto done;
    343    }
    344 
    345    /* make sure it made it */
    346    rv = pk11_matchAcrossTokens(arena, targetSlot, sourceSlot, privTemplate,
    347                                privTemplateCount, id, &targetKeyID);
    348    if (rv != SECSuccess) {
    349        goto done;
    350    }
    351 
    352    if (targetKeyID == CK_INVALID_HANDLE) {
    353        /* this time the key should exist */
    354        rv = SECFailure;
    355        goto done;
    356    }
    357 
    358    /* fill in remaining attributes */
    359    rv = pk11_copyAttributes(arena, targetSlot, targetKeyID, sourceSlot, id,
    360                             privCopyTemplate, privCopyTemplateCount);
    361 done:
    362    /* make sure the 'key' is cleared */
    363    PORT_Memset(randomData, 0, sizeof(randomData));
    364    if (nickname) {
    365        PORT_Free(nickname);
    366    }
    367    if (sourceKey) {
    368        SECKEY_DestroyPrivateKey(sourceKey);
    369    }
    370    if (epki) {
    371        SECKEY_DestroyEncryptedPrivateKeyInfo(epki, PR_TRUE);
    372    }
    373    if (arena) {
    374        PORT_FreeArena(arena, PR_FALSE);
    375    }
    376    return rv;
    377 }
    378 
    379 /*************************************************************************
    380 *
    381 *            Secret Keys
    382 *
    383 *************************************************************************/
    384 
    385 /*
    386 * we need to find a unique CKA_ID.
    387 *  The basic idea is to just increment the lowest byte.
    388 *  This code also handles the following corner cases:
    389 *   1) the single byte overflows. On overflow we increment the next byte up
    390 *    and so forth until we have overflowed the entire CKA_ID.
    391 *   2) If we overflow the entire CKA_ID we expand it by one byte.
    392 *   3) the CKA_ID is non-existent, we create a new one with one byte.
    393 *    This means no matter what CKA_ID is passed, the result of this function
    394 *    is always a new CKA_ID, and this function will never return the same
    395 *    CKA_ID the it has returned in the passed.
    396 */
    397 static SECStatus
    398 pk11_incrementID(PLArenaPool *arena, CK_ATTRIBUTE *ptemplate)
    399 {
    400    unsigned char *buf = ptemplate->pValue;
    401    CK_ULONG len = ptemplate->ulValueLen;
    402 
    403    if (buf == NULL || len == (CK_ULONG)-1) {
    404        /* we have no valid CKAID, we'll create a basic one byte CKA_ID below */
    405        len = 0;
    406    } else {
    407        CK_ULONG i;
    408 
    409        /* walk from the back to front, incrementing
    410         * the CKA_ID until we no longer have a carry,
    411         * or have hit the front of the id. */
    412        for (i = len; i != 0; i--) {
    413            buf[i - 1]++;
    414            if (buf[i - 1] != 0) {
    415                /* no more carries, the increment is complete */
    416                return SECSuccess;
    417            }
    418        }
    419        /* we've now overflowed, fall through and expand the CKA_ID by
    420         * one byte */
    421    }
    422    /* if we are here we've run the counter to zero (indicating an overflow).
    423     * create an CKA_ID that is all zeros, but has one more zero than
    424     * the previous CKA_ID */
    425    buf = PORT_ArenaZAlloc(arena, len + 1);
    426    if (buf == NULL) {
    427        return SECFailure;
    428    }
    429    ptemplate->pValue = buf;
    430    ptemplate->ulValueLen = len + 1;
    431    return SECSuccess;
    432 }
    433 
    434 static CK_FLAGS
    435 pk11_getSecretKeyFlags(PK11SlotInfo *slot, CK_OBJECT_HANDLE id)
    436 {
    437    CK_FLAGS flags = 0;
    438 
    439    if (PK11_HasAttributeSet(slot, id, CKA_UNWRAP, PR_FALSE)) {
    440        flags |= CKF_UNWRAP;
    441    }
    442    if (PK11_HasAttributeSet(slot, id, CKA_WRAP, PR_FALSE)) {
    443        flags |= CKF_WRAP;
    444    }
    445    if (PK11_HasAttributeSet(slot, id, CKA_ENCRYPT, PR_FALSE)) {
    446        flags |= CKF_ENCRYPT;
    447    }
    448    if (PK11_HasAttributeSet(slot, id, CKA_DECRYPT, PR_FALSE)) {
    449        flags |= CKF_DECRYPT;
    450    }
    451    if (PK11_HasAttributeSet(slot, id, CKA_DERIVE, PR_FALSE)) {
    452        flags |= CKF_DERIVE;
    453    }
    454    if (PK11_HasAttributeSet(slot, id, CKA_SIGN, PR_FALSE)) {
    455        flags |= CKF_SIGN;
    456    }
    457    if (PK11_HasAttributeSet(slot, id, CKA_SIGN_RECOVER, PR_FALSE)) {
    458        flags |= CKF_SIGN_RECOVER;
    459    }
    460    if (PK11_HasAttributeSet(slot, id, CKA_VERIFY, PR_FALSE)) {
    461        flags |= CKF_VERIFY;
    462    }
    463    if (PK11_HasAttributeSet(slot, id, CKA_VERIFY_RECOVER, PR_FALSE)) {
    464        flags |= CKF_VERIFY_RECOVER;
    465    }
    466    return flags;
    467 }
    468 
    469 static const char testString[] =
    470    "My Encrytion Test Data (should be at least 32 bytes long)";
    471 /*
    472 * merge a secret key,
    473 *
    474 * Secret keys may collide by CKA_ID as we merge 2 token. If we collide
    475 * on the CKA_ID, we need to make sure we are dealing with different keys.
    476 * The reason for this is it is possible that we've merged this database
    477 * before, and this key could have been merged already.  If the keys are
    478 * the same, we are done. If they are not, we need to update the CKA_ID of
    479 * the source key and try again.
    480 *
    481 * Once we know we have a unique key to merge in, we use NSS's underlying
    482 * key Move function which will do a key exchange if necessary to move
    483 * the key from one token to another. Then we set the CKA_ID and additional
    484 * pkcs #11 attributes.
    485 */
    486 static SECStatus
    487 pk11_mergeSecretKey(PK11SlotInfo *targetSlot, PK11SlotInfo *sourceSlot,
    488                    CK_OBJECT_HANDLE id, void *targetPwArg, void *sourcePwArg)
    489 {
    490    PK11SymKey *sourceKey = NULL;
    491    PK11SymKey *targetKey = NULL;
    492    SECItem *sourceOutput = NULL;
    493    SECItem *targetOutput = NULL;
    494    SECItem *param = NULL;
    495    int blockSize;
    496    SECItem input;
    497    CK_OBJECT_HANDLE targetKeyID;
    498    CK_FLAGS flags;
    499    PLArenaPool *arena = NULL;
    500    SECStatus rv = SECSuccess;
    501    CK_MECHANISM_TYPE keyMechType, cryptoMechType;
    502    CK_KEY_TYPE sourceKeyType, targetKeyType;
    503    CK_ATTRIBUTE symTemplate[] = {
    504        { CKA_ID, NULL, 0 },
    505        { CKA_CLASS, NULL, 0 }
    506    };
    507    const CK_ULONG symTemplateCount = sizeof(symTemplate) / sizeof(symTemplate[0]);
    508    CK_ATTRIBUTE symCopyTemplate[] = {
    509        { CKA_LABEL, NULL, 0 }
    510    };
    511    CK_ULONG symCopyTemplateCount =
    512        sizeof(symCopyTemplate) / sizeof(symCopyTemplate[0]);
    513 
    514    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
    515    if (arena == NULL) {
    516        rv = SECFailure;
    517        goto done;
    518    }
    519 
    520    sourceKeyType = PK11_ReadULongAttribute(sourceSlot, id, CKA_KEY_TYPE);
    521    if (sourceKeyType == (CK_ULONG)-1) {
    522        rv = SECFailure;
    523        goto done;
    524    }
    525 
    526    /* get the key mechanism */
    527    keyMechType = PK11_GetKeyMechanism(sourceKeyType);
    528    /* get a mechanism suitable to encryption.
    529     * PK11_GetKeyMechanism returns a mechanism that is unique to the key
    530     * type. It tries to return encryption/decryption mechanisms, however
    531     * CKM_DES3_CBC uses and abmiguous keyType, so keyMechType is returned as
    532     * 'keygen' mechanism. Detect that case here */
    533    cryptoMechType = keyMechType;
    534    if ((keyMechType == CKM_DES3_KEY_GEN) ||
    535        (keyMechType == CKM_DES2_KEY_GEN)) {
    536        cryptoMechType = CKM_DES3_CBC;
    537    }
    538 
    539    sourceKey = PK11_SymKeyFromHandle(sourceSlot, NULL, PK11_OriginDerive,
    540                                      keyMechType, id, PR_FALSE, sourcePwArg);
    541    if (sourceKey == NULL) {
    542        rv = SECFailure;
    543        goto done;
    544    }
    545 
    546    /* check to see a key with the same CKA_ID  already exists in
    547     * the target slot. If it does, then we need to verify if the keys
    548     * really matches. If they don't import the key with a new CKA_ID
    549     * value. */
    550    rv = pk11_matchAcrossTokens(arena, targetSlot, sourceSlot,
    551                                symTemplate, symTemplateCount, id, &targetKeyID);
    552    if (rv != SECSuccess) {
    553        goto done;
    554    }
    555 
    556    /* set up the input test */
    557    input.data = (unsigned char *)testString;
    558    blockSize = PK11_GetBlockSize(cryptoMechType, NULL);
    559    if (blockSize < 0) {
    560        rv = SECFailure;
    561        goto done;
    562    }
    563    input.len = blockSize;
    564    if (input.len == 0) {
    565        input.len = sizeof(testString);
    566    }
    567    while (targetKeyID != CK_INVALID_HANDLE) {
    568        /* test to see if the keys are identical */
    569        targetKeyType = PK11_ReadULongAttribute(sourceSlot, id, CKA_KEY_TYPE);
    570        if (targetKeyType == sourceKeyType) {
    571            /* same keyType  - see if it's the same key */
    572            targetKey = PK11_SymKeyFromHandle(targetSlot, NULL,
    573                                              PK11_OriginDerive, keyMechType, targetKeyID, PR_FALSE,
    574                                              targetPwArg);
    575            /* get a parameter if we don't already have one */
    576            if (!param) {
    577                param = PK11_GenerateNewParam(cryptoMechType, sourceKey);
    578                if (param == NULL) {
    579                    rv = SECFailure;
    580                    goto done;
    581                }
    582            }
    583            /* use the source key to encrypt a reference */
    584            if (!sourceOutput) {
    585                rv = pk11_encrypt(sourceKey, cryptoMechType, param, &input,
    586                                  &sourceOutput);
    587                if (rv != SECSuccess) {
    588                    goto done;
    589                }
    590            }
    591            /* encrypt the reference with the target key */
    592            rv = pk11_encrypt(targetKey, cryptoMechType, param, &input,
    593                              &targetOutput);
    594            if (rv == SECSuccess) {
    595                if (SECITEM_ItemsAreEqual(sourceOutput, targetOutput)) {
    596                    /* they produce the same output, they must be the
    597                     * same key */
    598                    goto done;
    599                }
    600                SECITEM_FreeItem(targetOutput, PR_TRUE);
    601                targetOutput = NULL;
    602            }
    603            PK11_FreeSymKey(targetKey);
    604            targetKey = NULL;
    605        }
    606        /* keys aren't equal, update the KEY_ID and look again */
    607        rv = pk11_incrementID(arena, &symTemplate[0]);
    608        if (rv != SECSuccess) {
    609            goto done;
    610        }
    611        targetKeyID = pk11_FindObjectByTemplate(targetSlot,
    612                                                symTemplate, symTemplateCount);
    613    }
    614 
    615    /* we didn't find a matching key, import this one with the new
    616     * CKAID */
    617    flags = pk11_getSecretKeyFlags(sourceSlot, id);
    618    targetKey = PK11_MoveSymKey(targetSlot, PK11_OriginDerive, flags, PR_TRUE,
    619                                sourceKey);
    620    if (targetKey == NULL) {
    621        rv = SECFailure;
    622        goto done;
    623    }
    624    /* set the key new CKAID */
    625    rv = pk11_setAttributes(targetSlot, targetKey->objectID, symTemplate, 1);
    626    if (rv != SECSuccess) {
    627        goto done;
    628    }
    629 
    630    /* fill in remaining attributes */
    631    rv = pk11_copyAttributes(arena, targetSlot, targetKey->objectID,
    632                             sourceSlot, id, symCopyTemplate, symCopyTemplateCount);
    633 done:
    634    if (sourceKey) {
    635        PK11_FreeSymKey(sourceKey);
    636    }
    637    if (targetKey) {
    638        PK11_FreeSymKey(targetKey);
    639    }
    640    if (sourceOutput) {
    641        SECITEM_FreeItem(sourceOutput, PR_TRUE);
    642    }
    643    if (targetOutput) {
    644        SECITEM_FreeItem(targetOutput, PR_TRUE);
    645    }
    646    if (param) {
    647        SECITEM_FreeItem(param, PR_TRUE);
    648    }
    649    if (arena) {
    650        PORT_FreeArena(arena, PR_FALSE);
    651    }
    652    return rv;
    653 }
    654 
    655 /*************************************************************************
    656 *
    657 *            Public Keys
    658 *
    659 *************************************************************************/
    660 
    661 /*
    662 * Merge public key
    663 *
    664 * Use the high level NSS calls to extract the public key and import it
    665 * into the token. Extra attributes are then copied to the new token.
    666 */
    667 static SECStatus
    668 pk11_mergePublicKey(PK11SlotInfo *targetSlot, PK11SlotInfo *sourceSlot,
    669                    CK_OBJECT_HANDLE id, void *targetPwArg, void *sourcePwArg)
    670 {
    671    SECKEYPublicKey *sourceKey = NULL;
    672    CK_OBJECT_HANDLE targetKeyID;
    673    PLArenaPool *arena = NULL;
    674    SECStatus rv = SECSuccess;
    675    CK_ATTRIBUTE pubTemplate[] = {
    676        { CKA_ID, NULL, 0 },
    677        { CKA_CLASS, NULL, 0 }
    678    };
    679    CK_ULONG pubTemplateCount = sizeof(pubTemplate) / sizeof(pubTemplate[0]);
    680    CK_ATTRIBUTE pubCopyTemplate[] = {
    681        { CKA_ID, NULL, 0 },
    682        { CKA_LABEL, NULL, 0 },
    683        { CKA_SUBJECT, NULL, 0 }
    684    };
    685    CK_ULONG pubCopyTemplateCount =
    686        sizeof(pubCopyTemplate) / sizeof(pubCopyTemplate[0]);
    687 
    688    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
    689    if (arena == NULL) {
    690        rv = SECFailure;
    691        goto done;
    692    }
    693 
    694    /* check to see if the key is already in the target slot */
    695    rv = pk11_matchAcrossTokens(arena, targetSlot, sourceSlot, pubTemplate,
    696                                pubTemplateCount, id, &targetKeyID);
    697    if (rv != SECSuccess) {
    698        goto done;
    699    }
    700 
    701    /* Key is already in the target slot */
    702    if (targetKeyID != CK_INVALID_HANDLE) {
    703        /* not an error ... */
    704        goto done;
    705    }
    706 
    707    /* fetch an NSS representation of the public key */
    708    sourceKey = PK11_ExtractPublicKey(sourceSlot, nullKey, id);
    709    if (sourceKey == NULL) {
    710        rv = SECFailure;
    711        goto done;
    712    }
    713 
    714    /* load the public key into the target token. */
    715    targetKeyID = PK11_ImportPublicKey(targetSlot, sourceKey, PR_TRUE);
    716    if (targetKeyID == CK_INVALID_HANDLE) {
    717        rv = SECFailure;
    718        goto done;
    719    }
    720 
    721    /* fill in remaining attributes */
    722    rv = pk11_copyAttributes(arena, targetSlot, targetKeyID, sourceSlot, id,
    723                             pubCopyTemplate, pubCopyTemplateCount);
    724 
    725 done:
    726    if (sourceKey) {
    727        SECKEY_DestroyPublicKey(sourceKey);
    728    }
    729    if (arena) {
    730        PORT_FreeArena(arena, PR_FALSE);
    731    }
    732    return rv;
    733 }
    734 
    735 /*************************************************************************
    736 *
    737 *            Certificates
    738 *
    739 *************************************************************************/
    740 
    741 /*
    742 * Two copies of the source code for this algorithm exist in NSS.
    743 * Changes must be made in both copies.
    744 * The other copy is in sftkdb_resolveConflicts() in softoken/sftkdb.c.
    745 */
    746 static char *
    747 pk11_IncrementNickname(char *nickname)
    748 {
    749    char *newNickname = NULL;
    750    int end;
    751    int digit;
    752    int len = strlen(nickname);
    753 
    754    /* does nickname end with " #n*" ? */
    755    for (end = len - 1;
    756         end >= 2 && (digit = nickname[end]) <= '9' && digit >= '0';
    757         end--) /* just scan */
    758        ;
    759    if (len >= 3 &&
    760        end < (len - 1) /* at least one digit */ &&
    761        nickname[end] == '#' &&
    762        nickname[end - 1] == ' ') {
    763        /* Already has a suitable suffix string */
    764    } else {
    765        /* ... append " #2" to the name */
    766        static const char num2[] = " #2";
    767        newNickname = PORT_Realloc(nickname, len + sizeof(num2));
    768        if (newNickname) {
    769            PORT_Strcat(newNickname, num2);
    770        } else {
    771            PORT_Free(nickname);
    772        }
    773        return newNickname;
    774    }
    775 
    776    for (end = len - 1;
    777         end >= 0 && (digit = nickname[end]) <= '9' && digit >= '0';
    778         end--) {
    779        if (digit < '9') {
    780            nickname[end]++;
    781            return nickname;
    782        }
    783        nickname[end] = '0';
    784    }
    785 
    786    /* we overflowed, insert a new '1' for a carry in front of the number */
    787    newNickname = PORT_Realloc(nickname, len + 2);
    788    if (newNickname) {
    789        newNickname[++end] = '1';
    790        PORT_Memset(&newNickname[end + 1], '0', len - end);
    791        newNickname[len + 1] = 0;
    792    } else {
    793        PORT_Free(nickname);
    794    }
    795    return newNickname;
    796 }
    797 
    798 /*
    799 * merge a certificate object
    800 *
    801 * Use the high level NSS calls to extract and import the certificate.
    802 */
    803 static SECStatus
    804 pk11_mergeCert(PK11SlotInfo *targetSlot, PK11SlotInfo *sourceSlot,
    805               CK_OBJECT_HANDLE id, void *targetPwArg, void *sourcePwArg)
    806 {
    807    CERTCertificate *sourceCert = NULL;
    808    CK_OBJECT_HANDLE targetCertID = CK_INVALID_HANDLE;
    809    char *nickname = NULL;
    810    SECStatus rv = SECSuccess;
    811    PLArenaPool *arena = NULL;
    812    CK_ATTRIBUTE sourceCKAID = { CKA_ID, NULL, 0 };
    813    CK_ATTRIBUTE targetCKAID = { CKA_ID, NULL, 0 };
    814    SECStatus lrv = SECSuccess;
    815    int error = SEC_ERROR_LIBRARY_FAILURE;
    816 
    817    sourceCert = PK11_MakeCertFromHandle(sourceSlot, id, NULL);
    818    if (sourceCert == NULL) {
    819        rv = SECFailure;
    820        goto done;
    821    }
    822 
    823    nickname = PK11_GetObjectNickname(sourceSlot, id);
    824 
    825    /* The database code will prevent nickname collisions for certs with
    826     * different subjects. This code will prevent us from getting
    827     * actual import errors */
    828    if (nickname) {
    829        const char *tokenName = PK11_GetTokenName(targetSlot);
    830        char *tokenNickname = NULL;
    831 
    832        do {
    833            tokenNickname = PR_smprintf("%s:%s", tokenName, nickname);
    834            if (!tokenNickname) {
    835                break;
    836            }
    837            if (!SEC_CertNicknameConflict(tokenNickname,
    838                                          &sourceCert->derSubject, CERT_GetDefaultCertDB())) {
    839                break;
    840            }
    841            nickname = pk11_IncrementNickname(nickname);
    842            if (!nickname) {
    843                break;
    844            }
    845            PR_smprintf_free(tokenNickname);
    846        } while (1);
    847        if (tokenNickname) {
    848            PR_smprintf_free(tokenNickname);
    849        }
    850    }
    851 
    852    /* see if the cert is already there */
    853    targetCertID = PK11_FindCertInSlot(targetSlot, sourceCert, targetPwArg);
    854    if (targetCertID == CK_INVALID_HANDLE) {
    855        /* cert doesn't exist load the cert in. */
    856        /* OK for the nickname to be NULL, not all certs have nicknames */
    857        rv = PK11_ImportCert(targetSlot, sourceCert, CK_INVALID_HANDLE,
    858                             nickname, PR_FALSE);
    859        goto done;
    860    }
    861 
    862    /* the cert already exists, see if the nickname and/or  CKA_ID need
    863     * to be updated */
    864 
    865    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
    866    if (arena == NULL) {
    867        rv = SECFailure;
    868        goto done;
    869    }
    870 
    871    /* does our source have a CKA_ID ? */
    872    rv = PK11_GetAttributes(arena, sourceSlot, id, &sourceCKAID, 1);
    873    if (rv != SECSuccess) {
    874        sourceCKAID.ulValueLen = 0;
    875    }
    876 
    877    /* if we have a source CKA_ID, see of we need to update the
    878     * target's CKA_ID */
    879    if (sourceCKAID.ulValueLen != 0) {
    880        rv = PK11_GetAttributes(arena, targetSlot, targetCertID,
    881                                &targetCKAID, 1);
    882        if (rv != SECSuccess) {
    883            targetCKAID.ulValueLen = 0;
    884        }
    885        /* if the target has no CKA_ID, update it from the source */
    886        if (targetCKAID.ulValueLen == 0) {
    887            lrv = pk11_setAttributes(targetSlot, targetCertID, &sourceCKAID, 1);
    888            if (lrv != SECSuccess) {
    889                error = PORT_GetError();
    890            }
    891        }
    892    }
    893    rv = SECSuccess;
    894 
    895    /* now check if we need to update the nickname */
    896    if (nickname && *nickname) {
    897        char *targetname;
    898        targetname = PK11_GetObjectNickname(targetSlot, targetCertID);
    899        if (!targetname || !*targetname) {
    900            /* target has no nickname, or it's empty, update it */
    901            rv = PK11_SetObjectNickname(targetSlot, targetCertID, nickname);
    902        }
    903        if (targetname) {
    904            PORT_Free(targetname);
    905        }
    906    }
    907 
    908    /* restore the error code if CKA_ID failed, but nickname didn't */
    909    if ((rv == SECSuccess) && (lrv != SECSuccess)) {
    910        rv = lrv;
    911        PORT_SetError(error);
    912    }
    913 
    914 done:
    915    if (nickname) {
    916        PORT_Free(nickname);
    917    }
    918    if (sourceCert) {
    919        CERT_DestroyCertificate(sourceCert);
    920    }
    921    if (arena) {
    922        PORT_FreeArena(arena, PR_FALSE);
    923    }
    924    return rv;
    925 }
    926 
    927 /*************************************************************************
    928 *
    929 *            Crls
    930 *
    931 *************************************************************************/
    932 
    933 /*
    934 * Use the raw PKCS #11 interface to merge the CRLs.
    935 *
    936 * In the case where of collision, choose the newest CRL that is valid.
    937 */
    938 static SECStatus
    939 pk11_mergeCrl(PK11SlotInfo *targetSlot, PK11SlotInfo *sourceSlot,
    940              CK_OBJECT_HANDLE id, void *targetPwArg, void *sourcePwArg)
    941 {
    942    CK_OBJECT_HANDLE targetCrlID;
    943    PLArenaPool *arena = NULL;
    944    SECStatus rv = SECSuccess;
    945    CK_ATTRIBUTE crlTemplate[] = {
    946        { CKA_SUBJECT, NULL, 0 },
    947        { CKA_CLASS, NULL, 0 },
    948        { CKA_NSS_KRL, NULL, 0 }
    949    };
    950    CK_ULONG crlTemplateCount = sizeof(crlTemplate) / sizeof(crlTemplate[0]);
    951    CK_ATTRIBUTE crlCopyTemplate[] = {
    952        { CKA_CLASS, NULL, 0 },
    953        { CKA_TOKEN, NULL, 0 },
    954        { CKA_LABEL, NULL, 0 },
    955        { CKA_PRIVATE, NULL, 0 },
    956        { CKA_MODIFIABLE, NULL, 0 },
    957        { CKA_SUBJECT, NULL, 0 },
    958        { CKA_NSS_KRL, NULL, 0 },
    959        { CKA_NSS_URL, NULL, 0 },
    960        { CKA_VALUE, NULL, 0 }
    961    };
    962    CK_ULONG crlCopyTemplateCount =
    963        sizeof(crlCopyTemplate) / sizeof(crlCopyTemplate[0]);
    964 
    965    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
    966    if (arena == NULL) {
    967        rv = SECFailure;
    968        goto done;
    969    }
    970    /* check to see if the crl is already in the target slot */
    971    rv = pk11_matchAcrossTokens(arena, targetSlot, sourceSlot, crlTemplate,
    972                                crlTemplateCount, id, &targetCrlID);
    973    if (rv != SECSuccess) {
    974        goto done;
    975    }
    976    if (targetCrlID != CK_INVALID_HANDLE) {
    977        /* we already have a CRL, check to see which is more up-to-date. */
    978        goto done;
    979    }
    980 
    981    /* load the CRL into the target token. */
    982    rv = pk11_copyAttributes(arena, targetSlot, targetCrlID, sourceSlot, id,
    983                             crlCopyTemplate, crlCopyTemplateCount);
    984 done:
    985    if (arena) {
    986        PORT_FreeArena(arena, PR_FALSE);
    987    }
    988    return rv;
    989 }
    990 
    991 /*************************************************************************
    992 *
    993 *            SMIME objects
    994 *
    995 *************************************************************************/
    996 
    997 /*
    998 * use the raw PKCS #11 interface to merge the S/MIME records
    999 */
   1000 static SECStatus
   1001 pk11_mergeSmime(PK11SlotInfo *targetSlot, PK11SlotInfo *sourceSlot,
   1002                CK_OBJECT_HANDLE id, void *targetPwArg, void *sourcePwArg)
   1003 {
   1004    CK_OBJECT_HANDLE targetSmimeID;
   1005    PLArenaPool *arena = NULL;
   1006    SECStatus rv = SECSuccess;
   1007    CK_ATTRIBUTE smimeTemplate[] = {
   1008        { CKA_SUBJECT, NULL, 0 },
   1009        { CKA_NSS_EMAIL, NULL, 0 },
   1010        { CKA_CLASS, NULL, 0 },
   1011    };
   1012    CK_ULONG smimeTemplateCount =
   1013        sizeof(smimeTemplate) / sizeof(smimeTemplate[0]);
   1014    CK_ATTRIBUTE smimeCopyTemplate[] = {
   1015        { CKA_CLASS, NULL, 0 },
   1016        { CKA_TOKEN, NULL, 0 },
   1017        { CKA_LABEL, NULL, 0 },
   1018        { CKA_PRIVATE, NULL, 0 },
   1019        { CKA_MODIFIABLE, NULL, 0 },
   1020        { CKA_SUBJECT, NULL, 0 },
   1021        { CKA_NSS_EMAIL, NULL, 0 },
   1022        { CKA_NSS_SMIME_TIMESTAMP, NULL, 0 },
   1023        { CKA_VALUE, NULL, 0 }
   1024    };
   1025    CK_ULONG smimeCopyTemplateCount =
   1026        sizeof(smimeCopyTemplate) / sizeof(smimeCopyTemplate[0]);
   1027 
   1028    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
   1029    if (arena == NULL) {
   1030        rv = SECFailure;
   1031        goto done;
   1032    }
   1033    /* check to see if the crl is already in the target slot */
   1034    rv = pk11_matchAcrossTokens(arena, targetSlot, sourceSlot, smimeTemplate,
   1035                                smimeTemplateCount, id, &targetSmimeID);
   1036    if (rv != SECSuccess) {
   1037        goto done;
   1038    }
   1039    if (targetSmimeID != CK_INVALID_HANDLE) {
   1040        /* we already have a SMIME record */
   1041        goto done;
   1042    }
   1043 
   1044    /* load the SMime Record into the target token. */
   1045    rv = pk11_copyAttributes(arena, targetSlot, targetSmimeID, sourceSlot, id,
   1046                             smimeCopyTemplate, smimeCopyTemplateCount);
   1047 done:
   1048    if (arena) {
   1049        PORT_FreeArena(arena, PR_FALSE);
   1050    }
   1051    return rv;
   1052 }
   1053 
   1054 /*************************************************************************
   1055 *
   1056 *            Trust Objects
   1057 *
   1058 *************************************************************************/
   1059 
   1060 /*
   1061 * decide which trust record entry wins. PR_TRUE (source) or PR_FALSE (target)
   1062 */
   1063 #define USE_TARGET PR_FALSE
   1064 #define USE_SOURCE PR_TRUE
   1065 PRBool
   1066 pk11_mergeTrustEntry(CK_ATTRIBUTE *target, CK_ATTRIBUTE *source)
   1067 {
   1068    CK_TRUST targetTrust = (target->ulValueLen == sizeof(CK_TRUST)) ? *(CK_TRUST *)target->pValue : CKT_TRUST_UNKNOWN;
   1069    CK_TRUST sourceTrust = (source->ulValueLen == sizeof(CK_TRUST)) ? *(CK_TRUST *)source->pValue : CKT_TRUST_UNKNOWN;
   1070 
   1071    /*
   1072     * Examine a single entry and deside if the source or target version
   1073     * should win out. When all the entries have been checked, if there is
   1074     * any case we need to update, we will write the whole source record
   1075     * to the target database. That means for each individual record.
   1076     */
   1077    /* if they are identical, short cut the rest of the tests. NOTE:
   1078     * if sourceTrust and targetTrust are different types, but 'identical'
   1079     * then we will continue down these lists, but always select the
   1080     * target anyway because we check the weak source versions first */
   1081    if (sourceTrust == targetTrust) {
   1082        return USE_TARGET; /* which equates to 'do nothing' */
   1083    }
   1084 
   1085    /* source has no idea, use the target's idea of the trust value */
   1086    if ((sourceTrust == CKT_TRUST_UNKNOWN) || (sourceTrust == CKT_NSS_TRUST_UNKNOWN)) {
   1087        return USE_TARGET;
   1088    }
   1089 
   1090    /* target has no idea, use the source's idea of the trust value */
   1091    if ((targetTrust == CKT_TRUST_UNKNOWN) || (targetTrust == CKT_NSS_TRUST_UNKNOWN)) {
   1092        /* source overwrites the target */
   1093        return USE_SOURCE;
   1094    }
   1095 
   1096    /* so both the target and the source have some idea of what this
   1097     * trust attribute should be, and neither agree exactly.
   1098     * At this point, we prefer 'hard' attributes over 'soft' ones.
   1099     * 'hard' ones are CKT_TRUSTED, CKT_TRUST_ANCHOR, CKT_UNTRUTED and
   1100     * their CKT_NSS equivalents. Soft ones are ones which don't change the
   1101     * actual trust of the cert (CKT_TRUST_MUST_VERIFY_TRUST,
   1102     * CKT_NSS_MUST_VERIFY_TRUST, and CKT_NSS_VALID_DELEGATOR).
   1103     */
   1104    if ((sourceTrust == CKT_TRUST_MUST_VERIFY_TRUST) ||
   1105        (sourceTrust == CKT_NSS_MUST_VERIFY_TRUST) ||
   1106        (sourceTrust == CKT_NSS_VALID_DELEGATOR)) {
   1107 
   1108        return USE_TARGET;
   1109    }
   1110    if ((targetTrust == CKT_TRUST_MUST_VERIFY_TRUST) ||
   1111        (targetTrust == CKT_NSS_MUST_VERIFY_TRUST) ||
   1112        (targetTrust == CKT_NSS_VALID_DELEGATOR)) {
   1113        /* source overrites the target */
   1114        return USE_SOURCE;
   1115    }
   1116 
   1117    /* both have hard attributes, we have a conflict, let the target win. */
   1118    return USE_TARGET;
   1119 }
   1120 
   1121 /*
   1122 * map the template trust value to the target class value.
   1123 */
   1124 void
   1125 pk11_map_trust_entry(CK_OBJECT_CLASS targetClass, CK_ATTRIBUTE *template)
   1126 {
   1127    CK_TRUST trust;
   1128    CK_TRUST newTrust;
   1129 
   1130    if (template->ulValueLen != sizeof(CK_TRUST)) {
   1131        return;
   1132    }
   1133    trust = *(CK_TRUST *)template->pValue;
   1134    newTrust = (targetClass == CKO_TRUST) ? CKT_TRUST_UNKNOWN
   1135                                          : CKT_NSS_TRUST_UNKNOWN;
   1136 
   1137    switch (trust) {
   1138        case CKT_NSS_TRUSTED:
   1139        case CKT_TRUSTED:
   1140            newTrust = (targetClass == CKO_TRUST) ? CKT_TRUSTED
   1141                                                  : CKT_NSS_TRUSTED;
   1142            break;
   1143        case CKT_NSS_TRUSTED_DELEGATOR:
   1144        case CKT_TRUST_ANCHOR:
   1145            newTrust = (targetClass == CKO_TRUST) ? CKT_TRUST_ANCHOR
   1146                                                  : CKT_NSS_TRUSTED_DELEGATOR;
   1147            break;
   1148        case CKT_NSS_VALID_DELEGATOR:
   1149            newTrust = (targetClass == CKO_TRUST) ? CKT_TRUST_MUST_VERIFY_TRUST
   1150                                                  : CKT_NSS_VALID_DELEGATOR;
   1151            break;
   1152        case CKT_NSS_MUST_VERIFY_TRUST:
   1153        case CKT_TRUST_MUST_VERIFY_TRUST:
   1154            newTrust = (targetClass == CKO_TRUST) ? CKT_TRUST_MUST_VERIFY_TRUST
   1155                                                  : CKT_NSS_MUST_VERIFY_TRUST;
   1156            break;
   1157        case CKT_NSS_NOT_TRUSTED:
   1158        case CKT_NOT_TRUSTED:
   1159            newTrust = (targetClass == CKO_TRUST) ? CKT_NOT_TRUSTED
   1160                                                  : CKT_NSS_NOT_TRUSTED;
   1161            break;
   1162        default: /* everything else is trust unknown, which we've already set */
   1163            break;
   1164    }
   1165    PORT_Memcpy(template->pValue, &newTrust, sizeof(newTrust));
   1166    return;
   1167 }
   1168 
   1169 /*
   1170 * use the raw PKCS #11 interface to merge the S/MIME records
   1171 */
   1172 static SECStatus
   1173 pk11_mergeTrust(PK11SlotInfo *targetSlot, PK11SlotInfo *sourceSlot,
   1174                CK_OBJECT_HANDLE id, CK_OBJECT_CLASS sourceClass,
   1175                void *targetPwArg, void *sourcePwArg)
   1176 {
   1177    CK_OBJECT_HANDLE targetTrustID;
   1178    PLArenaPool *arena = NULL;
   1179    SECStatus rv = SECSuccess;
   1180    int error = 0;
   1181    CK_ATTRIBUTE trustTemplate[] = {
   1182        { CKA_ISSUER, NULL, 0 },
   1183        { CKA_SERIAL_NUMBER, NULL, 0 },
   1184        { CKA_CLASS, NULL, 0 },
   1185    };
   1186    CK_ULONG trustTemplateCount =
   1187        sizeof(trustTemplate) / sizeof(trustTemplate[0]);
   1188    CK_ATTRIBUTE *trustCopyTemplate = NULL;
   1189    CK_ULONG trustCopyTemplateCount = 0;
   1190    CK_ATTRIBUTE nssTrustCopyTemplate[] = {
   1191        { CKA_CLASS, NULL, 0 },
   1192        { CKA_TOKEN, NULL, 0 },
   1193        { CKA_LABEL, NULL, 0 },
   1194        { CKA_PRIVATE, NULL, 0 },
   1195        { CKA_MODIFIABLE, NULL, 0 },
   1196        { CKA_ISSUER, NULL, 0 },
   1197        { CKA_SERIAL_NUMBER, NULL, 0 },
   1198        { CKA_NSS_CERT_SHA1_HASH, NULL, 0 },
   1199        { CKA_NSS_CERT_MD5_HASH, NULL, 0 },
   1200        { CKA_NSS_TRUST_SERVER_AUTH, NULL, 0 },
   1201        { CKA_NSS_TRUST_CLIENT_AUTH, NULL, 0 },
   1202        { CKA_NSS_TRUST_CODE_SIGNING, NULL, 0 },
   1203        { CKA_NSS_TRUST_EMAIL_PROTECTION, NULL, 0 },
   1204        { CKA_NSS_TRUST_STEP_UP_APPROVED, NULL, 0 }
   1205    };
   1206    CK_ULONG nssTrustCopyTemplateCount = PR_ARRAY_SIZE(nssTrustCopyTemplate);
   1207    CK_ATTRIBUTE pkcsTrustCopyTemplate[] = {
   1208        { CKA_CLASS, NULL, 0 },
   1209        { CKA_TOKEN, NULL, 0 },
   1210        { CKA_LABEL, NULL, 0 },
   1211        { CKA_PRIVATE, NULL, 0 },
   1212        { CKA_MODIFIABLE, NULL, 0 },
   1213        { CKA_ISSUER, NULL, 0 },
   1214        { CKA_SERIAL_NUMBER, NULL, 0 },
   1215        { CKA_HASH_OF_CERTIFICATE, NULL, 0 },
   1216        { CKA_NAME_HASH_ALGORITHM, NULL, 0 },
   1217        { CKA_PKCS_TRUST_SERVER_AUTH, NULL, 0 },
   1218        { CKA_PKCS_TRUST_CLIENT_AUTH, NULL, 0 },
   1219        { CKA_PKCS_TRUST_CODE_SIGNING, NULL, 0 },
   1220        { CKA_PKCS_TRUST_EMAIL_PROTECTION, NULL, 0 },
   1221    };
   1222    CK_ULONG pkcsTrustCopyTemplateCount = PR_ARRAY_SIZE(pkcsTrustCopyTemplate);
   1223    CK_OBJECT_CLASS targetClass;
   1224 
   1225    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
   1226    if (arena == NULL) {
   1227        rv = SECFailure;
   1228        goto done;
   1229    }
   1230    /* check to see if the trust object is already in the target slot */
   1231    rv = pk11_matchAcrossTokens(arena, targetSlot, sourceSlot, trustTemplate,
   1232                                trustTemplateCount, id, &targetTrustID);
   1233    if (rv != SECSuccess) {
   1234        goto done;
   1235    }
   1236    targetClass = pk11_getClassFromTemplate(trustTemplate, trustTemplateCount);
   1237    if (targetTrustID != CK_INVALID_HANDLE) {
   1238        /* a matching trust record already exists, merge it in */
   1239        CK_ATTRIBUTE_TYPE nssTrustAttrs[] = {
   1240            CKA_NSS_TRUST_SERVER_AUTH, CKA_NSS_TRUST_CLIENT_AUTH,
   1241            CKA_NSS_TRUST_CODE_SIGNING, CKA_NSS_TRUST_EMAIL_PROTECTION,
   1242            CKA_NSS_TRUST_IPSEC_TUNNEL, CKA_NSS_TRUST_TIME_STAMPING
   1243        };
   1244        CK_ATTRIBUTE_TYPE pkcsTrustAttrs[] = {
   1245            CKA_PKCS_TRUST_SERVER_AUTH, CKA_PKCS_TRUST_CLIENT_AUTH,
   1246            CKA_PKCS_TRUST_CODE_SIGNING, CKA_PKCS_TRUST_EMAIL_PROTECTION,
   1247            CKA_TRUST_IPSEC_IKE, CKA_PKCS_TRUST_TIME_STAMPING
   1248        };
   1249        CK_ULONG trustAttrsCount = PR_ARRAY_SIZE(pkcsTrustAttrs);
   1250 
   1251        CK_ULONG i;
   1252        CK_ATTRIBUTE targetTemplate, sourceTemplate;
   1253 
   1254        PORT_Assert(trustAttrsCount == PR_ARRAY_SIZE(nssTrustAttrs));
   1255 
   1256        /* existing trust record, merge the two together */
   1257        for (i = 0; i < trustAttrsCount; i++) {
   1258            targetTemplate.type = (targetClass == CKO_TRUST)
   1259                                      ? nssTrustAttrs[i]
   1260                                      : pkcsTrustAttrs[i];
   1261            sourceTemplate.type = (sourceClass == CKO_TRUST)
   1262                                      ? nssTrustAttrs[i]
   1263                                      : pkcsTrustAttrs[i];
   1264 
   1265            targetTemplate.pValue = sourceTemplate.pValue = NULL;
   1266            targetTemplate.ulValueLen = sourceTemplate.ulValueLen = 0;
   1267            PK11_GetAttributes(arena, sourceSlot, id, &sourceTemplate, 1);
   1268            PK11_GetAttributes(arena, targetSlot, targetTrustID,
   1269                               &targetTemplate, 1);
   1270            if (pk11_mergeTrustEntry(&targetTemplate, &sourceTemplate)) {
   1271                /* source wins, write out the source attribute to the target */
   1272                SECStatus lrv;
   1273 
   1274                /* store the trust value in the target's object format */
   1275                if (sourceClass != targetClass) {
   1276                    pk11_map_trust_entry(targetClass, &sourceTemplate);
   1277                }
   1278 
   1279                lrv = pk11_setAttributes(targetSlot, targetTrustID,
   1280                                         &sourceTemplate, 1);
   1281                if (lrv != SECSuccess) {
   1282                    rv = SECFailure;
   1283                    error = PORT_GetError();
   1284                }
   1285            }
   1286        }
   1287 
   1288        /* Only handle step up if both source and target are NSS Trust
   1289         * objects */
   1290        if ((sourceClass == CKO_NSS_TRUST) && (targetClass == CKO_NSS_TRUST)) {
   1291            /* handle step */
   1292            sourceTemplate.type = CKA_NSS_TRUST_STEP_UP_APPROVED;
   1293            sourceTemplate.pValue = NULL;
   1294            sourceTemplate.ulValueLen = 0;
   1295 
   1296            /* if the source has steup set, then set it in the target */
   1297            PK11_GetAttributes(arena, sourceSlot, id, &sourceTemplate, 1);
   1298            if ((sourceTemplate.ulValueLen == sizeof(CK_BBOOL)) &&
   1299                (sourceTemplate.pValue) &&
   1300                (*(CK_BBOOL *)sourceTemplate.pValue == CK_TRUE)) {
   1301                SECStatus lrv = pk11_setAttributes(targetSlot, targetTrustID,
   1302                                                   &sourceTemplate, 1);
   1303                if (lrv != SECSuccess) {
   1304                    rv = SECFailure;
   1305                    error = PORT_GetError();
   1306                }
   1307            }
   1308        }
   1309 
   1310        goto done;
   1311    }
   1312 
   1313    /* load the new trust Record into the target token. */
   1314    trustCopyTemplate = (sourceClass == CKO_TRUST) ? pkcsTrustCopyTemplate
   1315                                                   : nssTrustCopyTemplate;
   1316    trustCopyTemplateCount = (sourceClass == CKO_TRUST)
   1317                                 ? pkcsTrustCopyTemplateCount
   1318                                 : nssTrustCopyTemplateCount;
   1319    rv = pk11_copyAttributes(arena, targetSlot, targetTrustID, sourceSlot, id,
   1320                             trustCopyTemplate, trustCopyTemplateCount);
   1321 done:
   1322    if (arena) {
   1323        PORT_FreeArena(arena, PR_FALSE);
   1324    }
   1325 
   1326    /* restore the error code */
   1327    if (rv == SECFailure && error) {
   1328        PORT_SetError(error);
   1329    }
   1330 
   1331    return rv;
   1332 }
   1333 
   1334 /*************************************************************************
   1335 *
   1336 *            Central merge code
   1337 *
   1338 *************************************************************************/
   1339 /*
   1340 * merge a single object from sourceToken to targetToken
   1341 */
   1342 static SECStatus
   1343 pk11_mergeObject(PK11SlotInfo *targetSlot, PK11SlotInfo *sourceSlot,
   1344                 CK_OBJECT_HANDLE id, void *targetPwArg, void *sourcePwArg)
   1345 {
   1346 
   1347    CK_OBJECT_CLASS objClass;
   1348 
   1349    objClass = PK11_ReadULongAttribute(sourceSlot, id, CKA_CLASS);
   1350    if (objClass == (CK_ULONG)-1) {
   1351        PORT_SetError(SEC_ERROR_UNKNOWN_OBJECT_TYPE);
   1352        return SECFailure;
   1353    }
   1354 
   1355    switch (objClass) {
   1356        case CKO_CERTIFICATE:
   1357            return pk11_mergeCert(targetSlot, sourceSlot, id,
   1358                                  targetPwArg, sourcePwArg);
   1359        case CKO_NSS_TRUST:
   1360        case CKO_TRUST:
   1361            return pk11_mergeTrust(targetSlot, sourceSlot, id,
   1362                                   objClass, targetPwArg, sourcePwArg);
   1363        case CKO_PUBLIC_KEY:
   1364            return pk11_mergePublicKey(targetSlot, sourceSlot, id,
   1365                                       targetPwArg, sourcePwArg);
   1366        case CKO_PRIVATE_KEY:
   1367            return pk11_mergePrivateKey(targetSlot, sourceSlot, id,
   1368                                        targetPwArg, sourcePwArg);
   1369        case CKO_SECRET_KEY:
   1370            return pk11_mergeSecretKey(targetSlot, sourceSlot, id,
   1371                                       targetPwArg, sourcePwArg);
   1372        case CKO_NSS_CRL:
   1373            return pk11_mergeCrl(targetSlot, sourceSlot, id,
   1374                                 targetPwArg, sourcePwArg);
   1375        case CKO_NSS_SMIME:
   1376            return pk11_mergeSmime(targetSlot, sourceSlot, id,
   1377                                   targetPwArg, sourcePwArg);
   1378        default:
   1379            break;
   1380    }
   1381 
   1382    PORT_SetError(SEC_ERROR_UNKNOWN_OBJECT_TYPE);
   1383    return SECFailure;
   1384 }
   1385 
   1386 PK11MergeLogNode *
   1387 pk11_newMergeLogNode(PLArenaPool *arena,
   1388                     PK11SlotInfo *slot, CK_OBJECT_HANDLE id, int error)
   1389 {
   1390    PK11MergeLogNode *newLog;
   1391    PK11GenericObject *obj;
   1392 
   1393    newLog = PORT_ArenaZNew(arena, PK11MergeLogNode);
   1394    if (newLog == NULL) {
   1395        return NULL;
   1396    }
   1397 
   1398    obj = PORT_ArenaZNew(arena, PK11GenericObject);
   1399    if (!obj) {
   1400        return NULL;
   1401    }
   1402 
   1403    /* initialize it */
   1404    obj->slot = slot;
   1405    obj->objectID = id;
   1406    obj->owner = PR_FALSE;
   1407 
   1408    newLog->object = obj;
   1409    newLog->error = error;
   1410    return newLog;
   1411 }
   1412 
   1413 /*
   1414 * walk down each entry and merge it. keep track of the errors in the log
   1415 */
   1416 static SECStatus
   1417 pk11_mergeByObjectIDs(PK11SlotInfo *targetSlot, PK11SlotInfo *sourceSlot,
   1418                      CK_OBJECT_HANDLE *objectIDs, int count,
   1419                      PK11MergeLog *log, void *targetPwArg, void *sourcePwArg)
   1420 {
   1421    SECStatus rv = SECSuccess;
   1422    int error = SEC_ERROR_LIBRARY_FAILURE;
   1423    int i;
   1424 
   1425    for (i = 0; i < count; i++) {
   1426        /* try to update the entire database. On failure, keep going,
   1427         * but remember the error to report back to the caller */
   1428        SECStatus lrv;
   1429        PK11MergeLogNode *newLog;
   1430 
   1431        lrv = pk11_mergeObject(targetSlot, sourceSlot, objectIDs[i],
   1432                               targetPwArg, sourcePwArg);
   1433        if (lrv == SECSuccess) {
   1434            /* merged with no problem, go to next object */
   1435            continue;
   1436        }
   1437 
   1438        /* remember that we failed and why */
   1439        rv = SECFailure;
   1440        error = PORT_GetError();
   1441 
   1442        /* log the errors */
   1443        if (!log) {
   1444            /* not logging, go to next entry */
   1445            continue;
   1446        }
   1447        newLog = pk11_newMergeLogNode(log->arena, sourceSlot,
   1448                                      objectIDs[i], error);
   1449        if (!newLog) {
   1450            /* failed to allocate entry, just keep going */
   1451            continue;
   1452        }
   1453 
   1454        /* link in the errorlog entry */
   1455        newLog->next = NULL;
   1456        if (log->tail) {
   1457            log->tail->next = newLog;
   1458        } else {
   1459            log->head = newLog;
   1460        }
   1461        newLog->prev = log->tail;
   1462        log->tail = newLog;
   1463    }
   1464 
   1465    /* restore the last error code */
   1466    if (rv != SECSuccess) {
   1467        PORT_SetError(error);
   1468    }
   1469    return rv;
   1470 }
   1471 
   1472 /*
   1473 * Merge all the records in sourceSlot that aren't in targetSlot
   1474 *
   1475 *   This function will return failure if not all the objects
   1476 *   successfully merged.
   1477 *
   1478 *   Applications can pass in an optional error log which will record
   1479 *   each failing object and why it failed to import. PK11MergeLog
   1480 *   is modelled after the CERTVerifyLog.
   1481 */
   1482 SECStatus
   1483 PK11_MergeTokens(PK11SlotInfo *targetSlot, PK11SlotInfo *sourceSlot,
   1484                 PK11MergeLog *log, void *targetPwArg, void *sourcePwArg)
   1485 {
   1486    SECStatus rv = SECSuccess, lrv = SECSuccess;
   1487    int error = SEC_ERROR_LIBRARY_FAILURE;
   1488    int count = 0;
   1489    CK_ATTRIBUTE search[2];
   1490    CK_OBJECT_HANDLE *objectIDs = NULL;
   1491    CK_BBOOL ck_true = CK_TRUE;
   1492    CK_OBJECT_CLASS privKey = CKO_PRIVATE_KEY;
   1493 
   1494    PK11_SETATTRS(&search[0], CKA_TOKEN, &ck_true, sizeof(ck_true));
   1495    PK11_SETATTRS(&search[1], CKA_CLASS, &privKey, sizeof(privKey));
   1496    /*
   1497     * make sure both tokens are already authenticated if need be.
   1498     */
   1499    rv = PK11_Authenticate(targetSlot, PR_TRUE, targetPwArg);
   1500    if (rv != SECSuccess) {
   1501        goto loser;
   1502    }
   1503    rv = PK11_Authenticate(sourceSlot, PR_TRUE, sourcePwArg);
   1504    if (rv != SECSuccess) {
   1505        goto loser;
   1506    }
   1507 
   1508    /* turns out the old DB's are rather fragile if the private keys aren't
   1509     * merged in first, so do the private keys explicity. */
   1510    objectIDs = pk11_FindObjectsByTemplate(sourceSlot, search, 2, &count);
   1511    if (objectIDs) {
   1512        lrv = pk11_mergeByObjectIDs(targetSlot, sourceSlot,
   1513                                    objectIDs, count, log,
   1514                                    targetPwArg, sourcePwArg);
   1515        if (lrv != SECSuccess) {
   1516            error = PORT_GetError();
   1517        }
   1518        PORT_Free(objectIDs);
   1519        count = 0;
   1520    }
   1521 
   1522    /* now do the rest  (NOTE: this will repeat the private keys, but
   1523     * that shouldnt' be an issue as we will notice they are already
   1524     * merged in */
   1525    objectIDs = pk11_FindObjectsByTemplate(sourceSlot, search, 1, &count);
   1526    if (!objectIDs) {
   1527        rv = SECFailure;
   1528        goto loser;
   1529    }
   1530 
   1531    rv = pk11_mergeByObjectIDs(targetSlot, sourceSlot, objectIDs, count, log,
   1532                               targetPwArg, sourcePwArg);
   1533    if (rv == SECSuccess) {
   1534        /* if private keys failed, but the rest succeeded, be sure to let
   1535         * the caller know that private keys failed and why.
   1536         * NOTE: this is highly unlikely since the same keys that failed
   1537         * in the previous merge call will most likely fail in this one */
   1538        if (lrv != SECSuccess) {
   1539            rv = lrv;
   1540            PORT_SetError(error);
   1541        }
   1542    }
   1543 
   1544 loser:
   1545    if (objectIDs) {
   1546        PORT_Free(objectIDs);
   1547    }
   1548    return rv;
   1549 }
   1550 
   1551 PK11MergeLog *
   1552 PK11_CreateMergeLog(void)
   1553 {
   1554    PLArenaPool *arena;
   1555    PK11MergeLog *log;
   1556 
   1557    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
   1558    if (arena == NULL) {
   1559        return NULL;
   1560    }
   1561 
   1562    log = PORT_ArenaZNew(arena, PK11MergeLog);
   1563    if (log == NULL) {
   1564        PORT_FreeArena(arena, PR_FALSE);
   1565        return NULL;
   1566    }
   1567    log->arena = arena;
   1568    log->version = 1;
   1569    return log;
   1570 }
   1571 
   1572 void
   1573 PK11_DestroyMergeLog(PK11MergeLog *log)
   1574 {
   1575    if (log && log->arena) {
   1576        PORT_FreeArena(log->arena, PR_FALSE);
   1577    }
   1578 }