Integrating http://code.google.com/p/gnupg-ecc/source/detail?r=15 .
[gnupg.git] / g10 / pkglue.c
1 /* pkglue.c - public key operations glue code
2  *      Copyright (C) 2000, 2003 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
32
33 gcry_mpi_t
34 mpi_from_sexp (gcry_sexp_t sexp, const char * item)
35 {
36   gcry_sexp_t list;
37   gcry_mpi_t data;
38   
39   list = gcry_sexp_find_token (sexp, item, 0);
40   assert (list);
41   data = gcry_sexp_nth_mpi (list, 1, 0);
42   assert (data);
43   gcry_sexp_release (list);
44   return data;
45 }
46
47
48 /****************
49  * Emulate our old PK interface here - sometime in the future we might
50  * change the internal design to directly fit to libgcrypt.
51  */
52 int
53 pk_sign (int algo, gcry_mpi_t * data, gcry_mpi_t hash, gcry_mpi_t * skey)
54 {
55   gcry_sexp_t s_sig, s_hash, s_skey;
56   int rc;
57   int gcry_pkalgo = map_pk_openpgp_to_gcry( algo );
58
59   /* make a sexp from skey */
60   if (gcry_pkalgo == GCRY_PK_DSA)
61     {
62       rc = gcry_sexp_build (&s_skey, NULL,
63                             "(private-key(dsa(p%m)(q%m)(g%m)(y%m)(x%m)))",
64                             skey[0], skey[1], skey[2], skey[3], skey[4]);
65     }
66   else if (gcry_pkalgo == GCRY_PK_RSA || gcry_pkalgo == GCRY_PK_RSA_S)
67     {
68       rc = gcry_sexp_build (&s_skey, NULL,
69                             "(private-key(rsa(n%m)(e%m)(d%m)(p%m)(q%m)(u%m)))",
70                             skey[0], skey[1], skey[2], skey[3], skey[4],
71                             skey[5]);
72     }
73   else if (gcry_pkalgo == GCRY_PK_ELG || gcry_pkalgo == GCRY_PK_ELG_E)
74     {
75       rc = gcry_sexp_build (&s_skey, NULL,
76                             "(private-key(elg(p%m)(g%m)(y%m)(x%m)))",
77                             skey[0], skey[1], skey[2], skey[3]);
78     }
79   else if (gcry_pkalgo == GCRY_PK_ECDSA)
80     {
81       rc = gcry_sexp_build (&s_skey, NULL,
82                             "(private-key(ecdsa(c%m)(q%m)(d%m)))",
83                             skey[0], skey[1], skey[2] );
84     }
85   else
86     return GPG_ERR_PUBKEY_ALGO;
87
88   if (rc)
89     BUG ();
90
91   /* put hash into a S-Exp s_hash */
92   if (gcry_sexp_build (&s_hash, NULL, "%m", hash))
93     BUG ();
94
95   rc = gcry_pk_sign (&s_sig, s_hash, s_skey);
96   gcry_sexp_release (s_hash);
97   gcry_sexp_release (s_skey);
98
99   if (rc)
100     ;
101   else if (algo == GCRY_PK_RSA || algo == GCRY_PK_RSA_S)
102     data[0] = mpi_from_sexp (s_sig, "s");
103   else
104     {
105       data[0] = mpi_from_sexp (s_sig, "r");
106       data[1] = mpi_from_sexp (s_sig, "s");
107     }
108
109   gcry_sexp_release (s_sig);
110   return rc;
111 }
112
113 /****************
114  * Emulate our old PK interface here - sometime in the future we might
115  * change the internal design to directly fit to libgcrypt.
116  */
117 int
118 pk_verify (int algo, gcry_mpi_t hash, gcry_mpi_t * data, gcry_mpi_t * pkey)
119 {
120   gcry_sexp_t s_sig, s_hash, s_pkey;
121   int rc;
122   const int gcry_pkalgo = map_pk_openpgp_to_gcry( algo );
123
124   /* make a sexp from pkey */
125   if (gcry_pkalgo == GCRY_PK_DSA)
126     {
127       rc = gcry_sexp_build (&s_pkey, NULL,
128                             "(public-key(dsa(p%m)(q%m)(g%m)(y%m)))",
129                             pkey[0], pkey[1], pkey[2], pkey[3]);
130     }
131   else if (gcry_pkalgo == GCRY_PK_ELG || gcry_pkalgo == GCRY_PK_ELG_E)
132     {
133       rc = gcry_sexp_build (&s_pkey, NULL,
134                             "(public-key(elg(p%m)(g%m)(y%m)))",
135                             pkey[0], pkey[1], pkey[2]);
136     }
137   else if (gcry_pkalgo == GCRY_PK_RSA || gcry_pkalgo == GCRY_PK_RSA_S)
138     {
139       rc = gcry_sexp_build (&s_pkey, NULL,
140                             "(public-key(rsa(n%m)(e%m)))", pkey[0], pkey[1]);
141     }
142   else if (gcry_pkalgo == GCRY_PK_ECDSA)        /* same as GCRY_PK_ECDH */
143     {
144       rc = gcry_sexp_build (&s_pkey, NULL,
145                             "(public-key(ecdsa(c%m)(q%m)))", pkey[0], pkey[1]);
146     }
147   else
148     return GPG_ERR_PUBKEY_ALGO;
149
150   if (rc)
151     BUG ();  /* gcry_sexp_build should never fail.  */
152
153   /* put hash into a S-Exp s_hash */
154   if (gcry_sexp_build (&s_hash, NULL, "%m", hash))
155     BUG (); /* gcry_sexp_build should never fail.  */
156
157   /* Put data into a S-Exp s_sig. */
158   s_sig = NULL;
159   if (gcry_pkalgo == GCRY_PK_DSA)
160     {
161       if (!data[0] || !data[1])
162         rc = gpg_error (GPG_ERR_BAD_MPI);
163       else
164         rc = gcry_sexp_build (&s_sig, NULL,
165                               "(sig-val(dsa(r%m)(s%m)))", data[0], data[1]);
166     }
167   else if (gcry_pkalgo == GCRY_PK_ECDSA)
168     {
169       if (!data[0] || !data[1])
170         rc = gpg_error (GPG_ERR_BAD_MPI);
171       else
172         rc = gcry_sexp_build (&s_sig, NULL,
173                               "(sig-val(ecdsa(r%m)(s%m)))", data[0], data[1]);
174     }
175   else if (gcry_pkalgo == GCRY_PK_ELG || gcry_pkalgo == GCRY_PK_ELG_E)
176     {
177       if (!data[0] || !data[1])
178         rc = gpg_error (GPG_ERR_BAD_MPI);
179       else
180         rc = gcry_sexp_build (&s_sig, NULL,
181                               "(sig-val(elg(r%m)(s%m)))", data[0], data[1]);
182     }
183   else if (gcry_pkalgo == GCRY_PK_RSA || gcry_pkalgo == GCRY_PK_RSA_S)
184     {
185       if (!data[0])
186         rc = gpg_error (GPG_ERR_BAD_MPI);
187       else
188         rc = gcry_sexp_build (&s_sig, NULL, "(sig-val(rsa(s%m)))", data[0]);
189     }
190   else
191     BUG ();
192
193   if (!rc)
194     rc = gcry_pk_verify (s_sig, s_hash, s_pkey);
195
196   gcry_sexp_release (s_sig);
197   gcry_sexp_release (s_hash);
198   gcry_sexp_release (s_pkey);
199   return rc;
200 }
201
202
203
204
205 /****************
206  * Emulate our old PK interface here - sometime in the future we might
207  * change the internal design to directly fit to libgcrypt.
208  */
209 int
210 pk_encrypt (int algo, gcry_mpi_t * resarr, gcry_mpi_t data, const byte pk_fp[MAX_FINGERPRINT_LEN], gcry_mpi_t * pkey)
211 {
212   gcry_sexp_t s_ciph, s_data, s_pkey;
213   int rc;
214
215   /* make a sexp from pkey */
216   if (algo == GCRY_PK_ELG || algo == GCRY_PK_ELG_E)
217     {
218       rc = gcry_sexp_build (&s_pkey, NULL,
219                             "(public-key(elg(p%m)(g%m)(y%m)))",
220                             pkey[0], pkey[1], pkey[2]);
221     }
222   else if (algo == GCRY_PK_RSA || algo == GCRY_PK_RSA_E)
223     {
224       rc = gcry_sexp_build (&s_pkey, NULL,
225                             "(public-key(rsa(n%m)(e%m)))",
226                             pkey[0], pkey[1]);
227     }
228   else if (algo == PUBKEY_ALGO_ECDH)    
229     {
230       return pk_ecdh_encrypt( resarr, pk_fp, data, pkey );
231     }
232   else
233     return GPG_ERR_PUBKEY_ALGO;
234
235   if (rc)
236     BUG ();
237
238   /* put the data into a simple list */
239   if (gcry_sexp_build (&s_data, NULL, "%m", data))
240     BUG ();
241
242   /* pass it to libgcrypt */
243   rc = gcry_pk_encrypt (&s_ciph, s_data, s_pkey);
244   gcry_sexp_release (s_data);
245   gcry_sexp_release (s_pkey);
246
247   if (rc)
248     ;
249   else
250     { /* add better error handling or make gnupg use S-Exp directly */
251       resarr[0] = mpi_from_sexp (s_ciph, "a");
252       if (algo != GCRY_PK_RSA && algo != GCRY_PK_RSA_E && algo != PUBKEY_ALGO_ECDH)
253         resarr[1] = mpi_from_sexp (s_ciph, "b");
254     }
255
256   gcry_sexp_release (s_ciph);
257   return rc;
258 }
259
260
261
262 /****************
263  * Emulate our old PK interface here - sometime in the future we might
264  * change the internal design to directly fit to libgcrypt.
265  */
266 int
267 pk_decrypt (int algo, gcry_mpi_t * result, const byte sk_fp[MAX_FINGERPRINT_LEN], gcry_mpi_t * data,
268             gcry_mpi_t * skey)
269 {
270   gcry_sexp_t s_skey, s_data, s_plain;
271   int rc;
272
273   *result = NULL;
274   /* make a sexp from skey */
275   if (algo == GCRY_PK_ELG || algo == GCRY_PK_ELG_E)
276     {
277       rc = gcry_sexp_build (&s_skey, NULL,
278                             "(private-key(elg(p%m)(g%m)(y%m)(x%m)))",
279                             skey[0], skey[1], skey[2], skey[3]);
280     }
281   else if (algo == GCRY_PK_RSA || algo == GCRY_PK_RSA_E)
282     {
283       rc = gcry_sexp_build (&s_skey, NULL,
284                             "(private-key(rsa(n%m)(e%m)(d%m)(p%m)(q%m)(u%m)))",
285                             skey[0], skey[1], skey[2], skey[3], skey[4],
286                             skey[5]);
287     }
288   else if( algo == PUBKEY_ALGO_ECDH )  {
289       return pk_ecdh_decrypt( result, sk_fp, data, skey );
290   }
291   else
292     return GPG_ERR_PUBKEY_ALGO;
293
294   if (rc)
295     BUG ();
296
297   /* put data into a S-Exp s_data */
298   if (algo == GCRY_PK_ELG || algo == GCRY_PK_ELG_E)
299     {
300       if (!data[0] || !data[1])
301         rc = gpg_error (GPG_ERR_BAD_MPI);
302       else
303         rc = gcry_sexp_build (&s_data, NULL,
304                               "(enc-val(elg(a%m)(b%m)))", data[0], data[1]);
305     }
306   else if (algo == GCRY_PK_RSA || algo == GCRY_PK_RSA_E)
307     {
308       if (!data[0])
309         rc = gpg_error (GPG_ERR_BAD_MPI);
310       else
311         rc = gcry_sexp_build (&s_data, NULL, "(enc-val(rsa(a%m)))", data[0]);
312     }
313   else
314     BUG ();
315
316   if (rc)
317     BUG ();
318
319   rc = gcry_pk_decrypt (&s_plain, s_data, s_skey);
320   gcry_sexp_release (s_skey);
321   gcry_sexp_release (s_data);
322   if (rc)
323     return rc;
324
325   *result = gcry_sexp_nth_mpi (s_plain, 0, 0);
326   gcry_sexp_release (s_plain);
327   if (!*result)
328     return -1;                  /* oops */
329
330   return 0;
331 }
332
333
334 /* Check whether SKEY is a suitable secret key. */
335 int
336 pk_check_secret_key (int algo, gcry_mpi_t *skey)
337 {
338   gcry_sexp_t s_skey;
339   int rc;
340   const int gcry_pkalgo = map_pk_openpgp_to_gcry( algo );
341
342   if (gcry_pkalgo == GCRY_PK_DSA)
343     {
344       rc = gcry_sexp_build (&s_skey, NULL,
345                             "(private-key(dsa(p%m)(q%m)(g%m)(y%m)(x%m)))",
346                             skey[0], skey[1], skey[2], skey[3], skey[4]);
347     }
348   else if (gcry_pkalgo == GCRY_PK_ELG || gcry_pkalgo == GCRY_PK_ELG_E)
349     {
350       rc = gcry_sexp_build (&s_skey, NULL,
351                             "(private-key(elg(p%m)(g%m)(y%m)(x%m)))",
352                             skey[0], skey[1], skey[2], skey[3]);
353     }
354   else if (gcry_pkalgo == GCRY_PK_RSA
355            || gcry_pkalgo == GCRY_PK_RSA_S || gcry_pkalgo == GCRY_PK_RSA_E)
356     {
357       rc = gcry_sexp_build (&s_skey, NULL,
358                             "(private-key(rsa(n%m)(e%m)(d%m)(p%m)(q%m)(u%m)))",
359                             skey[0], skey[1], skey[2], skey[3], skey[4],
360                             skey[5]);
361     }
362   else if (gcry_pkalgo == GCRY_PK_ECDSA || gcry_pkalgo == GCRY_PK_ECDH)
363     {
364       rc = gcry_sexp_build (&s_skey, NULL,
365                             "(private-key(ecdsa(c%m)(q%m)(d%m)))",
366                             skey[0], skey[1], skey[2] );
367     }
368   else
369     return GPG_ERR_PUBKEY_ALGO;
370
371   if (!rc)
372     {
373       rc = gcry_pk_testkey (s_skey);
374       gcry_sexp_release (s_skey);
375     }
376   return rc;
377 }