gpg: Split a too large export function.
[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 <http://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 "status.h"
31 #include "keydb.h"
32 #include "util.h"
33 #include "i18n.h"
34
35
36 /* Return true if Libgcrypt's RNG is in faked mode.  */
37 int
38 random_is_faked (void)
39 {
40   return !!gcry_control (GCRYCTL_FAKED_RANDOM_P, 0);
41 }
42
43
44 void
45 release_sk_list (SK_LIST sk_list)
46 {
47   SK_LIST sk_rover;
48
49   for (; sk_list; sk_list = sk_rover)
50     {
51       sk_rover = sk_list->next;
52       free_public_key (sk_list->pk);
53       xfree (sk_list);
54     }
55 }
56
57
58 /* Check that we are only using keys which don't have
59  * the string "(insecure!)" or "not secure" or "do not use"
60  * in one of the user ids.  */
61 static int
62 is_insecure (PKT_public_key *pk)
63 {
64   u32 keyid[2];
65   KBNODE node = NULL, u;
66   int insecure = 0;
67
68   keyid_from_pk (pk, keyid);
69   node = get_pubkeyblock (keyid);
70   for (u = node; u; u = u->next)
71     {
72       if (u->pkt->pkttype == PKT_USER_ID)
73         {
74           PKT_user_id *id = u->pkt->pkt.user_id;
75           if (id->attrib_data)
76             continue;           /* skip attribute packets */
77           if (strstr (id->name, "(insecure!)")
78               || strstr (id->name, "not secure")
79               || strstr (id->name, "do not use")
80               || strstr (id->name, "(INSECURE!)"))
81             {
82               insecure = 1;
83               break;
84             }
85         }
86     }
87   release_kbnode (node);
88
89   return insecure;
90 }
91
92 static int
93 key_present_in_sk_list (SK_LIST sk_list, PKT_public_key *pk)
94 {
95   for (; sk_list; sk_list = sk_list->next)
96     {
97       if (!cmp_public_keys (sk_list->pk, pk))
98         return 0;
99     }
100   return -1;
101 }
102
103 static int
104 is_duplicated_entry (strlist_t list, strlist_t item)
105 {
106   for (; list && list != item; list = list->next)
107     {
108       if (!strcmp (list->d, item->d))
109         return 1;
110     }
111   return 0;
112 }
113
114
115 gpg_error_t
116 build_sk_list (ctrl_t ctrl,
117                strlist_t locusr, SK_LIST *ret_sk_list, unsigned int use)
118 {
119   gpg_error_t err;
120   SK_LIST sk_list = NULL;
121
122   /* XXX: Change this function to use get_pubkeys instead of
123      getkey_byname to detect ambiguous key specifications and warn
124      about duplicate keyblocks.  For ambiguous key specifications on
125      the command line or provided interactively, prompt the user to
126      select the best key.  If a key specification is ambiguous and we
127      are in batch mode, die.  */
128
129   if (!locusr) /* No user ids given - use the default key.  */
130     {
131       PKT_public_key *pk;
132
133       pk = xmalloc_clear (sizeof *pk);
134       pk->req_usage = use;
135       if ((err = getkey_byname (ctrl, NULL, pk, NULL, 1, NULL)))
136         {
137           free_public_key (pk);
138           pk = NULL;
139           log_error ("no default secret key: %s\n", gpg_strerror (err));
140           write_status_text (STATUS_INV_SGNR, get_inv_recpsgnr_code (err));
141         }
142       else if ((err = openpgp_pk_test_algo2 (pk->pubkey_algo, use)))
143         {
144           free_public_key (pk);
145           pk = NULL;
146           log_error ("invalid default secret key: %s\n", gpg_strerror (err));
147           write_status_text (STATUS_INV_SGNR, get_inv_recpsgnr_code (err));
148         }
149       else
150         {
151           SK_LIST r;
152
153           if (random_is_faked () && !is_insecure (pk))
154             {
155               log_info (_("key is not flagged as insecure - "
156                           "can't use it with the faked RNG!\n"));
157               free_public_key (pk);
158               pk = NULL;
159               write_status_text (STATUS_INV_SGNR,
160                                  get_inv_recpsgnr_code (GPG_ERR_NOT_TRUSTED));
161             }
162           else
163             {
164               r = xmalloc (sizeof *r);
165               r->pk = pk;
166               pk = NULL;
167               r->next = sk_list;
168               r->mark = 0;
169               sk_list = r;
170             }
171         }
172     }
173   else /* Check the given user ids.  */
174     {
175       strlist_t locusr_orig = locusr;
176
177       for (; locusr; locusr = locusr->next)
178         {
179           PKT_public_key *pk;
180
181           err = 0;
182           /* Do an early check against duplicated entries.  However
183            * this won't catch all duplicates because the user IDs may
184            * be specified in different ways.  */
185           if (is_duplicated_entry (locusr_orig, locusr))
186             {
187               log_info (_("skipped \"%s\": duplicated\n"), locusr->d);
188               continue;
189             }
190           pk = xmalloc_clear (sizeof *pk);
191           pk->req_usage = use;
192           if ((err = getkey_byname (ctrl, NULL, pk, locusr->d, 1, NULL)))
193             {
194               free_public_key (pk);
195               pk = NULL;
196               log_error (_("skipped \"%s\": %s\n"),
197                          locusr->d, gpg_strerror (err));
198               write_status_text_and_buffer
199                 (STATUS_INV_SGNR, get_inv_recpsgnr_code (err),
200                  locusr->d, strlen (locusr->d), -1);
201             }
202           else if (!key_present_in_sk_list (sk_list, pk))
203             {
204               free_public_key (pk);
205               pk = NULL;
206               log_info (_("skipped: secret key already present\n"));
207             }
208           else if ((err = openpgp_pk_test_algo2 (pk->pubkey_algo, use)))
209             {
210               free_public_key (pk);
211               pk = NULL;
212               log_error ("skipped \"%s\": %s\n", locusr->d, gpg_strerror (err));
213               write_status_text_and_buffer
214                 (STATUS_INV_SGNR, get_inv_recpsgnr_code (err),
215                  locusr->d, strlen (locusr->d), -1);
216             }
217           else
218             {
219               SK_LIST r;
220
221               if (pk->version == 4 && (use & PUBKEY_USAGE_SIG)
222                   && pk->pubkey_algo == PUBKEY_ALGO_ELGAMAL_E)
223                 {
224                   log_info (_("skipped \"%s\": %s\n"), locusr->d,
225                             _("this is a PGP generated Elgamal key which"
226                               " is not secure for signatures!"));
227                   free_public_key (pk);
228                   pk = NULL;
229                   write_status_text_and_buffer
230                     (STATUS_INV_SGNR,
231                      get_inv_recpsgnr_code (GPG_ERR_WRONG_KEY_USAGE),
232                      locusr->d, strlen (locusr->d), -1);
233                 }
234               else if (random_is_faked () && !is_insecure (pk))
235                 {
236                   log_info (_("key is not flagged as insecure - "
237                               "can't use it with the faked RNG!\n"));
238                   free_public_key (pk);
239                   pk = NULL;
240                   write_status_text_and_buffer
241                     (STATUS_INV_SGNR,
242                      get_inv_recpsgnr_code (GPG_ERR_NOT_TRUSTED),
243                      locusr->d, strlen (locusr->d), -1);
244                 }
245               else
246                 {
247                   r = xmalloc (sizeof *r);
248                   r->pk = pk;
249                   pk = NULL;
250                   r->next = sk_list;
251                   r->mark = 0;
252                   sk_list = r;
253                 }
254             }
255         }
256     }
257
258   if (!err && !sk_list)
259     {
260       log_error ("no valid signators\n");
261       write_status_text (STATUS_NO_SGNR, "0");
262       err = gpg_error (GPG_ERR_NO_USER_ID);
263     }
264
265   if (err)
266     release_sk_list (sk_list);
267   else
268     *ret_sk_list = sk_list;
269   return err;
270 }