agent.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664
  1. /* agent.c - Talking to gpg-agent.
  2. Copyright (C) 2006 g10 Code GmbH
  3. This file is part of Scute.
  4. Scute is free software; you can redistribute it and/or modify it
  5. under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. Scute is distributed in the hope that it will be useful, but
  9. WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with Scute; if not, write to the Free Software Foundation,
  14. Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  15. In addition, as a special exception, g10 Code GmbH gives permission
  16. to link this library: with the Mozilla Foundation's code for
  17. Mozilla (or with modified versions of it that use the same license
  18. as the "Mozilla" code), and distribute the linked executables. You
  19. must obey the GNU General Public License in all respects for all of
  20. the code used other than "Mozilla". If you modify this file, you
  21. may extend this exception to your version of the file, but you are
  22. not obligated to do so. If you do not wish to do so, delete this
  23. exception statement from your version. */
  24. #if HAVE_CONFIG_H
  25. #include <config.h>
  26. #endif
  27. #include <stdlib.h>
  28. #include <stdio.h>
  29. #include <locale.h>
  30. #include <errno.h>
  31. #include <string.h>
  32. #include <stdarg.h>
  33. #include <assuan.h>
  34. #include <gpg-error.h>
  35. #include "debug.h"
  36. #include "support.h"
  37. #include "agent.h"
  38. /* The global agent context. */
  39. static assuan_context_t agent_ctx = NULL;
  40. /* Establish a connection to a running GPG agent. */
  41. static gpg_error_t
  42. agent_connect (assuan_context_t *ctx_r)
  43. {
  44. gpg_error_t err = 0;
  45. char *infostr;
  46. char *ptr;
  47. int pid;
  48. int protocol_version;
  49. infostr = getenv ("GPG_AGENT_INFO");
  50. if (!infostr)
  51. {
  52. DEBUG ("missing GPG_AGENT_INFO environment variable");
  53. return gpg_error (GPG_ERR_NO_AGENT);
  54. }
  55. infostr = strdup (infostr);
  56. if (!infostr)
  57. return gpg_error_from_errno (errno);
  58. if (!(ptr = strchr (infostr, ':')) || ptr == infostr)
  59. {
  60. DEBUG ("malformed GPG_AGENT_INFO environment variable");
  61. free (infostr);
  62. return gpg_error (GPG_ERR_NO_AGENT);
  63. }
  64. *(ptr++) = 0;
  65. pid = atoi (ptr);
  66. while (*ptr && *ptr != ':')
  67. ptr++;
  68. protocol_version = *ptr ? atoi (ptr + 1) : 0;
  69. if (protocol_version != 1)
  70. {
  71. DEBUG ("GPG agent protocol version '%d' not supported",
  72. protocol_version);
  73. free (infostr);
  74. return gpg_error (GPG_ERR_NO_AGENT);
  75. }
  76. err = assuan_socket_connect (ctx_r, infostr, pid);
  77. free (infostr);
  78. if (err)
  79. {
  80. DEBUG ("cannot connect to GPG agent: %s", gpg_strerror (err));
  81. return gpg_error (GPG_ERR_NO_AGENT);
  82. }
  83. return 0;
  84. }
  85. /* Send a simple command to the agent. */
  86. static gpg_error_t
  87. agent_simple_cmd (assuan_context_t ctx, const char *fmt, ...)
  88. {
  89. gpg_error_t err;
  90. char *optstr;
  91. va_list arg;
  92. int res;
  93. va_start (arg, fmt);
  94. res = vasprintf (&optstr, fmt, arg);
  95. va_end (arg);
  96. if (res < 0)
  97. return gpg_error_from_errno (errno);
  98. err = assuan_transact (ctx, optstr, NULL, NULL, NULL, NULL, NULL, NULL);
  99. if (err)
  100. DEBUG ("gpg-agent command '%s' failed: %s", optstr, gpg_strerror (err));
  101. free (optstr);
  102. return err;
  103. }
  104. /* Configure the GPG agent at connection CTX. */
  105. static gpg_error_t
  106. agent_configure (assuan_context_t ctx)
  107. {
  108. gpg_error_t err = 0;
  109. char *dft_display = NULL;
  110. char *dft_ttyname = NULL;
  111. char *dft_ttytype = NULL;
  112. #if defined(HAVE_SETLOCALE) && (defined(LC_CTYPE) || defined(LC_MESSAGES))
  113. char *old_lc = NULL;
  114. char *dft_lc = NULL;
  115. #endif
  116. err = agent_simple_cmd (ctx, "RESET");
  117. if (err)
  118. return err;
  119. /* Set up display, terminal and locale options. */
  120. dft_display = getenv ("DISPLAY");
  121. if (dft_display)
  122. err = agent_simple_cmd (ctx, "OPTION display=%s", dft_display);
  123. if (err)
  124. return err;
  125. dft_ttyname = getenv ("GPG_TTY");
  126. if ((!dft_ttyname || !*dft_ttyname) && ttyname (0))
  127. dft_ttyname = ttyname (0);
  128. if (!dft_ttyname)
  129. return 0;
  130. err = agent_simple_cmd (ctx, "OPTION ttyname=%s", dft_ttyname);
  131. if (err)
  132. return err;
  133. dft_ttytype = getenv ("TERM");
  134. if (dft_ttytype)
  135. err = agent_simple_cmd (ctx, "OPTION ttytype=%s", dft_ttytype);
  136. if (err)
  137. return err;
  138. #if defined(HAVE_SETLOCALE) && defined(LC_CTYPE)
  139. old_lc = setlocale (LC_CTYPE, NULL);
  140. if (old_lc)
  141. {
  142. old_lc = strdup (old_lc);
  143. if (!old_lc)
  144. return gpg_error_from_errno (errno);
  145. }
  146. dft_lc = setlocale (LC_CTYPE, "");
  147. if (dft_lc)
  148. err = agent_simple_cmd ("OPTION lc-ctype=%s", dft_lc);
  149. if (old_lc)
  150. {
  151. setlocale (LC_CTYPE, old_lc);
  152. free (old_lc);
  153. }
  154. #endif
  155. if (err)
  156. return err;
  157. #if defined(HAVE_SETLOCALE) && defined(LC_MESSAGES)
  158. old_lc = setlocale (LC_MESSAGES, NULL);
  159. if (old_lc)
  160. {
  161. old_lc = strdup (old_lc);
  162. if (!old_lc)
  163. err = gpg_error_from_errno (errno);
  164. }
  165. dft_lc = setlocale (LC_MESSAGES, "");
  166. if (dft_lc)
  167. err = agent_simple_cmd ("OPTION lc-messages=%s", dft_lc);
  168. if (old_lc)
  169. {
  170. setlocale (LC_MESSAGES, old_lc);
  171. free (old_lc);
  172. }
  173. #endif
  174. return err;
  175. }
  176. /* Try to connect to the agent via socket. Handle the server's
  177. initial greeting. */
  178. gpg_error_t
  179. scute_agent_initialize (void)
  180. {
  181. gpg_error_t err = 0;
  182. if (agent_ctx)
  183. {
  184. DEBUG ("GPG Agent connection already established");
  185. return 0;
  186. }
  187. err = agent_connect (&agent_ctx);
  188. if (err)
  189. return err;
  190. err = agent_configure (agent_ctx);
  191. if (err)
  192. scute_agent_finalize ();
  193. return err;
  194. }
  195. /* Return a new malloced string by unescaping the string S. Escaping
  196. is percent escaping and '+'/space mapping. A binary nul will
  197. silently be replaced by a 0xFF. Function returns NULL to indicate
  198. an out of memory status. */
  199. static char *
  200. unescape_status_string (const unsigned char *src)
  201. {
  202. char *buffer;
  203. char *dst;
  204. buffer = malloc (strlen (src) + 1);
  205. if (!buffer)
  206. return NULL;
  207. dst = buffer;
  208. while (*src)
  209. {
  210. if (*src == '%' && src[1] && src[2])
  211. {
  212. src++;
  213. *dst = xtoi_2 (src);
  214. if (*dst == '\0')
  215. *dst = '\xff';
  216. dst++;
  217. src += 2;
  218. }
  219. else if (*src == '+')
  220. {
  221. *(dst++) = ' ';
  222. src++;
  223. }
  224. else
  225. *(dst++) = *(src++);
  226. }
  227. *dst = 0;
  228. return buffer;
  229. }
  230. /* Take a 20 byte hexencoded string and put it into the the provided
  231. 20 byte buffer FPR in binary format. Returns true if successful,
  232. and false otherwise. */
  233. static int
  234. unhexify_fpr (const char *hexstr, unsigned char *fpr)
  235. {
  236. const char *src;
  237. int cnt;
  238. /* Check for invalid or wrong length. */
  239. for (src = hexstr, cnt = 0; hexdigitp (src); src++, cnt++)
  240. ;
  241. if ((*src && !spacep (src)) || (cnt != 40))
  242. return 0;
  243. cnt /= 2;
  244. for (src = hexstr, cnt = 0; *src && !spacep (src); src += 2, cnt++)
  245. fpr[cnt] = xtoi_2 (src);
  246. return 1;
  247. }
  248. /* Take the serial number from LINE and return it verbatim in a newly
  249. allocated string. We make sure that only hex characters are
  250. returned. */
  251. static char *
  252. store_serialno (const char *line)
  253. {
  254. const char *src;
  255. char *ptr;
  256. for (src = line; hexdigitp (src); src++)
  257. ;
  258. ptr = malloc (src + 1 - line);
  259. if (ptr)
  260. {
  261. memcpy (ptr, line, src - line);
  262. ptr[src - line] = 0;
  263. }
  264. return ptr;
  265. }
  266. /* Release the card info structure INFO. */
  267. void
  268. scute_agent_release_card_info (struct agent_card_info_s *info)
  269. {
  270. if (!info)
  271. return;
  272. free (info->serialno);
  273. free (info->disp_name);
  274. free (info->disp_lang);
  275. free (info->pubkey_url);
  276. free (info->login_data);
  277. memset (info, 0, sizeof (*info));
  278. }
  279. /* FIXME: We are not returning out of memory errors. */
  280. static gpg_error_t
  281. learn_status_cb (void *opaque, const char *line)
  282. {
  283. struct agent_card_info_s *parm = opaque;
  284. const char *keyword = line;
  285. int keywordlen;
  286. int i;
  287. for (keywordlen = 0; *line && !spacep (line); line++, keywordlen++)
  288. ;
  289. while (spacep (line))
  290. line++;
  291. if (keywordlen == 8 && !memcmp (keyword, "SERIALNO", keywordlen))
  292. {
  293. if (parm->serialno)
  294. free (parm->serialno);
  295. parm->serialno = store_serialno (line);
  296. }
  297. else if (keywordlen == 9 && !memcmp (keyword, "DISP-NAME", keywordlen))
  298. {
  299. if (parm->disp_name)
  300. free (parm->disp_name);
  301. parm->disp_name = unescape_status_string (line);
  302. }
  303. else if (keywordlen == 9 && !memcmp (keyword, "DISP-LANG", keywordlen))
  304. {
  305. if (parm->disp_lang)
  306. free (parm->disp_lang);
  307. parm->disp_lang = unescape_status_string (line);
  308. }
  309. else if (keywordlen == 8 && !memcmp (keyword, "DISP-SEX", keywordlen))
  310. {
  311. parm->disp_sex = *line == '1'? 1 : *line == '2' ? 2: 0;
  312. }
  313. else if (keywordlen == 10 && !memcmp (keyword, "PUBKEY-URL", keywordlen))
  314. {
  315. if (parm->pubkey_url)
  316. free (parm->pubkey_url);
  317. parm->pubkey_url = unescape_status_string (line);
  318. }
  319. else if (keywordlen == 10 && !memcmp (keyword, "LOGIN-DATA", keywordlen))
  320. {
  321. if (parm->login_data)
  322. free (parm->login_data);
  323. parm->login_data = unescape_status_string (line);
  324. }
  325. else if (keywordlen == 11 && !memcmp (keyword, "SIG-COUNTER", keywordlen))
  326. {
  327. parm->sig_counter = strtoul (line, NULL, 0);
  328. }
  329. else if (keywordlen == 10 && !memcmp (keyword, "CHV-STATUS", keywordlen))
  330. {
  331. char *p, *buf;
  332. buf = p = unescape_status_string (line);
  333. if (buf)
  334. {
  335. while (spacep (p))
  336. p++;
  337. parm->chv1_cached = atoi (p);
  338. while (*p && !spacep (p))
  339. p++;
  340. while (spacep (p))
  341. p++;
  342. for (i = 0; *p && i < 3; i++)
  343. {
  344. parm->chvmaxlen[i] = atoi (p);
  345. while (*p && !spacep (p))
  346. p++;
  347. while (spacep (p))
  348. p++;
  349. }
  350. for (i=0; *p && i < 3; i++)
  351. {
  352. parm->chvretry[i] = atoi (p);
  353. while (*p && !spacep (p))
  354. p++;
  355. while (spacep (p))
  356. p++;
  357. }
  358. free (buf);
  359. }
  360. }
  361. else if (keywordlen == 7 && !memcmp (keyword, "KEY-FPR", keywordlen))
  362. {
  363. int no = atoi (line);
  364. while (*line && !spacep (line))
  365. line++;
  366. while (spacep (line))
  367. line++;
  368. if (no == 1)
  369. parm->fpr1valid = unhexify_fpr (line, parm->fpr1);
  370. else if (no == 2)
  371. parm->fpr2valid = unhexify_fpr (line, parm->fpr2);
  372. else if (no == 3)
  373. parm->fpr3valid = unhexify_fpr (line, parm->fpr3);
  374. }
  375. else if (keywordlen == 6 && !memcmp (keyword, "CA-FPR", keywordlen))
  376. {
  377. int no = atoi (line);
  378. while (*line && !spacep (line))
  379. line++;
  380. while (spacep (line))
  381. line++;
  382. if (no == 1)
  383. parm->cafpr1valid = unhexify_fpr (line, parm->cafpr1);
  384. else if (no == 2)
  385. parm->cafpr2valid = unhexify_fpr (line, parm->cafpr2);
  386. else if (no == 3)
  387. parm->cafpr3valid = unhexify_fpr (line, parm->cafpr3);
  388. }
  389. else if (keywordlen == 11 && !memcmp (keyword, "KEYPAIRINFO", keywordlen))
  390. {
  391. const char *grip = line;
  392. while (*line && !spacep (line))
  393. line++;
  394. if (line - grip == 40)
  395. {
  396. while (spacep (line))
  397. line++;
  398. if (!memcmp (line, "OPENPGP.", 8))
  399. {
  400. int no;
  401. line += 8;
  402. no = atoi (line);
  403. if (no == 1)
  404. {
  405. memcpy (parm->grip1, grip, 40);
  406. parm->grip1valid = 1;
  407. }
  408. else if (no == 2)
  409. {
  410. memcpy (parm->grip2, grip, 40);
  411. parm->grip2valid = 1;
  412. }
  413. else if (no == 3)
  414. {
  415. memcpy (parm->grip3, grip, 40);
  416. parm->grip3valid = 1;
  417. }
  418. }
  419. }
  420. }
  421. return 0;
  422. }
  423. /* Call the agent to learn about a smartcard. */
  424. gpg_error_t
  425. scute_agent_learn (struct agent_card_info_s *info)
  426. {
  427. gpg_error_t err;
  428. memset (info, 0, sizeof (*info));
  429. err = assuan_transact (agent_ctx, "LEARN --send",
  430. NULL, NULL, NULL, NULL, learn_status_cb, info);
  431. return err;
  432. }
  433. static gpg_error_t
  434. read_status_cb (void *opaque, const void *buffer, size_t length)
  435. {
  436. char *flag = opaque;
  437. if (length == 0)
  438. *flag = 'r';
  439. else
  440. *flag = *((char *) buffer);
  441. return 0;
  442. }
  443. /* Check the agent status. This returns 0 if a token is present,
  444. GPG_ERR_CARD_REMOVED if no token is present, and an error code
  445. otherwise. */
  446. gpg_error_t
  447. scute_agent_check_status (void)
  448. {
  449. gpg_error_t err;
  450. char flag = '-';
  451. err = assuan_transact (agent_ctx, "SCD GETINFO status",
  452. read_status_cb, &flag, NULL, NULL, NULL, NULL);
  453. if (err)
  454. return err;
  455. if (flag == 'r')
  456. return gpg_error (GPG_ERR_CARD_REMOVED);
  457. return 0;
  458. }
  459. #define MAX_SIGNATURE_LEN 256
  460. struct signature
  461. {
  462. unsigned char data[MAX_SIGNATURE_LEN];
  463. int len;
  464. };
  465. static gpg_error_t
  466. pksign_cb (void *opaque, const void *buffer, size_t length)
  467. {
  468. struct signature *sig = opaque;
  469. if (sig->len + length > MAX_SIGNATURE_LEN)
  470. return gpg_error (GPG_ERR_BAD_DATA);
  471. memcpy (&sig->data[sig->len], buffer, length);
  472. sig->len += length;
  473. return 0;
  474. }
  475. #define SIG_PREFIX "(7:sig-val(3:rsa(1:s128:"
  476. #define SIG_PREFIX_LEN (sizeof (SIG_PREFIX) - 1)
  477. #define SIG_POSTFIX ")))"
  478. #define SIG_POSTFIX_LEN (sizeof (SIG_POSTFIX) - 1)
  479. #define SIG_LEN 128
  480. /* Call the agent to learn about a smartcard. */
  481. gpg_error_t
  482. scute_agent_sign (char *grip, unsigned char *data, int len,
  483. unsigned char *sig_result, unsigned int *sig_len)
  484. {
  485. char cmd[150];
  486. gpg_error_t err;
  487. #define MAX_DATA_LEN 36
  488. unsigned char pretty_data[2 * MAX_DATA_LEN + 1];
  489. int i;
  490. struct signature sig;
  491. sig.len = 0;
  492. if (sig_len == NULL)
  493. return gpg_error (GPG_ERR_INV_ARG);
  494. if (sig_result == NULL)
  495. {
  496. *sig_len = SIG_LEN;
  497. return 0;
  498. }
  499. if (len > MAX_DATA_LEN)
  500. return gpg_error (GPG_ERR_INV_ARG);
  501. if (grip == NULL || sig_result == NULL || *sig_len < SIG_LEN)
  502. return gpg_error (GPG_ERR_INV_ARG);
  503. snprintf (cmd, sizeof (cmd), "SIGKEY %s", grip);
  504. err = assuan_transact (agent_ctx, cmd, NULL, NULL, NULL, NULL, NULL, NULL);
  505. if (err)
  506. return err;
  507. for (i = 0; i < len; i++)
  508. sprintf (&pretty_data[2 * i], "%02X", data[i]);
  509. pretty_data[2 * len] = '\0';
  510. snprintf (cmd, sizeof (cmd), "sethash --hash=tls-md5sha1 %s", pretty_data);
  511. err = assuan_transact (agent_ctx, cmd, NULL, NULL, NULL, NULL, NULL, NULL);
  512. if (err)
  513. return err;
  514. err = assuan_transact (agent_ctx, "PKSIGN",
  515. pksign_cb, &sig, NULL, NULL, NULL, NULL);
  516. if (err)
  517. return err;
  518. if (sig.len != SIG_PREFIX_LEN + SIG_LEN + SIG_POSTFIX_LEN)
  519. return gpg_error (GPG_ERR_BAD_SIGNATURE);
  520. if (memcmp (sig.data, SIG_PREFIX, SIG_PREFIX_LEN))
  521. return gpg_error (GPG_ERR_BAD_SIGNATURE);
  522. if (memcmp (sig.data + sig.len - SIG_POSTFIX_LEN,
  523. SIG_POSTFIX, SIG_POSTFIX_LEN))
  524. return gpg_error (GPG_ERR_BAD_SIGNATURE);
  525. memcpy (sig_result, sig.data + SIG_PREFIX_LEN, SIG_LEN);
  526. *sig_len = SIG_LEN;
  527. return 0;
  528. }
  529. /* Determine if FPR is trusted. */
  530. gpg_error_t scute_agent_is_trusted (char *fpr, bool *is_trusted)
  531. {
  532. gpg_error_t err;
  533. bool trusted = false;
  534. char cmd[150];
  535. snprintf (cmd, sizeof (cmd), "ISTRUSTED %s", fpr);
  536. err = assuan_transact (agent_ctx, cmd, NULL, NULL, NULL, NULL, NULL, NULL);
  537. if (err && gpg_err_code (err) != GPG_ERR_NOT_TRUSTED)
  538. return err;
  539. else if (!err)
  540. trusted = true;
  541. *is_trusted = trusted;
  542. return 0;
  543. }
  544. void
  545. scute_agent_finalize (void)
  546. {
  547. if (!agent_ctx)
  548. {
  549. DEBUG ("no GPG Agent connection established");
  550. return;
  551. }
  552. assuan_disconnect (agent_ctx);
  553. agent_ctx = NULL;
  554. }