summaryrefslogtreecommitdiff
path: root/src/certificate.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/certificate.c')
-rw-r--r--src/certificate.c355
1 files changed, 355 insertions, 0 deletions
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);
+ }
+}