summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorrelyea%netscape.com <devnull@localhost>2005-11-15 00:13:58 +0000
committerrelyea%netscape.com <devnull@localhost>2005-11-15 00:13:58 +0000
commit71488fac4553afc6f2c293b963f1ee86f35e9fe4 (patch)
treec5861ac87584c03fa93bbe4c1648c15bf7a5ecd6
parent8b6ab4292a8224737016d779d2e3e4a1b41f5a25 (diff)
downloadnss-hg-71488fac4553afc6f2c293b963f1ee86f35e9fe4.tar.gz
Add r/w support. The Capi token can now:
Import certs and keys. Delete certs and keys.
-rw-r--r--security/nss/lib/ckfw/capi/Makefile1
-rw-r--r--security/nss/lib/ckfw/capi/cfind.c169
-rw-r--r--security/nss/lib/ckfw/capi/cinst.c16
-rw-r--r--security/nss/lib/ckfw/capi/ckcapi.h173
-rw-r--r--security/nss/lib/ckfw/capi/cobject.c1761
-rw-r--r--security/nss/lib/ckfw/capi/crsa.c5
-rw-r--r--security/nss/lib/ckfw/capi/csession.c20
-rw-r--r--security/nss/lib/ckfw/capi/ctoken.c15
8 files changed, 1866 insertions, 294 deletions
diff --git a/security/nss/lib/ckfw/capi/Makefile b/security/nss/lib/ckfw/capi/Makefile
index 561fb6cd7..77afe8097 100644
--- a/security/nss/lib/ckfw/capi/Makefile
+++ b/security/nss/lib/ckfw/capi/Makefile
@@ -62,6 +62,7 @@ EXTRA_SHARED_LIBS += \
$(NSPR_LIB_DIR)/$(NSPR31_LIB_PREFIX)nspr4.lib \
crypt32.lib \
advapi32.lib \
+ rpcrt4.lib \
$(NULL)
endif # NS_USE_GCC
else
diff --git a/security/nss/lib/ckfw/capi/cfind.c b/security/nss/lib/ckfw/capi/cfind.c
index c9e1b104b..b685c0888 100644
--- a/security/nss/lib/ckfw/capi/cfind.c
+++ b/security/nss/lib/ckfw/capi/cfind.c
@@ -180,7 +180,7 @@ ckcapi_match
#define CKAPI_ITEM_CHUNK 20
-#define PUT_Object(obj) \
+#define PUT_Object(obj,err) \
{ \
if (count >= size) { \
*listp = *listp ? \
@@ -189,7 +189,7 @@ ckcapi_match
nss_ZNEWARRAY(NULL, ckcapiInternalObject *, \
(size+CKAPI_ITEM_CHUNK) ) ; \
if ((ckcapiInternalObject **)NULL == *listp) { \
- *pError = CKR_HOST_MEMORY; \
+ err = CKR_HOST_MEMORY; \
goto loser; \
} \
size += CKAPI_ITEM_CHUNK; \
@@ -198,6 +198,134 @@ ckcapi_match
count++; \
}
+
+/*
+ * pass parameters back through the callback.
+ */
+typedef struct BareCollectParamsStr {
+ CK_OBJECT_CLASS objClass;
+ CK_ATTRIBUTE_PTR pTemplate;
+ CK_ULONG ulAttributeCount;
+ ckcapiInternalObject ***listp;
+ PRUint32 size;
+ PRUint32 count;
+} BareCollectParams;
+
+/* collect_bare's callback. Called for each object that
+ * supposedly has a PROVINDER_INFO property */
+static BOOL WINAPI
+doBareCollect
+(
+ const CRYPT_HASH_BLOB *msKeyID,
+ DWORD flags,
+ void *reserved,
+ void *args,
+ DWORD cProp,
+ DWORD *propID,
+ void **propData,
+ DWORD *propSize
+)
+{
+ BareCollectParams *bcp = (BareCollectParams *) args;
+ PRUint32 size = bcp->size;
+ PRUint32 count = bcp->count;
+ ckcapiInternalObject ***listp = bcp->listp;
+ ckcapiInternalObject *io = NULL;
+ DWORD i;
+ CRYPT_KEY_PROV_INFO *keyProvInfo = NULL;
+ void *idData;
+ CK_RV error;
+
+ /* make sure there is a Key Provider Info property */
+ for (i=0; i < cProp; i++) {
+ if (CERT_KEY_PROV_INFO_PROP_ID == propID[i]) {
+ keyProvInfo = (CRYPT_KEY_PROV_INFO *)propData[i];
+ break;
+ }
+ }
+ if ((CRYPT_KEY_PROV_INFO *)NULL == keyProvInfo) {
+ return 1;
+ }
+
+ /* copy the key ID */
+ idData = nss_ZNEWARRAY(NULL, char, msKeyID->cbData);
+ if ((void *)NULL == idData) {
+ goto loser;
+ }
+ nsslibc_memcpy(idData, msKeyID->pbData, msKeyID->cbData);
+
+ /* build a bare internal object */
+ io = nss_ZNEW(NULL, ckcapiInternalObject);
+ if ((ckcapiInternalObject *)NULL == io) {
+ goto loser;
+ }
+ io->type = ckcapiBareKey;
+ io->objClass = bcp->objClass;
+ io->u.key.provInfo = *keyProvInfo;
+ io->u.key.provInfo.pwszContainerName =
+ nss_ckcapi_WideDup(keyProvInfo->pwszContainerName);
+ io->u.key.provInfo.pwszProvName =
+ nss_ckcapi_WideDup(keyProvInfo->pwszProvName);
+ io->u.key.provName = nss_ckcapi_WideToUTF8(keyProvInfo->pwszProvName);
+ io->u.key.containerName =
+ nss_ckcapi_WideToUTF8(keyProvInfo->pwszContainerName);
+ io->u.key.hProv = 0;
+ io->idData = idData;
+ io->id.data = idData;
+ io->id.size = msKeyID->cbData;
+ idData = NULL;
+
+ /* see if it matches */
+ if( CK_FALSE == ckcapi_match(bcp->pTemplate, bcp->ulAttributeCount, io) ) {
+ goto loser;
+ }
+ PUT_Object(io, error);
+ bcp->size = size;
+ bcp->count = count;
+ return 1;
+
+loser:
+ if (io) {
+ nss_ckcapi_DestroyInternalObject(io);
+ }
+ nss_ZFreeIf(idData);
+ return 1;
+}
+
+/*
+ * collect the bare keys running around
+ */
+static PRUint32
+collect_bare(
+ CK_OBJECT_CLASS objClass,
+ CK_ATTRIBUTE_PTR pTemplate,
+ CK_ULONG ulAttributeCount,
+ ckcapiInternalObject ***listp,
+ PRUint32 *sizep,
+ PRUint32 count,
+ CK_RV *pError
+)
+{
+ BOOL rc;
+ BareCollectParams bareCollectParams;
+
+ bareCollectParams.objClass = objClass;
+ bareCollectParams.pTemplate = pTemplate;
+ bareCollectParams.ulAttributeCount = ulAttributeCount;
+ bareCollectParams.listp = listp;
+ bareCollectParams.size = *sizep;
+ bareCollectParams.count = count;
+
+ rc = CryptEnumKeyIdentifierProperties(NULL, CERT_KEY_PROV_INFO_PROP_ID, 0,
+ NULL, NULL, &bareCollectParams, doBareCollect);
+
+ *sizep = bareCollectParams.size;
+ return bareCollectParams.count;
+}
+
+/* find all the certs that represent the appropriate object (cert, priv key, or
+ * pub key) in the cert store.
+ */
static PRUint32
collect_class(
CK_OBJECT_CLASS objClass,
@@ -213,20 +341,20 @@ collect_class(
{
PRUint32 size = *sizep;
ckcapiInternalObject *next = NULL;
- HCERTSTORE hstore;
+ HCERTSTORE hStore;
PCCERT_CONTEXT certContext = NULL;
PRBool isKey =
(objClass == CKO_PUBLIC_KEY) | (objClass == CKO_PRIVATE_KEY);
- hstore = CertOpenSystemStore((HCRYPTPROV)NULL, storeStr);
- if (NULL == hstore) {
+ hStore = CertOpenSystemStore((HCRYPTPROV)NULL, storeStr);
+ if (NULL == hStore) {
return count; /* none found does not imply an error */
}
/* FUTURE: use CertFindCertificateInStore to filter better -- so we don't
* have to enumerate all the certificates */
while ((PCERT_CONTEXT) NULL !=
- (certContext= CertEnumCertificatesInStore(hstore, certContext))) {
+ (certContext= CertEnumCertificatesInStore(hStore, certContext))) {
/* first filter out non user certs if we are looking for keys */
if (isKey) {
/* make sure there is a Key Provider Info property */
@@ -252,18 +380,20 @@ collect_class(
}
}
next->type = ckcapiCert;
- next->u.cert.objClass = objClass;
+ next->objClass = objClass;
next->u.cert.certContext = certContext;
next->u.cert.hasID = hasID;
+ next->u.cert.certStore = storeStr;
if( CK_TRUE == ckcapi_match(pTemplate, ulAttributeCount, next) ) {
/* clear cached values that may be dependent on our old certContext */
memset(&next->u.cert, 0, sizeof(next->u.cert));
/* get a 'permanent' context */
next->u.cert.certContext = CertDuplicateCertificateContext(certContext);
- next->u.cert.objClass = objClass;
+ next->objClass = objClass;
next->u.cert.certContext = certContext;
next->u.cert.hasID = hasID;
- PUT_Object(next);
+ next->u.cert.certStore = storeStr;
+ PUT_Object(next, *pError);
next = NULL; /* need to allocate a new one now */
} else {
/* don't cache the values we just loaded */
@@ -271,13 +401,14 @@ collect_class(
}
}
loser:
+ CertCloseStore(hStore, 0);
nss_ZFreeIf(next);
*sizep = size;
return count;
}
-static PRUint32
-collect_all_certs(
+NSS_IMPLEMENT PRUint32
+nss_ckcapi_collect_all_certs(
CK_ATTRIBUTE_PTR pTemplate,
CK_ULONG ulAttributeCount,
ckcapiInternalObject ***listp,
@@ -303,7 +434,7 @@ collect_all_certs(
return count;
}
-static CK_OBJECT_CLASS
+CK_OBJECT_CLASS
ckcapi_GetObjectClass(CK_ATTRIBUTE_PTR pTemplate,
CK_ULONG ulAttributeCount)
{
@@ -339,7 +470,7 @@ collect_objects(
ckcapiInternalObject *o = (ckcapiInternalObject *)&nss_ckcapi_data[i];
if( CK_TRUE == ckcapi_match(pTemplate, ulAttributeCount, o) ) {
- PUT_Object(o);
+ PUT_Object(o, *pError);
}
}
@@ -350,25 +481,33 @@ collect_objects(
*pError = CKR_OK;
switch (objClass) {
case CKO_CERTIFICATE:
- count = collect_all_certs(pTemplate, ulAttributeCount, listp,
+ count = nss_ckcapi_collect_all_certs(pTemplate, ulAttributeCount, listp,
&size, count, pError);
break;
case CKO_PUBLIC_KEY:
count = collect_class(objClass, "My", PR_TRUE, pTemplate,
ulAttributeCount, listp, &size, count, pError);
+ count = collect_bare(objClass, pTemplate, ulAttributeCount, listp,
+ &size, count, pError);
break;
case CKO_PRIVATE_KEY:
count = collect_class(objClass, "My", PR_TRUE, pTemplate,
ulAttributeCount, listp, &size, count, pError);
+ count = collect_bare(objClass, pTemplate, ulAttributeCount, listp,
+ &size, count, pError);
break;
/* all of them */
case CK_INVALID_HANDLE:
- count = collect_all_certs(pTemplate, ulAttributeCount, listp,
+ count = nss_ckcapi_collect_all_certs(pTemplate, ulAttributeCount, listp,
&size, count, pError);
count = collect_class(CKO_PUBLIC_KEY, "My", PR_TRUE, pTemplate,
ulAttributeCount, listp, &size, count, pError);
+ count = collect_bare(CKO_PUBLIC_KEY, pTemplate, ulAttributeCount, listp,
+ &size, count, pError);
count = collect_class(CKO_PRIVATE_KEY, "My", PR_TRUE, pTemplate,
ulAttributeCount, listp, &size, count, pError);
+ count = collect_bare(CKO_PRIVATE_KEY, pTemplate, ulAttributeCount, listp,
+ &size, count, pError);
break;
default:
goto done; /* no other object types we understand in this module */
diff --git a/security/nss/lib/ckfw/capi/cinst.c b/security/nss/lib/ckfw/capi/cinst.c
index 5a6ca55df..fe5c3d25e 100644
--- a/security/nss/lib/ckfw/capi/cinst.c
+++ b/security/nss/lib/ckfw/capi/cinst.c
@@ -117,6 +117,19 @@ ckcapi_mdInstance_GetSlots
return CKR_OK;
}
+static CK_BBOOL
+ckcapi_mdInstance_ModuleHandlesSessionObjects
+(
+ NSSCKMDInstance *mdInstance,
+ NSSCKFWInstance *fwInstance
+)
+{
+ /* we don't want to allow any session object creation, at least
+ * until we can investigate whether or not we can use those objects
+ */
+ return CK_TRUE;
+}
+
NSS_IMPLEMENT_DATA const NSSCKMDInstance
nss_ckcapi_mdInstance = {
(void *)NULL, /* etc */
@@ -127,7 +140,8 @@ nss_ckcapi_mdInstance = {
ckcapi_mdInstance_GetManufacturerID,
ckcapi_mdInstance_GetLibraryDescription,
ckcapi_mdInstance_GetLibraryVersion,
- NULL, /* ModuleHandlesSessionObjects -- defaults to false */
+ ckcapi_mdInstance_ModuleHandlesSessionObjects,
+ /*NULL, /* HandleSessionObjects */
ckcapi_mdInstance_GetSlots,
NULL, /* WaitForSlotEvent */
(void *)NULL /* null terminator */
diff --git a/security/nss/lib/ckfw/capi/ckcapi.h b/security/nss/lib/ckfw/capi/ckcapi.h
index 30b3871b3..fb434ce57 100644
--- a/security/nss/lib/ckfw/capi/ckcapi.h
+++ b/security/nss/lib/ckfw/capi/ckcapi.h
@@ -64,6 +64,10 @@ static const char CKCAPI_CVS_ID[] = "@(#) $RCSfile$ $Revision$ $Date$";
#include "WTypes.h"
#include "WinCrypt.h"
+/*
+ * statically defined raw objects. Allows us to data description objects
+ * to this PKCS #11 module.
+ */
struct ckcapiRawObjectStr {
CK_ULONG n;
const CK_ATTRIBUTE_TYPE *types;
@@ -71,17 +75,11 @@ struct ckcapiRawObjectStr {
};
typedef struct ckcapiRawObjectStr ckcapiRawObject;
-struct ckcapiCertObjectStr {
- CK_OBJECT_CLASS objClass;
- PCCERT_CONTEXT certContext;
- PRBool hasID;
- NSSItem hashKey;
- NSSItem label;
- NSSItem subject;
- NSSItem issuer;
- NSSItem serial;
- NSSItem derCert;
- NSSItem id;
+
+/*
+ * common values needed for both bare keys and cert referenced keys.
+ */
+struct ckcapiKeyParamsStr {
NSSItem modulus;
NSSItem exponent;
NSSItem privateExponent;
@@ -90,30 +88,72 @@ struct ckcapiCertObjectStr {
NSSItem exponent1;
NSSItem exponent2;
NSSItem coefficient;
+ unsigned char publicExponentData[sizeof(CK_ULONG)];
void *privateKey;
- /* static data: to do, make these dynamic like privateKey */
- unsigned char idData[256];
- unsigned char hashKeyData[128];
+ void *pubKey;
+};
+typedef struct ckcapiKeyParamsStr ckcapiKeyParams;
+
+/*
+ * Key objects. Handles bare keys which do not yet have certs associated
+ * with them. These are usually short lived, but may exist for several days
+ * while the CA is issuing the certificate.
+ */
+struct ckcapiKeyObjectStr {
+ CRYPT_KEY_PROV_INFO provInfo;
+ char *provName;
+ char *containerName;
+ HCRYPTPROV hProv;
+ ckcapiKeyParams key;
+};
+typedef struct ckcapiKeyObjectStr ckcapiKeyObject;
+
+/*
+ * Certificate and certificate referenced keys.
+ */
+struct ckcapiCertObjectStr {
+ PCCERT_CONTEXT certContext;
+ PRBool hasID;
+ const char *certStore;
+ NSSItem label;
+ NSSItem subject;
+ NSSItem issuer;
+ NSSItem serial;
+ NSSItem derCert;
+ ckcapiKeyParams key;
+ unsigned char *labelData;
+ /* static data: to do, make this dynamic like labelData */
unsigned char derSerial[128];
- unsigned char labelData[256];
};
typedef struct ckcapiCertObjectStr ckcapiCertObject;
typedef enum {
ckcapiRaw,
- ckcapiCert
+ ckcapiCert,
+ ckcapiBareKey
} ckcapiObjectType;
+/*
+ * all the various types of objects are abstracted away in cobject and
+ * cfind as ckcapiInternalObjects.
+ */
struct ckcapiInternalObjectStr {
ckcapiObjectType type;
union {
- ckcapiRawObject raw;
+ ckcapiRawObject raw;
ckcapiCertObject cert;
+ ckcapiKeyObject key;
} u;
+ CK_OBJECT_CLASS objClass;
+ NSSItem hashKey;
+ NSSItem id;
+ void *idData;
+ unsigned char hashKeyData[128];
NSSCKMDObject mdObject;
};
typedef struct ckcapiInternalObjectStr ckcapiInternalObject;
+/* our raw object data array */
NSS_EXTERN_DATA ckcapiInternalObject nss_ckcapi_data[];
NSS_EXTERN_DATA const PRUint32 nss_ckcapi_nObjects;
@@ -149,6 +189,9 @@ nss_ckcapi_FindObjectsInit
CK_RV *pError
);
+/*
+ * Object Utilities
+ */
NSS_EXTERN NSSCKMDObject *
nss_ckcapi_CreateMDObject
(
@@ -157,6 +200,51 @@ nss_ckcapi_CreateMDObject
CK_RV *pError
);
+NSS_EXTERN NSSCKMDObject *
+nss_ckcapi_CreateObject
+(
+ NSSCKFWSession *fwSession,
+ CK_ATTRIBUTE_PTR pTemplate,
+ CK_ULONG ulAttributeCount,
+ CK_RV *pError
+);
+
+NSS_EXTERN const NSSItem *
+nss_ckcapi_FetchAttribute
+(
+ ckcapiInternalObject *io,
+ CK_ATTRIBUTE_TYPE type
+);
+
+NSS_EXTERN void
+nss_ckcapi_DestroyInternalObject
+(
+ ckcapiInternalObject *io
+);
+
+NSS_EXTERN CK_RV
+nss_ckcapi_FetchKeyContainer
+(
+ ckcapiInternalObject *iKey,
+ HCRYPTPROV *hProv,
+ DWORD *keySpec,
+ HCRYPTKEY *hKey
+);
+
+/*
+ * generic utilities
+ */
+
+/*
+ * So everyone else in the worlds stores their bignum data MSB first, but not
+ * Microsoft, we need to byte swap everything coming into and out of CAPI.
+ */
+void
+ckcapi_ReverseData
+(
+ NSSItem *item
+);
+
/*
* unwrap a single DER value
*/
@@ -169,21 +257,52 @@ nss_ckcapi_DERUnwrap
char **next
);
-const NSSItem *
-nss_ckcapi_FetchAttribute(
- ckcapiInternalObject *io,
- CK_ATTRIBUTE_TYPE type
+/*
+ * Return the size in bytes of a wide string
+ */
+int
+nss_ckcapi_WideSize
+(
+ LPCWSTR wide
);
/*
- * So everyone else in the worlds stores their bignum data MSB first, but not
- * Microsoft, we need to byte swap everything coming into and out of CAPI.
+ * Covert a Unicode wide character string to a UTF8 string
*/
-void
-ckcapi_ReverseData(NSSItem *item);
+char *
+nss_ckcapi_WideToUTF8
+(
+ LPCWSTR wide
+);
-void
-nss_ckcapi_DestroyInternalObject(ckcapiInternalObject *io);
+/*
+ * Return a Wide String duplicated with nss allocated memory.
+ */
+LPWSTR
+nss_ckcapi_WideDup
+(
+ LPCWSTR wide
+);
+
+/*
+ * Covert a UTF8 string to Unicode wide character
+ */
+LPWSTR
+nss_ckcapi_UTF8ToWide
+(
+ char *buf
+);
+
+
+NSS_EXTERN PRUint32
+nss_ckcapi_collect_all_certs(
+ CK_ATTRIBUTE_PTR pTemplate,
+ CK_ULONG ulAttributeCount,
+ ckcapiInternalObject ***listp,
+ PRUint32 *sizep,
+ PRUint32 count,
+ CK_RV *pError
+);
#define NSS_CKCAPI_ARRAY_SIZE(x) ((sizeof (x))/(sizeof ((x)[0])))
diff --git a/security/nss/lib/ckfw/capi/cobject.c b/security/nss/lib/ckfw/capi/cobject.c
index aca3c39d0..09382073c 100644
--- a/security/nss/lib/ckfw/capi/cobject.c
+++ b/security/nss/lib/ckfw/capi/cobject.c
@@ -127,102 +127,12 @@ static const NSSItem ckcapi_privKeyClassItem = {
(void *)&cko_private_key, (PRUint32)sizeof(CK_OBJECT_CLASS) };
static const NSSItem ckcapi_pubKeyClassItem = {
(void *)&cko_public_key, (PRUint32)sizeof(CK_OBJECT_CLASS) };
+static const NSSItem ckcapi_emptyItem = {
+ (void *)&ck_true, 0};
/*
- * keep all the knowlege of how the internalObject is laid out in this function
- *
- * nss_ckcapi_FetchKeyContainer
- *
- * fetches the Provider container and info as well as a key handle for a
- * private key. If something other than a private key is passed in,
- * this function fails with CKR_KEY_TYPE_INCONSISTENT
+ * these are utilities. The chould be moved to a new utilities file.
*/
-NSS_EXTERN CK_RV
-nss_ckcapi_FetchKeyContainer
-(
- ckcapiInternalObject *iKey,
- HCRYPTPROV *hProv,
- DWORD *keySpec,
- HCRYPTKEY *hKey
-)
-{
- ckcapiCertObject *co;
- BOOL rc, dummy;
- DWORD msError;
-#ifdef DEBUG
- char string[512];
- DWORD stringLen;
- PCERT_PUBLIC_KEY_INFO pInfo;
-#endif
-
- if (ckcapiRaw == iKey->type) {
- /* can't have raw private keys */
- return CKR_KEY_TYPE_INCONSISTENT;
- }
- co=&iKey->u.cert;
- if (co->objClass != CKO_PRIVATE_KEY) {
- /* Only private keys have private key provider handles */
- return CKR_KEY_TYPE_INCONSISTENT;
- }
-
- /* OK, get the Provider */
- rc = CryptAcquireCertificatePrivateKey(co->certContext,
- CRYPT_ACQUIRE_CACHE_FLAG|CRYPT_ACQUIRE_COMPARE_KEY_FLAG, NULL, hProv,
- keySpec, &dummy);
- if (!rc) {
- goto loser;
- }
-
-#ifdef DEBUG
- /* get information about the provider for debugging purposes */
- stringLen = sizeof(string);
- rc = CryptGetProvParam(*hProv, PP_CONTAINER, string, &stringLen, 0);
- if (!rc) {
- msError = GetLastError();
- }
-
- stringLen = sizeof(string);
- rc = CryptGetProvParam(*hProv, PP_NAME, string, &stringLen, 0);
- if (!rc) {
- msError = GetLastError();
- }
-
- pInfo = (PCERT_PUBLIC_KEY_INFO) string;
- stringLen = sizeof(string);
- rc = CryptExportPublicKeyInfo(*hProv, *keySpec, X509_ASN_ENCODING,
- pInfo, &stringLen);
- if (!rc) {
- msError = GetLastError();
- }
-#endif
-
- /* and get the crypto handle */
- rc = CryptGetUserKey(*hProv, *keySpec, hKey);
- if (!rc) {
- goto loser;
- }
- return CKR_OK;
-loser:
- /* map the microsoft error before leaving */
- msError = GetLastError();
- switch (msError) {
- case ERROR_INVALID_HANDLE:
- case ERROR_INVALID_PARAMETER:
- case NTE_BAD_KEY:
- case NTE_NO_KEY:
- case NTE_BAD_PUBLIC_KEY:
- case NTE_BAD_KEYSET:
- case NTE_KEYSET_NOT_DEF:
- return CKR_KEY_TYPE_INCONSISTENT;
- case NTE_BAD_UID:
- case NTE_KEYSET_ENTRY_BAD:
- return CKR_DEVICE_ERROR;
- }
- return CKR_GENERAL_ERROR;
-}
-
-
-
/*
* unwrap a single DER value
@@ -274,96 +184,359 @@ nss_ckcapi_DERUnwrap
}
/*
- * take a DER PUBLIC Key block and return the modulus and exponent
+ * convert a PKCS #11 bytestrin into a CK_ULONG, the byte stream must be
+ * less than sizeof (CK_ULONG).
*/
-void
-ckcapi_PopulateModulusExponent(ckcapiInternalObject *io)
+CK_ULONG
+nss_ckcapi_DataToInt
+(
+ NSSItem *data,
+ CK_RV *pError
+)
{
- ckcapiCertObject *co = &io->u.cert;
- PCCERT_CONTEXT certContext = io->u.cert.certContext;
- char *pkData = certContext->pCertInfo->SubjectPublicKeyInfo.PublicKey.pbData;
- CK_ULONG size= certContext->pCertInfo->SubjectPublicKeyInfo.PublicKey.cbData;
- CK_ULONG newSize;
- char *ptr, *newptr;
+ CK_ULONG value = 0;
+ unsigned long count = data->size;
+ unsigned char *dataPtr = data->data;
+ unsigned long size = 0;
+
+ *pError = CKR_OK;
+
+ while (count--) {
+ value = value << 8;
+ value = value + *dataPtr++;
+ if (size || value) {
+ size++;
+ }
+ }
+ if (size > sizeof(CK_ULONG)) {
+ *pError = CKR_ATTRIBUTE_VALUE_INVALID;
+ }
+ return value;
+}
- /* find the start of the modulus -- this will not give good results if
- * the key isn't an rsa key! */
- ptr = nss_ckcapi_DERUnwrap(pkData, size, &newSize, NULL);
- co->modulus.data = nss_ckcapi_DERUnwrap(ptr, newSize,
- &co->modulus.size, &newptr);
- /* changed from signed to unsigned int */
- if (0 == *(char *)co->modulus.data) {
- co->modulus.data = ((char *)co->modulus.data)+1;
- co->modulus.size = co->modulus.size - 1;
+/*
+ * convert a CK_ULONG to a bytestream. Data is stored in the buffer 'buf'
+ * and must be at least CK_ULONG. Caller must provide buf.
+ */
+CK_ULONG
+nss_ckcapi_IntToData
+(
+ CK_ULONG value,
+ NSSItem *data,
+ unsigned char *dataPtr,
+ CK_RV *pError
+)
+{
+ unsigned long count = 0;
+ unsigned long i;
+#define SHIFT ((sizeof(CK_ULONG)-1)*8)
+ PRBool first = 0;
+
+ *pError = CKR_OK;
+
+ data->data = dataPtr;
+ for (i=0; i < sizeof(CK_ULONG); i++) {
+ unsigned char digit = (unsigned char)((value >> SHIFT) & 0xff);
+
+ value = value << 8;
+
+ /* drop leading zero bytes */
+ if (first && (0 == digit)) {
+ continue;
+ }
+ *dataPtr++ = digit;
+ count++;
}
- /* changed from signed to unsigned int */
- co->exponent.data = nss_ckcapi_DERUnwrap(newptr, (newptr-ptr)+newSize,
- &co->exponent.size, NULL);
- if (0 == *(char *)co->exponent.data) {
- co->exponent.data = ((char *)co->exponent.data)+1;
- co->exponent.size = co->exponent.size - 1;
+ data->size = count;
+ return count;
+}
+
+/*
+ * get an attribute from a template. Value is returned in NSS item.
+ * data for the item is owned by the template.
+ */
+CK_RV
+nss_ckcapi_GetAttribute
+(
+ CK_ATTRIBUTE_TYPE type,
+ CK_ATTRIBUTE *template,
+ CK_ULONG templateSize,
+ NSSItem *item
+)
+{
+ CK_ULONG i;
+
+ for (i=0; i < templateSize; i++) {
+ if (template[i].type == type) {
+ item->data = template[i].pValue;
+ item->size = template[i].ulValueLen;
+ return CKR_OK;
+ }
}
+ return CKR_TEMPLATE_INCOMPLETE;
+}
- return;
+/*
+ * get an attribute which is type CK_ULONG.
+ */
+CK_ULONG
+nss_ckcapi_GetULongAttribute
+(
+ CK_ATTRIBUTE_TYPE type,
+ CK_ATTRIBUTE *template,
+ CK_ULONG templateSize,
+ CK_RV *pError
+)
+{
+ NSSItem item;
+
+ *pError = nss_ckcapi_GetAttribute(type, template, templateSize, &item);
+ if (CKR_OK != *pError) {
+ return (CK_ULONG) 0;
+ }
+ if (item.size != sizeof(CK_ULONG)) {
+ *pError = CKR_ATTRIBUTE_VALUE_INVALID;
+ return (CK_ULONG) 0;
+ }
+ return *(CK_ULONG *)item.data;
}
/*
- * fetch the friendly name attribute.
+ * get an attribute which is type CK_BBOOL.
*/
-void
-ckcapi_FetchLabel(ckcapiInternalObject *io)
+CK_BBOOL
+nss_ckcapi_GetBoolAttribute
+(
+ CK_ATTRIBUTE_TYPE type,
+ CK_ATTRIBUTE *template,
+ CK_ULONG templateSize,
+ CK_RV *pError
+)
{
- ckcapiCertObject *co = &io->u.cert;
- PCCERT_CONTEXT certContext = io->u.cert.certContext;
- char labelDataUTF16[128];
- DWORD size = sizeof(labelDataUTF16);
- DWORD size8 = sizeof(co->labelData);
- BOOL rv;
+ NSSItem item;
- rv = CertGetCertificateContextProperty(certContext,
- CERT_FRIENDLY_NAME_PROP_ID, labelDataUTF16, &size);
- if (rv) {
- size = WideCharToMultiByte(CP_UTF8, 0, (LPCWSTR)labelDataUTF16, size,
- co->labelData, size8, NULL, 0);
- if (size == 0) {
- rv = 0;
+ *pError = nss_ckcapi_GetAttribute(type, template, templateSize, &item);
+ if (CKR_OK != *pError) {
+ return (CK_BBOOL) 0;
+ }
+ if (item.size != sizeof(CK_BBOOL)) {
+ *pError = CKR_ATTRIBUTE_VALUE_INVALID;
+ return (CK_BBOOL) 0;
+ }
+ return *(CK_BBOOL *)item.data;
+}
+
+/*
+ * Return the size in bytes of a wide string
+ */
+int
+nss_ckcapi_WideSize
+(
+ LPCWSTR wide
+)
+{
+ DWORD size = wcslen(wide)+1;
+ return size*2;
+}
+
+/*
+ * Covert a Unicode wide character string to a UTF8 string
+ */
+char *
+nss_ckcapi_WideToUTF8
+(
+ LPCWSTR wide
+)
+{
+ DWORD len = nss_ckcapi_WideSize(wide);
+ DWORD size;
+ char *buf;
+
+ size = WideCharToMultiByte(CP_UTF8, 0, wide, len, NULL, 0, NULL, 0);
+ if (size == 0) {
+ return NULL;
+ }
+ buf = nss_ZNEWARRAY(NULL, char, size);
+ size = WideCharToMultiByte(CP_UTF8, 0, wide, len, buf, size, NULL, 0);
+ if (size == 0) {
+ nss_ZFreeIf(buf);
+ return NULL;
+ }
+ return buf;
+}
+
+/*
+ * Return a Wide String duplicated with nss allocated memory.
+ */
+LPWSTR
+nss_ckcapi_WideDup
+(
+ LPCWSTR wide
+)
+{
+ DWORD len = nss_ckcapi_WideSize(wide);
+ LPWSTR buf;
+
+ buf = (LPWSTR) nss_ZNEWARRAY(NULL, char, len);
+ if ((LPWSTR) NULL == buf) {
+ return buf;
+ }
+ nsslibc_memcpy(buf, wide, len);
+ return buf;
+}
+
+/*
+ * Covert a UTF8 string to Unicode wide character
+ */
+LPWSTR
+nss_ckcapi_UTF8ToWide
+(
+ char *buf
+)
+{
+ DWORD size;
+ DWORD len = strlen(buf)+1;
+ LPWSTR wide;
+
+ size = MultiByteToWideChar(CP_UTF8, 0, buf, len, NULL, 0);
+ if (size == 0) {
+ return NULL;
+ }
+ wide = (LPWSTR)nss_ZNEWARRAY(NULL, char, size);
+ size = MultiByteToWideChar(CP_UTF8, 0, buf, len, wide, size);
+ if (size == 0) {
+ nss_ZFreeIf(wide);
+ return NULL;
+ }
+ return wide;
+}
+
+
+/*
+ * keep all the knowlege of how the internalObject is laid out in this function
+ *
+ * nss_ckcapi_FetchKeyContainer
+ *
+ * fetches the Provider container and info as well as a key handle for a
+ * private key. If something other than a private key is passed in,
+ * this function fails with CKR_KEY_TYPE_INCONSISTENT
+ */
+NSS_EXTERN CK_RV
+nss_ckcapi_FetchKeyContainer
+(
+ ckcapiInternalObject *iKey,
+ HCRYPTPROV *hProv,
+ DWORD *keySpec,
+ HCRYPTKEY *hKey
+)
+{
+ ckcapiCertObject *co;
+ ckcapiKeyObject *ko;
+ BOOL rc, dummy;
+ DWORD msError;
+
+
+ switch (iKey->type) {
+ default:
+ case ckcapiRaw:
+ /* can't have raw private keys */
+ return CKR_KEY_TYPE_INCONSISTENT;
+ case ckcapiCert:
+ if (iKey->objClass != CKO_PRIVATE_KEY) {
+ /* Only private keys have private key provider handles */
+ return CKR_KEY_TYPE_INCONSISTENT;
+ }
+ co = &iKey->u.cert;
+
+ /* OK, get the Provider */
+ rc = CryptAcquireCertificatePrivateKey(co->certContext,
+ CRYPT_ACQUIRE_CACHE_FLAG|CRYPT_ACQUIRE_COMPARE_KEY_FLAG, NULL, hProv,
+ keySpec, &dummy);
+ if (!rc) {
+ goto loser;
+ }
+ break;
+ case ckcapiBareKey:
+ if (iKey->objClass != CKO_PRIVATE_KEY) {
+ /* Only private keys have private key provider handles */
+ return CKR_KEY_TYPE_INCONSISTENT;
+ }
+ ko = &iKey->u.key;
+
+ /* OK, get the Provider */
+ if (0 == ko->hProv) {
+ rc = CryptAcquireContext(hProv,
+ ko->containerName,
+ ko->provName,
+ ko->provInfo.dwProvType , 0);
+ if (!rc) {
+ goto loser;
+ }
} else {
- size = strlen(co->labelData); /* sigh WideCharToMultiByte returns a
- * broken length, get the real one. */
+ *hProv = ko->hProv;
}
+ *keySpec = ko->provInfo.dwKeySpec;
+ break;
}
- /* we are presuming a user cert, make sure it has a nickname, even if
- * Microsoft never gave it one */
- if (!rv && co->hasID) {
- DWORD mserror = GetLastError();
-#define DEFAULT_NICKNAME "no Microsoft nickname"
- nsslibc_memcpy(co->labelData, DEFAULT_NICKNAME, sizeof(DEFAULT_NICKNAME));
- size = sizeof(DEFAULT_NICKNAME);
- rv = 1;
+
+ /* and get the crypto handle */
+ rc = CryptGetUserKey(*hProv, *keySpec, hKey);
+ if (!rc) {
+ goto loser;
}
-
- if (rv) {
- co->label.data = co->labelData;
- co->label.size = size;
+ return CKR_OK;
+loser:
+ /* map the microsoft error before leaving */
+ msError = GetLastError();
+ switch (msError) {
+ case ERROR_INVALID_HANDLE:
+ case ERROR_INVALID_PARAMETER:
+ case NTE_BAD_KEY:
+ case NTE_NO_KEY:
+ case NTE_BAD_PUBLIC_KEY:
+ case NTE_BAD_KEYSET:
+ case NTE_KEYSET_NOT_DEF:
+ return CKR_KEY_TYPE_INCONSISTENT;
+ case NTE_BAD_UID:
+ case NTE_KEYSET_ENTRY_BAD:
+ return CKR_DEVICE_ERROR;
}
- return;
+ return CKR_GENERAL_ERROR;
}
-void
-ckcapi_FetchSerial(ckcapiInternalObject *io)
+
+/*
+ * take a DER PUBLIC Key block and return the modulus and exponent
+ */
+static void
+ckcapi_CertPopulateModulusExponent
+(
+ ckcapiInternalObject *io
+)
{
- ckcapiCertObject *co = &io->u.cert;
+ ckcapiKeyParams *kp = &io->u.cert.key;
PCCERT_CONTEXT certContext = io->u.cert.certContext;
- DWORD size = sizeof(co->derSerial);
+ char *pkData = certContext->pCertInfo->SubjectPublicKeyInfo.PublicKey.pbData;
+ CK_ULONG size= certContext->pCertInfo->SubjectPublicKeyInfo.PublicKey.cbData;
+ CK_ULONG newSize;
+ char *ptr, *newptr;
- BOOL rc = CryptEncodeObject(X509_ASN_ENCODING,
- X509_MULTI_BYTE_INTEGER,
- &certContext->pCertInfo->SerialNumber,
- co->derSerial,
- &size);
- if (rc) {
- co->serial.data = co->derSerial;
- co->serial.size = size;
+ /* find the start of the modulus -- this will not give good results if
+ * the key isn't an rsa key! */
+ ptr = nss_ckcapi_DERUnwrap(pkData, size, &newSize, NULL);
+ kp->modulus.data = nss_ckcapi_DERUnwrap(ptr, newSize,
+ &kp->modulus.size, &newptr);
+ /* changed from signed to unsigned int */
+ if (0 == *(char *)kp->modulus.data) {
+ kp->modulus.data = ((char *)kp->modulus.data)+1;
+ kp->modulus.size = kp->modulus.size - 1;
+ }
+ /* changed from signed to unsigned int */
+ kp->exponent.data = nss_ckcapi_DERUnwrap(newptr, (newptr-ptr)+newSize,
+ &kp->exponent.size, NULL);
+ if (0 == *(char *)kp->exponent.data) {
+ kp->exponent.data = ((char *)kp->exponent.data)+1;
+ kp->exponent.size = kp->exponent.size - 1;
}
return;
}
@@ -383,9 +556,69 @@ typedef struct _CAPI_RSA_KEY_BLOB {
#define CAPI_PRIVATE_EXP_OFFSET(modSize) ((modSize)*3+(modSize)/2)
void
-ckcapi_FetchPrivateKey(ckcapiInternalObject *io)
+ckcapi_FetchPublicKey
+(
+ ckcapiInternalObject *io
+)
+{
+ ckcapiKeyParams *kp;
+ HCRYPTPROV hProv;
+ DWORD keySpec;
+ HCRYPTKEY hKey = 0;
+ CK_RV error;
+ DWORD bufLen;
+ BOOL rc;
+ unsigned long modulus;
+ char *buf = NULL;
+ CAPI_RSA_KEY_BLOB *blob;
+
+ error = nss_ckcapi_FetchKeyContainer(io, &hProv, &keySpec, &hKey);
+ if (CKR_OK != error) {
+ goto loser;
+ }
+ kp = (ckcapiCert == io->type) ? &io->u.cert.key : &io->u.key.key;
+
+ rc = CryptExportKey(hKey, 0, PUBLICKEYBLOB, 0, buf, &bufLen);
+ if (!rc) {
+ goto loser;
+ }
+ buf = nss_ZNEWARRAY(NULL, char, bufLen);
+ rc = CryptExportKey(hKey, 0, PUBLICKEYBLOB, 0, buf, &bufLen);
+ if (!rc) {
+ goto loser;
+ }
+ /* validate the blob */
+ blob = (CAPI_RSA_KEY_BLOB *)buf;
+ if ((PUBLICKEYBLOB != blob->header.bType) ||
+ (0x02 != blob->header.bVersion) ||
+ (0x31415352 != blob->rsa.magic)) {
+ goto loser;
+ }
+ modulus = blob->rsa.bitlen/8;
+ kp->pubKey = buf;
+ buf = NULL;
+
+ kp->modulus.data = &blob->data[CAPI_MODULUS_OFFSET(modulus)];
+ kp->modulus.size = modulus;
+ ckcapi_ReverseData(&kp->modulus);
+ nss_ckcapi_IntToData(blob->rsa.pubexp, &kp->exponent,
+ kp->publicExponentData, &error);
+
+loser:
+ nss_ZFreeIf(buf);
+ if (0 != hKey) {
+ CryptDestroyKey(hKey);
+ }
+ return;
+}
+
+void
+ckcapi_FetchPrivateKey
+(
+ ckcapiInternalObject *io
+)
{
- ckcapiCertObject *co = &io->u.cert;
+ ckcapiKeyParams *kp;
HCRYPTPROV hProv;
DWORD keySpec;
HCRYPTKEY hKey = 0;
@@ -400,6 +633,7 @@ ckcapi_FetchPrivateKey(ckcapiInternalObject *io)
if (CKR_OK != error) {
goto loser;
}
+ kp = (ckcapiCert == io->type) ? &io->u.cert.key : &io->u.key.key;
rc = CryptExportKey(hKey, 0, PRIVATEKEYBLOB, 0, buf, &bufLen);
if (!rc) {
@@ -418,27 +652,27 @@ ckcapi_FetchPrivateKey(ckcapiInternalObject *io)
goto loser;
}
modulus = blob->rsa.bitlen/8;
- co->privateKey = buf;
+ kp->privateKey = buf;
buf = NULL;
- co->privateExponent.data = &blob->data[CAPI_PRIVATE_EXP_OFFSET(modulus)];
- co->privateExponent.size = modulus;
- ckcapi_ReverseData(&co->privateExponent);
- co->prime1.data = &blob->data[CAPI_PRIME_1_OFFSET(modulus)];
- co->prime1.size = modulus/2;
- ckcapi_ReverseData(&co->prime1);
- co->prime2.data = &blob->data[CAPI_PRIME_2_OFFSET(modulus)];
- co->prime2.size = modulus/2;
- ckcapi_ReverseData(&co->prime2);
- co->exponent1.data = &blob->data[CAPI_EXPONENT_1_OFFSET(modulus)];
- co->exponent1.size = modulus/2;
- ckcapi_ReverseData(&co->exponent1);
- co->exponent2.data = &blob->data[CAPI_EXPONENT_2_OFFSET(modulus)];
- co->exponent2.size = modulus/2;
- ckcapi_ReverseData(&co->exponent2);
- co->coefficient.data = &blob->data[CAPI_COEFFICIENT_OFFSET(modulus)];
- co->coefficient.size = modulus/2;
- ckcapi_ReverseData(&co->coefficient);
+ kp->privateExponent.data = &blob->data[CAPI_PRIVATE_EXP_OFFSET(modulus)];
+ kp->privateExponent.size = modulus;
+ ckcapi_ReverseData(&kp->privateExponent);
+ kp->prime1.data = &blob->data[CAPI_PRIME_1_OFFSET(modulus)];
+ kp->prime1.size = modulus/2;
+ ckcapi_ReverseData(&kp->prime1);
+ kp->prime2.data = &blob->data[CAPI_PRIME_2_OFFSET(modulus)];
+ kp->prime2.size = modulus/2;
+ ckcapi_ReverseData(&kp->prime2);
+ kp->exponent1.data = &blob->data[CAPI_EXPONENT_1_OFFSET(modulus)];
+ kp->exponent1.size = modulus/2;
+ ckcapi_ReverseData(&kp->exponent1);
+ kp->exponent2.data = &blob->data[CAPI_EXPONENT_2_OFFSET(modulus)];
+ kp->exponent2.size = modulus/2;
+ ckcapi_ReverseData(&kp->exponent2);
+ kp->coefficient.data = &blob->data[CAPI_COEFFICIENT_OFFSET(modulus)];
+ kp->coefficient.size = modulus/2;
+ ckcapi_ReverseData(&kp->coefficient);
loser:
nss_ZFreeIf(buf);
@@ -448,54 +682,216 @@ loser:
return;
}
+
+void
+ckcapi_PopulateModulusExponent
+(
+ ckcapiInternalObject *io
+)
+{
+ if (ckcapiCert == io->type) {
+ ckcapi_CertPopulateModulusExponent(io);
+ } else {
+ ckcapi_FetchPublicKey(io);
+ }
+ return;
+}
+
/*
- * fetch the key ID.
+ * fetch the friendly name attribute.
+ * can only be called with ckcapiCert type objects!
*/
void
-ckcapi_FetchID(ckcapiInternalObject *io)
+ckcapi_FetchLabel
+(
+ ckcapiInternalObject *io
+)
{
ckcapiCertObject *co = &io->u.cert;
+ char *label;
PCCERT_CONTEXT certContext = io->u.cert.certContext;
- DWORD size = sizeof(co->idData);
+ char labelDataUTF16[128];
+ DWORD size = sizeof(labelDataUTF16);
+ DWORD size8 = sizeof(co->labelData);
BOOL rv;
rv = CertGetCertificateContextProperty(certContext,
- CERT_KEY_IDENTIFIER_PROP_ID, co->idData, &size);
+ CERT_FRIENDLY_NAME_PROP_ID, labelDataUTF16, &size);
+ if (rv) {
+ co->labelData = nss_ckcapi_WideToUTF8((LPCWSTR)labelDataUTF16);
+ if ((CHAR *)NULL == co->labelData) {
+ rv = 0;
+ } else {
+ size = strlen(co->labelData);
+ }
+ }
+ label = co->labelData;
+ /* we are presuming a user cert, make sure it has a nickname, even if
+ * Microsoft never gave it one */
+ if (!rv && co->hasID) {
+ DWORD mserror = GetLastError();
+#define DEFAULT_NICKNAME "no Microsoft nickname"
+ label = DEFAULT_NICKNAME;
+ size = sizeof(DEFAULT_NICKNAME);
+ rv = 1;
+ }
+
if (rv) {
- co->id.data = co->idData;
- co->id.size = size;
+ co->label.data = label;
+ co->label.size = size;
+ }
+ return;
+}
+
+void
+ckcapi_FetchSerial
+(
+ ckcapiInternalObject *io
+)
+{
+ ckcapiCertObject *co = &io->u.cert;
+ PCCERT_CONTEXT certContext = io->u.cert.certContext;
+ DWORD size = sizeof(co->derSerial);
+
+ BOOL rc = CryptEncodeObject(X509_ASN_ENCODING,
+ X509_MULTI_BYTE_INTEGER,
+ &certContext->pCertInfo->SerialNumber,
+ co->derSerial,
+ &size);
+ if (rc) {
+ co->serial.data = co->derSerial;
+ co->serial.size = size;
}
return;
}
/*
+ * fetch the key ID.
+ */
+void
+ckcapi_FetchID
+(
+ ckcapiInternalObject *io
+)
+{
+ PCCERT_CONTEXT certContext = io->u.cert.certContext;
+ DWORD size = 0;
+ BOOL rc;
+
+ rc = CertGetCertificateContextProperty(certContext,
+ CERT_KEY_IDENTIFIER_PROP_ID, NULL, &size);
+ if (!rc) {
+ return;
+ }
+ io->idData = nss_ZNEWARRAY(NULL, char, size);
+ if (io->idData == NULL) {
+ return;
+ }
+
+ rc = CertGetCertificateContextProperty(certContext,
+ CERT_KEY_IDENTIFIER_PROP_ID, io->idData, &size);
+ if (!rc) {
+ nss_ZFreeIf(io->idData);
+ io->idData = NULL;
+ return;
+ }
+ io->id.data = io->idData;
+ io->id.size = size;
+ return;
+}
+
+/*
* fetch the hash key.
*/
void
-ckcapi_FetchHashKey(ckcapiInternalObject *io)
+ckcapi_CertFetchHashKey
+(
+ ckcapiInternalObject *io
+)
{
ckcapiCertObject *co = &io->u.cert;
PCCERT_CONTEXT certContext = io->u.cert.certContext;
DWORD size = certContext->cbCertEncoded;
- DWORD max = sizeof(co->hashKeyData);
+ DWORD max = sizeof(io->hashKeyData)-1;
DWORD offset = 0;
- if (size+1 > max) {
- offset = size+1 - max;
- size = max-1;
+ /* make sure we don't over flow. NOTE: cutting the top of a cert is
+ * not a big issue because the signature for will be unique for the cert */
+ if (size > max) {
+ offset = size - max;
+ size = max;
}
- nsslibc_memcpy(co->hashKeyData,certContext->pbCertEncoded+offset, size);
- co->hashKeyData[size] = (char)(co->objClass & 0xff);
+ nsslibc_memcpy(io->hashKeyData,certContext->pbCertEncoded+offset, size);
+ io->hashKeyData[size] = (char)(io->objClass & 0xff);
- co->hashKey.data = co->hashKeyData;
- co->hashKey.size = size+1;
+ io->hashKey.data = io->hashKeyData;
+ io->hashKey.size = size+1;
return;
}
+/*
+ * fetch the hash key.
+ */
+void
+ckcapi_KeyFetchHashKey
+(
+ ckcapiInternalObject *io
+)
+{
+ ckcapiKeyObject *ko = &io->u.key;
+ DWORD size;
+ DWORD max = sizeof(io->hashKeyData)-2;
+ DWORD offset = 0;
+ DWORD provLen = strlen(ko->provName);
+ DWORD containerLen = strlen(ko->containerName);
+
+
+ size = provLen + containerLen;
+
+ /* make sure we don't overflow, try to keep things unique */
+ if (size > max) {
+ DWORD diff = ((size - max)+1)/2;
+ provLen -= diff;
+ containerLen -= diff;
+ size = provLen+containerLen;
+ }
+
+ nsslibc_memcpy(io->hashKeyData, ko->provName, provLen);
+ nsslibc_memcpy(&io->hashKeyData[provLen],
+ ko->containerName,
+ containerLen);
+ io->hashKeyData[size] = (char)(io->objClass & 0xff);
+ io->hashKeyData[size+1] = (char)(ko->provInfo.dwKeySpec & 0xff);
+
+ io->hashKey.data = io->hashKeyData;
+ io->hashKey.size = size+2;
+ return;
+}
+
+/*
+ * fetch the hash key.
+ */
+void
+ckcapi_FetchHashKey
+(
+ ckcapiInternalObject *io
+)
+{
+ if (ckcapiCert == io->type) {
+ ckcapi_CertFetchHashKey(io);
+ } else {
+ ckcapi_KeyFetchHashKey(io);
+ }
+ return;
+}
+
const NSSItem *
-ckcapi_FetchCertAttribute(ckcapiInternalObject *io,
- CK_ATTRIBUTE_TYPE type)
+ckcapi_FetchCertAttribute
+(
+ ckcapiInternalObject *io,
+ CK_ATTRIBUTE_TYPE type
+)
{
PCCERT_CONTEXT certContext = io->u.cert.certContext;
switch(type) {
@@ -542,22 +938,26 @@ ckcapi_FetchCertAttribute(ckcapiInternalObject *io,
if (!io->u.cert.hasID) {
return NULL;
}
- if (0 == io->u.cert.id.size) {
+ if (0 == io->id.size) {
ckcapi_FetchID(io);
}
- return &io->u.cert.id;
+ return &io->id;
default:
break;
}
return NULL;
}
-
const NSSItem *
-ckcapi_FetchPubKeyAttribute(ckcapiInternalObject *io,
- CK_ATTRIBUTE_TYPE type)
+ckcapi_FetchPubKeyAttribute
+(
+ ckcapiInternalObject *io,
+ CK_ATTRIBUTE_TYPE type
+)
{
- PCCERT_CONTEXT certContext = io->u.cert.certContext;
+ PRBool isCertType = (ckcapiCert == io->type);
+ ckcapiKeyParams *kp = isCertType ? &io->u.cert.key : &io->u.key.key;
+
switch(type) {
case CKA_CLASS:
return &ckcapi_pubKeyClassItem;
@@ -575,41 +975,54 @@ ckcapi_FetchPubKeyAttribute(ckcapiInternalObject *io,
case CKA_KEY_TYPE:
return &ckcapi_rsaItem;
case CKA_LABEL:
+ if (!isCertType) {
+ return &ckcapi_emptyItem;
+ }
if (0 == io->u.cert.label.size) {
ckcapi_FetchLabel(io);
}
return &io->u.cert.label;
case CKA_SUBJECT:
+ if (!isCertType) {
+ return &ckcapi_emptyItem;
+ }
if (0 == io->u.cert.subject.size) {
+ PCCERT_CONTEXT certContext= io->u.cert.certContext;
io->u.cert.subject.data = certContext->pCertInfo->Subject.pbData;
io->u.cert.subject.size = certContext->pCertInfo->Subject.cbData;
}
return &io->u.cert.subject;
case CKA_MODULUS:
- if (0 == io->u.cert.modulus.size) {
+ if (0 == kp->modulus.size) {
ckcapi_PopulateModulusExponent(io);
}
- return &io->u.cert.modulus;
+ return &kp->modulus;
case CKA_PUBLIC_EXPONENT:
- if (0 == io->u.cert.modulus.size) {
+ if (0 == kp->modulus.size) {
ckcapi_PopulateModulusExponent(io);
}
- return &io->u.cert.exponent;
+ return &kp->exponent;
case CKA_ID:
- if (0 == io->u.cert.id.size) {
+ if (0 == io->id.size) {
ckcapi_FetchID(io);
}
- return &io->u.cert.id;
+ return &io->id;
default:
break;
}
return NULL;
}
+
const NSSItem *
-ckcapi_FetchPrivKeyAttribute(ckcapiInternalObject *io,
- CK_ATTRIBUTE_TYPE type)
+ckcapi_FetchPrivKeyAttribute
+(
+ ckcapiInternalObject *io,
+ CK_ATTRIBUTE_TYPE type
+)
{
- PCCERT_CONTEXT certContext = io->u.cert.certContext;
+ PRBool isCertType = (ckcapiCert == io->type);
+ ckcapiKeyParams *kp = isCertType ? &io->u.cert.key : &io->u.key.key;
+
switch(type) {
case CKA_CLASS:
return &ckcapi_privKeyClassItem;
@@ -631,68 +1044,76 @@ ckcapi_FetchPrivKeyAttribute(ckcapiInternalObject *io,
case CKA_KEY_TYPE:
return &ckcapi_rsaItem;
case CKA_LABEL:
+ if (!isCertType) {
+ return &ckcapi_emptyItem;
+ }
if (0 == io->u.cert.label.size) {
ckcapi_FetchLabel(io);
}
return &io->u.cert.label;
case CKA_SUBJECT:
+ if (!isCertType) {
+ return &ckcapi_emptyItem;
+ }
if (0 == io->u.cert.subject.size) {
+ PCCERT_CONTEXT certContext= io->u.cert.certContext;
io->u.cert.subject.data = certContext->pCertInfo->Subject.pbData;
io->u.cert.subject.size = certContext->pCertInfo->Subject.cbData;
}
return &io->u.cert.subject;
case CKA_MODULUS:
- if (0 == io->u.cert.modulus.size) {
+ if (0 == kp->modulus.size) {
ckcapi_PopulateModulusExponent(io);
}
- return &io->u.cert.modulus;
+ return &kp->modulus;
case CKA_PUBLIC_EXPONENT:
- if (0 == io->u.cert.modulus.size) {
+ if (0 == kp->modulus.size) {
ckcapi_PopulateModulusExponent(io);
}
- return &io->u.cert.exponent;
+ return &kp->exponent;
case CKA_PRIVATE_EXPONENT:
- if (0 == io->u.cert.privateExponent.size) {
+ if (0 == kp->privateExponent.size) {
ckcapi_FetchPrivateKey(io);
}
- return &io->u.cert.privateExponent;
+ return &kp->privateExponent;
case CKA_PRIME_1:
- if (0 == io->u.cert.privateExponent.size) {
+ if (0 == kp->privateExponent.size) {
ckcapi_FetchPrivateKey(io);
}
- return &io->u.cert.prime1;
+ return &kp->prime1;
case CKA_PRIME_2:
- if (0 == io->u.cert.privateExponent.size) {
+ if (0 == kp->privateExponent.size) {
ckcapi_FetchPrivateKey(io);
}
- return &io->u.cert.prime2;
+ return &kp->prime2;
case CKA_EXPONENT_1:
- if (0 == io->u.cert.privateExponent.size) {
+ if (0 == kp->privateExponent.size) {
ckcapi_FetchPrivateKey(io);
}
- return &io->u.cert.exponent1;
+ return &kp->exponent1;
case CKA_EXPONENT_2:
- if (0 == io->u.cert.privateExponent.size) {
+ if (0 == kp->privateExponent.size) {
ckcapi_FetchPrivateKey(io);
}
- return &io->u.cert.exponent2;
+ return &kp->exponent2;
case CKA_COEFFICIENT:
- if (0 == io->u.cert.privateExponent.size) {
+ if (0 == kp->privateExponent.size) {
ckcapi_FetchPrivateKey(io);
}
- return &io->u.cert.coefficient;
+ return &kp->coefficient;
case CKA_ID:
- if (0 == io->u.cert.id.size) {
+ if (0 == io->id.size) {
ckcapi_FetchID(io);
}
- return &io->u.cert.id;
+ return &io->id;
default:
return NULL;
}
}
const NSSItem *
-nss_ckcapi_FetchAttribute(
+nss_ckcapi_FetchAttribute
+(
ckcapiInternalObject *io,
CK_ATTRIBUTE_TYPE type
)
@@ -708,7 +1129,7 @@ nss_ckcapi_FetchAttribute(
return NULL;
}
/* deal with the common attributes */
- switch (io->u.cert.objClass) {
+ switch (io->objClass) {
case CKO_CERTIFICATE:
return ckcapi_FetchCertAttribute(io, type);
case CKO_PRIVATE_KEY:
@@ -719,16 +1140,184 @@ nss_ckcapi_FetchAttribute(
return NULL;
}
+/*
+ * check to see if the certificate already exists
+ */
+static PRBool
+ckcapi_cert_exists(
+ NSSItem *value,
+ ckcapiInternalObject **io
+)
+{
+ int count,i;
+ PRUint32 size = 0;
+ ckcapiInternalObject **listp = NULL;
+ CK_ATTRIBUTE myTemplate[2];
+ CK_OBJECT_CLASS cert_class = CKO_CERTIFICATE;
+ CK_ULONG templateCount = 2;
+ CK_RV error;
+ PRBool found = PR_FALSE;
+
+ myTemplate[0].type = CKA_CLASS;
+ myTemplate[0].pValue = &cert_class;
+ myTemplate[0].ulValueLen = sizeof(cert_class);
+ myTemplate[1].type = CKA_VALUE;
+ myTemplate[1].pValue = value->data;
+ myTemplate[1].ulValueLen = value->size;
+
+ count = nss_ckcapi_collect_all_certs(myTemplate, templateCount, &listp,
+ &size, 0, &error);
+
+ /* free them */
+ if (count > 1) {
+ *io = listp[0];
+ found = PR_TRUE;
+ }
+
+ for (i=1; i < count; i++) {
+ nss_ckcapi_DestroyInternalObject(listp[i]);
+ }
+ nss_ZFreeIf(listp);
+ return found;
+}
+
+static PRBool
+ckcapi_cert_hasEmail
+(
+ PCCERT_CONTEXT certContext
+)
+{
+ int count;
+
+ count = CertGetNameString(certContext, CERT_NAME_EMAIL_TYPE,
+ 0, NULL, NULL, 0);
+
+ return count > 1 ? PR_TRUE : PR_FALSE;
+}
+
+static PRBool
+ckcapi_cert_isRoot
+(
+ PCCERT_CONTEXT certContext
+)
+{
+ return CertCompareCertificateName(certContext->dwCertEncodingType,
+ &certContext->pCertInfo->Issuer, &certContext->pCertInfo->Subject);
+}
+
+static PRBool
+ckcapi_cert_isCA
+(
+ PCCERT_CONTEXT certContext
+)
+{
+ PCERT_EXTENSION extension;
+ CERT_BASIC_CONSTRAINTS2_INFO basicInfo;
+ DWORD size = sizeof(basicInfo);
+ BOOL rc;
+
+ extension = CertFindExtension (szOID_BASIC_CONSTRAINTS,
+ certContext->pCertInfo->cExtension,
+ certContext->pCertInfo->rgExtension);
+ if ((PCERT_EXTENSION) NULL == extension ) {
+ return PR_FALSE;
+ }
+ rc = CryptDecodeObject(X509_ASN_ENCODING, szOID_BASIC_CONSTRAINTS2,
+ extension->Value.pbData, extension->Value.cbData,
+ 0, &basicInfo, &size);
+ if (!rc) {
+ return PR_FALSE;
+ }
+ return (PRBool) basicInfo.fCA;
+}
+
+static CRYPT_KEY_PROV_INFO *
+ckcapi_cert_getPrivateKeyInfo
+(
+ PCCERT_CONTEXT certContext,
+ NSSItem *keyID
+)
+{
+ BOOL rc;
+ CRYPT_HASH_BLOB msKeyID;
+ DWORD size = 0;
+ CRYPT_KEY_PROV_INFO *prov = NULL;
+
+ msKeyID.cbData = keyID->size;
+ msKeyID.pbData = keyID->data;
+
+ rc = CryptGetKeyIdentifierProperty(
+ &msKeyID,
+ CERT_KEY_PROV_INFO_PROP_ID,
+ 0, NULL, NULL, NULL, &size);
+ if (!rc) {
+ return (CRYPT_KEY_PROV_INFO *)NULL;
+ }
+ prov = (CRYPT_KEY_PROV_INFO *)nss_ZNEWARRAY(NULL, char, size);
+ if ((CRYPT_KEY_PROV_INFO *)prov == NULL) {
+ return (CRYPT_KEY_PROV_INFO *) NULL;
+ }
+ rc = CryptGetKeyIdentifierProperty(
+ &msKeyID,
+ CERT_KEY_PROV_INFO_PROP_ID,
+ 0, NULL, NULL, prov, &size);
+ if (!rc) {
+ nss_ZFreeIf(prov);
+ return (CRYPT_KEY_PROV_INFO *)NULL;
+ }
+
+ return prov;
+}
+
+static CRYPT_KEY_PROV_INFO *
+ckcapi_cert_getProvInfo
+(
+ ckcapiInternalObject *io
+)
+{
+ BOOL rc;
+ DWORD size = 0;
+ CRYPT_KEY_PROV_INFO *prov = NULL;
+
+ rc = CertGetCertificateContextProperty(
+ io->u.cert.certContext,
+ CERT_KEY_PROV_INFO_PROP_ID,
+ NULL, &size);
+ if (!rc) {
+ return (CRYPT_KEY_PROV_INFO *)NULL;
+ }
+ prov = (CRYPT_KEY_PROV_INFO *)nss_ZNEWARRAY(NULL, char, size);
+ if ((CRYPT_KEY_PROV_INFO *)prov == NULL) {
+ return (CRYPT_KEY_PROV_INFO *) NULL;
+ }
+ rc = CertGetCertificateContextProperty(
+ io->u.cert.certContext,
+ CERT_KEY_PROV_INFO_PROP_ID,
+ prov, &size);
+ if (!rc) {
+ nss_ZFreeIf(prov);
+ return (CRYPT_KEY_PROV_INFO *)NULL;
+ }
+
+ return prov;
+}
+
+/* forward declaration */
+static void
+ckcapi_removeObjectFromHash
+(
+ ckcapiInternalObject *io
+);
/*
* Finalize - unneeded
- * Destroy - CKR_SESSION_READ_ONLY
+ * Destroy
* IsTokenObject - CK_TRUE
* GetAttributeCount
* GetAttributeTypes
* GetAttributeSize
* GetAttribute
- * SetAttribute - unneeded
+ * SetAttribute
* GetObjectSize
*/
@@ -745,7 +1334,88 @@ ckcapi_mdObject_Destroy
NSSCKFWInstance *fwInstance
)
{
- return CKR_SESSION_READ_ONLY;
+ ckcapiInternalObject *io = (ckcapiInternalObject *)mdObject->etc;
+ CK_OBJECT_CLASS objClass;
+ BOOL rc;
+ DWORD provType;
+ DWORD msError;
+ PRBool isCertType = (PRBool)(ckcapiCert == io->type);
+ HCERTSTORE hStore = 0;
+
+ if (ckcapiRaw == io->type) {
+ /* there is not 'object write protected' error, use the next best thing */
+ return CKR_TOKEN_WRITE_PROTECTED;
+ }
+
+ objClass = io->objClass;
+ if (CKO_CERTIFICATE == objClass) {
+ PCCERT_CONTEXT certContext;
+
+ /* get the store */
+ hStore = CertOpenSystemStore(0, io->u.cert.certStore);
+ if (0 == hStore) {
+ rc = 0;
+ goto loser;
+ }
+ certContext = CertFindCertificateInStore(hStore, X509_ASN_ENCODING, 0,
+ CERT_FIND_EXISTING, io->u.cert.certContext, NULL);
+ if ((PCCERT_CONTEXT)NULL == certContext) {
+ rc = 0;
+ goto loser;
+ }
+ rc = CertDeleteCertificateFromStore(certContext);
+ CertFreeCertificateContext(certContext);
+ } else {
+ char *provName = NULL;
+ char *containerName = NULL;
+ HCRYPTPROV hProv;
+ CRYPT_HASH_BLOB msKeyID;
+
+ if (0 == io->id.size) {
+ ckcapi_FetchID(io);
+ }
+
+ if (isCertType) {
+ CRYPT_KEY_PROV_INFO * provInfo = ckcapi_cert_getProvInfo(io);
+ provName = nss_ckcapi_WideToUTF8(provInfo->pwszProvName);
+ containerName = nss_ckcapi_WideToUTF8(provInfo->pwszContainerName);
+ provType = provInfo->dwProvType;
+ nss_ZFreeIf(provInfo);
+ } else {
+ provName = io->u.key.provName;
+ containerName = io->u.key.containerName;
+ provType = io->u.key.provInfo.dwProvType;
+ io->u.key.provName = NULL;
+ io->u.key.containerName = NULL;
+ }
+ /* first remove the key id pointer */
+ msKeyID.cbData = io->id.size;
+ msKeyID.pbData = io->id.data;
+ rc = CryptSetKeyIdentifierProperty(&msKeyID,
+ CERT_KEY_PROV_INFO_PROP_ID, CRYPT_KEYID_DELETE_FLAG, NULL, NULL, NULL);
+ if (rc) {
+ rc = CryptAcquireContext(&hProv, containerName, provName, provType,
+ CRYPT_DELETEKEYSET);
+ }
+ nss_ZFreeIf(provName);
+ nss_ZFreeIf(containerName);
+ }
+loser:
+
+ if (hStore) {
+ CertCloseStore(hStore, 0);
+ }
+ if (!rc) {
+ msError = GetLastError();
+ return CKR_GENERAL_ERROR;
+ }
+
+ /* remove it from the hash */
+ ckcapi_removeObjectFromHash(io);
+
+ /* free the puppy.. */
+ nss_ckcapi_DestroyInternalObject(io);
+ return CKR_OK;
}
static CK_BBOOL
@@ -783,7 +1453,7 @@ ckcapi_mdObject_GetAttributeCount
if (ckcapiRaw == io->type) {
return io->u.raw.n;
}
- switch (io->u.cert.objClass) {
+ switch (io->objClass) {
case CKO_CERTIFICATE:
return certAttrsCount;
case CKO_PUBLIC_KEY:
@@ -824,7 +1494,7 @@ ckcapi_mdObject_GetAttributeTypes
}
if (io->type == ckcapiRaw) {
attrs = io->u.raw.types;
- } else switch(io->u.cert.objClass) {
+ } else switch(io->objClass) {
case CKO_CERTIFICATE:
attrs = certAttrs;
break;
@@ -873,6 +1543,24 @@ ckcapi_mdObject_GetAttributeSize
return b->size;
}
+static CK_RV
+ckcapi_mdObject_SetAttribute
+(
+ NSSCKMDObject *mdObject,
+ NSSCKFWObject *fwObject,
+ NSSCKMDSession *mdSession,
+ NSSCKFWSession *fwSession,
+ NSSCKMDToken *mdToken,
+ NSSCKFWToken *fwToken,
+ NSSCKMDInstance *mdInstance,
+ NSSCKFWInstance *fwInstance,
+ CK_ATTRIBUTE_TYPE attribute,
+ NSSItem *value
+)
+{
+ return CKR_OK;
+}
+
static NSSCKFWItem
ckcapi_mdObject_GetAttribute
(
@@ -933,7 +1621,7 @@ ckcapi_prototype_mdObject = {
ckcapi_mdObject_GetAttributeSize,
ckcapi_mdObject_GetAttribute,
NULL, /* FreeAttribute */
- NULL, /* SetAttribute */
+ ckcapi_mdObject_SetAttribute,
ckcapi_mdObject_GetObjectSize,
(void *)NULL /* null terminator */
};
@@ -953,7 +1641,7 @@ nss_ckcapi_CreateMDObject
}
if (ckcapiCert == io->type) {
/* the hash key, not a cryptographic key */
- NSSItem *key = &io->u.cert.hashKey;
+ NSSItem *key = &io->hashKey;
ckcapiInternalObject *old_o = NULL;
if (key->size == 0) {
@@ -977,14 +1665,597 @@ nss_ckcapi_CreateMDObject
return &io->mdObject;
}
+static void
+ckcapi_removeObjectFromHash
+(
+ ckcapiInternalObject *io
+)
+{
+ NSSItem *key = &io->hashKey;
+
+ if ((nssHash *)NULL == ckcapiInternalObjectHash) {
+ return;
+ }
+ if (key->size == 0) {
+ ckcapi_FetchHashKey(io);
+ }
+ nssHash_Remove(ckcapiInternalObjectHash, key);
+ return;
+}
+
void
-nss_ckcapi_DestroyInternalObject(ckcapiInternalObject *io)
+nss_ckcapi_DestroyInternalObject
+(
+ ckcapiInternalObject *io
+)
{
- if (ckcapiRaw == io->type) {
+ switch (io->type) {
+ case ckcapiRaw:
return;
+ case ckcapiCert:
+ CertFreeCertificateContext(io->u.cert.certContext);
+ nss_ZFreeIf(io->u.cert.labelData);
+ nss_ZFreeIf(io->u.cert.key.privateKey);
+ nss_ZFreeIf(io->u.cert.key.pubKey);
+ nss_ZFreeIf(io->idData);
+ break;
+ case ckcapiBareKey:
+ nss_ZFreeIf(io->u.key.provInfo.pwszContainerName);
+ nss_ZFreeIf(io->u.key.provInfo.pwszProvName);
+ nss_ZFreeIf(io->u.key.provName);
+ nss_ZFreeIf(io->u.key.containerName);
+ nss_ZFreeIf(io->u.key.key.privateKey);
+ nss_ZFreeIf(io->u.key.key.pubKey);
+ if (0 != io->u.key.hProv) {
+ CryptReleaseContext(io->u.key.hProv, 0);
+ }
+ nss_ZFreeIf(io->idData);
+ break;
}
- CertFreeCertificateContext(io->u.cert.certContext);
- nss_ZFreeIf(io->u.cert.privateKey);
nss_ZFreeIf(io);
return;
}
+
+static ckcapiInternalObject *
+nss_ckcapi_CreateCertificate
+(
+ NSSCKFWSession *fwSession,
+ CK_ATTRIBUTE_PTR pTemplate,
+ CK_ULONG ulAttributeCount,
+ CK_RV *pError
+)
+{
+ NSSItem value;
+ NSSItem keyID;
+ char *storeStr;
+ ckcapiInternalObject *io = NULL;
+ PCCERT_CONTEXT certContext = NULL;
+ PCCERT_CONTEXT storedCertContext = NULL;
+ CRYPT_KEY_PROV_INFO *prov_info = NULL;
+ HCERTSTORE hStore = 0;
+ DWORD msError = 0;
+ PRBool hasID;
+ BOOL rc;
+
+ *pError = nss_ckcapi_GetAttribute(CKA_VALUE, pTemplate,
+ ulAttributeCount, &value);
+
+ if (CKR_OK != *pError) {
+ return (ckcapiInternalObject *)NULL;
+ }
+
+ *pError = nss_ckcapi_GetAttribute(CKA_ID, pTemplate,
+ ulAttributeCount, &keyID);
+
+ if (CKR_OK != *pError) {
+ return (ckcapiInternalObject *)NULL;
+ }
+
+ if (ckcapi_cert_exists(&value, &io)) {
+ return io;
+ }
+
+ /* OK, we are creating a new one, figure out what store it belongs to..
+ * first get a certContext handle.. */
+ certContext = CertCreateCertificateContext(X509_ASN_ENCODING,
+ value.data, value.size);
+ if ((PCCERT_CONTEXT) NULL == certContext) {
+ msError = GetLastError();
+ *pError = CKR_ATTRIBUTE_VALUE_INVALID;
+ goto loser;
+ }
+
+ /* do we have a private key laying around... */
+ prov_info = ckcapi_cert_getPrivateKeyInfo(certContext, &keyID);
+ if (prov_info) {
+ CRYPT_DATA_BLOB msKeyID;
+ storeStr = "My";
+ hasID = PR_TRUE;
+ rc = CertSetCertificateContextProperty(certContext,
+ CERT_KEY_PROV_INFO_PROP_ID,
+ 0, prov_info);
+ nss_ZFreeIf(prov_info);
+ if (!rc) {
+ msError = GetLastError();
+ *pError = CKR_DEVICE_ERROR;
+ goto loser;
+ }
+ msKeyID.cbData = keyID.size;
+ msKeyID.pbData = keyID.data;
+ rc = CertSetCertificateContextProperty(certContext,
+ CERT_KEY_IDENTIFIER_PROP_ID,
+ 0, &msKeyID);
+ if (!rc) {
+ msError = GetLastError();
+ *pError = CKR_DEVICE_ERROR;
+ goto loser;
+ }
+ /* does it look like a CA */
+ } else if (ckcapi_cert_isCA(certContext)) {
+ storeStr = ckcapi_cert_isRoot(certContext) ? "CA" : "Root";
+ /* does it look like an S/MIME cert */
+ } else if (ckcapi_cert_hasEmail(certContext)) {
+ storeStr = "AddressBook";
+ } else {
+ /* just pick a store */
+ storeStr = "CA";
+ }
+
+ hStore = CertOpenSystemStore((HCRYPTPROV) NULL, storeStr);
+ if (0 == hStore) {
+ msError = GetLastError();
+ *pError = CKR_DEVICE_ERROR;
+ goto loser;
+ }
+
+ rc = CertAddCertificateContextToStore(hStore, certContext,
+ CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES, &storedCertContext);
+ CertFreeCertificateContext(certContext);
+ certContext = NULL;
+ CertCloseStore(hStore, 0);
+ hStore = 0;
+ if (!rc) {
+ msError = GetLastError();
+ *pError = CKR_DEVICE_ERROR;
+ goto loser;
+ }
+
+ io = nss_ZNEW(NULL, ckcapiInternalObject);
+ if ((ckcapiInternalObject *)NULL == io) {
+ *pError = CKR_HOST_MEMORY;
+ goto loser;
+ }
+ io->type = ckcapiCert;
+ io->objClass = CKO_CERTIFICATE;
+ io->u.cert.certContext = storedCertContext;
+ io->u.cert.hasID = hasID;
+ return io;
+
+loser:
+ if (certContext) {
+ CertFreeCertificateContext(certContext);
+ certContext = NULL;
+ }
+ if (storedCertContext) {
+ CertFreeCertificateContext(storedCertContext);
+ storedCertContext = NULL;
+ }
+ if (0 != hStore) {
+ CertCloseStore(hStore, 0);
+ }
+ return (ckcapiInternalObject *)NULL;
+
+}
+
+static char *
+ckcapi_getDefaultProvider
+(
+ CK_RV *pError
+)
+{
+ char *name = NULL;
+ BOOL rc;
+ DWORD nameLength = 0;
+
+ rc = CryptGetDefaultProvider(PROV_RSA_FULL, NULL, CRYPT_USER_DEFAULT, NULL,
+ &nameLength);
+ if (!rc) {
+ return (char *)NULL;
+ }
+
+ name = nss_ZNEWARRAY(NULL, char, nameLength);
+ if ((char *)NULL == name ) {
+ return (char *)NULL;
+ }
+ rc = CryptGetDefaultProvider(PROV_RSA_FULL, NULL, CRYPT_USER_DEFAULT, name,
+ &nameLength);
+ if (!rc) {
+ nss_ZFreeIf(name);
+ return (char *)NULL;
+ }
+
+ return name;
+}
+
+static char *
+ckcapi_getContainer
+(
+ CK_RV *pError,
+ NSSItem *id
+)
+{
+ RPC_STATUS rstat;
+ UUID uuid;
+ char *uuidStr;
+ char *container;
+
+ rstat = UuidCreate(&uuid);
+ rstat = UuidToString(&uuid, &uuidStr);
+
+ /* convert it from rcp memory to our own */
+ container = nssUTF8_Duplicate(uuidStr, NULL);
+ RpcStringFree(&uuidStr);
+
+ return container;
+}
+
+static CK_RV
+ckcapi_buildPrivateKeyBlob
+(
+ NSSItem *keyBlob,
+ NSSItem *modulus,
+ NSSItem *publicExponent,
+ NSSItem *privateExponent,
+ NSSItem *prime1,
+ NSSItem *prime2,
+ NSSItem *exponent1,
+ NSSItem *exponent2,
+ NSSItem *coefficient,
+ PRBool isKeyExchange
+)
+{
+ CAPI_RSA_KEY_BLOB *keyBlobData = NULL;
+ unsigned char *target;
+ unsigned long modSize = modulus->size;
+ unsigned long dataSize;
+ CK_RV error = CKR_OK;
+
+ /* validate extras */
+ if (privateExponent->size != modSize) {
+ error = CKR_ATTRIBUTE_VALUE_INVALID;
+ goto loser;
+ }
+ if (prime1->size != modSize/2) {
+ error = CKR_ATTRIBUTE_VALUE_INVALID;
+ goto loser;
+ }
+ if (prime2->size != modSize/2) {
+ error = CKR_ATTRIBUTE_VALUE_INVALID;
+ goto loser;
+ }
+ if (exponent1->size != modSize/2) {
+ error = CKR_ATTRIBUTE_VALUE_INVALID;
+ goto loser;
+ }
+ if (exponent2->size != modSize/2) {
+ error = CKR_ATTRIBUTE_VALUE_INVALID;
+ goto loser;
+ }
+ if (coefficient->size != modSize/2) {
+ error = CKR_ATTRIBUTE_VALUE_INVALID;
+ goto loser;
+ }
+ dataSize = (modSize*4)+(modSize/2) + sizeof(CAPI_RSA_KEY_BLOB);
+ keyBlobData = (CAPI_RSA_KEY_BLOB *)nss_ZNEWARRAY(NULL, char, dataSize);
+ if ((CAPI_RSA_KEY_BLOB *)NULL == keyBlobData) {
+ error = CKR_HOST_MEMORY;
+ goto loser;
+ }
+
+ keyBlobData->header.bType = PRIVATEKEYBLOB;
+ keyBlobData->header.bVersion = 0x02;
+ keyBlobData->header.reserved = 0x00;
+ keyBlobData->header.aiKeyAlg = isKeyExchange ? CALG_RSA_KEYX:CALG_RSA_SIGN;
+ keyBlobData->rsa.magic = 0x32415352;
+ keyBlobData->rsa.bitlen = modSize * 8;
+ keyBlobData->rsa.pubexp = nss_ckcapi_DataToInt(publicExponent,&error);
+ if (CKR_OK != error) {
+ goto loser;
+ }
+
+ target = &keyBlobData->data[CAPI_MODULUS_OFFSET(modSize)];
+ nsslibc_memcpy(target, modulus->data, modulus->size);
+ modulus->data = target;
+ ckcapi_ReverseData(modulus);
+
+ target = &keyBlobData->data[CAPI_PRIVATE_EXP_OFFSET(modSize)];
+ nsslibc_memcpy(target, privateExponent->data, privateExponent->size);
+ privateExponent->data = target;
+ ckcapi_ReverseData(privateExponent);
+
+ target = &keyBlobData->data[CAPI_PRIME_1_OFFSET(modSize)];
+ nsslibc_memcpy(target, prime1->data, prime1->size);
+ prime1->data = target;
+ ckcapi_ReverseData(prime1);
+
+ target = &keyBlobData->data[CAPI_PRIME_2_OFFSET(modSize)];
+ nsslibc_memcpy(target, prime2->data, prime2->size);
+ prime2->data = target;
+ ckcapi_ReverseData(prime2);
+
+ target = &keyBlobData->data[CAPI_EXPONENT_1_OFFSET(modSize)];
+ nsslibc_memcpy(target, exponent1->data, exponent1->size);
+ exponent1->data = target;
+ ckcapi_ReverseData(exponent1);
+
+ target = &keyBlobData->data[CAPI_EXPONENT_2_OFFSET(modSize)];
+ nsslibc_memcpy(target, exponent2->data, exponent2->size);
+ exponent2->data = target;
+ ckcapi_ReverseData(exponent2);
+
+ target = &keyBlobData->data[CAPI_COEFFICIENT_OFFSET(modSize)];
+ nsslibc_memcpy(target, coefficient->data, coefficient->size);
+ coefficient->data = target;
+ ckcapi_ReverseData(coefficient);
+
+ keyBlob->data = keyBlobData;
+ keyBlob->size = dataSize;
+
+ return CKR_OK;
+
+loser:
+ nss_ZFreeIf(keyBlobData);
+ return error;
+}
+
+static ckcapiInternalObject *
+nss_ckcapi_CreatePrivateKey
+(
+ NSSCKFWSession *fwSession,
+ CK_ATTRIBUTE_PTR pTemplate,
+ CK_ULONG ulAttributeCount,
+ CK_RV *pError
+)
+{
+ NSSItem modulus;
+ NSSItem publicExponent;
+ NSSItem privateExponent;
+ NSSItem exponent1;
+ NSSItem exponent2;
+ NSSItem prime1;
+ NSSItem prime2;
+ NSSItem coefficient;
+ NSSItem keyID;
+ NSSItem keyBlob;
+ ckcapiInternalObject *io = NULL;
+ char *providerName = NULL;
+ char *containerName = NULL;
+ char *idData = NULL;
+ CRYPT_KEY_PROV_INFO provInfo;
+ CRYPT_HASH_BLOB msKeyID;
+ CK_KEY_TYPE keyType;
+ HCRYPTPROV hProv = 0;
+ HCRYPTKEY hKey = 0;
+ PRBool decrypt;
+ DWORD keySpec;
+ DWORD msError;
+ BOOL rc;
+
+ keyType = nss_ckcapi_GetULongAttribute
+ (CKA_KEY_TYPE, pTemplate, ulAttributeCount, pError);
+ if (CKR_OK != *pError) {
+ return (ckcapiInternalObject *)NULL;
+ }
+ if (CKK_RSA != keyType) {
+ *pError = CKR_ATTRIBUTE_VALUE_INVALID;
+ return (ckcapiInternalObject *)NULL;
+ }
+
+ decrypt = nss_ckcapi_GetBoolAttribute(CKA_DECRYPT,
+ pTemplate, ulAttributeCount, pError);
+ if (CKR_TEMPLATE_INCOMPLETE == *pError) {
+ decrypt = PR_TRUE; /* default to true */
+ }
+ decrypt = decrypt || nss_ckcapi_GetBoolAttribute(CKA_UNWRAP,
+ pTemplate, ulAttributeCount, pError);
+ if (CKR_TEMPLATE_INCOMPLETE == *pError) {
+ decrypt = PR_TRUE; /* default to true */
+ }
+ keySpec = decrypt ? AT_KEYEXCHANGE : AT_SIGNATURE;
+
+ *pError = nss_ckcapi_GetAttribute(CKA_MODULUS, pTemplate,
+ ulAttributeCount, &modulus);
+ if (CKR_OK != *pError) {
+ return (ckcapiInternalObject *)NULL;
+ }
+ *pError = nss_ckcapi_GetAttribute(CKA_PUBLIC_EXPONENT, pTemplate,
+ ulAttributeCount, &publicExponent);
+ if (CKR_OK != *pError) {
+ return (ckcapiInternalObject *)NULL;
+ }
+ *pError = nss_ckcapi_GetAttribute(CKA_PRIVATE_EXPONENT, pTemplate,
+ ulAttributeCount, &privateExponent);
+ if (CKR_OK != *pError) {
+ return (ckcapiInternalObject *)NULL;
+ }
+ *pError = nss_ckcapi_GetAttribute(CKA_PRIME_1, pTemplate,
+ ulAttributeCount, &prime1);
+ if (CKR_OK != *pError) {
+ return (ckcapiInternalObject *)NULL;
+ }
+ *pError = nss_ckcapi_GetAttribute(CKA_PRIME_2, pTemplate,
+ ulAttributeCount, &prime2);
+ if (CKR_OK != *pError) {
+ return (ckcapiInternalObject *)NULL;
+ }
+ *pError = nss_ckcapi_GetAttribute(CKA_EXPONENT_1, pTemplate,
+ ulAttributeCount, &exponent1);
+ if (CKR_OK != *pError) {
+ return (ckcapiInternalObject *)NULL;
+ }
+ *pError = nss_ckcapi_GetAttribute(CKA_EXPONENT_2, pTemplate,
+ ulAttributeCount, &exponent2);
+ if (CKR_OK != *pError) {
+ return (ckcapiInternalObject *)NULL;
+ }
+ *pError = nss_ckcapi_GetAttribute(CKA_COEFFICIENT, pTemplate,
+ ulAttributeCount, &coefficient);
+ if (CKR_OK != *pError) {
+ return (ckcapiInternalObject *)NULL;
+ }
+ *pError = nss_ckcapi_GetAttribute(CKA_ID, pTemplate,
+ ulAttributeCount, &keyID);
+ if (CKR_OK != *pError) {
+ return (ckcapiInternalObject *)NULL;
+ }
+ providerName = ckcapi_getDefaultProvider(pError);
+ if ((char *)NULL == providerName ) {
+ return (ckcapiInternalObject *)NULL;
+ }
+ containerName = ckcapi_getContainer(pError, &keyID);
+ if ((char *)NULL == providerName ) {
+ goto loser;
+ }
+ rc = CryptAcquireContext(&hProv, containerName, providerName,
+ PROV_RSA_FULL, CRYPT_NEWKEYSET);
+ if (!rc) {
+ msError = GetLastError();
+ *pError = CKR_DEVICE_ERROR;
+ goto loser;
+ }
+
+ *pError = ckcapi_buildPrivateKeyBlob(
+ &keyBlob,
+ &modulus,
+ &publicExponent,
+ &privateExponent,
+ &prime1,
+ &prime2,
+ &exponent1,
+ &exponent2,
+ &coefficient,
+ decrypt);
+ if (CKR_OK != *pError) {
+ goto loser;
+ }
+
+ rc = CryptImportKey(hProv, keyBlob.data, keyBlob.size,
+ 0, CRYPT_EXPORTABLE, &hKey);
+ if (!rc) {
+ msError = GetLastError();
+ *pError = CKR_DEVICE_ERROR;
+ goto loser;
+ }
+
+ idData = nss_ZNEWARRAY(NULL, char, keyID.size);
+ if ((void *)NULL == idData) {
+ *pError = CKR_HOST_MEMORY;
+ goto loser;
+ }
+ nsslibc_memcpy(idData, keyID.data, keyID.size);
+
+ provInfo.pwszContainerName = nss_ckcapi_UTF8ToWide(containerName);
+ provInfo.pwszProvName = nss_ckcapi_UTF8ToWide(providerName);
+ provInfo.dwProvType = PROV_RSA_FULL;
+ provInfo.dwFlags = 0;
+ provInfo.cProvParam = 0;
+ provInfo.rgProvParam = NULL;
+ provInfo.dwKeySpec = keySpec;
+
+ msKeyID.cbData = keyID.size;
+ msKeyID.pbData = keyID.data;
+
+ rc = CryptSetKeyIdentifierProperty(&msKeyID, CERT_KEY_PROV_INFO_PROP_ID,
+ 0, NULL, NULL, &provInfo);
+ if (!rc) {
+ goto loser;
+ }
+
+ /* handle error here */
+ io = nss_ZNEW(NULL, ckcapiInternalObject);
+ if ((ckcapiInternalObject *)NULL == io) {
+ *pError = CKR_HOST_MEMORY;
+ goto loser;
+ }
+ io->type = ckcapiBareKey;
+ io->objClass = CKO_PRIVATE_KEY;
+ io->u.key.provInfo = provInfo;
+ io->u.key.provName = providerName;
+ io->u.key.containerName = containerName;
+ io->u.key.hProv = hProv; /* save the handle */
+ io->idData = idData;
+ io->id.data = idData;
+ io->id.size = keyID.size;
+ /* done with the key handle */
+ CryptDestroyKey(hKey);
+ return io;
+
+loser:
+ nss_ZFreeIf(containerName);
+ nss_ZFreeIf(providerName);
+ nss_ZFreeIf(idData);
+ if (0 != hProv) {
+ CryptReleaseContext(hProv, 0);
+ }
+ if (0 != hKey) {
+ CryptDestroyKey(hKey);
+ }
+ return (ckcapiInternalObject *)NULL;
+}
+
+
+NSS_EXTERN NSSCKMDObject *
+nss_ckcapi_CreateObject
+(
+ NSSCKFWSession *fwSession,
+ CK_ATTRIBUTE_PTR pTemplate,
+ CK_ULONG ulAttributeCount,
+ CK_RV *pError
+)
+{
+ CK_OBJECT_CLASS objClass;
+ ckcapiInternalObject *io;
+ CK_BBOOL isToken;
+
+ /*
+ * only create token objects
+ */
+ isToken = nss_ckcapi_GetBoolAttribute(CKA_TOKEN, pTemplate,
+ ulAttributeCount, pError);
+ if (CKR_OK != *pError) {
+ return (NSSCKMDObject *) NULL;
+ }
+ if (!isToken) {
+ *pError = CKR_ATTRIBUTE_VALUE_INVALID;
+ return (NSSCKMDObject *) NULL;
+ }
+
+ /*
+ * only create keys and certs.
+ */
+ objClass = nss_ckcapi_GetULongAttribute(CKA_CLASS, pTemplate,
+ ulAttributeCount, pError);
+ if (CKR_OK != *pError) {
+ return (NSSCKMDObject *) NULL;
+ }
+#ifdef notdef
+ if (objClass == CKO_PUBLIC_KEY) {
+ return CKR_OK; /* fake public key creation, happens as a side effect of
+ * private key creation */
+ }
+#endif
+ if (objClass == CKO_CERTIFICATE) {
+ io = nss_ckcapi_CreateCertificate(fwSession, pTemplate,
+ ulAttributeCount, pError);
+ } else if (objClass == CKO_PRIVATE_KEY) {
+ io = nss_ckcapi_CreatePrivateKey(fwSession, pTemplate,
+ ulAttributeCount, pError);
+ } else {
+ *pError = CKR_ATTRIBUTE_VALUE_INVALID;
+ }
+
+ if ((ckcapiInternalObject *)NULL == io) {
+ return (NSSCKMDObject *) NULL;
+ }
+ return nss_ckcapi_CreateMDObject(NULL, io, pError);
+}
diff --git a/security/nss/lib/ckfw/capi/crsa.c b/security/nss/lib/ckfw/capi/crsa.c
index abf11f19f..ce0f42797 100644
--- a/security/nss/lib/ckfw/capi/crsa.c
+++ b/security/nss/lib/ckfw/capi/crsa.c
@@ -738,12 +738,9 @@ nss_ckcapi_mdMechanismRSA = {
NULL, /* VerifyInit - default errs */
ckcapi_mdMechanismRSA_SignInit, /* SignRecoverInit */
NULL, /* VerifyRecoverInit - default errs */
- NULL, /* DigestEncryptUpdate - default errs */
- NULL, /* DecryptDigestUpdate - default errs */
- NULL, /* SignEncryptUpdate - default errs */
- NULL, /* DecryptVerifyUpdate - default errs */
NULL, /* GenerateKey - default errs */
NULL, /* GenerateKeyPair - default errs */
+ NULL, /* GetWrapKeyLength - default errs */
NULL, /* WrapKey - default errs */
NULL, /* UnwrapKey - default errs */
NULL, /* DeriveKey - default errs */
diff --git a/security/nss/lib/ckfw/capi/csession.c b/security/nss/lib/ckfw/capi/csession.c
index a19de5106..f0abd6d0b 100644
--- a/security/nss/lib/ckfw/capi/csession.c
+++ b/security/nss/lib/ckfw/capi/csession.c
@@ -66,6 +66,24 @@ ckcapi_mdSession_FindObjectsInit
return nss_ckcapi_FindObjectsInit(fwSession, pTemplate, ulAttributeCount, pError);
}
+static NSSCKMDObject *
+ckcapi_mdSession_CreateObject
+(
+ NSSCKMDSession *mdSession,
+ NSSCKFWSession *fwSession,
+ NSSCKMDToken *mdToken,
+ NSSCKFWToken *fwToken,
+ NSSCKMDInstance *mdInstance,
+ NSSCKFWInstance *fwInstance,
+ NSSArena *arena,
+ CK_ATTRIBUTE_PTR pTemplate,
+ CK_ULONG ulAttributeCount,
+ CK_RV *pError
+)
+{
+ return nss_ckcapi_CreateObject(fwSession, pTemplate, ulAttributeCount, pError);
+}
+
NSS_IMPLEMENT NSSCKMDSession *
nss_ckcapi_CreateSession
(
@@ -102,7 +120,7 @@ nss_ckcapi_CreateSession
/* rv->GetOperationStateLen */
/* rv->GetOperationState */
/* rv->SetOperationState */
- /* rv->CreateObject */
+ rv->CreateObject = ckcapi_mdSession_CreateObject;
/* rv->CopyObject */
rv->FindObjectsInit = ckcapi_mdSession_FindObjectsInit;
/* rv->SeedRandom */
diff --git a/security/nss/lib/ckfw/capi/ctoken.c b/security/nss/lib/ckfw/capi/ctoken.c
index dc75077de..bce2c17e2 100644
--- a/security/nss/lib/ckfw/capi/ctoken.c
+++ b/security/nss/lib/ckfw/capi/ctoken.c
@@ -110,6 +110,19 @@ ckcapi_mdToken_GetIsWriteProtected
NSSCKFWInstance *fwInstance
)
{
+ return CK_FALSE;
+}
+
+/* fake out Mozilla so we don't try to initialize the token */
+static CK_BBOOL
+ckcapi_mdToken_GetUserPinInitialized
+(
+ NSSCKMDToken *mdToken,
+ NSSCKFWToken *fwToken,
+ NSSCKMDInstance *mdInstance,
+ NSSCKFWInstance *fwInstance
+)
+{
return CK_TRUE;
}
@@ -209,7 +222,7 @@ nss_ckcapi_mdToken = {
NULL, /* GetHasRNG -- default is false */
ckcapi_mdToken_GetIsWriteProtected,
NULL, /* GetLoginRequired -- default is false */
- NULL, /* GetUserPinInitialized -- default is false */
+ ckcapi_mdToken_GetUserPinInitialized,
NULL, /* GetRestoreKeyNotNeeded -- irrelevant */
NULL, /* GetHasClockOnToken -- default is false */
NULL, /* GetHasProtectedAuthenticationPath -- default is false */