gpg: Rework ECC support and add experimental support for Ed25519.
[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 get_mpi_from_sexp (gcry_sexp_t sexp, const char *item, int mpifmt)
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, mpifmt);
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   int is_ed25519 = 0;
62
63   /* Make a sexp from pkey.  */
64   if (pkalgo == GCRY_PK_DSA)
65     {
66       rc = gcry_sexp_build (&s_pkey, NULL,
67                             "(public-key(dsa(p%m)(q%m)(g%m)(y%m)))",
68                             pkey[0], pkey[1], pkey[2], pkey[3]);
69     }
70   else if (pkalgo == GCRY_PK_ELG || pkalgo == GCRY_PK_ELG_E)
71     {
72       rc = gcry_sexp_build (&s_pkey, NULL,
73                             "(public-key(elg(p%m)(g%m)(y%m)))",
74                             pkey[0], pkey[1], pkey[2]);
75     }
76   else if (pkalgo == GCRY_PK_RSA || pkalgo == GCRY_PK_RSA_S)
77     {
78       rc = gcry_sexp_build (&s_pkey, NULL,
79                             "(public-key(rsa(n%m)(e%m)))", pkey[0], pkey[1]);
80     }
81   else if (pkalgo == GCRY_PK_ECDSA) /* Same as GCRY_PK_ECDH */
82     {
83       is_ed25519 = openpgp_oid_is_ed25519 (pkey[0]);
84       if (is_ed25519)
85         rc = gcry_sexp_build (&s_pkey, NULL,
86                               "(public-key(ecc(curve Ed25519)"
87                               "(flags eddsa)(q%m)))",
88                               pkey[1]);
89       else
90         {
91           char *curve = openpgp_oid_to_str (pkey[0]);
92           if (!curve)
93             rc = gpg_error_from_syserror ();
94           else
95             {
96               rc = gcry_sexp_build (&s_pkey, NULL,
97                                     "(public-key(ecdsa(curve %s)(q%m)))",
98                                     curve, pkey[1]);
99               xfree (curve);
100             }
101         }
102     }
103   else
104     return GPG_ERR_PUBKEY_ALGO;
105
106   if (rc)
107     BUG ();  /* gcry_sexp_build should never fail.  */
108
109   /* Put hash into a S-Exp s_hash. */
110   if (is_ed25519)
111     {
112       if (gcry_sexp_build (&s_hash, NULL,
113                            "(data(flags eddsa)(hash-algo sha512)(value %m))",
114                            hash))
115         BUG (); /* gcry_sexp_build should never fail.  */
116     }
117   else
118     {
119       if (gcry_sexp_build (&s_hash, NULL, "%m", hash))
120         BUG (); /* gcry_sexp_build should never fail.  */
121     }
122
123   /* Put data into a S-Exp s_sig. */
124   s_sig = NULL;
125   if (pkalgo == GCRY_PK_DSA)
126     {
127       if (!data[0] || !data[1])
128         rc = gpg_error (GPG_ERR_BAD_MPI);
129       else
130         rc = gcry_sexp_build (&s_sig, NULL,
131                               "(sig-val(dsa(r%m)(s%m)))", data[0], data[1]);
132     }
133   else if (pkalgo == GCRY_PK_ECDSA)
134     {
135       if (!data[0] || !data[1])
136         rc = gpg_error (GPG_ERR_BAD_MPI);
137       else if (is_ed25519)
138         rc = gcry_sexp_build (&s_sig, NULL,
139                               "(sig-val(eddsa(r%M)(s%M)))", data[0], data[1]);
140       else
141         rc = gcry_sexp_build (&s_sig, NULL,
142                               "(sig-val(ecdsa(r%m)(s%m)))", data[0], data[1]);
143     }
144   else if (pkalgo == GCRY_PK_ELG || pkalgo == GCRY_PK_ELG_E)
145     {
146       if (!data[0] || !data[1])
147         rc = gpg_error (GPG_ERR_BAD_MPI);
148       else
149         rc = gcry_sexp_build (&s_sig, NULL,
150                               "(sig-val(elg(r%m)(s%m)))", data[0], data[1]);
151     }
152   else if (pkalgo == GCRY_PK_RSA || pkalgo == GCRY_PK_RSA_S)
153     {
154       if (!data[0])
155         rc = gpg_error (GPG_ERR_BAD_MPI);
156       else
157         rc = gcry_sexp_build (&s_sig, NULL, "(sig-val(rsa(s%m)))", data[0]);
158     }
159   else
160     BUG ();
161
162   if (!rc)
163     rc = gcry_pk_verify (s_sig, s_hash, s_pkey);
164
165   gcry_sexp_release (s_sig);
166   gcry_sexp_release (s_hash);
167   gcry_sexp_release (s_pkey);
168   return rc;
169 }
170
171
172
173
174 /****************
175  * Emulate our old PK interface here - sometime in the future we might
176  * change the internal design to directly fit to libgcrypt.
177  * PK is only required to compute the fingerprint for ECDH.
178  */
179 int
180 pk_encrypt (int algo, gcry_mpi_t *resarr, gcry_mpi_t data,
181             PKT_public_key *pk, gcry_mpi_t *pkey)
182 {
183   gcry_sexp_t s_ciph, s_data, s_pkey;
184   int rc;
185
186   /* Make a sexp from pkey.  */
187   if (algo == GCRY_PK_ELG || algo == GCRY_PK_ELG_E)
188     {
189       rc = gcry_sexp_build (&s_pkey, NULL,
190                             "(public-key(elg(p%m)(g%m)(y%m)))",
191                             pkey[0], pkey[1], pkey[2]);
192       /* Put DATA into a simplified S-expression.  */
193       if (rc || gcry_sexp_build (&s_data, NULL, "%m", data))
194         BUG ();
195
196     }
197   else if (algo == GCRY_PK_RSA || algo == GCRY_PK_RSA_E)
198     {
199       rc = gcry_sexp_build (&s_pkey, NULL,
200                             "(public-key(rsa(n%m)(e%m)))",
201                             pkey[0], pkey[1]);
202       /* Put DATA into a simplified S-expression.  */
203       if (rc || gcry_sexp_build (&s_data, NULL, "%m", data))
204         BUG ();
205     }
206   else if (algo == PUBKEY_ALGO_ECDH)
207     {
208       gcry_mpi_t k;
209       char *curve;
210
211       rc = pk_ecdh_generate_ephemeral_key (pkey, &k);
212       if (rc)
213         return rc;
214
215       curve = openpgp_oid_to_str (pkey[0]);
216       if (!curve)
217         rc = gpg_error_from_syserror ();
218       else
219         {
220           /* Now use the ephemeral secret to compute the shared point.  */
221           rc = gcry_sexp_build (&s_pkey, NULL,
222                                 "(public-key(ecdh(curve%s)(q%m)))",
223                                 curve, pkey[1]);
224           xfree (curve);
225           /* FIXME: Take care of RC.  */
226           /* Put K into a simplified S-expression.  */
227           if (rc || gcry_sexp_build (&s_data, NULL, "%m", k))
228             BUG ();
229         }
230     }
231   else
232     return gpg_error (GPG_ERR_PUBKEY_ALGO);
233
234
235   /* Pass it to libgcrypt. */
236   rc = gcry_pk_encrypt (&s_ciph, s_data, s_pkey);
237   gcry_sexp_release (s_data);
238   gcry_sexp_release (s_pkey);
239
240   if (rc)
241     ;
242   else if (algo == PUBKEY_ALGO_ECDH)
243     {
244       gcry_mpi_t shared, public, result;
245       byte fp[MAX_FINGERPRINT_LEN];
246       size_t fpn;
247
248       /* Get the shared point and the ephemeral public key.  */
249       shared = get_mpi_from_sexp (s_ciph, "s", GCRYMPI_FMT_USG);
250       public = get_mpi_from_sexp (s_ciph, "e", GCRYMPI_FMT_USG);
251       gcry_sexp_release (s_ciph);
252       s_ciph = NULL;
253       if (DBG_CIPHER)
254         {
255           log_debug ("ECDH ephemeral key:");
256           gcry_mpi_dump (public);
257           log_printf ("\n");
258         }
259
260       result = NULL;
261       fingerprint_from_pk (pk, fp, &fpn);
262       if (fpn != 20)
263         rc = gpg_error (GPG_ERR_INV_LENGTH);
264       else
265         rc = pk_ecdh_encrypt_with_shared_point (1 /*=encrypton*/, shared,
266                                                 fp, data, pkey, &result);
267       gcry_mpi_release (shared);
268       if (!rc)
269         {
270           resarr[0] = public;
271           resarr[1] = result;
272         }
273       else
274         {
275           gcry_mpi_release (public);
276           gcry_mpi_release (result);
277         }
278     }
279   else /* Elgamal or RSA case.  */
280     { /* Fixme: Add better error handling or make gnupg use
281          S-expressions directly.  */
282       resarr[0] = get_mpi_from_sexp (s_ciph, "a", GCRYMPI_FMT_USG);
283       if (algo != GCRY_PK_RSA && algo != GCRY_PK_RSA_E)
284         resarr[1] = get_mpi_from_sexp (s_ciph, "b", GCRYMPI_FMT_USG);
285     }
286
287   gcry_sexp_release (s_ciph);
288   return rc;
289 }
290
291
292 /* Check whether SKEY is a suitable secret key. */
293 int
294 pk_check_secret_key (int algo, gcry_mpi_t *skey)
295 {
296   gcry_sexp_t s_skey;
297   int rc;
298   const int gcry_pkalgo = map_pk_openpgp_to_gcry( algo );
299
300   if (gcry_pkalgo == GCRY_PK_DSA)
301     {
302       rc = gcry_sexp_build (&s_skey, NULL,
303                             "(private-key(dsa(p%m)(q%m)(g%m)(y%m)(x%m)))",
304                             skey[0], skey[1], skey[2], skey[3], skey[4]);
305     }
306   else if (gcry_pkalgo == GCRY_PK_ELG || gcry_pkalgo == GCRY_PK_ELG_E)
307     {
308       rc = gcry_sexp_build (&s_skey, NULL,
309                             "(private-key(elg(p%m)(g%m)(y%m)(x%m)))",
310                             skey[0], skey[1], skey[2], skey[3]);
311     }
312   else if (gcry_pkalgo == GCRY_PK_RSA
313            || gcry_pkalgo == GCRY_PK_RSA_S || gcry_pkalgo == GCRY_PK_RSA_E)
314     {
315       rc = gcry_sexp_build (&s_skey, NULL,
316                             "(private-key(rsa(n%m)(e%m)(d%m)(p%m)(q%m)(u%m)))",
317                             skey[0], skey[1], skey[2], skey[3], skey[4],
318                             skey[5]);
319     }
320   else if (gcry_pkalgo == GCRY_PK_ECDSA || gcry_pkalgo == GCRY_PK_ECDH)
321     {
322       if (openpgp_oid_is_ed25519 (skey[0]))
323         {
324           rc = gcry_sexp_build (&s_skey, NULL,
325                                 "(private-key(ecc(curve Ed25519)"
326                                 "(flags eddsa)(q%m)(d%m)))",
327                                 skey[1], skey[2]);
328         }
329       else
330         {
331           char *curve = openpgp_oid_to_str (skey[0]);
332           if (!curve)
333             rc = gpg_error_from_syserror ();
334           else
335             {
336               rc = gcry_sexp_build (&s_skey, NULL,
337                                     "(private-key(ecdsa(curve%s)(q%m)(d%m)))",
338                                     curve, skey[1], skey[2]);
339               xfree (curve);
340             }
341         }
342     }
343   else
344     return GPG_ERR_PUBKEY_ALGO;
345
346   if (!rc)
347     {
348       rc = gcry_pk_testkey (s_skey);
349       gcry_sexp_release (s_skey);
350     }
351   return rc;
352 }