diff --git a/src/pkcs11/function_table.c b/src/pkcs11/function_table.c index a54ee79f..a6043630 100644 --- a/src/pkcs11/function_table.c +++ b/src/pkcs11/function_table.c @@ -1,7 +1,7 @@ #include "sc-pkcs11.h" CK_FUNCTION_LIST function_list = { - { 2, 10 }, + { 2, 11 }, // generic.c C_Initialize, C_Finalize, diff --git a/src/pkcs11/generic.c b/src/pkcs11/generic.c index 23ae918f..eda49a36 100644 --- a/src/pkcs11/generic.c +++ b/src/pkcs11/generic.c @@ -8,7 +8,8 @@ #include "../sc.h" struct sc_context *ctx = NULL; -struct sc_pkcs15_card *p15card = NULL; +struct sc_pkcs15_card *p15card[PKCS11_MAX_CARDS]; +struct pkcs11_session *session[PKCS11_MAX_SESSIONS]; void LOG(char *format, ...) { @@ -26,11 +27,13 @@ void LOG(char *format, ...) CK_RV C_Initialize(CK_VOID_PTR pReserved) { - int reader_count, reader_buf_size, rv; - char *reader_buf, *p; + int rv; LOG("C_Initialize(0x%x)\n", pReserved); + memset(session, 0, sizeof(session)); + memset(p15card, 0, sizeof(p15card)); + ctx = NULL; rv = sc_establish_context(&ctx); if (rv != 0) { @@ -42,13 +45,16 @@ CK_RV C_Initialize(CK_VOID_PTR pReserved) CK_RV C_Finalize(CK_VOID_PTR pReserved) { - int i; + int i; LOG("C_Finalize(0x%x)\n", pReserved); - if (p15card != NULL) { - sc_disconnect_card(p15card->card); - sc_pkcs15_destroy(p15card); + for (i=0; i < PKCS11_MAX_CARDS; i++) { + if (p15card[i] != NULL) { + sc_disconnect_card(p15card[i]->card); + sc_pkcs15_destroy(p15card[i]); + p15card[i] = NULL; + } } sc_destroy_context(ctx); @@ -60,7 +66,7 @@ CK_RV C_GetInfo(CK_INFO_PTR pInfo) LOG("C_GetInfo(0x%x)\n", pInfo); memset(pInfo, 0, sizeof(CK_INFO)); pInfo->cryptokiVersion.major = 2; - pInfo->cryptokiVersion.minor = 10; + pInfo->cryptokiVersion.minor = 11; strcpy(pInfo->manufacturerID, "Timo Teras & Juha Yrjola"); strcpy(pInfo->libraryDescription, "PC/SC PKCS#15 SmartCard reader"); pInfo->libraryVersion.major = 0; @@ -79,7 +85,7 @@ CK_RV C_GetSlotList(CK_BBOOL tokenPresent, /* only slots with token prese CK_SLOT_ID_PTR pSlotList, /* receives the array of slot IDs */ CK_ULONG_PTR pulCount) /* receives the number of slots */ { - int i, num; + int i; LOG("C_GetSlotList(%d, 0x%x, 0x%x)\n", tokenPresent, pSlotList, pulCount); @@ -88,10 +94,14 @@ CK_RV C_GetSlotList(CK_BBOOL tokenPresent, /* only slots with token prese return CKR_OK; } - num = ctx->reader_count > *pulCount ? *pulCount : ctx->reader_count; - for (i = 0; i < num; i++) + if (*pulCount < ctx->reader_count) { + *pulCount = ctx->reader_count; + return CKR_BUFFER_TOO_SMALL; + } + + for (i = 0; i < ctx->reader_count; i++) pSlotList[i] = i; - *pulCount = num; + *pulCount = ctx->reader_count; return CKR_OK; } @@ -108,13 +118,14 @@ CK_RV C_GetSlotInfo(CK_SLOT_ID slotID, CK_SLOT_INFO_PTR pInfo) sizeof(pInfo->slotDescription)); strcpy(pInfo->manufacturerID, "PC/SC interface"); pInfo->flags = CKF_REMOVABLE_DEVICE | CKF_HW_SLOT; - if (sc_detect_card(ctx, slotID) == 1) + if (sc_detect_card(ctx, slotID) == 1) { + LOG("Detected card in slot %d\n", slotID); pInfo->flags |= CKF_TOKEN_PRESENT; - else { - if (p15card != NULL) { - sc_disconnect_card(p15card->card); - sc_pkcs15_destroy(p15card); - p15card = NULL; + } else { + if (p15card[slotID] != NULL) { + sc_disconnect_card(p15card[slotID]->card); + sc_pkcs15_destroy(p15card[slotID]); + p15card[slotID] = NULL; } } pInfo->hardwareVersion.major = 1; @@ -134,18 +145,21 @@ CK_RV C_GetTokenInfo(CK_SLOT_ID slotID, CK_TOKEN_INFO_PTR pInfo) memset(pInfo, 0, sizeof(CK_SLOT_INFO)); - if (p15card == NULL) { + if (p15card[slotID] == NULL) { r = sc_connect_card(ctx, slotID, &card); - if (r) - return CKR_DEVICE_ERROR; - r = sc_pkcs15_init(card, &p15card); if (r) { + LOG("Failed to connect in slot %d (r=%d)\n", slotID, r); + return CKR_DEVICE_ERROR; + } + r = sc_pkcs15_init(card, &p15card[slotID]); + if (r) { + LOG("sc_pkcs15_init failed for slot %d (r=%d)\n", slotID, r); /* PKCS#15 compatible SC probably not present */ sc_disconnect_card(card); return CKR_DEVICE_ERROR; } } - strcpy(pInfo->label, p15card->label); + strcpy(pInfo->label, p15card[slotID]->label); strcpy(pInfo->manufacturerID, "unknown"); strcpy(pInfo->model, "unknown"); strcpy(pInfo->serialNumber, "unknown"); @@ -172,15 +186,35 @@ CK_RV C_GetMechanismList(CK_SLOT_ID slotID, CK_MECHANISM_TYPE_PTR pMechanismList, CK_ULONG_PTR pulCount) { - LOG("C_GetMechanismList(%d, 0x%x, 0x%x)\n", slotID, pMechanismList, pulCount); - return CKR_FUNCTION_NOT_SUPPORTED; + static const CK_MECHANISM_TYPE mechanism_list[] = { + CKM_RSA_PKCS, + CKM_RSA_X_509 + }; + const int numMechanisms = sizeof(mechanism_list) / sizeof(mechanism_list[0]); + + LOG("C_GetMechanismList(%d, 0x%x, 0x%x)\n", slotID, pMechanismList, pulCount); + if (slotID < 0 || slotID >= ctx->reader_count) + return CKR_SLOT_ID_INVALID; + + if (pMechanismList == NULL_PTR) { + *pulCount = numMechanisms; + return CKR_OK; + } + + if (*pulCount < numMechanisms) { + *pulCount = numMechanisms; + return CKR_BUFFER_TOO_SMALL; + } + memcpy(pMechanismList, &mechanism_list, sizeof(mechanism_list)); + + return CKR_OK; } CK_RV C_GetMechanismInfo(CK_SLOT_ID slotID, CK_MECHANISM_TYPE type, CK_MECHANISM_INFO_PTR pInfo) { - LOG("C_GetMechanismInfo(%d, %d, 0x%x)\n", slotID, type, pInfo); + LOG("C_GetMechanismInfo(%d, %d, 0x%x)\n", slotID, type, pInfo); return CKR_FUNCTION_NOT_SUPPORTED; } @@ -193,20 +227,4 @@ CK_RV C_InitToken(CK_SLOT_ID slotID, return CKR_FUNCTION_NOT_SUPPORTED; } -CK_RV C_InitPIN(CK_SESSION_HANDLE hSession, - CK_CHAR_PTR pPin, - CK_ULONG ulPinLen) -{ - LOG("C_InitPIN(%d, '%s', %d)\n", hSession, pPin, ulPinLen); - return CKR_FUNCTION_NOT_SUPPORTED; -} -CK_RV C_SetPIN(CK_SESSION_HANDLE hSession, - CK_CHAR_PTR pOldPin, - CK_ULONG ulOldLen, - CK_CHAR_PTR pNewPin, - CK_ULONG ulNewLen) -{ - LOG("C_SetPIN(%d, '%s', %d, '%s', %d)\n", hSession, pOldPin, ulOldLen, pNewPin, ulNewLen); - return CKR_FUNCTION_NOT_SUPPORTED; -} diff --git a/src/pkcs11/sc-pkcs11.h b/src/pkcs11/sc-pkcs11.h index a1711f66..57f8ffdd 100644 --- a/src/pkcs11/sc-pkcs11.h +++ b/src/pkcs11/sc-pkcs11.h @@ -1,13 +1,28 @@ #ifndef __sc_pkcs11_h__ #define __sc_pkcs11_h__ -#include "pkcs11/pkcs11.h" #include +#include "pkcs11/pkcs11.h" +#include "../sc.h" + +#define PKCS11_MAX_CARDS 4 +#define PKCS11_MAX_SESSIONS 8 + +struct pkcs11_session { + int slot; + CK_STATE state; + CK_FLAGS flags; + CK_NOTIFY notify_callback; + CK_VOID_PTR notify_parameter; +}; + extern CK_FUNCTION_LIST function_list; extern void LOG(char *format, ...); -extern SCARDCONTEXT sc_ctx; +extern struct sc_context *ctx; +extern struct sc_pkcs15_card *p15card[PKCS11_MAX_CARDS]; +extern struct pkcs11_session *session[PKCS11_MAX_SESSIONS]; #endif diff --git a/src/pkcs11/session.c b/src/pkcs11/session.c index 17e29ef3..490b69f2 100644 --- a/src/pkcs11/session.c +++ b/src/pkcs11/session.c @@ -1,3 +1,5 @@ +#include +#include #include "sc-pkcs11.h" @@ -7,29 +9,111 @@ CK_RV C_OpenSession(CK_SLOT_ID slotID, /* the slot's ID */ CK_NOTIFY Notify, /* notification callback function */ CK_SESSION_HANDLE_PTR phSession) /* receives new session handle */ { - return CKR_FUNCTION_NOT_SUPPORTED; + int i, rc; + struct pkcs11_session *ses; + + LOG("C_OpenSession(%d, 0x%x, 0x%x, 0x%x, 0x%x)\n", + slotID, flags, pApplication, Notify, phSession); + + if (!(flags & CKF_SERIAL_SESSION)) + return CKR_SESSION_PARALLEL_NOT_SUPPORTED; + + for (i=0; i= PKCS11_MAX_SESSIONS) + return CKR_SESSION_COUNT; + + if (p15card[slotID] == NULL) { + struct sc_card *card; + + rc = sc_connect_card(ctx, slotID, &card); + if (rc) { + LOG("Failed to connect in slot %d (rc=%d)\n", slotID, rc); + return CKR_DEVICE_ERROR; + } + rc = sc_pkcs15_init(card, &p15card[slotID]); + if (rc) { + LOG("sc_pkcs15_init failed for slot %d (rc=%d)\n", slotID, rc); + /* PKCS#15 compatible SC probably not present */ + sc_disconnect_card(card); + return CKR_DEVICE_ERROR; + } + } + + if (p15card[slotID]->pins[0].magic != SC_PKCS15_PIN_MAGIC) { + struct sc_pkcs15_pin_object pin; + int c = 0; + + LOG("Searching for PIN codes...\n"); + while (sc_pkcs15_read_pin_object(p15card[slotID], ++c, &pin) == 0) { + sc_pkcs15_print_pin_object(&pin); + } + } + + ses = session[i] = (struct pkcs11_session*) malloc(sizeof(struct pkcs11_session)); + memset(ses, 0, sizeof(struct pkcs11_session)); + ses->slot = slotID; + if (flags & CKF_RW_SESSION) + ses->state = CKS_RW_PUBLIC_SESSION; + else ses->state = CKS_RO_PUBLIC_SESSION; + ses->flags = flags; + ses->notify_callback = Notify; + ses->notify_parameter = pApplication; + + *phSession = i; + return CKR_OK; } CK_RV C_CloseSession(CK_SESSION_HANDLE hSession) /* the session's handle */ { - return CKR_FUNCTION_NOT_SUPPORTED; + LOG("C_CloseSession(0x%x)\n", hSession); + if (hSession < 0 || hSession >= PKCS11_MAX_SESSIONS || session[hSession] == NULL) + return CKR_SESSION_HANDLE_INVALID; + + free(session[hSession]); + session[hSession] = NULL; + return CKR_OK; } CK_RV C_CloseAllSessions(CK_SLOT_ID slotID) /* the token's slot */ { - return CKR_FUNCTION_NOT_SUPPORTED; + int i; + + LOG("C_CloseAllSessions(%d)\n", slotID); + for (i = 0; i < PKCS11_MAX_SESSIONS; i++) { + if (session[i] && session[i]->slot == slotID) + C_CloseSession(i); + } + + return CKR_OK; } CK_RV C_GetSessionInfo(CK_SESSION_HANDLE hSession, /* the session's handle */ CK_SESSION_INFO_PTR pInfo) /* receives session information */ { - return CKR_FUNCTION_NOT_SUPPORTED; + struct pkcs11_session *ses; + + LOG("C_GetSessionInfo(0x%x, 0x%x)\n", hSession, pInfo); + if (hSession < 0 || hSession >= PKCS11_MAX_SESSIONS || session[hSession] == NULL) + return CKR_SESSION_HANDLE_INVALID; + + ses = session[hSession]; + pInfo->slotID = ses->slot; + pInfo->state = ses->state; + pInfo->flags = ses->flags; + pInfo->ulDeviceError = 0; + + return CKR_OK; } CK_RV C_GetOperationState(CK_SESSION_HANDLE hSession, /* the session's handle */ CK_BYTE_PTR pOperationState, /* location receiving state */ CK_ULONG_PTR pulOperationStateLen) /* location receiving state length */ { + LOG("C_GetOperationState(0x%x, %0x%x, %d)\n", hSession, + pOperationState, pulOperationStateLen); return CKR_FUNCTION_NOT_SUPPORTED; } @@ -39,6 +123,9 @@ CK_RV C_SetOperationState(CK_SESSION_HANDLE hSession, /* the session' CK_OBJECT_HANDLE hEncryptionKey, /* handle of en/decryption key */ CK_OBJECT_HANDLE hAuthenticationKey) /* handle of sign/verify key */ { + LOG("C_SetOperationState(0x%x, 0x%x, %d, 0x%x, 0x%x)\n", + hSession, pOperationState, ulOperationStateLen, + hEncryptionKey, hAuthenticationKey); return CKR_FUNCTION_NOT_SUPPORTED; } @@ -47,12 +134,116 @@ CK_RV C_Login(CK_SESSION_HANDLE hSession, /* the session's handle */ CK_CHAR_PTR pPin, /* the user's PIN */ CK_ULONG ulPinLen) /* the length of the PIN */ { - return CKR_FUNCTION_NOT_SUPPORTED; + struct pkcs11_session *ses; + struct sc_pkcs15_card *card; + int rc; + + LOG("C_Login(0x%x, %d, 0x%x, %d)\n", hSession, userType, pPin, ulPinLen); + if (hSession < 0 || hSession >= PKCS11_MAX_SESSIONS || session[hSession] == NULL) + return CKR_SESSION_HANDLE_INVALID; + + if (userType != CKU_USER) { + LOG("Login tried for Security Officer\n"); + return CKR_USER_TYPE_INVALID; + } + + if (ulPinLen < 4 || ulPinLen > 8) + return CKR_PIN_LEN_RANGE; + + ses = session[hSession]; + card = p15card[ses->slot]; + + if (ses->state != CKS_RO_PUBLIC_SESSION && + ses->state != CKS_RW_PUBLIC_SESSION) + return CKR_USER_ALREADY_LOGGED_IN; + + LOG("Master PIN code verification starts.\n"); + rc = sc_pkcs15_verify_pin(card, &card->pins[0], pPin, ulPinLen); + switch (rc) { + case 0: + LOG("Master PIN code verified succesfully.\n"); + if (ses->state == CKS_RO_PUBLIC_SESSION) + ses->state = CKS_RO_USER_FUNCTIONS; + else ses->state = CKS_RW_USER_FUNCTIONS; + break; + case SC_ERROR_PIN_CODE_INCORRECT: + LOG("Master PIN code INVALID!\n"); + return CKR_PIN_INCORRECT; + default: + LOG("Device error!? rc=%d\n", rc); + return CKR_DEVICE_ERROR; + } + + return CKR_OK; } CK_RV C_Logout(CK_SESSION_HANDLE hSession) /* the session's handle */ { + struct pkcs11_session *ses; + + LOG("C_Logout(0x%x)\n", hSession); + if (hSession < 0 || hSession >= PKCS11_MAX_SESSIONS || session[hSession] == NULL) + return CKR_SESSION_HANDLE_INVALID; + + ses = session[hSession]; + switch (ses->state) { + case CKS_RO_PUBLIC_SESSION: + case CKS_RW_PUBLIC_SESSION: + return CKR_USER_NOT_LOGGED_IN; + case CKS_RO_USER_FUNCTIONS: + ses->state = CKS_RO_PUBLIC_SESSION; + break; + case CKS_RW_USER_FUNCTIONS: + case CKS_RW_SO_FUNCTIONS: + ses->state = CKS_RW_PUBLIC_SESSION; + break; + } + + return CKR_OK; +} + +CK_RV C_InitPIN(CK_SESSION_HANDLE hSession, + CK_CHAR_PTR pPin, + CK_ULONG ulPinLen) +{ + LOG("C_InitPIN(%d, '%s', %d)\n", hSession, pPin, ulPinLen); return CKR_FUNCTION_NOT_SUPPORTED; } +CK_RV C_SetPIN(CK_SESSION_HANDLE hSession, + CK_CHAR_PTR pOldPin, + CK_ULONG ulOldLen, + CK_CHAR_PTR pNewPin, + CK_ULONG ulNewLen) +{ + struct pkcs11_session *ses; + struct sc_pkcs15_card *card; + int rc; + + LOG("C_SetPIN(%d, '%s', %d, '%s', %d)\n", hSession, pOldPin, ulOldLen, pNewPin, ulNewLen); + if (hSession < 0 || hSession >= PKCS11_MAX_SESSIONS || session[hSession] == NULL) + return CKR_SESSION_HANDLE_INVALID; + + //if (!(ses->flags & CKF_RW_SESSION)) + // return CKR_SESSION_READ_ONLY; + + ses = session[hSession]; + card = p15card[ses->slot]; + + LOG("Master PIN code update starts.\n"); + rc = sc_pkcs15_change_pin(card, &card->pins[0], pOldPin, ulOldLen, pNewPin, ulNewLen); + switch (rc) { + case 0: + LOG("Master PIN code CHANGED succesfully.\n"); + break; + case SC_ERROR_PIN_CODE_INCORRECT: + LOG("Master PIN code INVALID!\n"); + return CKR_PIN_INCORRECT; + default: + LOG("Device error!? rc=%d\n", rc); + return CKR_DEVICE_ERROR; + } + + return CKR_OK; +}