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