andre@3: /* This Source Code Form is subject to the terms of the Mozilla Public andre@3: * License, v. 2.0. If a copy of the MPL was not distributed with this andre@3: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ andre@3: #include "secitem.h" andre@3: #include "pkcs11.h" andre@3: #include "lgdb.h" andre@3: #include "pcert.h" andre@3: #include "lowkeyi.h" andre@3: #include "blapi.h" andre@3: #include "secder.h" andre@3: #include "secasn1.h" andre@3: andre@3: #include "keydbi.h" andre@3: andre@3: /* andre@3: * ******************** Object Creation Utilities *************************** andre@3: */ andre@3: andre@3: /* andre@3: * check the consistancy and initialize a Certificate Object andre@3: */ andre@3: static CK_RV andre@3: lg_createCertObject(SDB *sdb, CK_OBJECT_HANDLE *handle, andre@3: const CK_ATTRIBUTE *templ, CK_ULONG count) andre@3: { andre@3: SECItem derCert; andre@3: NSSLOWCERTCertificate *cert; andre@3: NSSLOWCERTCertTrust *trust = NULL; andre@3: NSSLOWCERTCertTrust userTrust = andre@3: { CERTDB_USER, CERTDB_USER, CERTDB_USER }; andre@3: NSSLOWCERTCertTrust defTrust = andre@3: { CERTDB_TRUSTED_UNKNOWN, andre@3: CERTDB_TRUSTED_UNKNOWN, CERTDB_TRUSTED_UNKNOWN }; andre@3: char *label = NULL; andre@3: char *email = NULL; andre@3: SECStatus rv; andre@3: CK_RV crv; andre@3: PRBool inDB = PR_TRUE; andre@3: NSSLOWCERTCertDBHandle *certHandle = lg_getCertDB(sdb); andre@3: NSSLOWKEYDBHandle *keyHandle = NULL; andre@3: CK_CERTIFICATE_TYPE type; andre@3: const CK_ATTRIBUTE *attribute; andre@3: andre@3: /* we can't store any certs private */ andre@3: if (lg_isTrue(CKA_PRIVATE, templ, count)) { andre@3: return CKR_ATTRIBUTE_VALUE_INVALID; andre@3: } andre@3: andre@3: /* We only support X.509 Certs for now */ andre@3: crv = lg_GetULongAttribute(CKA_CERTIFICATE_TYPE, templ, count, &type); andre@3: if (crv != CKR_OK) { andre@3: return crv; andre@3: } andre@3: andre@3: if (type != CKC_X_509) { andre@3: return CKR_ATTRIBUTE_VALUE_INVALID; andre@3: } andre@3: andre@3: /* X.509 Certificate */ andre@3: andre@3: andre@3: if (certHandle == NULL) { andre@3: return CKR_TOKEN_WRITE_PROTECTED; andre@3: } andre@3: andre@3: /* get the der cert */ andre@3: attribute = lg_FindAttribute(CKA_VALUE, templ, count); andre@3: if (!attribute) { andre@3: return CKR_ATTRIBUTE_VALUE_INVALID; andre@3: } andre@3: andre@3: derCert.type = 0; andre@3: derCert.data = (unsigned char *)attribute->pValue; andre@3: derCert.len = attribute->ulValueLen ; andre@3: andre@3: label = lg_getString(CKA_LABEL, templ, count); andre@3: andre@3: cert = nsslowcert_FindCertByDERCert(certHandle, &derCert); andre@3: if (cert == NULL) { andre@3: cert = nsslowcert_DecodeDERCertificate(&derCert, label); andre@3: inDB = PR_FALSE; andre@3: } andre@3: if (cert == NULL) { andre@3: if (label) PORT_Free(label); andre@3: return CKR_ATTRIBUTE_VALUE_INVALID; andre@3: } andre@3: andre@3: keyHandle = lg_getKeyDB(sdb); andre@3: if (keyHandle) { andre@3: if (nsslowkey_KeyForCertExists(keyHandle,cert)) { andre@3: trust = &userTrust; andre@3: } andre@3: } andre@3: andre@3: if (!inDB) { andre@3: if (!trust) trust = &defTrust; andre@3: rv = nsslowcert_AddPermCert(certHandle, cert, label, trust); andre@3: } else { andre@3: rv = trust ? nsslowcert_ChangeCertTrust(certHandle,cert,trust) : andre@3: SECSuccess; andre@3: } andre@3: andre@3: if (label) PORT_Free(label); andre@3: andre@3: if (rv != SECSuccess) { andre@3: nsslowcert_DestroyCertificate(cert); andre@3: return CKR_DEVICE_ERROR; andre@3: } andre@3: andre@3: /* andre@3: * Add a NULL S/MIME profile if necessary. andre@3: */ andre@3: email = lg_getString(CKA_NSS_EMAIL, templ, count); andre@3: if (email) { andre@3: certDBEntrySMime *entry; andre@3: andre@3: entry = nsslowcert_ReadDBSMimeEntry(certHandle,email); andre@3: if (!entry) { andre@3: nsslowcert_SaveSMimeProfile(certHandle, email, andre@3: &cert->derSubject, NULL, NULL); andre@3: } else { andre@3: nsslowcert_DestroyDBEntry((certDBEntry *)entry); andre@3: } andre@3: PORT_Free(email); andre@3: } andre@3: *handle=lg_mkHandle(sdb,&cert->certKey,LG_TOKEN_TYPE_CERT); andre@3: nsslowcert_DestroyCertificate(cert); andre@3: andre@3: return CKR_OK; andre@3: } andre@3: andre@3: unsigned int andre@3: lg_MapTrust(CK_TRUST trust, PRBool clientAuth) andre@3: { andre@3: unsigned int trustCA = clientAuth ? CERTDB_TRUSTED_CLIENT_CA : andre@3: CERTDB_TRUSTED_CA; andre@3: switch (trust) { andre@3: case CKT_NSS_TRUSTED: andre@3: return CERTDB_TERMINAL_RECORD|CERTDB_TRUSTED; andre@3: case CKT_NSS_TRUSTED_DELEGATOR: andre@3: return CERTDB_VALID_CA|trustCA; andre@3: case CKT_NSS_MUST_VERIFY_TRUST: andre@3: return CERTDB_MUST_VERIFY; andre@3: case CKT_NSS_NOT_TRUSTED: andre@3: return CERTDB_TERMINAL_RECORD; andre@3: case CKT_NSS_VALID_DELEGATOR: /* implies must verify */ andre@3: return CERTDB_VALID_CA; andre@3: default: andre@3: break; andre@3: } andre@3: return CERTDB_TRUSTED_UNKNOWN; andre@3: } andre@3: andre@3: andre@3: /* andre@3: * check the consistancy and initialize a Trust Object andre@3: */ andre@3: static CK_RV andre@3: lg_createTrustObject(SDB *sdb, CK_OBJECT_HANDLE *handle, andre@3: const CK_ATTRIBUTE *templ, CK_ULONG count) andre@3: { andre@3: const CK_ATTRIBUTE *issuer = NULL; andre@3: const CK_ATTRIBUTE *serial = NULL; andre@3: NSSLOWCERTCertificate *cert = NULL; andre@3: const CK_ATTRIBUTE *trust; andre@3: CK_TRUST sslTrust = CKT_NSS_TRUST_UNKNOWN; andre@3: CK_TRUST clientTrust = CKT_NSS_TRUST_UNKNOWN; andre@3: CK_TRUST emailTrust = CKT_NSS_TRUST_UNKNOWN; andre@3: CK_TRUST signTrust = CKT_NSS_TRUST_UNKNOWN; andre@3: CK_BBOOL stepUp; andre@3: NSSLOWCERTCertTrust dbTrust = { 0 }; andre@3: SECStatus rv; andre@3: NSSLOWCERTCertDBHandle *certHandle = lg_getCertDB(sdb); andre@3: NSSLOWCERTIssuerAndSN issuerSN; andre@3: andre@3: /* we can't store any certs private */ andre@3: if (lg_isTrue(CKA_PRIVATE, templ, count)) { andre@3: return CKR_ATTRIBUTE_VALUE_INVALID; andre@3: } andre@3: andre@3: if (certHandle == NULL) { andre@3: return CKR_TOKEN_WRITE_PROTECTED; andre@3: } andre@3: andre@3: issuer = lg_FindAttribute(CKA_ISSUER, templ, count); andre@3: serial = lg_FindAttribute(CKA_SERIAL_NUMBER, templ, count); andre@3: andre@3: if (issuer && serial) { andre@3: issuerSN.derIssuer.data = (unsigned char *)issuer->pValue; andre@3: issuerSN.derIssuer.len = issuer->ulValueLen ; andre@3: andre@3: issuerSN.serialNumber.data = (unsigned char *)serial->pValue; andre@3: issuerSN.serialNumber.len = serial->ulValueLen ; andre@3: andre@3: cert = nsslowcert_FindCertByIssuerAndSN(certHandle,&issuerSN); andre@3: } andre@3: andre@3: if (cert == NULL) { andre@3: return CKR_ATTRIBUTE_VALUE_INVALID; andre@3: } andre@3: andre@3: lg_GetULongAttribute(CKA_TRUST_SERVER_AUTH, templ, count, &sslTrust); andre@3: lg_GetULongAttribute(CKA_TRUST_CLIENT_AUTH, templ, count, &clientTrust); andre@3: lg_GetULongAttribute(CKA_TRUST_EMAIL_PROTECTION, templ, count, &emailTrust); andre@3: lg_GetULongAttribute(CKA_TRUST_CODE_SIGNING, templ, count, &signTrust); andre@3: stepUp = CK_FALSE; andre@3: trust = lg_FindAttribute(CKA_TRUST_STEP_UP_APPROVED, templ, count); andre@3: if (trust) { andre@3: if (trust->ulValueLen == sizeof(CK_BBOOL)) { andre@3: stepUp = *(CK_BBOOL*)trust->pValue; andre@3: } andre@3: } andre@3: andre@3: /* preserve certain old fields */ andre@3: if (cert->trust) { andre@3: dbTrust.sslFlags = cert->trust->sslFlags & CERTDB_PRESERVE_TRUST_BITS; andre@3: dbTrust.emailFlags= andre@3: cert->trust->emailFlags & CERTDB_PRESERVE_TRUST_BITS; andre@3: dbTrust.objectSigningFlags = andre@3: cert->trust->objectSigningFlags & CERTDB_PRESERVE_TRUST_BITS; andre@3: } andre@3: andre@3: dbTrust.sslFlags |= lg_MapTrust(sslTrust,PR_FALSE); andre@3: dbTrust.sslFlags |= lg_MapTrust(clientTrust,PR_TRUE); andre@3: dbTrust.emailFlags |= lg_MapTrust(emailTrust,PR_FALSE); andre@3: dbTrust.objectSigningFlags |= lg_MapTrust(signTrust,PR_FALSE); andre@3: if (stepUp) { andre@3: dbTrust.sslFlags |= CERTDB_GOVT_APPROVED_CA; andre@3: } andre@3: andre@3: rv = nsslowcert_ChangeCertTrust(certHandle,cert,&dbTrust); andre@3: *handle=lg_mkHandle(sdb,&cert->certKey,LG_TOKEN_TYPE_TRUST); andre@3: nsslowcert_DestroyCertificate(cert); andre@3: if (rv != SECSuccess) { andre@3: return CKR_DEVICE_ERROR; andre@3: } andre@3: andre@3: return CKR_OK; andre@3: } andre@3: andre@3: /* andre@3: * check the consistancy and initialize a Trust Object andre@3: */ andre@3: static CK_RV andre@3: lg_createSMimeObject(SDB *sdb, CK_OBJECT_HANDLE *handle, andre@3: const CK_ATTRIBUTE *templ, CK_ULONG count) andre@3: { andre@3: SECItem derSubj,rawProfile,rawTime,emailKey; andre@3: SECItem *pRawProfile = NULL; andre@3: SECItem *pRawTime = NULL; andre@3: char *email = NULL; andre@3: const CK_ATTRIBUTE *subject = NULL, andre@3: *profile = NULL, andre@3: *time = NULL; andre@3: SECStatus rv; andre@3: NSSLOWCERTCertDBHandle *certHandle; andre@3: CK_RV ck_rv = CKR_OK; andre@3: andre@3: /* we can't store any certs private */ andre@3: if (lg_isTrue(CKA_PRIVATE,templ,count)) { andre@3: return CKR_ATTRIBUTE_VALUE_INVALID; andre@3: } andre@3: andre@3: certHandle = lg_getCertDB(sdb); andre@3: if (certHandle == NULL) { andre@3: return CKR_TOKEN_WRITE_PROTECTED; andre@3: } andre@3: andre@3: /* lookup SUBJECT */ andre@3: subject = lg_FindAttribute(CKA_SUBJECT,templ,count); andre@3: PORT_Assert(subject); andre@3: if (!subject) { andre@3: ck_rv = CKR_ATTRIBUTE_VALUE_INVALID; andre@3: goto loser; andre@3: } andre@3: andre@3: derSubj.data = (unsigned char *)subject->pValue; andre@3: derSubj.len = subject->ulValueLen ; andre@3: derSubj.type = 0; andre@3: andre@3: /* lookup VALUE */ andre@3: profile = lg_FindAttribute(CKA_VALUE,templ,count); andre@3: if (profile) { andre@3: rawProfile.data = (unsigned char *)profile->pValue; andre@3: rawProfile.len = profile->ulValueLen ; andre@3: rawProfile.type = siBuffer; andre@3: pRawProfile = &rawProfile; andre@3: } andre@3: andre@3: /* lookup Time */ andre@3: time = lg_FindAttribute(CKA_NSS_SMIME_TIMESTAMP,templ,count); andre@3: if (time) { andre@3: rawTime.data = (unsigned char *)time->pValue; andre@3: rawTime.len = time->ulValueLen ; andre@3: rawTime.type = siBuffer; andre@3: pRawTime = &rawTime; andre@3: } andre@3: andre@3: andre@3: email = lg_getString(CKA_NSS_EMAIL,templ,count); andre@3: if (!email) { andre@3: ck_rv = CKR_ATTRIBUTE_VALUE_INVALID; andre@3: goto loser; andre@3: } andre@3: andre@3: /* Store S/MIME Profile by SUBJECT */ andre@3: rv = nsslowcert_SaveSMimeProfile(certHandle, email, &derSubj, andre@3: pRawProfile,pRawTime); andre@3: if (rv != SECSuccess) { andre@3: ck_rv = CKR_DEVICE_ERROR; andre@3: goto loser; andre@3: } andre@3: emailKey.data = (unsigned char *)email; andre@3: emailKey.len = PORT_Strlen(email)+1; andre@3: andre@3: *handle = lg_mkHandle(sdb, &emailKey, LG_TOKEN_TYPE_SMIME); andre@3: andre@3: loser: andre@3: if (email) PORT_Free(email); andre@3: andre@3: return ck_rv; andre@3: } andre@3: andre@3: /* andre@3: * check the consistancy and initialize a Trust Object andre@3: */ andre@3: static CK_RV andre@3: lg_createCrlObject(SDB *sdb, CK_OBJECT_HANDLE *handle, andre@3: const CK_ATTRIBUTE *templ, CK_ULONG count) andre@3: { andre@3: PRBool isKRL = PR_FALSE; andre@3: SECItem derSubj,derCrl; andre@3: char *url = NULL; andre@3: const CK_ATTRIBUTE *subject,*crl; andre@3: SECStatus rv; andre@3: NSSLOWCERTCertDBHandle *certHandle; andre@3: andre@3: certHandle = lg_getCertDB(sdb); andre@3: andre@3: /* we can't store any private crls */ andre@3: if (lg_isTrue(CKA_PRIVATE,templ,count)) { andre@3: return CKR_ATTRIBUTE_VALUE_INVALID; andre@3: } andre@3: andre@3: if (certHandle == NULL) { andre@3: return CKR_TOKEN_WRITE_PROTECTED; andre@3: } andre@3: andre@3: /* lookup SUBJECT */ andre@3: subject = lg_FindAttribute(CKA_SUBJECT,templ,count); andre@3: if (!subject) { andre@3: return CKR_ATTRIBUTE_VALUE_INVALID; andre@3: } andre@3: andre@3: derSubj.data = (unsigned char *)subject->pValue; andre@3: derSubj.len = subject->ulValueLen ; andre@3: andre@3: /* lookup VALUE */ andre@3: crl = lg_FindAttribute(CKA_VALUE,templ,count); andre@3: PORT_Assert(crl); andre@3: if (!crl) { andre@3: return CKR_ATTRIBUTE_VALUE_INVALID; andre@3: } andre@3: derCrl.data = (unsigned char *)crl->pValue; andre@3: derCrl.len = crl->ulValueLen ; andre@3: andre@3: url = lg_getString(CKA_NSS_URL,templ,count); andre@3: isKRL = lg_isTrue(CKA_NSS_KRL,templ,count); andre@3: andre@3: /* Store CRL by SUBJECT */ andre@3: rv = nsslowcert_AddCrl(certHandle, &derCrl, &derSubj, url, isKRL); andre@3: andre@3: if (url) { andre@3: PORT_Free(url); andre@3: } andre@3: if (rv != SECSuccess) { andre@3: return CKR_DEVICE_ERROR; andre@3: } andre@3: andre@3: /* if we overwrote the existing CRL, poison the handle entry so we get andre@3: * a new object handle */ andre@3: (void) lg_poisonHandle(sdb, &derSubj, andre@3: isKRL ? LG_TOKEN_KRL_HANDLE : LG_TOKEN_TYPE_CRL); andre@3: *handle = lg_mkHandle(sdb, &derSubj, andre@3: isKRL ? LG_TOKEN_KRL_HANDLE : LG_TOKEN_TYPE_CRL); andre@3: andre@3: return CKR_OK; andre@3: } andre@3: andre@3: /* andre@3: * check the consistancy and initialize a Public Key Object andre@3: */ andre@3: static CK_RV andre@3: lg_createPublicKeyObject(SDB *sdb, CK_KEY_TYPE key_type, andre@3: CK_OBJECT_HANDLE *handle, const CK_ATTRIBUTE *templ, CK_ULONG count) andre@3: { andre@3: CK_ATTRIBUTE_TYPE pubKeyAttr = CKA_VALUE; andre@3: CK_RV crv = CKR_OK; andre@3: NSSLOWKEYPrivateKey *priv; andre@3: SECItem pubKeySpace = {siBuffer, NULL, 0}; andre@3: SECItem *pubKey; andre@3: #ifndef NSS_DISABLE_ECC andre@3: SECItem pubKey2Space = {siBuffer, NULL, 0}; andre@3: PLArenaPool *arena = NULL; andre@3: #endif /* NSS_DISABLE_ECC */ andre@3: NSSLOWKEYDBHandle *keyHandle = NULL; andre@3: andre@3: andre@3: switch (key_type) { andre@3: case CKK_RSA: andre@3: pubKeyAttr = CKA_MODULUS; andre@3: break; andre@3: #ifndef NSS_DISABLE_ECC andre@3: case CKK_EC: andre@3: pubKeyAttr = CKA_EC_POINT; andre@3: break; andre@3: #endif /* NSS_DISABLE_ECC */ andre@3: case CKK_DSA: andre@3: case CKK_DH: andre@3: break; andre@3: default: andre@3: return CKR_ATTRIBUTE_VALUE_INVALID; andre@3: } andre@3: andre@3: andre@3: pubKey = &pubKeySpace; andre@3: crv = lg_Attribute2SSecItem(NULL,pubKeyAttr,templ,count,pubKey); andre@3: if (crv != CKR_OK) return crv; andre@3: andre@3: #ifndef NSS_DISABLE_ECC andre@3: if (key_type == CKK_EC) { andre@3: SECStatus rv; andre@3: /* andre@3: * for ECC, use the decoded key first. andre@3: */ andre@3: arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); andre@3: if (arena == NULL) { andre@3: crv = CKR_HOST_MEMORY; andre@3: goto done; andre@3: } andre@3: rv= SEC_QuickDERDecodeItem(arena, &pubKey2Space, andre@3: SEC_ASN1_GET(SEC_OctetStringTemplate), andre@3: pubKey); andre@3: if (rv != SECSuccess) { andre@3: /* decode didn't work, just try the pubKey */ andre@3: PORT_FreeArena(arena, PR_FALSE); andre@3: arena = NULL; andre@3: } else { andre@3: /* try the decoded pub key first */ andre@3: pubKey = &pubKey2Space; andre@3: } andre@3: } andre@3: #endif /* NSS_DISABLE_ECC */ andre@3: andre@3: PORT_Assert(pubKey->data); andre@3: if (pubKey->data == NULL) { andre@3: crv = CKR_ATTRIBUTE_VALUE_INVALID; andre@3: goto done; andre@3: } andre@3: keyHandle = lg_getKeyDB(sdb); andre@3: if (keyHandle == NULL) { andre@3: crv = CKR_TOKEN_WRITE_PROTECTED; andre@3: goto done; andre@3: } andre@3: if (keyHandle->version != 3) { andre@3: unsigned char buf[SHA1_LENGTH]; andre@3: SHA1_HashBuf(buf,pubKey->data,pubKey->len); andre@3: PORT_Memcpy(pubKey->data,buf,sizeof(buf)); andre@3: pubKey->len = sizeof(buf); andre@3: } andre@3: /* make sure the associated private key already exists */ andre@3: /* only works if we are logged in */ andre@3: priv = nsslowkey_FindKeyByPublicKey(keyHandle, pubKey, sdb /*password*/); andre@3: #ifndef NSS_DISABLE_ECC andre@3: if (priv == NULL && pubKey == &pubKey2Space) { andre@3: /* no match on the decoded key, match the original pubkey */ andre@3: pubKey = &pubKeySpace; andre@3: priv = nsslowkey_FindKeyByPublicKey(keyHandle, pubKey, andre@3: sdb /*password*/); andre@3: } andre@3: #endif andre@3: if (priv == NULL) { andre@3: /* the legacy database can only 'store' public keys which already andre@3: * have their corresponding private keys in the database */ andre@3: crv = CKR_ATTRIBUTE_VALUE_INVALID; andre@3: goto done; andre@3: } andre@3: lg_nsslowkey_DestroyPrivateKey(priv); andre@3: crv = CKR_OK; andre@3: andre@3: *handle = lg_mkHandle(sdb, pubKey, LG_TOKEN_TYPE_PUB); andre@3: andre@3: done: andre@3: PORT_Free(pubKeySpace.data); andre@3: #ifndef NSS_DISABLE_ECC andre@3: if (arena) andre@3: PORT_FreeArena(arena, PR_FALSE); andre@3: #endif andre@3: andre@3: return crv; andre@3: } andre@3: andre@3: /* make a private key from a verified object */ andre@3: static NSSLOWKEYPrivateKey * andre@3: lg_mkPrivKey(SDB *sdb, const CK_ATTRIBUTE *templ, CK_ULONG count, andre@3: CK_KEY_TYPE key_type, CK_RV *crvp) andre@3: { andre@3: NSSLOWKEYPrivateKey *privKey; andre@3: PLArenaPool *arena; andre@3: CK_RV crv = CKR_OK; andre@3: SECStatus rv; andre@3: andre@3: arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); andre@3: if (arena == NULL) { andre@3: *crvp = CKR_HOST_MEMORY; andre@3: return NULL; andre@3: } andre@3: andre@3: privKey = (NSSLOWKEYPrivateKey *) andre@3: PORT_ArenaZAlloc(arena,sizeof(NSSLOWKEYPrivateKey)); andre@3: if (privKey == NULL) { andre@3: PORT_FreeArena(arena,PR_FALSE); andre@3: *crvp = CKR_HOST_MEMORY; andre@3: return NULL; andre@3: } andre@3: andre@3: /* in future this would be a switch on key_type */ andre@3: privKey->arena = arena; andre@3: switch (key_type) { andre@3: case CKK_RSA: andre@3: privKey->keyType = NSSLOWKEYRSAKey; andre@3: crv=lg_Attribute2SSecItem(arena,CKA_MODULUS,templ,count, andre@3: &privKey->u.rsa.modulus); andre@3: if (crv != CKR_OK) break; andre@3: crv=lg_Attribute2SSecItem(arena,CKA_PUBLIC_EXPONENT,templ,count, andre@3: &privKey->u.rsa.publicExponent); andre@3: if (crv != CKR_OK) break; andre@3: crv=lg_PrivAttr2SSecItem(arena,CKA_PRIVATE_EXPONENT,templ,count, andre@3: &privKey->u.rsa.privateExponent, sdb); andre@3: if (crv != CKR_OK) break; andre@3: crv=lg_PrivAttr2SSecItem(arena,CKA_PRIME_1,templ,count, andre@3: &privKey->u.rsa.prime1, sdb); andre@3: if (crv != CKR_OK) break; andre@3: crv=lg_PrivAttr2SSecItem(arena,CKA_PRIME_2,templ,count, andre@3: &privKey->u.rsa.prime2, sdb); andre@3: if (crv != CKR_OK) break; andre@3: crv=lg_PrivAttr2SSecItem(arena,CKA_EXPONENT_1,templ,count, andre@3: &privKey->u.rsa.exponent1, sdb); andre@3: if (crv != CKR_OK) break; andre@3: crv=lg_PrivAttr2SSecItem(arena,CKA_EXPONENT_2,templ,count, andre@3: &privKey->u.rsa.exponent2, sdb); andre@3: if (crv != CKR_OK) break; andre@3: crv=lg_PrivAttr2SSecItem(arena,CKA_COEFFICIENT,templ,count, andre@3: &privKey->u.rsa.coefficient, sdb); andre@3: if (crv != CKR_OK) break; andre@3: rv = DER_SetUInteger(privKey->arena, &privKey->u.rsa.version, andre@3: NSSLOWKEY_VERSION); andre@3: if (rv != SECSuccess) crv = CKR_HOST_MEMORY; andre@3: break; andre@3: andre@3: case CKK_DSA: andre@3: privKey->keyType = NSSLOWKEYDSAKey; andre@3: crv = lg_Attribute2SSecItem(arena,CKA_PRIME,templ,count, andre@3: &privKey->u.dsa.params.prime); andre@3: if (crv != CKR_OK) break; andre@3: crv = lg_Attribute2SSecItem(arena,CKA_SUBPRIME,templ,count, andre@3: &privKey->u.dsa.params.subPrime); andre@3: if (crv != CKR_OK) break; andre@3: crv = lg_Attribute2SSecItem(arena,CKA_BASE,templ,count, andre@3: &privKey->u.dsa.params.base); andre@3: if (crv != CKR_OK) break; andre@3: crv = lg_PrivAttr2SSecItem(arena,CKA_VALUE,templ,count, andre@3: &privKey->u.dsa.privateValue, sdb); andre@3: if (crv != CKR_OK) break; andre@3: if (lg_hasAttribute(CKA_NETSCAPE_DB, templ,count)) { andre@3: crv = lg_Attribute2SSecItem(arena, CKA_NETSCAPE_DB,templ,count, andre@3: &privKey->u.dsa.publicValue); andre@3: /* privKey was zero'd so public value is already set to NULL, 0 andre@3: * if we don't set it explicitly */ andre@3: } andre@3: break; andre@3: andre@3: case CKK_DH: andre@3: privKey->keyType = NSSLOWKEYDHKey; andre@3: crv = lg_Attribute2SSecItem(arena,CKA_PRIME,templ,count, andre@3: &privKey->u.dh.prime); andre@3: if (crv != CKR_OK) break; andre@3: crv = lg_Attribute2SSecItem(arena,CKA_BASE,templ,count, andre@3: &privKey->u.dh.base); andre@3: if (crv != CKR_OK) break; andre@3: crv = lg_PrivAttr2SSecItem(arena,CKA_VALUE,templ,count, andre@3: &privKey->u.dh.privateValue, sdb); andre@3: if (crv != CKR_OK) break; andre@3: if (lg_hasAttribute(CKA_NETSCAPE_DB, templ, count)) { andre@3: crv = lg_Attribute2SSecItem(arena, CKA_NETSCAPE_DB,templ,count, andre@3: &privKey->u.dh.publicValue); andre@3: /* privKey was zero'd so public value is already set to NULL, 0 andre@3: * if we don't set it explicitly */ andre@3: } andre@3: break; andre@3: andre@3: #ifndef NSS_DISABLE_ECC andre@3: case CKK_EC: andre@3: privKey->keyType = NSSLOWKEYECKey; andre@3: crv = lg_Attribute2SSecItem(arena, CKA_EC_PARAMS,templ,count, andre@3: &privKey->u.ec.ecParams.DEREncoding); andre@3: if (crv != CKR_OK) break; andre@3: andre@3: /* Fill out the rest of the ecParams structure andre@3: * based on the encoded params andre@3: */ andre@3: if (LGEC_FillParams(arena, &privKey->u.ec.ecParams.DEREncoding, andre@3: &privKey->u.ec.ecParams) != SECSuccess) { andre@3: crv = CKR_DOMAIN_PARAMS_INVALID; andre@3: break; andre@3: } andre@3: crv = lg_PrivAttr2SSecItem(arena,CKA_VALUE,templ,count, andre@3: &privKey->u.ec.privateValue, sdb); andre@3: if (crv != CKR_OK) break; andre@3: if (lg_hasAttribute(CKA_NETSCAPE_DB,templ,count)) { andre@3: crv = lg_Attribute2SSecItem(arena, CKA_NETSCAPE_DB,templ,count, andre@3: &privKey->u.ec.publicValue); andre@3: if (crv != CKR_OK) break; andre@3: /* privKey was zero'd so public value is already set to NULL, 0 andre@3: * if we don't set it explicitly */ andre@3: } andre@3: rv = DER_SetUInteger(privKey->arena, &privKey->u.ec.version, andre@3: NSSLOWKEY_EC_PRIVATE_KEY_VERSION); andre@3: if (rv != SECSuccess) crv = CKR_HOST_MEMORY; andre@3: break; andre@3: #endif /* NSS_DISABLE_ECC */ andre@3: andre@3: default: andre@3: crv = CKR_KEY_TYPE_INCONSISTENT; andre@3: break; andre@3: } andre@3: *crvp = crv; andre@3: if (crv != CKR_OK) { andre@3: PORT_FreeArena(arena,PR_FALSE); andre@3: return NULL; andre@3: } andre@3: return privKey; andre@3: } andre@3: andre@3: /* andre@3: * check the consistancy and initialize a Private Key Object andre@3: */ andre@3: static CK_RV andre@3: lg_createPrivateKeyObject(SDB *sdb, CK_KEY_TYPE key_type, andre@3: CK_OBJECT_HANDLE *handle, const CK_ATTRIBUTE *templ, CK_ULONG count) andre@3: { andre@3: NSSLOWKEYPrivateKey *privKey; andre@3: char *label; andre@3: SECStatus rv = SECSuccess; andre@3: CK_RV crv = CKR_DEVICE_ERROR; andre@3: SECItem pubKey; andre@3: NSSLOWKEYDBHandle *keyHandle = lg_getKeyDB(sdb); andre@3: andre@3: if (keyHandle == NULL) { andre@3: return CKR_TOKEN_WRITE_PROTECTED; andre@3: } andre@3: andre@3: privKey=lg_mkPrivKey(sdb, templ,count,key_type,&crv); andre@3: if (privKey == NULL) return crv; andre@3: label = lg_getString(CKA_LABEL,templ,count); andre@3: andre@3: crv = lg_Attribute2SSecItem(NULL,CKA_NETSCAPE_DB,templ,count,&pubKey); andre@3: if (crv != CKR_OK) { andre@3: crv = CKR_TEMPLATE_INCOMPLETE; andre@3: rv = SECFailure; andre@3: goto fail; andre@3: } andre@3: #ifdef notdef andre@3: if (keyHandle->version != 3) { andre@3: unsigned char buf[SHA1_LENGTH]; andre@3: SHA1_HashBuf(buf,pubKey.data,pubKey.len); andre@3: PORT_Memcpy(pubKey.data,buf,sizeof(buf)); andre@3: pubKey.len = sizeof(buf); andre@3: } andre@3: #endif andre@3: /* get the key type */ andre@3: if (key_type == CKK_RSA) { andre@3: rv = RSA_PrivateKeyCheck(&privKey->u.rsa); andre@3: if (rv == SECFailure) { andre@3: goto fail; andre@3: } andre@3: } andre@3: rv = nsslowkey_StoreKeyByPublicKey(keyHandle, privKey, &pubKey, andre@3: label, sdb /*->password*/); andre@3: andre@3: fail: andre@3: if (label) PORT_Free(label); andre@3: *handle = lg_mkHandle(sdb,&pubKey,LG_TOKEN_TYPE_PRIV); andre@3: if (pubKey.data) PORT_Free(pubKey.data); andre@3: lg_nsslowkey_DestroyPrivateKey(privKey); andre@3: if (rv != SECSuccess) return crv; andre@3: andre@3: return CKR_OK; andre@3: } andre@3: andre@3: andre@3: #define LG_KEY_MAX_RETRIES 10 /* don't hang if we are having problems with the rng */ andre@3: #define LG_KEY_ID_SIZE 18 /* don't use either SHA1 or MD5 sizes */ andre@3: /* andre@3: * Secret keys must have a CKA_ID value to be stored in the database. This code andre@3: * will generate one if there wasn't one already. andre@3: */ andre@3: static CK_RV andre@3: lg_GenerateSecretCKA_ID(NSSLOWKEYDBHandle *handle, SECItem *id, char *label) andre@3: { andre@3: unsigned int retries; andre@3: SECStatus rv = SECSuccess; andre@3: CK_RV crv = CKR_OK; andre@3: andre@3: id->data = NULL; andre@3: if (label) { andre@3: id->data = (unsigned char *)PORT_Strdup(label); andre@3: if (id->data == NULL) { andre@3: return CKR_HOST_MEMORY; andre@3: } andre@3: id->len = PORT_Strlen(label)+1; andre@3: if (!nsslowkey_KeyForIDExists(handle,id)) { andre@3: return CKR_OK; andre@3: } andre@3: PORT_Free(id->data); andre@3: id->data = NULL; andre@3: id->len = 0; andre@3: } andre@3: id->data = (unsigned char *)PORT_Alloc(LG_KEY_ID_SIZE); andre@3: if (id->data == NULL) { andre@3: return CKR_HOST_MEMORY; andre@3: } andre@3: id->len = LG_KEY_ID_SIZE; andre@3: andre@3: retries = 0; andre@3: do { andre@3: rv = RNG_GenerateGlobalRandomBytes(id->data,id->len); andre@3: } while (rv == SECSuccess && nsslowkey_KeyForIDExists(handle,id) && andre@3: (++retries <= LG_KEY_MAX_RETRIES)); andre@3: andre@3: if ((rv != SECSuccess) || (retries > LG_KEY_MAX_RETRIES)) { andre@3: crv = CKR_DEVICE_ERROR; /* random number generator is bad */ andre@3: PORT_Free(id->data); andre@3: id->data = NULL; andre@3: id->len = 0; andre@3: } andre@3: return crv; andre@3: } andre@3: andre@3: andre@3: static NSSLOWKEYPrivateKey *lg_mkSecretKeyRep(const CK_ATTRIBUTE *templ, andre@3: CK_ULONG count, CK_KEY_TYPE key_type, andre@3: SECItem *pubkey, SDB *sdbpw) andre@3: { andre@3: NSSLOWKEYPrivateKey *privKey = 0; andre@3: PLArenaPool *arena = 0; andre@3: CK_KEY_TYPE keyType; andre@3: PRUint32 keyTypeStorage; andre@3: SECItem keyTypeItem; andre@3: CK_RV crv; andre@3: SECStatus rv; andre@3: static unsigned char derZero[1] = { 0 }; andre@3: andre@3: arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); andre@3: if (arena == NULL) { crv = CKR_HOST_MEMORY; goto loser; } andre@3: andre@3: privKey = (NSSLOWKEYPrivateKey *) andre@3: PORT_ArenaZAlloc(arena,sizeof(NSSLOWKEYPrivateKey)); andre@3: if (privKey == NULL) { crv = CKR_HOST_MEMORY; goto loser; } andre@3: andre@3: privKey->arena = arena; andre@3: andre@3: /* Secret keys are represented in the database as "fake" RSA keys. andre@3: * The RSA key is marked as a secret key representation by setting the andre@3: * public exponent field to 0, which is an invalid RSA exponent. andre@3: * The other fields are set as follows: andre@3: * modulus - CKA_ID value for the secret key andre@3: * private exponent - CKA_VALUE (the key itself) andre@3: * coefficient - CKA_KEY_TYPE, which indicates what encryption algorithm andre@3: * is used for the key. andre@3: * all others - set to integer 0 andre@3: */ andre@3: privKey->keyType = NSSLOWKEYRSAKey; andre@3: andre@3: /* The modulus is set to the key id of the symmetric key */ andre@3: privKey->u.rsa.modulus.data = andre@3: (unsigned char *) PORT_ArenaAlloc(arena, pubkey->len); andre@3: if (privKey->u.rsa.modulus.data == NULL) { andre@3: crv = CKR_HOST_MEMORY; andre@3: goto loser; andre@3: } andre@3: privKey->u.rsa.modulus.len = pubkey->len; andre@3: PORT_Memcpy(privKey->u.rsa.modulus.data, pubkey->data, pubkey->len); andre@3: andre@3: /* The public exponent is set to 0 to indicate a special key */ andre@3: privKey->u.rsa.publicExponent.len = sizeof derZero; andre@3: privKey->u.rsa.publicExponent.data = derZero; andre@3: andre@3: /* The private exponent is the actual key value */ andre@3: crv = lg_PrivAttr2SecItem(arena, CKA_VALUE, templ, count, andre@3: &privKey->u.rsa.privateExponent, sdbpw); andre@3: if (crv != CKR_OK) goto loser; andre@3: andre@3: /* All other fields empty - needs testing */ andre@3: privKey->u.rsa.prime1.len = sizeof derZero; andre@3: privKey->u.rsa.prime1.data = derZero; andre@3: andre@3: privKey->u.rsa.prime2.len = sizeof derZero; andre@3: privKey->u.rsa.prime2.data = derZero; andre@3: andre@3: privKey->u.rsa.exponent1.len = sizeof derZero; andre@3: privKey->u.rsa.exponent1.data = derZero; andre@3: andre@3: privKey->u.rsa.exponent2.len = sizeof derZero; andre@3: privKey->u.rsa.exponent2.data = derZero; andre@3: andre@3: /* Coeficient set to KEY_TYPE */ andre@3: crv = lg_GetULongAttribute(CKA_KEY_TYPE, templ, count, &keyType); andre@3: if (crv != CKR_OK) goto loser; andre@3: /* on 64 bit platforms, we still want to store 32 bits of keyType (This is andre@3: * safe since the PKCS #11 defines for all types are 32 bits or less). */ andre@3: keyTypeStorage = (PRUint32) keyType; andre@3: keyTypeStorage = PR_htonl(keyTypeStorage); andre@3: keyTypeItem.data = (unsigned char *)&keyTypeStorage; andre@3: keyTypeItem.len = sizeof (keyTypeStorage); andre@3: rv = SECITEM_CopyItem(arena, &privKey->u.rsa.coefficient, &keyTypeItem); andre@3: if (rv != SECSuccess) { andre@3: crv = CKR_HOST_MEMORY; andre@3: goto loser; andre@3: } andre@3: andre@3: /* Private key version field set normally for compatibility */ andre@3: rv = DER_SetUInteger(privKey->arena, andre@3: &privKey->u.rsa.version, NSSLOWKEY_VERSION); andre@3: if (rv != SECSuccess) { crv = CKR_HOST_MEMORY; goto loser; } andre@3: andre@3: loser: andre@3: if (crv != CKR_OK) { andre@3: PORT_FreeArena(arena,PR_FALSE); andre@3: privKey = 0; andre@3: } andre@3: andre@3: return privKey; andre@3: } andre@3: andre@3: /* andre@3: * check the consistancy and initialize a Secret Key Object andre@3: */ andre@3: static CK_RV andre@3: lg_createSecretKeyObject(SDB *sdb, CK_KEY_TYPE key_type, andre@3: CK_OBJECT_HANDLE *handle, const CK_ATTRIBUTE *templ, CK_ULONG count) andre@3: { andre@3: CK_RV crv; andre@3: NSSLOWKEYPrivateKey *privKey = NULL; andre@3: NSSLOWKEYDBHandle *keyHandle = NULL; andre@3: SECItem pubKey; andre@3: char *label = NULL; andre@3: SECStatus rv = SECSuccess; andre@3: andre@3: pubKey.data = 0; andre@3: andre@3: /* If the object is a TOKEN object, store in the database */ andre@3: keyHandle = lg_getKeyDB(sdb); andre@3: andre@3: if (keyHandle == NULL) { andre@3: return CKR_TOKEN_WRITE_PROTECTED; andre@3: } andre@3: andre@3: label = lg_getString(CKA_LABEL,templ,count); andre@3: andre@3: crv = lg_Attribute2SecItem(NULL,CKA_ID,templ,count,&pubKey); andre@3: /* Should this be ID? */ andre@3: if (crv != CKR_OK) goto loser; andre@3: andre@3: /* if we don't have an ID, generate one */ andre@3: if (pubKey.len == 0) { andre@3: if (pubKey.data) { andre@3: PORT_Free(pubKey.data); andre@3: pubKey.data = NULL; andre@3: } andre@3: crv = lg_GenerateSecretCKA_ID(keyHandle, &pubKey, label); andre@3: if (crv != CKR_OK) goto loser; andre@3: } andre@3: andre@3: privKey = lg_mkSecretKeyRep(templ, count, key_type, &pubKey, sdb); andre@3: if (privKey == NULL) { andre@3: crv = CKR_HOST_MEMORY; andre@3: goto loser; andre@3: } andre@3: andre@3: rv = nsslowkey_StoreKeyByPublicKey(keyHandle, andre@3: privKey, &pubKey, label, sdb /*->password*/); andre@3: if (rv != SECSuccess) { andre@3: crv = CKR_DEVICE_ERROR; andre@3: goto loser; andre@3: } andre@3: andre@3: *handle = lg_mkHandle(sdb, &pubKey, LG_TOKEN_TYPE_KEY); andre@3: andre@3: loser: andre@3: if (label) PORT_Free(label); andre@3: if (privKey) lg_nsslowkey_DestroyPrivateKey(privKey); andre@3: if (pubKey.data) PORT_Free(pubKey.data); andre@3: andre@3: return crv; andre@3: } andre@3: andre@3: /* andre@3: * check the consistancy and initialize a Key Object andre@3: */ andre@3: static CK_RV andre@3: lg_createKeyObject(SDB *sdb, CK_OBJECT_CLASS objclass, andre@3: CK_OBJECT_HANDLE *handle, const CK_ATTRIBUTE *templ, CK_ULONG count) andre@3: { andre@3: CK_RV crv; andre@3: CK_KEY_TYPE key_type; andre@3: andre@3: /* get the key type */ andre@3: crv = lg_GetULongAttribute(CKA_KEY_TYPE, templ, count, &key_type); andre@3: if (crv != CKR_OK) { andre@3: return crv; andre@3: } andre@3: andre@3: switch (objclass) { andre@3: case CKO_PUBLIC_KEY: andre@3: return lg_createPublicKeyObject(sdb,key_type,handle,templ,count); andre@3: case CKO_PRIVATE_KEY: andre@3: return lg_createPrivateKeyObject(sdb,key_type,handle,templ,count); andre@3: case CKO_SECRET_KEY: andre@3: return lg_createSecretKeyObject(sdb,key_type,handle,templ,count); andre@3: default: andre@3: break; andre@3: } andre@3: return CKR_ATTRIBUTE_VALUE_INVALID; andre@3: } andre@3: andre@3: /* andre@3: * Parse the template and create an object stored in the DB that reflects. andre@3: * the object specified in the database. andre@3: */ andre@3: CK_RV andre@3: lg_CreateObject(SDB *sdb, CK_OBJECT_HANDLE *handle, andre@3: const CK_ATTRIBUTE *templ, CK_ULONG count) andre@3: { andre@3: CK_RV crv; andre@3: CK_OBJECT_CLASS objclass; andre@3: andre@3: /* get the object class */ andre@3: crv = lg_GetULongAttribute(CKA_CLASS, templ, count, &objclass); andre@3: if (crv != CKR_OK) { andre@3: return crv; andre@3: } andre@3: andre@3: /* Now handle the specific object class. andre@3: */ andre@3: switch (objclass) { andre@3: case CKO_CERTIFICATE: andre@3: crv = lg_createCertObject(sdb,handle,templ,count); andre@3: break; andre@3: case CKO_NSS_TRUST: andre@3: crv = lg_createTrustObject(sdb,handle,templ,count); andre@3: break; andre@3: case CKO_NSS_CRL: andre@3: crv = lg_createCrlObject(sdb,handle,templ,count); andre@3: break; andre@3: case CKO_NSS_SMIME: andre@3: crv = lg_createSMimeObject(sdb,handle,templ,count); andre@3: break; andre@3: case CKO_PRIVATE_KEY: andre@3: case CKO_PUBLIC_KEY: andre@3: case CKO_SECRET_KEY: andre@3: crv = lg_createKeyObject(sdb,objclass,handle,templ,count); andre@3: break; andre@3: default: andre@3: crv = CKR_ATTRIBUTE_VALUE_INVALID; andre@3: break; andre@3: } andre@3: andre@3: return crv; andre@3: } andre@3: