Reworked the ECC changes to better fit into the Libgcrypt API.
[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, 0);
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  */
155 int
156 pk_encrypt (int algo, gcry_mpi_t *resarr, gcry_mpi_t data,
157             const byte pk_fp[MAX_FINGERPRINT_LEN], gcry_mpi_t *pkey)
158 {
159   gcry_sexp_t s_ciph, s_data, s_pkey;
160   int rc;
161
162   /* Make a sexp from pkey.  */
163   if (algo == GCRY_PK_ELG || algo == GCRY_PK_ELG_E)
164     {
165       rc = gcry_sexp_build (&s_pkey, NULL,
166                             "(public-key(elg(p%m)(g%m)(y%m)))",
167                             pkey[0], pkey[1], pkey[2]);
168       /* Put DATA into a simplified S-expression.  */
169       if (rc || gcry_sexp_build (&s_data, NULL, "%m", data))
170         BUG ();
171
172     }
173   else if (algo == GCRY_PK_RSA || algo == GCRY_PK_RSA_E)
174     {
175       rc = gcry_sexp_build (&s_pkey, NULL,
176                             "(public-key(rsa(n%m)(e%m)))",
177                             pkey[0], pkey[1]);
178       /* Put DATA into a simplified S-expression.  */
179       if (rc || gcry_sexp_build (&s_data, NULL, "%m", data))
180         BUG ();
181     }
182   else if (algo == PUBKEY_ALGO_ECDH)    
183     {
184       gcry_mpi_t k;
185       char *curve;
186
187       rc = pk_ecdh_generate_ephemeral_key (pkey, &k);
188       if (rc)
189         return rc;
190       
191       curve = openpgp_oid_to_str (pkey[0]);
192       if (!curve)
193         rc = gpg_error_from_syserror ();
194       else
195         {
196           /* Now use the ephemeral secret to compute the shared point.  */
197           rc = gcry_sexp_build (&s_pkey, NULL,
198                                 "(public-key(ecdh(curve%s)(q%m)))",
199                                 curve, pkey[1]);
200           xfree (curve);
201           /* FIXME: Take care of RC.  */
202           /* Put K into a simplified S-expression.  */
203           if (rc || gcry_sexp_build (&s_data, NULL, "%m", k))
204             BUG ();
205         }
206     }
207   else
208     return gpg_error (GPG_ERR_PUBKEY_ALGO);
209
210
211   /* Pass it to libgcrypt. */
212   rc = gcry_pk_encrypt (&s_ciph, s_data, s_pkey);
213   gcry_sexp_release (s_data);
214   gcry_sexp_release (s_pkey);
215
216   if (rc)
217     ;
218   else if (algo == PUBKEY_ALGO_ECDH)    
219     {
220       gcry_mpi_t shared, public, result;
221
222       /* Get the shared point and the ephemeral public key.  */
223       shared = mpi_from_sexp (s_ciph, "a"); 
224       public = mpi_from_sexp (s_ciph, "b");
225       gcry_sexp_release (s_ciph);
226       s_ciph = NULL;
227       if (DBG_CIPHER)
228         {
229           log_debug ("ECDH ephemeral key:");
230           gcry_mpi_dump (public);
231           log_printf ("\n");
232         }
233     
234       result = NULL;
235       rc = pk_ecdh_encrypt_with_shared_point (1 /*=encrypton*/, shared,
236                                               pk_fp, data, pkey, &result);
237       gcry_mpi_release (shared);
238       if (!rc)
239         {
240           resarr[0] = public;
241           resarr[1] = result;
242         }
243       else
244         {
245           gcry_mpi_release (public);
246           gcry_mpi_release (result);
247         }
248     }
249   else /* Elgamal or RSA case.  */
250     { /* Fixme: Add better error handling or make gnupg use
251          S-expressions directly.  */
252       resarr[0] = mpi_from_sexp (s_ciph, "a");
253       if (algo != GCRY_PK_RSA && algo != GCRY_PK_RSA_E)
254         resarr[1] = mpi_from_sexp (s_ciph, "b");
255     }
256
257   gcry_sexp_release (s_ciph);
258   return rc;
259 }
260
261
262 /* Check whether SKEY is a suitable secret key. */
263 int
264 pk_check_secret_key (int algo, gcry_mpi_t *skey)
265 {
266   gcry_sexp_t s_skey;
267   int rc;
268   const int gcry_pkalgo = map_pk_openpgp_to_gcry( algo );
269
270   if (gcry_pkalgo == GCRY_PK_DSA)
271     {
272       rc = gcry_sexp_build (&s_skey, NULL,
273                             "(private-key(dsa(p%m)(q%m)(g%m)(y%m)(x%m)))",
274                             skey[0], skey[1], skey[2], skey[3], skey[4]);
275     }
276   else if (gcry_pkalgo == GCRY_PK_ELG || gcry_pkalgo == GCRY_PK_ELG_E)
277     {
278       rc = gcry_sexp_build (&s_skey, NULL,
279                             "(private-key(elg(p%m)(g%m)(y%m)(x%m)))",
280                             skey[0], skey[1], skey[2], skey[3]);
281     }
282   else if (gcry_pkalgo == GCRY_PK_RSA
283            || gcry_pkalgo == GCRY_PK_RSA_S || gcry_pkalgo == GCRY_PK_RSA_E)
284     {
285       rc = gcry_sexp_build (&s_skey, NULL,
286                             "(private-key(rsa(n%m)(e%m)(d%m)(p%m)(q%m)(u%m)))",
287                             skey[0], skey[1], skey[2], skey[3], skey[4],
288                             skey[5]);
289     }
290   else if (gcry_pkalgo == GCRY_PK_ECDSA || gcry_pkalgo == GCRY_PK_ECDH)
291     {
292       char *curve = openpgp_oid_to_str (skey[0]);
293       if (!curve)
294         rc = gpg_error_from_syserror ();
295       else
296         {
297           rc = gcry_sexp_build (&s_skey, NULL,
298                                 "(private-key(ecdsa(curve%s)(q%m)(d%m)))",
299                                 curve, skey[1], skey[2]);
300           xfree (curve);
301         }
302     }
303   else
304     return GPG_ERR_PUBKEY_ALGO;
305
306   if (!rc)
307     {
308       rc = gcry_pk_testkey (s_skey);
309       gcry_sexp_release (s_skey);
310     }
311   return rc;
312 }