1 /* gpg-pair-tool.c - The tool to run the pairing protocol.
2 * Copyright (C) 2018 g10 Code GmbH
3 *
4 * This file is part of GnuPG.
5 *
6 * This file is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License as
8 * published by the Free Software Foundation; either version 2.1 of
9 * the License, or (at your option) any later version.
10 *
11 * This file is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program; if not, see <https://www.gnu.org/licenses/>.
18 * SPDX-License-Identifier: LGPL-2.1-or-later
19 */
20
21 /* Protocol:
22 *
23 * Initiator Responder
24 * | |
25 * | COMMIT |
26 * |-------------------->|
27 * | |
28 * | DHPART1 |
29 * |<--------------------|
30 * | |
31 * | DHPART2 |
32 * |-------------------->|
33 * | |
34 * | CONFIRM |
35 * |<--------------------|
36 * | |
37 *
38 * The initiator creates a keypar (PKi,SKi) and sends this COMMIT
39 * message to the responder:
40 *
41 * 7 byte Magic, value: "GPG-pa1"
42 * 1 byte MessageType, value 1 (COMMIT)
43 * 8 byte SessionId, value: 8 random bytes
44 * 1 byte Realm, value 1
45 * 2 byte reserved, value 0
46 * 5 byte ExpireTime, value: seconds since Epoch as an unsigned int.
47 * 32 byte Hash(PKi)
48 *
49 * The initiator also needs to locally store the sessionid, the realm,
50 * the expiration time, the keypair and a hash of the entire message
51 * sent.
52 *
53 * The responder checks that the received message has not expired and
54 * stores sessionid, realm, expiretime and the Hash(PKi). The
55 * Responder then creates and locally stores its own keypair (PKr,SKr)
56 * and sends the DHPART1 message back:
57 *
58 * 7 byte Magic, value: "GPG-pa1"
59 * 1 byte MessageType, value 2 (DHPART1)
60 * 8 byte SessionId from COMMIT message
61 * 32 byte PKr
62 * 32 byte Hash(Hash(COMMIT) || DHPART1[0..47])
63 *
64 * Note that Hash(COMMIT) is the hash over the entire received COMMIT
65 * message. DHPART1[0..47] are the first 48 bytes of the created
66 * DHPART1 message.
67 *
68 * The Initiator receives the DHPART1 message and checks that the hash
69 * matches. Although this hash is easily malleable it is later in the
70 * protocol used to assert the integrity of all messages. The
71 * Initiator then computes the shared master secret from its SKi and
72 * the received PKr. Using this master secret several keys are
73 * derived:
74 *
75 * - HMACi-key using the label "GPG-pa1-HMACi-key".
76 * - SYMx-key using the label "GPG-pa1-SYMx-key"
77 *
78 * For details on the KDF see the implementation of the function kdf.
79 * The master secret is stored securily in the local state. The
80 * DHPART2 message is then created and send to the Responder:
81 *
82 * 7 byte Magic, value: "GPG-pa1"
83 * 1 byte MessageType, value 3 (DHPART2)
84 * 8 byte SessionId from COMMIT message
85 * 32 byte PKi
86 * 32 byte MAC(HMACi-key, Hash(DHPART1) || DHPART2[0..47] || SYMx-key)
87 *
88 * The Responder receives the DHPART2 message and checks that the hash
89 * of the received PKi matches the Hash(PKi) value as received earlier
90 * with the COMMIT message. The Responder now also computes the
91 * shared master secret from its SKr and the received PKi and derives
92 * the keys:
93 *
94 * - HMACi-key using the label "GPG-pa1-HMACi-key".
95 * - HMACr-key using the label "GPG-pa1-HMACr-key".
96 * - SYMx-key using the label "GPG-pa1-SYMx-key"
97 * - SAS using the label "GPG-pa1-SAS"
98 *
99 * With these keys the MAC from the received DHPART2 message is
100 * checked. On success a SAS is displayed to the user and a CONFIRM
101 * message send back:
102 *
103 * 7 byte Magic, value: "GPG-pa1"
104 * 1 byte MessageType, value 4 (CONFIRM)
105 * 8 byte SessionId from COMMIT message
106 * 32 byte MAC(HMACr-key, Hash(DHPART2) || CONFIRM[0..15] || SYMx-key)
107 *
108 * The Initiator receives this CONFIRM message, gets the master shared
109 * secrey from its local state and derives the keys. It checks the
110 * the MAC in the received CONFIRM message and ask the user to enter
111 * the SAS as displayed by the responder. Iff the SAS matches the
112 * master key is flagged as confirmed and the Initiator may now use a
113 * derived key to send encrypted data to the Responder.
114 *
115 * In case the Responder also needs to send encrypted data we need to
116 * introduce another final message to tell the responder that the
117 * Initiator validated the SAS.
118 *
119 * TODO: Encrypt the state files using a key stored in gpg-agent's cache.
120 *
121 */
122
123 #include <config.h>
124
125 #include <stdio.h>
126 #include <stdlib.h>
127 #include <string.h>
128 #include <sys/types.h>
129 #include <sys/stat.h>
130 #include <unistd.h>
131 #include <dirent.h>
132 #include <stdarg.h>
133
134 #include "../common/util.h"
135 #include "../common/status.h"
136 #include "../common/i18n.h"
137 #include "../common/sysutils.h"
138 #include "../common/init.h"
139 #include "../common/name-value.h"
140
141 /* Constants to identify the commands and options. */
142 enum cmd_and_opt_values
143 {
144 aNull = 0,
145
146 oQuiet = 'q',
147 oVerbose = 'v',
148 oOutput = 'o',
149 oArmor = 'a',
150
151 aInitiate = 400,
152 aRespond = 401,
153 aGet = 402,
154 aCleanup = 403,
155
156 oDebug = 500,
157 oStatusFD,
158 oHomedir,
159 oSAS,
160
161 oDummy
162 };
163
164
165 /* The list of commands and options. */
166 static gpgrt_opt_t opts[] = {
167 ARGPARSE_group (300, ("@Commands:\n ")),
168
169 ARGPARSE_c (aInitiate, "initiate", N_("initiate a pairing request")),
170 ARGPARSE_c (aRespond, "respond", N_("respond to a pairing request")),
171 ARGPARSE_c (aGet, "get", N_("return the keys")),
172 ARGPARSE_c (aCleanup, "cleanup", N_("remove expired states etc.")),
173
174 ARGPARSE_group (301, ("@\nOptions:\n ")),
175
176 ARGPARSE_s_n (oVerbose, "verbose", N_("verbose")),
177 ARGPARSE_s_n (oQuiet, "quiet", N_("be somewhat more quiet")),
178 ARGPARSE_s_n (oArmor, "armor", N_("create ascii armored output")),
179 ARGPARSE_s_s (oSAS, "sas", N_("|SAS|the SAS as shown by the peer")),
180 ARGPARSE_s_s (oDebug, "debug", "@"),
181 ARGPARSE_s_s (oOutput, "output", N_("|FILE|write the request to FILE")),
182 ARGPARSE_s_i (oStatusFD, "status-fd", N_("|FD|write status info to this FD")),
183
184 ARGPARSE_s_s (oHomedir, "homedir", "@"),
185
186 ARGPARSE_end ()
187 };
188
189
190 /* We keep all global options in the structure OPT. */
191 static struct
192 {
193 int verbose;
194 unsigned int debug;
195 int quiet;
196 int armor;
197 const char *output;
198 estream_t statusfp;
199 unsigned int ttl;
200 const char *sas;
201 } opt;
202
203
204 /* Debug values and macros. */
205 #define DBG_MESSAGE_VALUE 2 /* Debug the messages. */
206 #define DBG_CRYPTO_VALUE 4 /* Debug low level crypto. */
207 #define DBG_MEMORY_VALUE 32 /* Debug memory allocation stuff. */
208
209 #define DBG_MESSAGE (opt.debug & DBG_MESSAGE_VALUE)
210 #define DBG_CRYPTO (opt.debug & DBG_CRYPTO_VALUE)
211
212
213 /* The list of supported debug flags. */
214 static struct debug_flags_s debug_flags [] =
215 {
216 { DBG_MESSAGE_VALUE, "message" },
217 { DBG_CRYPTO_VALUE , "crypto" },
218 { DBG_MEMORY_VALUE , "memory" },
219 { 0, NULL }
220 };
221
222
223 /* The directory name below the cache dir to store paring states. */
224 #define PAIRING_STATE_DIR "state"
225
226 /* Message types. */
227 #define MSG_TYPE_COMMIT 1
228 #define MSG_TYPE_DHPART1 2
229 #define MSG_TYPE_DHPART2 3
230 #define MSG_TYPE_CONFIRM 4
231
232
233 /* Realm values. */
234 #define REALM_STANDARD 1
235
236
237
238
239 /* Local prototypes. */
240 static void wrong_args (const char *text) GPGRT_ATTR_NORETURN;
241 static void xnvc_set_printf (nvc_t nvc, const char *name, const char *format,
242 ...) GPGRT_ATTR_PRINTF(3,4);
243 static void *hash_data (void *result, size_t resultsize,
244 ...) GPGRT_ATTR_SENTINEL(0);
245 static void *hmac_data (void *result, size_t resultsize,
246 const unsigned char *key, size_t keylen,
247 ...) GPGRT_ATTR_SENTINEL(0);
248
249
250 static gpg_error_t command_initiate (void);
251 static gpg_error_t command_respond (void);
252 static gpg_error_t command_cleanup (void);
253 static gpg_error_t command_get (const char *sessionidstr);
254
255
256
257
258 /* Print usage information and provide strings for help. */
259 static const char *
my_strusage(int level)260 my_strusage( int level )
261 {
262 const char *p;
263
264 switch (level)
265 {
266 case 9: p = "LGPL-2.1-or-later"; break;
267 case 11: p = "gpg-pair-tool"; break;
268 case 12: p = "@GNUPG@"; break;
269 case 13: p = VERSION; break;
270 case 14: p = GNUPG_DEF_COPYRIGHT_LINE; break;
271 case 17: p = PRINTABLE_OS_NAME; break;
272 case 19: p = _("Please report bugs to <@EMAIL@>.\n"); break;
273
274 case 1:
275 case 40:
276 p = ("Usage: gpg-pair-tool [command] [options] [args] (-h for help)");
277 break;
278 case 41:
279 p = ("Syntax: gpg-pair-tool [command] [options] [args]\n"
280 "Client to run the pairing protocol\n");
281 break;
282
283 default: p = NULL; break;
284 }
285 return p;
286 }
287
288
289 static void
wrong_args(const char * text)290 wrong_args (const char *text)
291 {
292 es_fprintf (es_stderr, _("usage: %s [options] %s\n"),
293 gpgrt_strusage (11), text);
294 exit (2);
295 }
296
297
298 /* Set the status FD. */
299 static void
set_status_fd(int fd)300 set_status_fd (int fd)
301 {
302 static int last_fd = -1;
303
304 if (fd != -1 && last_fd == fd)
305 return;
306
307 if (opt.statusfp && opt.statusfp != es_stdout && opt.statusfp != es_stderr)
308 es_fclose (opt.statusfp);
309 opt.statusfp = NULL;
310 if (fd == -1)
311 return;
312
313 if (fd == 1)
314 opt.statusfp = es_stdout;
315 else if (fd == 2)
316 opt.statusfp = es_stderr;
317 else
318 opt.statusfp = es_fdopen (fd, "w");
319 if (!opt.statusfp)
320 {
321 log_fatal ("can't open fd %d for status output: %s\n",
322 fd, gpg_strerror (gpg_error_from_syserror ()));
323 }
324 last_fd = fd;
325 }
326
327
328 /* Write a status line with code NO followed by the output of the
329 * printf style FORMAT. The caller needs to make sure that LFs and
330 * CRs are not printed. */
331 static void
write_status(int no,const char * format,...)332 write_status (int no, const char *format, ...)
333 {
334 va_list arg_ptr;
335
336 if (!opt.statusfp)
337 return; /* Not enabled. */
338
339 es_fputs ("[GNUPG:] ", opt.statusfp);
340 es_fputs (get_status_string (no), opt.statusfp);
341 if (format)
342 {
343 es_putc (' ', opt.statusfp);
344 va_start (arg_ptr, format);
345 es_vfprintf (opt.statusfp, format, arg_ptr);
346 va_end (arg_ptr);
347 }
348 es_putc ('\n', opt.statusfp);
349 }
350
351
352
353 /* gpg-pair-tool main. */
354 int
main(int argc,char ** argv)355 main (int argc, char **argv)
356 {
357 gpg_error_t err;
358 gpgrt_argparse_t pargs = { &argc, &argv };
359 enum cmd_and_opt_values cmd = 0;
360
361 opt.ttl = 8*3600; /* Default to 8 hours. */
362
363 gnupg_reopen_std ("gpg-pair-tool");
364 gpgrt_set_strusage (my_strusage);
365 log_set_prefix ("gpg-pair-tool", GPGRT_LOG_WITH_PREFIX);
366
367 /* Make sure that our subsystems are ready. */
368 i18n_init();
369 init_common_subsystems (&argc, &argv);
370
371 /* Parse the command line. */
372 while (gpgrt_argparse (NULL, &pargs, opts))
373 {
374 switch (pargs.r_opt)
375 {
376 case oQuiet: opt.quiet = 1; break;
377 case oVerbose: opt.verbose++; break;
378 case oArmor: opt.armor = 1; break;
379
380 case oDebug:
381 if (parse_debug_flag (pargs.r.ret_str, &opt.debug, debug_flags))
382 {
383 pargs.r_opt = ARGPARSE_INVALID_ARG;
384 pargs.err = ARGPARSE_PRINT_ERROR;
385 }
386 break;
387
388 case oOutput:
389 opt.output = pargs.r.ret_str;
390 break;
391
392 case oStatusFD:
393 set_status_fd (translate_sys2libc_fd_int (pargs.r.ret_int, 1));
394 break;
395
396 case oHomedir:
397 gnupg_set_homedir (pargs.r.ret_str);
398 break;
399
400 case oSAS:
401 opt.sas = pargs.r.ret_str;
402 break;
403
404 case aInitiate:
405 case aRespond:
406 case aGet:
407 case aCleanup:
408 if (cmd && cmd != pargs.r_opt)
409 log_error (_("conflicting commands\n"));
410 else
411 cmd = pargs.r_opt;
412 break;
413
414 default: pargs.err = ARGPARSE_PRINT_WARNING; break;
415 }
416 }
417 gpgrt_argparse (NULL, &pargs, NULL); /* Release internal state. */
418
419 /* Print a warning if an argument looks like an option. */
420 if (!opt.quiet && !(pargs.flags & ARGPARSE_FLAG_STOP_SEEN))
421 {
422 int i;
423
424 for (i=0; i < argc; i++)
425 if (argv[i][0] == '-' && argv[i][1] == '-')
426 log_info (("NOTE: '%s' is not considered an option\n"), argv[i]);
427 }
428 gpgrt_argparse (NULL, &pargs, NULL); /* Free internal memory. */
429
430 if (opt.sas)
431 {
432 if (strlen (opt.sas) != 11
433 || !digitp (opt.sas+0) || !digitp (opt.sas+1) || !digitp (opt.sas+2)
434 || opt.sas[3] != '-'
435 || !digitp (opt.sas+4) || !digitp (opt.sas+5) || !digitp (opt.sas+6)
436 || opt.sas[7] != '-'
437 || !digitp (opt.sas+8) || !digitp (opt.sas+9) || !digitp (opt.sas+10))
438 log_error ("invalid formatted SAS\n");
439 }
440
441 /* Stop if any error, inclduing ARGPARSE_PRINT_WARNING, occurred. */
442 if (log_get_errorcount (0))
443 exit (2);
444
445 if (DBG_CRYPTO)
446 gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1|2);
447
448
449 /* Now run the requested command. */
450 switch (cmd)
451 {
452 case aInitiate:
453 if (argc)
454 wrong_args ("--initiate");
455 err = command_initiate ();
456 break;
457
458 case aRespond:
459 if (argc)
460 wrong_args ("--respond");
461 err = command_respond ();
462 break;
463
464 case aGet:
465 if (argc > 1)
466 wrong_args ("--respond [sessionid]");
467 err = command_get (argc? *argv:NULL);
468 break;
469
470 case aCleanup:
471 if (argc)
472 wrong_args ("--cleanup");
473 err = command_cleanup ();
474 break;
475
476 default:
477 gpgrt_usage (1);
478 err = 0;
479 break;
480 }
481
482 if (err)
483 write_status (STATUS_FAILURE, "- %u", err);
484 else if (log_get_errorcount (0))
485 write_status (STATUS_FAILURE, "- %u", GPG_ERR_GENERAL);
486 else
487 write_status (STATUS_SUCCESS, NULL);
488 return log_get_errorcount (0)? 1:0;
489 }
490
491
492
493 /* Wrapper around nvc_new which terminates in the error case. */
494 static nvc_t
xnvc_new(void)495 xnvc_new (void)
496 {
497 nvc_t c = nvc_new ();
498 if (!c)
499 log_fatal ("error creating NVC object: %s\n",
500 gpg_strerror (gpg_error_from_syserror ()));
501 return c;
502 }
503
504 /* Wrapper around nvc_set which terminates in the error case. */
505 static void
xnvc_set(nvc_t nvc,const char * name,const char * value)506 xnvc_set (nvc_t nvc, const char *name, const char *value)
507 {
508 gpg_error_t err = nvc_set (nvc, name, value);
509 if (err)
510 log_fatal ("error updating NVC object: %s\n", gpg_strerror (err));
511 }
512
513 /* Call vnc_set with (BUFFER, BUFLEN) converted to a hex string as
514 * value. Terminates in the error case. */
515 static void
xnvc_set_hex(nvc_t nvc,const char * name,const void * buffer,size_t buflen)516 xnvc_set_hex (nvc_t nvc, const char *name, const void *buffer, size_t buflen)
517 {
518 char *hex;
519
520 hex = bin2hex (buffer, buflen, NULL);
521 if (!hex)
522 xoutofcore ();
523 strlwr (hex);
524 xnvc_set (nvc, name, hex);
525 xfree (hex);
526 }
527
528 /* Call nvc_set with a value created from the string generated using
529 * the printf style FORMAT. Terminates in the error case. */
530 static void
xnvc_set_printf(nvc_t nvc,const char * name,const char * format,...)531 xnvc_set_printf (nvc_t nvc, const char *name, const char *format, ...)
532 {
533 va_list arg_ptr;
534 char *buffer;
535
536 va_start (arg_ptr, format);
537 if (gpgrt_vasprintf (&buffer, format, arg_ptr) < 0)
538 log_fatal ("estream_asprintf failed: %s\n",
539 gpg_strerror (gpg_error_from_syserror ()));
540 va_end (arg_ptr);
541 xnvc_set (nvc, name, buffer);
542 xfree (buffer);
543 }
544
545
546 /* Return the string for the first entry in NVC with NAME. If NAME is
547 * missing, an empty string is returned. The returned string is a
548 * pointer into NVC. */
549 static const char *
xnvc_get_string(nvc_t nvc,const char * name)550 xnvc_get_string (nvc_t nvc, const char *name)
551 {
552 nve_t item;
553
554 if (!nvc)
555 return "";
556 item = nvc_lookup (nvc, name);
557 if (!item)
558 return "";
559 return nve_value (item);
560 }
561
562
563
564 /* Return a string for MSGTYPE. */
565 const char *
msgtypestr(int msgtype)566 msgtypestr (int msgtype)
567 {
568 switch (msgtype)
569 {
570 case MSG_TYPE_COMMIT: return "Commit";
571 case MSG_TYPE_DHPART1: return "DHPart1";
572 case MSG_TYPE_DHPART2: return "DHPart2";
573 case MSG_TYPE_CONFIRM: return "Confirm";
574 }
575 return "?";
576 }
577
578
579 /* Private to {get,set}_session_id(). */
580 static struct {
581 int initialized;
582 unsigned char sessid[8];
583 } session_id;
584
585
586 /* Return the 8 octet session. */
587 static unsigned char *
get_session_id(void)588 get_session_id (void)
589 {
590 if (!session_id.initialized)
591 {
592 session_id.initialized = 1;
593 gcry_create_nonce (session_id.sessid, sizeof session_id.sessid);
594 }
595
596 return session_id.sessid;
597 }
598
599 static void
set_session_id(const void * sessid,size_t len)600 set_session_id (const void *sessid, size_t len)
601 {
602 log_assert (!session_id.initialized);
603 if (len > sizeof session_id.sessid)
604 len = sizeof session_id.sessid;
605 memcpy (session_id.sessid, sessid, len);
606 if (len < sizeof session_id.sessid)
607 memset (session_id.sessid+len, 0, sizeof session_id.sessid - len);
608 session_id.initialized = 1;
609 }
610
611 /* Return a string with the hexified session id. */
612 static const char *
get_session_id_hex(void)613 get_session_id_hex (void)
614 {
615 static char hexstr[16+1];
616
617 bin2hex (get_session_id (), 8, hexstr);
618 strlwr (hexstr);
619 return hexstr;
620 }
621
622
623 /* Return a fixed string with the directory used to store the state of
624 * pairings. On error a diagnostic is printed but the file name is
625 * returned anyway. It is expected that the expected failure of the
626 * following open is responsible for error handling. */
627 static const char *
get_pairing_statedir(void)628 get_pairing_statedir (void)
629 {
630 static char *fname;
631 gpg_error_t err = 0;
632 char *tmpstr;
633 struct stat statbuf;
634
635 if (fname)
636 return fname;
637
638 fname = make_filename (gnupg_homedir (), GNUPG_CACHE_DIR, NULL);
639 if (gnupg_stat (fname, &statbuf) && errno == ENOENT)
640 {
641 if (gnupg_mkdir (fname, "-rwx"))
642 {
643 err = gpg_error_from_syserror ();
644 log_error (_("can't create directory '%s': %s\n"),
645 fname, gpg_strerror (err) );
646 }
647 else if (!opt.quiet)
648 log_info (_("directory '%s' created\n"), fname);
649 }
650
651 tmpstr = make_filename (fname, PAIRING_STATE_DIR, NULL);
652 xfree (fname);
653 fname = tmpstr;
654 if (gnupg_stat (fname, &statbuf) && errno == ENOENT)
655 {
656 if (gnupg_mkdir (fname, "-rwx"))
657 {
658 if (!err)
659 {
660 err = gpg_error_from_syserror ();
661 log_error (_("can't create directory '%s': %s\n"),
662 fname, gpg_strerror (err) );
663 }
664 }
665 else if (!opt.quiet)
666 log_info (_("directory '%s' created\n"), fname);
667 }
668
669 return fname;
670 }
671
672
673 /* Open the pairing state file. SESSIONID is a 8 byte buffer with the
674 * session-id. If CREATE_FLAG is set the file is created and will
675 * always return a valid stream. If CREATE_FLAG is not set the file
676 * is opened for reading and writing. If the file does not exist NULL
677 * is return; in all other error cases the process is terminated. If
678 * R_FNAME is not NULL the name of the file is stored there and the
679 * caller needs to free it. */
680 static estream_t
open_pairing_state(const unsigned char * sessionid,int create_flag,char ** r_fname)681 open_pairing_state (const unsigned char *sessionid, int create_flag,
682 char **r_fname)
683 {
684 gpg_error_t err;
685 char *fname, *tmpstr;
686 estream_t fp;
687
688 /* The filename is the session id with a "pa1" suffix. Note that
689 * the state dir may eventually be used for other purposes as well
690 * and thus the suffix identifies that the file belongs to this
691 * tool. We use lowercase file names for no real reason. */
692 tmpstr = bin2hex (sessionid, 8, NULL);
693 if (!tmpstr)
694 xoutofcore ();
695 strlwr (tmpstr);
696 fname = xstrconcat (tmpstr, ".pa1", NULL);
697 xfree (tmpstr);
698 tmpstr = make_filename (get_pairing_statedir (), fname, NULL);
699 xfree (fname);
700 fname = tmpstr;
701
702 fp = es_fopen (fname, create_flag? "wbx,mode=-rw": "rb+,mode=-rw");
703 if (!fp)
704 {
705 err = gpg_error_from_syserror ();
706 if (create_flag)
707 {
708 /* We should always be able to create a file. Also we use a
709 * 64 bit session id, it is theoretically possible that such
710 * a session already exists. However, that is rare enough
711 * and thus the fatal error message should still be okay. */
712 log_fatal ("can't create '%s': %s\n", fname, gpg_strerror (err));
713 }
714 else if (gpg_err_code (err) == GPG_ERR_ENOENT)
715 {
716 /* That is an expected error; return NULL. */
717 }
718 else
719 {
720 log_fatal ("can't open '%s': %s\n", fname, gpg_strerror (err));
721 }
722 }
723
724 if (r_fname)
725 *r_fname = fname;
726 else
727 xfree (fname);
728
729 return fp;
730 }
731
732
733 /* Write the state to a possible new state file. */
734 static void
write_state(nvc_t state,int create_flag)735 write_state (nvc_t state, int create_flag)
736 {
737 gpg_error_t err;
738 char *fname = NULL;
739 estream_t fp;
740
741 fp = open_pairing_state (get_session_id (), create_flag, &fname);
742 log_assert (fp);
743
744 err = nvc_write (state, fp);
745 if (err)
746 {
747 es_fclose (fp);
748 gnupg_remove (fname);
749 log_fatal ("error writing '%s': %s\n", fname, gpg_strerror (err));
750 }
751
752 /* If we did not create the file, we need to truncate the file. */
753 if (!create_flag && ftruncate (es_fileno (fp), es_ftello (fp)))
754 {
755 err = gpg_error_from_syserror ();
756 log_fatal ("error truncating '%s': %s\n", fname, gpg_strerror (err));
757 }
758 if (es_ferror (fp) || es_fclose (fp))
759 {
760 err = gpg_error_from_syserror ();
761 es_fclose (fp);
762 gnupg_remove (fname);
763 log_fatal ("error writing '%s': %s\n", fname, gpg_strerror (err));
764 }
765 }
766
767
768 /* Read the state into a newly allocated state object and store that
769 * at R_STATE. If no state is available GPG_ERR_NOT_FOUND is returned
770 * and as with all errors NULL is tored at R_STATE. SESSIONID is an
771 * input with the 8 session id. */
772 static gpg_error_t
read_state(nvc_t * r_state)773 read_state (nvc_t *r_state)
774 {
775 gpg_error_t err;
776 char *fname = NULL;
777 estream_t fp;
778 nvc_t state = NULL;
779 nve_t item;
780 const char *value;
781 unsigned long expire;
782
783 *r_state = NULL;
784
785 fp = open_pairing_state (get_session_id (), 0, &fname);
786 if (!fp)
787 return gpg_error (GPG_ERR_NOT_FOUND);
788
789 err = nvc_parse (&state, NULL, fp);
790 if (err)
791 {
792 log_info ("failed to parse state file '%s': %s\n",
793 fname, gpg_strerror (err));
794 goto leave;
795 }
796
797 /* Check whether the state already expired. */
798 item = nvc_lookup (state, "Expires:");
799 if (!item)
800 {
801 log_info ("invalid state file '%s': %s\n",
802 fname, "field 'expire' not found");
803 goto leave;
804 }
805 value = nve_value (item);
806 if (!value || !(expire = strtoul (value, NULL, 10)))
807 {
808 log_info ("invalid state file '%s': %s\n",
809 fname, "field 'expire' has an invalid value");
810 goto leave;
811 }
812 if (expire <= gnupg_get_time ())
813 {
814 es_fclose (fp);
815 fp = NULL;
816 if (gnupg_remove (fname))
817 {
818 err = gpg_error_from_syserror ();
819 log_info ("failed to delete state file '%s': %s\n",
820 fname, gpg_strerror (err));
821 }
822 else if (opt.verbose)
823 log_info ("state file '%s' deleted\n", fname);
824 err = gpg_error (GPG_ERR_NOT_FOUND);
825 goto leave;
826 }
827
828 *r_state = state;
829 state = NULL;
830
831 leave:
832 nvc_release (state);
833 es_fclose (fp);
834 return err;
835 }
836
837
838 /* Send (MSG,MSGLEN) to the output device. */
839 static void
send_message(const unsigned char * msg,size_t msglen)840 send_message (const unsigned char *msg, size_t msglen)
841 {
842 gpg_error_t err;
843
844 if (opt.verbose)
845 log_info ("session %s: sending %s message\n",
846 get_session_id_hex (), msgtypestr (msg[7]));
847
848 if (DBG_MESSAGE)
849 log_printhex (msg, msglen, "send msg(%s):", msgtypestr (msg[7]));
850
851 /* FIXME: For now only stdout. */
852 if (opt.armor)
853 {
854 gpgrt_b64state_t state;
855
856 state = gpgrt_b64enc_start (es_stdout, "");
857 if (!state)
858 log_fatal ("error setting up base64 encoder: %s\n",
859 gpg_strerror (gpg_error_from_syserror ()));
860 err = gpgrt_b64enc_write (state, msg, msglen);
861 if (!err)
862 err = gpgrt_b64enc_finish (state);
863 if (err)
864 log_fatal ("error writing base64 to stdout: %s\n", gpg_strerror (err));
865 }
866 else
867 {
868 if (es_fwrite (msg, msglen, 1, es_stdout) != 1)
869 log_fatal ("error writing to stdout: %s\n",
870 gpg_strerror (gpg_error_from_syserror ()));
871 }
872 es_fputc ('\n', es_stdout);
873 }
874
875
876 /* Read a message from stdin and store it at the address (R_MSG,
877 * R_MSGLEN). This function detects armoring and removes it. On
878 * error NULL is stored at R_MSG, a diagnostic printed and an error
879 * code returned. The returned message has a proper message type and
880 * an appropriate length. The message type is stored at R_MSGTYPE and
881 * if a state is available it is stored at R_STATE. */
882 static gpg_error_t
read_message(unsigned char ** r_msg,size_t * r_msglen,int * r_msgtype,nvc_t * r_state)883 read_message (unsigned char **r_msg, size_t *r_msglen, int *r_msgtype,
884 nvc_t *r_state)
885 {
886 gpg_error_t err;
887 unsigned char msg[128]; /* max msg size is 80 but 107 with base64. */
888 size_t msglen;
889 size_t reqlen;
890
891 *r_msg = NULL;
892 *r_state = NULL;
893
894 es_setvbuf (es_stdin, NULL, _IONBF, 0);
895 es_set_binary (es_stdin);
896
897 if (es_read (es_stdin, msg, sizeof msg, &msglen))
898 {
899 err = gpg_error_from_syserror ();
900 log_error ("error reading from message: %s\n", gpg_strerror (err));
901 return err;
902 }
903
904 if (msglen > 4 && !memcmp (msg, "R1BH", 4))
905 {
906 /* This is base64 of the first 3 bytes. */
907 gpgrt_b64state_t state = gpgrt_b64dec_start (NULL);
908 if (!state)
909 log_fatal ("error setting up base64 decoder: %s\n",
910 gpg_strerror (gpg_error_from_syserror ()));
911 err = gpgrt_b64dec_proc (state, msg, msglen, &msglen);
912 gpgrt_b64dec_finish (state);
913 if (err)
914 {
915 log_error ("error decoding message: %s\n", gpg_strerror (err));
916 return err;
917 }
918 }
919
920 if (msglen < 16 || memcmp (msg, "GPG-pa1", 7))
921 {
922 log_error ("error parsing message: %s\n",
923 msglen? "invalid header":"empty message");
924 return gpg_error (GPG_ERR_INV_RESPONSE);
925 }
926 switch (msg[7])
927 {
928 case MSG_TYPE_COMMIT: reqlen = 56; break;
929 case MSG_TYPE_DHPART1: reqlen = 80; break;
930 case MSG_TYPE_DHPART2: reqlen = 80; break;
931 case MSG_TYPE_CONFIRM: reqlen = 48; break;
932
933 default:
934 log_error ("error parsing message: %s\n", "invalid message type");
935 return gpg_error (GPG_ERR_INV_RESPONSE);
936 }
937 if (msglen < reqlen)
938 {
939 log_error ("error parsing message: %s\n", "message too short");
940 return gpg_error (GPG_ERR_INV_RESPONSE);
941 }
942
943 if (DBG_MESSAGE)
944 log_printhex (msg, msglen, "recv msg(%s):", msgtypestr (msg[7]));
945
946 /* Note that we ignore any garbage at the end of a message. */
947 msglen = reqlen;
948
949 set_session_id (msg+8, 8);
950
951 if (opt.verbose)
952 log_info ("session %s: received %s message\n",
953 get_session_id_hex (), msgtypestr (msg[7]));
954
955 /* Read the state. */
956 err = read_state (r_state);
957 if (err && gpg_err_code (err) != GPG_ERR_NOT_FOUND)
958 return err;
959
960 *r_msg = xmalloc (msglen);
961 memcpy (*r_msg, msg, msglen);
962 *r_msglen = msglen;
963 *r_msgtype = msg[7];
964 return err;
965 }
966
967
968 /* Display the Short Authentication String (SAS). If WAIT is true the
969 * function waits until the user has entered the SAS as seen at the
970 * peer.
971 *
972 * To construct the SAS we take the 4 most significant octets of HASH,
973 * interpret them as a 32 bit big endian unsigned integer, divide that
974 * integer by 10^9 and take the remainder. The remainder is displayed
975 * as 3 groups of 3 decimal digits delimited by a hyphens. This gives
976 * a search space of close to 2^30 and is still easy to compare.
977 */
978 static gpg_error_t
display_sas(const unsigned char * hash,size_t hashlen,int wait)979 display_sas (const unsigned char *hash, size_t hashlen, int wait)
980 {
981 gpg_error_t err = 0;
982 unsigned long sas = 0;
983 char sasbuf[12];
984
985 log_assert (hashlen >= 4);
986
987 sas |= (unsigned long)hash[20] << 24;
988 sas |= (unsigned long)hash[21] << 16;
989 sas |= (unsigned long)hash[22] << 8;
990 sas |= (unsigned long)hash[23];
991 sas %= 1000000000ul;
992 snprintf (sasbuf, sizeof sasbuf, "%09lu", sas);
993 memmove (sasbuf+8, sasbuf+6, 3);
994 memmove (sasbuf+4, sasbuf+3, 3);
995 sasbuf[3] = sasbuf[7] = '-';
996 sasbuf[11] = 0;
997
998 if (wait)
999 log_info ("Please check the SAS:\n");
1000 else
1001 log_info ("Please note the SAS:\n");
1002 log_info ("\n");
1003 log_info (" %s\n", sasbuf);
1004 log_info ("\n");
1005
1006 if (wait)
1007 {
1008 if (!opt.sas || strcmp (sasbuf, opt.sas))
1009 err = gpg_error (GPG_ERR_NOT_CONFIRMED);
1010 else
1011 log_info ("SAS confirmed\n");
1012 }
1013
1014 if (err)
1015 log_info ("checking SAS failed: %s\n", gpg_strerror (err));
1016 return err;
1017 }
1018
1019
1020
1021 static gpg_error_t
create_dh_keypair(unsigned char * dh_secret,size_t dh_secret_len,unsigned char * dh_public,size_t dh_public_len)1022 create_dh_keypair (unsigned char *dh_secret, size_t dh_secret_len,
1023 unsigned char *dh_public, size_t dh_public_len)
1024 {
1025 gpg_error_t err;
1026 unsigned char *p;
1027
1028 /* We need a temporary buffer for the public key. Check the length
1029 * for the later memcpy. */
1030 if (dh_public_len < 32 || dh_secret_len < 32)
1031 return gpg_error (GPG_ERR_BUFFER_TOO_SHORT);
1032
1033 if (gcry_ecc_get_algo_keylen (GCRY_ECC_CURVE25519) > dh_public_len)
1034 return gpg_error (GPG_ERR_BUFFER_TOO_SHORT);
1035
1036 p = gcry_random_bytes (32, GCRY_VERY_STRONG_RANDOM);
1037 if (!p)
1038 return gpg_error_from_syserror ();
1039
1040 memcpy (dh_secret, p, 32);
1041 xfree (p);
1042
1043 err = gcry_ecc_mul_point (GCRY_ECC_CURVE25519, dh_public, dh_secret, NULL);
1044 if (err)
1045 return err;
1046
1047 if (DBG_CRYPTO)
1048 {
1049 log_printhex (dh_secret, 32, "DH secret:");
1050 log_printhex (dh_public, 32, "DH public:");
1051 }
1052
1053 return 0;
1054 }
1055
1056
1057 /* SHA256 the data given as varargs tuples of (const void*, size_t)
1058 * and store the result in RESULT. The end of the list is indicated
1059 * by a NULL element in a tuple. RESULTLEN gives the length of the
1060 * RESULT buffer which must be at least 32. Note that the second item
1061 * of the tuple is the length and it is a size_t. */
1062 static void *
hash_data(void * result,size_t resultsize,...)1063 hash_data (void *result, size_t resultsize, ...)
1064 {
1065 va_list arg_ptr;
1066 gpg_error_t err;
1067 gcry_md_hd_t hd;
1068 const void *data;
1069 size_t datalen;
1070
1071 log_assert (resultsize >= 32);
1072
1073 err = gcry_md_open (&hd, GCRY_MD_SHA256, 0);
1074 if (err)
1075 log_fatal ("error creating a Hash handle: %s\n", gpg_strerror (err));
1076 /* log_printhex ("", 0, "Hash-256:"); */
1077
1078 va_start (arg_ptr, resultsize);
1079 while ((data = va_arg (arg_ptr, const void *)))
1080 {
1081 datalen = va_arg (arg_ptr, size_t);
1082 /* log_printhex (data, datalen, " data:"); */
1083 gcry_md_write (hd, data, datalen);
1084 }
1085 va_end (arg_ptr);
1086
1087 memcpy (result, gcry_md_read (hd, 0), 32);
1088 /* log_printhex (result, 32, " result:"); */
1089
1090 gcry_md_close (hd);
1091
1092 return result;
1093 }
1094
1095
1096 /* HMAC-SHA256 the data given as varargs tuples of (const void*,
1097 * size_t) using (KEYLEN,KEY) and store the result in RESULT. The end
1098 * of the list is indicated by a NULL element in a tuple. RESULTLEN
1099 * gives the length of the RESULT buffer which must be at least 32.
1100 * Note that the second item of the tuple is the length and it is a
1101 * size_t. */
1102 static void *
hmac_data(void * result,size_t resultsize,const unsigned char * key,size_t keylen,...)1103 hmac_data (void *result, size_t resultsize,
1104 const unsigned char *key, size_t keylen, ...)
1105 {
1106 va_list arg_ptr;
1107 gpg_error_t err;
1108 gcry_mac_hd_t hd;
1109 const void *data;
1110 size_t datalen;
1111
1112 log_assert (resultsize >= 32);
1113
1114 err = gcry_mac_open (&hd, GCRY_MAC_HMAC_SHA256, 0, NULL);
1115 if (err)
1116 log_fatal ("error creating a MAC handle: %s\n", gpg_strerror (err));
1117 err = gcry_mac_setkey (hd, key, keylen);
1118 if (err)
1119 log_fatal ("error setting the MAC key: %s\n", gpg_strerror (err));
1120 /* log_printhex (key, keylen, "HMAC-key:"); */
1121
1122 va_start (arg_ptr, keylen);
1123 while ((data = va_arg (arg_ptr, const void *)))
1124 {
1125 datalen = va_arg (arg_ptr, size_t);
1126 /* log_printhex (data, datalen, " data:"); */
1127 err = gcry_mac_write (hd, data, datalen);
1128 if (err)
1129 log_fatal ("error writing to the MAC handle: %s\n", gpg_strerror (err));
1130 }
1131 va_end (arg_ptr);
1132
1133 err = gcry_mac_read (hd, result, &resultsize);
1134 if (err || resultsize != 32)
1135 log_fatal ("error reading MAC value: %s\n", gpg_strerror (err));
1136 /* log_printhex (result, resultsize, " result:"); */
1137
1138 gcry_mac_close (hd);
1139
1140 return result;
1141 }
1142
1143
1144 /* Key derivation function:
1145 *
1146 * FIXME(doc)
1147 */
1148 static void
kdf(unsigned char * result,size_t resultlen,const unsigned char * master,size_t masterlen,const unsigned char * sessionid,size_t sessionidlen,const unsigned char * expire,size_t expirelen,const char * label)1149 kdf (unsigned char *result, size_t resultlen,
1150 const unsigned char *master, size_t masterlen,
1151 const unsigned char *sessionid, size_t sessionidlen,
1152 const unsigned char *expire, size_t expirelen,
1153 const char *label)
1154 {
1155 log_assert (masterlen == 32 && sessionidlen == 8 && expirelen == 5);
1156 log_assert (*label);
1157 log_assert (resultlen == 32);
1158
1159 hmac_data (result, resultlen, master, masterlen,
1160 "\x00\x00\x00\x01", (size_t)4, /* Counter=1*/
1161 label, strlen (label) + 1, /* Label, 0x00 */
1162 sessionid, sessionidlen, /* Context */
1163 expire, expirelen, /* Context */
1164 "\x00\x00\x01\x00", (size_t)4, /* L=256 */
1165 NULL);
1166 }
1167
1168
1169 static gpg_error_t
compute_master_secret(unsigned char * master,size_t masterlen,const unsigned char * sk_a,size_t sk_a_len,const unsigned char * pk_b,size_t pk_b_len)1170 compute_master_secret (unsigned char *master, size_t masterlen,
1171 const unsigned char *sk_a, size_t sk_a_len,
1172 const unsigned char *pk_b, size_t pk_b_len)
1173 {
1174 gpg_error_t err;
1175
1176 log_assert (masterlen == 32);
1177 log_assert (sk_a_len == 32);
1178 log_assert (pk_b_len == 32);
1179
1180 err = gcry_ecc_mul_point (GCRY_ECC_CURVE25519, master, sk_a, pk_b);
1181 if (err)
1182 log_error ("error computing DH: %s\n", gpg_strerror (err));
1183
1184 return err;
1185 }
1186
1187
1188 /* We are the Initiator: Create the commit message. This function
1189 * sends the COMMIT message and writes STATE. */
1190 static gpg_error_t
make_msg_commit(nvc_t state)1191 make_msg_commit (nvc_t state)
1192 {
1193 gpg_error_t err;
1194 uint64_t now, expire;
1195 unsigned char secret[32];
1196 unsigned char public[32];
1197 unsigned char *newmsg;
1198 size_t newmsglen;
1199 unsigned char tmphash[32];
1200
1201 err = create_dh_keypair (secret, sizeof secret, public, sizeof public );
1202 if (err)
1203 log_error ("creating DH keypair failed: %s\n", gpg_strerror (err));
1204
1205 now = gnupg_get_time ();
1206 expire = now + opt.ttl;
1207
1208 newmsglen = 7+1+8+1+2+5+32;
1209 newmsg = xmalloc (newmsglen);
1210 memcpy (newmsg+0, "GPG-pa1", 7);
1211 newmsg[7] = MSG_TYPE_COMMIT;
1212 memcpy (newmsg+8, get_session_id (), 8);
1213 newmsg[16] = REALM_STANDARD;
1214 newmsg[17] = 0;
1215 newmsg[18] = 0;
1216 newmsg[19] = expire >> 32;
1217 newmsg[20] = expire >> 24;
1218 newmsg[21] = expire >> 16;
1219 newmsg[22] = expire >> 8;
1220 newmsg[23] = expire;
1221 gcry_md_hash_buffer (GCRY_MD_SHA256, newmsg+24, public, 32);
1222
1223 /* Create the state file. */
1224 xnvc_set (state, "State:", "Commit-sent");
1225 xnvc_set_printf (state, "Created:", "%llu", (unsigned long long)now);
1226 xnvc_set_printf (state, "Expires:", "%llu", (unsigned long long)expire);
1227 xnvc_set_hex (state, "DH-PKi:", public, 32);
1228 xnvc_set_hex (state, "DH-SKi:", secret, 32);
1229 gcry_md_hash_buffer (GCRY_MD_SHA256, tmphash, newmsg, newmsglen);
1230 xnvc_set_hex (state, "Hash-Commit:", tmphash, 32);
1231
1232 /* Write the state. Note that we need to create it. The state
1233 * updating should in theory be done atomically with send_message.
1234 * However, we can't assure that the message will actually be
1235 * delivered and thus it doesn't matter whether we have an already
1236 * update state when we later fail in send_message. */
1237 write_state (state, 1);
1238
1239 /* Write the message. */
1240 send_message (newmsg, newmsglen);
1241
1242 xfree (newmsg);
1243 return err;
1244 }
1245
1246
1247 /* We are the Responder: Process a commit message in (MSG,MSGLEN)
1248 * which has already been validated to have a correct header and
1249 * message type. Sends the DHPart1 message and writes STATE. */
1250 static gpg_error_t
proc_msg_commit(nvc_t state,const unsigned char * msg,size_t msglen)1251 proc_msg_commit (nvc_t state, const unsigned char *msg, size_t msglen)
1252 {
1253 gpg_error_t err;
1254 uint64_t now, expire;
1255 unsigned char tmphash[32];
1256 unsigned char secret[32];
1257 unsigned char public[32];
1258 unsigned char *newmsg = NULL;
1259 size_t newmsglen;
1260
1261 log_assert (msglen >= 56);
1262 now = gnupg_get_time ();
1263
1264 /* Check that the message has not expired. */
1265 expire = (uint64_t)msg[19] << 32;
1266 expire |= (uint64_t)msg[20] << 24;
1267 expire |= (uint64_t)msg[21] << 16;
1268 expire |= (uint64_t)msg[22] << 8;
1269 expire |= (uint64_t)msg[23];
1270 if (expire < now)
1271 {
1272 log_error ("received %s message is too old\n",
1273 msgtypestr (MSG_TYPE_COMMIT));
1274 err = gpg_error (GPG_ERR_TOO_OLD);
1275 goto leave;
1276 }
1277
1278 /* Create the response. */
1279 err = create_dh_keypair (secret, sizeof secret, public, sizeof public );
1280 if (err)
1281 {
1282 log_error ("creating DH keypair failed: %s\n", gpg_strerror (err));
1283 goto leave;
1284 }
1285
1286 newmsglen = 7+1+8+32+32;
1287 newmsg = xmalloc (newmsglen);
1288 memcpy (newmsg+0, "GPG-pa1", 7);
1289 newmsg[7] = MSG_TYPE_DHPART1;
1290 memcpy (newmsg+8, msg + 8, 8); /* SessionID. */
1291 memcpy (newmsg+16, public, 32); /* PKr */
1292 /* Hash(Hash(Commit) || DHPart1[0..47]) */
1293 gcry_md_hash_buffer (GCRY_MD_SHA256, tmphash, msg, msglen);
1294 hash_data (newmsg+48, 32,
1295 tmphash, sizeof tmphash,
1296 newmsg, (size_t)48,
1297 NULL);
1298
1299 /* Update the state. */
1300 xnvc_set (state, "State:", "DHPart1-sent");
1301 xnvc_set_printf (state, "Created:", "%llu", (unsigned long long)now);
1302 xnvc_set_printf (state, "Expires:", "%llu", (unsigned long long)expire);
1303 xnvc_set_hex (state, "Hash-PKi:", msg+24, 32);
1304 xnvc_set_hex (state, "DH-PKr:", public, 32);
1305 xnvc_set_hex (state, "DH-SKr:", secret, 32);
1306 gcry_md_hash_buffer (GCRY_MD_SHA256, tmphash, newmsg, newmsglen);
1307 xnvc_set_hex (state, "Hash-DHPart1:", tmphash, 32);
1308
1309 /* Write the state. Note that we need to create it. */
1310 write_state (state, 1);
1311
1312 /* Write the message. */
1313 send_message (newmsg, newmsglen);
1314
1315 leave:
1316 xfree (newmsg);
1317 return err;
1318 }
1319
1320
1321 /* We are the Initiator: Process a DHPART1 message in (MSG,MSGLEN)
1322 * which has already been validated to have a correct header and
1323 * message type. Sends the DHPart2 message and writes STATE. */
1324 static gpg_error_t
proc_msg_dhpart1(nvc_t state,const unsigned char * msg,size_t msglen)1325 proc_msg_dhpart1 (nvc_t state, const unsigned char *msg, size_t msglen)
1326 {
1327 gpg_error_t err;
1328 unsigned char hash[32];
1329 unsigned char tmphash[32];
1330 unsigned char pki[32];
1331 unsigned char pkr[32];
1332 unsigned char ski[32];
1333 unsigned char master[32];
1334 uint64_t expire;
1335 unsigned char expirebuf[5];
1336 unsigned char hmacikey[32];
1337 unsigned char symxkey[32];
1338 unsigned char *newmsg = NULL;
1339 size_t newmsglen;
1340
1341 log_assert (msglen >= 80);
1342
1343 /* Check that the message includes the Hash(Commit). */
1344 if (hex2bin (xnvc_get_string (state, "Hash-Commit:"), hash, sizeof hash) < 0)
1345 {
1346 err = gpg_error (GPG_ERR_INV_VALUE);
1347 log_error ("no or garbled 'Hash-Commit' in our state file\n");
1348 goto leave;
1349 }
1350 hash_data (tmphash, 32,
1351 hash, sizeof hash,
1352 msg, (size_t)48,
1353 NULL);
1354 if (memcmp (msg+48, tmphash, 32))
1355 {
1356 err = gpg_error (GPG_ERR_BAD_DATA);
1357 log_error ("manipulation of received %s message detected: %s\n",
1358 msgtypestr (MSG_TYPE_DHPART1), "Bad Hash");
1359 goto leave;
1360 }
1361 /* Check that the received PKr is different from our PKi and copy
1362 * PKr into PKR. */
1363 if (hex2bin (xnvc_get_string (state, "DH-PKi:"), pki, sizeof pki) < 0)
1364 {
1365 err = gpg_error (GPG_ERR_INV_VALUE);
1366 log_error ("no or garbled 'DH-PKi' in our state file\n");
1367 goto leave;
1368 }
1369 if (!memcmp (msg+16, pki, 32))
1370 {
1371 /* This can only happen if the state file leaked to the
1372 * responder. */
1373 err = gpg_error (GPG_ERR_BAD_DATA);
1374 log_error ("received our own public key PKi instead of PKr\n");
1375 goto leave;
1376 }
1377 memcpy (pkr, msg+16, 32);
1378
1379 /* Put the expire value into a buffer. */
1380 expire = string_to_u64 (xnvc_get_string (state, "Expires:"));
1381 if (!expire)
1382 {
1383 err = gpg_error (GPG_ERR_INV_VALUE);
1384 log_error ("no 'Expire' in our state file\n");
1385 goto leave;
1386 }
1387 expirebuf[0] = expire >> 32;
1388 expirebuf[1] = expire >> 24;
1389 expirebuf[2] = expire >> 16;
1390 expirebuf[3] = expire >> 8;
1391 expirebuf[4] = expire;
1392
1393 /* Get our secret from the state. */
1394 if (hex2bin (xnvc_get_string (state, "DH-SKi:"), ski, sizeof ski) < 0)
1395 {
1396 err = gpg_error (GPG_ERR_INV_VALUE);
1397 log_error ("no or garbled 'DH-SKi' in our state file\n");
1398 goto leave;
1399 }
1400
1401 /* Compute the shared secrets. */
1402 err = compute_master_secret (master, sizeof master,
1403 ski, sizeof ski, pkr, sizeof pkr);
1404 if (err)
1405 {
1406 log_error ("creating DH keypair failed: %s\n", gpg_strerror (err));
1407 goto leave;
1408 }
1409
1410 kdf (hmacikey, sizeof hmacikey,
1411 master, sizeof master, msg+8, 8, expirebuf, sizeof expirebuf,
1412 "GPG-pa1-HMACi-key");
1413 kdf (symxkey, sizeof symxkey,
1414 master, sizeof master, msg+8, 8, expirebuf, sizeof expirebuf,
1415 "GPG-pa1-SYMx-key");
1416
1417
1418 /* Create the response. */
1419 newmsglen = 7+1+8+32+32;
1420 newmsg = xmalloc (newmsglen);
1421 memcpy (newmsg+0, "GPG-pa1", 7);
1422 newmsg[7] = MSG_TYPE_DHPART2;
1423 memcpy (newmsg+8, msg + 8, 8); /* SessionID. */
1424 memcpy (newmsg+16, pki, 32); /* PKi */
1425 /* MAC(HMACi-key, Hash(DHPART1) || DHPART2[0..47] || SYMx-key) */
1426 gcry_md_hash_buffer (GCRY_MD_SHA256, tmphash, msg, msglen);
1427 hmac_data (newmsg+48, 32, hmacikey, sizeof hmacikey,
1428 tmphash, sizeof tmphash,
1429 newmsg, (size_t)48,
1430 symxkey, sizeof symxkey,
1431 NULL);
1432
1433 /* Update the state. */
1434 xnvc_set (state, "State:", "DHPart2-sent");
1435 xnvc_set_hex (state, "DH-Master:", master, sizeof master);
1436 gcry_md_hash_buffer (GCRY_MD_SHA256, tmphash, newmsg, newmsglen);
1437 xnvc_set_hex (state, "Hash-DHPart2:", tmphash, 32);
1438
1439 /* Write the state. */
1440 write_state (state, 0);
1441
1442 /* Write the message. */
1443 send_message (newmsg, newmsglen);
1444
1445 leave:
1446 xfree (newmsg);
1447 return err;
1448 }
1449
1450
1451 /* We are the Responder: Process a DHPART2 message in (MSG,MSGLEN)
1452 * which has already been validated to have a correct header and
1453 * message type. Sends the CONFIRM message and writes STATE. */
1454 static gpg_error_t
proc_msg_dhpart2(nvc_t state,const unsigned char * msg,size_t msglen)1455 proc_msg_dhpart2 (nvc_t state, const unsigned char *msg, size_t msglen)
1456 {
1457 gpg_error_t err;
1458 unsigned char hash[32];
1459 unsigned char tmphash[32];
1460 uint64_t expire;
1461 unsigned char expirebuf[5];
1462 unsigned char pki[32];
1463 unsigned char pkr[32];
1464 unsigned char skr[32];
1465 unsigned char master[32];
1466 unsigned char hmacikey[32];
1467 unsigned char hmacrkey[32];
1468 unsigned char symxkey[32];
1469 unsigned char sas[32];
1470 unsigned char *newmsg = NULL;
1471 size_t newmsglen;
1472
1473 log_assert (msglen >= 80);
1474
1475 /* Check that the PKi in the message matches the Hash(Pki) received
1476 * with the Commit message. */
1477 memcpy (pki, msg + 16, 32);
1478 gcry_md_hash_buffer (GCRY_MD_SHA256, hash, pki, 32);
1479 if (hex2bin (xnvc_get_string (state, "Hash-PKi:"),
1480 tmphash, sizeof tmphash) < 0)
1481 {
1482 err = gpg_error (GPG_ERR_INV_VALUE);
1483 log_error ("no or garbled 'Hash-PKi' in our state file\n");
1484 goto leave;
1485 }
1486 if (memcmp (hash, tmphash, 32))
1487 {
1488 err = gpg_error (GPG_ERR_BAD_DATA);
1489 log_error ("Initiator sent a different key in %s than announced in %s\n",
1490 msgtypestr (MSG_TYPE_DHPART2),
1491 msgtypestr (MSG_TYPE_COMMIT));
1492 goto leave;
1493 }
1494 /* Check that the received PKi is different from our PKr. */
1495 if (hex2bin (xnvc_get_string (state, "DH-PKr:"), pkr, sizeof pkr) < 0)
1496 {
1497 err = gpg_error (GPG_ERR_INV_VALUE);
1498 log_error ("no or garbled 'DH-PKr' in our state file\n");
1499 goto leave;
1500 }
1501 if (!memcmp (pkr, pki, 32))
1502 {
1503 err = gpg_error (GPG_ERR_BAD_DATA);
1504 log_error ("Initiator sent our own PKr back\n");
1505 goto leave;
1506 }
1507
1508 /* Put the expire value into a buffer. */
1509 expire = string_to_u64 (xnvc_get_string (state, "Expires:"));
1510 if (!expire)
1511 {
1512 err = gpg_error (GPG_ERR_INV_VALUE);
1513 log_error ("no 'Expire' in our state file\n");
1514 goto leave;
1515 }
1516 expirebuf[0] = expire >> 32;
1517 expirebuf[1] = expire >> 24;
1518 expirebuf[2] = expire >> 16;
1519 expirebuf[3] = expire >> 8;
1520 expirebuf[4] = expire;
1521
1522 /* Get our secret from the state. */
1523 if (hex2bin (xnvc_get_string (state, "DH-SKr:"), skr, sizeof skr) < 0)
1524 {
1525 err = gpg_error (GPG_ERR_INV_VALUE);
1526 log_error ("no or garbled 'DH-SKr' in our state file\n");
1527 goto leave;
1528 }
1529
1530 /* Compute the shared secrets. */
1531 err = compute_master_secret (master, sizeof master,
1532 skr, sizeof skr, pki, sizeof pki);
1533 if (err)
1534 {
1535 log_error ("creating DH keypair failed: %s\n", gpg_strerror (err));
1536 goto leave;
1537 }
1538
1539 kdf (hmacikey, sizeof hmacikey,
1540 master, sizeof master, msg+8, 8, expirebuf, sizeof expirebuf,
1541 "GPG-pa1-HMACi-key");
1542 kdf (hmacrkey, sizeof hmacrkey,
1543 master, sizeof master, msg+8, 8, expirebuf, sizeof expirebuf,
1544 "GPG-pa1-HMACr-key");
1545 kdf (symxkey, sizeof symxkey,
1546 master, sizeof master, msg+8, 8, expirebuf, sizeof expirebuf,
1547 "GPG-pa1-SYMx-key");
1548 kdf (sas, sizeof sas,
1549 master, sizeof master, msg+8, 8, expirebuf, sizeof expirebuf,
1550 "GPG-pa1-SAS");
1551
1552 /* Check the MAC from the message which is
1553 * MAC(HMACi-key, Hash(DHPART1) || DHPART2[0..47] || SYMx-key).
1554 * For that we need to fetch the stored hash from the state. */
1555 if (hex2bin (xnvc_get_string (state, "Hash-DHPart1:"),
1556 tmphash, sizeof tmphash) < 0)
1557 {
1558 err = gpg_error (GPG_ERR_INV_VALUE);
1559 log_error ("no or garbled 'Hash-DHPart1' in our state file\n");
1560 goto leave;
1561 }
1562 hmac_data (hash, 32, hmacikey, sizeof hmacikey,
1563 tmphash, sizeof tmphash,
1564 msg, 48,
1565 symxkey, sizeof symxkey,
1566 NULL);
1567 if (memcmp (msg+48, hash, 32))
1568 {
1569 err = gpg_error (GPG_ERR_BAD_DATA);
1570 log_error ("manipulation of received %s message detected: %s\n",
1571 msgtypestr (MSG_TYPE_DHPART2), "Bad MAC");
1572 goto leave;
1573 }
1574
1575 /* Create the response. */
1576 newmsglen = 7+1+8+32;
1577 newmsg = xmalloc (newmsglen);
1578 memcpy (newmsg+0, "GPG-pa1", 7);
1579 newmsg[7] = MSG_TYPE_CONFIRM;
1580 memcpy (newmsg+8, msg + 8, 8); /* SessionID. */
1581 /* MAC(HMACr-key, Hash(DHPART2) || CONFIRM[0..15] || SYMx-key) */
1582 gcry_md_hash_buffer (GCRY_MD_SHA256, tmphash, msg, msglen);
1583 hmac_data (newmsg+16, 32, hmacrkey, sizeof hmacrkey,
1584 tmphash, sizeof tmphash,
1585 newmsg, (size_t)16,
1586 symxkey, sizeof symxkey,
1587 NULL);
1588
1589 /* Update the state. */
1590 xnvc_set (state, "State:", "Confirm-sent");
1591 xnvc_set_hex (state, "DH-Master:", master, sizeof master);
1592
1593 /* Write the state. */
1594 write_state (state, 0);
1595
1596 /* Write the message. */
1597 send_message (newmsg, newmsglen);
1598
1599 display_sas (sas, sizeof sas, 0);
1600
1601
1602 leave:
1603 xfree (newmsg);
1604 return err;
1605 }
1606
1607
1608 /* We are the Initiator: Process a CONFIRM message in (MSG,MSGLEN)
1609 * which has already been validated to have a correct header and
1610 * message type. Does not send anything back. */
1611 static gpg_error_t
proc_msg_confirm(nvc_t state,const unsigned char * msg,size_t msglen)1612 proc_msg_confirm (nvc_t state, const unsigned char *msg, size_t msglen)
1613 {
1614 gpg_error_t err;
1615 unsigned char hash[32];
1616 unsigned char tmphash[32];
1617 unsigned char master[32];
1618 uint64_t expire;
1619 unsigned char expirebuf[5];
1620 unsigned char hmacrkey[32];
1621 unsigned char symxkey[32];
1622 unsigned char sas[32];
1623
1624 log_assert (msglen >= 48);
1625
1626 /* Put the expire value into a buffer. */
1627 expire = string_to_u64 (xnvc_get_string (state, "Expires:"));
1628 if (!expire)
1629 {
1630 err = gpg_error (GPG_ERR_INV_VALUE);
1631 log_error ("no 'Expire' in our state file\n");
1632 goto leave;
1633 }
1634 expirebuf[0] = expire >> 32;
1635 expirebuf[1] = expire >> 24;
1636 expirebuf[2] = expire >> 16;
1637 expirebuf[3] = expire >> 8;
1638 expirebuf[4] = expire;
1639
1640 /* Get the master secret. */
1641 if (hex2bin (xnvc_get_string (state, "DH-Master:"),master,sizeof master) < 0)
1642 {
1643 err = gpg_error (GPG_ERR_INV_VALUE);
1644 log_error ("no or garbled 'DH-Master' in our state file\n");
1645 goto leave;
1646 }
1647
1648 kdf (hmacrkey, sizeof hmacrkey,
1649 master, sizeof master, msg+8, 8, expirebuf, sizeof expirebuf,
1650 "GPG-pa1-HMACr-key");
1651 kdf (symxkey, sizeof symxkey,
1652 master, sizeof master, msg+8, 8, expirebuf, sizeof expirebuf,
1653 "GPG-pa1-SYMx-key");
1654 kdf (sas, sizeof sas,
1655 master, sizeof master, msg+8, 8, expirebuf, sizeof expirebuf,
1656 "GPG-pa1-SAS");
1657
1658 /* Check the MAC from the message which is */
1659 /* MAC(HMACr-key, Hash(DHPART2) || CONFIRM[0..15] || SYMx-key). */
1660 if (hex2bin (xnvc_get_string (state, "Hash-DHPart2:"),
1661 tmphash, sizeof tmphash) < 0)
1662 {
1663 err = gpg_error (GPG_ERR_INV_VALUE);
1664 log_error ("no or garbled 'Hash-DHPart2' in our state file\n");
1665 goto leave;
1666 }
1667 hmac_data (hash, 32, hmacrkey, sizeof hmacrkey,
1668 tmphash, sizeof tmphash,
1669 msg, (size_t)16,
1670 symxkey, sizeof symxkey,
1671 NULL);
1672 if (!memcmp (msg+48, hash, 32))
1673 {
1674 err = gpg_error (GPG_ERR_BAD_DATA);
1675 log_error ("manipulation of received %s message detected: %s\n",
1676 msgtypestr (MSG_TYPE_CONFIRM), "Bad MAC");
1677 goto leave;
1678 }
1679
1680
1681 err = display_sas (sas, sizeof sas, 1);
1682 if (err)
1683 goto leave;
1684
1685 /* Update the state. */
1686 xnvc_set (state, "State:", "Confirmed");
1687
1688 /* Write the state. */
1689 write_state (state, 0);
1690
1691 leave:
1692 return err;
1693 }
1694
1695
1696
1697 /* Expire old state files. This loops over all state files and remove
1698 * those which are expired. */
1699 static void
expire_old_states(void)1700 expire_old_states (void)
1701 {
1702 gpg_error_t err = 0;
1703 const char *dirname;
1704 gnupg_dir_t dir = NULL;
1705 gnupg_dirent_t dir_entry;
1706 char *fname = NULL;
1707 estream_t fp = NULL;
1708 nvc_t nvc = NULL;
1709 nve_t item;
1710 const char *value;
1711 unsigned long expire;
1712 unsigned long now = gnupg_get_time ();
1713
1714 dirname = get_pairing_statedir ();
1715 dir = gnupg_opendir (dirname);
1716 if (!dir)
1717 {
1718 err = gpg_error_from_syserror ();
1719 goto leave;
1720 }
1721
1722 while ((dir_entry = gnupg_readdir (dir)))
1723 {
1724 if (strlen (dir_entry->d_name) != 16+4
1725 || strcmp (dir_entry->d_name + 16, ".pa1"))
1726 continue;
1727
1728 xfree (fname);
1729 fname = make_filename (dirname, dir_entry->d_name, NULL);
1730 es_fclose (fp);
1731 fp = es_fopen (fname, "rb");
1732 if (!fp)
1733 {
1734 err = gpg_error_from_syserror ();
1735 if (gpg_err_code (err) != GPG_ERR_ENOENT)
1736 log_info ("failed to open state file '%s': %s\n",
1737 fname, gpg_strerror (err));
1738 continue;
1739 }
1740 nvc_release (nvc);
1741
1742 /* NB.: The following is similar to code in read_state. */
1743 err = nvc_parse (&nvc, NULL, fp);
1744 if (err)
1745 {
1746 log_info ("failed to parse state file '%s': %s\n",
1747 fname, gpg_strerror (err));
1748 continue; /* Skip */
1749 }
1750 item = nvc_lookup (nvc, "Expires:");
1751 if (!item)
1752 {
1753 log_info ("invalid state file '%s': %s\n",
1754 fname, "field 'expire' not found");
1755 continue; /* Skip */
1756 }
1757 value = nve_value (item);
1758 if (!value || !(expire = strtoul (value, NULL, 10)))
1759 {
1760 log_info ("invalid state file '%s': %s\n",
1761 fname, "field 'expire' has an invalid value");
1762 continue; /* Skip */
1763 }
1764
1765 if (expire <= now)
1766 {
1767 es_fclose (fp);
1768 fp = NULL;
1769 if (gnupg_remove (fname))
1770 {
1771 err = gpg_error_from_syserror ();
1772 log_info ("failed to delete state file '%s': %s\n",
1773 fname, gpg_strerror (err));
1774 }
1775 else if (opt.verbose)
1776 log_info ("state file '%s' deleted\n", fname);
1777 }
1778 }
1779
1780 leave:
1781 if (err)
1782 log_error ("expiring old states in '%s' failed: %s\n",
1783 dirname, gpg_strerror (err));
1784 gnupg_closedir (dir);
1785 es_fclose (fp);
1786 xfree (fname);
1787 }
1788
1789
1790
1791 /* Initiate a pairing. The output needs to be conveyed to the
1792 * peer */
1793 static gpg_error_t
command_initiate(void)1794 command_initiate (void)
1795 {
1796 gpg_error_t err;
1797 nvc_t state;
1798
1799 state = xnvc_new ();
1800 xnvc_set (state, "Version:", "GPG-pa1");
1801 xnvc_set_hex (state, "Session:", get_session_id (), 8);
1802 xnvc_set (state, "Role:", "Initiator");
1803
1804 err = make_msg_commit (state);
1805
1806 nvc_release (state);
1807 return err;
1808 }
1809
1810
1811
1812 /* Helper for command_respond(). */
1813 static gpg_error_t
expect_state(int msgtype,const char * statestr,const char * expected)1814 expect_state (int msgtype, const char *statestr, const char *expected)
1815 {
1816 if (strcmp (statestr, expected))
1817 {
1818 log_error ("received %s message in %s state (should be %s)\n",
1819 msgtypestr (msgtype), statestr, expected);
1820 return gpg_error (GPG_ERR_INV_RESPONSE);
1821 }
1822 return 0;
1823 }
1824
1825 /* Respond to a pairing intiation. This is used by the peer and later
1826 * by the original responder. Depending on the state the output needs
1827 * to be conveyed to the peer. */
1828 static gpg_error_t
command_respond(void)1829 command_respond (void)
1830 {
1831 gpg_error_t err;
1832 unsigned char *msg;
1833 size_t msglen = 0; /* In case that read_message returns an error. */
1834 int msgtype = 0; /* ditto. */
1835 nvc_t state;
1836 const char *rolestr;
1837 const char *statestr;
1838
1839 err = read_message (&msg, &msglen, &msgtype, &state);
1840 if (err && gpg_err_code (err) != GPG_ERR_NOT_FOUND)
1841 goto leave;
1842 rolestr = xnvc_get_string (state, "Role:");
1843 statestr = xnvc_get_string (state, "State:");
1844 if (DBG_MESSAGE)
1845 {
1846 if (!state)
1847 log_debug ("no state available\n");
1848 else
1849 log_debug ("we are %s, our current state is %s\n", rolestr, statestr);
1850 log_debug ("got message of type %s (%d)\n",
1851 msgtypestr (msgtype), msgtype);
1852 }
1853
1854 if (!state)
1855 {
1856 if (msgtype == MSG_TYPE_COMMIT)
1857 {
1858 state = xnvc_new ();
1859 xnvc_set (state, "Version:", "GPG-pa1");
1860 xnvc_set_hex (state, "Session:", get_session_id (), 8);
1861 xnvc_set (state, "Role:", "Responder");
1862 err = proc_msg_commit (state, msg, msglen);
1863 }
1864 else
1865 {
1866 log_error ("%s message expected but got %s\n",
1867 msgtypestr (MSG_TYPE_COMMIT), msgtypestr (msgtype));
1868 if (msgtype == MSG_TYPE_DHPART1)
1869 log_info ("the pairing probably took too long and timed out\n");
1870 err = gpg_error (GPG_ERR_INV_RESPONSE);
1871 goto leave;
1872 }
1873 }
1874 else if (!strcmp (rolestr, "Initiator"))
1875 {
1876 if (msgtype == MSG_TYPE_DHPART1)
1877 {
1878 if (!(err = expect_state (msgtype, statestr, "Commit-sent")))
1879 err = proc_msg_dhpart1 (state, msg, msglen);
1880 }
1881 else if (msgtype == MSG_TYPE_CONFIRM)
1882 {
1883 if (!(err = expect_state (msgtype, statestr, "DHPart2-sent")))
1884 err = proc_msg_confirm (state, msg, msglen);
1885 }
1886 else
1887 {
1888 log_error ("%s message not expected by Initiator\n",
1889 msgtypestr (msgtype));
1890 err = gpg_error (GPG_ERR_INV_RESPONSE);
1891 goto leave;
1892 }
1893 }
1894 else if (!strcmp (rolestr, "Responder"))
1895 {
1896 if (msgtype == MSG_TYPE_DHPART2)
1897 {
1898 if (!(err = expect_state (msgtype, statestr, "DHPart1-sent")))
1899 err = proc_msg_dhpart2 (state, msg, msglen);
1900 }
1901 else
1902 {
1903 log_error ("%s message not expected by Responder\n",
1904 msgtypestr (msgtype));
1905 err = gpg_error (GPG_ERR_INV_RESPONSE);
1906 goto leave;
1907 }
1908 }
1909 else
1910 log_fatal ("invalid role '%s' in state file\n", rolestr);
1911
1912
1913 leave:
1914 xfree (msg);
1915 nvc_release (state);
1916 return err;
1917 }
1918
1919
1920
1921 /* Return the keys for SESSIONIDSTR or the last one if it is NULL.
1922 * Two keys are returned: The first is the one for sending encrypted
1923 * data and the second one for decrypting received data. The keys are
1924 * always returned hex encoded and both are terminated by a LF. */
1925 static gpg_error_t
command_get(const char * sessionidstr)1926 command_get (const char *sessionidstr)
1927 {
1928 gpg_error_t err;
1929 unsigned char sessid[8];
1930 nvc_t state;
1931
1932 if (!sessionidstr)
1933 {
1934 log_error ("calling without session-id is not yet implemented\n");
1935 err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
1936 goto leave;
1937 }
1938 if (hex2bin (sessionidstr, sessid, sizeof sessid) < 0)
1939 {
1940 err = gpg_error (GPG_ERR_INV_VALUE);
1941 log_error ("invalid session id given\n");
1942 goto leave;
1943 }
1944 set_session_id (sessid, sizeof sessid);
1945 err = read_state (&state);
1946 if (err)
1947 {
1948 log_error ("reading state of session %s failed: %s\n",
1949 sessionidstr, gpg_strerror (err));
1950 goto leave;
1951 }
1952
1953 leave:
1954 return err;
1955 }
1956
1957
1958
1959 /* Cleanup command. */
1960 static gpg_error_t
command_cleanup(void)1961 command_cleanup (void)
1962 {
1963 expire_old_states ();
1964 return 0;
1965 }
1966