summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorStef Walter <stef@memberwebs.com>2008-12-05 20:23:01 +0000
committerStef Walter <stef@memberwebs.com>2008-12-05 20:23:01 +0000
commit9bf245ea2afb75c4180d7fac707bb0c1bcb6b17d (patch)
treef02ab06675059a887c53ebc0507e6d13a70fabc5 /src
parentd4c964b8c29e931e7561ac05c7a07445e2b3a26c (diff)
Implement RSA encrypt and decrypt.
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am5
-rw-r--r--src/check.c11
-rw-r--r--src/key.c78
-rw-r--r--src/object.c48
-rw-r--r--src/p11-tests.c1
-rw-r--r--src/p11-tests.h38
-rw-r--r--src/rsa-pkcs.c250
-rw-r--r--src/slot.c20
-rw-r--r--src/test-data.c70
9 files changed, 518 insertions, 3 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 0a725c1..6e51a6f 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -6,10 +6,13 @@ p11_tests_LDADD = -ldl -lpthread
p11_tests_SOURCES = \
check.c \
config.c \
+ key.c \
module.c \
msg.c \
object.c \
p11-tests.c \
+ rsa-pkcs.c \
session.c \
- slot.c
+ slot.c \
+ test-data.c
diff --git a/src/check.c b/src/check.c
index 01b19fb..334a9e7 100644
--- a/src/check.c
+++ b/src/check.c
@@ -4,6 +4,17 @@
#include "p11-tests.h"
#include <ctype.h>
+#include <stdarg.h>
+
+int
+p11t_check_fail(const char *message, ...)
+{
+ va_list va;
+ va_start(va, message);
+ p11t_msg_va(message, va);
+ va_end(va);
+ return 0;
+}
int
p11t_check_returns(const char *message, CK_RV have, CK_RV want)
diff --git a/src/key.c b/src/key.c
new file mode 100644
index 0000000..f8b79ae
--- /dev/null
+++ b/src/key.c
@@ -0,0 +1,78 @@
+
+#include "config.h"
+
+#include "p11-tests.h"
+
+CK_OBJECT_HANDLE
+find_related_object(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE key, CK_OBJECT_CLASS klass)
+{
+ CK_BYTE id[4096];
+ CK_ATTRIBUTE attrs[2];
+
+ attrs[0].type = CKA_ID;
+ attrs[0].pValue = id;
+ attrs[0].ulValueLen = sizeof(id);
+
+ if(!p11t_object_get(session, key, attrs, 1))
+ return CK_INVALID;
+
+ attrs[1].type = CKA_CLASS;
+ attrs[1].ulValueLen = sizeof(klass);
+ attrs[1].pValue = &klass;
+
+ return p11t_object_find_one(session, attrs, 2);
+}
+
+CK_OBJECT_HANDLE
+p11t_key_get_public(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE key)
+{
+ return find_related_object(session, key, CKO_PUBLIC_KEY);
+}
+
+CK_OBJECT_HANDLE
+p11t_key_get_private(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE key)
+{
+ return find_related_object(session, key, CKO_PRIVATE_KEY);
+}
+
+RSA*
+p11t_key_export_public_rsa(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE key)
+{
+ CK_ATTRIBUTE attrs[3];
+ CK_BYTE modulus[4096];
+ CK_BYTE public_exponent[4096];
+ CK_ULONG modulus_bits;
+ RSA *rsa;
+
+ attrs[0].type = CKA_MODULUS;
+ attrs[0].ulValueLen = sizeof(modulus);
+ attrs[0].pValue = modulus;
+
+ attrs[1].type = CKA_MODULUS_BITS;
+ attrs[1].ulValueLen = sizeof(modulus_bits);
+ attrs[1].pValue = &modulus_bits;
+
+ attrs[2].type = CKA_PUBLIC_EXPONENT;
+ attrs[2].ulValueLen = sizeof(public_exponent);
+ attrs[2].pValue = public_exponent;
+
+ if(!p11t_object_get(session, key, attrs, 3))
+ return NULL;
+
+ if(attrs[0].ulValueLen == CK_INVALID ||
+ attrs[2].ulValueLen == CK_INVALID)
+ return NULL;
+
+ rsa = RSA_new();
+ rsa->n = BN_bin2bn(modulus, attrs[0].ulValueLen, NULL);
+ rsa->e = BN_bin2bn(public_exponent, attrs[2].ulValueLen, NULL);
+ assert(rsa && rsa->n && rsa->e);
+
+ if(attrs[1].ulValueLen != CK_INVALID)
+ {
+ assert(RSA_size(rsa) == modulus_bits / 8);
+ }
+
+ return rsa;
+}
+
diff --git a/src/object.c b/src/object.c
index 87f89e2..fe4e801 100644
--- a/src/object.c
+++ b/src/object.c
@@ -364,7 +364,6 @@ p11t_object_find(CK_SESSION_HANDLE session, CK_ATTRIBUTE_PTR attrs,
{
CK_OBJECT_HANDLE_PTR objects;
CK_ATTRIBUTE dummy_attr;
- CK_ULONG count;
assert(p11t_module_funcs);
@@ -387,7 +386,7 @@ p11t_object_find(CK_SESSION_HANDLE session, CK_ATTRIBUTE_PTR attrs,
return NULL;
}
- if(!count)
+ if(!*n_objects)
{
free(objects);
return NULL;
@@ -396,3 +395,48 @@ p11t_object_find(CK_SESSION_HANDLE session, CK_ATTRIBUTE_PTR attrs,
return objects;
}
+CK_OBJECT_HANDLE
+p11t_object_find_one(CK_SESSION_HANDLE session, CK_ATTRIBUTE_PTR attrs,
+ CK_ULONG n_attrs)
+{
+ CK_OBJECT_HANDLE object;
+ CK_ULONG count;
+
+ assert(p11t_module_funcs);
+
+ if((p11t_module_funcs->C_FindObjectsInit)(session, attrs, n_attrs) != CKR_OK)
+ return CK_INVALID;
+
+ if((p11t_module_funcs->C_FindObjects)(session, &object, 1, &count) != CKR_OK)
+ return CK_INVALID;
+
+ if(count != 1)
+ return CK_INVALID;
+
+ return object;
+}
+
+
+int
+p11t_object_get(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE object,
+ CK_ATTRIBUTE_PTR attrs, CK_ULONG count)
+{
+ CK_RV rv;
+
+ assert(p11t_module_funcs);
+
+ if(!count)
+ return 1;
+
+ rv = (p11t_module_funcs->C_GetAttributeValue)(session, object, attrs, count);
+ switch(rv)
+ {
+ case CKR_OK:
+ case CKR_BUFFER_TOO_SMALL:
+ case CKR_ATTRIBUTE_TYPE_INVALID:
+ case CKR_ATTRIBUTE_SENSITIVE:
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/src/p11-tests.c b/src/p11-tests.c
index 689dba4..58d547a 100644
--- a/src/p11-tests.c
+++ b/src/p11-tests.c
@@ -54,6 +54,7 @@ main(int argc, char* argv[])
p11t_slot_tests();
p11t_session_tests();
p11t_object_tests();
+ p11t_rsa_tests();
/* Remaining module tests */
p11t_module_finalize();
diff --git a/src/p11-tests.h b/src/p11-tests.h
index b3ddc1e..c4a2e25 100644
--- a/src/p11-tests.h
+++ b/src/p11-tests.h
@@ -6,6 +6,8 @@
#include <assert.h>
#include <stdarg.h>
+#include <openssl/rsa.h>
+
#define CK_INVALID ((CK_ULONG)-1)
extern int p11t_test_unexpected;
@@ -29,6 +31,8 @@ void p11t_msg_prefix(const char *prefix);
* check.c
*/
+int p11t_check_fail(const char *message, ...);
+
int p11t_check_returns(const char *message, CK_RV have, CK_RV want);
#define p11t_check_padded(msg, padded) \
@@ -56,6 +60,16 @@ void p11t_config_parse(const char* filename);
void p11t_config_cleanup(void);
/* -------------------------------------------------------------------
+ * key.c
+ */
+
+CK_OBJECT_HANDLE p11t_key_get_public(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE key);
+
+CK_OBJECT_HANDLE p11t_key_get_private(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE key);
+
+RSA* p11t_key_export_public_rsa(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE key);
+
+/* -------------------------------------------------------------------
* module.c
*/
@@ -76,9 +90,21 @@ void p11t_module_finalize(void);
CK_OBJECT_HANDLE_PTR p11t_object_find(CK_SESSION_HANDLE session, CK_ATTRIBUTE_PTR attrs,
CK_ULONG n_attrs, CK_ULONG_PTR n_objects);
+int p11t_object_get(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE object,
+ CK_ATTRIBUTE_PTR attrs, CK_ULONG count);
+
+CK_OBJECT_HANDLE p11t_object_find_one(CK_SESSION_HANDLE session, CK_ATTRIBUTE_PTR attrs,
+ CK_ULONG n_attrs);
+
void p11t_object_tests(void);
/* -------------------------------------------------------------------
+ * rsa.c
+ */
+
+void p11t_rsa_tests(void);
+
+/* -------------------------------------------------------------------
* session.c
*/
@@ -104,5 +130,17 @@ CK_SLOT_ID p11t_slot_get_id(int index);
CK_SLOT_INFO_PTR p11t_slot_get_info(CK_SLOT_ID slot);
CK_TOKEN_INFO_PTR p11t_slot_get_token_info(CK_SLOT_ID slot);
+typedef void (*P11tSlotMechCallback)(CK_SLOT_ID slot, CK_MECHANISM_TYPE mech_type,
+ CK_MECHANISM_INFO_PTR mech_info);
+
+void p11t_slot_for_each_mech(CK_MECHANISM_TYPE mech_type, P11tSlotMechCallback callback);
+
+/* ------------------------------------------------------------------
+ * test-data.c
+ */
+
+extern const CK_BYTE p11t_test_data[];
+extern const CK_ULONG p11t_test_data_size;
+extern const CK_ULONG p11t_test_data_bits;
#endif /* P11TESTST_H_ */
diff --git a/src/rsa-pkcs.c b/src/rsa-pkcs.c
new file mode 100644
index 0000000..e97a3b0
--- /dev/null
+++ b/src/rsa-pkcs.c
@@ -0,0 +1,250 @@
+
+#include "config.h"
+
+#include "p11-tests.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+void
+test_rsa_decrypt(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE key,
+ CK_MECHANISM_TYPE mech_type, RSA* rsa)
+{
+ CK_BYTE encrypted[p11t_test_data_size];
+ CK_BYTE decrypted[p11t_test_data_size];
+ CK_MECHANISM mech;
+ const CK_BYTE* data;
+ CK_ULONG n_data, n_decrypted;
+ int size, n_encrypted;
+ CK_RV rv;
+
+ /** C_Decrypt */
+
+ data = p11t_test_data;
+ n_data = p11t_test_data_size;
+
+ size = RSA_size(rsa);
+ assert(size);
+ assert(size < sizeof(encrypted));
+ assert(size < sizeof(decrypted));
+ assert(size < n_data);
+
+ switch(mech_type)
+ {
+ case CKM_RSA_PKCS:
+ /** - CKM_RSA_PKCS */
+ n_data = size - 11;
+ n_encrypted = RSA_public_encrypt(n_data, data, encrypted, rsa, RSA_PKCS1_PADDING);
+ assert(n_encrypted == size);
+ break;
+ case CKM_RSA_X_509:
+ /** - CKM_RSA_X_509 */
+ n_data = size;
+ n_encrypted = RSA_public_encrypt(n_data, data, encrypted, rsa, RSA_NO_PADDING);
+ assert(n_encrypted == size);
+ break;
+ default:
+ return;
+ };
+
+ mech.mechanism = mech_type;
+ mech.pParameter = NULL;
+ mech.ulParameterLen = 0;
+
+ rv = (p11t_module_funcs->C_DecryptInit)(session, &mech, key);
+ p11t_check_returns("C_DecryptInit: rsa", rv, CKR_OK);
+
+ n_decrypted = sizeof(decrypted);
+ rv = (p11t_module_funcs->C_Decrypt)(session, encrypted, n_encrypted, decrypted, &n_decrypted);
+ p11t_check_returns("C_Decrypt: rsa", rv, CKR_OK);
+
+ if(n_decrypted != n_data)
+ p11t_check_fail("C_Decrypt: rsa decrypt failed, wrong length");
+ if(memcmp(data, decrypted, n_data) != 0)
+ p11t_check_fail("C_Decrypt: rsa decrypt failed, bad data");
+}
+
+void
+test_rsa_encrypt(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE key,
+ CK_MECHANISM_TYPE mech_type, RSA* rsa)
+{
+ CK_BYTE encrypted[p11t_test_data_size];
+ CK_BYTE check[p11t_test_data_size];
+ CK_OBJECT_HANDLE privkey;
+ CK_MECHANISM mech;
+ const CK_BYTE* data;
+ CK_ULONG n_data, n_check, n_encrypted;
+ int size;
+ CK_RV rv;
+
+ data = p11t_test_data;
+ n_data = p11t_test_data_size;
+
+ /** C_Encrypt */
+
+ size = RSA_size(rsa);
+ assert(size);
+ assert(size < sizeof(encrypted));
+ assert(size < sizeof(check));
+ assert(size < n_data);
+
+ switch(mech_type)
+ {
+ case CKM_RSA_PKCS:
+ /** - CKM_RSA_PKCS */
+ n_data = size - 11;
+ break;
+ case CKM_RSA_X_509:
+ /** - CKM_RSA_X_509 */
+ n_data = size;
+ break;
+ default:
+ return;
+ };
+
+ mech.mechanism = mech_type;
+ mech.pParameter = NULL;
+ mech.ulParameterLen = 0;
+
+ /* Now ask PKCS#11 to decrypt it */
+ rv = (p11t_module_funcs->C_EncryptInit)(session, &mech, key);
+ p11t_check_returns("C_EncryptInit: rsa", rv, CKR_OK);
+
+ n_encrypted = sizeof(encrypted);
+ rv = (p11t_module_funcs->C_Encrypt)(session, (CK_BYTE*)data, n_data, encrypted, &n_encrypted);
+ p11t_check_returns("C_Encrypt: rsa", rv, CKR_OK);
+
+ if(size != n_encrypted)
+ p11t_check_fail("C_Encrypt: rsa encrypt failed, wrong length");
+
+ /* We need to find a private key in order to validate */
+ privkey = p11t_key_get_private(session, key);
+ if(privkey == CK_INVALID)
+ return;
+
+ rv = (p11t_module_funcs->C_DecryptInit)(session, &mech, privkey);
+ p11t_check_returns("C_DecryptInit: rsa validate", rv, CKR_OK);
+
+ n_check = sizeof(check);
+ rv = (p11t_module_funcs->C_Decrypt)(session, encrypted, n_encrypted, check, &n_check);
+ p11t_check_returns("C_Decrypt: rsa validate", rv, CKR_OK);
+
+ if(n_check != n_data)
+ p11t_check_fail("C_Decrypt: rsa validate failed, wrong length");
+ if(memcmp(data, check, n_data) != 0)
+ p11t_check_fail("C_Decrypt: rsa validate failed, bad data");
+}
+
+void
+test_rsa_private_key(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE key,
+ CK_MECHANISM_TYPE mech_type)
+{
+ CK_ATTRIBUTE attrs[2];
+ CK_BBOOL can_decrypt = 0;
+ CK_BBOOL can_sign = 0;
+ RSA *rsa;
+
+ attrs[0].type = CKA_DECRYPT;
+ attrs[0].ulValueLen = sizeof(CK_BBOOL);
+ attrs[0].pValue = &can_decrypt;
+ attrs[1].type = CKA_SIGN;
+ attrs[1].ulValueLen = sizeof(CK_BBOOL);
+ attrs[1].pValue = &can_sign;
+
+ if(!p11t_object_get(session, key, attrs, 2))
+ return;
+
+ rsa = p11t_key_export_public_rsa(session, key);
+ if(!rsa)
+ return;
+
+ if(can_decrypt)
+ test_rsa_decrypt(session, key, mech_type, rsa);
+
+ RSA_free(rsa);
+}
+
+void
+test_rsa_public_key(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE key,
+ CK_MECHANISM_TYPE mech_type)
+{
+ CK_ATTRIBUTE attrs[2];
+ CK_BBOOL can_encrypt = 0;
+ CK_BBOOL can_verify = 0;
+ RSA *rsa;
+
+ attrs[0].type = CKA_ENCRYPT;
+ attrs[0].ulValueLen = sizeof(CK_BBOOL);
+ attrs[0].pValue = &can_encrypt;
+ attrs[1].type = CKA_VERIFY;
+ attrs[1].ulValueLen = sizeof(CK_BBOOL);
+ attrs[1].pValue = &can_verify;
+
+ if(!p11t_object_get(session, key, attrs, 2))
+ return;
+
+ rsa = p11t_key_export_public_rsa(session, key);
+ if(!rsa)
+ return;
+
+ if(can_encrypt)
+ test_rsa_encrypt(session, key, mech_type, rsa);
+
+ RSA_free(rsa);
+}
+
+void
+test_rsa_pkcs(CK_SLOT_ID slot, CK_MECHANISM_TYPE mech, CK_MECHANISM_INFO_PTR info)
+{
+ CK_SESSION_HANDLE session;
+ CK_ATTRIBUTE attrs[2];
+ CK_ATTRIBUTE attr;
+ CK_OBJECT_CLASS klass;
+ CK_KEY_TYPE key_type = CKK_RSA;
+ CK_BBOOL token = CK_TRUE;
+ CK_OBJECT_HANDLE_PTR keys;
+ CK_ULONG i, n_keys;
+
+ /* Find all keys that match this mechanism */
+ attrs[0].type = CKA_TOKEN;
+ attrs[0].ulValueLen = sizeof(token);
+ attrs[0].pValue = &token;
+ attrs[1].type = CKA_KEY_TYPE;
+ attrs[1].ulValueLen = sizeof(key_type);
+ attrs[1].pValue = &key_type;
+
+ session = p11t_session_open(slot, 0);
+ if(session == CK_INVALID)
+ return;
+
+ if(!p11t_session_login(session))
+ return;
+
+ keys = p11t_object_find(session, attrs, 2, &n_keys);
+ if(!keys)
+ return;
+
+ for(i = 0; i < n_keys; ++i)
+ {
+ attr.type = CKA_CLASS;
+ attr.ulValueLen = sizeof(klass);
+ attr.pValue = &klass;
+
+ if(p11t_object_get(session, keys[i], &attr, 1))
+ {
+ if(klass == CKO_PRIVATE_KEY)
+ test_rsa_private_key(session, keys[i], mech);
+ else if(klass == CKO_PUBLIC_KEY)
+ test_rsa_public_key(session, keys[i], mech);
+ }
+ }
+
+ free(keys);
+}
+
+void
+p11t_rsa_tests(void)
+{
+ p11t_slot_for_each_mech(CKM_RSA_PKCS, test_rsa_pkcs);
+}
diff --git a/src/slot.c b/src/slot.c
index e10bb4d..c9139d6 100644
--- a/src/slot.c
+++ b/src/slot.c
@@ -15,6 +15,7 @@ static CK_SLOT_INFO_PTR slot_info = NULL;
static CK_TOKEN_INFO_PTR slot_token_info = NULL;
static CK_ULONG *slot_mech_count;
+static CK_MECHANISM_TYPE_PTR *slot_mech_type;
static CK_MECHANISM_INFO_PTR *slot_mech_info;
/* ----------------------------------------------------------------------------------
@@ -288,6 +289,8 @@ test_slot_mechanisms(void)
slot_mech_info = calloc(p11t_slot_count, sizeof(CK_MECHANISM_INFO_PTR));
assert(slot_mech_info);
+ slot_mech_type = calloc(p11t_slot_count, sizeof(CK_MECHANISM_TYPE_PTR));
+ assert(slot_mech_type);
for(i = 0; i < p11t_slot_count; ++i)
{
@@ -377,6 +380,7 @@ test_slot_mechanisms(void)
slot_mech_info[i] = mech_info;
}
+ slot_mech_type[i] = mech_list;
slot_mech_count[i] = mech_count;
}
}
@@ -446,3 +450,19 @@ p11t_slot_get_token_info(CK_SLOT_ID slot)
return NULL;
}
+
+void
+p11t_slot_for_each_mech(CK_MECHANISM_TYPE mech_type,
+ P11tSlotMechCallback callback)
+{
+ CK_ULONG i, j;
+
+ for(i = 0; i < p11t_slot_count; ++i)
+ {
+ for(j = 0; j < slot_mech_count[i]; ++j)
+ {
+ if(mech_type == CK_INVALID || slot_mech_type[i][j] == mech_type)
+ (callback)(slot_ids[i], slot_mech_type[i][j], &slot_mech_info[i][j]);
+ }
+ }
+}
diff --git a/src/test-data.c b/src/test-data.c
new file mode 100644
index 0000000..6d94e74
--- /dev/null
+++ b/src/test-data.c
@@ -0,0 +1,70 @@
+
+#include "config.h"
+
+#include "p11-tests.h"
+
+const CK_BYTE p11t_test_data[] =
+ "0123456789ABCD 1" \
+ "0123456789ABCD 2" \
+ "0123456789ABCD 3" \
+ "0123456789ABCD 4" \
+ "0123456789ABCD 5" \
+ "0123456789ABCD 6" \
+ "0123456789ABCD 7" \
+ "0123456789ABCD 8" \
+ "0123456789ABCD 9" \
+ "0123456789ABCD A" \
+ "0123456789ABCD B" \
+ "0123456789ABCD C" \
+ "0123456789ABCD D" \
+ "0123456789ABCD E" \
+ "0123456789ABCD F" \
+ "0123456789ABCD 1" \
+ "0123456789ABCD 2" \
+ "0123456789ABCD 3" \
+ "0123456789ABCD 4" \
+ "0123456789ABCD 5" \
+ "0123456789ABCD 6" \
+ "0123456789ABCD 7" \
+ "0123456789ABCD 8" \
+ "0123456789ABCD 9" \
+ "0123456789ABCD A" \
+ "0123456789ABCD B" \
+ "0123456789ABCD C" \
+ "0123456789ABCD D" \
+ "0123456789ABCD E" \
+ "0123456789ABCD F" \
+ "0123456789ABCD 1" \
+ "0123456789ABCD 2" \
+ "0123456789ABCD 3" \
+ "0123456789ABCD 4" \
+ "0123456789ABCD 5" \
+ "0123456789ABCD 6" \
+ "0123456789ABCD 7" \
+ "0123456789ABCD 8" \
+ "0123456789ABCD 9" \
+ "0123456789ABCD A" \
+ "0123456789ABCD B" \
+ "0123456789ABCD C" \
+ "0123456789ABCD D" \
+ "0123456789ABCD E" \
+ "0123456789ABCD F" \
+ "0123456789ABCD 1" \
+ "0123456789ABCD 2" \
+ "0123456789ABCD 3" \
+ "0123456789ABCD 4" \
+ "0123456789ABCD 5" \
+ "0123456789ABCD 6" \
+ "0123456789ABCD 7" \
+ "0123456789ABCD 8" \
+ "0123456789ABCD 9" \
+ "0123456789ABCD A" \
+ "0123456789ABCD B" \
+ "0123456789ABCD C" \
+ "0123456789ABCD D" \
+ "0123456789ABCD E" \
+ "0123456789ABCD F";
+
+const CK_ULONG p11t_test_data_size = 1024;
+const CK_ULONG p11t_test_data_bits = 1024 * 8;
+