indent: Improve readability of some comments in getkey.c
[gnupg.git] / g10 / skclist.c
1 /* skclist.c - Build a list of secret keys
2  * Copyright (C) 1998, 1999, 2000, 2001, 2006,
3  *               2010 Free Software Foundation, Inc.
4  *
5  * This file is part of GnuPG.
6  *
7  * GnuPG is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * GnuPG is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, see <https://www.gnu.org/licenses/>.
19  */
20
21 #include <config.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <errno.h>
26
27 #include "gpg.h"
28 #include "options.h"
29 #include "packet.h"
30 #include "../common/status.h"
31 #include "keydb.h"
32 #include "../common/util.h"
33 #include "../common/i18n.h"
34 #include "call-agent.h"
35
36
37 /* Return true if Libgcrypt's RNG is in faked mode.  */
38 int
39 random_is_faked (void)
40 {
41   return !!gcry_control (GCRYCTL_FAKED_RANDOM_P, 0);
42 }
43
44
45 void
46 release_sk_list (SK_LIST sk_list)
47 {
48   SK_LIST sk_rover;
49
50   for (; sk_list; sk_list = sk_rover)
51     {
52       sk_rover = sk_list->next;
53       free_public_key (sk_list->pk);
54       xfree (sk_list);
55     }
56 }
57
58
59 /* Check that we are only using keys which don't have
60  * the string "(insecure!)" or "not secure" or "do not use"
61  * in one of the user ids.  */
62 static int
63 is_insecure (ctrl_t ctrl, PKT_public_key *pk)
64 {
65   u32 keyid[2];
66   KBNODE node = NULL, u;
67   int insecure = 0;
68
69   keyid_from_pk (pk, keyid);
70   node = get_pubkeyblock (ctrl, keyid);
71   for (u = node; u; u = u->next)
72     {
73       if (u->pkt->pkttype == PKT_USER_ID)
74         {
75           PKT_user_id *id = u->pkt->pkt.user_id;
76           if (id->attrib_data)
77             continue;           /* skip attribute packets */
78           if (strstr (id->name, "(insecure!)")
79               || strstr (id->name, "not secure")
80               || strstr (id->name, "do not use")
81               || strstr (id->name, "(INSECURE!)"))
82             {
83               insecure = 1;
84               break;
85             }
86         }
87     }
88   release_kbnode (node);
89
90   return insecure;
91 }
92
93 static int
94 key_present_in_sk_list (SK_LIST sk_list, PKT_public_key *pk)
95 {
96   for (; sk_list; sk_list = sk_list->next)
97     {
98       if (!cmp_public_keys (sk_list->pk, pk))
99         return 0;
100     }
101   return -1;
102 }
103
104 static int
105 is_duplicated_entry (strlist_t list, strlist_t item)
106 {
107   for (; list && list != item; list = list->next)
108     {
109       if (!strcmp (list->d, item->d))
110         return 1;
111     }
112   return 0;
113 }
114
115
116 gpg_error_t
117 build_sk_list (ctrl_t ctrl,
118                strlist_t locusr, SK_LIST *ret_sk_list, unsigned int use)
119 {
120   gpg_error_t err;
121   SK_LIST sk_list = NULL;
122
123   /* XXX: Change this function to use get_pubkeys instead of
124      getkey_byname to detect ambiguous key specifications and warn
125      about duplicate keyblocks.  For ambiguous key specifications on
126      the command line or provided interactively, prompt the user to
127      select the best key.  If a key specification is ambiguous and we
128      are in batch mode, die.  */
129
130   if (!locusr) /* No user ids given - use the card key or the default key.  */
131     {
132       struct agent_card_info_s info;
133       PKT_public_key *pk;
134       char *serialno;
135
136       memset (&info, 0, sizeof(info));
137       pk = xmalloc_clear (sizeof *pk);
138       pk->req_usage = use;
139
140       /* Check if a card is available.  If any, use the key as a hint.  */
141       err = agent_scd_serialno (&serialno, NULL);
142       if (!err)
143         {
144           xfree (serialno);
145           err = agent_scd_getattr ("KEY-FPR", &info);
146           if (err)
147             log_error ("error retrieving key fingerprint from card: %s\n",
148                        gpg_strerror (err));
149         }
150
151       err = get_seckey_default_or_card (ctrl, pk,
152                                         info.fpr1valid? info.fpr1 : NULL, 20);
153       if (err)
154         {
155           free_public_key (pk);
156           pk = NULL;
157           log_error ("no default secret key: %s\n", gpg_strerror (err));
158           write_status_text (STATUS_INV_SGNR, get_inv_recpsgnr_code (err));
159         }
160       else if ((err = openpgp_pk_test_algo2 (pk->pubkey_algo, use)))
161         {
162           free_public_key (pk);
163           pk = NULL;
164           log_error ("invalid default secret key: %s\n", gpg_strerror (err));
165           write_status_text (STATUS_INV_SGNR, get_inv_recpsgnr_code (err));
166         }
167       else
168         {
169           SK_LIST r;
170
171           if (random_is_faked () && !is_insecure (ctrl, pk))
172             {
173               log_info (_("key is not flagged as insecure - "
174                           "can't use it with the faked RNG!\n"));
175               free_public_key (pk);
176               pk = NULL;
177               write_status_text (STATUS_INV_SGNR,
178                                  get_inv_recpsgnr_code (GPG_ERR_NOT_TRUSTED));
179             }
180           else
181             {
182               r = xmalloc (sizeof *r);
183               r->pk = pk;
184               pk = NULL;
185               r->next = sk_list;
186               r->mark = 0;
187               sk_list = r;
188             }
189         }
190     }
191   else /* Check the given user ids.  */
192     {
193       strlist_t locusr_orig = locusr;
194
195       for (; locusr; locusr = locusr->next)
196         {
197           PKT_public_key *pk;
198
199           err = 0;
200           /* Do an early check against duplicated entries.  However
201            * this won't catch all duplicates because the user IDs may
202            * be specified in different ways.  */
203           if (is_duplicated_entry (locusr_orig, locusr))
204             {
205               log_info (_("skipped \"%s\": duplicated\n"), locusr->d);
206               continue;
207             }
208           pk = xmalloc_clear (sizeof *pk);
209           pk->req_usage = use;
210           if ((err = getkey_byname (ctrl, NULL, pk, locusr->d, 1, NULL)))
211             {
212               free_public_key (pk);
213               pk = NULL;
214               log_error (_("skipped \"%s\": %s\n"),
215                          locusr->d, gpg_strerror (err));
216               write_status_text_and_buffer
217                 (STATUS_INV_SGNR, get_inv_recpsgnr_code (err),
218                  locusr->d, strlen (locusr->d), -1);
219             }
220           else if (!key_present_in_sk_list (sk_list, pk))
221             {
222               free_public_key (pk);
223               pk = NULL;
224               log_info (_("skipped: secret key already present\n"));
225             }
226           else if ((err = openpgp_pk_test_algo2 (pk->pubkey_algo, use)))
227             {
228               free_public_key (pk);
229               pk = NULL;
230               log_error ("skipped \"%s\": %s\n", locusr->d, gpg_strerror (err));
231               write_status_text_and_buffer
232                 (STATUS_INV_SGNR, get_inv_recpsgnr_code (err),
233                  locusr->d, strlen (locusr->d), -1);
234             }
235           else
236             {
237               SK_LIST r;
238
239               if (pk->version == 4 && (use & PUBKEY_USAGE_SIG)
240                   && pk->pubkey_algo == PUBKEY_ALGO_ELGAMAL_E)
241                 {
242                   log_info (_("skipped \"%s\": %s\n"), locusr->d,
243                             _("this is a PGP generated Elgamal key which"
244                               " is not secure for signatures!"));
245                   free_public_key (pk);
246                   pk = NULL;
247                   write_status_text_and_buffer
248                     (STATUS_INV_SGNR,
249                      get_inv_recpsgnr_code (GPG_ERR_WRONG_KEY_USAGE),
250                      locusr->d, strlen (locusr->d), -1);
251                 }
252               else if (random_is_faked () && !is_insecure (ctrl, pk))
253                 {
254                   log_info (_("key is not flagged as insecure - "
255                               "can't use it with the faked RNG!\n"));
256                   free_public_key (pk);
257                   pk = NULL;
258                   write_status_text_and_buffer
259                     (STATUS_INV_SGNR,
260                      get_inv_recpsgnr_code (GPG_ERR_NOT_TRUSTED),
261                      locusr->d, strlen (locusr->d), -1);
262                 }
263               else
264                 {
265                   r = xmalloc (sizeof *r);
266                   r->pk = pk;
267                   pk = NULL;
268                   r->next = sk_list;
269                   r->mark = 0;
270                   sk_list = r;
271                 }
272             }
273         }
274     }
275
276   if (!err && !sk_list)
277     {
278       log_error ("no valid signators\n");
279       write_status_text (STATUS_NO_SGNR, "0");
280       err = gpg_error (GPG_ERR_NO_USER_ID);
281     }
282
283   if (err)
284     release_sk_list (sk_list);
285   else
286     *ret_sk_list = sk_list;
287   return err;
288 }