CTK: Added support for PIN pad

This commit is contained in:
Frank Morgner 2017-10-12 08:39:19 +02:00
parent ad6515ba55
commit c70ed34669
1 changed files with 195 additions and 11 deletions

View File

@ -43,6 +43,30 @@ static struct sc_reader_driver cryptotokenkit_reader_driver = {
NULL
};
static int convertError(NSError *error)
{
switch (error.code) {
case TKErrorCodeNotImplemented:
return SC_ERROR_NOT_IMPLEMENTED;
case TKErrorCodeCommunicationError:
return SC_ERROR_TRANSMIT_FAILED;
case TKErrorCodeCorruptedData:
return SC_ERROR_CORRUPTED_DATA;
case TKErrorCodeCanceledByUser:
return SC_ERROR_KEYPAD_CANCELLED;
case TKErrorCodeAuthenticationFailed:
return SC_ERROR_PIN_CODE_INCORRECT;
case TKErrorCodeObjectNotFound:
return SC_ERROR_OBJECT_NOT_FOUND;
case TKErrorCodeTokenNotFound:
return SC_ERROR_CARD_REMOVED;
case TKErrorCodeBadParameter:
return SC_ERROR_INVALID_ARGUMENTS;
default:
return SC_ERROR_UNKNOWN;
}
}
static int cryptotokenkit_init(sc_context_t *ctx)
{
return SC_SUCCESS;
@ -197,8 +221,7 @@ static int cryptotokenkit_lock(sc_reader_t *reader)
[priv->tksmartcard beginSessionWithReply:^(BOOL success, NSError *error) {
if (success != TRUE) {
NSLog(@"Error locking card <%@>", error);
r = SC_ERROR_UNKNOWN;
r = convertError(error);
} else {
r = SC_SUCCESS;
}
@ -250,18 +273,14 @@ static int cryptotokenkit_transmit(sc_reader_t *reader, sc_apdu_t *apdu)
if (response) {
rsize = [response length];
rbuf = malloc(rsize);
if (!rbuf)
if (!rbuf) {
r = SC_ERROR_OUT_OF_MEMORY;
else
memcpy(rbuf, (unsigned char*) [response bytes], rsize);
}
if (r == SC_SUCCESS) {
if (error) {
NSLog(@"Error transmitting to card <%@>", error);
r = SC_ERROR_TRANSMIT_FAILED;
} else {
memcpy(rbuf, (unsigned char*) [response bytes], rsize);
r = SC_SUCCESS;
}
} else {
r = convertError(error);
}
dispatch_semaphore_signal(sema);
}];
@ -285,6 +304,169 @@ err:
LOG_FUNC_RETURN(reader->ctx, r);
}
TKSmartCardPINFormat *getPINFormat(struct sc_pin_cmd_pin *pin)
{
TKSmartCardPINFormat *format = [[TKSmartCardPINFormat alloc] init];
switch (pin->encoding) {
case SC_PIN_ENCODING_GLP:
/* GLP PIN length is encoded in 4 bits and block size is always 8 bytes */
format.PINLengthBitSize = 4;
format.PINBlockByteLength = 8;
/* fall through */
case SC_PIN_ENCODING_BCD:
format.encoding = TKSmartCardPINEncodingBCD;
break;
case SC_PIN_ENCODING_ASCII:
format.encoding = TKSmartCardPINEncodingASCII;
format.PINBlockByteLength = pin->pad_length;
break;
default:
return nil;
}
format.minPINLength = pin->min_length;
format.maxPINLength = pin->max_length;
if (pin->length_offset > 4) {
format.PINLengthBitOffset = (pin->length_offset-5)*8;
}
return format;
}
int cryptotokenkit_perform_verify(struct sc_reader *reader, struct sc_pin_cmd_data *data)
{
u8 template[SC_MAX_APDU_BUFFER_SIZE];
__block int r;
__block UInt16 sw;
size_t ssize = 0;
u8 *sbuf = NULL, *rbuf = NULL;
struct cryptotokenkit_private_data *priv = reader->drv_data;
dispatch_semaphore_t sema = dispatch_semaphore_create(0);
LOG_FUNC_CALLED(reader->ctx);
if (reader->ctx->flags & SC_CTX_FLAG_TERMINATE)
return SC_ERROR_NOT_ALLOWED;
/* The APDU must be provided by the card driver */
if (!data->apdu) {
return SC_ERROR_NOT_SUPPORTED;
}
r = sc_apdu_get_octets(reader->ctx, data->apdu, &sbuf, &ssize, reader->active_protocol);
LOG_TEST_GOTO_ERR(reader->ctx, r, "Could not encode APDU template");
NSData *apdu = [NSData dataWithBytes:sbuf length:ssize];
TKSmartCardPINFormat *format;
struct sc_pin_cmd_pin *pin_ref = &data->pin1;
TKSmartCardUserInteractionForPINOperation *interaction;
switch (data->cmd) {
case SC_PIN_CMD_VERIFY:
format = getPINFormat(pin_ref);
NSInteger offset;
if (data->pin1.length_offset != 4) {
offset = data->pin1.offset - 5;
} else {
offset = 0;
}
interaction = [priv->tksmartcard userInteractionForSecurePINVerificationWithPINFormat:format APDU:apdu PINByteOffset:offset];
break;
case SC_PIN_CMD_CHANGE:
case SC_PIN_CMD_UNBLOCK:
if (data->flags & SC_PIN_CMD_IMPLICIT_CHANGE) {
pin_ref = &data->pin2;
}
/* TODO: set confirmation and text */
format = getPINFormat(pin_ref);
NSInteger oldOffset, newOffset;
if (data->pin1.length_offset != 4) {
oldOffset = data->pin1.offset - 5;
newOffset = data->pin2.offset - 5;
} else {
oldOffset = 0;
newOffset = 0;
}
interaction = [priv->tksmartcard userInteractionForSecurePINChangeWithPINFormat:format APDU:apdu currentPINByteOffset:oldOffset newPINByteOffset:newOffset];
break;
default:
sc_log(reader->ctx, "Unknown PIN command %d", data->cmd);
r = SC_ERROR_NOT_SUPPORTED;
goto err;
}
if (nil == interaction) {
r = SC_ERROR_NOT_SUPPORTED;
goto err;
}
[interaction runWithReply:^(BOOL success, NSError *error) {
if (success) {
NSData *response = interaction.resultData;
if (nil != response) {
data->apdu->resplen = response.length;
memcpy(data->apdu->resp, (unsigned char *) response.bytes, response.length);
} else {
data->apdu->resplen = 0;
}
sw = interaction.resultSW;
r = SC_SUCCESS;
} else {
r = convertError(error);
}
dispatch_semaphore_signal(sema);
}];
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
if (r != SC_SUCCESS) {
goto err;
}
data->apdu->sw1 = sw >> 8;
data->apdu->sw2 = sw & 0xFF;
switch (sw) {
case 0x6400:
/* Input timed out */
r = SC_ERROR_KEYPAD_TIMEOUT;
break;
case 0x6401:
/* Input cancelled */
r = SC_ERROR_KEYPAD_CANCELLED;
break;
case 0x6402:
/* PINs don't match */
r = SC_ERROR_KEYPAD_PIN_MISMATCH;
break;
case 0x6403:
/* Entered PIN is not in length limits */
r = SC_ERROR_INVALID_PIN_LENGTH; /* XXX: designed to be returned when PIN is in API call */
break;
case 0x6B80:
/* Wrong data in the buffer, rejected by firmware */
r = SC_ERROR_READER;
break;
}
err:
if (sbuf != NULL) {
sc_mem_clear(sbuf, ssize);
free(sbuf);
}
LOG_FUNC_RETURN(reader->ctx, r);
}
void cryptotokenkit_detect_reader_features(struct sc_reader *reader, TKSmartCard* tksmartcard)
{
if (tksmartcard) {
const u8 template[] = {tksmartcard.cla, 0x20, 0x00, 0x80, 0x08, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
NSData *data = [NSData dataWithBytes:template length:sizeof template];
TKSmartCardPINFormat *PINFormat = [[TKSmartCardPINFormat alloc] init];
PINFormat.PINBitOffset = 0;
if (nil != [tksmartcard userInteractionForSecurePINVerificationWithPINFormat:PINFormat APDU:data PINByteOffset:0])
reader->capabilities |= SC_READER_CAP_PIN_PAD;
}
}
int cryptotokenkit_use_reader(sc_context_t *ctx, void *pcsc_context_handle, void *pcsc_card_handle)
{
int r;
@ -341,6 +523,8 @@ int cryptotokenkit_use_reader(sc_context_t *ctx, void *pcsc_context_handle, void
cryptotokenkit_detect_card_presence(reader);
cryptotokenkit_detect_reader_features(reader, tksmartcard);
r = _sc_add_reader(ctx, reader);
err:
@ -426,7 +610,7 @@ struct sc_reader_driver *sc_get_cryptotokenkit_driver(void)
cryptotokenkit_ops.lock = cryptotokenkit_lock;
cryptotokenkit_ops.unlock = cryptotokenkit_unlock;
cryptotokenkit_ops.transmit = cryptotokenkit_transmit;
cryptotokenkit_ops.perform_verify = NULL;
cryptotokenkit_ops.perform_verify = cryptotokenkit_perform_verify;
cryptotokenkit_ops.perform_pace = NULL;
cryptotokenkit_ops.use_reader = cryptotokenkit_use_reader;
cryptotokenkit_ops.detect_readers = cryptotokenkit_detect_readers;