summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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>