155 {
156 if (handle_as_int < 0 || !keygrip || !message || !signature_out || !signature_len_out) {
157 log_error("Invalid arguments to gpg_agent_sign");
158 return -1;
159 }
160
161 pipe_t handle = (pipe_t)(intptr_t)handle_as_int;
163
164
165 char sigkey_cmd[128];
166 safe_snprintf(sigkey_cmd,
sizeof(sigkey_cmd),
"SIGKEY %s", keygrip);
167 if (send_agent_command(handle, sigkey_cmd) != 0) {
168 log_error("Failed to send SIGKEY command");
169 return -1;
170 }
171
172 if (read_agent_line(handle, response, sizeof(response)) != 0) {
173 log_error("Failed to read SIGKEY response");
174 return -1;
175 }
176
177 if (!is_ok_response(response)) {
178 log_error("SIGKEY failed: %s", response);
179 return -1;
180 }
181
182
183
184
185
186
187
188 uint8_t hash[crypto_hash_sha512_BYTES];
189 crypto_hash_sha512(hash, message, message_len);
190
191
192
193 char sethash_cmd[256];
194 int offset =
safe_snprintf(sethash_cmd,
sizeof(sethash_cmd),
"SETHASH 10 ");
195 for (size_t i = 0; i < crypto_hash_sha512_BYTES; i++) {
196 offset +=
safe_snprintf(sethash_cmd + offset,
sizeof(sethash_cmd) - (
size_t)offset,
"%02X", hash[i]);
197 }
198
199 log_debug("Sending SETHASH command with SHA512 hash");
200 if (send_agent_command(handle, sethash_cmd) != 0) {
201 log_error("Failed to send SETHASH command");
202 return -1;
203 }
204
205
206 if (read_agent_line(handle, response, sizeof(response)) != 0) {
207 log_error("Failed to read SETHASH response");
208 return -1;
209 }
210
211 if (!is_ok_response(response)) {
212 log_error("SETHASH failed: %s", response);
213 return -1;
214 }
215
216
217 if (send_agent_command(handle, "PKSIGN") != 0) {
218 log_error("Failed to send PKSIGN command");
219 return -1;
220 }
221
222
223
224
225 bool found_data = false;
226 for (int attempts = 0; attempts < 20; attempts++) {
227 if (read_agent_line(handle, response, sizeof(response)) != 0) {
228 log_error("Failed to read PKSIGN response");
229 return -1;
230 }
231
232 log_debug("PKSIGN response line %d: %s", attempts + 1, response);
233
234
235 if (response[0] == 'S' && response[1] == ' ') {
236 log_debug("Skipping PKSIGN status line: %s", response);
237 continue;
238 }
239
240
241
242 if (strncmp(response, "ERR", 3) == 0) {
243 log_debug("Skipping PKSIGN error line (informational): %s", response);
244 continue;
245 }
246
247
248 if (response[0] == 'D' && response[1] == ' ') {
249 log_debug("Found signature data line");
250 found_data = true;
251 break;
252 }
253
254
255 if (strncmp(response, "OK", 2) == 0) {
256 log_warn("PKSIGN returned OK without data line");
257 continue;
258 }
259
260
261 if (strncmp(response, "INQUIRE", 7) == 0) {
262 log_error("Unexpected INQUIRE after PKSIGN: %s", response);
263 return -1;
264 }
265
266
267 log_warn("Unexpected PKSIGN response (attempt %d): %s", attempts + 1, response);
268 }
269
270 if (!found_data) {
271 log_error("Expected D line from PKSIGN after %d attempts", 20);
272 return -1;
273 }
274
275
276
277
278
279
280
281 char debug_buf[201];
282 size_t response_len = strlen(response);
283 size_t debug_len = response_len < 200 ? response_len : 200;
284 memcpy(debug_buf, response, debug_len);
285 debug_buf[debug_len] = '\0';
286 log_debug("GPG agent D line (first 200 bytes): %s", debug_buf);
287
288 const char *data = response + 2;
289
290
291
292
293
294
295 const char *r_marker = strstr(data, "(1:r32:");
296 if (!r_marker) {
297 log_error("Could not find r value marker in S-expression");
298 return -1;
299 }
300
301
302 const char *r_data = r_marker + 7;
303
304
305 const char *s_marker = strstr(r_data + 32, "(1:s32:");
306 if (!s_marker) {
307 log_error("Could not find s value marker in S-expression");
308 return -1;
309 }
310
311
312 const char *s_data = s_marker + 7;
313
314
315 memcpy(signature_out, r_data, 32);
316 memcpy(signature_out + 32, s_data, 32);
317
318 *signature_len_out = 64;
319
320
321 char sig_hex[129];
322 for (int i = 0; i < 64; i++) {
323 safe_snprintf(sig_hex + i * 2, 3,
"%02x", (
unsigned char)signature_out[i]);
324 }
325 sig_hex[128] = '\0';
326 log_debug("Extracted signature (64 bytes): %s", sig_hex);
327
328
329 if (read_agent_line(handle, response, sizeof(response)) != 0) {
330 log_error("Failed to read final PKSIGN response");
331 return -1;
332 }
333
334 if (!is_ok_response(response)) {
335 log_error("PKSIGN final response not OK: %s", response);
336 return -1;
337 }
338
339 log_debug("Successfully signed message with GPG agent");
340 return 0;
341}
int safe_snprintf(char *buffer, size_t buffer_size, const char *format,...)
Safe formatted string printing to buffer.