mirror of
https://github.com/linuxboot/heads.git
synced 2024-12-20 13:33:10 +00:00
modules/hotp-verification: revert to 1.6, add patches tested instead
Signed-off-by: Thierry Laurion <insurgo@riseup.net>
This commit is contained in:
parent
c4832eed0e
commit
a9d3d96ec1
@ -2,12 +2,12 @@ modules-$(CONFIG_HOTPKEY) += hotp-verification
|
|||||||
|
|
||||||
hotp-verification_depends := libusb $(musl_dep)
|
hotp-verification_depends := libusb $(musl_dep)
|
||||||
|
|
||||||
# v1.6 + patch from https://github.com/Nitrokey/nitrokey-hotp-verification/pull/46/commits/de355ed93ba50280bf377772082b76b7a2285185
|
# v1.6
|
||||||
hotp-verification_version := de355ed93ba50280bf377772082b76b7a2285185
|
hotp-verification_version := e9050e0c914e7a8ffef5d1c82a014e0e2bf79346
|
||||||
hotp-verification_dir := hotp-verification-$(hotp-verification_version)
|
hotp-verification_dir := hotp-verification-$(hotp-verification_version)
|
||||||
hotp-verification_tar := nitrokey-hotp-verification-$(hotp-verification_version).tar.gz
|
hotp-verification_tar := nitrokey-hotp-verification-$(hotp-verification_version).tar.gz
|
||||||
hotp-verification_url := https://github.com/Nitrokey/nitrokey-hotp-verification/archive/$(hotp-verification_version).tar.gz
|
hotp-verification_url := https://github.com/Nitrokey/nitrokey-hotp-verification/archive/$(hotp-verification_version).tar.gz
|
||||||
hotp-verification_hash := adbc2eb75257f4adda201419ed1282950a8cf86d167b2c76f708047d0b7aeaa5
|
hotp-verification_hash := 480c978d3585eee73b9aa5186b471d4caeeeeba411217e1544eef7cfd90312ac
|
||||||
|
|
||||||
hotp-verification_target := \
|
hotp-verification_target := \
|
||||||
$(MAKE_JOBS) \
|
$(MAKE_JOBS) \
|
||||||
|
@ -0,0 +1,450 @@
|
|||||||
|
From 707c6545a509eeb24a06537e5f835d786c2e657e Mon Sep 17 00:00:00 2001
|
||||||
|
From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= <sosthene@nitrokey.com>
|
||||||
|
Date: Thu, 5 Dec 2024 16:44:30 +0100
|
||||||
|
Subject: [PATCH] Add support for nitrokey 3 distinction between the secrets
|
||||||
|
app and other
|
||||||
|
|
||||||
|
This now adds the secrets app version and the nitrokey 3 firmware version,
|
||||||
|
and also the gpg pins
|
||||||
|
---
|
||||||
|
src/ccid.c | 71 +++++++++++++++++++++++++-
|
||||||
|
src/ccid.h | 2 +
|
||||||
|
src/device.c | 29 +++++------
|
||||||
|
src/device.h | 2 +-
|
||||||
|
src/main.c | 41 +++++++++++----
|
||||||
|
src/operations_ccid.c | 113 +++++++++++++++++++++++++++++++++++++-----
|
||||||
|
src/operations_ccid.h | 2 +-
|
||||||
|
src/structs.h | 19 +++++++
|
||||||
|
8 files changed, 238 insertions(+), 41 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/src/ccid.c b/src/ccid.c
|
||||||
|
index 9cf24a0..a2cc919 100644
|
||||||
|
--- a/src/ccid.c
|
||||||
|
+++ b/src/ccid.c
|
||||||
|
@@ -104,7 +104,7 @@ IccResult parse_icc_result(uint8_t *buf, size_t buf_len) {
|
||||||
|
// .buffer_len = buf_len
|
||||||
|
};
|
||||||
|
// Make sure the response do not contain overread attempts
|
||||||
|
- rassert(i.data_len < buf_len - 10);
|
||||||
|
+ rassert(i.data_len <= buf_len - 10);
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -307,6 +307,75 @@ int send_select_ccid(libusb_device_handle *handle, uint8_t buf[], size_t buf_siz
|
||||||
|
return RET_NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
+int send_select_nk3_admin_ccid(libusb_device_handle *handle, uint8_t buf[], size_t buf_size, IccResult *iccResult) {
|
||||||
|
+ unsigned char cmd_select[] = {
|
||||||
|
+ 0x6f,
|
||||||
|
+ 0x0E,
|
||||||
|
+ 0x00,
|
||||||
|
+ 0x00,
|
||||||
|
+ 0x00,
|
||||||
|
+ 0x00,
|
||||||
|
+ 0x00,
|
||||||
|
+ 0x00,
|
||||||
|
+ 0x00,
|
||||||
|
+ 0x00,
|
||||||
|
+ 0x00,
|
||||||
|
+ 0xa4,
|
||||||
|
+ 0x04,
|
||||||
|
+ 0x00,
|
||||||
|
+ 0x09,
|
||||||
|
+ 0xa0,
|
||||||
|
+ 0x00,
|
||||||
|
+ 0x00,
|
||||||
|
+ 0x08,
|
||||||
|
+ 0x47,
|
||||||
|
+ 0x00,
|
||||||
|
+ 0x00,
|
||||||
|
+ 0x00,
|
||||||
|
+ 0x01,
|
||||||
|
+ };
|
||||||
|
+
|
||||||
|
+ check_ret(
|
||||||
|
+ ccid_process_single(handle, buf, buf_size, cmd_select, sizeof cmd_select, iccResult),
|
||||||
|
+ RET_COMM_ERROR);
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+ return RET_NO_ERROR;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+int send_select_nk3_pgp_ccid(libusb_device_handle *handle, uint8_t buf[], size_t buf_size, IccResult *iccResult) {
|
||||||
|
+ unsigned char cmd_select[] = {
|
||||||
|
+ 0x6f,
|
||||||
|
+ 0x0C,
|
||||||
|
+ 0x00,
|
||||||
|
+ 0x00,
|
||||||
|
+ 0x00,
|
||||||
|
+ 0x00,
|
||||||
|
+ 0x00,
|
||||||
|
+ 0x00,
|
||||||
|
+ 0x00,
|
||||||
|
+ 0x00,
|
||||||
|
+ 0x00,
|
||||||
|
+ 0xA4,
|
||||||
|
+ 0x04,
|
||||||
|
+ 0x00,
|
||||||
|
+ 0x06,
|
||||||
|
+ 0xD2,
|
||||||
|
+ 0x76,
|
||||||
|
+ 0x00,
|
||||||
|
+ 0x01,
|
||||||
|
+ 0x24,
|
||||||
|
+ 0x01,
|
||||||
|
+ 0x00,
|
||||||
|
+ };
|
||||||
|
+
|
||||||
|
+ check_ret(
|
||||||
|
+ ccid_process_single(handle, buf, buf_size, cmd_select, sizeof cmd_select, iccResult),
|
||||||
|
+ RET_COMM_ERROR);
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+ return RET_NO_ERROR;
|
||||||
|
+}
|
||||||
|
|
||||||
|
int ccid_init(libusb_device_handle *handle) {
|
||||||
|
|
||||||
|
diff --git a/src/ccid.h b/src/ccid.h
|
||||||
|
index ed17dc7..3dcf106 100644
|
||||||
|
--- a/src/ccid.h
|
||||||
|
+++ b/src/ccid.h
|
||||||
|
@@ -70,6 +70,8 @@ uint32_t icc_pack_tlvs_for_sending(uint8_t *buf, size_t buflen, TLV tlvs[], int
|
||||||
|
libusb_device_handle *get_device(libusb_context *ctx, const struct VidPid pPid[], int devices_count);
|
||||||
|
int ccid_init(libusb_device_handle *handle);
|
||||||
|
int send_select_ccid(libusb_device_handle *handle, uint8_t buf[], size_t buf_size, IccResult *iccResult);
|
||||||
|
+int send_select_nk3_admin_ccid(libusb_device_handle *handle, uint8_t buf[], size_t buf_size, IccResult *iccResult);
|
||||||
|
+int send_select_nk3_pgp_ccid(libusb_device_handle *handle, uint8_t buf[], size_t buf_size, IccResult *iccResult);
|
||||||
|
|
||||||
|
|
||||||
|
enum {
|
||||||
|
diff --git a/src/device.c b/src/device.c
|
||||||
|
index 4b9361e..52acece 100644
|
||||||
|
--- a/src/device.c
|
||||||
|
+++ b/src/device.c
|
||||||
|
@@ -29,6 +29,7 @@
|
||||||
|
#include "structs.h"
|
||||||
|
#include "utils.h"
|
||||||
|
#include <assert.h>
|
||||||
|
+#include <hidapi/hidapi.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
@@ -259,23 +260,19 @@ int device_receive_buf(struct Device *dev) {
|
||||||
|
|
||||||
|
#include "operations_ccid.h"
|
||||||
|
|
||||||
|
-int device_get_status(struct Device *dev, struct ResponseStatus *out_status) {
|
||||||
|
- assert(out_status != NULL);
|
||||||
|
+int device_get_status(struct Device *dev, struct FullResponseStatus *out_response) {
|
||||||
|
+ assert(out_response != NULL);
|
||||||
|
assert(dev != NULL);
|
||||||
|
- memset(out_status, 0, sizeof(struct ResponseStatus));
|
||||||
|
+ memset(out_response, 0, sizeof(struct FullResponseStatus));
|
||||||
|
+
|
||||||
|
+ struct ResponseStatus *out_status = &out_response->response_status;
|
||||||
|
|
||||||
|
if (dev->connection_type == CONNECTION_CCID) {
|
||||||
|
- int counter = 0;
|
||||||
|
- uint32_t serial = 0;
|
||||||
|
- uint16_t version = 0;
|
||||||
|
- int res = status_ccid(dev->mp_devhandle_ccid,
|
||||||
|
- &counter,
|
||||||
|
- &version,
|
||||||
|
- &serial);
|
||||||
|
- out_status->retry_admin = counter;
|
||||||
|
- out_status->retry_user = counter;
|
||||||
|
- out_status->card_serial_u32 = serial;
|
||||||
|
- out_status->firmware_version = version;
|
||||||
|
+ int res = status_ccid(dev->mp_devhandle_ccid, out_response);
|
||||||
|
+ // out_status->retry_admin = counter;
|
||||||
|
+ // out_status->retry_user = counter;
|
||||||
|
+ // out_status->card_serial_u32 = serial;
|
||||||
|
+ // out_status->firmware_version = version;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -290,7 +287,7 @@ int device_get_status(struct Device *dev, struct ResponseStatus *out_status) {
|
||||||
|
|
||||||
|
device_send_buf(dev, GET_STATUS);
|
||||||
|
device_receive_buf(dev);
|
||||||
|
- *out_status = *(struct ResponseStatus *) dev->packet_response.response_st.payload;
|
||||||
|
+ out_response->response_status = *(struct ResponseStatus *) dev->packet_response.response_st.payload;
|
||||||
|
|
||||||
|
if (out_status->firmware_version_st.minor == 1) {
|
||||||
|
for (int i = 0; i < 100; ++i) {
|
||||||
|
@@ -343,4 +340,4 @@ const char *command_status_to_string(uint8_t status_code) {
|
||||||
|
void clean_buffers(struct Device *dev) {
|
||||||
|
memset(dev->ccid_buffer_in, 0, sizeof dev->ccid_buffer_in);
|
||||||
|
memset(dev->ccid_buffer_out, 0, sizeof dev->ccid_buffer_out);
|
||||||
|
-}
|
||||||
|
\ No newline at end of file
|
||||||
|
+}
|
||||||
|
diff --git a/src/device.h b/src/device.h
|
||||||
|
index c895546..97feeeb 100644
|
||||||
|
--- a/src/device.h
|
||||||
|
+++ b/src/device.h
|
||||||
|
@@ -72,7 +72,7 @@ struct Device {
|
||||||
|
|
||||||
|
int device_connect(struct Device *dev);
|
||||||
|
int device_disconnect(struct Device *dev);
|
||||||
|
-int device_get_status(struct Device *dev, struct ResponseStatus *out_status);
|
||||||
|
+int device_get_status(struct Device *dev, struct FullResponseStatus *out_status);
|
||||||
|
int device_send(struct Device *dev, uint8_t *in_data, size_t data_size, uint8_t command_ID);
|
||||||
|
int device_receive(struct Device *dev, uint8_t *out_data, size_t out_buffer_size);
|
||||||
|
int device_send_buf(struct Device *dev, uint8_t command_ID);
|
||||||
|
diff --git a/src/main.c b/src/main.c
|
||||||
|
index 059069e..9b38552 100644
|
||||||
|
--- a/src/main.c
|
||||||
|
+++ b/src/main.c
|
||||||
|
@@ -93,25 +93,46 @@ int parse_cmd_and_run(int argc, char *const *argv) {
|
||||||
|
res = RET_NO_ERROR;
|
||||||
|
break;
|
||||||
|
case 'i': {// id | info
|
||||||
|
- struct ResponseStatus status;
|
||||||
|
+ struct FullResponseStatus status;
|
||||||
|
+ memset(&status, 0, sizeof (struct FullResponseStatus));
|
||||||
|
+
|
||||||
|
res = device_get_status(&dev, &status);
|
||||||
|
check_ret((res != RET_NO_ERROR) && (res != RET_NO_PIN_ATTEMPTS), res);
|
||||||
|
if (strnlen(argv[1], 10) == 2 && argv[1][1] == 'd') {
|
||||||
|
// id command - print ID only
|
||||||
|
- print_card_serial(&status);
|
||||||
|
+ print_card_serial(&status.response_status);
|
||||||
|
} else {
|
||||||
|
// info command - print status
|
||||||
|
printf("Connected device status:\n");
|
||||||
|
printf("\tCard serial: ");
|
||||||
|
- print_card_serial(&status);
|
||||||
|
- printf("\tFirmware: v%d.%d\n",
|
||||||
|
- status.firmware_version_st.major,
|
||||||
|
- status.firmware_version_st.minor);
|
||||||
|
- if (res != RET_NO_PIN_ATTEMPTS) {
|
||||||
|
- printf("\tCard counters: Admin %d, User %d\n",
|
||||||
|
- status.retry_admin, status.retry_user);
|
||||||
|
+ print_card_serial(&status.response_status);
|
||||||
|
+ if (status.device_type == Nk3) {
|
||||||
|
+ printf("\tFirmware Nitrokey 3: v%d.%d.%d\n",
|
||||||
|
+ (status.nk3_extra_info.firmware_version >> 22) & 0b1111111111,
|
||||||
|
+ (status.nk3_extra_info.firmware_version >> 6) & 0xFFFF,
|
||||||
|
+ status.nk3_extra_info.firmware_version & 0b111111);
|
||||||
|
+ printf("\tFirmware Secrets App: v%d.%d\n",
|
||||||
|
+ status.response_status.firmware_version_st.major,
|
||||||
|
+ status.response_status.firmware_version_st.minor);
|
||||||
|
+ if (res != RET_NO_PIN_ATTEMPTS) {
|
||||||
|
+ printf("\tSecrets app PIN counter: %d\n",
|
||||||
|
+ status.response_status.retry_user);
|
||||||
|
+ } else {
|
||||||
|
+ printf("\tSecrets app PIN counter: PIN is not set - set PIN before the first use\n");
|
||||||
|
+ }
|
||||||
|
+ printf("\tGPG Card counters: Admin %d, User %d\n",
|
||||||
|
+ status.nk3_extra_info.pgp_admin_pin_retries,
|
||||||
|
+ status.nk3_extra_info.pgp_user_pin_retries);
|
||||||
|
} else {
|
||||||
|
- printf("\tCard counters: PIN is not set - set PIN before the first use\n");
|
||||||
|
+ printf("\tFirmware: v%d.%d\n",
|
||||||
|
+ status.response_status.firmware_version_st.major,
|
||||||
|
+ status.response_status.firmware_version_st.minor);
|
||||||
|
+ if (res != RET_NO_PIN_ATTEMPTS) {
|
||||||
|
+ printf("\tCard counters: Admin %d, User %d\n",
|
||||||
|
+ status.response_status.retry_admin, status.response_status.retry_user);
|
||||||
|
+ } else {
|
||||||
|
+ printf("\tCard counters: PIN is not set - set PIN before the first use\n");
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (res == RET_NO_PIN_ATTEMPTS) {
|
||||||
|
diff --git a/src/operations_ccid.c b/src/operations_ccid.c
|
||||||
|
index eb46124..25772e5 100644
|
||||||
|
--- a/src/operations_ccid.c
|
||||||
|
+++ b/src/operations_ccid.c
|
||||||
|
@@ -273,14 +273,102 @@ int verify_code_ccid(struct Device *dev, const uint32_t code_to_verify) {
|
||||||
|
return RET_VALIDATION_PASSED;
|
||||||
|
}
|
||||||
|
|
||||||
|
-int status_ccid(libusb_device_handle *handle, int *attempt_counter, uint16_t *firmware_version, uint32_t *serial_number) {
|
||||||
|
+int status_ccid(libusb_device_handle *handle, struct FullResponseStatus *full_response) {
|
||||||
|
+ rassert(full_response != NULL);
|
||||||
|
+ struct ResponseStatus *response = &full_response->response_status;
|
||||||
|
rassert(handle != NULL);
|
||||||
|
- rassert(attempt_counter != NULL);
|
||||||
|
- rassert(firmware_version != NULL);
|
||||||
|
- rassert(serial_number != NULL);
|
||||||
|
uint8_t buf[1024] = {};
|
||||||
|
IccResult iccResult = {};
|
||||||
|
- int r = send_select_ccid(handle, buf, sizeof buf, &iccResult);
|
||||||
|
+ bool pin_counter_is_error = false;
|
||||||
|
+ int r;
|
||||||
|
+ libusb_device *usb_dev;
|
||||||
|
+ struct libusb_device_descriptor usb_desc;
|
||||||
|
+
|
||||||
|
+ usb_dev = libusb_get_device(handle);
|
||||||
|
+
|
||||||
|
+ r = libusb_get_device_descriptor(usb_dev, &usb_desc);
|
||||||
|
+
|
||||||
|
+ if (r < 0) {
|
||||||
|
+ return r;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+ if (usb_desc.idVendor == NITROKEY_USB_VID || usb_desc.idProduct == NITROKEY_3_USB_PID) {
|
||||||
|
+ full_response->device_type = Nk3;
|
||||||
|
+ } else if (usb_desc.idVendor == NITROKEY_USB_VID || usb_desc.idProduct == NITROKEY_PRO_USB_PID) {
|
||||||
|
+ full_response->device_type = NkPro2;
|
||||||
|
+ } else if (usb_desc.idVendor == NITROKEY_USB_VID || usb_desc.idProduct == NITROKEY_STORAGE_USB_PID) {
|
||||||
|
+ full_response->device_type = NkStorage;
|
||||||
|
+ } else if (usb_desc.idVendor == LIBREM_KEY_USB_VID || usb_desc.idProduct == LIBREM_KEY_USB_PID) {
|
||||||
|
+ full_response->device_type = LibremKey;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (full_response->device_type == Nk3) {
|
||||||
|
+ r = send_select_nk3_admin_ccid(handle, buf, sizeof buf, &iccResult);
|
||||||
|
+ if (r != RET_NO_ERROR) {
|
||||||
|
+ return r;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ uint8_t data_iso[MAX_CCID_BUFFER_SIZE] = {};
|
||||||
|
+ uint32_t iso_actual_length = iso7816_compose(
|
||||||
|
+ data_iso, sizeof data_iso,
|
||||||
|
+ 0x61, 0, 0, 0, 4, NULL, 0);
|
||||||
|
+
|
||||||
|
+ // encode ccid wrapper
|
||||||
|
+ uint32_t icc_actual_length = icc_compose(buf, sizeof buf,
|
||||||
|
+ 0x6F, iso_actual_length,
|
||||||
|
+ 0, 0, 0, data_iso);
|
||||||
|
+ int transferred;
|
||||||
|
+ r = ccid_send(handle, &transferred, buf, icc_actual_length);
|
||||||
|
+ if (r != 0) {
|
||||||
|
+ return r;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ r = ccid_receive(handle, &transferred, buf, sizeof buf);
|
||||||
|
+ if (r != 0) {
|
||||||
|
+ return r;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ IccResult iccResult = parse_icc_result(buf, transferred);
|
||||||
|
+ rassert(iccResult.data_status_code == 0x9000);
|
||||||
|
+ rassert(iccResult.data_len == 6);
|
||||||
|
+ full_response->nk3_extra_info.firmware_version = be32toh(*(uint32_t *) iccResult.data);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (full_response->device_type == Nk3) {
|
||||||
|
+ r = send_select_nk3_pgp_ccid(handle, buf, sizeof buf, &iccResult);
|
||||||
|
+ if (r != RET_NO_ERROR) {
|
||||||
|
+ return r;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ uint8_t data_iso[MAX_CCID_BUFFER_SIZE] = {};
|
||||||
|
+ uint32_t iso_actual_length = iso7816_compose(
|
||||||
|
+ data_iso, sizeof data_iso,
|
||||||
|
+ 0xCA, 0, 0xC4, 0, 0xFF, NULL, 0);
|
||||||
|
+
|
||||||
|
+ // encode ccid wrapper
|
||||||
|
+ uint32_t icc_actual_length = icc_compose(buf, sizeof buf,
|
||||||
|
+ 0x6F, iso_actual_length,
|
||||||
|
+ 0, 0, 0, data_iso);
|
||||||
|
+ int transferred;
|
||||||
|
+ r = ccid_send(handle, &transferred, buf, icc_actual_length);
|
||||||
|
+ if (r != 0) {
|
||||||
|
+ return r;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ r = ccid_receive(handle, &transferred, buf, sizeof buf);
|
||||||
|
+ if (r != 0) {
|
||||||
|
+ return r;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ IccResult iccResult = parse_icc_result(buf, transferred);
|
||||||
|
+ rassert(iccResult.data_status_code == 0x9000);
|
||||||
|
+ rassert(iccResult.data_len == 9);
|
||||||
|
+ full_response->nk3_extra_info.pgp_user_pin_retries = iccResult.data[4];
|
||||||
|
+ full_response->nk3_extra_info.pgp_admin_pin_retries = iccResult.data[6];
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ r = send_select_ccid(handle, buf, sizeof buf, &iccResult);
|
||||||
|
if (r != RET_NO_ERROR) {
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
@@ -292,29 +380,30 @@ int status_ccid(libusb_device_handle *handle, int *attempt_counter, uint16_t *fi
|
||||||
|
r = get_tlv(iccResult.data, iccResult.data_len, Tag_PINCounter, &counter_tlv);
|
||||||
|
if (!(r == RET_NO_ERROR && counter_tlv.tag == Tag_PINCounter)) {
|
||||||
|
// PIN counter not found - comm error (ignore) or PIN not set
|
||||||
|
- *attempt_counter = -1;
|
||||||
|
+ pin_counter_is_error = true;
|
||||||
|
} else {
|
||||||
|
- *attempt_counter = counter_tlv.v_data[0];
|
||||||
|
+ response->retry_admin = counter_tlv.v_data[0];
|
||||||
|
+ response->retry_user = counter_tlv.v_data[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
TLV serial_tlv = {};
|
||||||
|
r = get_tlv(iccResult.data, iccResult.data_len, Tag_SerialNumber, &serial_tlv);
|
||||||
|
if (r == RET_NO_ERROR && serial_tlv.tag == Tag_SerialNumber) {
|
||||||
|
- *serial_number = be32toh(*(uint32_t *) serial_tlv.v_data);
|
||||||
|
+ response->card_serial_u32 = be32toh(*(uint32_t *) serial_tlv.v_data);
|
||||||
|
} else {
|
||||||
|
// ignore errors - unsupported or hidden serial_tlv number
|
||||||
|
- *serial_number = 0;
|
||||||
|
+ response->card_serial_u32 = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
TLV version_tlv = {};
|
||||||
|
r = get_tlv(iccResult.data, iccResult.data_len, Tag_Version, &version_tlv);
|
||||||
|
if (!(r == RET_NO_ERROR && version_tlv.tag == Tag_Version)) {
|
||||||
|
- *firmware_version = 0;
|
||||||
|
+ response->firmware_version = 0;
|
||||||
|
return RET_COMM_ERROR;
|
||||||
|
}
|
||||||
|
- *firmware_version = be16toh(*(uint16_t *) version_tlv.v_data);
|
||||||
|
+ response->firmware_version = be16toh(*(uint16_t *) version_tlv.v_data);
|
||||||
|
|
||||||
|
- if (*attempt_counter == -1) {
|
||||||
|
+ if (pin_counter_is_error == true) {
|
||||||
|
return RET_NO_PIN_ATTEMPTS;
|
||||||
|
}
|
||||||
|
return RET_NO_ERROR;
|
||||||
|
diff --git a/src/operations_ccid.h b/src/operations_ccid.h
|
||||||
|
index b26b3c7..ea463b4 100644
|
||||||
|
--- a/src/operations_ccid.h
|
||||||
|
+++ b/src/operations_ccid.h
|
||||||
|
@@ -10,7 +10,7 @@ int authenticate_ccid(struct Device *dev, const char *admin_PIN);
|
||||||
|
int authenticate_or_set_ccid(struct Device *dev, const char *admin_PIN);
|
||||||
|
int set_secret_on_device_ccid(struct Device *dev, const char *admin_PIN, const char *OTP_secret_base32, const uint64_t hotp_counter);
|
||||||
|
int verify_code_ccid(struct Device *dev, const uint32_t code_to_verify);
|
||||||
|
-int status_ccid(libusb_device_handle *handle, int *attempt_counter, uint16_t *firmware_version, uint32_t *serial_number);
|
||||||
|
+int status_ccid(libusb_device_handle *handle, struct FullResponseStatus *full_response);
|
||||||
|
|
||||||
|
|
||||||
|
#endif//NITROKEY_HOTP_VERIFICATION_OPERATIONS_CCID_H
|
||||||
|
diff --git a/src/structs.h b/src/structs.h
|
||||||
|
index 6309cd0..9e87134 100644
|
||||||
|
--- a/src/structs.h
|
||||||
|
+++ b/src/structs.h
|
||||||
|
@@ -116,6 +116,25 @@ struct ResponseStatus {
|
||||||
|
uint8_t retry_user; /*not present in the firmware response for the Status command in v0.8 firmware*/
|
||||||
|
};
|
||||||
|
|
||||||
|
+enum DeviceType {
|
||||||
|
+ Unknown = 0,
|
||||||
|
+ Nk3,
|
||||||
|
+ NkPro2,
|
||||||
|
+ NkStorage,
|
||||||
|
+ LibremKey,
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+struct FullResponseStatus {
|
||||||
|
+ enum DeviceType device_type;
|
||||||
|
+ struct ResponseStatus response_status;
|
||||||
|
+ struct {
|
||||||
|
+ // Only valid if device_type is NK3
|
||||||
|
+ uint8_t pgp_admin_pin_retries;
|
||||||
|
+ uint8_t pgp_user_pin_retries;
|
||||||
|
+ uint32_t firmware_version;
|
||||||
|
+ } nk3_extra_info;
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
|
||||||
|
struct WriteToOTPSlot {
|
||||||
|
//admin auth
|
@ -0,0 +1,219 @@
|
|||||||
|
From de355ed93ba50280bf377772082b76b7a2285185 Mon Sep 17 00:00:00 2001
|
||||||
|
From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= <sosthene@nitrokey.com>
|
||||||
|
Date: Mon, 25 Nov 2024 17:04:47 +0100
|
||||||
|
Subject: [PATCH 1/3] Add reset command for nitrokey 3
|
||||||
|
|
||||||
|
---
|
||||||
|
src/main.c | 10 ++++++++--
|
||||||
|
src/operations_ccid.c | 41 +++++++++++++++++++++++++++++++++++++++++
|
||||||
|
src/operations_ccid.h | 1 +
|
||||||
|
3 files changed, 50 insertions(+), 2 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/src/main.c b/src/main.c
|
||||||
|
index 059069e..b80b71d 100644
|
||||||
|
--- a/src/main.c
|
||||||
|
+++ b/src/main.c
|
||||||
|
@@ -21,6 +21,7 @@
|
||||||
|
|
||||||
|
#include "ccid.h"
|
||||||
|
#include "operations.h"
|
||||||
|
+#include "operations_ccid.h"
|
||||||
|
#include "return_codes.h"
|
||||||
|
#include "utils.h"
|
||||||
|
#include "version.h"
|
||||||
|
@@ -134,8 +135,13 @@ int parse_cmd_and_run(int argc, char *const *argv) {
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'r':
|
||||||
|
- if (argc != 3) break;
|
||||||
|
- res = regenerate_AES_key(&dev, argv[2]);
|
||||||
|
+ if (strncmp(argv[1], "reset", 15) == 0) {
|
||||||
|
+ if (argc != 2) break;
|
||||||
|
+ res = nk3_reset(&dev);
|
||||||
|
+ } else if (strncmp(argv[1], "regenerate", 15) == 0) {
|
||||||
|
+ if (argc != 3) break;
|
||||||
|
+ res = regenerate_AES_key(&dev, argv[2]);
|
||||||
|
+ }
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
diff --git a/src/operations_ccid.c b/src/operations_ccid.c
|
||||||
|
index eb46124..574155d 100644
|
||||||
|
--- a/src/operations_ccid.c
|
||||||
|
+++ b/src/operations_ccid.c
|
||||||
|
@@ -32,6 +32,47 @@
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
|
||||||
|
+
|
||||||
|
+int nk3_reset(struct Device *dev) {
|
||||||
|
+ libusb_device *usb_dev;
|
||||||
|
+ struct libusb_device_descriptor usb_desc;
|
||||||
|
+ usb_dev = libusb_get_device(dev->mp_devhandle_ccid);
|
||||||
|
+
|
||||||
|
+ int r = libusb_get_device_descriptor(usb_dev, &usb_desc);
|
||||||
|
+
|
||||||
|
+ if (r < 0) {
|
||||||
|
+ return r;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+ if (usb_desc.idVendor != NITROKEY_USB_VID || usb_desc.idProduct != NITROKEY_3_USB_PID) {
|
||||||
|
+ return 0;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+ uint8_t buf[10];
|
||||||
|
+ // encode
|
||||||
|
+ uint32_t icc_actual_length = iso7816_compose(buf, sizeof buf, Ins_Reset, 0xDE, 0xAD, 0, 0, NULL, 0);
|
||||||
|
+
|
||||||
|
+ // encode ccid wrapper
|
||||||
|
+ icc_actual_length = icc_compose(dev->ccid_buffer_out, sizeof dev->ccid_buffer_out,
|
||||||
|
+ 0x6F, icc_actual_length,
|
||||||
|
+ 0, 0, 0, buf);
|
||||||
|
+ // send
|
||||||
|
+ IccResult iccResult;
|
||||||
|
+ r = ccid_process_single(dev->mp_devhandle_ccid, dev->ccid_buffer_in, sizeof dev->ccid_buffer_in,
|
||||||
|
+ dev->ccid_buffer_out, icc_actual_length, &iccResult);
|
||||||
|
+ if (r != 0) {
|
||||||
|
+ return r;
|
||||||
|
+ }
|
||||||
|
+ // check status code
|
||||||
|
+ if (iccResult.data_status_code != 0x9000) {
|
||||||
|
+ return 1;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return RET_NO_ERROR;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
int set_pin_ccid(struct Device *dev, const char *admin_PIN) {
|
||||||
|
TLV tlvs[] = {
|
||||||
|
{
|
||||||
|
diff --git a/src/operations_ccid.h b/src/operations_ccid.h
|
||||||
|
index b26b3c7..ec0070c 100644
|
||||||
|
--- a/src/operations_ccid.h
|
||||||
|
+++ b/src/operations_ccid.h
|
||||||
|
@@ -11,6 +11,7 @@ int authenticate_or_set_ccid(struct Device *dev, const char *admin_PIN);
|
||||||
|
int set_secret_on_device_ccid(struct Device *dev, const char *admin_PIN, const char *OTP_secret_base32, const uint64_t hotp_counter);
|
||||||
|
int verify_code_ccid(struct Device *dev, const uint32_t code_to_verify);
|
||||||
|
int status_ccid(libusb_device_handle *handle, int *attempt_counter, uint16_t *firmware_version, uint32_t *serial_number);
|
||||||
|
+int nk3_reset(struct Device *dev);
|
||||||
|
|
||||||
|
|
||||||
|
#endif//NITROKEY_HOTP_VERIFICATION_OPERATIONS_CCID_H
|
||||||
|
|
||||||
|
From 8425e8c622138aef9ab207119e14f7cbedd40175 Mon Sep 17 00:00:00 2001
|
||||||
|
From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= <sosthene@nitrokey.com>
|
||||||
|
Date: Mon, 2 Dec 2024 10:29:59 +0100
|
||||||
|
Subject: [PATCH 2/3] Add optional new pin when resetting
|
||||||
|
|
||||||
|
---
|
||||||
|
src/main.c | 9 +++++----
|
||||||
|
src/operations_ccid.c | 6 +++++-
|
||||||
|
src/operations_ccid.h | 5 ++++-
|
||||||
|
3 files changed, 14 insertions(+), 6 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/src/main.c b/src/main.c
|
||||||
|
index b80b71d..3f4a1cc 100644
|
||||||
|
--- a/src/main.c
|
||||||
|
+++ b/src/main.c
|
||||||
|
@@ -38,9 +38,10 @@ void print_help(char *app_name) {
|
||||||
|
"\t%s info\n"
|
||||||
|
"\t%s version\n"
|
||||||
|
"\t%s check <HOTP CODE>\n"
|
||||||
|
- "\t%s regenerate <ADMIN PIN>\n"
|
||||||
|
+ "\t%s reset [ADMIN PIN]\n"
|
||||||
|
+ "\t%s regenerate\n"
|
||||||
|
"\t%s set <BASE32 HOTP SECRET> <ADMIN PIN> [COUNTER]\n",
|
||||||
|
- app_name, app_name, app_name, app_name, app_name, app_name);
|
||||||
|
+ app_name, app_name, app_name, app_name, app_name, app_name, app_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@@ -136,8 +137,8 @@ int parse_cmd_and_run(int argc, char *const *argv) {
|
||||||
|
break;
|
||||||
|
case 'r':
|
||||||
|
if (strncmp(argv[1], "reset", 15) == 0) {
|
||||||
|
- if (argc != 2) break;
|
||||||
|
- res = nk3_reset(&dev);
|
||||||
|
+ if (argc != 2 && argc != 3) break;
|
||||||
|
+ res = nk3_reset(&dev, argc == 3 ? argv[2]: NULL);
|
||||||
|
} else if (strncmp(argv[1], "regenerate", 15) == 0) {
|
||||||
|
if (argc != 3) break;
|
||||||
|
res = regenerate_AES_key(&dev, argv[2]);
|
||||||
|
diff --git a/src/operations_ccid.c b/src/operations_ccid.c
|
||||||
|
index 574155d..07834ce 100644
|
||||||
|
--- a/src/operations_ccid.c
|
||||||
|
+++ b/src/operations_ccid.c
|
||||||
|
@@ -33,7 +33,7 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-int nk3_reset(struct Device *dev) {
|
||||||
|
+int nk3_reset(struct Device *dev, const char * new_pin) {
|
||||||
|
libusb_device *usb_dev;
|
||||||
|
struct libusb_device_descriptor usb_desc;
|
||||||
|
usb_dev = libusb_get_device(dev->mp_devhandle_ccid);
|
||||||
|
@@ -70,6 +70,10 @@ int nk3_reset(struct Device *dev) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ if (new_pin != NULL) {
|
||||||
|
+ set_pin_ccid(dev, new_pin);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
return RET_NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
diff --git a/src/operations_ccid.h b/src/operations_ccid.h
|
||||||
|
index ec0070c..61cad72 100644
|
||||||
|
--- a/src/operations_ccid.h
|
||||||
|
+++ b/src/operations_ccid.h
|
||||||
|
@@ -11,7 +11,10 @@ int authenticate_or_set_ccid(struct Device *dev, const char *admin_PIN);
|
||||||
|
int set_secret_on_device_ccid(struct Device *dev, const char *admin_PIN, const char *OTP_secret_base32, const uint64_t hotp_counter);
|
||||||
|
int verify_code_ccid(struct Device *dev, const uint32_t code_to_verify);
|
||||||
|
int status_ccid(libusb_device_handle *handle, int *attempt_counter, uint16_t *firmware_version, uint32_t *serial_number);
|
||||||
|
-int nk3_reset(struct Device *dev);
|
||||||
|
+// new_pin can be `null`
|
||||||
|
+//
|
||||||
|
+// If it is, no new pin will be set
|
||||||
|
+int nk3_reset(struct Device *dev, const char * new_pin);
|
||||||
|
|
||||||
|
|
||||||
|
#endif//NITROKEY_HOTP_VERIFICATION_OPERATIONS_CCID_H
|
||||||
|
|
||||||
|
From 596f701985682adf6bfab06c78cbe132cbcb2aae Mon Sep 17 00:00:00 2001
|
||||||
|
From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= <sosthene@nitrokey.com>
|
||||||
|
Date: Tue, 3 Dec 2024 10:48:27 +0100
|
||||||
|
Subject: [PATCH 3/3] Fix null pointer bug on non nk3
|
||||||
|
|
||||||
|
---
|
||||||
|
src/operations_ccid.c | 8 +++++++-
|
||||||
|
1 file changed, 7 insertions(+), 1 deletion(-)
|
||||||
|
|
||||||
|
diff --git a/src/operations_ccid.c b/src/operations_ccid.c
|
||||||
|
index 07834ce..538d434 100644
|
||||||
|
--- a/src/operations_ccid.c
|
||||||
|
+++ b/src/operations_ccid.c
|
||||||
|
@@ -36,6 +36,12 @@
|
||||||
|
int nk3_reset(struct Device *dev, const char * new_pin) {
|
||||||
|
libusb_device *usb_dev;
|
||||||
|
struct libusb_device_descriptor usb_desc;
|
||||||
|
+
|
||||||
|
+ if (!dev->mp_devhandle_ccid) {
|
||||||
|
+ // Not an NK3
|
||||||
|
+ return RET_NO_ERROR;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
usb_dev = libusb_get_device(dev->mp_devhandle_ccid);
|
||||||
|
|
||||||
|
int r = libusb_get_device_descriptor(usb_dev, &usb_desc);
|
||||||
|
@@ -46,7 +52,7 @@ int nk3_reset(struct Device *dev, const char * new_pin) {
|
||||||
|
|
||||||
|
|
||||||
|
if (usb_desc.idVendor != NITROKEY_USB_VID || usb_desc.idProduct != NITROKEY_3_USB_PID) {
|
||||||
|
- return 0;
|
||||||
|
+ return RET_NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user