From c9099836f080c8bb821264050f5f6d59a1ceddba Mon Sep 17 00:00:00 2001 From: Stef Walter Date: Tue, 9 Dec 2008 00:08:01 +0000 Subject: Add tests for X509 certificates. --- src/certificate.c | 355 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 355 insertions(+) create mode 100644 src/certificate.c (limited to 'src/certificate.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 +#include + +#include + +/* ---------------------------------------------------------------------------------- + * 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); + } +} -- cgit v1.2.3