#include "p11-tests.h" #include "p11-tests-lib.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; const char *msg; 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); msg = p11t_certificate_validate_dn(attr.pValue, attr.ulValueLen); if(msg != NULL) return msg; /* 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); 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_SERIAL_NUMBER, CKA_ISSUER, "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 && category != 0) 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); if(attr.ulValueLen) 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); if(attr.ulValueLen) 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); } } const char* p11t_certificate_validate_dn(CK_BYTE_PTR der, CK_ULONG n_der) { CK_BYTE_PTR ptr; X509_NAME* name; /* Let openssl parse it */ ptr = der; name = d2i_X509_NAME(NULL, (const unsigned char**)&ptr, n_der); if(name == NULL) return p11t_msg_openssl(); if(ptr - der != n_der) return "Extra trailing bytes"; X509_NAME_free(name); return NULL; }