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