mirror of
https://github.com/rn10950/RetroZilla.git
synced 2024-11-14 11:40:13 +01:00
44b7f056d9
bug1001332, 56b691c003ad, bug1086145, bug1054069, bug1155922, bug991783, bug1125025, bug1162521, bug1162644, bug1132941, bug1164364, bug1166205, bug1166163, bug1166515, bug1138554, bug1167046, bug1167043, bug1169451, bug1172128, bug1170322, bug102794, bug1128184, bug557830, bug1174648, bug1180244, bug1177784, bug1173413, bug1169174, bug1084669, bug951455, bug1183395, bug1177430, bug1183827, bug1160139, bug1154106, bug1142209, bug1185033, bug1193467, bug1182667(with sha512 changes backed out, which breaks VC6 compilation), bug1158489, bug337796
1580 lines
47 KiB
C
1580 lines
47 KiB
C
/* 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/. */
|
|
|
|
#include "pkcs11.h"
|
|
|
|
#ifndef DEVM_H
|
|
#include "devm.h"
|
|
#endif /* DEVM_H */
|
|
|
|
#ifndef CKHELPER_H
|
|
#include "ckhelper.h"
|
|
#endif /* CKHELPER_H */
|
|
|
|
#include "pk11func.h"
|
|
#include "dev3hack.h"
|
|
#include "secerr.h"
|
|
|
|
extern const NSSError NSS_ERROR_NOT_FOUND;
|
|
extern const NSSError NSS_ERROR_INVALID_ARGUMENT;
|
|
extern const NSSError NSS_ERROR_PKCS11;
|
|
|
|
/* The number of object handles to grab during each call to C_FindObjects */
|
|
#define OBJECT_STACK_SIZE 16
|
|
|
|
NSS_IMPLEMENT PRStatus
|
|
nssToken_Destroy (
|
|
NSSToken *tok
|
|
)
|
|
{
|
|
if (tok) {
|
|
if (PR_ATOMIC_DECREMENT(&tok->base.refCount) == 0) {
|
|
PZ_DestroyLock(tok->base.lock);
|
|
nssTokenObjectCache_Destroy(tok->cache);
|
|
/* The token holds the first/last reference to the slot.
|
|
* When the token is actually destroyed, that ref must go too.
|
|
*/
|
|
(void)nssSlot_Destroy(tok->slot);
|
|
return nssArena_Destroy(tok->base.arena);
|
|
}
|
|
}
|
|
return PR_SUCCESS;
|
|
}
|
|
|
|
NSS_IMPLEMENT void
|
|
nssToken_Remove (
|
|
NSSToken *tok
|
|
)
|
|
{
|
|
nssTokenObjectCache_Clear(tok->cache);
|
|
}
|
|
|
|
NSS_IMPLEMENT void
|
|
NSSToken_Destroy (
|
|
NSSToken *tok
|
|
)
|
|
{
|
|
(void)nssToken_Destroy(tok);
|
|
}
|
|
|
|
NSS_IMPLEMENT NSSToken *
|
|
nssToken_AddRef (
|
|
NSSToken *tok
|
|
)
|
|
{
|
|
PR_ATOMIC_INCREMENT(&tok->base.refCount);
|
|
return tok;
|
|
}
|
|
|
|
NSS_IMPLEMENT NSSSlot *
|
|
nssToken_GetSlot (
|
|
NSSToken *tok
|
|
)
|
|
{
|
|
return nssSlot_AddRef(tok->slot);
|
|
}
|
|
|
|
NSS_IMPLEMENT void *
|
|
nssToken_GetCryptokiEPV (
|
|
NSSToken *token
|
|
)
|
|
{
|
|
return nssSlot_GetCryptokiEPV(token->slot);
|
|
}
|
|
|
|
NSS_IMPLEMENT nssSession *
|
|
nssToken_GetDefaultSession (
|
|
NSSToken *token
|
|
)
|
|
{
|
|
return token->defaultSession;
|
|
}
|
|
|
|
NSS_IMPLEMENT NSSUTF8 *
|
|
nssToken_GetName (
|
|
NSSToken *tok
|
|
)
|
|
{
|
|
if (tok == NULL) {
|
|
return "";
|
|
}
|
|
if (tok->base.name[0] == 0) {
|
|
(void) nssSlot_IsTokenPresent(tok->slot);
|
|
}
|
|
return tok->base.name;
|
|
}
|
|
|
|
NSS_IMPLEMENT NSSUTF8 *
|
|
NSSToken_GetName (
|
|
NSSToken *token
|
|
)
|
|
{
|
|
return nssToken_GetName(token);
|
|
}
|
|
|
|
NSS_IMPLEMENT PRBool
|
|
nssToken_IsLoginRequired (
|
|
NSSToken *token
|
|
)
|
|
{
|
|
return (token->ckFlags & CKF_LOGIN_REQUIRED);
|
|
}
|
|
|
|
NSS_IMPLEMENT PRBool
|
|
nssToken_NeedsPINInitialization (
|
|
NSSToken *token
|
|
)
|
|
{
|
|
return (!(token->ckFlags & CKF_USER_PIN_INITIALIZED));
|
|
}
|
|
|
|
NSS_IMPLEMENT PRStatus
|
|
nssToken_DeleteStoredObject (
|
|
nssCryptokiObject *instance
|
|
)
|
|
{
|
|
CK_RV ckrv;
|
|
PRStatus status;
|
|
PRBool createdSession = PR_FALSE;
|
|
NSSToken *token = instance->token;
|
|
nssSession *session = NULL;
|
|
void *epv = nssToken_GetCryptokiEPV(instance->token);
|
|
if (token->cache) {
|
|
nssTokenObjectCache_RemoveObject(token->cache, instance);
|
|
}
|
|
if (instance->isTokenObject) {
|
|
if (token->defaultSession &&
|
|
nssSession_IsReadWrite(token->defaultSession)) {
|
|
session = token->defaultSession;
|
|
} else {
|
|
session = nssSlot_CreateSession(token->slot, NULL, PR_TRUE);
|
|
createdSession = PR_TRUE;
|
|
}
|
|
}
|
|
if (session == NULL) {
|
|
return PR_FAILURE;
|
|
}
|
|
nssSession_EnterMonitor(session);
|
|
ckrv = CKAPI(epv)->C_DestroyObject(session->handle, instance->handle);
|
|
nssSession_ExitMonitor(session);
|
|
if (createdSession) {
|
|
nssSession_Destroy(session);
|
|
}
|
|
status = PR_SUCCESS;
|
|
if (ckrv != CKR_OK) {
|
|
status = PR_FAILURE;
|
|
/* use the error stack to pass the PKCS #11 error out */
|
|
nss_SetError(ckrv);
|
|
nss_SetError(NSS_ERROR_PKCS11);
|
|
}
|
|
return status;
|
|
}
|
|
|
|
static nssCryptokiObject *
|
|
import_object (
|
|
NSSToken *tok,
|
|
nssSession *sessionOpt,
|
|
CK_ATTRIBUTE_PTR objectTemplate,
|
|
CK_ULONG otsize
|
|
)
|
|
{
|
|
nssSession *session = NULL;
|
|
PRBool createdSession = PR_FALSE;
|
|
nssCryptokiObject *object = NULL;
|
|
CK_OBJECT_HANDLE handle;
|
|
CK_RV ckrv;
|
|
void *epv = nssToken_GetCryptokiEPV(tok);
|
|
if (nssCKObject_IsTokenObjectTemplate(objectTemplate, otsize)) {
|
|
if (sessionOpt) {
|
|
if (!nssSession_IsReadWrite(sessionOpt)) {
|
|
nss_SetError(NSS_ERROR_INVALID_ARGUMENT);
|
|
return NULL;
|
|
}
|
|
session = sessionOpt;
|
|
} else if (tok->defaultSession &&
|
|
nssSession_IsReadWrite(tok->defaultSession)) {
|
|
session = tok->defaultSession;
|
|
} else {
|
|
session = nssSlot_CreateSession(tok->slot, NULL, PR_TRUE);
|
|
createdSession = PR_TRUE;
|
|
}
|
|
} else {
|
|
session = (sessionOpt) ? sessionOpt : tok->defaultSession;
|
|
}
|
|
if (session == NULL) {
|
|
nss_SetError(NSS_ERROR_INVALID_ARGUMENT);
|
|
return NULL;
|
|
}
|
|
nssSession_EnterMonitor(session);
|
|
ckrv = CKAPI(epv)->C_CreateObject(session->handle,
|
|
objectTemplate, otsize,
|
|
&handle);
|
|
nssSession_ExitMonitor(session);
|
|
if (ckrv == CKR_OK) {
|
|
object = nssCryptokiObject_Create(tok, session, handle);
|
|
} else {
|
|
nss_SetError(ckrv);
|
|
nss_SetError(NSS_ERROR_PKCS11);
|
|
}
|
|
if (createdSession) {
|
|
nssSession_Destroy(session);
|
|
}
|
|
return object;
|
|
}
|
|
|
|
static nssCryptokiObject **
|
|
create_objects_from_handles (
|
|
NSSToken *tok,
|
|
nssSession *session,
|
|
CK_OBJECT_HANDLE *handles,
|
|
PRUint32 numH
|
|
)
|
|
{
|
|
nssCryptokiObject **objects;
|
|
objects = nss_ZNEWARRAY(NULL, nssCryptokiObject *, numH + 1);
|
|
if (objects) {
|
|
PRInt32 i;
|
|
for (i=0; i<(PRInt32)numH; i++) {
|
|
objects[i] = nssCryptokiObject_Create(tok, session, handles[i]);
|
|
if (!objects[i]) {
|
|
for (--i; i>0; --i) {
|
|
nssCryptokiObject_Destroy(objects[i]);
|
|
}
|
|
nss_ZFreeIf(objects);
|
|
objects = NULL;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return objects;
|
|
}
|
|
|
|
static nssCryptokiObject **
|
|
find_objects (
|
|
NSSToken *tok,
|
|
nssSession *sessionOpt,
|
|
CK_ATTRIBUTE_PTR obj_template,
|
|
CK_ULONG otsize,
|
|
PRUint32 maximumOpt,
|
|
PRStatus *statusOpt
|
|
)
|
|
{
|
|
CK_RV ckrv = CKR_OK;
|
|
CK_ULONG count;
|
|
CK_OBJECT_HANDLE *objectHandles = NULL;
|
|
CK_OBJECT_HANDLE staticObjects[OBJECT_STACK_SIZE];
|
|
PRUint32 arraySize, numHandles;
|
|
void *epv = nssToken_GetCryptokiEPV(tok);
|
|
nssCryptokiObject **objects;
|
|
nssSession *session = (sessionOpt) ? sessionOpt : tok->defaultSession;
|
|
|
|
/* Don't ask the module to use an invalid session handle. */
|
|
if (!session || session->handle == CK_INVALID_SESSION) {
|
|
ckrv = CKR_SESSION_HANDLE_INVALID;
|
|
goto loser;
|
|
}
|
|
|
|
/* the arena is only for the array of object handles */
|
|
if (maximumOpt > 0) {
|
|
arraySize = maximumOpt;
|
|
} else {
|
|
arraySize = OBJECT_STACK_SIZE;
|
|
}
|
|
numHandles = 0;
|
|
if (arraySize <= OBJECT_STACK_SIZE) {
|
|
objectHandles = staticObjects;
|
|
} else {
|
|
objectHandles = nss_ZNEWARRAY(NULL, CK_OBJECT_HANDLE, arraySize);
|
|
}
|
|
if (!objectHandles) {
|
|
ckrv = CKR_HOST_MEMORY;
|
|
goto loser;
|
|
}
|
|
nssSession_EnterMonitor(session); /* ==== session lock === */
|
|
/* Initialize the find with the template */
|
|
ckrv = CKAPI(epv)->C_FindObjectsInit(session->handle,
|
|
obj_template, otsize);
|
|
if (ckrv != CKR_OK) {
|
|
nssSession_ExitMonitor(session);
|
|
goto loser;
|
|
}
|
|
while (PR_TRUE) {
|
|
/* Issue the find for up to arraySize - numHandles objects */
|
|
ckrv = CKAPI(epv)->C_FindObjects(session->handle,
|
|
objectHandles + numHandles,
|
|
arraySize - numHandles,
|
|
&count);
|
|
if (ckrv != CKR_OK) {
|
|
nssSession_ExitMonitor(session);
|
|
goto loser;
|
|
}
|
|
/* bump the number of found objects */
|
|
numHandles += count;
|
|
if (maximumOpt > 0 || numHandles < arraySize) {
|
|
/* When a maximum is provided, the search is done all at once,
|
|
* so the search is finished. If the number returned was less
|
|
* than the number sought, the search is finished.
|
|
*/
|
|
break;
|
|
}
|
|
/* the array is filled, double it and continue */
|
|
arraySize *= 2;
|
|
if (objectHandles == staticObjects) {
|
|
objectHandles = nss_ZNEWARRAY(NULL,CK_OBJECT_HANDLE, arraySize);
|
|
if (objectHandles) {
|
|
PORT_Memcpy(objectHandles, staticObjects,
|
|
OBJECT_STACK_SIZE * sizeof(objectHandles[1]));
|
|
}
|
|
} else {
|
|
objectHandles = nss_ZREALLOCARRAY(objectHandles,
|
|
CK_OBJECT_HANDLE,
|
|
arraySize);
|
|
}
|
|
if (!objectHandles) {
|
|
nssSession_ExitMonitor(session);
|
|
ckrv = CKR_HOST_MEMORY;
|
|
goto loser;
|
|
}
|
|
}
|
|
ckrv = CKAPI(epv)->C_FindObjectsFinal(session->handle);
|
|
nssSession_ExitMonitor(session); /* ==== end session lock === */
|
|
if (ckrv != CKR_OK) {
|
|
goto loser;
|
|
}
|
|
if (numHandles > 0) {
|
|
objects = create_objects_from_handles(tok, session,
|
|
objectHandles, numHandles);
|
|
} else {
|
|
nss_SetError(NSS_ERROR_NOT_FOUND);
|
|
objects = NULL;
|
|
}
|
|
if (objectHandles && objectHandles != staticObjects) {
|
|
nss_ZFreeIf(objectHandles);
|
|
}
|
|
if (statusOpt) *statusOpt = PR_SUCCESS;
|
|
return objects;
|
|
loser:
|
|
if (objectHandles && objectHandles != staticObjects) {
|
|
nss_ZFreeIf(objectHandles);
|
|
}
|
|
/*
|
|
* These errors should be treated the same as if the objects just weren't
|
|
* found..
|
|
*/
|
|
if ((ckrv == CKR_ATTRIBUTE_TYPE_INVALID) ||
|
|
(ckrv == CKR_ATTRIBUTE_VALUE_INVALID) ||
|
|
(ckrv == CKR_DATA_INVALID) ||
|
|
(ckrv == CKR_DATA_LEN_RANGE) ||
|
|
(ckrv == CKR_FUNCTION_NOT_SUPPORTED) ||
|
|
(ckrv == CKR_TEMPLATE_INCOMPLETE) ||
|
|
(ckrv == CKR_TEMPLATE_INCONSISTENT)) {
|
|
|
|
nss_SetError(NSS_ERROR_NOT_FOUND);
|
|
if (statusOpt) *statusOpt = PR_SUCCESS;
|
|
} else {
|
|
nss_SetError(ckrv);
|
|
nss_SetError(NSS_ERROR_PKCS11);
|
|
if (statusOpt) *statusOpt = PR_FAILURE;
|
|
}
|
|
return (nssCryptokiObject **)NULL;
|
|
}
|
|
|
|
static nssCryptokiObject **
|
|
find_objects_by_template (
|
|
NSSToken *token,
|
|
nssSession *sessionOpt,
|
|
CK_ATTRIBUTE_PTR obj_template,
|
|
CK_ULONG otsize,
|
|
PRUint32 maximumOpt,
|
|
PRStatus *statusOpt
|
|
)
|
|
{
|
|
CK_OBJECT_CLASS objclass = (CK_OBJECT_CLASS)-1;
|
|
nssCryptokiObject **objects = NULL;
|
|
PRUint32 i;
|
|
|
|
if (!token) {
|
|
PORT_SetError(SEC_ERROR_NO_TOKEN);
|
|
if (statusOpt)
|
|
*statusOpt = PR_FAILURE;
|
|
return NULL;
|
|
}
|
|
for (i=0; i<otsize; i++) {
|
|
if (obj_template[i].type == CKA_CLASS) {
|
|
objclass = *(CK_OBJECT_CLASS *)obj_template[i].pValue;
|
|
break;
|
|
}
|
|
}
|
|
PR_ASSERT(i < otsize);
|
|
if (i == otsize) {
|
|
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
|
|
if (statusOpt) *statusOpt = PR_FAILURE;
|
|
return NULL;
|
|
}
|
|
/* If these objects are being cached, try looking there first */
|
|
if (token->cache &&
|
|
nssTokenObjectCache_HaveObjectClass(token->cache, objclass))
|
|
{
|
|
PRStatus status;
|
|
objects = nssTokenObjectCache_FindObjectsByTemplate(token->cache,
|
|
objclass,
|
|
obj_template,
|
|
otsize,
|
|
maximumOpt,
|
|
&status);
|
|
if (status == PR_SUCCESS) {
|
|
if (statusOpt) *statusOpt = status;
|
|
return objects;
|
|
}
|
|
}
|
|
/* Either they are not cached, or cache failed; look on token. */
|
|
objects = find_objects(token, sessionOpt,
|
|
obj_template, otsize,
|
|
maximumOpt, statusOpt);
|
|
return objects;
|
|
}
|
|
|
|
extern const NSSError NSS_ERROR_INVALID_CERTIFICATE;
|
|
|
|
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;
|
|
}
|
|
|
|
/* traverse all objects of the given class - this should only happen
|
|
* if the token has been marked as "traversable"
|
|
*/
|
|
NSS_IMPLEMENT nssCryptokiObject **
|
|
nssToken_FindObjects (
|
|
NSSToken *token,
|
|
nssSession *sessionOpt,
|
|
CK_OBJECT_CLASS objclass,
|
|
nssTokenSearchType searchType,
|
|
PRUint32 maximumOpt,
|
|
PRStatus *statusOpt
|
|
)
|
|
{
|
|
CK_ATTRIBUTE_PTR attr;
|
|
CK_ATTRIBUTE obj_template[2];
|
|
CK_ULONG obj_size;
|
|
nssCryptokiObject **objects;
|
|
NSS_CK_TEMPLATE_START(obj_template, attr, obj_size);
|
|
/* Set the search to token/session only if provided */
|
|
if (searchType == nssTokenSearchType_SessionOnly) {
|
|
NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
|
|
} else if (searchType == nssTokenSearchType_TokenOnly ||
|
|
searchType == nssTokenSearchType_TokenForced) {
|
|
NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
|
|
}
|
|
NSS_CK_SET_ATTRIBUTE_VAR( attr, CKA_CLASS, objclass);
|
|
NSS_CK_TEMPLATE_FINISH(obj_template, attr, obj_size);
|
|
|
|
if (searchType == nssTokenSearchType_TokenForced) {
|
|
objects = find_objects(token, sessionOpt,
|
|
obj_template, obj_size,
|
|
maximumOpt, statusOpt);
|
|
} else {
|
|
objects = find_objects_by_template(token, sessionOpt,
|
|
obj_template, obj_size,
|
|
maximumOpt, statusOpt);
|
|
}
|
|
return objects;
|
|
}
|
|
|
|
NSS_IMPLEMENT nssCryptokiObject **
|
|
nssToken_FindCertificatesBySubject (
|
|
NSSToken *token,
|
|
nssSession *sessionOpt,
|
|
NSSDER *subject,
|
|
nssTokenSearchType searchType,
|
|
PRUint32 maximumOpt,
|
|
PRStatus *statusOpt
|
|
)
|
|
{
|
|
CK_ATTRIBUTE_PTR attr;
|
|
CK_ATTRIBUTE subj_template[3];
|
|
CK_ULONG stsize;
|
|
nssCryptokiObject **objects;
|
|
NSS_CK_TEMPLATE_START(subj_template, attr, stsize);
|
|
/* Set the search to token/session only if provided */
|
|
if (searchType == nssTokenSearchType_SessionOnly) {
|
|
NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
|
|
} else if (searchType == nssTokenSearchType_TokenOnly) {
|
|
NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
|
|
}
|
|
NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_cert);
|
|
NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SUBJECT, subject);
|
|
NSS_CK_TEMPLATE_FINISH(subj_template, attr, stsize);
|
|
/* now locate the token certs matching this template */
|
|
objects = find_objects_by_template(token, sessionOpt,
|
|
subj_template, stsize,
|
|
maximumOpt, statusOpt);
|
|
return objects;
|
|
}
|
|
|
|
NSS_IMPLEMENT nssCryptokiObject **
|
|
nssToken_FindCertificatesByNickname (
|
|
NSSToken *token,
|
|
nssSession *sessionOpt,
|
|
const NSSUTF8 *name,
|
|
nssTokenSearchType searchType,
|
|
PRUint32 maximumOpt,
|
|
PRStatus *statusOpt
|
|
)
|
|
{
|
|
CK_ATTRIBUTE_PTR attr;
|
|
CK_ATTRIBUTE nick_template[3];
|
|
CK_ULONG ntsize;
|
|
nssCryptokiObject **objects;
|
|
NSS_CK_TEMPLATE_START(nick_template, attr, ntsize);
|
|
NSS_CK_SET_ATTRIBUTE_UTF8(attr, CKA_LABEL, name);
|
|
/* Set the search to token/session only if provided */
|
|
if (searchType == nssTokenSearchType_SessionOnly) {
|
|
NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
|
|
} else if (searchType == nssTokenSearchType_TokenOnly) {
|
|
NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
|
|
}
|
|
NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_cert);
|
|
NSS_CK_TEMPLATE_FINISH(nick_template, attr, ntsize);
|
|
/* now locate the token certs matching this template */
|
|
objects = find_objects_by_template(token, sessionOpt,
|
|
nick_template, ntsize,
|
|
maximumOpt, statusOpt);
|
|
if (!objects) {
|
|
/* This is to workaround the fact that PKCS#11 doesn't specify
|
|
* whether the '\0' should be included. XXX Is that still true?
|
|
* im - this is not needed by the current softoken. However, I'm
|
|
* leaving it in until I have surveyed more tokens to see if it needed.
|
|
* well, its needed by the builtin token...
|
|
*/
|
|
nick_template[0].ulValueLen++;
|
|
objects = find_objects_by_template(token, sessionOpt,
|
|
nick_template, ntsize,
|
|
maximumOpt, statusOpt);
|
|
}
|
|
return objects;
|
|
}
|
|
|
|
/* XXX
|
|
* This function *does not* use the token object cache, because not even
|
|
* the softoken will return a value for CKA_NSS_EMAIL from a call
|
|
* to GetAttributes. The softoken does allow searches with that attribute,
|
|
* it just won't return a value for it.
|
|
*/
|
|
NSS_IMPLEMENT nssCryptokiObject **
|
|
nssToken_FindCertificatesByEmail (
|
|
NSSToken *token,
|
|
nssSession *sessionOpt,
|
|
NSSASCII7 *email,
|
|
nssTokenSearchType searchType,
|
|
PRUint32 maximumOpt,
|
|
PRStatus *statusOpt
|
|
)
|
|
{
|
|
CK_ATTRIBUTE_PTR attr;
|
|
CK_ATTRIBUTE email_template[3];
|
|
CK_ULONG etsize;
|
|
nssCryptokiObject **objects;
|
|
NSS_CK_TEMPLATE_START(email_template, attr, etsize);
|
|
NSS_CK_SET_ATTRIBUTE_UTF8(attr, CKA_NSS_EMAIL, email);
|
|
/* Set the search to token/session only if provided */
|
|
if (searchType == nssTokenSearchType_SessionOnly) {
|
|
NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
|
|
} else if (searchType == nssTokenSearchType_TokenOnly) {
|
|
NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
|
|
}
|
|
NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_cert);
|
|
NSS_CK_TEMPLATE_FINISH(email_template, attr, etsize);
|
|
/* now locate the token certs matching this template */
|
|
objects = find_objects(token, sessionOpt,
|
|
email_template, etsize,
|
|
maximumOpt, statusOpt);
|
|
if (!objects) {
|
|
/* This is to workaround the fact that PKCS#11 doesn't specify
|
|
* whether the '\0' should be included. XXX Is that still true?
|
|
* im - this is not needed by the current softoken. However, I'm
|
|
* leaving it in until I have surveyed more tokens to see if it needed.
|
|
* well, its needed by the builtin token...
|
|
*/
|
|
email_template[0].ulValueLen++;
|
|
objects = find_objects(token, sessionOpt,
|
|
email_template, etsize,
|
|
maximumOpt, statusOpt);
|
|
}
|
|
return objects;
|
|
}
|
|
|
|
NSS_IMPLEMENT nssCryptokiObject **
|
|
nssToken_FindCertificatesByID (
|
|
NSSToken *token,
|
|
nssSession *sessionOpt,
|
|
NSSItem *id,
|
|
nssTokenSearchType searchType,
|
|
PRUint32 maximumOpt,
|
|
PRStatus *statusOpt
|
|
)
|
|
{
|
|
CK_ATTRIBUTE_PTR attr;
|
|
CK_ATTRIBUTE id_template[3];
|
|
CK_ULONG idtsize;
|
|
nssCryptokiObject **objects;
|
|
NSS_CK_TEMPLATE_START(id_template, attr, idtsize);
|
|
NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ID, id);
|
|
/* Set the search to token/session only if provided */
|
|
if (searchType == nssTokenSearchType_SessionOnly) {
|
|
NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
|
|
} else if (searchType == nssTokenSearchType_TokenOnly) {
|
|
NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
|
|
}
|
|
NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_cert);
|
|
NSS_CK_TEMPLATE_FINISH(id_template, attr, idtsize);
|
|
/* now locate the token certs matching this template */
|
|
objects = find_objects_by_template(token, sessionOpt,
|
|
id_template, idtsize,
|
|
maximumOpt, statusOpt);
|
|
return objects;
|
|
}
|
|
|
|
/*
|
|
* decode the serial item and return our result.
|
|
* NOTE serialDecode's data is really stored in serial. Don't free it.
|
|
*/
|
|
static PRStatus
|
|
nssToken_decodeSerialItem(NSSItem *serial, NSSItem *serialDecode)
|
|
{
|
|
unsigned char *data = (unsigned char *)serial->data;
|
|
int data_left, data_len, index;
|
|
|
|
if ((serial->size >= 3) && (data[0] == 0x2)) {
|
|
/* remove the der encoding of the serial number before generating the
|
|
* key.. */
|
|
data_left = serial->size-2;
|
|
data_len = data[1];
|
|
index = 2;
|
|
|
|
/* extended length ? (not very likely for a serial number) */
|
|
if (data_len & 0x80) {
|
|
int len_count = data_len & 0x7f;
|
|
|
|
data_len = 0;
|
|
data_left -= len_count;
|
|
if (data_left > 0) {
|
|
while (len_count --) {
|
|
data_len = (data_len << 8) | data[index++];
|
|
}
|
|
}
|
|
}
|
|
/* XXX leaving any leading zeros on the serial number for backwards
|
|
* compatibility
|
|
*/
|
|
/* not a valid der, must be just an unlucky serial number value */
|
|
if (data_len == data_left) {
|
|
serialDecode->size = data_len;
|
|
serialDecode->data = &data[index];
|
|
return PR_SUCCESS;
|
|
}
|
|
}
|
|
return PR_FAILURE;
|
|
}
|
|
|
|
NSS_IMPLEMENT nssCryptokiObject *
|
|
nssToken_FindCertificateByIssuerAndSerialNumber (
|
|
NSSToken *token,
|
|
nssSession *sessionOpt,
|
|
NSSDER *issuer,
|
|
NSSDER *serial,
|
|
nssTokenSearchType searchType,
|
|
PRStatus *statusOpt
|
|
)
|
|
{
|
|
CK_ATTRIBUTE_PTR attr;
|
|
CK_ATTRIBUTE_PTR serialAttr;
|
|
CK_ATTRIBUTE cert_template[4];
|
|
CK_ULONG ctsize;
|
|
nssCryptokiObject **objects;
|
|
nssCryptokiObject *rvObject = NULL;
|
|
NSS_CK_TEMPLATE_START(cert_template, attr, ctsize);
|
|
|
|
if (!token) {
|
|
PORT_SetError(SEC_ERROR_NO_TOKEN);
|
|
if (statusOpt)
|
|
*statusOpt = PR_FAILURE;
|
|
return NULL;
|
|
}
|
|
/* Set the search to token/session only if provided */
|
|
if (searchType == nssTokenSearchType_SessionOnly) {
|
|
NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
|
|
} else if ((searchType == nssTokenSearchType_TokenOnly) ||
|
|
(searchType == nssTokenSearchType_TokenForced)) {
|
|
NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
|
|
}
|
|
/* Set the unique id */
|
|
NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_cert);
|
|
NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ISSUER, issuer);
|
|
serialAttr = attr;
|
|
NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SERIAL_NUMBER, serial);
|
|
NSS_CK_TEMPLATE_FINISH(cert_template, attr, ctsize);
|
|
/* get the object handle */
|
|
if (searchType == nssTokenSearchType_TokenForced) {
|
|
objects = find_objects(token, sessionOpt,
|
|
cert_template, ctsize,
|
|
1, statusOpt);
|
|
} else {
|
|
objects = find_objects_by_template(token, sessionOpt,
|
|
cert_template, ctsize,
|
|
1, statusOpt);
|
|
}
|
|
if (objects) {
|
|
rvObject = objects[0];
|
|
nss_ZFreeIf(objects);
|
|
}
|
|
|
|
/*
|
|
* NSS used to incorrectly store serial numbers in their decoded form.
|
|
* because of this old tokens have decoded serial numbers.
|
|
*/
|
|
if (!objects) {
|
|
NSSItem serialDecode;
|
|
PRStatus status;
|
|
|
|
status = nssToken_decodeSerialItem(serial, &serialDecode);
|
|
if (status != PR_SUCCESS) {
|
|
return NULL;
|
|
}
|
|
NSS_CK_SET_ATTRIBUTE_ITEM(serialAttr,CKA_SERIAL_NUMBER,&serialDecode);
|
|
if (searchType == nssTokenSearchType_TokenForced) {
|
|
objects = find_objects(token, sessionOpt,
|
|
cert_template, ctsize,
|
|
1, statusOpt);
|
|
} else {
|
|
objects = find_objects_by_template(token, sessionOpt,
|
|
cert_template, ctsize,
|
|
1, statusOpt);
|
|
}
|
|
if (objects) {
|
|
rvObject = objects[0];
|
|
nss_ZFreeIf(objects);
|
|
}
|
|
}
|
|
return rvObject;
|
|
}
|
|
|
|
NSS_IMPLEMENT nssCryptokiObject *
|
|
nssToken_FindCertificateByEncodedCertificate (
|
|
NSSToken *token,
|
|
nssSession *sessionOpt,
|
|
NSSBER *encodedCertificate,
|
|
nssTokenSearchType searchType,
|
|
PRStatus *statusOpt
|
|
)
|
|
{
|
|
CK_ATTRIBUTE_PTR attr;
|
|
CK_ATTRIBUTE cert_template[3];
|
|
CK_ULONG ctsize;
|
|
nssCryptokiObject **objects;
|
|
nssCryptokiObject *rvObject = NULL;
|
|
NSS_CK_TEMPLATE_START(cert_template, attr, ctsize);
|
|
/* Set the search to token/session only if provided */
|
|
if (searchType == nssTokenSearchType_SessionOnly) {
|
|
NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
|
|
} else if (searchType == nssTokenSearchType_TokenOnly) {
|
|
NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
|
|
}
|
|
NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_cert);
|
|
NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_VALUE, encodedCertificate);
|
|
NSS_CK_TEMPLATE_FINISH(cert_template, attr, ctsize);
|
|
/* get the object handle */
|
|
objects = find_objects_by_template(token, sessionOpt,
|
|
cert_template, ctsize,
|
|
1, statusOpt);
|
|
if (objects) {
|
|
rvObject = objects[0];
|
|
nss_ZFreeIf(objects);
|
|
}
|
|
return rvObject;
|
|
}
|
|
|
|
NSS_IMPLEMENT nssCryptokiObject **
|
|
nssToken_FindPrivateKeys (
|
|
NSSToken *token,
|
|
nssSession *sessionOpt,
|
|
nssTokenSearchType searchType,
|
|
PRUint32 maximumOpt,
|
|
PRStatus *statusOpt
|
|
)
|
|
{
|
|
CK_ATTRIBUTE_PTR attr;
|
|
CK_ATTRIBUTE key_template[2];
|
|
CK_ULONG ktsize;
|
|
nssCryptokiObject **objects;
|
|
|
|
NSS_CK_TEMPLATE_START(key_template, attr, ktsize);
|
|
NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_privkey);
|
|
if (searchType == nssTokenSearchType_SessionOnly) {
|
|
NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
|
|
} else if (searchType == nssTokenSearchType_TokenOnly) {
|
|
NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
|
|
}
|
|
NSS_CK_TEMPLATE_FINISH(key_template, attr, ktsize);
|
|
|
|
objects = find_objects_by_template(token, sessionOpt,
|
|
key_template, ktsize,
|
|
maximumOpt, statusOpt);
|
|
return objects;
|
|
}
|
|
|
|
/* XXX ?there are no session cert objects, so only search token objects */
|
|
NSS_IMPLEMENT nssCryptokiObject *
|
|
nssToken_FindPrivateKeyByID (
|
|
NSSToken *token,
|
|
nssSession *sessionOpt,
|
|
NSSItem *keyID
|
|
)
|
|
{
|
|
CK_ATTRIBUTE_PTR attr;
|
|
CK_ATTRIBUTE key_template[3];
|
|
CK_ULONG ktsize;
|
|
nssCryptokiObject **objects;
|
|
nssCryptokiObject *rvKey = NULL;
|
|
|
|
NSS_CK_TEMPLATE_START(key_template, attr, ktsize);
|
|
NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_privkey);
|
|
NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
|
|
NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ID, keyID);
|
|
NSS_CK_TEMPLATE_FINISH(key_template, attr, ktsize);
|
|
|
|
objects = find_objects_by_template(token, sessionOpt,
|
|
key_template, ktsize,
|
|
1, NULL);
|
|
if (objects) {
|
|
rvKey = objects[0];
|
|
nss_ZFreeIf(objects);
|
|
}
|
|
return rvKey;
|
|
}
|
|
|
|
/* XXX ?there are no session cert objects, so only search token objects */
|
|
NSS_IMPLEMENT nssCryptokiObject *
|
|
nssToken_FindPublicKeyByID (
|
|
NSSToken *token,
|
|
nssSession *sessionOpt,
|
|
NSSItem *keyID
|
|
)
|
|
{
|
|
CK_ATTRIBUTE_PTR attr;
|
|
CK_ATTRIBUTE key_template[3];
|
|
CK_ULONG ktsize;
|
|
nssCryptokiObject **objects;
|
|
nssCryptokiObject *rvKey = NULL;
|
|
|
|
NSS_CK_TEMPLATE_START(key_template, attr, ktsize);
|
|
NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_pubkey);
|
|
NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
|
|
NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ID, keyID);
|
|
NSS_CK_TEMPLATE_FINISH(key_template, attr, ktsize);
|
|
|
|
objects = find_objects_by_template(token, sessionOpt,
|
|
key_template, ktsize,
|
|
1, NULL);
|
|
if (objects) {
|
|
rvKey = objects[0];
|
|
nss_ZFreeIf(objects);
|
|
}
|
|
return rvKey;
|
|
}
|
|
|
|
static void
|
|
sha1_hash(NSSItem *input, NSSItem *output)
|
|
{
|
|
NSSAlgorithmAndParameters *ap;
|
|
PK11SlotInfo *internal = PK11_GetInternalSlot();
|
|
NSSToken *token = PK11Slot_GetNSSToken(internal);
|
|
ap = NSSAlgorithmAndParameters_CreateSHA1Digest(NULL);
|
|
(void)nssToken_Digest(token, NULL, ap, input, output, NULL);
|
|
PK11_FreeSlot(token->pk11slot);
|
|
nss_ZFreeIf(ap);
|
|
}
|
|
|
|
static void
|
|
md5_hash(NSSItem *input, NSSItem *output)
|
|
{
|
|
NSSAlgorithmAndParameters *ap;
|
|
PK11SlotInfo *internal = PK11_GetInternalSlot();
|
|
NSSToken *token = PK11Slot_GetNSSToken(internal);
|
|
ap = NSSAlgorithmAndParameters_CreateMD5Digest(NULL);
|
|
(void)nssToken_Digest(token, NULL, ap, input, output, NULL);
|
|
PK11_FreeSlot(token->pk11slot);
|
|
nss_ZFreeIf(ap);
|
|
}
|
|
|
|
static CK_TRUST
|
|
get_ck_trust (
|
|
nssTrustLevel nssTrust
|
|
)
|
|
{
|
|
CK_TRUST t;
|
|
switch (nssTrust) {
|
|
case nssTrustLevel_NotTrusted: t = CKT_NSS_NOT_TRUSTED; break;
|
|
case nssTrustLevel_TrustedDelegator: t = CKT_NSS_TRUSTED_DELEGATOR;
|
|
break;
|
|
case nssTrustLevel_ValidDelegator: t = CKT_NSS_VALID_DELEGATOR; break;
|
|
case nssTrustLevel_Trusted: t = CKT_NSS_TRUSTED; break;
|
|
case nssTrustLevel_MustVerify: t = CKT_NSS_MUST_VERIFY_TRUST; break;
|
|
case nssTrustLevel_Unknown:
|
|
default: t = CKT_NSS_TRUST_UNKNOWN; break;
|
|
}
|
|
return t;
|
|
}
|
|
|
|
NSS_IMPLEMENT nssCryptokiObject *
|
|
nssToken_ImportTrust (
|
|
NSSToken *tok,
|
|
nssSession *sessionOpt,
|
|
NSSDER *certEncoding,
|
|
NSSDER *certIssuer,
|
|
NSSDER *certSerial,
|
|
nssTrustLevel serverAuth,
|
|
nssTrustLevel clientAuth,
|
|
nssTrustLevel codeSigning,
|
|
nssTrustLevel emailProtection,
|
|
PRBool stepUpApproved,
|
|
PRBool asTokenObject
|
|
)
|
|
{
|
|
nssCryptokiObject *object;
|
|
CK_OBJECT_CLASS tobjc = CKO_NSS_TRUST;
|
|
CK_TRUST ckSA, ckCA, ckCS, ckEP;
|
|
CK_ATTRIBUTE_PTR attr;
|
|
CK_ATTRIBUTE trust_tmpl[11];
|
|
CK_ULONG tsize;
|
|
PRUint8 sha1[20]; /* this is cheating... */
|
|
PRUint8 md5[16];
|
|
NSSItem sha1_result, md5_result;
|
|
sha1_result.data = sha1; sha1_result.size = sizeof sha1;
|
|
md5_result.data = md5; md5_result.size = sizeof md5;
|
|
sha1_hash(certEncoding, &sha1_result);
|
|
md5_hash(certEncoding, &md5_result);
|
|
ckSA = get_ck_trust(serverAuth);
|
|
ckCA = get_ck_trust(clientAuth);
|
|
ckCS = get_ck_trust(codeSigning);
|
|
ckEP = get_ck_trust(emailProtection);
|
|
NSS_CK_TEMPLATE_START(trust_tmpl, attr, tsize);
|
|
if (asTokenObject) {
|
|
NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
|
|
} else {
|
|
NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
|
|
}
|
|
NSS_CK_SET_ATTRIBUTE_VAR( attr, CKA_CLASS, tobjc);
|
|
NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ISSUER, certIssuer);
|
|
NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SERIAL_NUMBER, certSerial);
|
|
NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CERT_SHA1_HASH, &sha1_result);
|
|
NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CERT_MD5_HASH, &md5_result);
|
|
/* now set the trust values */
|
|
NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_TRUST_SERVER_AUTH, ckSA);
|
|
NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_TRUST_CLIENT_AUTH, ckCA);
|
|
NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_TRUST_CODE_SIGNING, ckCS);
|
|
NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_TRUST_EMAIL_PROTECTION, ckEP);
|
|
if (stepUpApproved) {
|
|
NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TRUST_STEP_UP_APPROVED,
|
|
&g_ck_true);
|
|
} else {
|
|
NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TRUST_STEP_UP_APPROVED,
|
|
&g_ck_false);
|
|
}
|
|
NSS_CK_TEMPLATE_FINISH(trust_tmpl, attr, tsize);
|
|
/* import the trust object onto the token */
|
|
object = import_object(tok, sessionOpt, trust_tmpl, tsize);
|
|
if (object && tok->cache) {
|
|
nssTokenObjectCache_ImportObject(tok->cache, object, tobjc,
|
|
trust_tmpl, tsize);
|
|
}
|
|
return object;
|
|
}
|
|
|
|
NSS_IMPLEMENT nssCryptokiObject *
|
|
nssToken_FindTrustForCertificate (
|
|
NSSToken *token,
|
|
nssSession *sessionOpt,
|
|
NSSDER *certEncoding,
|
|
NSSDER *certIssuer,
|
|
NSSDER *certSerial,
|
|
nssTokenSearchType searchType
|
|
)
|
|
{
|
|
CK_OBJECT_CLASS tobjc = CKO_NSS_TRUST;
|
|
CK_ATTRIBUTE_PTR attr;
|
|
CK_ATTRIBUTE tobj_template[5];
|
|
CK_ULONG tobj_size;
|
|
nssSession *session = sessionOpt ? sessionOpt : token->defaultSession;
|
|
nssCryptokiObject *object = NULL, **objects;
|
|
|
|
/* Don't ask the module to use an invalid session handle. */
|
|
if (!session || session->handle == CK_INVALID_SESSION) {
|
|
PORT_SetError(SEC_ERROR_NO_TOKEN);
|
|
return object;
|
|
}
|
|
|
|
NSS_CK_TEMPLATE_START(tobj_template, attr, tobj_size);
|
|
if (searchType == nssTokenSearchType_TokenOnly) {
|
|
NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
|
|
}
|
|
NSS_CK_SET_ATTRIBUTE_VAR( attr, CKA_CLASS, tobjc);
|
|
NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ISSUER, certIssuer);
|
|
NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SERIAL_NUMBER , certSerial);
|
|
NSS_CK_TEMPLATE_FINISH(tobj_template, attr, tobj_size);
|
|
objects = find_objects_by_template(token, session,
|
|
tobj_template, tobj_size,
|
|
1, NULL);
|
|
if (objects) {
|
|
object = objects[0];
|
|
nss_ZFreeIf(objects);
|
|
}
|
|
return object;
|
|
}
|
|
|
|
NSS_IMPLEMENT nssCryptokiObject *
|
|
nssToken_ImportCRL (
|
|
NSSToken *token,
|
|
nssSession *sessionOpt,
|
|
NSSDER *subject,
|
|
NSSDER *encoding,
|
|
PRBool isKRL,
|
|
NSSUTF8 *url,
|
|
PRBool asTokenObject
|
|
)
|
|
{
|
|
nssCryptokiObject *object;
|
|
CK_OBJECT_CLASS crlobjc = CKO_NSS_CRL;
|
|
CK_ATTRIBUTE_PTR attr;
|
|
CK_ATTRIBUTE crl_tmpl[6];
|
|
CK_ULONG crlsize;
|
|
|
|
NSS_CK_TEMPLATE_START(crl_tmpl, attr, crlsize);
|
|
if (asTokenObject) {
|
|
NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
|
|
} else {
|
|
NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
|
|
}
|
|
NSS_CK_SET_ATTRIBUTE_VAR( attr, CKA_CLASS, crlobjc);
|
|
NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SUBJECT, subject);
|
|
NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_VALUE, encoding);
|
|
NSS_CK_SET_ATTRIBUTE_UTF8(attr, CKA_NSS_URL, url);
|
|
if (isKRL) {
|
|
NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_NSS_KRL, &g_ck_true);
|
|
} else {
|
|
NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_NSS_KRL, &g_ck_false);
|
|
}
|
|
NSS_CK_TEMPLATE_FINISH(crl_tmpl, attr, crlsize);
|
|
|
|
/* import the crl object onto the token */
|
|
object = import_object(token, sessionOpt, crl_tmpl, crlsize);
|
|
if (object && token->cache) {
|
|
nssTokenObjectCache_ImportObject(token->cache, object, crlobjc,
|
|
crl_tmpl, crlsize);
|
|
}
|
|
return object;
|
|
}
|
|
|
|
NSS_IMPLEMENT nssCryptokiObject **
|
|
nssToken_FindCRLsBySubject (
|
|
NSSToken *token,
|
|
nssSession *sessionOpt,
|
|
NSSDER *subject,
|
|
nssTokenSearchType searchType,
|
|
PRUint32 maximumOpt,
|
|
PRStatus *statusOpt
|
|
)
|
|
{
|
|
CK_OBJECT_CLASS crlobjc = CKO_NSS_CRL;
|
|
CK_ATTRIBUTE_PTR attr;
|
|
CK_ATTRIBUTE crlobj_template[3];
|
|
CK_ULONG crlobj_size;
|
|
nssCryptokiObject **objects = NULL;
|
|
nssSession *session = sessionOpt ? sessionOpt : token->defaultSession;
|
|
|
|
/* Don't ask the module to use an invalid session handle. */
|
|
if (!session || session->handle == CK_INVALID_SESSION) {
|
|
PORT_SetError(SEC_ERROR_NO_TOKEN);
|
|
return objects;
|
|
}
|
|
|
|
NSS_CK_TEMPLATE_START(crlobj_template, attr, crlobj_size);
|
|
if (searchType == nssTokenSearchType_SessionOnly) {
|
|
NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
|
|
} else if (searchType == nssTokenSearchType_TokenOnly ||
|
|
searchType == nssTokenSearchType_TokenForced) {
|
|
NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
|
|
}
|
|
NSS_CK_SET_ATTRIBUTE_VAR( attr, CKA_CLASS, crlobjc);
|
|
NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SUBJECT, subject);
|
|
NSS_CK_TEMPLATE_FINISH(crlobj_template, attr, crlobj_size);
|
|
|
|
objects = find_objects_by_template(token, session,
|
|
crlobj_template, crlobj_size,
|
|
maximumOpt, statusOpt);
|
|
return objects;
|
|
}
|
|
|
|
NSS_IMPLEMENT PRStatus
|
|
nssToken_GetCachedObjectAttributes (
|
|
NSSToken *token,
|
|
NSSArena *arenaOpt,
|
|
nssCryptokiObject *object,
|
|
CK_OBJECT_CLASS objclass,
|
|
CK_ATTRIBUTE_PTR atemplate,
|
|
CK_ULONG atlen
|
|
)
|
|
{
|
|
if (!token->cache) {
|
|
return PR_FAILURE;
|
|
}
|
|
return nssTokenObjectCache_GetObjectAttributes(token->cache, arenaOpt,
|
|
object, objclass,
|
|
atemplate, atlen);
|
|
}
|
|
|
|
NSS_IMPLEMENT NSSItem *
|
|
nssToken_Digest (
|
|
NSSToken *tok,
|
|
nssSession *sessionOpt,
|
|
NSSAlgorithmAndParameters *ap,
|
|
NSSItem *data,
|
|
NSSItem *rvOpt,
|
|
NSSArena *arenaOpt
|
|
)
|
|
{
|
|
CK_RV ckrv;
|
|
CK_ULONG digestLen;
|
|
CK_BYTE_PTR digest;
|
|
NSSItem *rvItem = NULL;
|
|
void *epv = nssToken_GetCryptokiEPV(tok);
|
|
nssSession *session = (sessionOpt) ? sessionOpt : tok->defaultSession;
|
|
|
|
/* Don't ask the module to use an invalid session handle. */
|
|
if (!session || session->handle == CK_INVALID_SESSION) {
|
|
PORT_SetError(SEC_ERROR_NO_TOKEN);
|
|
return rvItem;
|
|
}
|
|
|
|
nssSession_EnterMonitor(session);
|
|
ckrv = CKAPI(epv)->C_DigestInit(session->handle, &ap->mechanism);
|
|
if (ckrv != CKR_OK) {
|
|
nssSession_ExitMonitor(session);
|
|
return NULL;
|
|
}
|
|
#if 0
|
|
/* XXX the standard says this should work, but it doesn't */
|
|
ckrv = CKAPI(epv)->C_Digest(session->handle, NULL, 0, NULL, &digestLen);
|
|
if (ckrv != CKR_OK) {
|
|
nssSession_ExitMonitor(session);
|
|
return NULL;
|
|
}
|
|
#endif
|
|
digestLen = 0; /* XXX for now */
|
|
digest = NULL;
|
|
if (rvOpt) {
|
|
if (rvOpt->size > 0 && rvOpt->size < digestLen) {
|
|
nssSession_ExitMonitor(session);
|
|
/* the error should be bad args */
|
|
return NULL;
|
|
}
|
|
if (rvOpt->data) {
|
|
digest = rvOpt->data;
|
|
}
|
|
digestLen = rvOpt->size;
|
|
}
|
|
if (!digest) {
|
|
digest = (CK_BYTE_PTR)nss_ZAlloc(arenaOpt, digestLen);
|
|
if (!digest) {
|
|
nssSession_ExitMonitor(session);
|
|
return NULL;
|
|
}
|
|
}
|
|
ckrv = CKAPI(epv)->C_Digest(session->handle,
|
|
(CK_BYTE_PTR)data->data,
|
|
(CK_ULONG)data->size,
|
|
(CK_BYTE_PTR)digest,
|
|
&digestLen);
|
|
nssSession_ExitMonitor(session);
|
|
if (ckrv != CKR_OK) {
|
|
nss_ZFreeIf(digest);
|
|
return NULL;
|
|
}
|
|
if (!rvOpt) {
|
|
rvItem = nssItem_Create(arenaOpt, NULL, digestLen, (void *)digest);
|
|
}
|
|
return rvItem;
|
|
}
|
|
|
|
NSS_IMPLEMENT PRStatus
|
|
nssToken_BeginDigest (
|
|
NSSToken *tok,
|
|
nssSession *sessionOpt,
|
|
NSSAlgorithmAndParameters *ap
|
|
)
|
|
{
|
|
CK_RV ckrv;
|
|
void *epv = nssToken_GetCryptokiEPV(tok);
|
|
nssSession *session = (sessionOpt) ? sessionOpt : tok->defaultSession;
|
|
|
|
/* Don't ask the module to use an invalid session handle. */
|
|
if (!session || session->handle == CK_INVALID_SESSION) {
|
|
PORT_SetError(SEC_ERROR_NO_TOKEN);
|
|
return PR_FAILURE;
|
|
}
|
|
|
|
nssSession_EnterMonitor(session);
|
|
ckrv = CKAPI(epv)->C_DigestInit(session->handle, &ap->mechanism);
|
|
nssSession_ExitMonitor(session);
|
|
return (ckrv == CKR_OK) ? PR_SUCCESS : PR_FAILURE;
|
|
}
|
|
|
|
NSS_IMPLEMENT PRStatus
|
|
nssToken_ContinueDigest (
|
|
NSSToken *tok,
|
|
nssSession *sessionOpt,
|
|
NSSItem *item
|
|
)
|
|
{
|
|
CK_RV ckrv;
|
|
void *epv = nssToken_GetCryptokiEPV(tok);
|
|
nssSession *session = (sessionOpt) ? sessionOpt : tok->defaultSession;
|
|
|
|
/* Don't ask the module to use an invalid session handle. */
|
|
if (!session || session->handle == CK_INVALID_SESSION) {
|
|
PORT_SetError(SEC_ERROR_NO_TOKEN);
|
|
return PR_FAILURE;
|
|
}
|
|
|
|
nssSession_EnterMonitor(session);
|
|
ckrv = CKAPI(epv)->C_DigestUpdate(session->handle,
|
|
(CK_BYTE_PTR)item->data,
|
|
(CK_ULONG)item->size);
|
|
nssSession_ExitMonitor(session);
|
|
return (ckrv == CKR_OK) ? PR_SUCCESS : PR_FAILURE;
|
|
}
|
|
|
|
NSS_IMPLEMENT NSSItem *
|
|
nssToken_FinishDigest (
|
|
NSSToken *tok,
|
|
nssSession *sessionOpt,
|
|
NSSItem *rvOpt,
|
|
NSSArena *arenaOpt
|
|
)
|
|
{
|
|
CK_RV ckrv;
|
|
CK_ULONG digestLen;
|
|
CK_BYTE_PTR digest;
|
|
NSSItem *rvItem = NULL;
|
|
void *epv = nssToken_GetCryptokiEPV(tok);
|
|
nssSession *session = (sessionOpt) ? sessionOpt : tok->defaultSession;
|
|
|
|
/* Don't ask the module to use an invalid session handle. */
|
|
if (!session || session->handle == CK_INVALID_SESSION) {
|
|
PORT_SetError(SEC_ERROR_NO_TOKEN);
|
|
return NULL;
|
|
}
|
|
|
|
nssSession_EnterMonitor(session);
|
|
ckrv = CKAPI(epv)->C_DigestFinal(session->handle, NULL, &digestLen);
|
|
if (ckrv != CKR_OK || digestLen == 0) {
|
|
nssSession_ExitMonitor(session);
|
|
return NULL;
|
|
}
|
|
digest = NULL;
|
|
if (rvOpt) {
|
|
if (rvOpt->size > 0 && rvOpt->size < digestLen) {
|
|
nssSession_ExitMonitor(session);
|
|
/* the error should be bad args */
|
|
return NULL;
|
|
}
|
|
if (rvOpt->data) {
|
|
digest = rvOpt->data;
|
|
}
|
|
digestLen = rvOpt->size;
|
|
}
|
|
if (!digest) {
|
|
digest = (CK_BYTE_PTR)nss_ZAlloc(arenaOpt, digestLen);
|
|
if (!digest) {
|
|
nssSession_ExitMonitor(session);
|
|
return NULL;
|
|
}
|
|
}
|
|
ckrv = CKAPI(epv)->C_DigestFinal(session->handle, digest, &digestLen);
|
|
nssSession_ExitMonitor(session);
|
|
if (ckrv != CKR_OK) {
|
|
nss_ZFreeIf(digest);
|
|
return NULL;
|
|
}
|
|
if (!rvOpt) {
|
|
rvItem = nssItem_Create(arenaOpt, NULL, digestLen, (void *)digest);
|
|
}
|
|
return rvItem;
|
|
}
|
|
|
|
NSS_IMPLEMENT PRBool
|
|
nssToken_IsPresent (
|
|
NSSToken *token
|
|
)
|
|
{
|
|
return nssSlot_IsTokenPresent(token->slot);
|
|
}
|
|
|
|
/* Sigh. The methods to find objects declared above cause problems with
|
|
* the low-level object cache in the softoken -- the objects are found in
|
|
* toto, then one wave of GetAttributes is done, then another. Having a
|
|
* large number of objects causes the cache to be thrashed, as the objects
|
|
* are gone before there's any chance to ask for their attributes.
|
|
* So, for now, bringing back traversal methods for certs. This way all of
|
|
* the cert's attributes can be grabbed immediately after finding it,
|
|
* increasing the likelihood that the cache takes care of it.
|
|
*/
|
|
NSS_IMPLEMENT PRStatus
|
|
nssToken_TraverseCertificates (
|
|
NSSToken *token,
|
|
nssSession *sessionOpt,
|
|
nssTokenSearchType searchType,
|
|
PRStatus (* callback)(nssCryptokiObject *instance, void *arg),
|
|
void *arg
|
|
)
|
|
{
|
|
CK_RV ckrv;
|
|
CK_ULONG count;
|
|
CK_OBJECT_HANDLE *objectHandles;
|
|
CK_ATTRIBUTE_PTR attr;
|
|
CK_ATTRIBUTE cert_template[2];
|
|
CK_ULONG ctsize;
|
|
NSSArena *arena;
|
|
PRUint32 arraySize, numHandles;
|
|
nssCryptokiObject **objects;
|
|
void *epv = nssToken_GetCryptokiEPV(token);
|
|
nssSession *session = (sessionOpt) ? sessionOpt : token->defaultSession;
|
|
|
|
/* Don't ask the module to use an invalid session handle. */
|
|
if (!session || session->handle == CK_INVALID_SESSION) {
|
|
PORT_SetError(SEC_ERROR_NO_TOKEN);
|
|
return PR_FAILURE;
|
|
}
|
|
|
|
/* template for all certs */
|
|
NSS_CK_TEMPLATE_START(cert_template, attr, ctsize);
|
|
if (searchType == nssTokenSearchType_SessionOnly) {
|
|
NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
|
|
} else if (searchType == nssTokenSearchType_TokenOnly ||
|
|
searchType == nssTokenSearchType_TokenForced) {
|
|
NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
|
|
}
|
|
NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_cert);
|
|
NSS_CK_TEMPLATE_FINISH(cert_template, attr, ctsize);
|
|
|
|
/* the arena is only for the array of object handles */
|
|
arena = nssArena_Create();
|
|
if (!arena) {
|
|
return PR_FAILURE;
|
|
}
|
|
arraySize = OBJECT_STACK_SIZE;
|
|
numHandles = 0;
|
|
objectHandles = nss_ZNEWARRAY(arena, CK_OBJECT_HANDLE, arraySize);
|
|
if (!objectHandles) {
|
|
goto loser;
|
|
}
|
|
nssSession_EnterMonitor(session); /* ==== session lock === */
|
|
/* Initialize the find with the template */
|
|
ckrv = CKAPI(epv)->C_FindObjectsInit(session->handle,
|
|
cert_template, ctsize);
|
|
if (ckrv != CKR_OK) {
|
|
nssSession_ExitMonitor(session);
|
|
goto loser;
|
|
}
|
|
while (PR_TRUE) {
|
|
/* Issue the find for up to arraySize - numHandles objects */
|
|
ckrv = CKAPI(epv)->C_FindObjects(session->handle,
|
|
objectHandles + numHandles,
|
|
arraySize - numHandles,
|
|
&count);
|
|
if (ckrv != CKR_OK) {
|
|
nssSession_ExitMonitor(session);
|
|
goto loser;
|
|
}
|
|
/* bump the number of found objects */
|
|
numHandles += count;
|
|
if (numHandles < arraySize) {
|
|
break;
|
|
}
|
|
/* the array is filled, double it and continue */
|
|
arraySize *= 2;
|
|
objectHandles = nss_ZREALLOCARRAY(objectHandles,
|
|
CK_OBJECT_HANDLE,
|
|
arraySize);
|
|
if (!objectHandles) {
|
|
nssSession_ExitMonitor(session);
|
|
goto loser;
|
|
}
|
|
}
|
|
ckrv = CKAPI(epv)->C_FindObjectsFinal(session->handle);
|
|
nssSession_ExitMonitor(session); /* ==== end session lock === */
|
|
if (ckrv != CKR_OK) {
|
|
goto loser;
|
|
}
|
|
if (numHandles > 0) {
|
|
objects = create_objects_from_handles(token, session,
|
|
objectHandles, numHandles);
|
|
if (objects) {
|
|
nssCryptokiObject **op;
|
|
for (op = objects; *op; op++) {
|
|
(void)(*callback)(*op, arg);
|
|
}
|
|
nss_ZFreeIf(objects);
|
|
}
|
|
}
|
|
nssArena_Destroy(arena);
|
|
return PR_SUCCESS;
|
|
loser:
|
|
nssArena_Destroy(arena);
|
|
return PR_FAILURE;
|
|
}
|
|
|
|
NSS_IMPLEMENT PRBool
|
|
nssToken_IsPrivateKeyAvailable (
|
|
NSSToken *token,
|
|
NSSCertificate *c,
|
|
nssCryptokiObject *instance
|
|
)
|
|
{
|
|
CK_OBJECT_CLASS theClass;
|
|
|
|
if (token == NULL) return PR_FALSE;
|
|
if (c == NULL) return PR_FALSE;
|
|
|
|
theClass = CKO_PRIVATE_KEY;
|
|
if (!nssSlot_IsLoggedIn(token->slot)) {
|
|
theClass = CKO_PUBLIC_KEY;
|
|
}
|
|
if (PK11_MatchItem(token->pk11slot, instance->handle, theClass)
|
|
!= CK_INVALID_HANDLE) {
|
|
return PR_TRUE;
|
|
}
|
|
return PR_FALSE;
|
|
}
|