Do not run the setuid test if running under as root proper.
[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, 0);
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)
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)
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)
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 ();
138
139   /* put hash into a S-Exp s_hash */
140   if (gcry_sexp_build (&s_hash, NULL, "%m", hash))
141     BUG ();
142
143   /* put data into a S-Exp s_sig */
144   if (algo == GCRY_PK_DSA)
145     {
146       if (!data[0] || !data[1])
147         rc = gpg_error (GPG_ERR_BAD_MPI);
148       else
149         rc = gcry_sexp_build (&s_sig, NULL,
150                               "(sig-val(dsa(r%m)(s%m)))", data[0], data[1]);
151     }
152   else if (algo == GCRY_PK_ELG || algo == GCRY_PK_ELG_E)
153     {
154       if (!data[0] || !data[1])
155         rc = gpg_error (GPG_ERR_BAD_MPI);
156       else
157         rc = gcry_sexp_build (&s_sig, NULL,
158                               "(sig-val(elg(r%m)(s%m)))", data[0], data[1]);
159     }
160   else if (algo == GCRY_PK_RSA)
161     {
162       if (!data[0])
163         rc = gpg_error (GPG_ERR_BAD_MPI);
164       else
165         rc = gcry_sexp_build (&s_sig, NULL, "(sig-val(rsa(s%m)))", data[0]);
166     }
167   else
168     BUG ();
169
170   if (rc)
171     BUG ();
172
173
174   rc = gcry_pk_verify (s_sig, s_hash, s_pkey);
175   gcry_sexp_release (s_sig);
176   gcry_sexp_release (s_hash);
177   gcry_sexp_release (s_pkey);
178   return rc;
179 }
180
181
182
183
184 /****************
185  * Emulate our old PK interface here - sometime in the future we might
186  * change the internal design to directly fit to libgcrypt.
187  */
188 int
189 pk_encrypt (int algo, gcry_mpi_t * resarr, gcry_mpi_t data, gcry_mpi_t * pkey)
190 {
191   gcry_sexp_t s_ciph, s_data, s_pkey;
192   int rc;
193
194   /* make a sexp from pkey */
195   if (algo == GCRY_PK_ELG || algo == GCRY_PK_ELG_E)
196     {
197       rc = gcry_sexp_build (&s_pkey, NULL,
198                             "(public-key(elg(p%m)(g%m)(y%m)))",
199                             pkey[0], pkey[1], pkey[2]);
200     }
201   else if (algo == GCRY_PK_RSA)
202     {
203       rc = gcry_sexp_build (&s_pkey, NULL,
204                             "(public-key(rsa(n%m)(e%m)))",
205                             pkey[0], pkey[1]);
206     }
207   else
208     return GPG_ERR_PUBKEY_ALGO;
209
210   if (rc)
211     BUG ();
212
213   /* put the data into a simple list */
214   if (gcry_sexp_build (&s_data, NULL, "%m", data))
215     BUG ();
216
217   /* pass it to libgcrypt */
218   rc = gcry_pk_encrypt (&s_ciph, s_data, s_pkey);
219   gcry_sexp_release (s_data);
220   gcry_sexp_release (s_pkey);
221
222   if (rc)
223     ;
224   else
225     { /* add better error handling or make gnupg use S-Exp directly */
226       resarr[0] = mpi_from_sexp (s_ciph, "a");
227       if (algo != GCRY_PK_RSA)
228         resarr[1] = mpi_from_sexp (s_ciph, "b");
229     }
230
231   gcry_sexp_release (s_ciph);
232   return rc;
233 }
234
235
236
237 /****************
238  * Emulate our old PK interface here - sometime in the future we might
239  * change the internal design to directly fit to libgcrypt.
240  */
241 int
242 pk_decrypt (int algo, gcry_mpi_t * result, gcry_mpi_t * data,
243             gcry_mpi_t * skey)
244 {
245   gcry_sexp_t s_skey, s_data, s_plain;
246   int rc;
247
248   *result = NULL;
249   /* make a sexp from skey */
250   if (algo == GCRY_PK_ELG || algo == GCRY_PK_ELG_E)
251     {
252       rc = gcry_sexp_build (&s_skey, NULL,
253                             "(private-key(elg(p%m)(g%m)(y%m)(x%m)))",
254                             skey[0], skey[1], skey[2], skey[3]);
255     }
256   else if (algo == GCRY_PK_RSA)
257     {
258       rc = gcry_sexp_build (&s_skey, NULL,
259                             "(private-key(rsa(n%m)(e%m)(d%m)(p%m)(q%m)(u%m)))",
260                             skey[0], skey[1], skey[2], skey[3], skey[4],
261                             skey[5]);
262     }
263   else
264     return GPG_ERR_PUBKEY_ALGO;
265
266   if (rc)
267     BUG ();
268
269   /* put data into a S-Exp s_data */
270   if (algo == GCRY_PK_ELG || algo == GCRY_PK_ELG_E)
271     {
272       if (!data[0] || !data[1])
273         rc = gpg_error (GPG_ERR_BAD_MPI);
274       else
275         rc = gcry_sexp_build (&s_data, NULL,
276                               "(enc-val(elg(a%m)(b%m)))", data[0], data[1]);
277     }
278   else if (algo == GCRY_PK_RSA)
279     {
280       if (!data[0])
281         rc = gpg_error (GPG_ERR_BAD_MPI);
282       else
283         rc = gcry_sexp_build (&s_data, NULL, "(enc-val(rsa(a%m)))", data[0]);
284     }
285   else
286     BUG ();
287
288   if (rc)
289     BUG ();
290
291   rc = gcry_pk_decrypt (&s_plain, s_data, s_skey);
292   gcry_sexp_release (s_skey);
293   gcry_sexp_release (s_data);
294   if (rc)
295     return rc;
296
297   *result = gcry_sexp_nth_mpi (s_plain, 0, 0);
298   gcry_sexp_release (s_plain);
299   if (!*result)
300     return -1;                  /* oops */
301
302   return 0;
303 }
304
305
306 /* Check whether SKEY is a suitable secret key. */
307 int
308 pk_check_secret_key (int algo, gcry_mpi_t *skey)
309 {
310   gcry_sexp_t s_skey;
311   int rc;
312
313   if (algo == GCRY_PK_DSA)
314     {
315       rc = gcry_sexp_build (&s_skey, NULL,
316                             "(private-key(dsa(p%m)(q%m)(g%m)(y%m)(x%m)))",
317                             skey[0], skey[1], skey[2], skey[3], skey[4]);
318     }
319   else if (algo == GCRY_PK_ELG || algo == GCRY_PK_ELG_E)
320     {
321       rc = gcry_sexp_build (&s_skey, NULL,
322                             "(private-key(elg(p%m)(g%m)(y%m)(x%m)))",
323                             skey[0], skey[1], skey[2], skey[3]);
324     }
325   else if (algo == GCRY_PK_RSA)
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 }