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