8#include "../keys_validation.h"
21#define SAFE_POPEN _popen
22#define SAFE_PCLOSE _pclose
24#define SAFE_POPEN popen
25#define SAFE_PCLOSE pclose
33 if (!gpg_key_id || !key_out) {
42 const char *key_id = gpg_key_id;
43 if (strncmp(key_id,
"0x", 2) == 0 || strncmp(key_id,
"0X", 2) == 0) {
47 size_t key_id_len = strlen(key_id);
48 if (key_id_len != 8 && key_id_len != 16 && key_id_len != 40) {
53 for (
size_t i = 0; i < key_id_len; i++) {
55 if (!((c >=
'0' && c <=
'9') || (c >=
'a' && c <=
'f') || (c >=
'A' && c <=
'F'))) {
64 return extract_result;
70 memcpy(key_out->
key, ed25519_pk, 32);
79 if (!gpg_key_binary || !key_out) {
96 if (!gpg_key_id || !ed25519_pk) {
112 if (!gpg_key_text || !x25519_pk) {
121 return extract_result;
125 if (crypto_sign_ed25519_pk_to_curve25519(x25519_pk, ed25519_pk) != 0) {
138 if (!gpg_key_text || !fingerprint_out) {
152 if (!gpg_key_text || !key_id_out) {
165 if (!gpg_key_text || !is_expired) {
173 size_t key_len = strlen(gpg_key_text);
174 const char *key_id = gpg_key_text;
178 for (
size_t i = 0; i < key_len; i++) {
179 if (!((gpg_key_text[i] >=
'0' && gpg_key_text[i] <=
'9') || (gpg_key_text[i] >=
'A' && gpg_key_text[i] <=
'F') ||
180 (gpg_key_text[i] >=
'a' && gpg_key_text[i] <=
'f'))) {
187 if (!is_hex || (key_len != 8 && key_len != 16 && key_len != 40)) {
188 log_warn(
"check_gpg_key_expiry: Input is not a key ID format (expected 8/16/40 hex chars)");
195 safe_snprintf(cmd,
sizeof(cmd),
"gpg --list-keys --with-colons %s 2>/dev/null", key_id);
199 log_error(
"Failed to run gpg --list-keys for key %s", key_id);
205 bool found_pub =
false;
211 while (fgets(line,
sizeof(line), fp)) {
212 if (strncmp(line,
"pub:", 4) == 0) {
219 char *field_start = ptr;
221 while (*ptr && field_count < 12) {
222 if (*ptr ==
':' || *ptr ==
'\n') {
224 fields[field_count++] = field_start;
225 field_start = ptr + 1;
231 if (field_count >= 7 && strlen(fields[6]) > 0) {
233 long expiry_timestamp = atol(fields[6]);
234 time_t now = time(NULL);
236 if (expiry_timestamp > 0 && expiry_timestamp < now) {
238 log_warn(
"GPG key %s has expired (expiry: %ld, now: %ld)", key_id, expiry_timestamp, (
long)now);
239 }
else if (expiry_timestamp > 0) {
240 log_debug(
"GPG key %s expires at timestamp %ld (valid)", key_id, expiry_timestamp);
242 log_debug(
"GPG key %s has no expiration date", key_id);
245 log_debug(
"GPG key %s has no expiration date (field empty)", key_id);
255 log_warn(
"Could not find GPG key %s in keyring", key_id);
267 if (!gpg_key_text || !output) {
272 if (output_size < 64) {
282 SAFE_STRNCPY(output,
"GPG key (key ID extraction failed)", output_size - 1);
288 for (
int i = 0; i < 8; i++) {
291 hex_key_id[16] =
'\0';
294 int result =
safe_snprintf(output, output_size,
"GPG key ID: %s", hex_key_id);
295 if (result < 0 || result >= (
int)output_size) {
304 if (!gpg_key_text || !comment_out) {
309 if (comment_size == 0) {
⚠️‼️ Error and/or exit() when things go bad.
GPG public key export interface.
#define SAFE_STRNCPY(dst, src, size)
int gpg_get_public_key(const char *key_id, uint8_t *public_key_out, char *keygrip_out)
Get public key from GPG keyring by key ID.
#define SET_ERRNO(code, context_msg,...)
Set error code with custom context message and log it.
asciichat_error_t
Error and exit codes - unified status values (0-255)
asciichat_error_t check_gpg_key_expiry(const char *gpg_key_text, bool *is_expired)
Check if GPG key is expired.
asciichat_error_t extract_ed25519_from_gpg(const char *gpg_key_id, uint8_t ed25519_pk[32])
Extract Ed25519 public key from GPG key.
asciichat_error_t extract_gpg_key_comment(const char *gpg_key_text, char *comment_out, size_t comment_size)
Extract key comment/email from GPG key.
asciichat_error_t get_gpg_key_id(const char *gpg_key_text, uint8_t key_id_out[8])
Get GPG key ID (short fingerprint)
asciichat_error_t parse_gpg_key(const char *gpg_key_id, public_key_t *key_out)
Parse GPG key from armored text format.
asciichat_error_t get_gpg_fingerprint(const char *gpg_key_text, uint8_t fingerprint_out[20])
Get GPG key fingerprint.
asciichat_error_t parse_gpg_key_binary(const uint8_t *gpg_key_binary, size_t key_size, public_key_t *key_out)
Parse GPG key from binary format.
asciichat_error_t format_gpg_key_display(const char *gpg_key_text, char *output, size_t output_size)
Format GPG key for display.
asciichat_error_t gpg_to_x25519_public(const char *gpg_key_text, uint8_t x25519_pk[32])
Convert GPG key to X25519 for key exchange.
#define log_warn(...)
Log a WARN message.
#define log_error(...)
Log an ERROR message.
#define log_debug(...)
Log a DEBUG message.
⏱️ High-precision timing utilities using sokol_time.h and uthash
🔤 String Manipulation and Shell Escaping Utilities