Started with some code cleanups in ECDH.
[gnupg.git] / g10 / pkglue.c
1 /* pkglue.c - public key operations glue code
2  *      Copyright (C) 2000, 2003, 2010 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 #include "options.h"
32
33 /* FIXME: Better chnage the fucntion name because mpi_ is used by
34    gcrypt macros.  */
35 gcry_mpi_t
36 mpi_from_sexp (gcry_sexp_t sexp, const char * item)
37 {
38   gcry_sexp_t list;
39   gcry_mpi_t data;
40   
41   list = gcry_sexp_find_token (sexp, item, 0);
42   assert (list);
43   data = gcry_sexp_nth_mpi (list, 1, 0);
44   assert (data);
45   gcry_sexp_release (list);
46   return data;
47 }
48
49
50
51 /****************
52  * Emulate our old PK interface here - sometime in the future we might
53  * change the internal design to directly fit to libgcrypt.
54  */
55 int
56 pk_verify (int algo, gcry_mpi_t hash, gcry_mpi_t *data, gcry_mpi_t *pkey)
57 {
58   gcry_sexp_t s_sig, s_hash, s_pkey;
59   int rc;
60   const int pkalgo = map_pk_openpgp_to_gcry (algo);
61
62   /* Make a sexp from pkey.  */
63   if (pkalgo == GCRY_PK_DSA)
64     {
65       rc = gcry_sexp_build (&s_pkey, NULL,
66                             "(public-key(dsa(p%m)(q%m)(g%m)(y%m)))",
67                             pkey[0], pkey[1], pkey[2], pkey[3]);
68     }
69   else if (pkalgo == GCRY_PK_ELG || pkalgo == GCRY_PK_ELG_E)
70     {
71       rc = gcry_sexp_build (&s_pkey, NULL,
72                             "(public-key(elg(p%m)(g%m)(y%m)))",
73                             pkey[0], pkey[1], pkey[2]);
74     }
75   else if (pkalgo == GCRY_PK_RSA || pkalgo == GCRY_PK_RSA_S)
76     {
77       rc = gcry_sexp_build (&s_pkey, NULL,
78                             "(public-key(rsa(n%m)(e%m)))", pkey[0], pkey[1]);
79     }
80   else if (pkalgo == GCRY_PK_ECDSA) /* Same as GCRY_PK_ECDH */
81     {
82       rc = gcry_sexp_build (&s_pkey, NULL,
83                             "(public-key(ecdsa(c%m)(q%m)))", pkey[0], pkey[1]);
84     }
85   else
86     return GPG_ERR_PUBKEY_ALGO;
87
88   if (rc)
89     BUG ();  /* gcry_sexp_build should never fail.  */
90
91   /* Put hash into a S-Exp s_hash. */
92   if (gcry_sexp_build (&s_hash, NULL, "%m", hash))
93     BUG (); /* gcry_sexp_build should never fail.  */
94
95   /* Put data into a S-Exp s_sig. */
96   s_sig = NULL;
97   if (pkalgo == GCRY_PK_DSA)
98     {
99       if (!data[0] || !data[1])
100         rc = gpg_error (GPG_ERR_BAD_MPI);
101       else
102         rc = gcry_sexp_build (&s_sig, NULL,
103                               "(sig-val(dsa(r%m)(s%m)))", data[0], data[1]);
104     }
105   else if (pkalgo == GCRY_PK_ECDSA)
106     {
107       if (!data[0] || !data[1])
108         rc = gpg_error (GPG_ERR_BAD_MPI);
109       else
110         rc = gcry_sexp_build (&s_sig, NULL,
111                               "(sig-val(ecdsa(r%m)(s%m)))", data[0], data[1]);
112     }
113   else if (pkalgo == GCRY_PK_ELG || pkalgo == GCRY_PK_ELG_E)
114     {
115       if (!data[0] || !data[1])
116         rc = gpg_error (GPG_ERR_BAD_MPI);
117       else
118         rc = gcry_sexp_build (&s_sig, NULL,
119                               "(sig-val(elg(r%m)(s%m)))", data[0], data[1]);
120     }
121   else if (pkalgo == GCRY_PK_RSA || pkalgo == GCRY_PK_RSA_S)
122     {
123       if (!data[0])
124         rc = gpg_error (GPG_ERR_BAD_MPI);
125       else
126         rc = gcry_sexp_build (&s_sig, NULL, "(sig-val(rsa(s%m)))", data[0]);
127     }
128   else
129     BUG ();
130
131   if (!rc)
132     rc = gcry_pk_verify (s_sig, s_hash, s_pkey);
133
134   gcry_sexp_release (s_sig);
135   gcry_sexp_release (s_hash);
136   gcry_sexp_release (s_pkey);
137   return rc;
138 }
139
140
141
142
143 /****************
144  * Emulate our old PK interface here - sometime in the future we might
145  * change the internal design to directly fit to libgcrypt.
146  */
147 int
148 pk_encrypt (int algo, gcry_mpi_t *resarr, gcry_mpi_t data,
149             const byte pk_fp[MAX_FINGERPRINT_LEN], gcry_mpi_t *pkey)
150 {
151   gcry_sexp_t s_ciph, s_data, s_pkey;
152   int rc;
153
154   /* Make a sexp from pkey.  */
155   if (algo == GCRY_PK_ELG || algo == GCRY_PK_ELG_E)
156     {
157       rc = gcry_sexp_build (&s_pkey, NULL,
158                             "(public-key(elg(p%m)(g%m)(y%m)))",
159                             pkey[0], pkey[1], pkey[2]);
160       /* Put DATA into a simplified S-expression.  */
161       if (rc || gcry_sexp_build (&s_data, NULL, "%m", data))
162         BUG ();
163
164     }
165   else if (algo == GCRY_PK_RSA || algo == GCRY_PK_RSA_E)
166     {
167       rc = gcry_sexp_build (&s_pkey, NULL,
168                             "(public-key(rsa(n%m)(e%m)))",
169                             pkey[0], pkey[1]);
170       /* Put DATA into a simplified S-expression.  */
171       if (rc || gcry_sexp_build (&s_data, NULL, "%m", data))
172         BUG ();
173     }
174   else if (algo == PUBKEY_ALGO_ECDH)    
175     {
176       gcry_mpi_t k;
177
178       rc = pk_ecdh_generate_ephemeral_key (pkey, &k);
179       if (rc)
180         return rc;
181       
182       /* Now use the ephemeral secret to compute the shared point.  */
183       rc = gcry_sexp_build (&s_pkey, NULL,
184                             "(public-key(ecdh(c%m)(q%m)(p%m)))",
185                             pkey[0], pkey[1], pkey[2]);
186       /* Put K into a simplified S-expression.  */
187       if (rc || gcry_sexp_build (&s_data, NULL, "%m", k))
188         BUG ();
189     }
190   else
191     return gpg_error (GPG_ERR_PUBKEY_ALGO);
192
193
194   /* Pass it to libgcrypt. */
195   rc = gcry_pk_encrypt (&s_ciph, s_data, s_pkey);
196   gcry_sexp_release (s_data);
197   gcry_sexp_release (s_pkey);
198
199   if (rc)
200     ;
201   else if (algo == PUBKEY_ALGO_ECDH)    
202     {
203       gcry_mpi_t shared, public, result;
204
205       /* Get the shared point and the ephemeral public key.  */
206       shared = mpi_from_sexp (s_ciph, "a"); 
207       public = mpi_from_sexp (s_ciph, "b");
208       gcry_sexp_release (s_ciph);
209       s_ciph = NULL;
210       if (DBG_CIPHER)
211         {
212           log_debug ("ECDH ephemeral key:");
213           gcry_mpi_dump (public);
214           log_printf ("\n");
215         }
216     
217       result = NULL;
218       rc = pk_ecdh_encrypt_with_shared_point (1 /*=encrypton*/, shared,
219                                               pk_fp, data, pkey, &result);
220       gcry_mpi_release (shared);
221       if (!rc)
222         {
223           resarr[0] = public;
224           resarr[1] = result;
225         }
226       else
227         {
228           gcry_mpi_release (public);
229           gcry_mpi_release (result);
230         }
231     }
232   else /* Elgamal or RSA case.  */
233     { /* Fixme: Add better error handling or make gnupg use
234          S-expressions directly.  */
235       resarr[0] = mpi_from_sexp (s_ciph, "a");
236       if (algo != GCRY_PK_RSA && algo != GCRY_PK_RSA_E)
237         resarr[1] = mpi_from_sexp (s_ciph, "b");
238     }
239
240   gcry_sexp_release (s_ciph);
241   return rc;
242 }
243
244
245 /* Check whether SKEY is a suitable secret key. */
246 int
247 pk_check_secret_key (int algo, gcry_mpi_t *skey)
248 {
249   gcry_sexp_t s_skey;
250   int rc;
251   const int gcry_pkalgo = map_pk_openpgp_to_gcry( algo );
252
253   if (gcry_pkalgo == GCRY_PK_DSA)
254     {
255       rc = gcry_sexp_build (&s_skey, NULL,
256                             "(private-key(dsa(p%m)(q%m)(g%m)(y%m)(x%m)))",
257                             skey[0], skey[1], skey[2], skey[3], skey[4]);
258     }
259   else if (gcry_pkalgo == GCRY_PK_ELG || gcry_pkalgo == GCRY_PK_ELG_E)
260     {
261       rc = gcry_sexp_build (&s_skey, NULL,
262                             "(private-key(elg(p%m)(g%m)(y%m)(x%m)))",
263                             skey[0], skey[1], skey[2], skey[3]);
264     }
265   else if (gcry_pkalgo == GCRY_PK_RSA
266            || gcry_pkalgo == GCRY_PK_RSA_S || gcry_pkalgo == GCRY_PK_RSA_E)
267     {
268       rc = gcry_sexp_build (&s_skey, NULL,
269                             "(private-key(rsa(n%m)(e%m)(d%m)(p%m)(q%m)(u%m)))",
270                             skey[0], skey[1], skey[2], skey[3], skey[4],
271                             skey[5]);
272     }
273   else if (gcry_pkalgo == GCRY_PK_ECDSA || gcry_pkalgo == GCRY_PK_ECDH)
274     {
275       rc = gcry_sexp_build (&s_skey, NULL,
276                             "(private-key(ecdsa(c%m)(q%m)(d%m)))",
277                             skey[0], skey[1], skey[2] );
278     }
279   else
280     return GPG_ERR_PUBKEY_ALGO;
281
282   if (!rc)
283     {
284       rc = gcry_pk_testkey (s_skey);
285       gcry_sexp_release (s_skey);
286     }
287   return rc;
288 }