/* 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 "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 "sslerr.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_NETSCAPE_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_NETSCAPE_KRL, NULL, 0}, { CKA_NETSCAPE_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_NETSCAPE_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_NETSCAPE_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_NETSCAPE_KRL, NULL, 0}, { CKA_NETSCAPE_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;idata = 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_NETSCAPE_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); collection = nssCRLCollection_Create(td, NULL); if (!collection) { goto loser; } instances = nssToken_FindCRLsBySubject(token, NULL, &subject, tokenOnly, 0, NULL); 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 = PK11Slot_GetNSSToken(slot); 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); object = nssToken_ImportCRL(token, NULL, &derSubject, &derCRL, isKRL, url, PR_TRUE); 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; NSSToken *token; nssCryptokiObject *object; 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); object = nss_ZNEW(NULL, nssCryptokiObject); if (!object) { return SECFailure; } object->token = nssToken_AddRef(token); 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_NETSCAPE_SMIME; CK_ATTRIBUTE theTemplate[] = { { CKA_SUBJECT, NULL, 0 }, { CKA_CLASS, NULL, 0 }, { CKA_NETSCAPE_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 */ int 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_NETSCAPE_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_NETSCAPE_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_NETSCAPE_SMIME; CK_BBOOL ck_true = CK_TRUE; CK_ATTRIBUTE theTemplate[] = { { CKA_CLASS, NULL, 0 }, { CKA_TOKEN, NULL, 0 }, { CKA_SUBJECT, NULL, 0 }, { CKA_NETSCAPE_EMAIL, NULL, 0 }, { CKA_NETSCAPE_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_NETSCAPE_EMAIL, emailAddr, PORT_Strlen(emailAddr)+1); attrs++; if (profileTime) { PK11_SETATTRS(attrs, CKA_NETSCAPE_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_SESSION) { 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); }