45 size_t *signature_len_out) {
46 if (!key_id || !message || message_len == 0 || !signature_out || !signature_len_out) {
47 log_error(
"Invalid parameters to gpg_sign_with_key");
58 char temp_dir[MAX_PATH];
59 if (GetTempPathA(
sizeof(temp_dir), temp_dir) == 0) {
60 log_error(
"Failed to get temp directory");
66 safe_snprintf(msg_prefix,
sizeof(msg_prefix),
"asc_msg_%lu_", GetCurrentProcessId());
67 safe_snprintf(sig_prefix,
sizeof(sig_prefix),
"asc_sig_%lu_", GetCurrentProcessId());
69 if (GetTempFileNameA(temp_dir, msg_prefix, 0, msg_path) == 0) {
70 log_error(
"Failed to create temp message file");
73 if (GetTempFileNameA(temp_dir, sig_prefix, 0, sig_path) == 0) {
74 log_error(
"Failed to create temp signature file");
79 msg_fd =
platform_open(msg_path, O_WRONLY | O_CREAT | O_TRUNC, 0600);
82 safe_snprintf(msg_path,
sizeof(msg_path),
"/tmp/asciichat_msg_%d_XXXXXX", getpid());
83 safe_snprintf(sig_path,
sizeof(sig_path),
"/tmp/asciichat_sig_%d_XXXXXX", getpid());
85 msg_fd = mkstemp(msg_path);
92 int sig_fd = mkstemp(sig_path);
104 log_error(
"Failed to open temp message file");
109 ssize_t written = write(msg_fd, message, message_len);
113 if (written != (ssize_t)message_len) {
114 log_error(
"Failed to write message to temp file");
119 char escaped_key_id[64];
121 log_error(
"Failed to escape GPG key ID for shell command");
128 safe_snprintf(cmd,
sizeof(cmd),
"gpg --local-user 0x%s --detach-sign --output \"%s\" \"%s\" 2>nul", escaped_key_id,
131 safe_snprintf(cmd,
sizeof(cmd),
"gpg --local-user 0x%s --detach-sign --output \"%s\" \"%s\" 2>/dev/null",
132 escaped_key_id, sig_path, msg_path);
136 int status = system(cmd);
138 log_error(
"GPG signing failed (exit code %d)", status);
143 FILE *sig_fp = fopen(sig_path,
"rb");
149 fseek(sig_fp, 0, SEEK_END);
150 long sig_size = ftell(sig_fp);
151 fseek(sig_fp, 0, SEEK_SET);
153 if (sig_size <= 0 || sig_size > 512) {
154 log_error(
"Invalid signature size: %ld bytes", sig_size);
159 size_t bytes_read = fread(signature_out, 1, sig_size, sig_fp);
162 if (bytes_read != (
size_t)sig_size) {
163 log_error(
"Failed to read signature file");
167 *signature_len_out = sig_size;
168 log_info(
"GPG signature created successfully (%zu bytes)", *signature_len_out);
182 log_info(
"gpg_sign_detached_ed25519: Signing with key ID %s (fallback mode)", key_id);
185 uint8_t openpgp_signature[512];
186 size_t openpgp_len = 0;
188 int result =
gpg_sign_with_key(key_id, message, message_len, openpgp_signature, &openpgp_len);
190 log_error(
"GPG detached signing failed for key %s", key_id);
194 log_debug(
"gpg_sign_with_key returned %zu bytes", openpgp_len);
196 if (openpgp_len < 10) {
197 log_error(
"GPG signature too short: %zu bytes", openpgp_len);
201 log_debug(
"Parsing OpenPGP signature packet (%zu bytes) to extract Ed25519 signature", openpgp_len);
209 uint8_t tag = openpgp_signature[offset++];
210 size_t packet_len = 0;
212 if ((tag & 0x40) == 0) {
214 uint8_t length_type = tag & 0x03;
215 if (length_type == 0) {
216 packet_len = openpgp_signature[offset++];
217 }
else if (length_type == 1) {
218 packet_len = (openpgp_signature[offset] << 8) | openpgp_signature[offset + 1];
220 }
else if (length_type == 2) {
221 packet_len = (openpgp_signature[offset] << 24) | (openpgp_signature[offset + 1] << 16) |
222 (openpgp_signature[offset + 2] << 8) | openpgp_signature[offset + 3];
225 log_error(
"Unsupported old-format packet length type: %d", length_type);
230 uint8_t length_byte = openpgp_signature[offset++];
231 if (length_byte < 192) {
232 packet_len = length_byte;
233 }
else if (length_byte < 224) {
234 packet_len = ((length_byte - 192) << 8) + openpgp_signature[offset++] + 192;
235 }
else if (length_byte == 255) {
236 packet_len = (openpgp_signature[offset] << 24) | (openpgp_signature[offset + 1] << 16) |
237 (openpgp_signature[offset + 2] << 8) | openpgp_signature[offset + 3];
240 log_error(
"Unsupported new-format packet length encoding: %d", length_byte);
245 if (offset + packet_len > openpgp_len) {
246 log_error(
"Packet length exceeds signature size: %zu + %zu > %zu", offset, packet_len, openpgp_len);
250 log_debug(
"Signature packet: offset=%zu, length=%zu", offset, packet_len);
254 if (offset + 4 > openpgp_len) {
255 log_error(
"Signature packet too short for header");
259 uint8_t version = openpgp_signature[offset++];
260 uint8_t sig_type = openpgp_signature[offset++];
261 uint8_t pub_algo = openpgp_signature[offset++];
262 uint8_t hash_algo = openpgp_signature[offset++];
264 log_debug(
"Signature: version=%d, type=%d, algo=%d, hash=%d", version, sig_type, pub_algo, hash_algo);
267 if (pub_algo != 22) {
268 log_error(
"Expected EdDSA algorithm (22), got %d", pub_algo);
274 if (offset + 2 > openpgp_len) {
275 log_error(
"Cannot read hashed subpacket length");
278 uint16_t hashed_len = (openpgp_signature[offset] << 8) | openpgp_signature[offset + 1];
280 offset += hashed_len;
282 if (offset + 2 > openpgp_len) {
283 log_error(
"Cannot read unhashed subpacket length");
286 uint16_t unhashed_len = (openpgp_signature[offset] << 8) | openpgp_signature[offset + 1];
288 offset += unhashed_len;
291 if (offset + 2 > openpgp_len) {
302 if (offset + 2 > openpgp_len) {
303 log_error(
"Cannot read MPI bit count for R");
307 uint16_t r_bits = (openpgp_signature[offset] << 8) | openpgp_signature[offset + 1];
309 size_t r_bytes = (r_bits + 7) / 8;
311 log_debug(
"R: %d bits (%zu bytes)", r_bits, r_bytes);
314 log_error(
"Expected 32-byte R value, got %zu bytes", r_bytes);
318 if (offset + r_bytes > openpgp_len) {
319 log_error(
"R value exceeds packet size");
323 memcpy(signature_out, &openpgp_signature[offset], 32);
327 if (offset + 2 > openpgp_len) {
328 log_error(
"Cannot read MPI bit count for S");
332 uint16_t s_bits = (openpgp_signature[offset] << 8) | openpgp_signature[offset + 1];
334 size_t s_bytes = (s_bits + 7) / 8;
336 log_debug(
"S: %d bits (%zu bytes)", s_bits, s_bytes);
339 log_error(
"Expected 32-byte S value, got %zu bytes", s_bytes);
343 if (offset + s_bytes > openpgp_len) {
344 log_error(
"S value exceeds packet size");
348 memcpy(signature_out + 32, &openpgp_signature[offset], 32);
350 log_info(
"Successfully extracted 64-byte Ed25519 signature from OpenPGP packet");
353 char hex_r[65], hex_s[65];
354 for (
int i = 0; i < 32; i++) {
356 safe_snprintf(hex_s + i * 2, 3,
"%02x", signature_out[i + 32]);
358 hex_r[64] = hex_s[64] =
'\0';
359 log_debug(
"Signature R (first 32 bytes): %s", hex_r);
360 log_debug(
"Signature S (last 32 bytes): %s", hex_s);
int gpg_sign_detached_ed25519(const char *key_id, const uint8_t *message, size_t message_len, uint8_t signature_out[64])
Sign message with GPG and extract raw Ed25519 signature.
int gpg_sign_with_key(const char *key_id, const uint8_t *message, size_t message_len, uint8_t *signature_out, size_t *signature_len_out)
Sign a message using GPG key (via gpg –detach-sign)