Source code

Revision control

Copy as Markdown

Other Tools

/* 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;
}
/* search with email with and without NULL
* The sql database accepts the email with a NULL as it's written,
* the dbm database strips the NULL on write so won't match if
* it's there on find */
static CK_OBJECT_HANDLE
pk11_FindSMimeObjectByTemplate(PK11SlotInfo *slot,
CK_ATTRIBUTE *theTemplate, size_t tsize)
{
CK_OBJECT_HANDLE smimeh = CK_INVALID_HANDLE;
CK_ATTRIBUTE *last;
PORT_Assert(tsize != 0);
smimeh = pk11_FindObjectByTemplate(slot, theTemplate, (int)tsize);
if (smimeh != CK_INVALID_HANDLE) {
return smimeh;
}
last = &theTemplate[tsize - 1];
if ((last->type == CKA_NSS_EMAIL) && (last->ulValueLen != 0)) {
CK_ULONG save_len = last->ulValueLen;
last->ulValueLen--;
smimeh = pk11_FindObjectByTemplate(slot, theTemplate, (int)tsize);
last->ulValueLen = save_len; /* restore the original */
return smimeh;
}
return CK_INVALID_HANDLE;
}
/*
* 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_CLASS, NULL, 0 },
{ CKA_SUBJECT, 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_CLASS, &smimeClass, sizeof(smimeClass));
attrs++;
PK11_SETATTRS(attrs, CKA_SUBJECT, name->data, name->len);
attrs++;
PK11_SETATTRS(attrs, CKA_NSS_EMAIL, emailAddr, strlen(emailAddr) + 1);
attrs++;
if (*slot) {
smimeh = pk11_FindSMimeObjectByTemplate(*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_FindSMimeObjectByTemplate(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);
}