5#include <mbedtls/sha1.h>
6#include <mbedtls/sha256.h>
14static const uint8_t kOidEd25519[] = {0x09, 0x2B, 0x06, 0x01, 0x04, 0x01,
15 0xDA, 0x47, 0x0F, 0x01};
16static const uint8_t kOidP256[] = {0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D,
21size_t buildPublicKeyBody(uint8_t
curve,
22 const uint8_t* pubkey,
size_t pubkey_len,
24 uint8_t* out,
size_t out_size)
26 if (!out || !pubkey)
return 0;
31 if (!is_ed25519 && pubkey_len < 64)
return 0;
34 const uint8_t* oid = is_ed25519 ? kOidEd25519 : kOidP256;
35 const size_t oid_len = is_ed25519 ?
sizeof(kOidEd25519) : sizeof(kOidP256);
43 mpi[0] =
static_cast<uint8_t
>((bits >> 8) & 0xFF);
44 mpi[1] =
static_cast<uint8_t
>(bits & 0xFF);
51 mpi[0] =
static_cast<uint8_t
>((bits >> 8) & 0xFF);
52 mpi[1] =
static_cast<uint8_t
>(bits & 0xFF);
58 const size_t total = 1 + 4 + 1 + oid_len + mpi_len;
59 if (total > out_size)
return 0;
63 out[off++] = (created_at >> 24) & 0xFF;
64 out[off++] = (created_at >> 16) & 0xFF;
65 out[off++] = (created_at >> 8) & 0xFF;
66 out[off++] = created_at & 0xFF;
68 std::memcpy(out + off, oid, oid_len);
70 std::memcpy(out + off, mpi, mpi_len);
76void v4FpFromBody(
const uint8_t* body,
size_t body_len, uint8_t out_fp[20])
78 const uint8_t prefix[3] = {
80 static_cast<uint8_t
>((body_len >> 8) & 0xFF),
81 static_cast<uint8_t
>(body_len & 0xFF),
83 mbedtls_sha1_context ctx;
84 mbedtls_sha1_init(&ctx);
85 mbedtls_sha1_starts(&ctx);
86 mbedtls_sha1_update(&ctx, prefix,
sizeof(prefix));
87 mbedtls_sha1_update(&ctx, body, body_len);
88 mbedtls_sha1_finish(&ctx, out_fp);
89 mbedtls_sha1_free(&ctx);
95 uint8_t* out,
size_t out_size)
97 if (!out || !pubkey)
return 0;
102 mpi[0] =
static_cast<uint8_t
>((bits >> 8) & 0xFF);
103 mpi[1] =
static_cast<uint8_t
>(bits & 0xFF);
111 const size_t total = 1 + 4 + 1 +
sizeof(kOidP256) + mpi_len +
sizeof(kdf);
112 if (total > out_size)
return 0;
116 out[off++] = (created_at >> 24) & 0xFF;
117 out[off++] = (created_at >> 16) & 0xFF;
118 out[off++] = (created_at >> 8) & 0xFF;
119 out[off++] = created_at & 0xFF;
121 std::memcpy(out + off, kOidP256,
sizeof(kOidP256));
122 off +=
sizeof(kOidP256);
123 std::memcpy(out + off, mpi, mpi_len);
125 std::memcpy(out + off, kdf,
sizeof(kdf));
133 if (!out_fp || !pubkey)
return false;
136 if (body_len == 0)
return false;
137 v4FpFromBody(body, body_len, out_fp);
142 const uint8_t* pubkey,
size_t pubkey_len,
146 if (!out_fp)
return false;
149 const size_t body_len = buildPublicKeyBody(
curve, pubkey, pubkey_len,
150 created_at, body,
sizeof(body));
151 if (body_len == 0)
return false;
153 v4FpFromBody(body, body_len, out_fp);
158 const uint8_t* pubkey,
size_t pubkey_len,
162 if (!out_fp)
return false;
165 const size_t body_len = buildPublicKeyBody(
curve, pubkey, pubkey_len,
166 created_at, body,
sizeof(body));
167 if (body_len == 0)
return false;
170 const uint8_t prefix[5] = {
172 static_cast<uint8_t
>((body_len >> 24) & 0xFF),
173 static_cast<uint8_t
>((body_len >> 16) & 0xFF),
174 static_cast<uint8_t
>((body_len >> 8) & 0xFF),
175 static_cast<uint8_t
>(body_len & 0xFF),
178 mbedtls_sha256_context ctx;
179 mbedtls_sha256_init(&ctx);
180 mbedtls_sha256_starts(&ctx, 0);
181 mbedtls_sha256_update(&ctx, prefix,
sizeof(prefix));
182 mbedtls_sha256_update(&ctx, body, body_len);
183 mbedtls_sha256_finish(&ctx, out_fp);
184 mbedtls_sha256_free(&ctx);
190 uint8_t out_hash[32])
192 if (!fp_v4 || !
user_id || !out_hash)
return false;
194 uint8_t input[84] = {0};
195 std::memcpy(input, fp_v4, 20);
196 const size_t uid_len = std::strlen(
user_id);
197 std::memcpy(input + 20,
user_id, uid_len > 64 ? 64 : uid_len);
199 mbedtls_sha256(input,
sizeof(input), out_hash, 0);
#define ED25519_PUBKEY_SIZE
Ed25519 raw public key size in bytes.
#define OPENPGP_ALGO_ECDSA
OpenPGP algorithm ID for ECDSA (RFC 4880 Section 9.1).
#define P256_PUBKEY_BITS
Canonical OpenPGP MPI bit-length of an uncompressed P-256 point.
#define OPENPGP_ECDH_KDF_HASH
KDF hash algorithm ID embedded in an ECDH public key (SHA-256).
#define MPI_HEADER_SIZE
OpenPGP MPI header size (2-byte length prefix).
#define OPENPGP_ECDH_KDF_SYM
KEK wrap cipher ID embedded in an ECDH public key (AES-128).
#define OPENPGP_ALGO_ECDH
Centralized magic-value constants for the OpenPGP smart-card application.
#define OPENPGP_ALGO_EDDSA
OpenPGP algorithm ID for EdDSA (Ed25519).
#define MPI_FULL_SIZE_P256
Full P-256 MPI buffer size: 2 byte length prefix + 65 byte uncompressed key.
#define CDC_CURVE_ED25519
uint8_t user_id[FIDO2_USER_ID_MAX_LEN]
bool calculateFingerprintV4(uint8_t curve, const uint8_t *pubkey, size_t pubkey_len, uint32_t created_at, uint8_t out_fp[20])
Compute the RFC 4880 V4 OpenPGP fingerprint (SHA-1, 20 bytes).
bool calculateFingerprintV4Ecdh(const uint8_t *pubkey, uint32_t created_at, uint8_t out_fp[20])
Compute the V4 fingerprint of an ECDH (DEC) subkey.
size_t buildEcdhPubkeyBody(const uint8_t *pubkey, uint32_t created_at, uint8_t *out, size_t out_size)
Serialise an RFC 6637 ECDH Public Key Packet body (algorithm 18).
bool gpgCrossSignDigest(const uint8_t fp_v4[20], const char *user_id, uint8_t out_hash[32])
Build the digest input for a cross-signature.
bool calculateFingerprintV5(uint8_t curve, const uint8_t *pubkey, size_t pubkey_len, uint32_t created_at, uint8_t out_fp[32])
Compute the V5 / RFC 9580 OpenPGP fingerprint (SHA-256, 32 bytes).