tor-browser

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

lgcreate.c (32972B)


      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 #include "secitem.h"
      5 #include "pkcs11.h"
      6 #include "lgdb.h"
      7 #include "pcert.h"
      8 #include "lowkeyi.h"
      9 #include "blapi.h"
     10 #include "secder.h"
     11 #include "secasn1.h"
     12 
     13 #include "keydbi.h"
     14 
     15 /*
     16 * ******************** Object Creation Utilities ***************************
     17 */
     18 
     19 /*
     20 * check the consistancy and initialize a Certificate Object
     21 */
     22 static CK_RV
     23 lg_createCertObject(SDB *sdb, CK_OBJECT_HANDLE *handle,
     24                    const CK_ATTRIBUTE *templ, CK_ULONG count)
     25 {
     26    SECItem derCert;
     27    NSSLOWCERTCertificate *cert;
     28    NSSLOWCERTCertTrust *trust = NULL;
     29    NSSLOWCERTCertTrust userTrust = { CERTDB_USER, CERTDB_USER, CERTDB_USER };
     30    NSSLOWCERTCertTrust defTrust = { CERTDB_TRUSTED_UNKNOWN,
     31                                     CERTDB_TRUSTED_UNKNOWN, CERTDB_TRUSTED_UNKNOWN };
     32    char *label = NULL;
     33    char *email = NULL;
     34    SECStatus rv;
     35    CK_RV crv;
     36    PRBool inDB = PR_TRUE;
     37    NSSLOWCERTCertDBHandle *certHandle = lg_getCertDB(sdb);
     38    NSSLOWKEYDBHandle *keyHandle = NULL;
     39    CK_CERTIFICATE_TYPE type;
     40    const CK_ATTRIBUTE *attribute;
     41 
     42    /* we can't store any certs private */
     43    if (lg_isTrue(CKA_PRIVATE, templ, count)) {
     44        return CKR_ATTRIBUTE_VALUE_INVALID;
     45    }
     46 
     47    /* We only support X.509 Certs for now */
     48    crv = lg_GetULongAttribute(CKA_CERTIFICATE_TYPE, templ, count, &type);
     49    if (crv != CKR_OK) {
     50        return crv;
     51    }
     52 
     53    if (type != CKC_X_509) {
     54        return CKR_ATTRIBUTE_VALUE_INVALID;
     55    }
     56 
     57    /* X.509 Certificate */
     58 
     59    if (certHandle == NULL) {
     60        return CKR_TOKEN_WRITE_PROTECTED;
     61    }
     62 
     63    /* get the der cert */
     64    attribute = lg_FindAttribute(CKA_VALUE, templ, count);
     65    if (!attribute) {
     66        return CKR_ATTRIBUTE_VALUE_INVALID;
     67    }
     68 
     69    derCert.type = 0;
     70    derCert.data = (unsigned char *)attribute->pValue;
     71    derCert.len = attribute->ulValueLen;
     72 
     73    label = lg_getString(CKA_LABEL, templ, count);
     74 
     75    cert = nsslowcert_FindCertByDERCert(certHandle, &derCert);
     76    if (cert == NULL) {
     77        cert = nsslowcert_DecodeDERCertificate(&derCert, label);
     78        inDB = PR_FALSE;
     79    }
     80    if (cert == NULL) {
     81        if (label)
     82            PORT_Free(label);
     83        return CKR_ATTRIBUTE_VALUE_INVALID;
     84    }
     85 
     86    keyHandle = lg_getKeyDB(sdb);
     87    if (keyHandle) {
     88        if (nsslowkey_KeyForCertExists(keyHandle, cert)) {
     89            trust = &userTrust;
     90        }
     91    }
     92 
     93    if (!inDB) {
     94        if (!trust)
     95            trust = &defTrust;
     96        rv = nsslowcert_AddPermCert(certHandle, cert, label, trust);
     97    } else {
     98        rv = trust ? nsslowcert_ChangeCertTrust(certHandle, cert, trust) : SECSuccess;
     99    }
    100 
    101    if (label)
    102        PORT_Free(label);
    103 
    104    if (rv != SECSuccess) {
    105        nsslowcert_DestroyCertificate(cert);
    106        return CKR_DEVICE_ERROR;
    107    }
    108 
    109    /*
    110     * Add a NULL S/MIME profile if necessary.
    111     */
    112    email = lg_getString(CKA_NSS_EMAIL, templ, count);
    113    if (email) {
    114        certDBEntrySMime *entry;
    115 
    116        entry = nsslowcert_ReadDBSMimeEntry(certHandle, email);
    117        if (!entry) {
    118            nsslowcert_SaveSMimeProfile(certHandle, email,
    119                                        &cert->derSubject, NULL, NULL);
    120        } else {
    121            nsslowcert_DestroyDBEntry((certDBEntry *)entry);
    122        }
    123        PORT_Free(email);
    124    }
    125    *handle = lg_mkHandle(sdb, &cert->certKey, LG_TOKEN_TYPE_CERT);
    126    nsslowcert_DestroyCertificate(cert);
    127 
    128    return CKR_OK;
    129 }
    130 
    131 unsigned int
    132 lg_MapTrust(CK_TRUST trust, PRBool clientAuth)
    133 {
    134    unsigned int trustCA = clientAuth ? CERTDB_TRUSTED_CLIENT_CA : CERTDB_TRUSTED_CA;
    135    switch (trust) {
    136        case CKT_NSS_TRUSTED:
    137        case CKT_TRUSTED:
    138            return CERTDB_TERMINAL_RECORD | CERTDB_TRUSTED;
    139        case CKT_NSS_TRUSTED_DELEGATOR:
    140        case CKT_TRUST_ANCHOR:
    141            return CERTDB_VALID_CA | trustCA;
    142        case CKT_NSS_MUST_VERIFY_TRUST:
    143        case CKT_TRUST_MUST_VERIFY_TRUST:
    144            return CERTDB_MUST_VERIFY;
    145        case CKT_NSS_NOT_TRUSTED:
    146        case CKT_NOT_TRUSTED:
    147            return CERTDB_TERMINAL_RECORD;
    148        case CKT_NSS_VALID_DELEGATOR: /* implies must verify */
    149            return CERTDB_VALID_CA;
    150        default:
    151            break;
    152    }
    153    return CERTDB_TRUSTED_UNKNOWN;
    154 }
    155 
    156 /*
    157 * check the consistancy and initialize a Trust Object
    158 */
    159 static CK_RV
    160 lg_createTrustObject(SDB *sdb, CK_OBJECT_HANDLE *handle,
    161                     const CK_ATTRIBUTE *templ, CK_ULONG count,
    162                     CK_OBJECT_HANDLE lgClass)
    163 {
    164    const CK_ATTRIBUTE *issuer = NULL;
    165    const CK_ATTRIBUTE *serial = NULL;
    166    NSSLOWCERTCertificate *cert = NULL;
    167    const CK_ATTRIBUTE *trust;
    168    CK_TRUST sslTrust = CKT_NSS_TRUST_UNKNOWN;
    169    CK_TRUST clientTrust = CKT_NSS_TRUST_UNKNOWN;
    170    CK_TRUST emailTrust = CKT_NSS_TRUST_UNKNOWN;
    171    CK_TRUST signTrust = CKT_NSS_TRUST_UNKNOWN;
    172    CK_BBOOL stepUp;
    173    NSSLOWCERTCertTrust dbTrust = { 0 };
    174    SECStatus rv;
    175    NSSLOWCERTCertDBHandle *certHandle = lg_getCertDB(sdb);
    176    NSSLOWCERTIssuerAndSN issuerSN;
    177 
    178    /* we can't store any certs private */
    179    if (lg_isTrue(CKA_PRIVATE, templ, count)) {
    180        return CKR_ATTRIBUTE_VALUE_INVALID;
    181    }
    182 
    183    if (certHandle == NULL) {
    184        return CKR_TOKEN_WRITE_PROTECTED;
    185    }
    186 
    187    issuer = lg_FindAttribute(CKA_ISSUER, templ, count);
    188    serial = lg_FindAttribute(CKA_SERIAL_NUMBER, templ, count);
    189 
    190    if (issuer && serial) {
    191        issuerSN.derIssuer.data = (unsigned char *)issuer->pValue;
    192        issuerSN.derIssuer.len = issuer->ulValueLen;
    193 
    194        issuerSN.serialNumber.data = (unsigned char *)serial->pValue;
    195        issuerSN.serialNumber.len = serial->ulValueLen;
    196 
    197        cert = nsslowcert_FindCertByIssuerAndSN(certHandle, &issuerSN);
    198    }
    199 
    200    if (cert == NULL) {
    201        return CKR_ATTRIBUTE_VALUE_INVALID;
    202    }
    203 
    204    lg_GetULongAttribute(CKA_NSS_TRUST_SERVER_AUTH, templ, count, &sslTrust);
    205    lg_GetULongAttribute(CKA_PKCS_TRUST_SERVER_AUTH, templ, count, &sslTrust);
    206    lg_GetULongAttribute(CKA_NSS_TRUST_CLIENT_AUTH, templ, count, &clientTrust);
    207    lg_GetULongAttribute(CKA_PKCS_TRUST_CLIENT_AUTH, templ, count, &clientTrust);
    208    lg_GetULongAttribute(CKA_NSS_TRUST_EMAIL_PROTECTION, templ, count, &emailTrust);
    209    lg_GetULongAttribute(CKA_PKCS_TRUST_EMAIL_PROTECTION, templ, count, &emailTrust);
    210    lg_GetULongAttribute(CKA_NSS_TRUST_CODE_SIGNING, templ, count, &signTrust);
    211    lg_GetULongAttribute(CKA_PKCS_TRUST_CODE_SIGNING, templ, count, &signTrust);
    212    stepUp = CK_FALSE;
    213    trust = lg_FindAttribute(CKA_TRUST_STEP_UP_APPROVED, templ, count);
    214    if (trust) {
    215        if (trust->ulValueLen == sizeof(CK_BBOOL)) {
    216            stepUp = *(CK_BBOOL *)trust->pValue;
    217        }
    218    }
    219 
    220    /* preserve certain old fields */
    221    if (cert->trust) {
    222        dbTrust.sslFlags = cert->trust->sslFlags & CERTDB_PRESERVE_TRUST_BITS;
    223        dbTrust.emailFlags =
    224            cert->trust->emailFlags & CERTDB_PRESERVE_TRUST_BITS;
    225        dbTrust.objectSigningFlags =
    226            cert->trust->objectSigningFlags & CERTDB_PRESERVE_TRUST_BITS;
    227    }
    228 
    229    dbTrust.sslFlags |= lg_MapTrust(sslTrust, PR_FALSE);
    230    dbTrust.sslFlags |= lg_MapTrust(clientTrust, PR_TRUE);
    231    dbTrust.emailFlags |= lg_MapTrust(emailTrust, PR_FALSE);
    232    dbTrust.objectSigningFlags |= lg_MapTrust(signTrust, PR_FALSE);
    233    if (stepUp) {
    234        dbTrust.sslFlags |= CERTDB_GOVT_APPROVED_CA;
    235    }
    236 
    237    rv = nsslowcert_ChangeCertTrust(certHandle, cert, &dbTrust);
    238    *handle = lg_mkHandle(sdb, &cert->certKey, lgClass);
    239    nsslowcert_DestroyCertificate(cert);
    240    if (rv != SECSuccess) {
    241        return CKR_DEVICE_ERROR;
    242    }
    243 
    244    return CKR_OK;
    245 }
    246 
    247 /*
    248 * check the consistancy and initialize a Trust Object
    249 */
    250 static CK_RV
    251 lg_createSMimeObject(SDB *sdb, CK_OBJECT_HANDLE *handle,
    252                     const CK_ATTRIBUTE *templ, CK_ULONG count)
    253 {
    254    SECItem derSubj, rawProfile, rawTime, emailKey;
    255    SECItem *pRawProfile = NULL;
    256    SECItem *pRawTime = NULL;
    257    char *email = NULL;
    258    const CK_ATTRIBUTE *subject = NULL,
    259                       *profile = NULL,
    260                       *time = NULL;
    261    SECStatus rv;
    262    NSSLOWCERTCertDBHandle *certHandle;
    263    CK_RV ck_rv = CKR_OK;
    264 
    265    /* we can't store any certs private */
    266    if (lg_isTrue(CKA_PRIVATE, templ, count)) {
    267        return CKR_ATTRIBUTE_VALUE_INVALID;
    268    }
    269 
    270    certHandle = lg_getCertDB(sdb);
    271    if (certHandle == NULL) {
    272        return CKR_TOKEN_WRITE_PROTECTED;
    273    }
    274 
    275    /* lookup SUBJECT */
    276    subject = lg_FindAttribute(CKA_SUBJECT, templ, count);
    277    PORT_Assert(subject);
    278    if (!subject) {
    279        ck_rv = CKR_ATTRIBUTE_VALUE_INVALID;
    280        goto loser;
    281    }
    282 
    283    derSubj.data = (unsigned char *)subject->pValue;
    284    derSubj.len = subject->ulValueLen;
    285    derSubj.type = 0;
    286 
    287    /* lookup VALUE */
    288    profile = lg_FindAttribute(CKA_VALUE, templ, count);
    289    if (profile) {
    290        rawProfile.data = (unsigned char *)profile->pValue;
    291        rawProfile.len = profile->ulValueLen;
    292        rawProfile.type = siBuffer;
    293        pRawProfile = &rawProfile;
    294    }
    295 
    296    /* lookup Time */
    297    time = lg_FindAttribute(CKA_NSS_SMIME_TIMESTAMP, templ, count);
    298    if (time) {
    299        rawTime.data = (unsigned char *)time->pValue;
    300        rawTime.len = time->ulValueLen;
    301        rawTime.type = siBuffer;
    302        pRawTime = &rawTime;
    303    }
    304 
    305    email = lg_getString(CKA_NSS_EMAIL, templ, count);
    306    if (!email) {
    307        ck_rv = CKR_ATTRIBUTE_VALUE_INVALID;
    308        goto loser;
    309    }
    310 
    311    /* Store S/MIME Profile by SUBJECT */
    312    rv = nsslowcert_SaveSMimeProfile(certHandle, email, &derSubj,
    313                                     pRawProfile, pRawTime);
    314    if (rv != SECSuccess) {
    315        ck_rv = CKR_DEVICE_ERROR;
    316        goto loser;
    317    }
    318    emailKey.data = (unsigned char *)email;
    319    emailKey.len = PORT_Strlen(email) + 1;
    320 
    321    *handle = lg_mkHandle(sdb, &emailKey, LG_TOKEN_TYPE_SMIME);
    322 
    323 loser:
    324    if (email)
    325        PORT_Free(email);
    326 
    327    return ck_rv;
    328 }
    329 
    330 /*
    331 * check the consistancy and initialize a Trust Object
    332 */
    333 static CK_RV
    334 lg_createCrlObject(SDB *sdb, CK_OBJECT_HANDLE *handle,
    335                   const CK_ATTRIBUTE *templ, CK_ULONG count)
    336 {
    337    PRBool isKRL = PR_FALSE;
    338    SECItem derSubj, derCrl;
    339    char *url = NULL;
    340    const CK_ATTRIBUTE *subject, *crl;
    341    SECStatus rv;
    342    NSSLOWCERTCertDBHandle *certHandle;
    343 
    344    certHandle = lg_getCertDB(sdb);
    345 
    346    /* we can't store any private crls */
    347    if (lg_isTrue(CKA_PRIVATE, templ, count)) {
    348        return CKR_ATTRIBUTE_VALUE_INVALID;
    349    }
    350 
    351    if (certHandle == NULL) {
    352        return CKR_TOKEN_WRITE_PROTECTED;
    353    }
    354 
    355    /* lookup SUBJECT */
    356    subject = lg_FindAttribute(CKA_SUBJECT, templ, count);
    357    if (!subject) {
    358        return CKR_ATTRIBUTE_VALUE_INVALID;
    359    }
    360 
    361    derSubj.data = (unsigned char *)subject->pValue;
    362    derSubj.len = subject->ulValueLen;
    363 
    364    /* lookup VALUE */
    365    crl = lg_FindAttribute(CKA_VALUE, templ, count);
    366    PORT_Assert(crl);
    367    if (!crl) {
    368        return CKR_ATTRIBUTE_VALUE_INVALID;
    369    }
    370    derCrl.data = (unsigned char *)crl->pValue;
    371    derCrl.len = crl->ulValueLen;
    372 
    373    url = lg_getString(CKA_NSS_URL, templ, count);
    374    isKRL = lg_isTrue(CKA_NSS_KRL, templ, count);
    375 
    376    /* Store CRL by SUBJECT */
    377    rv = nsslowcert_AddCrl(certHandle, &derCrl, &derSubj, url, isKRL);
    378 
    379    if (url) {
    380        PORT_Free(url);
    381    }
    382    if (rv != SECSuccess) {
    383        return CKR_DEVICE_ERROR;
    384    }
    385 
    386    /* if we overwrote the existing CRL, poison the handle entry so we get
    387     * a new object handle */
    388    (void)lg_poisonHandle(sdb, &derSubj,
    389                          isKRL ? LG_TOKEN_KRL_HANDLE : LG_TOKEN_TYPE_CRL);
    390    *handle = lg_mkHandle(sdb, &derSubj,
    391                          isKRL ? LG_TOKEN_KRL_HANDLE : LG_TOKEN_TYPE_CRL);
    392 
    393    return CKR_OK;
    394 }
    395 
    396 /*
    397 * check the consistancy and initialize a Public Key Object
    398 */
    399 static CK_RV
    400 lg_createPublicKeyObject(SDB *sdb, CK_KEY_TYPE key_type,
    401                         CK_OBJECT_HANDLE *handle, const CK_ATTRIBUTE *templ, CK_ULONG count)
    402 {
    403    CK_ATTRIBUTE_TYPE pubKeyAttr = CKA_VALUE;
    404    CK_RV crv = CKR_OK;
    405    NSSLOWKEYPrivateKey *priv;
    406    SECItem pubKeySpace = { siBuffer, NULL, 0 };
    407    SECItem *pubKey;
    408    SECItem pubKey2Space = { siBuffer, NULL, 0 };
    409    PLArenaPool *arena = NULL;
    410    NSSLOWKEYDBHandle *keyHandle = NULL;
    411 
    412    switch (key_type) {
    413        case CKK_RSA:
    414            pubKeyAttr = CKA_MODULUS;
    415            break;
    416        case CKK_EC:
    417            pubKeyAttr = CKA_EC_POINT;
    418            break;
    419        case CKK_DSA:
    420        case CKK_DH:
    421            break;
    422        default:
    423            return CKR_ATTRIBUTE_VALUE_INVALID;
    424    }
    425 
    426    pubKey = &pubKeySpace;
    427    crv = lg_Attribute2SSecItem(NULL, pubKeyAttr, templ, count, pubKey);
    428    if (crv != CKR_OK)
    429        return crv;
    430 
    431    if (key_type == CKK_EC) {
    432        SECStatus rv;
    433        /*
    434         * for ECC, use the decoded key first.
    435         */
    436        arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
    437        if (arena == NULL) {
    438            crv = CKR_HOST_MEMORY;
    439            goto done;
    440        }
    441        rv = SEC_QuickDERDecodeItem(arena, &pubKey2Space,
    442                                    SEC_ASN1_GET(SEC_OctetStringTemplate),
    443                                    pubKey);
    444        if (rv != SECSuccess) {
    445            /* decode didn't work, just try the pubKey */
    446            PORT_FreeArena(arena, PR_FALSE);
    447            arena = NULL;
    448        } else {
    449            /* try the decoded pub key first */
    450            pubKey = &pubKey2Space;
    451        }
    452    }
    453 
    454    PORT_Assert(pubKey->data);
    455    if (pubKey->data == NULL) {
    456        crv = CKR_ATTRIBUTE_VALUE_INVALID;
    457        goto done;
    458    }
    459    keyHandle = lg_getKeyDB(sdb);
    460    if (keyHandle == NULL) {
    461        crv = CKR_TOKEN_WRITE_PROTECTED;
    462        goto done;
    463    }
    464    if (keyHandle->version != 3) {
    465        unsigned char buf[SHA1_LENGTH];
    466        SHA1_HashBuf(buf, pubKey->data, pubKey->len);
    467        PORT_Memcpy(pubKey->data, buf, sizeof(buf));
    468        pubKey->len = sizeof(buf);
    469    }
    470    /* make sure the associated private key already exists */
    471    /* only works if we are logged in */
    472    priv = nsslowkey_FindKeyByPublicKey(keyHandle, pubKey, sdb /*password*/);
    473    if (priv == NULL && pubKey == &pubKey2Space) {
    474        /* no match on the decoded key, match the original pubkey */
    475        pubKey = &pubKeySpace;
    476        priv = nsslowkey_FindKeyByPublicKey(keyHandle, pubKey,
    477                                            sdb /*password*/);
    478    }
    479    if (priv == NULL) {
    480        /* the legacy database can only 'store' public keys which already
    481         * have their corresponding private keys in the database */
    482        crv = CKR_ATTRIBUTE_VALUE_INVALID;
    483        goto done;
    484    }
    485    lg_nsslowkey_DestroyPrivateKey(priv);
    486    crv = CKR_OK;
    487 
    488    *handle = lg_mkHandle(sdb, pubKey, LG_TOKEN_TYPE_PUB);
    489 
    490 done:
    491    PORT_Free(pubKeySpace.data);
    492    if (arena) {
    493        PORT_FreeArena(arena, PR_FALSE);
    494    }
    495 
    496    return crv;
    497 }
    498 
    499 /* make a private key from a verified object */
    500 static NSSLOWKEYPrivateKey *
    501 lg_mkPrivKey(SDB *sdb, const CK_ATTRIBUTE *templ, CK_ULONG count,
    502             CK_KEY_TYPE key_type, CK_RV *crvp)
    503 {
    504    NSSLOWKEYPrivateKey *privKey;
    505    PLArenaPool *arena;
    506    CK_RV crv = CKR_OK;
    507    SECStatus rv;
    508 
    509    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
    510    if (arena == NULL) {
    511        *crvp = CKR_HOST_MEMORY;
    512        return NULL;
    513    }
    514 
    515    privKey = (NSSLOWKEYPrivateKey *)
    516        PORT_ArenaZAlloc(arena, sizeof(NSSLOWKEYPrivateKey));
    517    if (privKey == NULL) {
    518        PORT_FreeArena(arena, PR_FALSE);
    519        *crvp = CKR_HOST_MEMORY;
    520        return NULL;
    521    }
    522 
    523    /* in future this would be a switch on key_type */
    524    privKey->arena = arena;
    525    switch (key_type) {
    526        case CKK_RSA:
    527            privKey->keyType = NSSLOWKEYRSAKey;
    528            crv = lg_Attribute2SSecItem(arena, CKA_MODULUS, templ, count,
    529                                        &privKey->u.rsa.modulus);
    530            if (crv != CKR_OK)
    531                break;
    532            crv = lg_Attribute2SSecItem(arena, CKA_PUBLIC_EXPONENT, templ, count,
    533                                        &privKey->u.rsa.publicExponent);
    534            if (crv != CKR_OK)
    535                break;
    536            crv = lg_PrivAttr2SSecItem(arena, CKA_PRIVATE_EXPONENT, templ, count,
    537                                       &privKey->u.rsa.privateExponent, sdb);
    538            if (crv != CKR_OK)
    539                break;
    540            crv = lg_PrivAttr2SSecItem(arena, CKA_PRIME_1, templ, count,
    541                                       &privKey->u.rsa.prime1, sdb);
    542            if (crv != CKR_OK)
    543                break;
    544            crv = lg_PrivAttr2SSecItem(arena, CKA_PRIME_2, templ, count,
    545                                       &privKey->u.rsa.prime2, sdb);
    546            if (crv != CKR_OK)
    547                break;
    548            crv = lg_PrivAttr2SSecItem(arena, CKA_EXPONENT_1, templ, count,
    549                                       &privKey->u.rsa.exponent1, sdb);
    550            if (crv != CKR_OK)
    551                break;
    552            crv = lg_PrivAttr2SSecItem(arena, CKA_EXPONENT_2, templ, count,
    553                                       &privKey->u.rsa.exponent2, sdb);
    554            if (crv != CKR_OK)
    555                break;
    556            crv = lg_PrivAttr2SSecItem(arena, CKA_COEFFICIENT, templ, count,
    557                                       &privKey->u.rsa.coefficient, sdb);
    558            if (crv != CKR_OK)
    559                break;
    560            rv = DER_SetUInteger(privKey->arena, &privKey->u.rsa.version,
    561                                 NSSLOWKEY_VERSION);
    562            if (rv != SECSuccess)
    563                crv = CKR_HOST_MEMORY;
    564            break;
    565 
    566        case CKK_DSA:
    567            privKey->keyType = NSSLOWKEYDSAKey;
    568            crv = lg_Attribute2SSecItem(arena, CKA_PRIME, templ, count,
    569                                        &privKey->u.dsa.params.prime);
    570            if (crv != CKR_OK)
    571                break;
    572            crv = lg_Attribute2SSecItem(arena, CKA_SUBPRIME, templ, count,
    573                                        &privKey->u.dsa.params.subPrime);
    574            if (crv != CKR_OK)
    575                break;
    576            crv = lg_Attribute2SSecItem(arena, CKA_BASE, templ, count,
    577                                        &privKey->u.dsa.params.base);
    578            if (crv != CKR_OK)
    579                break;
    580            crv = lg_PrivAttr2SSecItem(arena, CKA_VALUE, templ, count,
    581                                       &privKey->u.dsa.privateValue, sdb);
    582            if (crv != CKR_OK)
    583                break;
    584            if (lg_hasAttribute(CKA_NSS_DB, templ, count)) {
    585                crv = lg_Attribute2SSecItem(arena, CKA_NSS_DB, templ, count,
    586                                            &privKey->u.dsa.publicValue);
    587                /* privKey was zero'd so public value is already set to NULL, 0
    588                 * if we don't set it explicitly */
    589            }
    590            break;
    591 
    592        case CKK_DH:
    593            privKey->keyType = NSSLOWKEYDHKey;
    594            crv = lg_Attribute2SSecItem(arena, CKA_PRIME, templ, count,
    595                                        &privKey->u.dh.prime);
    596            if (crv != CKR_OK)
    597                break;
    598            crv = lg_Attribute2SSecItem(arena, CKA_BASE, templ, count,
    599                                        &privKey->u.dh.base);
    600            if (crv != CKR_OK)
    601                break;
    602            crv = lg_PrivAttr2SSecItem(arena, CKA_VALUE, templ, count,
    603                                       &privKey->u.dh.privateValue, sdb);
    604            if (crv != CKR_OK)
    605                break;
    606            if (lg_hasAttribute(CKA_NSS_DB, templ, count)) {
    607                crv = lg_Attribute2SSecItem(arena, CKA_NSS_DB, templ, count,
    608                                            &privKey->u.dh.publicValue);
    609                /* privKey was zero'd so public value is already set to NULL, 0
    610                 * if we don't set it explicitly */
    611            }
    612            break;
    613 
    614        case CKK_EC:
    615            privKey->keyType = NSSLOWKEYECKey;
    616            crv = lg_Attribute2SSecItem(arena, CKA_EC_PARAMS, templ, count,
    617                                        &privKey->u.ec.ecParams.DEREncoding);
    618            if (crv != CKR_OK)
    619                break;
    620 
    621            /* Fill out the rest of the ecParams structure
    622             * based on the encoded params
    623             */
    624            if (LGEC_FillParams(arena, &privKey->u.ec.ecParams.DEREncoding,
    625                                &privKey->u.ec.ecParams) != SECSuccess) {
    626                crv = CKR_DOMAIN_PARAMS_INVALID;
    627                break;
    628            }
    629            crv = lg_PrivAttr2SSecItem(arena, CKA_VALUE, templ, count,
    630                                       &privKey->u.ec.privateValue, sdb);
    631            if (crv != CKR_OK)
    632                break;
    633            if (lg_hasAttribute(CKA_NSS_DB, templ, count)) {
    634                crv = lg_Attribute2SSecItem(arena, CKA_NSS_DB, templ, count,
    635                                            &privKey->u.ec.publicValue);
    636                if (crv != CKR_OK)
    637                    break;
    638                /* privKey was zero'd so public value is already set to NULL, 0
    639                 * if we don't set it explicitly */
    640            }
    641            rv = DER_SetUInteger(privKey->arena, &privKey->u.ec.version,
    642                                 NSSLOWKEY_EC_PRIVATE_KEY_VERSION);
    643            if (rv != SECSuccess)
    644                crv = CKR_HOST_MEMORY;
    645            break;
    646 
    647        default:
    648            crv = CKR_KEY_TYPE_INCONSISTENT;
    649            break;
    650    }
    651    *crvp = crv;
    652    if (crv != CKR_OK) {
    653        PORT_FreeArena(arena, PR_FALSE);
    654        return NULL;
    655    }
    656    return privKey;
    657 }
    658 
    659 /*
    660 * check the consistancy and initialize a Private Key Object
    661 */
    662 static CK_RV
    663 lg_createPrivateKeyObject(SDB *sdb, CK_KEY_TYPE key_type,
    664                          CK_OBJECT_HANDLE *handle, const CK_ATTRIBUTE *templ, CK_ULONG count)
    665 {
    666    NSSLOWKEYPrivateKey *privKey;
    667    char *label;
    668    SECStatus rv = SECSuccess;
    669    CK_RV crv = CKR_DEVICE_ERROR;
    670    SECItem pubKey;
    671    NSSLOWKEYDBHandle *keyHandle = lg_getKeyDB(sdb);
    672 
    673    if (keyHandle == NULL) {
    674        return CKR_TOKEN_WRITE_PROTECTED;
    675    }
    676 
    677    privKey = lg_mkPrivKey(sdb, templ, count, key_type, &crv);
    678    if (privKey == NULL)
    679        return crv;
    680    label = lg_getString(CKA_LABEL, templ, count);
    681 
    682    crv = lg_Attribute2SSecItem(NULL, CKA_NSS_DB, templ, count, &pubKey);
    683    if (crv != CKR_OK) {
    684        crv = CKR_TEMPLATE_INCOMPLETE;
    685        rv = SECFailure;
    686        goto fail;
    687    }
    688 #ifdef notdef
    689    if (keyHandle->version != 3) {
    690        unsigned char buf[SHA1_LENGTH];
    691        SHA1_HashBuf(buf, pubKey.data, pubKey.len);
    692        PORT_Memcpy(pubKey.data, buf, sizeof(buf));
    693        pubKey.len = sizeof(buf);
    694    }
    695 #endif
    696    /* get the key type */
    697    if (key_type == CKK_RSA) {
    698        rv = RSA_PrivateKeyCheck(&privKey->u.rsa);
    699        if (rv == SECFailure) {
    700            goto fail;
    701        }
    702    }
    703    rv = nsslowkey_StoreKeyByPublicKey(keyHandle, privKey, &pubKey,
    704                                       label, sdb /*->password*/);
    705 
    706 fail:
    707    if (label)
    708        PORT_Free(label);
    709    *handle = lg_mkHandle(sdb, &pubKey, LG_TOKEN_TYPE_PRIV);
    710    if (pubKey.data)
    711        PORT_Free(pubKey.data);
    712    lg_nsslowkey_DestroyPrivateKey(privKey);
    713    if (rv != SECSuccess)
    714        return crv;
    715 
    716    return CKR_OK;
    717 }
    718 
    719 #define LG_KEY_MAX_RETRIES 10 /* don't hang if we are having problems with the rng */
    720 #define LG_KEY_ID_SIZE 18     /* don't use either SHA1 or MD5 sizes */
    721 /*
    722 * Secret keys must have a CKA_ID value to be stored in the database. This code
    723 * will generate one if there wasn't one already.
    724 */
    725 static CK_RV
    726 lg_GenerateSecretCKA_ID(NSSLOWKEYDBHandle *handle, SECItem *id, char *label)
    727 {
    728    unsigned int retries;
    729    SECStatus rv = SECSuccess;
    730    CK_RV crv = CKR_OK;
    731 
    732    id->data = NULL;
    733    if (label) {
    734        id->data = (unsigned char *)PORT_Strdup(label);
    735        if (id->data == NULL) {
    736            return CKR_HOST_MEMORY;
    737        }
    738        id->len = PORT_Strlen(label) + 1;
    739        if (!nsslowkey_KeyForIDExists(handle, id)) {
    740            return CKR_OK;
    741        }
    742        PORT_Free(id->data);
    743        id->data = NULL;
    744        id->len = 0;
    745    }
    746    id->data = (unsigned char *)PORT_Alloc(LG_KEY_ID_SIZE);
    747    if (id->data == NULL) {
    748        return CKR_HOST_MEMORY;
    749    }
    750    id->len = LG_KEY_ID_SIZE;
    751 
    752    retries = 0;
    753    do {
    754        rv = RNG_GenerateGlobalRandomBytes(id->data, id->len);
    755    } while (rv == SECSuccess && nsslowkey_KeyForIDExists(handle, id) &&
    756             (++retries <= LG_KEY_MAX_RETRIES));
    757 
    758    if ((rv != SECSuccess) || (retries > LG_KEY_MAX_RETRIES)) {
    759        crv = CKR_DEVICE_ERROR; /* random number generator is bad */
    760        PORT_Free(id->data);
    761        id->data = NULL;
    762        id->len = 0;
    763    }
    764    return crv;
    765 }
    766 
    767 static NSSLOWKEYPrivateKey *
    768 lg_mkSecretKeyRep(const CK_ATTRIBUTE *templ,
    769                  CK_ULONG count, CK_KEY_TYPE key_type,
    770                  SECItem *pubkey, SDB *sdbpw)
    771 {
    772    NSSLOWKEYPrivateKey *privKey = 0;
    773    PLArenaPool *arena = 0;
    774    CK_KEY_TYPE keyType;
    775    PRUint32 keyTypeStorage;
    776    SECItem keyTypeItem;
    777    CK_RV crv;
    778    SECStatus rv;
    779    static unsigned char derZero[1] = { 0 };
    780 
    781    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
    782    if (arena == NULL) {
    783        crv = CKR_HOST_MEMORY;
    784        goto loser;
    785    }
    786 
    787    privKey = (NSSLOWKEYPrivateKey *)
    788        PORT_ArenaZAlloc(arena, sizeof(NSSLOWKEYPrivateKey));
    789    if (privKey == NULL) {
    790        crv = CKR_HOST_MEMORY;
    791        goto loser;
    792    }
    793 
    794    privKey->arena = arena;
    795 
    796    /* Secret keys are represented in the database as "fake" RSA keys.
    797     * The RSA key is marked as a secret key representation by setting the
    798     * public exponent field to 0, which is an invalid RSA exponent.
    799     * The other fields are set as follows:
    800     *   modulus - CKA_ID value for the secret key
    801     *   private exponent - CKA_VALUE (the key itself)
    802     *   coefficient - CKA_KEY_TYPE, which indicates what encryption algorithm
    803     *      is used for the key.
    804     *   all others - set to integer 0
    805     */
    806    privKey->keyType = NSSLOWKEYRSAKey;
    807 
    808    /* The modulus is set to the key id of the symmetric key */
    809    privKey->u.rsa.modulus.data =
    810        (unsigned char *)PORT_ArenaAlloc(arena, pubkey->len);
    811    if (privKey->u.rsa.modulus.data == NULL) {
    812        crv = CKR_HOST_MEMORY;
    813        goto loser;
    814    }
    815    privKey->u.rsa.modulus.len = pubkey->len;
    816    PORT_Memcpy(privKey->u.rsa.modulus.data, pubkey->data, pubkey->len);
    817 
    818    /* The public exponent is set to 0 to indicate a special key */
    819    privKey->u.rsa.publicExponent.len = sizeof derZero;
    820    privKey->u.rsa.publicExponent.data = derZero;
    821 
    822    /* The private exponent is the actual key value */
    823    crv = lg_PrivAttr2SecItem(arena, CKA_VALUE, templ, count,
    824                              &privKey->u.rsa.privateExponent, sdbpw);
    825    if (crv != CKR_OK)
    826        goto loser;
    827 
    828    /* All other fields empty - needs testing */
    829    privKey->u.rsa.prime1.len = sizeof derZero;
    830    privKey->u.rsa.prime1.data = derZero;
    831 
    832    privKey->u.rsa.prime2.len = sizeof derZero;
    833    privKey->u.rsa.prime2.data = derZero;
    834 
    835    privKey->u.rsa.exponent1.len = sizeof derZero;
    836    privKey->u.rsa.exponent1.data = derZero;
    837 
    838    privKey->u.rsa.exponent2.len = sizeof derZero;
    839    privKey->u.rsa.exponent2.data = derZero;
    840 
    841    /* Coeficient set to KEY_TYPE */
    842    crv = lg_GetULongAttribute(CKA_KEY_TYPE, templ, count, &keyType);
    843    if (crv != CKR_OK)
    844        goto loser;
    845    /* on 64 bit platforms, we still want to store 32 bits of keyType (This is
    846     * safe since the PKCS #11 defines for all types are 32 bits or less). */
    847    keyTypeStorage = (PRUint32)keyType;
    848    keyTypeStorage = PR_htonl(keyTypeStorage);
    849    keyTypeItem.data = (unsigned char *)&keyTypeStorage;
    850    keyTypeItem.len = sizeof(keyTypeStorage);
    851    rv = SECITEM_CopyItem(arena, &privKey->u.rsa.coefficient, &keyTypeItem);
    852    if (rv != SECSuccess) {
    853        crv = CKR_HOST_MEMORY;
    854        goto loser;
    855    }
    856 
    857    /* Private key version field set normally for compatibility */
    858    rv = DER_SetUInteger(privKey->arena,
    859                         &privKey->u.rsa.version, NSSLOWKEY_VERSION);
    860    if (rv != SECSuccess) {
    861        crv = CKR_HOST_MEMORY;
    862        goto loser;
    863    }
    864 
    865 loser:
    866    if (crv != CKR_OK) {
    867        PORT_FreeArena(arena, PR_FALSE);
    868        privKey = 0;
    869    }
    870 
    871    return privKey;
    872 }
    873 
    874 /*
    875 * check the consistancy and initialize a Secret Key Object
    876 */
    877 static CK_RV
    878 lg_createSecretKeyObject(SDB *sdb, CK_KEY_TYPE key_type,
    879                         CK_OBJECT_HANDLE *handle, const CK_ATTRIBUTE *templ, CK_ULONG count)
    880 {
    881    CK_RV crv;
    882    NSSLOWKEYPrivateKey *privKey = NULL;
    883    NSSLOWKEYDBHandle *keyHandle = NULL;
    884    SECItem pubKey;
    885    char *label = NULL;
    886    SECStatus rv = SECSuccess;
    887 
    888    pubKey.data = 0;
    889 
    890    /* If the object is a TOKEN object, store in the database */
    891    keyHandle = lg_getKeyDB(sdb);
    892 
    893    if (keyHandle == NULL) {
    894        return CKR_TOKEN_WRITE_PROTECTED;
    895    }
    896 
    897    label = lg_getString(CKA_LABEL, templ, count);
    898 
    899    crv = lg_Attribute2SecItem(NULL, CKA_ID, templ, count, &pubKey);
    900    /* Should this be ID? */
    901    if (crv != CKR_OK)
    902        goto loser;
    903 
    904    /* if we don't have an ID, generate one */
    905    if (pubKey.len == 0) {
    906        if (pubKey.data) {
    907            PORT_Free(pubKey.data);
    908            pubKey.data = NULL;
    909        }
    910        crv = lg_GenerateSecretCKA_ID(keyHandle, &pubKey, label);
    911        if (crv != CKR_OK)
    912            goto loser;
    913    }
    914 
    915    privKey = lg_mkSecretKeyRep(templ, count, key_type, &pubKey, sdb);
    916    if (privKey == NULL) {
    917        crv = CKR_HOST_MEMORY;
    918        goto loser;
    919    }
    920 
    921    rv = nsslowkey_StoreKeyByPublicKey(keyHandle,
    922                                       privKey, &pubKey, label, sdb /*->password*/);
    923    if (rv != SECSuccess) {
    924        crv = CKR_DEVICE_ERROR;
    925        goto loser;
    926    }
    927 
    928    *handle = lg_mkHandle(sdb, &pubKey, LG_TOKEN_TYPE_KEY);
    929 
    930 loser:
    931    if (label)
    932        PORT_Free(label);
    933    if (privKey)
    934        lg_nsslowkey_DestroyPrivateKey(privKey);
    935    if (pubKey.data)
    936        PORT_Free(pubKey.data);
    937 
    938    return crv;
    939 }
    940 
    941 /*
    942 * check the consistancy and initialize a Key Object
    943 */
    944 static CK_RV
    945 lg_createKeyObject(SDB *sdb, CK_OBJECT_CLASS objclass,
    946                   CK_OBJECT_HANDLE *handle, const CK_ATTRIBUTE *templ, CK_ULONG count)
    947 {
    948    CK_RV crv;
    949    CK_KEY_TYPE key_type;
    950 
    951    /* get the key type */
    952    crv = lg_GetULongAttribute(CKA_KEY_TYPE, templ, count, &key_type);
    953    if (crv != CKR_OK) {
    954        return crv;
    955    }
    956 
    957    switch (objclass) {
    958        case CKO_PUBLIC_KEY:
    959            return lg_createPublicKeyObject(sdb, key_type, handle, templ, count);
    960        case CKO_PRIVATE_KEY:
    961            return lg_createPrivateKeyObject(sdb, key_type, handle, templ, count);
    962        case CKO_SECRET_KEY:
    963            return lg_createSecretKeyObject(sdb, key_type, handle, templ, count);
    964        default:
    965            break;
    966    }
    967    return CKR_ATTRIBUTE_VALUE_INVALID;
    968 }
    969 
    970 /*
    971 * return the 'next' key handle
    972 */
    973 CK_RV
    974 lg_GetNewObjectID(SDB *sdb, CK_OBJECT_HANDLE *handle)
    975 {
    976    /* the upper level needs the Object ID early to populate any
    977     * signature attributes. The legacy can't really return a new
    978     * handle without the full object template (chicken and egg issue).
    979     * Fortunately we can just return a bogus handle because the legacy
    980     * database doesn't support meta data and can't store any of the signed
    981     * attributes anyway */
    982    *handle = CK_INVALID_HANDLE;
    983    return CKR_OK;
    984 }
    985 
    986 /*
    987 * Parse the template and create an object stored in the DB that reflects.
    988 * the object specified in the database.
    989 */
    990 CK_RV
    991 lg_CreateObject(SDB *sdb, CK_OBJECT_HANDLE *handle,
    992                const CK_ATTRIBUTE *templ, CK_ULONG count)
    993 {
    994    CK_RV crv;
    995    CK_OBJECT_CLASS objclass;
    996 
    997    /* get the object class */
    998    crv = lg_GetULongAttribute(CKA_CLASS, templ, count, &objclass);
    999    if (crv != CKR_OK) {
   1000        return crv;
   1001    }
   1002 
   1003    /* Now handle the specific object class.
   1004     */
   1005    switch (objclass) {
   1006        case CKO_CERTIFICATE:
   1007            crv = lg_createCertObject(sdb, handle, templ, count);
   1008            break;
   1009        case CKO_NSS_TRUST:
   1010            crv = lg_createTrustObject(sdb, handle, templ, count,
   1011                                       LG_TOKEN_TYPE_NSS_TRUST);
   1012            break;
   1013        case CKO_TRUST:
   1014            crv = lg_createTrustObject(sdb, handle, templ, count,
   1015                                       LG_TOKEN_TYPE_TRUST);
   1016            break;
   1017        case CKO_NSS_CRL:
   1018            crv = lg_createCrlObject(sdb, handle, templ, count);
   1019            break;
   1020        case CKO_NSS_SMIME:
   1021            crv = lg_createSMimeObject(sdb, handle, templ, count);
   1022            break;
   1023        case CKO_PRIVATE_KEY:
   1024        case CKO_PUBLIC_KEY:
   1025        case CKO_SECRET_KEY:
   1026            crv = lg_createKeyObject(sdb, objclass, handle, templ, count);
   1027            break;
   1028        default:
   1029            crv = CKR_ATTRIBUTE_VALUE_INVALID;
   1030            break;
   1031    }
   1032 
   1033    return crv;
   1034 }