Coverage Report

Created: 2026-01-10 07:05

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gnupg/g10/pkglue.c
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
}