/* gcc -o sclist sclist.c -ldl */ #include #include #include #include #include #include #include #include static CK_RV (*c_get_function_list)(CK_FUNCTION_LIST_PTR_PTR); static CK_FUNCTION_LIST_PTR funcs; char *gets_noecho(unsigned *l); void pstrl(const char **strlist, unsigned size, unsigned ind); void printhexstring(char *data, unsigned size); int ckr_errprint(const char *msg, CK_RV status); void *loadfile(const char *filename, off_t *filesize); #define NOBJECTCLASSES 10 const char *objectclasses[NOBJECTCLASSES]= { "Data", "Certificate", "Public key", "Private key", "Secret key", "HW feature", "Domain parameters", "Mechanism", "OTP key", "Profile" }; #define MAXSLOTS 10 #define MAXATTRS 10 #define ATTRBUFSIZE 2048 #define MAXOBJS 100 int main(int argc, char **argv) { char *derfile= NULL; unsigned long long off_len[6]; void *dlhandle; char *pin; off_t derlen; unsigned pinlen; int argind; int dologin= 0; CK_ULONG nslots, plainsize; CK_SLOT_ID slotIDs[MAXSLOTS]; CK_SLOT_INFO slotinf; CK_TOKEN_INFO tokinf; CK_SESSION_HANDLE sh; CK_SESSION_INFO sesinf; char attrbuf[ATTRBUFSIZE]; CK_ATTRIBUTE attrlist[MAXATTRS]; CK_OBJECT_CLASS objclass; CK_BBOOL maybe; CK_OBJECT_HANDLE objs[MAXOBJS]; CK_ULONG objcount, objind; CK_MECHANISM mech; CK_RV status; if( argc == 3 && argv[1][0] == '-' && argv[1][1] == 'l' && argv[1][2] == 0 ) dologin= 1; else if( argc != 2 + dologin ) { printf("usage: sclist [-l] \n" "List keys on a smart card using the given library, logging in to the card if -l\n" "is passed.\n"); return 1; } dlhandle= dlopen(argv[argc-1], RTLD_LAZY); if( ! dlhandle ) { printf("Error loading module lib %s: %s\n", argv[argc-1], dlerror()); return 1; } c_get_function_list= (CK_RV(*)(CK_FUNCTION_LIST_PTR_PTR))dlsym(dlhandle, "C_GetFunctionList"); if( ! c_get_function_list ) { printf("Error finding function list function: %s\n", dlerror()); goto dlerr; } status= (*c_get_function_list)(&funcs); if( ckr_errprint("C_GetFunctionList", status) || !funcs ) goto dlerr; status= funcs->C_Initialize(NULL); if( ckr_errprint("C_Initialize", status) ) goto dlerr; status= funcs->C_GetSlotList(CK_TRUE, NULL, &nslots); if( ckr_errprint("C_GetSlotList", status) ) goto ckerr; if( nslots <= 0 || nslots > MAXSLOTS ) { if( nslots <= 0 ) printf("No slots with tokens\n"); else printf("Too many slots to obtain slot IDs\n"); goto ckerr; } status= funcs->C_GetSlotList(CK_TRUE, slotIDs, &nslots); if( ckr_errprint("C_GetSlotList", status) ) goto ckerr; status= funcs->C_OpenSession(slotIDs[0], CKF_SERIAL_SESSION, NULL, NULL, &sh); if( ckr_errprint("C_OpenSession", status) ) goto ckerr; if( dologin ) { printf("Enter PIN:\n"); fflush(stdout); pin= gets_noecho(&pinlen); if( ! pin ) { printf("\nCould not get PIN\n"); goto seserr; } status= funcs->C_Login(sh, CKU_USER, pin, pinlen); memset(pin, 0, pinlen); if( ckr_errprint("C_Login", status) ) goto seserr; } attrlist[0].type= CKA_TOKEN; maybe= CK_TRUE; attrlist[0].pValue= &maybe; attrlist[0].ulValueLen= sizeof(maybe); status= funcs->C_FindObjectsInit(sh, attrlist, 1); if( ckr_errprint("C_FindObjectsInit", status) ) goto seserr; status= funcs->C_FindObjects(sh, objs, MAXOBJS, &objcount); if( ckr_errprint("C_FindObjects", status) ) goto seserr; status= funcs->C_FindObjectsFinal(sh); if( ckr_errprint("C_FindObjectsFinal", status) ) goto seserr; if( objcount == 0 ) { printf("No objects found\n"); goto seserr; } for( objind= 0; objind < objcount; ++objind ) { printf("\nObject with index %u\n", (unsigned)objind); printf("Class: "); attrlist[0].type= CKA_CLASS; attrlist[0].pValue= &objclass; attrlist[0].ulValueLen= sizeof(objclass); status= funcs->C_GetAttributeValue(sh, objs[objind], attrlist, 1); if( ! ckr_errprint("C_GetAttributeValue", status) ) printf("%s\n", ((unsigned)objclass) < NOBJECTCLASSES ? objectclasses[objclass] : "?"); printf("ID: "); attrlist[0].type= CKA_ID; attrlist[0].pValue= attrbuf; attrlist[0].ulValueLen= ATTRBUFSIZE; status= funcs->C_GetAttributeValue(sh, objs[objind], attrlist, 1); if( ! ckr_errprint("C_GetAttributeValue", status) ) printhexstring(attrlist[0].pValue, attrlist[0].ulValueLen); if( objclass == CKO_CERTIFICATE ) { printf("Serial number (DER encoded): "); attrlist[0].type= CKA_SERIAL_NUMBER; attrlist[0].pValue= attrbuf; attrlist[0].ulValueLen= ATTRBUFSIZE; status= funcs->C_GetAttributeValue(sh, objs[objind], attrlist, 1); if( ! ckr_errprint("C_GetAttributeValue", status) ) printhexstring(attrlist[0].pValue, attrlist[0].ulValueLen); } } status= funcs->C_CloseSession(sh); if( ckr_errprint("C_CloseSession", status) ) goto ckerr; status= funcs->C_Finalize(NULL); if( ckr_errprint("C_Finalize", status) ) goto dlerr; dlclose(dlhandle); return 0; seserr: status= funcs->C_CloseSession(sh); ckr_errprint("C_CloseSession", status); ckerr: status= funcs->C_Finalize(NULL); ckr_errprint("C_Finalize", status); dlerr: dlclose(dlhandle); free(derfile); return 1; } #define MAXNOECHOLEN 100 char *gets_noecho(unsigned *l) { static char buf[MAXNOECHOLEN]; struct termios old, new; char *in; unsigned len; int stdoutno; stdoutno= fileno(stdout); if( tcgetattr(stdoutno, &old) ) { perror("tcgetattr"); return NULL; } new= old; new.c_lflag &= ~ECHO; if( tcsetattr(stdoutno, TCSAFLUSH, &new) ) return NULL; in= fgets(buf, MAXNOECHOLEN, stdin); if( in ) { len= strlen(in); while( len > 0 && (in[len-1] == '\n' || in[len-1] == '\r') ) --len; in[len]= 0; } tcsetattr(stdoutno, TCSAFLUSH, &old); fputs("\n", stdout); if( in && l ) *l= len; return in; } /* print string list entry, with index check */ void pstrl(const char **strlist, unsigned size, unsigned ind) { printf("%s", ind< size ? strlist[ind] : "?"); } void printhexstring(char *data, unsigned size) { unsigned i; for( i= 0; i< size; ++i ) printf("%02X", (unsigned)((unsigned char*)data)[i]); printf("\n"); } typedef struct { unsigned val; const char *str; } errstr; int cmp_errstr(const void *a, const void *b) { return (int)((errstr*)a)->val - (int)((errstr*)b)->val; } #define CKR_NSTRS 96 errstr ckr_strs[CKR_NSTRS]= { 0x00000000UL, "CKR_OK ", 0x00000001UL, "CKR_CANCEL ", 0x00000002UL, "CKR_HOST_MEMORY ", 0x00000003UL, "CKR_SLOT_ID_INVALID ", 0x00000005UL, "CKR_GENERAL_ERROR ", 0x00000006UL, "CKR_FUNCTION_FAILED ", 0x00000007UL, "CKR_ARGUMENTS_BAD ", 0x00000008UL, "CKR_NO_EVENT ", 0x00000009UL, "CKR_NEED_TO_CREATE_THREADS ", 0x0000000AUL, "CKR_CANT_LOCK ", 0x00000010UL, "CKR_ATTRIBUTE_READ_ONLY ", 0x00000011UL, "CKR_ATTRIBUTE_SENSITIVE ", 0x00000012UL, "CKR_ATTRIBUTE_TYPE_INVALID ", 0x00000013UL, "CKR_ATTRIBUTE_VALUE_INVALID ", 0x0000001BUL, "CKR_ACTION_PROHIBITED ", 0x00000020UL, "CKR_DATA_INVALID ", 0x00000021UL, "CKR_DATA_LEN_RANGE ", 0x00000030UL, "CKR_DEVICE_ERROR ", 0x00000031UL, "CKR_DEVICE_MEMORY ", 0x00000032UL, "CKR_DEVICE_REMOVED ", 0x00000040UL, "CKR_ENCRYPTED_DATA_INVALID ", 0x00000041UL, "CKR_ENCRYPTED_DATA_LEN_RANGE ", 0x00000050UL, "CKR_FUNCTION_CANCELED ", 0x00000051UL, "CKR_FUNCTION_NOT_PARALLEL ", 0x00000054UL, "CKR_FUNCTION_NOT_SUPPORTED ", 0x00000060UL, "CKR_KEY_HANDLE_INVALID ", 0x00000062UL, "CKR_KEY_SIZE_RANGE ", 0x00000063UL, "CKR_KEY_TYPE_INCONSISTENT ", 0x00000064UL, "CKR_KEY_NOT_NEEDED ", 0x00000065UL, "CKR_KEY_CHANGED ", 0x00000066UL, "CKR_KEY_NEEDED ", 0x00000067UL, "CKR_KEY_INDIGESTIBLE ", 0x00000068UL, "CKR_KEY_FUNCTION_NOT_PERMITTED ", 0x00000069UL, "CKR_KEY_NOT_WRAPPABLE ", 0x0000006AUL, "CKR_KEY_UNEXTRACTABLE ", 0x00000070UL, "CKR_MECHANISM_INVALID ", 0x00000071UL, "CKR_MECHANISM_PARAM_INVALID ", 0x00000082UL, "CKR_OBJECT_HANDLE_INVALID ", 0x00000090UL, "CKR_OPERATION_ACTIVE ", 0x00000091UL, "CKR_OPERATION_NOT_INITIALIZED ", 0x000000A0UL, "CKR_PIN_INCORRECT ", 0x000000A1UL, "CKR_PIN_INVALID ", 0x000000A2UL, "CKR_PIN_LEN_RANGE ", 0x000000A3UL, "CKR_PIN_EXPIRED ", 0x000000A4UL, "CKR_PIN_LOCKED ", 0x000000B0UL, "CKR_SESSION_CLOSED ", 0x000000B1UL, "CKR_SESSION_COUNT ", 0x000000B3UL, "CKR_SESSION_HANDLE_INVALID ", 0x000000B4UL, "CKR_SESSION_PARALLEL_NOT_SUPPORTED ", 0x000000B5UL, "CKR_SESSION_READ_ONLY ", 0x000000B6UL, "CKR_SESSION_EXISTS ", 0x000000B7UL, "CKR_SESSION_READ_ONLY_EXISTS ", 0x000000B8UL, "CKR_SESSION_READ_WRITE_SO_EXISTS ", 0x000000C0UL, "CKR_SIGNATURE_INVALID ", 0x000000C1UL, "CKR_SIGNATURE_LEN_RANGE ", 0x000000D0UL, "CKR_TEMPLATE_INCOMPLETE ", 0x000000D1UL, "CKR_TEMPLATE_INCONSISTENT ", 0x000000E0UL, "CKR_TOKEN_NOT_PRESENT ", 0x000000E1UL, "CKR_TOKEN_NOT_RECOGNIZED ", 0x000000E2UL, "CKR_TOKEN_WRITE_PROTECTED ", 0x000000F0UL, "CKR_UNWRAPPING_KEY_HANDLE_INVALID ", 0x000000F1UL, "CKR_UNWRAPPING_KEY_SIZE_RANGE ", 0x000000F2UL, "CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT ", 0x00000100UL, "CKR_USER_ALREADY_LOGGED_IN ", 0x00000101UL, "CKR_USER_NOT_LOGGED_IN ", 0x00000102UL, "CKR_USER_PIN_NOT_INITIALIZED ", 0x00000103UL, "CKR_USER_TYPE_INVALID ", 0x00000104UL, "CKR_USER_ANOTHER_ALREADY_LOGGED_IN ", 0x00000105UL, "CKR_USER_TOO_MANY_TYPES ", 0x00000110UL, "CKR_WRAPPED_KEY_INVALID ", 0x00000112UL, "CKR_WRAPPED_KEY_LEN_RANGE ", 0x00000113UL, "CKR_WRAPPING_KEY_HANDLE_INVALID ", 0x00000114UL, "CKR_WRAPPING_KEY_SIZE_RANGE ", 0x00000115UL, "CKR_WRAPPING_KEY_TYPE_INCONSISTENT ", 0x00000120UL, "CKR_RANDOM_SEED_NOT_SUPPORTED ", 0x00000121UL, "CKR_RANDOM_NO_RNG ", 0x00000130UL, "CKR_DOMAIN_PARAMS_INVALID ", 0x00000140UL, "CKR_CURVE_NOT_SUPPORTED ", 0x00000150UL, "CKR_BUFFER_TOO_SMALL ", 0x00000160UL, "CKR_SAVED_STATE_INVALID ", 0x00000170UL, "CKR_INFORMATION_SENSITIVE ", 0x00000180UL, "CKR_STATE_UNSAVEABLE ", 0x00000190UL, "CKR_CRYPTOKI_NOT_INITIALIZED ", 0x00000191UL, "CKR_CRYPTOKI_ALREADY_INITIALIZED ", 0x000001A0UL, "CKR_MUTEX_BAD ", 0x000001A1UL, "CKR_MUTEX_NOT_LOCKED ", 0x000001B0UL, "CKR_NEW_PIN_MODE ", 0x000001B1UL, "CKR_NEXT_OTP ", 0x000001B5UL, "CKR_EXCEEDED_MAX_ITERATIONS ", 0x000001B6UL, "CKR_FIPS_SELF_TEST_FAILED ", 0x000001B7UL, "CKR_LIBRARY_LOAD_FAILED ", 0x000001B8UL, "CKR_PIN_TOO_WEAK ", 0x000001B9UL, "CKR_PUBLIC_KEY_INVALID ", 0x00000200UL, "CKR_FUNCTION_REJECTED ", 0x00000201UL, "CKR_TOKEN_RESOURCE_EXCEEDED ", 0x00000202UL, "CKR_OPERATION_CANCEL_FAILED ", }; int ckr_errprint(const char *msg, CK_RV status) { errstr thiserr, *found; if( status == CKR_OK ) return 0; thiserr.val= status; found= bsearch(&thiserr, ckr_strs, CKR_NSTRS, sizeof(errstr), cmp_errstr); if( found ) printf("%s: %s\n", msg, found->str); else printf("%s: 0x%X\n", msg, thiserr.val); fflush(stdout); return 1; } /* Read complete file into RAM after allocating buffer of appropriate size. */ void *loadfile(const char *filename, off_t *filesize) { FILE *in; void *buf; off_t size; in= fopen(filename, "rb"); if( !in ) { perror("Could not open input file for reading"); fprintf(stderr, "Could not open `%s' for reading.\n", filename); return NULL; } fseeko(in, 0, SEEK_END); size= ftello(in); fseeko(in, 0, SEEK_SET); buf= malloc(size); if( !buf ) { fprintf(stderr, "Could not allocate memory for loading `%s'.\n", filename); fclose(in); return NULL; } if( ferror(in) || fread(buf, 1, size, in) != size ) { perror("Error reading input file"); fprintf(stderr, "Error reading `%s'.\n", filename); free(buf); fclose(in); return NULL; } fclose(in); if( filesize ) *filesize= size; return buf; }