diff --git a/g10/call-agent.c b/g10/call-agent.c index a49c987fa..31943d7df 100644 --- a/g10/call-agent.c +++ b/g10/call-agent.c @@ -2878,6 +2878,7 @@ agent_pkdecrypt (ctrl_t ctrl, const char *keygrip, const char *desc, membuf_t data; size_t n, len; char *p, *buf, *endp; + const char *keygrip2 = NULL; struct default_inq_parm_s dfltparm; memset (&dfltparm, 0, sizeof dfltparm); @@ -2886,13 +2887,26 @@ agent_pkdecrypt (ctrl_t ctrl, const char *keygrip, const char *desc, dfltparm.keyinfo.mainkeyid = mainkeyid; dfltparm.keyinfo.pubkey_algo = pubkey_algo; - if (!keygrip || strlen(keygrip) != 40 - || !s_ciphertext || !r_buf || !r_buflen || !r_padding) + if (!keygrip || !s_ciphertext || !r_buf || !r_buflen || !r_padding) return gpg_error (GPG_ERR_INV_VALUE); *r_buf = NULL; *r_padding = -1; + /* Parse the keygrip in case of a dual algo. */ + keygrip2 = strchr (keygrip, ','); + if (!keygrip2) + keygrip2 = keygrip + strlen (keygrip); + if (keygrip2 - keygrip != 40) + return gpg_error (GPG_ERR_INV_VALUE); + if (*keygrip2) + { + keygrip2++; + if (strlen (keygrip2) != 40) + return gpg_error (GPG_ERR_INV_VALUE); + } + + err = start_agent (ctrl, 0); if (err) return err; @@ -2903,11 +2917,19 @@ agent_pkdecrypt (ctrl_t ctrl, const char *keygrip, const char *desc, if (err) return err; - snprintf (line, sizeof line, "SETKEY %s", keygrip); + snprintf (line, sizeof line, "SETKEY %.40s", keygrip); err = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL); if (err) return err; + if (*keygrip2) + { + snprintf (line, sizeof line, "SETKEY --another %.40s", keygrip2); + err = assuan_transact (agent_ctx, line, NULL, NULL,NULL,NULL,NULL,NULL); + if (err) + return err; + } + if (desc) { snprintf (line, DIM(line), "SETKEYDESC %s", desc); @@ -2926,7 +2948,8 @@ agent_pkdecrypt (ctrl_t ctrl, const char *keygrip, const char *desc, err = make_canon_sexp (s_ciphertext, &parm.ciphertext, &parm.ciphertextlen); if (err) return err; - err = assuan_transact (agent_ctx, "PKDECRYPT", + err = assuan_transact (agent_ctx, + *keygrip2? "PKDECRYPT --kem=PQC-PGP":"PKDECRYPT", put_membuf_cb, &data, inq_ciphertext_cb, &parm, padding_info_cb, r_padding); diff --git a/g10/ecdh.c b/g10/ecdh.c index 4938e419d..279508bec 100644 --- a/g10/ecdh.c +++ b/g10/ecdh.c @@ -537,7 +537,7 @@ pk_ecdh_decrypt (gcry_mpi_t *r_result, const byte sk_fp[MAX_FINGERPRINT_LEN], nbytes = (nbits+7)/8; data_buf_size = nbytes; - if ((data_buf_size & 7) != 1) + if ((data_buf_size & 7) != 1 || data_buf_size <= 1 + 8) { log_error ("can't use a shared secret of %d bytes for ecdh\n", data_buf_size); diff --git a/g10/keyid.c b/g10/keyid.c index 09940cbfe..08f684829 100644 --- a/g10/keyid.c +++ b/g10/keyid.c @@ -336,17 +336,24 @@ do_hash_public_key (gcry_md_hd_t md, PKT_public_key *pk, int use_v5) { /* Ugly: We need to re-construct the wire format of the * key parameter. It would be easier to use a second - * second index for pp and nn which could bump - * independet of i. */ + * index for pp and nn which we could bump independet of + * i. */ const char *p; p = gcry_mpi_get_opaque (pk->pkey[i], &nbits); - pp[i] = xmalloc ((nbits+7)/8 + 1); + nn[i] = (nbits+7)/8; + pp[i] = xmalloc (4 + nn[i] + 1); if (p) - memcpy (pp[i], p, (nbits+7)/8); + { + pp[i][0] = nn[i] >> 24; + pp[i][1] = nn[i] >> 16; + pp[i][2] = nn[i] >> 8; + pp[i][3] = nn[i]; + memcpy (pp[i] + 4 , p, nn[i]); + nn[i] += 4; + } else pp[i] = NULL; - nn[i] = (nbits+7)/8; n += nn[i]; } else if (gcry_mpi_get_flag (pk->pkey[i], GCRYMPI_FLAG_OPAQUE)) diff --git a/g10/mainproc.c b/g10/mainproc.c index d2e00514f..6f3254e88 100644 --- a/g10/mainproc.c +++ b/g10/mainproc.c @@ -143,6 +143,8 @@ release_list( CTX c ) mpi_release (c->pkenc_list->data[0]); mpi_release (c->pkenc_list->data[1]); + mpi_release (c->pkenc_list->data[2]); + mpi_release (c->pkenc_list->data[3]); xfree (c->pkenc_list); c->pkenc_list = tmp; } @@ -527,11 +529,13 @@ proc_pubkey_enc (CTX c, PACKET *pkt) x->keyid[1] = enc->keyid[1]; x->pubkey_algo = enc->pubkey_algo; x->result = -1; - x->data[0] = x->data[1] = NULL; + x->data[0] = x->data[1] = x->data[2] = x->data[3] = NULL; if (enc->data[0]) { x->data[0] = mpi_copy (enc->data[0]); x->data[1] = mpi_copy (enc->data[1]); + x->data[2] = mpi_copy (enc->data[2]); + x->data[3] = mpi_copy (enc->data[3]); } x->next = c->pkenc_list; c->pkenc_list = x; diff --git a/g10/misc.c b/g10/misc.c index 432fe1760..ce0c04b3b 100644 --- a/g10/misc.c +++ b/g10/misc.c @@ -750,6 +750,8 @@ openpgp_pk_test_algo2 (pubkey_algo_t algo, unsigned int use) ga = GCRY_PK_ELG; break; + case PUBKEY_ALGO_KYBER: ga = GCRY_PK_KEM; break; + default: break; } diff --git a/g10/parse-packet.c b/g10/parse-packet.c index 2163787cb..c55bb1b71 100644 --- a/g10/parse-packet.c +++ b/g10/parse-packet.c @@ -1444,6 +1444,7 @@ parse_symkeyenc (IOBUF inp, int pkttype, unsigned long pktlen, } +/* Parse a public key encrypted packet (Tag 1). */ static int parse_pubkeyenc (IOBUF inp, int pkttype, unsigned long pktlen, PACKET * packet) @@ -1514,9 +1515,14 @@ parse_pubkeyenc (IOBUF inp, int pkttype, unsigned long pktlen, { log_assert (ndata == 4); /* Get the ephemeral public key. */ - rc = read_octet_string (inp, &pktlen, 4, 0, 0, k->data + 0); - if (rc) - goto leave; + n = pktlen; + k->data[0] = sos_read (inp, &n, 0); + pktlen -= n; + if (!k->data[0]) + { + rc = gpg_error (GPG_ERR_INV_PACKET); + goto leave; + } /* Get the Kyber ciphertext. */ rc = read_octet_string (inp, &pktlen, 4, 0, 0, k->data + 1); if (rc) diff --git a/g10/pubkey-enc.c b/g10/pubkey-enc.c index 3e9daa963..873b864b5 100644 --- a/g10/pubkey-enc.c +++ b/g10/pubkey-enc.c @@ -117,6 +117,7 @@ get_session_key (ctrl_t ctrl, struct pubkey_enc_list *list, DEK *dek) { if (!(k->pubkey_algo == PUBKEY_ALGO_ELGAMAL_E || k->pubkey_algo == PUBKEY_ALGO_ECDH + || k->pubkey_algo == PUBKEY_ALGO_KYBER || k->pubkey_algo == PUBKEY_ALGO_RSA || k->pubkey_algo == PUBKEY_ALGO_RSA_E || k->pubkey_algo == PUBKEY_ALGO_ELGAMAL)) @@ -237,6 +238,16 @@ get_it (ctrl_t ctrl, err = gcry_sexp_build (&s_data, NULL, "(enc-val(ecdh(s%m)(e%m)))", enc->data[1], enc->data[0]); } + else if (sk->pubkey_algo == PUBKEY_ALGO_KYBER) + { + if (!enc->data[0] || !enc->data[1] || !enc->data[2] || !enc->data[3]) + err = gpg_error (GPG_ERR_BAD_MPI); + else + err = gcry_sexp_build (&s_data, NULL, + "(enc-val(pqc(e%m)(k%m)(s%m)(fixed-info%s)))", + enc->data[0], enc->data[1], enc->data[3], + "\x1d" /*PUBKEY_ALGO_KYBER*/); + } else err = gpg_error (GPG_ERR_BUG); @@ -249,7 +260,6 @@ get_it (ctrl_t ctrl, /* Decrypt. */ desc = gpg_format_keydesc (ctrl, sk, FORMAT_KEYDESC_NORMAL, 1); - /*FIXME: Support dual keys. */ err = agent_pkdecrypt (NULL, keygrip, desc, sk->keyid, sk->main_keyid, sk->pubkey_algo, s_data, &frame, &nframe, &padding);