summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStef Walter <stef@memberwebs.com>2008-12-04 18:59:50 +0000
committerStef Walter <stef@memberwebs.com>2008-12-04 18:59:50 +0000
commitd611032e1e5b4e2261625ee924071e9713320837 (patch)
tree66683785a16c02975b675017f460eb9ed14e799d
parentb00eb56b7ffe5019bb33ad399d351b90f4715132 (diff)
Implement RSA Sign and Decrypt operations. Not tested.
-rw-r--r--ckcapi-der.c177
-rw-r--r--ckcapi-der.h35
-rw-r--r--ckcapi-key.c92
-rw-r--r--ckcapi-key.h11
-rw-r--r--ckcapi-rsa.c405
-rw-r--r--ckcapi-rsa.h41
-rw-r--r--ckcapi-session.c199
-rw-r--r--ckcapi-session.h27
-rw-r--r--ckcapi.c128
-rw-r--r--ckcapi.h5
-rw-r--r--ckcapi.vcproj16
11 files changed, 1063 insertions, 73 deletions
diff --git a/ckcapi-der.c b/ckcapi-der.c
new file mode 100644
index 0000000..602b831
--- /dev/null
+++ b/ckcapi-der.c
@@ -0,0 +1,177 @@
+/*
+ * Portions derived from NSS source files:
+ * lib/ckfw/capi/cobject.c
+ * lib/ckfw/capi/crsa.c
+ *
+ * Portions of this file:
+ * Copyright (C) Stef Walter 2008
+ *
+ */
+
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1994-2000
+ * the Initial Developer. All Rights Reserved.
+ * Portions created by Red Hat, Inc, are Copyright (C) 2005
+ *
+ * Contributor(s):
+ * Bob Relyea (rrelyea@redhat.com)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "ckcapi.h"
+#include "ckcapi-der.h"
+
+/*
+ * unwrap a single DER value
+ */
+BYTE*
+ckcapi_der_unwrap(BYTE* src, DWORD n_src,
+ DWORD* n_result, BYTE** next)
+{
+ BYTE* start = src;
+ BYTE* end = src + n_src;
+ DWORD len = 0;
+
+ /* initialize error condition return values */
+ *n_result = 0;
+ if(next)
+ *next = src;
+
+ if(n_src < 2)
+ return start;
+
+ src++ ; /* skip the tag -- should check it against an expected value! */
+ len = (DWORD)*src++;
+ if(len & 0x80)
+ {
+ DWORD count = len & 0x7f;
+ len = 0;
+
+ if(count + 2 > n_src)
+ return start;
+
+ while(count-- > 0)
+ len = (len << 8) | (DWORD)*src++;
+ }
+
+ if(len + (src - start) > (DWORD)n_src)
+ return start;
+
+ if(next)
+ *next = src + len;
+
+ *n_result = len;
+ return src;
+}
+
+/*
+ * write a Decimal value to a string
+ */
+
+static char*
+put_decimal_string(char* cstr, DWORD value)
+{
+ DWORD tenpower;
+ BOOL first = TRUE;
+
+ for(tenpower = 10000000; tenpower; tenpower /= 10)
+ {
+ BYTE digit = (BYTE)(value / tenpower);
+ value = value % tenpower;
+
+ /* drop leading zeros */
+ if(first && (0 == digit))
+ continue;
+
+ first = FALSE;
+ *cstr++ = digit + '0';
+ }
+
+ /* if value was zero, put one of them out */
+ if(first)
+ *cstr++ = '0';
+
+ return cstr;
+}
+
+/*
+ * Create a Capi OID string value from a DER OID
+ */
+char*
+ckcapi_der_read_oid(BYTE* oid_tag, DWORD n_oid_tag)
+{
+ BYTE* oid;
+ char *oid_str;
+ char *cstr;
+ DWORD value;
+ DWORD n_oid;
+
+ /* wasn't an oid */
+ if(CKCAPI_DER_OBJECT_ID != *oid_tag)
+ return NULL;
+
+ oid = ckcapi_der_unwrap(oid_tag, n_oid_tag, &n_oid, NULL);;
+ if(n_oid < 2)
+ return NULL;
+
+ oid_str = malloc(n_oid * 4);
+ if(!oid_str)
+ return NULL;
+
+ cstr = oid_str;
+ cstr = put_decimal_string(cstr, (*oid) / 40);
+ *cstr++ = '.';
+ cstr = put_decimal_string(cstr, (*oid) % 40);
+ n_oid--;
+
+ value = 0;
+ while(n_oid--)
+ {
+ oid++;
+ value = (value << 7) + (*oid & 0x7f);
+ if(0 == (*oid & 0x80))
+ {
+ *cstr++ = '.';
+ cstr = put_decimal_string(cstr, value);
+ value = 0;
+ }
+ }
+
+ *cstr = 0; /* NULL terminate */
+
+ if(value != 0)
+ {
+ free(oid_str);
+ return NULL;
+ }
+
+ return oid_str;
+}
diff --git a/ckcapi-der.h b/ckcapi-der.h
new file mode 100644
index 0000000..9030ce3
--- /dev/null
+++ b/ckcapi-der.h
@@ -0,0 +1,35 @@
+/*
+ * 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_DER_H
+#define CKCAPI_DER_H
+
+#include "ckcapi.h"
+
+#define CKCAPI_DER_OCTET_STRING 0x04
+#define CKCAPI_DER_OBJECT_ID 0x06
+#define CKCAPI_DER_SEQUENCE 0x10
+#define CKCAPI_DER_CONSTRUCTED 0x20
+
+BYTE* ckcapi_der_unwrap (BYTE* src, DWORD n_src,
+ DWORD* n_result, BYTE** next);
+
+char* ckcapi_der_read_oid (BYTE* oid_tag, DWORD n_oid_tag);
+
+#endif /* CRYPTOKI_DER_H */
diff --git a/ckcapi-key.c b/ckcapi-key.c
index 1ce057c..88e769e 100644
--- a/ckcapi-key.c
+++ b/ckcapi-key.c
@@ -98,6 +98,40 @@ typedef struct _KeyObjectData
KeyObjectData;
static CK_RV
+load_key_handle (CkCapiObjectData* objdata, 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);
+
+ CryptReleaseContext(prov, 0);
+ return CKR_OK;
+}
+
+
+static CK_RV
load_raw_public_key(KeyObjectData* kdata)
{
BOOL success = FALSE;
@@ -108,7 +142,7 @@ load_raw_public_key(KeyObjectData* kdata)
ASSERT(kdata);
ASSERT(!kdata->raw_public_key.pbData);
- ret = ckcapi_key_object_data_get_handles(&kdata->base, NULL, &key);
+ ret = load_key_handle(&kdata->base, &key);
if(ret != CKR_OK)
return ret;
@@ -994,40 +1028,42 @@ ckcapi_key_find(CkCapiSession* sess, CK_OBJECT_CLASS cls,
return ret;
}
-CK_RV
-ckcapi_key_object_data_get_handles (CkCapiObjectData* objdata, HCRYPTPROV* ret_prov,
- HCRYPTKEY* ret_key)
+DWORD
+ckcapi_key_object_data_get_bits(CkCapiObjectData* objdata)
{
- KeyObjectData* kdata = (KeyObjectData*)objdata;
- HCRYPTPROV prov;
- HCRYPTKEY key;
- DWORD error;
+ KeyObjectData* kdata;
+ PUBLICKEYSTRUC* header;
+ RSAPUBKEY* pubkey;
+ CK_RV ret;
- ASSERT(kdata);
+ ASSERT(objdata);
- if(!CryptAcquireContextW(&prov, kdata->prov_info->pwszContainerName,
- kdata->prov_info->pwszProvName,
- kdata->prov_info->dwProvType, 0))
+ kdata = (KeyObjectData*)objdata;
+
+ if(!kdata->raw_public_key.pbData)
{
- return ckcapi_winerr_to_ckr(GetLastError());
+ ret = load_raw_public_key(kdata);
+ if(ret != CKR_OK)
+ return ret;
}
- if(!CryptGetUserKey(prov, kdata->prov_info->dwKeySpec, &key))
- {
- error = GetLastError();
- CryptReleaseContext(prov, 0);
- return ckcapi_winerr_to_ckr(error);
- }
+ header = (PUBLICKEYSTRUC*)kdata->raw_public_key.pbData;
+ if(!header->bType == PUBLICKEYBLOB)
+ return 0;
- if(ret_key)
- *ret_key = key;
- else
- CryptDestroyKey(key);
+ pubkey = (RSAPUBKEY*)(header + 1);
+ if(!pubkey->magic == 0x31415352)
+ return 0;
- if(ret_prov)
- *ret_prov = prov;
- else
- CryptReleaseContext(prov, 0);
+ return pubkey->bitlen;
+}
- return CKR_OK;
+CRYPT_KEY_PROV_INFO*
+ckcapi_key_object_data_get_prov_info(CkCapiObjectData* objdata)
+{
+ KeyObjectData* kdata;
+
+ ASSERT(objdata);
+ kdata = (KeyObjectData*)objdata;
+ return kdata->prov_info;
}
diff --git a/ckcapi-key.h b/ckcapi-key.h
index d09b30c..eabe7a9 100644
--- a/ckcapi-key.h
+++ b/ckcapi-key.h
@@ -23,11 +23,12 @@
#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_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);
+DWORD ckcapi_key_object_data_get_bits (CkCapiObjectData* objdata);
+
+CRYPT_KEY_PROV_INFO* ckcapi_key_object_data_get_prov_info (CkCapiObjectData* objdata);
#endif /* CRYPTOKI_KEY_H */
diff --git a/ckcapi-rsa.c b/ckcapi-rsa.c
new file mode 100644
index 0000000..0d4e75d
--- /dev/null
+++ b/ckcapi-rsa.c
@@ -0,0 +1,405 @@
+/*
+ * 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-der.h"
+#include "ckcapi-key.h"
+#include "ckcapi-object.h"
+
+/*
+ * Portions derived from NSS source files:
+ * lib/ckfw/capi/crsa.c
+ */
+
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Red Hat, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 2005
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Bob Relyea (rrelyea@redhat.com)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#define SSL3_SHAMD5_HASH_SIZE 36 /* LEN_MD5 (16) + LEN_SHA1 (20) */
+
+/*
+ * PKCS #11 sign for RSA expects to take a fully DER-encoded hash value,
+ * which includes the hash OID. CAPI expects to take a Hash Context. While
+ * CAPI does have the capability of setting a raw hash value, it does not
+ * have the ability to sign an arbitrary value. This function tries to
+ * reduce the passed in data into something that CAPI could actually sign.
+ */
+static CK_BYTE_PTR
+parse_rsa_pkcs_der_hash(CK_BYTE_PTR input, CK_ULONG n_input,
+ ALG_ID* algorithm, CK_ULONG_PTR n_hash)
+{
+ BYTE* algid;
+ BYTE* oid;
+ BYTE* hash_data;
+ BYTE* oid_str;
+ DWORD n_oid;
+ DWORD n_algid;
+
+ /*
+ * there are 2 types of hashes NSS typically tries to sign, regular
+ * RSA signature format (with encoded DER_OIDS), and SSL3 Signed hashes.
+ * CAPI knows not to add any oids to SSL3_Signed hashes, so if we have any
+ * random hash that is exactly the same size as an SSL3 hash, then we can
+ * just pass the data through. CAPI has know way of knowing if the value
+ * is really a combined hash or some other arbitrary data, so it's safe to
+ * handle this case first.
+ */
+ if(SSL3_SHAMD5_HASH_SIZE == n_input)
+ {
+ *n_hash = n_input;
+ *algorithm = CALG_SSL3_SHAMD5;
+ return input;
+ }
+
+ /* make sure we have a sequence tag */
+ if((CKCAPI_DER_SEQUENCE | CKCAPI_DER_CONSTRUCTED) != *input)
+ return NULL;
+
+ /*
+ * parse the input block to get 1) the hash oid, and 2) the raw hash value.
+ * unfortunatly CAPI doesn't have a builtin function to do this work, so
+ * we go ahead and do it by hand here.
+ *
+ * format is:
+ * SEQUENCE {
+ * SECQUENCE { // algid
+ * OID {} // oid
+ * ANY {} // optional params
+ * }
+ * OCTECT {} // hash
+ */
+
+ /* unwrap */
+ algid = ckcapi_der_unwrap(input, n_input, &n_algid, NULL);
+ if(!algid)
+ return NULL;
+
+ /* make sure there is not extra data at the end */
+ if(algid + n_algid != input + n_input)
+ return NULL;
+
+ /* wasn't an algid */
+ if((CKCAPI_DER_SEQUENCE | CKCAPI_DER_CONSTRUCTED) != *algid)
+ return NULL;
+
+ oid = ckcapi_der_unwrap(algid, n_algid, &n_oid, &hash_data);
+ if(!oid || !hash_data)
+ return NULL;
+
+ if(algorithm)
+ {
+ /*
+ * get the real oid as a string. Again, Microsoft does not
+ * export anything that does this for us
+ */
+ oid_str = ckcapi_der_read_oid(oid, n_oid);
+ if(!oid_str)
+ return NULL;
+
+ /* look up the hash alg from the oid (fortunately CAPI does to this) */
+ *algorithm = CertOIDToAlgId(oid_str);
+ free(oid_str);
+ }
+
+ /* wasn't a hash? */
+ if(CKCAPI_DER_OCTET_STRING != *hash_data)
+ return NULL;
+
+ /* get the real raw hash */
+ return ckcapi_der_unwrap(hash_data, n_algid - (hash_data - algid),
+ n_hash, NULL);
+}
+
+CK_RV
+ckcapi_rsa_pkcs_sign_init(CkCapiObjectData *keydata, void** operation)
+{
+ CRYPT_KEY_PROV_INFO* prov_info;
+
+ ASSERT(keydata);
+ ASSERT(operation);
+ ASSERT(!*operation);
+
+ prov_info = ckcapi_key_object_data_get_prov_info(keydata);
+ if(prov_info->dwProvType == PROV_RSA_FULL)
+ return CKR_KEY_TYPE_INCONSISTENT;
+
+ *operation = keydata;
+ return CKR_OK;
+}
+
+CK_RV
+ckcapi_rsa_pkcs_sign_perform (CK_BYTE_PTR data, CK_ULONG n_data,
+ CK_BYTE_PTR signature, CK_ULONG_PTR n_signature,
+ void** operation)
+{
+ CRYPT_KEY_PROV_INFO* prov_info;
+ CkCapiObjectData* keydata;
+ ALG_ID algorithm;
+ BYTE* hash_data;
+ DWORD n_hash_data;
+ BOOL capifail;
+ DWORD len, check;
+ DWORD bits;
+ CK_RV ret;
+
+ HCRYPTPROV prov = 0;
+ HCRYPTHASH hash = 0;
+
+
+ ASSERT(operation);
+ ASSERT(*operation);
+
+ if(!data || !n_data)
+ return CKR_ARGUMENTS_BAD;
+
+ keydata = (CkCapiObjectData*)*operation;
+
+ prov_info = ckcapi_key_object_data_get_prov_info(keydata);
+ ASSERT(prov_info);
+
+ /* Calculate the number of bits */
+ bits = ckcapi_key_object_data_get_bits (keydata);
+ if(!bits)
+ return CKR_GENERAL_ERROR;
+
+ /* Want to know the length */
+ if(!signature)
+ {
+ *n_signature = bits / 8;
+ return CKR_OK;
+ }
+
+ /* TODO: Support arbitrary input on Vista */
+
+ /*
+ * PKCS #11 sign for RSA expects to take a fully DER-encoded hash value,
+ * which includes the hash OID. CAPI expects to take a Hash Context. While
+ * CAPI does have the capability of setting a raw hash value, it does not
+ * have the ability to sign an arbitrary value. This function tries to
+ * reduce the passed in data into something that CAPI could actually sign.
+ */
+ hash_data = parse_rsa_pkcs_der_hash(data, n_data, &algorithm, &n_hash_data);
+ if(!hash_data)
+ return CKR_DATA_INVALID;
+
+ capifail = TRUE;
+ if(CryptAcquireContextW(&prov, prov_info->pwszContainerName, prov_info->pwszProvName,
+ prov_info->dwProvType, 0))
+ {
+ if(CryptCreateHash(prov, algorithm, 0, 0, &hash))
+ {
+ /* make sure the hash lens match before we set it */
+ len = sizeof(DWORD);
+ if(CryptGetHashParam(hash, HP_HASHSIZE, (BYTE*)&check, &len, 0))
+ {
+ if(check != n_hash_data)
+ {
+ capifail = FALSE;
+ ret = CKR_DATA_INVALID;
+ }
+
+ /*
+ * we have an explicit hash, set it, note that the length is
+ * implicit by the hashAlg used in create
+ */
+ if(CryptSetHashParam(hash, HP_HASHVAL, hash_data, 0))
+ {
+ /* OK, we have the data in a hash structure, sign it! */
+ if(CryptSignHash(hash, prov_info->dwKeySpec,
+ NULL, 0, signature, n_signature))
+ {
+ /*
+ * OK, Microsoft likes to do things completely
+ * differently than anyone else. We need to reverse
+ * the data we recieved here
+ */
+ if(signature)
+ ckcapi_reverse_memory(signature, *n_signature);
+
+ capifail = FALSE;
+ ret = CKR_OK;
+ }
+ }
+ }
+ }
+ }
+
+ if(capifail)
+ ret = ckcapi_winerr_to_ckr(GetLastError());
+
+ if(hash)
+ CryptDestroyHash(hash);
+ if(prov)
+ CryptReleaseContext(prov, 0);
+
+ return ret;
+}
+
+void
+ckcapi_rsa_pkcs_sign_cleanup (void* operation)
+{
+ /* Nothing to do */
+}
+
+
+CK_RV
+ckcapi_rsa_pkcs_decrypt_init(CkCapiObjectData* keydata, void** operation)
+{
+ CRYPT_KEY_PROV_INFO* prov_info;
+
+ ASSERT(keydata);
+ ASSERT(operation);
+ ASSERT(!*operation);
+
+ prov_info = ckcapi_key_object_data_get_prov_info(keydata);
+ if(prov_info->dwProvType == PROV_RSA_FULL)
+ return CKR_KEY_TYPE_INCONSISTENT;
+
+ *operation = keydata;
+ return CKR_OK;
+}
+
+CK_RV
+ckcapi_rsa_pkcs_decrypt_perform(CK_BYTE_PTR encdata, CK_ULONG n_encdata,
+ CK_BYTE_PTR result, CK_ULONG_PTR n_result,
+ void** operation)
+{
+ CRYPT_KEY_PROV_INFO* prov_info;
+ CkCapiObjectData* keydata;
+ BOOL capifail;
+ DWORD bits, error;
+ CK_RV ret;
+
+ HCRYPTPROV prov = 0;
+ HCRYPTKEY key = 0;
+ void* buffer = NULL;
+
+ ASSERT(operation);
+ ASSERT(*operation);
+ ASSERT(encdata);
+ ASSERT(n_encdata);
+
+ keydata = (CkCapiObjectData*)*operation;
+
+ prov_info = ckcapi_key_object_data_get_prov_info(keydata);
+ ASSERT(prov_info);
+
+ /* Calculate the number of bits */
+ bits = ckcapi_key_object_data_get_bits (keydata);
+ if(!bits)
+ return CKR_GENERAL_ERROR;
+
+ /* Want to know the length */
+ if(!result)
+ {
+ *n_result = bits / 8;
+ return CKR_OK;
+ }
+
+ /*
+ * Copy the input, since CAPI operates in place, and
+ * we must also reverse it properly.
+ */
+ buffer = malloc(n_encdata);
+ if(!buffer)
+ return CKR_HOST_MEMORY;
+
+ memcpy(buffer, encdata, n_encdata);
+ ckcapi_reverse_memory(buffer, n_encdata);
+
+ capifail = TRUE;
+ if(CryptAcquireContextW(&prov, prov_info->pwszContainerName, prov_info->pwszProvName,
+ prov_info->dwProvType, 0))
+ {
+ if(CryptGetUserKey(prov, prov_info->dwKeySpec, &key))
+ {
+ *n_result = n_encdata;
+ if(CryptDecrypt(key, 0, TRUE, 0, buffer, n_result))
+ {
+ capifail = FALSE;
+ ret = CKR_OK;
+ }
+ }
+ }
+
+ if(capifail)
+ {
+ error = GetLastError();
+ switch(error)
+ {
+ case NTE_BAD_DATA:
+ ret = CKR_ENCRYPTED_DATA_INVALID;
+ default:
+ ret = ckcapi_winerr_to_ckr(error);
+ };
+ }
+
+ /* Copy the memory out to the result buffer */
+ if(ret == CKR_OK)
+ ret = ckcapi_return_data_raw(result, n_result, buffer, *n_result);
+
+ if(key)
+ CryptDestroyKey(key);
+ if(prov)
+ CryptReleaseContext(prov, 0);
+ if(buffer)
+ free(buffer);
+
+ return ret;
+}
+
+void
+ckcapi_rsa_pkcs_decrypt_cleanup(void* operation)
+{
+ /* Nothing to do */
+}
diff --git a/ckcapi-rsa.h b/ckcapi-rsa.h
new file mode 100644
index 0000000..4e00133
--- /dev/null
+++ b/ckcapi-rsa.h
@@ -0,0 +1,41 @@
+/*
+ * 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_RSA_H
+#define CKCAPI_RSA_H
+
+#include "ckcapi.h"
+
+CK_RV ckcapi_rsa_pkcs_sign_init (CkCapiObjectData* keydata, void** operation);
+
+CK_RV ckcapi_rsa_pkcs_sign_perform (CK_BYTE_PTR data, CK_ULONG data_len,
+ CK_BYTE_PTR signature, CK_ULONG_PTR signature_len,
+ void** operation);
+
+void ckcapi_rsa_pkcs_sign_cleanup (void* operation);
+
+CK_RV ckcapi_rsa_pkcs_decrypt_init (CkCapiObjectData* keydata, void** operation);
+
+CK_RV ckcapi_rsa_pkcs_decrypt_perform (CK_BYTE_PTR encdata, CK_ULONG n_encdata,
+ CK_BYTE_PTR result, CK_ULONG_PTR n_result,
+ void** operation);
+
+void ckcapi_rsa_pkcs_decrypt_cleanup (void* operation);
+
+#endif /* CKCAPI_RSA_H */
diff --git a/ckcapi-session.c b/ckcapi-session.c
index 46de60a..0745cb7 100644
--- a/ckcapi-session.c
+++ b/ckcapi-session.c
@@ -23,10 +23,20 @@
#include "ckcapi-builtin.h"
#include "ckcapi-cert.h"
#include "ckcapi-object.h"
+#include "ckcapi-rsa.h"
#include "ckcapi-session.h"
#include "ckcapi-token.h"
#include "ckcapi-trust.h"
+/* For operation_type in CkCapiSession */
+enum
+{
+ OPERATION_NONE,
+ OPERATION_FIND,
+ OPERATION_SIGN,
+ OPERATION_DECRYPT
+};
+
static CkCapiArray* all_sessions = NULL;
static void
@@ -721,3 +731,192 @@ ckcapi_session_find_final(CkCapiSession* sess)
}
+/* ----------------------------------------------------------------------------
+ * CRYPTO OPERATIONS
+ */
+
+typedef struct _CryptoContext
+{
+ CK_MECHANISM_TYPE mech_type;
+ CkCapiDestroyFunc mech_cleanup;
+ void* mech_data;
+}
+CryptoContext;
+
+void
+cleanup_crypto_operation(CkCapiSession* sess)
+{
+ CryptoContext* ctx;
+
+ if(sess->operation_data)
+ {
+ ctx = (CryptoContext*)sess->operation_data;
+ if(ctx->mech_cleanup)
+ (ctx->mech_cleanup)(ctx->mech_data);
+ free(ctx);
+ }
+
+ sess->operation_type = OPERATION_NONE;
+ sess->operation_data = NULL;
+ sess->operation_cancel = NULL;
+}
+
+CK_RV
+ckcapi_session_sign_init(CkCapiSession* sess, CK_MECHANISM_PTR mech,
+ CkCapiObjectData *objdata)
+{
+ CryptoContext* ctx;
+ CK_RV ret;
+
+ ASSERT(sess);
+ ASSERT(mech);
+ ASSERT(objdata);
+
+ if(sess->operation_type != OPERATION_NONE)
+ return CKR_OPERATION_ACTIVE;
+
+ ctx = calloc(1, sizeof(CryptoContext));
+ if(!ctx)
+ return CKR_HOST_MEMORY;
+
+ ctx->mech_type = mech->mechanism;
+
+ switch(mech->mechanism)
+ {
+ case CKM_RSA_PKCS:
+ ret = ckcapi_rsa_pkcs_sign_init(objdata, &ctx->mech_data);
+ ctx->mech_cleanup = ckcapi_rsa_pkcs_sign_cleanup;
+ default:
+ ret = CKR_MECHANISM_INVALID;
+ };
+
+ if(ret != CKR_OK)
+ {
+ free(ctx);
+ ASSERT(!sess->operation_data);
+ return ret;
+ }
+
+ sess->operation_type = OPERATION_SIGN;
+ sess->operation_data = ctx;
+ sess->operation_cancel = cleanup_crypto_operation;
+ return CKR_OK;
+}
+
+CK_RV
+ckcapi_session_sign(CkCapiSession* sess, CK_BYTE_PTR data, CK_ULONG n_data,
+ CK_BYTE_PTR signature, CK_ULONG_PTR n_signature)
+{
+ CryptoContext *ctx;
+ BOOL incomplete;
+ CK_RV ret;
+
+ ASSERT(sess);
+ ASSERT(data);
+ ASSERT(n_data);
+
+ if(sess->operation_type != OPERATION_SIGN)
+ return CKR_OPERATION_NOT_INITIALIZED;
+
+ ctx = (CryptoContext*)sess->operation_data;
+ switch(ctx->mech_type)
+ {
+ case CKM_RSA_PKCS:
+ ret = ckcapi_rsa_pkcs_sign_perform(data, n_data, signature, n_signature,
+ &ctx->mech_data);
+ break;
+
+ default:
+ ASSERT(FALSE);
+ ret = CKR_GENERAL_ERROR;
+ break;
+ }
+
+ /* Buffer calculation, we don't end operation */
+ incomplete = (ret == CKR_BUFFER_TOO_SMALL || (ret == CKR_OK && !signature));
+
+ if(!incomplete)
+ cleanup_crypto_operation(sess);
+
+ return ret;
+}
+
+CK_RV
+ckcapi_session_decrypt_init(CkCapiSession* sess, CK_MECHANISM_PTR mech,
+ CkCapiObjectData *objdata)
+{
+ CryptoContext* ctx;
+ CK_RV ret;
+
+ ASSERT(sess);
+ ASSERT(mech);
+ ASSERT(objdata);
+
+ if(sess->operation_type != OPERATION_NONE)
+ return CKR_OPERATION_ACTIVE;
+
+ ctx = calloc(1, sizeof(CryptoContext));
+ if(!ctx)
+ return CKR_HOST_MEMORY;
+
+ ctx->mech_type = mech->mechanism;
+
+ switch(mech->mechanism)
+ {
+ case CKM_RSA_PKCS:
+ ret = ckcapi_rsa_pkcs_decrypt_init(objdata, &ctx->mech_data);
+ ctx->mech_cleanup = ckcapi_rsa_pkcs_decrypt_cleanup;
+ default:
+ ret = CKR_MECHANISM_INVALID;
+ };
+
+ if(ret != CKR_OK)
+ {
+ free(ctx);
+ ASSERT(!sess->operation_data);
+ return ret;
+ }
+
+ sess->operation_type = OPERATION_DECRYPT;
+ sess->operation_data = ctx;
+ sess->operation_cancel = cleanup_crypto_operation;
+ return CKR_OK;
+}
+
+CK_RV
+ckcapi_session_decrypt(CkCapiSession* sess, CK_BYTE_PTR encdata, CK_ULONG n_encdata,
+ CK_BYTE_PTR result, CK_ULONG_PTR n_result)
+{
+ CryptoContext *ctx;
+ BOOL incomplete;
+ CK_RV ret;
+
+ ASSERT(sess);
+ ASSERT(encdata);
+ ASSERT(n_encdata);
+
+ if(sess->operation_type != OPERATION_DECRYPT)
+ return CKR_OPERATION_NOT_INITIALIZED;
+
+ ctx = (CryptoContext*)sess->operation_data;
+ switch(ctx->mech_type)
+ {
+ case CKM_RSA_PKCS:
+ ret = ckcapi_rsa_pkcs_decrypt_perform(encdata, n_encdata, result, n_result,
+ &ctx->mech_data);
+ break;
+
+ default:
+ ASSERT(FALSE);
+ ret = CKR_GENERAL_ERROR;
+ break;
+ }
+
+ /* Buffer calculation, we don't end operation */
+ incomplete = (ret == CKR_BUFFER_TOO_SMALL || (ret == CKR_OK && !result));
+
+ if(!incomplete)
+ cleanup_crypto_operation(sess);
+
+ return ret;
+}
diff --git a/ckcapi-session.h b/ckcapi-session.h
index 6007662..4fb68fa 100644
--- a/ckcapi-session.h
+++ b/ckcapi-session.h
@@ -22,14 +22,7 @@
#include "ckcapi.h"
-/* For operation_type in CkCapiSession */
-enum
-{
- OPERATION_NONE = 0,
- OPERATION_FIND = 1,
-};
-
-/* Callback to cancel a current operation */
+/* Callback to cleanup a current operation */
typedef void (*CkCapiSessionCancel) (struct _CkCapiSession* sess);
/* Represents an open session */
@@ -95,7 +88,25 @@ CK_RV ckcapi_session_find (CkCapiSession* sess,
CK_RV ckcapi_session_find_final (CkCapiSession* sess);
+/* Start a sign operation on a session */
+CK_RV ckcapi_session_sign_init (CkCapiSession* sess,
+ CK_MECHANISM_PTR mech,
+ CkCapiObjectData *objdata);
+
+/* Perform sign operation */
+CK_RV ckcapi_session_sign (CkCapiSession* sess,
+ CK_BYTE_PTR data, CK_ULONG n_data,
+ CK_BYTE_PTR sig, CK_ULONG_PTR n_sig);
+
+/* Start a decrypt operation on a session */
+CK_RV ckcapi_session_decrypt_init (CkCapiSession* sess,
+ CK_MECHANISM_PTR mech,
+ CkCapiObjectData *objdata);
+/* Perform decrypt operation */
+CK_RV ckcapi_session_decrypt (CkCapiSession* sess,
+ CK_BYTE_PTR encdata, CK_ULONG n_encdata,
+ CK_BYTE_PTR result, CK_ULONG_PTR n_result);
/* Get object data for an object */
CK_RV ckcapi_session_get_object_data (CkCapiSession* sess,
diff --git a/ckcapi.c b/ckcapi.c
index 75c133a..b032c13 100644
--- a/ckcapi.c
+++ b/ckcapi.c
@@ -138,28 +138,39 @@ ckcapi_winerr_to_ckr(DWORD werr)
}
CK_RV
-ckcapi_return_data(CK_ATTRIBUTE_PTR attr, CK_VOID_PTR src, DWORD slen)
+ckcapi_return_data_raw(CK_VOID_PTR output, CK_ULONG_PTR n_output,
+ CK_VOID_PTR input, CK_ULONG n_input)
{
+ ASSERT(n_output);
+ ASSERT(input);
+
/* Just asking for the length */
- if(!attr->pValue)
+ if(!output)
{
- attr->ulValueLen = slen;
+ *n_output = n_input;
return CKR_OK;
}
/* Buffer is too short */
- if(slen > attr->ulValueLen)
+ if(n_input > *n_output)
{
- attr->ulValueLen = slen;
+ *n_output = n_input;
return CKR_BUFFER_TOO_SMALL;
}
- attr->ulValueLen = slen;
- memcpy(attr->pValue, src, slen);
+ *n_output = n_input;
+ memcpy(output, input, n_input);
return CKR_OK;
}
CK_RV
+ckcapi_return_data(CK_ATTRIBUTE_PTR attr, CK_VOID_PTR input, DWORD n_input)
+{
+ return ckcapi_return_data_raw(attr->pValue, &(attr->ulValueLen),
+ input, n_input);
+}
+
+CK_RV
ckcapi_return_string(CK_ATTRIBUTE_PTR attr, WCHAR* string)
{
DWORD error;
@@ -866,7 +877,7 @@ CC_C_EncryptUpdate(CK_SESSION_HANDLE session, CK_BYTE_PTR part,
ENTER(C_EncryptUpdate);
PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
- /* TODO: See if we need to implement this */
+ /* RSA/DSA mechs don't support incremental crypto operations. */
RETURN(CKR_FUNCTION_NOT_SUPPORTED);
}
@@ -877,7 +888,7 @@ CC_C_EncryptFinal(CK_SESSION_HANDLE session, CK_BYTE_PTR last_encrypted_part,
ENTER(C_EncryptFinal);
PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
- /* TODO: See if we need to implement this */
+ /* RSA/DSA mechs don't support incremental crypto operations. */
RETURN(CKR_FUNCTION_NOT_SUPPORTED);
}
@@ -885,22 +896,49 @@ static CK_RV
CC_C_DecryptInit(CK_SESSION_HANDLE session, CK_MECHANISM_PTR mechanism,
CK_OBJECT_HANDLE key)
{
+ CkCapiObjectData* objdata;
+ CkCapiSession* sess;
+ CK_RV ret;
+
ENTER(C_DecryptInit);
PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
+ PREREQ(mechanism, CKR_ARGUMENTS_BAD);
+ PREREQ(key, CKR_ARGUMENTS_BAD);
- /* TODO: Implement this */
- RETURN(CKR_FUNCTION_NOT_SUPPORTED);
+ ret = ckcapi_session_get_lock_ref(session, 0, &sess);
+ if(ret == CKR_OK)
+ {
+ ret = ckcapi_session_get_object_data_for(sess, key, &objdata);
+ if(ret == CKR_OK)
+ ret = ckcapi_session_decrypt_init(sess, mechanism, objdata);
+
+ ckcapi_session_unref_unlock(sess);
+ }
+
+ RETURN(ret);
}
static CK_RV
CC_C_Decrypt(CK_SESSION_HANDLE session, CK_BYTE_PTR encrypted_data,
CK_ULONG encrypted_data_len, CK_BYTE_PTR data, CK_ULONG_PTR data_len)
{
+ CkCapiSession* sess;
+ CK_RV ret;
+
ENTER(C_Decrypt);
PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
+ PREREQ(encrypted_data, CKR_ARGUMENTS_BAD);
+ PREREQ(encrypted_data_len, CKR_ARGUMENTS_BAD);
- /* TODO: Implement this */
- RETURN(CKR_FUNCTION_NOT_SUPPORTED);
+ ret = ckcapi_session_get_lock_ref(session, 0, &sess);
+ if(ret == CKR_OK)
+ {
+ ret = ckcapi_session_decrypt(sess, encrypted_data, encrypted_data_len,
+ data, data_len);
+ ckcapi_session_unref_unlock(sess);
+ }
+
+ RETURN(ret);
}
static CK_RV
@@ -910,7 +948,7 @@ CC_C_DecryptUpdate(CK_SESSION_HANDLE session, CK_BYTE_PTR encrypted_part,
ENTER(C_DecryptUpdate);
PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
- /* TODO: Implement this */
+ /* RSA/DSA mechs don't support incremental crypto operations. */
RETURN(CKR_FUNCTION_NOT_SUPPORTED);
}
@@ -921,7 +959,7 @@ CC_C_DecryptFinal(CK_SESSION_HANDLE session, CK_BYTE_PTR pLastPart,
ENTER(C_DecryptFinal);
PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
- /* TODO: Implement this */
+ /* RSA/DSA mechs don't support incremental crypto operations. */
RETURN(CKR_FUNCTION_NOT_SUPPORTED);
}
@@ -931,7 +969,7 @@ CC_C_DigestInit(CK_SESSION_HANDLE session, CK_MECHANISM_PTR mechanism)
ENTER(C_DigestInit);
PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
- /* TODO: Implement this */
+ /* RSA/DSA mechs don't support digest. */
RETURN(CKR_FUNCTION_NOT_SUPPORTED);
}
@@ -942,7 +980,7 @@ CC_C_Digest(CK_SESSION_HANDLE session, CK_BYTE_PTR data, CK_ULONG data_len,
ENTER(C_Digest);
PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
- /* TODO: See if we need to implement this */
+ /* RSA/DSA mechs don't support digest. */
RETURN(CKR_FUNCTION_NOT_SUPPORTED);
}
@@ -952,7 +990,7 @@ CC_C_DigestUpdate(CK_SESSION_HANDLE session, CK_BYTE_PTR part, CK_ULONG part_len
ENTER(C_DigestUpdate);
PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
- /* TODO: See if we need to implement this */
+ /* RSA/DSA mechs don't support digest. */
RETURN(CKR_FUNCTION_NOT_SUPPORTED);
}
@@ -962,7 +1000,7 @@ CC_C_DigestKey(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE key)
ENTER(C_DigestKey);
PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
- /* TODO: See if we need to implement this */
+ /* RSA/DSA mechs don't support digest. */
RETURN(CKR_FUNCTION_NOT_SUPPORTED);
}
@@ -973,7 +1011,7 @@ CC_C_DigestFinal(CK_SESSION_HANDLE session, CK_BYTE_PTR digest,
ENTER(C_DigestFinal);
PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
- /* TODO: See if we need to implement this */
+ /* RSA/DSA mechs don't support digest. */
RETURN(CKR_FUNCTION_NOT_SUPPORTED);
}
@@ -981,22 +1019,48 @@ static CK_RV
CC_C_SignInit(CK_SESSION_HANDLE session, CK_MECHANISM_PTR mechanism,
CK_OBJECT_HANDLE key)
{
+ CkCapiObjectData* objdata;
+ CkCapiSession* sess;
+ CK_RV ret;
+
ENTER(C_SignInit);
PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
+ PREREQ(mechanism, CKR_ARGUMENTS_BAD);
+ PREREQ(key, CKR_ARGUMENTS_BAD);
- /* TODO: Implement this */
- RETURN(CKR_FUNCTION_NOT_SUPPORTED);
+ ret = ckcapi_session_get_lock_ref(session, 0, &sess);
+ if(ret == CKR_OK)
+ {
+ ret = ckcapi_session_get_object_data_for(sess, key, &objdata);
+ if(ret == CKR_OK)
+ ret = ckcapi_session_sign_init(sess, mechanism, objdata);
+
+ ckcapi_session_unref_unlock(sess);
+ }
+
+ RETURN(ret);
}
static CK_RV
CC_C_Sign(CK_SESSION_HANDLE session, CK_BYTE_PTR data, CK_ULONG data_len,
CK_BYTE_PTR signature, CK_ULONG_PTR signature_len)
{
+ CkCapiSession* sess;
+ CK_RV ret;
+
ENTER(C_Sign);
PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
+ PREREQ(data, CKR_ARGUMENTS_BAD);
+ PREREQ(data_len, CKR_ARGUMENTS_BAD);
- /* TODO: Implement this */
- RETURN(CKR_FUNCTION_NOT_SUPPORTED);
+ ret = ckcapi_session_get_lock_ref(session, 0, &sess);
+ if(ret == CKR_OK)
+ {
+ ret = ckcapi_session_sign(sess, data, data_len, signature, signature_len);
+ ckcapi_session_unref_unlock(sess);
+ }
+
+ RETURN(ret);
}
static CK_RV
@@ -1005,7 +1069,7 @@ CC_C_SignUpdate(CK_SESSION_HANDLE session, CK_BYTE_PTR part, CK_ULONG part_len)
ENTER(C_SignUpdate);
PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
- /* TODO: Implement this */
+ /* RSA/DSA mechs don't support incremental crypto operations. */
RETURN(CKR_FUNCTION_NOT_SUPPORTED);
}
@@ -1016,7 +1080,7 @@ CC_C_SignFinal(CK_SESSION_HANDLE session, CK_BYTE_PTR signature,
ENTER(C_SignFinal);
PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
- /* TODO: Implement this */
+ /* RSA/DSA mechs don't support incremental crypto operations. */
RETURN(CKR_FUNCTION_NOT_SUPPORTED);
}
@@ -1070,7 +1134,7 @@ CC_C_VerifyUpdate(CK_SESSION_HANDLE session, CK_BYTE_PTR part, CK_ULONG part_len
ENTER(C_VerifyUpdate);
PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
- /* TODO: See if we need to implement this */
+ /* RSA/DSA mechs don't support incremental crypto operations. */
RETURN(CKR_FUNCTION_NOT_SUPPORTED);
}
@@ -1081,7 +1145,7 @@ CC_C_VerifyFinal(CK_SESSION_HANDLE session, CK_BYTE_PTR signature,
ENTER(C_VerifyFinal);
PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
- /* TODO: See if we need to implement this */
+ /* RSA/DSA mechs don't support incremental crypto operations. */
RETURN(CKR_FUNCTION_NOT_SUPPORTED);
}
@@ -1115,7 +1179,7 @@ CC_C_DigestEncryptUpdate(CK_SESSION_HANDLE session, CK_BYTE_PTR part,
ENTER(C_DigestEncryptUpdate);
PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
- /* TODO: See if we need to implement this */
+ /* RSA/DSA mechs don't support incremental crypto operations. */
RETURN(CKR_FUNCTION_NOT_SUPPORTED);
}
@@ -1127,7 +1191,7 @@ CC_C_DecryptDigestUpdate(CK_SESSION_HANDLE session, CK_BYTE_PTR encrypted_part,
ENTER(C_DecryptDigestUpdate);
PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
- /* TODO: See if we need to implement this */
+ /* RSA/DSA mechs don't support incremental crypto operations. */
RETURN(CKR_FUNCTION_NOT_SUPPORTED);
}
@@ -1139,7 +1203,7 @@ CC_C_SignEncryptUpdate(CK_SESSION_HANDLE session, CK_BYTE_PTR part,
ENTER(C_SignEncryptUpdate);
PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
- /* TODO: See if we need to implement this */
+ /* RSA/DSA mechs don't support incremental crypto operations. */
RETURN(CKR_FUNCTION_NOT_SUPPORTED);
}
@@ -1151,7 +1215,7 @@ CC_C_DecryptVerifyUpdate(CK_SESSION_HANDLE session, CK_BYTE_PTR encrypted_part,
ENTER(C_DecryptVerifyUpdate);
PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED);
- /* TODO: See if we need to implement this */
+ /* RSA/DSA mechs don't support incremental crypto operations. */
RETURN(CKR_FUNCTION_NOT_SUPPORTED);
}
diff --git a/ckcapi.h b/ckcapi.h
index 18f304f..54929bc 100644
--- a/ckcapi.h
+++ b/ckcapi.h
@@ -91,6 +91,9 @@ CK_RV ckcapi_winerr_to_ckr (DWORD werr);
CK_RV ckcapi_return_data (CK_ATTRIBUTE_PTR attr,
CK_VOID_PTR src, DWORD slen);
+CK_RV ckcapi_return_data_raw (CK_VOID_PTR output, CK_ULONG_PTR n_output,
+ CK_VOID_PTR input, CK_ULONG n_input);
+
/*
* This stores a string in the output buffer with appropriate
* PKCS#11 codes when the buffer is too short, or the caller
@@ -107,6 +110,8 @@ CK_RV ckcapi_return_reversed_data (CK_ATTRIBUTE_PTR attr,
/* ------------------------------------------------------------------ */
+typedef void (*CkCapiDestroyFunc)(void* data);
+
#ifndef ASSERT
#include "assert.h"
#define ASSERT assert
diff --git a/ckcapi.vcproj b/ckcapi.vcproj
index 5abc307..8ca8b36 100644
--- a/ckcapi.vcproj
+++ b/ckcapi.vcproj
@@ -252,6 +252,10 @@
</FileConfiguration>
</File>
<File
+ RelativePath=".\ckcapi-der.c"
+ >
+ </File>
+ <File
RelativePath=".\ckcapi-key.c"
>
</File>
@@ -276,6 +280,10 @@
</FileConfiguration>
</File>
<File
+ RelativePath=".\ckcapi-rsa.c"
+ >
+ </File>
+ <File
RelativePath="ckcapi-session.c"
>
<FileConfiguration
@@ -385,6 +393,10 @@
>
</File>
<File
+ RelativePath=".\ckcapi-der.h"
+ >
+ </File>
+ <File
RelativePath=".\ckcapi-key.h"
>
</File>
@@ -393,6 +405,10 @@
>
</File>
<File
+ RelativePath=".\ckcapi-rsa.h"
+ >
+ </File>
+ <File
RelativePath=".\ckcapi-session.h"
>
</File>