@@ -874,10 +874,16 @@ /** Extra certificates to include in token **/ struct cackey_pcsc_identity extra_certs[] = { #include "cackey_builtin_certs.h" }; +/* Protected Authentication Path command */ +#define CACKEY_PIN_COMMAND_DEFAULT_XSTR(str) CACKEY_PIN_COMMAND_DEFAULT_STR(str) +#define CACKEY_PIN_COMMAND_DEFAULT_STR(str) #str +static char *cackey_pin_command = NULL; +static char *cackey_pin_command_xonly = NULL; + /* PCSC Global Handles */ static LPSCARDCONTEXT cackey_pcsc_handle = NULL; static unsigned long cackey_getversion(void) { static unsigned long retval = 255; @@ -3054,10 +3060,17 @@ if (pin_len >= 8) { memcpy(cac_pin, pin, 8); } else { memcpy(cac_pin, pin, pin_len); } + + /* Reject PINs which are too short */ + if (pin_len < 5) { + CACKEY_DEBUG_PRINTF("Rejecting PIN which is too short (length = %lu, must be atleast 5)", pin_len); + + return(CACKEY_PCSC_E_BADPIN); + } /* PIV authentication uses a "key_reference" of 0x80 */ pcsc_identities = cackey_read_certs(slot, NULL, &num_certs); if (num_certs > 0 && pcsc_identities != NULL) { switch (pcsc_identities[0].id_type) { @@ -4135,10 +4148,30 @@ return(CKR_CANT_LOCK); } cackey_biglock_init = 1; } + + /* Define a command to prompt user for a PIN */ +#ifdef CACKEY_PIN_COMMAND_DEFAULT + cackey_pin_command = CACKEY_PIN_COMMAND_DEFAULT_XSTR(CACKEY_PIN_COMMAND_DEFAULT); +#endif +#ifdef CACKEY_PIN_COMMAND_XONLY_DEFAULT + cackey_pin_command_xonly = CACKEY_PIN_COMMAND_DEFAULT_XSTR(CACKEY_PIN_COMMAND_XONLY_DEFAULT); +#endif + + if (getenv("DISPLAY") != NULL) { + cackey_pin_command = cackey_pin_command_xonly; + } + + if (getenv("CACKEY_PIN_COMMAND_XONLY") != NULL && getenv("DISPLAY") != NULL) { + cackey_pin_command = getenv("CACKEY_PIN_COMMAND_XONLY"); + } + + if (getenv("CACKEY_PIN_COMMAND") != NULL) { + cackey_pin_command = getenv("CACKEY_PIN_COMMAND"); + } CACKEY_DEBUG_PRINTF("Returning CKR_OK (%i)", CKR_OK); return(CKR_OK); } @@ -4667,10 +4700,14 @@ pInfo->firmwareVersion.major = 0x00; pInfo->firmwareVersion.minor = 0x00; pInfo->flags = CKF_WRITE_PROTECTED | CKF_USER_PIN_INITIALIZED | CKF_TOKEN_INITIALIZED | cackey_slots[slotID].token_flags; + + if (cackey_pin_command != NULL) { + pInfo->flags |= CKF_PROTECTED_AUTHENTICATION_PATH; + } pInfo->ulMaxSessionCount = (sizeof(cackey_sessions) / sizeof(cackey_sessions[0])) - 1; pInfo->ulSessionCount = CK_UNAVAILABLE_INFORMATION; pInfo->ulMaxRwSessionCount = 0; pInfo->ulRwSessionCount = CK_UNAVAILABLE_INFORMATION; @@ -5130,13 +5167,16 @@ return(CKR_FUNCTION_NOT_SUPPORTED); } CK_DEFINE_FUNCTION(CK_RV, C_Login)(CK_SESSION_HANDLE hSession, CK_USER_TYPE userType, CK_UTF8CHAR_PTR pPin, CK_ULONG ulPinLen) { CK_SLOT_ID slotID; + FILE *pinfd; + char *pincmd, pinbuf[64], *fgets_ret; int mutex_retval; int tries_remaining; int login_ret; + int pclose_ret; CACKEY_DEBUG_PRINTF("Called."); if (!cackey_initialized) { CACKEY_DEBUG_PRINTF("Error. Not initialized."); @@ -5184,19 +5224,74 @@ cackey_mutex_unlock(cackey_biglock); return(CKR_GENERAL_ERROR); } + + pincmd = cackey_pin_command; + if (pincmd != NULL) { + CACKEY_DEBUG_PRINTF("CACKEY_PIN_COMMAND = %s", pincmd); + + if (pPin != NULL) { + CACKEY_DEBUG_PRINTF("Protected authentication path in effect and PIN provided !?"); + } + + pinfd = popen(pincmd, "r"); + if (pinfd == NULL) { + CACKEY_DEBUG_PRINTF("Error. %s: Unable to run", pincmd); + + cackey_mutex_unlock(cackey_biglock); + + CACKEY_DEBUG_PRINTF("Returning CKR_PIN_INCORRECT (%i)", (int) CKR_PIN_INCORRECT); + + return(CKR_PIN_INCORRECT); + } + + fgets_ret = fgets(pinbuf, sizeof(pinbuf), pinfd); + if (fgets_ret == NULL) { + pinbuf[0] = '\0'; + } + + pclose_ret = pclose(pinfd); + if (pclose_ret != 0) { + CACKEY_DEBUG_PRINTF("Error. %s: exited with non-zero status of %i", pincmd, pclose_ret); + + cackey_mutex_unlock(cackey_biglock); + + CACKEY_DEBUG_PRINTF("Returning CKR_PIN_INCORRECT (%i)", (int) CKR_PIN_INCORRECT); + + return(CKR_PIN_INCORRECT); + } + + if (strlen(pinbuf) < 1) { + CACKEY_DEBUG_PRINTF("Error. %s: returned no data", pincmd); + + cackey_mutex_unlock(cackey_biglock); + + CACKEY_DEBUG_PRINTF("Returning CKR_PIN_INCORRECT (%i)", (int) CKR_PIN_INCORRECT); + + return(CKR_PIN_INCORRECT); + } + + if (pinbuf[strlen(pinbuf) - 1] == '\n') { + pinbuf[strlen(pinbuf) - 1] = '\0'; + } + + pPin = (CK_UTF8CHAR_PTR) pinbuf; + ulPinLen = strlen(pinbuf); + } login_ret = cackey_login(&cackey_slots[slotID], pPin, ulPinLen, &tries_remaining); if (login_ret != CACKEY_PCSC_S_OK) { cackey_mutex_unlock(cackey_biglock); if (login_ret == CACKEY_PCSC_E_LOCKED) { CACKEY_DEBUG_PRINTF("Error. Token is locked."); cackey_slots[slotID].token_flags |= CKF_USER_PIN_LOCKED; + + CACKEY_DEBUG_PRINTF("Returning CKR_PIN_LOCKED (%i)", (int) CKR_PIN_LOCKED); return(CKR_PIN_LOCKED); } else if (login_ret == CACKEY_PCSC_E_BADPIN) { CACKEY_DEBUG_PRINTF("Error. Invalid PIN."); @@ -5203,10 +5298,12 @@ cackey_slots[slotID].token_flags |= CKF_USER_PIN_COUNT_LOW; if (tries_remaining == 1) { cackey_slots[slotID].token_flags |= CKF_USER_PIN_FINAL_TRY; } + + CACKEY_DEBUG_PRINTF("Returning CKR_PIN_INCORRECT (%i)", (int) CKR_PIN_INCORRECT); return(CKR_PIN_INCORRECT); } CACKEY_DEBUG_PRINTF("Error. Unknown error returned from cackey_login() (%i)", login_ret);