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