summaryrefslogtreecommitdiffstats
path: root/security/nss/lib/pk11wrap/pk11nobj.c
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
commit26a029d407be480d791972afb5975cf62c9360a6 (patch)
treef435a8308119effd964b339f76abb83a57c29483 /security/nss/lib/pk11wrap/pk11nobj.c
parentInitial commit. (diff)
downloadfirefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz
firefox-26a029d407be480d791972afb5975cf62c9360a6.zip
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'security/nss/lib/pk11wrap/pk11nobj.c')
-rw-r--r--security/nss/lib/pk11wrap/pk11nobj.c807
1 files changed, 807 insertions, 0 deletions
diff --git a/security/nss/lib/pk11wrap/pk11nobj.c b/security/nss/lib/pk11wrap/pk11nobj.c
new file mode 100644
index 0000000000..586ed80e32
--- /dev/null
+++ b/security/nss/lib/pk11wrap/pk11nobj.c
@@ -0,0 +1,807 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/*
+ * This file manages Netscape specific PKCS #11 objects (CRLs, Trust objects,
+ * etc).
+ */
+
+#include <stddef.h>
+
+#include "secport.h"
+#include "seccomon.h"
+#include "secmod.h"
+#include "secmodi.h"
+#include "secmodti.h"
+#include "pkcs11.h"
+#include "pk11func.h"
+#include "cert.h"
+#include "certi.h"
+#include "secitem.h"
+#include "sechash.h"
+#include "secoid.h"
+
+#include "certdb.h"
+#include "secerr.h"
+
+#include "pki3hack.h"
+#include "dev3hack.h"
+
+#include "devm.h"
+#include "pki.h"
+#include "pkim.h"
+
+extern const NSSError NSS_ERROR_NOT_FOUND;
+
+CK_TRUST
+pk11_GetTrustField(PK11SlotInfo *slot, PLArenaPool *arena,
+ CK_OBJECT_HANDLE id, CK_ATTRIBUTE_TYPE type)
+{
+ CK_TRUST rv = 0;
+ SECItem item;
+
+ item.data = NULL;
+ item.len = 0;
+
+ if (SECSuccess == PK11_ReadAttribute(slot, id, type, arena, &item)) {
+ PORT_Assert(item.len == sizeof(CK_TRUST));
+ PORT_Memcpy(&rv, item.data, sizeof(CK_TRUST));
+ /* Damn, is there an endian problem here? */
+ return rv;
+ }
+
+ return 0;
+}
+
+PRBool
+pk11_HandleTrustObject(PK11SlotInfo *slot, CERTCertificate *cert, CERTCertTrust *trust)
+{
+ PLArenaPool *arena;
+
+ CK_ATTRIBUTE tobjTemplate[] = {
+ { CKA_CLASS, NULL, 0 },
+ { CKA_CERT_SHA1_HASH, NULL, 0 },
+ };
+
+ CK_OBJECT_CLASS tobjc = CKO_NSS_TRUST;
+ CK_OBJECT_HANDLE tobjID;
+ unsigned char sha1_hash[SHA1_LENGTH];
+
+ CK_TRUST serverAuth, codeSigning, emailProtection, clientAuth;
+
+ PK11_HashBuf(SEC_OID_SHA1, sha1_hash, cert->derCert.data, cert->derCert.len);
+
+ PK11_SETATTRS(&tobjTemplate[0], CKA_CLASS, &tobjc, sizeof(tobjc));
+ PK11_SETATTRS(&tobjTemplate[1], CKA_CERT_SHA1_HASH, sha1_hash,
+ SHA1_LENGTH);
+
+ tobjID = pk11_FindObjectByTemplate(slot, tobjTemplate,
+ sizeof(tobjTemplate) / sizeof(tobjTemplate[0]));
+ if (CK_INVALID_HANDLE == tobjID) {
+ return PR_FALSE;
+ }
+
+ arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+ if (NULL == arena)
+ return PR_FALSE;
+
+ /* Unfortunately, it seems that PK11_GetAttributes doesn't deal
+ * well with nonexistent attributes. I guess we have to check
+ * the trust info fields one at a time.
+ */
+
+ /* We could verify CKA_CERT_HASH here */
+
+ /* We could verify CKA_EXPIRES here */
+
+ /* "Purpose" trust information */
+ serverAuth = pk11_GetTrustField(slot, arena, tobjID, CKA_TRUST_SERVER_AUTH);
+ clientAuth = pk11_GetTrustField(slot, arena, tobjID, CKA_TRUST_CLIENT_AUTH);
+ codeSigning = pk11_GetTrustField(slot, arena, tobjID, CKA_TRUST_CODE_SIGNING);
+ emailProtection = pk11_GetTrustField(slot, arena, tobjID,
+ CKA_TRUST_EMAIL_PROTECTION);
+ /* Here's where the fun logic happens. We have to map back from the
+ * key usage, extended key usage, purpose, and possibly other trust values
+ * into the old trust-flags bits. */
+
+ /* First implementation: keep it simple for testing. We can study what other
+ * mappings would be appropriate and add them later.. fgmr 20000724 */
+
+ if (serverAuth == CKT_NSS_TRUSTED) {
+ trust->sslFlags |= CERTDB_TERMINAL_RECORD | CERTDB_TRUSTED;
+ }
+
+ if (serverAuth == CKT_NSS_TRUSTED_DELEGATOR) {
+ trust->sslFlags |= CERTDB_VALID_CA | CERTDB_TRUSTED_CA |
+ CERTDB_NS_TRUSTED_CA;
+ }
+ if (clientAuth == CKT_NSS_TRUSTED_DELEGATOR) {
+ trust->sslFlags |= CERTDB_TRUSTED_CLIENT_CA;
+ }
+
+ if (emailProtection == CKT_NSS_TRUSTED) {
+ trust->emailFlags |= CERTDB_TERMINAL_RECORD | CERTDB_TRUSTED;
+ }
+
+ if (emailProtection == CKT_NSS_TRUSTED_DELEGATOR) {
+ trust->emailFlags |= CERTDB_VALID_CA | CERTDB_TRUSTED_CA | CERTDB_NS_TRUSTED_CA;
+ }
+
+ if (codeSigning == CKT_NSS_TRUSTED) {
+ trust->objectSigningFlags |= CERTDB_TERMINAL_RECORD | CERTDB_TRUSTED;
+ }
+
+ if (codeSigning == CKT_NSS_TRUSTED_DELEGATOR) {
+ trust->objectSigningFlags |= CERTDB_VALID_CA | CERTDB_TRUSTED_CA | CERTDB_NS_TRUSTED_CA;
+ }
+
+ /* There's certainly a lot more logic that can go here.. */
+
+ PORT_FreeArena(arena, PR_FALSE);
+
+ return PR_TRUE;
+}
+
+static SECStatus
+pk11_CollectCrls(PK11SlotInfo *slot, CK_OBJECT_HANDLE crlID, void *arg)
+{
+ SECItem derCrl;
+ CERTCrlHeadNode *head = (CERTCrlHeadNode *)arg;
+ CERTCrlNode *new_node = NULL;
+ CK_ATTRIBUTE fetchCrl[3] = {
+ { CKA_VALUE, NULL, 0 },
+ { CKA_NSS_KRL, NULL, 0 },
+ { CKA_NSS_URL, NULL, 0 },
+ };
+ const int fetchCrlSize = sizeof(fetchCrl) / sizeof(fetchCrl[2]);
+ CK_RV crv;
+ SECStatus rv = SECFailure;
+
+ crv = PK11_GetAttributes(head->arena, slot, crlID, fetchCrl, fetchCrlSize);
+ if (CKR_OK != crv) {
+ PORT_SetError(PK11_MapError(crv));
+ goto loser;
+ }
+
+ if (!fetchCrl[1].pValue) {
+ PORT_SetError(SEC_ERROR_CRL_INVALID);
+ goto loser;
+ }
+
+ new_node = (CERTCrlNode *)PORT_ArenaAlloc(head->arena, sizeof(CERTCrlNode));
+ if (new_node == NULL) {
+ goto loser;
+ }
+
+ if (*((CK_BBOOL *)fetchCrl[1].pValue))
+ new_node->type = SEC_KRL_TYPE;
+ else
+ new_node->type = SEC_CRL_TYPE;
+
+ derCrl.type = siBuffer;
+ derCrl.data = (unsigned char *)fetchCrl[0].pValue;
+ derCrl.len = fetchCrl[0].ulValueLen;
+ new_node->crl = CERT_DecodeDERCrl(head->arena, &derCrl, new_node->type);
+ if (new_node->crl == NULL) {
+ goto loser;
+ }
+
+ if (fetchCrl[2].pValue) {
+ int nnlen = fetchCrl[2].ulValueLen;
+ new_node->crl->url = (char *)PORT_ArenaAlloc(head->arena, nnlen + 1);
+ if (!new_node->crl->url) {
+ goto loser;
+ }
+ PORT_Memcpy(new_node->crl->url, fetchCrl[2].pValue, nnlen);
+ new_node->crl->url[nnlen] = 0;
+ } else {
+ new_node->crl->url = NULL;
+ }
+
+ new_node->next = NULL;
+ if (head->last) {
+ head->last->next = new_node;
+ head->last = new_node;
+ } else {
+ head->first = head->last = new_node;
+ }
+ rv = SECSuccess;
+
+loser:
+ return (rv);
+}
+
+/*
+ * Return a list of all the CRLs .
+ * CRLs are allocated in the list's arena.
+ */
+SECStatus
+PK11_LookupCrls(CERTCrlHeadNode *nodes, int type, void *wincx)
+{
+ pk11TraverseSlot creater;
+ CK_ATTRIBUTE theTemplate[2];
+ CK_ATTRIBUTE *attrs;
+ CK_OBJECT_CLASS certClass = CKO_NSS_CRL;
+ CK_BBOOL isKrl = CK_FALSE;
+
+ attrs = theTemplate;
+ PK11_SETATTRS(attrs, CKA_CLASS, &certClass, sizeof(certClass));
+ attrs++;
+ if (type != -1) {
+ isKrl = (CK_BBOOL)(type == SEC_KRL_TYPE);
+ PK11_SETATTRS(attrs, CKA_NSS_KRL, &isKrl, sizeof(isKrl));
+ attrs++;
+ }
+
+ creater.callback = pk11_CollectCrls;
+ creater.callbackArg = (void *)nodes;
+ creater.findTemplate = theTemplate;
+ creater.templateCount = (attrs - theTemplate);
+
+ return pk11_TraverseAllSlots(PK11_TraverseSlot, &creater, PR_FALSE, wincx);
+}
+
+struct crlOptionsStr {
+ CERTCrlHeadNode *head;
+ PRInt32 decodeOptions;
+};
+
+typedef struct crlOptionsStr crlOptions;
+
+static SECStatus
+pk11_RetrieveCrlsCallback(PK11SlotInfo *slot, CK_OBJECT_HANDLE crlID,
+ void *arg)
+{
+ SECItem *derCrl = NULL;
+ crlOptions *options = (crlOptions *)arg;
+ CERTCrlHeadNode *head = options->head;
+ CERTCrlNode *new_node = NULL;
+ CK_ATTRIBUTE fetchCrl[3] = {
+ { CKA_VALUE, NULL, 0 },
+ { CKA_NSS_KRL, NULL, 0 },
+ { CKA_NSS_URL, NULL, 0 },
+ };
+ const int fetchCrlSize = sizeof(fetchCrl) / sizeof(fetchCrl[2]);
+ CK_RV crv;
+ SECStatus rv = SECFailure;
+ PRBool adopted = PR_FALSE; /* whether the CRL adopted the DER memory
+ successfully */
+ int i;
+
+ crv = PK11_GetAttributes(NULL, slot, crlID, fetchCrl, fetchCrlSize);
+ if (CKR_OK != crv) {
+ PORT_SetError(PK11_MapError(crv));
+ goto loser;
+ }
+
+ if (!fetchCrl[1].pValue) {
+ /* reject KRLs */
+ PORT_SetError(SEC_ERROR_CRL_INVALID);
+ goto loser;
+ }
+
+ new_node = (CERTCrlNode *)PORT_ArenaAlloc(head->arena,
+ sizeof(CERTCrlNode));
+ if (new_node == NULL) {
+ goto loser;
+ }
+
+ new_node->type = SEC_CRL_TYPE;
+
+ derCrl = SECITEM_AllocItem(NULL, NULL, 0);
+ if (!derCrl) {
+ goto loser;
+ }
+ derCrl->type = siBuffer;
+ derCrl->data = (unsigned char *)fetchCrl[0].pValue;
+ derCrl->len = fetchCrl[0].ulValueLen;
+ new_node->crl = CERT_DecodeDERCrlWithFlags(NULL, derCrl, new_node->type,
+ options->decodeOptions);
+ if (new_node->crl == NULL) {
+ goto loser;
+ }
+ adopted = PR_TRUE; /* now that the CRL has adopted the DER memory,
+ we won't need to free it upon exit */
+
+ if (fetchCrl[2].pValue && fetchCrl[2].ulValueLen) {
+ /* copy the URL if there is one */
+ int nnlen = fetchCrl[2].ulValueLen;
+ new_node->crl->url = (char *)PORT_ArenaAlloc(new_node->crl->arena,
+ nnlen + 1);
+ if (!new_node->crl->url) {
+ goto loser;
+ }
+ PORT_Memcpy(new_node->crl->url, fetchCrl[2].pValue, nnlen);
+ new_node->crl->url[nnlen] = 0;
+ } else {
+ new_node->crl->url = NULL;
+ }
+
+ new_node->next = NULL;
+ if (head->last) {
+ head->last->next = new_node;
+ head->last = new_node;
+ } else {
+ head->first = head->last = new_node;
+ }
+ rv = SECSuccess;
+ new_node->crl->slot = PK11_ReferenceSlot(slot);
+ new_node->crl->pkcs11ID = crlID;
+
+loser:
+ /* free attributes that weren't adopted by the CRL */
+ for (i = 1; i < fetchCrlSize; i++) {
+ if (fetchCrl[i].pValue) {
+ PORT_Free(fetchCrl[i].pValue);
+ }
+ }
+ /* free the DER if the CRL object didn't adopt it */
+ if (fetchCrl[0].pValue && PR_FALSE == adopted) {
+ PORT_Free(fetchCrl[0].pValue);
+ }
+ if (derCrl && !adopted) {
+ /* clear the data fields, which we already took care of above */
+ derCrl->data = NULL;
+ derCrl->len = 0;
+ /* free the memory for the SECItem structure itself */
+ SECITEM_FreeItem(derCrl, PR_TRUE);
+ }
+ return (rv);
+}
+
+/*
+ * Return a list of CRLs matching specified issuer and type
+ * CRLs are not allocated in the list's arena, but rather in their own,
+ * arena, so that they can be used individually in the CRL cache .
+ * CRLs are always partially decoded for efficiency.
+ */
+SECStatus
+pk11_RetrieveCrls(CERTCrlHeadNode *nodes, SECItem *issuer,
+ void *wincx)
+{
+ pk11TraverseSlot creater;
+ CK_ATTRIBUTE theTemplate[2];
+ CK_ATTRIBUTE *attrs;
+ CK_OBJECT_CLASS crlClass = CKO_NSS_CRL;
+ crlOptions options;
+
+ attrs = theTemplate;
+ PK11_SETATTRS(attrs, CKA_CLASS, &crlClass, sizeof(crlClass));
+ attrs++;
+
+ options.head = nodes;
+
+ /* - do a partial decoding - we don't need to decode the entries while fetching
+ - don't copy the DER for optimal performance - CRL can be very large
+ - have the CRL objects adopt the DER, so SEC_DestroyCrl will free it
+ - keep bad CRL objects. The CRL cache is interested in them, for
+ security purposes. Bad CRL objects are a sign of something amiss.
+ */
+
+ options.decodeOptions = CRL_DECODE_SKIP_ENTRIES | CRL_DECODE_DONT_COPY_DER |
+ CRL_DECODE_ADOPT_HEAP_DER | CRL_DECODE_KEEP_BAD_CRL;
+ if (issuer) {
+ PK11_SETATTRS(attrs, CKA_SUBJECT, issuer->data, issuer->len);
+ attrs++;
+ }
+
+ creater.callback = pk11_RetrieveCrlsCallback;
+ creater.callbackArg = (void *)&options;
+ creater.findTemplate = theTemplate;
+ creater.templateCount = (attrs - theTemplate);
+
+ return pk11_TraverseAllSlots(PK11_TraverseSlot, &creater, PR_FALSE, wincx);
+}
+
+/*
+ * return the crl associated with a derSubjectName
+ */
+SECItem *
+PK11_FindCrlByName(PK11SlotInfo **slot, CK_OBJECT_HANDLE *crlHandle,
+ SECItem *name, int type, char **pUrl)
+{
+ NSSCRL **crls, **crlp, *crl = NULL;
+ NSSDER subject;
+ SECItem *rvItem;
+ NSSTrustDomain *td = STAN_GetDefaultTrustDomain();
+ char *url = NULL;
+
+ PORT_SetError(0);
+ NSSITEM_FROM_SECITEM(&subject, name);
+ if (*slot) {
+ nssCryptokiObject **instances;
+ nssPKIObjectCollection *collection;
+ nssTokenSearchType tokenOnly = nssTokenSearchType_TokenOnly;
+ NSSToken *token = PK11Slot_GetNSSToken(*slot);
+ if (!token) {
+ goto loser;
+ }
+ collection = nssCRLCollection_Create(td, NULL);
+ if (!collection) {
+ (void)nssToken_Destroy(token);
+ goto loser;
+ }
+ instances = nssToken_FindCRLsBySubject(token, NULL, &subject,
+ tokenOnly, 0, NULL);
+ (void)nssToken_Destroy(token);
+ nssPKIObjectCollection_AddInstances(collection, instances, 0);
+ nss_ZFreeIf(instances);
+ crls = nssPKIObjectCollection_GetCRLs(collection, NULL, 0, NULL);
+ nssPKIObjectCollection_Destroy(collection);
+ } else {
+ crls = nssTrustDomain_FindCRLsBySubject(td, &subject);
+ }
+ if ((!crls) || (*crls == NULL)) {
+ if (crls) {
+ nssCRLArray_Destroy(crls);
+ }
+ if (NSS_GetError() == NSS_ERROR_NOT_FOUND) {
+ PORT_SetError(SEC_ERROR_CRL_NOT_FOUND);
+ }
+ goto loser;
+ }
+ for (crlp = crls; *crlp; crlp++) {
+ if ((!(*crlp)->isKRL && type == SEC_CRL_TYPE) ||
+ ((*crlp)->isKRL && type != SEC_CRL_TYPE)) {
+ crl = nssCRL_AddRef(*crlp);
+ break;
+ }
+ }
+ nssCRLArray_Destroy(crls);
+ if (!crl) {
+ /* CRL collection was found, but no interesting CRL's were on it.
+ * Not an error */
+ PORT_SetError(SEC_ERROR_CRL_NOT_FOUND);
+ goto loser;
+ }
+ if (crl->url) {
+ url = PORT_Strdup(crl->url);
+ if (!url) {
+ goto loser;
+ }
+ }
+ rvItem = SECITEM_AllocItem(NULL, NULL, crl->encoding.size);
+ if (!rvItem) {
+ goto loser;
+ }
+ memcpy(rvItem->data, crl->encoding.data, crl->encoding.size);
+ *slot = PK11_ReferenceSlot(crl->object.instances[0]->token->pk11slot);
+ *crlHandle = crl->object.instances[0]->handle;
+ *pUrl = url;
+ nssCRL_Destroy(crl);
+ return rvItem;
+
+loser:
+ if (url)
+ PORT_Free(url);
+ if (crl)
+ nssCRL_Destroy(crl);
+ if (PORT_GetError() == 0) {
+ PORT_SetError(SEC_ERROR_CRL_NOT_FOUND);
+ }
+ return NULL;
+}
+
+CK_OBJECT_HANDLE
+PK11_PutCrl(PK11SlotInfo *slot, SECItem *crl, SECItem *name,
+ char *url, int type)
+{
+ NSSItem derCRL, derSubject;
+ NSSToken *token;
+ nssCryptokiObject *object;
+ PRBool isKRL = (type == SEC_CRL_TYPE) ? PR_FALSE : PR_TRUE;
+ CK_OBJECT_HANDLE rvH;
+
+ NSSITEM_FROM_SECITEM(&derSubject, name);
+ NSSITEM_FROM_SECITEM(&derCRL, crl);
+ token = PK11Slot_GetNSSToken(slot);
+ if (!token) {
+ PORT_SetError(SEC_ERROR_NO_TOKEN);
+ return CK_INVALID_HANDLE;
+ }
+ object = nssToken_ImportCRL(token, NULL,
+ &derSubject, &derCRL, isKRL, url, PR_TRUE);
+ (void)nssToken_Destroy(token);
+
+ if (object) {
+ rvH = object->handle;
+ nssCryptokiObject_Destroy(object);
+ } else {
+ rvH = CK_INVALID_HANDLE;
+ PORT_SetError(SEC_ERROR_CRL_IMPORT_FAILED);
+ }
+ return rvH;
+}
+
+/*
+ * delete a crl.
+ */
+SECStatus
+SEC_DeletePermCRL(CERTSignedCrl *crl)
+{
+ PRStatus status;
+ nssCryptokiObject *object;
+ NSSToken *token;
+ PK11SlotInfo *slot = crl->slot;
+
+ if (slot == NULL) {
+ PORT_Assert(slot);
+ /* shouldn't happen */
+ PORT_SetError(SEC_ERROR_CRL_INVALID);
+ return SECFailure;
+ }
+
+ token = PK11Slot_GetNSSToken(slot);
+ if (!token) {
+ return SECFailure;
+ }
+ object = nss_ZNEW(NULL, nssCryptokiObject);
+ if (!object) {
+ (void)nssToken_Destroy(token);
+ return SECFailure;
+ }
+ object->token = token; /* object takes ownership */
+ object->handle = crl->pkcs11ID;
+ object->isTokenObject = PR_TRUE;
+
+ status = nssToken_DeleteStoredObject(object);
+
+ nssCryptokiObject_Destroy(object);
+ return (status == PR_SUCCESS) ? SECSuccess : SECFailure;
+}
+
+/*
+ * return the certificate associated with a derCert
+ */
+SECItem *
+PK11_FindSMimeProfile(PK11SlotInfo **slot, char *emailAddr,
+ SECItem *name, SECItem **profileTime)
+{
+ CK_OBJECT_CLASS smimeClass = CKO_NSS_SMIME;
+ CK_ATTRIBUTE theTemplate[] = {
+ { CKA_SUBJECT, NULL, 0 },
+ { CKA_CLASS, NULL, 0 },
+ { CKA_NSS_EMAIL, NULL, 0 },
+ };
+ CK_ATTRIBUTE smimeData[] = {
+ { CKA_SUBJECT, NULL, 0 },
+ { CKA_VALUE, NULL, 0 },
+ };
+ /* if you change the array, change the variable below as well */
+ const size_t tsize = sizeof(theTemplate) / sizeof(theTemplate[0]);
+ CK_OBJECT_HANDLE smimeh = CK_INVALID_HANDLE;
+ CK_ATTRIBUTE *attrs = theTemplate;
+ CK_RV crv;
+ SECItem *emailProfile = NULL;
+
+ if (!emailAddr || !emailAddr[0]) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return NULL;
+ }
+
+ PK11_SETATTRS(attrs, CKA_SUBJECT, name->data, name->len);
+ attrs++;
+ PK11_SETATTRS(attrs, CKA_CLASS, &smimeClass, sizeof(smimeClass));
+ attrs++;
+ PK11_SETATTRS(attrs, CKA_NSS_EMAIL, emailAddr, strlen(emailAddr));
+ attrs++;
+
+ if (*slot) {
+ smimeh = pk11_FindObjectByTemplate(*slot, theTemplate, tsize);
+ } else {
+ PK11SlotList *list = PK11_GetAllTokens(CKM_INVALID_MECHANISM,
+ PR_FALSE, PR_TRUE, NULL);
+ PK11SlotListElement *le;
+
+ if (!list) {
+ return NULL;
+ }
+ /* loop through all the slots */
+ for (le = list->head; le; le = le->next) {
+ smimeh = pk11_FindObjectByTemplate(le->slot, theTemplate, tsize);
+ if (smimeh != CK_INVALID_HANDLE) {
+ *slot = PK11_ReferenceSlot(le->slot);
+ break;
+ }
+ }
+ PK11_FreeSlotList(list);
+ }
+
+ if (smimeh == CK_INVALID_HANDLE) {
+ PORT_SetError(SEC_ERROR_NO_KRL);
+ return NULL;
+ }
+
+ if (profileTime) {
+ PK11_SETATTRS(smimeData, CKA_NSS_SMIME_TIMESTAMP, NULL, 0);
+ }
+
+ crv = PK11_GetAttributes(NULL, *slot, smimeh, smimeData, 2);
+ if (crv != CKR_OK) {
+ PORT_SetError(PK11_MapError(crv));
+ goto loser;
+ }
+
+ if (!profileTime) {
+ SECItem profileSubject;
+
+ profileSubject.data = (unsigned char *)smimeData[0].pValue;
+ profileSubject.len = smimeData[0].ulValueLen;
+ if (!SECITEM_ItemsAreEqual(&profileSubject, name)) {
+ goto loser;
+ }
+ }
+
+ emailProfile = (SECItem *)PORT_ZAlloc(sizeof(SECItem));
+ if (emailProfile == NULL) {
+ goto loser;
+ }
+
+ emailProfile->data = (unsigned char *)smimeData[1].pValue;
+ emailProfile->len = smimeData[1].ulValueLen;
+
+ if (profileTime) {
+ *profileTime = (SECItem *)PORT_ZAlloc(sizeof(SECItem));
+ if (*profileTime) {
+ (*profileTime)->data = (unsigned char *)smimeData[0].pValue;
+ (*profileTime)->len = smimeData[0].ulValueLen;
+ }
+ }
+
+loser:
+ if (emailProfile == NULL) {
+ if (smimeData[1].pValue) {
+ PORT_Free(smimeData[1].pValue);
+ }
+ }
+ if (profileTime == NULL || *profileTime == NULL) {
+ if (smimeData[0].pValue) {
+ PORT_Free(smimeData[0].pValue);
+ }
+ }
+ return emailProfile;
+}
+
+SECStatus
+PK11_SaveSMimeProfile(PK11SlotInfo *slot, char *emailAddr, SECItem *derSubj,
+ SECItem *emailProfile, SECItem *profileTime)
+{
+ CK_OBJECT_CLASS smimeClass = CKO_NSS_SMIME;
+ CK_BBOOL ck_true = CK_TRUE;
+ CK_ATTRIBUTE theTemplate[] = {
+ { CKA_CLASS, NULL, 0 },
+ { CKA_TOKEN, NULL, 0 },
+ { CKA_SUBJECT, NULL, 0 },
+ { CKA_NSS_EMAIL, NULL, 0 },
+ { CKA_NSS_SMIME_TIMESTAMP, NULL, 0 },
+ { CKA_VALUE, NULL, 0 }
+ };
+ /* if you change the array, change the variable below as well */
+ int realSize = 0;
+ CK_OBJECT_HANDLE smimeh = CK_INVALID_HANDLE;
+ CK_ATTRIBUTE *attrs = theTemplate;
+ CK_SESSION_HANDLE rwsession;
+ PK11SlotInfo *free_slot = NULL;
+ CK_RV crv;
+#ifdef DEBUG
+ int tsize = sizeof(theTemplate) / sizeof(theTemplate[0]);
+#endif
+
+ PK11_SETATTRS(attrs, CKA_CLASS, &smimeClass, sizeof(smimeClass));
+ attrs++;
+ PK11_SETATTRS(attrs, CKA_TOKEN, &ck_true, sizeof(ck_true));
+ attrs++;
+ PK11_SETATTRS(attrs, CKA_SUBJECT, derSubj->data, derSubj->len);
+ attrs++;
+ PK11_SETATTRS(attrs, CKA_NSS_EMAIL,
+ emailAddr, PORT_Strlen(emailAddr) + 1);
+ attrs++;
+ if (profileTime) {
+ PK11_SETATTRS(attrs, CKA_NSS_SMIME_TIMESTAMP, profileTime->data,
+ profileTime->len);
+ attrs++;
+ PK11_SETATTRS(attrs, CKA_VALUE, emailProfile->data,
+ emailProfile->len);
+ attrs++;
+ }
+ realSize = attrs - theTemplate;
+ PORT_Assert(realSize <= tsize);
+
+ if (slot == NULL) {
+ free_slot = slot = PK11_GetInternalKeySlot();
+ /* we need to free the key slot in the end!!! */
+ }
+
+ rwsession = PK11_GetRWSession(slot);
+ if (rwsession == CK_INVALID_HANDLE) {
+ PORT_SetError(SEC_ERROR_READ_ONLY);
+ if (free_slot) {
+ PK11_FreeSlot(free_slot);
+ }
+ return SECFailure;
+ }
+
+ crv = PK11_GETTAB(slot)->C_CreateObject(rwsession, theTemplate, realSize, &smimeh);
+ if (crv != CKR_OK) {
+ PORT_SetError(PK11_MapError(crv));
+ }
+
+ PK11_RestoreROSession(slot, rwsession);
+
+ if (free_slot) {
+ PK11_FreeSlot(free_slot);
+ }
+ return SECSuccess;
+}
+
+CERTSignedCrl *crl_storeCRL(PK11SlotInfo *slot, char *url,
+ CERTSignedCrl *newCrl, SECItem *derCrl, int type);
+
+/* import the CRL into the token */
+
+CERTSignedCrl *
+PK11_ImportCRL(PK11SlotInfo *slot, SECItem *derCRL, char *url,
+ int type, void *wincx, PRInt32 importOptions, PLArenaPool *arena,
+ PRInt32 decodeoptions)
+{
+ CERTSignedCrl *newCrl, *crl;
+ SECStatus rv;
+ CERTCertificate *caCert = NULL;
+
+ newCrl = crl = NULL;
+
+ do {
+ newCrl = CERT_DecodeDERCrlWithFlags(arena, derCRL, type,
+ decodeoptions);
+ if (newCrl == NULL) {
+ if (type == SEC_CRL_TYPE) {
+ /* only promote error when the error code is too generic */
+ if (PORT_GetError() == SEC_ERROR_BAD_DER)
+ PORT_SetError(SEC_ERROR_CRL_INVALID);
+ } else {
+ PORT_SetError(SEC_ERROR_KRL_INVALID);
+ }
+ break;
+ }
+
+ if (0 == (importOptions & CRL_IMPORT_BYPASS_CHECKS)) {
+ CERTCertDBHandle *handle = CERT_GetDefaultCertDB();
+ PR_ASSERT(handle != NULL);
+ caCert = CERT_FindCertByName(handle,
+ &newCrl->crl.derName);
+ if (caCert == NULL) {
+ PORT_SetError(SEC_ERROR_UNKNOWN_ISSUER);
+ break;
+ }
+
+ /* If caCert is a v3 certificate, make sure that it can be used for
+ crl signing purpose */
+ rv = CERT_CheckCertUsage(caCert, KU_CRL_SIGN);
+ if (rv != SECSuccess) {
+ break;
+ }
+
+ rv = CERT_VerifySignedData(&newCrl->signatureWrap, caCert,
+ PR_Now(), wincx);
+ if (rv != SECSuccess) {
+ if (type == SEC_CRL_TYPE) {
+ PORT_SetError(SEC_ERROR_CRL_BAD_SIGNATURE);
+ } else {
+ PORT_SetError(SEC_ERROR_KRL_BAD_SIGNATURE);
+ }
+ break;
+ }
+ }
+
+ crl = crl_storeCRL(slot, url, newCrl, derCRL, type);
+
+ } while (0);
+
+ if (crl == NULL) {
+ SEC_DestroyCrl(newCrl);
+ }
+ if (caCert) {
+ CERT_DestroyCertificate(caCert);
+ }
+ return (crl);
+}