10#include <mbedtls/sha1.h>
11#include <mbedtls/base64.h>
12#include <mbedtls/platform_util.h>
18constexpr const char*
TAG =
"GPG";
26uint32_t get_unix_time(
void) {
27 return static_cast<uint32_t
>(time(
nullptr));
34bool se_get_pubkey(uint8_t slot, uint8_t* pubkey,
size_t max_len, uint8_t* curve_out) {
36 if (!se || !pubkey)
return false;
38 LOG_E(
TAG,
"se_get_pubkey: buffer too small (slot=%u max_len=%zu)", slot, max_len);
42 auto res = se->eccGetPublicKey(slot, pubkey, &
curve);
44 LOG_E(
TAG,
"se_get_pubkey: slot=%u failed (%d)", slot,
static_cast<int>(res));
54bool se_generate_key(uint8_t slot, uint8_t
curve) {
57 LOG_E(
TAG,
"se_generate_key: no SE (slot=%u)", slot);
64 LOG_W(
TAG,
"se_generate_key: slot %u initial fail (%d), retry after delete",
65 slot,
static_cast<int>(res));
67 res = se->eccGenerate(slot, c);
70 LOG_E(
TAG,
"se_generate_key: slot %u curve=%u failed (%d)",
71 slot,
curve,
static_cast<int>(res));
77bool calculate_fingerprint(
const uint8_t *pubkey, uint8_t
curve,
78 uint32_t created_at, uint8_t *fp_out) {
80 return ::cdc::mod_gpg::calculateFingerprintV4(
curve, pubkey, pubkey_len,
87 s_pending_user_id[0] =
'\0';
96 if (!status)
return false;
97 memset(status, 0,
sizeof(*status));
100 status->initialized =
true;
104 memcpy(status->fingerprint, fp,
sizeof(status->fingerprint));
116 strncpy(status->user_id,
name,
sizeof(status->user_id) - 1);
123 strncpy(s_pending_user_id,
user_id,
sizeof(s_pending_user_id) - 1);
124 s_pending_user_id[
sizeof(s_pending_user_id) - 1] =
'\0';
129 return s_pending_user_id[0] !=
'\0';
134 LOG_E(
TAG,
"generate: storage not ready");
138 LOG_E(
TAG,
"generate: missing user-id");
145 LOG_I(
TAG,
"generate: curve=%u sig_slot=%u dec_slot=%u aut_slot=%u",
146 curve, sig_slot, dec_slot, aut_slot);
149 if (!se_generate_key(sig_slot,
curve)) {
150 LOG_E(
TAG,
"generate: SIG key generation failed");
153 if (!se_generate_key(aut_slot,
curve)) {
154 LOG_E(
TAG,
"generate: AUT key generation failed");
163 se->eccDelete(dec_slot);
168 LOG_E(
TAG,
"generate: DEC ECDH keypair failed");
172 mbedtls_platform_zeroize(dec_priv,
sizeof(dec_priv));
174 LOG_E(
TAG,
"generate: DEC privkey save failed");
178 uint32_t created_at = get_unix_time();
180 uint8_t pub_sig[64] = {};
181 uint8_t pub_aut[64] = {};
182 uint8_t curve_sig =
curve;
183 uint8_t curve_aut =
curve;
184 if (!se_get_pubkey(sig_slot, pub_sig,
sizeof(pub_sig), &curve_sig)) {
185 LOG_E(
TAG,
"generate: read SIG pubkey failed");
188 if (!se_get_pubkey(aut_slot, pub_aut,
sizeof(pub_aut), &curve_aut)) {
189 LOG_E(
TAG,
"generate: read AUT pubkey failed");
196 if (!calculate_fingerprint(pub_sig, curve_sig, created_at, fp_sig)) {
197 LOG_E(
TAG,
"generate: SIG fingerprint failed");
202 if (!calculate_fingerprint(dec_pub65 + 1,
CDC_CURVE_P256, created_at, fp_dec)) {
203 LOG_E(
TAG,
"generate: DEC fingerprint failed");
206 if (!calculate_fingerprint(pub_aut, curve_aut, created_at, fp_aut)) {
207 LOG_E(
TAG,
"generate: AUT fingerprint failed");
215 if (s_pending_user_id[0]) {
219 s_pending_user_id[0] =
'\0';
229 s_pending_user_id[0] =
'\0';
234 if (!buf || size < 256 || !out_len) {
239 LOG_W(
TAG,
"export: no key configured");
254 auto res = se->eccGetPublicKey(sig_slot, pubkey, &eccCurve);
256 LOG_W(
TAG,
"export: eccGetPublicKey slot=%u failed (%d)",
257 sig_slot,
static_cast<int>(res));
267 static const uint8_t ed25519_prefix[] = {
270 0x06, 0x03, 0x2b, 0x65, 0x70,
274 uint8_t der[
sizeof(ed25519_prefix) + 32];
275 memcpy(der, ed25519_prefix,
sizeof(ed25519_prefix));
276 memcpy(der +
sizeof(ed25519_prefix), pubkey, 32);
280 if (mbedtls_base64_encode(
reinterpret_cast<unsigned char*
>(b64),
sizeof(b64),
281 &b64_len, der,
sizeof(der)) != 0) {
285 int written = snprintf(buf, size,
286 "-----BEGIN PUBLIC KEY-----\n%s\n-----END PUBLIC KEY-----\n",
288 if (written < 0 ||
static_cast<size_t>(written) >= size)
return false;
289 *out_len =
static_cast<size_t>(written);
293 static const uint8_t p256_prefix[] = {
296 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01,
297 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07,
300 uint8_t der[
sizeof(p256_prefix) + 65];
301 memcpy(der, p256_prefix,
sizeof(p256_prefix));
302 der[
sizeof(p256_prefix)] = 0x04;
303 memcpy(der +
sizeof(p256_prefix) + 1, pubkey, 64);
307 if (mbedtls_base64_encode(
reinterpret_cast<unsigned char*
>(b64),
sizeof(b64),
308 &b64_len, der,
sizeof(der)) != 0) {
311 int written = snprintf(buf, size,
312 "-----BEGIN PUBLIC KEY-----\n%s\n-----END PUBLIC KEY-----\n",
314 if (written < 0 ||
static_cast<size_t>(written) >= size)
return false;
315 *out_len =
static_cast<size_t>(written);
uint8_t gpg_storage_dec_slot(void)
bool gpg_storage_ready(void)
bool gpg_storage_save_dec_privkey(const uint8_t *privkey, const char *pin)
Saves a DEC private key into R-Memory using PIN-bound AES-GCM.
uint8_t gpg_storage_aut_slot(void)
uint8_t gpg_storage_sig_slot(void)
#define KEY_FINGERPRINT_MAX_LEN
bool key_fingerprint_generate(uint8_t slot, char *buf, size_t len)
Reads public key from secure element slot and generates fingerprint.
char name[cdc::hal::ISecureElement::RMEM_NAME_LEN]
CDC Log: logging over TinyUSB CDC and UART.
#define LOG_W(tag, fmt,...)
#define LOG_I(tag, fmt,...)
#define LOG_E(tag, fmt,...)
#define ED25519_PUBKEY_SIZE
Ed25519 raw public key size in bytes.
#define P256_PUBKEY_SIZE
P-256 uncompressed public key size: 0x04 || X(32) || Y(32).
#define P256_PRIVKEY_SIZE
P-256 private key (scalar) size in bytes.
bool ecdh_p256_generate_keypair(uint8_t *privkey_out, uint8_t *pubkey_out)
#define CDC_CURVE_ED25519
uint8_t user_id[FIDO2_USER_ID_MAX_LEN]
bool gpg_has_pending_user_id(void)
Returns whether a user-id was staged via gpg_set_pending_user_id().
bool gpg_init(void)
Initializes the GPG module bookkeeping.
bool gpg_set_pending_user_id(const char *user_id)
Stages a user-id string for the next on-device key generation. The string is forwarded to OpenpgpNvsS...
bool gpg_generate_key(uint8_t curve)
Generates SIG / DEC / AUT keys on the device and announces them to the OpenPGP card application (fing...
bool gpg_alchemy_fingerprint(char *buf, size_t len)
Writes the alchemical-word fingerprint of the SIG public key.
bool gpg_get_status(gpg_status_t *status)
Fills status from the OpenPGP card-application state.
bool gpg_is_initialized(void)
Reports whether at least one OpenPGP key role has a configured fingerprint on the card.
bool gpg_export_pubkey_pem(char *buf, size_t size, size_t *out_len)
Renders the current SIG public key as a SubjectPublicKeyInfo PEM. The key is read straight from the s...
bool gpg_reset(void)
Factory-resets all GPG key material and metadata.
#define GPG_FINGERPRINT_LEN
ISecureElement * getSecureElementInstance()
Returns singleton secure-element stub instance.
bool openpgp_get_fingerprint(uint8_t key_type, uint8_t *fp_out)
Reads the stored OpenPGP v4 fingerprint for a key role.
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_key_fingerprint(uint8_t key_type, const uint8_t *fingerprint, uint32_t gen_time)
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<<Firstn...
bool openpgp_set_cardholder_name(const char *name)
Sets the cardholder name (OpenPGP DO 0x5B) and persists state.
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....
void openpgp_factory_reset(void)