From 6a533371d185946e1b49d62a193b81db31a1604f Mon Sep 17 00:00:00 2001 From: Stef Walter Date: Thu, 4 Dec 2008 22:50:10 +0000 Subject: Add GetInfo, GetSlotInfo, GetTokenInfo, GetSlotList tests. --- src/Makefile.am | 2 + src/check.c | 61 ++++++++++++++ src/info.c | 241 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/module.c | 64 ++++++++++----- src/p11-tests.c | 5 ++ src/p11-tests.h | 42 +++++++++- 6 files changed, 394 insertions(+), 21 deletions(-) create mode 100644 src/check.c create mode 100644 src/info.c (limited to 'src') diff --git a/src/Makefile.am b/src/Makefile.am index d8cbb2d..6b24785 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -4,6 +4,8 @@ bin_PROGRAMS = p11-tests p11_tests_LDADD = -ldl p11_tests_SOURCES = \ + check.c \ + info.c \ module.c \ msg.c \ p11-tests.c diff --git a/src/check.c b/src/check.c new file mode 100644 index 0000000..61cee45 --- /dev/null +++ b/src/check.c @@ -0,0 +1,61 @@ + +#include "config.h" + +#include "p11-tests.h" + +int +p11t_check_returns(const char *message, CK_RV have, CK_RV want) +{ + if(have != want) + { + p11t_msg_print("%s: expected %s but got %s", message, + p11t_msg_rv(want), p11t_msg_rv(have)); + return 0; + } + + return 1; +} + +int +p11t_check_padded_len(const char *message, const CK_UTF8CHAR_PTR padded, + CK_ULONG length) +{ + CK_ULONG i; + + for(i = 0; i < length; ++i) + { + if(!padded[i]) + { + p11t_msg_print("%s: not blank padded", message); + return 0; + } + } + + return 1; +} + +int +p11t_check_ulong(const char *message, CK_ULONG have, CK_ULONG want) +{ + if(have != want) + { + p11t_msg_print("%s: expected 0x%08x but have 0x%08x", message, + want, have); + return 0; + } + + return 1; +} + +int +p11t_check_mask(const char *message, CK_ULONG flags, CK_ULONG mask) +{ + if((flags & ~mask) != 0) + { + p11t_msg_print("%s: extra flags outside of mask: 0x08x", + (flags & ~mask)); + return 0; + } + + return 1; +} diff --git a/src/info.c b/src/info.c new file mode 100644 index 0000000..0071431 --- /dev/null +++ b/src/info.c @@ -0,0 +1,241 @@ + +#include "config.h" + +#include "p11-tests.h" + +#include +#include +#include + +CK_INFO p11t_info_global; + +CK_ULONG p11t_info_slot_count = 0; +CK_SLOT_ID_PTR p11t_info_slot_ids = NULL; +CK_SLOT_INFO_PTR p11t_info_slot_info = NULL; +CK_TOKEN_INFO_PTR p11t_info_token_info = NULL; + +CK_ULONG p11t_info_mech_count = 0; +CK_MECHANISM_TYPE_PTR p11t_info_mech_types = NULL; +CK_MECHANISM_INFO_PTR p11t_info_mech_info = NULL; + +void +info_global(void) +{ + CK_RV rv; + + /** C_GetInfo */ + + assert(p11t_module_funcs); + + /** - NULL argument */ + rv = (p11t_module_funcs->C_GetInfo)(NULL); + p11t_check_returns("C_GetInfo", rv, CKR_ARGUMENTS_BAD); + + /* Obvious crap fill */ + memset(&p11t_info_global, 0xFF, sizeof(CK_INFO)); + + /** - Normal call */ + rv = (p11t_module_funcs->C_GetInfo)(&p11t_info_global); + if(p11t_check_returns("C_GetInfo", rv, CKR_OK)) + { + memset(&p11t_info_global, 0, sizeof(CK_INFO)); + return; + } + + /** - Cryptoki version matches that in library entry point data */ + if(memcmp(&p11t_info_global.cryptokiVersion, &p11t_module_funcs->version, sizeof(CK_VERSION)) != 0) + p11t_msg_print("version from CK_INFO.cryptokiVersion does not match from CK_FUNCTION_LIST.version"); + + /** - Space padded strings in CK_INFO */ + p11t_check_padded("CK_INFO.manufacturerID", p11t_info_global.manufacturerID); + p11t_check_padded("CK_INFO.libraryDescription", p11t_info_global.libraryDescription); + + /** - No flags set */ + p11t_check_ulong("CK_INFO.flags", p11t_info_global.flags, 0); +} + +int +compar_slot_id(const void *one, const void *two) +{ + CK_SLOT_ID a = *((CK_SLOT_ID*)one); + CK_SLOT_ID b = *((CK_SLOT_ID*)two); + if(a == b) + return 0; + if(a > b) + return 1; + return -1; +} + +void +info_slots(void) +{ + CK_SLOT_ID_PTR present, only; + CK_ULONG n_present, n_only, count; + CK_ULONG i; + CK_RV rv; + + /** C_GetSlotList */ + + assert(p11t_module_funcs); + + /** - NULL arguments */ + rv = (p11t_module_funcs->C_GetSlotList)(FALSE, NULL, NULL); + p11t_check_returns("C_GetSlotList", rv, CKR_ARGUMENTS_BAD); + + /** - Retrieving the count */ + rv = (p11t_module_funcs->C_GetSlotList)(FALSE, NULL, &p11t_info_slot_count); + p11t_check_returns("C_GetSlotList", rv, CKR_OK); + + if(p11t_info_slot_count == 0) + { + p11t_msg_print("no slots to test"); + return; + } + + /* Allocate a bit extra. We're going to try and trip up module */ + p11t_info_slot_ids = calloc(p11t_info_slot_count + 5, sizeof(CK_SLOT_ID)); + assert(p11t_info_slot_ids); + + p11t_info_slot_info = calloc(p11t_info_slot_count, sizeof(CK_SLOT_INFO)); + assert(p11t_info_slot_info); + + p11t_info_token_info = calloc(p11t_info_slot_count, sizeof(CK_TOKEN_INFO)); + assert(p11t_info_token_info); + + /** - Passing buffer space along with zero count. */ + count = 0; + rv = (p11t_module_funcs->C_GetSlotList)(FALSE, p11t_info_slot_ids, &count); + p11t_check_returns("C_GetSlotList", rv, CKR_BUFFER_TOO_SMALL); + p11t_check_ulong("Count invalid zero space passed to C_GetSlotList", count, p11t_info_slot_count); + + if(p11t_info_slot_count > 1) + { + /** - Passing buffer space along with low count. */ + count = 1; + rv = (p11t_module_funcs->C_GetSlotList)(FALSE, p11t_info_slot_ids, &count); + p11t_check_returns("C_GetSlotList", rv, CKR_BUFFER_TOO_SMALL); + p11t_check_ulong("Count invalid when too little space passed to C_GetSlotList", count, p11t_info_slot_count); + } + + /** - Passing too much buffer space. */ + count = p11t_info_slot_ids + 5; + rv = (p11t_module_funcs->C_GetSlotList)(FALSE, p11t_info_slot_ids, &count); + if(!p11t_check_returns("C_GetSlotList", rv, CKR_OK)) + { + p11t_info_slot_count = 0; + return; + } + + p11t_check_ulong("Count invalid when too much space passed to C_GetSlotList", count, p11t_info_slot_count); + + /* When we ask for just token valid ones, they should only be the ones we noted with flags */ + present = calloc(p11t_info_slot_count, sizeof(CK_SLOT_ID)); + only = calloc(p11t_info_slot_count, sizeof(CK_SLOT_ID)); + assert(present && only); + n_present = 0; + + /* Now go through and load info about each slot */ + for(i = 0; i < p11t_info_slot_count; ++i) + { + /** C_GetSlotInfo */ + + /** - NULL argument */ + rv = (p11t_module_funcs->C_GetSlotInfo)(p11t_info_slot_ids[i], NULL); + p11t_check_returns("C_GetSlotInfo", rv, CKR_ARGUMENTS_BAD); + + /** - Normal call */ + rv = (p11t_module_funcs->C_GetSlotInfo)(p11t_info_slot_ids[i], &p11t_info_slot_info[i]); + p11t_check_returns("C_GetSlotInfo", rv, CKR_OK); + + /** - Space padded CK_SLOT_INFO fields */ + p11t_check_padded("CK_SLOT_INFO.slotDescription", p11t_info_slot_info[i].slotDescription); + p11t_check_padded("CK_SLOT_INFO.manufacturerID", p11t_info_slot_info[i].manufacturerID); + + /** - CK_SLOT_INFO flags are from valid set */ + p11t_check_mask("CK_SLOT_INFO.flags", p11t_info_slot_info[i].flags, + CKF_TOKEN_PRESENT | CKF_REMOVABLE_DEVICE | CKF_HW_SLOT); + + /** - Track CKF_TOKEN_PRESENT flag and compare to C_GetSlotList(TRUE) */ + if((p11t_info_slot_info[i].flags & CKF_TOKEN_PRESENT) == CKF_TOKEN_PRESENT) + { + /* Note if token is present for later */ + present[n_present++] = p11t_info_slot_ids[i]; + + /** C_GetTokenInfo */ + + /** - Null arguments */ + rv = (p11t_module_funcs->C_GetTokenInfo)(p11t_info_slot_ids[i], NULL); + p11t_check_returns("C_GetSlotInfo", rv, CKR_ARGUMENTS_BAD); + + /** - Normal call */ + rv = (p11t_module_funcs->C_GetTokenInfo)(p11t_info_slot_ids[i], &p11t_info_token_info[i]); + p11t_check_returns("C_GetSlotInfo", rv, CKR_OK); + + /** - Space padded CK_TOKEN_INFO fields */ + p11t_check_padded("CK_TOKEN_INFO.label", p11t_info_token_info[i].label); + p11t_check_padded("CK_TOKEN_INFO.manufacturerID", p11t_info_token_info[i].manufacturerID); + p11t_check_padded("CK_TOKEN_INFO.model", p11t_info_token_info[i].model); + p11t_check_padded("CK_TOKEN_INFO.serialNumber", p11t_info_token_info[i].serialNumber); + + /** - CK_TOKEN_INFO flags are from valid set */ + p11t_check_mask("CK_TOKEN_INFO.flags", p11t_info_token_info[i].flags, + CKF_RNG | CKF_WRITE_PROTECTED | CKF_LOGIN_REQUIRED | CKF_USER_PIN_INITIALIZED | + CKF_RESTORE_KEY_NOT_NEEDED | CKF_CLOCK_ON_TOKEN | CKF_PROTECTED_AUTHENTICATION_PATH | + CKF_DUAL_CRYPTO_OPERATIONS | CKF_TOKEN_INITIALIZED | CKF_SECONDARY_AUTHENTICATION | + CKF_USER_PIN_COUNT_LOW | CKF_USER_PIN_FINAL_TRY | CKF_USER_PIN_LOCKED | + CKF_USER_PIN_TO_BE_CHANGED | CKF_SO_PIN_COUNT_LOW | CKF_SO_PIN_FINAL_TRY | + CKF_SO_PIN_LOCKED | CKF_SO_PIN_TO_BE_CHANGED); + + /* Can't validate all the statistics, any number is valid */ + + /** - Validate token time when CKF_CLOCK_ON_TOKEN */ + if((p11t_info_token_info[i].flags & CKF_CLOCK_ON_TOKEN) == CKF_CLOCK_ON_TOKEN) + { + int year, month, day, hour, minute, second, extra, n; + char buffer[sizeof(p11t_info_token_info[i].utcTime) + 1]; + + memcpy(buffer, (char*)p11t_info_token_info[i].utcTime, + sizeof(p11t_info_token_info[i].utcTime)); + buffer[sizeof(p11t_info_token_info[i].utcTime)] = 0; + + n = sscanf(buffer, "%04d%02d%02d%02d%02d%02d%02d", + &year, &month, &day, &hour, &minute, &second, &extra); + + if(n != 7 || + year < 0 || year > 9999 || + month < 1 || month > 12 || + day < 1 || day > 31 || + hour < 0 || hour > 23 || + minute < 0 || minute > 59 || + second < 0 || second > 50 || + extra != 0) + { + p11t_msg_print("invalid time on token: %s", buffer); + } + } + } + else + { + /** - Calling on slot without token */ + rv = (p11t_module_funcs->C_GetTokenInfo)(p11t_info_slot_ids[i], &p11t_info_token_info[i]); + p11t_check_returns("C_GetSlotInfo", rv, CKR_TOKEN_NOT_PRESENT); + } + } + + rv = (p11t_module_funcs->C_GetSlotList)(TRUE, only, &n_only); + p11t_check_returns("C_GetSlotList (only tokens)", rv, CKR_OK); + + p11t_check_ulong("number of present tokens doesn't match token info flags. ie: CKF_TOKEN_PRESENT", n_only, n_present); + + qsort(only, n_only, sizeof(CK_SLOT_ID), compar_slot_id); + qsort(present, n_present, sizeof(CK_SLOT_ID), compar_slot_id); + if(memcmp(only, present, sizeof(CK_SLOT_ID) * n_only) != 0) + p11t_msg_print("present tokens don't match those in token info flags. ie: CKF_TOKEN_PRESENT"); +} + +void +p11t_info_tests(void) +{ + info_global(); + info_slots(); +} diff --git a/src/module.c b/src/module.c index 8677c22..c20bd3c 100644 --- a/src/module.c +++ b/src/module.c @@ -10,7 +10,7 @@ #include static void *module = NULL; -CK_FUNCTION_LIST_PTR p11_funcs = NULL; +CK_FUNCTION_LIST_PTR p11t_module_funcs = NULL; static CK_C_INITIALIZE_ARGS init_args; static int is_initialized = 0; @@ -144,6 +144,7 @@ unlock_mutex (void *mutex) void p11t_module_load(const char *filename) { + CK_FUNCTION_LIST_PTR list; CK_C_GetFunctionList get_function_list; CK_RV rv; @@ -157,15 +158,24 @@ p11t_module_load(const char *filename) p11t_msg_fatal("couldn't find C_GetFunctionList function in library: %s: %s", filename, dlerror()); /* Get the function list */ - rv = (get_function_list)(&p11_funcs); + rv = (get_function_list)(&p11t_module_funcs); if(rv != CKR_OK) p11t_msg_fatal("couldn't get function list: %s", p11t_msg_rv(rv)); /* Make sure we have a compatible version */ - if(p11_funcs->version.major != CRYPTOKI_VERSION_MAJOR) + if(p11t_module_funcs->version.major != CRYPTOKI_VERSION_MAJOR) p11t_msg_fatal("incompatible version of pkcs11 module: %d.%d", - (int)p11_funcs->version.major, - (int)p11_funcs->version.minor); + (int)p11t_module_funcs->version.major, + (int)p11t_module_funcs->version.minor); + + /** C_GetFunctionList */ + rv = (p11t_module_funcs->C_GetFunctionList)(&list); + if(rv != CKR_OK) + p11t_msg_print("C_GetFunctionList call through function list failed: %s", p11t_msg_rv(rv)); + + /** - See if returns same data as library entry point */ + if(!memcmp(list, p11t_module_funcs, sizeof(*list)) != 0) + p11t_msg_print("function lists returned directly and recursively differ"); } static void @@ -173,9 +183,12 @@ initialize_common(const char *mode) { CK_RV rv; - assert(p11_funcs); + /** C_Initialize **/ + + assert(p11t_module_funcs); - rv = (p11_funcs->C_Initialize) (&init_args); + /** - Normal call */ + rv = (p11t_module_funcs->C_Initialize) (&init_args); if (rv != CKR_OK) { if(rv != CKR_CANT_LOCK) @@ -190,6 +203,7 @@ initialize_common(const char *mode) static void initialize_locking_1(const char *initstr) { + /** - Locking: no threads */ memset(&init_args, 0, sizeof (init_args)); init_args.pReserved = (void*)initstr; initialize_common("locking mode 1: no threads"); @@ -198,6 +212,7 @@ initialize_locking_1(const char *initstr) static void initialize_locking_2(const char *initstr) { + /** - Locking: os locking */ memset(&init_args, 0, sizeof (init_args)); init_args.flags = CKF_OS_LOCKING_OK; init_args.pReserved = (void*)initstr; @@ -207,6 +222,7 @@ initialize_locking_2(const char *initstr) static void initialize_locking_3(const char *initstr) { + /** - Locking: app locking */ memset(&init_args, 0, sizeof (init_args)); init_args.flags = 0; init_args.CreateMutex = create_mutex; @@ -220,6 +236,7 @@ initialize_locking_3(const char *initstr) static void initialize_locking_4(const char *initstr) { + /** - Locking: either locking */ memset(&init_args, 0, sizeof (init_args)); init_args.flags = CKF_OS_LOCKING_OK; init_args.CreateMutex = create_mutex; @@ -236,14 +253,18 @@ p11t_module_initialize(const char *initstr) CK_INFO info; CK_RV rv; - assert(p11_funcs); + assert(p11t_module_funcs); - /* Some invalid use without initializing */ - rv = (p11_funcs->C_GetInfo)(&info); - if(rv != CKR_CRYPTOKI_NOT_INITIALIZED) - p11t_msg_print("shouldn't run without initialize: %s", p11t_msg_rv(rv)); + /** - Calls without initializing */ + rv = (p11t_module_funcs->C_GetInfo)(&info); + p11t_check_returns("shouldn't run without initialize: %s", rv, CKR_CRYPTOKI_NOT_INITIALIZED); - /* The various different locking modes */ + /** - NULL argument */ + rv = (p11t_module_funcs->C_Initialize) (NULL); + p11t_check_returns("should succeed with null argument", rv, CKR_OK); + p11t_module_finalize(); + + /** - Multiple initialize with C_Finalize between */ initialize_locking_1(initstr); p11t_module_finalize(); initialize_locking_2(initstr); @@ -255,8 +276,8 @@ p11t_module_initialize(const char *initstr) if(!is_initialized) p11t_msg_fatal("liberal locking strategy failed, can't continue"); - /* Double initialize */ - rv = (p11_funcs->C_Initialize) (&init_args); + /** - Double initialize in a row */ + rv = (p11t_module_funcs->C_Initialize) (&init_args); if (rv != CKR_CRYPTOKI_ALREADY_INITIALIZED) { p11t_msg_print("double initialize should return CKR_CRYPTOKI_ALREADY_INITIALIZED: %s", p11t_msg_rv(rv)); @@ -272,14 +293,19 @@ p11t_module_finalize(void) { CK_RV rv; + /** C_Finalize */ if(is_initialized) { - assert(p11_funcs); - rv = p11_funcs->C_Finalize(NULL); - if(rv != CKR_OK) - p11t_msg_print("C_Finalize failed: %s", p11t_msg_rv(rv)); + /** - Normal call */ + assert(p11t_module_funcs); + rv = p11t_module_funcs->C_Finalize(NULL); + p11t_check_returns("C_Finalize", rv, CKR_OK); is_initialized = 0; } + + /** - Double finalize in a row */ + rv = p11t_module_funcs->C_Finalize(NULL); + p11t_check_returns("C_Finalize", rv, CKR_CRYPTOKI_NOT_INITIALIZED); } void diff --git a/src/p11-tests.c b/src/p11-tests.c index b871533..bb67dd7 100644 --- a/src/p11-tests.c +++ b/src/p11-tests.c @@ -35,9 +35,14 @@ main(int argc, char* argv[]) if(argc < 1 || argc > 2) usage(); + /* Basic module tests */ p11t_module_load(argv[0]); p11t_module_initialize(argc == 2 ? argv[1] : NULL); + p11t_info_tests(); + + /* Remaining module tests */ + p11t_module_finalize(); p11t_module_unload(); return 0; diff --git a/src/p11-tests.h b/src/p11-tests.h index cf37346..89b856c 100644 --- a/src/p11-tests.h +++ b/src/p11-tests.h @@ -7,7 +7,7 @@ #include /* ------------------------------------------------------------------- - * message.c + * msg.c */ const char* p11t_msg_rv(CK_RV rv); @@ -17,13 +17,51 @@ void p11t_msg_print(const char *message, ...); void p11t_msg_fatal(const char *message, ...); void p11t_msg_prefix(const char *prefix); +#define p11t_msg_here() \ + (__func__ "() at " __FILE__ ":" __LINE__) + +/* ------------------------------------------------------------------- + * check.c + */ + +int p11t_check_returns(const char *message, CK_RV have, CK_RV want); + +#define p11t_check_padded(msg, padded) \ + (p11t_check_padded_len((msg), (padded), sizeof(padded))) + +int p11t_check_padded_len(const char *message, const CK_UTF8CHAR_PTR padded, CK_ULONG length); + +int p11t_check_ulong(const char *message, CK_ULONG have, CK_ULONG want); + +int p11t_check_mask(const char *message, CK_ULONG flags, CK_ULONG mask); + +/* ------------------------------------------------------------------- + * info.c + */ + +extern CK_INFO p11t_info_global; + +extern CK_ULONG p11t_info_slot_count; +extern CK_SLOT_ID_PTR p11t_info_slot_ids; +extern CK_SLOT_INFO_PTR p11t_info_slot_info; +extern CK_TOKEN_INFO_PTR p11t_info_token_info; + +extern CK_ULONG p11t_info_mech_count; +extern CK_MECHANISM_TYPE_PTR p11t_info_mech_types; +extern CK_MECHANISM_INFO_PTR p11t_info_mech_info; + +void p11t_info_tests(void); + /* ------------------------------------------------------------------- * module.c */ +extern CK_FUNCTION_LIST_PTR p11t_module_funcs; + void p11t_module_load(const char *filename); +void p11t_module_unload(void); + void p11t_module_initialize(const char *initstr); void p11t_module_finalize(void); -void p11t_module_unload(void); #endif /* P11TESTST_H_ */ -- cgit v1.2.3