#include "p11-tests.h" /* ---------------------------------------------------------------------------------- * TESTS */ static int test_key_attributes(CK_SLOT_ID slot, CK_SESSION_HANDLE session, CK_OBJECT_HANDLE object, CK_KEY_TYPE* key_type) { CK_BYTE buffer[4096]; CK_ATTRIBUTE attr; CK_MECHANISM_TYPE mech_type; CK_MECHANISM_TYPE_PTR mechanisms; CK_ULONG n_mechanisms, i; CK_BBOOL bval, local; CK_DATE date; CK_RV rv; P11T_SECTION("Key Object"); attr.type = CKA_KEY_TYPE; attr.ulValueLen = sizeof(*key_type); attr.pValue = key_type; rv = (p11t_module_funcs->C_GetAttributeValue)(session, object, &attr, 1); P11T_CHECK_RV("CKA_KEY_TYPE", rv, CKR_OK); attr.type = CKA_ID; attr.ulValueLen = sizeof(buffer); attr.pValue = buffer; rv = (p11t_module_funcs->C_GetAttributeValue)(session, object, &attr, 1); P11T_CHECK_RV("CKA_ID", rv, CKR_OK); attr.type = CKA_DERIVE; attr.ulValueLen = sizeof(bval); attr.pValue = &bval; rv = (p11t_module_funcs->C_GetAttributeValue)(session, object, &attr, 1); P11T_CHECK_RV("CKA_DERIVE", rv, CKR_OK); P11T_CHECK_BOOL("CKA_DERIVE", bval); if(p11t_test_unexpected) { attr.type = CKA_START_DATE; attr.ulValueLen = sizeof(date); attr.pValue = &date; rv = (p11t_module_funcs->C_GetAttributeValue)(session, object, &attr, 1); P11T_CHECK_RV("CKA_START_DATE", rv, CKR_OK); if(attr.ulValueLen > 0) P11T_CHECK_DATE("CKA_START_DATE", &date); attr.type = CKA_END_DATE; attr.ulValueLen = sizeof(date); attr.pValue = &date; rv = (p11t_module_funcs->C_GetAttributeValue)(session, object, &attr, 1); P11T_CHECK_RV("CKA_END_DATE", rv, CKR_OK); if(attr.ulValueLen > 0) P11T_CHECK_DATE("CKA_END_DATE", &date); attr.type = CKA_LOCAL; attr.ulValueLen = sizeof(local); attr.pValue = &local; rv = (p11t_module_funcs->C_GetAttributeValue)(session, object, &attr, 1); P11T_CHECK_RV("CKA_LOCAL", rv, CKR_OK); P11T_CHECK_BOOL("CKA_LOCAL", local); attr.type = CKA_KEY_GEN_MECHANISM; attr.ulValueLen = sizeof(mech_type); attr.pValue = &mech_type; rv = (p11t_module_funcs->C_GetAttributeValue)(session, object, &attr, 1); P11T_CHECK_RV("CKA_KEY_GEN_MECHANISM", rv, CKR_OK); /* Key was generated with this */ if(mech_type != CK_UNAVAILABLE_INFORMATION) { if(!local) P11T_CHECK_FAIL_MSG("CKA_KEY_GEN_MECHANISM", "Non locally generated key has key gen mechanism"); if(!p11t_slot_get_mech_info(slot, mech_type)) P11T_CHECK_FAIL_MSG("CKA_KEY_GEN_MECHANISM", "Mechanism not present on slot"); } attr.type = CKA_ALLOWED_MECHANISMS; attr.ulValueLen = sizeof(buffer); attr.pValue = buffer; rv = (p11t_module_funcs->C_GetAttributeValue)(session, object, &attr, 1); P11T_CHECK_RV("CKA_ALLOWED_MECHANISMS", rv, CKR_OK); if(attr.ulValueLen % sizeof(CK_MECHANISM_TYPE) != 0) P11T_CHECK_FAIL_MSG("CKA_ALLOWED_MECHANISMS", "Invalid size memory returned"); mechanisms = (CK_MECHANISM_TYPE_PTR)buffer; n_mechanisms = attr.ulValueLen / sizeof(CK_MECHANISM_TYPE); for(i = 0; i < n_mechanisms; ++i) { if(!p11t_slot_get_mech_info(slot, mechanisms[i])) P11T_CHECK_FAIL_MSG("CKA_ALLOWED_MECHANISMS", "Mechanism not present in slot"); } } return CONTINUE; } static int test_rsa_public(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE object) { CK_ATTRIBUTE attr; CK_BYTE modulus[16384]; CK_ULONG n_modulus; CK_BYTE exponent[1024]; CK_ULONG n_exponent; CK_ULONG bits; CK_RV rv; RSA* rsa; P11T_SECTION("CKK_RSA Public"); attr.type = CKA_MODULUS; attr.pValue = modulus; attr.ulValueLen = sizeof(modulus); rv = (p11t_module_funcs->C_GetAttributeValue)(session, object, &attr, 1); P11T_CHECK_RV("CKA_MODULUS", rv, CKR_OK); n_modulus = attr.ulValueLen; attr.type = CKA_PUBLIC_EXPONENT; attr.pValue = exponent; attr.ulValueLen = sizeof(exponent); rv = (p11t_module_funcs->C_GetAttributeValue)(session, object, &attr, 1); P11T_CHECK_RV("CKA_PUBLIC_EXPONENT", rv, CKR_OK); n_exponent = attr.ulValueLen; attr.type = CKA_MODULUS_BITS; attr.pValue = &bits; attr.ulValueLen = sizeof(bits); rv = (p11t_module_funcs->C_GetAttributeValue)(session, object, &attr, 1); P11T_CHECK_RV("CKA_MODULUS_BITS", rv, CKR_OK); rsa = RSA_new(); assert(rsa); rsa->n = BN_bin2bn(modulus, n_modulus, NULL); if(!rsa->n) P11T_CHECK_FAIL_MSG("CKA_MODULUS", "Couldn't parse"); rsa->e = BN_bin2bn(exponent, n_exponent, NULL); if(!rsa->e) P11T_CHECK_FAIL_MSG("CKA_PUBLIC_EXPONENT", "Couldn't parse"); if(RSA_size(rsa) != bits / 8) P11T_CHECK_FAIL_MSG("CKA_MODULUS_BITS", "Does not match bits in actual modulus"); return CONTINUE; } static int test_rsa_private(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE object) { CK_ATTRIBUTE attr; CK_BYTE buffer[32768]; CK_RV rv; RSA* rsa; P11T_SECTION("CKK_RSA Private"); rsa = RSA_new(); assert(rsa); attr.type = CKA_MODULUS; attr.pValue = buffer; attr.ulValueLen = sizeof(buffer); rv = (p11t_module_funcs->C_GetAttributeValue)(session, object, &attr, 1); P11T_CHECK_RV("CKA_MODULUS", rv, CKR_OK); rsa->n = BN_bin2bn(attr.pValue, attr.ulValueLen, NULL); if(rsa->n == NULL) P11T_CHECK_FAIL_MSG("CKA_MODULUS", p11t_msg_openssl()); attr.type = CKA_PRIVATE_EXPONENT; attr.pValue = buffer; attr.ulValueLen = sizeof(buffer); rv = (p11t_module_funcs->C_GetAttributeValue)(session, object, &attr, 1); if(rv == CKR_ATTRIBUTE_SENSITIVE) return CONTINUE; P11T_CHECK_RV("CKA_PRIVATE_EXPONENT", rv, CKR_OK); rsa->d = BN_bin2bn(attr.pValue, attr.ulValueLen, NULL); if(rsa->d == NULL) P11T_CHECK_FAIL_MSG("CKA_PRIVATE_EXPONENT", p11t_msg_openssl()); if(p11t_test_unexpected) { attr.type = CKA_PUBLIC_EXPONENT; attr.pValue = buffer; attr.ulValueLen = sizeof(buffer); rv = (p11t_module_funcs->C_GetAttributeValue)(session, object, &attr, 1); if(rv != CKR_ATTRIBUTE_SENSITIVE || rv != CKR_ATTRIBUTE_TYPE_INVALID) { P11T_CHECK_RV("CKA_PUBLIC_EXPONENT", rv, CKR_OK); rsa->e = BN_bin2bn(attr.pValue, attr.ulValueLen, NULL); if(rsa->e == NULL) P11T_CHECK_FAIL_MSG("CKA_PUBLIC_EXPONENT", p11t_msg_openssl()); } attr.type = CKA_PRIME_1; attr.pValue = buffer; attr.ulValueLen = sizeof(buffer); rv = (p11t_module_funcs->C_GetAttributeValue)(session, object, &attr, 1); if(rv != CKR_ATTRIBUTE_SENSITIVE || rv != CKR_ATTRIBUTE_TYPE_INVALID) { P11T_CHECK_RV("CKA_PRIME_1", rv, CKR_OK); rsa->p = BN_bin2bn(attr.pValue, attr.ulValueLen, NULL); if(rsa->p == NULL) P11T_CHECK_FAIL_MSG("CKA_PRIME_1", p11t_msg_openssl()); } attr.type = CKA_PRIME_2; attr.pValue = buffer; attr.ulValueLen = sizeof(buffer); rv = (p11t_module_funcs->C_GetAttributeValue)(session, object, &attr, 1); if(rv != CKR_ATTRIBUTE_SENSITIVE || rv != CKR_ATTRIBUTE_TYPE_INVALID) { P11T_CHECK_RV("CKA_PRIME_2", rv, CKR_OK); rsa->q = BN_bin2bn(attr.pValue, attr.ulValueLen, NULL); if(rsa->q == NULL) P11T_CHECK_FAIL_MSG("CKA_PRIME_2", p11t_msg_openssl()); } attr.type = CKA_EXPONENT_1; attr.pValue = buffer; attr.ulValueLen = sizeof(buffer); rv = (p11t_module_funcs->C_GetAttributeValue)(session, object, &attr, 1); if(rv != CKR_ATTRIBUTE_SENSITIVE || rv != CKR_ATTRIBUTE_TYPE_INVALID) { P11T_CHECK_RV("CKA_EXPONENT_1", rv, CKR_OK); rsa->dmp1 = BN_bin2bn(attr.pValue, attr.ulValueLen, NULL); if(rsa->dmp1 == NULL) P11T_CHECK_FAIL_MSG("CKA_EXPONENT_1", p11t_msg_openssl()); } attr.type = CKA_EXPONENT_2; attr.pValue = buffer; attr.ulValueLen = sizeof(buffer); rv = (p11t_module_funcs->C_GetAttributeValue)(session, object, &attr, 1); if(rv != CKR_ATTRIBUTE_SENSITIVE || rv != CKR_ATTRIBUTE_TYPE_INVALID) { P11T_CHECK_RV("CKA_EXPONENT_2", rv, CKR_OK); rsa->dmq1 = BN_bin2bn(attr.pValue, attr.ulValueLen, NULL); if(rsa->dmq1 == NULL) P11T_CHECK_FAIL_MSG("CKA_EXPONENT_2", p11t_msg_openssl()); } attr.type = CKA_COEFFICIENT; attr.pValue = buffer; attr.ulValueLen = sizeof(buffer); rv = (p11t_module_funcs->C_GetAttributeValue)(session, object, &attr, 1); if(rv != CKR_ATTRIBUTE_SENSITIVE || rv != CKR_ATTRIBUTE_TYPE_INVALID) { P11T_CHECK_RV("CKA_COEFFICIENT", rv, CKR_OK); rsa->iqmp = BN_bin2bn(attr.pValue, attr.ulValueLen, NULL); if(rsa->iqmp == NULL) P11T_CHECK_FAIL_MSG("CKA_COEFFICIENT", p11t_msg_openssl()); } } /* Can we validate the key? */ assert(rsa->n && rsa->d); if(rsa->e && rsa->p && rsa->q) { int res = RSA_check_key(rsa); if(res < 0) P11T_CHECK_FAIL_MSG("Check RSA private key", p11t_msg_openssl()); else if(res == 0) P11T_CHECK_FAIL_MSG("Check RSA private key", "RSA key is not valid"); } return CONTINUE; } static int test_public_attributes(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE object) { CK_BYTE buffer[4096]; CK_ATTRIBUTE attr; CK_BBOOL bval, wrap; const char *msg; CK_RV rv; P11T_SECTION("CKO_PUBLIC_KEY"); attr.type = CKA_SUBJECT; attr.pValue = buffer; attr.ulValueLen = sizeof(buffer); rv = (p11t_module_funcs->C_GetAttributeValue)(session, object, &attr, 1); P11T_CHECK_RV("CKA_SUBJECT", rv, CKR_OK); if(attr.ulValueLen) { msg = p11t_certificate_validate_dn(attr.pValue, attr.ulValueLen); if(msg != NULL) P11T_CHECK_FAIL_MSG("CKA_SUBJECT", msg); } attr.type = CKA_ENCRYPT; attr.pValue = &bval; attr.ulValueLen = sizeof(bval); rv = (p11t_module_funcs->C_GetAttributeValue)(session, object, &attr, 1); P11T_CHECK_RV("CKA_ENCRYPT", rv, CKR_OK); P11T_CHECK_BOOL("CKA_ENCRYPT", bval); attr.type = CKA_VERIFY; attr.pValue = &bval; attr.ulValueLen = sizeof(bval); rv = (p11t_module_funcs->C_GetAttributeValue)(session, object, &attr, 1); P11T_CHECK_RV("CKA_VERIFY", rv, CKR_OK); P11T_CHECK_BOOL("CKA_VERIFY", bval); attr.type = CKA_VERIFY_RECOVER; attr.pValue = &bval; attr.ulValueLen = sizeof(bval); rv = (p11t_module_funcs->C_GetAttributeValue)(session, object, &attr, 1); P11T_CHECK_RV("CKA_VERIFY_RECOVER", rv, CKR_OK); P11T_CHECK_BOOL("CKA_VERIFY_RECOVER", bval); attr.type = CKA_TRUSTED; attr.pValue = &bval; attr.ulValueLen = sizeof(bval); rv = (p11t_module_funcs->C_GetAttributeValue)(session, object, &attr, 1); P11T_CHECK_RV("CKA_TRUSTED", rv, CKR_OK); P11T_CHECK_BOOL("CKA_TRUSTED", bval); attr.type = CKA_WRAP; attr.pValue = &wrap; attr.ulValueLen = sizeof(wrap); rv = (p11t_module_funcs->C_GetAttributeValue)(session, object, &attr, 1); P11T_CHECK_RV("CKA_WRAP", rv, CKR_OK); P11T_CHECK_BOOL("CKA_WRAP", wrap); return CONTINUE; } static int test_private_attributes(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE object) { CK_BYTE buffer[4096]; CK_ATTRIBUTE attr; CK_BBOOL bval; const char *msg; CK_RV rv; P11T_SECTION("CKO_PRIVATE_KEY"); attr.type = CKA_SUBJECT; attr.pValue = buffer; attr.ulValueLen = sizeof(buffer); rv = (p11t_module_funcs->C_GetAttributeValue)(session, object, &attr, 1); P11T_CHECK_RV("CKA_SUBJECT", rv, CKR_OK); if(attr.ulValueLen) { msg = p11t_certificate_validate_dn(attr.pValue, attr.ulValueLen); if(msg != NULL) P11T_CHECK_FAIL_MSG("CKA_SUBJECT", msg); } attr.type = CKA_SENSITIVE; attr.pValue = &bval; attr.ulValueLen = sizeof(bval); rv = (p11t_module_funcs->C_GetAttributeValue)(session, object, &attr, 1); P11T_CHECK_RV("CKA_SENSITIVE", rv, CKR_OK); P11T_CHECK_BOOL("CKA_SENSITIVE", bval); attr.type = CKA_DECRYPT; attr.pValue = &bval; attr.ulValueLen = sizeof(bval); rv = (p11t_module_funcs->C_GetAttributeValue)(session, object, &attr, 1); P11T_CHECK_RV("CKA_DECRYPT", rv, CKR_OK); P11T_CHECK_BOOL("CKA_DECRYPT", bval); attr.type = CKA_SIGN; attr.pValue = &bval; attr.ulValueLen = sizeof(bval); rv = (p11t_module_funcs->C_GetAttributeValue)(session, object, &attr, 1); P11T_CHECK_RV("CKA_SIGN", rv, CKR_OK); P11T_CHECK_BOOL("CKA_SIGN", bval); attr.type = CKA_SIGN_RECOVER; attr.pValue = &bval; attr.ulValueLen = sizeof(bval); rv = (p11t_module_funcs->C_GetAttributeValue)(session, object, &attr, 1); P11T_CHECK_RV("CKA_SIGN_RECOVER", rv, CKR_OK); P11T_CHECK_BOOL("CKA_SIGN_RECOVER", bval); attr.type = CKA_UNWRAP; attr.pValue = &bval; attr.ulValueLen = sizeof(bval); rv = (p11t_module_funcs->C_GetAttributeValue)(session, object, &attr, 1); P11T_CHECK_RV("CKA_UNWRAP", rv, CKR_OK); P11T_CHECK_BOOL("CKA_UNWRAP", bval); attr.type = CKA_EXTRACTABLE; attr.pValue = &bval; attr.ulValueLen = sizeof(bval); rv = (p11t_module_funcs->C_GetAttributeValue)(session, object, &attr, 1); P11T_CHECK_RV("CKA_EXTRACTABLE", rv, CKR_OK); P11T_CHECK_BOOL("CKA_EXTRACTABLE", bval); attr.type = CKA_ALWAYS_SENSITIVE; attr.pValue = &bval; attr.ulValueLen = sizeof(bval); rv = (p11t_module_funcs->C_GetAttributeValue)(session, object, &attr, 1); P11T_CHECK_RV("CKA_ALWAYS_SENSITIVE", rv, CKR_OK); P11T_CHECK_BOOL("CKA_ALWAYS_SENSITIVE", bval); attr.type = CKA_NEVER_EXTRACTABLE; attr.pValue = &bval; attr.ulValueLen = sizeof(bval); rv = (p11t_module_funcs->C_GetAttributeValue)(session, object, &attr, 1); P11T_CHECK_RV("CKA_NEVER_EXTRACTABLE", rv, CKR_OK); P11T_CHECK_BOOL("CKA_NEVER_EXTRACTABLE", bval); if(p11t_test_unexpected) { attr.type = CKA_WRAP_WITH_TRUSTED; attr.pValue = &bval; attr.ulValueLen = sizeof(bval); rv = (p11t_module_funcs->C_GetAttributeValue)(session, object, &attr, 1); P11T_CHECK_RV("CKA_WRAP_WITH_TRUSTED", rv, CKR_OK); P11T_CHECK_BOOL("CKA_WRAP_WITH_TRUSTED", bval); attr.type = CKA_ALWAYS_AUTHENTICATE; attr.pValue = &bval; attr.ulValueLen = sizeof(bval); rv = (p11t_module_funcs->C_GetAttributeValue)(session, object, &attr, 1); P11T_CHECK_RV("CKA_ALWAYS_AUTHENTICATE", rv, CKR_OK); P11T_CHECK_BOOL("CKA_ALWAYS_AUTHENTICATE", bval); } return CONTINUE; } void p11t_key_tests(void) { CK_OBJECT_CLASS klass; CK_OBJECT_HANDLE_PTR objects; CK_SESSION_HANDLE session; CK_OBJECT_HANDLE object; CK_ATTRIBUTE attrs[1]; CK_ULONG j, i, n_objects; CK_SLOT_ID slot; CK_KEY_TYPE key_type; attrs[0].type = CKA_CLASS; attrs[0].ulValueLen = sizeof(klass); attrs[0].pValue = &klass; for(j = 0; j < p11t_slot_count; ++j) { slot = p11t_slot_get_id(j); session = p11t_session_open(slot, 0); if(!session) continue; klass = CKO_PUBLIC_KEY; objects = p11t_object_find(session, attrs, 1, &n_objects); for(i = 0; objects && i < n_objects; ++i) { object = objects[i]; if(test_key_attributes(slot, session, object, &key_type)) { test_public_attributes(session, object); if(key_type == CKK_RSA) test_rsa_public(session, object); } } free(objects); if(p11t_session_login(session)) { klass = CKO_PRIVATE_KEY; objects = p11t_object_find(session, attrs, 1, &n_objects); for(i = 0; objects && i < n_objects; ++i) { object = objects[i]; if(test_key_attributes(slot, session, object, &key_type)) { test_private_attributes(session, object); if(key_type == CKK_RSA) test_rsa_private(session, object); } } free(objects); } p11t_session_close(session); } } /* ---------------------------------------------------------------------------------- * METHODS */ 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; }