Line data Source code
1 : /* pkglue.c - public key operations glue code
2 : * Copyright (C) 2000, 2003, 2010 Free Software Foundation, Inc.
3 : * Copyright (C) 2014 Werner Koch
4 : *
5 : * This file is part of GnuPG.
6 : *
7 : * GnuPG is free software; you can redistribute it and/or modify
8 : * it under the terms of the GNU General Public License as published by
9 : * the Free Software Foundation; either version 3 of the License, or
10 : * (at your option) any later version.
11 : *
12 : * GnuPG is distributed in the hope that it will be useful,
13 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 : * GNU General Public License for more details.
16 : *
17 : * You should have received a copy of the GNU General Public License
18 : * along with this program; if not, see <http://www.gnu.org/licenses/>.
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 : #include "main.h"
32 : #include "options.h"
33 :
34 : /* FIXME: Better chnage the fucntion name because mpi_ is used by
35 : gcrypt macros. */
36 : gcry_mpi_t
37 704 : get_mpi_from_sexp (gcry_sexp_t sexp, const char *item, int mpifmt)
38 : {
39 : gcry_sexp_t list;
40 : gcry_mpi_t data;
41 :
42 704 : list = gcry_sexp_find_token (sexp, item, 0);
43 704 : assert (list);
44 704 : data = gcry_sexp_nth_mpi (list, 1, mpifmt);
45 704 : assert (data);
46 704 : gcry_sexp_release (list);
47 704 : return data;
48 : }
49 :
50 :
51 :
52 : /****************
53 : * Emulate our old PK interface here - sometime in the future we might
54 : * change the internal design to directly fit to libgcrypt.
55 : */
56 : int
57 367 : pk_verify (pubkey_algo_t pkalgo, gcry_mpi_t hash,
58 : gcry_mpi_t *data, gcry_mpi_t *pkey)
59 : {
60 : gcry_sexp_t s_sig, s_hash, s_pkey;
61 : int rc;
62 :
63 : /* Make a sexp from pkey. */
64 367 : if (pkalgo == PUBKEY_ALGO_DSA)
65 : {
66 882 : rc = gcry_sexp_build (&s_pkey, NULL,
67 : "(public-key(dsa(p%m)(q%m)(g%m)(y%m)))",
68 882 : pkey[0], pkey[1], pkey[2], pkey[3]);
69 : }
70 73 : else if (pkalgo == PUBKEY_ALGO_ELGAMAL_E || pkalgo == PUBKEY_ALGO_ELGAMAL)
71 : {
72 0 : rc = gcry_sexp_build (&s_pkey, NULL,
73 : "(public-key(elg(p%m)(g%m)(y%m)))",
74 0 : pkey[0], pkey[1], pkey[2]);
75 : }
76 73 : else if (pkalgo == PUBKEY_ALGO_RSA || pkalgo == PUBKEY_ALGO_RSA_S)
77 : {
78 36 : rc = gcry_sexp_build (&s_pkey, NULL,
79 36 : "(public-key(rsa(n%m)(e%m)))", pkey[0], pkey[1]);
80 : }
81 37 : else if (pkalgo == PUBKEY_ALGO_ECDSA)
82 : {
83 37 : char *curve = openpgp_oid_to_str (pkey[0]);
84 37 : if (!curve)
85 0 : rc = gpg_error_from_syserror ();
86 : else
87 : {
88 37 : rc = gcry_sexp_build (&s_pkey, NULL,
89 : "(public-key(ecdsa(curve %s)(q%m)))",
90 37 : curve, pkey[1]);
91 37 : xfree (curve);
92 : }
93 : }
94 0 : else if (pkalgo == PUBKEY_ALGO_EDDSA)
95 : {
96 0 : char *curve = openpgp_oid_to_str (pkey[0]);
97 0 : if (!curve)
98 0 : rc = gpg_error_from_syserror ();
99 : else
100 : {
101 0 : rc = gcry_sexp_build (&s_pkey, NULL,
102 : "(public-key(ecc(curve %s)"
103 : "(flags eddsa)(q%m)))",
104 0 : curve, pkey[1]);
105 0 : xfree (curve);
106 : }
107 : }
108 : else
109 0 : return GPG_ERR_PUBKEY_ALGO;
110 :
111 367 : if (rc)
112 0 : BUG (); /* gcry_sexp_build should never fail. */
113 :
114 : /* Put hash into a S-Exp s_hash. */
115 367 : if (pkalgo == PUBKEY_ALGO_EDDSA)
116 : {
117 0 : if (gcry_sexp_build (&s_hash, NULL,
118 : "(data(flags eddsa)(hash-algo sha512)(value %m))",
119 : hash))
120 0 : BUG (); /* gcry_sexp_build should never fail. */
121 : }
122 : else
123 : {
124 367 : if (gcry_sexp_build (&s_hash, NULL, "%m", hash))
125 0 : BUG (); /* gcry_sexp_build should never fail. */
126 : }
127 :
128 : /* Put data into a S-Exp s_sig. */
129 367 : s_sig = NULL;
130 367 : if (pkalgo == PUBKEY_ALGO_DSA)
131 : {
132 294 : if (!data[0] || !data[1])
133 0 : rc = gpg_error (GPG_ERR_BAD_MPI);
134 : else
135 294 : rc = gcry_sexp_build (&s_sig, NULL,
136 294 : "(sig-val(dsa(r%m)(s%m)))", data[0], data[1]);
137 : }
138 73 : else if (pkalgo == PUBKEY_ALGO_ECDSA)
139 : {
140 37 : if (!data[0] || !data[1])
141 0 : rc = gpg_error (GPG_ERR_BAD_MPI);
142 : else
143 37 : rc = gcry_sexp_build (&s_sig, NULL,
144 37 : "(sig-val(ecdsa(r%m)(s%m)))", data[0], data[1]);
145 : }
146 36 : else if (pkalgo == PUBKEY_ALGO_EDDSA)
147 : {
148 0 : if (!data[0] || !data[1])
149 0 : rc = gpg_error (GPG_ERR_BAD_MPI);
150 : else
151 0 : rc = gcry_sexp_build (&s_sig, NULL,
152 0 : "(sig-val(eddsa(r%M)(s%M)))", data[0], data[1]);
153 : }
154 36 : else if (pkalgo == PUBKEY_ALGO_ELGAMAL || pkalgo == PUBKEY_ALGO_ELGAMAL_E)
155 : {
156 0 : if (!data[0] || !data[1])
157 0 : rc = gpg_error (GPG_ERR_BAD_MPI);
158 : else
159 0 : rc = gcry_sexp_build (&s_sig, NULL,
160 0 : "(sig-val(elg(r%m)(s%m)))", data[0], data[1]);
161 : }
162 36 : else if (pkalgo == PUBKEY_ALGO_RSA || pkalgo == PUBKEY_ALGO_RSA_S)
163 : {
164 72 : if (!data[0])
165 0 : rc = gpg_error (GPG_ERR_BAD_MPI);
166 : else
167 36 : rc = gcry_sexp_build (&s_sig, NULL, "(sig-val(rsa(s%m)))", data[0]);
168 : }
169 : else
170 0 : BUG ();
171 :
172 367 : if (!rc)
173 367 : rc = gcry_pk_verify (s_sig, s_hash, s_pkey);
174 :
175 367 : gcry_sexp_release (s_sig);
176 367 : gcry_sexp_release (s_hash);
177 367 : gcry_sexp_release (s_pkey);
178 367 : 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 : * PK is only required to compute the fingerprint for ECDH.
188 : */
189 : int
190 236 : pk_encrypt (pubkey_algo_t algo, gcry_mpi_t *resarr, gcry_mpi_t data,
191 : PKT_public_key *pk, gcry_mpi_t *pkey)
192 : {
193 236 : gcry_sexp_t s_ciph = NULL;
194 236 : gcry_sexp_t s_data = NULL;
195 236 : gcry_sexp_t s_pkey = NULL;
196 : int rc;
197 :
198 : /* Make a sexp from pkey. */
199 236 : if (algo == PUBKEY_ALGO_ELGAMAL || algo == PUBKEY_ALGO_ELGAMAL_E)
200 : {
201 430 : rc = gcry_sexp_build (&s_pkey, NULL,
202 : "(public-key(elg(p%m)(g%m)(y%m)))",
203 430 : pkey[0], pkey[1], pkey[2]);
204 : /* Put DATA into a simplified S-expression. */
205 430 : if (!rc)
206 215 : rc = gcry_sexp_build (&s_data, NULL, "%m", data);
207 : }
208 21 : else if (algo == PUBKEY_ALGO_RSA || algo == PUBKEY_ALGO_RSA_E)
209 : {
210 0 : rc = gcry_sexp_build (&s_pkey, NULL,
211 : "(public-key(rsa(n%m)(e%m)))",
212 0 : pkey[0], pkey[1]);
213 : /* Put DATA into a simplified S-expression. */
214 0 : if (!rc)
215 0 : rc = gcry_sexp_build (&s_data, NULL, "%m", data);
216 : }
217 21 : else if (algo == PUBKEY_ALGO_ECDH)
218 : {
219 : gcry_mpi_t k;
220 :
221 21 : rc = pk_ecdh_generate_ephemeral_key (pkey, &k);
222 21 : if (!rc)
223 : {
224 : char *curve;
225 :
226 21 : curve = openpgp_oid_to_str (pkey[0]);
227 21 : if (!curve)
228 0 : rc = gpg_error_from_syserror ();
229 : else
230 : {
231 21 : int with_djb_tweak_flag = openpgp_oid_is_crv25519 (pkey[0]);
232 :
233 : /* Now use the ephemeral secret to compute the shared point. */
234 21 : rc = gcry_sexp_build (&s_pkey, NULL,
235 : with_djb_tweak_flag ?
236 : "(public-key(ecdh(curve%s)(flags djb-tweak)(q%m)))"
237 : : "(public-key(ecdh(curve%s)(q%m)))",
238 21 : curve, pkey[1]);
239 21 : xfree (curve);
240 : /* Put K into a simplified S-expression. */
241 21 : if (!rc)
242 21 : rc = gcry_sexp_build (&s_data, NULL, "%m", k);
243 : }
244 21 : gcry_mpi_release (k);
245 : }
246 : }
247 : else
248 0 : rc = gpg_error (GPG_ERR_PUBKEY_ALGO);
249 :
250 : /* Pass it to libgcrypt. */
251 236 : if (!rc)
252 236 : rc = gcry_pk_encrypt (&s_ciph, s_data, s_pkey);
253 :
254 236 : gcry_sexp_release (s_data);
255 236 : gcry_sexp_release (s_pkey);
256 :
257 236 : if (rc)
258 : ;
259 236 : else if (algo == PUBKEY_ALGO_ECDH)
260 : {
261 : gcry_mpi_t shared, public, result;
262 : byte fp[MAX_FINGERPRINT_LEN];
263 : size_t fpn;
264 :
265 : /* Get the shared point and the ephemeral public key. */
266 21 : shared = get_mpi_from_sexp (s_ciph, "s", GCRYMPI_FMT_USG);
267 21 : public = get_mpi_from_sexp (s_ciph, "e", GCRYMPI_FMT_USG);
268 21 : gcry_sexp_release (s_ciph);
269 21 : s_ciph = NULL;
270 21 : if (DBG_CRYPTO)
271 : {
272 0 : log_debug ("ECDH ephemeral key:");
273 0 : gcry_mpi_dump (public);
274 0 : log_printf ("\n");
275 : }
276 :
277 21 : result = NULL;
278 21 : fingerprint_from_pk (pk, fp, &fpn);
279 21 : if (fpn != 20)
280 0 : rc = gpg_error (GPG_ERR_INV_LENGTH);
281 : else
282 21 : rc = pk_ecdh_encrypt_with_shared_point (1 /*=encrypton*/, shared,
283 : fp, data, pkey, &result);
284 21 : gcry_mpi_release (shared);
285 21 : if (!rc)
286 : {
287 21 : resarr[0] = public;
288 21 : resarr[1] = result;
289 : }
290 : else
291 : {
292 0 : gcry_mpi_release (public);
293 0 : gcry_mpi_release (result);
294 : }
295 : }
296 : else /* Elgamal or RSA case. */
297 : { /* Fixme: Add better error handling or make gnupg use
298 : S-expressions directly. */
299 215 : resarr[0] = get_mpi_from_sexp (s_ciph, "a", GCRYMPI_FMT_USG);
300 215 : if (!is_RSA (algo))
301 215 : resarr[1] = get_mpi_from_sexp (s_ciph, "b", GCRYMPI_FMT_USG);
302 : }
303 :
304 236 : gcry_sexp_release (s_ciph);
305 236 : return rc;
306 : }
307 :
308 :
309 : /* Check whether SKEY is a suitable secret key. */
310 : int
311 0 : pk_check_secret_key (pubkey_algo_t pkalgo, gcry_mpi_t *skey)
312 : {
313 : gcry_sexp_t s_skey;
314 : int rc;
315 :
316 0 : if (pkalgo == PUBKEY_ALGO_DSA)
317 : {
318 0 : rc = gcry_sexp_build (&s_skey, NULL,
319 : "(private-key(dsa(p%m)(q%m)(g%m)(y%m)(x%m)))",
320 0 : skey[0], skey[1], skey[2], skey[3], skey[4]);
321 : }
322 0 : else if (pkalgo == PUBKEY_ALGO_ELGAMAL || pkalgo == PUBKEY_ALGO_ELGAMAL_E)
323 : {
324 0 : rc = gcry_sexp_build (&s_skey, NULL,
325 : "(private-key(elg(p%m)(g%m)(y%m)(x%m)))",
326 0 : skey[0], skey[1], skey[2], skey[3]);
327 : }
328 0 : else if (is_RSA (pkalgo))
329 : {
330 0 : rc = gcry_sexp_build (&s_skey, NULL,
331 : "(private-key(rsa(n%m)(e%m)(d%m)(p%m)(q%m)(u%m)))",
332 0 : skey[0], skey[1], skey[2], skey[3], skey[4],
333 0 : skey[5]);
334 : }
335 0 : else if (pkalgo == PUBKEY_ALGO_ECDSA || pkalgo == PUBKEY_ALGO_ECDH)
336 0 : {
337 0 : char *curve = openpgp_oid_to_str (skey[0]);
338 0 : if (!curve)
339 0 : rc = gpg_error_from_syserror ();
340 : else
341 : {
342 0 : rc = gcry_sexp_build (&s_skey, NULL,
343 : "(private-key(ecc(curve%s)(q%m)(d%m)))",
344 0 : curve, skey[1], skey[2]);
345 0 : xfree (curve);
346 : }
347 : }
348 0 : else if (pkalgo == PUBKEY_ALGO_EDDSA)
349 : {
350 0 : char *curve = openpgp_oid_to_str (skey[0]);
351 0 : if (!curve)
352 0 : rc = gpg_error_from_syserror ();
353 : else
354 : {
355 0 : rc = gcry_sexp_build (&s_skey, NULL,
356 : "(private-key(ecc(curve %s)"
357 : "(flags eddsa)(q%m)(d%m)))",
358 0 : curve, skey[1], skey[2]);
359 0 : xfree (curve);
360 : }
361 : }
362 : else
363 0 : return GPG_ERR_PUBKEY_ALGO;
364 :
365 0 : if (!rc)
366 : {
367 0 : rc = gcry_pk_testkey (s_skey);
368 0 : gcry_sexp_release (s_skey);
369 : }
370 0 : return rc;
371 : }
|