diff options
author | relyea%netscape.com <devnull@localhost> | 2005-11-15 00:13:58 +0000 |
---|---|---|
committer | relyea%netscape.com <devnull@localhost> | 2005-11-15 00:13:58 +0000 |
commit | 71488fac4553afc6f2c293b963f1ee86f35e9fe4 (patch) | |
tree | c5861ac87584c03fa93bbe4c1648c15bf7a5ecd6 /security/nss | |
parent | 8b6ab4292a8224737016d779d2e3e4a1b41f5a25 (diff) | |
download | nss-hg-71488fac4553afc6f2c293b963f1ee86f35e9fe4.tar.gz |
Add r/w support. The Capi token can now:
Import certs and keys.
Delete certs and keys.
Diffstat (limited to 'security/nss')
-rw-r--r-- | security/nss/lib/ckfw/capi/Makefile | 1 | ||||
-rw-r--r-- | security/nss/lib/ckfw/capi/cfind.c | 169 | ||||
-rw-r--r-- | security/nss/lib/ckfw/capi/cinst.c | 16 | ||||
-rw-r--r-- | security/nss/lib/ckfw/capi/ckcapi.h | 173 | ||||
-rw-r--r-- | security/nss/lib/ckfw/capi/cobject.c | 1761 | ||||
-rw-r--r-- | security/nss/lib/ckfw/capi/crsa.c | 5 | ||||
-rw-r--r-- | security/nss/lib/ckfw/capi/csession.c | 20 | ||||
-rw-r--r-- | security/nss/lib/ckfw/capi/ctoken.c | 15 |
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 */ |