NSS_IMPLEMENT nssCryptokiObject * nssCryptokiObject_Create ( NSSToken *t, nssSession *session, CK_OBJECT_HANDLE h ) { PRStatus status; NSSSlot *slot; nssCryptokiObject *object; CK_BBOOL *isTokenObject; CK_ATTRIBUTE cert_template[] = { { CKA_TOKEN, NULL, 0 }, { CKA_LABEL, NULL, 0 } }; slot = nssToken_GetSlot(t); status = nssCKObject_GetAttributes(h, cert_template, 2, NULL, session, slot); nssSlot_Destroy(slot); if (status != PR_SUCCESS) { /* a failure here indicates a device error */ return (nssCryptokiObject *)NULL; } object = nss_ZNEW(NULL, nssCryptokiObject); if (!object) { return (nssCryptokiObject *)NULL; } object->handle = h; object->token = nssToken_AddRef(t); isTokenObject = (CK_BBOOL *)cert_template[0].pValue; object->isTokenObject = *isTokenObject; nss_ZFreeIf(isTokenObject); NSS_CK_ATTRIBUTE_TO_UTF8(&cert_template[1], object->label); return object; }
NSS_IMPLEMENT PRStatus nssCKObject_GetAttributeItem( CK_OBJECT_HANDLE object, CK_ATTRIBUTE_TYPE attribute, NSSArena *arenaOpt, nssSession *session, NSSSlot *slot, NSSItem *rvItem) { CK_ATTRIBUTE attr = { 0, NULL, 0 }; PRStatus nssrv; attr.type = attribute; nssrv = nssCKObject_GetAttributes(object, &attr, 1, arenaOpt, session, slot); if (nssrv != PR_SUCCESS) { return nssrv; } rvItem->data = (void *)attr.pValue; rvItem->size = (PRUint32)attr.ulValueLen; return PR_SUCCESS; }
NSS_IMPLEMENT nssCryptokiObject * nssToken_ImportCertificate ( NSSToken *tok, nssSession *sessionOpt, NSSCertificateType certType, NSSItem *id, const NSSUTF8 *nickname, NSSDER *encoding, NSSDER *issuer, NSSDER *subject, NSSDER *serial, NSSASCII7 *email, PRBool asTokenObject ) { PRStatus status; CK_CERTIFICATE_TYPE cert_type; CK_ATTRIBUTE_PTR attr; CK_ATTRIBUTE cert_tmpl[10]; CK_ULONG ctsize; nssTokenSearchType searchType; nssCryptokiObject *rvObject = NULL; if (!tok) { PORT_SetError(SEC_ERROR_NO_TOKEN); return NULL; } if (certType == NSSCertificateType_PKIX) { cert_type = CKC_X_509; } else { return (nssCryptokiObject *)NULL; } NSS_CK_TEMPLATE_START(cert_tmpl, attr, ctsize); if (asTokenObject) { NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true); searchType = nssTokenSearchType_TokenOnly; } else { NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false); searchType = nssTokenSearchType_SessionOnly; } NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_cert); NSS_CK_SET_ATTRIBUTE_VAR( attr, CKA_CERTIFICATE_TYPE, cert_type); NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ID, id); NSS_CK_SET_ATTRIBUTE_UTF8(attr, CKA_LABEL, nickname); NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_VALUE, encoding); NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ISSUER, issuer); NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SUBJECT, subject); NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SERIAL_NUMBER, serial); if (email) { NSS_CK_SET_ATTRIBUTE_UTF8(attr, CKA_NSS_EMAIL, email); } NSS_CK_TEMPLATE_FINISH(cert_tmpl, attr, ctsize); /* see if the cert is already there */ rvObject = nssToken_FindCertificateByIssuerAndSerialNumber(tok, sessionOpt, issuer, serial, searchType, NULL); if (rvObject) { NSSItem existingDER; NSSSlot *slot = nssToken_GetSlot(tok); nssSession *session = nssSlot_CreateSession(slot, NULL, PR_TRUE); if (!session) { nssCryptokiObject_Destroy(rvObject); nssSlot_Destroy(slot); return (nssCryptokiObject *)NULL; } /* Reject any attempt to import a new cert that has the same * issuer/serial as an existing cert, but does not have the * same encoding */ NSS_CK_TEMPLATE_START(cert_tmpl, attr, ctsize); NSS_CK_SET_ATTRIBUTE_NULL(attr, CKA_VALUE); NSS_CK_TEMPLATE_FINISH(cert_tmpl, attr, ctsize); status = nssCKObject_GetAttributes(rvObject->handle, cert_tmpl, ctsize, NULL, session, slot); NSS_CK_ATTRIBUTE_TO_ITEM(cert_tmpl, &existingDER); if (status == PR_SUCCESS) { if (!nssItem_Equal(encoding, &existingDER, NULL)) { nss_SetError(NSS_ERROR_INVALID_CERTIFICATE); status = PR_FAILURE; } nss_ZFreeIf(existingDER.data); } if (status == PR_FAILURE) { nssCryptokiObject_Destroy(rvObject); nssSession_Destroy(session); nssSlot_Destroy(slot); return (nssCryptokiObject *)NULL; } /* according to PKCS#11, label, ID, issuer, and serial number * may change after the object has been created. For PKIX, the * last two attributes can't change, so for now we'll only worry * about the first two. */ NSS_CK_TEMPLATE_START(cert_tmpl, attr, ctsize); NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ID, id); NSS_CK_SET_ATTRIBUTE_UTF8(attr, CKA_LABEL, nickname); NSS_CK_TEMPLATE_FINISH(cert_tmpl, attr, ctsize); /* reset the mutable attributes on the token */ nssCKObject_SetAttributes(rvObject->handle, cert_tmpl, ctsize, session, slot); if (!rvObject->label && nickname) { rvObject->label = nssUTF8_Duplicate(nickname, NULL); } nssSession_Destroy(session); nssSlot_Destroy(slot); } else { /* Import the certificate onto the token */ rvObject = import_object(tok, sessionOpt, cert_tmpl, ctsize); } if (rvObject && tok->cache) { /* The cache will overwrite the attributes if the object already * exists. */ nssTokenObjectCache_ImportObject(tok->cache, rvObject, CKO_CERTIFICATE, cert_tmpl, ctsize); } return rvObject; }
NSS_IMPLEMENT PRStatus nssCKObject_GetAttributes( CK_OBJECT_HANDLE object, CK_ATTRIBUTE_PTR obj_template, CK_ULONG count, NSSArena *arenaOpt, nssSession *session, NSSSlot *slot) { nssArenaMark *mark = NULL; CK_SESSION_HANDLE hSession; CK_ULONG i = 0; CK_RV ckrv; PRStatus nssrv; PRBool alloced = PR_FALSE; void *epv = nssSlot_GetCryptokiEPV(slot); hSession = session->handle; if (arenaOpt) { mark = nssArena_Mark(arenaOpt); if (!mark) { goto loser; } } nssSession_EnterMonitor(session); /* XXX kinda hacky, if the storage size is already in the first template * item, then skip the alloc portion */ if (obj_template[0].ulValueLen == 0) { /* Get the storage size needed for each attribute */ ckrv = CKAPI(epv)->C_GetAttributeValue(hSession, object, obj_template, count); if (ckrv != CKR_OK && ckrv != CKR_ATTRIBUTE_TYPE_INVALID && ckrv != CKR_ATTRIBUTE_SENSITIVE) { nssSession_ExitMonitor(session); nss_SetError(NSS_ERROR_DEVICE_ERROR); goto loser; } /* Allocate memory for each attribute. */ for (i = 0; i < count; i++) { CK_ULONG ulValueLen = obj_template[i].ulValueLen; if (ulValueLen == 0 || ulValueLen == (CK_ULONG)-1) { obj_template[i].pValue = NULL; obj_template[i].ulValueLen = 0; continue; } if (is_string_attribute(obj_template[i].type)) { ulValueLen++; } obj_template[i].pValue = nss_ZAlloc(arenaOpt, ulValueLen); if (!obj_template[i].pValue) { nssSession_ExitMonitor(session); goto loser; } } alloced = PR_TRUE; } /* Obtain the actual attribute values. */ ckrv = CKAPI(epv)->C_GetAttributeValue(hSession, object, obj_template, count); nssSession_ExitMonitor(session); if (ckrv != CKR_OK && ckrv != CKR_ATTRIBUTE_TYPE_INVALID && ckrv != CKR_ATTRIBUTE_SENSITIVE) { nss_SetError(NSS_ERROR_DEVICE_ERROR); goto loser; } if (alloced && arenaOpt) { nssrv = nssArena_Unmark(arenaOpt, mark); if (nssrv != PR_SUCCESS) { goto loser; } } if (count > 1 && ((ckrv == CKR_ATTRIBUTE_TYPE_INVALID) || (ckrv == CKR_ATTRIBUTE_SENSITIVE))) { /* old tokens would keep the length of '0' and not deal with any * of the attributes we passed. For those tokens read them one at * a time */ for (i = 0; i < count; i++) { if ((obj_template[i].ulValueLen == 0) || (obj_template[i].ulValueLen == -1)) { obj_template[i].ulValueLen = 0; (void)nssCKObject_GetAttributes(object, &obj_template[i], 1, arenaOpt, session, slot); } } } return PR_SUCCESS; loser: if (alloced) { if (arenaOpt) { /* release all arena memory allocated before the failure. */ (void)nssArena_Release(arenaOpt, mark); } else { CK_ULONG j; /* free each heap object that was allocated before the failure. */ for (j = 0; j < i; j++) { nss_ZFreeIf(obj_template[j].pValue); } } } return PR_FAILURE; }
NSS_IMPLEMENT PRStatus nssCryptokiCRL_GetAttributes( nssCryptokiObject *crlObject, nssSession *sessionOpt, NSSArena *arenaOpt, NSSItem *encodingOpt, NSSItem *subjectOpt, CK_ULONG *crl_class, NSSUTF8 **urlOpt, PRBool *isKRLOpt) { PRStatus status; NSSSlot *slot; nssSession *session; CK_ATTRIBUTE_PTR attr; CK_ATTRIBUTE crl_template[7]; CK_ULONG crl_size; PRUint32 i; NSS_CK_TEMPLATE_START(crl_template, attr, crl_size); if (crl_class) { NSS_CK_SET_ATTRIBUTE_NULL(attr, CKA_CLASS); } if (encodingOpt) { NSS_CK_SET_ATTRIBUTE_NULL(attr, CKA_VALUE); } if (urlOpt) { NSS_CK_SET_ATTRIBUTE_NULL(attr, CKA_NSS_URL); } if (isKRLOpt) { NSS_CK_SET_ATTRIBUTE_NULL(attr, CKA_NSS_KRL); } if (subjectOpt) { NSS_CK_SET_ATTRIBUTE_NULL(attr, CKA_SUBJECT); } NSS_CK_TEMPLATE_FINISH(crl_template, attr, crl_size); status = nssToken_GetCachedObjectAttributes(crlObject->token, NULL, crlObject, CKO_NSS_CRL, crl_template, crl_size); if (status != PR_SUCCESS) { session = sessionOpt ? sessionOpt : nssToken_GetDefaultSession(crlObject->token); if (session == NULL) { nss_SetError(NSS_ERROR_INVALID_ARGUMENT); return PR_FAILURE; } slot = nssToken_GetSlot(crlObject->token); status = nssCKObject_GetAttributes(crlObject->handle, crl_template, crl_size, arenaOpt, session, slot); nssSlot_Destroy(slot); if (status != PR_SUCCESS) { return status; } } i = 0; if (crl_class) { NSS_CK_ATTRIBUTE_TO_ULONG(&crl_template[i], *crl_class); i++; } if (encodingOpt) { NSS_CK_ATTRIBUTE_TO_ITEM(&crl_template[i], encodingOpt); i++; } if (urlOpt) { NSS_CK_ATTRIBUTE_TO_UTF8(&crl_template[i], *urlOpt); i++; } if (isKRLOpt) { NSS_CK_ATTRIBUTE_TO_BOOL(&crl_template[i], *isKRLOpt); i++; } if (subjectOpt) { NSS_CK_ATTRIBUTE_TO_ITEM(&crl_template[i], subjectOpt); i++; } return PR_SUCCESS; }
NSS_IMPLEMENT PRStatus nssCryptokiTrust_GetAttributes( nssCryptokiObject *trustObject, nssSession *sessionOpt, NSSItem *sha1_hash, nssTrustLevel *serverAuth, nssTrustLevel *clientAuth, nssTrustLevel *codeSigning, nssTrustLevel *emailProtection, PRBool *stepUpApproved) { PRStatus status; NSSSlot *slot; nssSession *session; CK_BBOOL isToken = PR_FALSE; CK_BBOOL stepUp = PR_FALSE; CK_TRUST saTrust = CKT_NSS_TRUST_UNKNOWN; CK_TRUST caTrust = CKT_NSS_TRUST_UNKNOWN; CK_TRUST epTrust = CKT_NSS_TRUST_UNKNOWN; CK_TRUST csTrust = CKT_NSS_TRUST_UNKNOWN; CK_ATTRIBUTE_PTR attr; CK_ATTRIBUTE trust_template[7]; CK_ATTRIBUTE_PTR sha1_hash_attr; CK_ULONG trust_size; /* Use the trust object to find the trust settings */ NSS_CK_TEMPLATE_START(trust_template, attr, trust_size); NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_TOKEN, isToken); NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_TRUST_SERVER_AUTH, saTrust); NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_TRUST_CLIENT_AUTH, caTrust); NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_TRUST_EMAIL_PROTECTION, epTrust); NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_TRUST_CODE_SIGNING, csTrust); NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_TRUST_STEP_UP_APPROVED, stepUp); sha1_hash_attr = attr; NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CERT_SHA1_HASH, sha1_hash); NSS_CK_TEMPLATE_FINISH(trust_template, attr, trust_size); status = nssToken_GetCachedObjectAttributes(trustObject->token, NULL, trustObject, CKO_NSS_TRUST, trust_template, trust_size); if (status != PR_SUCCESS) { session = sessionOpt ? sessionOpt : nssToken_GetDefaultSession(trustObject->token); if (!session) { nss_SetError(NSS_ERROR_INVALID_ARGUMENT); return PR_FAILURE; } slot = nssToken_GetSlot(trustObject->token); status = nssCKObject_GetAttributes(trustObject->handle, trust_template, trust_size, NULL, session, slot); nssSlot_Destroy(slot); if (status != PR_SUCCESS) { return status; } } if (sha1_hash_attr->ulValueLen == -1) { /* The trust object does not have the CKA_CERT_SHA1_HASH attribute. */ sha1_hash_attr->ulValueLen = 0; } sha1_hash->size = sha1_hash_attr->ulValueLen; *serverAuth = get_nss_trust(saTrust); *clientAuth = get_nss_trust(caTrust); *emailProtection = get_nss_trust(epTrust); *codeSigning = get_nss_trust(csTrust); *stepUpApproved = stepUp; return PR_SUCCESS; }
/* incoming pointers must be valid */ NSS_IMPLEMENT PRStatus nssCryptokiCertificate_GetAttributes( nssCryptokiObject *certObject, nssSession *sessionOpt, NSSArena *arenaOpt, NSSCertificateType *certTypeOpt, NSSItem *idOpt, NSSDER *encodingOpt, NSSDER *issuerOpt, NSSDER *serialOpt, NSSDER *subjectOpt) { PRStatus status; PRUint32 i; nssSession *session; NSSSlot *slot; CK_ULONG template_size; CK_ATTRIBUTE_PTR attr; CK_ATTRIBUTE cert_template[6]; /* Set up a template of all options chosen by caller */ NSS_CK_TEMPLATE_START(cert_template, attr, template_size); if (certTypeOpt) { NSS_CK_SET_ATTRIBUTE_NULL(attr, CKA_CERTIFICATE_TYPE); } if (idOpt) { NSS_CK_SET_ATTRIBUTE_NULL(attr, CKA_ID); } if (encodingOpt) { NSS_CK_SET_ATTRIBUTE_NULL(attr, CKA_VALUE); } if (issuerOpt) { NSS_CK_SET_ATTRIBUTE_NULL(attr, CKA_ISSUER); } if (serialOpt) { NSS_CK_SET_ATTRIBUTE_NULL(attr, CKA_SERIAL_NUMBER); } if (subjectOpt) { NSS_CK_SET_ATTRIBUTE_NULL(attr, CKA_SUBJECT); } NSS_CK_TEMPLATE_FINISH(cert_template, attr, template_size); if (template_size == 0) { /* caller didn't want anything */ return PR_SUCCESS; } status = nssToken_GetCachedObjectAttributes(certObject->token, arenaOpt, certObject, CKO_CERTIFICATE, cert_template, template_size); if (status != PR_SUCCESS) { session = sessionOpt ? sessionOpt : nssToken_GetDefaultSession(certObject->token); if (!session) { nss_SetError(NSS_ERROR_INVALID_ARGUMENT); return PR_FAILURE; } slot = nssToken_GetSlot(certObject->token); status = nssCKObject_GetAttributes(certObject->handle, cert_template, template_size, arenaOpt, session, slot); nssSlot_Destroy(slot); if (status != PR_SUCCESS) { return status; } } i = 0; if (certTypeOpt) { *certTypeOpt = nss_cert_type_from_ck_attrib(&cert_template[i]); i++; } if (idOpt) { NSS_CK_ATTRIBUTE_TO_ITEM(&cert_template[i], idOpt); i++; } if (encodingOpt) { NSS_CK_ATTRIBUTE_TO_ITEM(&cert_template[i], encodingOpt); i++; } if (issuerOpt) { NSS_CK_ATTRIBUTE_TO_ITEM(&cert_template[i], issuerOpt); i++; } if (serialOpt) { NSS_CK_ATTRIBUTE_TO_ITEM(&cert_template[i], serialOpt); i++; } if (subjectOpt) { NSS_CK_ATTRIBUTE_TO_ITEM(&cert_template[i], subjectOpt); i++; } return PR_SUCCESS; }