Don't print anonymous recipient messages in quiet mode.
[gnupg.git] / g10 / pkglue.c
1 /* pkglue.c - public key operations glue code
2  *      Copyright (C) 2000, 2003, 2010 Free Software Foundation, Inc.
3  *
4  * This file is part of GnuPG.
5  *
6  * GnuPG is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * GnuPG is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include <config.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <errno.h>
25 #include <assert.h>
26
27 #include "gpg.h"
28 #include "util.h"
29 #include "pkglue.h"
30 #include "main.h"
31 #include "options.h"
32
33 /* FIXME: Better chnage the fucntion name because mpi_ is used by
34    gcrypt macros.  */
35 gcry_mpi_t
36 mpi_from_sexp (gcry_sexp_t sexp, const char * item)
37 {
38   gcry_sexp_t list;
39   gcry_mpi_t data;
40
41   list = gcry_sexp_find_token (sexp, item, 0);
42   assert (list);
43   data = gcry_sexp_nth_mpi (list, 1, GCRYMPI_FMT_USG);
44   assert (data);
45   gcry_sexp_release (list);
46   return data;
47 }
48
49
50
51 /****************
52  * Emulate our old PK interface here - sometime in the future we might
53  * change the internal design to directly fit to libgcrypt.
54  */
55 int
56 pk_verify (int algo, gcry_mpi_t hash, gcry_mpi_t *data, gcry_mpi_t *pkey)
57 {
58   gcry_sexp_t s_sig, s_hash, s_pkey;
59   int rc;
60   const int pkalgo = map_pk_openpgp_to_gcry (algo);
61
62   /* Make a sexp from pkey.  */
63   if (pkalgo == GCRY_PK_DSA)
64     {
65       rc = gcry_sexp_build (&s_pkey, NULL,
66                             "(public-key(dsa(p%m)(q%m)(g%m)(y%m)))",
67                             pkey[0], pkey[1], pkey[2], pkey[3]);
68     }
69   else if (pkalgo == GCRY_PK_ELG || pkalgo == GCRY_PK_ELG_E)
70     {
71       rc = gcry_sexp_build (&s_pkey, NULL,
72                             "(public-key(elg(p%m)(g%m)(y%m)))",
73                             pkey[0], pkey[1], pkey[2]);
74     }
75   else if (pkalgo == GCRY_PK_RSA || pkalgo == GCRY_PK_RSA_S)
76     {
77       rc = gcry_sexp_build (&s_pkey, NULL,
78                             "(public-key(rsa(n%m)(e%m)))", pkey[0], pkey[1]);
79     }
80   else if (pkalgo == GCRY_PK_ECDSA) /* Same as GCRY_PK_ECDH */
81     {
82       char *curve = openpgp_oid_to_str (pkey[0]);
83       if (!curve)
84         rc = gpg_error_from_syserror ();
85       else
86         {
87           rc = gcry_sexp_build (&s_pkey, NULL,
88                                 "(public-key(ecdsa(curve %s)(q%m)))",
89                                 curve, pkey[1]);
90           xfree (curve);
91         }
92     }
93   else
94     return GPG_ERR_PUBKEY_ALGO;
95
96   if (rc)
97     BUG ();  /* gcry_sexp_build should never fail.  */
98
99   /* Put hash into a S-Exp s_hash. */
100   if (gcry_sexp_build (&s_hash, NULL, "%m", hash))
101     BUG (); /* gcry_sexp_build should never fail.  */
102
103   /* Put data into a S-Exp s_sig. */
104   s_sig = NULL;
105   if (pkalgo == GCRY_PK_DSA)
106     {
107       if (!data[0] || !data[1])
108         rc = gpg_error (GPG_ERR_BAD_MPI);
109       else
110         rc = gcry_sexp_build (&s_sig, NULL,
111                               "(sig-val(dsa(r%m)(s%m)))", data[0], data[1]);
112     }
113   else if (pkalgo == GCRY_PK_ECDSA)
114     {
115       if (!data[0] || !data[1])
116         rc = gpg_error (GPG_ERR_BAD_MPI);
117       else
118         rc = gcry_sexp_build (&s_sig, NULL,
119                               "(sig-val(ecdsa(r%m)(s%m)))", data[0], data[1]);
120     }
121   else if (pkalgo == GCRY_PK_ELG || pkalgo == GCRY_PK_ELG_E)
122     {
123       if (!data[0] || !data[1])
124         rc = gpg_error (GPG_ERR_BAD_MPI);
125       else
126         rc = gcry_sexp_build (&s_sig, NULL,
127                               "(sig-val(elg(r%m)(s%m)))", data[0], data[1]);
128     }
129   else if (pkalgo == GCRY_PK_RSA || pkalgo == GCRY_PK_RSA_S)
130     {
131       if (!data[0])
132         rc = gpg_error (GPG_ERR_BAD_MPI);
133       else
134         rc = gcry_sexp_build (&s_sig, NULL, "(sig-val(rsa(s%m)))", data[0]);
135     }
136   else
137     BUG ();
138
139   if (!rc)
140     rc = gcry_pk_verify (s_sig, s_hash, s_pkey);
141
142   gcry_sexp_release (s_sig);
143   gcry_sexp_release (s_hash);
144   gcry_sexp_release (s_pkey);
145   return rc;
146 }
147
148
149
150
151 /****************
152  * Emulate our old PK interface here - sometime in the future we might
153  * change the internal design to directly fit to libgcrypt.
154  * PK is only required to compute the fingerprint for ECDH.
155  */
156 int
157 pk_encrypt (int algo, gcry_mpi_t *resarr, gcry_mpi_t data,
158             PKT_public_key *pk, gcry_mpi_t *pkey)
159 {
160   gcry_sexp_t s_ciph, s_data, s_pkey;
161   int rc;
162
163   /* Make a sexp from pkey.  */
164   if (algo == GCRY_PK_ELG || algo == GCRY_PK_ELG_E)
165     {
166       rc = gcry_sexp_build (&s_pkey, NULL,
167                             "(public-key(elg(p%m)(g%m)(y%m)))",
168                             pkey[0], pkey[1], pkey[2]);
169       /* Put DATA into a simplified S-expression.  */
170       if (rc || gcry_sexp_build (&s_data, NULL, "%m", data))
171         BUG ();
172
173     }
174   else if (algo == GCRY_PK_RSA || algo == GCRY_PK_RSA_E)
175     {
176       rc = gcry_sexp_build (&s_pkey, NULL,
177                             "(public-key(rsa(n%m)(e%m)))",
178                             pkey[0], pkey[1]);
179       /* Put DATA into a simplified S-expression.  */
180       if (rc || gcry_sexp_build (&s_data, NULL, "%m", data))
181         BUG ();
182     }
183   else if (algo == PUBKEY_ALGO_ECDH)
184     {
185       gcry_mpi_t k;
186       char *curve;
187
188       rc = pk_ecdh_generate_ephemeral_key (pkey, &k);
189       if (rc)
190         return rc;
191
192       curve = openpgp_oid_to_str (pkey[0]);
193       if (!curve)
194         rc = gpg_error_from_syserror ();
195       else
196         {
197           /* Now use the ephemeral secret to compute the shared point.  */
198           rc = gcry_sexp_build (&s_pkey, NULL,
199                                 "(public-key(ecdh(curve%s)(q%m)))",
200                                 curve, pkey[1]);
201           xfree (curve);
202           /* FIXME: Take care of RC.  */
203           /* Put K into a simplified S-expression.  */
204           if (rc || gcry_sexp_build (&s_data, NULL, "%m", k))
205             BUG ();
206         }
207     }
208   else
209     return gpg_error (GPG_ERR_PUBKEY_ALGO);
210
211
212   /* Pass it to libgcrypt. */
213   rc = gcry_pk_encrypt (&s_ciph, s_data, s_pkey);
214   gcry_sexp_release (s_data);
215   gcry_sexp_release (s_pkey);
216
217   if (rc)
218     ;
219   else if (algo == PUBKEY_ALGO_ECDH)
220     {
221       gcry_mpi_t shared, public, result;
222       byte fp[MAX_FINGERPRINT_LEN];
223       size_t fpn;
224
225       /* Get the shared point and the ephemeral public key.  */
226       shared = mpi_from_sexp (s_ciph, "s");
227       public = mpi_from_sexp (s_ciph, "e");
228       gcry_sexp_release (s_ciph);
229       s_ciph = NULL;
230       if (DBG_CIPHER)
231         {
232           log_debug ("ECDH ephemeral key:");
233           gcry_mpi_dump (public);
234           log_printf ("\n");
235         }
236
237       result = NULL;
238       fingerprint_from_pk (pk, fp, &fpn);
239       if (fpn != 20)
240         rc = gpg_error (GPG_ERR_INV_LENGTH);
241       else
242         rc = pk_ecdh_encrypt_with_shared_point (1 /*=encrypton*/, shared,
243                                                 fp, data, pkey, &result);
244       gcry_mpi_release (shared);
245       if (!rc)
246         {
247           resarr[0] = public;
248           resarr[1] = result;
249         }
250       else
251         {
252           gcry_mpi_release (public);
253           gcry_mpi_release (result);
254         }
255     }
256   else /* Elgamal or RSA case.  */
257     { /* Fixme: Add better error handling or make gnupg use
258          S-expressions directly.  */
259       resarr[0] = mpi_from_sexp (s_ciph, "a");
260       if (algo != GCRY_PK_RSA && algo != GCRY_PK_RSA_E)
261         resarr[1] = mpi_from_sexp (s_ciph, "b");
262     }
263
264   gcry_sexp_release (s_ciph);
265   return rc;
266 }
267
268
269 /* Check whether SKEY is a suitable secret key. */
270 int
271 pk_check_secret_key (int algo, gcry_mpi_t *skey)
272 {
273   gcry_sexp_t s_skey;
274   int rc;
275   const int gcry_pkalgo = map_pk_openpgp_to_gcry( algo );
276
277   if (gcry_pkalgo == GCRY_PK_DSA)
278     {
279       rc = gcry_sexp_build (&s_skey, NULL,
280                             "(private-key(dsa(p%m)(q%m)(g%m)(y%m)(x%m)))",
281                             skey[0], skey[1], skey[2], skey[3], skey[4]);
282     }
283   else if (gcry_pkalgo == GCRY_PK_ELG || gcry_pkalgo == GCRY_PK_ELG_E)
284     {
285       rc = gcry_sexp_build (&s_skey, NULL,
286                             "(private-key(elg(p%m)(g%m)(y%m)(x%m)))",
287                             skey[0], skey[1], skey[2], skey[3]);
288     }
289   else if (gcry_pkalgo == GCRY_PK_RSA
290            || gcry_pkalgo == GCRY_PK_RSA_S || gcry_pkalgo == GCRY_PK_RSA_E)
291     {
292       rc = gcry_sexp_build (&s_skey, NULL,
293                             "(private-key(rsa(n%m)(e%m)(d%m)(p%m)(q%m)(u%m)))",
294                             skey[0], skey[1], skey[2], skey[3], skey[4],
295                             skey[5]);
296     }
297   else if (gcry_pkalgo == GCRY_PK_ECDSA || gcry_pkalgo == GCRY_PK_ECDH)
298     {
299       char *curve = openpgp_oid_to_str (skey[0]);
300       if (!curve)
301         rc = gpg_error_from_syserror ();
302       else
303         {
304           rc = gcry_sexp_build (&s_skey, NULL,
305                                 "(private-key(ecdsa(curve%s)(q%m)(d%m)))",
306                                 curve, skey[1], skey[2]);
307           xfree (curve);
308         }
309     }
310   else
311     return GPG_ERR_PUBKEY_ALGO;
312
313   if (!rc)
314     {
315       rc = gcry_pk_testkey (s_skey);
316       gcry_sexp_release (s_skey);
317     }
318   return rc;
319 }