mirror of
https://github.com/polhenarejos/pico-openpgp.git
synced 2024-09-20 03:10:10 +00:00
Compare commits
7 Commits
3a4ca80970
...
1051690b79
Author | SHA1 | Date | |
---|---|---|---|
|
1051690b79 | ||
|
8a5c734c41 | ||
|
c09f96e956 | ||
|
c28852d0ea | ||
|
209cd389e5 | ||
|
10c3389c51 | ||
|
197bf3c056 |
@ -17,6 +17,11 @@
|
||||
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
|
||||
if(ESP_PLATFORM)
|
||||
set(EXTRA_COMPONENT_DIRS src pico-keys-sdk/src)
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
else()
|
||||
|
||||
if(ENABLE_EMULATION)
|
||||
else()
|
||||
include(pico_sdk_import.cmake)
|
||||
@ -33,11 +38,13 @@ pico_sdk_init()
|
||||
endif()
|
||||
|
||||
add_executable(pico_openpgp)
|
||||
endif()
|
||||
|
||||
set(SOURCES ${SOURCES}
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/openpgp/openpgp.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/openpgp/files.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/openpgp/piv.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/openpgp/management.c
|
||||
)
|
||||
|
||||
set(INCLUDES ${INCLUDES}
|
||||
@ -46,7 +53,11 @@ set(INCLUDES ${INCLUDES}
|
||||
|
||||
set(USB_ITF_CCID 1)
|
||||
include(pico-keys-sdk/pico_keys_sdk_import.cmake)
|
||||
if(ESP_PLATFORM)
|
||||
project(pico_fido)
|
||||
endif()
|
||||
|
||||
if(NOT ESP_PLATFORM)
|
||||
target_sources(pico_openpgp PUBLIC ${SOURCES})
|
||||
target_include_directories(pico_openpgp PUBLIC ${INCLUDES})
|
||||
|
||||
@ -78,3 +89,4 @@ pico_add_extra_outputs(pico_openpgp)
|
||||
|
||||
target_link_libraries(pico_openpgp PRIVATE pico_keys_sdk pico_stdlib tinyusb_device tinyusb_board pico_multicore hardware_flash hardware_sync hardware_adc pico_unique_id hardware_rtc)
|
||||
endif()
|
||||
endif()
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit f4ad8e1af2e2657f3900f1e01db031d7d73d623b
|
||||
Subproject commit d379a39bd699a679e2f5e5605af95922dc35576f
|
@ -161,4 +161,6 @@
|
||||
#define EF_PIV_RETIRED19 0xc11f
|
||||
#define EF_PIV_RETIRED20 0xc120
|
||||
|
||||
#define EF_DEV_CONF 0x1122
|
||||
|
||||
#endif
|
||||
|
152
src/openpgp/management.c
Normal file
152
src/openpgp/management.c
Normal file
@ -0,0 +1,152 @@
|
||||
/*
|
||||
* This file is part of the Pico FIDO distribution (https://github.com/polhenarejos/pico-fido).
|
||||
* Copyright (c) 2022 Pol Henarejos.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "pico_keys.h"
|
||||
#include "apdu.h"
|
||||
#include "version.h"
|
||||
#include "files.h"
|
||||
#include "asn1.h"
|
||||
#include "management.h"
|
||||
|
||||
int man_process_apdu();
|
||||
int man_unload();
|
||||
|
||||
const uint8_t man_aid[] = {
|
||||
8,
|
||||
0xa0, 0x00, 0x00, 0x05, 0x27, 0x47, 0x11, 0x17
|
||||
};
|
||||
|
||||
extern void init_piv();
|
||||
int man_select(app_t *a) {
|
||||
a->process_apdu = man_process_apdu;
|
||||
a->unload = man_unload;
|
||||
sprintf((char *) res_APDU, "%d.%d.0", PIV_VERSION_MAJOR, PIV_VERSION_MINOR);
|
||||
res_APDU_size = strlen((char *) res_APDU);
|
||||
apdu.ne = res_APDU_size;
|
||||
init_piv();
|
||||
return CCID_OK;
|
||||
}
|
||||
|
||||
INITIALIZER( man_ctor ) {
|
||||
register_app(man_select, man_aid);
|
||||
}
|
||||
|
||||
int man_unload() {
|
||||
return CCID_OK;
|
||||
}
|
||||
|
||||
bool cap_supported(uint16_t cap) {
|
||||
file_t *ef = search_dynamic_file(EF_DEV_CONF);
|
||||
if (file_has_data(ef)) {
|
||||
uint16_t tag = 0x0;
|
||||
uint8_t *tag_data = NULL, *p = NULL;
|
||||
uint16_t tag_len = 0;
|
||||
asn1_ctx_t ctxi;
|
||||
asn1_ctx_init(file_get_data(ef), file_get_size(ef), &ctxi);
|
||||
while (walk_tlv(&ctxi, &p, &tag, &tag_len, &tag_data)) {
|
||||
if (tag == TAG_USB_ENABLED) {
|
||||
uint16_t ecaps = tag_data[0];
|
||||
if (tag_len == 2) {
|
||||
ecaps = (tag_data[0] << 8) | tag_data[1];
|
||||
}
|
||||
return ecaps & cap;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int man_get_config() {
|
||||
file_t *ef = search_dynamic_file(EF_DEV_CONF);
|
||||
res_APDU_size = 0;
|
||||
res_APDU[res_APDU_size++] = 0; // Overall length. Filled later
|
||||
res_APDU[res_APDU_size++] = TAG_USB_SUPPORTED;
|
||||
res_APDU[res_APDU_size++] = 1;
|
||||
res_APDU[res_APDU_size++] = CAP_PIV | CAP_OPENPGP;
|
||||
res_APDU[res_APDU_size++] = TAG_SERIAL;
|
||||
res_APDU[res_APDU_size++] = 4;
|
||||
memcpy(res_APDU + res_APDU_size, pico_serial.id, 4);
|
||||
res_APDU_size += 4;
|
||||
res_APDU[res_APDU_size++] = TAG_FORM_FACTOR;
|
||||
res_APDU[res_APDU_size++] = 1;
|
||||
res_APDU[res_APDU_size++] = 0x01;
|
||||
res_APDU[res_APDU_size++] = TAG_VERSION;
|
||||
res_APDU[res_APDU_size++] = 3;
|
||||
res_APDU[res_APDU_size++] = PIV_VERSION_MAJOR;
|
||||
res_APDU[res_APDU_size++] = PIV_VERSION_MINOR;
|
||||
res_APDU[res_APDU_size++] = 0;
|
||||
res_APDU[res_APDU_size++] = TAG_NFC_SUPPORTED;
|
||||
res_APDU[res_APDU_size++] = 1;
|
||||
res_APDU[res_APDU_size++] = 0x00;
|
||||
if (!file_has_data(ef)) {
|
||||
res_APDU[res_APDU_size++] = TAG_USB_ENABLED;
|
||||
res_APDU[res_APDU_size++] = 1;
|
||||
res_APDU[res_APDU_size++] = CAP_PIV | CAP_OPENPGP;
|
||||
res_APDU[res_APDU_size++] = TAG_DEVICE_FLAGS;
|
||||
res_APDU[res_APDU_size++] = 1;
|
||||
res_APDU[res_APDU_size++] = FLAG_EJECT;
|
||||
res_APDU[res_APDU_size++] = TAG_CONFIG_LOCK;
|
||||
res_APDU[res_APDU_size++] = 1;
|
||||
res_APDU[res_APDU_size++] = 0x00;
|
||||
res_APDU[res_APDU_size++] = TAG_NFC_ENABLED;
|
||||
res_APDU[res_APDU_size++] = 1;
|
||||
res_APDU[res_APDU_size++] = 0x00;
|
||||
}
|
||||
else {
|
||||
memcpy(res_APDU + res_APDU_size, file_get_data(ef), file_get_size(ef));
|
||||
res_APDU_size += file_get_size(ef);
|
||||
}
|
||||
res_APDU[0] = res_APDU_size - 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cmd_read_config() {
|
||||
man_get_config();
|
||||
return SW_OK();
|
||||
}
|
||||
|
||||
int cmd_write_config() {
|
||||
if (apdu.data[0] != apdu.nc - 1) {
|
||||
return SW_WRONG_DATA();
|
||||
}
|
||||
file_t *ef = file_new(EF_DEV_CONF);
|
||||
file_put_data(ef, apdu.data + 1, apdu.nc - 1);
|
||||
low_flash_available();
|
||||
return SW_OK();
|
||||
}
|
||||
|
||||
#define INS_READ_CONFIG 0x1D
|
||||
#define INS_WRITE_CONFIG 0x1C
|
||||
|
||||
static const cmd_t cmds[] = {
|
||||
{ INS_READ_CONFIG, cmd_read_config },
|
||||
{ INS_WRITE_CONFIG, cmd_write_config },
|
||||
{ 0x00, 0x0 }
|
||||
};
|
||||
|
||||
int man_process_apdu() {
|
||||
if (CLA(apdu) != 0x00) {
|
||||
return SW_CLA_NOT_SUPPORTED();
|
||||
}
|
||||
for (const cmd_t *cmd = cmds; cmd->ins != 0x00; cmd++) {
|
||||
if (cmd->ins == INS(apdu)) {
|
||||
int r = cmd->cmd_handler();
|
||||
return r;
|
||||
}
|
||||
}
|
||||
return SW_INS_NOT_SUPPORTED();
|
||||
}
|
55
src/openpgp/management.h
Normal file
55
src/openpgp/management.h
Normal file
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* This file is part of the Pico FIDO distribution (https://github.com/polhenarejos/pico-fido).
|
||||
* Copyright (c) 2022 Pol Henarejos.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _MANAGEMENT_H_
|
||||
#define _MANAGEMENT_H_
|
||||
|
||||
#include <stdlib.h>
|
||||
#if !defined(ENABLE_EMULATION) && !defined(ESP_PLATFORM)
|
||||
#include "pico/stdlib.h"
|
||||
#endif
|
||||
|
||||
#define TAG_USB_SUPPORTED 0x01
|
||||
#define TAG_SERIAL 0x02
|
||||
#define TAG_USB_ENABLED 0x03
|
||||
#define TAG_FORM_FACTOR 0x04
|
||||
#define TAG_VERSION 0x05
|
||||
#define TAG_AUTO_EJECT_TIMEOUT 0x06
|
||||
#define TAG_CHALRESP_TIMEOUT 0x07
|
||||
#define TAG_DEVICE_FLAGS 0x08
|
||||
#define TAG_APP_VERSIONS 0x09
|
||||
#define TAG_CONFIG_LOCK 0x0A
|
||||
#define TAG_UNLOCK 0x0B
|
||||
#define TAG_REBOOT 0x0C
|
||||
#define TAG_NFC_SUPPORTED 0x0D
|
||||
#define TAG_NFC_ENABLED 0x0E
|
||||
|
||||
#define CAP_OTP 0x01
|
||||
#define CAP_U2F 0x02
|
||||
#define CAP_FIDO2 0x200
|
||||
#define CAP_OATH 0x20
|
||||
#define CAP_PIV 0x10
|
||||
#define CAP_OPENPGP 0x08
|
||||
#define CAP_HSMAUTH 0x100
|
||||
|
||||
#define FLAG_REMOTE_WAKEUP 0x40
|
||||
#define FLAG_EJECT 0x80
|
||||
|
||||
extern bool cap_supported(uint16_t cap);
|
||||
extern int man_get_config();
|
||||
|
||||
#endif //_MANAGEMENT_H
|
@ -15,7 +15,12 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifdef ESP_PLATFORM
|
||||
#include "esp_compat.h"
|
||||
#define MBEDTLS_ALLOW_PRIVATE_ACCESS
|
||||
#else
|
||||
#include "common.h"
|
||||
#endif
|
||||
#include "openpgp.h"
|
||||
#include "version.h"
|
||||
#include "files.h"
|
||||
@ -58,7 +63,6 @@ char atr_openpgp[] = {
|
||||
|
||||
int openpgp_process_apdu();
|
||||
|
||||
|
||||
extern uint32_t board_button_read(void);
|
||||
|
||||
static bool wait_button_pressed(uint16_t fid) {
|
||||
@ -166,11 +170,7 @@ void scan_files() {
|
||||
file_t *ef;
|
||||
if ((ef = search_by_fid(EF_FULL_AID, NULL, SPECIFY_ANY))) {
|
||||
ef->data = openpgp_aid_full;
|
||||
#ifndef ENABLE_EMULATION
|
||||
pico_get_unique_board_id_string((char *) ef->data + 12, 4);
|
||||
#else
|
||||
memset((char *) ef->data + 12, 0, 4);
|
||||
#endif
|
||||
memcpy(ef->data + 12, pico_serial.id, 4);
|
||||
}
|
||||
bool reset_dek = false;
|
||||
if ((ef = search_by_fid(EF_DEK, NULL, SPECIFY_ANY))) {
|
||||
@ -365,7 +365,7 @@ int openpgp_unload() {
|
||||
|
||||
extern char __StackLimit;
|
||||
int heapLeft() {
|
||||
#ifndef ENABLE_EMULATION
|
||||
#if !defined(ENABLE_EMULATION) && !defined(ESP_PLATFORM)
|
||||
char *p = malloc(256); // try to avoid undue fragmentation
|
||||
int left = &__StackLimit - p;
|
||||
free(p);
|
||||
@ -392,7 +392,7 @@ int openpgp_select_aid(app_t *a) {
|
||||
return CCID_OK;
|
||||
}
|
||||
|
||||
void __attribute__((constructor)) openpgp_ctor() {
|
||||
INITIALIZER( openpgp_ctor ) {
|
||||
ccid_atr = (uint8_t *) atr_openpgp;
|
||||
register_app(openpgp_select_aid, openpgp_aid);
|
||||
}
|
||||
|
@ -19,7 +19,7 @@
|
||||
#define __OPENPGP_H_
|
||||
|
||||
#include "stdlib.h"
|
||||
#ifndef ENABLE_EMULATION
|
||||
#if !defined(ENABLE_EMULATION) && !defined(ESP_PLATFORM)
|
||||
#include <pico/stdlib.h>
|
||||
#endif
|
||||
|
||||
|
@ -15,7 +15,12 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifdef ESP_PLATFORM
|
||||
#include "esp_compat.h"
|
||||
#define MBEDTLS_ALLOW_PRIVATE_ACCESS
|
||||
#else
|
||||
#include "common.h"
|
||||
#endif
|
||||
#include "files.h"
|
||||
#include "apdu.h"
|
||||
#include "pico_keys.h"
|
||||
@ -23,9 +28,6 @@
|
||||
#include "eac.h"
|
||||
#include "crypto_utils.h"
|
||||
#include "version.h"
|
||||
#ifndef ENABLE_EMULATION
|
||||
#include "pico/unique_id.h"
|
||||
#endif
|
||||
#include "asn1.h"
|
||||
#include "mbedtls/aes.h"
|
||||
#include "mbedtls/des.h"
|
||||
@ -70,10 +72,6 @@ uint8_t yk_aid[] = {
|
||||
8,
|
||||
0xA0, 0x00, 0x00, 0x05, 0x27, 0x20, 0x1, 0x1
|
||||
};
|
||||
uint8_t mgmt_aid[] = {
|
||||
8,
|
||||
0xA0, 0x00, 0x00, 0x05, 0x27, 0x47, 0x11, 0x17
|
||||
};
|
||||
|
||||
bool has_pwpiv = false;
|
||||
uint8_t session_pwpiv[32];
|
||||
@ -81,14 +79,8 @@ uint8_t session_pwpiv[32];
|
||||
int piv_process_apdu();
|
||||
|
||||
static int get_serial() {
|
||||
#ifndef ENABLE_EMULATION
|
||||
pico_unique_board_id_t unique_id;
|
||||
pico_get_unique_board_id(&unique_id);
|
||||
uint32_t serial = (unique_id.id[0] & 0x7F) << 24 | unique_id.id[1] << 16 | unique_id.id[2] << 8 | unique_id.id[3];
|
||||
uint32_t serial = (pico_serial.id[0] & 0x7F) << 24 | pico_serial.id[1] << 16 | pico_serial.id[2] << 8 | pico_serial.id[3];
|
||||
return serial;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int x509_create_cert(void *pk_ctx, uint8_t algo, uint8_t slot, bool attestation, uint8_t *buffer, size_t buffer_size) {
|
||||
@ -315,10 +307,9 @@ int piv_select_aid(app_t *a) {
|
||||
return CCID_OK;
|
||||
}
|
||||
|
||||
void __attribute__((constructor)) piv_ctor() {
|
||||
INITIALIZER( piv_ctor ) {
|
||||
register_app(piv_select_aid, piv_aid);
|
||||
register_app(piv_select_aid, yk_aid);
|
||||
register_app(piv_select_aid, mgmt_aid);
|
||||
}
|
||||
|
||||
static int cmd_version() {
|
||||
@ -404,7 +395,7 @@ static int cmd_get_data() {
|
||||
fid |= apdu.data[2 + lt];
|
||||
}
|
||||
if ((fid & 0xFFFF00) != 0x5FC100 && (fid & 0xFFFF) != EF_PIV_BITGT && (fid & 0xFFFF) != EF_PIV_DISCOVERY && (fid & 0xFFFF) != EF_PIV_ATTESTATION) {
|
||||
return SW_REFERENCE_NOT_FOUND();
|
||||
return SW_FILE_NOT_FOUND();
|
||||
}
|
||||
file_t *ef = NULL;
|
||||
if ((ef = search_by_fid((uint16_t)(fid & 0xFFFF), NULL, SPECIFY_EF))) {
|
||||
@ -451,7 +442,7 @@ static int cmd_get_metadata() {
|
||||
}
|
||||
file_t *ef_key = search_by_fid(key_ref, NULL, SPECIFY_EF);
|
||||
if (!file_has_data(ef_key)) {
|
||||
return SW_MEMORY_FAILURE();
|
||||
return SW_REFERENCE_NOT_FOUND();
|
||||
}
|
||||
if (key_ref != EF_PIV_PIN && key_ref != EF_PIV_PUK) {
|
||||
int meta_len = 0;
|
||||
@ -470,6 +461,8 @@ static int cmd_get_metadata() {
|
||||
res_APDU[res_APDU_size++] = meta[3];
|
||||
if (meta[0] == PIV_ALGO_RSA1024 || meta[0] == PIV_ALGO_RSA2048 || meta[0] == PIV_ALGO_RSA3072 || meta[0] == PIV_ALGO_RSA4096 || meta[0] == PIV_ALGO_ECCP256 || meta[0] == PIV_ALGO_ECCP384) {
|
||||
res_APDU[res_APDU_size++] = 0x4;
|
||||
res_APDU[res_APDU_size++] = 0; // Filled later
|
||||
uint8_t *pk = &res_APDU[res_APDU_size];
|
||||
if (meta[0] == PIV_ALGO_RSA1024 || meta[0] == PIV_ALGO_RSA2048 || meta[0] == PIV_ALGO_RSA3072 || meta[0] == PIV_ALGO_RSA4096) {
|
||||
mbedtls_rsa_context ctx;
|
||||
mbedtls_rsa_init(&ctx);
|
||||
@ -509,9 +502,26 @@ static int cmd_get_metadata() {
|
||||
memcpy(res_APDU + res_APDU_size, pt, plen);
|
||||
res_APDU_size += plen;
|
||||
}
|
||||
uint16_t pk_len = res_APDU_size - (pk - res_APDU);
|
||||
if (pk_len > 255) {
|
||||
memmove(pk + 2, pk, pk_len);
|
||||
pk[-1] = 0x82;
|
||||
pk[0] = pk_len >> 8;
|
||||
pk[1] = pk_len & 0xff;
|
||||
res_APDU_size += 2;
|
||||
}
|
||||
else if (pk_len > 127) {
|
||||
memmove(pk + 1, pk, pk_len);
|
||||
pk[-1] = 0x81;
|
||||
pk[0] = pk_len;
|
||||
res_APDU_size += 1;
|
||||
}
|
||||
else {
|
||||
pk[-1] = pk_len;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (key_ref == EF_PIV_PIN || key_ref == EF_PIV_PUK || key_ref == EF_PIV_KEY_MANAGEMENT) {
|
||||
if (key_ref == EF_PIV_PIN || key_ref == EF_PIV_PUK || key_ref == EF_PIV_KEY_CARDMGM) {
|
||||
uint8_t dhash[32];
|
||||
int32_t eq = false;
|
||||
if (key_ref == EF_PIV_PIN) {
|
||||
@ -522,7 +532,7 @@ static int cmd_get_metadata() {
|
||||
double_hash_pin((const uint8_t *)"\x31\x32\x33\x34\x35\x36\x37\x38", 8, dhash);
|
||||
eq = memcmp(dhash, file_get_data(ef_key) + 1, file_get_size(ef_key) - 1);
|
||||
}
|
||||
else if (key_ref == EF_PIV_KEY_MANAGEMENT) {
|
||||
else if (key_ref == EF_PIV_KEY_CARDMGM) {
|
||||
eq = memcmp("\x01\x02\x03\x04\x05\x06\x07\x08\x01\x02\x03\x04\x05\x06\x07\x08\x01\x02\x03\x04\x05\x06\x07\x08", file_get_data(ef_key), file_get_size(ef_key));
|
||||
}
|
||||
res_APDU[res_APDU_size++] = 0x5;
|
||||
@ -534,8 +544,13 @@ static int cmd_get_metadata() {
|
||||
return SW_REFERENCE_NOT_FOUND();
|
||||
}
|
||||
uint8_t retries = *(file_get_data(pw_status) + 3 + (key_ref & 0xf));
|
||||
if (!(pw_status = search_by_fid(EF_PW_RETRIES, NULL, SPECIFY_EF))) {
|
||||
return SW_REFERENCE_NOT_FOUND();
|
||||
}
|
||||
uint8_t total = *(file_get_data(pw_status) + (key_ref & 0xf));
|
||||
res_APDU[res_APDU_size++] = 0x6;
|
||||
res_APDU[res_APDU_size++] = 1;
|
||||
res_APDU[res_APDU_size++] = 2;
|
||||
res_APDU[res_APDU_size++] = total;
|
||||
res_APDU[res_APDU_size++] = retries;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user