2003-08-25 Timo Schulz <twoaday@freakmail.de>
[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 2 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, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
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 "util.h"
30 #include "pkglue.h"
31
32
33 static 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
58   /* make a sexp from skey */
59   if (algo == GCRY_PK_DSA)
60     {
61       rc = gcry_sexp_build (&s_skey, NULL,
62                             "(private-key(dsa(p%m)(q%m)(g%m)(y%m)(x%m)))",
63                             skey[0], skey[1], skey[2], skey[3], skey[4]);
64     }
65   else if (algo == GCRY_PK_RSA)
66     {
67       rc = gcry_sexp_build (&s_skey, NULL,
68                             "(private-key(rsa(n%m)(e%m)(d%m)(p%m)(q%m)(u%m)))",
69                             skey[0], skey[1], skey[2], skey[3], skey[4],
70                             skey[5]);
71     }
72   else if (algo == GCRY_PK_ELG || algo == GCRY_PK_ELG_E)
73     {
74       rc = gcry_sexp_build (&s_skey, NULL,
75                             "(private-key(elg(p%m)(g%m)(y%m)(x%m)))",
76                             skey[0], skey[1], skey[2], skey[3]);
77     }
78   else
79     return GPG_ERR_PUBKEY_ALGO;
80
81   if (rc)
82     BUG ();
83
84   /* put hash into a S-Exp s_hash */
85   if (gcry_sexp_build (&s_hash, NULL, "%m", hash))
86     BUG ();
87
88   rc = gcry_pk_sign (&s_sig, s_hash, s_skey);
89   gcry_sexp_release (s_hash);
90   gcry_sexp_release (s_skey);
91
92   if (rc)
93     ;
94   else if (algo == GCRY_PK_RSA)
95     data[0] = mpi_from_sexp (s_sig, "s");
96   else
97     {
98       data[0] = mpi_from_sexp (s_sig, "r");
99       data[1] = mpi_from_sexp (s_sig, "s");
100     }
101
102   gcry_sexp_release (s_sig);
103   return rc;
104 }
105
106 /****************
107  * Emulate our old PK interface here - sometime in the future we might
108  * change the internal design to directly fit to libgcrypt.
109  */
110 int
111 pk_verify (int algo, gcry_mpi_t hash, gcry_mpi_t * data, gcry_mpi_t * pkey)
112 {
113   gcry_sexp_t s_sig, s_hash, s_pkey;
114   int rc;
115
116   /* make a sexp from pkey */
117   if (algo == GCRY_PK_DSA)
118     {
119       rc = gcry_sexp_build (&s_pkey, NULL,
120                             "(public-key(dsa(p%m)(q%m)(g%m)(y%m)))",
121                             pkey[0], pkey[1], pkey[2], pkey[3]);
122     }
123   else if (algo == GCRY_PK_ELG || algo == GCRY_PK_ELG_E)
124     {
125       rc = gcry_sexp_build (&s_pkey, NULL,
126                             "(public-key(elg(p%m)(g%m)(y%m)))",
127                             pkey[0], pkey[1], pkey[2]);
128     }
129   else if (algo == GCRY_PK_RSA)
130     {
131       rc = gcry_sexp_build (&s_pkey, NULL,
132                             "(public-key(rsa(n%m)(e%m)))", pkey[0], pkey[1]);
133     }
134   else
135     return GPG_ERR_PUBKEY_ALGO;
136
137   if (rc)
138     BUG ();
139
140   /* put hash into a S-Exp s_hash */
141   if (gcry_sexp_build (&s_hash, NULL, "%m", hash))
142     BUG ();
143
144   /* put data into a S-Exp s_sig */
145   if (algo == GCRY_PK_DSA)
146     {
147       if (!data[0] || !data[1])
148         rc = gpg_error (GPG_ERR_BAD_MPI);
149       else
150         rc = gcry_sexp_build (&s_sig, NULL,
151                               "(sig-val(dsa(r%m)(s%m)))", data[0], data[1]);
152     }
153   else if (algo == GCRY_PK_ELG || algo == GCRY_PK_ELG_E)
154     {
155       if (!data[0] || !data[1])
156         rc = gpg_error (GPG_ERR_BAD_MPI);
157       else
158         rc = gcry_sexp_build (&s_sig, NULL,
159                               "(sig-val(elg(r%m)(s%m)))", data[0], data[1]);
160     }
161   else if (algo == GCRY_PK_RSA)
162     {
163       if (!data[0])
164         rc = gpg_error (GPG_ERR_BAD_MPI);
165       else
166         rc = gcry_sexp_build (&s_sig, NULL, "(sig-val(rsa(s%m)))", data[0]);
167     }
168   else
169     BUG ();
170
171   if (rc)
172     BUG ();
173
174
175   rc = gcry_pk_verify (s_sig, s_hash, s_pkey);
176   gcry_sexp_release (s_sig);
177   gcry_sexp_release (s_hash);
178   gcry_sexp_release (s_pkey);
179   return rc;
180 }
181
182
183
184
185 /****************
186  * Emulate our old PK interface here - sometime in the future we might
187  * change the internal design to directly fit to libgcrypt.
188  */
189 int
190 pk_encrypt (int algo, gcry_mpi_t * resarr, gcry_mpi_t data, gcry_mpi_t * pkey)
191 {
192   gcry_sexp_t s_ciph, s_data, s_pkey;
193   int rc;
194
195   /* make a sexp from pkey */
196   if (algo == GCRY_PK_ELG || algo == GCRY_PK_ELG_E)
197     {
198       rc = gcry_sexp_build (&s_pkey, NULL,
199                             "(public-key(elg(p%m)(g%m)(y%m)))",
200                             pkey[0], pkey[1], pkey[2]);
201     }
202   else if (algo == GCRY_PK_RSA)
203     {
204       rc = gcry_sexp_build (&s_pkey, NULL,
205                             "(public-key(rsa(n%m)(e%m)))",
206                             pkey[0], pkey[1]);
207     }
208   else
209     return GPG_ERR_PUBKEY_ALGO;
210
211   if (rc)
212     BUG ();
213
214   /* put the data into a simple list */
215   if (gcry_sexp_build (&s_data, NULL, "%m", data))
216     BUG ();
217
218   /* pass it to libgcrypt */
219   rc = gcry_pk_encrypt (&s_ciph, s_data, s_pkey);
220   gcry_sexp_release (s_data);
221   gcry_sexp_release (s_pkey);
222
223   if (rc)
224     ;
225   else
226     { /* add better error handling or make gnupg use S-Exp directly */
227       resarr[0] = mpi_from_sexp (s_ciph, "a");
228       if (algo != GCRY_PK_RSA)
229         resarr[1] = mpi_from_sexp (s_ciph, "b");
230     }
231
232   gcry_sexp_release (s_ciph);
233   return rc;
234 }
235
236
237
238 /****************
239  * Emulate our old PK interface here - sometime in the future we might
240  * change the internal design to directly fit to libgcrypt.
241  */
242 int
243 pk_decrypt (int algo, gcry_mpi_t * result, gcry_mpi_t * data,
244             gcry_mpi_t * skey)
245 {
246   gcry_sexp_t s_skey, s_data, s_plain;
247   int rc;
248
249   *result = NULL;
250   /* make a sexp from skey */
251   if (algo == GCRY_PK_ELG || algo == GCRY_PK_ELG_E)
252     {
253       rc = gcry_sexp_build (&s_skey, NULL,
254                             "(private-key(elg(p%m)(g%m)(y%m)(x%m)))",
255                             skey[0], skey[1], skey[2], skey[3]);
256     }
257   else if (algo == GCRY_PK_RSA)
258     {
259       rc = gcry_sexp_build (&s_skey, NULL,
260                             "(private-key(rsa(n%m)(e%m)(d%m)(p%m)(q%m)(u%m)))",
261                             skey[0], skey[1], skey[2], skey[3], skey[4],
262                             skey[5]);
263     }
264   else
265     return GPG_ERR_PUBKEY_ALGO;
266
267   if (rc)
268     BUG ();
269
270   /* put data into a S-Exp s_data */
271   if (algo == GCRY_PK_ELG || algo == GCRY_PK_ELG_E)
272     {
273       if (!data[0] || !data[1])
274         rc = gpg_error (GPG_ERR_BAD_MPI);
275       else
276         rc = gcry_sexp_build (&s_data, NULL,
277                               "(enc-val(elg(a%m)(b%m)))", data[0], data[1]);
278     }
279   else if (algo == GCRY_PK_RSA)
280     {
281       if (!data[0])
282         rc = gpg_error (GPG_ERR_BAD_MPI);
283       else
284         rc = gcry_sexp_build (&s_data, NULL, "(enc-val(rsa(a%m)))", data[0]);
285     }
286   else
287     BUG ();
288
289   if (rc)
290     BUG ();
291
292   rc = gcry_pk_decrypt (&s_plain, s_data, s_skey);
293   gcry_sexp_release (s_skey);
294   gcry_sexp_release (s_data);
295   if (rc)
296     return rc;
297
298   *result = gcry_sexp_nth_mpi (s_plain, 0, 0);
299   gcry_sexp_release (s_plain);
300   if (!*result)
301     return -1;                  /* oops */
302
303   return 0;
304 }
305
306
307 /* Check whether SKEY is a suitable secret key. */
308 int
309 pk_check_secret_key (int algo, gcry_mpi_t *skey)
310 {
311   gcry_sexp_t s_skey;
312   int rc;
313
314   if (algo == GCRY_PK_DSA)
315     {
316       rc = gcry_sexp_build (&s_skey, NULL,
317                             "(private-key(dsa(p%m)(q%m)(g%m)(y%m)(x%m)))",
318                             skey[0], skey[1], skey[2], skey[3], skey[4]);
319     }
320   else if (algo == GCRY_PK_ELG || algo == GCRY_PK_ELG_E)
321     {
322       rc = gcry_sexp_build (&s_skey, NULL,
323                             "(private-key(elg(p%m)(g%m)(y%m)(x%m)))",
324                             skey[0], skey[1], skey[2], skey[3]);
325     }
326   else if (algo == GCRY_PK_RSA)
327     {
328       rc = gcry_sexp_build (&s_skey, NULL,
329                             "(private-key(rsa(n%m)(e%m)(d%m)(p%m)(q%m)(u%m)))",
330                             skey[0], skey[1], skey[2], skey[3], skey[4],
331                             skey[5]);
332     }
333   else
334     return GPG_ERR_PUBKEY_ALGO;
335
336   if (!rc)
337     {
338       rc = gcry_pk_testkey (s_skey);
339       gcry_sexp_release (s_skey);
340     }
341   return rc;
342 }