Compare commits

..

2 Commits

Author SHA1 Message Date
75dbefad73 Merge pull request #205 from m3hm00d/sanitize
Fix minor typo in comment
2019-07-05 10:28:11 -04:00
e14700f398 Fix minor typo in comment
'USBD_HID_DeInit' is written as 'USBD_HID_Init'; likely a copy-paste
error. This patch should fix it.
2019-06-20 16:44:17 +00:00
23 changed files with 116 additions and 404 deletions

2
.gitignore vendored
View File

@ -83,5 +83,3 @@ targets/*/docs/
main
builds/*
tools/testing/.idea/*
tools/testing/tests/__pycache__/*

View File

@ -1,32 +0,0 @@
# Security Policy
## Supported Versions
We fix security issues as soon as they are found, and release firmware updates.
Each such release is accompanied by release notes, see <https://github.com/solokeys/solo/releases>.
The latest version can be determined using the file <https://github.com/solokeys/solo/blob/master/STABLE_VERSION>.
To update your key:
- either visit <https://update.solokeys.com>, or
- use our commandline tool <https://github.com/solokeys/solo-python>:
```
solo key update [--secure|--hacker]
```
## Reporting a Vulnerability
To report vulnerabilities you have found:
- preferably contact [@conor1](https://keybase.io/conor1), [@0x0ece](https://keybase.io/0x0ece) or [@nickray](https://keybase.io/nickray) via Keybase, or
- send us e-mail using OpenPGP to [security@solokeys.com](mailto:security@solokeys.com).
<https://keys.openpgp.org/vks/v1/by-fingerprint/85AFA2769F4381E5712C36A04DDFC46FEF1F7F3F>
We do not currently run a paid bug bounty program, but are happy to provide you with a bunch of Solo keys in recognition of your findings.
## Mailing List
Join our release notification mailing list to be informed about each release:
https://sendy.solokeys.com/subscription?f=9MLIqMDmox1Ucz89C892Kq09IqYMM7OB8UrBrkvtTkDI763QF3L5PMYlRhlVNo2AI892mO

View File

@ -1 +1 @@
2.3.0
2.2.2

Binary file not shown.

Before

Width:  |  Height:  |  Size: 134 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 129 KiB

View File

@ -1,122 +0,0 @@
// Copyright 2019 SoloKeys Developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
// iso7816:2013. 5.3.2 Decoding conventions for command bodies
#include "apdu.h"
int apdu_decode(uint8_t *data, size_t len, APDU_STRUCT *apdu)
{
EXT_APDU_HEADER *hapdu = (EXT_APDU_HEADER *)data;
apdu->cla = hapdu->cla;
apdu->ins = hapdu->ins;
apdu->p1 = hapdu->p1;
apdu->p2 = hapdu->p2;
apdu->lc = 0;
apdu->data = NULL;
apdu->le = 0;
apdu->extended_apdu = false;
apdu->case_type = 0x00;
uint8_t b0 = hapdu->lc[0];
// case 1
if (len == 4)
{
apdu->case_type = 0x01;
}
// case 2S (Le)
if (len == 5)
{
apdu->case_type = 0x02;
apdu->le = b0;
if (!apdu->le)
apdu->le = 0x100;
}
// case 3S (Lc + data)
if (len == 5U + b0 && b0 != 0)
{
apdu->case_type = 0x03;
apdu->lc = b0;
}
// case 4S (Lc + data + Le)
if (len == 5U + b0 + 1U && b0 != 0)
{
apdu->case_type = 0x04;
apdu->lc = b0;
apdu->le = data[len - 1];
if (!apdu->le)
apdu->le = 0x100;
}
// extended length apdu
if (len >= 7 && b0 == 0)
{
uint16_t extlen = (hapdu->lc[1] << 8) + hapdu->lc[2];
// case 2E (Le) - extended
if (len == 7)
{
apdu->case_type = 0x12;
apdu->extended_apdu = true;
apdu->le = extlen;
if (!apdu->le)
apdu->le = 0x10000;
}
// case 3E (Lc + data) - extended
if (len == 7U + extlen)
{
apdu->case_type = 0x13;
apdu->extended_apdu = true;
apdu->lc = extlen;
}
// case 4E (Lc + data + Le) - extended 2-byte Le
if (len == 7U + extlen + 2U)
{
apdu->case_type = 0x14;
apdu->extended_apdu = true;
apdu->lc = extlen;
apdu->le = (data[len - 2] << 8) + data[len - 1];
if (!apdu->le)
apdu->le = 0x10000;
}
// case 4E (Lc + data + Le) - extended 3-byte Le
if (len == 7U + extlen + 3U && data[len - 3] == 0)
{
apdu->case_type = 0x24;
apdu->extended_apdu = true;
apdu->lc = extlen;
apdu->le = (data[len - 2] << 8) + data[len - 1];
if (!apdu->le)
apdu->le = 0x10000;
}
}
if (!apdu->case_type)
return 1;
if (apdu->lc)
{
if (apdu->extended_apdu)
{
apdu->data = data + 7;
} else {
apdu->data = data + 5;
}
}
return 0;
}

View File

@ -2,8 +2,6 @@
#define _APDU_H_
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
typedef struct
{
@ -14,30 +12,6 @@ typedef struct
uint8_t lc;
} __attribute__((packed)) APDU_HEADER;
typedef struct
{
uint8_t cla;
uint8_t ins;
uint8_t p1;
uint8_t p2;
uint8_t lc[3];
} __attribute__((packed)) EXT_APDU_HEADER;
typedef struct
{
uint8_t cla;
uint8_t ins;
uint8_t p1;
uint8_t p2;
uint16_t lc;
uint8_t *data;
uint32_t le;
bool extended_apdu;
uint8_t case_type;
} __attribute__((packed)) APDU_STRUCT;
extern int apdu_decode(uint8_t *data, size_t len, APDU_STRUCT *apdu);
#define APDU_FIDO_U2F_REGISTER 0x01
#define APDU_FIDO_U2F_AUTHENTICATE 0x02
#define APDU_FIDO_U2F_VERSION 0x03
@ -51,7 +25,6 @@ extern int apdu_decode(uint8_t *data, size_t len, APDU_STRUCT *apdu);
#define SW_COND_USE_NOT_SATISFIED 0x6985
#define SW_FILE_NOT_FOUND 0x6a82
#define SW_INS_INVALID 0x6d00 // Instruction code not supported or invalid
#define SW_CLA_INVALID 0x6e00
#define SW_INTERNAL_EXCEPTION 0x6f00
#endif //_APDU_H_

View File

@ -1987,5 +1987,5 @@ void ctap_reset()
memset(PIN_CODE_HASH,0,sizeof(PIN_CODE_HASH));
ctap_reset_key_agreement();
crypto_load_master_secret(STATE.key_space);
crypto_reset_master_secret();
}

View File

@ -929,15 +929,7 @@ uint8_t parse_credential_descriptor(CborValue * arr, CTAP_credentialDescriptor *
buflen = sizeof(type);
ret = cbor_value_copy_text_string(&val, type, &buflen, NULL);
if (ret == CborErrorOutOfMemory)
{
cred->type = PUB_KEY_CRED_UNKNOWN;
}
else
{
check_ret(ret);
}
check_ret(ret);
if (strncmp(type, "public-key",11) == 0)
{

View File

@ -105,8 +105,6 @@ void device_set_clock_rate(DEVICE_CLOCK_RATE param);
#define NFC_IS_AVAILABLE 2
int device_is_nfc();
void request_from_nfc(bool request_active);
void device_init_button();
#endif

View File

@ -113,14 +113,14 @@ end:
printf1(TAG_U2F,"u2f resp: "); dump_hex1(TAG_U2F, _u2f_resp->data, _u2f_resp->length);
}
void u2f_request_nfc(uint8_t * header, uint8_t * data, int datalen, CTAP_RESPONSE * resp)
void u2f_request_nfc(uint8_t * req, int len, CTAP_RESPONSE * resp)
{
if (!header)
if (len < 5 || !req)
return;
request_from_nfc(true); // disable presence test
u2f_request_ex((APDU_HEADER *)header, data, datalen, resp);
request_from_nfc(false); // enable presence test
uint32_t alen = req[4];
u2f_request_ex((APDU_HEADER *)req, &req[5], alen, resp);
}
void u2f_request(struct u2f_request_apdu* req, CTAP_RESPONSE * resp)

View File

@ -101,7 +101,7 @@ void u2f_request(struct u2f_request_apdu* req, CTAP_RESPONSE * resp);
// u2f_request send a U2F message to NFC protocol
// @req data with iso7816 apdu message
// @len data length
void u2f_request_nfc(uint8_t * header, uint8_t * data, int datalen, CTAP_RESPONSE * resp);
void u2f_request_nfc(uint8_t * req, int len, CTAP_RESPONSE * resp);
int8_t u2f_authenticate_credential(struct u2f_key_handle * kh, uint8_t * appid);

View File

@ -20,9 +20,6 @@
],
"userVerificationDetails": [
[
{
"userVerification": 1
},
{
"userVerification": 4
}

View File

@ -7,7 +7,7 @@ SRC += src/startup_stm32l432xx.s src/system_stm32l4xx.c
SRC += $(DRIVER_LIBS) $(USB_LIB)
# FIDO2 lib
SRC += ../../fido2/apdu.c ../../fido2/util.c ../../fido2/u2f.c ../../fido2/test_power.c
SRC += ../../fido2/util.c ../../fido2/u2f.c ../../fido2/test_power.c
SRC += ../../fido2/stubs.c ../../fido2/log.c ../../fido2/ctaphid.c ../../fido2/ctap.c
SRC += ../../fido2/ctap_parse.c ../../fido2/main.c
SRC += ../../fido2/extensions/extensions.c ../../fido2/extensions/solo.c

View File

@ -309,7 +309,7 @@ static uint8_t USBD_HID_Init (USBD_HandleTypeDef *pdev, uint8_t cfgidx)
}
/**
* @brief USBD_HID_Init
* @brief USBD_HID_DeInit
* DeInitialize the HID layer
* @param pdev: device instance
* @param cfgidx: Configuration index

View File

@ -31,7 +31,7 @@
// #define DISABLE_CTAPHID_WINK
// #define DISABLE_CTAPHID_CBOR
// #define ENABLE_SERIAL_PRINTING
#define ENABLE_SERIAL_PRINTING
#if defined(SOLO_HACKER)
#define SOLO_PRODUCT_NAME "Solo Hacker " SOLO_VERSION

View File

@ -43,7 +43,6 @@ uint32_t __last_update = 0;
extern PCD_HandleTypeDef hpcd;
static int _NFC_status = 0;
static bool isLowFreq = 0;
static bool _RequestComeFromNFC = false;
// #define IS_BUTTON_PRESSED() (0 == (LL_GPIO_ReadInputPort(SOLO_BUTTON_PORT) & SOLO_BUTTON_PIN))
static int is_physical_button_pressed()
@ -58,10 +57,6 @@ static int is_touch_button_pressed()
int (*IS_BUTTON_PRESSED)() = is_physical_button_pressed;
void request_from_nfc(bool request_active) {
_RequestComeFromNFC = request_active;
}
// Timer6 overflow handler. happens every ~90ms.
void TIM6_DAC_IRQHandler()
{
@ -496,7 +491,7 @@ static int handle_packets()
int ctap_user_presence_test(uint32_t up_delay)
{
int ret;
if (device_is_nfc() == NFC_IS_ACTIVE || _RequestComeFromNFC)
if (device_is_nfc() == NFC_IS_ACTIVE)
{
return 1;
}

View File

@ -14,16 +14,6 @@
#define IS_IRQ_ACTIVE() (1 == (LL_GPIO_ReadInputPort(SOLO_AMS_IRQ_PORT) & SOLO_AMS_IRQ_PIN))
uint8_t p14443_block_offset(uint8_t pcb) {
uint8_t offset = 1;
// NAD following
if (pcb & 0x04) offset++;
// CID following
if (pcb & 0x08) offset++;
return offset;
}
// Capability container
const CAPABILITY_CONTAINER NFC_CC = {
.cclen_hi = 0x00, .cclen_lo = 0x0f,
@ -122,7 +112,6 @@ bool ams_receive_with_timeout(uint32_t timeout_ms, uint8_t * data, int maxlen, i
while (tstart + timeout_ms > millis())
{
uint8_t int0 = ams_read_reg(AMS_REG_INT0);
if (int0) process_int0(int0);
uint8_t buffer_status2 = ams_read_reg(AMS_REG_BUF2);
if (buffer_status2 && (int0 & AMS_INT_RXE))
@ -172,18 +161,14 @@ bool nfc_write_response_ex(uint8_t req0, uint8_t * data, uint8_t len, uint16_t r
if (len > 32 - 3)
return false;
res[0] = NFC_CMD_IBLOCK | (req0 & 0x0f);
res[1] = 0;
res[2] = 0;
uint8_t block_offset = p14443_block_offset(req0);
res[0] = NFC_CMD_IBLOCK | (req0 & 3);
if (len && data)
memcpy(&res[block_offset], data, len);
memcpy(&res[1], data, len);
res[len + block_offset + 0] = resp >> 8;
res[len + block_offset + 1] = resp & 0xff;
nfc_write_frame(res, block_offset + len + 2);
res[len + 1] = resp >> 8;
res[len + 2] = resp & 0xff;
nfc_write_frame(res, 3 + len);
return true;
}
@ -197,24 +182,21 @@ void nfc_write_response_chaining(uint8_t req0, uint8_t * data, int len)
{
uint8_t res[32 + 2];
int sendlen = 0;
uint8_t iBlock = NFC_CMD_IBLOCK | (req0 & 0x0f);
uint8_t block_offset = p14443_block_offset(req0);
uint8_t iBlock = NFC_CMD_IBLOCK | (req0 & 3);
if (len <= 31)
{
uint8_t res[32] = {0};
res[0] = iBlock;
res[0] = iBlock;
if (len && data)
memcpy(&res[block_offset], data, len);
nfc_write_frame(res, len + block_offset);
memcpy(&res[1], data, len);
nfc_write_frame(res, len + 1);
} else {
do {
// transmit I block
int vlen = MIN(32 - block_offset, len - sendlen);
res[0] = iBlock;
res[1] = 0;
res[2] = 0;
memcpy(&res[block_offset], &data[sendlen], vlen);
int vlen = MIN(31, len - sendlen);
res[0] = iBlock;
memcpy(&res[1], &data[sendlen], vlen);
// if not a last block
if (vlen + sendlen < len)
@ -223,7 +205,7 @@ void nfc_write_response_chaining(uint8_t req0, uint8_t * data, int len)
}
// send data
nfc_write_frame(res, vlen + block_offset);
nfc_write_frame(res, vlen + 1);
sendlen += vlen;
// wait for transmit (32 bytes aprox 2,5ms)
@ -244,10 +226,9 @@ void nfc_write_response_chaining(uint8_t req0, uint8_t * data, int len)
break;
}
uint8_t rblock_offset = p14443_block_offset(recbuf[0]);
if (reclen != rblock_offset)
if (reclen != 1)
{
printf1(TAG_NFC, "R block length error. len: %d. %d/%d \r\n", reclen, sendlen, len);
printf1(TAG_NFC, "R block length error. len: %d. %d/%d \r\n", reclen,sendlen,len);
dump_hex1(TAG_NFC, recbuf, reclen);
break;
}
@ -390,72 +371,39 @@ int answer_rats(uint8_t parameter)
nfc_write_frame(res, sizeof(res));
if (!ams_wait_for_tx(10))
{
printf1(TAG_NFC, "RATS TX timeout.\r\n");
ams_write_command(AMS_CMD_DEFAULT);
return 1;
}
ams_wait_for_tx(10);
return 0;
}
void rblock_acknowledge(uint8_t req0, bool ack)
void rblock_acknowledge()
{
uint8_t buf[32] = {0};
uint8_t block_offset = p14443_block_offset(req0);
uint8_t buf[32];
NFC_STATE.block_num = !NFC_STATE.block_num;
buf[0] = NFC_CMD_RBLOCK | (req0 & 0x0f);
if (ack)
buf[0] |= NFC_CMD_RBLOCK_ACK;
nfc_write_frame(buf, block_offset);
}
// international AID = RID:PIX
// RID length == 5 bytes
// usually aid length must be between 5 and 16 bytes
int applet_cmp(uint8_t * aid, int len, uint8_t * const_aid, int const_len)
{
if (len > const_len)
return 10;
// if international AID
if ((const_aid[0] & 0xf0) == 0xa0)
{
if (len < 5)
return 11;
return memcmp(aid, const_aid, MIN(len, const_len));
} else {
if (len != const_len)
return 11;
return memcmp(aid, const_aid, const_len);
}
buf[0] = NFC_CMD_RBLOCK | NFC_STATE.block_num;
nfc_write_frame(buf,1);
}
// Selects application. Returns 1 if success, 0 otherwise
int select_applet(uint8_t * aid, int len)
{
if (applet_cmp(aid, len, (uint8_t *)AID_FIDO, sizeof(AID_FIDO) - 1) == 0)
if (memcmp(aid,AID_FIDO,sizeof(AID_FIDO)) == 0)
{
NFC_STATE.selected_applet = APP_FIDO;
return APP_FIDO;
}
else if (applet_cmp(aid, len, (uint8_t *)AID_NDEF_TYPE_4, sizeof(AID_NDEF_TYPE_4) - 1) == 0)
else if (memcmp(aid,AID_NDEF_TYPE_4,sizeof(AID_NDEF_TYPE_4)) == 0)
{
NFC_STATE.selected_applet = APP_NDEF_TYPE_4;
return APP_NDEF_TYPE_4;
}
else if (applet_cmp(aid, len, (uint8_t *)AID_CAPABILITY_CONTAINER, sizeof(AID_CAPABILITY_CONTAINER) - 1) == 0)
else if (memcmp(aid,AID_CAPABILITY_CONTAINER,sizeof(AID_CAPABILITY_CONTAINER)) == 0)
{
NFC_STATE.selected_applet = APP_CAPABILITY_CONTAINER;
return APP_CAPABILITY_CONTAINER;
}
else if (applet_cmp(aid, len, (uint8_t *)AID_NDEF_TAG, sizeof(AID_NDEF_TAG) - 1) == 0)
else if (memcmp(aid,AID_NDEF_TAG,sizeof(AID_NDEF_TAG)) == 0)
{
NFC_STATE.selected_applet = APP_NDEF_TAG;
return APP_NDEF_TAG;
@ -465,36 +413,25 @@ int select_applet(uint8_t * aid, int len)
void nfc_process_iblock(uint8_t * buf, int len)
{
APDU_HEADER * apdu = (APDU_HEADER *)(buf + 1);
uint8_t * payload = buf + 1 + 5;
uint8_t plen = apdu->lc;
int selected;
CTAP_RESPONSE ctap_resp;
int status;
uint16_t reslen;
printf1(TAG_NFC,"Iblock: ");
dump_hex1(TAG_NFC, buf, len);
uint8_t block_offset = p14443_block_offset(buf[0]);
APDU_STRUCT apdu;
if (apdu_decode(buf + block_offset, len - block_offset, &apdu)) {
printf1(TAG_NFC,"apdu decode error\r\n");
nfc_write_response(buf[0], SW_COND_USE_NOT_SATISFIED);
return;
}
printf1(TAG_NFC,"apdu ok. %scase=%02x cla=%02x ins=%02x p1=%02x p2=%02x lc=%d le=%d\r\n",
apdu.extended_apdu ? "[e]":"", apdu.case_type, apdu.cla, apdu.ins, apdu.p1, apdu.p2, apdu.lc, apdu.le);
// check CLA
if (apdu.cla != 0x00 && apdu.cla != 0x80) {
printf1(TAG_NFC, "Unknown CLA %02x\r\n", apdu.cla);
nfc_write_response(buf[0], SW_CLA_INVALID);
return;
}
// TODO this needs to be organized better
switch(apdu.ins)
switch(apdu->ins)
{
case APDU_INS_SELECT:
if (plen > len - 6)
{
printf1(TAG_ERR, "Truncating APDU length %d\r\n", apdu->lc);
plen = len-6;
}
// if (apdu->p1 == 0 && apdu->p2 == 0x0c)
// {
// printf1(TAG_NFC,"Select NDEF\r\n");
@ -509,9 +446,14 @@ void nfc_process_iblock(uint8_t * buf, int len)
// }
// else
{
selected = select_applet(apdu.data, apdu.lc);
selected = select_applet(payload, plen);
if (selected == APP_FIDO)
{
// block = buf[0] & 1;
// block = NFC_STATE.block_num;
// block = !block;
// NFC_STATE.block_num = block;
// NFC_STATE.block_num = block;
nfc_write_response_ex(buf[0], (uint8_t *)"U2F_V2", 6, SW_SUCCESS);
printf1(TAG_NFC, "FIDO applet selected.\r\n");
}
@ -523,7 +465,7 @@ void nfc_process_iblock(uint8_t * buf, int len)
else
{
nfc_write_response(buf[0], SW_FILE_NOT_FOUND);
printf1(TAG_NFC, "NOT selected "); dump_hex1(TAG_NFC, apdu.data, apdu.lc);
printf1(TAG_NFC, "NOT selected\r\n"); dump_hex1(TAG_NFC,payload, plen);
}
}
break;
@ -536,8 +478,7 @@ void nfc_process_iblock(uint8_t * buf, int len)
printf1(TAG_NFC, "U2F GetVersion command.\r\n");
u2f_request_nfc(&buf[block_offset], apdu.data, apdu.lc, &ctap_resp);
nfc_write_response_chaining(buf[0], ctap_resp.data, ctap_resp.length);
nfc_write_response_ex(buf[0], (uint8_t *)"U2F_V2", 6, SW_SUCCESS);
break;
case APDU_FIDO_U2F_REGISTER:
@ -548,9 +489,9 @@ void nfc_process_iblock(uint8_t * buf, int len)
printf1(TAG_NFC, "U2F Register command.\r\n");
if (apdu.lc != 64)
if (plen != 64)
{
printf1(TAG_NFC, "U2F Register request length error. len=%d.\r\n", apdu.lc);
printf1(TAG_NFC, "U2F Register request length error. len=%d.\r\n", plen);
nfc_write_response(buf[0], SW_WRONG_LENGTH);
return;
}
@ -561,16 +502,20 @@ void nfc_process_iblock(uint8_t * buf, int len)
// WTX_on(WTX_TIME_DEFAULT);
// SystemClock_Config_LF32();
// delay(300);
if (device_is_nfc() == NFC_IS_ACTIVE) device_set_clock_rate(DEVICE_LOW_POWER_FAST);
u2f_request_nfc(&buf[block_offset], apdu.data, apdu.lc, &ctap_resp);
if (device_is_nfc() == NFC_IS_ACTIVE) device_set_clock_rate(DEVICE_LOW_POWER_IDLE);
if (device_is_nfc()) device_set_clock_rate(DEVICE_LOW_POWER_FAST);;
u2f_request_nfc(&buf[1], len, &ctap_resp);
if (device_is_nfc()) device_set_clock_rate(DEVICE_LOW_POWER_IDLE);;
// if (!WTX_off())
// return;
printf1(TAG_NFC, "U2F resp len: %d\r\n", ctap_resp.length);
printf1(TAG_NFC,"U2F Register P2 took %d\r\n", timestamp());
nfc_write_response_chaining(buf[0], ctap_resp.data, ctap_resp.length);
// printf1(TAG_NFC, "U2F resp len: %d\r\n", ctap_resp.length);
printf1(TAG_NFC,"U2F Register answered %d (took %d)\r\n", millis(), timestamp());
break;
@ -582,17 +527,17 @@ void nfc_process_iblock(uint8_t * buf, int len)
printf1(TAG_NFC, "U2F Authenticate command.\r\n");
if (apdu.lc != 64 + 1 + apdu.data[64])
if (plen != 64 + 1 + buf[6 + 64])
{
delay(5);
printf1(TAG_NFC, "U2F Authenticate request length error. len=%d keyhlen=%d.\r\n", apdu.lc, apdu.data[64]);
printf1(TAG_NFC, "U2F Authenticate request length error. len=%d keyhlen=%d.\r\n", plen, buf[6 + 64]);
nfc_write_response(buf[0], SW_WRONG_LENGTH);
return;
}
timestamp();
// WTX_on(WTX_TIME_DEFAULT);
u2f_request_nfc(&buf[block_offset], apdu.data, apdu.lc, &ctap_resp);
u2f_request_nfc(&buf[1], len, &ctap_resp);
// if (!WTX_off())
// return;
@ -605,16 +550,14 @@ void nfc_process_iblock(uint8_t * buf, int len)
case APDU_FIDO_NFCCTAP_MSG:
if (NFC_STATE.selected_applet != APP_FIDO) {
nfc_write_response(buf[0], SW_INS_INVALID);
return;
break;
}
printf1(TAG_NFC, "FIDO2 CTAP message. %d\r\n", timestamp());
WTX_on(WTX_TIME_DEFAULT);
request_from_nfc(true);
ctap_response_init(&ctap_resp);
status = ctap_request(apdu.data, apdu.lc, &ctap_resp);
request_from_nfc(false);
status = ctap_request(payload, plen, &ctap_resp);
if (!WTX_off())
return;
@ -637,37 +580,44 @@ void nfc_process_iblock(uint8_t * buf, int len)
break;
case APDU_INS_READ_BINARY:
// response length
reslen = apdu.le & 0xffff;
switch(NFC_STATE.selected_applet)
{
case APP_CAPABILITY_CONTAINER:
printf1(TAG_NFC,"APP_CAPABILITY_CONTAINER\r\n");
if (reslen == 0 || reslen > sizeof(NFC_CC))
reslen = sizeof(NFC_CC);
nfc_write_response_ex(buf[0], (uint8_t *)&NFC_CC, reslen, SW_SUCCESS);
if (plen > 15)
{
printf1(TAG_ERR, "Truncating requested CC length %d\r\n", apdu->lc);
plen = 15;
}
nfc_write_response_ex(buf[0], (uint8_t *)&NFC_CC, plen, SW_SUCCESS);
ams_wait_for_tx(10);
break;
case APP_NDEF_TAG:
printf1(TAG_NFC,"APP_NDEF_TAG\r\n");
if (reslen == 0 || reslen > sizeof(NDEF_SAMPLE) - 1)
reslen = sizeof(NDEF_SAMPLE) - 1;
nfc_write_response_ex(buf[0], NDEF_SAMPLE, reslen, SW_SUCCESS);
if (plen > (sizeof(NDEF_SAMPLE) - 1))
{
printf1(TAG_ERR, "Truncating requested CC length %d\r\n", apdu->lc);
plen = sizeof(NDEF_SAMPLE) - 1;
}
nfc_write_response_ex(buf[0], NDEF_SAMPLE, plen, SW_SUCCESS);
ams_wait_for_tx(10);
break;
default:
nfc_write_response(buf[0], SW_FILE_NOT_FOUND);
printf1(TAG_ERR, "No binary applet selected!\r\n");
return;
break;
}
break;
default:
printf1(TAG_NFC, "Unknown INS %02x\r\n", apdu.ins);
printf1(TAG_NFC, "Unknown INS %02x\r\n", apdu->ins);
nfc_write_response(buf[0], SW_INS_INVALID);
break;
}
}
static uint8_t ibuf[1024];
@ -681,7 +631,7 @@ void clear_ibuf()
void nfc_process_block(uint8_t * buf, unsigned int len)
{
printf1(TAG_NFC, "-----\r\n");
if (!len)
return;
@ -691,7 +641,6 @@ void nfc_process_block(uint8_t * buf, unsigned int len)
}
else if (IS_IBLOCK(buf[0]))
{
uint8_t block_offset = p14443_block_offset(buf[0]);
if (buf[0] & 0x10)
{
printf1(TAG_NFC_APDU, "NFC_CMD_IBLOCK chaining blen=%d len=%d\r\n", ibuflen, len);
@ -705,27 +654,27 @@ void nfc_process_block(uint8_t * buf, unsigned int len)
printf1(TAG_NFC_APDU,"i> ");
dump_hex1(TAG_NFC_APDU, buf, len);
if (len > block_offset)
if (len)
{
memcpy(&ibuf[ibuflen], &buf[block_offset], len - block_offset);
ibuflen += len - block_offset;
memcpy(&ibuf[ibuflen], &buf[1], len - 1);
ibuflen += len - 1;
}
// send R block
rblock_acknowledge(buf[0], true);
uint8_t rb = NFC_CMD_RBLOCK | NFC_CMD_RBLOCK_ACK | (buf[0] & 3);
nfc_write_frame(&rb, 1);
} else {
if (ibuflen)
{
if (len > block_offset)
if (len)
{
memcpy(&ibuf[ibuflen], &buf[block_offset], len - block_offset);
ibuflen += len - block_offset;
memcpy(&ibuf[ibuflen], &buf[1], len - 1);
ibuflen += len - 1;
}
// add last chaining to top of the block
memmove(&ibuf[block_offset], ibuf, ibuflen);
memmove(ibuf, buf, block_offset);
ibuflen += block_offset;
memmove(&ibuf[1], ibuf, ibuflen);
ibuf[0] = buf[0];
ibuflen++;
printf1(TAG_NFC_APDU, "NFC_CMD_IBLOCK chaining last block. blen=%d len=%d\r\n", ibuflen, len);
@ -734,6 +683,7 @@ void nfc_process_block(uint8_t * buf, unsigned int len)
nfc_process_iblock(ibuf, ibuflen);
} else {
// printf1(TAG_NFC, "NFC_CMD_IBLOCK\r\n");
nfc_process_iblock(buf, len);
}
clear_ibuf();
@ -741,7 +691,7 @@ void nfc_process_block(uint8_t * buf, unsigned int len)
}
else if (IS_RBLOCK(buf[0]))
{
rblock_acknowledge(buf[0], false);
rblock_acknowledge();
printf1(TAG_NFC, "NFC_CMD_RBLOCK\r\n");
}
else if (IS_SBLOCK(buf[0]))
@ -760,7 +710,6 @@ void nfc_process_block(uint8_t * buf, unsigned int len)
else
{
printf1(TAG_NFC, "NFC_CMD_SBLOCK, Unknown. len[%d]\r\n", len);
nfc_write_response(buf[0], SW_COND_USE_NOT_SATISFIED);
}
dump_hex1(TAG_NFC, buf, len);
}

View File

@ -40,8 +40,6 @@ typedef struct
#define NFC_CMD_SBLOCK 0xc0
#define IS_SBLOCK(x) ( (((x) & 0xc0) == NFC_CMD_SBLOCK) && (((x) & 0x02) == 0x02) )
extern uint8_t p14443_block_offset(uint8_t pcb);
#define NFC_SBLOCK_DESELECT 0x30
#define NFC_SBLOCK_WTX 0x30

View File

@ -19,9 +19,7 @@ from tests import Tester, FIDO2Tests, U2FTests, HIDTests, SoloTests
if __name__ == "__main__":
if len(sys.argv) < 2:
print("Usage: %s [sim] [nfc] <[u2f]|[fido2]|[rk]|[hid]|[ping]>")
print(" sim - test via UDP simulation backend only")
print(" nfc - test via NFC interface only")
print("Usage: %s [sim] <[u2f]|[fido2]|[rk]|[hid]|[ping]>")
sys.exit(0)
t = Tester()
@ -33,11 +31,7 @@ if __name__ == "__main__":
t.set_sim(True)
t.set_user_count(10)
nfcOnly = False
if "nfc" in sys.argv:
nfcOnly = True
t.find_device(nfcOnly)
t.find_device()
if "solo" in sys.argv:
SoloTests(t).run()

View File

@ -78,7 +78,7 @@ def TestCborKeysSorted(cbor_obj):
# https://fidoalliance.org/specs/fido-v2.0-ps-20190130/fido-client-to-authenticator-protocol-v2.0-ps-20190130.html#ctap2-canonical-cbor-encoding-form
if isinstance(cbor_obj, bytes):
cbor_obj = cbor.decode_from(cbor_obj)[0]
cbor_obj = cbor.loads(cbor_obj)[0]
if isinstance(cbor_obj, dict):
l = [x for x in cbor_obj]
@ -222,7 +222,9 @@ class FIDO2Tests(Tester):
)
with Test("Get shared secret"):
key_agreement, shared_secret = self.client.pin_protocol.get_shared_secret()
key_agreement, shared_secret = (
self.client.pin_protocol._init_shared_secret()
)
cipher = Cipher(
algorithms.AES(shared_secret),
modes.CBC(b"\x00" * 16),
@ -339,8 +341,8 @@ class FIDO2Tests(Tester):
def test_get_info(self,):
with Test("Get info"):
info = self.ctap.get_info()
print("data:", bytes(info))
print("decoded:", cbor.decode_from(bytes(info)))
print(bytes(info))
print(cbor.loads(bytes(info)))
with Test("Check FIDO2 string is in VERSIONS field"):
assert "FIDO_2_0" in info.versions
@ -619,20 +621,6 @@ class FIDO2Tests(Tester):
other={"exclude_list": [{"id": b"1234", "type": "rot13"}]},
)
self.testMC(
"Send MC request with excludeList item with bogus type, expect SUCCESS",
cdh,
rp,
user,
key_params,
expectedError=CtapError.ERR.SUCCESS,
other={
"exclude_list": [
{"id": b"1234", "type": "mangoPapayaCoconutNotAPublicKey"}
]
},
)
self.testMC(
"Send MC request with excludeList with bad item, expect error",
cdh,

View File

@ -1,5 +1,5 @@
import time, struct
from fido2.pcsc import CtapPcscDevice
from fido2.hid import CtapHidDevice
from fido2.client import Fido2Client
from fido2.ctap1 import CTAP1
@ -51,7 +51,6 @@ class Tester:
self.host = "examplo.org"
self.user_count = 10
self.is_sim = False
self.nfc_interface_only = False
if tester:
self.initFromTester(tester)
@ -62,23 +61,10 @@ class Tester:
self.ctap = tester.ctap
self.ctap1 = tester.ctap1
self.client = tester.client
self.nfc_interface_only = tester.nfc_interface_only
def find_device(self, nfcInterfaceOnly=False):
dev = None
self.nfc_interface_only = nfcInterfaceOnly
if not nfcInterfaceOnly:
print("--- HID ---")
print(list(CtapHidDevice.list_devices()))
dev = next(CtapHidDevice.list_devices(), None)
if not dev:
from fido2.pcsc import CtapPcscDevice
print("--- NFC ---")
print(list(CtapPcscDevice.list_devices()))
dev = next(CtapPcscDevice.list_devices(), None)
def find_device(self,):
print(list(CtapHidDevice.list_devices()))
dev = next(CtapHidDevice.list_devices(), None)
if not dev:
raise RuntimeError("No FIDO device found")
self.dev = dev
@ -103,7 +89,7 @@ class Tester:
else:
print("Please reboot authentictor and hit enter")
input()
self.find_device(self.nfc_interface_only)
self.find_device()
def send_data(self, cmd, data):
if not isinstance(data, bytes):
@ -197,7 +183,7 @@ class Tester:
print("You must power cycle authentictor. Hit enter when done.")
input()
time.sleep(0.2)
self.find_device(self.nfc_interface_only)
self.find_device()
self.ctap.reset()
def testMC(self, test, *args, **kwargs):

View File

@ -42,14 +42,12 @@ class U2FTests(Tester):
with Test("Check bad INS"):
try:
self.ctap1.send_apdu(0, 0, 0, 0, b"")
assert False
except ApduError as e:
assert e.code == 0x6D00
with Test("Check bad CLA"):
try:
self.ctap1.send_apdu(1, CTAP1.INS.VERSION, 0, 0, b"abc")
assert False
except ApduError as e:
assert e.code == 0x6E00