aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--agent/agent.h1
-rw-r--r--agent/command.c14
-rw-r--r--agent/pkdecrypt.c53
-rw-r--r--common/kem.c93
-rw-r--r--common/util.h17
-rw-r--r--g10/pkglue.c13
6 files changed, 93 insertions, 98 deletions
diff --git a/agent/agent.h b/agent/agent.h
index d1192f505..626bf48c9 100644
--- a/agent/agent.h
+++ b/agent/agent.h
@@ -569,7 +569,6 @@ enum kemids
gpg_error_t agent_kem_decrypt (ctrl_t ctrl, const char *desc_text, int kemid,
const unsigned char *ct, size_t ctlen,
- const unsigned char *option, size_t optionlen,
membuf_t *outbuf);
/*-- genkey.c --*/
diff --git a/agent/command.c b/agent/command.c
index dcb758e37..d1ff8e27c 100644
--- a/agent/command.c
+++ b/agent/command.c
@@ -1080,8 +1080,6 @@ cmd_pkdecrypt (assuan_context_t ctx, char *line)
size_t valuelen;
membuf_t outbuf;
int padding = -1;
- unsigned char *option = NULL;
- size_t optionlen = 0;
const char *p;
int kemid = -1;
@@ -1107,10 +1105,7 @@ cmd_pkdecrypt (assuan_context_t ctx, char *line)
rc = print_assuan_status (ctx, "INQUIRE_MAXLEN", "%u", MAXLEN_CIPHERTEXT);
if (!rc)
rc = assuan_inquire (ctx, "CIPHERTEXT",
- &value, &valuelen, MAXLEN_CIPHERTEXT);
- if (!rc && kemid > KEM_PGP)
- rc = assuan_inquire (ctx, "OPTION",
- &option, &optionlen, MAXLEN_CIPHERTEXT);
+ &value, &valuelen, MAXLEN_CIPHERTEXT);
if (rc)
return rc;
@@ -1120,11 +1115,8 @@ cmd_pkdecrypt (assuan_context_t ctx, char *line)
rc = agent_pkdecrypt (ctrl, ctrl->server_local->keydesc,
value, valuelen, &outbuf, &padding);
else
- {
- rc = agent_kem_decrypt (ctrl, ctrl->server_local->keydesc, kemid,
- value, valuelen, option, optionlen, &outbuf);
- xfree (option);
- }
+ rc = agent_kem_decrypt (ctrl, ctrl->server_local->keydesc, kemid,
+ value, valuelen, &outbuf);
xfree (value);
if (rc)
clear_outbuf (&outbuf);
diff --git a/agent/pkdecrypt.c b/agent/pkdecrypt.c
index fc2e84c13..deb121c01 100644
--- a/agent/pkdecrypt.c
+++ b/agent/pkdecrypt.c
@@ -455,7 +455,7 @@ ecc_pgp_kem_decap (ctrl_t ctrl, gcry_sexp_t s_skey0,
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&)))
+ (enc-val(pqc(c%d)(e%m)(k%m)(s%m)(fixed-info%b)))
c: cipher identifier (of session key (wrapped key))
e: ECDH ciphertext
k: ML-KEM ciphertext
@@ -563,9 +563,10 @@ composite_pgp_kem_decrypt (ctrl_t ctrl, const char *desc_text,
goto leave;
ecc_hashalgo = ecc->hash_algo;
ecc_shared_len = gcry_md_get_algo_dlen (ecc_hashalgo);
- err = gnupg_ecc_kem_kdf (ecc_ss, ecc_shared_len, ecc_hashalgo,
- ecc_ecdh, ecc_point_len, ecc_ct, ecc_point_len,
- ecc_pk, ecc_point_len, NULL, 0);
+ err = gnupg_ecc_kem_simple_kdf (ecc_ss, ecc_shared_len, ecc_hashalgo,
+ ecc_ecdh, ecc_point_len,
+ ecc_ct, ecc_point_len,
+ ecc_pk, ecc_point_len);
if (err)
{
if (opt.verbose)
@@ -706,19 +707,19 @@ composite_pgp_kem_decrypt (ctrl_t ctrl, const char *desc_text,
return err;
}
-/* For ECC PGP KEM, decrypt CIPHERTEXT using KEM API. CIPHERTEXT
+/* For ECC PGP/CMS KEM, decrypt CIPHERTEXT using KEM API. CIPHERTEXT
should follow the format of:
- (enc-val(ecc(c%d)(h%d)(e%m)(s%m)(kdf-params&)))
+ (enc-val(ecc(c%d)(h%d)(e%m)(s%m)(kdf-params%b)))
c: cipher identifier (of wrapping key)
h: hash identifier
e: ECDH ciphertext
s: encrypted session key
- fixed-info: A buffer with the fixed info (the KDF parameters).
+ kdf-params: A buffer with the KDF parameters.
*/
static gpg_error_t
-ecc_kem_decrypt (ctrl_t ctrl, const char *desc_text,
+ecc_kem_decrypt (int is_pgp, ctrl_t ctrl, const char *desc_text,
gcry_sexp_t s_cipher, membuf_t *outbuf)
{
gcry_sexp_t s_skey = NULL;
@@ -783,7 +784,7 @@ ecc_kem_decrypt (ctrl_t ctrl, const char *desc_text,
encrypted_sessionkey_len = (nbits+7)/8;
kek_len = gcry_cipher_get_algo_keylen (algo);
- if (kek_len == 0 || kek_len > gcry_md_get_algo_dlen (hashalgo))
+ if (kek_len == 0)
{
err = gpg_error (GPG_ERR_INV_DATA);
goto leave;
@@ -802,13 +803,12 @@ ecc_kem_decrypt (ctrl_t ctrl, const char *desc_text,
ecc_ecdh, ecc_pk, &ecc);
if (err)
goto leave;
- err = gnupg_ecc_kem_kdf (kek, kek_len, hashalgo,
+ err = gnupg_ecc_kem_kdf (kek, kek_len, is_pgp, hashalgo,
ecc->point_len > ecc->scalar_len ?
/* For Weierstrass curve, extract
x-component from the point. */
ecc_ecdh + 1 : ecc_ecdh,
- ecc->scalar_len, ecc_ct, ecc_point_len,
- ecc_pk, ecc_point_len,
+ ecc->scalar_len,
(char *)kdf_params.data+kdf_params.off,
kdf_params.len);
if (err)
@@ -832,18 +832,18 @@ ecc_kem_decrypt (ctrl_t ctrl, const char *desc_text,
goto leave;
}
- if (encrypted_sessionkey[0] != encrypted_sessionkey_len - 1)
+ if (is_pgp && encrypted_sessionkey[0] != encrypted_sessionkey_len - 1)
{
err = gpg_error (GPG_ERR_INV_DATA);
goto leave;
}
err = gcry_cipher_setkey (hd, kek, kek_len);
- sessionkey_len = encrypted_sessionkey_len - 8 - 1;
+ sessionkey_len = encrypted_sessionkey_len - 8 - !!is_pgp;
if (!err)
err = gcry_cipher_decrypt (hd, sessionkey, sessionkey_len,
- encrypted_sessionkey + 1,
- encrypted_sessionkey_len - 1);
+ encrypted_sessionkey + !!is_pgp,
+ encrypted_sessionkey_len - !!is_pgp);
gcry_cipher_close (hd);
if (err)
@@ -873,21 +873,16 @@ ecc_kem_decrypt (ctrl_t ctrl, const char *desc_text,
/* 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. For now,
- * KEMID==KEM_CMS is _not_ yet supported.
+ * 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;
- (void)optionlen;
-
err = gcry_sexp_sscan (&s_cipher, NULL, (char*)ciphertext, ciphertextlen);
if (err)
{
@@ -895,15 +890,8 @@ agent_kem_decrypt (ctrl_t ctrl, const char *desc_text, int kemid,
return gpg_error (GPG_ERR_INV_DATA);
}
- if (option)
- {
- log_error ("KEM (%d) requires no option\n", kemid);
- err = gpg_error (GPG_ERR_INV_ARG);
- goto leave;
- }
-
- if (kemid == KEM_PGP)
- err = ecc_kem_decrypt (ctrl, desc_text, s_cipher, outbuf);
+ if (kemid == KEM_PGP || kemid == KEM_CMS)
+ err = ecc_kem_decrypt (kemid == KEM_PGP, ctrl, desc_text, s_cipher, outbuf);
else if (kemid == KEM_PQC_PGP)
{
if (!ctrl->have_keygrip)
@@ -927,8 +915,9 @@ agent_kem_decrypt (ctrl_t ctrl, const char *desc_text, int kemid,
err = composite_pgp_kem_decrypt (ctrl, desc_text, s_cipher, outbuf);
}
+ else
+ err = gpg_error (GPG_ERR_INV_ARG);
- leave:
gcry_sexp_release (s_cipher);
return err;
}
diff --git a/common/kem.c b/common/kem.c
index 94ad13457..2f479aa7a 100644
--- a/common/kem.c
+++ b/common/kem.c
@@ -144,60 +144,67 @@ compute_kmac256 (void *digest, size_t digestlen,
}
-/* Compute KEK for ECC with HASHALGO, ECDH result, ciphertext in
- * ECC_CT (which is an ephemeral key), and public key in ECC_PK.
+/* Compute KEK for ECC with HASHALGO, ECDH result, and KDF_PARAMS.
*
- * For traditional ECC (of v4), KDF_PARAMS is specified by upper layer
- * and an ephemeral key and public key are not used for the
- * computation.
+ * KDF_PARAMS is specified by upper layer.
*/
gpg_error_t
-gnupg_ecc_kem_kdf (void *kek, size_t kek_len,
+gnupg_ecc_kem_kdf (void *kek, size_t kek_len, int is_pgp,
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,
- unsigned char *kdf_params, size_t kdf_params_len)
+ const unsigned char *kdf_params, size_t kdf_params_len)
{
- if (kdf_params)
- {
- /* Traditional ECC */
- gpg_error_t err;
- gcry_kdf_hd_t hd;
- unsigned long param[1];
-
- param[0] = kek_len;
- err = gcry_kdf_open (&hd, GCRY_KDF_ONESTEP_KDF, hashalgo, param, 1,
- ecdh, ecdh_len, NULL, 0, NULL, 0,
- kdf_params, kdf_params_len);
- if (!err)
- {
- gcry_kdf_compute (hd, NULL);
- gcry_kdf_final (hd, kek_len, kek);
- gcry_kdf_close (hd);
- }
+ /* Traditional ECC */
+ gpg_error_t err;
+ gcry_kdf_hd_t hd;
+ unsigned long param[1];
+ int kdf_algo;
- return err;
- }
+ if (is_pgp)
+ kdf_algo = GCRY_KDF_ONESTEP_KDF;
else
+ kdf_algo = GCRY_KDF_X963_KDF;
+
+ param[0] = kek_len;
+ err = gcry_kdf_open (&hd, kdf_algo, hashalgo, param, 1,
+ ecdh, ecdh_len, NULL, 0, NULL, 0,
+ kdf_params, kdf_params_len);
+ if (!err)
{
- /* ECC in composite KEM */
- gcry_buffer_t iov[3];
- unsigned int dlen;
+ gcry_kdf_compute (hd, NULL);
+ gcry_kdf_final (hd, kek_len, kek);
+ gcry_kdf_close (hd);
+ }
+
+ return err;
+}
+
+
+/* Compute KEK for ECC with HASHALGO, ECDH result, ciphertext in
+ * ECC_CT (which is an ephemeral key), and public key in ECC_PK.
+ */
+gpg_error_t
+gnupg_ecc_kem_simple_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)
+{
+ /* ECC part in composite KEM */
+ 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);
+ dlen = gcry_md_get_algo_dlen (hashalgo);
+ if (kek_len != dlen)
+ return gpg_error (GPG_ERR_INV_LENGTH);
- memset (iov, 0, sizeof (iov));
+ 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);
- }
+ 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;
}
diff --git a/common/util.h b/common/util.h
index 3fb205685..8f54ffaa5 100644
--- a/common/util.h
+++ b/common/util.h
@@ -315,13 +315,22 @@ char *gnupg_get_help_string (const char *key, int only_current_locale);
const char *gnupg_messages_locale_name (void);
/*-- kem.c --*/
-gpg_error_t gnupg_ecc_kem_kdf (void *kek, size_t kek_len,
+gpg_error_t
+gpgsm_ecc_kem_kdf (void *kek, size_t kek_len,
+ int hashalgo, const void *ecdh, size_t ecdh_len,
+ const unsigned char *wrap, size_t wrap_len,
+ const unsigned char *ukm, size_t ukm_len);
+
+gpg_error_t gnupg_ecc_kem_kdf (void *kek, size_t kek_len, int is_pgp,
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,
- unsigned char *kdf_params,
+ const unsigned char *kdf_params,
size_t kdf_params_len);
+gpg_error_t gnupg_ecc_kem_simple_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,
diff --git a/g10/pkglue.c b/g10/pkglue.c
index 11d252f0a..a9d4d8549 100644
--- a/g10/pkglue.c
+++ b/g10/pkglue.c
@@ -544,11 +544,11 @@ do_encrypt_kem (PKT_public_key *pk, gcry_mpi_t data, int seskey_algo,
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, NULL, 0);
+ err = gnupg_ecc_kem_simple_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)
@@ -851,12 +851,11 @@ do_encrypt_ecdh (PKT_public_key *pk, gcry_mpi_t data, gcry_mpi_t *resarr)
goto leave;
}
- err = gnupg_ecc_kem_kdf (kek, kek_len, kdf_hash_algo,
+ err = gnupg_ecc_kem_kdf (kek, kek_len, 1, kdf_hash_algo,
ecc->is_weierstrauss ?
ecc_ecdh + 1 : ecc_ecdh,
ecc->is_weierstrauss ?
(ecc_ecdh_len - 1) / 2 : ecc_ecdh_len,
- NULL, 0, NULL, 0,
kdf_params, kdf_params_len);
xfree (kdf_params);
if (err)