Line data Source code
1 : /* name-value.c - Parser and writer for a name-value format.
2 : * Copyright (C) 2016 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 either
8 : *
9 : * - the GNU Lesser General Public License as published by the Free
10 : * Software Foundation; either version 3 of the License, or (at
11 : * your option) any later version.
12 : *
13 : * or
14 : *
15 : * - the GNU General Public License as published by the Free
16 : * Software Foundation; either version 2 of the License, or (at
17 : * your option) any later version.
18 : *
19 : * or both in parallel, as here.
20 : *
21 : * GnuPG is distributed in the hope that it will be useful,
22 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 : * GNU General Public License for more details.
25 : *
26 : * You should have received a copy of the GNU General Public License
27 : * along with this program; if not, see <http://www.gnu.org/licenses/>.
28 : */
29 :
30 : /*
31 : * This module aso provides features for the extended private key
32 : * format of gpg-agent.
33 : */
34 :
35 : #include <config.h>
36 : #include <assert.h>
37 : #include <gcrypt.h>
38 : #include <gpg-error.h>
39 : #include <string.h>
40 :
41 : #include "mischelp.h"
42 : #include "strlist.h"
43 : #include "util.h"
44 : #include "name-value.h"
45 :
46 : struct name_value_container
47 : {
48 : struct name_value_entry *first;
49 : struct name_value_entry *last;
50 : unsigned int private_key_mode:1;
51 : };
52 :
53 :
54 : struct name_value_entry
55 : {
56 : struct name_value_entry *prev;
57 : struct name_value_entry *next;
58 :
59 : /* The name. Comments and blank lines have NAME set to NULL. */
60 : char *name;
61 :
62 : /* The value as stored in the file. We store it when when we parse
63 : a file so that we can reproduce it. */
64 : strlist_t raw_value;
65 :
66 : /* The decoded value. */
67 : char *value;
68 : };
69 :
70 :
71 : /* Helper */
72 : static inline gpg_error_t
73 0 : my_error_from_syserror (void)
74 : {
75 0 : return gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
76 : }
77 :
78 :
79 : static inline gpg_error_t
80 2 : my_error (gpg_err_code_t ec)
81 : {
82 2 : return gpg_err_make (default_errsource, ec);
83 : }
84 :
85 :
86 :
87 :
88 : /* Allocation and deallocation. */
89 :
90 : /* Allocate a private key container structure. */
91 : nvc_t
92 20 : nvc_new (void)
93 : {
94 20 : return xtrycalloc (1, sizeof (struct name_value_container));
95 : }
96 :
97 :
98 : /* Allocate a private key container structure for use with private keys. */
99 : nvc_t
100 10 : nvc_new_private_key (void)
101 : {
102 10 : nvc_t nvc = nvc_new ();
103 10 : if (nvc)
104 10 : nvc->private_key_mode = 1;
105 10 : return nvc;
106 : }
107 :
108 :
109 : static void
110 67 : nve_release (nve_t entry, int private_key_mode)
111 : {
112 67 : if (entry == NULL)
113 67 : return;
114 :
115 67 : xfree (entry->name);
116 67 : if (entry->value && private_key_mode)
117 10 : wipememory (entry->value, strlen (entry->value));
118 67 : xfree (entry->value);
119 67 : if (private_key_mode)
120 34 : free_strlist_wipe (entry->raw_value);
121 : else
122 33 : free_strlist (entry->raw_value);
123 67 : xfree (entry);
124 : }
125 :
126 :
127 : /* Release a private key container structure. */
128 : void
129 20 : nvc_release (nvc_t pk)
130 : {
131 : nve_t e, next;
132 :
133 20 : if (pk == NULL)
134 20 : return;
135 :
136 79 : for (e = pk->first; e; e = next)
137 : {
138 59 : next = e->next;
139 59 : nve_release (e, pk->private_key_mode);
140 : }
141 :
142 20 : xfree (pk);
143 : }
144 :
145 :
146 :
147 : /* Dealing with names and values. */
148 :
149 : /* Check whether the given name is valid. Valid names start with a
150 : letter, end with a colon, and contain only alphanumeric characters
151 : and the hyphen. */
152 : static int
153 60 : valid_name (const char *name)
154 : {
155 60 : size_t i, len = strlen (name);
156 :
157 60 : if (! alphap (name) || len == 0 || name[len - 1] != ':')
158 0 : return 0;
159 :
160 380 : for (i = 1; i < len - 1; i++)
161 320 : if (! alnump (&name[i]) && name[i] != '-')
162 0 : return 0;
163 :
164 60 : return 1;
165 : }
166 :
167 :
168 : /* Makes sure that ENTRY has a RAW_VALUE. */
169 : static gpg_error_t
170 99 : assert_raw_value (nve_t entry)
171 : {
172 99 : gpg_error_t err = 0;
173 : size_t len, offset;
174 : #define LINELEN 70
175 : char buf[LINELEN+3];
176 :
177 99 : if (entry->raw_value)
178 80 : return 0;
179 :
180 19 : len = strlen (entry->value);
181 19 : offset = 0;
182 65 : while (len)
183 : {
184 27 : size_t amount, linelen = LINELEN;
185 :
186 : /* On the first line we need to subtract space for the name. */
187 27 : if (entry->raw_value == NULL && strlen (entry->name) < linelen)
188 19 : linelen -= strlen (entry->name);
189 :
190 : /* See if the rest of the value fits in this line. */
191 27 : if (len <= linelen)
192 19 : amount = len;
193 : else
194 : {
195 : size_t i;
196 :
197 : /* Find a suitable space to break on. */
198 74 : for (i = linelen - 1; linelen - i < 30 && linelen - i > offset; i--)
199 72 : if (ascii_isspace (entry->value[i]))
200 : break;
201 :
202 8 : if (ascii_isspace (entry->value[i]))
203 : {
204 : /* Found one. */
205 6 : amount = i;
206 : }
207 : else
208 : {
209 : /* Just induce a hard break. */
210 2 : amount = linelen;
211 : }
212 : }
213 :
214 27 : snprintf (buf, sizeof buf, " %.*s\n", (int) amount,
215 27 : &entry->value[offset]);
216 27 : if (append_to_strlist_try (&entry->raw_value, buf) == NULL)
217 : {
218 0 : err = my_error_from_syserror ();
219 0 : goto leave;
220 : }
221 :
222 27 : offset += amount;
223 27 : len -= amount;
224 : }
225 :
226 : leave:
227 19 : if (err)
228 : {
229 0 : free_strlist_wipe (entry->raw_value);
230 0 : entry->raw_value = NULL;
231 : }
232 :
233 19 : return err;
234 : #undef LINELEN
235 : }
236 :
237 :
238 : /* Computes the length of the value encoded as continuation. If
239 : *SWALLOW_WS is set, all whitespace at the beginning of S is
240 : swallowed. If START is given, a pointer to the beginning of the
241 : value is stored there. */
242 : static size_t
243 58 : continuation_length (const char *s, int *swallow_ws, const char **start)
244 : {
245 : size_t len;
246 :
247 58 : if (*swallow_ws)
248 : {
249 : /* The previous line was a blank line and we inserted a newline.
250 : Swallow all whitespace at the beginning of this line. */
251 16 : while (ascii_isspace (*s))
252 8 : s++;
253 : }
254 : else
255 : {
256 : /* Iff a continuation starts with more than one space, it
257 : encodes a space. */
258 54 : if (ascii_isspace (*s))
259 54 : s++;
260 : }
261 :
262 : /* Strip whitespace at the end. */
263 58 : len = strlen (s);
264 170 : while (len > 0 && ascii_isspace (s[len-1]))
265 54 : len--;
266 :
267 58 : if (len == 0)
268 : {
269 : /* Blank lines encode newlines. */
270 4 : len = 1;
271 4 : s = "\n";
272 4 : *swallow_ws = 1;
273 : }
274 : else
275 54 : *swallow_ws = 0;
276 :
277 58 : if (start)
278 29 : *start = s;
279 :
280 58 : return len;
281 : }
282 :
283 :
284 : /* Makes sure that ENTRY has a VALUE. */
285 : static gpg_error_t
286 7 : assert_value (nve_t entry)
287 : {
288 : size_t len;
289 : int swallow_ws;
290 : strlist_t s;
291 : char *p;
292 :
293 7 : if (entry->value)
294 0 : return 0;
295 :
296 7 : len = 0;
297 7 : swallow_ws = 0;
298 36 : for (s = entry->raw_value; s; s = s->next)
299 29 : len += continuation_length (s->d, &swallow_ws, NULL);
300 :
301 : /* Add one for the terminating zero. */
302 7 : len += 1;
303 :
304 7 : entry->value = p = xtrymalloc (len);
305 7 : if (entry->value == NULL)
306 0 : return my_error_from_syserror ();
307 :
308 7 : swallow_ws = 0;
309 36 : for (s = entry->raw_value; s; s = s->next)
310 : {
311 : const char *start;
312 29 : size_t l = continuation_length (s->d, &swallow_ws, &start);
313 :
314 29 : memcpy (p, start, l);
315 29 : p += l;
316 : }
317 :
318 7 : *p++ = 0;
319 7 : assert (p - entry->value == len);
320 :
321 7 : return 0;
322 : }
323 :
324 :
325 : /* Get the name. */
326 : char *
327 0 : nve_name (nve_t pke)
328 : {
329 0 : return pke->name;
330 : }
331 :
332 :
333 : /* Get the value. */
334 : char *
335 6 : nve_value (nve_t pke)
336 : {
337 6 : if (assert_value (pke))
338 0 : return NULL;
339 6 : return pke->value;
340 : }
341 :
342 :
343 :
344 : /* Adding and modifying values. */
345 :
346 : /* Add (NAME, VALUE, RAW_VALUE) to PK. NAME may be NULL for comments
347 : and blank lines. At least one of VALUE and RAW_VALUE must be
348 : given. If PRESERVE_ORDER is not given, entries with the same name
349 : are grouped. NAME, VALUE and RAW_VALUE is consumed. */
350 : static gpg_error_t
351 67 : _nvc_add (nvc_t pk, char *name, char *value, strlist_t raw_value,
352 : int preserve_order)
353 : {
354 67 : gpg_error_t err = 0;
355 : nve_t e;
356 :
357 67 : assert (value || raw_value);
358 :
359 67 : if (name && ! valid_name (name))
360 : {
361 0 : err = my_error (GPG_ERR_INV_NAME);
362 0 : goto leave;
363 : }
364 :
365 67 : if (name
366 45 : && pk->private_key_mode
367 23 : && !ascii_strcasecmp (name, "Key:")
368 2 : && nvc_lookup (pk, "Key:"))
369 : {
370 0 : err = my_error (GPG_ERR_INV_NAME);
371 0 : goto leave;
372 : }
373 :
374 67 : e = xtrycalloc (1, sizeof *e);
375 67 : if (e == NULL)
376 : {
377 0 : err = my_error_from_syserror ();
378 0 : goto leave;
379 : }
380 :
381 67 : e->name = name;
382 67 : e->value = value;
383 67 : e->raw_value = raw_value;
384 :
385 67 : if (pk->first)
386 : {
387 : nve_t last;
388 :
389 46 : if (preserve_order || name == NULL)
390 40 : last = pk->last;
391 : else
392 : {
393 : /* See if there is already an entry with NAME. */
394 6 : last = nvc_lookup (pk, name);
395 :
396 : /* If so, find the last in that block. */
397 6 : if (last)
398 : {
399 4 : while (last->next)
400 : {
401 2 : nve_t next = last->next;
402 :
403 2 : if (next->name && ascii_strcasecmp (next->name, name) == 0)
404 0 : last = next;
405 : else
406 : break;
407 : }
408 : }
409 : else /* Otherwise, just find the last entry. */
410 4 : last = pk->last;
411 : }
412 :
413 46 : if (last->next)
414 : {
415 2 : e->prev = last;
416 2 : e->next = last->next;
417 2 : last->next = e;
418 2 : e->next->prev = e;
419 : }
420 : else
421 : {
422 44 : e->prev = last;
423 44 : last->next = e;
424 44 : pk->last = e;
425 : }
426 : }
427 : else
428 21 : pk->first = pk->last = e;
429 :
430 : leave:
431 67 : if (err)
432 : {
433 0 : xfree (name);
434 0 : if (value)
435 0 : wipememory (value, strlen (value));
436 0 : xfree (value);
437 0 : free_strlist_wipe (raw_value);
438 : }
439 :
440 67 : return err;
441 : }
442 :
443 :
444 : /* Add (NAME, VALUE) to PK. If an entry with NAME already exists, it
445 : is not updated but the new entry is appended. */
446 : gpg_error_t
447 11 : nvc_add (nvc_t pk, const char *name, const char *value)
448 : {
449 : char *k, *v;
450 :
451 11 : k = xtrystrdup (name);
452 11 : if (k == NULL)
453 0 : return my_error_from_syserror ();
454 :
455 11 : v = xtrystrdup (value);
456 11 : if (v == NULL)
457 : {
458 0 : xfree (k);
459 0 : return my_error_from_syserror ();
460 : }
461 :
462 11 : return _nvc_add (pk, k, v, NULL, 0);
463 : }
464 :
465 :
466 : /* Add (NAME, VALUE) to PK. If an entry with NAME already exists, it
467 : is updated with VALUE. If multiple entries with NAME exist, the
468 : first entry is updated. */
469 : gpg_error_t
470 15 : nvc_set (nvc_t pk, const char *name, const char *value)
471 : {
472 : nve_t e;
473 :
474 15 : if (! valid_name (name))
475 0 : return GPG_ERR_INV_NAME;
476 :
477 15 : e = nvc_lookup (pk, name);
478 15 : if (e)
479 : {
480 : char *v;
481 :
482 8 : v = xtrystrdup (value);
483 8 : if (v == NULL)
484 0 : return my_error_from_syserror ();
485 :
486 8 : free_strlist_wipe (e->raw_value);
487 8 : e->raw_value = NULL;
488 8 : if (e->value)
489 8 : wipememory (e->value, strlen (e->value));
490 8 : xfree (e->value);
491 8 : e->value = v;
492 :
493 8 : return 0;
494 : }
495 : else
496 7 : return nvc_add (pk, name, value);
497 : }
498 :
499 :
500 : /* Delete the given entry from PK. */
501 : void
502 8 : nvc_delete (nvc_t pk, nve_t entry)
503 : {
504 8 : if (entry->prev)
505 4 : entry->prev->next = entry->next;
506 : else
507 4 : pk->first = entry->next;
508 :
509 8 : if (entry->next)
510 4 : entry->next->prev = entry->prev;
511 : else
512 4 : pk->last = entry->prev;
513 :
514 8 : nve_release (entry, pk->private_key_mode);
515 8 : }
516 :
517 :
518 :
519 : /* Lookup and iteration. */
520 :
521 : /* Get the first non-comment entry. */
522 : nve_t
523 4 : nvc_first (nvc_t pk)
524 : {
525 : nve_t entry;
526 6 : for (entry = pk->first; entry; entry = entry->next)
527 6 : if (entry->name)
528 4 : return entry;
529 0 : return NULL;
530 : }
531 :
532 :
533 : /* Get the first entry with the given name. */
534 : nve_t
535 62 : nvc_lookup (nvc_t pk, const char *name)
536 : {
537 : nve_t entry;
538 136 : for (entry = pk->first; entry; entry = entry->next)
539 123 : if (entry->name && ascii_strcasecmp (entry->name, name) == 0)
540 49 : return entry;
541 13 : return NULL;
542 : }
543 :
544 :
545 : /* Get the next non-comment entry. */
546 : nve_t
547 8 : nve_next (nve_t entry)
548 : {
549 8 : for (entry = entry->next; entry; entry = entry->next)
550 6 : if (entry->name)
551 6 : return entry;
552 2 : return NULL;
553 : }
554 :
555 :
556 : /* Get the next entry with the given name. */
557 : nve_t
558 8 : nve_next_value (nve_t entry, const char *name)
559 : {
560 10 : for (entry = entry->next; entry; entry = entry->next)
561 8 : if (entry->name && ascii_strcasecmp (entry->name, name) == 0)
562 6 : return entry;
563 2 : return NULL;
564 : }
565 :
566 :
567 :
568 : /* Private key handling. */
569 :
570 : /* Get the private key. */
571 : gpg_error_t
572 2 : nvc_get_private_key (nvc_t pk, gcry_sexp_t *retsexp)
573 : {
574 : gpg_error_t err;
575 : nve_t e;
576 :
577 2 : e = pk->private_key_mode? nvc_lookup (pk, "Key:") : NULL;
578 2 : if (e == NULL)
579 1 : return my_error (GPG_ERR_MISSING_KEY);
580 :
581 1 : err = assert_value (e);
582 1 : if (err)
583 0 : return err;
584 :
585 1 : return gcry_sexp_sscan (retsexp, NULL, e->value, strlen (e->value));
586 : }
587 :
588 :
589 : /* Set the private key. */
590 : gpg_error_t
591 2 : nvc_set_private_key (nvc_t pk, gcry_sexp_t sexp)
592 : {
593 : gpg_error_t err;
594 : char *raw, *clean, *p;
595 : size_t len, i;
596 :
597 2 : if (!pk->private_key_mode)
598 1 : return my_error (GPG_ERR_MISSING_KEY);
599 :
600 1 : len = gcry_sexp_sprint (sexp, GCRYSEXP_FMT_ADVANCED, NULL, 0);
601 :
602 1 : raw = xtrymalloc (len);
603 1 : if (raw == NULL)
604 0 : return my_error_from_syserror ();
605 :
606 1 : clean = xtrymalloc (len);
607 1 : if (clean == NULL)
608 : {
609 0 : xfree (raw);
610 0 : return my_error_from_syserror ();
611 : }
612 :
613 1 : gcry_sexp_sprint (sexp, GCRYSEXP_FMT_ADVANCED, raw, len);
614 :
615 : /* Strip any whitespace at the end. */
616 1 : i = strlen (raw) - 1;
617 3 : while (i && ascii_isspace (raw[i]))
618 : {
619 1 : raw[i] = 0;
620 1 : i--;
621 : }
622 :
623 : /* Replace any newlines with spaces, remove superfluous whitespace. */
624 1 : len = strlen (raw);
625 14 : for (p = clean, i = 0; i < len; i++)
626 : {
627 13 : char c = raw[i];
628 :
629 : /* Collapse contiguous and superfluous spaces. */
630 13 : if (ascii_isspace (c) && i > 0
631 1 : && (ascii_isspace (raw[i-1]) || raw[i-1] == '(' || raw[i-1] == ')'))
632 0 : continue;
633 :
634 13 : if (c == '\n')
635 0 : c = ' ';
636 :
637 13 : *p++ = c;
638 : }
639 1 : *p = 0;
640 :
641 1 : err = nvc_set (pk, "Key:", clean);
642 1 : xfree (raw);
643 1 : xfree (clean);
644 1 : return err;
645 : }
646 :
647 :
648 :
649 : /* Parsing and serialization. */
650 :
651 : static gpg_error_t
652 16 : do_nvc_parse (nvc_t *result, int *errlinep, estream_t stream,
653 : int for_private_key)
654 : {
655 16 : gpg_error_t err = 0;
656 : gpgrt_ssize_t len;
657 16 : char *buf = NULL;
658 16 : size_t buf_len = 0;
659 16 : char *name = NULL;
660 16 : strlist_t raw_value = NULL;
661 :
662 16 : *result = for_private_key? nvc_new_private_key () : nvc_new ();
663 16 : if (*result == NULL)
664 0 : return my_error_from_syserror ();
665 :
666 16 : if (errlinep)
667 0 : *errlinep = 0;
668 136 : while ((len = es_read_line (stream, &buf, &buf_len, NULL)) > 0)
669 : {
670 : char *p;
671 104 : if (errlinep)
672 0 : *errlinep += 1;
673 :
674 : /* Skip any whitespace. */
675 104 : for (p = buf; *p && ascii_isspace (*p); p++)
676 : /* Do nothing. */;
677 :
678 104 : if (name && (spacep (buf) || *p == 0))
679 : {
680 : /* A continuation. */
681 48 : if (append_to_strlist_try (&raw_value, buf) == NULL)
682 : {
683 0 : err = my_error_from_syserror ();
684 0 : goto leave;
685 : }
686 48 : continue;
687 : }
688 :
689 : /* No continuation. Add the current entry if any. */
690 56 : if (raw_value)
691 : {
692 40 : err = _nvc_add (*result, name, NULL, raw_value, 1);
693 40 : if (err)
694 0 : goto leave;
695 : }
696 :
697 : /* And prepare for the next one. */
698 56 : name = NULL;
699 56 : raw_value = NULL;
700 :
701 56 : if (*p != 0 && *p != '#')
702 : {
703 : char *colon, *value, tmp;
704 :
705 34 : colon = strchr (buf, ':');
706 34 : if (colon == NULL)
707 : {
708 0 : err = my_error (GPG_ERR_INV_VALUE);
709 0 : goto leave;
710 : }
711 :
712 34 : value = colon + 1;
713 34 : tmp = *value;
714 34 : *value = 0;
715 34 : name = xtrystrdup (p);
716 34 : *value = tmp;
717 :
718 34 : if (name == NULL)
719 : {
720 0 : err = my_error_from_syserror ();
721 0 : goto leave;
722 : }
723 :
724 34 : if (append_to_strlist_try (&raw_value, value) == NULL)
725 : {
726 0 : err = my_error_from_syserror ();
727 0 : goto leave;
728 : }
729 34 : continue;
730 : }
731 :
732 22 : if (append_to_strlist_try (&raw_value, buf) == NULL)
733 : {
734 0 : err = my_error_from_syserror ();
735 0 : goto leave;
736 : }
737 : }
738 16 : if (len < 0)
739 : {
740 0 : err = gpg_error_from_syserror ();
741 0 : goto leave;
742 : }
743 :
744 : /* Add the final entry. */
745 16 : if (raw_value)
746 16 : err = _nvc_add (*result, name, NULL, raw_value, 1);
747 :
748 : leave:
749 16 : gpgrt_free (buf);
750 16 : if (err)
751 : {
752 0 : nvc_release (*result);
753 0 : *result = NULL;
754 : }
755 :
756 16 : return err;
757 : }
758 :
759 :
760 : /* Parse STREAM and return a newly allocated name value container
761 : structure in RESULT. If ERRLINEP is given, the line number the
762 : parser was last considering is stored there. */
763 : gpg_error_t
764 8 : nvc_parse (nvc_t *result, int *errlinep, estream_t stream)
765 : {
766 8 : return do_nvc_parse (result, errlinep, stream, 0);
767 : }
768 :
769 :
770 : /* Parse STREAM and return a newly allocated name value container
771 : structure in RESULT - assuming the extended private key format. If
772 : ERRLINEP is given, the line number the parser was last considering
773 : is stored there. */
774 : gpg_error_t
775 8 : nvc_parse_private_key (nvc_t *result, int *errlinep, estream_t stream)
776 : {
777 8 : return do_nvc_parse (result, errlinep, stream, 1);
778 : }
779 :
780 :
781 : /* Write a representation of PK to STREAM. */
782 : gpg_error_t
783 43 : nvc_write (nvc_t pk, estream_t stream)
784 : {
785 : gpg_error_t err;
786 : nve_t entry;
787 : strlist_t s;
788 :
789 142 : for (entry = pk->first; entry; entry = entry->next)
790 : {
791 99 : if (entry->name)
792 77 : es_fputs (entry->name, stream);
793 :
794 99 : err = assert_raw_value (entry);
795 99 : if (err)
796 0 : return err;
797 :
798 254 : for (s = entry->raw_value; s; s = s->next)
799 155 : es_fputs (s->d, stream);
800 :
801 99 : if (es_ferror (stream))
802 0 : return my_error_from_syserror ();
803 : }
804 :
805 43 : return 0;
806 : }
|