Compare commits

..

6 Commits

Author SHA1 Message Date
a7cda74741 Update solo-extras.md 2019-08-16 14:03:41 +08:00
a8baba422f add info for rng use 2019-08-16 14:03:07 +08:00
abd2eca3ca run through fixes 2019-08-16 13:53:28 +08:00
038c594e37 dont remove solo.hex bootloader.hex 2019-08-16 13:52:17 +08:00
f09900a391 initial draft 2019-08-16 11:59:54 +08:00
bd822dd95f add secure build that uses default attestation key 2019-08-16 10:29:24 +08:00
11 changed files with 53 additions and 215 deletions

View File

@ -1,19 +1,25 @@
**NEW!** We launched a new tiny security key called Somu, it's live on Crowd Supply and you can [pre-order it now](https://solokeys.com/somu)! [![License](https://img.shields.io/github/license/solokeys/solo.svg)](https://github.com/solokeys/solo/blob/master/LICENSE)
[![All Contributors](https://img.shields.io/badge/all_contributors-17-orange.svg?style=flat-square)](#contributors)
[<img src="https://miro.medium.com/max/1400/1*PnzCPLqq_5nt1gjgSEY2LQ.png" width="600">](https://solokeys.com/somu) [![Build Status](https://travis-ci.com/solokeys/solo.svg?branch=master)](https://travis-ci.com/solokeys/solo)
[![Discourse Users](https://img.shields.io/discourse/https/discourse.solokeys.com/users.svg)](https://discourse.solokeys.com)
Somu is the micro version of Solo. We were inspired to make a secure Tomu, so we took its tiny form factor, we added the secure microcontroller and firmware of Solo, et voilà! Here we have Somu.
[![latest release](https://img.shields.io/github/release/solokeys/solo.svg)](https://update.solokeys.com/)
[![Keybase Chat](https://img.shields.io/badge/chat-on%20keybase-brightgreen.svg)](https://keybase.io/team/solokeys.public) [![Keybase Chat](https://img.shields.io/badge/chat-on%20keybase-brightgreen.svg)](https://keybase.io/team/solokeys.public)
[![Build Status](https://travis-ci.com/solokeys/solo.svg?style=flat-square&branch=master)](https://travis-ci.com/solokeys/solo) [![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fsolokeys%2Fsolo.svg?type=shield)](https://app.fossa.io/projects/git%2Bgithub.com%2Fsolokeys%2Fsolo?ref=badge_shield)
[![latest release](https://img.shields.io/github/release/solokeys/solo.svg)](https://github.com/solokeys/solo/releases)
[![commits since last release](https://img.shields.io/github/commits-since/solokeys/solo/latest.svg)](https://github.com/solokeys/solo/commits/master)
[![last commit](https://img.shields.io/github/last-commit/solokeys/solo.svg)](https://github.com/solokeys/solo/commits/master)
[![commit activity](https://img.shields.io/github/commit-activity/m/solokeys/solo.svg)](https://github.com/solokeys/solo/commits/master)
[![contributors](https://img.shields.io/github/contributors/solokeys/solo.svg)](https://github.com/solokeys/solo/graphs/contributors)
# Solo
Solo is an open source security key, and you can get one at [solokeys.com](https://solokeys.com). Solo is an open source security key, and you can get one at [solokeys.com](https://solokeys.com).
[<img src="https://static.solokeys.com/images/photos/hero-on-white-cropped.png" width="600">](https://solokeys.com)
Solo supports FIDO2 and U2F standards for strong two-factor authentication and password-less login, and it will protect you against phishing and other online attacks. With colored cases and multilingual guides we want to make secure login more personable and accessible to everyone around the globe. Solo supports FIDO2 and U2F standards for strong two-factor authentication and password-less login, and it will protect you against phishing and other online attacks. With colored cases and multilingual guides we want to make secure login more personable and accessible to everyone around the globe.
<img src="https://static.solokeys.com/images/photos/hero-on-white-cropped.png" width="600">
This repo contains the Solo firmware, including implementations of FIDO2 and U2F (CTAP2 and CTAP) over USB and NFC. The main implementation is for STM32L432, but it is easily portable. This repo contains the Solo firmware, including implementations of FIDO2 and U2F (CTAP2 and CTAP) over USB and NFC. The main implementation is for STM32L432, but it is easily portable.
For development no hardware is needed, Solo also runs as a standalone application for Windows, Linux, and Mac OSX. If you like (or want to learn) hardware instead, you can run Solo on the NUCLEO-L432KC development board, or we make Solo for Hacker, an unlocked version of Solo that lets you customize its firmware. For development no hardware is needed, Solo also runs as a standalone application for Windows, Linux, and Mac OSX. If you like (or want to learn) hardware instead, you can run Solo on the NUCLEO-L432KC development board, or we make Solo for Hacker, an unlocked version of Solo that lets you customize its firmware.
@ -36,7 +42,7 @@ Solo for Hacker is a special version of Solo that let you customize its firmware
Check out [solokeys.com](https://solokeys.com), for options on where to buy Solo. Solo Hacker can be converted to a secure version, but normal Solo cannot be converted to a Hacker version. Check out [solokeys.com](https://solokeys.com), for options on where to buy Solo. Solo Hacker can be converted to a secure version, but normal Solo cannot be converted to a Hacker version.
If you have a Solo for Hacker, here's how you can load your own code on it. You can find more details, including how to permanently lock it, in our [documentation](https://docs.solokeys.io/solo/building/). We support Python3. If you have a Solo for Hacker, here's how you can load your own code on it. You can find more details, including how to permanently lock it, in our [documentation](https://docs.solokeys.io/solo/building/). We only support Python3.
```bash ```bash
git clone --recurse-submodules https://github.com/solokeys/solo git clone --recurse-submodules https://github.com/solokeys/solo
@ -162,19 +168,3 @@ You may use Solo documentation under the terms of the CC-BY-SA 4.0 license
You can buy Solo, Solo Tap, and Solo for Hackers at [solokeys.com](https://solokeys.com). You can buy Solo, Solo Tap, and Solo for Hackers at [solokeys.com](https://solokeys.com).
<br/>
<hr/>
<br/>
[![License](https://img.shields.io/github/license/solokeys/solo.svg)](https://github.com/solokeys/solo/blob/master/LICENSE)
[![All Contributors](https://img.shields.io/badge/all_contributors-17-orange.svg?style=flat-square)](#contributors)
[![Build Status](https://travis-ci.com/solokeys/solo.svg?branch=master)](https://travis-ci.com/solokeys/solo)
[![Discourse Users](https://img.shields.io/discourse/https/discourse.solokeys.com/users.svg)](https://discourse.solokeys.com)
[![Keybase Chat](https://img.shields.io/badge/chat-on%20keybase-brightgreen.svg)](https://keybase.io/team/solokeys.public)
[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fsolokeys%2Fsolo.svg?type=shield)](https://app.fossa.io/projects/git%2Bgithub.com%2Fsolokeys%2Fsolo?ref=badge_shield)
[![latest release](https://img.shields.io/github/release/solokeys/solo.svg)](https://github.com/solokeys/solo/releases)
[![commits since last release](https://img.shields.io/github/commits-since/solokeys/solo/latest.svg)](https://github.com/solokeys/solo/commits/master)
[![last commit](https://img.shields.io/github/last-commit/solokeys/solo.svg)](https://github.com/solokeys/solo/commits/master)
[![commit activity](https://img.shields.io/github/commit-activity/m/solokeys/solo.svg)](https://github.com/solokeys/solo/commits/master)
[![contributors](https://img.shields.io/github/contributors/solokeys/solo.svg)](https://github.com/solokeys/solo/graphs/contributors)

View File

@ -1 +1 @@
2.4.3 2.4.2

View File

@ -1,21 +1,20 @@
# Summary # Summary
On Linux, by default USB dongles can't be accessed by users, for security reasons. To allow user access, so-called "udev rules" must be installed. On Linux, by default USB dongles can't be accessed by users, for security reasons. To allow user access, so-called "udev rules" must be installed. (Under Fedora, your key may work without such a rule.)
For some users, things will work automatically: Create a file like [`70-solokeys-access.rules`](https://github.com/solokeys/solo/blob/master/udev/70-solokeys-access.rules) in your `/etc/udev/rules.d` directory, for instance the following rule should cover normal access (it has to be on one line):
- Fedora seems to use a ["universal" udev rule for FIDO devices](https://github.com/amluto/u2f-hidraw-policy) ```
- Our udev rule made it into [libu2f-host](https://github.com/Yubico/libu2f-host/) v1.1.10 SUBSYSTEM=="hidraw", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="a2ca", TAG+="uaccess", MODE="0660", GROUP="plugdev"
- Arch Linux [has this package](https://www.archlinux.org/packages/community/x86_64/libu2f-host/) ```
- [Debian sid](https://packages.debian.org/sid/libu2f-udev) and [Ubuntu Eon](https://packages.ubuntu.com/eoan/libu2f-udev) can use the `libu2f-udev` package
- Debian Buster and Ubuntu Disco still distribute v1.1.10, so need the manual rule
- FreeBSD has support in [u2f-devd](https://github.com/solokeys/solo/issues/144#issuecomment-500216020)
There is hope that `udev` itself will adopt the Fedora approach (which is to check for HID usage page `F1D0`, and avoids manually whitelisting each U2F/FIDO2 key): <https://github.com/systemd/systemd/issues/11996>. Additionally, run the following command after you create this file (it is not necessary to do this again in the future):
Further progress is tracked in: <https://github.com/solokeys/solo/issues/144>. ```
sudo udevadm control --reload-rules && sudo udevadm trigger
```
If you still need to setup a rule, a simple way to do it is: A simple way to setup both the udev rule and the udevadm reload is:
``` ```
git clone git@github.com:solokeys/solo.git git clone git@github.com:solokeys/solo.git
@ -23,11 +22,9 @@ cd solo/udev
make setup make setup
``` ```
Or, manually, create a file like [`70-solokeys-access.rules`](https://github.com/solokeys/solo/blob/master/udev/70-solokeys-access.rules) in your `/etc/udev/rules.d` directory. We are working on getting user access to Solo keys enabled automatically in common Linux distributions: <https://github.com/solokeys/solo/issues/144>.
Additionally, run the following command after you create this file (it is not necessary to do this again in the future):
```
sudo udevadm control --reload-rules && sudo udevadm trigger
```
# How do udev rules work and why are they needed # How do udev rules work and why are they needed

View File

@ -13,7 +13,7 @@ int apdu_decode(uint8_t *data, size_t len, APDU_STRUCT *apdu)
{ {
EXT_APDU_HEADER *hapdu = (EXT_APDU_HEADER *)data; EXT_APDU_HEADER *hapdu = (EXT_APDU_HEADER *)data;
apdu->cla = hapdu->cla & 0xef; // mask chaining bit if any apdu->cla = hapdu->cla;
apdu->ins = hapdu->ins; apdu->ins = hapdu->ins;
apdu->p1 = hapdu->p1; apdu->p1 = hapdu->p1;
apdu->p2 = hapdu->p2; apdu->p2 = hapdu->p2;

View File

@ -44,14 +44,12 @@ extern int apdu_decode(uint8_t *data, size_t len, APDU_STRUCT *apdu);
#define APDU_FIDO_NFCCTAP_MSG 0x10 #define APDU_FIDO_NFCCTAP_MSG 0x10
#define APDU_INS_SELECT 0xA4 #define APDU_INS_SELECT 0xA4
#define APDU_INS_READ_BINARY 0xB0 #define APDU_INS_READ_BINARY 0xB0
#define APDU_GET_RESPONSE 0xC0
#define SW_SUCCESS 0x9000 #define SW_SUCCESS 0x9000
#define SW_GET_RESPONSE 0x6100 // Command successfully executed; 'XX' bytes of data are available and can be requested using GET RESPONSE. #define SW_GET_RESPONSE 0x6100 // Command successfully executed; 'XX' bytes of data are available and can be requested using GET RESPONSE.
#define SW_WRONG_LENGTH 0x6700 #define SW_WRONG_LENGTH 0x6700
#define SW_COND_USE_NOT_SATISFIED 0x6985 #define SW_COND_USE_NOT_SATISFIED 0x6985
#define SW_FILE_NOT_FOUND 0x6a82 #define SW_FILE_NOT_FOUND 0x6a82
#define SW_INCORRECT_P1P2 0x6a86
#define SW_INS_INVALID 0x6d00 // Instruction code not supported or invalid #define SW_INS_INVALID 0x6d00 // Instruction code not supported or invalid
#define SW_CLA_INVALID 0x6e00 #define SW_CLA_INVALID 0x6e00
#define SW_INTERNAL_EXCEPTION 0x6f00 #define SW_INTERNAL_EXCEPTION 0x6f00

View File

@ -262,11 +262,6 @@ void crypto_ecc256_derive_public_key(uint8_t * data, int len, uint8_t * x, uint8
memmove(y,pubkey+32,32); memmove(y,pubkey+32,32);
} }
void crypto_ecc256_compute_public_key(uint8_t * privkey, uint8_t * pubkey)
{
uECC_compute_public_key(privkey, pubkey, _es256_curve);
}
void crypto_load_external_key(uint8_t * key, int len) void crypto_load_external_key(uint8_t * key, int len)
{ {
_signing_key = key; _signing_key = key;

View File

@ -26,7 +26,6 @@ void crypto_sha512_final(uint8_t * hash);
void crypto_ecc256_init(); void crypto_ecc256_init();
void crypto_ecc256_derive_public_key(uint8_t * data, int len, uint8_t * x, uint8_t * y); void crypto_ecc256_derive_public_key(uint8_t * data, int len, uint8_t * x, uint8_t * y);
void crypto_ecc256_compute_public_key(uint8_t * privkey, uint8_t * pubkey);
void crypto_ecc256_load_key(uint8_t * data, int len, uint8_t * data2, int len2); void crypto_ecc256_load_key(uint8_t * data, int len, uint8_t * data2, int len2);
void crypto_ecc256_load_attestation_key(); void crypto_ecc256_load_attestation_key();

View File

@ -256,9 +256,7 @@ static int ctap_generate_cose_key(CborEncoder * cose_key, uint8_t * hmac_input,
switch(algtype) switch(algtype)
{ {
case COSE_ALG_ES256: case COSE_ALG_ES256:
if (device_is_nfc() == NFC_IS_ACTIVE) device_set_clock_rate(DEVICE_LOW_POWER_FAST);
crypto_ecc256_derive_public_key(hmac_input, len, x, y); crypto_ecc256_derive_public_key(hmac_input, len, x, y);
if (device_is_nfc() == NFC_IS_ACTIVE) device_set_clock_rate(DEVICE_LOW_POWER_IDLE);
break; break;
default: default:
printf2(TAG_ERR,"Error, COSE alg %d not supported\n", algtype); printf2(TAG_ERR,"Error, COSE alg %d not supported\n", algtype);
@ -1481,11 +1479,6 @@ uint8_t ctap_client_pin(CborEncoder * encoder, uint8_t * request, int length)
ret = cbor_encode_int(&map, RESP_keyAgreement); ret = cbor_encode_int(&map, RESP_keyAgreement);
check_ret(ret); check_ret(ret);
if (device_is_nfc() == NFC_IS_ACTIVE) device_set_clock_rate(DEVICE_LOW_POWER_FAST);
crypto_ecc256_compute_public_key(KEY_AGREEMENT_PRIV, KEY_AGREEMENT_PUB);
if (device_is_nfc() == NFC_IS_ACTIVE) device_set_clock_rate(DEVICE_LOW_POWER_IDLE);
ret = ctap_add_cose_key(&map, KEY_AGREEMENT_PUB, KEY_AGREEMENT_PUB+32, PUB_KEY_CRED_PUB_KEY, COSE_ALG_ECDH_ES_HKDF_256); ret = ctap_add_cose_key(&map, KEY_AGREEMENT_PUB, KEY_AGREEMENT_PUB+32, PUB_KEY_CRED_PUB_KEY, COSE_ALG_ECDH_ES_HKDF_256);
check_retr(ret); check_retr(ret);
@ -1685,7 +1678,7 @@ uint8_t ctap_request(uint8_t * pkt_raw, int length, CTAP_RESPONSE * resp)
break; break;
default: default:
status = CTAP1_ERR_INVALID_COMMAND; status = CTAP1_ERR_INVALID_COMMAND;
printf2(TAG_ERR,"error, invalid cmd: 0x%02x\n", cmd); printf2(TAG_ERR,"error, invalid cmd\n");
} }
done: done:
@ -1774,7 +1767,10 @@ void ctap_init()
exit(1); exit(1);
} }
ctap_reset_key_agreement(); if (device_is_nfc() != NFC_IS_ACTIVE)
{
ctap_reset_key_agreement();
}
#ifdef BRIDGE_TO_WALLET #ifdef BRIDGE_TO_WALLET
wallet_init(); wallet_init();
@ -1973,7 +1969,7 @@ int8_t ctap_load_key(uint8_t index, uint8_t * key)
static void ctap_reset_key_agreement() static void ctap_reset_key_agreement()
{ {
ctap_generate_rng(KEY_AGREEMENT_PRIV, sizeof(KEY_AGREEMENT_PRIV)); crypto_ecc256_make_key_pair(KEY_AGREEMENT_PUB, KEY_AGREEMENT_PRIV);
} }
void ctap_reset() void ctap_reset()

View File

@ -628,8 +628,3 @@ int device_is_nfc()
{ {
return 0; return 0;
} }
void device_set_clock_rate(DEVICE_CLOCK_RATE param)
{
}

View File

@ -282,11 +282,6 @@ void crypto_ecc256_derive_public_key(uint8_t * data, int len, uint8_t * x, uint8
memmove(x,pubkey,32); memmove(x,pubkey,32);
memmove(y,pubkey+32,32); memmove(y,pubkey+32,32);
} }
void crypto_ecc256_compute_public_key(uint8_t * privkey, uint8_t * pubkey)
{
uECC_compute_public_key(privkey, pubkey, _es256_curve);
}
void crypto_load_external_key(uint8_t * key, int len) void crypto_load_external_key(uint8_t * key, int len)
{ {

View File

@ -14,11 +14,6 @@
#define IS_IRQ_ACTIVE() (1 == (LL_GPIO_ReadInputPort(SOLO_AMS_IRQ_PORT) & SOLO_AMS_IRQ_PIN)) #define IS_IRQ_ACTIVE() (1 == (LL_GPIO_ReadInputPort(SOLO_AMS_IRQ_PORT) & SOLO_AMS_IRQ_PIN))
// chain buffer for 61XX responses
static uint8_t chain_buffer[2048] = {0};
static size_t chain_buffer_len = 0;
static bool chain_buffer_tx = false;
uint8_t p14443_block_offset(uint8_t pcb) { uint8_t p14443_block_offset(uint8_t pcb) {
uint8_t offset = 1; uint8_t offset = 1;
// NAD following // NAD following
@ -201,14 +196,7 @@ bool nfc_write_response_ex(uint8_t req0, uint8_t * data, uint8_t len, uint16_t r
res[len + block_offset + 0] = resp >> 8; res[len + block_offset + 0] = resp >> 8;
res[len + block_offset + 1] = resp & 0xff; res[len + block_offset + 1] = resp & 0xff;
nfc_write_frame(res, block_offset + len + 2); nfc_write_frame(res, block_offset + len + 2);
if (!ams_wait_for_tx(1))
{
printf1(TAG_NFC, "TX resp timeout. len: %d \r\n", len);
return false;
}
return true; return true;
} }
@ -218,7 +206,7 @@ bool nfc_write_response(uint8_t req0, uint16_t resp)
return nfc_write_response_ex(req0, NULL, 0, resp); return nfc_write_response_ex(req0, NULL, 0, resp);
} }
void nfc_write_response_chaining_plain(uint8_t req0, uint8_t * data, int len) void nfc_write_response_chaining(uint8_t req0, uint8_t * data, int len)
{ {
uint8_t res[32 + 2]; uint8_t res[32 + 2];
uint8_t iBlock = NFC_CMD_IBLOCK | (req0 & 0x0f); uint8_t iBlock = NFC_CMD_IBLOCK | (req0 & 0x0f);
@ -289,38 +277,6 @@ void nfc_write_response_chaining_plain(uint8_t req0, uint8_t * data, int len)
} }
} }
void append_get_response(uint8_t *data, size_t rest_len)
{
data[0] = 0x61;
data[1] = 0x00;
if (rest_len <= 0xff)
data[1] = rest_len & 0xff;
}
void nfc_write_response_chaining(uint8_t req0, uint8_t * data, int len, bool extapdu)
{
chain_buffer_len = 0;
chain_buffer_tx = true;
// if we dont need to break data to parts that need to exchange via GET RESPONSE command (ISO 7816-4 7.1.3)
if (len <= 255 || extapdu)
{
nfc_write_response_chaining_plain(req0, data, len);
} else {
size_t pcklen = MIN(253, len);
chain_buffer_len = len - pcklen;
printf1(TAG_NFC, "61XX chaining %d/%d.\r\n", pcklen, chain_buffer_len);
memmove(chain_buffer, data, pcklen);
append_get_response(&chain_buffer[pcklen], chain_buffer_len);
nfc_write_response_chaining_plain(req0, chain_buffer, pcklen + 2); // 2 for 61XX
// put the rest data into chain buffer
memmove(chain_buffer, &data[pcklen], chain_buffer_len);
}
}
// WTX on/off: // WTX on/off:
// sends/receives WTX frame to reader every `WTX_time` time in ms // sends/receives WTX frame to reader every `WTX_time` time in ms
// works via timer interrupts // works via timer interrupts
@ -526,15 +482,12 @@ void nfc_process_iblock(uint8_t * buf, int len)
CTAP_RESPONSE ctap_resp; CTAP_RESPONSE ctap_resp;
int status; int status;
uint16_t reslen; uint16_t reslen;
printf1(TAG_NFC,"Iblock: ");
dump_hex1(TAG_NFC, buf, len);
uint8_t block_offset = p14443_block_offset(buf[0]); uint8_t block_offset = p14443_block_offset(buf[0]);
// clear tx chain buffer if we have some other command than GET RESPONSE
if (chain_buffer_tx && buf[block_offset + 1] != APDU_GET_RESPONSE) {
chain_buffer_len = 0;
chain_buffer_tx = false;
}
APDU_STRUCT apdu; APDU_STRUCT apdu;
if (apdu_decode(buf + block_offset, len - block_offset, &apdu)) { if (apdu_decode(buf + block_offset, len - block_offset, &apdu)) {
printf1(TAG_NFC,"apdu decode error\r\n"); printf1(TAG_NFC,"apdu decode error\r\n");
@ -544,31 +497,6 @@ void nfc_process_iblock(uint8_t * buf, int len)
printf1(TAG_NFC,"apdu ok. %scase=%02x cla=%02x ins=%02x p1=%02x p2=%02x lc=%d le=%d\r\n", 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); apdu.extended_apdu ? "[e]":"", apdu.case_type, apdu.cla, apdu.ins, apdu.p1, apdu.p2, apdu.lc, apdu.le);
// APDU level chaining. ISO7816-4, 5.1.1. class byte
if (!chain_buffer_tx && buf[block_offset] & 0x10) {
if (chain_buffer_len + len > sizeof(chain_buffer)) {
nfc_write_response(buf[0], SW_WRONG_LENGTH);
return;
}
memmove(&chain_buffer[chain_buffer_len], apdu.data, apdu.lc);
chain_buffer_len += apdu.lc;
delay(1);
nfc_write_response(buf[0], SW_SUCCESS);
printf1(TAG_NFC, "APDU chaining ok. %d/%d\r\n", apdu.lc, chain_buffer_len);
return;
}
// if we have ISO 7816 APDU chain - move there all the data
if (!chain_buffer_tx && chain_buffer_len > 0) {
delay(1);
memmove(&apdu.data[chain_buffer_len], apdu.data, apdu.lc);
memmove(apdu.data, chain_buffer, chain_buffer_len);
apdu.lc += chain_buffer_len; // here apdu struct does not match with memory!
printf1(TAG_NFC, "APDU chaining merge. %d/%d\r\n", chain_buffer_len, apdu.lc);
}
// check CLA // check CLA
if (apdu.cla != 0x00 && apdu.cla != 0x80) { if (apdu.cla != 0x00 && apdu.cla != 0x80) {
printf1(TAG_NFC, "Unknown CLA %02x\r\n", apdu.cla); printf1(TAG_NFC, "Unknown CLA %02x\r\n", apdu.cla);
@ -579,53 +507,6 @@ void nfc_process_iblock(uint8_t * buf, int len)
// TODO this needs to be organized better // TODO this needs to be organized better
switch(apdu.ins) switch(apdu.ins)
{ {
// ISO 7816. 7.1 GET RESPONSE command
case APDU_GET_RESPONSE:
if (apdu.p1 != 0x00 || apdu.p2 != 0x00)
{
nfc_write_response(buf[0], SW_INCORRECT_P1P2);
printf1(TAG_NFC, "P1 or P2 error\r\n");
return;
}
// too many bytes needs. 0x00 and 0x100 - any length
if (apdu.le != 0 && apdu.le != 0x100 && apdu.le > chain_buffer_len)
{
uint16_t wlresp = SW_WRONG_LENGTH; // here can be 6700, 6C00, 6FXX. but the most standard way - 67XX or 6700
if (chain_buffer_len <= 0xff)
wlresp += chain_buffer_len & 0xff;
nfc_write_response(buf[0], wlresp);
printf1(TAG_NFC, "buffer length less than requesteds\r\n");
return;
}
// create temporary packet
uint8_t pck[255] = {0};
size_t pcklen = 253;
if (apdu.le)
pcklen = apdu.le;
if (pcklen > chain_buffer_len)
pcklen = chain_buffer_len;
printf1(TAG_NFC, "GET RESPONSE. pck len: %d buffer len: %d\r\n", pcklen, chain_buffer_len);
// create packet and add 61XX there if we have another portion(s) of data
memmove(pck, chain_buffer, pcklen);
size_t dlen = 0;
if (chain_buffer_len - pcklen)
{
append_get_response(&pck[pcklen], chain_buffer_len - pcklen);
dlen = 2;
}
// send
nfc_write_response_chaining_plain(buf[0], pck, pcklen + dlen); // dlen for 61XX
// shift the buffer
chain_buffer_len -= pcklen;
memmove(chain_buffer, &chain_buffer[pcklen], chain_buffer_len);
break;
case APDU_INS_SELECT: case APDU_INS_SELECT:
// if (apdu->p1 == 0 && apdu->p2 == 0x0c) // if (apdu->p1 == 0 && apdu->p2 == 0x0c)
// { // {
@ -669,7 +550,7 @@ void nfc_process_iblock(uint8_t * buf, int len)
printf1(TAG_NFC, "U2F GetVersion command.\r\n"); printf1(TAG_NFC, "U2F GetVersion command.\r\n");
u2f_request_nfc(&buf[block_offset], apdu.data, apdu.lc, &ctap_resp); u2f_request_nfc(&buf[block_offset], apdu.data, apdu.lc, &ctap_resp);
nfc_write_response_chaining(buf[0], ctap_resp.data, ctap_resp.length, apdu.extended_apdu); nfc_write_response_chaining(buf[0], ctap_resp.data, ctap_resp.length);
break; break;
case APDU_FIDO_U2F_REGISTER: case APDU_FIDO_U2F_REGISTER:
@ -701,7 +582,7 @@ void nfc_process_iblock(uint8_t * buf, int len)
printf1(TAG_NFC, "U2F resp len: %d\r\n", ctap_resp.length); printf1(TAG_NFC, "U2F resp len: %d\r\n", ctap_resp.length);
printf1(TAG_NFC,"U2F Register P2 took %d\r\n", timestamp()); printf1(TAG_NFC,"U2F Register P2 took %d\r\n", timestamp());
nfc_write_response_chaining(buf[0], ctap_resp.data, ctap_resp.length, apdu.extended_apdu); nfc_write_response_chaining(buf[0], ctap_resp.data, ctap_resp.length);
printf1(TAG_NFC,"U2F Register answered %d (took %d)\r\n", millis(), timestamp()); printf1(TAG_NFC,"U2F Register answered %d (took %d)\r\n", millis(), timestamp());
break; break;
@ -730,7 +611,7 @@ void nfc_process_iblock(uint8_t * buf, int len)
printf1(TAG_NFC, "U2F resp len: %d\r\n", ctap_resp.length); printf1(TAG_NFC, "U2F resp len: %d\r\n", ctap_resp.length);
printf1(TAG_NFC,"U2F Authenticate processing %d (took %d)\r\n", millis(), timestamp()); printf1(TAG_NFC,"U2F Authenticate processing %d (took %d)\r\n", millis(), timestamp());
nfc_write_response_chaining(buf[0], ctap_resp.data, ctap_resp.length, apdu.extended_apdu); nfc_write_response_chaining(buf[0], ctap_resp.data, ctap_resp.length);
printf1(TAG_NFC,"U2F Authenticate answered %d (took %d)\r\n", millis(), timestamp); printf1(TAG_NFC,"U2F Authenticate answered %d (took %d)\r\n", millis(), timestamp);
break; break;
@ -742,16 +623,13 @@ void nfc_process_iblock(uint8_t * buf, int len)
printf1(TAG_NFC, "FIDO2 CTAP message. %d\r\n", timestamp()); printf1(TAG_NFC, "FIDO2 CTAP message. %d\r\n", timestamp());
// WTX_on(WTX_TIME_DEFAULT); WTX_on(WTX_TIME_DEFAULT);
request_from_nfc(true); request_from_nfc(true);
ctap_response_init(&ctap_resp); ctap_response_init(&ctap_resp);
delay(1);
printf1(TAG_NFC,"[%d] ", apdu.lc);
dump_hex1(TAG_NFC,apdu.data, apdu.lc);
status = ctap_request(apdu.data, apdu.lc, &ctap_resp); status = ctap_request(apdu.data, apdu.lc, &ctap_resp);
request_from_nfc(false); request_from_nfc(false);
// if (!WTX_off()) if (!WTX_off())
// return; return;
printf1(TAG_NFC, "CTAP resp: 0x%02x len: %d\r\n", status, ctap_resp.length); printf1(TAG_NFC, "CTAP resp: 0x%02x len: %d\r\n", status, ctap_resp.length);
@ -767,7 +645,7 @@ void nfc_process_iblock(uint8_t * buf, int len)
ctap_resp.data[ctap_resp.length - 1] = SW_SUCCESS & 0xff; ctap_resp.data[ctap_resp.length - 1] = SW_SUCCESS & 0xff;
printf1(TAG_NFC,"CTAP processing %d (took %d)\r\n", millis(), timestamp()); printf1(TAG_NFC,"CTAP processing %d (took %d)\r\n", millis(), timestamp());
nfc_write_response_chaining(buf[0], ctap_resp.data, ctap_resp.length, apdu.extended_apdu); nfc_write_response_chaining(buf[0], ctap_resp.data, ctap_resp.length);
printf1(TAG_NFC,"CTAP answered %d (took %d)\r\n", millis(), timestamp()); printf1(TAG_NFC,"CTAP answered %d (took %d)\r\n", millis(), timestamp());
break; break;
@ -803,9 +681,6 @@ void nfc_process_iblock(uint8_t * buf, int len)
nfc_write_response(buf[0], SW_INS_INVALID); nfc_write_response(buf[0], SW_INS_INVALID);
break; break;
} }
printf1(TAG_NFC,"prev.Iblock: ");
dump_hex1(TAG_NFC, buf, len);
} }
static uint8_t ibuf[1024]; static uint8_t ibuf[1024];
@ -839,7 +714,7 @@ void nfc_process_block(uint8_t * buf, unsigned int len)
uint8_t block_offset = p14443_block_offset(buf[0]); uint8_t block_offset = p14443_block_offset(buf[0]);
if (buf[0] & 0x10) if (buf[0] & 0x10)
{ {
printf1(TAG_NFC_APDU, "NFC_CMD_IBLOCK chaining blen=%d len=%d offs=%d\r\n", ibuflen, len, block_offset); printf1(TAG_NFC_APDU, "NFC_CMD_IBLOCK chaining blen=%d len=%d\r\n", ibuflen, len);
if (ibuflen + len > sizeof(ibuf)) if (ibuflen + len > sizeof(ibuf))
{ {
printf1(TAG_NFC, "I block memory error! must have %d but have only %d\r\n", ibuflen + len, sizeof(ibuf)); printf1(TAG_NFC, "I block memory error! must have %d but have only %d\r\n", ibuflen + len, sizeof(ibuf));
@ -872,15 +747,14 @@ void nfc_process_block(uint8_t * buf, unsigned int len)
memmove(ibuf, buf, block_offset); memmove(ibuf, buf, block_offset);
ibuflen += block_offset; ibuflen += block_offset;
printf1(TAG_NFC_APDU, "NFC_CMD_IBLOCK chaining last block. blen=%d len=%d offset=%d\r\n", ibuflen, len, block_offset); printf1(TAG_NFC_APDU, "NFC_CMD_IBLOCK chaining last block. blen=%d len=%d\r\n", ibuflen, len);
printf1(TAG_NFC_APDU,"i> "); printf1(TAG_NFC_APDU,"i> ");
dump_hex1(TAG_NFC_APDU, buf, len); dump_hex1(TAG_NFC_APDU, buf, len);
nfc_process_iblock(ibuf, ibuflen); nfc_process_iblock(ibuf, ibuflen);
} else { } else {
memcpy(ibuf, buf, len); // because buf only 32b nfc_process_iblock(buf, len);
nfc_process_iblock(ibuf, len);
} }
clear_ibuf(); clear_ibuf();
} }
@ -978,7 +852,6 @@ int nfc_loop()
printf1(TAG_NFC, "NFC_CMD_WUPA\r\n"); printf1(TAG_NFC, "NFC_CMD_WUPA\r\n");
break; break;
case NFC_CMD_HLTA: case NFC_CMD_HLTA:
ams_write_command(AMS_CMD_SLEEP);
printf1(TAG_NFC, "HLTA/Halt\r\n"); printf1(TAG_NFC, "HLTA/Halt\r\n");
break; break;
case NFC_CMD_RATS: case NFC_CMD_RATS: