diff --git a/agent/pkdecrypt.c b/agent/pkdecrypt.c index e93ac0a26..3848bcefc 100644 --- a/agent/pkdecrypt.c +++ b/agent/pkdecrypt.c @@ -1,473 +1,464 @@ /* 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" /* 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 hybrid 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(s%m)(e%m)(k%m)))) s: encrypted session key e: ECDH ciphertext k: ML-KEM ciphertext FIXME: For now, possibile keys on smartcard are not supported. */ static gpg_error_t agent_hybrid_pgp_kem_decrypt (ctrl_t ctrl, const char *desc_text, gcry_sexp_t s_cipher, membuf_t *outbuf) { #if GCRYPT_VERSION_NUMBER >= 0x010b00 gcry_sexp_t s_skey0 = NULL; gcry_sexp_t s_skey1 = NULL; unsigned char *shadow_info = NULL; gpg_error_t err = 0; unsigned int nbits; const unsigned char *p; size_t len; - gcry_mpi_t encrypted_sessionkey_mpi; + gcry_mpi_t encrypted_sessionkey_mpi = NULL; const unsigned char *encrypted_sessionkey; size_t encrypted_sessionkey_len; - gcry_mpi_t ecc_sk_mpi; + gcry_mpi_t ecc_sk_mpi = NULL; unsigned char ecc_sk[32]; - gcry_mpi_t ecc_pk_mpi; + gcry_mpi_t ecc_pk_mpi = NULL; unsigned char ecc_pk[32]; - gcry_mpi_t ecc_ct_mpi; + gcry_mpi_t ecc_ct_mpi = NULL; const unsigned char *ecc_ct; size_t ecc_ct_len; unsigned char ecc_ecdh[32]; unsigned char ecc_ss[32]; - gcry_mpi_t mlkem_sk_mpi; - gcry_mpi_t mlkem_ct_mpi; + gcry_mpi_t mlkem_sk_mpi = NULL; + gcry_mpi_t mlkem_ct_mpi = NULL; const unsigned char *mlkem_sk; const unsigned char *mlkem_ct; unsigned char mlkem_ss[GCRY_KEM_MLKEM768_SHARED_LEN]; - gcry_buffer_t iov[6]; - - unsigned char kekkey[32]; - size_t kekkeylen = 32; /* AES-256 is mandatory */ + 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; const unsigned char fixedinfo[1] = { 105 }; 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 */ gcry_sexp_extract_param (s_cipher, NULL, "/e/k/s", &ecc_ct_mpi, &mlkem_ct_mpi, &encrypted_sessionkey_mpi, NULL); encrypted_sessionkey = gcry_mpi_get_opaque (encrypted_sessionkey_mpi, &nbits); encrypted_sessionkey_len = (nbits+7)/8; encrypted_sessionkey_len--; if (encrypted_sessionkey[0] != encrypted_sessionkey_len) { err = GPG_ERR_INV_DATA; goto leave; } encrypted_sessionkey++; /* Skip the length. */ if (encrypted_sessionkey[0] != CIPHER_ALGO_AES256) { err = GPG_ERR_INV_DATA; goto leave; } encrypted_sessionkey_len--; encrypted_sessionkey++; /* Skip the sym algo */ /* Fistly, ECC part. FIXME: For now, we assume X25519. */ gcry_sexp_extract_param (s_skey0, NULL, "/q/d", &ecc_pk_mpi, &ecc_sk_mpi, NULL); p = gcry_mpi_get_opaque (ecc_pk_mpi, &nbits); len = (nbits+7)/8; memcpy (ecc_pk, p+1, 32); /* Remove the 0x40 prefix */ p = gcry_mpi_get_opaque (ecc_sk_mpi, &nbits); len = (nbits+7)/8; if (len > 32) { err = GPG_ERR_INV_DATA; goto leave; } memset (ecc_sk, 0, 32); memcpy (ecc_sk + 32 - len, p, len); reverse_buffer (ecc_sk, 32); mpi_release (ecc_pk_mpi); mpi_release (ecc_sk_mpi); + ecc_pk_mpi = NULL; + ecc_sk_mpi = NULL; ecc_ct = gcry_mpi_get_opaque (ecc_ct_mpi, &nbits); ecc_ct_len = (nbits+7)/8; if (ecc_ct_len != 32) { err = GPG_ERR_INV_DATA; goto leave; } err = gcry_kem_decap (GCRY_KEM_RAW_X25519, ecc_sk, 32, ecc_ct, ecc_ct_len, ecc_ecdh, 32, NULL, 0); - iov[0].data = ecc_ecdh; - iov[0].off = 0; - iov[0].len = 32; - iov[1].data = (unsigned char *)ecc_ct; - iov[1].off = 0; - iov[1].len = 32; - iov[2].data = ecc_pk; - iov[2].off = 0; - iov[2].len = 32; - gcry_md_hash_buffers (GCRY_MD_SHA3_256, 0, ecc_ss, iov, 3); + if (err) + goto leave; + + err = gnupg_ecc_kem_kdf (ecc_ss, 32, GCRY_MD_SHA3_256, + ecc_ecdh, 32, ecc_ct, 32, ecc_pk, 32); + + if (err) + goto leave; /* Secondly, PQC part. For now, we assume ML-KEM. */ gcry_sexp_extract_param (s_skey1, NULL, "/s", &mlkem_sk_mpi, NULL); mlkem_sk = gcry_mpi_get_opaque (mlkem_sk_mpi, &nbits); len = (nbits+7)/8; if (len != GCRY_KEM_MLKEM768_SECKEY_LEN) { err = GPG_ERR_INV_DATA; goto leave; } mlkem_ct = gcry_mpi_get_opaque (mlkem_ct_mpi, &nbits); len = (nbits+7)/8; if (len != GCRY_KEM_MLKEM768_CIPHER_LEN) { err = GPG_ERR_INV_DATA; goto leave; } err = gcry_kem_decap (GCRY_KEM_MLKEM768, mlkem_sk, GCRY_KEM_MLKEM768_SECKEY_LEN, mlkem_ct, GCRY_KEM_MLKEM768_CIPHER_LEN, mlkem_ss, GCRY_KEM_MLKEM768_SHARED_LEN, NULL, 0); + if (err) + goto leave; mpi_release (mlkem_sk_mpi); - - /* Then, combine two shared secrets into one */ - - iov[0].data = "\x00\x00\x00\x01"; /* Counter */ - iov[0].off = 0; - iov[0].len = 4; - - iov[1].data = ecc_ss; - iov[1].off = 0; - iov[1].len = 32; - - iov[2].data = (unsigned char *)ecc_ct; - iov[2].off = 0; - iov[2].len = 32; - - iov[3].data = mlkem_ss; - iov[3].off = 0; - iov[3].len = GCRY_KEM_MLKEM768_SHARED_LEN; - - iov[4].data = (unsigned char *)mlkem_ct; - iov[4].off = 0; - iov[4].len = GCRY_KEM_MLKEM768_ENCAPS_LEN; - - iov[5].data = (unsigned char *)fixedinfo; - iov[5].off = 0; - iov[5].len = 1; - - err = compute_kmac256 (kekkey, kekkeylen, - "OpenPGPCompositeKeyDerivationFunction", 37, - "KDF", 3, iov, 6); + mlkem_sk_mpi = NULL; + + /* Then, combine two shared secrets and ciphertexts into one KEK */ + err = gnupg_kem_combiner (kek, kek_len, + ecc_ss, 32, ecc_ct, 32, + mlkem_ss, GCRY_KEM_MLKEM768_SHARED_LEN, + mlkem_ct, GCRY_KEM_MLKEM768_CIPHER_LEN, + fixedinfo, 1); + if (err) + { + log_error ("KEM combiner failed: %s\n", gpg_strerror (err)); + goto leave; + } mpi_release (ecc_ct_mpi); mpi_release (mlkem_ct_mpi); + ecc_ct_mpi = NULL; + mlkem_ct_mpi = NULL; if (DBG_CRYPTO) { - log_printhex (kekkey, kekkeylen, "KEK key: "); + log_printhex (kek, kek_len, "KEK key: "); } err = gcry_cipher_open (&hd, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_AESWRAP, 0); if (err) { log_error ("ecdh failed to initialize AESWRAP: %s\n", gpg_strerror (err)); - mpi_release (encrypted_sessionkey_mpi); goto leave; } - err = gcry_cipher_setkey (hd, kekkey, kekkeylen); + 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: + 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_sexp_release (s_skey0); gcry_sexp_release (s_skey1); return err; #else return gpg_error (GPG_ERR_NOT_IMPLEMENTED); #endif } /* 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 ("hybrid 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, "keygrip:"); log_printhex (ctrl->keygrip1, 20, "keygrip1:"); log_printhex (ciphertext, ciphertextlen, "cipher: "); } err = agent_hybrid_pgp_kem_decrypt (ctrl, desc_text, s_cipher, outbuf); gcry_sexp_release (s_cipher); return err; } diff --git a/common/kmac.c b/common/kmac.c index 69e18a2c3..c5de8b102 100644 --- a/common/kmac.c +++ b/common/kmac.c @@ -1,136 +1,209 @@ -/* kmac.c - Keccak based MAC +/* kem.c - KEM helper functions * Copyright (C) 2024 g10 Code GmbH. * * This file is part of GnuPG. * * GnuPG is free software; you can redistribute and/or modify this * part of GnuPG 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. * * 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 copies of the GNU General Public License * and the GNU Lesser General Public License along with this program; * if not, see . */ #include #include #include #include #include #include "mischelp.h" #define KECCAK512_BLOCKSIZE 136 -gpg_error_t +static gpg_error_t compute_kmac256 (void *digest, size_t digestlen, const void *key, size_t keylen, const void *custom, size_t customlen, gcry_buffer_t *data_iov, int data_iovlen) { #if GCRYPT_VERSION_NUMBER >= 0x010b00 gpg_error_t err; gcry_buffer_t iov[20]; const unsigned char headPAD[2] = { 1, KECCAK512_BLOCKSIZE }; unsigned char headK[3]; const unsigned char pad[KECCAK512_BLOCKSIZE] = { 0 }; unsigned char right_encode_L[3]; unsigned int len; int iovcnt; if (data_iovlen >= DIM(iov) - 6) return gpg_error (GPG_ERR_TOO_LARGE); /* Check the validity conditions of NIST SP 800-185 */ if (keylen >= 255 || customlen >= 255 || digestlen >= 255) return gpg_error (GPG_ERR_TOO_LARGE); iovcnt = 0; iov[iovcnt].data = "KMAC"; iov[iovcnt].off = 0; iov[iovcnt].len = 4; iovcnt++; iov[iovcnt].data = (void *)custom; iov[iovcnt].off = 0; iov[iovcnt].len = customlen; iovcnt++; iov[iovcnt].data = (void *)headPAD; iov[iovcnt].off = 0; iov[iovcnt].len = sizeof (headPAD); iovcnt++; if (keylen < 32) { headK[0] = 1; headK[1] = (keylen*8)&0xff; iov[iovcnt].data = headK; iov[iovcnt].off = 0; iov[iovcnt].len = 2; } else { headK[0] = 2; headK[1] = (keylen*8)>>8; headK[2] = (keylen*8)&0xff; iov[iovcnt].data = headK; iov[iovcnt].off = 0; iov[iovcnt].len = 3; } iovcnt++; iov[iovcnt].data = (void *)key; iov[iovcnt].off = 0; iov[iovcnt].len = keylen; iovcnt++; len = iov[2].len + iov[3].len + iov[4].len; len %= KECCAK512_BLOCKSIZE; iov[iovcnt].data = (unsigned char *)pad; iov[iovcnt].off = 0; iov[iovcnt].len = sizeof (pad) - len; iovcnt++; memcpy (&iov[iovcnt], data_iov, data_iovlen * sizeof (gcry_buffer_t)); iovcnt += data_iovlen; if (digestlen < 32) { right_encode_L[0] = (digestlen * 8) & 0xff; right_encode_L[1] = 1; } else { right_encode_L[0] = (digestlen * 8) >> 8; right_encode_L[1] = (digestlen * 8) & 0xff; right_encode_L[2] = 2; } iov[iovcnt].data = right_encode_L; iov[iovcnt].off = 0; iov[iovcnt].len = 3; iovcnt++; err = gcry_md_hash_buffers_ext (GCRY_MD_CSHAKE256, 0, digest, digestlen, iov, iovcnt); return err; #else return gpg_error (GPG_ERR_NOT_IMPLEMENTED); #endif } + +/* Compute KEK (shared secret) for ECC with HASHALGO, ECDH result, + ciphertext in ECC_CT, public key in ECC_PK. */ +gpg_error_t +gnupg_ecc_kem_kdf (void *kek, size_t kek_len, + int hashalgo, const void *ecdh, size_t ecdh_len, + const void *ecc_ct, size_t ecc_ct_len, + const void *ecc_pk, size_t ecc_pk_len) +{ + gcry_buffer_t iov[3]; + unsigned int dlen; + + dlen = gcry_md_get_algo_dlen (hashalgo); + if (kek_len != dlen) + return gpg_error (GPG_ERR_INV_LENGTH); + + memset (iov, 0, sizeof (iov)); + + iov[0].data = (unsigned char *)ecdh; + iov[0].len = ecdh_len; + iov[1].data = (unsigned char *)ecc_ct; + iov[1].len = ecc_ct_len; + iov[2].data = (unsigned char *)ecc_pk; + iov[2].len = ecc_pk_len; + gcry_md_hash_buffers (hashalgo, 0, kek, iov, 3); + + return 0; +} + + +/* domSeperation */ +#define KMAC_KEY "OpenPGPCompositeKeyDerivationFunction" + +/* customizationString */ +#define KMAC_CUSTOM "KDF" + +/* Compute KEK by combining two KEMs. */ +gpg_error_t +gnupg_kem_combiner (void *kek, size_t kek_len, + const void *ecc_ss, size_t ecc_ss_len, + const void *ecc_ct, size_t ecc_ct_len, + const void *mlkem_ss, size_t mlkem_ss_len, + const void *mlkem_ct, size_t mlkem_ct_len, + const void *fixedinfo, size_t fixedinfo_len) +{ + gpg_error_t err; + gcry_buffer_t iov[6]; + + memset (iov, 0, sizeof (iov)); + + iov[0].data = "\x00\x00\x00\x01"; /* Counter */ + iov[0].len = 4; + + iov[1].data = (unsigned char *)ecc_ss; + iov[1].len = ecc_ss_len; + + iov[2].data = (unsigned char *)ecc_ct; + iov[2].len = ecc_ct_len; + + iov[3].data = (unsigned char *)mlkem_ss; + iov[3].len = mlkem_ss_len; + + iov[4].data = (unsigned char *)mlkem_ct; + iov[4].len = mlkem_ct_len; + + iov[5].data = (unsigned char *)fixedinfo; + iov[5].len = fixedinfo_len; + + err = compute_kmac256 (kek, kek_len, + KMAC_KEY, strlen (KMAC_KEY), + KMAC_CUSTOM, strlen (KMAC_CUSTOM), iov, 6); + return err; +} diff --git a/common/util.h b/common/util.h index 7b2601db1..5c953a8a1 100644 --- a/common/util.h +++ b/common/util.h @@ -1,415 +1,422 @@ /* util.h - Utility functions for GnuPG * Copyright (C) 2001, 2002, 2003, 2004, 2009 Free Software Foundation, Inc. * * This file is part of GnuPG. * * GnuPG is free software; you can redistribute and/or modify this * part of GnuPG 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. * * 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 copies of the GNU General Public License * and the GNU Lesser General Public License along with this program; * if not, see . */ #ifndef GNUPG_COMMON_UTIL_H #define GNUPG_COMMON_UTIL_H #include /* We need this for the memory function protos. */ #include /* We need errno. */ #include /* We need gpg_error_t and estream. */ /* These error codes are used but not defined in the required * libgpg-error version. Define them here. * Example: (#if GPG_ERROR_VERSION_NUMBER < 0x011500 // 1.21) */ #if GPG_ERROR_VERSION_NUMBER < 0x012f00 /* 1.47 */ # define GPG_ERR_BAD_PUK 320 # define GPG_ERR_NO_RESET_CODE 321 # define GPG_ERR_BAD_RESET_CODE 322 #endif #ifndef EXTERN_UNLESS_MAIN_MODULE # if !defined (INCLUDED_BY_MAIN_MODULE) # define EXTERN_UNLESS_MAIN_MODULE extern # else # define EXTERN_UNLESS_MAIN_MODULE # endif #endif /* Hash function used with libksba. */ #define HASH_FNC ((void (*)(void *, const void*,size_t))gcry_md_write) /* The length of the keygrip. This is a SHA-1 hash of the key * parameters as generated by gcry_pk_get_keygrip. */ #define KEYGRIP_LEN 20 /* The length of the unique blob identifier as used by the keyboxd. * This is the possible truncated fingerprint of the primary key. */ #define UBID_LEN 20 /* Get all the stuff from jnlib. */ #include "../common/logging.h" #include "../common/stringhelp.h" #include "../common/mischelp.h" #include "../common/strlist.h" #include "../common/dotlock.h" #include "../common/utf8conv.h" #include "../common/dynload.h" #include "../common/fwddecl.h" #include "../common/utilproto.h" #include "gettime.h" /* Redefine asprintf by our estream version which uses our own memory allocator.. */ #define asprintf gpgrt_asprintf #define vasprintf gpgrt_vasprintf /* Due to a bug in mingw32's snprintf related to the 'l' modifier and for increased portability we use our snprintf on all systems. */ #undef snprintf #define snprintf gpgrt_snprintf /* Replacements for macros not available with libgpg-error < 1.20. */ /* We need this type even if we are not using libreadline and or we did not include libreadline in the current file. */ #ifndef GNUPG_LIBREADLINE_H_INCLUDED typedef char **rl_completion_func_t (const char *, int, int); #endif /*!GNUPG_LIBREADLINE_H_INCLUDED*/ /* Handy malloc macros - please use only them. */ #define xtrymalloc(a) gcry_malloc ((a)) #define xtrymalloc_secure(a) gcry_malloc_secure ((a)) #define xtrycalloc(a,b) gcry_calloc ((a),(b)) #define xtrycalloc_secure(a,b) gcry_calloc_secure ((a),(b)) #define xtryrealloc(a,b) gcry_realloc ((a),(b)) #define xtryreallocarray(a,b,c,d) gpgrt_reallocarray ((a),(b),(c),(d)) #define xtrystrdup(a) gcry_strdup ((a)) #define xfree(a) gcry_free ((a)) #define xfree_fnc gcry_free #define xmalloc(a) gcry_xmalloc ((a)) #define xmalloc_secure(a) gcry_xmalloc_secure ((a)) #define xcalloc(a,b) gcry_xcalloc ((a),(b)) #define xcalloc_secure(a,b) gcry_xcalloc_secure ((a),(b)) #define xrealloc(a,b) gcry_xrealloc ((a),(b)) #define xstrdup(a) gcry_xstrdup ((a)) /* See also the xreallocarray prototype below. */ /* For compatibility with gpg 1.4 we also define these: */ #define xmalloc_clear(a) gcry_xcalloc (1, (a)) #define xmalloc_secure_clear(a) gcry_xcalloc_secure (1, (a)) /* The default error source of the application. This is different from GPG_ERR_SOURCE_DEFAULT in that it does not depend on the source file and thus is usable in code shared by applications. Defined by init.c. */ extern gpg_err_source_t default_errsource; /* Convenience function to return a gpg-error code for memory allocation failures. This function makes sure that an error will be returned even if accidentally ERRNO is not set. */ static inline gpg_error_t out_of_core (void) { return gpg_error_from_syserror (); } /*-- yesno.c --*/ int answer_is_yes (const char *s); int answer_is_yes_no_default (const char *s, int def_answer); int answer_is_yes_no_quit (const char *s); int answer_is_okay_cancel (const char *s, int def_answer); /*-- xreadline.c --*/ ssize_t read_line (FILE *fp, char **addr_of_buffer, size_t *length_of_buffer, size_t *max_length); /*-- sexputil.c */ char *canon_sexp_to_string (const unsigned char *canon, size_t canonlen); void log_printcanon (const char *text, const unsigned char *sexp, size_t sexplen); void log_printsexp (const char *text, gcry_sexp_t sexp); gpg_error_t make_canon_sexp (gcry_sexp_t sexp, unsigned char **r_buffer, size_t *r_buflen); gpg_error_t make_canon_sexp_pad (gcry_sexp_t sexp, int secure, unsigned char **r_buffer, size_t *r_buflen); gpg_error_t keygrip_from_canon_sexp (const unsigned char *key, size_t keylen, unsigned char *grip); int cmp_simple_canon_sexp (const unsigned char *a, const unsigned char *b); int cmp_canon_sexp (const unsigned char *a, size_t alen, const unsigned char *b, size_t blen, int (*tcmp)(void *ctx, int depth, const unsigned char *aval, size_t avallen, const unsigned char *bval, size_t bvallen), void *tcmpctx); unsigned char *make_simple_sexp_from_hexstr (const char *line, size_t *nscanned); int hash_algo_from_sigval (const unsigned char *sigval); unsigned char *make_canon_sexp_from_rsa_pk (const void *m, size_t mlen, const void *e, size_t elen, size_t *r_len); gpg_error_t get_rsa_pk_from_canon_sexp (const unsigned char *keydata, size_t keydatalen, unsigned char const **r_n, size_t *r_nlen, unsigned char const **r_e, size_t *r_elen); gpg_error_t get_ecc_q_from_canon_sexp (const unsigned char *keydata, size_t keydatalen, unsigned char const **r_q, size_t *r_qlen); gpg_error_t uncompress_ecc_q_in_canon_sexp (const unsigned char *keydata, size_t keydatalen, unsigned char **r_newkeydata, size_t *r_newkeydatalen); int get_pk_algo_from_key (gcry_sexp_t key); int get_pk_algo_from_canon_sexp (const unsigned char *keydata, size_t keydatalen); char *pubkey_algo_string (gcry_sexp_t s_pkey, enum gcry_pk_algos *r_algoid); const char *pubkey_algo_to_string (int algo); const char *hash_algo_to_string (int algo); const char *cipher_mode_to_string (int mode); /*-- convert.c --*/ int hex2bin (const char *string, void *buffer, size_t length); int hexcolon2bin (const char *string, void *buffer, size_t length); char *bin2hex (const void *buffer, size_t length, char *stringbuf); char *bin2hexcolon (const void *buffer, size_t length, char *stringbuf); const char *hex2str (const char *hexstring, char *buffer, size_t bufsize, size_t *buflen); char *hex2str_alloc (const char *hexstring, size_t *r_count); unsigned int hex2fixedbuf (const char *hexstr, void *buffer, size_t bufsize); /*-- percent.c --*/ char *percent_plus_escape (const char *string); char *percent_data_escape (int plus, const char *prefix, const void *data, size_t datalen); char *percent_plus_unescape (const char *string, int nulrepl); char *percent_unescape (const char *string, int nulrepl); size_t percent_plus_unescape_inplace (char *string, int nulrepl); size_t percent_unescape_inplace (char *string, int nulrepl); /*-- openpgp-oid.c --*/ gpg_error_t openpgp_oid_from_str (const char *string, gcry_mpi_t *r_mpi); char *openpgp_oidbuf_to_str (const unsigned char *buf, size_t len); char *openpgp_oid_to_str (gcry_mpi_t a); int openpgp_oidbuf_is_ed25519 (const void *buf, size_t len); int openpgp_oid_is_ed25519 (gcry_mpi_t a); int openpgp_oidbuf_is_cv25519 (const void *buf, size_t len); int openpgp_oid_is_cv25519 (gcry_mpi_t a); int openpgp_oid_is_cv448 (gcry_mpi_t a); int openpgp_oid_is_ed448 (gcry_mpi_t a); const char *openpgp_curve_to_oid (const char *name, unsigned int *r_nbits, int *r_algo); const char *openpgp_oid_to_curve (const char *oid, int mode); const char *openpgp_oid_or_name_to_curve (const char *oidname, int canon); const char *openpgp_enum_curves (int *idxp); const char *openpgp_is_curve_supported (const char *name, int *r_algo, unsigned int *r_nbits); const char *get_keyalgo_string (enum gcry_pk_algos algo, unsigned int nbits, const char *curve); /*-- homedir.c --*/ const char *standard_homedir (void); void gnupg_set_homedir (const char *newdir); void gnupg_maybe_make_homedir (const char *fname, int quiet); const char *gnupg_homedir (void); int gnupg_default_homedir_p (void); const char *gnupg_registry_dir (void); const char *gnupg_daemon_rootdir (void); const char *gnupg_socketdir (void); const char *gnupg_sysconfdir (void); const char *gnupg_bindir (void); const char *gnupg_libexecdir (void); const char *gnupg_libdir (void); const char *gnupg_datadir (void); const char *gnupg_localedir (void); const char *gpg_agent_socket_name (void); const char *dirmngr_socket_name (void); const char *keyboxd_socket_name (void); char *_gnupg_socketdir_internal (int skip_checks, unsigned *r_info); /* All module names. We also include gpg and gpgsm for the sake for gpgconf. */ #define GNUPG_MODULE_NAME_AGENT 1 #define GNUPG_MODULE_NAME_PINENTRY 2 #define GNUPG_MODULE_NAME_SCDAEMON 3 #define GNUPG_MODULE_NAME_DIRMNGR 4 #define GNUPG_MODULE_NAME_PROTECT_TOOL 5 #define GNUPG_MODULE_NAME_CHECK_PATTERN 6 #define GNUPG_MODULE_NAME_GPGSM 7 #define GNUPG_MODULE_NAME_GPG 8 #define GNUPG_MODULE_NAME_CONNECT_AGENT 9 #define GNUPG_MODULE_NAME_GPGCONF 10 #define GNUPG_MODULE_NAME_DIRMNGR_LDAP 11 #define GNUPG_MODULE_NAME_GPGV 12 #define GNUPG_MODULE_NAME_KEYBOXD 13 #define GNUPG_MODULE_NAME_TPM2DAEMON 14 #define GNUPG_MODULE_NAME_CARD 15 #define GNUPG_MODULE_NAME_GPGTAR 16 const char *gnupg_module_name (int which); void gnupg_module_name_flush_some (void); void gnupg_set_builddir (const char *newdir); /* A list of constants to identify protocols. This is used by tools * which need to distinguish between the different protocols * implemented by GnuPG. May be used as bit flags. */ #define GNUPG_PROTOCOL_OPENPGP 1 /* The one and only (gpg). */ #define GNUPG_PROTOCOL_CMS 2 /* The core of S/MIME (gpgsm) */ #define GNUPG_PROTOCOL_SSH_AGENT 4 /* Out ssh-agent implementation */ /*-- gpgrlhelp.c --*/ void gnupg_rl_initialize (void); /*-- helpfile.c --*/ char *gnupg_get_help_string (const char *key, int only_current_locale); /*-- localename.c --*/ const char *gnupg_messages_locale_name (void); -/*-- kmac.c --*/ -gpg_error_t compute_kmac256 (void *digest, size_t digestlen, - const void *key, size_t keylen, - const void *custom, size_t customlen, - gcry_buffer_t *data_iov, int data_iovlen); +/*-- kem.c --*/ +gpg_error_t gnupg_ecc_kem_kdf (void *kek, size_t kek_len, + int hashalgo, const void *ecdh, size_t ecdh_len, + const void *ecc_ct, size_t ecc_ct_len, + const void *ecc_pk, size_t ecc_pk_len); + +gpg_error_t gnupg_kem_combiner (void *kek, size_t kek_len, + const void *ecc_ss, size_t ecc_ss_len, + const void *ecc_ct, size_t ecc_ct_len, + const void *mlkem_ss, size_t mlkem_ss_len, + const void *mlkem_ct, size_t mlkem_ct_len, + const void *fixedinfo, size_t fixedinfo_len); /*-- miscellaneous.c --*/ /* This function is called at startup to tell libgcrypt to use our own logging subsystem. */ void setup_libgcrypt_logging (void); /* Print an out of core message and die. */ void xoutofcore (void); /* Wrapper aroung gpgrt_reallocarray. Uses the gpgrt alloc function * which redirects to the Libgcrypt versions via * init_common_subsystems. Thus this can be used interchangeable with * the other alloc functions. */ void *xreallocarray (void *a, size_t oldnmemb, size_t nmemb, size_t size); /* Same as estream_asprintf but die on memory failure. */ char *xasprintf (const char *fmt, ...) GPGRT_ATTR_PRINTF(1,2); /* This is now an alias to estream_asprintf. */ char *xtryasprintf (const char *fmt, ...) GPGRT_ATTR_PRINTF(1,2); /* Replacement for gcry_cipher_algo_name. */ const char *gnupg_cipher_algo_name (int algo); void obsolete_option (const char *configname, unsigned int configlineno, const char *name); const char *print_fname_stdout (const char *s); const char *print_fname_stdin (const char *s); void print_utf8_buffer3 (estream_t fp, const void *p, size_t n, const char *delim); void print_utf8_buffer2 (estream_t fp, const void *p, size_t n, int delim); void print_utf8_buffer (estream_t fp, const void *p, size_t n); void print_utf8_string (estream_t stream, const char *p); void print_hexstring (FILE *fp, const void *buffer, size_t length, int reserved); char *try_make_printable_string (const void *p, size_t n, int delim); char *make_printable_string (const void *p, size_t n, int delim); char *decode_c_string (const char *src); int match_multistr (const char *multistr,const char *match); int gnupg_compare_version (const char *a, const char *b); struct debug_flags_s { unsigned int flag; const char *name; }; int parse_debug_flag (const char *string, unsigned int *debugvar, const struct debug_flags_s *flags); struct compatibility_flags_s { unsigned int flag; const char *name; const char *desc; }; int parse_compatibility_flags (const char *string, unsigned int *flagvar, const struct compatibility_flags_s *flags); gpg_error_t b64decode (const char *string, const char *title, void **r_buffer, size_t *r_buflen); /*-- Simple replacement functions. */ /* We use the gnupg_ttyname macro to be safe not to run into conflicts with an existing but broken ttyname. */ #if !defined(HAVE_TTYNAME) || defined(HAVE_BROKEN_TTYNAME) # define gnupg_ttyname(n) _gnupg_ttyname ((n)) /* Systems without ttyname (W32) will merely return NULL. */ static inline char * _gnupg_ttyname (int fd) { (void)fd; return NULL; } #else /*HAVE_TTYNAME*/ # define gnupg_ttyname(n) ttyname ((n)) #endif /*HAVE_TTYNAME */ #define gnupg_isatty(a) isatty ((a)) /*-- Macros to replace ctype ones to avoid locale problems. --*/ #define spacep(p) (*(p) == ' ' || *(p) == '\t') #define digitp(p) (*(p) >= '0' && *(p) <= '9') #define alphap(p) ((*(p) >= 'A' && *(p) <= 'Z') \ || (*(p) >= 'a' && *(p) <= 'z')) #define alnump(p) (alphap (p) || digitp (p)) #define hexdigitp(a) (digitp (a) \ || (*(a) >= 'A' && *(a) <= 'F') \ || (*(a) >= 'a' && *(a) <= 'f')) /* Note this isn't identical to a C locale isspace() without \f and \v, but works for the purposes used here. */ #define ascii_isspace(a) ((a)==' ' || (a)=='\n' || (a)=='\r' || (a)=='\t') /* The atoi macros assume that the buffer has only valid digits. */ #define atoi_1(p) (*(p) - '0' ) #define atoi_2(p) ((atoi_1(p) * 10) + atoi_1((p)+1)) #define atoi_4(p) ((atoi_2(p) * 100) + atoi_2((p)+2)) #define xtoi_1(p) (*(p) <= '9'? (*(p)- '0'): \ *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10)) #define xtoi_2(p) ((xtoi_1(p) * 16) + xtoi_1((p)+1)) #define xtoi_4(p) ((xtoi_2(p) * 256) + xtoi_2((p)+2)) #endif /*GNUPG_COMMON_UTIL_H*/