98 if (platform_get_gpg_agent_socket(agent_path,
sizeof(agent_path)) != 0) {
99 log_error(
"Failed to get GPG agent path");
103 log_debug(
"Connecting to GPG agent at: %s", agent_path);
106 pipe_t pipe = platform_pipe_connect(agent_path);
107 if (!platform_pipe_is_valid(pipe)) {
108 log_error(
"Failed to connect to GPG agent");
114 if (read_agent_line(pipe, response,
sizeof(response)) != 0) {
115 log_error(
"Failed to read GPG agent greeting");
116 platform_pipe_close(pipe);
120 if (!is_ok_response(response)) {
121 log_error(
"Unexpected GPG agent greeting: %s", response);
122 platform_pipe_close(pipe);
126 log_debug(
"Connected to GPG agent successfully");
130 if (send_agent_command(pipe,
"OPTION pinentry-mode=loopback") != 0) {
131 log_warn(
"Failed to set loopback pinentry mode (continuing anyway)");
134 if (read_agent_line(pipe, response,
sizeof(response)) != 0) {
135 log_warn(
"Failed to read OPTION command response (continuing anyway)");
136 }
else if (is_ok_response(response)) {
137 log_debug(
"Loopback pinentry mode enabled");
139 log_warn(
"Failed to enable loopback pinentry mode: %s (continuing anyway)", response);
143 return (
int)(intptr_t)pipe;
154int gpg_agent_sign(
int handle_as_int,
const char *keygrip,
const uint8_t *message,
size_t message_len,
155 uint8_t *signature_out,
size_t *signature_len_out) {
156 if (handle_as_int < 0 || !keygrip || !message || !signature_out || !signature_len_out) {
157 log_error(
"Invalid arguments to gpg_agent_sign");
161 pipe_t handle = (pipe_t)(intptr_t)handle_as_int;
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");
172 if (read_agent_line(handle, response,
sizeof(response)) != 0) {
173 log_error(
"Failed to read SIGKEY response");
177 if (!is_ok_response(response)) {
178 log_error(
"SIGKEY failed: %s", response);
188 uint8_t hash[crypto_hash_sha512_BYTES];
189 crypto_hash_sha512(hash, message, message_len);
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]);
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");
206 if (read_agent_line(handle, response,
sizeof(response)) != 0) {
207 log_error(
"Failed to read SETHASH response");
211 if (!is_ok_response(response)) {
212 log_error(
"SETHASH failed: %s", response);
217 if (send_agent_command(handle,
"PKSIGN") != 0) {
218 log_error(
"Failed to send PKSIGN command");
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");
232 log_debug(
"PKSIGN response line %d: %s", attempts + 1, response);
235 if (response[0] ==
'S' && response[1] ==
' ') {
236 log_debug(
"Skipping PKSIGN status line: %s", response);
242 if (strncmp(response,
"ERR", 3) == 0) {
243 log_debug(
"Skipping PKSIGN error line (informational): %s", response);
248 if (response[0] ==
'D' && response[1] ==
' ') {
249 log_debug(
"Found signature data line");
255 if (strncmp(response,
"OK", 2) == 0) {
256 log_warn(
"PKSIGN returned OK without data line");
261 if (strncmp(response,
"INQUIRE", 7) == 0) {
262 log_error(
"Unexpected INQUIRE after PKSIGN: %s", response);
267 log_warn(
"Unexpected PKSIGN response (attempt %d): %s", attempts + 1, response);
271 log_error(
"Expected D line from PKSIGN after %d attempts", 20);
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);
288 const char *data = response + 2;
295 const char *r_marker = strstr(data,
"(1:r32:");
297 log_error(
"Could not find r value marker in S-expression");
302 const char *r_data = r_marker + 7;
305 const char *s_marker = strstr(r_data + 32,
"(1:s32:");
307 log_error(
"Could not find s value marker in S-expression");
312 const char *s_data = s_marker + 7;
315 memcpy(signature_out, r_data, 32);
316 memcpy(signature_out + 32, s_data, 32);
318 *signature_len_out = 64;
322 for (
int i = 0; i < 64; i++) {
323 safe_snprintf(sig_hex + i * 2, 3,
"%02x", (
unsigned char)signature_out[i]);
326 log_debug(
"Extracted signature (64 bytes): %s", sig_hex);
329 if (read_agent_line(handle, response,
sizeof(response)) != 0) {
330 log_error(
"Failed to read final PKSIGN response");
334 if (!is_ok_response(response)) {
335 log_error(
"PKSIGN final response not OK: %s", response);
339 log_debug(
"Successfully signed message with GPG agent");
int gpg_agent_sign(int handle_as_int, const char *keygrip, const uint8_t *message, size_t message_len, uint8_t *signature_out, size_t *signature_len_out)
int safe_snprintf(char *buffer, size_t buffer_size, const char *format,...)
Safe formatted string printing to buffer.