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 :
27 : #include "gpg.h"
28 : #include "util.h"
29 : #include "pkglue.h"
30 : #include "main.h"
31 : #include "options.h"
32 :
33 : /* FIXME: Better change the function name because mpi_ is used by
34 : gcrypt macros. */
35 : gcry_mpi_t
36 756 : get_mpi_from_sexp (gcry_sexp_t sexp, const char *item, int mpifmt)
37 : {
38 : gcry_sexp_t list;
39 : gcry_mpi_t data;
40 :
41 756 : list = gcry_sexp_find_token (sexp, item, 0);
42 756 : log_assert (list);
43 756 : data = gcry_sexp_nth_mpi (list, 1, mpifmt);
44 756 : log_assert (data);
45 756 : gcry_sexp_release (list);
46 756 : 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 559 : pk_verify (pubkey_algo_t pkalgo, gcry_mpi_t hash,
57 : gcry_mpi_t *data, gcry_mpi_t *pkey)
58 : {
59 : gcry_sexp_t s_sig, s_hash, s_pkey;
60 : int rc;
61 559 : unsigned int neededfixedlen = 0;
62 :
63 : /* Make a sexp from pkey. */
64 559 : if (pkalgo == PUBKEY_ALGO_DSA)
65 : {
66 951 : rc = gcry_sexp_build (&s_pkey, NULL,
67 : "(public-key(dsa(p%m)(q%m)(g%m)(y%m)))",
68 951 : pkey[0], pkey[1], pkey[2], pkey[3]);
69 : }
70 242 : 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 242 : else if (pkalgo == PUBKEY_ALGO_RSA || pkalgo == PUBKEY_ALGO_RSA_S)
77 : {
78 195 : rc = gcry_sexp_build (&s_pkey, NULL,
79 195 : "(public-key(rsa(n%m)(e%m)))", pkey[0], pkey[1]);
80 : }
81 47 : 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 10 : else if (pkalgo == PUBKEY_ALGO_EDDSA)
95 : {
96 10 : char *curve = openpgp_oid_to_str (pkey[0]);
97 10 : if (!curve)
98 0 : rc = gpg_error_from_syserror ();
99 : else
100 : {
101 10 : rc = gcry_sexp_build (&s_pkey, NULL,
102 : "(public-key(ecc(curve %s)"
103 : "(flags eddsa)(q%m)))",
104 10 : curve, pkey[1]);
105 10 : xfree (curve);
106 : }
107 :
108 10 : if (openpgp_oid_is_ed25519 (pkey[0]))
109 10 : neededfixedlen = 256 / 8;
110 : }
111 : else
112 0 : return GPG_ERR_PUBKEY_ALGO;
113 :
114 559 : if (rc)
115 0 : BUG (); /* gcry_sexp_build should never fail. */
116 :
117 : /* Put hash into a S-Exp s_hash. */
118 559 : if (pkalgo == PUBKEY_ALGO_EDDSA)
119 : {
120 10 : if (gcry_sexp_build (&s_hash, NULL,
121 : "(data(flags eddsa)(hash-algo sha512)(value %m))",
122 : hash))
123 0 : BUG (); /* gcry_sexp_build should never fail. */
124 : }
125 : else
126 : {
127 549 : if (gcry_sexp_build (&s_hash, NULL, "%m", hash))
128 0 : BUG (); /* gcry_sexp_build should never fail. */
129 : }
130 :
131 : /* Put data into a S-Exp s_sig. */
132 559 : s_sig = NULL;
133 559 : if (pkalgo == PUBKEY_ALGO_DSA)
134 : {
135 317 : if (!data[0] || !data[1])
136 0 : rc = gpg_error (GPG_ERR_BAD_MPI);
137 : else
138 317 : rc = gcry_sexp_build (&s_sig, NULL,
139 317 : "(sig-val(dsa(r%m)(s%m)))", data[0], data[1]);
140 : }
141 242 : else if (pkalgo == PUBKEY_ALGO_ECDSA)
142 : {
143 37 : if (!data[0] || !data[1])
144 0 : rc = gpg_error (GPG_ERR_BAD_MPI);
145 : else
146 37 : rc = gcry_sexp_build (&s_sig, NULL,
147 37 : "(sig-val(ecdsa(r%m)(s%m)))", data[0], data[1]);
148 : }
149 205 : else if (pkalgo == PUBKEY_ALGO_EDDSA)
150 : {
151 10 : gcry_mpi_t r = data[0];
152 10 : gcry_mpi_t s = data[1];
153 : size_t rlen, slen, n; /* (bytes) */
154 : char buf[64];
155 :
156 10 : log_assert (neededfixedlen <= sizeof buf);
157 :
158 10 : if (!r || !s)
159 0 : rc = gpg_error (GPG_ERR_BAD_MPI);
160 10 : else if ((rlen = (gcry_mpi_get_nbits (r)+7)/8) > neededfixedlen || !rlen)
161 0 : rc = gpg_error (GPG_ERR_BAD_MPI);
162 10 : else if ((slen = (gcry_mpi_get_nbits (s)+7)/8) > neededfixedlen || !slen)
163 0 : rc = gpg_error (GPG_ERR_BAD_MPI);
164 : else
165 : {
166 : /* We need to fixup the length in case of leading zeroes.
167 : * OpenPGP does not allow leading zeroes and the parser for
168 : * the signature packet has no information on the use curve,
169 : * thus we need to do it here. We won't do it for opaque
170 : * MPIs under the assumption that they are known to be fine;
171 : * we won't see them here anyway but the check is anyway
172 : * required. Fixme: A nifty feature for gcry_sexp_build
173 : * would be a format to left pad the value (e.g. "%*M"). */
174 10 : rc = 0;
175 :
176 10 : if (rlen < neededfixedlen
177 1 : && !gcry_mpi_get_flag (r, GCRYMPI_FLAG_OPAQUE)
178 1 : && !(rc=gcry_mpi_print (GCRYMPI_FMT_USG, buf, sizeof buf, &n, r)))
179 : {
180 1 : log_assert (n < neededfixedlen);
181 1 : memmove (buf + (neededfixedlen - n), buf, n);
182 1 : memset (buf, 0, neededfixedlen - n);
183 1 : r = gcry_mpi_set_opaque_copy (NULL, buf, neededfixedlen * 8);
184 : }
185 10 : if (slen < neededfixedlen
186 1 : && !gcry_mpi_get_flag (s, GCRYMPI_FLAG_OPAQUE)
187 1 : && !(rc=gcry_mpi_print (GCRYMPI_FMT_USG, buf, sizeof buf, &n, s)))
188 : {
189 1 : log_assert (n < neededfixedlen);
190 1 : memmove (buf + (neededfixedlen - n), buf, n);
191 1 : memset (buf, 0, neededfixedlen - n);
192 1 : s = gcry_mpi_set_opaque_copy (NULL, buf, neededfixedlen * 8);
193 : }
194 :
195 10 : if (!rc)
196 10 : rc = gcry_sexp_build (&s_sig, NULL,
197 : "(sig-val(eddsa(r%M)(s%M)))", r, s);
198 :
199 10 : if (r != data[0])
200 1 : gcry_mpi_release (r);
201 10 : if (s != data[1])
202 1 : gcry_mpi_release (s);
203 : }
204 : }
205 195 : else if (pkalgo == PUBKEY_ALGO_ELGAMAL || pkalgo == PUBKEY_ALGO_ELGAMAL_E)
206 : {
207 0 : if (!data[0] || !data[1])
208 0 : rc = gpg_error (GPG_ERR_BAD_MPI);
209 : else
210 0 : rc = gcry_sexp_build (&s_sig, NULL,
211 0 : "(sig-val(elg(r%m)(s%m)))", data[0], data[1]);
212 : }
213 195 : else if (pkalgo == PUBKEY_ALGO_RSA || pkalgo == PUBKEY_ALGO_RSA_S)
214 : {
215 390 : if (!data[0])
216 0 : rc = gpg_error (GPG_ERR_BAD_MPI);
217 : else
218 195 : rc = gcry_sexp_build (&s_sig, NULL, "(sig-val(rsa(s%m)))", data[0]);
219 : }
220 : else
221 0 : BUG ();
222 :
223 559 : if (!rc)
224 559 : rc = gcry_pk_verify (s_sig, s_hash, s_pkey);
225 :
226 559 : gcry_sexp_release (s_sig);
227 559 : gcry_sexp_release (s_hash);
228 559 : gcry_sexp_release (s_pkey);
229 559 : return rc;
230 : }
231 :
232 :
233 :
234 :
235 : /****************
236 : * Emulate our old PK interface here - sometime in the future we might
237 : * change the internal design to directly fit to libgcrypt.
238 : * PK is only required to compute the fingerprint for ECDH.
239 : */
240 : int
241 255 : pk_encrypt (pubkey_algo_t algo, gcry_mpi_t *resarr, gcry_mpi_t data,
242 : PKT_public_key *pk, gcry_mpi_t *pkey)
243 : {
244 255 : gcry_sexp_t s_ciph = NULL;
245 255 : gcry_sexp_t s_data = NULL;
246 255 : gcry_sexp_t s_pkey = NULL;
247 : int rc;
248 :
249 : /* Make a sexp from pkey. */
250 255 : if (algo == PUBKEY_ALGO_ELGAMAL || algo == PUBKEY_ALGO_ELGAMAL_E)
251 : {
252 446 : rc = gcry_sexp_build (&s_pkey, NULL,
253 : "(public-key(elg(p%m)(g%m)(y%m)))",
254 446 : pkey[0], pkey[1], pkey[2]);
255 : /* Put DATA into a simplified S-expression. */
256 446 : if (!rc)
257 223 : rc = gcry_sexp_build (&s_data, NULL, "%m", data);
258 : }
259 32 : else if (algo == PUBKEY_ALGO_RSA || algo == PUBKEY_ALGO_RSA_E)
260 : {
261 8 : rc = gcry_sexp_build (&s_pkey, NULL,
262 : "(public-key(rsa(n%m)(e%m)))",
263 8 : pkey[0], pkey[1]);
264 : /* Put DATA into a simplified S-expression. */
265 16 : if (!rc)
266 8 : rc = gcry_sexp_build (&s_data, NULL, "%m", data);
267 : }
268 24 : else if (algo == PUBKEY_ALGO_ECDH)
269 : {
270 : gcry_mpi_t k;
271 :
272 24 : rc = pk_ecdh_generate_ephemeral_key (pkey, &k);
273 24 : if (!rc)
274 : {
275 : char *curve;
276 :
277 24 : curve = openpgp_oid_to_str (pkey[0]);
278 24 : if (!curve)
279 0 : rc = gpg_error_from_syserror ();
280 : else
281 : {
282 24 : int with_djb_tweak_flag = openpgp_oid_is_cv25519 (pkey[0]);
283 :
284 : /* Now use the ephemeral secret to compute the shared point. */
285 24 : rc = gcry_sexp_build (&s_pkey, NULL,
286 : with_djb_tweak_flag ?
287 : "(public-key(ecdh(curve%s)(flags djb-tweak)(q%m)))"
288 : : "(public-key(ecdh(curve%s)(q%m)))",
289 24 : curve, pkey[1]);
290 24 : xfree (curve);
291 : /* Put K into a simplified S-expression. */
292 24 : if (!rc)
293 24 : rc = gcry_sexp_build (&s_data, NULL, "%m", k);
294 : }
295 24 : gcry_mpi_release (k);
296 : }
297 : }
298 : else
299 0 : rc = gpg_error (GPG_ERR_PUBKEY_ALGO);
300 :
301 : /* Pass it to libgcrypt. */
302 255 : if (!rc)
303 255 : rc = gcry_pk_encrypt (&s_ciph, s_data, s_pkey);
304 :
305 255 : gcry_sexp_release (s_data);
306 255 : gcry_sexp_release (s_pkey);
307 :
308 255 : if (rc)
309 : ;
310 255 : else if (algo == PUBKEY_ALGO_ECDH)
311 : {
312 : gcry_mpi_t shared, public, result;
313 : byte fp[MAX_FINGERPRINT_LEN];
314 : size_t fpn;
315 :
316 : /* Get the shared point and the ephemeral public key. */
317 24 : shared = get_mpi_from_sexp (s_ciph, "s", GCRYMPI_FMT_USG);
318 24 : public = get_mpi_from_sexp (s_ciph, "e", GCRYMPI_FMT_USG);
319 24 : gcry_sexp_release (s_ciph);
320 24 : s_ciph = NULL;
321 24 : if (DBG_CRYPTO)
322 : {
323 0 : log_debug ("ECDH ephemeral key:");
324 0 : gcry_mpi_dump (public);
325 0 : log_printf ("\n");
326 : }
327 :
328 24 : result = NULL;
329 24 : fingerprint_from_pk (pk, fp, &fpn);
330 24 : if (fpn != 20)
331 0 : rc = gpg_error (GPG_ERR_INV_LENGTH);
332 : else
333 24 : rc = pk_ecdh_encrypt_with_shared_point (1 /*=encrypton*/, shared,
334 : fp, data, pkey, &result);
335 24 : gcry_mpi_release (shared);
336 24 : if (!rc)
337 : {
338 24 : resarr[0] = public;
339 24 : resarr[1] = result;
340 : }
341 : else
342 : {
343 0 : gcry_mpi_release (public);
344 0 : gcry_mpi_release (result);
345 : }
346 : }
347 : else /* Elgamal or RSA case. */
348 : { /* Fixme: Add better error handling or make gnupg use
349 : S-expressions directly. */
350 231 : resarr[0] = get_mpi_from_sexp (s_ciph, "a", GCRYMPI_FMT_USG);
351 231 : if (!is_RSA (algo))
352 223 : resarr[1] = get_mpi_from_sexp (s_ciph, "b", GCRYMPI_FMT_USG);
353 : }
354 :
355 255 : gcry_sexp_release (s_ciph);
356 255 : return rc;
357 : }
358 :
359 :
360 : /* Check whether SKEY is a suitable secret key. */
361 : int
362 0 : pk_check_secret_key (pubkey_algo_t pkalgo, gcry_mpi_t *skey)
363 : {
364 : gcry_sexp_t s_skey;
365 : int rc;
366 :
367 0 : if (pkalgo == PUBKEY_ALGO_DSA)
368 : {
369 0 : rc = gcry_sexp_build (&s_skey, NULL,
370 : "(private-key(dsa(p%m)(q%m)(g%m)(y%m)(x%m)))",
371 0 : skey[0], skey[1], skey[2], skey[3], skey[4]);
372 : }
373 0 : else if (pkalgo == PUBKEY_ALGO_ELGAMAL || pkalgo == PUBKEY_ALGO_ELGAMAL_E)
374 : {
375 0 : rc = gcry_sexp_build (&s_skey, NULL,
376 : "(private-key(elg(p%m)(g%m)(y%m)(x%m)))",
377 0 : skey[0], skey[1], skey[2], skey[3]);
378 : }
379 0 : else if (is_RSA (pkalgo))
380 : {
381 0 : rc = gcry_sexp_build (&s_skey, NULL,
382 : "(private-key(rsa(n%m)(e%m)(d%m)(p%m)(q%m)(u%m)))",
383 0 : skey[0], skey[1], skey[2], skey[3], skey[4],
384 0 : skey[5]);
385 : }
386 0 : else if (pkalgo == PUBKEY_ALGO_ECDSA || pkalgo == PUBKEY_ALGO_ECDH)
387 0 : {
388 0 : char *curve = openpgp_oid_to_str (skey[0]);
389 0 : if (!curve)
390 0 : rc = gpg_error_from_syserror ();
391 : else
392 : {
393 0 : rc = gcry_sexp_build (&s_skey, NULL,
394 : "(private-key(ecc(curve%s)(q%m)(d%m)))",
395 0 : curve, skey[1], skey[2]);
396 0 : xfree (curve);
397 : }
398 : }
399 0 : else if (pkalgo == PUBKEY_ALGO_EDDSA)
400 : {
401 0 : char *curve = openpgp_oid_to_str (skey[0]);
402 0 : if (!curve)
403 0 : rc = gpg_error_from_syserror ();
404 : else
405 : {
406 0 : rc = gcry_sexp_build (&s_skey, NULL,
407 : "(private-key(ecc(curve %s)"
408 : "(flags eddsa)(q%m)(d%m)))",
409 0 : curve, skey[1], skey[2]);
410 0 : xfree (curve);
411 : }
412 : }
413 : else
414 0 : return GPG_ERR_PUBKEY_ALGO;
415 :
416 0 : if (!rc)
417 : {
418 0 : rc = gcry_pk_testkey (s_skey);
419 0 : gcry_sexp_release (s_skey);
420 : }
421 0 : return rc;
422 : }
|