diff options
| -rw-r--r-- | agent/agent.h | 1 | ||||
| -rw-r--r-- | agent/command.c | 14 | ||||
| -rw-r--r-- | agent/pkdecrypt.c | 53 | ||||
| -rw-r--r-- | common/kem.c | 93 | ||||
| -rw-r--r-- | common/util.h | 17 | ||||
| -rw-r--r-- | g10/pkglue.c | 13 |
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) |
