|
CDC Badge OS
Firmware for the CDC Badge v1.0 hardware security key
|
#include "mod_gpg/openpgp/openpgp.h"#include "mod_gpg/openpgp/apdu.h"#include "mod_gpg/openpgp/algo_attr.h"#include "mod_gpg/openpgp/constants.h"#include "cdc_log.h"#include "mod_gpg/gpg.h"#include "mod_gpg/GpgStorage.h"#include "ecdh.h"#include "cdc_core/pin_storage_c.h"#include "cdc_core/PinManager.h"#include "cdc_hal/ISecureElement.h"#include <mbedtls/platform_util.h>#include <mbedtls/sha256.h>#include <mbedtls/aes.h>#include <mbedtls/ecp.h>#include <mbedtls/ecdsa.h>#include <mbedtls/bignum.h>#include <esp_attr.h>#include <string.h>#include <time.h>#include <esp_mac.h>#include <nvs_flash.h>#include <nvs.h>#include <esp_random.h>Go to the source code of this file.
Classes | |
| struct | put_data_desc_t |
| Descriptor entry for table-driven PUT DATA processing. More... | |
Macros | |
| #define | OPENPGP_RC_MIN_LEN 8 |
| Resetting Code (RC) — optional per OpenPGP 3.4.1 §4.3.2. When set, the host can unblock PW1 with the RC instead of PW3 (RESET RETRY COUNTER with P1=0x00). We persist the configured RC bytes plus a separate retry counter in NVS. | |
| #define | NVS_NAMESPACE "openpgp" |
| NVS namespace used for OpenPGP persistent data. | |
| #define | NVS_STATE_KEY "state" |
Typedefs | |
| typedef bool(* | pin_change_fn_t) (const char *pin) |
| Type alias for PIN change callbacks. | |
Enumerations | |
| enum | key_type_t { KEY_TYPE_SIG = 0 , KEY_TYPE_DEC = 1 , KEY_TYPE_AUT = 2 } |
| Builders for OpenPGP application-related data objects. More... | |
| enum | put_data_kind_t { PUT_KIND_BLOB_FIXED = 0 , PUT_KIND_STRING_BOUNDED = 1 } |
| Storage kind for PUT DATA descriptor entries. More... | |
| enum | pin_slot_t { PIN_SLOT_PW1 = 0 , PIN_SLOT_PW3 = 1 } |
| PIN slot identifier used by PIN helper routines. More... | |
Functions | |
| static cdc::hal::ISecureElement * | get_se () |
| Returns secure-element instance used by OpenPGP backend. | |
| static bool | se_ecc_key_read (uint8_t slot, uint8_t *pubkey, size_t max_len, uint8_t *curve_out) |
| Reads ECC public key from secure element and exposes curve metadata. | |
| static bool | se_ecc_key_generate (uint8_t slot, uint8_t curve) |
| Generates ECC key material in secure element slot. | |
| static bool | se_ecdsa_sign (uint8_t slot, const uint8_t *hash, size_t hash_len, uint8_t *sig) |
| Signs a hash using secure-element ECDSA key. | |
| static bool | se_eddsa_sign (uint8_t slot, const uint8_t *msg, size_t msg_len, uint8_t *sig) |
| Signs a message using secure-element EdDSA key. | |
| static void | se_random_fill (uint8_t *buf, size_t len) |
| Fills buffer with secure random bytes, with ESP fallback. | |
| static bool | compute_rc_hash (const uint8_t *rc, size_t rc_len, const uint8_t *salt, uint8_t *hash_out) |
| Iterated-salted SHA-256 over salt||rc for resetting-code storage. Same construction as PinManager::computeKdfHash (OpenPGP S2K). | |
| static void | chain_reset (void) |
| struct | __attribute__ ((packed)) OpenpgpNvsState |
| Single-blob persistent OpenPGP runtime state. | |
| static size_t | tlv_write_tag (uint8_t *buf, uint16_t tag) |
| TLV builder helper functions. | |
| static size_t | tlv_write_len (uint8_t *buf, size_t len) |
| Writes a TLV length field using DER length encoding. | |
| static size_t | tlv_build (uint8_t *buf, size_t buf_max, uint16_t tag, const uint8_t *value, size_t value_len) |
| Builds complete TLV object and returns total encoded length. | |
| static const uint8_t * | get_algo_attr (key_type_t key_type, size_t *len) |
| Returns algorithm attributes for a key role based on stored key type. | |
| static int | build_do_app_related (uint8_t *buf, size_t buf_max) |
| Builds OpenPGP DO 0x6E (Application Related Data). | |
| static int | build_do_cardholder (uint8_t *buf, size_t buf_max) |
| Builds OpenPGP DO 0x65 (Cardholder Related Data). | |
| static bool | verify_state_signature (cdc::hal::ISecureElement *se, const uint8_t *payload, size_t payload_len, const uint8_t *sig, size_t sig_len) |
| Verifies the P-256 ECDSA attestation signature over an OpenPGP state payload. Same construction as PinManager. | |
| static void | load_state_from_nvs (void) |
| Loads persistent OpenPGP runtime state from NVS. | |
| static void | save_state_to_nvs (void) |
| Persists OpenPGP runtime state to NVS. | |
| static void | init_aid_from_mac (void) |
| Initializes the OpenPGP AID serial section from the ESP32 MAC address. | |
| bool | openpgp_init (void) |
| bool | openpgp_is_selected (void) |
| uint32_t | openpgp_get_sig_count (void) |
| bool | openpgp_get_fingerprint (uint8_t key_type, uint8_t *fp_out) |
| Reads the stored OpenPGP v4 fingerprint for a key role. | |
| static bool | fp_is_set (const uint8_t fp[OPENPGP_FINGERPRINT_SIZE]) |
| bool | openpgp_has_any_key (void) |
| Reports whether any of the SIG / DEC / AUT roles has a non-zero fingerprint configured. Acts as the canonical "card has keys" check. | |
| size_t | openpgp_get_cardholder_name (char *out, size_t out_size) |
| Copies the cardholder name (OpenPGP DO 0x5B) into the caller buffer. Format is gpg's "Surname<<Firstname" or empty when unset. | |
| uint32_t | openpgp_get_gen_time (uint8_t key_type) |
| Returns the stored Unix timestamp of key generation, or 0 when unset. | |
| bool | openpgp_set_cardholder_name (const char *name) |
| Sets the cardholder name (OpenPGP DO 0x5B) and persists state. | |
| bool | openpgp_set_key_fingerprint (uint8_t key_type, const uint8_t *fingerprint, uint32_t gen_time) |
| static int | cmd_select (const apdu_t *apdu, uint8_t *resp, size_t resp_max) |
| Handles APDU SELECT command processing. | |
| static int | cmd_get_data (const apdu_t *apdu, uint8_t *resp, size_t resp_max) |
| Handles APDU GET DATA command processing. | |
| static const put_data_desc_t * | find_put_data_desc (uint16_t tag) |
| Returns descriptor for an OpenPGP PUT DATA tag. | |
| static int | apply_put_data_desc (const put_data_desc_t *desc, const apdu_t *apdu, uint8_t *resp) |
| Applies a PUT DATA descriptor to the request payload. | |
| static int | put_data_algo_attr (uint16_t tag, const apdu_t *apdu, uint8_t *resp) |
| Handles APDU PUT DATA command processing. | |
| static int | cmd_put_data (const apdu_t *apdu, uint8_t *resp, size_t resp_max) |
| static void | update_generation_timestamp (uint8_t key_ref) |
| Updates and persists the generation timestamp for a key role. | |
| static bool | ehl_parse_one (const uint8_t *buf, size_t buf_len, size_t *pos, uint16_t *tag_out, const uint8_t **value_out, size_t *value_len_out) |
Parse one BER-TLV field at pos. | |
| static int | cmd_put_data_odd (const apdu_t *apdu, uint8_t *resp, size_t resp_max) |
| Handles APDU PUT DATA (odd INS, 0xDB) for keypair import. | |
| static int | cmd_verify (const apdu_t *apdu, uint8_t *resp, size_t resp_max) |
| Handles APDU VERIFY command for PIN verification. | |
| static bool | compute_kdf_hash (const char *pin, const uint8_t *salt, uint32_t iterations, uint8_t hash_out[32]) |
| Computes the iterated-salted S2K hash (OpenPGP KDF) for a PIN candidate. | |
| static bool | const_time_equal (const uint8_t *a, const uint8_t *b, size_t n) |
| Constant-time comparison of two equal-length byte buffers. | |
| static bool | peek_verify_pin (pin_slot_t slot, const char *pin) |
| Compares a candidate PIN against the stored hash without touching retry counters. | |
| static bool | try_change_pin (const uint8_t *data, size_t len, size_t min_len, pin_slot_t slot, pin_change_fn_t change_fn) |
| Searches the split point for CHANGE REFERENCE DATA without consuming retries. | |
| static int | cmd_change_reference_data (const apdu_t *apdu, uint8_t *resp, size_t resp_max) |
| Handles APDU CHANGE REFERENCE DATA command for PIN updates. | |
| static int | cmd_pso_cds (const apdu_t *apdu, uint8_t *resp, size_t resp_max) |
| Handles APDU PSO: COMPUTE DIGITAL SIGNATURE. | |
| static int | cmd_pso_decipher_aes (const apdu_t *apdu, uint8_t *resp, size_t resp_max) |
| Handles APDU PSO: DECIPHER for ECDH key agreement. | |
| static int | cmd_pso_decipher (const apdu_t *apdu, uint8_t *resp, size_t resp_max) |
| static int | cmd_manage_security_env (const apdu_t *apdu, uint8_t *resp, size_t resp_max) |
| Handles APDU MANAGE SECURITY ENVIRONMENT (INS 0x22). | |
| static int | cmd_internal_authenticate (const apdu_t *apdu, uint8_t *resp, size_t resp_max) |
| Handles APDU INTERNAL AUTHENTICATE (INS 0x88). | |
| static int | cmd_terminate_df (const apdu_t *apdu, uint8_t *resp, size_t resp_max) |
| Handles APDU TERMINATE DF (INS 0xE6). | |
| static int | cmd_activate_file (const apdu_t *apdu, uint8_t *resp, size_t resp_max) |
| Handles APDU ACTIVATE FILE (INS 0x44). | |
| void | openpgp_factory_reset (void) |
| static int | cmd_reset_retry_counter (const apdu_t *apdu, uint8_t *resp, size_t resp_max) |
| Handles APDU RESET RETRY COUNTER (INS 0x2C). | |
| static uint8_t | get_ecc_slot_for_key_ref (uint8_t key_ref) |
| Returns ECC slot mapping for an OpenPGP key reference. | |
| static key_type_t | get_key_type_for_ref (uint8_t key_ref) |
| Maps an OpenPGP key reference to an internal key type. | |
| static uint16_t | generate_dec_key (uint8_t *pubkey_out) |
| Generates a software ECDH P-256 key pair for the DEC slot. | |
| static uint16_t | generate_hardware_key (uint8_t ecc_slot, uint8_t curve) |
| Generates a hardware ECC key pair in the TROPIC01 secure element. | |
| static bool | read_public_key (key_type_t key_type, uint8_t ecc_slot, uint8_t *pubkey, uint8_t *curve_out) |
| Reads the public key for a given key role. | |
| static void | encode_pubkey_with_prefix (const uint8_t *pubkey, uint8_t curve, uint8_t *out, size_t *out_len) |
| Encodes the public key with the OpenPGP/SEC1 uncompressed prefix. | |
| static int | cmd_generate_keypair (const apdu_t *apdu, uint8_t *resp, size_t resp_max) |
| Handles APDU GENERATE ASYMMETRIC KEY PAIR. | |
| static int | apply_response_chaining (uint32_t le, uint8_t *resp, size_t resp_max, int result_len) |
| Trim an APDU response to the host-requested Le window. | |
| static int | cmd_get_response (const apdu_t *apdu, uint8_t *resp, size_t resp_max) |
| Handles INS GET RESPONSE (0xC0) — drains the chained response buffer. | |
| int | openpgp_process_apdu (const uint8_t *cmd, size_t cmd_len, uint8_t *resp, size_t resp_max) |
Variables | |
| static const char * | TAG = "OpenPGP" |
| OpenPGP smart-card application implementation for CDC Badge. | |
| static uint8_t | s_openpgp_aid [16] |
| OpenPGP Application ID (RID + PIX), initialized dynamically. | |
| const uint8_t * | OPENPGP_AID = s_openpgp_aid |
| const uint8_t | OPENPGP_AID_LEN = sizeof(s_openpgp_aid) |
| static bool | app_selected = false |
| ATR is defined in ccid.cpp and accessed via ccid_get_atr(). | |
| static bool | pw1_verified = false |
| static bool | pw3_verified = false |
| static uint32_t | sig_count = 0 |
| static constexpr size_t | RC_SALT_SIZE = 16 |
| static constexpr size_t | RC_HASH_SIZE = 32 |
| static constexpr size_t | RC_KDF_TOTAL_BYTES = 100000 |
| static uint8_t | s_rc_salt [RC_SALT_SIZE] = {0} |
| static uint8_t | s_rc_hash [RC_HASH_SIZE] = {0} |
| static uint8_t | s_rc_len = 0 |
| static uint8_t | s_rc_retries = 3 |
| static uint8_t | selected_curve_sig = CDC_CURVE_ED25519 |
| Host-selected ECC curve per key role. DEC is fixed to P-256 because the TROPIC01 cannot perform ECDH natively and the firmware only carries a software P-256 ECDH path in ecdh.cpp. SIG and AUT default to Ed25519 (the project's preferred curve for signing) and can be flipped to P-256 via PUT DATA C1 / C3 per OpenPGP 3.4.1 §4.4.3.7-9. | |
| static uint8_t | selected_curve_aut = CDC_CURVE_ED25519 |
| static bool | card_terminated = false |
| Card lifecycle state per OpenPGP 3.4.1 §7.2.18. | |
| static uint8_t | g_resp_buffer [4096] |
| Buffered remainder of an APDU response that did not fit into the caller-supplied Le window. Drained one chunk at a time via GET RESPONSE (INS 0xC0) per ISO 7816-4 §5.3.4. Lifetime is bound to the next APDU on the same logical channel: the buffer is invalidated when any non-GET RESPONSE command arrives. | |
| static size_t | g_resp_remaining = 0 |
| static size_t | g_resp_pos = 0 |
| static uint8_t | g_chain_buffer [4096] |
| Command-chaining accumulator (ISO 7816-4 §5.1.1). | |
| static size_t | g_chain_len = 0 |
| static bool | g_chain_active = false |
| static uint8_t | g_chain_ins = 0 |
| static uint8_t | g_chain_p1 = 0 |
| static uint8_t | g_chain_p2 = 0 |
| static char | s_session_pin [OPENPGP_PIN_MAX_LEN+1] = {} |
| Session PIN cache for DEC key decryption (temporary after VERIFY for PSO:DECIPHER). | |
| static constexpr uint8_t | OPENPGP_NVS_SCHEMA_V2 = 2 |
| static uint8_t | fingerprint_sig [OPENPGP_FINGERPRINT_SIZE] = {0} |
| Data object storage buffers (fingerprints and related metadata). | |
| static uint8_t | fingerprint_dec [OPENPGP_FINGERPRINT_SIZE] = {0} |
| static uint8_t | fingerprint_aut [OPENPGP_FINGERPRINT_SIZE] = {0} |
| static uint8_t | gen_time_sig [4] = {0} |
| Key-generation timestamps (4-byte big-endian Unix time each). | |
| static uint8_t | gen_time_dec [4] = {0} |
| static uint8_t | gen_time_aut [4] = {0} |
| static uint8_t | ca_fp_1 [OPENPGP_FINGERPRINT_SIZE] = {0} |
| Optional CA fingerprints for trust-chain metadata. | |
| static uint8_t | ca_fp_2 [OPENPGP_FINGERPRINT_SIZE] = {0} |
| static uint8_t | ca_fp_3 [OPENPGP_FINGERPRINT_SIZE] = {0} |
| static char | cardholder_name [40] = {0} |
| Cardholder profile data stored in NVS. | |
| static char | cardholder_lang [8] = "en" |
| static uint8_t | cardholder_sex = 0x39 |
| static char | cardholder_url [64] = {0} |
| static char | cardholder_login [32] = {0} |
| static const uint8_t | HIST_BYTES [] |
| Historical bytes used in OpenPGP ATR-related data objects. | |
| static const uint8_t | ALGO_ATTR_ED25519 [] |
| Algorithm attributes for Ed25519 (EdDSA with curve25519). | |
| static const uint8_t | ALGO_ATTR_P256_ECDSA [] |
| Algorithm attributes for P-256 ECDSA (signature/authentication roles). | |
| static const uint8_t | ALGO_ATTR_P256_ECDH [] |
| Algorithm attributes for P-256 ECDH (decryption role). | |
| static const uint8_t | EXT_CAPABILITIES [] |
| Extended capabilities object per OpenPGP 3.4.1 section 4.2.1. | |
| static constexpr uint8_t | ATTESTATION_ECC_SLOT = 0 |
| static constexpr size_t | OPENPGP_STATE_SIG_SIZE = 64 |
| #define NVS_NAMESPACE "openpgp" |
NVS namespace used for OpenPGP persistent data.
Definition at line 296 of file openpgp.cpp.
| #define NVS_STATE_KEY "state" |
Definition at line 297 of file openpgp.cpp.
Referenced by load_state_from_nvs(), and save_state_to_nvs().
| #define OPENPGP_RC_MIN_LEN 8 |
Resetting Code (RC) — optional per OpenPGP 3.4.1 §4.3.2. When set, the host can unblock PW1 with the RC instead of PW3 (RESET RETRY COUNTER with P1=0x00). We persist the configured RC bytes plus a separate retry counter in NVS.
Storage rationale: the existing PW1/PW3 path stores hashes inside the TROPIC01 R-Memory; allocating extra slots there for RC is deferred until the next slot-map revision. Plain NVS bytes are equivalent to plaintext Yubikey behaviour and unlock the same workflow.
Definition at line 182 of file openpgp.cpp.
Referenced by cmd_put_data().
| typedef bool(* pin_change_fn_t) (const char *pin) |
Type alias for PIN change callbacks.
Definition at line 1732 of file openpgp.cpp.
| enum key_type_t |
Builders for OpenPGP application-related data objects.
Key role discriminator used for algorithm-attribute selection.
| Enumerator | |
|---|---|
| KEY_TYPE_SIG | |
| KEY_TYPE_DEC | |
| KEY_TYPE_AUT | |
Definition at line 489 of file openpgp.cpp.
| enum pin_slot_t |
PIN slot identifier used by PIN helper routines.
| Enumerator | |
|---|---|
| PIN_SLOT_PW1 | |
| PIN_SLOT_PW3 | |
Definition at line 1637 of file openpgp.cpp.
| enum put_data_kind_t |
Storage kind for PUT DATA descriptor entries.
BLOB_FIXED requires apdu->lc == max_size; STRING_BOUNDED requires apdu->lc < max_size and writes a trailing NUL terminator.
| Enumerator | |
|---|---|
| PUT_KIND_BLOB_FIXED | |
| PUT_KIND_STRING_BOUNDED | |
Definition at line 1202 of file openpgp.cpp.
| struct __attribute__ | ( | (packed) | ) |
Single-blob persistent OpenPGP runtime state.
One nvs_set_blob per save keeps NVS page fragmentation bounded: the default 20 KB NVS partition is shared with every other module and the old per-field layout (~21 entries) silently filled up under load.
Definition at line 291 of file openpgp.cpp.
References OPENPGP_PIN_MAX_LEN, and s_session_pin.
|
static |
Applies a PUT DATA descriptor to the request payload.
| desc | Descriptor from find_put_data_desc. |
| apdu | Parsed APDU containing the new value. |
| resp | Response buffer. |
Definition at line 1264 of file openpgp.cpp.
References apdu_sw(), put_data_desc_t::buffer, put_data_desc_t::kind, LOG_I, put_data_desc_t::log_label, put_data_desc_t::max_size, PUT_KIND_STRING_BOUNDED, save_state_to_nvs(), SW_OK, SW_WRONG_LENGTH, and TAG.
Referenced by cmd_put_data().
|
static |
Trim an APDU response to the host-requested Le window.
If the dispatcher produced more payload than the host asked for, we keep the head (Le bytes) in resp and stash the rest in g_resp_buffer so the host can retrieve it via GET RESPONSE (INS 0xC0). The status word becomes 61xx where xx = remaining payload size (capped at 0xFF, 0x00 means "more
than 255 still pending"). Responses that already fit pass through.
Definition at line 2621 of file openpgp.cpp.
References g_resp_buffer, g_resp_pos, g_resp_remaining, LOG_W, SW_OK, and TAG.
Referenced by openpgp_process_apdu().
|
static |
Builds OpenPGP DO 0x6E (Application Related Data).
| buf | Output buffer for the encoded TLV object. |
| buf_max | Maximum size of buf. |
Definition at line 524 of file openpgp.cpp.
References ca_fp_1, ca_fp_2, ca_fp_3, DO_AID, DO_ALGO_AUT, DO_ALGO_DEC, DO_ALGO_SIG, DO_EXT_CAP, DO_HIST_BYTES, DO_PW_STATUS, EXT_CAPABILITIES, fingerprint_aut, fingerprint_dec, fingerprint_sig, gen_time_aut, gen_time_dec, gen_time_sig, get_algo_attr(), HIST_BYTES, KEY_TYPE_AUT, KEY_TYPE_DEC, KEY_TYPE_SIG, OPENPGP_AID, OPENPGP_AID_LEN, OPENPGP_FINGERPRINT_SIZE, OPENPGP_PIN_MAX_LEN, pin_storage_openpgp_pw1_retries(), pin_storage_openpgp_pw3_retries(), s_rc_len, s_rc_retries, tlv_build(), tlv_write_len(), and tlv_write_tag().
Referenced by cmd_get_data().
|
static |
Builds OpenPGP DO 0x65 (Cardholder Related Data).
| buf | Output buffer for the encoded TLV object. |
| buf_max | Maximum size of buf. |
Definition at line 618 of file openpgp.cpp.
References cardholder_lang, cardholder_name, cardholder_sex, DO_CARDHOLDER, DO_LANG_PREF, DO_NAME, DO_SEX, tlv_build(), tlv_write_len(), and tlv_write_tag().
Referenced by cmd_get_data().
|
static |
Definition at line 280 of file openpgp.cpp.
References g_chain_active, g_chain_ins, g_chain_len, g_chain_p1, and g_chain_p2.
Referenced by openpgp_process_apdu().
|
static |
Handles APDU ACTIVATE FILE (INS 0x44).
Per OpenPGP 3.4.1 §7.2.18: in operational state ACTIVATE FILE is a no-op (SW_OK). In terminated state it wipes every persistent OpenPGP artefact (keys, fingerprints, generation times, cardholder data, PINs) and returns the card to operational state.
Definition at line 2205 of file openpgp.cpp.
References apdu_sw(), card_terminated, LOG_W, openpgp_factory_reset(), SW_INCORRECT_P1P2, SW_OK, and TAG.
Referenced by openpgp_process_apdu().
|
static |
Handles APDU CHANGE REFERENCE DATA command for PIN updates.
| apdu | Parsed APDU request. |
| resp | Output response buffer. |
| resp_max | Maximum size of resp. |
Definition at line 1784 of file openpgp.cpp.
References apdu_sw(), LOG_I, OPENPGP_PIN_MAX_LEN, OPENPGP_PW1_MIN_LEN, OPENPGP_PW3_MIN_LEN, PIN_SLOT_PW1, PIN_SLOT_PW3, pin_storage_openpgp_change_pw1(), pin_storage_openpgp_change_pw3(), pin_storage_openpgp_pw1_retries(), pin_storage_openpgp_pw3_retries(), pin_storage_openpgp_verify_pw1(), pin_storage_openpgp_verify_pw3(), PW1_CODE_1, PW3_CODE, SW_AUTH_METHOD_BLOCKED, SW_INCORRECT_P1P2, SW_OK, SW_WRONG_LENGTH, TAG, and try_change_pin().
Referenced by openpgp_process_apdu().
|
static |
Handles APDU GENERATE ASYMMETRIC KEY PAIR.
| apdu | Parsed APDU request. |
| resp | Output response buffer. |
| resp_max | Maximum size of resp. |
Definition at line 2507 of file openpgp.cpp.
References apdu_build_response(), apdu_sw(), CDC_CURVE_P256, curve, encode_pubkey_with_prefix(), generate_dec_key(), generate_hardware_key(), get_ecc_slot_for_key_ref(), get_key_type_for_ref(), KEY_SIG, KEY_TYPE_AUT, KEY_TYPE_DEC, KEY_TYPE_SIG, LOG_I, LOG_W, P256_PUBKEY_SIZE, pw3_verified, read_public_key(), selected_curve_aut, selected_curve_sig, SW_OK, SW_REFERENCED_DATA_NOT_FOUND, SW_SECURITY_NOT_SATISFIED, TAG, tlv_build(), tlv_write_len(), and update_generation_timestamp().
Referenced by openpgp_process_apdu().
|
static |
Handles APDU GET DATA command processing.
| apdu | Parsed APDU request. |
| resp | Output response buffer. |
| resp_max | Maximum size of resp. |
Definition at line 1016 of file openpgp.cpp.
References apdu_build_response(), apdu_sw(), build_do_app_related(), build_do_cardholder(), ca_fp_1, ca_fp_2, ca_fp_3, cardholder_lang, cardholder_login, cardholder_name, cardholder_sex, cardholder_url, curve, DO_AID, DO_ALGO_AUT, DO_ALGO_DEC, DO_ALGO_SIG, DO_APP_RELATED, DO_CA_FP_1, DO_CA_FP_2, DO_CA_FP_3, DO_CARDHOLDER, DO_CARDHOLDER_CERT, DO_EXT_CAP, DO_FP_AUT, DO_FP_DEC, DO_FP_SIG, DO_GEN_TIME_AUT, DO_GEN_TIME_DEC, DO_GEN_TIME_SIG, DO_HIST_BYTES, DO_KDF, DO_KEY_INFO, DO_LANG_PREF, DO_LOGIN, DO_NAME, DO_PW_STATUS, DO_SEC_TPL, DO_SEX, DO_SIG_COUNT, DO_UIF_AUT, DO_UIF_DEC, DO_UIF_SIG, DO_URL, EXT_CAPABILITIES, fingerprint_aut, fingerprint_dec, fingerprint_sig, gen_time_aut, gen_time_dec, gen_time_sig, get_algo_attr(), gpg_storage_aut_slot(), gpg_storage_dec_slot(), gpg_storage_sig_slot(), HIST_BYTES, KEY_TYPE_AUT, KEY_TYPE_DEC, KEY_TYPE_SIG, LOG_W, OPENPGP_AID, OPENPGP_AID_LEN, OPENPGP_FINGERPRINT_SIZE, OPENPGP_PIN_MAX_LEN, P256_PUBKEY_SIZE, pin_storage_openpgp_pw1_retries(), pin_storage_openpgp_pw3_retries(), s_rc_len, s_rc_retries, se_ecc_key_read(), sig_count, SW_OK, SW_REFERENCED_DATA_NOT_FOUND, SW_UNKNOWN, and TAG.
Referenced by openpgp_process_apdu().
|
static |
Handles INS GET RESPONSE (0xC0) — drains the chained response buffer.
Definition at line 2651 of file openpgp.cpp.
References apdu_sw(), g_resp_buffer, g_resp_pos, g_resp_remaining, SW_CONDITIONS_NOT_SATISFIED, SW_INCORRECT_P1P2, and SW_OK.
Referenced by openpgp_process_apdu().
|
static |
Handles APDU INTERNAL AUTHENTICATE (INS 0x88).
Signs the supplied authentication challenge with the AUT key (ECC slot 3). Used by gpg-agent / ssh for client authentication.
Per OpenPGP 3.4.1 §7.2.13: P1=0x00 P2=0x00, Lc = challenge length, Le = signature length. PW1 (reference 0x82) must be verified; we reuse the PW1 session flag.
Signature format matches PSO:CDS: raw R||S for ECDSA, 64-byte EdDSA sig.
Definition at line 2137 of file openpgp.cpp.
References apdu_build_response(), apdu_sw(), CDC_CURVE_P256, curve, gpg_storage_aut_slot(), LOG_E, P256_PUBKEY_SIZE, pw1_verified, se_ecc_key_read(), se_ecdsa_sign(), se_eddsa_sign(), SW_CONDITIONS_NOT_SATISFIED, SW_INCORRECT_P1P2, SW_OK, SW_SECURITY_NOT_SATISFIED, SW_UNKNOWN, SW_WRONG_LENGTH, and TAG.
Referenced by openpgp_process_apdu().
|
static |
Handles APDU MANAGE SECURITY ENVIRONMENT (INS 0x22).
Per OpenPGP 3.4.1 §7.2.10: gpg / scd issue MSE before PSO to point the key reference into a different slot. Two combinations matter in practice: P1=0x41 P2=0xB6 + tag 83 01 01 → use SIG key for DSI (signature) P1=0x41 P2=0xA4 + tag 83 01 03 → use AUT key for INTERNAL AUTHENTICATE
Our key-slot mapping is fixed by role (SIG=B6, DEC=B8, AUT=A4) so MSE is effectively a no-op as long as the requested reference matches the role encoded in P2. We accept the documented combinations and return SW_OK, which is enough for gpg-card / ssh workflows that issue MSE defensively.
Definition at line 2097 of file openpgp.cpp.
References apdu_sw(), KEY_AUT, KEY_DEC, KEY_SIG, SW_CONDITIONS_NOT_SATISFIED, SW_INCORRECT_P1P2, SW_OK, SW_WRONG_DATA, and SW_WRONG_LENGTH.
Referenced by openpgp_process_apdu().
|
static |
Handles APDU PSO: COMPUTE DIGITAL SIGNATURE.
| apdu | Parsed APDU request. |
| resp | Output response buffer. |
| resp_max | Maximum size of resp. |
Definition at line 1847 of file openpgp.cpp.
References apdu_build_response(), apdu_sw(), CDC_CURVE_P256, curve, gpg_storage_sig_slot(), LOG_E, LOG_I, P256_PUBKEY_SIZE, pw1_verified, save_state_to_nvs(), se_ecc_key_read(), se_ecdsa_sign(), se_eddsa_sign(), SHA256_DIGEST_SIZE, sig_count, SW_CONDITIONS_NOT_SATISFIED, SW_OK, SW_SECURITY_NOT_SATISFIED, SW_UNKNOWN, SW_WRONG_DATA, and TAG.
Referenced by openpgp_process_apdu().
|
static |
Definition at line 1980 of file openpgp.cpp.
References apdu_build_response(), apdu_sw(), cmd_pso_decipher_aes(), ecdh_p256_compute_shared_secret(), gpg_storage_has_dec_privkey(), gpg_storage_load_dec_privkey(), P256_ECDH_SECRET_SIZE, P256_PRIVKEY_SIZE, P256_PUBKEY_SIZE, pw1_verified, SW_CONDITIONS_NOT_SATISFIED, SW_OK, SW_SECURITY_NOT_SATISFIED, SW_UNKNOWN, and SW_WRONG_DATA.
Referenced by openpgp_process_apdu().
|
static |
Handles APDU PSO: DECIPHER for ECDH key agreement.
| apdu | Parsed APDU request. |
| resp | Output response buffer. |
| resp_max | Maximum size of resp. |
PSO:DECIPHER - ECDH Decryption.
SECURITY NOTE: The TROPIC01 secure element does NOT support native ECDH operations. Therefore, the DEC private key is stored encrypted in R-Memory and temporarily decrypted in RAM for the ECDH computation.
This is a necessary trade-off for GPG compatibility. See docs/GPG_ECDH_SECURITY.md for details.
Mitigations:
OpenPGP 3.4.1, Section 7.2.11: Command: 00 2A 80 86 <Lc> <data> <Le> Data format for ECDH: 7F49 <len> – Cipher DO A6 <len> – External Public Key template 86 <len> – External Public Key point (04||X||Y for P-256) <65 bytes ephemeral pubkey> Response: Shared Secret (32 bytes for P-256)
Decrypts an AES-CFB128 payload using the stored symmetric key (DO 0xD5).
| apdu | Parsed APDU request, payload[0] = 0x02 padding indicator. |
| resp | Output response buffer. |
| resp_max | Maximum size of resp. |
Payload format: 0x02 || IV(16) || ciphertext.
Definition at line 1928 of file openpgp.cpp.
References apdu_build_response(), apdu_sw(), gpg_storage_has_aes_key(), gpg_storage_load_aes_key(), s_session_pin, SW_CONDITIONS_NOT_SATISFIED, SW_OK, SW_SECURITY_NOT_SATISFIED, SW_UNKNOWN, SW_WRONG_DATA, and SW_WRONG_LENGTH.
Referenced by cmd_pso_decipher().
|
static |
Definition at line 1359 of file openpgp.cpp.
References apdu_sw(), apply_put_data_desc(), cardholder_sex, compute_rc_hash(), DO_AES_KEY, DO_ALGO_AUT, DO_ALGO_DEC, DO_ALGO_SIG, DO_RC, DO_SEX, find_put_data_desc(), gpg_storage_save_aes_key(), LOG_I, LOG_W, OPENPGP_PIN_MAX_LEN, OPENPGP_RC_MIN_LEN, put_data_algo_attr(), pw3_verified, RC_HASH_SIZE, RC_SALT_SIZE, s_rc_hash, s_rc_len, s_rc_retries, s_rc_salt, s_session_pin, save_state_to_nvs(), se_random_fill(), SW_FILE_NOT_FOUND, SW_OK, SW_SECURITY_NOT_SATISFIED, SW_UNKNOWN, SW_WRONG_LENGTH, and TAG.
Referenced by openpgp_process_apdu().
|
static |
Handles APDU PUT DATA (odd INS, 0xDB) for keypair import.
Used by gpg --card-edit → generate when the user answers "Y" to "Make off-card backup of encryption key?": GnuPG generates the key on the host and ships it as an OpenPGP 3.4.1 §7.2.8 Extended Header List
4D LL <CRT> // B6 00 (SIG) / B8 00 (DEC) / A4 00 (AUT) 7F48 LL // Cardholder Private Key Template (tag list) 5F48 LL // Concatenation of values (priv [|| pub])
Currently only DEC (CRT B8) is supported, mirroring the on-card path that also reserves software-ECDH for the decipher key (the only role TROPIC01 does not handle natively). SIG/AUT keys live in the secure element with no key-import path exposed by our HAL.
Definition at line 1498 of file openpgp.cpp.
References apdu_sw(), ehl_parse_one(), gpg_storage_save_dec_privkey(), KEY_DEC, P256_PRIVKEY_SIZE, pw3_verified, SW_INCORRECT_P1P2, SW_OK, SW_SECURITY_NOT_SATISFIED, SW_UNKNOWN, SW_WRONG_DATA, SW_WRONG_LENGTH, and update_generation_timestamp().
Referenced by openpgp_process_apdu().
|
static |
Handles APDU RESET RETRY COUNTER (INS 0x2C).
Per OpenPGP 3.4.1 §7.2.7: P1=0x02, P2=0x81: reset PW1 with admin authorisation. Lc = new PW1 length. Requires PW3 verified. P1=0x00, P2=0x81: reset PW1 using the Resetting Code. Lc = RC || new PW1. Not yet implemented — returns SW_INS_NOT_SUPPORTED until the RC store lands (planned in Phase D.3, full path).
Definition at line 2265 of file openpgp.cpp.
References apdu_sw(), compute_rc_hash(), LOG_I, OPENPGP_PIN_MAX_LEN, OPENPGP_PW1_MIN_LEN, pin_storage_openpgp_change_pw1(), pin_storage_openpgp_reset_pw1_retries(), PW1_CODE_1, pw1_verified, pw3_verified, RC_HASH_SIZE, s_rc_hash, s_rc_len, s_rc_retries, s_rc_salt, save_state_to_nvs(), SW_AUTH_METHOD_BLOCKED, SW_CONDITIONS_NOT_SATISFIED, SW_INCORRECT_P1P2, SW_OK, SW_SECURITY_NOT_SATISFIED, SW_UNKNOWN, SW_WRONG_LENGTH, and TAG.
Referenced by openpgp_process_apdu().
|
static |
Handles APDU SELECT command processing.
| apdu | Parsed APDU request. |
| resp | Output response buffer. |
| resp_max | Maximum size of resp. |
Definition at line 991 of file openpgp.cpp.
References apdu_sw(), app_selected, gpg_storage_clear_session(), LOG_I, OPENPGP_AID, pw1_verified, pw3_verified, s_session_pin, SW_FILE_NOT_FOUND, SW_OK, and TAG.
Referenced by openpgp_process_apdu().
|
static |
Handles APDU TERMINATE DF (INS 0xE6).
Per OpenPGP 3.4.1 §7.2.18: takes the card into the terminated lifecycle state. Allowed under PW3 verification, or unconditionally when both PW1 and PW3 retry counters have reached zero (last-resort recovery).
After TERMINATE only SELECT and ACTIVATE FILE are accepted; every other command returns SW_FILE_TERMINATED (0x6285).
Definition at line 2179 of file openpgp.cpp.
References apdu_sw(), card_terminated, LOG_W, pin_storage_openpgp_pw1_blocked(), pin_storage_openpgp_pw3_blocked(), pw1_verified, pw3_verified, save_state_to_nvs(), SW_INCORRECT_P1P2, SW_OK, SW_SECURITY_NOT_SATISFIED, and TAG.
Referenced by openpgp_process_apdu().
|
static |
Handles APDU VERIFY command for PIN verification.
| apdu | Parsed APDU request. |
| resp | Output response buffer. |
| resp_max | Maximum size of resp. |
Definition at line 1566 of file openpgp.cpp.
References apdu_sw(), gpg_storage_set_session_pin(), LOG_I, LOG_W, OPENPGP_PIN_MAX_LEN, pin_storage_openpgp_pw1_blocked(), pin_storage_openpgp_pw1_retries(), pin_storage_openpgp_pw3_blocked(), pin_storage_openpgp_pw3_retries(), pin_storage_openpgp_verify_pw1(), pin_storage_openpgp_verify_pw3(), PW1_CODE_1, PW1_CODE_2, pw1_verified, PW3_CODE, pw3_verified, s_session_pin, SW_AUTH_METHOD_BLOCKED, SW_INCORRECT_P1P2, SW_OK, SW_WRONG_LENGTH, and TAG.
Referenced by openpgp_process_apdu().
|
static |
Computes the iterated-salted S2K hash (OpenPGP KDF) for a PIN candidate.
| pin | PIN string. |
| salt | 8-byte salt. |
| iterations | Iteration count from PinManager. |
| hash_out | 32-byte output buffer. |
Definition at line 1650 of file openpgp.cpp.
References OPENPGP_PIN_MAX_LEN.
Referenced by peek_verify_pin().
|
static |
Iterated-salted SHA-256 over salt||rc for resetting-code storage. Same construction as PinManager::computeKdfHash (OpenPGP S2K).
Definition at line 195 of file openpgp.cpp.
References OPENPGP_PIN_MAX_LEN, RC_KDF_TOTAL_BYTES, and RC_SALT_SIZE.
Referenced by cmd_put_data(), and cmd_reset_retry_counter().
|
static |
Constant-time comparison of two equal-length byte buffers.
| a | First buffer. |
| b | Second buffer. |
| n | Number of bytes to compare. |
Definition at line 1693 of file openpgp.cpp.
Referenced by peek_verify_pin().
|
static |
Parse one BER-TLV field at pos.
Supports 1- or 2-byte tags and short-form / 0x81 / 0x82 length encodings, which covers everything the OpenPGP 3.4.1 PUT DATA odd payload uses.
pos is advanced past the parsed value. Definition at line 1445 of file openpgp.cpp.
Referenced by cmd_put_data_odd().
|
static |
Encodes the public key with the OpenPGP/SEC1 uncompressed prefix.
P-256 keys are normalized to 0x04 || X || Y. Ed25519 keys are returned as their raw 32-byte encoding without prefix.
| pubkey | Source public key buffer. |
| curve | Curve identifier (CDC_CURVE_*). |
| out | Destination buffer (must hold at least P256_PUBKEY_SIZE bytes). |
| out_len | Receives the encoded length. |
Definition at line 2483 of file openpgp.cpp.
References CDC_CURVE_P256, curve, ED25519_PUBKEY_SIZE, and P256_PUBKEY_SIZE.
Referenced by cmd_generate_keypair().
|
static |
Returns descriptor for an OpenPGP PUT DATA tag.
| tag | OpenPGP DO tag. |
Definition at line 1226 of file openpgp.cpp.
References ca_fp_1, ca_fp_2, ca_fp_3, cardholder_lang, cardholder_login, cardholder_name, cardholder_url, DO_CA_FP_1, DO_CA_FP_2, DO_CA_FP_3, DO_FP_AUT, DO_FP_DEC, DO_FP_SIG, DO_GEN_TIME_AUT, DO_GEN_TIME_DEC, DO_GEN_TIME_SIG, DO_LANG_PREF, DO_LOGIN, DO_NAME, DO_URL, fingerprint_aut, fingerprint_dec, fingerprint_sig, gen_time_aut, gen_time_dec, gen_time_sig, OPENPGP_FINGERPRINT_SIZE, PUT_KIND_BLOB_FIXED, and PUT_KIND_STRING_BOUNDED.
Referenced by cmd_put_data().
|
static |
Definition at line 900 of file openpgp.cpp.
References OPENPGP_FINGERPRINT_SIZE.
Referenced by openpgp_has_any_key().
|
static |
Generates a software ECDH P-256 key pair for the DEC slot.
The TROPIC01 secure element does not support ECDH, so the DEC private key is generated and persisted by gpg_storage (encrypted by device key). Memory holding the raw key is zeroized before returning.
Definition at line 2382 of file openpgp.cpp.
References ecdh_p256_generate_keypair(), gpg_storage_save_dec_privkey(), P256_PRIVKEY_SIZE, SW_OK, and SW_UNKNOWN.
Referenced by cmd_generate_keypair().
|
static |
Generates a hardware ECC key pair in the TROPIC01 secure element.
| ecc_slot | ECC slot index targeted by the key generation. |
| curve | Curve identifier (CDC_CURVE_*). |
Definition at line 2401 of file openpgp.cpp.
References curve, LOG_E, LOG_I, se_ecc_key_generate(), SW_OK, SW_UNKNOWN, and TAG.
Referenced by cmd_generate_keypair().
|
static |
Returns algorithm attributes for a key role based on stored key type.
| key_type | Key role (signature, decryption, authentication). |
| len | Output pointer receiving the attribute length. |
Definition at line 501 of file openpgp.cpp.
References ALGO_ATTR_ED25519, ALGO_ATTR_P256_ECDH, ALGO_ATTR_P256_ECDSA, CDC_CURVE_P256, curve, KEY_TYPE_AUT, KEY_TYPE_DEC, selected_curve_aut, and selected_curve_sig.
Referenced by build_do_app_related(), and cmd_get_data().
|
static |
Returns ECC slot mapping for an OpenPGP key reference.
| key_ref | OpenPGP key reference value. |
Definition at line 2346 of file openpgp.cpp.
References gpg_storage_aut_slot(), gpg_storage_dec_slot(), gpg_storage_sig_slot(), KEY_AUT, KEY_DEC, and KEY_SIG.
Referenced by cmd_generate_keypair().
|
static |
Maps an OpenPGP key reference to an internal key type.
| key_ref | OpenPGP key reference value. |
Definition at line 2364 of file openpgp.cpp.
References KEY_AUT, KEY_DEC, KEY_SIG, KEY_TYPE_AUT, KEY_TYPE_DEC, and KEY_TYPE_SIG.
Referenced by cmd_generate_keypair().
|
static |
Returns secure-element instance used by OpenPGP backend.
Definition at line 41 of file openpgp.cpp.
References cdc::hal::getSecureElementInstance().
Referenced by load_state_from_nvs(), openpgp_factory_reset(), put_data_algo_attr(), save_state_to_nvs(), se_ecc_key_generate(), se_ecc_key_read(), se_ecdsa_sign(), se_eddsa_sign(), and se_random_fill().
|
static |
Initializes the OpenPGP AID serial section from the ESP32 MAC address.
Definition at line 833 of file openpgp.cpp.
References LOG_I, LOG_W, s_openpgp_aid, and TAG.
Referenced by openpgp_init().
|
static |
Loads persistent OpenPGP runtime state from NVS.
Definition at line 698 of file openpgp.cpp.
References ca_fp_1, ca_fp_2, ca_fp_3, card_terminated, cardholder_lang, cardholder_login, cardholder_name, cardholder_sex, cardholder_url, CDC_CURVE_ED25519, CDC_CURVE_P256, fingerprint_aut, fingerprint_dec, fingerprint_sig, gen_time_aut, gen_time_dec, gen_time_sig, get_se(), LOG_W, NVS_NAMESPACE, NVS_STATE_KEY, OPENPGP_FINGERPRINT_SIZE, OPENPGP_NVS_SCHEMA_V2, OPENPGP_PIN_MAX_LEN, OPENPGP_STATE_SIG_SIZE, RC_HASH_SIZE, RC_SALT_SIZE, s_rc_hash, s_rc_len, s_rc_retries, s_rc_salt, selected_curve_aut, selected_curve_sig, sig_count, TAG, and verify_state_signature().
Referenced by openpgp_init().
| void openpgp_factory_reset | ( | void | ) |
Definition at line 2218 of file openpgp.cpp.
References ca_fp_1, ca_fp_2, ca_fp_3, card_terminated, cardholder_lang, cardholder_login, cardholder_name, cardholder_sex, cardholder_url, CDC_CURVE_ED25519, fingerprint_aut, fingerprint_dec, fingerprint_sig, gen_time_aut, gen_time_dec, gen_time_sig, get_se(), gpg_storage_aut_slot(), gpg_storage_clear_session(), gpg_storage_delete_dec_privkey(), gpg_storage_sig_slot(), pin_storage_openpgp_reset(), pw1_verified, pw3_verified, s_rc_hash, s_rc_len, s_rc_retries, s_rc_salt, save_state_to_nvs(), selected_curve_aut, selected_curve_sig, and sig_count.
Referenced by cmd_activate_file(), and gpg_reset().
| size_t openpgp_get_cardholder_name | ( | char * | out, |
| size_t | out_size ) |
Copies the cardholder name (OpenPGP DO 0x5B) into the caller buffer. Format is gpg's "Surname<<Firstname" or empty when unset.
Definition at line 913 of file openpgp.cpp.
References cardholder_name.
Referenced by gpg_get_status().
| bool openpgp_get_fingerprint | ( | uint8_t | key_type, |
| uint8_t * | fp_out ) |
Reads the stored OpenPGP v4 fingerprint for a key role.
| key_type | One of KEY_SIG, KEY_DEC, KEY_AUT. |
| fp_out | 20-byte output buffer. |
Definition at line 890 of file openpgp.cpp.
References fingerprint_aut, fingerprint_dec, fingerprint_sig, KEY_AUT, KEY_DEC, KEY_SIG, and OPENPGP_FINGERPRINT_SIZE.
Referenced by gpg_get_status().
| uint32_t openpgp_get_gen_time | ( | uint8_t | key_type | ) |
Returns the stored Unix timestamp of key generation, or 0 when unset.
| key_type | One of KEY_SIG, KEY_DEC, KEY_AUT. |
Definition at line 922 of file openpgp.cpp.
References gen_time_aut, gen_time_dec, gen_time_sig, KEY_AUT, KEY_DEC, and KEY_SIG.
Referenced by gpg_get_status().
| uint32_t openpgp_get_sig_count | ( | void | ) |
| bool openpgp_has_any_key | ( | void | ) |
Reports whether any of the SIG / DEC / AUT roles has a non-zero fingerprint configured. Acts as the canonical "card has keys" check.
Definition at line 907 of file openpgp.cpp.
References fingerprint_aut, fingerprint_dec, fingerprint_sig, and fp_is_set().
Referenced by gpg_export_pubkey_pem(), gpg_generate_key(), gpg_get_status(), gpg_is_initialized(), and cdc::mod_gpg::rebuildMenu().
| bool openpgp_init | ( | void | ) |
Definition at line 863 of file openpgp.cpp.
References gpg_init(), init_aid_from_mac(), load_state_from_nvs(), LOG_E, LOG_I, pin_storage_openpgp_init(), sig_count, and TAG.
Referenced by ccid_init().
| bool openpgp_is_selected | ( | void | ) |
Definition at line 882 of file openpgp.cpp.
References app_selected.
| int openpgp_process_apdu | ( | const uint8_t * | cmd, |
| size_t | cmd_len, | ||
| uint8_t * | resp, | ||
| size_t | resp_max ) |
Definition at line 2683 of file openpgp.cpp.
References apdu_build_response(), apdu_parse(), apdu_sw(), app_selected, apply_response_chaining(), card_terminated, chain_reset(), cmd_activate_file(), cmd_change_reference_data(), cmd_generate_keypair(), cmd_get_data(), cmd_get_response(), cmd_internal_authenticate(), cmd_manage_security_env(), cmd_pso_cds(), cmd_pso_decipher(), cmd_put_data(), cmd_put_data_odd(), cmd_reset_retry_counter(), cmd_select(), cmd_terminate_df(), cmd_verify(), g_chain_active, g_chain_buffer, g_chain_ins, g_chain_len, g_chain_p1, g_chain_p2, g_resp_pos, g_resp_remaining, INS_ACTIVATE, INS_CHANGE_PIN, INS_GENERATE_KEYPAIR, INS_GET_CHALLENGE, INS_GET_DATA, INS_GET_RESPONSE, INS_INTERNAL_AUTH, INS_MSE, INS_PSO, INS_PUT_DATA, INS_PUT_DATA_ODD, INS_RESET_RETRY, INS_SELECT, INS_TERMINATE, INS_VERIFY, LOG_D, LOG_E, LOG_W, se_random_fill(), SW_CLA_NOT_SUPPORTED, SW_CONDITIONS_NOT_SATISFIED, SW_FILE_TERMINATED, SW_INCORRECT_P1P2, SW_INS_NOT_SUPPORTED, SW_OK, SW_WRONG_DATA, SW_WRONG_LENGTH, and TAG.
Referenced by ccid_process_message().
| bool openpgp_set_cardholder_name | ( | const char * | name | ) |
Sets the cardholder name (OpenPGP DO 0x5B) and persists state.
| name | UTF-8 string; truncated to fit the storage buffer. |
Definition at line 936 of file openpgp.cpp.
References cardholder_name, name, and save_state_to_nvs().
Referenced by gpg_generate_key().
| bool openpgp_set_key_fingerprint | ( | uint8_t | key_type, |
| const uint8_t * | fingerprint, | ||
| uint32_t | gen_time ) |
Definition at line 949 of file openpgp.cpp.
References fingerprint_aut, fingerprint_dec, fingerprint_sig, gen_time_aut, gen_time_dec, gen_time_sig, KEY_AUT, KEY_DEC, KEY_SIG, LOG_E, LOG_I, OPENPGP_FINGERPRINT_SIZE, save_state_to_nvs(), and TAG.
Referenced by gpg_generate_key().
|
static |
Compares a candidate PIN against the stored hash without touching retry counters.
| slot | PIN slot to query. |
| pin | Candidate PIN string. |
Definition at line 1705 of file openpgp.cpp.
References compute_kdf_hash(), const_time_equal(), cdc::core::PinManager::instance(), and PIN_SLOT_PW1.
Referenced by try_change_pin().
|
static |
Handles APDU PUT DATA command processing.
| apdu | Parsed APDU request. |
| resp | Output response buffer. |
| resp_max | Maximum size of resp. |
Parses and applies a PUT DATA payload addressed to one of the algorithm-attribute Data Objects (C1, C2, C3).
For SIG (C1) and AUT (C3) the selected curve is updated and the existing key in the corresponding slot is wiped to force the host to regenerate it. DEC (C2) is constrained to P-256 ECDH (software path), so we accept the documented attribute and reject everything else.
Definition at line 1307 of file openpgp.cpp.
References ALGO_ATTR_CURVE_ED25519, ALGO_ATTR_CURVE_P256, ALGO_ATTR_ID_ECDH, ALGO_ATTR_OK, algo_attr_parse(), ALGO_ATTR_ROLE_AUT, ALGO_ATTR_ROLE_DEC, ALGO_ATTR_ROLE_SIG, algo_attr_validate_capability(), algo_attr_validate_role(), algo_attr_t::algo_id, apdu_sw(), CDC_CURVE_ED25519, CDC_CURVE_P256, algo_attr_t::curve, DO_ALGO_AUT, DO_ALGO_DEC, DO_ALGO_SIG, fingerprint_aut, fingerprint_sig, gen_time_aut, gen_time_sig, get_se(), gpg_storage_aut_slot(), gpg_storage_sig_slot(), LOG_I, save_state_to_nvs(), selected_curve_aut, selected_curve_sig, SW_FILE_NOT_FOUND, SW_OK, SW_WRONG_DATA, and TAG.
Referenced by cmd_put_data().
|
static |
Reads the public key for a given key role.
For SIG/AUT keys this reads from the TROPIC01 ECC slot. For DEC keys, the public key is derived from the encrypted software-stored private key; the temporary private-key buffer is zeroized after use.
| key_type | Logical key role. |
| ecc_slot | ECC slot index for hardware-backed keys. |
| pubkey | Output buffer (must be at least P256_PUBKEY_SIZE bytes). |
| curve_out | Curve detected for the loaded public key. |
Definition at line 2445 of file openpgp.cpp.
References CDC_CURVE_P256, ecdh_p256_derive_pubkey(), gpg_storage_has_dec_privkey(), gpg_storage_load_dec_privkey(), KEY_TYPE_DEC, LOG_I, LOG_W, P256_PRIVKEY_SIZE, P256_PUBKEY_SIZE, se_ecc_key_read(), and TAG.
Referenced by cmd_generate_keypair().
|
static |
Persists OpenPGP runtime state to NVS.
Definition at line 765 of file openpgp.cpp.
References ATTESTATION_ECC_SLOT, ca_fp_1, ca_fp_2, ca_fp_3, card_terminated, cardholder_lang, cardholder_login, cardholder_name, cardholder_sex, cardholder_url, fingerprint_aut, fingerprint_dec, fingerprint_sig, gen_time_aut, gen_time_dec, gen_time_sig, get_se(), LOG_E, NVS_NAMESPACE, NVS_STATE_KEY, cdc::hal::OK, OPENPGP_FINGERPRINT_SIZE, OPENPGP_NVS_SCHEMA_V2, OPENPGP_STATE_SIG_SIZE, RC_HASH_SIZE, RC_SALT_SIZE, s_rc_hash, s_rc_len, s_rc_retries, s_rc_salt, selected_curve_aut, selected_curve_sig, sig_count, and TAG.
Referenced by apply_put_data_desc(), cmd_pso_cds(), cmd_put_data(), cmd_reset_retry_counter(), cmd_terminate_df(), openpgp_factory_reset(), openpgp_set_cardholder_name(), openpgp_set_key_fingerprint(), put_data_algo_attr(), and update_generation_timestamp().
|
static |
Generates ECC key material in secure element slot.
| slot | ECC slot index. |
| curve | Curve identifier (CDC_CURVE_*). |
Definition at line 74 of file openpgp.cpp.
References CDC_CURVE_ED25519, curve, cdc::hal::ED25519, get_se(), LOG_E, LOG_W, cdc::hal::OK, cdc::hal::P256, and TAG.
Referenced by generate_hardware_key().
|
static |
Reads ECC public key from secure element and exposes curve metadata.
| slot | ECC slot index. |
| pubkey | Output public key buffer. |
| max_len | Capacity of pubkey. |
| curve_out | Optional output curve identifier. |
Definition at line 53 of file openpgp.cpp.
References CDC_CURVE_ED25519, CDC_CURVE_P256, curve, cdc::hal::ED25519, ED25519_PUBKEY_SIZE, get_se(), cdc::hal::OK, cdc::hal::P256, and P256_PUBKEY_SIZE.
Referenced by cmd_get_data(), cmd_internal_authenticate(), cmd_pso_cds(), and read_public_key().
|
static |
Signs a hash using secure-element ECDSA key.
| slot | ECC slot index. |
| hash | Hash bytes to sign. |
| hash_len | Hash length. |
| sig | Output 64-byte signature buffer. |
Definition at line 109 of file openpgp.cpp.
References get_se(), and cdc::hal::OK.
Referenced by cmd_internal_authenticate(), and cmd_pso_cds().
|
static |
Signs a message using secure-element EdDSA key.
| slot | ECC slot index. |
| Message transfer (badge-to-badge) | Message bytes. |
| msg_len | Message length. |
| sig | Output signature buffer. |
Definition at line 124 of file openpgp.cpp.
References get_se(), and cdc::hal::OK.
Referenced by cmd_internal_authenticate(), and cmd_pso_cds().
|
static |
Fills buffer with secure random bytes, with ESP fallback.
| buf | Output buffer. |
| len | Number of bytes to generate. |
Definition at line 135 of file openpgp.cpp.
References get_se().
Referenced by cmd_put_data(), and openpgp_process_apdu().
|
static |
Builds complete TLV object and returns total encoded length.
| buf | Output buffer. |
| buf_max | Maximum size of buf. |
| tag | TLV tag. |
| value | Optional value bytes. |
| value_len | Value length. |
Definition at line 470 of file openpgp.cpp.
References tlv_write_len(), and tlv_write_tag().
Referenced by build_do_app_related(), build_do_cardholder(), and cmd_generate_keypair().
|
static |
Writes a TLV length field using DER length encoding.
| buf | Output buffer receiving the encoded length. |
| len | Length value to encode. |
Definition at line 445 of file openpgp.cpp.
Referenced by build_do_app_related(), build_do_cardholder(), cmd_generate_keypair(), and tlv_build().
|
static |
TLV builder helper functions.
Writes a TLV tag using one or two bytes.
| buf | Output buffer receiving the tag bytes. |
| tag | TLV tag value. |
Definition at line 429 of file openpgp.cpp.
Referenced by build_do_app_related(), build_do_cardholder(), and tlv_build().
|
static |
Searches the split point for CHANGE REFERENCE DATA without consuming retries.
Iterates over candidate old-PIN lengths and uses a non-decrementing hash comparison. Only the matched split is applied through change_fn; the underlying retry counter is left untouched until the caller consumes one retry on overall failure.
| data | Concatenated old||new PIN bytes. |
| len | Total length of data. |
| min_len | Minimum PIN length for the target slot. |
| slot | PIN slot identifier. |
| change_fn | Callback that applies the new PIN. |
Definition at line 1749 of file openpgp.cpp.
References OPENPGP_PIN_MAX_LEN, and peek_verify_pin().
Referenced by cmd_change_reference_data().
|
static |
Updates and persists the generation timestamp for a key role.
Definition at line 2414 of file openpgp.cpp.
References gen_time_aut, gen_time_dec, gen_time_sig, KEY_AUT, KEY_DEC, KEY_SIG, and save_state_to_nvs().
Referenced by cmd_generate_keypair(), and cmd_put_data_odd().
|
static |
Verifies the P-256 ECDSA attestation signature over an OpenPGP state payload. Same construction as PinManager.
Definition at line 653 of file openpgp.cpp.
References ATTESTATION_ECC_SLOT, curve, cdc::hal::ISecureElement::eccGetPublicKey(), cdc::hal::OK, OPENPGP_STATE_SIG_SIZE, and cdc::hal::P256.
Referenced by load_state_from_nvs().
|
static |
Algorithm attributes for Ed25519 (EdDSA with curve25519).
Format: Algorithm ID (1) + OID bytes (no length prefix per OpenPGP 3.4.1).
Definition at line 381 of file openpgp.cpp.
Referenced by get_algo_attr().
|
static |
Algorithm attributes for P-256 ECDH (decryption role).
Format: Algorithm ID (1) + OID bytes (no length prefix per OpenPGP 3.4.1).
Definition at line 401 of file openpgp.cpp.
Referenced by get_algo_attr().
|
static |
Algorithm attributes for P-256 ECDSA (signature/authentication roles).
Format: Algorithm ID (1) + OID bytes (no length prefix per OpenPGP 3.4.1).
Definition at line 391 of file openpgp.cpp.
Referenced by get_algo_attr().
|
static |
ATR is defined in ccid.cpp and accessed via ccid_get_atr().
Application session/authentication state.
Definition at line 166 of file openpgp.cpp.
Referenced by cmd_select(), openpgp_is_selected(), and openpgp_process_apdu().
|
staticconstexpr |
Definition at line 646 of file openpgp.cpp.
Referenced by save_state_to_nvs(), and verify_state_signature().
|
static |
Optional CA fingerprints for trust-chain metadata.
Definition at line 351 of file openpgp.cpp.
Referenced by build_do_app_related(), cmd_get_data(), find_put_data_desc(), load_state_from_nvs(), openpgp_factory_reset(), and save_state_to_nvs().
|
static |
Definition at line 352 of file openpgp.cpp.
Referenced by build_do_app_related(), cmd_get_data(), find_put_data_desc(), load_state_from_nvs(), openpgp_factory_reset(), and save_state_to_nvs().
|
static |
Definition at line 353 of file openpgp.cpp.
Referenced by build_do_app_related(), cmd_get_data(), find_put_data_desc(), load_state_from_nvs(), openpgp_factory_reset(), and save_state_to_nvs().
|
static |
Card lifecycle state per OpenPGP 3.4.1 §7.2.18.
false = operational, true = terminated. While terminated the dispatcher accepts only SELECT and ACTIVATE FILE; everything else returns SW_FILE_TERMINATED (0x6285). ACTIVATE FILE wipes keys, DOs and PINs back to factory defaults.
Definition at line 248 of file openpgp.cpp.
Referenced by cmd_activate_file(), cmd_terminate_df(), load_state_from_nvs(), openpgp_factory_reset(), openpgp_process_apdu(), and save_state_to_nvs().
|
static |
Definition at line 359 of file openpgp.cpp.
Referenced by build_do_cardholder(), cmd_get_data(), find_put_data_desc(), load_state_from_nvs(), openpgp_factory_reset(), and save_state_to_nvs().
|
static |
Definition at line 362 of file openpgp.cpp.
Referenced by cmd_get_data(), find_put_data_desc(), load_state_from_nvs(), openpgp_factory_reset(), and save_state_to_nvs().
|
static |
Cardholder profile data stored in NVS.
Definition at line 358 of file openpgp.cpp.
Referenced by build_do_cardholder(), cmd_get_data(), find_put_data_desc(), load_state_from_nvs(), openpgp_factory_reset(), openpgp_get_cardholder_name(), openpgp_set_cardholder_name(), and save_state_to_nvs().
|
static |
Definition at line 360 of file openpgp.cpp.
Referenced by build_do_cardholder(), cmd_get_data(), cmd_put_data(), load_state_from_nvs(), openpgp_factory_reset(), and save_state_to_nvs().
|
static |
Definition at line 361 of file openpgp.cpp.
Referenced by cmd_get_data(), find_put_data_desc(), load_state_from_nvs(), openpgp_factory_reset(), and save_state_to_nvs().
|
static |
Extended capabilities object per OpenPGP 3.4.1 section 4.2.1.
Definition at line 409 of file openpgp.cpp.
Referenced by build_do_app_related(), and cmd_get_data().
|
static |
Definition at line 339 of file openpgp.cpp.
Referenced by build_do_app_related(), cmd_get_data(), find_put_data_desc(), load_state_from_nvs(), openpgp_factory_reset(), openpgp_get_fingerprint(), openpgp_has_any_key(), openpgp_set_key_fingerprint(), put_data_algo_attr(), and save_state_to_nvs().
|
static |
Definition at line 338 of file openpgp.cpp.
Referenced by build_do_app_related(), cmd_get_data(), find_put_data_desc(), load_state_from_nvs(), openpgp_factory_reset(), openpgp_get_fingerprint(), openpgp_has_any_key(), openpgp_set_key_fingerprint(), and save_state_to_nvs().
|
static |
Data object storage buffers (fingerprints and related metadata).
Definition at line 337 of file openpgp.cpp.
Referenced by build_do_app_related(), cmd_get_data(), find_put_data_desc(), load_state_from_nvs(), openpgp_factory_reset(), openpgp_get_fingerprint(), openpgp_has_any_key(), openpgp_set_key_fingerprint(), put_data_algo_attr(), and save_state_to_nvs().
|
static |
Definition at line 275 of file openpgp.cpp.
Referenced by chain_reset(), and openpgp_process_apdu().
|
static |
Command-chaining accumulator (ISO 7816-4 §5.1.1).
The host sets the CLA chaining bit (0x10) on every intermediate APDU and clears it on the last one. We accumulate the command data here until the final chunk arrives, then dispatch a single synthetic APDU. Triggered by gpg key import (RSA / large ECC), large PUT DATA (e.g. cardholder cert), and PSO:DECIPHER with extended Cipher DOs.
Definition at line 273 of file openpgp.cpp.
Referenced by openpgp_process_apdu().
|
static |
Definition at line 276 of file openpgp.cpp.
Referenced by chain_reset(), and openpgp_process_apdu().
|
static |
Definition at line 274 of file openpgp.cpp.
Referenced by chain_reset(), and openpgp_process_apdu().
|
static |
Definition at line 277 of file openpgp.cpp.
Referenced by chain_reset(), and openpgp_process_apdu().
|
static |
Definition at line 278 of file openpgp.cpp.
Referenced by chain_reset(), and openpgp_process_apdu().
|
static |
Buffered remainder of an APDU response that did not fit into the caller-supplied Le window. Drained one chunk at a time via GET RESPONSE (INS 0xC0) per ISO 7816-4 §5.3.4. Lifetime is bound to the next APDU on the same logical channel: the buffer is invalidated when any non-GET RESPONSE command arrives.
4 kB cap covers the largest OpenPGP DOs (Cardholder Certificate, Application Related Data with full key info) without claiming PSRAM.
Definition at line 260 of file openpgp.cpp.
Referenced by apply_response_chaining(), and cmd_get_response().
|
static |
Definition at line 262 of file openpgp.cpp.
Referenced by apply_response_chaining(), cmd_get_response(), and openpgp_process_apdu().
|
static |
Definition at line 261 of file openpgp.cpp.
Referenced by apply_response_chaining(), cmd_get_response(), and openpgp_process_apdu().
|
static |
Definition at line 346 of file openpgp.cpp.
Referenced by build_do_app_related(), cmd_get_data(), find_put_data_desc(), load_state_from_nvs(), openpgp_factory_reset(), openpgp_get_gen_time(), openpgp_set_key_fingerprint(), put_data_algo_attr(), save_state_to_nvs(), and update_generation_timestamp().
|
static |
Definition at line 345 of file openpgp.cpp.
Referenced by build_do_app_related(), cmd_get_data(), find_put_data_desc(), load_state_from_nvs(), openpgp_factory_reset(), openpgp_get_gen_time(), openpgp_set_key_fingerprint(), save_state_to_nvs(), and update_generation_timestamp().
|
static |
Key-generation timestamps (4-byte big-endian Unix time each).
Definition at line 344 of file openpgp.cpp.
Referenced by build_do_app_related(), cmd_get_data(), find_put_data_desc(), load_state_from_nvs(), openpgp_factory_reset(), openpgp_get_gen_time(), openpgp_set_key_fingerprint(), put_data_algo_attr(), save_state_to_nvs(), and update_generation_timestamp().
|
static |
Historical bytes used in OpenPGP ATR-related data objects.
Definition at line 367 of file openpgp.cpp.
Referenced by build_do_app_related(), and cmd_get_data().
| const uint8_t* OPENPGP_AID = s_openpgp_aid |
Definition at line 156 of file openpgp.cpp.
Referenced by build_do_app_related(), cmd_get_data(), and cmd_select().
| const uint8_t OPENPGP_AID_LEN = sizeof(s_openpgp_aid) |
Definition at line 157 of file openpgp.cpp.
Referenced by build_do_app_related(), and cmd_get_data().
|
staticconstexpr |
Definition at line 332 of file openpgp.cpp.
Referenced by load_state_from_nvs(), and save_state_to_nvs().
|
staticconstexpr |
Definition at line 647 of file openpgp.cpp.
Referenced by load_state_from_nvs(), save_state_to_nvs(), and verify_state_signature().
|
static |
Definition at line 167 of file openpgp.cpp.
Referenced by cmd_internal_authenticate(), cmd_pso_cds(), cmd_pso_decipher(), cmd_reset_retry_counter(), cmd_select(), cmd_terminate_df(), cmd_verify(), and openpgp_factory_reset().
|
static |
Definition at line 168 of file openpgp.cpp.
Referenced by cmd_generate_keypair(), cmd_put_data(), cmd_put_data_odd(), cmd_reset_retry_counter(), cmd_select(), cmd_terminate_df(), cmd_verify(), and openpgp_factory_reset().
|
staticconstexpr |
Definition at line 184 of file openpgp.cpp.
Referenced by cmd_put_data(), cmd_reset_retry_counter(), load_state_from_nvs(), and save_state_to_nvs().
|
staticconstexpr |
Definition at line 185 of file openpgp.cpp.
Referenced by compute_rc_hash().
|
staticconstexpr |
Definition at line 183 of file openpgp.cpp.
Referenced by cmd_put_data(), compute_rc_hash(), load_state_from_nvs(), and save_state_to_nvs().
|
static |
OpenPGP Application ID (RID + PIX), initialized dynamically.
D2 76 00 01 24 01 = OpenPGP RID. Structure: RID(6) + Version(2) + Manufacturer(2) + Serial(4) + RFU(2) = 16 bytes.
Definition at line 149 of file openpgp.cpp.
Referenced by init_aid_from_mac().
|
static |
Definition at line 187 of file openpgp.cpp.
Referenced by cmd_put_data(), cmd_reset_retry_counter(), load_state_from_nvs(), openpgp_factory_reset(), and save_state_to_nvs().
|
static |
Definition at line 188 of file openpgp.cpp.
Referenced by build_do_app_related(), cmd_get_data(), cmd_put_data(), cmd_reset_retry_counter(), load_state_from_nvs(), openpgp_factory_reset(), and save_state_to_nvs().
|
static |
Definition at line 189 of file openpgp.cpp.
Referenced by build_do_app_related(), cmd_get_data(), cmd_put_data(), cmd_reset_retry_counter(), load_state_from_nvs(), openpgp_factory_reset(), and save_state_to_nvs().
|
static |
Definition at line 186 of file openpgp.cpp.
Referenced by cmd_put_data(), cmd_reset_retry_counter(), load_state_from_nvs(), openpgp_factory_reset(), and save_state_to_nvs().
|
static |
Session PIN cache for DEC key decryption (temporary after VERIFY for PSO:DECIPHER).
Definition at line 291 of file openpgp.cpp.
Referenced by __attribute__(), cmd_pso_decipher_aes(), cmd_put_data(), cmd_select(), and cmd_verify().
|
static |
Definition at line 238 of file openpgp.cpp.
Referenced by cmd_generate_keypair(), get_algo_attr(), load_state_from_nvs(), openpgp_factory_reset(), put_data_algo_attr(), and save_state_to_nvs().
|
static |
Host-selected ECC curve per key role. DEC is fixed to P-256 because the TROPIC01 cannot perform ECDH natively and the firmware only carries a software P-256 ECDH path in ecdh.cpp. SIG and AUT default to Ed25519 (the project's preferred curve for signing) and can be flipped to P-256 via PUT DATA C1 / C3 per OpenPGP 3.4.1 §4.4.3.7-9.
Definition at line 237 of file openpgp.cpp.
Referenced by cmd_generate_keypair(), get_algo_attr(), load_state_from_nvs(), openpgp_factory_reset(), put_data_algo_attr(), and save_state_to_nvs().
|
static |
Definition at line 169 of file openpgp.cpp.
Referenced by cmd_get_data(), cmd_pso_cds(), load_state_from_nvs(), openpgp_factory_reset(), openpgp_get_sig_count(), openpgp_init(), and save_state_to_nvs().
|
static |
OpenPGP smart-card application implementation for CDC Badge.
Based on pico-openpgp (https://github.com/polhenarejos/pico-openpgp), adapted for CDC Badge and TROPIC01 secure element integration. Specification target: OpenPGP Smart Card Application 3.4.1.
Definition at line 35 of file openpgp.cpp.