diff --git a/agent/pkdecrypt.c b/agent/pkdecrypt.c index 10bd92152..5509b1169 100644 --- a/agent/pkdecrypt.c +++ b/agent/pkdecrypt.c @@ -1,652 +1,658 @@ /* pkdecrypt.c - public key decryption (well, actually using a secret key) * Copyright (C) 2001, 2003 Free Software Foundation, Inc. * * This file is part of GnuPG. * * GnuPG is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * GnuPG is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . */ #include #include #include #include #include #include #include #include #include "agent.h" #include "../common/openpgpdefs.h" /* Table with parameters for KEM decryption. Use get_ecc_parms to * find an entry. */ struct ecc_params { const char *curve; /* Canonical name of the curve. */ size_t pubkey_len; /* Pubkey in the SEXP representation. */ size_t scalar_len; size_t point_len; size_t shared_len; int hash_algo; int algo; int scalar_reverse; }; static const struct ecc_params ecc_table[] = { { "Curve25519", 33, 32, 32, 32, GCRY_MD_SHA3_256, GCRY_KEM_RAW_X25519, 1 }, { "X448", 56, 56, 56, 64, GCRY_MD_SHA3_512, GCRY_KEM_RAW_X448, 0 }, { "brainpoolP256r1", 65, 32, 65, 32, GCRY_MD_SHA3_256, GCRY_KEM_RAW_BP256, 0 }, { "brainpoolP384r1", 97, 48, 97, 64, GCRY_MD_SHA3_512, GCRY_KEM_RAW_BP384, 0 }, + { + "brainpoolP512r1", + 129, 64, 129, 64, + GCRY_MD_SHA3_512, GCRY_KEM_RAW_BP512, + 0 + }, { NULL, 0, 0, 0, 0, 0, 0, 0 } }; /* Maximum buffer sizes required for ECC KEM. Keep this aligned to * the ecc_table above. */ #define ECC_SCALAR_LEN_MAX 64 #define ECC_POINT_LEN_MAX (1+2*64) #define ECC_HASH_LEN_MAX 64 /* Return the ECC parameters for CURVE. CURVE is expected to be the * canonical name. */ static const struct ecc_params * get_ecc_params (const char *curve) { int i; for (i = 0; ecc_table[i].curve; i++) if (!strcmp (ecc_table[i].curve, curve)) return &ecc_table[i]; return NULL; } /* DECRYPT the stuff in ciphertext which is expected to be a S-Exp. Try to get the key from CTRL and write the decoded stuff back to OUTFP. The padding information is stored at R_PADDING with -1 for not known. */ gpg_error_t agent_pkdecrypt (ctrl_t ctrl, const char *desc_text, const unsigned char *ciphertext, size_t ciphertextlen, membuf_t *outbuf, int *r_padding) { gcry_sexp_t s_skey = NULL, s_cipher = NULL, s_plain = NULL; unsigned char *shadow_info = NULL; gpg_error_t err = 0; int no_shadow_info = 0; char *buf = NULL; size_t len; *r_padding = -1; if (!ctrl->have_keygrip) { log_error ("speculative decryption not yet supported\n"); err = gpg_error (GPG_ERR_NO_SECKEY); goto leave; } err = gcry_sexp_sscan (&s_cipher, NULL, (char*)ciphertext, ciphertextlen); if (err) { log_error ("failed to convert ciphertext: %s\n", gpg_strerror (err)); err = gpg_error (GPG_ERR_INV_DATA); goto leave; } if (DBG_CRYPTO) { log_printhex (ctrl->keygrip, 20, "keygrip:"); log_printhex (ciphertext, ciphertextlen, "cipher: "); } err = agent_key_from_file (ctrl, NULL, desc_text, NULL, &shadow_info, CACHE_MODE_NORMAL, NULL, &s_skey, NULL, NULL); if (gpg_err_code (err) == GPG_ERR_NO_SECKEY) no_shadow_info = 1; else if (err) { log_error ("failed to read the secret key\n"); goto leave; } if (shadow_info || no_shadow_info) { /* divert operation to the smartcard */ if (!gcry_sexp_canon_len (ciphertext, ciphertextlen, NULL, NULL)) { err = gpg_error (GPG_ERR_INV_SEXP); goto leave; } if (s_skey && agent_is_tpm2_key (s_skey)) err = divert_tpm2_pkdecrypt (ctrl, ciphertext, shadow_info, &buf, &len, r_padding); else err = divert_pkdecrypt (ctrl, ctrl->keygrip, ciphertext, &buf, &len, r_padding); if (err) { /* We restore the original error (ie. no seckey) is no card * has been found and we have no shadow key. This avoids a * surprising "card removed" error code. */ if ((gpg_err_code (err) == GPG_ERR_CARD_REMOVED || gpg_err_code (err) == GPG_ERR_CARD_NOT_PRESENT) && no_shadow_info) err = gpg_error (GPG_ERR_NO_SECKEY); else log_error ("smartcard decryption failed: %s\n", gpg_strerror (err)); goto leave; } put_membuf_printf (outbuf, "(5:value%u:", (unsigned int)len); put_membuf (outbuf, buf, len); put_membuf (outbuf, ")", 2); } else { /* No smartcard, but a private key */ /* if (DBG_CRYPTO ) */ /* { */ /* log_debug ("skey: "); */ /* gcry_sexp_dump (s_skey); */ /* } */ err = gcry_pk_decrypt (&s_plain, s_cipher, s_skey); if (err) { log_error ("decryption failed: %s\n", gpg_strerror (err)); goto leave; } if (DBG_CRYPTO) { log_debug ("plain: "); gcry_sexp_dump (s_plain); } len = gcry_sexp_sprint (s_plain, GCRYSEXP_FMT_CANON, NULL, 0); log_assert (len); buf = xmalloc (len); len = gcry_sexp_sprint (s_plain, GCRYSEXP_FMT_CANON, buf, len); log_assert (len); if (*buf == '(') put_membuf (outbuf, buf, len); else { /* Old style libgcrypt: This is only an S-expression part. Turn it into a complete S-expression. */ put_membuf (outbuf, "(5:value", 8); put_membuf (outbuf, buf, len); put_membuf (outbuf, ")", 2); } } leave: gcry_sexp_release (s_skey); gcry_sexp_release (s_plain); gcry_sexp_release (s_cipher); xfree (buf); xfree (shadow_info); return err; } /* Reverse BUFFER to change the endianness. */ static void reverse_buffer (unsigned char *buffer, unsigned int length) { unsigned int tmp, i; for (i=0; i < length/2; i++) { tmp = buffer[i]; buffer[i] = buffer[length-1-i]; buffer[length-1-i] = tmp; } } /* For composite PGP KEM (ECC+ML-KEM), decrypt CIPHERTEXT using KEM API. First keygrip is for ECC, second keygrip is for PQC. CIPHERTEXT should follow the format of: (enc-val(pqc(c%d)(e%m)(k%m)(s%m)(fixed-info&))) c: cipher identifier (symmetric) e: ECDH ciphertext k: ML-KEM ciphertext s: encrypted session key fixed-info: A buffer with the fixed info. FIXME: For now, possible keys on smartcard are not supported. */ static gpg_error_t composite_pgp_kem_decrypt (ctrl_t ctrl, const char *desc_text, gcry_sexp_t s_cipher, membuf_t *outbuf) { gcry_sexp_t s_skey0 = NULL; gcry_sexp_t s_skey1 = NULL; unsigned char *shadow_info = NULL; gpg_error_t err = 0; const struct ecc_params *ecc; unsigned int nbits; const unsigned char *p; size_t len; int algo; gcry_mpi_t encrypted_sessionkey_mpi = NULL; const unsigned char *encrypted_sessionkey; size_t encrypted_sessionkey_len; gcry_mpi_t ecc_sk_mpi = NULL; unsigned char ecc_sk[ECC_SCALAR_LEN_MAX]; gcry_mpi_t ecc_pk_mpi = NULL; unsigned char ecc_pk[ECC_POINT_LEN_MAX]; gcry_mpi_t ecc_ct_mpi = NULL; const unsigned char *ecc_ct; unsigned char ecc_ecdh[ECC_POINT_LEN_MAX]; unsigned char ecc_ss[ECC_HASH_LEN_MAX]; enum gcry_kem_algos mlkem_kem_algo; gcry_mpi_t mlkem_sk_mpi = NULL; gcry_mpi_t mlkem_ct_mpi = NULL; const unsigned char *mlkem_sk; size_t mlkem_sk_len; const unsigned char *mlkem_ct; size_t mlkem_ct_len; unsigned char mlkem_ss[GCRY_KEM_MLKEM1024_SHARED_LEN]; size_t mlkem_ss_len; unsigned char kek[32]; size_t kek_len = 32; /* AES-256 is mandatory */ gcry_cipher_hd_t hd; unsigned char sessionkey[256]; size_t sessionkey_len; gcry_buffer_t fixed_info = { 0, 0, 0, NULL }; gcry_sexp_t curve = NULL; char *curve_name = NULL; err = agent_key_from_file (ctrl, NULL, desc_text, ctrl->keygrip, &shadow_info, CACHE_MODE_NORMAL, NULL, &s_skey0, NULL, NULL); if (err) { log_error ("failed to read the secret key\n"); goto leave; } err = agent_key_from_file (ctrl, NULL, desc_text, ctrl->keygrip1, &shadow_info, CACHE_MODE_NORMAL, NULL, &s_skey1, NULL, NULL); if (err) { log_error ("failed to read the another secret key\n"); goto leave; } /* Here assumes no smartcard, but private keys */ err = gcry_sexp_extract_param (s_cipher, NULL, "%dc/eks&'fixed-info'", &algo, &ecc_ct_mpi, &mlkem_ct_mpi, &encrypted_sessionkey_mpi, &fixed_info, NULL); if (err) { if (opt.verbose) log_info ("%s: extracting parameters failed\n", __func__); goto leave; } len = gcry_cipher_get_algo_keylen (algo); encrypted_sessionkey = gcry_mpi_get_opaque (encrypted_sessionkey_mpi, &nbits); encrypted_sessionkey_len = (nbits+7)/8; if (len == 0 || encrypted_sessionkey_len != len + 8) { if (opt.verbose) log_info ("%s: encrypted session key length %zu" " does not match the length for algo %d\n", __func__, encrypted_sessionkey_len, algo); err = gpg_error (GPG_ERR_INV_DATA); goto leave; } /* Firstly, ECC part. */ curve = gcry_sexp_find_token (s_skey0, "curve", 0); if (!curve) { if (opt.verbose) log_info ("%s: no curve given\n", __func__); err = gpg_error (GPG_ERR_BAD_SECKEY); goto leave; } curve_name = gcry_sexp_nth_string (curve, 1); ecc = get_ecc_params (curve_name); if (!ecc) { if (opt.verbose) log_info ("%s: curve '%s' not supported\n", __func__, curve_name); err = gpg_error (GPG_ERR_BAD_SECKEY); goto leave; } err = gcry_sexp_extract_param (s_skey0, NULL, "/qd", &ecc_pk_mpi, &ecc_sk_mpi, NULL); if (err) { if (opt.verbose) log_info ("%s: extracting q and d from ECC key failed\n", __func__); goto leave; } p = gcry_mpi_get_opaque (ecc_pk_mpi, &nbits); len = (nbits+7)/8; if (len != ecc->pubkey_len) { if (opt.verbose) log_info ("%s: ECC public key length invalid (%zu)\n", __func__, len); err = gpg_error (GPG_ERR_INV_DATA); goto leave; } else if (len == ecc->point_len) memcpy (ecc_pk, p, ecc->point_len); else if (len == ecc->point_len + 1 && p[0] == 0x40) /* Remove the 0x40 prefix (for Curve25519) */ memcpy (ecc_pk, p+1, ecc->point_len); else { err = gpg_error (GPG_ERR_BAD_SECKEY); goto leave; } mpi_release (ecc_pk_mpi); ecc_pk_mpi = NULL; p = gcry_mpi_get_opaque (ecc_sk_mpi, &nbits); len = (nbits+7)/8; if (len > ecc->scalar_len) { if (opt.verbose) log_info ("%s: ECC secret key too long (%zu)\n", __func__, len); err = gpg_error (GPG_ERR_INV_DATA); goto leave; } memset (ecc_sk, 0, ecc->scalar_len - len); memcpy (ecc_sk + ecc->scalar_len - len, p, len); if (ecc->scalar_reverse) reverse_buffer (ecc_sk, ecc->scalar_len); mpi_release (ecc_sk_mpi); ecc_sk_mpi = NULL; ecc_ct = gcry_mpi_get_opaque (ecc_ct_mpi, &nbits); if (ecc->point_len != (nbits+7)/8) { if (opt.verbose) log_info ("%s: ECC cipher text length invalid (%zu)\n", __func__, ecc->point_len); err = gpg_error (GPG_ERR_INV_DATA); goto leave; } if (DBG_CRYPTO) { log_debug ("ECC curve: %s\n", curve_name); log_printhex (ecc_pk, ecc->pubkey_len, "ECC pubkey:"); log_printhex (ecc_sk, ecc->scalar_len, "ECC seckey:"); log_printhex (ecc_ct, ecc->point_len, "ECC ephem:"); } err = gcry_kem_decap (ecc->algo, ecc_sk, ecc->scalar_len, ecc_ct, ecc->point_len, ecc_ecdh, ecc->point_len, NULL, 0); if (err) { if (opt.verbose) log_info ("%s: gcry_kem_decap for ECC failed\n", __func__); goto leave; } if (DBG_CRYPTO) log_printhex (ecc_ecdh, ecc->point_len, "ECC ecdh:"); err = gnupg_ecc_kem_kdf (ecc_ss, ecc->shared_len, ecc->hash_algo, ecc_ecdh, ecc->point_len, ecc_ct, ecc->point_len, ecc_pk, ecc->point_len); if (err) { if (opt.verbose) log_info ("%s: kdf for ECC failed\n", __func__); goto leave; } if (DBG_CRYPTO) log_printhex (ecc_ss, ecc->shared_len, "ECC shared:"); /* Secondly, PQC part. For now, we assume ML-KEM. */ err = gcry_sexp_extract_param (s_skey1, NULL, "/s", &mlkem_sk_mpi, NULL); if (err) { if (opt.verbose) log_info ("%s: extracting s from PQ key failed\n", __func__); goto leave; } mlkem_sk = gcry_mpi_get_opaque (mlkem_sk_mpi, &nbits); mlkem_sk_len = (nbits+7)/8; if (mlkem_sk_len == GCRY_KEM_MLKEM512_SECKEY_LEN) { mlkem_kem_algo = GCRY_KEM_MLKEM512; mlkem_ss_len = GCRY_KEM_MLKEM512_SHARED_LEN; mlkem_ct_len = GCRY_KEM_MLKEM512_CIPHER_LEN; } else if (mlkem_sk_len == GCRY_KEM_MLKEM768_SECKEY_LEN) { mlkem_kem_algo = GCRY_KEM_MLKEM768; mlkem_ss_len = GCRY_KEM_MLKEM768_SHARED_LEN; mlkem_ct_len = GCRY_KEM_MLKEM768_CIPHER_LEN; } else if (mlkem_sk_len == GCRY_KEM_MLKEM1024_SECKEY_LEN) { mlkem_kem_algo = GCRY_KEM_MLKEM1024; mlkem_ss_len = GCRY_KEM_MLKEM1024_SHARED_LEN; mlkem_ct_len = GCRY_KEM_MLKEM1024_CIPHER_LEN; } else { if (opt.verbose) log_info ("%s: PQ key length invalid (%zu)\n", __func__, mlkem_sk_len); err = gpg_error (GPG_ERR_INV_DATA); goto leave; } mlkem_ct = gcry_mpi_get_opaque (mlkem_ct_mpi, &nbits); len = (nbits+7)/8; if (len != mlkem_ct_len) { if (opt.verbose) log_info ("%s: PQ cipher text length invalid (%zu)\n", __func__, mlkem_ct_len); err = gpg_error (GPG_ERR_INV_DATA); goto leave; } err = gcry_kem_decap (mlkem_kem_algo, mlkem_sk, mlkem_sk_len, mlkem_ct, mlkem_ct_len, mlkem_ss, mlkem_ss_len, NULL, 0); if (err) { if (opt.verbose) log_info ("%s: gcry_kem_decap for PQ failed\n", __func__); goto leave; } mpi_release (mlkem_sk_mpi); mlkem_sk_mpi = NULL; /* Then, combine two shared secrets and ciphertexts into one KEK */ err = gnupg_kem_combiner (kek, kek_len, ecc_ss, ecc->shared_len, ecc_ct, ecc->point_len, mlkem_ss, mlkem_ss_len, mlkem_ct, mlkem_ct_len, fixed_info.data, fixed_info.size); if (err) { if (opt.verbose) log_info ("%s: KEM combiner failed\n", __func__); goto leave; } mpi_release (ecc_ct_mpi); ecc_ct_mpi = NULL; mpi_release (mlkem_ct_mpi); mlkem_ct_mpi = NULL; if (DBG_CRYPTO) { log_printhex (kek, kek_len, "KEK key: "); } err = gcry_cipher_open (&hd, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_AESWRAP, 0); if (err) { if (opt.verbose) log_error ("ecdh failed to initialize AESWRAP: %s\n", gpg_strerror (err)); goto leave; } err = gcry_cipher_setkey (hd, kek, kek_len); sessionkey_len = encrypted_sessionkey_len - 8; err = gcry_cipher_decrypt (hd, sessionkey, sessionkey_len, encrypted_sessionkey, encrypted_sessionkey_len); gcry_cipher_close (hd); mpi_release (encrypted_sessionkey_mpi); encrypted_sessionkey_mpi = NULL; if (err) { log_error ("KEM decrypt failed: %s\n", gpg_strerror (err)); goto leave; } put_membuf_printf (outbuf, "(5:value%u:", (unsigned int)sessionkey_len); put_membuf (outbuf, sessionkey, sessionkey_len); put_membuf (outbuf, ")", 2); leave: wipememory (ecc_sk, sizeof ecc_sk); wipememory (ecc_ecdh, sizeof ecc_ecdh); wipememory (ecc_ss, sizeof ecc_ss); wipememory (mlkem_ss, sizeof mlkem_ss); wipememory (kek, sizeof kek); wipememory (sessionkey, sizeof sessionkey); mpi_release (mlkem_sk_mpi); mpi_release (ecc_pk_mpi); mpi_release (ecc_sk_mpi); mpi_release (ecc_ct_mpi); mpi_release (mlkem_ct_mpi); mpi_release (encrypted_sessionkey_mpi); gcry_free (fixed_info.data); gcry_sexp_release (curve); xfree (curve_name); gcry_sexp_release (s_skey0); gcry_sexp_release (s_skey1); return err; } /* DECRYPT the encrypted stuff (like encrypted session key) in CIPHERTEXT using KEM API, with KEMID. Keys (or a key) are specified in CTRL. DESC_TEXT is used to retrieve private key. OPTION can be specified for upper layer option for KEM. Decrypted stuff (like session key) is written to OUTBUF. */ gpg_error_t agent_kem_decrypt (ctrl_t ctrl, const char *desc_text, int kemid, const unsigned char *ciphertext, size_t ciphertextlen, const unsigned char *option, size_t optionlen, membuf_t *outbuf) { gcry_sexp_t s_cipher = NULL; gpg_error_t err = 0; /* For now, only PQC-PGP is supported. */ if (kemid != KEM_PQC_PGP) return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM); (void)optionlen; if (kemid == KEM_PQC_PGP && option) { log_error ("PQC-PGP requires no option\n"); return gpg_error (GPG_ERR_INV_ARG); } if (!ctrl->have_keygrip) { log_error ("speculative decryption not yet supported\n"); return gpg_error (GPG_ERR_NO_SECKEY); } if (!ctrl->have_keygrip1) { log_error ("Composite KEM requires two KEYGRIPs\n"); return gpg_error (GPG_ERR_NO_SECKEY); } err = gcry_sexp_sscan (&s_cipher, NULL, (char*)ciphertext, ciphertextlen); if (err) { log_error ("failed to convert ciphertext: %s\n", gpg_strerror (err)); return gpg_error (GPG_ERR_INV_DATA); } if (DBG_CRYPTO) { log_printhex (ctrl->keygrip, 20, "keygrip0:"); log_printhex (ctrl->keygrip1, 20, "keygrip1:"); gcry_log_debugsxp ("cipher", s_cipher); } err = composite_pgp_kem_decrypt (ctrl, desc_text, s_cipher, outbuf); gcry_sexp_release (s_cipher); return err; } diff --git a/common/openpgp-oid.c b/common/openpgp-oid.c index a374904cf..92f0dfbcd 100644 --- a/common/openpgp-oid.c +++ b/common/openpgp-oid.c @@ -1,780 +1,781 @@ /* openpgp-oids.c - OID helper for OpenPGP * Copyright (C) 2011 Free Software Foundation, Inc. * Copyright (C) 2013 Werner Koch * * This file is part of GnuPG. * * This file is free software; you can redistribute it and/or modify * it under the terms of either * * - the GNU Lesser General Public License as published by the Free * Software Foundation; either version 3 of the License, or (at * your option) any later version. * * or * * - the GNU General Public License as published by the Free * Software Foundation; either version 2 of the License, or (at * your option) any later version. * * or both in parallel, as here. * * This file is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . */ #include #include #include #include #include #include "util.h" #include "openpgpdefs.h" /* A table with all our supported OpenPGP curves. */ static struct { const char *name; /* Standard name. */ const char *oidstr; /* IETF formatted OID. */ unsigned int nbits; /* Nominal bit length of the curve. */ const char *alias; /* NULL or alternative name of the curve. */ const char *abbr; /* NULL or abbreviated name of the curve. */ int pubkey_algo; /* Required OpenPGP algo or 0 for ECDSA/ECDH. */ enum gcry_kem_algos kem_algo; /* 0 or the KEM algorithm for PQC. */ } oidtable[] = { { "Curve25519", "1.3.6.1.4.1.3029.1.5.1", 255, "cv25519", NULL, PUBKEY_ALGO_ECDH, GCRY_KEM_RAW_X25519 /* only during development */}, { "Ed25519", "1.3.6.1.4.1.11591.15.1", 255, "ed25519", NULL, PUBKEY_ALGO_EDDSA }, { "Curve25519", "1.3.101.110", 255, "cv25519", NULL, PUBKEY_ALGO_ECDH, GCRY_KEM_RAW_X25519 }, { "Ed25519", "1.3.101.112", 255, "ed25519", NULL, PUBKEY_ALGO_EDDSA }, { "X448", "1.3.101.111", 448, "cv448", NULL, PUBKEY_ALGO_ECDH, GCRY_KEM_RAW_X448 }, { "Ed448", "1.3.101.113", 456, "ed448", NULL, PUBKEY_ALGO_EDDSA }, { "NIST P-256", "1.2.840.10045.3.1.7", 256, "nistp256" }, { "NIST P-384", "1.3.132.0.34", 384, "nistp384" }, { "NIST P-521", "1.3.132.0.35", 521, "nistp521" }, { "brainpoolP256r1", "1.3.36.3.3.2.8.1.1.7", 256, NULL, "bp256", 0, GCRY_KEM_RAW_BP256 }, { "brainpoolP384r1", "1.3.36.3.3.2.8.1.1.11", 384, NULL, "bp384", 0, GCRY_KEM_RAW_BP384 }, - { "brainpoolP512r1", "1.3.36.3.3.2.8.1.1.13", 512, NULL, "bp512" }, + { "brainpoolP512r1", "1.3.36.3.3.2.8.1.1.13", 512, NULL, "bp512", + 0, GCRY_KEM_RAW_BP512 }, { "secp256k1", "1.3.132.0.10", 256 }, { NULL, NULL, 0} }; /* The OID for Curve Ed25519 in OpenPGP format. The shorter v5 * variant may only be used with v5 keys. */ static const char oid_ed25519[] = { 0x09, 0x2b, 0x06, 0x01, 0x04, 0x01, 0xda, 0x47, 0x0f, 0x01 }; static const char oid_ed25519_v5[] = { 0x03, 0x2b, 0x65, 0x70 }; /* The OID for Curve25519 in OpenPGP format. The shorter v5 * variant may only be used with v5 keys. */ static const char oid_cv25519[] = { 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x97, 0x55, 0x01, 0x05, 0x01 }; static const char oid_cv25519_v5[] = { 0x03, 0x2b, 0x65, 0x6e }; /* The OID for X448 in OpenPGP format. */ /* * Here, we have a little semantic discrepancy. X448 is the name of * the ECDH computation and the OID is assigned to the algorithm in * RFC 8410. Note that this OID is not the one which is assigned to * the curve itself (originally in 8410). Nevertheless, we use "X448" * for the curve in libgcrypt. */ static const char oid_cv448[] = { 0x03, 0x2b, 0x65, 0x6f }; /* The OID for Ed448 in OpenPGP format. */ static const char oid_ed448[] = { 0x03, 0x2b, 0x65, 0x71 }; /* A table to store keyalgo strings like "rsa2048 or "ed25519" so that * we do not need to allocate them. This is currently a simple array * but may eventually be changed to a fast data structure. Noet that * unknown algorithms are stored with (NBITS,CURVE) set to (0,NULL). */ struct keyalgo_string_s { enum gcry_pk_algos algo; /* Mandatory. */ unsigned int nbits; /* Size for classical algos. */ char *curve; /* Curvename (OID) or NULL. */ char *name; /* Allocated name. */ }; static struct keyalgo_string_s *keyalgo_strings; /* The table. */ static size_t keyalgo_strings_size; /* Allocated size. */ static size_t keyalgo_strings_used; /* Used size. */ /* Helper for openpgp_oid_from_str. */ static size_t make_flagged_int (unsigned long value, char *buf, size_t buflen) { int more = 0; int shift; /* fixme: figure out the number of bits in an ulong and start with that value as shift (after making it a multiple of 7) a more straigtforward implementation is to do it in reverse order using a temporary buffer - saves a lot of compares */ for (more=0, shift=28; shift > 0; shift -= 7) { if (more || value >= (1<> shift); value -= (value >> shift) << shift; more = 1; } } buf[buflen++] = value; return buflen; } /* Convert the OID given in dotted decimal form in STRING to an DER * encoding and store it as an opaque value at R_MPI. The format of * the DER encoded is not a regular ASN.1 object but the modified * format as used by OpenPGP for the ECC curve description. On error * the function returns and error code an NULL is stored at R_BUG. * Note that scanning STRING stops at the first white space * character. */ gpg_error_t openpgp_oid_from_str (const char *string, gcry_mpi_t *r_mpi) { unsigned char *buf; size_t buflen; unsigned long val1, val; const char *endp; int arcno; *r_mpi = NULL; if (!string || !*string) return gpg_error (GPG_ERR_INV_VALUE); /* We can safely assume that the encoded OID is shorter than the string. */ buf = xtrymalloc (1 + strlen (string) + 2); if (!buf) return gpg_error_from_syserror (); /* Save the first byte for the length. */ buflen = 1; val1 = 0; /* Avoid compiler warning. */ arcno = 0; do { arcno++; val = strtoul (string, (char**)&endp, 10); if (!digitp (string) || !(*endp == '.' || !*endp)) { xfree (buf); return gpg_error (GPG_ERR_INV_OID_STRING); } if (*endp == '.') string = endp+1; if (arcno == 1) { if (val > 2) break; /* Not allowed, error caught below. */ val1 = val; } else if (arcno == 2) { /* Need to combine the first two arcs in one octet. */ if (val1 < 2) { if (val > 39) { xfree (buf); return gpg_error (GPG_ERR_INV_OID_STRING); } buf[buflen++] = val1*40 + val; } else { val += 80; buflen = make_flagged_int (val, buf, buflen); } } else { buflen = make_flagged_int (val, buf, buflen); } } while (*endp == '.'); if (arcno == 1 || buflen < 2 || buflen > 254 ) { /* It is not possible to encode only the first arc. */ xfree (buf); return gpg_error (GPG_ERR_INV_OID_STRING); } *buf = buflen - 1; *r_mpi = gcry_mpi_set_opaque (NULL, buf, buflen * 8); if (!*r_mpi) { xfree (buf); return gpg_error_from_syserror (); } return 0; } /* Return a malloced string representation of the OID in the buffer * (BUF,LEN). In case of an error NULL is returned and ERRNO is set. * As per OpenPGP spec the first byte of the buffer is the length of * the rest; the function performs a consistency check. */ char * openpgp_oidbuf_to_str (const unsigned char *buf, size_t len) { char *string, *p; int n = 0; unsigned long val, valmask; valmask = (unsigned long)0xfe << (8 * (sizeof (valmask) - 1)); /* The first bytes gives the length; check consistency. */ if (!len || buf[0] != len -1) { gpg_err_set_errno (EINVAL); return NULL; } /* Skip length byte. */ len--; buf++; /* To calculate the length of the string we can safely assume an upper limit of 3 decimal characters per byte. Two extra bytes account for the special first octet */ string = p = xtrymalloc (len*(1+3)+2+1); if (!string) return NULL; if (!len) { *p = 0; return string; } if (buf[0] < 40) p += sprintf (p, "0.%d", buf[n]); else if (buf[0] < 80) p += sprintf (p, "1.%d", buf[n]-40); else { val = buf[n] & 0x7f; while ( (buf[n]&0x80) && ++n < len ) { if ( (val & valmask) ) goto badoid; /* Overflow. */ val <<= 7; val |= buf[n] & 0x7f; } if (val < 80) goto badoid; val -= 80; sprintf (p, "2.%lu", val); p += strlen (p); } for (n++; n < len; n++) { val = buf[n] & 0x7f; while ( (buf[n]&0x80) && ++n < len ) { if ( (val & valmask) ) goto badoid; /* Overflow. */ val <<= 7; val |= buf[n] & 0x7f; } sprintf (p, ".%lu", val); p += strlen (p); } *p = 0; return string; badoid: /* Return a special OID (gnu.gnupg.badoid) to indicate the error case. The OID is broken and thus we return one which can't do any harm. Formally this does not need to be a bad OID but an OID with an arc that can't be represented in a 32 bit word is more than likely corrupt. */ xfree (string); return xtrystrdup ("1.3.6.1.4.1.11591.2.12242973"); } /* Return a malloced string representation of the OID in the opaque * MPI A. In case of an error NULL is returned and ERRNO is set. */ char * openpgp_oid_to_str (gcry_mpi_t a) { const unsigned char *buf; unsigned int lengthi; if (!a || !gcry_mpi_get_flag (a, GCRYMPI_FLAG_OPAQUE) || !(buf = gcry_mpi_get_opaque (a, &lengthi))) { gpg_err_set_errno (EINVAL); return NULL; } return openpgp_oidbuf_to_str (buf, (lengthi+7)/8); } /* Return true if (BUF,LEN) represents the OID for Ed25519. */ int openpgp_oidbuf_is_ed25519 (const void *buf, size_t len) { if (!buf) return 0; return ((len == DIM (oid_ed25519) && !memcmp (buf, oid_ed25519, DIM (oid_ed25519))) || (len == DIM (oid_ed25519_v5) && !memcmp (buf, oid_ed25519_v5, DIM (oid_ed25519_v5)))); } /* Return true if A represents the OID for Ed25519. */ int openpgp_oid_is_ed25519 (gcry_mpi_t a) { const unsigned char *buf; unsigned int nbits; if (!a || !gcry_mpi_get_flag (a, GCRYMPI_FLAG_OPAQUE)) return 0; buf = gcry_mpi_get_opaque (a, &nbits); return openpgp_oidbuf_is_ed25519 (buf, (nbits+7)/8); } /* Return true if (BUF,LEN) represents the OID for Curve25519. */ int openpgp_oidbuf_is_cv25519 (const void *buf, size_t len) { if (!buf) return 0; return ((len == DIM (oid_cv25519) && !memcmp (buf, oid_cv25519, DIM (oid_cv25519))) || (len == DIM (oid_cv25519_v5) && !memcmp (buf, oid_cv25519_v5, DIM (oid_cv25519_v5)))); } /* Return true if (BUF,LEN) represents the OID for Ed448. */ static int openpgp_oidbuf_is_ed448 (const void *buf, size_t len) { return (buf && len == DIM (oid_ed448) && !memcmp (buf, oid_ed448, DIM (oid_ed448))); } /* Return true if (BUF,LEN) represents the OID for X448. */ static int openpgp_oidbuf_is_cv448 (const void *buf, size_t len) { return (buf && len == DIM (oid_cv448) && !memcmp (buf, oid_cv448, DIM (oid_cv448))); } /* Return true if the MPI A represents the OID for Curve25519. */ int openpgp_oid_is_cv25519 (gcry_mpi_t a) { const unsigned char *buf; unsigned int nbits; if (!a || !gcry_mpi_get_flag (a, GCRYMPI_FLAG_OPAQUE)) return 0; buf = gcry_mpi_get_opaque (a, &nbits); return openpgp_oidbuf_is_cv25519 (buf, (nbits+7)/8); } /* Return true if the MPI A represents the OID for Ed448. */ int openpgp_oid_is_ed448 (gcry_mpi_t a) { const unsigned char *buf; unsigned int nbits; if (!a || !gcry_mpi_get_flag (a, GCRYMPI_FLAG_OPAQUE)) return 0; buf = gcry_mpi_get_opaque (a, &nbits); return openpgp_oidbuf_is_ed448 (buf, (nbits+7)/8); } /* Return true if the MPI A represents the OID for X448. */ int openpgp_oid_is_cv448 (gcry_mpi_t a) { const unsigned char *buf; unsigned int nbits; if (!a || !gcry_mpi_get_flag (a, GCRYMPI_FLAG_OPAQUE)) return 0; buf = gcry_mpi_get_opaque (a, &nbits); return openpgp_oidbuf_is_cv448 (buf, (nbits+7)/8); } /* Map the Libgcrypt ECC curve NAME to an OID. If R_NBITS is not NULL store the bit size of the curve there. Returns NULL for unknown curve names. If R_ALGO is not NULL and a specific ECC algorithm is required for this curve its OpenPGP algorithm number is stored there; otherwise 0 is stored which indicates that ECDSA or ECDH can be used. */ const char * openpgp_curve_to_oid (const char *name, unsigned int *r_nbits, int *r_algo) { int i; unsigned int nbits = 0; const char *oidstr = NULL; int algo = 0; if (name) { for (i=0; oidtable[i].name; i++) if (!ascii_strcasecmp (oidtable[i].name, name) || (oidtable[i].alias && !ascii_strcasecmp (oidtable[i].alias, name))) { oidstr = oidtable[i].oidstr; nbits = oidtable[i].nbits; algo = oidtable[i].pubkey_algo; break; } if (!oidtable[i].name) { /* If not found assume the input is already an OID and check whether we support it. */ for (i=0; oidtable[i].name; i++) if (!ascii_strcasecmp (name, oidtable[i].oidstr)) { oidstr = oidtable[i].oidstr; nbits = oidtable[i].nbits; algo = oidtable[i].pubkey_algo; break; } } } if (r_nbits) *r_nbits = nbits; if (r_algo) *r_algo = algo; return oidstr; } /* Map an OpenPGP OID to the Libgcrypt curve name. Returns NULL for * unknown curve names. MODE defines which version of the curve name * is returned. For example: * * | OID | mode=0 | mode=1 | mode=2 | * |----------------------+-----------------+-----------------+----------| * | 1.2.840.10045.3.1.7 | nistp256 | NIST P-256 | nistp256 | * | 1.3.36.3.3.2.8.1.1.7 | brainpoolP256r1 | brainpoolP256r1 | bp256 | * * Thus mode 0 returns the name as commonly used gpg, mode 1 returns * the canonical name, and mode 2 prefers an abbreviated name over the * commonly used name. */ const char * openpgp_oid_to_curve (const char *oidstr, int mode) { int i; if (!oidstr) return NULL; for (i=0; oidtable[i].name; i++) if (!strcmp (oidtable[i].oidstr, oidstr)) { if (mode == 2) { if (oidtable[i].abbr) return oidtable[i].abbr; mode = 0; /* No abbreviation - fallback to mode 0. */ } return !mode && oidtable[i].alias? oidtable[i].alias : oidtable[i].name; } return NULL; } /* Map an OpenPGP OID, name or alias to the Libgcrypt curve name. * Returns NULL for unknown curve names. Unless CANON is set we * prefer an alias name here which is more suitable for printing. */ const char * openpgp_oid_or_name_to_curve (const char *oidname, int canon) { int i; if (!oidname) return NULL; for (i=0; oidtable[i].name; i++) if (!ascii_strcasecmp (oidtable[i].oidstr, oidname) || !ascii_strcasecmp (oidtable[i].name, oidname) || (oidtable[i].alias && !ascii_strcasecmp (oidtable[i].alias, oidname))) return !canon && oidtable[i].alias? oidtable[i].alias : oidtable[i].name; return NULL; } /* Return the KEM algorithm id for the curve with OIDNAME. */ enum gcry_kem_algos openpgp_oid_to_kem_algo (const char *oidname) { int i; if (!oidname) return 0; for (i=0; oidtable[i].name; i++) if (!strcmp (oidtable[i].oidstr, oidname)) return oidtable[i].kem_algo; for (i=0; oidtable[i].name; i++) if (!ascii_strcasecmp (oidtable[i].name, oidname) || (oidtable[i].alias && !ascii_strcasecmp (oidtable[i].alias, oidname))) return oidtable[i].kem_algo; return 0; } /* Return true if the curve with NAME is supported. */ static int curve_supported_p (const char *name) { int result = 0; gcry_sexp_t keyparms; if (!gcry_sexp_build (&keyparms, NULL, "(public-key(ecc(curve %s)))", name)) { result = !!gcry_pk_get_curve (keyparms, 0, NULL); gcry_sexp_release (keyparms); } return result; } /* Enumerate available and supported OpenPGP curves. The caller needs to set the integer variable at ITERP to zero and keep on calling this function until NULL is returned. */ const char * openpgp_enum_curves (int *iterp) { int idx = *iterp; while (idx >= 0 && idx < DIM (oidtable) && oidtable[idx].name) { if (curve_supported_p (oidtable[idx].name)) { *iterp = idx + 1; return oidtable[idx].alias? oidtable[idx].alias : oidtable[idx].name; } idx++; } *iterp = idx; return NULL; } /* Return the Libgcrypt name for the gpg curve NAME if supported. If * R_ALGO is not NULL the required OpenPGP public key algo or 0 is * stored at that address. If R_NBITS is not NULL the nominal bitsize * of the curves is stored there. NULL is returned if the curve is * not supported. */ const char * openpgp_is_curve_supported (const char *name, int *r_algo, unsigned int *r_nbits) { int idx; if (r_algo) *r_algo = 0; if (r_nbits) *r_nbits = 0; for (idx = 0; idx < DIM (oidtable) && oidtable[idx].name; idx++) { if ((!ascii_strcasecmp (name, oidtable[idx].name) || (oidtable[idx].alias && !ascii_strcasecmp (name, (oidtable[idx].alias))) || (oidtable[idx].abbr && !ascii_strcasecmp (name, (oidtable[idx].abbr)))) && curve_supported_p (oidtable[idx].name)) { if (r_algo) *r_algo = oidtable[idx].pubkey_algo; if (r_nbits) *r_nbits = oidtable[idx].nbits; return oidtable[idx].name; } } return NULL; } /* Map a Gcrypt public key algorithm number to the used by OpenPGP. * Returns 0 for unknown gcry algorithm. */ pubkey_algo_t map_gcry_pk_to_openpgp (enum gcry_pk_algos algo) { switch (algo) { case GCRY_PK_EDDSA: return PUBKEY_ALGO_EDDSA; case GCRY_PK_ECDSA: return PUBKEY_ALGO_ECDSA; case GCRY_PK_ECDH: return PUBKEY_ALGO_ECDH; case GCRY_PK_KEM: return PUBKEY_ALGO_KYBER; default: return algo < 110 ? (pubkey_algo_t)algo : 0; } } /* Map an OpenPGP public key algorithm number to the one used by * Libgcrypt. Returns 0 for unknown gcry algorithm. */ enum gcry_pk_algos map_openpgp_pk_to_gcry (pubkey_algo_t algo) { switch (algo) { case PUBKEY_ALGO_EDDSA: return GCRY_PK_EDDSA; case PUBKEY_ALGO_ECDSA: return GCRY_PK_ECDSA; case PUBKEY_ALGO_ECDH: return GCRY_PK_ECDH; default: return algo < 110 ? (enum gcry_pk_algos)algo : 0; } } /* Return a string describing the public key algorithm and the * keysize. For elliptic curves the function prints the name of the * curve because the keysize is a property of the curve. ALGO is the * Gcrypt algorithm number, CURVE is either NULL or gives the OID of * the curve, NBITS is either 0 or the size for algorithms like RSA. * The returned string is taken from permanent table. Examples * for the output are: * * "rsa3072" - RSA with 3072 bit * "elg1024" - Elgamal with 1024 bit * "ed25519" - ECC using the curve Ed25519. * "E_1.2.3.4" - ECC using the unsupported curve with OID "1.2.3.4". * "E_1.3.6.1.4.1.11591.2.12242973" - ECC with a bogus OID. * "unknown_N" - Unknown OpenPGP algorithm N. * If N is > 110 this is a gcrypt algo. */ const char * get_keyalgo_string (enum gcry_pk_algos algo, unsigned int nbits, const char *curve) { const char *prefix; int i; char *name, *curvebuf; switch (algo) { case GCRY_PK_RSA: prefix = "rsa"; break; case GCRY_PK_ELG: prefix = "elg"; break; case GCRY_PK_DSA: prefix = "dsa"; break; case GCRY_PK_ECC: case GCRY_PK_ECDH: case GCRY_PK_ECDSA: case GCRY_PK_EDDSA: prefix = ""; break; default: prefix = NULL; break; } if (prefix && *prefix && nbits) { for (i=0; i < keyalgo_strings_used; i++) { if (keyalgo_strings[i].algo == algo && keyalgo_strings[i].nbits && keyalgo_strings[i].nbits == nbits) return keyalgo_strings[i].name; } /* Not yet in the table - add it. */ name = xasprintf ("%s%u", prefix, nbits); nbits = nbits? nbits : 1; /* No nbits - oops - use 1 instead. */ curvebuf = NULL; } else if (prefix && !*prefix) { const char *curvename; for (i=0; i < keyalgo_strings_used; i++) { if (keyalgo_strings[i].algo == algo && keyalgo_strings[i].curve && curve && !ascii_strcasecmp (keyalgo_strings[i].curve, curve)) return keyalgo_strings[i].name; } /* Not yet in the table - add it. */ curvename = openpgp_oid_or_name_to_curve (curve, 0); if (curvename) name = xasprintf ("%s", curvename); else if (curve) name = xasprintf ("E_%s", curve); else name = xasprintf ("E_error"); nbits = 0; curvebuf = curve? xstrdup (curve) : NULL; } else { for (i=0; i < keyalgo_strings_used; i++) { if (keyalgo_strings[i].algo == algo && !keyalgo_strings[i].nbits && !keyalgo_strings[i].curve) return keyalgo_strings[i].name; } /* Not yet in the table - add it. */ name = xasprintf ("unknown_%u", (unsigned int)algo); nbits = 0; curvebuf = NULL; } /* Store a new entry. This is a loop because of a possible nPth * thread switch during xrealloc. */ while (keyalgo_strings_used >= keyalgo_strings_size) { keyalgo_strings_size += 10; if (keyalgo_strings_size > 1024*1024) log_fatal ("%s: table getting too large - possible DoS\n", __func__); keyalgo_strings = xrealloc (keyalgo_strings, (keyalgo_strings_size * sizeof *keyalgo_strings)); } keyalgo_strings[keyalgo_strings_used].algo = algo; keyalgo_strings[keyalgo_strings_used].nbits = nbits; keyalgo_strings[keyalgo_strings_used].curve = curvebuf; keyalgo_strings[keyalgo_strings_used].name = name; keyalgo_strings_used++; return name; /* Note that this is in the table. */ } diff --git a/g10/pkglue.c b/g10/pkglue.c index 170a1c54b..f4efa8fc5 100644 --- a/g10/pkglue.c +++ b/g10/pkglue.c @@ -1,978 +1,994 @@ /* pkglue.c - public key operations glue code * Copyright (C) 2000, 2003, 2010 Free Software Foundation, Inc. * Copyright (C) 2014 Werner Koch * Copyright (C) 2024 g10 Code GmbH. * * This file is part of GnuPG. * * GnuPG is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * GnuPG is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * SPDX-License-Identifier: GPL-3.0-or-later */ #include #include #include #include #include #include "gpg.h" #include "../common/util.h" #include "pkglue.h" #include "main.h" #include "options.h" /* Maximum buffer sizes required for ECC KEM. */ #define ECC_POINT_LEN_MAX (1+2*64) #define ECC_HASH_LEN_MAX 64 /* FIXME: Better change the function name because mpi_ is used by gcrypt macros. */ gcry_mpi_t get_mpi_from_sexp (gcry_sexp_t sexp, const char *item, int mpifmt) { gcry_sexp_t list; gcry_mpi_t data; list = gcry_sexp_find_token (sexp, item, 0); log_assert (list); data = gcry_sexp_nth_mpi (list, 1, mpifmt); log_assert (data); gcry_sexp_release (list); return data; } /* * SOS (Simply, Octet String) is an attempt to handle opaque octet * string in OpenPGP, where well-formed MPI cannot represent octet * string with leading zero octets. * * To retain maximum compatibility to existing MPI handling, SOS * has same structure, but allows leading zero octets. When there * is no leading zero octets, SOS representation is as same as MPI one. * With leading zero octets, NBITS is 8*(length of octets), regardless * of leading zero bits. */ /* Extract SOS representation from SEXP for PARAM, return the result * in R_SOS. It is represented by opaque MPI with GCRYMPI_FLAG_USER2 * flag. */ gpg_error_t sexp_extract_param_sos (gcry_sexp_t sexp, const char *param, gcry_mpi_t *r_sos) { gpg_error_t err; gcry_sexp_t l2 = gcry_sexp_find_token (sexp, param, 0); *r_sos = NULL; if (!l2) err = gpg_error (GPG_ERR_NO_OBJ); else { size_t buflen; void *p0 = gcry_sexp_nth_buffer (l2, 1, &buflen); if (!p0) err = gpg_error_from_syserror (); else { gcry_mpi_t sos; unsigned int nbits = buflen*8; unsigned char *p = p0; if (*p && nbits >= 8 && !(*p & 0x80)) if (--nbits >= 7 && !(*p & 0x40)) if (--nbits >= 6 && !(*p & 0x20)) if (--nbits >= 5 && !(*p & 0x10)) if (--nbits >= 4 && !(*p & 0x08)) if (--nbits >= 3 && !(*p & 0x04)) if (--nbits >= 2 && !(*p & 0x02)) if (--nbits >= 1 && !(*p & 0x01)) --nbits; sos = gcry_mpi_set_opaque (NULL, p0, nbits); if (sos) { gcry_mpi_set_flag (sos, GCRYMPI_FLAG_USER2); *r_sos = sos; err = 0; } else err = gpg_error_from_syserror (); } gcry_sexp_release (l2); } return err; } /* "No leading zero octets" (nlz) version of the function above. * * This routine is used for backward compatibility to existing * implementation with the weird handling of little endian integer * representation with leading zero octets. For the sake of * "well-fomed" MPI, which is designed for big endian integer, leading * zero octets are removed when output, and they are recovered at * input. * * Extract SOS representation from SEXP for PARAM, removing leading * zeros, return the result in R_SOS. */ gpg_error_t sexp_extract_param_sos_nlz (gcry_sexp_t sexp, const char *param, gcry_mpi_t *r_sos) { gpg_error_t err; gcry_sexp_t l2 = gcry_sexp_find_token (sexp, param, 0); *r_sos = NULL; if (!l2) err = gpg_error (GPG_ERR_NO_OBJ); else { size_t buflen; const void *p0 = gcry_sexp_nth_data (l2, 1, &buflen); if (!p0) err = gpg_error_from_syserror (); else { gcry_mpi_t sos; unsigned int nbits = buflen*8; const unsigned char *p = p0; /* Strip leading zero bits. */ for (; nbits >= 8 && !*p; p++, nbits -= 8) ; if (nbits >= 8 && !(*p & 0x80)) if (--nbits >= 7 && !(*p & 0x40)) if (--nbits >= 6 && !(*p & 0x20)) if (--nbits >= 5 && !(*p & 0x10)) if (--nbits >= 4 && !(*p & 0x08)) if (--nbits >= 3 && !(*p & 0x04)) if (--nbits >= 2 && !(*p & 0x02)) if (--nbits >= 1 && !(*p & 0x01)) --nbits; sos = gcry_mpi_set_opaque_copy (NULL, p, nbits); if (sos) { gcry_mpi_set_flag (sos, GCRYMPI_FLAG_USER2); *r_sos = sos; err = 0; } else err = gpg_error_from_syserror (); } gcry_sexp_release (l2); } return err; } static byte * get_data_from_sexp (gcry_sexp_t sexp, const char *item, size_t *r_size) { gcry_sexp_t list; size_t valuelen; const char *value; byte *v; if (DBG_CRYPTO) log_printsexp ("get_data_from_sexp:", sexp); list = gcry_sexp_find_token (sexp, item, 0); log_assert (list); value = gcry_sexp_nth_data (list, 1, &valuelen); log_assert (value); v = xtrymalloc (valuelen); memcpy (v, value, valuelen); gcry_sexp_release (list); *r_size = valuelen; return v; } /**************** * Emulate our old PK interface here - sometime in the future we might * change the internal design to directly fit to libgcrypt. */ int pk_verify (pubkey_algo_t pkalgo, gcry_mpi_t hash, gcry_mpi_t *data, gcry_mpi_t *pkey) { gcry_sexp_t s_sig, s_hash, s_pkey; int rc; /* Make a sexp from pkey. */ if (pkalgo == PUBKEY_ALGO_DSA) { rc = gcry_sexp_build (&s_pkey, NULL, "(public-key(dsa(p%m)(q%m)(g%m)(y%m)))", pkey[0], pkey[1], pkey[2], pkey[3]); } else if (pkalgo == PUBKEY_ALGO_ELGAMAL_E || pkalgo == PUBKEY_ALGO_ELGAMAL) { rc = gcry_sexp_build (&s_pkey, NULL, "(public-key(elg(p%m)(g%m)(y%m)))", pkey[0], pkey[1], pkey[2]); } else if (pkalgo == PUBKEY_ALGO_RSA || pkalgo == PUBKEY_ALGO_RSA_S) { rc = gcry_sexp_build (&s_pkey, NULL, "(public-key(rsa(n%m)(e%m)))", pkey[0], pkey[1]); } else if (pkalgo == PUBKEY_ALGO_ECDSA) { char *curve = openpgp_oid_to_str (pkey[0]); if (!curve) rc = gpg_error_from_syserror (); else { rc = gcry_sexp_build (&s_pkey, NULL, "(public-key(ecdsa(curve %s)(q%m)))", curve, pkey[1]); xfree (curve); } } else if (pkalgo == PUBKEY_ALGO_EDDSA) { char *curve = openpgp_oid_to_str (pkey[0]); if (!curve) rc = gpg_error_from_syserror (); else { const char *fmt; if (openpgp_oid_is_ed25519 (pkey[0])) fmt = "(public-key(ecc(curve %s)(flags eddsa)(q%m)))"; else fmt = "(public-key(ecc(curve %s)(q%m)))"; rc = gcry_sexp_build (&s_pkey, NULL, fmt, curve, pkey[1]); xfree (curve); } } else return GPG_ERR_PUBKEY_ALGO; if (rc) BUG (); /* gcry_sexp_build should never fail. */ /* Put hash into a S-Exp s_hash. */ if (pkalgo == PUBKEY_ALGO_EDDSA) { const char *fmt; if (openpgp_oid_is_ed25519 (pkey[0])) fmt = "(data(flags eddsa)(hash-algo sha512)(value %m))"; else fmt = "(data(value %m))"; if (gcry_sexp_build (&s_hash, NULL, fmt, hash)) BUG (); /* gcry_sexp_build should never fail. */ } else { if (gcry_sexp_build (&s_hash, NULL, "%m", hash)) BUG (); /* gcry_sexp_build should never fail. */ } /* Put data into a S-Exp s_sig. */ s_sig = NULL; if (pkalgo == PUBKEY_ALGO_DSA) { if (!data[0] || !data[1]) rc = gpg_error (GPG_ERR_BAD_MPI); else rc = gcry_sexp_build (&s_sig, NULL, "(sig-val(dsa(r%m)(s%m)))", data[0], data[1]); } else if (pkalgo == PUBKEY_ALGO_ECDSA) { if (!data[0] || !data[1]) rc = gpg_error (GPG_ERR_BAD_MPI); else rc = gcry_sexp_build (&s_sig, NULL, "(sig-val(ecdsa(r%m)(s%m)))", data[0], data[1]); } else if (pkalgo == PUBKEY_ALGO_EDDSA) { gcry_mpi_t r = data[0]; gcry_mpi_t s = data[1]; if (openpgp_oid_is_ed25519 (pkey[0])) { size_t rlen, slen, n; /* (bytes) */ char buf[64]; unsigned int nbits; unsigned int neededfixedlen = 256 / 8; log_assert (neededfixedlen <= sizeof buf); if (!r || !s) rc = gpg_error (GPG_ERR_BAD_MPI); else if ((rlen = (gcry_mpi_get_nbits (r)+7)/8) > neededfixedlen || !rlen) rc = gpg_error (GPG_ERR_BAD_MPI); else if ((slen = (gcry_mpi_get_nbits (s)+7)/8) > neededfixedlen || !slen) rc = gpg_error (GPG_ERR_BAD_MPI); else { /* We need to fixup the length in case of leading zeroes. * OpenPGP does not allow leading zeroes and the parser for * the signature packet has no information on the use curve, * thus we need to do it here. We won't do it for opaque * MPIs under the assumption that they are known to be fine; * we won't see them here anyway but the check is anyway * required. Fixme: A nifty feature for gcry_sexp_build * would be a format to left pad the value (e.g. "%*M"). */ rc = 0; if (rlen < neededfixedlen && !gcry_mpi_get_flag (r, GCRYMPI_FLAG_OPAQUE) && !(rc=gcry_mpi_print (GCRYMPI_FMT_USG, buf, sizeof buf, &n, r))) { log_assert (n < neededfixedlen); memmove (buf + (neededfixedlen - n), buf, n); memset (buf, 0, neededfixedlen - n); r = gcry_mpi_set_opaque_copy (NULL, buf, neededfixedlen * 8); } else if (rlen < neededfixedlen && gcry_mpi_get_flag (r, GCRYMPI_FLAG_OPAQUE)) { const unsigned char *p; p = gcry_mpi_get_opaque (r, &nbits); n = (nbits+7)/8; memcpy (buf + (neededfixedlen - n), p, n); memset (buf, 0, neededfixedlen - n); gcry_mpi_set_opaque_copy (r, buf, neededfixedlen * 8); } if (slen < neededfixedlen && !gcry_mpi_get_flag (s, GCRYMPI_FLAG_OPAQUE) && !(rc=gcry_mpi_print (GCRYMPI_FMT_USG, buf, sizeof buf, &n, s))) { log_assert (n < neededfixedlen); memmove (buf + (neededfixedlen - n), buf, n); memset (buf, 0, neededfixedlen - n); s = gcry_mpi_set_opaque_copy (NULL, buf, neededfixedlen * 8); } else if (slen < neededfixedlen && gcry_mpi_get_flag (s, GCRYMPI_FLAG_OPAQUE)) { const unsigned char *p; p = gcry_mpi_get_opaque (s, &nbits); n = (nbits+7)/8; memcpy (buf + (neededfixedlen - n), p, n); memset (buf, 0, neededfixedlen - n); gcry_mpi_set_opaque_copy (s, buf, neededfixedlen * 8); } } } else rc = 0; if (!rc) rc = gcry_sexp_build (&s_sig, NULL, "(sig-val(eddsa(r%M)(s%M)))", r, s); if (r != data[0]) gcry_mpi_release (r); if (s != data[1]) gcry_mpi_release (s); } else if (pkalgo == PUBKEY_ALGO_ELGAMAL || pkalgo == PUBKEY_ALGO_ELGAMAL_E) { if (!data[0] || !data[1]) rc = gpg_error (GPG_ERR_BAD_MPI); else rc = gcry_sexp_build (&s_sig, NULL, "(sig-val(elg(r%m)(s%m)))", data[0], data[1]); } else if (pkalgo == PUBKEY_ALGO_RSA || pkalgo == PUBKEY_ALGO_RSA_S) { if (!data[0]) rc = gpg_error (GPG_ERR_BAD_MPI); else rc = gcry_sexp_build (&s_sig, NULL, "(sig-val(rsa(s%m)))", data[0]); } else BUG (); if (!rc) rc = gcry_pk_verify (s_sig, s_hash, s_pkey); gcry_sexp_release (s_sig); gcry_sexp_release (s_hash); gcry_sexp_release (s_pkey); return rc; } #if GCRY_KEM_MLKEM1024_ENCAPS_LEN < GCRY_KEM_MLKEM768_ENCAPS_LEN \ || GCRY_KEM_MLKEM1024_SHARED_LEN < GCRY_KEM_MLKEM768_SHARED_LEN # error Bad Kyber constants in Libgcrypt #endif /* Core of the encryption for KEM algorithms. See pk_decrypt for a * description of the arguments. */ static gpg_error_t do_encrypt_kem (PKT_public_key *pk, gcry_mpi_t data, int seskey_algo, gcry_mpi_t *resarr) { gpg_error_t err; int i; unsigned int nbits, n; gcry_sexp_t s_data = NULL; gcry_cipher_hd_t hd = NULL; char *ecc_oid = NULL; enum gcry_kem_algos kyber_algo, ecc_algo; const unsigned char *ecc_pubkey; size_t ecc_pubkey_len; const unsigned char *kyber_pubkey; size_t kyber_pubkey_len; const unsigned char *seskey; size_t seskey_len; unsigned char *enc_seskey = NULL; size_t enc_seskey_len; int ecc_hash_algo; unsigned char ecc_ct[ECC_POINT_LEN_MAX]; unsigned char ecc_ecdh[ECC_POINT_LEN_MAX]; unsigned char ecc_ss[ECC_HASH_LEN_MAX]; size_t ecc_ct_len, ecc_ecdh_len, ecc_ss_len; unsigned char kyber_ct[GCRY_KEM_MLKEM1024_ENCAPS_LEN]; unsigned char kyber_ss[GCRY_KEM_MLKEM1024_SHARED_LEN]; size_t kyber_ct_len, kyber_ss_len; char fixedinfo[1+MAX_FINGERPRINT_LEN]; int fixedlen; unsigned char kek[32]; /* AES-256 is mandatory. */ size_t kek_len = 32; /* For later error checking we make sure the array is cleared. */ resarr[0] = resarr[1] = resarr[2] = NULL; /* As of now we use KEM only for the combined Kyber and thus a * second public key is expected. Right now we take the keys * directly from the PK->data elements. */ ecc_oid = openpgp_oid_to_str (pk->pkey[0]); if (!ecc_oid) { err = gpg_error_from_syserror (); log_error ("%s: error getting OID for ECC key\n", __func__); goto leave; } ecc_algo = openpgp_oid_to_kem_algo (ecc_oid); if (ecc_algo == GCRY_KEM_RAW_X25519) { if (!strcmp (ecc_oid, "1.3.6.1.4.1.3029.1.5.1")) log_info ("Warning: " "legacy OID for cv25519 accepted during develpment\n"); ecc_pubkey = gcry_mpi_get_opaque (pk->pkey[1], &nbits); ecc_pubkey_len = (nbits+7)/8; if (ecc_pubkey_len == 33 && *ecc_pubkey == 0x40) { ecc_pubkey++; /* Remove the 0x40 prefix. */ ecc_pubkey_len--; } if (ecc_pubkey_len != 32) { if (opt.verbose) log_info ("%s: ECC public key length invalid (%zu)\n", __func__, ecc_pubkey_len); err = gpg_error (GPG_ERR_INV_DATA); goto leave; } ecc_ct_len = ecc_ecdh_len = 32; ecc_ss_len = 32; ecc_hash_algo = GCRY_MD_SHA3_256; } else if (ecc_algo == GCRY_KEM_RAW_X448) { ecc_pubkey = gcry_mpi_get_opaque (pk->pkey[1], &nbits); ecc_pubkey_len = (nbits+7)/8; if (ecc_pubkey_len != 56) { if (opt.verbose) log_info ("%s: ECC public key length invalid (%zu)\n", __func__, ecc_pubkey_len); err = gpg_error (GPG_ERR_INV_DATA); goto leave; } ecc_ct_len = ecc_ecdh_len = 56; ecc_ss_len = 64; ecc_hash_algo = GCRY_MD_SHA3_512; } else if (ecc_algo == GCRY_KEM_RAW_BP256) { ecc_pubkey = gcry_mpi_get_opaque (pk->pkey[1], &nbits); ecc_pubkey_len = (nbits+7)/8; if (ecc_pubkey_len != 65) { if (opt.verbose) log_info ("%s: ECC public key length invalid (%zu)\n", __func__, ecc_pubkey_len); err = gpg_error (GPG_ERR_INV_DATA); goto leave; } ecc_ct_len = ecc_ecdh_len = 65; ecc_ss_len = 32; ecc_hash_algo = GCRY_MD_SHA3_256; } else if (ecc_algo == GCRY_KEM_RAW_BP384) { ecc_pubkey = gcry_mpi_get_opaque (pk->pkey[1], &nbits); ecc_pubkey_len = (nbits+7)/8; if (ecc_pubkey_len != 97) { if (opt.verbose) log_info ("%s: ECC public key length invalid (%zu)\n", __func__, ecc_pubkey_len); err = gpg_error (GPG_ERR_INV_DATA); goto leave; } ecc_ct_len = ecc_ecdh_len = 97; ecc_ss_len = 64; ecc_hash_algo = GCRY_MD_SHA3_512; } + else if (ecc_algo == GCRY_KEM_RAW_BP512) + { + ecc_pubkey = gcry_mpi_get_opaque (pk->pkey[1], &nbits); + ecc_pubkey_len = (nbits+7)/8; + if (ecc_pubkey_len != 129) + { + if (opt.verbose) + log_info ("%s: ECC public key length invalid (%zu)\n", + __func__, ecc_pubkey_len); + err = gpg_error (GPG_ERR_INV_DATA); + goto leave; + } + ecc_ct_len = ecc_ecdh_len = 129; + ecc_ss_len = 64; + ecc_hash_algo = GCRY_MD_SHA3_512; + } else { if (opt.verbose) log_info ("%s: ECC curve %s not supported\n", __func__, ecc_oid); err = gpg_error (GPG_ERR_INV_DATA); goto leave; } if (DBG_CRYPTO) { log_debug ("ECC curve: %s\n", ecc_oid); log_printhex (ecc_pubkey, ecc_pubkey_len, "ECC pubkey:"); } err = gcry_kem_encap (ecc_algo, ecc_pubkey, ecc_pubkey_len, ecc_ct, ecc_ct_len, ecc_ecdh, ecc_ecdh_len, NULL, 0); if (err) { if (opt.verbose) log_info ("%s: gcry_kem_encap for ECC (%s) failed\n", __func__, ecc_oid); goto leave; } if (DBG_CRYPTO) { log_printhex (ecc_ct, ecc_ct_len, "ECC ephem:"); log_printhex (ecc_ecdh, ecc_ecdh_len, "ECC ecdh:"); } err = gnupg_ecc_kem_kdf (ecc_ss, ecc_ss_len, ecc_hash_algo, ecc_ecdh, ecc_ecdh_len, ecc_ct, ecc_ct_len, ecc_pubkey, ecc_pubkey_len); if (err) { if (opt.verbose) log_info ("%s: kdf for ECC failed\n", __func__); goto leave; } if (DBG_CRYPTO) log_printhex (ecc_ss, ecc_ss_len, "ECC shared:"); kyber_pubkey = gcry_mpi_get_opaque (pk->pkey[2], &nbits); kyber_pubkey_len = (nbits+7)/8; if (kyber_pubkey_len == GCRY_KEM_MLKEM768_PUBKEY_LEN) { kyber_algo = GCRY_KEM_MLKEM768; kyber_ct_len = GCRY_KEM_MLKEM768_ENCAPS_LEN; kyber_ss_len = GCRY_KEM_MLKEM768_SHARED_LEN; } else if (kyber_pubkey_len == GCRY_KEM_MLKEM1024_PUBKEY_LEN) { kyber_algo = GCRY_KEM_MLKEM1024; kyber_ct_len = GCRY_KEM_MLKEM1024_ENCAPS_LEN; kyber_ss_len = GCRY_KEM_MLKEM1024_SHARED_LEN; } else { if (opt.verbose) log_info ("%s: Kyber public key length invalid (%zu)\n", __func__, kyber_pubkey_len); err = gpg_error (GPG_ERR_INV_DATA); goto leave; } if (DBG_CRYPTO) log_printhex (kyber_pubkey, kyber_pubkey_len, "|!trunc|Kyber pubkey:"); err = gcry_kem_encap (kyber_algo, kyber_pubkey, kyber_pubkey_len, kyber_ct, kyber_ct_len, kyber_ss, kyber_ss_len, NULL, 0); if (err) { if (opt.verbose) log_info ("%s: gcry_kem_encap for ECC failed\n", __func__); goto leave; } if (DBG_CRYPTO) { log_printhex (kyber_ct, kyber_ct_len, "|!trunc|Kyber ephem:"); log_printhex (kyber_ss, kyber_ss_len, "Kyber shared:"); } fixedinfo[0] = seskey_algo; v5_fingerprint_from_pk (pk, fixedinfo+1, NULL); fixedlen = 33; err = gnupg_kem_combiner (kek, kek_len, ecc_ss, ecc_ss_len, ecc_ct, ecc_ct_len, kyber_ss, kyber_ss_len, kyber_ct, kyber_ct_len, fixedinfo, fixedlen); if (err) { if (opt.verbose) log_info ("%s: KEM combiner failed\n", __func__); goto leave; } if (DBG_CRYPTO) log_printhex (kek, kek_len, "KEK:"); err = gcry_cipher_open (&hd, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_AESWRAP, 0); if (!err) err = gcry_cipher_setkey (hd, kek, kek_len); if (err) { if (opt.verbose) log_error ("%s: failed to initialize AESWRAP: %s\n", __func__, gpg_strerror (err)); goto leave; } err = gcry_sexp_build (&s_data, NULL, "%m", data); if (err) goto leave; n = gcry_cipher_get_algo_keylen (seskey_algo); seskey = gcry_mpi_get_opaque (data, &nbits); seskey_len = (nbits+7)/8; if (seskey_len != n) { if (opt.verbose) log_info ("%s: session key length %zu" " does not match the length for algo %d\n", __func__, seskey_len, seskey_algo); err = gpg_error (GPG_ERR_INV_DATA); goto leave; } if (DBG_CRYPTO) log_printhex (seskey, seskey_len, "seskey:"); enc_seskey_len = 1 + seskey_len + 8; enc_seskey = xtrymalloc (enc_seskey_len); if (!enc_seskey || enc_seskey_len > 254) { err = gpg_error_from_syserror (); goto leave; } enc_seskey[0] = enc_seskey_len - 1; err = gcry_cipher_encrypt (hd, enc_seskey+1, enc_seskey_len-1, seskey, seskey_len); if (err) { log_error ("%s: wrapping session key failed\n", __func__); goto leave; } if (DBG_CRYPTO) log_printhex (enc_seskey, enc_seskey_len, "enc_seskey:"); resarr[0] = gcry_mpi_set_opaque_copy (NULL, ecc_ct, 8 * ecc_ct_len); if (resarr[0]) resarr[1] = gcry_mpi_set_opaque_copy (NULL, kyber_ct, 8 * kyber_ct_len); if (resarr[1]) resarr[2] = gcry_mpi_set_opaque_copy (NULL, enc_seskey, 8 * enc_seskey_len); if (!resarr[0] || !resarr[1] || !resarr[2]) { err = gpg_error_from_syserror (); for (i=0; i < 3; i++) gcry_mpi_release (resarr[i]), resarr[i] = NULL; } leave: wipememory (ecc_ct, sizeof ecc_ct); wipememory (ecc_ecdh, sizeof ecc_ecdh); wipememory (ecc_ss, sizeof ecc_ss); wipememory (kyber_ct, sizeof kyber_ct); wipememory (kyber_ss, sizeof kyber_ss); wipememory (kek, kek_len); xfree (enc_seskey); gcry_cipher_close (hd); xfree (ecc_oid); return err; } /* Core of the encryption for the ECDH algorithms. See pk_decrypt for * a description of the arguments. */ static gpg_error_t do_encrypt_ecdh (PKT_public_key *pk, gcry_mpi_t data, gcry_mpi_t *resarr) { gcry_mpi_t *pkey = pk->pkey; gcry_sexp_t s_ciph = NULL; gcry_sexp_t s_data = NULL; gcry_sexp_t s_pkey = NULL; gpg_error_t err; gcry_mpi_t k = NULL; char *curve = NULL; int with_djb_tweak_flag; gcry_mpi_t public = NULL; gcry_mpi_t result = NULL; byte fp[MAX_FINGERPRINT_LEN]; byte *shared = NULL; byte *p; size_t nshared; unsigned int nbits; err = pk_ecdh_generate_ephemeral_key (pkey, &k); if (err) goto leave; curve = openpgp_oid_to_str (pkey[0]); if (!curve) { err = gpg_error_from_syserror (); goto leave; } with_djb_tweak_flag = openpgp_oid_is_cv25519 (pkey[0]); /* Now use the ephemeral secret to compute the shared point. */ err = gcry_sexp_build (&s_pkey, NULL, with_djb_tweak_flag ? "(public-key(ecdh(curve%s)(flags djb-tweak)(q%m)))" : "(public-key(ecdh(curve%s)(q%m)))", curve, pkey[1]); if (err) goto leave; /* Put K into a simplified S-expression. */ err = gcry_sexp_build (&s_data, NULL, "%m", k); if (err) goto leave; /* Run encryption. */ err = gcry_pk_encrypt (&s_ciph, s_data, s_pkey); if (err) goto leave; gcry_sexp_release (s_data); s_data = NULL; gcry_sexp_release (s_pkey); s_pkey = NULL; /* Get the shared point and the ephemeral public key. */ shared = get_data_from_sexp (s_ciph, "s", &nshared); if (!shared) { err = gpg_error_from_syserror (); goto leave; } err = sexp_extract_param_sos (s_ciph, "e", &public); gcry_sexp_release (s_ciph); s_ciph = NULL; if (DBG_CRYPTO) { log_debug ("ECDH ephemeral key:"); gcry_mpi_dump (public); log_printf ("\n"); } fingerprint_from_pk (pk, fp, NULL); p = gcry_mpi_get_opaque (data, &nbits); result = NULL; err = pk_ecdh_encrypt_with_shared_point (shared, nshared, fp, p, (nbits+7)/8, pkey, &result); if (err) goto leave; resarr[0] = public; public = NULL; resarr[1] = result; result = NULL; leave: gcry_mpi_release (public); gcry_mpi_release (result); xfree (shared); gcry_sexp_release (s_ciph); gcry_sexp_release (s_data); gcry_sexp_release (s_pkey); xfree (curve); gcry_mpi_release (k); return err; } /* Core of the encryption for RSA and Elgamal algorithms. See * pk_decrypt for a description of the arguments. */ static gpg_error_t do_encrypt_rsa_elg (PKT_public_key *pk, gcry_mpi_t data, gcry_mpi_t *resarr) { pubkey_algo_t algo = pk->pubkey_algo; gcry_mpi_t *pkey = pk->pkey; gcry_sexp_t s_ciph = NULL; gcry_sexp_t s_data = NULL; gcry_sexp_t s_pkey = NULL; gpg_error_t err; if (algo == PUBKEY_ALGO_ELGAMAL || algo == PUBKEY_ALGO_ELGAMAL_E) err = gcry_sexp_build (&s_pkey, NULL, "(public-key(elg(p%m)(g%m)(y%m)))", pkey[0], pkey[1], pkey[2]); else err = gcry_sexp_build (&s_pkey, NULL, "(public-key(rsa(n%m)(e%m)))", pkey[0], pkey[1]); if (err) goto leave; err = gcry_sexp_build (&s_data, NULL, "%m", data); if (err) goto leave; err = gcry_pk_encrypt (&s_ciph, s_data, s_pkey); if (err) goto leave; gcry_sexp_release (s_data); s_data = NULL; gcry_sexp_release (s_pkey); s_pkey = NULL; resarr[0] = get_mpi_from_sexp (s_ciph, "a", GCRYMPI_FMT_USG); if (!is_RSA (algo)) resarr[1] = get_mpi_from_sexp (s_ciph, "b", GCRYMPI_FMT_USG); leave: gcry_sexp_release (s_data); gcry_sexp_release (s_pkey); gcry_sexp_release (s_ciph); return err; } /* * Emulate our old PK interface here - sometime in the future we might * change the internal design to directly fit to libgcrypt. PK is is * the OpenPGP public key packet, DATA is an MPI with the to be * encrypted data, and RESARR receives the encrypted data. RESARRAY * is expected to be an two item array which will be filled with newly * allocated MPIs. SESKEY_ALGO is required for public key algorithms * which do not encode it in DATA. */ gpg_error_t pk_encrypt (PKT_public_key *pk, gcry_mpi_t data, int seskey_algo, gcry_mpi_t *resarr) { pubkey_algo_t algo = pk->pubkey_algo; if (algo == PUBKEY_ALGO_KYBER) return do_encrypt_kem (pk, data, seskey_algo, resarr); else if (algo == PUBKEY_ALGO_ECDH) return do_encrypt_ecdh (pk, data, resarr); else if (algo == PUBKEY_ALGO_ELGAMAL || algo == PUBKEY_ALGO_ELGAMAL_E) return do_encrypt_rsa_elg (pk, data, resarr); else if (algo == PUBKEY_ALGO_RSA || algo == PUBKEY_ALGO_RSA_E) return do_encrypt_rsa_elg (pk, data, resarr); else return gpg_error (GPG_ERR_PUBKEY_ALGO); } /* Check whether SKEY is a suitable secret key. */ int pk_check_secret_key (pubkey_algo_t pkalgo, gcry_mpi_t *skey) { gcry_sexp_t s_skey; int rc; if (pkalgo == PUBKEY_ALGO_DSA) { rc = gcry_sexp_build (&s_skey, NULL, "(private-key(dsa(p%m)(q%m)(g%m)(y%m)(x%m)))", skey[0], skey[1], skey[2], skey[3], skey[4]); } else if (pkalgo == PUBKEY_ALGO_ELGAMAL || pkalgo == PUBKEY_ALGO_ELGAMAL_E) { rc = gcry_sexp_build (&s_skey, NULL, "(private-key(elg(p%m)(g%m)(y%m)(x%m)))", skey[0], skey[1], skey[2], skey[3]); } else if (is_RSA (pkalgo)) { rc = gcry_sexp_build (&s_skey, NULL, "(private-key(rsa(n%m)(e%m)(d%m)(p%m)(q%m)(u%m)))", skey[0], skey[1], skey[2], skey[3], skey[4], skey[5]); } else if (pkalgo == PUBKEY_ALGO_ECDSA || pkalgo == PUBKEY_ALGO_ECDH) { char *curve = openpgp_oid_to_str (skey[0]); if (!curve) rc = gpg_error_from_syserror (); else { rc = gcry_sexp_build (&s_skey, NULL, "(private-key(ecc(curve%s)(q%m)(d%m)))", curve, skey[1], skey[2]); xfree (curve); } } else if (pkalgo == PUBKEY_ALGO_EDDSA) { char *curve = openpgp_oid_to_str (skey[0]); if (!curve) rc = gpg_error_from_syserror (); else { const char *fmt; if (openpgp_oid_is_ed25519 (skey[0])) fmt = "(private-key(ecc(curve %s)(flags eddsa)(q%m)(d%m)))"; else fmt = "(private-key(ecc(curve %s)(q%m)(d%m)))"; rc = gcry_sexp_build (&s_skey, NULL, fmt, curve, skey[1], skey[2]); xfree (curve); } } else return GPG_ERR_PUBKEY_ALGO; if (!rc) { rc = gcry_pk_testkey (s_skey); gcry_sexp_release (s_skey); } return rc; } diff --git a/tests/openpgp/Makefile.am b/tests/openpgp/Makefile.am index e32ff3d17..d1f04e99b 100644 --- a/tests/openpgp/Makefile.am +++ b/tests/openpgp/Makefile.am @@ -1,307 +1,322 @@ # Makefile.am - For tests/openpgp # Copyright (C) 1998, 1999, 2000, 2001, 2003, # 2010 Free Software Foundation, Inc. # # This file is part of GnuPG. # # GnuPG is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # GnuPG is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, see . # Process this file with automake to create Makefile.in # Programs required before we can run these tests. required_pgms = ../../g10/gpg$(EXEEXT) ../../agent/gpg-agent$(EXEEXT) \ ../../tools/gpg-connect-agent$(EXEEXT) \ ../gpgscm/gpgscm$(EXEEXT) AM_CPPFLAGS = -I$(top_srcdir)/common include $(top_srcdir)/am/cmacros.am AM_CFLAGS = noinst_PROGRAMS = fake-pinentry fake_pinentry_SOURCES = fake-pinentry.c TESTS_ENVIRONMENT = LC_ALL=C \ EXEEXT=$(EXEEXT) \ PATH="../gpgscm:$(PATH)" \ abs_top_srcdir="$(abs_top_srcdir)" \ objdir="$(abs_top_builddir)" \ GNUPG_BUILD_ROOT="$(abs_top_builddir)" \ GNUPG_IN_TEST_SUITE=fact \ GPGSCM_PATH="$(abs_top_srcdir)/tests/gpgscm" XTESTS = \ version.scm \ enarmor.scm \ mds.scm \ decrypt.scm \ decrypt-sym.scm \ decrypt-multifile.scm \ decrypt-dsa.scm \ decrypt-session-key.scm \ decrypt-unwrap-verify.scm \ sigs.scm \ sigs-dsa.scm \ encrypt.scm \ encrypt-multifile.scm \ encrypt-dsa.scm \ compression.scm \ seat.scm \ clearsig.scm \ encryptp.scm \ detach.scm \ detachm.scm \ armsigs.scm \ armencrypt.scm \ armencryptp.scm \ signencrypt.scm \ signencrypt-dsa.scm \ armsignencrypt.scm \ armdetach.scm \ armdetachm.scm \ genkey1024.scm \ conventional.scm \ conventional-mdc.scm \ multisig.scm \ verify.scm \ verify-multifile.scm \ gpgv.scm \ gpgv-forged-keyring.scm \ armor.scm \ import.scm \ import-revocation-certificate.scm \ ecc.scm \ 4gb-packet.scm \ tofu.scm \ trust-pgp-1.scm \ trust-pgp-2.scm \ trust-pgp-3.scm \ trust-pgp-4.scm \ gpgtar.scm \ use-exact-key.scm \ default-key.scm \ export.scm \ ssh-import.scm \ ssh-export.scm \ quick-key-manipulation.scm \ key-selection.scm \ delete-keys.scm \ gpgconf.scm \ issue2015.scm \ issue2346.scm \ issue2417.scm \ issue2419.scm \ issue2929.scm \ issue2941.scm # XXX: Currently, one cannot override automake's 'check' target. As a # workaround, we avoid defining 'TESTS', thus automake will not emit # the 'check' target. For extra robustness, we merely define a # dependency on 'xcheck', so this hack should also work even if # automake would emit the 'check' target, as adding dependencies to # targets is okay. check: xcheck .PHONY: xcheck xcheck: $(TESTS_ENVIRONMENT) $(abs_top_builddir)/tests/gpgscm/gpgscm$(EXEEXT) \ $(abs_srcdir)/run-tests.scm $(TESTFLAGS) $(TESTS) TEST_FILES = pubring.asc secring.asc plain-1o.asc plain-2o.asc plain-3o.asc \ plain-1.asc plain-2.asc plain-3.asc plain-1-pgp.asc \ plain-largeo.asc plain-large.asc \ pubring.pkr.asc secring.skr.asc secdemo.asc pubdemo.asc \ bug537-test.data.asc bug894-test.asc \ bug1223-good.asc bug1223-bogus.asc 4gb-packet.asc \ tofu/conflicting/1C005AF3.gpg \ tofu/conflicting/1C005AF3-secret.gpg \ tofu/conflicting/1C005AF3-1.txt \ tofu/conflicting/1C005AF3-2.txt \ tofu/conflicting/1C005AF3-3.txt \ tofu/conflicting/1C005AF3-4.txt \ tofu/conflicting/1C005AF3-5.txt \ tofu/conflicting/B662E42F.gpg \ tofu/conflicting/B662E42F-secret.gpg \ tofu/conflicting/B662E42F-1.txt \ tofu/conflicting/B662E42F-2.txt \ tofu/conflicting/B662E42F-3.txt \ tofu/conflicting/B662E42F-4.txt \ tofu/conflicting/B662E42F-5.txt \ tofu/conflicting/BE04EB2B.gpg \ tofu/conflicting/BE04EB2B-secret.gpg \ tofu/conflicting/BE04EB2B-1.txt \ tofu/conflicting/BE04EB2B-2.txt \ tofu/conflicting/BE04EB2B-3.txt \ tofu/conflicting/BE04EB2B-4.txt \ tofu/conflicting/BE04EB2B-5.txt \ tofu/cross-sigs/EC38277E-secret.gpg \ tofu/cross-sigs/EC38277E-1.gpg \ tofu/cross-sigs/EC38277E-1.txt \ tofu/cross-sigs/EC38277E-2.gpg \ tofu/cross-sigs/EC38277E-2.txt \ tofu/cross-sigs/EC38277E-3.txt \ tofu/cross-sigs/871C2247-secret.gpg \ tofu/cross-sigs/871C2247-1.gpg \ tofu/cross-sigs/871C2247-1.txt \ tofu/cross-sigs/871C2247-2.gpg \ tofu/cross-sigs/871C2247-2.txt \ tofu/cross-sigs/871C2247-3.gpg \ tofu/cross-sigs/871C2247-3.txt \ tofu/cross-sigs/871C2247-4.gpg \ tofu/cross-sigs/README \ key-selection/0.asc \ key-selection/1.asc \ key-selection/2.asc \ key-selection/3.asc \ key-selection/4.asc \ trust-pgp/scenario1.asc \ trust-pgp/scenario2.asc \ trust-pgp/scenario3.asc \ trust-pgp/scenario4.asc \ trust-pgp/alice.sec.asc \ trust-pgp/bobby.sec.asc \ trust-pgp/carol.sec.asc \ trust-pgp/david.sec.asc \ trust-pgp/frank.sec.asc \ trust-pgp/grace.sec.asc \ trust-pgp/heidi.sec.asc data_files = data-500 data-9000 data-32000 data-80000 plain-large priv_keys = privkeys/50B2D4FA4122C212611048BC5FC31BD44393626E.asc \ privkeys/7E201E28B6FEB2927B321F443205F4724EBE637E.asc \ privkeys/13FDB8809B17C5547779F9D205C45F47CE0217CE.asc \ privkeys/343D8AF79796EE107D645A2787A9D9252F924E6F.asc \ privkeys/8B5ABF3EF9EB8D96B91A0B8C2C4401C91C834C34.asc \ privkeys/0D6F6AD4C4C803B25470F9104E9F4E6A4CA64255.asc \ privkeys/FD692BD59D6640A84C8422573D469F84F3B98E53.asc \ privkeys/76F7E2B35832976B50A27A282D9B87E44577EB66.asc \ privkeys/A0747D5F9425E6664F4FFBEED20FBCA79FDED2BD.asc \ privkeys/0DD40284FF992CD24DC4AAC367037E066FCEE26A.asc \ privkeys/2BC997C0B8691D41D29A4EC81CCBCF08454E4961.asc \ privkeys/3C9D5ECA70130C2DBB1FC6AC0076BEEEC197716F.asc \ privkeys/449E644892C951A37525654730DD32C202079926.asc \ privkeys/58FFE844087634E62440224908BDE44BEA7EB730.asc \ privkeys/4DF9172D6FF428C97A0E9AA96F03E8BCE3B2F188.asc \ privkeys/9D7CD8F53F2F14C3E2177D1E9D1D11F39513A4A4.asc \ privkeys/6E6B7ED0BD4425018FFC54F3921D5467A3AE00EB.asc \ privkeys/C905D0AB6AE9655C5A35975939997BBF3325D6DD.asc \ privkeys/B2BAA7144303DF19BB6FDE23781DD3FDD97918D4.asc \ privkeys/CF60965BF51F67CF80DECE853E0D2D343468571D.asc \ privkeys/DF00E361D34F80868D06879AC21D7A7D4E4FAD76.asc \ privkeys/00FE67F28A52A8AA08FFAED20AF832DA916D1985.asc \ privkeys/1DF48228FEFF3EC2481B106E0ACA8C465C662CC5.asc \ privkeys/A2832820DC9F40751BDCD375BB0945BA33EC6B4C.asc \ privkeys/ADE710D74409777B7729A7653373D820F67892E0.asc \ privkeys/CEFC51AF91F68A2904FBFF62C4F075A4785B803F.asc \ privkeys/1E28F20E41B54C2D1234D896096495FF57E08D18.asc \ privkeys/EB33B687EB8581AB64D04852A54453E85F3DF62D.asc \ privkeys/C6A6390E9388CDBAD71EAEA698233FE5E04F001E.asc \ privkeys/D69102E0F5AC6B6DB8E4D16DA8E18CF46D88CAE3.asc \ privkeys/891067FFFC6D67D37BD4BFC399191C5F3989D1B5.key \ privkeys/F27FC04CB01723A4CB6F5399F7B86CCD82C0169C.key \ privkeys/DC60E0AE48E0F14E8FD7C9C36E18C6651E99BA93.key \ privkeys/2F4CD0990D56D41A74456668469E3139A7960CD4.key \ privkeys/8B2E1355C97C34E0AC1CBC9DFDF2526BFE8990A7.key \ privkeys/F5DB116462B7BD2FA83A4453C4DFA2AE8604FB59.key \ privkeys/8F9ABF3E5BBFC50D168DD524EB8F7263E7B33859.key \ - privkeys/A1598F57316F7FEC3F946895E35A7D2EAE8D3A13.key + privkeys/A1598F57316F7FEC3F946895E35A7D2EAE8D3A13.key \ + privkeys/19C87B74004E9839F3D56992B0A9943BF90B56F7.key \ + privkeys/513906BEA5A40F25C9D6EBBCEF62D0784E7235A5.key \ + privkeys/6EC551A7895031EE4543A1C789E16E6A6C229CFC.key \ + privkeys/702F599E35E6E0BE68E6FDF25D887229D42780F7.key \ + privkeys/7C31A4A632A49C4E8B1C8CBA53976ADFF714510F.key \ + privkeys/A1ABFD89944870D04039D40C218EE127254AEEE9.key \ + privkeys/A87B85D88DB8B2B5A62A9958C8F2878F49605D09.key \ + privkeys/D54E9B75C3541D95C45E430DAC9645E9FB62C668.key \ + privkeys/EAD718DCE3D2F33A20BFC8BA617844DEF3FFAF3A.key sample_keys = samplekeys/README \ samplekeys/ecc-sample-1-pub.asc \ samplekeys/ecc-sample-2-pub.asc \ samplekeys/ecc-sample-3-pub.asc \ samplekeys/ecc-sample-1-sec.asc \ samplekeys/ecc-sample-2-sec.asc \ samplekeys/ecc-sample-3-sec.asc \ samplekeys/eddsa-sample-1-pub.asc \ samplekeys/eddsa-sample-1-sec.asc \ samplekeys/dda252ebb8ebe1af-1.asc \ samplekeys/dda252ebb8ebe1af-2.asc \ samplekeys/whats-new-in-2.1.asc \ samplekeys/e2e-p256-1-clr.asc \ samplekeys/e2e-p256-1-prt.asc \ samplekeys/E657FB607BB4F21C90BB6651BC067AF28BC90111.asc \ samplekeys/rsa-rsa-sample-1.asc \ samplekeys/ed25519-cv25519-sample-1.asc \ samplekeys/ed25519-cv25519-sample-2.asc \ samplekeys/silent-running.asc \ samplekeys/ssh-dsa.key \ samplekeys/ssh-ecdsa.key \ samplekeys/ssh-ed25519.key \ samplekeys/ssh-rsa.key \ samplekeys/issue2346.gpg \ samplekeys/authenticate-only.pub.asc \ samplekeys/authenticate-only.sec.asc \ samplekeys/pqc-sample-1.key.asc \ - samplekeys/pqc-sample-2.key.asc + samplekeys/pqc-sample-2.key.asc \ + samplekeys/pqc-sample-3.key.asc \ + samplekeys/pqc-sample-4.key.asc \ + samplekeys/pqc-sample-5.key.asc sample_msgs = samplemsgs/clearsig-1-key-1.asc \ samplemsgs/clearsig-2-keys-1.asc \ samplemsgs/clearsig-2-keys-2.asc \ samplemsgs/enc-sym-cfb-1.asc \ samplemsgs/enc-sym-cfb-2.asc \ samplemsgs/enc-sym-ocb-1.asc \ samplemsgs/enc-sym-ocb-2.asc \ samplemsgs/enc-1-key-1.asc \ samplemsgs/enc-1-key-2.asc \ samplemsgs/enc-2-keys-1.asc \ samplemsgs/enc-2-keys-2.asc \ samplemsgs/enc-2-keys-hh-1.asc \ samplemsgs/enc-2-keys-hr-1.asc \ samplemsgs/enc-2-keys-rh-1.asc \ samplemsgs/encsig-2-2-keys-3.asc \ samplemsgs/encsig-2-2-keys-4.asc \ samplemsgs/encsig-2-keys-1.asc \ samplemsgs/encsig-2-keys-2.asc \ samplemsgs/encsig-2-keys-3.asc \ samplemsgs/encsig-2-keys-4.asc \ samplemsgs/encz0-1-key-1.asc \ samplemsgs/encz0-1-key-2.asc \ samplemsgs/issue2419.asc \ samplemsgs/revoke-2D727CC768697734.asc \ samplemsgs/sig-1-key-1.asc \ samplemsgs/sig-1-key-2.asc \ samplemsgs/sig-2-keys-1.asc \ samplemsgs/sig-2-keys-2.asc \ samplemsgs/signed-1-key-1.asc \ samplemsgs/signed-1-key-2.asc \ samplemsgs/signed-2-keys-1.asc \ samplemsgs/signed-2-keys-2.asc \ samplemsgs/pqc-sample-1.enc.asc \ - samplemsgs/pqc-sample-2.enc.asc + samplemsgs/pqc-sample-2.enc.asc \ + samplemsgs/pqc-sample-3.enc.asc \ + samplemsgs/pqc-sample-4.enc.asc \ + samplemsgs/pqc-sample-5.enc.asc EXTRA_DIST = defs.scm trust-pgp/common.scm $(XTESTS) $(TEST_FILES) \ mkdemodirs signdemokey $(priv_keys) $(sample_keys) \ $(sample_msgs) ChangeLog-2011 run-tests.scm \ setup.scm shell.scm all-tests.scm signed-messages.scm CLEANFILES = prepared.stamp x y yy z out err $(data_files) \ plain-1 plain-2 plain-3 trustdb.gpg *.lock .\#lk* \ *.log gpg_dearmor gpg.conf gpg-agent.conf S.gpg-agent \ pubring.gpg pubring.gpg~ pubring.kbx pubring.kbx~ \ common.conf secring.gpg pubring.pkr secring.skr \ gnupg-test.stop random_seed gpg-agent.log tofu.db \ passphrases sshcontrol S.gpg-agent.ssh report.xml clean-local: -rm -rf private-keys-v1.d openpgp-revocs.d tofu.d gpgtar.d # We need to depend on a couple of programs so that the tests don't # start before all programs are built. all-local: $(required_pgms) diff --git a/tests/openpgp/privkeys/19C87B74004E9839F3D56992B0A9943BF90B56F7.key b/tests/openpgp/privkeys/19C87B74004E9839F3D56992B0A9943BF90B56F7.key new file mode 100644 index 000000000..d0c602d3f --- /dev/null +++ b/tests/openpgp/privkeys/19C87B74004E9839F3D56992B0A9943BF90B56F7.key @@ -0,0 +1,7 @@ +Created: 20240423T121650 +Key: (private-key (ecc (curve brainpoolP384r1)(q + #0472FB0D5A0A01E55C29E9FB8C5C425BDF37150DAFA3C556C786E2FEF9E011919E68 + 3DBC7731D1281FDB9780C4B7FD7785198516BE2033D06448BA7EA39C2BCB7128BC1E0B + 3F81F2E734434E6FE96B29E19C57B423C5009134010CD87FADCA63A1#)(d + #474FD16712E9A8EC87A6F94E553E369358985475B453E95CFFD2123E4E97679720AA + 269CD6002DC688C9F3B9B8C456F1#))) diff --git a/tests/openpgp/privkeys/513906BEA5A40F25C9D6EBBCEF62D0784E7235A5.key b/tests/openpgp/privkeys/513906BEA5A40F25C9D6EBBCEF62D0784E7235A5.key new file mode 100644 index 000000000..c902ecf25 --- /dev/null +++ b/tests/openpgp/privkeys/513906BEA5A40F25C9D6EBBCEF62D0784E7235A5.key @@ -0,0 +1,8 @@ +Created: 20240423T151658 +Key: (private-key (ecc (curve brainpoolP512r1)(q + #046E26896EAC8D3D7F31F0B57439FFDBC0078841CEF7A9A98AB15F489FEE34E9D15E + 2050EAFCA0CD4C7021E5E018F601EEC7EDDE1AACE959EA13F84143861489DD54ADAA4F + F86E5FF75E3CC2EA6453716075DD908B9647B45257A64AE88DD390D7325B9E30698027 + 16B3743AFE7A7E44495AF625C3E009C581C63E341A16A23D07#)(d + #1A1364149C7AB54D76D9345424EF755139031E85B5B7DEB0D221855D0189A579614B + BCB6D01D9E02627F5C187338D7A176A830DF55422FE20D3BFF7812255C1A#))) diff --git a/tests/openpgp/privkeys/6EC551A7895031EE4543A1C789E16E6A6C229CFC.key b/tests/openpgp/privkeys/6EC551A7895031EE4543A1C789E16E6A6C229CFC.key new file mode 100644 index 000000000..e9df95c0a --- /dev/null +++ b/tests/openpgp/privkeys/6EC551A7895031EE4543A1C789E16E6A6C229CFC.key @@ -0,0 +1,137 @@ +Created: 20240423T151658 +Key: (private-key (kyber1024 (p #BE7768B33800B583978414965EC439D29A4180 + 655B0A58BA40CB9C29D10088A07D66B47AE6124B986156A9347878FBCFC0351049D2C1 + 8835CEE72BADE28B7AC8BA7FF8345AD885B1E730409939C5B3A1A5867AB7912538F234 + 59AA335204ECC5E94A9B651772A9AC5C60A5137AA74719996479D7A424839172398078 + 57493825896C628DA1726418D843E4946F9838A2E2DA5B93C6805995CD7D4B26EB79BC + BD645E52B31703986686CB2AB26A22029879BD57212928096F0954A65654FAD6651FEB + 11039C6E0F03172025303480AE6F5A0ED786A17E3779ABD775B15407B6560C97C42CF8 + 6A63D7AA1032767D20D97EAD7A3EFCD346D00B4DFD147FAE9C7BCC64224837B6C62770 + 76E25BE756C201A58445779AE98679C753C2BBA69425D343A5156EAED17AACF0B939C4 + 9B3FE83AA80C5E4399BE81C13F0A2CB4E6B08E588A13B8944AC9F74D79541FAB1691BE + 88156F920FA836C4D41AC4965009FAA174DA36B5521C79F4313B498525311369261B64 + 48FC7AEE6B9D44455BF6347C35F2B99F95254C6027759B99CA16659006BAD1F7C0B20C + BDBFF66A8F454E24863B175A0B614830AC8ACB1AFB93F1D3C54F7216DAA05AE210B57B + 503E4657B6870A8CD448644B7A5B68F565E9F51C9F12890AC8315ED52015F6BBED89C6 + 924BC756EB752FB3502BC50CAFA073E1B6AE3DD29E0C9269F8B505CA0654702114F03B + AE81C945B13631EA6C28B244BCDFB159B55B1EACAC30AF7872BD3C8F5BEA0EE9056DB2 + E6C87C9B204AB21018696217D648EFCBBB4C078C16751B03702BAF447FFB741FDB2455 + AF5A9BCA6A3340C5B8F6B82748723024B20E6F5A3D56278DBC975D4EA70D9399A6E355 + 533920A3C5E858AD5180BD4434F3E42B971908AA591ABBF3C1EBF257627CB2BF740DC1 + B88C7551A5B8462F6CE3B58C65A390C07C01A15C2BC624AB007924D9B76DD1A50603C1 + 92278A24CC86CFAA952E66ACFE99A800D56C473A7877955FC7D83C1DD548A57527B259 + 0B56B6CB3E8525F06986725379C4130F8FE15524D569346AAF451538DC663149F1946D + 5509BE3BB6026031F87AC4B21B80D66981F8527CDAF0AD4BFC2A3B3265BDAC4E65190B + 5D777275896EA238606CA7B2173C1C4DE01058965128BC866B8CC2991045AE47324243 + CBB0808E2F851FC9563779AC269664B01AECBEF45465FEB9584CC47F3B031794594BF5 + 7497446B0A856755429A7389A21AB3573C2D8A036238486451013D647D288979200A83 + 72C6039FA23E35877008408C7C815E55035A5BA9165BBB3BA56A96253B526DDC37FCC2 + 9F16F18E7D6676A393B867849C85927CAF996A9FE388FF880D5615AC64B7B4251803D7 + 9599D2232D560C85F562643E9B9F33F8139D0B61ABE98F76043E5166145A045B83E574 + AAB35D9D119A3EB3107FB3388EF483B056726B3036C29663018C929FD972D444C54373 + 16D749AF0D12556F159FC02584C6B8456BF56DC2128DCA61B794E7AAFB61969354B5A6 + DA82EB545CFA242CE997A5168AA43926131165B534FBBE1F15A4D4432FF5BB8446A575 + E528480B7C3FA0328C8134C0BF778792C05902EB32476326AE979CCF0C80C39C4B7332 + 9FC4EA365164A848D529BCB43985D35B3AE30B02AC057E1910BDB616F50A79F22441B3 + 51C77C8A17AB4052F44930B991AF7C751209253C4D27C8C5166C3285A1B1D39981B85E + CE5CC7AF11B4B8B38170963766E6130A66ABD736478067C0A86470C542216AE1593591 + 62F72C34241601E4F54087D64A8752C38FD85CC09C0C7F38CE3A0320E5E16B507302D7 + 830EA18793774A3D7BAA807971AD17332D8862C0FA757D98782CE927577A32B45BF18E + EE77B393F410620C03093620470BBC93313489F11C96871C42DA296909ABF16A885950 + A2CF896CD18A61D54B3C529C96355AC2D3C69324C3AE634C8718C3CBFA734C40E78F91 + 53A1286B379E0B7636141DD20B43A26B6BB2E03A56F008F0868CE2B940CF108FCE7954 + C0A1B933CC15FE156E2C4C4E4EDCBBA1E87108E3CFF24865548A838E7619315B25C265 + 3465158CAE4683AA03696870C397359B118CB37AA853D46CC5B05ACFDBC010C8984284 + 07009340A4793A05718B0E12E95FA8685A213B8559B44021B8C3A458AF81C2476775AB + F0015DBFF820427CA306265DE9AE0F4AE474DF627DCD167AEA9FB7A6EB3F021BA4A78A + E111275F13AC923E23#)(s #2EB39309148C404770B9EC5188D13FEDD24E3DAA78FCC3 + 5AAA6840B1458E30511A973C389FF3B4F8073ACF9780AC09A648822E460C6399C125B5 + 191DCF16C92C350FFCF25A94E22E4E80C9A25C18DFC884D9536D2E8469CAC88781726C + CE899E477BAFE3B25F3319A310E499AF030CC65867E207D0BCFA1C1EF711F2403B8293 + 7F83A0859051CDC9AA9B43B53197CB47B1F47BC6BB5A073A3D5B2182A312C747A50C5B + E67CB43315019CB0B6D73216943144A5228307A4D7FA3C88B0B3AA1B088CCC73A81AA3 + 0EF56D06D3A2139517215A843E093C1F61C1B1890FE5E9A0FC64986622BBFF7635F6F7 + 70C1325727300665B437544456C1211FC7D1753B724DB691CAE729BC89CA97B5C60363 + 710FF5A2502C54C429591824A62547D70FB17A8D177979473B254E12BA1A589B1039CC + 9AF061FF098AF5B09B89334DF3E54B6D524FB8B99F7C9A41F4731175D4904BA040A201 + 76BF153241FC5F38D63665629C75C97935F99DF7B7B415816705C00A47020DB2D8A6C7 + 945FD950206FB1CE970A973A285469FC6B2D495BCC50BACCCC9DD03A9D85C2B667BB64 + 887A37EB645DC5F4281ABA6FA5D2B73C0B97D9AC9220DB5A0ADABA6B438367E60E0412 + 453E6791C275A19F1B44D23A9C00E11610EABC332746F6FC09DDAAA402475E7528C57F + 8B79BE8B506F100E43AB3131C138225622DC597F0405B86A3CCABF2B45CBA028FE1221 + A9AB4368EA6D9129A80A26B2F8CB76438A15D0FC8BD0B26BD6D5BDAB75BA25F636A889 + 95DCE2656A21C66C3CCBE2CACF38C66F2D66BB55C81A66C1695BA5391BA327F44B6596 + 4A035A37C6C3BA7198F27E758C822EDAC40E50CBC86274E6EC6710B74178321FEAD3B7 + 20319A50D34EAC953424379CCCF9753E3C26D60B896A555C62D21F226899620995CCEA + 312F840D08294A6816789DC77B1D730151FA5084BB8CA3CBA402E834CA5C2069D6455B + 133864F64CCDAA7C98B7038AD6A1FCF24C81E6B20D2C7BA1B1B45B4A949D48AC51683F + A8C4938B4CBBA49C258318742BFAA172DC58C5E628BD9A10A9C54116705B6E9C80D936 + 2C62E26DC5A132F02B2A4B1A2376A74668ECA44D2080C414941C6A3836CA90C590CD3D + 2B74F2C33C82288B15B708F4178D7B1A01990308DC76C0C83794063B0D2F434EE86AAE + 9240163AB0AB49DC36F5AC925F05C38CD6722E70B09F8871F04066DF90A4EF06AB3776 + 161DD8817313653A0A58CCE69040EBB5D84B9B1DEB0892E8071B073965D68F4C191354 + 184E2D0100A272636560C305394185D01D0FE527A66CC1F4ECB34C208222FB505FB39F + 5B47A6CE87BA58C848EAD5ADC78B17CE6584A4336C3AF8C23C9BBE805ACA16AC53247A + 621D074A1AC79339B83661D7018E55A6091C58441606A862C29A79BCB7600041AC7CFF + 5C76961B48D4C47437E3119D2697B28502748036784A99F4D07F21FC16C6A1C5F44070 + C2F07F71FC74D91114C8E71053E18A59EB567C1445CBE3216CAB431FE59D42E627BB8C + 5C905C4FDA2B1C0A5B3B67567879660E044B5FA0666310939250020AAF31A6FA789B38 + 904121713F08A5760EAAC87EA58444D25FC40787A3600B55059FE081AA535BBF6DF25C + 1C4A27DBA8A243AC88A4D879BBAB260BFA62DF0557BF7B7466654DE5C69DDBB18C3E17 + B5EBD0AD91A80AEA71C2F5F076794C1B60323E7C5416F11179CAD8A6F48C943AAB6265 + 6A9AFAFA2F5CE8918935C21E169806463CE140B1CF6930B9A3AD4AFCA1B2607867B441 + 5EE696E3949D53AAA74A8692913AA900E5A32BD7C9482284F1133245A08EBA41C17C70 + 987FC106C3961B3A13C2E9966DC6F9B42CFBA39EBA7620CA6E42DC7F58759315F04703 + 262E334B45CDD90FDE270C679A67C91B8D80076E4F539678822AF993633EC54FE6486D + 53E51DE286C5887B66A6188BC7E88BFF4455C03160F3A2AF2BF9C7EED288D1F977EB69 + 72BA48742543325FB667DA80B5B6CB3C70B76C15940A93CB2ABAC76315F18E7A578370 + 6320299C33B8636E0354966E46585025462444300BFB94C36784904A1DF199C6B1AB62 + 410723D6365F50111CD7854384296D47A1BA7B241FD179443C5721D3655435069C0F6A + 4DD6E21C40F3CAA5502431601486DB3ADC329888D7ACB364B3902B6781B52712C70054 + 8C61F811184A00AEBE7768B33800B583978414965EC439D29A4180655B0A58BA40CB9C + 29D10088A07D66B47AE6124B986156A9347878FBCFC0351049D2C18835CEE72BADE28B + 7AC8BA7FF8345AD885B1E730409939C5B3A1A5867AB7912538F23459AA335204ECC5E9 + 4A9B651772A9AC5C60A5137AA74719996479D7A42483917239807857493825896C628D + A1726418D843E4946F9838A2E2DA5B93C6805995CD7D4B26EB79BCBD645E52B3170398 + 6686CB2AB26A22029879BD57212928096F0954A65654FAD6651FEB11039C6E0F031720 + 25303480AE6F5A0ED786A17E3779ABD775B15407B6560C97C42CF86A63D7AA1032767D + 20D97EAD7A3EFCD346D00B4DFD147FAE9C7BCC64224837B6C6277076E25BE756C201A5 + 8445779AE98679C753C2BBA69425D343A5156EAED17AACF0B939C49B3FE83AA80C5E43 + 99BE81C13F0A2CB4E6B08E588A13B8944AC9F74D79541FAB1691BE88156F920FA836C4 + D41AC4965009FAA174DA36B5521C79F4313B498525311369261B6448FC7AEE6B9D4445 + 5BF6347C35F2B99F95254C6027759B99CA16659006BAD1F7C0B20CBDBFF66A8F454E24 + 863B175A0B614830AC8ACB1AFB93F1D3C54F7216DAA05AE210B57B503E4657B6870A8C + D448644B7A5B68F565E9F51C9F12890AC8315ED52015F6BBED89C6924BC756EB752FB3 + 502BC50CAFA073E1B6AE3DD29E0C9269F8B505CA0654702114F03BAE81C945B13631EA + 6C28B244BCDFB159B55B1EACAC30AF7872BD3C8F5BEA0EE9056DB2E6C87C9B204AB210 + 18696217D648EFCBBB4C078C16751B03702BAF447FFB741FDB2455AF5A9BCA6A3340C5 + B8F6B82748723024B20E6F5A3D56278DBC975D4EA70D9399A6E355533920A3C5E858AD + 5180BD4434F3E42B971908AA591ABBF3C1EBF257627CB2BF740DC1B88C7551A5B8462F + 6CE3B58C65A390C07C01A15C2BC624AB007924D9B76DD1A50603C192278A24CC86CFAA + 952E66ACFE99A800D56C473A7877955FC7D83C1DD548A57527B2590B56B6CB3E8525F0 + 6986725379C4130F8FE15524D569346AAF451538DC663149F1946D5509BE3BB6026031 + F87AC4B21B80D66981F8527CDAF0AD4BFC2A3B3265BDAC4E65190B5D777275896EA238 + 606CA7B2173C1C4DE01058965128BC866B8CC2991045AE47324243CBB0808E2F851FC9 + 563779AC269664B01AECBEF45465FEB9584CC47F3B031794594BF57497446B0A856755 + 429A7389A21AB3573C2D8A036238486451013D647D288979200A8372C6039FA23E3587 + 7008408C7C815E55035A5BA9165BBB3BA56A96253B526DDC37FCC29F16F18E7D6676A3 + 93B867849C85927CAF996A9FE388FF880D5615AC64B7B4251803D79599D2232D560C85 + F562643E9B9F33F8139D0B61ABE98F76043E5166145A045B83E574AAB35D9D119A3EB3 + 107FB3388EF483B056726B3036C29663018C929FD972D444C5437316D749AF0D12556F + 159FC02584C6B8456BF56DC2128DCA61B794E7AAFB61969354B5A6DA82EB545CFA242C + E997A5168AA43926131165B534FBBE1F15A4D4432FF5BB8446A575E528480B7C3FA032 + 8C8134C0BF778792C05902EB32476326AE979CCF0C80C39C4B73329FC4EA365164A848 + D529BCB43985D35B3AE30B02AC057E1910BDB616F50A79F22441B351C77C8A17AB4052 + F44930B991AF7C751209253C4D27C8C5166C3285A1B1D39981B85ECE5CC7AF11B4B8B3 + 8170963766E6130A66ABD736478067C0A86470C542216AE159359162F72C34241601E4 + F54087D64A8752C38FD85CC09C0C7F38CE3A0320E5E16B507302D7830EA18793774A3D + 7BAA807971AD17332D8862C0FA757D98782CE927577A32B45BF18EEE77B393F410620C + 03093620470BBC93313489F11C96871C42DA296909ABF16A885950A2CF896CD18A61D5 + 4B3C529C96355AC2D3C69324C3AE634C8718C3CBFA734C40E78F9153A1286B379E0B76 + 36141DD20B43A26B6BB2E03A56F008F0868CE2B940CF108FCE7954C0A1B933CC15FE15 + 6E2C4C4E4EDCBBA1E87108E3CFF24865548A838E7619315B25C2653465158CAE4683AA + 03696870C397359B118CB37AA853D46CC5B05ACFDBC010C898428407009340A4793A05 + 718B0E12E95FA8685A213B8559B44021B8C3A458AF81C2476775ABF0015DBFF820427C + A306265DE9AE0F4AE474DF627DCD167AEA9FB7A6EB3F021BA4A78AE111275F13AC923E + 23D1F7082DD2B7C9BA1CF7957573C9778E452967D9D35277277471D1E15EC88ED243E0 + ABDAF1149BF31CEC85D81BB32BF3CFFB4E62301100C95B53023559948E18#))) diff --git a/tests/openpgp/privkeys/702F599E35E6E0BE68E6FDF25D887229D42780F7.key b/tests/openpgp/privkeys/702F599E35E6E0BE68E6FDF25D887229D42780F7.key new file mode 100644 index 000000000..cb3e6ea3e --- /dev/null +++ b/tests/openpgp/privkeys/702F599E35E6E0BE68E6FDF25D887229D42780F7.key @@ -0,0 +1,7 @@ +Created: 20240423T121603 +Key: (private-key (ecc (curve brainpoolP384r1)(q + #044F9318AAA2E3A3D28DA76F4B3B6B7CCAFA9B77A571E9A5BFFDEAC24A0FD96C6BB3 + 8F74FCF980696EDD5F4CBCA2B628AE24C9DBC1C60EF1D5809D4D544EBAA01F7744233E + 248106D98A67CE1ED52D14FA942F6090C9988AA5EEB2368E19F679E2#)(d + #0D146C6EDEC6AE142765DABBFFEF4EA6CA290EB7DDF99676F3F59AE6CA3942531B31 + 7330A07F5C8AAAEDFF69E6855301#))) diff --git a/tests/openpgp/privkeys/7C31A4A632A49C4E8B1C8CBA53976ADFF714510F.key b/tests/openpgp/privkeys/7C31A4A632A49C4E8B1C8CBA53976ADFF714510F.key new file mode 100644 index 000000000..e46ebbc6e --- /dev/null +++ b/tests/openpgp/privkeys/7C31A4A632A49C4E8B1C8CBA53976ADFF714510F.key @@ -0,0 +1,137 @@ +Created: 20240423T121650 +Key: (private-key (kyber1024 (p #9A9A0790782C7F4A7F51934777FBCF7E56C66C + 2A56158680E424196D2749B7D624FDC9AC2B890BF8594CAE427E79DB4B0551A1512736 + ACA58CA8ACB41DDB854A08B546170190075051E91A85529795044500E239514A2ABAD1 + BE0D4C9F6512A887C30903AABECFDB6A6708185641402473637C80806162BDF85C2133 + B0BBA05450E638860784902616621FE7529A107A5A976FAC4985C3583BEFF33DC4A05E + 52767599D426C11BBDE0A0C0BC45B6AEC3747A316E3119ADA71A5B6589927797483E36 + 13E9F836C87685A26BB35C93CCDCC8B2C3B8AF38C60B2B8BB54B21C9ADC91644D541E1 + 70AE1A97ABCAC321BF41855A48B71CF9250A39948601100AD1B26DA8740E2AA117E60F + B813848A126FDB87C0F2856B0497104250590B9041919A0253ECA5F283688D25C7788B + 68A21450F388B1FFDBB6736A9E38CCBC2A2B0F6A64AD45F882EDAC680AF060C0FA2B73 + 921E7F053EDA54549176BE0E65ABD94B490FE75681822B21B4784D849FB32C76DF08C8 + 17846A2628B1118580818740B637CEF7B31C1EC2B10FA7ADB8B4AEC9B541C568244E74 + A4D94817E7B294B78A637A8AAD9F762028398B757063445C1BEE807B316788A3FCB7F8 + A288C5463975301E4EA27171738EA0983D5AE01CD38811E9699F5065101CCCA251C052 + 4CB5B147B98FF65902243C98B1992475D297910383F6AAC31BE8A32D8A6341F436F5C4 + 928826AD4628C51A443826C05314E11851BC41CA1571E43061BB730A5AA1CBC9963690 + 3745458851E28864E54A885C0BC88C423670795777784A9607A3BD2004F1F51871000D + C6F2578AC434D486871E665D14C76B1A416CC72676A96C4E6F79B75BE23FA31C2527D7 + C976133F4B211E07E0BF4ED46C2FB77D81272290DB760DE8B567527B36316276AA9A36 + 89AF4B3790C08820A844258D139856944EB8C40C9EBB6D199A196D446FCF25B0E61688 + 4591950021AC9D5B62AFF2A46A955C36D21EC41B294EE3AC6235323BA1B3A3000B384B + 87813550FCAA470C6C6CBCC16D8732C5A3387C16C87B34B60D56B71797B177584C6A20 + 804C9C145698A2ADA0453ABB290B36124D2690124D1B4A0FB37BAA9A1BA0237690018B + 66E426B7F1400A8B3C0635A79689861F3B1A8041919F600B435179E375859591293E98 + 209A2B07AFE028982B5532275157E0545F844BC07C0491E55A2757A6DBDBB0A0817D58 + 0CA677E8C60823AEFC76B42845AB54C40BF0D5733198C326AAA99F11667FD583A97195 + D4091BA790C419BB2312684479E15E09D94974B5BF747CCC99BB9F348C411178645555 + 372EE08C514B6AF5BC4EAF357FE0132AF374475BFC7754B29945D525E5E45561967002 + 452C9B6A99B7340577D9AC5184911D3BA1E833C3FCD93B3401B3E8913721179D75AAB9 + 94A17FA6C9C62C2CCE4194C563B4A78BABAE8CC82E177835AB351884FA1638898D5491 + 2A2E87A5BF14170FD689E0E494DED76C43EBC23CE564B0EB94A5927DEC720C98346562 + D375E116AE6E00B5081B69CC45AB8263ADA4304C50615FCB3C78FA37961953560912B0 + 1D2C255541B94C929E1F105B6F462A36436090461473ECAA05BCCCB26536DFC157EA60 + B37B49B4A17154AE6003A1C053E52329DF375F86A48300B7855C6865A7FAAA3F04A10D + 7821B18A978B8AA8DD096C6C101015C4CF385422CD1105E765201A445D9D22B3C61525 + C4A09C692CA838E01EEF6B45F82A25B9F15108441A5911C5529498BB629A22543239EA + 9765453633C51E75B8C62F2C2D5E8A524E69097DF8480E8347F0F94ECC193DD9E2C86B + 7134066189C7FA6BC12331D5622CCAC42D090553E1191186E6315165BAD5039AA3A75A + 777AB9057A59D463C0E93B5DC34A058519848C78A607ECC631CC050554CEA61B29658A + 75D4D33DBC95AF5E587C1EC3B2B8E717FE85B8D3D41AE5C4700DCC449EA65491B55685 + 791686CB9B51E97B18671D92F1A356A3060001CAB220707206B485EA6E0BD85F53719D + FA3876C6534058C4C291330244C19AC87B944B6945B77B44577772DDC8727C60260C5B + 17B4819A2C801A9D168D0EEA03BCA50236BC20F69886CEFB0C6994BF25C1CC09209EA5 + 3B6C04F15F9613C5D04646D151457A206F0B35C9A40CC3782B2F851759F93040CC0BC9 + 75477C7228BD7D1435DA80607EAB07CAF93F3FAFC623B4458888F05949EA9B2972888F + D40F3E6E009F8C935E#)(s #8D204312E102743757098841C5E7661CD0469E50326578 + B3F7324E3A303617BBBFB9022E03C61F69BAA89890C72AB82964B60F039786C9436A84 + 7223E412A76F34B1AB913C44D0CC9682593BAB0738072748F2014A38A424DA91D629A4 + 33DC33928C862BBC466B3166884010AD6A33E20A75D9870D3C07C183C01F410444D982 + A15B8A377806136DB03A94EB5D2EF1311AE03884E92CED483365C582E5C60EE708AF20 + 939E135A5EE45781448911DAA90EBCA6792F86C13579C4D6305816F493A35C4F8BC3C6 + 4D516D901A38174701B33C597AA40953FAB5CF3C672C4B29220176BE370846AB24E216 + B634F3A6ED26CA88757854883FFB203382DB609F473686E57AF1970B75724E8D339DF8 + A7B614063556E72569447A81901705A319686125EE5480FB8C3C1B73CDE6DC8EFE7060 + 2D8811C52C85DB834C06B57850AC742683C05451B27F8B47C7491A42B102D1A83AB114 + 0D8EEA401C80467CC1826C59B572DCCA3B32880E07BC14C7A6A39015E7548197FC1BB8 + C8203554312F170FC3916727E9A5A349B427EBCC2833C77F4C045E8C4F5B39708C4C61 + FD2761BD824BCD5606992B1716C15EDE0155DD311238BC529C7838AD6B65BFB31915F6 + 7248021410E6A4BA44817D307B0F713689186BA91C683EAA7C29B509D57A41BA0A09FA + 4427F5C806CD705039669A5871C4170BB3F7081A77E17BFB1455311650EEFCC35C8336 + 03976CC8B34C9C23CA52641698DB36ED45AAABE15540A757F0BB09647B5D0943305FA7 + 91C89C623EC941D24CA283A208EB8745F0B2049E196CB3CC032782BB44F01B94A89883 + B5C52040806BFABA3143464677CF8540876E189FBE69BEA7B151D8106711F666929596 + D61A7344D783A7A741BCC4C5F8A9064FB29C27D8A08EA009E13414523088361B52A6C8 + 5C5FE88D54E4CAC784804F9C0E9B508E49DC7F1FD9574863C2B3B39EE74614BA60ABA6 + 52777832175026613BD08EB979B66B92AFEE89341C30770601892172CC7A34587C04B3 + FB901F0618CFEC0BA54874C95F833C99AC2ED7F20AB74C3719A27D7572CA6F8A99A221 + 843CA939491B210703497CB3288F227680E54F0954B62B455650979250336509709280 + 7BB80349A2B4F8576B4600225A8D059608C8173E78398C971A12940B14F414208ABA1D + 00343DA1332E2A813164D80C8E9B54D0212A481027EC0B81D3580E74982D63DA100265 + 9EB600A9E096140938526AA3B709B9086F1A9E78076EF36B372EF3C4DC4C6A1BE015C6 + 9B7DCFE960AAE67449424BD4448861520EE59008391243C9F508DBF22A7DF1C90DA9AB + FF663DD1D7BA02B2C21DE9BB5656BD935B639565982BE41805D5A2FE63646CB48A4A69 + 26A8E11C3185BAEF032372B8687ECC71021BB44004ADA09A9B6AAC0F335C2A9B689BEB + 556D9C706CCFC480DA20695CD0C94807A05BCAB436B88911FBB36DD36E1F734E66F288 + 5A325A06CCA6CEA3BECCE02E1E6B71FB9A5327A13B172C9E9D908327655A25DA8E6307 + C9BC251C4C7CA11B211327C68783727AB7F280FB654EAE3883BA3B54D2EBB4564A7C23 + 7AA44D3C15F48817A23B9A6D346D562560C34B41CAE117075857F9A6B23B717EBD719F + D4A75537D9420F411C0D9A75BF3160DA172FA9615579E4B0D4D965376B6F5006660330 + 216DB476F2688B512A836D52A2CBDC4C56B690BE205D1C681EB1D55702BC0611B960F6 + 558AACD22B41370C04B10BBC63B4EBE10BBDDC024C94BD7046C525F2767C6A55668A0B + EB47C0330C1A4E17493B15460DA6AD8084C304268DC0203013119017B59C5FE2C785A6 + 6BD7E130004DCEC940BB422CCE6D434049385443E18FC832C0A2C60553A5B4C81B8708 + 78AB143016F883A36A4742ED7B2BE8EAA13C817475F6B0A49462AD38A0993CB1A6F5A3 + 88E0835A8164B5F9B53B8C7A41E419F9E42ABEA1921BC5154B293D00B05CD900323533 + 1384E8AA789304F570249BF2B1D2AC7FD4AB93F76B41E49421ECBA3AA0D44A7A72296A + 5711069C94394270D03B3B13D99CAEB78B091C8C71924D5241ABD14C80FDE9C2E34346 + 8A974A844B760BF80A2826249A22A20E26ABFB1486AAD01E815B54A2CB32E179946C04 + 3F6F298DAB042FEEB65494376784F8424D73099910154F29CF1CC55A4D76BA3487C41F + 7A9E5B9C8FC324A49A9A0790782C7F4A7F51934777FBCF7E56C66C2A56158680E42419 + 6D2749B7D624FDC9AC2B890BF8594CAE427E79DB4B0551A1512736ACA58CA8ACB41DDB + 854A08B546170190075051E91A85529795044500E239514A2ABAD1BE0D4C9F6512A887 + C30903AABECFDB6A6708185641402473637C80806162BDF85C2133B0BBA05450E63886 + 0784902616621FE7529A107A5A976FAC4985C3583BEFF33DC4A05E52767599D426C11B + BDE0A0C0BC45B6AEC3747A316E3119ADA71A5B6589927797483E3613E9F836C87685A2 + 6BB35C93CCDCC8B2C3B8AF38C60B2B8BB54B21C9ADC91644D541E170AE1A97ABCAC321 + BF41855A48B71CF9250A39948601100AD1B26DA8740E2AA117E60FB813848A126FDB87 + C0F2856B0497104250590B9041919A0253ECA5F283688D25C7788B68A21450F388B1FF + DBB6736A9E38CCBC2A2B0F6A64AD45F882EDAC680AF060C0FA2B73921E7F053EDA5454 + 9176BE0E65ABD94B490FE75681822B21B4784D849FB32C76DF08C817846A2628B11185 + 80818740B637CEF7B31C1EC2B10FA7ADB8B4AEC9B541C568244E74A4D94817E7B294B7 + 8A637A8AAD9F762028398B757063445C1BEE807B316788A3FCB7F8A288C5463975301E + 4EA27171738EA0983D5AE01CD38811E9699F5065101CCCA251C0524CB5B147B98FF659 + 02243C98B1992475D297910383F6AAC31BE8A32D8A6341F436F5C4928826AD4628C51A + 443826C05314E11851BC41CA1571E43061BB730A5AA1CBC99636903745458851E28864 + E54A885C0BC88C423670795777784A9607A3BD2004F1F51871000DC6F2578AC434D486 + 871E665D14C76B1A416CC72676A96C4E6F79B75BE23FA31C2527D7C976133F4B211E07 + E0BF4ED46C2FB77D81272290DB760DE8B567527B36316276AA9A3689AF4B3790C08820 + A844258D139856944EB8C40C9EBB6D199A196D446FCF25B0E616884591950021AC9D5B + 62AFF2A46A955C36D21EC41B294EE3AC6235323BA1B3A3000B384B87813550FCAA470C + 6C6CBCC16D8732C5A3387C16C87B34B60D56B71797B177584C6A20804C9C145698A2AD + A0453ABB290B36124D2690124D1B4A0FB37BAA9A1BA0237690018B66E426B7F1400A8B + 3C0635A79689861F3B1A8041919F600B435179E375859591293E98209A2B07AFE02898 + 2B5532275157E0545F844BC07C0491E55A2757A6DBDBB0A0817D580CA677E8C60823AE + FC76B42845AB54C40BF0D5733198C326AAA99F11667FD583A97195D4091BA790C419BB + 2312684479E15E09D94974B5BF747CCC99BB9F348C411178645555372EE08C514B6AF5 + BC4EAF357FE0132AF374475BFC7754B29945D525E5E45561967002452C9B6A99B73405 + 77D9AC5184911D3BA1E833C3FCD93B3401B3E8913721179D75AAB994A17FA6C9C62C2C + CE4194C563B4A78BABAE8CC82E177835AB351884FA1638898D54912A2E87A5BF14170F + D689E0E494DED76C43EBC23CE564B0EB94A5927DEC720C98346562D375E116AE6E00B5 + 081B69CC45AB8263ADA4304C50615FCB3C78FA37961953560912B01D2C255541B94C92 + 9E1F105B6F462A36436090461473ECAA05BCCCB26536DFC157EA60B37B49B4A17154AE + 6003A1C053E52329DF375F86A48300B7855C6865A7FAAA3F04A10D7821B18A978B8AA8 + DD096C6C101015C4CF385422CD1105E765201A445D9D22B3C61525C4A09C692CA838E0 + 1EEF6B45F82A25B9F15108441A5911C5529498BB629A22543239EA9765453633C51E75 + B8C62F2C2D5E8A524E69097DF8480E8347F0F94ECC193DD9E2C86B7134066189C7FA6B + C12331D5622CCAC42D090553E1191186E6315165BAD5039AA3A75A777AB9057A59D463 + C0E93B5DC34A058519848C78A607ECC631CC050554CEA61B29658A75D4D33DBC95AF5E + 587C1EC3B2B8E717FE85B8D3D41AE5C4700DCC449EA65491B55685791686CB9B51E97B + 18671D92F1A356A3060001CAB220707206B485EA6E0BD85F53719DFA3876C6534058C4 + C291330244C19AC87B944B6945B77B44577772DDC8727C60260C5B17B4819A2C801A9D + 168D0EEA03BCA50236BC20F69886CEFB0C6994BF25C1CC09209EA53B6C04F15F9613C5 + D04646D151457A206F0B35C9A40CC3782B2F851759F93040CC0BC975477C7228BD7D14 + 35DA80607EAB07CAF93F3FAFC623B4458888F05949EA9B2972888FD40F3E6E009F8C93 + 5EFC819BE888E45002962BD84C240119DDC2FB54BAC77FFB2D990600F53E83DA47DE79 + 15EC78E7947BADC403546041E8985FB1BB2CEBE867C9D6E08C213E54992D#))) diff --git a/tests/openpgp/privkeys/A1ABFD89944870D04039D40C218EE127254AEEE9.key b/tests/openpgp/privkeys/A1ABFD89944870D04039D40C218EE127254AEEE9.key new file mode 100644 index 000000000..fd50945f6 --- /dev/null +++ b/tests/openpgp/privkeys/A1ABFD89944870D04039D40C218EE127254AEEE9.key @@ -0,0 +1,8 @@ +Created: 20240423T151629 +Key: (private-key (ecc (curve brainpoolP512r1)(q + #04681C6E8D70DEF5DED6097972643ECEA2538EA6CA3F9F87DC1E4B27D37CFDA3296A + F129D5EEB331D836EC7A215CC1CF4103184D21F7AA184C1EE9C338BAB19147438F4C30 + 705E610E142C29F712C913D01132D862F5B65D7FADE1E145B4D9FB08E8B281DA94139D + 11D3FDC0A55B85D1AFF0DDFE052779115A72DE03BB098E03DD#)(d + #32C7C4790D709ADC404D85A791FB119C327FA8E88F835BE8C4076E250ABAD2858237 + 6496ACC61573108A9518789BCF13FA7D33D6D4324D962895F6554DD6A129#))) diff --git a/tests/openpgp/privkeys/A87B85D88DB8B2B5A62A9958C8F2878F49605D09.key b/tests/openpgp/privkeys/A87B85D88DB8B2B5A62A9958C8F2878F49605D09.key new file mode 100644 index 000000000..b3898c99d --- /dev/null +++ b/tests/openpgp/privkeys/A87B85D88DB8B2B5A62A9958C8F2878F49605D09.key @@ -0,0 +1,5 @@ +Created: 20240423T121404 +Key: (private-key (ecc (curve brainpoolP256r1)(q + #0431801CBE11209D65705872CDBED8E8718ADEBC8F4F44D69A71244F883EFFF54654 + 7B31DCC0BC0D1BF5DE953DBE11A753DC3B9BD39DB955DCA30C1F2535F59CB4#)(d + #6418FBDFBCE6B9389971AF84468050995EC79FBCF42BE6AB5A5F96BF4A8000BE#))) diff --git a/tests/openpgp/privkeys/D54E9B75C3541D95C45E430DAC9645E9FB62C668.key b/tests/openpgp/privkeys/D54E9B75C3541D95C45E430DAC9645E9FB62C668.key new file mode 100644 index 000000000..835045265 --- /dev/null +++ b/tests/openpgp/privkeys/D54E9B75C3541D95C45E430DAC9645E9FB62C668.key @@ -0,0 +1,5 @@ +Created: 20240423T121447 +Key: (private-key (ecc (curve brainpoolP256r1)(q + #049A80F4C7499AE14056F51D49D9899D7B73DB1BE7EE62EEEAA477C7A1F96F55F118 + CC0C0F89FF23E636C4F27AC51F6C571802606689A9FD9940D717EEDB0702ED#)(d + #409D4A1B8E6B0C8CB466BCD8D6C0B1D832A73FD8241C6EA65F01EA2D3BFFE1A4#))) diff --git a/tests/openpgp/privkeys/EAD718DCE3D2F33A20BFC8BA617844DEF3FFAF3A.key b/tests/openpgp/privkeys/EAD718DCE3D2F33A20BFC8BA617844DEF3FFAF3A.key new file mode 100644 index 000000000..bc1e024a4 --- /dev/null +++ b/tests/openpgp/privkeys/EAD718DCE3D2F33A20BFC8BA617844DEF3FFAF3A.key @@ -0,0 +1,104 @@ +Created: 20240423T121447 +Key: (private-key (kyber768 (p #46A3CE8B663A26CB4AFC5A5ED35A405AD3B3A66 + B47A859A458AC6F1BF3518575209D91CD2311777DEA1A14D196E50388AC7A2E2599221 + FF2697F5129FE6A5FC6B89AB1667AAD7179A99111CBD874E3D18699DBC03A601E82E16 + 0547C2AA2962972B5AFD1EA74ECE3C67599693448760CB383FF044F8F716C37493865B + 419872B60173360AC74CCC31035C23A380D7660B536105ABA2CB2598F2434631C733E4 + 952398A182C799C732BE69FBCC94796781AFA137D27080FCE314B9590A8F48261A3FC7 + CB94A2094535E9712A29E02BA50C3BDA4D8B76F68BEE95907BB72A6913829245C7B9EB + C86778994FFC183EB423B9C48AF1A3A149621868CB984A67CAA8A8987DA6983337418E + 50217F0780C595BA39845A724A0400DA35FD0E308D2250F83723B009D41818C38156B9 + 6C5C6ACDBD592BED95D67E939486A16565005EF105D55D7983E534F1E8767814B5C141 + 867A0AC7CBE297CD39885BF837C9602BFD4344158F304B1BBC91F832B291214AAA0BE4 + 7661168F16D9229A1A4B53B0BEC7C657729D0D6365A51C4A7919CC49B7D88DA619A5B4 + 0FB082A33C26BE6100C5D183D2A72634AC46D314825B190B4AAF27573844E0CCCB21C6 + 69513A5279AC0B5F1588D48C01167478E940BC62247A772065E80F339B708651740B8D + B2955F3BA78F50C2E5C645F995BCBCCFB466E0390DF2A595B69193FF3ADF1422D41A08 + 33940355DDC48DD93960B0A4D9681A5BD54234DB94B24C44B2EFC9A90731978B9B4E2D + 12E4C253A58A947651658FA949A267323A79C4875488A7F9C0D22EB743EF6A39EE30E3 + 423B6911677827BC3C2001154027381843E4C58B0B43B59EF317DEC146A27817664990 + 2DC68245406C4835A56BB0174A30C50CD59598F873A979A6F15612B5044798C1AAEEB5 + 40883A33766BB274A1B390BCB8AFC0C9C11A14A4D5568F237A9EC3232AA782BEFE6BBF + 2F8385B5C5E5133232907BAF963789F24B3EE989DC78C3AD0F59045B7ACF66340FDA65 + 5442A19AADA6697175013FB0668C45153B61EF722C2CBF571AE3810801A3B1567CD797 + 49C33955A4B413DCC989F24EA4AAFE80A2C3A24925574E422C11BA8735E9C96E9929DE + 9D263DA7ACD08A80A5BACA156C11161B3A7D0C56BADE20385C51A30941C16D4849EFCC + 89D479ADC6A9C06FC383AD900BA03750EC3BA81F97916D90FBC6582DE92CDF3E7C7DF5 + C9621CA99CCA47D72A171C8C945E6891E421C87CAF523776874A3C441C2A824704ACDC + 5D384F65958D47A46DEB079A1B895F0D37D9CF36F6622A1D19109FB1933B52B4D9D271 + 83496547B1794CDC675437C90C0C36C38F12A23D70B6D83540CC395BBA1B1885A3B8EB + 582D0A5C294E0048E7A94BC1A2E17F89DA710887C3B8241DB4D0891564D939932C047F + B28A2180B878F5BC142EB152E49411C8C1AB33A568E401BB827AD4E7B7B04A89236C40 + 0B233006A89A77CC362F5F63D57715A85EC08BB175348FA305876CD3A282547A3502FD + 14AB85004BEB50EB6C8B2F5E217FF086C86473F1B34672FB9CBFA63BE1DB8A13DC76A9 + CB30C6FEA0A25C828D8A6B6FB725569B888692B46DAEC53332A9AF9B61B1FC92851A02 + 33384A9735B86F076A05F44C97DA491C69AAD8622CEC7530C0BD13CA98B91E58BC1229 + 7CA2C2B37CDCE455EB5#)(s #0679BE74A86EB9B647B637B40EE3A26C4B3EA6D57024B + 56827C02017071E98052BCF0A4CA78036A672849D39975C06173FDAC73E6A732ACCB2E + FF887D77BA3D8E56A34643438A92ABCA1332F8C01AAB537AD721AD8E46DBB6742FE7C6 + 9BDDA9D6FC3139081839AD702979018E41C60BCA2650C682DD003BD05C8AE3622761EB + 775BFCB89EEC67A12211FC67700DD0C62D499C0E75A7084E618F4B141461ACA2387380 + 98947E8EBCDC86440426A8DB0F5737724218E75084E5C0A8CC96BFD842FEE6712B12B9 + A1EF5A506577C7DDC1CD7905F7A853588452CD4A17707546DB6039C90AB82FA17026AD + B035C329AF7309BC560B3706919A2770337E008C14936F30900FCF541FAE7050A49A6B + CA80DDF0695D3A885EBD1AAA80009C9F06D72D10FAD4A1A8908832E151B668575678CC + FB67A4A34B6489CE3CC5865A5AD290853B12668401076A6355837359C27229B748E400 + 2BC24506E42DA05DE5562107138DDBC13B99421C784CACA035766C040C9B8A5925666A + C218E7E1B300D3B5CC0D826F9E36871C860E7497804652F12D65BC2610FD5A3BD6AC4B + B0C38262C719EF66868CD4245F67C623CD5B7FAD28674E21564826A0D5B95E8125B03C + 9C99EB4ADD7B74AC16BC1CCF613453143F935A0AB34222FB6C079A4C372AC1632770FA + 8B30FA9B6399DCBAFA67723C760378DB081FCD8C825B18F45721550FBB86E747C1E7B0 + 2A68A3796266C11FC3444D38CBE0B72D9D885C5C77F0AE48A038B7EE2CA97B1C126333 + A9130DA1BDB94C6317660655C0F09D8C130A72ACA784176D4ADE57161B6801333A11C3 + E119CA2757BBEB08B5112AF06965452C1CD797165E51209BF04C6F90B3373F2CC9E02B + 1A1594D4895B4C18C4774D222C0505BABEA18216642E7B7CBA796ACBC5C82354152ECB + 765B2D56F10E925F57BC45ED1421638AF87B8C125A74473B78D026295F341315D7A1A6 + B1B2EA946817222338E8342C093CD5FC393F1A92931C92678766D2A465E5A4C5A90C35 + 758C20BE0AAB6A8E0752250607DCB0603018CF4F07390AA328CF2C8364AA63FB25C815 + 8A37A69716E743FE47303B498968E095226E59A24E4761676060504C5B0ABB5F0548DB + 3650854FB1AB66061426C3DBB177EFB1C0ADED3C142405C0CF7756A50776EBB76D4882 + 44AD008ABB3766594071C38A835CC477C01A169E0C6AFA43AB81037A6E9606CB234590 + 77DA8CC72F7C98732A56D557201B2C46E29460C37A3BD808C0E7BD346951292BFB51BE + 81C3A384B3277912CCCB521CB0BC81C76565CA65DF354680A1A243915655CA311374C4 + E998977DB488A79B63864C440C8EC0E59F9C169A181AC48CCED41722FBC16D8DC22179 + C3988237EF7E75467DC5AAC434AD6498690F28407A46015491BD0EC779AB079A9C0194 + 5C0B3DF39036F3A0BFE80CB1DF898B24A1354B0BE35560EA0DBB12C30935BF047ACF36 + 1CAC11B8D3C1D1C624B16F76EC3A80783C3742E195B031943C9A9A21702399BF9A4A25 + 848A8951DFB047FCBC4ADBDD79C73EC27F6348281072BD670831BA5B414945CC12423F + 2D5C2CF34C9F4C841AD620B665623CD74CCFC162E0AD04BD0646F581C372EBA355DA8A + 64CA92BE1056B2CFA7B46A3CE8B663A26CB4AFC5A5ED35A405AD3B3A66B47A859A458A + C6F1BF3518575209D91CD2311777DEA1A14D196E50388AC7A2E2599221FF2697F5129F + E6A5FC6B89AB1667AAD7179A99111CBD874E3D18699DBC03A601E82E160547C2AA2962 + 972B5AFD1EA74ECE3C67599693448760CB383FF044F8F716C37493865B419872B60173 + 360AC74CCC31035C23A380D7660B536105ABA2CB2598F2434631C733E4952398A182C7 + 99C732BE69FBCC94796781AFA137D27080FCE314B9590A8F48261A3FC7CB94A2094535 + E9712A29E02BA50C3BDA4D8B76F68BEE95907BB72A6913829245C7B9EBC86778994FFC + 183EB423B9C48AF1A3A149621868CB984A67CAA8A8987DA6983337418E50217F0780C5 + 95BA39845A724A0400DA35FD0E308D2250F83723B009D41818C38156B96C5C6ACDBD59 + 2BED95D67E939486A16565005EF105D55D7983E534F1E8767814B5C141867A0AC7CBE2 + 97CD39885BF837C9602BFD4344158F304B1BBC91F832B291214AAA0BE47661168F16D9 + 229A1A4B53B0BEC7C657729D0D6365A51C4A7919CC49B7D88DA619A5B40FB082A33C26 + BE6100C5D183D2A72634AC46D314825B190B4AAF27573844E0CCCB21C669513A5279AC + 0B5F1588D48C01167478E940BC62247A772065E80F339B708651740B8DB2955F3BA78F + 50C2E5C645F995BCBCCFB466E0390DF2A595B69193FF3ADF1422D41A0833940355DDC4 + 8DD93960B0A4D9681A5BD54234DB94B24C44B2EFC9A90731978B9B4E2D12E4C253A58A + 947651658FA949A267323A79C4875488A7F9C0D22EB743EF6A39EE30E3423B69116778 + 27BC3C2001154027381843E4C58B0B43B59EF317DEC146A278176649902DC68245406C + 4835A56BB0174A30C50CD59598F873A979A6F15612B5044798C1AAEEB540883A33766B + B274A1B390BCB8AFC0C9C11A14A4D5568F237A9EC3232AA782BEFE6BBF2F8385B5C5E5 + 133232907BAF963789F24B3EE989DC78C3AD0F59045B7ACF66340FDA655442A19AADA6 + 697175013FB0668C45153B61EF722C2CBF571AE3810801A3B1567CD79749C33955A4B4 + 13DCC989F24EA4AAFE80A2C3A24925574E422C11BA8735E9C96E9929DE9D263DA7ACD0 + 8A80A5BACA156C11161B3A7D0C56BADE20385C51A30941C16D4849EFCC89D479ADC6A9 + C06FC383AD900BA03750EC3BA81F97916D90FBC6582DE92CDF3E7C7DF5C9621CA99CCA + 47D72A171C8C945E6891E421C87CAF523776874A3C441C2A824704ACDC5D384F65958D + 47A46DEB079A1B895F0D37D9CF36F6622A1D19109FB1933B52B4D9D27183496547B179 + 4CDC675437C90C0C36C38F12A23D70B6D83540CC395BBA1B1885A3B8EB582D0A5C294E + 0048E7A94BC1A2E17F89DA710887C3B8241DB4D0891564D939932C047FB28A2180B878 + F5BC142EB152E49411C8C1AB33A568E401BB827AD4E7B7B04A89236C400B233006A89A + 77CC362F5F63D57715A85EC08BB175348FA305876CD3A282547A3502FD14AB85004BEB + 50EB6C8B2F5E217FF086C86473F1B34672FB9CBFA63BE1DB8A13DC76A9CB30C6FEA0A2 + 5C828D8A6B6FB725569B888692B46DAEC53332A9AF9B61B1FC92851A0233384A9735B8 + 6F076A05F44C97DA491C69AAD8622CEC7530C0BD13CA98B91E58BC12297CA2C2B37CDC + E455EB5F45B962B404EC9D9ADA018C9243AA1C5DB1F39D31391BF62AB800F85D6BAB5C + 503A078F0E1B47A9475FF068E159DED6A0D5C8291D6054524B0A8064D9DA18A39#))) diff --git a/tests/openpgp/samplekeys/README b/tests/openpgp/samplekeys/README index 8e8b598b3..88361ee30 100644 --- a/tests/openpgp/samplekeys/README +++ b/tests/openpgp/samplekeys/README @@ -1,38 +1,41 @@ no-creation-time.gpg A key with a zero creation time. ecc-sample-1-pub.asc A NIST P-256 ECC sample key. ecc-sample-1-sec.asc Ditto, but the secret keyblock. ecc-sample-2-pub.asc A NIST P-384 ECC sample key. ecc-sample-2-sec.asc Ditto, but the secret keyblock. ecc-sample-3-pub.asc A NIST P-521 ECC sample key. ecc-sample-3-sec.asc Ditto, but the secret keyblock. eddsa-sample-1-pub.asc An Ed25519 sample key. eddsa-sample-1-sec.asc Ditto, but as protected secret keyblock. dda252ebb8ebe1af-1.asc rsa4096 key 1 dda252ebb8ebe1af-2.asc rsa4096 key 2 with a long keyid collision. whats-new-in-2.1.asc Collection of sample keys. e2e-p256-1-clr.asc Google End-end-End test key (no protection) e2e-p256-1-prt.asc Ditto, but protected with passphrase "a". E657FB607BB4F21C90BB6651BC067AF28BC90111.asc Key with subkeys (no protection) pgp-desktop-skr.asc Secret key with subkeys w/o signatures rsa-rsa-sample-1.asc RSA+RSA sample key (no passphrase) ed25519-cv25519-sample-1.asc Ed25519+CV25519 sample key (no passphrase) ed25519-cv25519-sample-2.asc Ed25519+CV25519 sample key (no passphrase) silent-running.asc Collection of sample secret keys (no passphrases) rsa-primary-auth-only.pub.asc rsa2408 primary only, usage: cert,auth rsa-primary-auth-only.sec.asc Ditto but the secret keyblock. v5-sample-1-pub.asc A version 5 key (ed25519/cert,sign,v5+cv25519/v5) v5-sample-1-sec.asc Ditto, but the secret keyblock (unprotected). pqc-sample-1.key.asc ky768_cv25519 public key. [*] pqc-sample-2.key.asc ky1024_cv448 public key. [*] +pqc-sample-3.key.asc ky768_bp256 public key. [*] +pqc-sample-4.key.asc ky1024_bp384 public key. [*] +pqc-sample-5.key.asc ky1024_bp384 public key. [*] Notes: - A [*] marks public keys with their private parts in ../privkeys. - pgp-desktop-skr.asc is a secret keyblock without the uid and subkey binding signatures. When exporting a secret key from PGP desktop such a file is created which is then directly followed by a separate armored public key block. To create such a sample concatenate pgp-desktop-skr.asc and E657FB607BB4F21C90BB6651BC067AF28BC90111.asc - ecc-sample-2-sec.asc and ecc-sample-3-sec.asc do not have and binding signatures either. ecc-sample-1-sec.asc has them, though. diff --git a/tests/openpgp/samplekeys/pqc-sample-3.key.asc b/tests/openpgp/samplekeys/pqc-sample-3.key.asc new file mode 100644 index 000000000..78f9a8f75 --- /dev/null +++ b/tests/openpgp/samplekeys/pqc-sample-3.key.asc @@ -0,0 +1,48 @@ +pub brainpoolP256r1 2024-04-23 [SC] + 9F7DCCABC11EFE248F48CECD6F6570B33D05BDF8 + Keygrip = A87B85D88DB8B2B5A62A9958C8F2878F49605D09 +uid pqc-sample-3 +sub ky768_bp256 2024-04-23 [E] + B4707EA9BF0FF29F65190D779BE6064181208C59988A80BCD2B2177A9BBDFE22 + Keygrip = D54E9B75C3541D95C45E430DAC9645E9FB62C668, + EAD718DCE3D2F33A20BFC8BA617844DEF3FFAF3A + +-----BEGIN PGP PUBLIC KEY BLOCK----- + +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 +x4ISI2U8yiITrTcSWAKs9A== +=6QFw +-----END PGP PUBLIC KEY BLOCK----- diff --git a/tests/openpgp/samplekeys/pqc-sample-4.key.asc b/tests/openpgp/samplekeys/pqc-sample-4.key.asc new file mode 100644 index 000000000..e913f78da --- /dev/null +++ b/tests/openpgp/samplekeys/pqc-sample-4.key.asc @@ -0,0 +1,58 @@ +pub brainpoolP384r1 2024-04-23 [SC] + A8237D19988A8255E70D2566EC280D0923FB2DF7 + Keygrip = 702F599E35E6E0BE68E6FDF25D887229D42780F7 +uid pqc-sample-4 +sub ky1024_bp384 2024-04-23 [E] + FBCD76AC9908E094D22CAE2564C9CB50EC69AACF0E3AEC91AA115CE43C71DC81 + Keygrip = 19C87B74004E9839F3D56992B0A9943BF90B56F7, + 7C31A4A632A49C4E8B1C8CBA53976ADFF714510F + +-----BEGIN PGP PUBLIC KEY BLOCK----- + +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 +=Ztpi +-----END PGP PUBLIC KEY BLOCK----- diff --git a/tests/openpgp/samplekeys/pqc-sample-5.key.asc b/tests/openpgp/samplekeys/pqc-sample-5.key.asc new file mode 100644 index 000000000..6da585015 --- /dev/null +++ b/tests/openpgp/samplekeys/pqc-sample-5.key.asc @@ -0,0 +1,61 @@ +pub brainpoolP512r1 2024-04-23 [SC] + 7B3986A550E5DB116054B4B42CBE157D37FDEC1D + Keygrip = A1ABFD89944870D04039D40C218EE127254AEEE9 +uid pqc-sample-5 +sub ky1024_bp512 2024-04-23 [E] + CA44B5ED43D33290398C5D0983EE5EE4721EC5C680AEA12C2282451D3ED65F4F + Keygrip = 513906BEA5A40F25C9D6EBBCEF62D0784E7235A5, + 6EC551A7895031EE4543A1C789E16E6A6C229CFC + +-----BEGIN PGP PUBLIC KEY BLOCK----- + +mJMEZifQzRMJKyQDAwIIAQENBAMEaBxujXDe9d7WCXlyZD7OolOOpso/n4fcHksn +03z9oylq8SnV7rMx2DbseiFcwc9BAxhNIfeqGEwe6cM4urGRR0OPTDBwXmEOFCwp +9xLJE9ARMthi9bZdf63h4UW02fsI6LKB2pQTnRHT/cClW4XRr/Dd/gUneRFact4D +uwmOA920DHBxYy1zYW1wbGUtNYjTBBMTCgA7FiEEezmGpVDl2xFgVLS0LL4VfTf9 +7B0FAmYn0M0CGwMFCwkIBwICIgIGFQoJCAsCBBYCAwECHgcCF4AACgkQLL4VfTf9 +7B3UcwH+JBipc+OsxxqdhGeoNrYUAmDL4NoXMAhkTYPa7Qwub48ThWz3GjFOCnqr +dyfxBPrEjW5MjRarC2eomaWO7mGbbQH/VXLH4/pq2MGlrhpRfupidbWDmFtHH2NQ +oXSACpYNSTAjuy72p9s4dYbMMWRl85qQxh+4PtmY5XgQXOfd0FFgF7kGuwVmJ9Dq +HQAABrEJKyQDAwIIAQENBAMEbiaJbqyNPX8x8LV0Of/bwAeIQc73qamKsV9In+40 +6dFeIFDq/KDNTHAh5eAY9gHux+3eGqzpWeoT+EFDhhSJ3VStqk/4bl/3XjzC6mRT +cWB13ZCLlke0UlemSuiN05DXMlueMGmAJxazdDr+en5ESVr2JcPgCcWBxj40Ghai +PQcAAAYgvndoszgAtYOXhBSWXsQ50ppBgGVbCli6QMucKdEAiKB9ZrR65hJLmGFW +qTR4ePvPwDUQSdLBiDXO5yut4ot6yLp/+DRa2IWx5zBAmTnFs6Glhnq3kSU48jRZ +qjNSBOzF6UqbZRdyqaxcYKUTeqdHGZlkedekJIORcjmAeFdJOCWJbGKNoXJkGNhD +5JRvmDii4tpbk8aAWZXNfUsm63m8vWReUrMXA5hmhssqsmoiAph5vVchKSgJbwlU +plZU+tZlH+sRA5xuDwMXICUwNICub1oO14ahfjd5q9d1sVQHtlYMl8Qs+Gpj16oQ +MnZ9INl+rXo+/NNG0AtN/RR/rpx7zGQiSDe2xidwduJb51bCAaWERXea6YZ5x1PC +u6aUJdNDpRVurtF6rPC5OcSbP+g6qAxeQ5m+gcE/Ciy05rCOWIoTuJRKyfdNeVQf +qxaRvogVb5IPqDbE1BrEllAJ+qF02ja1Uhx59DE7SYUlMRNpJhtkSPx67mudREVb +9jR8NfK5n5UlTGAndZuZyhZlkAa60ffAsgy9v/Zqj0VOJIY7F1oLYUgwrIrLGvuT +8dPFT3IW2qBa4hC1e1A+Rle2hwqM1EhkS3pbaPVl6fUcnxKJCsgxXtUgFfa77YnG +kkvHVut1L7NQK8UMr6Bz4bauPdKeDJJp+LUFygZUcCEU8DuugclFsTYx6mwoskS8 +37FZtVserKwwr3hyvTyPW+oO6QVtsubIfJsgSrIQGGliF9ZI78u7TAeMFnUbA3Ar +r0R/+3Qf2yRVr1qbymozQMW49rgnSHIwJLIOb1o9VieNvJddTqcNk5mm41VTOSCj +xehYrVGAvUQ08+QrlxkIqlkau/PB6/JXYnyyv3QNwbiMdVGluEYvbOO1jGWjkMB8 +AaFcK8YkqwB5JNm3bdGlBgPBkieKJMyGz6qVLmas/pmoANVsRzp4d5Vfx9g8HdVI +pXUnslkLVrbLPoUl8GmGclN5xBMPj+FVJNVpNGqvRRU43GYxSfGUbVUJvju2AmAx ++HrEshuA1mmB+FJ82vCtS/wqOzJlvaxOZRkLXXdydYluojhgbKeyFzwcTeAQWJZR +KLyGa4zCmRBFrkcyQkPLsICOL4UfyVY3eawmlmSwGuy+9FRl/rlYTMR/OwMXlFlL +9XSXRGsKhWdVQppziaIas1c8LYoDYjhIZFEBPWR9KIl5IAqDcsYDn6I+NYdwCECM +fIFeVQNaW6kWW7s7pWqWJTtSbdw3/MKfFvGOfWZ2o5O4Z4SchZJ8r5lqn+OI/4gN +VhWsZLe0JRgD15WZ0iMtVgyF9WJkPpufM/gTnQthq+mPdgQ+UWYUWgRbg+V0qrNd +nRGaPrMQf7M4jvSDsFZyazA2wpZjAYySn9ly1ETFQ3MW10mvDRJVbxWfwCWExrhF +a/VtwhKNymG3lOeq+2GWk1S1ptqC61Rc+iQs6ZelFoqkOSYTEWW1NPu+HxWk1EMv +9buERqV15ShIC3w/oDKMgTTAv3eHksBZAusyR2MmrpeczwyAw5xLczKfxOo2UWSo +SNUpvLQ5hdNbOuMLAqwFfhkQvbYW9Qp58iRBs1HHfIoXq0BS9EkwuZGvfHUSCSU8 +TSfIxRZsMoWhsdOZgbhezlzHrxG0uLOBcJY3ZuYTCmar1zZHgGfAqGRwxUIhauFZ +NZFi9yw0JBYB5PVAh9ZKh1LDj9hcwJwMfzjOOgMg5eFrUHMC14MOoYeTd0o9e6qA +eXGtFzMtiGLA+nV9mHgs6SdXejK0W/GO7nezk/QQYgwDCTYgRwu8kzE0ifEclocc +QtopaQmr8WqIWVCiz4ls0Yph1Us8UpyWNVrC08aTJMOuY0yHGMPL+nNMQOePkVOh +KGs3ngt2NhQd0gtDomtrsuA6VvAI8IaM4rlAzxCPznlUwKG5M8wV/hVuLExOTty7 +oehxCOPP8khlVIqDjnYZMVslwmU0ZRWMrkaDqgNpaHDDlzWbEYyzeqhT1GzFsFrP +28AQyJhChAcAk0CkeToFcYsOEulfqGhaITuFWbRAIbjDpFivgcJHZ3Wr8AFdv/gg +QnyjBiZd6a4PSuR032J9zRZ66p+3pus/Ahukp4rhESdfE6ySPiOIuAQYEwoAIBYh +BHs5hqVQ5dsRYFS0tCy+FX03/ewdBQJmJ9DqAhsMAAoJECy+FX03/ewdgGQB/3hG +AN5CHePZ4HY9ijl6NtptnzotFl0upj+ItZGsQAd+VroLkPI3Mk0HBecsWplYniS5 +ccBhUFTxlrDpPUXziHgB/0OtCd8cWWJtDOKs2rqdGxb+wfGKYmpOfELMIM6xkh43 +xYAjT76qD4Ht7Hf8tXBLJ3sYfcR2CCSQlDmoXrEUdFg= +=qQEJ +-----END PGP PUBLIC KEY BLOCK----- diff --git a/tests/openpgp/samplemsgs/pqc-sample-3.enc.asc b/tests/openpgp/samplemsgs/pqc-sample-3.enc.asc new file mode 100644 index 000000000..6ceed5f6b --- /dev/null +++ b/tests/openpgp/samplemsgs/pqc-sample-3.enc.asc @@ -0,0 +1,32 @@ +-----BEGIN PGP MESSAGE----- + +hQS7A7Rwfqm/D/KfHQIDBHU3DvDIzFvwqYhmBHaN2qSe8cDi8rsj8Q4aJkioD9W/ +RJwG2ca+WWpOeBt1LBrZRE2+e1303lPxbWioK/osn+0AAARAZv6eblIHDvd1SgKP +Ta+5aYdnfSSkUVwes2RrE3g9sa1LbkHACvpyYaA1ZsKjnueqw9q0tSr3IiSQ1Pnb +yHbokFafgSViMJPbWtWv0d+Nr8piFa8bdNVCtTfwntnHqqHfsMhdBwoH8feq028K +yqC2kDJq/f22puO3ANOp8cwzuVGRaalDToY7U1umNV1xrv70iyOL/ZRxYIgltV0a +ZlxZ1xLC4vRcfcczRI/N3+A9w/rBinvxw2d5GYYjRlpjw9xFU6YskbuG3XExus+C +F0WcJ0DMduSpFpCELuqnD2RuDQKd01IHajzkLuRcBrglUC49+IBNJVNtXkHu3TVH +OllgHFMp2GaD28uil50oQYYj89Ok7JNir17aUChGNmKVaEkheOiDgeLQKJRpRwu+ +fL4LJYdI2sXnxSUv2uO7qUAvdk5xX5L1QCe4keAF//T14iSt9q00MX+wRfsmP6WC +nhK7DJJwjN40RcyBrSU0IUe4oR+AIzWNVJRbb1QMA6mhKDICMGknOnKAgfjPYbhp +kw579C6MS4XxwvwyaZaUQy3loKfOwN7ahp+Hdzn9ojpzDH8WHdgl/UZjj8A6+xC0 +626exdhGm0HSbsIW5ZUa5CZfbwlgsmRDlzovymtJl6Qvqp0845m4H969wwOxM3yC +8NTUn2yNiZA1WBlM9hHvypU6l8M+cmvLd8aP2v54e47039f+dmeZfnF4N+7C59kA +YrUyiFmYQEZfNLQAJ4cnggLqQIkS39aYjNVDitw3xhQw9J5uaoMN819pSI4w9rp+ +20JqzRszH7dUVsIFsAwB8kc6eIuJun7sd9Z9a16vRzSP39mM4xMnjyTF0EUSG849 +7n7Kwwgi92aA+VgYCIYc4aKyBeElMTLMdCS2Zlwz3/mMEAiDn9xLE3i0anZ4AoYj +my1A9lmOB0Ms5F6NKc08riz8/ONerbqO6ArSDo1icrARWtzRsozarPdHTE29Aq9C +kHYQLJ1aCnUs/f3KLbJEjReXNFimR1L9jsxuof82PeJO9LUAsdUTmkfdh0Ya0gjl +jaYMdWm7bhoOjoFWPrhBfSlF5D7CCpiFyblio0SrE4FkCawDelhQG12HfcXi/UhF +Y10g/xnvK86ntus1Gmk/M8BLgKQq3EzWgYvlS/+fI8oNPIxZWyZjW71TAkvjxR8L +ctnh9rvCQtq38d0lQslZUvmgFZOdPK3y3H3KOZP7vldCW4giI8Dv9fgqqLK/crlT +WQWgtI0KIFtFeKreLupeMOFRW/cxdZ8Hr5cO8nJkQXGkc7H0Fm2b4IJl3g6h+iLe +qiw+aEFbNE0j80WV2skRoS+YhhaESoP+Q9S6O+o0g6M9hZpGszLGN7RgUScTq9oV +N0zMUJ1phrVR9q0DwIaxm9bnuswO/qpmkIOcO/w/eIx49HAwlzSf8em34laGJNBC +hofsGUNKy/8tNikiJClvZU9s4kwJKOHU/UlwTZyyqHewonFrqnuNxTWPcKe+3gP1 +sxTzLo9nqC1SsWIwn53UeAEJAhDorI7/L0xtmEijEyFL73ztomomHYQkCfh1i9+z +9z0pzPXAFv8mWqKhj/jWOlQoGSO+o3yOcsfCcHG0fRwrCi88Gqe1r5AcWEjlm3Ru +BfsI2CQsGk6vslxsAAUx5HMajVohSl+fb4ptpPoQi4UlafSJPCxJig== +=Cv77 +-----END PGP MESSAGE----- diff --git a/tests/openpgp/samplemsgs/pqc-sample-4.enc.asc b/tests/openpgp/samplemsgs/pqc-sample-4.enc.asc new file mode 100644 index 000000000..f083a1248 --- /dev/null +++ b/tests/openpgp/samplemsgs/pqc-sample-4.enc.asc @@ -0,0 +1,43 @@ +-----BEGIN PGP MESSAGE----- + +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 +se4uGUbzOJfEhVQ7 +=rlF7 +-----END PGP MESSAGE----- diff --git a/tests/openpgp/samplemsgs/pqc-sample-5.enc.asc b/tests/openpgp/samplemsgs/pqc-sample-5.enc.asc new file mode 100644 index 000000000..eb20f9791 --- /dev/null +++ b/tests/openpgp/samplemsgs/pqc-sample-5.enc.asc @@ -0,0 +1,45 @@ +-----BEGIN PGP MESSAGE----- + +hQbbA8pEte1D0zKQHQQDBD2VswlYqdsXhS8MJSsUJ6Hmg0uyG0Ovz8Tkifmqkq43 +Tkc/i1RXTb6JPmBsEipfJ7kjmHG7FrQphfMfAU7fdaU1LC2c0cHADw96f2dgQ3qS +c0YsFLzpJDu+t9KPnGyHGDSZvNmTfNM15WoGqyQQvAefuvkJB4e5x7GYmD8a/a21 +AAAGIFGuzK90gQgSBR5LxVwmtc3oM22nKb6MTooMs+IG+SFXB2vIZDUaYO7qdPrv +NhUH584QCPbrUSk7FcPddHSwdK5+ZG5UG+aYqzDfhyGImyuMwuCMzUpVNX46ENSp +LWu0ZQiixmasjZYf0JfiNbW2KLhDMjmwuLSKK9Q/J8yfgIsqKD8NSr0mESkuA/wr +jXXhyouZzIgC0l7iNsKdWzUrjvSptA+a/nyOjnVHFrvfW58SmgRMuw4Oju4DbR3o +4u0RtKC94f599BfDnpozsHVaDqbcMI92aESDiOIiXC1QLS1I4moasAaL2r43c7cK +rmlEoqtNP2vDcjYeHopwkzJPchXBT2r0k0+1ncUUCpIiKfdv4jkb02prT8pU6e7R +D6IkGlxFZ5yMkjvZdIUxdVdSzhCJHdIcQTltx5HVtpZcdFcjYHR5yW/5r5T8wBg6 +M1a5ZAVryuJivQCszOvSDEeTQ60/yLPl2FtpuN4zLRw2+Pg6VeYYf96dYO4ez8eY +fLuNlZiljmKcl94vf5eLCf4qIGcKKn7Tse3Rk2sCX9kib9AsJ/8sQCqg09KtMHF2 +YY6PyiMMyxiDXV3Gr5IXgd0gWly1b2dTVcxrlOebCWgC+oQmhU7weCME09TDOJrT +QxZVFtIY0gyZQBLIjnoEX1ta49VAHk0JFfKywHWNfzWh11/rY6rbacD5kto9H8ga +4ox9WsG1Wlkpi6eyFIzc/mcPLkzdK5Z4GKIc+rz6OXUpypUBsbcNpihYmi84vdbv +SFxwabc7GRumcAbyGsn5Tfc1ByQ+iZlQFl1moYgOq3aRbvWzgQ18QPsDprlfeOL1 ++YVSq4/EemzEntnfpk63RtoK0gJpLTy5V8wVwqJ5hzvTYYk9i9U72IuAp9uYYnNj +OlkGU4UYk3RR0qFt092zjXIkPEg+7CvnOdSEtFMhJvrSn0Du4X87c63rypF+Tr41 +mW2v1AE4Zpr3hJCf+d02X9RCSEiGMJwLUGk/uYNtwYfSyNldJI25xwHQizhcgHSV +mA0NEdvAWuMbzu9q2GOvCATofd9G1NXQ+bHYlDh+JRP0DZpyBSefRsNg2YwByUDG +XVlugx6mP5OiRUVMI4zOfCAsvaQ+qaKgccD2wJabhcbJBCW2L0WsnrW+0Tebac9S +tCOxfIpxxGCSiRz02Hw7auqoQwOq47f1uuKH0zZ2WuRO75IIF4/D+/tm5Ba+6Iz5 +L811hIUTvDesXFO7O4EXB8TAh5dLqEWTqCR8D6mmT+KWGf/9VEAJ8KzELdKgdMC4 +LOuVDce3SWXp+S692RxrPJrUMsNDbYJpeFkTR+6gpQqDDpQybdvXJgRaTsb0Sull +UtmjgkOZAFrZ5Go6wcNvK3KCP6136oStM/4kEJvdL0qpN/u2G6kgmG+VCvwjPCng +dRMqO2F5Coj5LbviRwFsHPdf2WgDuOeq+KmDIcryKFR+7s7r/98m7oOYpJDXQDpO +xIki9Y+Aou/8v389g7lWoFqKLPzYGJbVo+1i4tMFlQ4WJ8IJVomRhFJP5xEWHzY5 +3JsDTG6077ftm7wSfx4p3P3sTtjZRo+dnuvsHPeKjLvUCdjLveCls97DMu9enk01 +sZxCVO4anSBzrWWe/dNPFHvV+le+/2tF+wDIk8xJIZKqQn9O26Edm/E7M0VldtHS +nbq0IMNjID3tSDevLFN4HSvEKAZpNsTS4f1Z/DuQndGVUBEgStPF6/iBOKcfZ7Eo +dqA4/o0nhBPmw7/EhZJ9TQgS0hH//PlfXteMpVxsHh3O0B8gIgAxbgJsn8JO8Owd +6OCzq3TQfwE3bS7dgyAzLZ5E03ZmVwnQ7GBSLvpYCi3S4S33Ki4qsqSVm23yYo9n +FzE8iVcIvWzkHhvvWf32cv27cbbtdrVXKXtCuYw1gxe47ilGkP2GWUhShJKv5rrS +MMkIctimmDaAApNFnIjZNIzGTmBkMxpkaVWIKL8lofOFlcuB9pl6l3hEUto8MB+7 +SVmzBnGFJwkvjnbIKDxB7myo882x+BBDgp4niECLyWfUuGk0q1x0lYNL7Njya8x/ +Sbtolk1l0BP4z/seUAwxKQyZAtOh55X0V1jPsdnwLzWMLMvbCSgAuu11jblp33oF +eWKn7tHsKmS2EMoas1AnEVW63Xt8meBXrzKeZV6X1K0BCQIQzhAKL6eK3Er01f1M +SWatf3nuMir/gpVxHelc5KE8CiLso+4+LxoTjsfMU+usFCJCP296eEOeE0e+tJ5g +mQp5WQNloshZPeyKknYYOnb4k8LZL5rwuB4kXCrJaARp0Wvatt3jtTccYk2bjo91 +Q1vjARFTcW45x5vD3tH55CBaWrveU08iZA4Dn95rWpoRi5q5JxV/DSHugSG1uYBP +MQHiPA1Y6KsYPhsQYg== +=aAoH +-----END PGP MESSAGE-----