summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStef Walter <stef@memberwebs.com>2008-12-03 00:20:13 +0000
committerStef Walter <stef@memberwebs.com>2008-12-03 00:20:13 +0000
commitb00eb56b7ffe5019bb33ad399d351b90f4715132 (patch)
tree0dbf8ab4425a6eb4f8cbc028556403515e516d68
parent4b5eb21486d188f57f2bf7a91cd5da225dd3e0d1 (diff)
Add basic key object support. No support yet for actual crypto ops. Not tested. Wanted to check it in so it doesn't get lost as it represents a lot of work.
-rw-r--r--ckcapi-cert.c34
-rw-r--r--ckcapi-cert.h4
-rw-r--r--ckcapi-key.c1033
-rw-r--r--ckcapi-key.h33
-rw-r--r--ckcapi-trust.c4
-rw-r--r--ckcapi-util.c17
-rw-r--r--ckcapi-util.h3
-rw-r--r--ckcapi.c79
-rw-r--r--ckcapi.h14
-rw-r--r--ckcapi.vcproj14
10 files changed, 1185 insertions, 50 deletions
diff --git a/ckcapi-cert.c b/ckcapi-cert.c
index 6e51f3e..6d2dd53 100644
--- a/ckcapi-cert.c
+++ b/ckcapi-cert.c
@@ -106,7 +106,7 @@ cert_bool_attribute(CkCapiObjectData* objdata, CK_ATTRIBUTE_PTR attr)
return CKR_ATTRIBUTE_TYPE_INVALID;
};
- return ckcapi_return_data(attr->pValue, &attr->ulValueLen, &val, sizeof(CK_BBOOL));
+ return ckcapi_return_data(attr, &val, sizeof(CK_BBOOL));
}
static CK_RV
@@ -148,7 +148,7 @@ cert_ulong_attribute(CkCapiObjectData* objdata, CK_ATTRIBUTE_PTR attr)
return CKR_ATTRIBUTE_TYPE_INVALID;
};
- return ckcapi_return_data(attr->pValue, &attr->ulValueLen, &val, sizeof(CK_ULONG));
+ return ckcapi_return_data(attr, &val, sizeof(CK_ULONG));
}
static CK_RV
@@ -286,12 +286,9 @@ static const CkCapiObjectVtable cert_object_vtable = {
CK_RV
ckcapi_cert_certificate_get_bytes(PCCERT_CONTEXT cert, CK_ATTRIBUTE_PTR attr)
{
- CK_VOID_PTR data = attr->pValue;
- CK_ULONG_PTR len = &attr->ulValueLen;
DWORD err;
ASSERT(cert);
- ASSERT(len);
ASSERT(attr);
switch(attr->type)
@@ -325,7 +322,7 @@ ckcapi_cert_certificate_get_bytes(PCCERT_CONTEXT cert, CK_ATTRIBUTE_PTR attr)
return ckcapi_winerr_to_ckr(GetLastError());
}
- return ckcapi_return_string(data, len, utf16);
+ return ckcapi_return_string(attr, utf16);
}
break;
@@ -338,7 +335,7 @@ ckcapi_cert_certificate_get_bytes(PCCERT_CONTEXT cert, CK_ATTRIBUTE_PTR attr)
*/
case CKA_ID:
if(!CertGetCertificateContextProperty(cert, CERT_KEY_IDENTIFIER_PROP_ID,
- data, (DWORD*)len))
+ attr->pValue, (DWORD*)&attr->ulValueLen))
{
err = GetLastError();
if(err == CRYPT_E_NOT_FOUND)
@@ -355,8 +352,8 @@ ckcapi_cert_certificate_get_bytes(PCCERT_CONTEXT cert, CK_ATTRIBUTE_PTR attr)
* directly.
*/
case CKA_SUBJECT:
- return ckcapi_return_data(data, len, cert->pCertInfo->Subject.pbData,
- cert->pCertInfo->Subject.cbData);
+ return ckcapi_return_data(attr, cert->pCertInfo->Subject.pbData,
+ cert->pCertInfo->Subject.cbData);
/*
* DER-encoding of the certificate issuer name.
@@ -365,8 +362,8 @@ ckcapi_cert_certificate_get_bytes(PCCERT_CONTEXT cert, CK_ATTRIBUTE_PTR attr)
* directly.
*/
case CKA_ISSUER:
- return ckcapi_return_data(data, len, cert->pCertInfo->Issuer.pbData,
- cert->pCertInfo->Issuer.cbData);
+ return ckcapi_return_data(attr, cert->pCertInfo->Issuer.pbData,
+ cert->pCertInfo->Issuer.cbData);
/*
* DER-encoding of the certificate serial number.
@@ -380,7 +377,8 @@ ckcapi_cert_certificate_get_bytes(PCCERT_CONTEXT cert, CK_ATTRIBUTE_PTR attr)
*/
case CKA_SERIAL_NUMBER:
if(!CryptEncodeObject(X509_ASN_ENCODING, X509_MULTI_BYTE_INTEGER,
- &cert->pCertInfo->SerialNumber, data, len))
+ &cert->pCertInfo->SerialNumber,
+ attr->pValue, (DWORD*)&attr->ulValueLen))
{
err = GetLastError();
if(err == ERROR_FILE_NOT_FOUND)
@@ -395,7 +393,7 @@ ckcapi_cert_certificate_get_bytes(PCCERT_CONTEXT cert, CK_ATTRIBUTE_PTR attr)
* We use CAPI's CERT_CONTEXT pbCertEncoded field directly.
*/
case CKA_VALUE:
- return ckcapi_return_data(data, len, cert->pbCertEncoded,
+ return ckcapi_return_data(attr, cert->pbCertEncoded,
cert->cbCertEncoded);
/*
@@ -406,29 +404,27 @@ ckcapi_cert_certificate_get_bytes(PCCERT_CONTEXT cert, CK_ATTRIBUTE_PTR attr)
* in full.
*/
case CKA_URL:
- break;
+ return CKR_ATTRIBUTE_TYPE_INVALID;
/*
* Checksum
* - TODO: Work out what to do here
*/
case CKA_CHECK_VALUE:
- break;
+ return CKR_ATTRIBUTE_TYPE_INVALID;
/*
* TODO: Should we support these?
*/
case CKA_HASH_OF_SUBJECT_PUBLIC_KEY:
case CKA_HASH_OF_ISSUER_PUBLIC_KEY:
- break;
+ return CKR_ATTRIBUTE_TYPE_INVALID;
/* Not supported */
default:
- break;
+ return CKR_ATTRIBUTE_TYPE_INVALID;
};
-
- return CKR_ATTRIBUTE_TYPE_INVALID;
}
PCCERT_CONTEXT
diff --git a/ckcapi-cert.h b/ckcapi-cert.h
index 0a7622c..28edd9d 100644
--- a/ckcapi-cert.h
+++ b/ckcapi-cert.h
@@ -46,10 +46,10 @@ CK_RV ckcapi_cert_find (CkCapiSession* sess, CK_OBJECT_CLASS cls,
CK_ATTRIBUTE_PTR match, CK_ULONG count,
CkCapiArray* arr);
-
-/* Called by trust stuff */
+/* Called by trust and key stuff */
CK_RV ckcapi_cert_certificate_get_bytes (PCCERT_CONTEXT cert,
CK_ATTRIBUTE_PTR attr);
+
PCCERT_CONTEXT ckcapi_cert_object_data_get_certificate (CkCapiObjectData* objdata);
#endif /* CRYPTOKI_CERT_H */
diff --git a/ckcapi-key.c b/ckcapi-key.c
new file mode 100644
index 0000000..1ce057c
--- /dev/null
+++ b/ckcapi-key.c
@@ -0,0 +1,1033 @@
+/*
+ * Copyright (C) 2008 Stef Walter
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "ckcapi.h"
+#include "ckcapi-cert.h"
+#include "ckcapi-key.h"
+#include "ckcapi-object.h"
+#include "ckcapi-session.h"
+#include "ckcapi-token.h"
+#include "x509-usages.h"
+
+/*
+ * These are the attributes expected by NSS on a
+ * private key object:
+ *
+ * CKA_ALWAYS_AUTHENTICATE
+ * CKA_ALWAYS_SENSITIVE
+ * CKA_CLASS
+ * CKA_DECRYPT
+ * CKA_DERIVE
+ * CKA_END_DATE
+ * CKA_EXTRACTABLE
+ * CKA_ID
+ * CKA_LABEL
+ * CKA_LOCAL
+ * CKA_KEY_TYPE
+ * CKA_KEY_GEN_MECHANISM
+ * CKA_MODIFIABLE
+ * CKA_NEVER_EXTRACTABLE
+ * CKA_PRIVATE
+ * CKA_SENSITIVE
+ * CKA_SIGN
+ * CKA_SIGN_RECOVER
+ * CKA_START_DATE
+ * CKA_SUBJECT
+ * CKA_TOKEN
+ * CKA_UNWRAP
+ * CKA_UNWRAP_TEMPLATE
+ * CKA_ALLOWED_MECHANISMS
+ * CKA_WRAP_WITH_TRUSTED
+ *
+ * Additional attributes for RSA keys:
+ *
+ * CKA_COEFFICIENT
+ * CKA_EXPONENT_1
+ * CKA_EXPONENT_2
+ * CKA_MODULUS
+ * CKA_PRIME_1
+ * CKA_PRIME_2
+ * CKA_PRIVATE_EXPONENT
+ * CKA_PUBLIC_EXPONENT
+ *
+ * Additional attributes for DSA keys:
+ *
+ * CKA_BASE
+ * CKA_PRIME
+ * CKA_SUBPRIME
+ * CKA_VALUE
+ */
+
+typedef struct _KeyObject
+{
+ CkCapiObject obj;
+
+ /* The raw key identifier */
+ CRYPT_HASH_BLOB key_identifier;
+
+ /* Together these form the unique key. Must be contiguous */
+ CK_OBJECT_CLASS object_class;
+ BYTE tail_data[1];
+}
+KeyObject;
+
+typedef struct _KeyObjectData
+{
+ CkCapiObjectData base;
+ CK_OBJECT_CLASS object_class;
+ CRYPT_INTEGER_BLOB key_identifier;
+ CRYPT_DATA_BLOB raw_public_key;
+ CRYPT_KEY_PROV_INFO* prov_info;
+}
+KeyObjectData;
+
+static CK_RV
+load_raw_public_key(KeyObjectData* kdata)
+{
+ BOOL success = FALSE;
+ HCRYPTKEY key;
+ CK_RV ret;
+ DWORD error;
+
+ ASSERT(kdata);
+ ASSERT(!kdata->raw_public_key.pbData);
+
+ ret = ckcapi_key_object_data_get_handles(&kdata->base, NULL, &key);
+ if(ret != CKR_OK)
+ return ret;
+
+ if(CryptExportKey(key, 0, PUBLICKEYBLOB, 0, NULL, &kdata->raw_public_key.cbData))
+ {
+ kdata->raw_public_key.pbData = malloc(kdata->raw_public_key.cbData);
+ if(!kdata->raw_public_key.pbData)
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ else
+ {
+ if(CryptExportKey(key, 0, PUBLICKEYBLOB, 0, kdata->raw_public_key.pbData,
+ &kdata->raw_public_key.cbData))
+ {
+ success = TRUE;
+ }
+ }
+ }
+
+ CryptDestroyKey(key);
+
+ if(success)
+ {
+ return CKR_OK;
+ }
+ else
+ {
+ error = GetLastError();
+ if(error == NTE_BAD_KEY_STATE)
+ return CKR_ATTRIBUTE_SENSITIVE;
+ return ckcapi_winerr_to_ckr(error);
+ }
+}
+
+static CK_RV
+lookup_rsa_attribute(KeyObjectData* kdata, CK_ATTRIBUTE_PTR attr)
+{
+ PUBLICKEYSTRUC* header;
+ RSAPUBKEY* pubkey;
+ CK_ULONG number;
+ CK_RV ret;
+
+ ASSERT(kdata);
+ ASSERT(attr);
+
+ if(!kdata->raw_public_key.pbData)
+ {
+ ret = load_raw_public_key(kdata);
+ if(ret != CKR_OK)
+ return ret;
+ }
+
+ header = (PUBLICKEYSTRUC*)kdata->raw_public_key.pbData;
+ if(!header->bType == PUBLICKEYBLOB)
+ return CKR_GENERAL_ERROR;
+
+ pubkey = (RSAPUBKEY*)(header + 1);
+ if(!pubkey->magic == 0x31415352)
+ return CKR_GENERAL_ERROR;
+
+ switch(attr->type)
+ {
+ case CKA_MODULUS_BITS:
+ number = pubkey->bitlen;
+ return ckcapi_return_data(attr, &number, sizeof(CK_ULONG));
+
+ case CKA_PUBLIC_EXPONENT:
+ return ckcapi_return_dword_as_bytes(attr, pubkey->pubexp);
+
+ case CKA_MODULUS:
+ return ckcapi_return_reversed_data(attr, (pubkey + 1),
+ pubkey->bitlen / 8);
+
+ case CKA_PRIVATE_EXPONENT:
+ case CKA_PRIME_1:
+ case CKA_PRIME_2:
+ case CKA_EXPONENT_1:
+ case CKA_EXPONENT_2:
+ case CKA_COEFFICIENT:
+ if(kdata->object_class == CKO_PRIVATE_KEY)
+ return CKR_ATTRIBUTE_SENSITIVE;
+ else
+ return CKR_ATTRIBUTE_TYPE_INVALID;
+
+ default:
+ ASSERT(FALSE);
+ return CKR_ATTRIBUTE_TYPE_INVALID;
+ }
+}
+
+static CK_RV
+key_bool_attribute(CkCapiObjectData* objdata, CK_ATTRIBUTE_PTR attr)
+{
+ KeyObjectData* kdata = (KeyObjectData*)objdata;
+ CK_BBOOL val;
+ CK_BBOOL is_private;
+
+ ASSERT(objdata);
+ ASSERT(attr);
+
+ is_private = (kdata->object_class == CKO_PRIVATE_KEY);
+
+ switch(attr->type)
+ {
+
+ /*
+ * Whether to authenticate before every use.
+ * - CAPI does all authentication
+ */
+ case CKA_ALWAYS_AUTHENTICATE:
+ val = CK_FALSE;
+ break;
+
+ /*
+ * Whether this key has always been sensitive.
+ * TODO: Can we detect this?
+ */
+ case CKA_ALWAYS_SENSITIVE:
+ val = CK_FALSE;
+ break;
+
+ /*
+ * Whether this key can be used to decrypt.
+ * - CKK_RSA but not CKK_DSA.
+ */
+ case CKA_DECRYPT:
+ val = CK_TRUE;
+ break;
+
+ /*
+ * Whether this key can be used to derive a session or
+ * other key.
+ * - Not true for CKK_RSA or CKK_DSA.
+ */
+ case CKA_DERIVE:
+ val = CK_FALSE;
+ break;
+
+ /*
+ * Whether this key can be exported or not.
+ * TODO: We may want to support this for public keys.
+ */
+ case CKA_EXTRACTABLE:
+ val = CK_FALSE;
+ break;
+
+ /*
+ * Whether this key was created on token.
+ * TODO: Can we implement this properly?
+ */
+ case CKA_LOCAL:
+ val = CK_FALSE;
+ break;
+
+ /*
+ * Whether this object is modifiable.
+ * - Keys are generally. never modifiable.
+ */
+ case CKA_MODIFIABLE:
+ val = CK_FALSE;
+ break;
+
+ /*
+ * Whether this key was ever extractable.
+ * TODO: Can we determine this?
+ */
+ case CKA_NEVER_EXTRACTABLE:
+ val = CK_FALSE;
+ break;
+
+ /*
+ * Whether this is a private object or not.
+ * - This 'private' means login before use. But maps
+ * well to private key use, since we're always logged in.
+ */
+ case CKA_PRIVATE:
+ val = is_private;
+ break;
+
+ /*
+ * Whether this is a sensitive object or not.
+ * - Private keys are sensitive, some attributes not
+ * readable.
+ */
+ case CKA_SENSITIVE:
+ val = is_private;
+ break;
+
+ /*
+ * Can this key sign stuff?
+ * - Private keys can sign.
+ */
+ case CKA_SIGN:
+ val = is_private;
+ break;
+
+ /*
+ * Can this key sign recoverable.
+ * - Private RSA keys can sign recoverable.
+ * TODO: When implementing DSA more logic needed.
+ */
+ case CKA_SIGN_RECOVER:
+ val = is_private;
+ break;
+
+ /*
+ * Is this stored on the token?
+ * - All CAPI objects are.
+ */
+ case CKA_TOKEN:
+ val = CK_TRUE;
+ break;
+
+ /*
+ * Can do a unwrap operation?
+ * - We don't implement this.
+ */
+ case CKA_UNWRAP:
+ val = CK_FALSE;
+ break;
+
+ /*
+ * Wrap, and unwrap stuff.
+ * - We don't implement this.
+ */
+ case CKA_UNWRAP_TEMPLATE:
+ case CKA_WRAP_WITH_TRUSTED:
+ return CKR_ATTRIBUTE_TYPE_INVALID;
+
+
+ default:
+ return CKR_ATTRIBUTE_TYPE_INVALID;
+ };
+
+ return ckcapi_return_data(attr, &val, sizeof(CK_BBOOL));
+}
+
+static CK_RV
+key_ulong_attribute(CkCapiObjectData* objdata, CK_ATTRIBUTE_PTR attr)
+{
+ KeyObjectData* kdata = (KeyObjectData*)objdata;
+ CK_ULONG val;
+
+ ASSERT(kdata);
+ ASSERT(attr);
+
+ switch(attr->type)
+ {
+
+ /*
+ * Object class.
+ */
+ case CKA_CLASS:
+ val = kdata->object_class;
+ break;
+
+ /*
+ * The key type.
+ * - Right now we only support (and load) RSA.
+ */
+ case CKA_KEY_TYPE:
+ if(kdata->prov_info->dwProvType == PROV_RSA_FULL)
+ val = CKK_RSA;
+ else
+ val = CK_UNAVAILABLE_INFORMATION;
+ break;
+
+ /*
+ * The key generation mechanism.
+ * TODO: We don't yet support key generation.
+ */
+ case CKA_KEY_GEN_MECHANISM:
+ val = CK_UNAVAILABLE_INFORMATION;
+ break;
+
+ /*
+ * The RSA modulus bits.
+ */
+ case CKA_MODULUS_BITS:
+ if(kdata->prov_info->dwProvType == PROV_RSA_FULL)
+ return lookup_rsa_attribute(kdata, attr);
+ else
+ return CKR_ATTRIBUTE_TYPE_INVALID;
+
+ default:
+ return CKR_ATTRIBUTE_TYPE_INVALID;
+ };
+
+ return ckcapi_return_data(attr, &val, sizeof(CK_ULONG));
+}
+
+static CK_RV
+key_bytes_attribute(CkCapiObjectData* objdata, CK_ATTRIBUTE_PTR attr)
+{
+ KeyObjectData* kdata = (KeyObjectData*)objdata;
+ CK_MECHANISM_TYPE allowed_mechanisms[] = { CKM_RSA_PKCS };
+ WCHAR* label;
+
+ ASSERT(kdata);
+ ASSERT(attr);
+
+ switch(attr->type)
+ {
+ /*
+ * The ID of the key. This should match the ID we
+ * return for any matching certificates.
+ */
+ case CKA_ID:
+ return ckcapi_return_data(attr, kdata->key_identifier.pbData,
+ kdata->key_identifier.cbData);
+
+ /*
+ * The key label.
+ * - We use the container name.
+ */
+ case CKA_LABEL:
+ label = kdata->prov_info->pwszContainerName;
+ if(!label)
+ label = L"Unnamed Key";
+ return ckcapi_return_string(attr, label);
+
+ /*
+ * The subject of the related certificate.
+ * TODO: Implement this lookup.
+ */
+ case CKA_SUBJECT:
+ return ckcapi_return_data(attr, "", 0);
+
+ /*
+ * Allowed mechanisms with this key.
+ * - RSA used with CKM_RSA
+ * TODO: Needs updating when DSA implemented.
+ */
+ case CKA_ALLOWED_MECHANISMS:
+ return ckcapi_return_data(attr, &allowed_mechanisms,
+ sizeof(allowed_mechanisms));
+
+ /*
+ * Various RSA public attributes.
+ */
+ case CKA_MODULUS:
+ case CKA_PUBLIC_EXPONENT:
+ case CKA_PRIVATE_EXPONENT:
+ case CKA_PRIME_1:
+ case CKA_PRIME_2:
+ case CKA_EXPONENT_1:
+ case CKA_EXPONENT_2:
+ case CKA_COEFFICIENT:
+ if(kdata->prov_info->dwProvType = PROV_RSA_FULL)
+ return lookup_rsa_attribute(kdata, attr);
+ else
+ return CKR_ATTRIBUTE_TYPE_INVALID;
+
+ default:
+ return CKR_ATTRIBUTE_TYPE_INVALID;
+ };
+}
+
+static CK_RV
+key_date_attribute(CkCapiObjectData* objdata, CK_ATTRIBUTE_PTR attr)
+{
+ switch(attr->type)
+ {
+ /*
+ * Last date this key can be used.
+ * TODO: Does CAPI support this ability?
+ */
+ case CKA_END_DATE:
+ case CKA_START_DATE:
+ return CKR_ATTRIBUTE_TYPE_INVALID;
+
+ default:
+ return CKR_ATTRIBUTE_TYPE_INVALID;
+ };
+}
+
+static void
+key_release(void* data)
+{
+ KeyObjectData* kdata = (KeyObjectData*)data;
+ ASSERT(kdata);
+
+ ASSERT(kdata->key_identifier.pbData);
+ ASSERT(kdata->prov_info);
+
+ free(kdata->key_identifier.pbData);
+ free(kdata->prov_info);
+
+ free(kdata);
+}
+
+static const CkCapiObjectDataVtable key_objdata_vtable = {
+ key_bool_attribute,
+ key_ulong_attribute,
+ key_bytes_attribute,
+ key_date_attribute,
+ key_release,
+};
+
+static CRYPT_KEY_PROV_INFO*
+duplicate_prov_info(CRYPT_KEY_PROV_INFO* original)
+{
+ DWORD container_length, prov_length;
+ CRYPT_KEY_PROV_INFO* result;
+ DWORD length, i;
+ BYTE* at;
+ BYTE* end;
+
+ if(!original)
+ return NULL;
+
+ /* Go through and calculate the length */
+ length = sizeof(CRYPT_KEY_PROV_INFO);
+ if(original->pwszContainerName)
+ {
+ container_length = (wcslen(original->pwszContainerName) + 1) * sizeof(WCHAR);
+ length += container_length;
+ }
+
+ if(original->pwszProvName)
+ {
+ prov_length = (wcslen(original->pwszProvName) + 1) * sizeof(WCHAR);
+ length += prov_length;
+ }
+
+ length = sizeof(CRYPT_KEY_PROV_PARAM) * original->cProvParam;
+ for(i = 0; i < original->cProvParam; ++i)
+ length += original->rgProvParam[i].cbData;
+
+ /* Allocate a single block of memory for everything */
+ at = (BYTE*)malloc(length);
+ if(!at)
+ {
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ return NULL;
+ }
+
+ /* Copy in very carefully */
+ end = at + length;
+
+ memcpy(at, original, sizeof(CRYPT_KEY_PROV_INFO));
+ result = (CRYPT_KEY_PROV_INFO*)at;
+ at += sizeof(CRYPT_KEY_PROV_INFO);
+
+ if(result->pwszContainerName)
+ {
+ memcpy(at, result->pwszContainerName, container_length);
+ result->pwszContainerName = (LPWSTR)at;
+ at += container_length;
+ }
+
+ if(result->pwszProvName)
+ {
+ memcpy(at, result->pwszProvName, prov_length);
+ result->pwszProvName = (LPWSTR)at;
+ at += prov_length;
+ }
+
+ if(original->cProvParam)
+ {
+ memcpy(at, result->rgProvParam, sizeof(CRYPT_KEY_PROV_PARAM) * result->cProvParam);
+ result->rgProvParam = (CRYPT_KEY_PROV_PARAM*)at;
+ at += sizeof(CRYPT_KEY_PROV_PARAM) * result->cProvParam;
+
+ for(i = 0; i < result->cProvParam; ++i)
+ {
+ memcpy(at, result->rgProvParam[i].pbData, result->rgProvParam[i].cbData);
+ result->rgProvParam[i].pbData = (BYTE*)at;
+ at += result->rgProvParam[i].cbData;
+ }
+ }
+
+ ASSERT(at == end);
+ return result;
+}
+
+static CkCapiObjectData*
+key_alloc_data(CkCapiSession* sess, CkCapiObject* obj, CRYPT_KEY_PROV_INFO* prov_info)
+{
+ KeyObject* kobj = (KeyObject*)obj;
+ KeyObjectData* kdata;
+
+ kdata = (KeyObjectData*)calloc(1, sizeof(KeyObjectData));
+ if(!kdata)
+ return NULL;
+
+ /* Allocate memory for key identifier */
+ kdata->key_identifier.pbData = malloc(kobj->key_identifier.cbData);
+ if(!kdata->key_identifier.pbData)
+ {
+ free(kdata);
+ return NULL;
+ }
+
+ /* Setup the object data */
+ kdata->object_class = kobj->object_class;
+ kdata->prov_info = prov_info;
+ kdata->key_identifier.cbData = kobj->key_identifier.cbData;
+ memcpy(kdata->key_identifier.pbData, kobj->key_identifier.pbData,
+ kdata->key_identifier.cbData);
+ kdata->raw_public_key.pbData = NULL;
+ kdata->raw_public_key.cbData = 0;
+
+ kdata->base.object = obj->id;
+ kdata->base.data_funcs = &key_objdata_vtable;
+
+ return &(kdata->base);
+}
+
+static BOOL WINAPI
+load_key_property_info(PCRYPT_HASH_BLOB key_identifier, DWORD flags,
+ void* reserved, void* arg, DWORD n_props, DWORD* props,
+ void** datas, DWORD* n_datas)
+{
+ CRYPT_KEY_PROV_INFO** prov_info = (CRYPT_KEY_PROV_INFO**)arg;
+ DWORD i;
+
+ /*
+ * Already got a provider info. This shouldn't happen
+ * but can occur if the same key is present twice.
+ */
+ if(*prov_info)
+ return TRUE;
+
+ /* Find the key provider info property */
+ for(i = 0; i < n_props; ++i)
+ {
+ if(props[i] == CERT_KEY_PROV_INFO_PROP_ID)
+ {
+ *prov_info = duplicate_prov_info((CRYPT_KEY_PROV_INFO*)datas[i]);
+ break;
+ }
+ }
+
+ return TRUE;
+}
+
+static CK_RV
+key_load_data(CkCapiSession* sess, CkCapiObject* obj, CkCapiObjectData** objdata)
+{
+ KeyObject* kobj = (KeyObject*)obj;
+ CRYPT_KEY_PROV_INFO* prov_info = NULL;
+
+ ASSERT(kobj);
+ ASSERT(objdata);
+
+ /* Load the provider info */
+ if(!CryptEnumKeyIdentifierProperties((CRYPT_HASH_BLOB*)&kobj->key_identifier,
+ CERT_KEY_PROV_INFO_PROP_ID, 0, NULL, NULL,
+ &prov_info, load_key_property_info))
+ return ckcapi_winerr_to_ckr(GetLastError());
+
+ /* No provider info, bad news */
+ if(!prov_info)
+ return CKR_GENERAL_ERROR;
+
+ *objdata = key_alloc_data(sess, obj, prov_info);
+ if(!(*objdata))
+ {
+ free(prov_info);
+ return CKR_HOST_MEMORY;
+ }
+
+ return CKR_OK;
+}
+
+static void
+key_object_release(void* data)
+{
+ KeyObject* kobj = (KeyObject*)data;
+ ASSERT(kobj);
+ free(kobj);
+}
+
+static const CkCapiObjectVtable key_object_vtable = {
+ key_load_data,
+ key_object_release,
+};
+
+static CK_RV
+register_key_object(CkCapiSession* sess, CK_OBJECT_CLASS cls,
+ CRYPT_HASH_BLOB* key_identifier, CkCapiObject** obj)
+{
+ KeyObject* kobj;
+ CK_RV ret;
+
+ ASSERT(obj);
+ ASSERT(key_identifier);
+ ASSERT(cls == CKO_PRIVATE_KEY || cls == CKO_PUBLIC_KEY);
+
+ kobj = calloc(sizeof(KeyObject) + key_identifier->cbData, 1);
+ if(!kobj)
+ return CKR_HOST_MEMORY;
+
+ kobj->obj.id = 0;
+ kobj->obj.obj_funcs = &key_object_vtable;
+ kobj->obj.unique_key = UNIQUE_KEY_AT(kobj, object_class);
+ kobj->obj.unique_len = UNIQUE_KEY_VAR_LEN(kobj, object_class, tail_data,
+ key_identifier->cbData);
+
+ kobj->object_class = cls;
+ kobj->key_identifier.pbData = kobj->tail_data;
+ kobj->key_identifier.cbData = key_identifier->cbData;
+ memcpy(kobj->key_identifier.pbData, key_identifier->pbData,
+ kobj->key_identifier.cbData);
+
+ ret = ckcapi_token_register_object(sess->slot, &(kobj->obj));
+ if(ret != CKR_OK)
+ {
+ free(kobj);
+ return ret;
+ }
+
+ ASSERT(kobj->obj.id != 0);
+ *obj = &(kobj->obj);
+
+ return CKR_OK;
+}
+
+typedef struct _EnumArguments
+{
+ CkCapiSession* sess;
+ CK_OBJECT_CLASS object_class;
+ CK_ATTRIBUTE_PTR match;
+ CK_ULONG count;
+ CkCapiArray* results;
+ CK_RV ret;
+}
+EnumArguments;
+
+static BOOL WINAPI
+enum_key_property_info(PCRYPT_HASH_BLOB key_identifier, DWORD flags,
+ void* reserved, void* arg, DWORD n_props, DWORD* props,
+ void** datas, DWORD* n_datas)
+{
+ EnumArguments* args = (EnumArguments*)arg;
+ CRYPT_KEY_PROV_INFO* prov_info = NULL;
+ CkCapiObject *obj = NULL;
+ KeyObjectData kdata;
+ DWORD i;
+
+ /* Find the key provider info property */
+ for(i = 0; i < n_props; ++i)
+ {
+ if(props[i] == CERT_KEY_PROV_INFO_PROP_ID)
+ {
+ prov_info = (CRYPT_KEY_PROV_INFO*)datas[i];
+ break;
+ }
+ }
+
+ /* Strange key, skip */
+ if(!prov_info)
+ return TRUE;
+
+ /* Match the public key */
+ kdata.prov_info = prov_info;
+ kdata.object_class = args->object_class;
+ kdata.base.object = 0;
+ kdata.base.data_funcs = &key_objdata_vtable;
+
+ if(ckcapi_object_data_match(&kdata.base, args->match, args->count))
+ {
+ args->ret = register_key_object(args->sess, args->object_class, key_identifier, &obj);
+ if(args->ret == CKR_OK)
+ {
+ ASSERT(obj);
+ ckcapi_array_append(args->results, obj->id);
+ }
+ }
+
+ return TRUE;
+
+}
+
+static CK_RV
+find_any_keys(CkCapiSession* sess, CK_OBJECT_CLASS cls,
+ CK_ATTRIBUTE_PTR match, CK_ULONG count, CkCapiArray* arr)
+{
+ CRYPT_HASH_BLOB find_id;
+ EnumArguments enum_args;
+ CK_ULONG i;
+
+ /* Try to setup for an efficient search based on key id */
+ memset(&find_id, 0, sizeof(find_id));
+ for(i = 0; i < count; ++i)
+ {
+ if(!match[i].pValue || !match[i].ulValueLen)
+ continue;
+ if(match[i].type == CKA_ID)
+ {
+ find_id.cbData = match[i].ulValueLen;
+ find_id.pbData = match[i].pValue;
+ }
+ }
+
+ enum_args.sess = sess;
+ enum_args.match = match;
+ enum_args.count = count;
+ enum_args.results = arr;
+ enum_args.object_class = cls;
+ enum_args.ret = CKR_OK;
+
+ if(!CryptEnumKeyIdentifierProperties(find_id.cbData != 0 ? &find_id : NULL,
+ CERT_KEY_PROV_INFO_PROP_ID, 0, NULL, NULL,
+ &enum_args, enum_key_property_info))
+ return ckcapi_winerr_to_ckr(GetLastError());
+
+ return enum_args.ret;
+}
+
+static CK_RV
+list_matching_certificates(CkCapiSession* sess, CK_ATTRIBUTE_PTR match,
+ CK_ULONG count, CkCapiArray* arr)
+{
+ CK_OBJECT_CLASS cert_class = CKO_CERTIFICATE;
+ CK_ATTRIBUTE search[3];
+ CK_ULONG n_search = 0;
+ CK_ULONG i;
+
+ /* The class */
+ search[0].type = CKA_CLASS;
+ search[0].pValue = &cert_class;
+ search[0].ulValueLen = sizeof(CK_OBJECT_CLASS);
+ ++n_search;
+
+ for(i = 0; i < count && n_search < 3; ++i)
+ {
+ /*
+ * This is the attributes that tie a certificate
+ * to key object, so try match certs with these
+ */
+ if(match[i].type == CKA_ID)
+ {
+ search[n_search].type = match[i].type;
+ search[n_search].pValue = match[i].pValue;
+ search[n_search].ulValueLen = match[i].ulValueLen;
+ ++n_search;
+ }
+ }
+
+ /* Do the certificate search */
+ return ckcapi_cert_find(sess, CKO_CERTIFICATE, search, n_search, arr);
+}
+
+static CK_RV
+find_certificate_key(CkCapiSession* session, CK_OBJECT_CLASS cls,
+ CK_ATTRIBUTE_PTR match, CK_ULONG count,
+ PCCERT_CONTEXT cert, CkCapiArray* arr)
+{
+ CRYPT_KEY_PROV_INFO* prov_info;
+ CRYPT_HASH_BLOB key_identifier;
+ CkCapiObjectData* objdata;
+ KeyObjectData kdata;
+ CkCapiObject* obj;
+ DWORD prov_length;
+ CK_RV ret;
+
+ /* Look up the key provider info and identifier */
+ if(!CertGetCertificateContextProperty(cert, CERT_KEY_PROV_INFO_PROP_ID, NULL, &prov_length) ||
+ !CertGetCertificateContextProperty(cert, CERT_KEY_IDENTIFIER_PROP_ID, NULL, &key_identifier.cbData))
+ return ckcapi_winerr_to_ckr(GetLastError());
+
+ /* We own the info memory */
+ prov_info = malloc(prov_length);
+ if(!prov_info)
+ return CKR_HOST_MEMORY;
+ key_identifier.pbData = malloc(key_identifier.cbData);
+ if(!key_identifier.pbData)
+ {
+ free(prov_info);
+ return CKR_HOST_MEMORY;
+ }
+
+ /* Lookup the key provider info and identifier */
+ if(CertGetCertificateContextProperty(cert, CERT_KEY_PROV_INFO_PROP_ID, prov_info, &prov_length) &&
+ CertGetCertificateContextProperty(cert, CERT_KEY_IDENTIFIER_PROP_ID, key_identifier.pbData, &key_identifier.cbData))
+ {
+ kdata.object_class = cls;
+ kdata.prov_info = prov_info;
+ kdata.key_identifier = key_identifier;
+ kdata.base.object = 0;
+ kdata.base.data_funcs = &key_objdata_vtable;
+
+ if(ckcapi_object_data_match(&kdata.base, match, count))
+ {
+ ret = register_key_object(session, cls, &key_identifier, &obj);
+ if(ret == CKR_OK)
+ {
+ ASSERT(obj);
+
+ /* Store away the object data for performance reasons */
+ objdata = key_alloc_data(session, obj, prov_info);
+ if(objdata)
+ {
+ ckcapi_session_take_object_data(session, obj, objdata);
+
+ /* Note these are used, and not to be freed */
+ key_identifier.pbData = NULL;
+ key_identifier.cbData = 0;
+ prov_info = NULL;
+ }
+
+ ckcapi_array_append(arr, obj->id);
+ }
+ }
+ }
+
+ if(key_identifier.pbData)
+ free(key_identifier.pbData);
+ if(prov_info)
+ free(prov_info);
+
+ return ret;
+}
+
+static CK_RV
+find_certificate_keys(CkCapiSession* session, CK_OBJECT_CLASS cls,
+ CK_ATTRIBUTE_PTR match, CK_ULONG count, CkCapiArray* arr)
+{
+ CK_OBJECT_HANDLE id;
+ CkCapiObjectData* certdata;
+ CkCapiArray* certarr;
+ PCCERT_CONTEXT cert;
+ CK_RV ret = CKR_OK;
+ CK_ULONG i;
+
+ /* Get a list of all certificates */
+ certarr = ckcapi_array_new(0, 1, sizeof(CK_OBJECT_HANDLE));
+ if(!certarr)
+ return CKR_HOST_MEMORY;
+ ret = list_matching_certificates(session, match, count, certarr);
+
+ /* Now match each of them against our criteria */
+ if(ret == CKR_OK)
+ {
+ for(i = 0; i < certarr->len; ++i)
+ {
+ id = ckcapi_array_index(certarr, CK_OBJECT_HANDLE, i);
+ ASSERT(id);
+
+ /* Get the certificate data for this certificate object */
+ if(ckcapi_session_get_object_data_for(session, id, &certdata) != CKR_OK)
+ continue;
+
+ /* Get the certificate context */
+ cert = ckcapi_cert_object_data_get_certificate(certdata);
+ if(!cert)
+ continue;
+
+ /* Remember we can have either or both keys for each certificate */
+ ret = find_certificate_key(session, cls, match, count, cert, arr);
+ }
+ }
+
+ ckcapi_array_free(certarr, TRUE);
+ return ret;
+}
+
+CK_RV
+ckcapi_key_find(CkCapiSession* sess, CK_OBJECT_CLASS cls,
+ CK_ATTRIBUTE_PTR match, CK_ULONG count, CkCapiArray* arr)
+{
+ CK_RV ret = CKR_OK;
+
+ /* Is this somewhere we have all keys present? */
+ if(ckcapi_token_get_flags(sess->slot) & CKCAPI_SLOT_ANYKEY)
+ {
+ if((cls == CKO_PRIVATE_KEY || cls == CKO_ANY) && ret == CKR_OK)
+ ret = find_any_keys(sess, CKO_PRIVATE_KEY, match, count, arr);
+ if((cls == CKO_PUBLIC_KEY || cls == CKO_ANY) && ret == CKR_OK)
+ ret = find_any_keys(sess, CKO_PUBLIC_KEY, match, count, arr);
+ }
+
+ /* Otherwise we can only list the keys that have certificates */
+ else
+ {
+ if((cls == CKO_PRIVATE_KEY || cls == CKO_ANY) && ret == CKR_OK)
+ ret = find_certificate_keys(sess, CKO_PRIVATE_KEY, match, count, arr);
+ if((cls == CKO_PUBLIC_KEY || cls == CKO_ANY) && ret == CKR_OK)
+ ret = find_certificate_keys(sess, CKO_PUBLIC_KEY, match, count, arr);
+ }
+
+ return ret;
+}
+
+CK_RV
+ckcapi_key_object_data_get_handles (CkCapiObjectData* objdata, HCRYPTPROV* ret_prov,
+ HCRYPTKEY* ret_key)
+{
+ KeyObjectData* kdata = (KeyObjectData*)objdata;
+ HCRYPTPROV prov;
+ HCRYPTKEY key;
+ DWORD error;
+
+ ASSERT(kdata);
+
+ if(!CryptAcquireContextW(&prov, kdata->prov_info->pwszContainerName,
+ kdata->prov_info->pwszProvName,
+ kdata->prov_info->dwProvType, 0))
+ {
+ return ckcapi_winerr_to_ckr(GetLastError());
+ }
+
+ if(!CryptGetUserKey(prov, kdata->prov_info->dwKeySpec, &key))
+ {
+ error = GetLastError();
+ CryptReleaseContext(prov, 0);
+ return ckcapi_winerr_to_ckr(error);
+ }
+
+ if(ret_key)
+ *ret_key = key;
+ else
+ CryptDestroyKey(key);
+
+ if(ret_prov)
+ *ret_prov = prov;
+ else
+ CryptReleaseContext(prov, 0);
+
+ return CKR_OK;
+}
diff --git a/ckcapi-key.h b/ckcapi-key.h
new file mode 100644
index 0000000..d09b30c
--- /dev/null
+++ b/ckcapi-key.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2008 Stef Walter
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef CKCAPI_KEY_H
+#define CKCAPI_KEY_H
+
+#include "ckcapi.h"
+
+/* Find key objects matching criteria */
+CK_RV ckcapi_key_find (CkCapiSession* sess, CK_OBJECT_CLASS cls,
+ CK_ATTRIBUTE_PTR match, CK_ULONG count,
+ CkCapiArray* arr);
+
+CK_RV ckcapi_key_object_data_get_handles (CkCapiObjectData* objdata, HCRYPTPROV* prov,
+ HCRYPTKEY* key);
+
+#endif /* CRYPTOKI_KEY_H */
diff --git a/ckcapi-trust.c b/ckcapi-trust.c
index 98c0046..6107ac5 100644
--- a/ckcapi-trust.c
+++ b/ckcapi-trust.c
@@ -141,7 +141,7 @@ trust_bool_attribute(CkCapiObjectData* objdata, CK_ATTRIBUTE_PTR attr)
return CKR_ATTRIBUTE_TYPE_INVALID;
};
- return ckcapi_return_data(attr->pValue, &attr->ulValueLen, &val, sizeof(CK_BBOOL));
+ return ckcapi_return_data(attr, &val, sizeof(CK_BBOOL));
}
static CK_RV
@@ -221,7 +221,7 @@ trust_ulong_attribute(CkCapiObjectData* objdata, CK_ATTRIBUTE_PTR attr)
return CKR_ATTRIBUTE_TYPE_INVALID;
};
- return ckcapi_return_data(attr->pValue, &attr->ulValueLen, &val, sizeof(CK_ULONG));
+ return ckcapi_return_data(attr, &val, sizeof(CK_ULONG));
}
static CK_RV
diff --git a/ckcapi-util.c b/ckcapi-util.c
index 5c0ab9b..3bd18a5 100644
--- a/ckcapi-util.c
+++ b/ckcapi-util.c
@@ -23,6 +23,23 @@
#include <stdlib.h>
#include <string.h>
+
+void
+ckcapi_reverse_memory (void* data, size_t length)
+{
+ size_t end = length - 1;
+ size_t middle = length / 2;
+ unsigned char* buf = data;
+ size_t i;
+
+ for (i = 0; i < middle; i++)
+ {
+ unsigned char tmp = buf[i];
+ buf[i] = buf[end - i];
+ buf[end - i] = tmp;
+ }
+}
+
/*
* Array code originially from Glib.
* Modified extensively by Stef Walter <nielsen@memberwebs.com>
diff --git a/ckcapi-util.h b/ckcapi-util.h
index 1ea07f2..6ae74a0 100644
--- a/ckcapi-util.h
+++ b/ckcapi-util.h
@@ -22,6 +22,9 @@
#include <stdlib.h>
+
+void ckcapi_reverse_memory (void* data, size_t length);
+
/* --------------------------------------------------------------------------------
* ARRAYS
*/
diff --git a/ckcapi.c b/ckcapi.c
index 9ea7815..75c133a 100644
--- a/ckcapi.c
+++ b/ckcapi.c
@@ -113,6 +113,7 @@ ckcapi_winerr_to_ckr(DWORD werr)
switch(werr)
{
case ERROR_NOT_ENOUGH_MEMORY:
+ case ERROR_OUTOFMEMORY:
return CKR_HOST_MEMORY;
break;
case NTE_NO_MEMORY:
@@ -124,45 +125,42 @@ ckcapi_winerr_to_ckr(DWORD werr)
case ERROR_INVALID_HANDLE: /* inputs, so if they are bad, the input */
case NTE_BAD_ALGID: /* data is bad */
case NTE_BAD_HASH:
+ case NTE_BAD_TYPE:
+ case NTE_BAD_PUBLIC_KEY:
return CKR_DATA_INVALID;
- break;
case ERROR_BUSY:
case NTE_FAIL:
case NTE_BAD_UID:
return CKR_DEVICE_ERROR;
- break;
default:
return CKR_GENERAL_ERROR;
};
}
-
CK_RV
-ckcapi_return_data(CK_VOID_PTR dst, CK_ULONG_PTR dlen,
- CK_VOID_PTR src, DWORD slen)
+ckcapi_return_data(CK_ATTRIBUTE_PTR attr, CK_VOID_PTR src, DWORD slen)
{
/* Just asking for the length */
- if(!dst)
+ if(!attr->pValue)
{
- *dlen = slen;
+ attr->ulValueLen = slen;
return CKR_OK;
}
/* Buffer is too short */
- if(slen > *dlen)
+ if(slen > attr->ulValueLen)
{
- *dlen = slen;
+ attr->ulValueLen = slen;
return CKR_BUFFER_TOO_SMALL;
}
- *dlen = slen;
- memcpy(dst, src, slen);
+ attr->ulValueLen = slen;
+ memcpy(attr->pValue, src, slen);
return CKR_OK;
}
CK_RV
-ckcapi_return_string(CK_VOID_PTR dst, CK_ULONG_PTR dlen,
- WCHAR* string)
+ckcapi_return_string(CK_ATTRIBUTE_PTR attr, WCHAR* string)
{
DWORD error;
int result;
@@ -175,11 +173,11 @@ ckcapi_return_string(CK_VOID_PTR dst, CK_ULONG_PTR dlen,
* case this part.
*/
if(!string[0])
- return ckcapi_return_data(dst, dlen, "\0", 1);
+ return ckcapi_return_data(attr, "\0", 1);
result = WideCharToMultiByte(CP_UTF8, 0, string, -1,
- dst, dst ? *dlen : 0, NULL, NULL);
-
+ attr->pValue, attr->pValue ? attr->ulValueLen : 0,
+ NULL, NULL);
/* An error result somehow */
if(!result)
@@ -193,7 +191,7 @@ ckcapi_return_string(CK_VOID_PTR dst, CK_ULONG_PTR dlen,
NULL, 0, NULL, NULL);
if(!result)
return CKR_GENERAL_ERROR;
- *dlen = result;
+ attr->ulValueLen = result;
return CKR_BUFFER_TOO_SMALL;
/* A strange zero length success */
@@ -206,7 +204,52 @@ ckcapi_return_string(CK_VOID_PTR dst, CK_ULONG_PTR dlen,
}
}
- *dlen = result;
+ attr->ulValueLen = result;
+ return CKR_OK;
+}
+
+CK_RV
+ckcapi_return_dword_as_bytes(CK_ATTRIBUTE_PTR attr, DWORD value)
+{
+ int i;
+ CK_ULONG count = 0;
+ BOOL first = TRUE;
+ BYTE* at = attr->pValue;
+ CK_RV ret = CKR_OK;
+
+ for(i = 0; i < sizeof(DWORD); i++)
+ {
+ BYTE digit = (BYTE)((value >> (((sizeof(DWORD)-1)*8))) & 0xFF);
+ value = value << 8;
+
+ /* No leading zero */
+ if (first && digit == 0)
+ continue;
+
+ first = FALSE;
+ if(at)
+ {
+ if(count > attr->ulValueLen)
+ ret = CKR_BUFFER_TOO_SMALL;
+ else
+ *(at++) = digit;
+ }
+
+ count++;
+ }
+
+ attr->ulValueLen = count;
+ return ret;
+}
+
+CK_RV
+ckcapi_return_reversed_data(CK_ATTRIBUTE_PTR attr, CK_VOID_PTR data, CK_ULONG length)
+{
+ CK_RV ret = ckcapi_return_data(attr, data, length);
+ if(ret != CKR_OK || !attr->pValue)
+ return ret;
+
+ ckcapi_reverse_memory(attr->pValue, attr->ulValueLen);
return CKR_OK;
}
diff --git a/ckcapi.h b/ckcapi.h
index 707d7f8..18f304f 100644
--- a/ckcapi.h
+++ b/ckcapi.h
@@ -88,16 +88,22 @@ CK_RV ckcapi_winerr_to_ckr (DWORD werr);
* PKCS#11 codes when the buffer is too short, or the caller
* just wants to know the length, etc.
*/
-CK_RV ckcapi_return_data (CK_VOID_PTR dst, CK_ULONG_PTR dlen,
- CK_VOID_PTR src, DWORD slen);
+CK_RV ckcapi_return_data (CK_ATTRIBUTE_PTR attr,
+ CK_VOID_PTR src, DWORD slen);
/*
* This stores a string in the output buffer with appropriate
* PKCS#11 codes when the buffer is too short, or the caller
* just wants to know the length, etc.
*/
-CK_RV ckcapi_return_string (CK_VOID_PTR dst, CK_ULONG_PTR dlen,
- WCHAR* string);
+CK_RV ckcapi_return_string (CK_ATTRIBUTE_PTR attr,
+ WCHAR* string);
+
+CK_RV ckcapi_return_dword_as_bytes (CK_ATTRIBUTE_PTR attr,
+ DWORD value);
+
+CK_RV ckcapi_return_reversed_data (CK_ATTRIBUTE_PTR attr,
+ CK_VOID_PTR data, CK_ULONG length);
/* ------------------------------------------------------------------ */
diff --git a/ckcapi.vcproj b/ckcapi.vcproj
index c2a77bb..5abc307 100644
--- a/ckcapi.vcproj
+++ b/ckcapi.vcproj
@@ -73,7 +73,7 @@
/>
<Tool
Name="VCLinkerTool"
- AdditionalDependencies="odbc32.lib odbccp32.lib crypt32.lib"
+ AdditionalDependencies="odbc32.lib odbccp32.lib crypt32.lib advapi32.lib"
OutputFile=".\Debug/ckcapi.dll"
LinkIncremental="2"
SuppressStartupBanner="true"
@@ -252,6 +252,10 @@
</FileConfiguration>
</File>
<File
+ RelativePath=".\ckcapi-key.c"
+ >
+ </File>
+ <File
RelativePath="ckcapi-object.c"
>
<FileConfiguration
@@ -381,6 +385,10 @@
>
</File>
<File
+ RelativePath=".\ckcapi-key.h"
+ >
+ </File>
+ <File
RelativePath=".\ckcapi-object.h"
>
</File>
@@ -405,10 +413,6 @@
>
</File>
<File
- RelativePath=".\pkcs11\ckcapi.h"
- >
- </File>
- <File
RelativePath="pkcs11\pkcs11.h"
>
</File>