summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStef Walter <stef@memberwebs.com>2008-12-09 00:08:01 +0000
committerStef Walter <stef@memberwebs.com>2008-12-09 00:08:01 +0000
commitc9099836f080c8bb821264050f5f6d59a1ceddba (patch)
tree956a3eabfebafb441ce21895227aa969e935c0c1
parent3f036e4311b4742017f8e3cf802a1b80944a2b59 (diff)
Add tests for X509 certificates.
-rw-r--r--src/Makefile.am1
-rw-r--r--src/certificate.c355
-rw-r--r--src/check.c33
-rw-r--r--src/msg.c14
-rw-r--r--src/p11-tests.c7
-rw-r--r--src/p11-tests.h39
-rw-r--r--src/rsa.c1
7 files changed, 434 insertions, 16 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 5139896..33abf3f 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -4,6 +4,7 @@ bin_PROGRAMS = p11-tests
p11_tests_LDADD = -ldl -lpthread
p11_tests_SOURCES = \
+ certificate.c \
check.c \
config.c \
key.c \
diff --git a/src/certificate.c b/src/certificate.c
new file mode 100644
index 0000000..ce4cac3
--- /dev/null
+++ b/src/certificate.c
@@ -0,0 +1,355 @@
+
+#include "p11-tests.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <openssl/x509.h>
+
+/* ----------------------------------------------------------------------------------
+ * TESTS
+ */
+
+static const char*
+test_x509_name(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE object,
+ CK_ATTRIBUTE_TYPE attr_type, const char *attr_name,
+ X509_NAME* compare)
+{
+ CK_BYTE_PTR ptr, encoded;
+ CK_ATTRIBUTE attr;
+ X509_NAME* name;
+ CK_RV rv;
+ int len;
+
+ /*
+ * We return any messages, so this function can be called for
+ * different X509 dns.
+ */
+
+ attr.type = attr_type;
+ attr.pValue = NULL;
+ attr.ulValueLen = 0;
+ rv = (p11t_module_funcs->C_GetAttributeValue)(session, object, &attr, 1);
+ if(rv != CKR_OK)
+ return p11t_msg_rv(rv);
+
+ attr.pValue = malloc(attr.ulValueLen);
+ assert(attr.pValue);
+
+ rv = (p11t_module_funcs->C_GetAttributeValue)(session, object, &attr, 1);
+ if(rv != CKR_OK)
+ return p11t_msg_rv(rv);
+
+ /* Let openssl parse it */
+ ptr = attr.pValue;
+ name = d2i_X509_NAME(NULL, (const unsigned char**)&ptr, attr.ulValueLen);
+ if(name == NULL)
+ return p11t_msg_openssl();
+ if(ptr - (CK_BYTE_PTR)attr.pValue != attr.ulValueLen)
+ return "Extra trailing bytes";
+
+ /* Serialize the compare one */
+ len = i2d_X509_NAME(compare, NULL);
+ assert(len >= 0);
+ encoded = malloc(len);
+ assert(encoded);
+ ptr = encoded;
+ len = i2d_X509_NAME(compare, &ptr);
+ assert(len >= 0);
+
+ if(len != attr.ulValueLen || memcmp(encoded, attr.pValue, len) != 0)
+ return "Encoding of the DN didn't match what was in certificate";
+
+ free(attr.pValue);
+ free(encoded);
+
+ X509_NAME_free(name);
+
+ return NULL;
+}
+
+static int
+test_x509_cross_search(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE object,
+ CK_ATTRIBUTE_TYPE one, CK_ATTRIBUTE_TYPE two,
+ const char *description)
+{
+ CK_OBJECT_HANDLE_PTR objects;
+ CK_ULONG n_objects;
+ CK_ATTRIBUTE attrs[2];
+ CK_ULONG i, n_attrs = 0;
+ CK_BBOOL success = CK_FALSE;
+ CK_RV rv;
+
+ P11T_SECTION("CKC_X_509");
+
+ if(one != CK_INVALID)
+ {
+ attrs[n_attrs].type = one;
+ attrs[n_attrs].pValue = NULL;
+ attrs[n_attrs].ulValueLen = 0;
+ ++n_attrs;
+ }
+
+ if(two != CK_INVALID)
+ {
+ attrs[n_attrs].type = two;
+ attrs[n_attrs].pValue = NULL;
+ attrs[n_attrs].ulValueLen = 0;
+ ++n_attrs;
+ }
+
+ rv = (p11t_module_funcs->C_GetAttributeValue)(session, object, attrs, n_attrs);
+ P11T_CHECK_RV("Cross find certificates by attributes", rv, CKR_OK);
+
+ for(i = 0; i < n_attrs; ++i)
+ {
+ attrs[i].pValue = malloc(attrs[i].ulValueLen);
+ assert(attrs[i].pValue);
+ }
+
+ rv = (p11t_module_funcs->C_GetAttributeValue)(session, object, attrs, n_attrs);
+ P11T_CHECK_RV("Cross find certificates by attributes", rv, CKR_OK);
+
+ /* Now find all the objects with the same */
+ objects = p11t_object_find(session, attrs, n_attrs, &n_objects);
+ for(i = 0; objects && i < n_objects; ++i)
+ {
+ if(objects[i] == object)
+ {
+ success = CK_TRUE;
+ break;
+ }
+ }
+
+ for(i = 0; i < n_attrs; ++i)
+ free(attrs[i].pValue);
+
+ free(objects);
+
+ if(!success)
+ {
+ p11t_check_fail("Couldn't find certificates by attributes %s", description);
+ return STOP;
+ }
+
+ return CONTINUE;
+}
+
+static int
+test_x509_certificate(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE object)
+{
+ CK_BYTE check[4096];
+ CK_BYTE buffer[4096];
+ CK_ATTRIBUTE attr;
+ CK_BYTE_PTR der_value;
+ CK_BYTE_PTR ptr;
+ CK_ULONG n_der_value;
+ CK_ULONG java_midp;
+ const char* msg;
+ X509* cert;
+ CK_RV rv;
+ int len;
+
+ P11T_SECTION("CKC_X_509");
+
+ /* Get the certificate DER */
+ attr.type = CKA_VALUE;
+ attr.ulValueLen = 0;
+ attr.pValue = NULL;
+ rv = (p11t_module_funcs->C_GetAttributeValue)(session, object, &attr, 1);
+ P11T_CHECK_RV("CKA_VALUE", rv, CKR_OK);
+ attr.pValue = der_value = malloc(attr.ulValueLen);
+ assert(der_value);
+ rv = (p11t_module_funcs->C_GetAttributeValue)(session, object, &attr, 1);
+ P11T_CHECK_RV("CKA_VALUE", rv, CKR_OK);
+ n_der_value = attr.ulValueLen;
+
+ /* Have OpenSSL parse it */
+ ptr = der_value;
+ cert = d2i_X509(NULL, (const unsigned char**)&ptr, n_der_value);
+ if(cert == NULL)
+ P11T_CHECK_FAIL_MSG("CKA_VALUE", p11t_msg_openssl());
+ if(ptr - der_value != n_der_value)
+ P11T_CHECK_FAIL_MSG("CKA_VALUE", "Extra trailing bytes");
+
+
+ /* Cross check the certificate with the CKA_CHECK_VALUE */
+ if(p11t_test_unexpected)
+ {
+ attr.type = CKA_CHECK_VALUE;
+ attr.pValue = buffer;
+ attr.ulValueLen = sizeof(buffer);
+ rv = (p11t_module_funcs->C_GetAttributeValue)(session, object, &attr, 1);
+ P11T_CHECK_RV("CKA_CHECK_VALUE", rv, CKR_OK);
+ SHA1(der_value, n_der_value, check);
+ if(memcmp(check, buffer, 3) != 0)
+ P11T_CHECK_FAIL_MSG("CKA_CHECK_VALUE", "not equal to first 3 bytes of SHA1 hash of CKA_VALUE");
+ }
+
+ /* CKA_SUBJECT */
+ msg = test_x509_name(session, object, CKA_SUBJECT, "CKA_SUBJECT", cert->cert_info->subject);
+ if(msg != NULL)
+ P11T_CHECK_FAIL_MSG("CKA_SUBJECT", msg);
+
+ /* CKA_ISSUER */
+ msg = test_x509_name(session, object, CKA_ISSUER, "CKA_ISSUER", cert->cert_info->issuer);
+ if(msg != NULL)
+ P11T_CHECK_FAIL_MSG("CKA_ISSUER", msg);
+
+ /* CKA_SERIAL_NUMBER */
+ attr.type = CKA_SERIAL_NUMBER;
+ attr.pValue = check;
+ attr.ulValueLen = sizeof(check);
+ rv = (p11t_module_funcs->C_GetAttributeValue)(session, object, &attr, 1);
+ P11T_CHECK_RV("CKA_SERIAL_NUMBER", rv, CKR_OK);
+ ptr = buffer;
+ len = i2d_ASN1_INTEGER(cert->cert_info->serialNumber, &ptr);
+ assert(len >= 0);
+ if(attr.ulValueLen != len || memcmp(check, buffer, len) != 0)
+ P11T_CHECK_FAIL_MSG("CKA_SERIAL_NUMBER", "serial number does not match one encoded in CKA_VALUE");
+
+ if(p11t_test_unexpected)
+ {
+ /* CKA_URL */
+ attr.type = CKA_URL;
+ attr.pValue = check;
+ attr.ulValueLen = sizeof(check);
+ rv = (p11t_module_funcs->C_GetAttributeValue)(session, object, &attr, 1);
+ P11T_CHECK_RV("CKA_URL", rv, CKR_OK);
+
+ /* CKA_HASH_OF_SUBJECT_PUBLIC_KEY */
+ attr.type = CKA_HASH_OF_SUBJECT_PUBLIC_KEY;
+ attr.pValue = check;
+ attr.ulValueLen = sizeof(check);
+ rv = (p11t_module_funcs->C_GetAttributeValue)(session, object, &attr, 1);
+ P11T_CHECK_RV("CKA_HASH_OF_SUBJECT_PUBLIC_KEY", rv, CKR_OK);
+
+ /* CKA_HASH_OF_ISSUER_PUBLIC_KEY */
+ attr.type = CKA_HASH_OF_ISSUER_PUBLIC_KEY;
+ attr.pValue = check;
+ attr.ulValueLen = sizeof(check);
+ rv = (p11t_module_funcs->C_GetAttributeValue)(session, object, &attr, 1);
+ P11T_CHECK_RV("CKA_HASH_OF_ISSUER_PUBLIC_KEY", rv, CKR_OK);
+
+ /* CKA_JAVA_MIDP_SECURITY_DOMAIN */
+ attr.type = CKA_JAVA_MIDP_SECURITY_DOMAIN;
+ attr.pValue = &java_midp;
+ attr.ulValueLen = sizeof(java_midp);
+ rv = (p11t_module_funcs->C_GetAttributeValue)(session, object, &attr, 1);
+ P11T_CHECK_RV("CKA_JAVA_MIDP_SECURITY_DOMAIN", rv, CKR_OK);
+ if(java_midp != 0 || java_midp != 1 || java_midp != 2 || java_midp != 3)
+ P11T_CHECK_FAIL_MSG("CKA_JAVA_MIDP_SECURITY_DOMAIN", "Unrecognized value");
+
+ /* CKA_ID */
+ attr.type = CKA_ID;
+ attr.pValue = check;
+ attr.ulValueLen = sizeof(check);
+ rv = (p11t_module_funcs->C_GetAttributeValue)(session, object, &attr, 1);
+ P11T_CHECK_RV("CKA_ID", rv, CKR_OK);
+ if(attr.ulValueLen == 0)
+ P11T_CHECK_FAIL_MSG("CKA_ID", "zero length CKA_ID");
+ }
+
+ test_x509_cross_search(session, object, CKA_ID, CK_INVALID, "CKA_ID");
+ test_x509_cross_search(session, object, CKA_ID, CK_INVALID, "CKA_SERIAL_NUMBER, CKA_ISSUER");
+
+ X509_free(cert);
+ free(der_value);
+
+ return CONTINUE;
+}
+
+static int
+test_certificate_object(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE object)
+{
+ CK_CERTIFICATE_TYPE cert_type;
+ CK_BYTE check_value[256];
+ CK_ATTRIBUTE attr;
+ CK_ULONG category;
+ CK_BBOOL trusted;
+ CK_DATE start_date;
+ CK_DATE end_date;
+ CK_RV rv;
+
+ P11T_SECTION("CKO_CERTIFICATE");
+
+ attr.type = CKA_CERTIFICATE_TYPE;
+ attr.ulValueLen = sizeof(cert_type);
+ attr.pValue = &cert_type;
+ rv = (p11t_module_funcs->C_GetAttributeValue)(session, object, &attr, 1);
+ P11T_CHECK_RV("CKA_CERTIFICATE_TYPE", rv, CKR_OK);
+
+ if(p11t_test_unexpected)
+ {
+ attr.type = CKA_TRUSTED;
+ attr.ulValueLen = sizeof(trusted);
+ attr.pValue = &trusted;
+ rv = (p11t_module_funcs->C_GetAttributeValue)(session, object, &attr, 1);
+ P11T_CHECK_RV("CKA_TRUSTED", rv, CKR_OK);
+ P11T_CHECK_BOOL("CKA_TRUSTED", trusted);
+
+ attr.type = CKA_CERTIFICATE_CATEGORY;
+ attr.ulValueLen = sizeof(category);
+ attr.pValue = &category;
+ rv = (p11t_module_funcs->C_GetAttributeValue)(session, object, &attr, 1);
+ P11T_CHECK_RV("CKA_CERTIFICATE_CATEGORY", rv, CKR_OK);
+ if(category != 1 && category != 2 && category != 3)
+ P11T_CHECK_FAIL_MSG("CKA_CERTIFICATE_CATEGORY", "invalid value");
+
+ attr.type = CKA_CHECK_VALUE;
+ attr.ulValueLen = sizeof(check_value);
+ attr.pValue = check_value;
+ rv = (p11t_module_funcs->C_GetAttributeValue)(session, object, &attr, 1);
+ P11T_CHECK_RV("CKA_CHECK_VALUE", rv, CKR_OK);
+ if(attr.ulValueLen != 3)
+ P11T_CHECK_FAIL_MSG("CKA_CHECK_VALUE", "length must be 3 bytes");
+
+ attr.type = CKA_START_DATE;
+ attr.ulValueLen = sizeof(start_date);
+ attr.pValue = &start_date;
+ rv = (p11t_module_funcs->C_GetAttributeValue)(session, object, &attr, 1);
+ P11T_CHECK_RV("CKA_START_DATE", rv, CKR_OK);
+ P11T_CHECK_DATE("CKA_START_DATE", &start_date);
+
+ attr.type = CKA_END_DATE;
+ attr.ulValueLen = sizeof(end_date);
+ attr.pValue = &end_date;
+ rv = (p11t_module_funcs->C_GetAttributeValue)(session, object, &attr, 1);
+ P11T_CHECK_RV("CKA_END_DATE", rv, CKR_OK);
+ P11T_CHECK_DATE("CKA_END_DATE", &end_date);
+ }
+
+ test_x509_certificate(session, object);
+
+ return CONTINUE;
+}
+
+void
+p11t_certificate_tests(void)
+{
+ CK_OBJECT_CLASS klass = CKO_CERTIFICATE;
+ CK_OBJECT_HANDLE_PTR objects;
+ CK_SESSION_HANDLE session;
+ CK_ATTRIBUTE attrs[1];
+ CK_ULONG j, i, n_objects;
+ CK_SLOT_ID slot;
+
+ for(j = 0; j < p11t_slot_count; ++j)
+ {
+ slot = p11t_slot_get_id(j);
+ session = p11t_session_open(slot, 0);
+ if(!session)
+ continue;
+
+ attrs[0].type = CKA_CLASS;
+ attrs[0].ulValueLen = sizeof(klass);
+ attrs[0].pValue = &klass;
+
+ objects = p11t_object_find(session, attrs, 1, &n_objects);
+ for(i = 0; objects && i < n_objects; ++i)
+ test_certificate_object(session, objects[i]);
+ free(objects);
+
+ p11t_session_close(session);
+ }
+}
diff --git a/src/check.c b/src/check.c
index 4c71edd..cf12dd4 100644
--- a/src/check.c
+++ b/src/check.c
@@ -104,6 +104,39 @@ _p11t_check_bool(const char *what, CK_BBOOL value)
return CONTINUE;
}
+static int
+atoin (const char *p, int digits)
+{
+ int ret = 0, base = 1;
+ while(--digits >= 0) {
+ if (p[digits] < '0' || p[digits] > '9')
+ return -1;
+ ret += (p[digits] - '0') * base;
+ base *= 10;
+ }
+ return ret;
+}
+
+int
+_p11t_check_date(const char *what, CK_DATE* value)
+{
+ int year, month, day;
+
+ year = atoin((const char*)value->year, 4);
+ month = atoin((const char*)value->month, 2);
+ day = atoin((const char*)value->day, 2);
+
+ if(year < 0 || year > 9999 ||
+ month < 1 || month > 12 ||
+ day < 1 || day > 31)
+ {
+ p11t_check_fail("%s: invalid date", what);
+ return STOP;
+ }
+
+ return CONTINUE;
+}
+
int
_p11t_check_string(const char *what, CK_UTF8CHAR_PTR value, CK_ULONG length)
{
diff --git a/src/msg.c b/src/msg.c
index 6ad4fa3..be2fdcd 100644
--- a/src/msg.c
+++ b/src/msg.c
@@ -13,6 +13,8 @@
#include <errno.h>
#endif
+#include <openssl/err.h>
+
static const char *the_prefix = NULL;
const char*
@@ -118,9 +120,9 @@ p11t_msg_rv(CK_RV rv)
static char last_error[1024];
const char*
-p11t_msg_lasterr(void)
+p11t_msg_os(void)
{
- LPVOID lpMsgBuf;
+ LPVOID lpMsgBuf;
DWORD error = GetLastError();
DWORD dwRet = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_MAX_WIDTH_MASK, NULL, error,
@@ -142,13 +144,19 @@ p11t_msg_lasterr(void)
#else /* _WIN32 */
const char*
-p11t_msg_lasterr(void)
+p11t_msg_os(void)
{
return strerror(errno);
}
#endif /* _WIN32 */
+const char*
+p11t_msg_openssl(void)
+{
+ return ERR_error_string(ERR_get_error(), NULL);
+}
+
void
p11t_msg_va(const char *message, va_list va)
{
diff --git a/src/p11-tests.c b/src/p11-tests.c
index 0e7975c..e4e4110 100644
--- a/src/p11-tests.c
+++ b/src/p11-tests.c
@@ -6,6 +6,9 @@
#include <stdio.h>
#include <stdlib.h>
+#include <openssl/err.h>
+#include <openssl/evp.h>
+
int p11t_test_unexpected = 1;
static void
@@ -50,6 +53,9 @@ main(int argc, char* argv[])
if(config)
p11t_config_parse(config);
+ ERR_load_crypto_strings();
+ OpenSSL_add_all_digests();
+
/* Basic module tests */
p11t_module_load(argv[0]);
p11t_module_initialize();
@@ -58,6 +64,7 @@ main(int argc, char* argv[])
p11t_session_tests();
p11t_object_tests();
p11t_rsa_tests();
+ p11t_certificate_tests();
/* Remaining module tests */
p11t_module_finalize();
diff --git a/src/p11-tests.h b/src/p11-tests.h
index 82bc691..efacace 100644
--- a/src/p11-tests.h
+++ b/src/p11-tests.h
@@ -21,20 +21,10 @@
extern int p11t_test_unexpected;
/* -------------------------------------------------------------------
- * msg.c
+ * certificate.c
*/
-const char* p11t_msg_rv(CK_RV rv);
-const char* p11t_msg_lasterr(void);
-
-void p11t_msg_va(const char *message, va_list va);
-void p11t_msg_code(const char* code, const char *message, va_list va);
-void p11t_msg_print(const char *message, ...);
-void p11t_msg_fatal(const char *message, ...);
-const char* p11t_msg_prefix(const char *prefix);
-
-#define p11t_msg_here() \
- (__func__ "() at " __FILE__ ":" __LINE__)
+void p11t_certificate_tests(void);
/* -------------------------------------------------------------------
* check.c
@@ -57,6 +47,9 @@ extern int p11t_check_verbose;
#define P11T_CHECK_FAIL(what) \
_P11T_BEGIN p11t_check_fail("%s", (what)); return STOP; _P11T_END
+#define P11T_CHECK_FAIL_MSG(what, msg) \
+ _P11T_BEGIN p11t_check_fail("%s: %s", (what), (msg)); return STOP; _P11T_END
+
int p11t_check_fail(const char *message, ...);
int p11t_check_warn(const char *message, ...);
int p11t_check_info(const char *message, ...);
@@ -101,6 +94,11 @@ int _p11t_check_bool(const char *what, CK_BBOOL value);
int _p11t_check_string(const char *what, CK_UTF8CHAR_PTR value, CK_ULONG length);
+#define P11T_CHECK_DATE(what, value) \
+ _P11T_BEGIN if(!_p11t_check_date((what), (value))) return STOP; _P11T_END
+
+int _p11t_check_date(const char *what, CK_DATE* value);
+
#define P11T_CHECK_NOTE(what)
/* -------------------------------------------------------------------
@@ -121,6 +119,23 @@ CK_OBJECT_HANDLE p11t_key_get_private(CK_SESSION_HANDLE session, CK_OBJECT_HANDL
RSA* p11t_key_export_public_rsa(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE key);
/* -------------------------------------------------------------------
+ * msg.c
+ */
+
+const char* p11t_msg_rv(CK_RV rv);
+const char* p11t_msg_os(void);
+const char* p11t_msg_openssl(void);
+
+void p11t_msg_va(const char *message, va_list va);
+void p11t_msg_code(const char* code, const char *message, va_list va);
+void p11t_msg_print(const char *message, ...);
+void p11t_msg_fatal(const char *message, ...);
+const char* p11t_msg_prefix(const char *prefix);
+
+#define p11t_msg_here() \
+ (__func__ "() at " __FILE__ ":" __LINE__)
+
+/* -------------------------------------------------------------------
* module.c
*/
diff --git a/src/rsa.c b/src/rsa.c
index b8371cc..fa3d372 100644
--- a/src/rsa.c
+++ b/src/rsa.c
@@ -444,6 +444,5 @@ test_rsa_pkcs(CK_SLOT_ID slot, CK_MECHANISM_TYPE mech, CK_MECHANISM_INFO_PTR inf
void
p11t_rsa_tests(void)
{
- OpenSSL_add_all_digests();
p11t_slot_for_each_mech(CKM_RSA_PKCS, test_rsa_pkcs);
}