141 {
142 log_debug("gpg_sign_detached_ed25519: Signing with key ID %s (fallback mode)", key_id);
143
144
145 uint8_t openpgp_signature[512];
146 size_t openpgp_len = 0;
147
148 int result =
gpg_sign_with_key(key_id, message, message_len, openpgp_signature, &openpgp_len);
149 if (result != 0) {
150 log_error("GPG detached signing failed for key %s", key_id);
151 return -1;
152 }
153
154 log_debug("gpg_sign_with_key returned %zu bytes", openpgp_len);
155
156 if (openpgp_len < 10) {
157 log_error("GPG signature too short: %zu bytes", openpgp_len);
158 return -1;
159 }
160
161 log_debug("Parsing OpenPGP signature packet (%zu bytes) to extract Ed25519 signature", openpgp_len);
162
163
164
165
166 size_t offset = 0;
167
168
169 uint8_t tag = openpgp_signature[offset++];
170 size_t packet_len = 0;
171
172 if ((tag & 0x40) == 0) {
173
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];
179 offset += 2;
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];
183 offset += 4;
184 } else {
185 log_error("Unsupported old-format packet length type: %d", length_type);
186 return -1;
187 }
188 } else {
189
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];
198 offset += 4;
199 } else {
200 log_error("Unsupported new-format packet length encoding: %d", length_byte);
201 return -1;
202 }
203 }
204
205 if (offset + packet_len > openpgp_len) {
206 log_error("Packet length exceeds signature size: %zu + %zu > %zu", offset, packet_len, openpgp_len);
207 return -1;
208 }
209
210 log_debug("Signature packet: offset=%zu, length=%zu", offset, packet_len);
211
212
213
214 if (offset + 4 > openpgp_len) {
215 log_error("Signature packet too short for header");
216 return -1;
217 }
218
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++];
223
224 log_debug("Signature: version=%d, type=%d, algo=%d, hash=%d", version, sig_type, pub_algo, hash_algo);
225
226
227 if (pub_algo != 22) {
228 log_error("Expected EdDSA algorithm (22), got %d", pub_algo);
229 return -1;
230 }
231
232
233 if (version == 4) {
234 if (offset + 2 > openpgp_len) {
235 log_error("Cannot read hashed subpacket length");
236 return -1;
237 }
238 uint16_t hashed_len = (openpgp_signature[offset] << 8) | openpgp_signature[offset + 1];
239 offset += 2;
240 offset += hashed_len;
241
242 if (offset + 2 > openpgp_len) {
243 log_error("Cannot read unhashed subpacket length");
244 return -1;
245 }
246 uint16_t unhashed_len = (openpgp_signature[offset] << 8) | openpgp_signature[offset + 1];
247 offset += 2;
248 offset += unhashed_len;
249
250
251 if (offset + 2 > openpgp_len) {
252 log_error("Cannot read hash left bits");
253 return -1;
254 }
255 offset += 2;
256 }
257
258
259
260
261
262 if (offset + 2 > openpgp_len) {
263 log_error("Cannot read MPI bit count for R");
264 return -1;
265 }
266
267 uint16_t r_bits = (openpgp_signature[offset] << 8) | openpgp_signature[offset + 1];
268 offset += 2;
269 size_t r_bytes = (r_bits + 7) / 8;
270
271 log_debug("R: %d bits (%zu bytes)", r_bits, r_bytes);
272
273 if (r_bytes != 32) {
274 log_error("Expected 32-byte R value, got %zu bytes", r_bytes);
275 return -1;
276 }
277
278 if (offset + r_bytes > openpgp_len) {
279 log_error("R value exceeds packet size");
280 return -1;
281 }
282
283 memcpy(signature_out, &openpgp_signature[offset], 32);
284 offset += r_bytes;
285
286
287 if (offset + 2 > openpgp_len) {
288 log_error("Cannot read MPI bit count for S");
289 return -1;
290 }
291
292 uint16_t s_bits = (openpgp_signature[offset] << 8) | openpgp_signature[offset + 1];
293 offset += 2;
294 size_t s_bytes = (s_bits + 7) / 8;
295
296 log_debug("S: %d bits (%zu bytes)", s_bits, s_bytes);
297
298 if (s_bytes != 32) {
299 log_error("Expected 32-byte S value, got %zu bytes", s_bytes);
300 return -1;
301 }
302
303 if (offset + s_bytes > openpgp_len) {
304 log_error("S value exceeds packet size");
305 return -1;
306 }
307
308 memcpy(signature_out + 32, &openpgp_signature[offset], 32);
309
310 log_debug("Successfully extracted 64-byte Ed25519 signature from OpenPGP packet");
311
312
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]);
317 }
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);
321
322 return 0;
323}
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)
int safe_snprintf(char *buffer, size_t buffer_size, const char *format,...)
Safe formatted string printing to buffer.