41int gpg_sign_with_key(
const char *key_id,
const uint8_t *message,
size_t message_len, uint8_t *signature_out,
42 size_t *signature_len_out) {
43 if (!key_id || !message || message_len == 0 || !signature_out || !signature_len_out) {
44 log_error(
"Invalid parameters to gpg_sign_with_key");
55 if (platform_create_temp_file(msg_path,
sizeof(msg_path),
"asciichat_msg", &msg_fd) != 0) {
56 log_error(
"Failed to create temp message file");
60 if (platform_create_temp_file(sig_path,
sizeof(sig_path),
"asciichat_sig", &sig_fd) != 0) {
61 log_error(
"Failed to create temp signature file");
62 platform_delete_temp_file(msg_path);
70 platform_delete_temp_file(sig_path);
73 ssize_t written = write(msg_fd, message, message_len);
77 if (written != (ssize_t)message_len) {
78 log_error(
"Failed to write message to temp file");
83 char escaped_key_id[64];
85 log_error(
"Failed to escape GPG key ID for shell command");
90 char cmd[BUFFER_SIZE_LARGE];
92 "gpg --local-user 0x%s --detach-sign --output \"%s\" \"%s\" " PLATFORM_SHELL_NULL_REDIRECT,
93 escaped_key_id, sig_path, msg_path);
95 log_debug(
"Signing with GPG: %s", cmd);
96 int status = system(cmd);
98 log_error(
"GPG signing failed (exit code %d)", status);
105 log_error(
"Failed to open signature file: %s", SAFE_STRERROR(errno));
109 fseek(sig_fp, 0, SEEK_END);
110 long sig_size = ftell(sig_fp);
111 fseek(sig_fp, 0, SEEK_SET);
113 if (sig_size <= 0 || sig_size > 512) {
114 log_error(
"Invalid signature size: %ld bytes", sig_size);
119 size_t bytes_read = fread(signature_out, 1, sig_size, sig_fp);
122 if (bytes_read != (
size_t)sig_size) {
123 log_error(
"Failed to read signature file");
127 *signature_len_out = sig_size;
128 log_debug(
"GPG signature created successfully (%zu bytes)", *signature_len_out);
135 platform_delete_temp_file(msg_path);
136 platform_delete_temp_file(sig_path);
141 uint8_t signature_out[64]) {
142 log_debug(
"gpg_sign_detached_ed25519: Signing with key ID %s (fallback mode)", key_id);
145 uint8_t openpgp_signature[512];
146 size_t openpgp_len = 0;
148 int result =
gpg_sign_with_key(key_id, message, message_len, openpgp_signature, &openpgp_len);
150 log_error(
"GPG detached signing failed for key %s", key_id);
154 log_debug(
"gpg_sign_with_key returned %zu bytes", openpgp_len);
156 if (openpgp_len < 10) {
157 log_error(
"GPG signature too short: %zu bytes", openpgp_len);
161 log_debug(
"Parsing OpenPGP signature packet (%zu bytes) to extract Ed25519 signature", openpgp_len);
169 uint8_t tag = openpgp_signature[offset++];
170 size_t packet_len = 0;
172 if ((tag & 0x40) == 0) {
174 uint8_t length_type = tag & 0x03;
175 if (length_type == 0) {
176 packet_len = openpgp_signature[offset++];
177 }
else if (length_type == 1) {
178 packet_len = (openpgp_signature[offset] << 8) | openpgp_signature[offset + 1];
180 }
else if (length_type == 2) {
181 packet_len = (openpgp_signature[offset] << 24) | (openpgp_signature[offset + 1] << 16) |
182 (openpgp_signature[offset + 2] << 8) | openpgp_signature[offset + 3];
185 log_error(
"Unsupported old-format packet length type: %d", length_type);
190 uint8_t length_byte = openpgp_signature[offset++];
191 if (length_byte < 192) {
192 packet_len = length_byte;
193 }
else if (length_byte < 224) {
194 packet_len = ((length_byte - 192) << 8) + openpgp_signature[offset++] + 192;
195 }
else if (length_byte == 255) {
196 packet_len = (openpgp_signature[offset] << 24) | (openpgp_signature[offset + 1] << 16) |
197 (openpgp_signature[offset + 2] << 8) | openpgp_signature[offset + 3];
200 log_error(
"Unsupported new-format packet length encoding: %d", length_byte);
205 if (offset + packet_len > openpgp_len) {
206 log_error(
"Packet length exceeds signature size: %zu + %zu > %zu", offset, packet_len, openpgp_len);
210 log_debug(
"Signature packet: offset=%zu, length=%zu", offset, packet_len);
214 if (offset + 4 > openpgp_len) {
215 log_error(
"Signature packet too short for header");
219 uint8_t version = openpgp_signature[offset++];
220 uint8_t sig_type = openpgp_signature[offset++];
221 uint8_t pub_algo = openpgp_signature[offset++];
222 uint8_t hash_algo = openpgp_signature[offset++];
224 log_debug(
"Signature: version=%d, type=%d, algo=%d, hash=%d", version, sig_type, pub_algo, hash_algo);
227 if (pub_algo != 22) {
228 log_error(
"Expected EdDSA algorithm (22), got %d", pub_algo);
234 if (offset + 2 > openpgp_len) {
235 log_error(
"Cannot read hashed subpacket length");
238 uint16_t hashed_len = (openpgp_signature[offset] << 8) | openpgp_signature[offset + 1];
240 offset += hashed_len;
242 if (offset + 2 > openpgp_len) {
243 log_error(
"Cannot read unhashed subpacket length");
246 uint16_t unhashed_len = (openpgp_signature[offset] << 8) | openpgp_signature[offset + 1];
248 offset += unhashed_len;
251 if (offset + 2 > openpgp_len) {
252 log_error(
"Cannot read hash left bits");
262 if (offset + 2 > openpgp_len) {
263 log_error(
"Cannot read MPI bit count for R");
267 uint16_t r_bits = (openpgp_signature[offset] << 8) | openpgp_signature[offset + 1];
269 size_t r_bytes = (r_bits + 7) / 8;
271 log_debug(
"R: %d bits (%zu bytes)", r_bits, r_bytes);
274 log_error(
"Expected 32-byte R value, got %zu bytes", r_bytes);
278 if (offset + r_bytes > openpgp_len) {
279 log_error(
"R value exceeds packet size");
283 memcpy(signature_out, &openpgp_signature[offset], 32);
287 if (offset + 2 > openpgp_len) {
288 log_error(
"Cannot read MPI bit count for S");
292 uint16_t s_bits = (openpgp_signature[offset] << 8) | openpgp_signature[offset + 1];
294 size_t s_bytes = (s_bits + 7) / 8;
296 log_debug(
"S: %d bits (%zu bytes)", s_bits, s_bytes);
299 log_error(
"Expected 32-byte S value, got %zu bytes", s_bytes);
303 if (offset + s_bytes > openpgp_len) {
304 log_error(
"S value exceeds packet size");
308 memcpy(signature_out + 32, &openpgp_signature[offset], 32);
310 log_debug(
"Successfully extracted 64-byte Ed25519 signature from OpenPGP packet");
313 char hex_r[65], hex_s[65];
314 for (
int i = 0; i < 32; i++) {
316 safe_snprintf(hex_s + i * 2, 3,
"%02x", signature_out[i + 32]);
318 hex_r[64] = hex_s[64] =
'\0';
319 log_debug(
"Signature R (first 32 bytes): %s", hex_r);
320 log_debug(
"Signature S (last 32 bytes): %s", hex_s);
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)