Line | Count | Source |
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 | | * Copyright (C) 2024 g10 Code GmbH. |
5 | | * |
6 | | * This file is part of GnuPG. |
7 | | * |
8 | | * GnuPG is free software; you can redistribute it and/or modify |
9 | | * it under the terms of the GNU General Public License as published by |
10 | | * the Free Software Foundation; either version 3 of the License, or |
11 | | * (at your option) any later version. |
12 | | * |
13 | | * GnuPG is distributed in the hope that it will be useful, |
14 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16 | | * GNU General Public License for more details. |
17 | | * |
18 | | * You should have received a copy of the GNU General Public License |
19 | | * along with this program; if not, see <https://www.gnu.org/licenses/>. |
20 | | * SPDX-License-Identifier: GPL-3.0-or-later |
21 | | */ |
22 | | |
23 | | #include <config.h> |
24 | | #include <stdio.h> |
25 | | #include <stdlib.h> |
26 | | #include <string.h> |
27 | | #include <errno.h> |
28 | | |
29 | | #include "gpg.h" |
30 | | #include "../common/util.h" |
31 | | #include "pkglue.h" |
32 | | #include "main.h" |
33 | | #include "options.h" |
34 | | |
35 | | |
36 | | /* FIXME: Better change the function name because mpi_ is used by |
37 | | gcrypt macros. */ |
38 | | gcry_mpi_t |
39 | | get_mpi_from_sexp (gcry_sexp_t sexp, const char *item, int mpifmt) |
40 | 0 | { |
41 | 0 | gcry_sexp_t list; |
42 | 0 | gcry_mpi_t data; |
43 | |
|
44 | 0 | list = gcry_sexp_find_token (sexp, item, 0); |
45 | 0 | log_assert (list); |
46 | 0 | data = gcry_sexp_nth_mpi (list, 1, mpifmt); |
47 | 0 | log_assert (data); |
48 | 0 | gcry_sexp_release (list); |
49 | 0 | return data; |
50 | 0 | } |
51 | | |
52 | | |
53 | | /* |
54 | | * SOS (Simply, Octet String) is an attempt to handle opaque octet |
55 | | * string in OpenPGP, where well-formed MPI cannot represent octet |
56 | | * string with leading zero octets. |
57 | | * |
58 | | * To retain maximum compatibility to existing MPI handling, SOS |
59 | | * has same structure, but allows leading zero octets. When there |
60 | | * is no leading zero octets, SOS representation is as same as MPI one. |
61 | | * With leading zero octets, NBITS is 8*(length of octets), regardless |
62 | | * of leading zero bits. |
63 | | */ |
64 | | /* Extract SOS representation from SEXP for PARAM, return the result |
65 | | * in R_SOS. It is represented by opaque MPI with GCRYMPI_FLAG_USER2 |
66 | | * flag. */ |
67 | | gpg_error_t |
68 | | sexp_extract_param_sos (gcry_sexp_t sexp, const char *param, gcry_mpi_t *r_sos) |
69 | 0 | { |
70 | 0 | gpg_error_t err; |
71 | 0 | gcry_sexp_t l2 = gcry_sexp_find_token (sexp, param, 0); |
72 | |
|
73 | 0 | *r_sos = NULL; |
74 | 0 | if (!l2) |
75 | 0 | err = gpg_error (GPG_ERR_NO_OBJ); |
76 | 0 | else |
77 | 0 | { |
78 | 0 | size_t buflen; |
79 | 0 | void *p0 = gcry_sexp_nth_buffer (l2, 1, &buflen); |
80 | |
|
81 | 0 | if (!p0) |
82 | 0 | err = gpg_error_from_syserror (); |
83 | 0 | else |
84 | 0 | { |
85 | 0 | gcry_mpi_t sos; |
86 | 0 | unsigned int nbits = buflen*8; |
87 | 0 | unsigned char *p = p0; |
88 | |
|
89 | 0 | if (*p && nbits >= 8 && !(*p & 0x80)) |
90 | 0 | if (--nbits >= 7 && !(*p & 0x40)) |
91 | 0 | if (--nbits >= 6 && !(*p & 0x20)) |
92 | 0 | if (--nbits >= 5 && !(*p & 0x10)) |
93 | 0 | if (--nbits >= 4 && !(*p & 0x08)) |
94 | 0 | if (--nbits >= 3 && !(*p & 0x04)) |
95 | 0 | if (--nbits >= 2 && !(*p & 0x02)) |
96 | 0 | if (--nbits >= 1 && !(*p & 0x01)) |
97 | 0 | --nbits; |
98 | |
|
99 | 0 | sos = gcry_mpi_set_opaque (NULL, p0, nbits); |
100 | 0 | if (sos) |
101 | 0 | { |
102 | 0 | gcry_mpi_set_flag (sos, GCRYMPI_FLAG_USER2); |
103 | 0 | *r_sos = sos; |
104 | 0 | err = 0; |
105 | 0 | } |
106 | 0 | else |
107 | 0 | err = gpg_error_from_syserror (); |
108 | 0 | } |
109 | 0 | gcry_sexp_release (l2); |
110 | 0 | } |
111 | |
|
112 | 0 | return err; |
113 | 0 | } |
114 | | |
115 | | |
116 | | /* "No leading zero octets" (nlz) version of the function above. |
117 | | * |
118 | | * This routine is used for backward compatibility to existing |
119 | | * implementation with the weird handling of little endian integer |
120 | | * representation with leading zero octets. For the sake of |
121 | | * "well-fomed" MPI, which is designed for big endian integer, leading |
122 | | * zero octets are removed when output, and they are recovered at |
123 | | * input. |
124 | | * |
125 | | * Extract SOS representation from SEXP for PARAM, removing leading |
126 | | * zeros, return the result in R_SOS. */ |
127 | | gpg_error_t |
128 | | sexp_extract_param_sos_nlz (gcry_sexp_t sexp, const char *param, |
129 | | gcry_mpi_t *r_sos) |
130 | 0 | { |
131 | 0 | gpg_error_t err; |
132 | 0 | gcry_sexp_t l2 = gcry_sexp_find_token (sexp, param, 0); |
133 | |
|
134 | 0 | *r_sos = NULL; |
135 | 0 | if (!l2) |
136 | 0 | err = gpg_error (GPG_ERR_NO_OBJ); |
137 | 0 | else |
138 | 0 | { |
139 | 0 | size_t buflen; |
140 | 0 | const void *p0 = gcry_sexp_nth_data (l2, 1, &buflen); |
141 | |
|
142 | 0 | if (!p0) |
143 | 0 | err = gpg_error_from_syserror (); |
144 | 0 | else |
145 | 0 | { |
146 | 0 | gcry_mpi_t sos; |
147 | 0 | unsigned int nbits = buflen*8; |
148 | 0 | const unsigned char *p = p0; |
149 | | |
150 | | /* Strip leading zero bits. */ |
151 | 0 | for (; nbits >= 8 && !*p; p++, nbits -= 8) |
152 | 0 | ; |
153 | |
|
154 | 0 | if (nbits >= 8 && !(*p & 0x80)) |
155 | 0 | if (--nbits >= 7 && !(*p & 0x40)) |
156 | 0 | if (--nbits >= 6 && !(*p & 0x20)) |
157 | 0 | if (--nbits >= 5 && !(*p & 0x10)) |
158 | 0 | if (--nbits >= 4 && !(*p & 0x08)) |
159 | 0 | if (--nbits >= 3 && !(*p & 0x04)) |
160 | 0 | if (--nbits >= 2 && !(*p & 0x02)) |
161 | 0 | if (--nbits >= 1 && !(*p & 0x01)) |
162 | 0 | --nbits; |
163 | |
|
164 | 0 | sos = gcry_mpi_set_opaque_copy (NULL, p, nbits); |
165 | 0 | if (sos) |
166 | 0 | { |
167 | 0 | gcry_mpi_set_flag (sos, GCRYMPI_FLAG_USER2); |
168 | 0 | *r_sos = sos; |
169 | 0 | err = 0; |
170 | 0 | } |
171 | 0 | else |
172 | 0 | err = gpg_error_from_syserror (); |
173 | 0 | } |
174 | 0 | gcry_sexp_release (l2); |
175 | 0 | } |
176 | |
|
177 | 0 | return err; |
178 | 0 | } |
179 | | |
180 | | |
181 | | /**************** |
182 | | * Emulate our old PK interface here - sometime in the future we might |
183 | | * change the internal design to directly fit to libgcrypt. |
184 | | */ |
185 | | int |
186 | | pk_verify (pubkey_algo_t pkalgo, gcry_mpi_t hash, |
187 | | gcry_mpi_t *data, gcry_mpi_t *pkey) |
188 | 21.3k | { |
189 | 21.3k | gcry_sexp_t s_sig, s_hash, s_pkey; |
190 | 21.3k | int rc; |
191 | | |
192 | | /* Make a sexp from pkey. */ |
193 | 21.3k | if (pkalgo == PUBKEY_ALGO_DSA) |
194 | 2.91k | { |
195 | 2.91k | rc = gcry_sexp_build (&s_pkey, NULL, |
196 | 2.91k | "(public-key(dsa(p%m)(q%m)(g%m)(y%m)))", |
197 | 2.91k | pkey[0], pkey[1], pkey[2], pkey[3]); |
198 | 2.91k | } |
199 | 18.4k | else if (pkalgo == PUBKEY_ALGO_ELGAMAL_E || pkalgo == PUBKEY_ALGO_ELGAMAL) |
200 | 0 | { |
201 | 0 | rc = gcry_sexp_build (&s_pkey, NULL, |
202 | 0 | "(public-key(elg(p%m)(g%m)(y%m)))", |
203 | 0 | pkey[0], pkey[1], pkey[2]); |
204 | 0 | } |
205 | 18.4k | else if (pkalgo == PUBKEY_ALGO_RSA || pkalgo == PUBKEY_ALGO_RSA_S) |
206 | 1.68k | { |
207 | 1.68k | rc = gcry_sexp_build (&s_pkey, NULL, |
208 | 1.68k | "(public-key(rsa(n%m)(e%m)))", pkey[0], pkey[1]); |
209 | 1.68k | } |
210 | 16.7k | else if (pkalgo == PUBKEY_ALGO_ECDSA) |
211 | 1.39k | { |
212 | 1.39k | char *curve = openpgp_oid_to_str (pkey[0]); |
213 | 1.39k | if (!curve) |
214 | 0 | rc = gpg_error_from_syserror (); |
215 | 1.39k | else |
216 | 1.39k | { |
217 | 1.39k | rc = gcry_sexp_build (&s_pkey, NULL, |
218 | 1.39k | "(public-key(ecdsa(curve %s)(q%m)))", |
219 | 1.39k | curve, pkey[1]); |
220 | 1.39k | xfree (curve); |
221 | 1.39k | } |
222 | 1.39k | } |
223 | 15.3k | else if (pkalgo == PUBKEY_ALGO_EDDSA) |
224 | 15.3k | { |
225 | 15.3k | char *curve = openpgp_oid_to_str (pkey[0]); |
226 | 15.3k | if (!curve) |
227 | 0 | rc = gpg_error_from_syserror (); |
228 | 15.3k | else |
229 | 15.3k | { |
230 | 15.3k | const char *fmt; |
231 | | |
232 | 15.3k | if (openpgp_oid_is_ed25519 (pkey[0])) |
233 | 15.3k | fmt = "(public-key(ecc(curve %s)(flags eddsa)(q%m)))"; |
234 | 0 | else |
235 | 0 | fmt = "(public-key(ecc(curve %s)(q%m)))"; |
236 | | |
237 | 15.3k | rc = gcry_sexp_build (&s_pkey, NULL, fmt, curve, pkey[1]); |
238 | 15.3k | xfree (curve); |
239 | 15.3k | } |
240 | 15.3k | } |
241 | 0 | else |
242 | 0 | return GPG_ERR_PUBKEY_ALGO; |
243 | | |
244 | 21.3k | if (rc) |
245 | 0 | BUG (); /* gcry_sexp_build should never fail. */ |
246 | | |
247 | | /* Put hash into a S-Exp s_hash. */ |
248 | 21.3k | if (pkalgo == PUBKEY_ALGO_EDDSA) |
249 | 15.3k | { |
250 | 15.3k | const char *fmt; |
251 | | |
252 | 15.3k | if (openpgp_oid_is_ed25519 (pkey[0])) |
253 | 15.3k | fmt = "(data(flags eddsa)(hash-algo sha512)(value %m))"; |
254 | 0 | else |
255 | 0 | fmt = "(data(value %m))"; |
256 | | |
257 | 15.3k | if (gcry_sexp_build (&s_hash, NULL, fmt, hash)) |
258 | 0 | BUG (); /* gcry_sexp_build should never fail. */ |
259 | 15.3k | } |
260 | 5.98k | else |
261 | 5.98k | { |
262 | 5.98k | if (gcry_sexp_build (&s_hash, NULL, "%m", hash)) |
263 | 0 | BUG (); /* gcry_sexp_build should never fail. */ |
264 | 5.98k | } |
265 | | |
266 | | /* Put data into a S-Exp s_sig. */ |
267 | 21.3k | s_sig = NULL; |
268 | 21.3k | if (pkalgo == PUBKEY_ALGO_DSA) |
269 | 2.91k | { |
270 | 2.91k | if (!data[0] || !data[1]) |
271 | 566 | rc = gpg_error (GPG_ERR_BAD_MPI); |
272 | 2.35k | else |
273 | 2.35k | rc = gcry_sexp_build (&s_sig, NULL, |
274 | 2.35k | "(sig-val(dsa(r%m)(s%m)))", data[0], data[1]); |
275 | 2.91k | } |
276 | 18.4k | else if (pkalgo == PUBKEY_ALGO_ECDSA) |
277 | 1.39k | { |
278 | 1.39k | if (!data[0] || !data[1]) |
279 | 197 | rc = gpg_error (GPG_ERR_BAD_MPI); |
280 | 1.19k | else |
281 | 1.19k | rc = gcry_sexp_build (&s_sig, NULL, |
282 | 1.19k | "(sig-val(ecdsa(r%m)(s%m)))", data[0], data[1]); |
283 | 1.39k | } |
284 | 17.0k | else if (pkalgo == PUBKEY_ALGO_EDDSA) |
285 | 15.3k | { |
286 | 15.3k | gcry_mpi_t r = data[0]; |
287 | 15.3k | gcry_mpi_t s = data[1]; |
288 | | |
289 | 15.3k | if (openpgp_oid_is_ed25519 (pkey[0])) |
290 | 15.3k | { |
291 | 15.3k | size_t rlen, slen, n; /* (bytes) */ |
292 | 15.3k | char buf[64]; |
293 | 15.3k | unsigned int nbits; |
294 | 15.3k | unsigned int neededfixedlen = 256 / 8; |
295 | | |
296 | 15.3k | log_assert (neededfixedlen <= sizeof buf); |
297 | | |
298 | 15.3k | if (!r || !s) |
299 | 1.50k | rc = gpg_error (GPG_ERR_BAD_MPI); |
300 | 13.8k | else if ((rlen = (gcry_mpi_get_nbits (r)+7)/8) > neededfixedlen || !rlen) |
301 | 218 | rc = gpg_error (GPG_ERR_BAD_MPI); |
302 | 13.6k | else if ((slen = (gcry_mpi_get_nbits (s)+7)/8) > neededfixedlen || !slen) |
303 | 71 | rc = gpg_error (GPG_ERR_BAD_MPI); |
304 | 13.5k | else |
305 | 13.5k | { |
306 | 13.5k | r = gcry_mpi_copy (r); |
307 | 13.5k | s = gcry_mpi_copy (s); |
308 | | |
309 | 13.5k | if (!r || !s) |
310 | 0 | { |
311 | 0 | rc = gpg_error_from_syserror (); |
312 | 0 | goto leave; |
313 | 0 | } |
314 | | |
315 | | /* We need to fixup the length in case of leading zeroes. |
316 | | * OpenPGP does not allow leading zeroes and the parser for |
317 | | * the signature packet has no information on the used curve, |
318 | | * thus we need to do it here. We won't do it for opaque |
319 | | * MPIs under the assumption that they are known to be fine; |
320 | | * we won't see them here anyway but the check is anyway |
321 | | * required. Fixme: A nifty feature for gcry_sexp_build |
322 | | * would be a format to left pad the value (e.g. "%*M"). */ |
323 | 13.5k | rc = 0; |
324 | | |
325 | 13.5k | if (rlen < neededfixedlen |
326 | 552 | && !gcry_mpi_get_flag (r, GCRYMPI_FLAG_OPAQUE) |
327 | 82 | && !(rc=gcry_mpi_print (GCRYMPI_FMT_USG, |
328 | 82 | buf, sizeof buf, &n, r))) |
329 | 82 | { |
330 | 82 | log_assert (n < neededfixedlen); |
331 | 82 | memmove (buf + (neededfixedlen - n), buf, n); |
332 | 82 | memset (buf, 0, neededfixedlen - n); |
333 | 82 | gcry_mpi_set_opaque_copy (r, buf, neededfixedlen * 8); |
334 | 82 | } |
335 | 13.5k | else if (rlen < neededfixedlen |
336 | 470 | && gcry_mpi_get_flag (r, GCRYMPI_FLAG_OPAQUE)) |
337 | 470 | { |
338 | 470 | const unsigned char *p; |
339 | | |
340 | 470 | p = gcry_mpi_get_opaque (r, &nbits); |
341 | 470 | n = (nbits+7)/8; |
342 | 470 | memcpy (buf + (neededfixedlen - n), p, n); |
343 | 470 | memset (buf, 0, neededfixedlen - n); |
344 | 470 | gcry_mpi_set_opaque_copy (r, buf, neededfixedlen * 8); |
345 | 470 | } |
346 | | |
347 | 13.5k | if (rc) |
348 | 0 | ; |
349 | 13.5k | else if (slen < neededfixedlen |
350 | 569 | && !gcry_mpi_get_flag (s, GCRYMPI_FLAG_OPAQUE) |
351 | 83 | && !(rc=gcry_mpi_print (GCRYMPI_FMT_USG, |
352 | 83 | buf, sizeof buf, &n, s))) |
353 | 83 | { |
354 | 83 | log_assert (n < neededfixedlen); |
355 | 83 | memmove (buf + (neededfixedlen - n), buf, n); |
356 | 83 | memset (buf, 0, neededfixedlen - n); |
357 | 83 | gcry_mpi_set_opaque_copy (s, buf, neededfixedlen * 8); |
358 | 83 | } |
359 | 13.5k | else if (slen < neededfixedlen |
360 | 486 | && gcry_mpi_get_flag (s, GCRYMPI_FLAG_OPAQUE)) |
361 | 486 | { |
362 | 486 | const unsigned char *p; |
363 | | |
364 | 486 | p = gcry_mpi_get_opaque (s, &nbits); |
365 | 486 | n = (nbits+7)/8; |
366 | 486 | memcpy (buf + (neededfixedlen - n), p, n); |
367 | 486 | memset (buf, 0, neededfixedlen - n); |
368 | 486 | gcry_mpi_set_opaque_copy (s, buf, neededfixedlen * 8); |
369 | 486 | } |
370 | 13.5k | } |
371 | 15.3k | } |
372 | 0 | else |
373 | 0 | rc = 0; |
374 | | |
375 | 15.3k | if (!rc) |
376 | 13.5k | rc = gcry_sexp_build (&s_sig, NULL, |
377 | 13.5k | "(sig-val(eddsa(r%M)(s%M)))", r, s); |
378 | | |
379 | 15.3k | if (r != data[0]) |
380 | 13.5k | gcry_mpi_release (r); |
381 | 15.3k | if (s != data[1]) |
382 | 13.5k | gcry_mpi_release (s); |
383 | 15.3k | } |
384 | 1.68k | else if (pkalgo == PUBKEY_ALGO_ELGAMAL || pkalgo == PUBKEY_ALGO_ELGAMAL_E) |
385 | 0 | { |
386 | 0 | if (!data[0] || !data[1]) |
387 | 0 | rc = gpg_error (GPG_ERR_BAD_MPI); |
388 | 0 | else |
389 | 0 | rc = gcry_sexp_build (&s_sig, NULL, |
390 | 0 | "(sig-val(elg(r%m)(s%m)))", data[0], data[1]); |
391 | 0 | } |
392 | 1.68k | else if (pkalgo == PUBKEY_ALGO_RSA || pkalgo == PUBKEY_ALGO_RSA_S) |
393 | 1.68k | { |
394 | 1.68k | if (!data[0]) |
395 | 0 | rc = gpg_error (GPG_ERR_BAD_MPI); |
396 | 1.68k | else |
397 | 1.68k | rc = gcry_sexp_build (&s_sig, NULL, "(sig-val(rsa(s%m)))", data[0]); |
398 | 1.68k | } |
399 | 0 | else |
400 | 0 | BUG (); |
401 | | |
402 | 21.3k | if (!rc) |
403 | 18.8k | rc = gcry_pk_verify (s_sig, s_hash, s_pkey); |
404 | | |
405 | 21.3k | leave: |
406 | 21.3k | gcry_sexp_release (s_sig); |
407 | 21.3k | gcry_sexp_release (s_hash); |
408 | 21.3k | gcry_sexp_release (s_pkey); |
409 | 21.3k | return rc; |
410 | 21.3k | } |
411 | | |
412 | | |
413 | | #if GCRY_KEM_MLKEM1024_ENCAPS_LEN < GCRY_KEM_MLKEM768_ENCAPS_LEN \ |
414 | | || GCRY_KEM_MLKEM1024_SHARED_LEN < GCRY_KEM_MLKEM768_SHARED_LEN |
415 | | # error Bad Kyber constants in Libgcrypt |
416 | | #endif |
417 | | |
418 | | /* Core of the encryption for KEM algorithms. See pk_decrypt for a |
419 | | * description of the arguments. */ |
420 | | static gpg_error_t |
421 | | do_encrypt_kem (PKT_public_key *pk, gcry_mpi_t data, int seskey_algo, |
422 | | gcry_mpi_t *resarr) |
423 | 0 | { |
424 | 0 | gpg_error_t err; |
425 | 0 | int i; |
426 | 0 | unsigned int nbits, n; |
427 | 0 | gcry_sexp_t s_data = NULL; |
428 | 0 | gcry_cipher_hd_t hd = NULL; |
429 | 0 | char *ecc_oid = NULL; |
430 | 0 | const char *curve; |
431 | 0 | const struct gnupg_ecc_params *ecc; |
432 | 0 | enum gcry_kem_algos kyber_algo; |
433 | |
|
434 | 0 | const unsigned char *ecc_pubkey; |
435 | 0 | size_t ecc_pubkey_len; |
436 | 0 | const unsigned char *kyber_pubkey; |
437 | 0 | size_t kyber_pubkey_len; |
438 | 0 | const unsigned char *seskey; |
439 | 0 | size_t seskey_len; |
440 | 0 | unsigned char *enc_seskey = NULL; |
441 | 0 | size_t enc_seskey_len; |
442 | 0 | int ecc_hash_algo; |
443 | |
|
444 | 0 | unsigned char ecc_ct[ECC_POINT_LEN_MAX]; |
445 | 0 | unsigned char ecc_ecdh[ECC_POINT_LEN_MAX]; |
446 | 0 | unsigned char ecc_ss[ECC_HASH_LEN_MAX]; |
447 | 0 | size_t ecc_ct_len, ecc_ecdh_len, ecc_ss_len; |
448 | |
|
449 | 0 | unsigned char kyber_ct[GCRY_KEM_MLKEM1024_ENCAPS_LEN]; |
450 | 0 | unsigned char kyber_ss[GCRY_KEM_MLKEM1024_SHARED_LEN]; |
451 | 0 | size_t kyber_ct_len, kyber_ss_len; |
452 | |
|
453 | 0 | char fixedinfo[1+MAX_FINGERPRINT_LEN]; |
454 | 0 | int fixedlen; |
455 | |
|
456 | 0 | unsigned char kek[32]; /* AES-256 is mandatory. */ |
457 | 0 | size_t kek_len = 32; |
458 | | |
459 | | /* For later error checking we make sure the array is cleared. */ |
460 | 0 | resarr[0] = resarr[1] = resarr[2] = NULL; |
461 | | |
462 | | /* As of now we use KEM only for the combined Kyber and thus a |
463 | | * second public key is expected. Right now we take the keys |
464 | | * directly from the PK->data elements. */ |
465 | |
|
466 | 0 | ecc_oid = openpgp_oid_to_str (pk->pkey[0]); |
467 | 0 | if (!ecc_oid) |
468 | 0 | { |
469 | 0 | err = gpg_error_from_syserror (); |
470 | 0 | log_error ("%s: error getting OID for ECC key\n", __func__); |
471 | 0 | goto leave; |
472 | 0 | } |
473 | 0 | curve = openpgp_oid_to_curve (ecc_oid, 1); |
474 | 0 | if (!curve) |
475 | 0 | { |
476 | 0 | err = gpg_error (GPG_ERR_INV_DATA); |
477 | 0 | log_error ("%s: error getting curve for ECC key\n", __func__); |
478 | 0 | goto leave; |
479 | 0 | } |
480 | 0 | ecc = gnupg_get_ecc_params (curve); |
481 | 0 | if (!ecc) |
482 | 0 | { |
483 | 0 | if (opt.verbose) |
484 | 0 | log_info ("%s: ECC curve %s not supported\n", __func__, curve); |
485 | 0 | err = gpg_error (GPG_ERR_INV_DATA); |
486 | 0 | goto leave; |
487 | 0 | } |
488 | 0 | ecc_ct_len = ecc_ecdh_len = ecc->point_len; |
489 | 0 | ecc_hash_algo = ecc->hash_algo; |
490 | 0 | ecc_ss_len = gcry_md_get_algo_dlen (ecc_hash_algo); |
491 | |
|
492 | 0 | ecc_pubkey = gcry_mpi_get_opaque (pk->pkey[1], &nbits); |
493 | 0 | ecc_pubkey_len = (nbits+7)/8; |
494 | 0 | if (ecc_pubkey_len != ecc->pubkey_len) |
495 | 0 | { |
496 | 0 | if (ecc->kem_algo == GCRY_KEM_RAW_X25519 |
497 | 0 | && ecc_pubkey_len == ecc->pubkey_len - 1) |
498 | | /* For Curve25519, we also accept no prefix in the point |
499 | | * representation. */ |
500 | 0 | ; |
501 | 0 | else |
502 | 0 | { |
503 | 0 | if (opt.verbose) |
504 | 0 | log_info ("%s: ECC public key length invalid (%zu)\n", |
505 | 0 | __func__, ecc_pubkey_len); |
506 | 0 | err = gpg_error (GPG_ERR_INV_DATA); |
507 | 0 | goto leave; |
508 | 0 | } |
509 | 0 | } |
510 | | |
511 | 0 | if (ecc->kem_algo == GCRY_KEM_RAW_X25519) |
512 | 0 | { |
513 | 0 | if (!strcmp (ecc_oid, "1.3.6.1.4.1.3029.1.5.1")) |
514 | 0 | log_info ("Warning: " |
515 | 0 | "legacy OID for cv25519 accepted during development\n"); |
516 | | /* Optional prefix handling */ |
517 | 0 | if (ecc_pubkey_len == 33 && *ecc_pubkey == 0x40) |
518 | 0 | { |
519 | 0 | ecc_pubkey++; /* Remove the 0x40 prefix. */ |
520 | 0 | ecc_pubkey_len--; |
521 | 0 | } |
522 | 0 | } |
523 | |
|
524 | 0 | if (DBG_CRYPTO) |
525 | 0 | { |
526 | 0 | log_debug ("ECC curve: %s\n", ecc_oid); |
527 | 0 | log_printhex (ecc_pubkey, ecc_pubkey_len, "ECC pubkey:"); |
528 | 0 | } |
529 | |
|
530 | 0 | err = gcry_kem_encap (ecc->kem_algo, |
531 | 0 | ecc_pubkey, ecc_pubkey_len, |
532 | 0 | ecc_ct, ecc_ct_len, |
533 | 0 | ecc_ecdh, ecc_ecdh_len, |
534 | 0 | NULL, 0); |
535 | 0 | if (err) |
536 | 0 | { |
537 | 0 | if (opt.verbose) |
538 | 0 | log_info ("%s: gcry_kem_encap for ECC (%s) failed\n", |
539 | 0 | __func__, ecc_oid); |
540 | 0 | goto leave; |
541 | 0 | } |
542 | 0 | if (DBG_CRYPTO) |
543 | 0 | { |
544 | 0 | log_printhex (ecc_ct, ecc_ct_len, "ECC ephem:"); |
545 | 0 | log_printhex (ecc_ecdh, ecc_ecdh_len, "ECC ecdh:"); |
546 | 0 | } |
547 | 0 | err = gnupg_ecc_kem_simple_kdf (ecc_ss, ecc_ss_len, |
548 | 0 | ecc_hash_algo, |
549 | 0 | ecc_ecdh, ecc_ecdh_len, |
550 | 0 | ecc_ct, ecc_ct_len, |
551 | 0 | ecc_pubkey, ecc_pubkey_len); |
552 | 0 | if (err) |
553 | 0 | { |
554 | 0 | if (opt.verbose) |
555 | 0 | log_info ("%s: kdf for ECC failed\n", __func__); |
556 | 0 | goto leave; |
557 | 0 | } |
558 | 0 | if (DBG_CRYPTO) |
559 | 0 | log_printhex (ecc_ss, ecc_ss_len, "ECC shared:"); |
560 | |
|
561 | 0 | kyber_pubkey = gcry_mpi_get_opaque (pk->pkey[2], &nbits); |
562 | 0 | kyber_pubkey_len = (nbits+7)/8; |
563 | 0 | if (kyber_pubkey_len == GCRY_KEM_MLKEM768_PUBKEY_LEN) |
564 | 0 | { |
565 | 0 | kyber_algo = GCRY_KEM_MLKEM768; |
566 | 0 | kyber_ct_len = GCRY_KEM_MLKEM768_ENCAPS_LEN; |
567 | 0 | kyber_ss_len = GCRY_KEM_MLKEM768_SHARED_LEN; |
568 | 0 | } |
569 | 0 | else if (kyber_pubkey_len == GCRY_KEM_MLKEM1024_PUBKEY_LEN) |
570 | 0 | { |
571 | 0 | kyber_algo = GCRY_KEM_MLKEM1024; |
572 | 0 | kyber_ct_len = GCRY_KEM_MLKEM1024_ENCAPS_LEN; |
573 | 0 | kyber_ss_len = GCRY_KEM_MLKEM1024_SHARED_LEN; |
574 | 0 | } |
575 | 0 | else |
576 | 0 | { |
577 | 0 | if (opt.verbose) |
578 | 0 | log_info ("%s: Kyber public key length invalid (%zu)\n", |
579 | 0 | __func__, kyber_pubkey_len); |
580 | 0 | err = gpg_error (GPG_ERR_INV_DATA); |
581 | 0 | goto leave; |
582 | 0 | } |
583 | 0 | if (DBG_CRYPTO) |
584 | 0 | log_printhex (kyber_pubkey, kyber_pubkey_len, "|!trunc|Kyber pubkey:"); |
585 | |
|
586 | 0 | err = gcry_kem_encap (kyber_algo, |
587 | 0 | kyber_pubkey, kyber_pubkey_len, |
588 | 0 | kyber_ct, kyber_ct_len, |
589 | 0 | kyber_ss, kyber_ss_len, |
590 | 0 | NULL, 0); |
591 | 0 | if (err) |
592 | 0 | { |
593 | 0 | if (opt.verbose) |
594 | 0 | log_info ("%s: gcry_kem_encap for ECC failed\n", __func__); |
595 | 0 | goto leave; |
596 | 0 | } |
597 | | |
598 | 0 | if (DBG_CRYPTO) |
599 | 0 | { |
600 | 0 | log_printhex (kyber_ct, kyber_ct_len, "|!trunc|Kyber ephem:"); |
601 | 0 | log_printhex (kyber_ss, kyber_ss_len, "Kyber shared:"); |
602 | 0 | } |
603 | | |
604 | |
|
605 | 0 | fixedinfo[0] = seskey_algo; |
606 | 0 | v5_fingerprint_from_pk (pk, fixedinfo+1, NULL); |
607 | 0 | fixedlen = 33; |
608 | |
|
609 | 0 | err = gnupg_kem_combiner (kek, kek_len, |
610 | 0 | ecc_ss, ecc_ss_len, ecc_ct, ecc_ct_len, |
611 | 0 | kyber_ss, kyber_ss_len, kyber_ct, kyber_ct_len, |
612 | 0 | fixedinfo, fixedlen); |
613 | 0 | if (err) |
614 | 0 | { |
615 | 0 | if (opt.verbose) |
616 | 0 | log_info ("%s: KEM combiner failed\n", __func__); |
617 | 0 | goto leave; |
618 | 0 | } |
619 | 0 | if (DBG_CRYPTO) |
620 | 0 | log_printhex (kek, kek_len, "KEK:"); |
621 | |
|
622 | 0 | err = gcry_cipher_open (&hd, GCRY_CIPHER_AES256, |
623 | 0 | GCRY_CIPHER_MODE_AESWRAP, 0); |
624 | 0 | if (!err) |
625 | 0 | err = gcry_cipher_setkey (hd, kek, kek_len); |
626 | 0 | if (err) |
627 | 0 | { |
628 | 0 | if (opt.verbose) |
629 | 0 | log_error ("%s: failed to initialize AESWRAP: %s\n", __func__, |
630 | 0 | gpg_strerror (err)); |
631 | 0 | goto leave; |
632 | 0 | } |
633 | | |
634 | 0 | err = gcry_sexp_build (&s_data, NULL, "%m", data); |
635 | 0 | if (err) |
636 | 0 | goto leave; |
637 | | |
638 | 0 | n = gcry_cipher_get_algo_keylen (seskey_algo); |
639 | 0 | seskey = gcry_mpi_get_opaque (data, &nbits); |
640 | 0 | seskey_len = (nbits+7)/8; |
641 | 0 | if (seskey_len != n) |
642 | 0 | { |
643 | 0 | if (opt.verbose) |
644 | 0 | log_info ("%s: session key length %zu" |
645 | 0 | " does not match the length for algo %d\n", |
646 | 0 | __func__, seskey_len, seskey_algo); |
647 | 0 | err = gpg_error (GPG_ERR_INV_DATA); |
648 | 0 | goto leave; |
649 | 0 | } |
650 | 0 | if (DBG_CRYPTO) |
651 | 0 | log_printhex (seskey, seskey_len, "seskey:"); |
652 | |
|
653 | 0 | enc_seskey_len = 1 + seskey_len + 8; |
654 | 0 | enc_seskey = xtrymalloc (enc_seskey_len); |
655 | 0 | if (!enc_seskey || enc_seskey_len > 254) |
656 | 0 | { |
657 | 0 | err = gpg_error_from_syserror (); |
658 | 0 | goto leave; |
659 | 0 | } |
660 | | |
661 | 0 | enc_seskey[0] = enc_seskey_len - 1; |
662 | 0 | err = gcry_cipher_encrypt (hd, enc_seskey+1, enc_seskey_len-1, |
663 | 0 | seskey, seskey_len); |
664 | 0 | if (err) |
665 | 0 | { |
666 | 0 | log_error ("%s: wrapping session key failed\n", __func__); |
667 | 0 | goto leave; |
668 | 0 | } |
669 | 0 | if (DBG_CRYPTO) |
670 | 0 | log_printhex (enc_seskey, enc_seskey_len, "enc_seskey:"); |
671 | |
|
672 | 0 | resarr[0] = gcry_mpi_set_opaque_copy (NULL, ecc_ct, 8 * ecc_ct_len); |
673 | 0 | if (resarr[0]) |
674 | 0 | resarr[1] = gcry_mpi_set_opaque_copy (NULL, kyber_ct, 8 * kyber_ct_len); |
675 | 0 | if (resarr[1]) |
676 | 0 | resarr[2] = gcry_mpi_set_opaque_copy (NULL, enc_seskey, 8 * enc_seskey_len); |
677 | 0 | if (!resarr[0] || !resarr[1] || !resarr[2]) |
678 | 0 | { |
679 | 0 | err = gpg_error_from_syserror (); |
680 | 0 | for (i=0; i < 3; i++) |
681 | 0 | gcry_mpi_release (resarr[i]), resarr[i] = NULL; |
682 | 0 | } |
683 | |
|
684 | 0 | leave: |
685 | 0 | wipememory (ecc_ct, sizeof ecc_ct); |
686 | 0 | wipememory (ecc_ecdh, sizeof ecc_ecdh); |
687 | 0 | wipememory (ecc_ss, sizeof ecc_ss); |
688 | 0 | wipememory (kyber_ct, sizeof kyber_ct); |
689 | 0 | wipememory (kyber_ss, sizeof kyber_ss); |
690 | 0 | wipememory (kek, kek_len); |
691 | 0 | xfree (enc_seskey); |
692 | 0 | gcry_cipher_close (hd); |
693 | 0 | xfree (ecc_oid); |
694 | 0 | return err; |
695 | 0 | } |
696 | | |
697 | | |
698 | | /* Core of the encryption for the ECDH algorithms. See pk_decrypt for |
699 | | * a description of the arguments. */ |
700 | | static gpg_error_t |
701 | | do_encrypt_ecdh (PKT_public_key *pk, gcry_mpi_t data, gcry_mpi_t *resarr) |
702 | 0 | { |
703 | 0 | gpg_error_t err; |
704 | 0 | unsigned int nbits; |
705 | 0 | gcry_cipher_hd_t hd = NULL; |
706 | 0 | char *ecc_oid = NULL; |
707 | 0 | const char *curve; |
708 | 0 | const struct gnupg_ecc_params *ecc; |
709 | |
|
710 | 0 | const unsigned char *ecc_pubkey; |
711 | 0 | size_t ecc_pubkey_len; |
712 | 0 | const unsigned char *seskey; |
713 | 0 | size_t seskey_len; |
714 | 0 | unsigned char *enc_seskey = NULL; |
715 | 0 | size_t enc_seskey_len; |
716 | |
|
717 | 0 | unsigned char ecc_ct[ECC_POINT_LEN_MAX]; |
718 | 0 | unsigned char ecc_ecdh[ECC_POINT_LEN_MAX]; |
719 | 0 | size_t ecc_ct_len, ecc_ecdh_len; |
720 | 0 | const char *shared_secret; |
721 | 0 | size_t shared_secretlen; |
722 | 0 | const char *ephemeral_pubkey; |
723 | 0 | size_t ephemeral_pubkeylen; |
724 | |
|
725 | 0 | unsigned char *kek = NULL; |
726 | 0 | size_t kek_len; |
727 | |
|
728 | 0 | const unsigned char *kdf_params_spec; |
729 | 0 | byte fp[MAX_FINGERPRINT_LEN]; |
730 | 0 | int keywrap_cipher_algo; |
731 | 0 | int kdf_hash_algo; |
732 | 0 | unsigned char *kdf_params = NULL; |
733 | 0 | size_t kdf_params_len = 0; |
734 | |
|
735 | 0 | fingerprint_from_pk (pk, fp, NULL); |
736 | |
|
737 | 0 | ecc_oid = openpgp_oid_to_str (pk->pkey[0]); |
738 | 0 | if (!ecc_oid) |
739 | 0 | { |
740 | 0 | err = gpg_error_from_syserror (); |
741 | 0 | log_error ("%s: error getting OID for ECC key\n", __func__); |
742 | 0 | goto leave; |
743 | 0 | } |
744 | 0 | curve = openpgp_oid_to_curve (ecc_oid, 1); |
745 | 0 | if (!curve) |
746 | 0 | { |
747 | 0 | err = gpg_error (GPG_ERR_INV_DATA); |
748 | 0 | log_error ("%s: error getting curve for ECC key\n", __func__); |
749 | 0 | goto leave; |
750 | 0 | } |
751 | 0 | ecc = gnupg_get_ecc_params (curve); |
752 | 0 | if (!ecc) |
753 | 0 | { |
754 | 0 | if (opt.verbose) |
755 | 0 | log_info ("%s: ECC curve %s not supported\n", __func__, curve); |
756 | 0 | err = gpg_error (GPG_ERR_INV_DATA); |
757 | 0 | goto leave; |
758 | 0 | } |
759 | 0 | ecc_ct_len = ecc_ecdh_len = ecc->point_len; |
760 | |
|
761 | 0 | ecc_pubkey = gcry_mpi_get_opaque (pk->pkey[1], &nbits); |
762 | 0 | ecc_pubkey_len = (nbits+7)/8; |
763 | 0 | if (ecc_pubkey_len != ecc->pubkey_len) |
764 | 0 | { |
765 | 0 | if (ecc->kem_algo == GCRY_KEM_RAW_X25519 |
766 | 0 | && ecc_pubkey_len == ecc->pubkey_len - 1) |
767 | | /* For Curve25519, we also accept no prefix in the point |
768 | | * representation. */ |
769 | 0 | ; |
770 | 0 | else |
771 | 0 | { |
772 | 0 | if (opt.verbose) |
773 | 0 | log_info ("%s: ECC public key length invalid (%zu)\n", |
774 | 0 | __func__, ecc_pubkey_len); |
775 | 0 | err = gpg_error (GPG_ERR_INV_DATA); |
776 | 0 | goto leave; |
777 | 0 | } |
778 | 0 | } |
779 | | |
780 | 0 | if (ecc->kem_algo == GCRY_KEM_RAW_X25519) |
781 | 0 | { |
782 | | /* Note: Legacy OID is OK here. */ |
783 | | /* Optional prefix handling */ |
784 | 0 | if (ecc_pubkey_len == 33 && *ecc_pubkey == 0x40) |
785 | 0 | { |
786 | 0 | ecc_pubkey++; /* Remove the 0x40 prefix. */ |
787 | 0 | ecc_pubkey_len--; |
788 | 0 | } |
789 | 0 | } |
790 | |
|
791 | 0 | if (DBG_CRYPTO) |
792 | 0 | { |
793 | 0 | log_debug ("ECC curve: %s\n", ecc_oid); |
794 | 0 | log_printhex (ecc_pubkey, ecc_pubkey_len, "ECC pubkey:"); |
795 | 0 | } |
796 | |
|
797 | 0 | err = gcry_kem_encap (ecc->kem_algo, |
798 | 0 | ecc_pubkey, ecc_pubkey_len, |
799 | 0 | ecc_ct, ecc_ct_len, |
800 | 0 | ecc_ecdh, ecc_ecdh_len, |
801 | 0 | NULL, 0); |
802 | 0 | if (err) |
803 | 0 | { |
804 | 0 | if (opt.verbose) |
805 | 0 | log_info ("%s: gcry_kem_encap for ECC (%s) failed\n", |
806 | 0 | __func__, ecc_oid); |
807 | 0 | goto leave; |
808 | 0 | } |
809 | 0 | if (DBG_CRYPTO) |
810 | 0 | { |
811 | 0 | log_printhex (ecc_ct, ecc_ct_len, "ECC ephem:"); |
812 | 0 | log_printhex (ecc_ecdh, ecc_ecdh_len, "ECC ecdh:"); |
813 | 0 | } |
814 | |
|
815 | 0 | if (ecc->is_weierstrauss) |
816 | 0 | { |
817 | 0 | shared_secret = ecc_ecdh + 1; |
818 | 0 | shared_secretlen = (ecc_ecdh_len - 1) / 2; |
819 | 0 | ephemeral_pubkey = ecc_ct; |
820 | 0 | ephemeral_pubkeylen = ecc_ct_len; |
821 | 0 | } |
822 | 0 | else |
823 | 0 | { |
824 | 0 | shared_secret = ecc_ecdh; |
825 | 0 | shared_secretlen = ecc_ecdh_len; |
826 | |
|
827 | 0 | if (ecc->may_have_prefix) |
828 | 0 | { |
829 | 0 | ephemeral_pubkeylen = ecc_ct_len + 1; |
830 | 0 | memmove (ecc_ct + 1, ecc_ct, ecc_ct_len); |
831 | 0 | ecc_ct[0] = 0x40; |
832 | 0 | } |
833 | 0 | else |
834 | 0 | ephemeral_pubkeylen = ecc_ct_len; |
835 | |
|
836 | 0 | ephemeral_pubkey = ecc_ct; |
837 | 0 | } |
838 | |
|
839 | 0 | err = ecc_build_kdf_params (&kdf_params, &kdf_params_len, |
840 | 0 | &kdf_params_spec, pk->pkey, fp); |
841 | 0 | if (err) |
842 | 0 | return err; |
843 | | |
844 | 0 | keywrap_cipher_algo = kdf_params_spec[3]; |
845 | 0 | kdf_hash_algo = kdf_params_spec[2]; |
846 | |
|
847 | 0 | if (DBG_CRYPTO) |
848 | 0 | log_debug ("ecdh KDF algorithms %s+%s with aeswrap\n", |
849 | 0 | openpgp_md_algo_name (kdf_hash_algo), |
850 | 0 | openpgp_cipher_algo_name (keywrap_cipher_algo)); |
851 | |
|
852 | 0 | if (kdf_hash_algo != GCRY_MD_SHA256 |
853 | 0 | && kdf_hash_algo != GCRY_MD_SHA384 |
854 | 0 | && kdf_hash_algo != GCRY_MD_SHA512) |
855 | 0 | { |
856 | 0 | err = gpg_error (GPG_ERR_BAD_PUBKEY); |
857 | 0 | goto leave; |
858 | 0 | } |
859 | | |
860 | 0 | if (keywrap_cipher_algo != CIPHER_ALGO_AES |
861 | 0 | && keywrap_cipher_algo != CIPHER_ALGO_AES192 |
862 | 0 | && keywrap_cipher_algo != CIPHER_ALGO_AES256) |
863 | 0 | { |
864 | 0 | err = gpg_error (GPG_ERR_BAD_PUBKEY); |
865 | 0 | goto leave; |
866 | 0 | } |
867 | | |
868 | 0 | kek_len = gcry_cipher_get_algo_keylen (keywrap_cipher_algo); |
869 | 0 | if (kek_len > gcry_md_get_algo_dlen (kdf_hash_algo)) |
870 | 0 | { |
871 | 0 | err = gpg_error (GPG_ERR_BAD_PUBKEY); |
872 | 0 | goto leave; |
873 | 0 | } |
874 | | |
875 | 0 | kek = xtrymalloc (kek_len); |
876 | 0 | if (!kek) |
877 | 0 | { |
878 | 0 | err = gpg_error_from_syserror (); |
879 | 0 | goto leave; |
880 | 0 | } |
881 | | |
882 | 0 | err = gnupg_ecc_kem_kdf (kek, kek_len, 1, kdf_hash_algo, |
883 | 0 | shared_secret, shared_secretlen, |
884 | 0 | kdf_params, kdf_params_len); |
885 | 0 | xfree (kdf_params); |
886 | 0 | if (err) |
887 | 0 | { |
888 | 0 | if (opt.verbose) |
889 | 0 | log_info ("%s: kdf for ECC failed\n", __func__); |
890 | 0 | goto leave; |
891 | 0 | } |
892 | | |
893 | 0 | if (DBG_CRYPTO) |
894 | 0 | log_printhex (kek, kek_len, "KEK:"); |
895 | |
|
896 | 0 | err = gcry_cipher_open (&hd, keywrap_cipher_algo, |
897 | 0 | GCRY_CIPHER_MODE_AESWRAP, 0); |
898 | 0 | if (!err) |
899 | 0 | err = gcry_cipher_setkey (hd, kek, kek_len); |
900 | 0 | if (err) |
901 | 0 | { |
902 | 0 | if (opt.verbose) |
903 | 0 | log_error ("%s: failed to initialize AESWRAP: %s\n", __func__, |
904 | 0 | gpg_strerror (err)); |
905 | 0 | goto leave; |
906 | 0 | } |
907 | | |
908 | 0 | seskey = gcry_mpi_get_opaque (data, &nbits); |
909 | 0 | seskey_len = (nbits+7)/8; |
910 | |
|
911 | 0 | enc_seskey_len = 1 + seskey_len + 8; |
912 | 0 | enc_seskey = xtrymalloc (enc_seskey_len); |
913 | 0 | if (!enc_seskey || enc_seskey_len > 254) |
914 | 0 | { |
915 | 0 | err = gpg_error_from_syserror (); |
916 | 0 | goto leave; |
917 | 0 | } |
918 | | |
919 | 0 | enc_seskey[0] = enc_seskey_len - 1; |
920 | 0 | err = gcry_cipher_encrypt (hd, enc_seskey+1, enc_seskey_len-1, |
921 | 0 | seskey, seskey_len); |
922 | 0 | if (err) |
923 | 0 | { |
924 | 0 | log_error ("%s: wrapping session key failed\n", __func__); |
925 | 0 | goto leave; |
926 | 0 | } |
927 | 0 | if (DBG_CRYPTO) |
928 | 0 | log_printhex (enc_seskey, enc_seskey_len, "enc_seskey:"); |
929 | |
|
930 | 0 | resarr[0] = gcry_mpi_set_opaque_copy (NULL, ephemeral_pubkey, |
931 | 0 | 8 * ephemeral_pubkeylen); |
932 | 0 | if (!resarr[0]) |
933 | 0 | { |
934 | 0 | err = gpg_error_from_syserror (); |
935 | 0 | goto leave; |
936 | 0 | } |
937 | | |
938 | 0 | resarr[1] = gcry_mpi_set_opaque_copy (NULL, enc_seskey, 8 * enc_seskey_len); |
939 | 0 | if (!resarr[1]) |
940 | 0 | { |
941 | 0 | err = gpg_error_from_syserror (); |
942 | 0 | gcry_mpi_release (resarr[0]); |
943 | 0 | } |
944 | |
|
945 | 0 | leave: |
946 | 0 | xfree (enc_seskey); |
947 | 0 | gcry_cipher_close (hd); |
948 | 0 | xfree (kek); |
949 | 0 | wipememory (ecc_ct, sizeof ecc_ct); |
950 | 0 | wipememory (ecc_ecdh, sizeof ecc_ecdh); |
951 | 0 | xfree (ecc_oid); |
952 | 0 | return err; |
953 | 0 | } |
954 | | |
955 | | |
956 | | /* Core of the encryption for RSA and Elgamal algorithms. See |
957 | | * pk_decrypt for a description of the arguments. */ |
958 | | static gpg_error_t |
959 | | do_encrypt_rsa_elg (PKT_public_key *pk, gcry_mpi_t data, gcry_mpi_t *resarr) |
960 | 0 | { |
961 | 0 | pubkey_algo_t algo = pk->pubkey_algo; |
962 | 0 | gcry_mpi_t *pkey = pk->pkey; |
963 | 0 | gcry_sexp_t s_ciph = NULL; |
964 | 0 | gcry_sexp_t s_data = NULL; |
965 | 0 | gcry_sexp_t s_pkey = NULL; |
966 | 0 | gpg_error_t err; |
967 | |
|
968 | 0 | if (algo == PUBKEY_ALGO_ELGAMAL || algo == PUBKEY_ALGO_ELGAMAL_E) |
969 | 0 | err = gcry_sexp_build (&s_pkey, NULL, |
970 | 0 | "(public-key(elg(p%m)(g%m)(y%m)))", |
971 | 0 | pkey[0], pkey[1], pkey[2]); |
972 | 0 | else |
973 | 0 | err = gcry_sexp_build (&s_pkey, NULL, |
974 | 0 | "(public-key(rsa(n%m)(e%m)))", |
975 | 0 | pkey[0], pkey[1]); |
976 | 0 | if (err) |
977 | 0 | goto leave; |
978 | | |
979 | 0 | err = gcry_sexp_build (&s_data, NULL, "%m", data); |
980 | 0 | if (err) |
981 | 0 | goto leave; |
982 | | |
983 | 0 | err = gcry_pk_encrypt (&s_ciph, s_data, s_pkey); |
984 | 0 | if (err) |
985 | 0 | goto leave; |
986 | | |
987 | 0 | gcry_sexp_release (s_data); s_data = NULL; |
988 | 0 | gcry_sexp_release (s_pkey); s_pkey = NULL; |
989 | |
|
990 | 0 | resarr[0] = get_mpi_from_sexp (s_ciph, "a", GCRYMPI_FMT_USG); |
991 | 0 | if (!is_RSA (algo)) |
992 | 0 | resarr[1] = get_mpi_from_sexp (s_ciph, "b", GCRYMPI_FMT_USG); |
993 | |
|
994 | 0 | leave: |
995 | 0 | gcry_sexp_release (s_data); |
996 | 0 | gcry_sexp_release (s_pkey); |
997 | 0 | gcry_sexp_release (s_ciph); |
998 | 0 | return err; |
999 | 0 | } |
1000 | | |
1001 | | |
1002 | | /* |
1003 | | * Emulate our old PK interface here - sometime in the future we might |
1004 | | * change the internal design to directly fit to libgcrypt. PK is is |
1005 | | * the OpenPGP public key packet, DATA is an MPI with the to be |
1006 | | * encrypted data, and RESARR receives the encrypted data. RESARRAY |
1007 | | * is expected to be an two/three item array which will be filled with |
1008 | | * newly allocated MPIs. SESKEY_ALGO is required for public key |
1009 | | * algorithms which do not encode it in DATA. |
1010 | | */ |
1011 | | gpg_error_t |
1012 | | pk_encrypt (PKT_public_key *pk, gcry_mpi_t data, int seskey_algo, |
1013 | | gcry_mpi_t *resarr) |
1014 | 0 | { |
1015 | 0 | pubkey_algo_t algo = pk->pubkey_algo; |
1016 | |
|
1017 | 0 | if (algo == PUBKEY_ALGO_KYBER) |
1018 | 0 | return do_encrypt_kem (pk, data, seskey_algo, resarr); |
1019 | 0 | else if (algo == PUBKEY_ALGO_ECDH) |
1020 | 0 | return do_encrypt_ecdh (pk, data, resarr); |
1021 | 0 | else if (algo == PUBKEY_ALGO_ELGAMAL || algo == PUBKEY_ALGO_ELGAMAL_E) |
1022 | 0 | return do_encrypt_rsa_elg (pk, data, resarr); |
1023 | 0 | else if (algo == PUBKEY_ALGO_RSA || algo == PUBKEY_ALGO_RSA_E) |
1024 | 0 | return do_encrypt_rsa_elg (pk, data, resarr); |
1025 | 0 | else |
1026 | 0 | return gpg_error (GPG_ERR_PUBKEY_ALGO); |
1027 | 0 | } |
1028 | | |
1029 | | |
1030 | | /* Check whether SKEY is a suitable secret key. */ |
1031 | | int |
1032 | | pk_check_secret_key (pubkey_algo_t pkalgo, gcry_mpi_t *skey) |
1033 | 0 | { |
1034 | 0 | gcry_sexp_t s_skey; |
1035 | 0 | int rc; |
1036 | |
|
1037 | 0 | if (pkalgo == PUBKEY_ALGO_DSA) |
1038 | 0 | { |
1039 | 0 | rc = gcry_sexp_build (&s_skey, NULL, |
1040 | 0 | "(private-key(dsa(p%m)(q%m)(g%m)(y%m)(x%m)))", |
1041 | 0 | skey[0], skey[1], skey[2], skey[3], skey[4]); |
1042 | 0 | } |
1043 | 0 | else if (pkalgo == PUBKEY_ALGO_ELGAMAL || pkalgo == PUBKEY_ALGO_ELGAMAL_E) |
1044 | 0 | { |
1045 | 0 | rc = gcry_sexp_build (&s_skey, NULL, |
1046 | 0 | "(private-key(elg(p%m)(g%m)(y%m)(x%m)))", |
1047 | 0 | skey[0], skey[1], skey[2], skey[3]); |
1048 | 0 | } |
1049 | 0 | else if (is_RSA (pkalgo)) |
1050 | 0 | { |
1051 | 0 | rc = gcry_sexp_build (&s_skey, NULL, |
1052 | 0 | "(private-key(rsa(n%m)(e%m)(d%m)(p%m)(q%m)(u%m)))", |
1053 | 0 | skey[0], skey[1], skey[2], skey[3], skey[4], |
1054 | 0 | skey[5]); |
1055 | 0 | } |
1056 | 0 | else if (pkalgo == PUBKEY_ALGO_ECDSA || pkalgo == PUBKEY_ALGO_ECDH) |
1057 | 0 | { |
1058 | 0 | char *curve = openpgp_oid_to_str (skey[0]); |
1059 | 0 | if (!curve) |
1060 | 0 | rc = gpg_error_from_syserror (); |
1061 | 0 | else |
1062 | 0 | { |
1063 | 0 | rc = gcry_sexp_build (&s_skey, NULL, |
1064 | 0 | "(private-key(ecc(curve%s)(q%m)(d%m)))", |
1065 | 0 | curve, skey[1], skey[2]); |
1066 | 0 | xfree (curve); |
1067 | 0 | } |
1068 | 0 | } |
1069 | 0 | else if (pkalgo == PUBKEY_ALGO_EDDSA) |
1070 | 0 | { |
1071 | 0 | char *curve = openpgp_oid_to_str (skey[0]); |
1072 | 0 | if (!curve) |
1073 | 0 | rc = gpg_error_from_syserror (); |
1074 | 0 | else |
1075 | 0 | { |
1076 | 0 | const char *fmt; |
1077 | |
|
1078 | 0 | if (openpgp_oid_is_ed25519 (skey[0])) |
1079 | 0 | fmt = "(private-key(ecc(curve %s)(flags eddsa)(q%m)(d%m)))"; |
1080 | 0 | else |
1081 | 0 | fmt = "(private-key(ecc(curve %s)(q%m)(d%m)))"; |
1082 | |
|
1083 | 0 | rc = gcry_sexp_build (&s_skey, NULL, fmt, curve, skey[1], skey[2]); |
1084 | 0 | xfree (curve); |
1085 | 0 | } |
1086 | 0 | } |
1087 | 0 | else |
1088 | 0 | return GPG_ERR_PUBKEY_ALGO; |
1089 | | |
1090 | 0 | if (!rc) |
1091 | 0 | { |
1092 | 0 | rc = gcry_pk_testkey (s_skey); |
1093 | 0 | gcry_sexp_release (s_skey); |
1094 | 0 | } |
1095 | 0 | return rc; |
1096 | 0 | } |