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