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