aboutsummaryrefslogtreecommitdiffstats
path: root/g10
diff options
context:
space:
mode:
Diffstat (limited to 'g10')
-rw-r--r--g10/build-packet.c175
-rw-r--r--g10/call-agent.c148
-rw-r--r--g10/call-dirmngr.c3
-rw-r--r--g10/call-keyboxd.c16
-rw-r--r--g10/card-util.c24
-rw-r--r--g10/dearmor.c4
-rw-r--r--g10/decrypt.c19
-rw-r--r--g10/ecdh.c31
-rw-r--r--g10/encrypt.c28
-rw-r--r--g10/export.c27
-rw-r--r--g10/filter.h4
-rw-r--r--g10/getkey.c17
-rw-r--r--g10/gpg.c42
-rw-r--r--g10/gpg.h4
-rw-r--r--g10/import.c4
-rw-r--r--g10/keydb.h3
-rw-r--r--g10/keyedit.c1
-rw-r--r--g10/keygen.c484
-rw-r--r--g10/keyid.c162
-rw-r--r--g10/keylist.c454
-rw-r--r--g10/keyring.c2
-rw-r--r--g10/main.h22
-rw-r--r--g10/mainproc.c41
-rw-r--r--g10/mdfilter.c295
-rw-r--r--g10/misc.c20
-rw-r--r--g10/openfile.c10
-rw-r--r--g10/options.h6
-rw-r--r--g10/packet.h22
-rw-r--r--g10/parse-packet.c270
-rw-r--r--g10/photoid.c67
-rw-r--r--g10/pkglue.c593
-rw-r--r--g10/pkglue.h4
-rw-r--r--g10/plaintext.c27
-rw-r--r--g10/pubkey-enc.c113
-rw-r--r--g10/revoke.c4
-rw-r--r--g10/server.c31
-rw-r--r--g10/seskey.c16
-rw-r--r--g10/sign.c72
-rw-r--r--g10/tdbdump.c13
-rw-r--r--g10/verify.c6
40 files changed, 2570 insertions, 714 deletions
diff --git a/g10/build-packet.c b/g10/build-packet.c
index 19a13760a..606c5c2d8 100644
--- a/g10/build-packet.c
+++ b/g10/build-packet.c
@@ -433,7 +433,7 @@ sos_write (iobuf_t out, gcry_mpi_t a, unsigned int *r_nwritten)
* Write an opaque string to the output stream without length info.
*/
gpg_error_t
-gpg_mpi_write_nohdr (iobuf_t out, gcry_mpi_t a)
+gpg_mpi_write_opaque_nohdr (iobuf_t out, gcry_mpi_t a)
{
int rc;
@@ -452,6 +452,45 @@ gpg_mpi_write_nohdr (iobuf_t out, gcry_mpi_t a)
}
+/*
+ * Write an opaque MPI string with a four-byte octet count to the
+ * output stream. If R_NWRITTEN is not NULL the number of written
+ * bytes is stored there. OUT may be NULL in which case only
+ * R_NWRITTEN is updated and error checking is done.
+ */
+gpg_error_t
+gpg_mpi_write_opaque_32 (iobuf_t out, gcry_mpi_t a, unsigned int *r_nwritten)
+{
+ gpg_error_t err;
+
+ if (gcry_mpi_get_flag (a, GCRYMPI_FLAG_OPAQUE))
+ {
+ unsigned int nbits, nbytes;
+ const void *p;
+
+ p = gcry_mpi_get_opaque (a, &nbits);
+ nbytes = (nbits + 7)/8;
+ if (out)
+ {
+ write_32 (out, nbytes);
+ err = p ? iobuf_write (out, p, nbytes) : 0;
+ }
+ else
+ err = 0;
+ if (r_nwritten)
+ *r_nwritten = 4 + (p? nbytes : 0);
+ }
+ else
+ {
+ err = gpg_error (GPG_ERR_BAD_MPI);
+ if (r_nwritten)
+ *r_nwritten = 0;
+ }
+
+ return err;
+}
+
+
/* Calculate the length of a packet described by PKT. */
u32
calc_packet_length( PACKET *pkt )
@@ -639,8 +678,14 @@ do_key (iobuf_t out, int ctb, PKT_public_key *pk)
{
if ( (pk->pubkey_algo == PUBKEY_ALGO_ECDSA && (i == 0))
|| (pk->pubkey_algo == PUBKEY_ALGO_EDDSA && (i == 0))
- || (pk->pubkey_algo == PUBKEY_ALGO_ECDH && (i == 0 || i == 2)))
- err = gpg_mpi_write_nohdr (a, pk->pkey[i]);
+ || (pk->pubkey_algo == PUBKEY_ALGO_ECDH && (i == 0 || i == 2))
+ || (pk->pubkey_algo == PUBKEY_ALGO_KYBER && (i == 0)))
+ err = gpg_mpi_write_opaque_nohdr (a, pk->pkey[i]);
+ else if (pk->pubkey_algo == PUBKEY_ALGO_KYBER && i == 2)
+ {
+ /* Write a four-octet count prefixed Kyber public key. */
+ err = gpg_mpi_write_opaque_32 (a, pk->pkey[2], NULL);
+ }
else if (pk->pubkey_algo == PUBKEY_ALGO_ECDSA
|| pk->pubkey_algo == PUBKEY_ALGO_EDDSA
|| pk->pubkey_algo == PUBKEY_ALGO_ECDH)
@@ -779,9 +824,15 @@ do_key (iobuf_t out, int ctb, PKT_public_key *pk)
for (j=i; j < nskey; j++ )
{
- if (pk->pubkey_algo == PUBKEY_ALGO_ECDSA
- || pk->pubkey_algo == PUBKEY_ALGO_EDDSA
- || pk->pubkey_algo == PUBKEY_ALGO_ECDH)
+ if (pk->pubkey_algo == PUBKEY_ALGO_KYBER && j == 4)
+ {
+ if ((err=gpg_mpi_write_opaque_32 (NULL,pk->pkey[j], &n)))
+ goto leave;
+ }
+ else if (pk->pubkey_algo == PUBKEY_ALGO_ECDSA
+ || pk->pubkey_algo == PUBKEY_ALGO_EDDSA
+ || pk->pubkey_algo == PUBKEY_ALGO_ECDH
+ || pk->pubkey_algo == PUBKEY_ALGO_KYBER)
{
if ((err = sos_write (NULL, pk->pkey[j], &n)))
goto leave;
@@ -798,16 +849,26 @@ do_key (iobuf_t out, int ctb, PKT_public_key *pk)
}
for ( ; i < nskey; i++ )
- if (pk->pubkey_algo == PUBKEY_ALGO_ECDSA
- || pk->pubkey_algo == PUBKEY_ALGO_EDDSA
- || pk->pubkey_algo == PUBKEY_ALGO_ECDH)
- {
- if ((err = sos_write (a, pk->pkey[i], NULL)))
- goto leave;
- }
- else
- if ((err = gpg_mpi_write (a, pk->pkey[i], NULL)))
- goto leave;
+ {
+ if (pk->pubkey_algo == PUBKEY_ALGO_KYBER && i == 4)
+ {
+ err = gpg_mpi_write_opaque_32 (a, pk->pkey[i], NULL);
+ if (err)
+ goto leave;
+ }
+ else if (pk->pubkey_algo == PUBKEY_ALGO_ECDSA
+ || pk->pubkey_algo == PUBKEY_ALGO_EDDSA
+ || pk->pubkey_algo == PUBKEY_ALGO_ECDH)
+ {
+ if ((err = sos_write (a, pk->pkey[i], NULL)))
+ goto leave;
+ }
+ else
+ {
+ if ((err = gpg_mpi_write (a, pk->pkey[i], NULL)))
+ goto leave;
+ }
+ }
write_16 (a, ski->csum );
}
@@ -921,9 +982,19 @@ do_pubkey_enc( IOBUF out, int ctb, PKT_pubkey_enc *enc )
for (i=0; i < n && !rc ; i++ )
{
- if (enc->pubkey_algo == PUBKEY_ALGO_ECDH && i == 1)
- rc = gpg_mpi_write_nohdr (a, enc->data[i]);
- else if (enc->pubkey_algo == PUBKEY_ALGO_ECDH)
+ /* For Kyber we need to insert the algo before the final data
+ * element because it is not stored in the data array. */
+ if (enc->pubkey_algo == PUBKEY_ALGO_KYBER && i == 2)
+ iobuf_put (a, enc->seskey_algo);
+
+ if (i == 1 && enc->pubkey_algo == PUBKEY_ALGO_ECDH)
+ rc = gpg_mpi_write_opaque_nohdr (a, enc->data[i]);
+ else if (i == 1 && enc->pubkey_algo == PUBKEY_ALGO_KYBER)
+ rc = gpg_mpi_write_opaque_32 (a, enc->data[i], NULL);
+ else if (i == 2 && enc->pubkey_algo == PUBKEY_ALGO_KYBER)
+ rc = gpg_mpi_write_opaque_nohdr (a, enc->data[i]);
+ else if (enc->pubkey_algo == PUBKEY_ALGO_ECDH
+ || enc->pubkey_algo == PUBKEY_ALGO_KYBER)
rc = sos_write (a, enc->data[i], NULL);
else
rc = gpg_mpi_write (a, enc->data[i], NULL);
@@ -1748,6 +1819,72 @@ sig_to_notation(PKT_signature *sig)
return list;
}
+
+/* Return a list of notation data matching NAME. The caller needs to
+ * to free the list using free_notation. Other than sig_to_notation
+ * this function does not return the notation in human readable format
+ * but always returns the raw data. The human readable flag is set
+ * anyway set but .value is always NULL. */
+struct notation *
+search_sig_notations (PKT_signature *sig, const char *name)
+{
+ const byte *p;
+ size_t len;
+ int seq = 0;
+ int crit;
+ notation_t list = NULL;
+
+ while((p=enum_sig_subpkt (sig, 1, SIGSUBPKT_NOTATION, &len, &seq, &crit)))
+ {
+ int n1,n2;
+ struct notation *n=NULL;
+
+ if (len < 8)
+ {
+ log_info (_("WARNING: invalid notation data found\n"));
+ continue;
+ }
+
+ /* name length. */
+ n1=(p[4]<<8)|p[5];
+ /* value length. */
+ n2=(p[6]<<8)|p[7];
+
+ if (8 + n1 + n2 != len)
+ {
+ log_info (_("WARNING: invalid notation data found\n"));
+ continue;
+ }
+
+ if (!name)
+ ; /* Return everything. */
+ else if (n1 != strlen (name) || memcmp (p+8, name, n1))
+ continue; /* Not the requested name. */
+
+
+ n = xmalloc_clear (sizeof *n);
+ n->name = xmalloc (n1+1);
+
+ memcpy (n->name,p + 8, n1);
+ n->name[n1]='\0';
+
+ /* In any case append a Nul. */
+ n->bdat = xmalloc (n2+1);
+ memcpy (n->bdat, p + 8 + n1, n2);
+ n->bdat[n2] = '\0';
+ n->blen = n2;
+ n->flags.human = !!(p[0] & 0x80);
+
+ n->flags.critical = crit;
+
+ n->next = list;
+ list = n;
+ }
+
+ return list;
+}
+
+
/* Release the resources associated with the *list* of notations. To
release a single notation, make sure that notation->next is
NULL. */
diff --git a/g10/call-agent.c b/g10/call-agent.c
index 69207566e..cfd4c086a 100644
--- a/g10/call-agent.c
+++ b/g10/call-agent.c
@@ -251,7 +251,8 @@ start_agent (ctrl_t ctrl, int flag_for_card)
opt.agent_program,
opt.lc_ctype, opt.lc_messages,
opt.session_env,
- opt.autostart, opt.verbose, DBG_IPC,
+ opt.autostart?ASSHELP_FLAG_AUTOSTART:0,
+ opt.verbose, DBG_IPC,
NULL, NULL);
if (!opt.autostart && gpg_err_code (rc) == GPG_ERR_NO_AGENT)
{
@@ -1079,6 +1080,12 @@ agent_keytotpm (ctrl_t ctrl, const char *hexgrip)
snprintf(line, DIM(line), "KEYTOTPM %s\n", hexgrip);
+ if (strchr (hexgrip, ','))
+ {
+ log_error ("storing a part of a dual key is not yet supported\n");
+ return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
+ }
+
rc = start_agent (ctrl, 0);
if (rc)
return rc;
@@ -1108,6 +1115,13 @@ agent_keytocard (const char *hexgrip, int keyno, int force,
memset (&parm, 0, sizeof parm);
+ if (strchr (hexgrip, ','))
+ {
+ log_error ("storing a part of a dual key is not yet supported\n");
+ return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
+ }
+
+
snprintf (line, DIM(line), "KEYTOCARD %s%s %s OPENPGP.%d %s%s%s",
force?"--force ": "", hexgrip, serialno, keyno, timestamp,
ecdh_param_str? " ":"", ecdh_param_str? ecdh_param_str:"");
@@ -2239,9 +2253,9 @@ agent_probe_secret_key (ctrl_t ctrl, PKT_public_key *pk)
{
gpg_error_t err;
char line[ASSUAN_LINELENGTH];
- char *hexgrip;
-
+ char *hexgrip, *p;
struct keyinfo_data_parm_s keyinfo;
+ int result, result2;
memset (&keyinfo, 0, sizeof keyinfo);
@@ -2252,28 +2266,64 @@ agent_probe_secret_key (ctrl_t ctrl, PKT_public_key *pk)
err = hexkeygrip_from_pk (pk, &hexgrip);
if (err)
return 0;
+ if ((p=strchr (hexgrip, ',')))
+ *p++ = 0;
snprintf (line, sizeof line, "KEYINFO %s", hexgrip);
- xfree (hexgrip);
err = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL,
keyinfo_status_cb, &keyinfo);
xfree (keyinfo.serialno);
if (err)
- return 0;
+ result = 0;
+ else if (keyinfo.card_available)
+ result = 4;
+ else if (keyinfo.passphrase_cached)
+ result = 3;
+ else if (keyinfo.is_smartcard)
+ result = 2;
+ else
+ result = 1;
- if (keyinfo.card_available)
- return 4;
+ if (!p)
+ {
+ xfree (hexgrip);
+ return result; /* Not a dual algo - we are ready. */
+ }
- if (keyinfo.passphrase_cached)
- return 3;
+ /* Now check the second keygrip. */
+ memset (&keyinfo, 0, sizeof keyinfo);
+ snprintf (line, sizeof line, "KEYINFO %s", p);
- if (keyinfo.is_smartcard)
- return 2;
+ err = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL,
+ keyinfo_status_cb, &keyinfo);
+ xfree (keyinfo.serialno);
+ if (err)
+ result2 = 0;
+ else if (keyinfo.card_available)
+ result2 = 4;
+ else if (keyinfo.passphrase_cached)
+ result2 = 3;
+ else if (keyinfo.is_smartcard)
+ result2 = 2;
+ else
+ result2 = 1;
- return 1;
+ xfree (hexgrip);
+
+ if (result == result2)
+ return result; /* Both keys have the same status. */
+ else if (!result && result2)
+ return 0; /* Only first key available - return no key. */
+ else if (result && !result2)
+ return 0; /* Only second key not availabale - return no key. */
+ else if (result == 4 || result == 2)
+ return result; /* First key on card - don't care where the second is. */
+ else
+ return result;
}
+
/* Ask the agent whether a secret key is available for any of the
keys (primary or sub) in KEYBLOCK. Returns 0 if available. */
gpg_error_t
@@ -2285,6 +2335,8 @@ agent_probe_any_secret_key (ctrl_t ctrl, kbnode_t keyblock)
kbnode_t kbctx, node;
int nkeys; /* (always zero in secret_keygrips mode) */
unsigned char grip[KEYGRIP_LEN];
+ unsigned char grip2[KEYGRIP_LEN];
+ int grip2_valid;
const unsigned char *s;
unsigned int n;
@@ -2340,22 +2392,30 @@ agent_probe_any_secret_key (ctrl_t ctrl, kbnode_t keyblock)
if (ctrl && ctrl->secret_keygrips)
{
/* We got an array with all secret keygrips. Check this. */
- err = keygrip_from_pk (node->pkt->pkt.public_key, grip);
+ err = keygrip_from_pk (node->pkt->pkt.public_key, grip, 0);
if (err)
return err;
+ err = keygrip_from_pk (node->pkt->pkt.public_key, grip2, 1);
+ if (err && gpg_err_code (err) != GPG_ERR_FALSE)
+ return err;
+ grip2_valid = !err;
+
for (s=ctrl->secret_keygrips, n = 0;
n < ctrl->secret_keygrips_len;
s += 20, n += 20)
{
if (!memcmp (s, grip, 20))
return 0;
+ if (grip2_valid && !memcmp (s, grip2, 20))
+ return 0;
}
err = gpg_error (GPG_ERR_NO_SECKEY);
/* Keep on looping over the keyblock. Never bump nkeys. */
}
else
{
- if (nkeys && ((p - line) + 41) > (ASSUAN_LINELENGTH - 2))
+ if (nkeys
+ && ((p - line) + 4*KEYGRIP_LEN+1+1) > (ASSUAN_LINELENGTH - 2))
{
err = assuan_transact (agent_ctx, line,
NULL, NULL, NULL, NULL, NULL, NULL);
@@ -2365,13 +2425,24 @@ agent_probe_any_secret_key (ctrl_t ctrl, kbnode_t keyblock)
nkeys = 0;
}
- err = keygrip_from_pk (node->pkt->pkt.public_key, grip);
+ err = keygrip_from_pk (node->pkt->pkt.public_key, grip, 0);
if (err)
return err;
*p++ = ' ';
bin2hex (grip, 20, p);
p += 40;
nkeys++;
+
+ err = keygrip_from_pk (node->pkt->pkt.public_key, grip2, 1);
+ if (err && gpg_err_code (err) != GPG_ERR_FALSE)
+ return err;
+ if (!err) /* Add the second keygrip from dual algos. */
+ {
+ *p++ = ' ';
+ bin2hex (grip2, 20, p);
+ p += 40;
+ nkeys++;
+ }
}
}
@@ -2398,6 +2469,7 @@ agent_get_keyinfo (ctrl_t ctrl, const char *hexkeygrip,
gpg_error_t err;
char line[ASSUAN_LINELENGTH];
struct keyinfo_data_parm_s keyinfo;
+ const char *s;
memset (&keyinfo, 0,sizeof keyinfo);
@@ -2407,10 +2479,20 @@ agent_get_keyinfo (ctrl_t ctrl, const char *hexkeygrip,
if (err)
return err;
- if (!hexkeygrip || strlen (hexkeygrip) != 40)
+ /* FIXME: Support dual keys. Maybe under the assumption that the
+ * first key might be on a card. */
+ if (!hexkeygrip)
+ return gpg_error (GPG_ERR_INV_VALUE);
+ s = strchr (hexkeygrip, ',');
+ if (!s)
+ s = hexkeygrip + strlen (hexkeygrip);
+ if (s - hexkeygrip != 40)
return gpg_error (GPG_ERR_INV_VALUE);
- snprintf (line, DIM(line), "KEYINFO %s", hexkeygrip);
+ /* Note that for a dual algo we only get info for the first key.
+ * FIXME: We need to see how we can show the status of the second
+ * key in a key listing. */
+ snprintf (line, DIM(line), "KEYINFO %.40s", hexkeygrip);
err = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL,
keyinfo_status_cb, &keyinfo);
@@ -2796,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);
@@ -2804,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;
@@ -2821,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);
@@ -2844,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);
@@ -3174,6 +3279,7 @@ agent_delete_key (ctrl_t ctrl, const char *hexkeygrip, const char *desc,
return err;
}
+ /* FIXME: Shall we add support to DELETE_KEY for dual keys? */
snprintf (line, DIM(line), "DELETE_KEY%s %s",
force? " --force":"", hexkeygrip);
err = assuan_transact (agent_ctx, line, NULL, NULL,
diff --git a/g10/call-dirmngr.c b/g10/call-dirmngr.c
index c47bf0928..d00f61450 100644
--- a/g10/call-dirmngr.c
+++ b/g10/call-dirmngr.c
@@ -166,7 +166,8 @@ create_context (ctrl_t ctrl, assuan_context_t *r_ctx)
err = start_new_dirmngr (&ctx,
GPG_ERR_SOURCE_DEFAULT,
opt.dirmngr_program,
- opt.autostart, opt.verbose, DBG_IPC,
+ opt.autostart?ASSHELP_FLAG_AUTOSTART:0,
+ opt.verbose, DBG_IPC,
NULL /*gpg_status2*/, ctrl);
if (!opt.autostart && gpg_err_code (err) == GPG_ERR_NO_DIRMNGR)
{
diff --git a/g10/call-keyboxd.c b/g10/call-keyboxd.c
index 121b7aa2a..bc3806f0b 100644
--- a/g10/call-keyboxd.c
+++ b/g10/call-keyboxd.c
@@ -94,8 +94,6 @@ gpg_keyboxd_deinit_session_data (ctrl_t ctrl)
log_error ("oops: trying to cleanup an active keyboxd context\n");
else
{
- kbx_client_data_release (kbl->kcd);
- kbl->kcd = NULL;
if (kbl->ctx && in_transaction)
{
/* This is our hack to commit the changes done during a
@@ -112,6 +110,15 @@ gpg_keyboxd_deinit_session_data (ctrl_t ctrl)
}
assuan_release (kbl->ctx);
kbl->ctx = NULL;
+ /*
+ * Since there may be pipe output FD sent to the server (so
+ * that it can receive data through the pipe), we should
+ * release the assuan connection before releasing KBL->KCD.
+ * This way, the data receiving thread can finish cleanly,
+ * and we can join the thread.
+ */
+ kbx_client_data_release (kbl->kcd);
+ kbl->kcd = NULL;
}
xfree (kbl);
}
@@ -143,7 +150,8 @@ create_new_context (ctrl_t ctrl, assuan_context_t *r_ctx)
err = start_new_keyboxd (&ctx,
GPG_ERR_SOURCE_DEFAULT,
opt.keyboxd_program,
- opt.autostart, opt.verbose, DBG_IPC,
+ opt.autostart?ASSHELP_FLAG_AUTOSTART:0,
+ opt.verbose, DBG_IPC,
NULL, ctrl);
if (!opt.autostart && gpg_err_code (err) == GPG_ERR_NO_KEYBOXD)
{
@@ -223,7 +231,7 @@ open_context (ctrl_t ctrl, keyboxd_local_t *r_kbl)
return err;
}
- err = kbx_client_data_new (&kbl->kcd, kbl->ctx, 1);
+ err = kbx_client_data_new (&kbl->kcd, kbl->ctx, 0);
if (err)
{
assuan_release (kbl->ctx);
diff --git a/g10/card-util.c b/g10/card-util.c
index a66c2e3de..7df505f62 100644
--- a/g10/card-util.c
+++ b/g10/card-util.c
@@ -28,9 +28,7 @@
# include <readline/readline.h>
#endif /*HAVE_LIBREADLINE*/
-#if GNUPG_MAJOR_VERSION != 1
# include "gpg.h"
-#endif /*GNUPG_MAJOR_VERSION != 1*/
#include "../common/util.h"
#include "../common/i18n.h"
#include "../common/ttyio.h"
@@ -39,11 +37,7 @@
#include "main.h"
#include "keyserver-internal.h"
-#if GNUPG_MAJOR_VERSION == 1
-# include "cardglue.h"
-#else /*GNUPG_MAJOR_VERSION!=1*/
-# include "call-agent.h"
-#endif /*GNUPG_MAJOR_VERSION!=1*/
+#include "call-agent.h"
#define CONTROL_D ('D' - 'A' + 1)
@@ -949,14 +943,6 @@ get_data_from_file (const char *fname, char **r_buffer)
*r_buffer = NULL;
fp = es_fopen (fname, "rb");
-#if GNUPG_MAJOR_VERSION == 1
- if (fp && is_secured_file (fileno (fp)))
- {
- fclose (fp);
- fp = NULL;
- errno = EPERM;
- }
-#endif
if (!fp)
{
tty_printf (_("can't open '%s': %s\n"), fname, strerror (errno));
@@ -992,14 +978,6 @@ put_data_to_file (const char *fname, const void *buffer, size_t length)
estream_t fp;
fp = es_fopen (fname, "wb");
-#if GNUPG_MAJOR_VERSION == 1
- if (fp && is_secured_file (fileno (fp)))
- {
- fclose (fp);
- fp = NULL;
- errno = EPERM;
- }
-#endif
if (!fp)
{
tty_printf (_("can't create '%s': %s\n"), fname, strerror (errno));
diff --git a/g10/dearmor.c b/g10/dearmor.c
index c0bd9ecf6..f6bb59ef6 100644
--- a/g10/dearmor.c
+++ b/g10/dearmor.c
@@ -63,7 +63,7 @@ dearmor_file( const char *fname )
push_armor_filter ( afx, inp );
- if( (rc = open_outfile (-1, fname, 0, 0, &out)) )
+ if( (rc = open_outfile (GNUPG_INVALID_FD, fname, 0, 0, &out)) )
goto leave;
iobuf_copy (out, inp);
@@ -107,7 +107,7 @@ enarmor_file( const char *fname )
}
- if( (rc = open_outfile (-1, fname, 1, 0, &out )) )
+ if( (rc = open_outfile (GNUPG_INVALID_FD, fname, 1, 0, &out )) )
goto leave;
afx->what = 4;
diff --git a/g10/decrypt.c b/g10/decrypt.c
index cb9e36a93..b30359af4 100644
--- a/g10/decrypt.c
+++ b/g10/decrypt.c
@@ -100,7 +100,8 @@ decrypt_message (ctrl_t ctrl, const char *filename)
/* Same as decrypt_message but takes a file descriptor for input and
output. */
gpg_error_t
-decrypt_message_fd (ctrl_t ctrl, int input_fd, int output_fd)
+decrypt_message_fd (ctrl_t ctrl, gnupg_fd_t input_fd,
+ gnupg_fd_t output_fd)
{
#ifdef HAVE_W32_SYSTEM
/* No server mode yet. */
@@ -138,13 +139,25 @@ decrypt_message_fd (ctrl_t ctrl, int input_fd, int output_fd)
return err;
}
- opt.outfp = es_fdopen_nc (output_fd, "wb");
+ if (is_secured_file (output_fd))
+ {
+ char xname[64];
+
+ err = gpg_error (GPG_ERR_EPERM);
+ snprintf (xname, sizeof xname, "[fd %d]", FD_DBG (output_fd));
+ log_error (_("can't open '%s': %s\n"), xname, gpg_strerror (err));
+ iobuf_close (fp);
+ release_progress_context (pfx);
+ return err;
+ }
+
+ opt.outfp = open_stream_nc (output_fd, "w");
if (!opt.outfp)
{
char xname[64];
err = gpg_error_from_syserror ();
- snprintf (xname, sizeof xname, "[fd %d]", output_fd);
+ snprintf (xname, sizeof xname, "[fd %d]", FD_DBG (output_fd));
log_error (_("can't open '%s': %s\n"), xname, gpg_strerror (err));
iobuf_close (fp);
release_progress_context (pfx);
diff --git a/g10/ecdh.c b/g10/ecdh.c
index eb14154a1..279508bec 100644
--- a/g10/ecdh.c
+++ b/g10/ecdh.c
@@ -156,11 +156,11 @@ build_kdf_params (unsigned char kdf_params[256], size_t *r_size,
return gpg_error_from_syserror ();
/* variable-length field 1, curve name OID */
- err = gpg_mpi_write_nohdr (obuf, pkey[0]);
+ err = gpg_mpi_write_opaque_nohdr (obuf, pkey[0]);
/* fixed-length field 2 */
iobuf_put (obuf, PUBKEY_ALGO_ECDH);
/* variable-length field 3, KDF params */
- err = (err ? err : gpg_mpi_write_nohdr (obuf, pkey[2]));
+ err = (err ? err : gpg_mpi_write_opaque_nohdr (obuf, pkey[2]));
/* fixed-length field 4 */
iobuf_write (obuf, "Anonymous Sender ", 20);
/* fixed-length field 5, recipient fp (or first 20 octets of fp) */
@@ -524,8 +524,7 @@ pk_ecdh_decrypt (gcry_mpi_t *r_result, const byte sk_fp[MAX_FINGERPRINT_LEN],
size_t nbytes;
byte *data_buf;
int data_buf_size;
- byte *in;
- const void *p;
+ const unsigned char *p;
unsigned int nbits;
*r_result = NULL;
@@ -538,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);
@@ -546,7 +545,10 @@ pk_ecdh_decrypt (gcry_mpi_t *r_result, const byte sk_fp[MAX_FINGERPRINT_LEN],
return gpg_error (GPG_ERR_BAD_DATA);
}
- data_buf = xtrymalloc_secure( 1 + 2*data_buf_size + 8);
+ /* The first octet is for length. It's longer than the result
+ because of one additional block of AESWRAP. */
+ data_buf_size -= 1 + 8;
+ data_buf = xtrymalloc_secure (data_buf_size);
if (!data_buf)
{
err = gpg_error_from_syserror ();
@@ -560,22 +562,18 @@ pk_ecdh_decrypt (gcry_mpi_t *r_result, const byte sk_fp[MAX_FINGERPRINT_LEN],
gcry_cipher_close (hd);
return gpg_error (GPG_ERR_BAD_MPI);
}
- memcpy (data_buf, p, nbytes);
- if (data_buf[0] != nbytes-1)
+ if (p[0] != nbytes-1)
{
log_error ("ecdh inconsistent size\n");
xfree (data_buf);
gcry_cipher_close (hd);
return gpg_error (GPG_ERR_BAD_MPI);
}
- in = data_buf+data_buf_size;
- data_buf_size = data_buf[0];
if (DBG_CRYPTO)
- log_printhex (data_buf+1, data_buf_size, "ecdh decrypting :");
+ log_printhex (p+1, nbytes-1, "ecdh decrypting :");
- err = gcry_cipher_decrypt (hd, in, data_buf_size, data_buf+1,
- data_buf_size);
+ err = gcry_cipher_decrypt (hd, data_buf, data_buf_size, p+1, nbytes-1);
gcry_cipher_close (hd);
if (err)
{
@@ -585,10 +583,8 @@ pk_ecdh_decrypt (gcry_mpi_t *r_result, const byte sk_fp[MAX_FINGERPRINT_LEN],
return err;
}
- data_buf_size -= 8;
-
if (DBG_CRYPTO)
- log_printhex (in, data_buf_size, "ecdh decrypted to :");
+ log_printhex (data_buf, data_buf_size, "ecdh decrypted to :");
/* Padding is removed later. */
/* if (in[data_buf_size-1] > 8 ) */
@@ -598,7 +594,8 @@ pk_ecdh_decrypt (gcry_mpi_t *r_result, const byte sk_fp[MAX_FINGERPRINT_LEN],
/* return gpg_error (GPG_ERR_BAD_KEY); */
/* } */
- err = gcry_mpi_scan (r_result, GCRYMPI_FMT_USG, in, data_buf_size, NULL);
+ err = gcry_mpi_scan (r_result, GCRYMPI_FMT_USG, data_buf,
+ data_buf_size, NULL);
xfree (data_buf);
if (err)
{
diff --git a/g10/encrypt.c b/g10/encrypt.c
index b335b9797..8ce6164ce 100644
--- a/g10/encrypt.c
+++ b/g10/encrypt.c
@@ -507,7 +507,8 @@ encrypt_simple (const char *filename, int mode, int use_seskey)
/**/ : "CFB");
}
- if ( rc || (rc = open_outfile (-1, filename, opt.armor? 1:0, 0, &out )))
+ if (rc || (rc = open_outfile (GNUPG_INVALID_FD, filename, opt.armor? 1:0,
+ 0, &out )))
{
iobuf_cancel (inp);
xfree (cfx.dek);
@@ -757,15 +758,15 @@ write_symkey_enc (STRING2KEY *symkey_s2k, aead_algo_t aead_algo,
* Encrypt the file with the given userids (or ask if none is
* supplied). Either FILENAME or FILEFD must be given, but not both.
* The caller may provide a checked list of public keys in
- * PROVIDED_PKS; if not the function builds a list of keys on its own.
+ * PROVIDED_KEYS; if not the function builds a list of keys on its own.
*
* Note that FILEFD is currently only used by cmd_encrypt in the
* not yet finished server.c.
*/
int
-encrypt_crypt (ctrl_t ctrl, int filefd, const char *filename,
+encrypt_crypt (ctrl_t ctrl, gnupg_fd_t filefd, const char *filename,
strlist_t remusr, int use_symkey, pk_list_t provided_keys,
- int outputfd)
+ gnupg_fd_t outputfd)
{
iobuf_t inp = NULL;
iobuf_t out = NULL;
@@ -783,7 +784,7 @@ encrypt_crypt (ctrl_t ctrl, int filefd, const char *filename,
PK_LIST pk_list;
int do_compress;
- if (filefd != -1 && filename)
+ if (filefd != GNUPG_INVALID_FD && filename)
return gpg_error (GPG_ERR_INV_ARG); /* Both given. */
do_compress = !!opt.compress_algo;
@@ -814,7 +815,7 @@ encrypt_crypt (ctrl_t ctrl, int filefd, const char *filename,
/* Prepare iobufs. */
#ifdef HAVE_W32_SYSTEM
- if (filefd == -1)
+ if (filefd == GNUPG_INVALID_FD)
inp = iobuf_open (filename);
else
{
@@ -822,7 +823,7 @@ encrypt_crypt (ctrl_t ctrl, int filefd, const char *filename,
gpg_err_set_errno (ENOSYS);
}
#else
- if (filefd == -1)
+ if (filefd == GNUPG_INVALID_FD)
inp = iobuf_open (filename);
else
inp = iobuf_fdopen_nc (filefd, "rb");
@@ -840,8 +841,8 @@ encrypt_crypt (ctrl_t ctrl, int filefd, const char *filename,
char xname[64];
rc = gpg_error_from_syserror ();
- if (filefd != -1)
- snprintf (xname, sizeof xname, "[fd %d]", filefd);
+ if (filefd != GNUPG_INVALID_FD)
+ snprintf (xname, sizeof xname, "[fd %d]", FD_DBG (filefd));
else if (!filename)
strcpy (xname, "[stdin]");
else
@@ -1121,6 +1122,7 @@ write_pubkey_enc (ctrl_t ctrl,
enc->pubkey_algo = pk->pubkey_algo;
keyid_from_pk( pk, enc->keyid );
enc->throw_keyid = throw_keyid;
+ enc->seskey_algo = dek->algo; /* (Used only by PUBKEY_ALGO_KYBER.) */
/* Okay, what's going on: We have the session key somewhere in
* the structure DEK and want to encode this session key in an
@@ -1136,7 +1138,7 @@ write_pubkey_enc (ctrl_t ctrl,
* build_packet(). */
frame = encode_session_key (pk->pubkey_algo, dek,
pubkey_nbits (pk->pubkey_algo, pk->pkey));
- rc = pk_encrypt (pk->pubkey_algo, enc->data, frame, pk, pk->pkey);
+ rc = pk_encrypt (pk, frame, dek->algo, enc->data);
gcry_mpi_release (frame);
if (rc)
log_error ("pubkey_encrypt failed: %s\n", gpg_strerror (rc) );
@@ -1224,7 +1226,8 @@ encrypt_crypt_files (ctrl_t ctrl, int nfiles, char **files, strlist_t remusr)
}
line[strlen(line)-1] = '\0';
print_file_status(STATUS_FILE_START, line, 2);
- rc = encrypt_crypt (ctrl, -1, line, remusr, 0, NULL, -1);
+ rc = encrypt_crypt (ctrl, GNUPG_INVALID_FD, line, remusr,
+ 0, NULL, GNUPG_INVALID_FD);
if (rc)
log_error ("encryption of '%s' failed: %s\n",
print_fname_stdin(line), gpg_strerror (rc) );
@@ -1236,7 +1239,8 @@ encrypt_crypt_files (ctrl_t ctrl, int nfiles, char **files, strlist_t remusr)
while (nfiles--)
{
print_file_status(STATUS_FILE_START, *files, 2);
- if ( (rc = encrypt_crypt (ctrl, -1, *files, remusr, 0, NULL, -1)) )
+ if ((rc = encrypt_crypt (ctrl, GNUPG_INVALID_FD, *files, remusr,
+ 0, NULL, GNUPG_INVALID_FD)))
log_error("encryption of '%s' failed: %s\n",
print_fname_stdin(*files), gpg_strerror (rc) );
write_status( STATUS_FILE_DONE );
diff --git a/g10/export.c b/g10/export.c
index 224847e0f..2417edef1 100644
--- a/g10/export.c
+++ b/g10/export.c
@@ -428,7 +428,7 @@ do_export (ctrl_t ctrl, strlist_t users, int secret, unsigned int options,
memset( &zfx, 0, sizeof zfx);
- rc = open_outfile (-1, NULL, 0, !!secret, &out );
+ rc = open_outfile (GNUPG_INVALID_FD, NULL, 0, !!secret, &out);
if (rc)
return rc;
@@ -1961,6 +1961,11 @@ do_export_one_keyblock (ctrl_t ctrl, kbnode_t keyblock, u32 *keyid,
err = 0;
continue;
}
+ if (strchr (hexgrip, ','))
+ {
+ log_error ("exporting a secret dual key is not yet supported\n");
+ return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
+ }
xfree (serialno);
serialno = NULL;
@@ -2707,18 +2712,18 @@ export_one_ssh_key (estream_t fp, PKT_public_key *pk)
blob = get_membuf (&mb, &bloblen);
if (blob)
{
- struct b64state b64_state;
+ gpgrt_b64state_t b64_state;
es_fprintf (fp, "%s ", identifier);
- err = b64enc_start_es (&b64_state, fp, "");
- if (err)
+ b64_state = gpgrt_b64enc_start (fp, "");
+ if (!b64_state)
{
xfree (blob);
goto leave;
}
- err = b64enc_write (&b64_state, blob, bloblen);
- b64enc_finish (&b64_state);
+ err = gpgrt_b64enc_write (b64_state, blob, bloblen);
+ gpgrt_b64enc_finish (b64_state);
es_fprintf (fp, " openpgp:0x%08lX\n", (ulong)keyid_from_pk (pk, NULL));
xfree (blob);
@@ -2962,7 +2967,7 @@ export_secret_ssh_key (ctrl_t ctrl, const char *userid)
int pkalgo;
int i;
gcry_mpi_t keyparam[10] = { NULL };
- struct b64state b64_state;
+ gpgrt_b64state_t b64_state;
init_membuf_secure (&mb, 1024);
init_membuf_secure (&mb2, 1024);
@@ -3140,11 +3145,11 @@ export_secret_ssh_key (ctrl_t ctrl, const char *userid)
goto leave;
}
- err = b64enc_start_es (&b64_state, fp, "OPENSSH PRIVATE_KEY");
- if (err)
+ b64_state = gpgrt_b64enc_start (fp, "OPENSSH PRIVATE_KEY");
+ if (!b64_state)
goto leave;
- err = b64enc_write (&b64_state, blob, bloblen);
- b64enc_finish (&b64_state);
+ err = gpgrt_b64enc_write (b64_state, blob, bloblen);
+ gpgrt_b64enc_finish (b64_state);
if (err)
goto leave;
diff --git a/g10/filter.h b/g10/filter.h
index 4b4fc55ff..321b553dc 100644
--- a/g10/filter.h
+++ b/g10/filter.h
@@ -29,6 +29,9 @@ typedef struct {
size_t maxbuf_size;
} md_filter_context_t;
+typedef struct md_thd_filter_context *md_thd_filter_context_t;
+void md_thd_filter_set_md (md_thd_filter_context_t mfx, gcry_md_hd_t md);
+
typedef struct {
int refcount; /* Initialized to 1. */
@@ -165,6 +168,7 @@ typedef struct {
/*-- mdfilter.c --*/
int md_filter( void *opaque, int control, iobuf_t a, byte *buf, size_t *ret_len);
+int md_thd_filter( void *opaque, int control, iobuf_t a, byte *buf, size_t *ret_len);
void free_md_filter_context( md_filter_context_t *mfx );
/*-- armor.c --*/
diff --git a/g10/getkey.c b/g10/getkey.c
index ce59628a0..f2d1e7d7b 100644
--- a/g10/getkey.c
+++ b/g10/getkey.c
@@ -3779,6 +3779,16 @@ finish_lookup (kbnode_t keyblock, unsigned int req_usage, int want_exact,
continue;
}
+ if (opt.flags.require_pqc_encryption
+ && (req_usage & PUBKEY_USAGE_ENC)
+ && pk->pubkey_algo != PUBKEY_ALGO_KYBER)
+ {
+ if (DBG_LOOKUP)
+ log_debug ("\tsubkey is not quantum-resistant\n");
+ continue;
+ }
+
+
if (want_secret)
{
int secret_key_avail = agent_probe_secret_key (NULL, pk);
@@ -3857,6 +3867,13 @@ finish_lookup (kbnode_t keyblock, unsigned int req_usage, int want_exact,
if (DBG_LOOKUP)
log_debug ("\tprimary key has expired\n");
}
+ else if (opt.flags.require_pqc_encryption
+ && (req_usage & PUBKEY_USAGE_ENC)
+ && pk->pubkey_algo != PUBKEY_ALGO_KYBER)
+ {
+ if (DBG_LOOKUP)
+ log_debug ("\tprimary key is not quantum-resistant\n");
+ }
else /* Okay. */
{
if (DBG_LOOKUP)
diff --git a/g10/gpg.c b/g10/gpg.c
index bba486aea..82745fa18 100644
--- a/g10/gpg.c
+++ b/g10/gpg.c
@@ -207,6 +207,7 @@ enum cmd_and_opt_values
oWithV5Fingerprint,
oWithFingerprint,
oWithSubkeyFingerprint,
+ oWithoutSubkeyFingerprint,
oWithICAOSpelling,
oWithKeygrip,
oWithKeyScreening,
@@ -355,6 +356,7 @@ enum cmd_and_opt_values
oAllowSecretKeyImport,
oAllowOldCipherAlgos,
oEnableSpecialFilenames,
+ oDisableFdTranslation,
oNoLiteral,
oSetFilesize,
oHonorHttpProxy,
@@ -454,6 +456,7 @@ enum cmd_and_opt_values
oAssertSigner,
oAssertPubkeyAlgo,
oKbxBufferSize,
+ oRequirePQCEncryption,
oNoop
};
@@ -825,6 +828,7 @@ static gpgrt_opt_t opts[] = {
ARGPARSE_s_n (oWithFingerprint, "with-fingerprint", "@"),
ARGPARSE_s_n (oWithSubkeyFingerprint, "with-subkey-fingerprint", "@"),
ARGPARSE_s_n (oWithSubkeyFingerprint, "with-subkey-fingerprints", "@"),
+ ARGPARSE_s_n (oWithoutSubkeyFingerprint, "without-subkey-fingerprint", "@"),
ARGPARSE_s_n (oWithICAOSpelling, "with-icao-spelling", "@"),
ARGPARSE_s_n (oWithKeygrip, "with-keygrip", "@"),
ARGPARSE_s_n (oWithKeyScreening,"with-key-screening", "@"),
@@ -882,7 +886,6 @@ static gpgrt_opt_t opts[] = {
ARGPARSE_s_n (oAllowOldCipherAlgos, "allow-old-cipher-algos", "@"),
ARGPARSE_s_s (oWeakDigest, "weak-digest","@"),
ARGPARSE_s_s (oVerifyOptions, "verify-options", "@"),
- ARGPARSE_s_n (oEnableSpecialFilenames, "enable-special-filenames", "@"),
ARGPARSE_s_n (oNoRandomSeedFile, "no-random-seed-file", "@"),
ARGPARSE_s_n (oNoSigCache, "no-sig-cache", "@"),
ARGPARSE_s_n (oIgnoreTimeConflict, "ignore-time-conflict", "@"),
@@ -894,7 +897,7 @@ static gpgrt_opt_t opts[] = {
ARGPARSE_s_s (oCipherAlgo, "cipher-algo", "@"),
ARGPARSE_s_s (oDigestAlgo, "digest-algo", "@"),
ARGPARSE_s_s (oCertDigestAlgo, "cert-digest-algo", "@"),
-
+ ARGPARSE_s_n (oRequirePQCEncryption, "require-pqc-encryption", "@"),
ARGPARSE_header (NULL, N_("Options for unattended use")),
@@ -914,6 +917,8 @@ static gpgrt_opt_t opts[] = {
ARGPARSE_s_i (oPassphraseRepeat,"passphrase-repeat", "@"),
ARGPARSE_s_s (oPinentryMode, "pinentry-mode", "@"),
ARGPARSE_s_n (oForceSignKey, "force-sign-key", "@"),
+ ARGPARSE_s_n (oEnableSpecialFilenames, "enable-special-filenames", "@"),
+ ARGPARSE_s_n (oDisableFdTranslation, "disable-fd-translation", "@"),
ARGPARSE_header (NULL, N_("Other options")),
@@ -1033,6 +1038,8 @@ static struct debug_flags_s debug_flags [] =
/* The list of compatibility flags. */
static struct compatibility_flags_s compatibility_flags [] =
{
+ { COMPAT_PARALLELIZED, "parallelized" },
+ { COMPAT_T7014_OLD, "t7014-old" },
{ 0, NULL }
};
@@ -1087,10 +1094,6 @@ static void read_sessionkey_from_fd (int fd);
-/* NPth wrapper function definitions. */
-ASSUAN_SYSTEM_NPTH_IMPL;
-
-
static char *
make_libversion (const char *libname, const char *(*getfnc)(const char*))
{
@@ -2091,6 +2094,8 @@ parse_list_options(char *str)
NULL},
{"show-user-notations",LIST_SHOW_USER_NOTATIONS,NULL,
N_("show user-supplied notations during signature listings")},
+ {"show-x509-notations",LIST_SHOW_X509_NOTATIONS,NULL, NULL },
+ {"store-x509-notations",LIST_STORE_X509_NOTATIONS,NULL, NULL },
{"show-keyserver-urls",LIST_SHOW_KEYSERVER_URLS,NULL,
N_("show preferred keyserver URLs during signature listings")},
{"show-uid-validity",LIST_SHOW_UID_VALIDITY,NULL,
@@ -2505,6 +2510,7 @@ main (int argc, char **argv)
opt.passphrase_repeat = 1;
opt.emit_version = 0;
opt.weak_digests = NULL;
+ opt.with_subkey_fingerprint = 1;
opt.compliance = CO_GNUPG;
/* Check special options given on the command line. */
@@ -2912,6 +2918,9 @@ main (int argc, char **argv)
case oWithSubkeyFingerprint:
opt.with_subkey_fingerprint = 1;
break;
+ case oWithoutSubkeyFingerprint:
+ opt.with_subkey_fingerprint = 0;
+ break;
case oWithICAOSpelling:
opt.with_icao_spelling = 1;
break;
@@ -3063,6 +3072,9 @@ main (int argc, char **argv)
break;
case oMinRSALength: opt.min_rsa_length = pargs.r.ret_ulong; break;
+ case oRequirePQCEncryption:
+ opt.flags.require_pqc_encryption = 1;
+ break;
case oRFC2440Text: opt.rfc2440_text=1; break;
case oNoRFC2440Text: opt.rfc2440_text=0; break;
@@ -3569,6 +3581,10 @@ main (int argc, char **argv)
enable_special_filenames ();
break;
+ case oDisableFdTranslation:
+ disable_translate_sys2libc_fd ();
+ break;
+
case oNoExpensiveTrustChecks: opt.no_expensive_trust_checks=1; break;
case oAutoCheckTrustDB: opt.no_auto_check_trustdb=0; break;
case oNoAutoCheckTrustDB: opt.no_auto_check_trustdb=1; break;
@@ -3907,8 +3923,8 @@ main (int argc, char **argv)
/* Init threading which is used by some helper functions. */
npth_init ();
- assuan_set_system_hooks (ASSUAN_SYSTEM_NPTH);
gpgrt_set_syscall_clamp (npth_unprotect, npth_protect);
+ assuan_control (ASSUAN_CONTROL_REINIT_SYSCALL_CLAMP, NULL);
if (logfile)
{
@@ -4453,7 +4469,8 @@ main (int argc, char **argv)
{
if( argc > 1 )
wrong_args("--encrypt [filename]");
- if( (rc = encrypt_crypt (ctrl, -1, fname, remusr, 0, NULL, -1)) )
+ if ((rc = encrypt_crypt (ctrl, GNUPG_INVALID_FD, fname, remusr,
+ 0, NULL, GNUPG_INVALID_FD)))
{
write_status_failure ("encrypt", rc);
log_error("%s: encryption failed: %s\n",
@@ -4478,7 +4495,8 @@ main (int argc, char **argv)
gnupg_compliance_option_string (opt.compliance));
else
{
- if( (rc = encrypt_crypt (ctrl, -1, fname, remusr, 1, NULL, -1)) )
+ if ((rc = encrypt_crypt (ctrl, GNUPG_INVALID_FD, fname, remusr,
+ 1, NULL, GNUPG_INVALID_FD)))
{
write_status_failure ("encrypt", rc);
log_error ("%s: encryption failed: %s\n",
@@ -5676,13 +5694,13 @@ print_mds( const char *fname, int algo )
}
else
{
- fp = es_fopen (fname, "rb" );
- if (fp && is_secured_file (es_fileno (fp)))
+ if (is_secured_filename (fname))
{
- es_fclose (fp);
fp = NULL;
gpg_err_set_errno (EPERM);
}
+ else
+ fp = es_fopen (fname, "rb" );
}
if (!fp)
{
diff --git a/g10/gpg.h b/g10/gpg.h
index c51bbbb46..167cdaf28 100644
--- a/g10/gpg.h
+++ b/g10/gpg.h
@@ -41,6 +41,10 @@
/* Number of bits we accept when reading or writing MPIs. */
#define MAX_EXTERN_MPI_BITS 16384
+/* Number of bytes we accept when reading four-octet count prefixed
+ * key parameters. Needs to fit as a positive number into an int. */
+#define MAX_EXTERN_KEYPARM_BITS (32768*8)
+
/* The maximum length of a binary fingerprints. This is used to
* provide a static buffer and will be increased if we need to support
* longer fingerprints. Warning: At some places we have some
diff --git a/g10/import.c b/g10/import.c
index ff8847cb6..bbeeebdfe 100644
--- a/g10/import.c
+++ b/g10/import.c
@@ -2175,10 +2175,12 @@ import_one_real (ctrl_t ctrl,
merge_keys_done = 1;
/* Note that we do not want to show the validity because the key
* has not yet imported. */
- list_keyblock_direct (ctrl, keyblock, from_sk, 0,
+ err = list_keyblock_direct (ctrl, keyblock, from_sk, 0,
opt.fingerprint || opt.with_fingerprint, 1);
es_fflush (es_stdout);
no_usable_encr_subkeys_warning (keyblock);
+ if (err)
+ goto leave;
}
/* Write the keyblock to the output and do not actually import. */
diff --git a/g10/keydb.h b/g10/keydb.h
index 62a99295d..75a8ded72 100644
--- a/g10/keydb.h
+++ b/g10/keydb.h
@@ -578,7 +578,8 @@ char *hexfingerprint (PKT_public_key *pk, char *buffer, size_t buflen);
char *v5hexfingerprint (PKT_public_key *pk, char *buffer, size_t buflen);
char *format_hexfingerprint (const char *fingerprint,
char *buffer, size_t buflen);
-gpg_error_t keygrip_from_pk (PKT_public_key *pk, unsigned char *array);
+gpg_error_t keygrip_from_pk (PKT_public_key *pk, unsigned char *array,
+ int get_second);
gpg_error_t hexkeygrip_from_pk (PKT_public_key *pk, char **r_grip);
char *ecdh_param_str_from_pk (PKT_public_key *pk);
diff --git a/g10/keyedit.c b/g10/keyedit.c
index f4f59de03..81ea06c24 100644
--- a/g10/keyedit.c
+++ b/g10/keyedit.c
@@ -1103,6 +1103,7 @@ change_passphrase (ctrl_t ctrl, kbnode_t keyblock)
err = hexkeygrip_from_pk (pk, &hexgrip);
if (err)
goto leave;
+ /* FIXME: Handle dual keys. */
err = agent_get_keyinfo (ctrl, hexgrip, &serialno, NULL);
if (!err && serialno)
; /* Key on card. */
diff --git a/g10/keygen.c b/g10/keygen.c
index 48e5b3a40..4bdb9f53a 100644
--- a/g10/keygen.c
+++ b/g10/keygen.c
@@ -1,7 +1,7 @@
/* keygen.c - Generate a key pair
* Copyright (C) 1998-2007, 2009-2011 Free Software Foundation, Inc.
* Copyright (C) 2014, 2015, 2016, 2017, 2018 Werner Koch
- * Copyright (C) 2020 g10 Code GmbH
+ * Copyright (C) 2020, 2024 g10 Code GmbH
*
* This file is part of GnuPG.
*
@@ -139,10 +139,23 @@ struct common_gen_cb_parm_s
* may take a copy of this so that the result can be used after we
* are back from the deep key generation call stack. */
gcry_sexp_t genkey_result;
+ /* For a dual algorithms the result of the second algorithm
+ * (e.g. Kyber). */
+ gcry_sexp_t genkey_result2;
};
typedef struct common_gen_cb_parm_s *common_gen_cb_parm_t;
+/* A communication object to help adding certain notations to a key
+ * binding signature. */
+struct opaque_data_usage_and_pk
+{
+ unsigned int usage;
+ const char *cpl_notation;
+ PKT_public_key *pk;
+};
+
+
/* FIXME: These globals vars are ugly. And using MAX_PREFS even for
* aeads is useless, given that we don't expects more than a very few
* algorithms. */
@@ -174,6 +187,9 @@ static gpg_error_t gen_card_key (int keyno, int algo, int is_primary,
u32 expireval, int *keygen_flags);
static unsigned int get_keysize_range (int algo,
unsigned int *min, unsigned int *max);
+static void do_add_notation (PKT_signature *sig,
+ const char *name, const char *value,
+ int critical);
@@ -338,6 +354,20 @@ keygen_add_key_flags_and_expire (PKT_signature *sig, void *opaque)
}
+/* This is only used to write the key binding signature. It is not
+ * used for the primary key. */
+static int
+keygen_add_key_flags_from_oduap (PKT_signature *sig, void *opaque)
+{
+ struct opaque_data_usage_and_pk *oduap = opaque;
+
+ do_add_key_flags (sig, oduap->usage);
+ if (oduap->cpl_notation)
+ do_add_notation (sig, "[email protected]", oduap->cpl_notation, 0);
+ return keygen_add_key_expire (sig, oduap->pk);
+}
+
+
static int
set_one_pref (int val, int type, const char *item, byte *buf, int *nbuf)
{
@@ -943,6 +973,44 @@ keygen_add_keyserver_url(PKT_signature *sig, void *opaque)
return 0;
}
+
+/* This function is used to add a notations to a signature. In
+ * general the caller should have cleared exiting notations before
+ * adding new ones. For example by calling:
+ *
+ * delete_sig_subpkt(sig->hashed,SIGSUBPKT_NOTATION);
+ * delete_sig_subpkt(sig->unhashed,SIGSUBPKT_NOTATION);
+ *
+ * Only human readable notaions may be added. NAME and value are
+ * expected to be UTF-* strings.
+ */
+static void
+do_add_notation (PKT_signature *sig, const char *name, const char *value,
+ int critical)
+{
+ unsigned char *buf;
+ unsigned int n1,n2;
+
+ n1 = strlen (name);
+ n2 = strlen (value);
+
+ buf = xmalloc (8 + n1 + n2);
+
+ buf[0] = 0x80; /* human readable. */
+ buf[1] = buf[2] = buf[3] = 0;
+ buf[4] = n1 >> 8;
+ buf[5] = n1;
+ buf[6] = n2 >> 8;
+ buf[7] = n2;
+ memcpy (buf+8, name, n1);
+ memcpy (buf+8+n1, value, n2);
+ build_sig_subpkt (sig,
+ (SIGSUBPKT_NOTATION|(critical?SIGSUBPKT_FLAG_CRITICAL:0)),
+ buf, 8+n1+n2 );
+ xfree (buf);
+}
+
+
int
keygen_add_notations(PKT_signature *sig,void *opaque)
{
@@ -992,6 +1060,7 @@ keygen_add_notations(PKT_signature *sig,void *opaque)
return 0;
}
+
int
keygen_add_revkey (PKT_signature *sig, void *opaque)
{
@@ -1225,6 +1294,7 @@ write_keybinding (ctrl_t ctrl, kbnode_t root,
PKT_signature *sig;
KBNODE node;
PKT_public_key *pri_pk, *sub_pk;
+ struct opaque_data_usage_and_pk oduap;
if (opt.verbose)
log_info(_("writing key binding signature\n"));
@@ -1250,10 +1320,21 @@ write_keybinding (ctrl_t ctrl, kbnode_t root,
BUG();
/* Make the signature. */
- sub_pk->pubkey_usage = use;
+ oduap.usage = use;
+ if ((use & PUBKEY_USAGE_ENC)
+ && opt.compliance == CO_DE_VS
+ /* The required libgcrypt 1.11 won't yet claim a compliant RNG. */
+ && gnupg_rng_is_compliant (CO_DE_VS))
+ oduap.cpl_notation = "de-vs";
+ else if ((use & PUBKEY_USAGE_ENC)
+ && sub_pk->pubkey_algo == PUBKEY_ALGO_KYBER)
+ oduap.cpl_notation = "fips203.ipd.2023-08-24";
+ else
+ oduap.cpl_notation = NULL;
+ oduap.pk = sub_pk;
err = make_keysig_packet (ctrl, &sig, pri_pk, NULL, sub_pk, pri_psk, 0x18,
timestamp, 0,
- keygen_add_key_flags_and_expire, sub_pk,
+ keygen_add_key_flags_from_oduap, &oduap,
cache_nonce);
if (err)
{
@@ -1311,8 +1392,12 @@ curve_is_448 (gcry_sexp_t sexp)
}
+/* Extract the parameters in OpenPGP format from SEXP and put them
+ * into the caller provided ARRAY. SEXP2 is used to provide the
+ * parameters for dual algorithm (e.g. Kyber). */
static gpg_error_t
-ecckey_from_sexp (gcry_mpi_t *array, gcry_sexp_t sexp, int algo)
+ecckey_from_sexp (gcry_mpi_t *array, gcry_sexp_t sexp,
+ gcry_sexp_t sexp2, int algo, int pkversion)
{
gpg_error_t err;
gcry_sexp_t list, l2;
@@ -1355,6 +1440,10 @@ ecckey_from_sexp (gcry_mpi_t *array, gcry_sexp_t sexp, int algo)
err = gpg_error (GPG_ERR_INV_OBJ);
goto leave;
}
+ /* For v5 keys we prefer the modern OID for cv25519. */
+ if (pkversion > 4 && !strcmp (oidstr, "1.3.6.1.4.1.3029.1.5.1"))
+ oidstr = "1.3.101.110";
+
err = openpgp_oid_from_str (oidstr, &array[0]);
if (err)
goto leave;
@@ -1364,8 +1453,46 @@ ecckey_from_sexp (gcry_mpi_t *array, gcry_sexp_t sexp, int algo)
goto leave;
gcry_sexp_release (list);
+ list = NULL;
- if (algo == PUBKEY_ALGO_ECDH)
+ if (algo == PUBKEY_ALGO_KYBER)
+ {
+ if (!sexp2)
+ {
+ err = gpg_error (GPG_ERR_MISSING_VALUE);
+ goto leave;
+ }
+
+ list = gcry_sexp_find_token (sexp2, "public-key", 0);
+ if (!list)
+ {
+ err = gpg_error (GPG_ERR_INV_OBJ);
+ goto leave;
+ }
+ l2 = gcry_sexp_cadr (list);
+ gcry_sexp_release (list);
+ list = l2;
+ if (!list)
+ {
+ err = gpg_error (GPG_ERR_NO_OBJ);
+ goto leave;
+ }
+
+ l2 = gcry_sexp_find_token (list, "p", 1);
+ if (!l2)
+ {
+ err = gpg_error (GPG_ERR_NO_OBJ); /* required parameter not found */
+ goto leave;
+ }
+ array[2] = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_OPAQUE);
+ gcry_sexp_release (l2);
+ if (!array[2])
+ {
+ err = gpg_error (GPG_ERR_INV_OBJ); /* required parameter invalid */
+ goto leave;
+ }
+ }
+ else if (algo == PUBKEY_ALGO_ECDH)
{
array[2] = pk_ecdh_default_params (nbits);
if (!array[2])
@@ -1377,6 +1504,7 @@ ecckey_from_sexp (gcry_mpi_t *array, gcry_sexp_t sexp, int algo)
leave:
xfree (curve);
+ gcry_sexp_release (list);
if (err)
{
for (i=0; i < 3; i++)
@@ -1455,10 +1583,24 @@ do_create_from_keygrip (ctrl_t ctrl, int algo,
PACKET *pkt;
PKT_public_key *pk;
gcry_sexp_t s_key;
+ gcry_sexp_t s_key2 = NULL;
const char *algoelem;
+ char *hexkeygrip_buffer = NULL;
+ char *hexkeygrip2 = NULL;
if (hexkeygrip[0] == '&')
hexkeygrip++;
+ if (strchr (hexkeygrip, ','))
+ {
+ hexkeygrip_buffer = xtrystrdup (hexkeygrip);
+ if (!hexkeygrip_buffer)
+ return gpg_error_from_syserror ();
+ hexkeygrip = hexkeygrip_buffer;
+ hexkeygrip2 = strchr (hexkeygrip_buffer, ',');
+ if (hexkeygrip2)
+ *hexkeygrip2++ = 0;
+ }
+
switch (algo)
{
@@ -1468,16 +1610,21 @@ do_create_from_keygrip (ctrl_t ctrl, int algo,
case PUBKEY_ALGO_ECDH:
case PUBKEY_ALGO_ECDSA: algoelem = ""; break;
case PUBKEY_ALGO_EDDSA: algoelem = ""; break;
- default: return gpg_error (GPG_ERR_INTERNAL);
+ case PUBKEY_ALGO_KYBER: algoelem = ""; break;
+ default:
+ xfree (hexkeygrip_buffer);
+ return gpg_error (GPG_ERR_INTERNAL);
}
-
/* Ask the agent for the public key matching HEXKEYGRIP. */
if (cardkey)
{
err = agent_scd_readkey (ctrl, hexkeygrip, &s_key, NULL);
if (err)
- return err;
+ {
+ xfree (hexkeygrip_buffer);
+ return err;
+ }
}
else
{
@@ -1485,16 +1632,41 @@ do_create_from_keygrip (ctrl_t ctrl, int algo,
err = agent_readkey (ctrl, 0, hexkeygrip, &public);
if (err)
- return err;
+ {
+ xfree (hexkeygrip_buffer);
+ return err;
+ }
err = gcry_sexp_sscan (&s_key, NULL, public,
gcry_sexp_canon_len (public, 0, NULL, NULL));
xfree (public);
if (err)
- return err;
+ {
+ xfree (hexkeygrip_buffer);
+ return err;
+ }
+ if (hexkeygrip2)
+ {
+ err = agent_readkey (ctrl, 0, hexkeygrip2, &public);
+ if (err)
+ {
+ gcry_sexp_release (s_key);
+ xfree (hexkeygrip_buffer);
+ return err;
+ }
+ err = gcry_sexp_sscan (&s_key2, NULL, public,
+ gcry_sexp_canon_len (public, 0, NULL, NULL));
+ xfree (public);
+ if (err)
+ {
+ gcry_sexp_release (s_key);
+ xfree (hexkeygrip_buffer);
+ return err;
+ }
+ }
}
- /* For X448 we force the use of v5 packets. */
- if (curve_is_448 (s_key))
+ /* For X448 and Kyber we force the use of v5 packets. */
+ if (curve_is_448 (s_key) || algo == PUBKEY_ALGO_KYBER)
*keygen_flags |= KEYGEN_FLAG_CREATE_V5_KEY;
/* Build a public key packet. */
@@ -1503,6 +1675,8 @@ do_create_from_keygrip (ctrl_t ctrl, int algo,
{
err = gpg_error_from_syserror ();
gcry_sexp_release (s_key);
+ gcry_sexp_release (s_key2);
+ xfree (hexkeygrip_buffer);
return err;
}
@@ -1512,26 +1686,32 @@ do_create_from_keygrip (ctrl_t ctrl, int algo,
pk->expiredate = pk->timestamp + expireval;
pk->pubkey_algo = algo;
- if (algo == PUBKEY_ALGO_ECDSA
+ if (algo == PUBKEY_ALGO_KYBER)
+ err = ecckey_from_sexp (pk->pkey, s_key, s_key2, algo, pk->version);
+ else if (algo == PUBKEY_ALGO_ECDSA
|| algo == PUBKEY_ALGO_EDDSA
|| algo == PUBKEY_ALGO_ECDH )
- err = ecckey_from_sexp (pk->pkey, s_key, algo);
+ err = ecckey_from_sexp (pk->pkey, s_key, NULL, algo, pk->version);
else
err = key_from_sexp (pk->pkey, s_key, "public-key", algoelem);
if (err)
{
log_error ("key_from_sexp failed: %s\n", gpg_strerror (err) );
gcry_sexp_release (s_key);
+ gcry_sexp_release (s_key2);
free_public_key (pk);
+ xfree (hexkeygrip_buffer);
return err;
}
gcry_sexp_release (s_key);
+ gcry_sexp_release (s_key2);
pkt = xtrycalloc (1, sizeof *pkt);
if (!pkt)
{
err = gpg_error_from_syserror ();
free_public_key (pk);
+ xfree (hexkeygrip_buffer);
return err;
}
@@ -1539,16 +1719,18 @@ do_create_from_keygrip (ctrl_t ctrl, int algo,
pkt->pkt.public_key = pk;
add_kbnode (pub_root, new_kbnode (pkt));
+ xfree (hexkeygrip_buffer);
return 0;
}
-/* Common code for the key generation function gen_xxx. The optinal
+/* Common code for the key generation function gen_xxx. The optional
* (COMMON_GEN_CB,COMMON_GEN_CB_PARM) can be used as communication
- * object.
+ * object. A KEYPARMS2 forces the use of a dual key (e.g. Kyber+ECC).
*/
static int
-common_gen (const char *keyparms, int algo, const char *algoelem,
+common_gen (const char *keyparms, const char *keyparms2,
+ int algo, const char *algoelem,
kbnode_t pub_root, u32 timestamp, u32 expireval, int is_subkey,
int keygen_flags, const char *passphrase,
char **cache_nonce_addr, char **passwd_nonce_addr,
@@ -1559,6 +1741,7 @@ common_gen (const char *keyparms, int algo, const char *algoelem,
PACKET *pkt;
PKT_public_key *pk;
gcry_sexp_t s_key;
+ gcry_sexp_t s_key2 = NULL;
err = agent_genkey (NULL, cache_nonce_addr, passwd_nonce_addr, keyparms,
!!(keygen_flags & KEYGEN_FLAG_NO_PROTECTION),
@@ -1570,14 +1753,32 @@ common_gen (const char *keyparms, int algo, const char *algoelem,
return err;
}
+ if (keyparms2)
+ {
+ err = agent_genkey (NULL, NULL, NULL, keyparms2,
+ 1 /* No protection */,
+ NULL, timestamp,
+ &s_key2);
+ if (err)
+ {
+ log_error ("agent_genkey failed for second algo: %s\n",
+ gpg_strerror (err) );
+ gcry_sexp_release (s_key);
+ return err;
+ }
+ }
+
if (common_gen_cb && common_gen_cb_parm)
{
common_gen_cb_parm->genkey_result = s_key;
+ common_gen_cb_parm->genkey_result2 = s_key2;
err = common_gen_cb (common_gen_cb_parm);
common_gen_cb_parm->genkey_result = NULL;
+ common_gen_cb_parm->genkey_result2 = NULL;
if (err)
{
gcry_sexp_release (s_key);
+ gcry_sexp_release (s_key2);
return err;
}
}
@@ -1596,10 +1797,12 @@ common_gen (const char *keyparms, int algo, const char *algoelem,
pk->expiredate = pk->timestamp + expireval;
pk->pubkey_algo = algo;
- if (algo == PUBKEY_ALGO_ECDSA
- || algo == PUBKEY_ALGO_EDDSA
- || algo == PUBKEY_ALGO_ECDH )
- err = ecckey_from_sexp (pk->pkey, s_key, algo);
+ if (algo == PUBKEY_ALGO_KYBER)
+ err = ecckey_from_sexp (pk->pkey, s_key, s_key2, algo, pk->version);
+ else if (algo == PUBKEY_ALGO_ECDSA
+ || algo == PUBKEY_ALGO_EDDSA
+ || algo == PUBKEY_ALGO_ECDH )
+ err = ecckey_from_sexp (pk->pkey, s_key, NULL, algo, pk->version);
else
err = key_from_sexp (pk->pkey, s_key, "public-key", algoelem);
if (err)
@@ -1610,6 +1813,7 @@ common_gen (const char *keyparms, int algo, const char *algoelem,
return err;
}
gcry_sexp_release (s_key);
+ gcry_sexp_release (s_key2);
pkt = xtrycalloc (1, sizeof *pkt);
if (!pkt)
@@ -1675,7 +1879,7 @@ gen_elg (int algo, unsigned int nbits, KBNODE pub_root,
err = gpg_error_from_syserror ();
else
{
- err = common_gen (keyparms, algo, "pgy",
+ err = common_gen (keyparms, NULL, algo, "pgy",
pub_root, timestamp, expireval, is_subkey,
keygen_flags, passphrase,
cache_nonce_addr, passwd_nonce_addr,
@@ -1767,7 +1971,7 @@ gen_dsa (unsigned int nbits, KBNODE pub_root,
err = gpg_error_from_syserror ();
else
{
- err = common_gen (keyparms, PUBKEY_ALGO_DSA, "pqgy",
+ err = common_gen (keyparms, NULL, PUBKEY_ALGO_DSA, "pqgy",
pub_root, timestamp, expireval, is_subkey,
keygen_flags, passphrase,
cache_nonce_addr, passwd_nonce_addr,
@@ -1868,7 +2072,7 @@ gen_ecc (int algo, const char *curve, kbnode_t pub_root,
err = gpg_error_from_syserror ();
else
{
- err = common_gen (keyparms, algo, "",
+ err = common_gen (keyparms, NULL, algo, "",
pub_root, timestamp, expireval, is_subkey,
*keygen_flags, passphrase,
cache_nonce_addr, passwd_nonce_addr,
@@ -1880,6 +2084,79 @@ gen_ecc (int algo, const char *curve, kbnode_t pub_root,
}
+/* Generate a dual ECC+Kyber key. Note that KEYGEN_FLAGS will be
+ * updated by this function to indicate the forced creation of a v5
+ * key. */
+static gpg_error_t
+gen_kyber (int algo, unsigned int nbits, const char *curve, kbnode_t pub_root,
+ u32 timestamp, u32 expireval, int is_subkey,
+ int *keygen_flags, const char *passphrase,
+ char **cache_nonce_addr, char **passwd_nonce_addr,
+ gpg_error_t (*common_gen_cb)(common_gen_cb_parm_t),
+ common_gen_cb_parm_t common_gen_cb_parm)
+{
+ gpg_error_t err;
+ char *keyparms1;
+ const char *keyparms2;
+
+ log_assert (algo == PUBKEY_ALGO_KYBER);
+
+ if (nbits == 768)
+ keyparms2 = "(genkey(kyber768))";
+ else if (nbits == 1024)
+ keyparms2 = "(genkey(kyber1024))";
+ else
+ return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM);
+
+ if (!curve || !*curve)
+ return gpg_error (GPG_ERR_UNKNOWN_CURVE);
+
+ *keygen_flags |= KEYGEN_FLAG_CREATE_V5_KEY;
+
+ if (!strcmp (curve, "Curve25519"))
+ {
+ keyparms1 = xtryasprintf
+ ("(genkey(ecc(curve %zu:%s)(flags djb-tweak comp%s)))",
+ strlen (curve), curve,
+ (((*keygen_flags & KEYGEN_FLAG_TRANSIENT_KEY)
+ && (*keygen_flags & KEYGEN_FLAG_NO_PROTECTION))?
+ " transient-key" : ""));
+ }
+ else if (!strcmp (curve, "X448"))
+ {
+ keyparms1 = xtryasprintf
+ ("(genkey(ecc(curve %zu:%s)(flags comp%s)))",
+ strlen (curve), curve,
+ (((*keygen_flags & KEYGEN_FLAG_TRANSIENT_KEY)
+ && (*keygen_flags & KEYGEN_FLAG_NO_PROTECTION))?
+ " transient-key" : ""));
+ }
+ else /* Should we use the compressed format? Check smartcard support. */
+ {
+ keyparms1 = xtryasprintf
+ ("(genkey(ecc(curve %zu:%s)(flags nocomp%s)))",
+ strlen (curve), curve,
+ (((*keygen_flags & KEYGEN_FLAG_TRANSIENT_KEY)
+ && (*keygen_flags & KEYGEN_FLAG_NO_PROTECTION))?
+ " transient-key" : ""));
+ }
+
+ if (!keyparms1)
+ err = gpg_error_from_syserror ();
+ else
+ {
+ err = common_gen (keyparms1, keyparms2, algo, "",
+ pub_root, timestamp, expireval, is_subkey,
+ *keygen_flags, passphrase,
+ cache_nonce_addr, passwd_nonce_addr,
+ common_gen_cb, common_gen_cb_parm);
+ xfree (keyparms1);
+ }
+
+ return err;
+}
+
+
/*
* Generate an RSA key.
*/
@@ -1928,7 +2205,7 @@ gen_rsa (int algo, unsigned int nbits, KBNODE pub_root,
err = gpg_error_from_syserror ();
else
{
- err = common_gen (keyparms, algo, "ne",
+ err = common_gen (keyparms, NULL, algo, "ne",
pub_root, timestamp, expireval, is_subkey,
keygen_flags, passphrase,
cache_nonce_addr, passwd_nonce_addr,
@@ -2350,7 +2627,26 @@ ask_algo (ctrl_t ctrl, int addmode, int *r_subkey_algo, unsigned int *r_usage,
continue;
}
- if (strlen (answer) != 40 &&
+ if (strlen (answer) == 40+1+40 && answer[40]==',')
+ {
+ int algo1, algo2;
+
+ answer[40] = 0;
+ algo1 = check_keygrip (ctrl, answer);
+ algo2 = check_keygrip (ctrl, answer+41);
+ answer[40] = ',';
+ if (algo1 == PUBKEY_ALGO_ECDH && algo2 == PUBKEY_ALGO_KYBER)
+ {
+ algo = PUBKEY_ALGO_KYBER;
+ break;
+ }
+ else if (!algo1 || !algo2)
+ tty_printf (_("No key with this keygrip\n"));
+ else
+ tty_printf ("Invalid combination for dual algo (%d,%d)\n",
+ algo1, algo2);
+ }
+ else if (strlen (answer) != 40 &&
!(answer[0] == '&' && strlen (answer+1) == 40))
tty_printf
(_("Not a valid keygrip (expecting 40 hex digits)\n"));
@@ -2560,6 +2856,12 @@ get_keysize_range (int algo, unsigned int *min, unsigned int *max)
def=255;
break;
+ case PUBKEY_ALGO_KYBER:
+ *min = 768;
+ *max = 1024;
+ def = 768;
+ break;
+
default:
*min = opt.compliance == CO_DE_VS ? 2048: 1024;
*max = 4096;
@@ -2575,45 +2877,44 @@ get_keysize_range (int algo, unsigned int *min, unsigned int *max)
static unsigned int
fixup_keysize (unsigned int nbits, int algo, int silent)
{
+ unsigned int orig_nbits = nbits;
+
if (algo == PUBKEY_ALGO_DSA && (nbits % 64))
{
nbits = ((nbits + 63) / 64) * 64;
- if (!silent)
- tty_printf (_("rounded up to %u bits\n"), nbits);
}
else if (algo == PUBKEY_ALGO_EDDSA)
{
- if (nbits != 255 && nbits != 441)
- {
- if (nbits < 256)
- nbits = 255;
- else
- nbits = 441;
- if (!silent)
- tty_printf (_("rounded to %u bits\n"), nbits);
- }
+ if (nbits < 256)
+ nbits = 255;
+ else
+ nbits = 441;
}
else if (algo == PUBKEY_ALGO_ECDH || algo == PUBKEY_ALGO_ECDSA)
{
- if (nbits != 256 && nbits != 384 && nbits != 521)
- {
- if (nbits < 256)
- nbits = 256;
- else if (nbits < 384)
- nbits = 384;
- else
- nbits = 521;
- if (!silent)
- tty_printf (_("rounded to %u bits\n"), nbits);
- }
+ if (nbits < 256)
+ nbits = 256;
+ else if (nbits < 384)
+ nbits = 384;
+ else
+ nbits = 521;
+ }
+ else if (algo == PUBKEY_ALGO_KYBER)
+ {
+ /* (in reality the numbers are not bits) */
+ if (nbits < 768)
+ nbits = 768;
+ else if (nbits > 1024)
+ nbits = 1024;
}
else if ((nbits % 32))
{
nbits = ((nbits + 31) / 32) * 32;
- if (!silent)
- tty_printf (_("rounded up to %u bits\n"), nbits );
}
+ if (!silent && orig_nbits != nbits)
+ tty_printf (_("rounded to %u bits\n"), nbits);
+
return nbits;
}
@@ -3343,6 +3644,12 @@ do_create (int algo, unsigned int nbits, const char *curve, kbnode_t pub_root,
keygen_flags, passphrase,
cache_nonce_addr, passwd_nonce_addr,
common_gen_cb, common_gen_cb_parm);
+ else if (algo == PUBKEY_ALGO_KYBER)
+ err = gen_kyber (algo, nbits, curve,
+ pub_root, timestamp, expiredate, is_subkey,
+ keygen_flags, passphrase,
+ cache_nonce_addr, passwd_nonce_addr,
+ common_gen_cb, common_gen_cb_parm);
else if (algo == PUBKEY_ALGO_RSA)
err = gen_rsa (algo, nbits, pub_root, timestamp, expiredate, is_subkey,
*keygen_flags, passphrase,
@@ -3421,6 +3728,7 @@ parse_key_parameter_part (ctrl_t ctrl,
char *keygrip = NULL;
u32 keytime = 0;
int is_448 = 0;
+ int is_pqc = 0;
if (!string || !*string)
return 0; /* Success. */
@@ -3446,6 +3754,7 @@ parse_key_parameter_part (ctrl_t ctrl,
; /* We need the flags before we can figure out the key to use. */
else if (algo)
{
+ /* This is one of the algos parsed above (rsa, dsa, or elg). */
if (!string[3])
size = get_keysize_range (algo, NULL, NULL);
else
@@ -3455,6 +3764,63 @@ parse_key_parameter_part (ctrl_t ctrl,
return gpg_error (GPG_ERR_INV_VALUE);
}
}
+ else if (!ascii_strcasecmp (string, "kyber")
+ || !ascii_strcasecmp (string, "kyber768"))
+ {
+ /* Get the curve and check that it can technically be used
+ * (i.e. everything except the EdXXXX curves. */
+ curve = openpgp_is_curve_supported ("brainpoolP256r1", &algo, NULL);
+ if (!curve || algo == PUBKEY_ALGO_EDDSA)
+ return gpg_error (GPG_ERR_UNKNOWN_CURVE);
+ algo = PUBKEY_ALGO_KYBER;
+ size = 768;
+ is_pqc = 1;
+ }
+ else if (!ascii_strcasecmp (string, "kyber1024"))
+ {
+ /* Get the curve and check that it can technically be used
+ * (i.e. everything except the EdXXXX curves. */
+ curve = openpgp_is_curve_supported ("brainpoolP384r1", &algo, NULL);
+ if (!curve || algo == PUBKEY_ALGO_EDDSA)
+ return gpg_error (GPG_ERR_UNKNOWN_CURVE);
+ algo = PUBKEY_ALGO_KYBER;
+ size = 1024;
+ is_pqc = 1;
+ }
+ else if (!ascii_strncasecmp (string, "ky768_", 6)
+ || !ascii_strncasecmp (string, "ky1024_", 7)
+ || !ascii_strncasecmp (string, "kyber768_", 9)
+ || !ascii_strncasecmp (string, "kyber1024_", 10)
+ )
+ {
+ /* Get the curve and check that it can technically be used
+ * (i.e. everything except the EdXXXX curves. */
+ s = strchr (string, '_');
+ log_assert (s);
+ s++;
+ curve = openpgp_is_curve_supported (s, &algo, NULL);
+ if (!curve || algo == PUBKEY_ALGO_EDDSA)
+ return gpg_error (GPG_ERR_UNKNOWN_CURVE);
+ algo = PUBKEY_ALGO_KYBER;
+ size = strstr (string, "768_")? 768 : 1024;
+ is_pqc = 1;
+ }
+ else if (!ascii_strcasecmp (string, "dil3"))
+ {
+ algo = PUBKEY_ALGO_DIL3_25519;
+ is_pqc = 1;
+ }
+ else if (!ascii_strcasecmp (string, "dil5"))
+ {
+ algo = PUBKEY_ALGO_DIL5_448;
+ is_pqc = 1;
+ }
+ else if (!ascii_strcasecmp (string, "sphinx")
+ || !ascii_strcasecmp (string, "sphinx_sha2"))
+ {
+ algo = PUBKEY_ALGO_SPHINX_SHA2;
+ is_pqc = 1;
+ }
else if ((curve = openpgp_is_curve_supported (string, &algo, &size)))
{
if (!algo)
@@ -3703,8 +4069,8 @@ parse_key_parameter_part (ctrl_t ctrl,
return gpg_error (GPG_ERR_WRONG_KEY_USAGE);
}
- /* Ed448 and X448 must only be used as v5 keys. */
- if (is_448)
+ /* Ed448, X448 and the PQC algos must only be used as v5 keys. */
+ if (is_448 || is_pqc)
{
if (keyversion == 4)
log_info (_("WARNING: v4 is specified, but overridden by v5.\n"));
@@ -3768,6 +4134,8 @@ parse_key_parameter_part (ctrl_t ctrl,
* cv25519 := ECDH using curve Curve25519.
* cv448 := ECDH using curve X448.
* nistp256:= ECDSA or ECDH using curve NIST P-256
+ * kyber := Kyber with the default parameters
+ * ky768_bp384 := Kyber-768 with BrainpoolP256r1 as second algo
*
* All strings with an unknown prefix are considered an elliptic
* curve. Curves which have no implicit algorithm require that FLAGS
@@ -5924,9 +6292,12 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
list_keyblock_direct (ctrl, pub_root, 0, 1,
opt.fingerprint || opt.with_fingerprint,
1);
+ /* Note that we ignore errors from the list function
+ * because that would only be an additional info. It
+ * has already been remarked that the key has been
+ * created. */
}
-
if (!opt.batch
&& (get_parameter_algo (ctrl, para,
pKEYTYPE, NULL) == PUBKEY_ALGO_DSA
@@ -6137,6 +6508,8 @@ generate_subkeypair (ctrl_t ctrl, kbnode_t keyblock, const char *algostr,
err = hexkeygrip_from_pk (pri_psk, &hexgrip);
if (err)
goto leave;
+ /* FIXME: Right now the primary key won't be a dual key. But this
+ * will change */
if (agent_get_keyinfo (NULL, hexgrip, &serialno, NULL))
{
if (interactive)
@@ -6476,12 +6849,14 @@ gen_card_key (int keyno, int algo, int is_primary, kbnode_t pub_root,
if (curve_is_448 (s_key))
*keygen_flags |= KEYGEN_FLAG_CREATE_V5_KEY;
+ pk->version = (*keygen_flags & KEYGEN_FLAG_CREATE_V5_KEY)? 5 : 4;
+
if (algo == PUBKEY_ALGO_RSA)
err = key_from_sexp (pk->pkey, s_key, "public-key", "ne");
else if (algo == PUBKEY_ALGO_ECDSA
|| algo == PUBKEY_ALGO_EDDSA
|| algo == PUBKEY_ALGO_ECDH )
- err = ecckey_from_sexp (pk->pkey, s_key, algo);
+ err = ecckey_from_sexp (pk->pkey, s_key, NULL, algo, pk->version);
else
err = gpg_error (GPG_ERR_PUBKEY_ALGO);
gcry_sexp_release (s_key);
@@ -6494,7 +6869,6 @@ gen_card_key (int keyno, int algo, int is_primary, kbnode_t pub_root,
}
pk->timestamp = *timestamp;
- pk->version = (*keygen_flags & KEYGEN_FLAG_CREATE_V5_KEY)? 5 : 4;
if (expireval)
pk->expiredate = pk->timestamp + expireval;
pk->pubkey_algo = algo;
diff --git a/g10/keyid.c b/g10/keyid.c
index fab1e3a36..08f684829 100644
--- a/g10/keyid.c
+++ b/g10/keyid.c
@@ -74,12 +74,18 @@ pubkey_letter( int algo )
is copied to the supplied buffer up a length of BUFSIZE-1.
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".
+ "rsa3072" - RSA with 3072 bit
+ "elg1024" - Elgamal with 1024 bit
+ "ed25519" - EdDSA using the curve Ed25519.
+ "cv25519" - ECDH using the curve X25519.
+ "ky768_cv448 - Kyber-768 with X448 as second algo.
+ "ky1025_bp512 - Kyber-1024 with BrainpoolP256r1 as second algo.
+ "E_1.2.3.4" - ECC using the unsupported curve with OID "1.2.3.4".
+ "unknown_N" - Unknown OpenPGP algorithm N.
"E_1.3.6.1.4.1.11591.2.12242973" ECC with a bogus OID.
- "unknown_N" - Unknown OpenPGP algorithm N.
+
+ Note that with Kyber we use "bp" as abbreviation for BrainpoolP and
+ ignore the final r1 part.
If the option --legacy-list-mode is active, the output use the
legacy format:
@@ -97,6 +103,9 @@ char *
pubkey_string (PKT_public_key *pk, char *buffer, size_t bufsize)
{
const char *prefix = NULL;
+ int dual = 0;
+ char *curve;
+ const char *name;
if (opt.legacy_list_mode)
{
@@ -116,14 +125,34 @@ pubkey_string (PKT_public_key *pk, char *buffer, size_t bufsize)
case PUBKEY_ALGO_ECDH:
case PUBKEY_ALGO_ECDSA:
case PUBKEY_ALGO_EDDSA: prefix = ""; break;
+ case PUBKEY_ALGO_KYBER: prefix = "ky"; dual = 1; break;
+ case PUBKEY_ALGO_DIL3_25519: prefix = "dil3"; break;
+ case PUBKEY_ALGO_DIL5_448: prefix = "dil5"; break;
+ case PUBKEY_ALGO_SPHINX_SHA2: prefix = "sphinx_sha2"; break;
}
+
if (prefix && *prefix)
- snprintf (buffer, bufsize, "%s%u", prefix, nbits_from_pk (pk));
+ {
+ if (dual)
+ {
+ curve = openpgp_oid_to_str (pk->pkey[0]);
+ /* Note that we prefer the abbreviated name of the curve. */
+ name = openpgp_oid_to_curve (curve, 2);
+ if (!name)
+ name = "unknown";
+
+ snprintf (buffer, bufsize, "%s%u_%s",
+ prefix, nbits_from_pk (pk), name);
+ xfree (curve);
+ }
+ else
+ snprintf (buffer, bufsize, "%s%u", prefix, nbits_from_pk (pk));
+ }
else if (prefix)
{
- char *curve = openpgp_oid_to_str (pk->pkey[0]);
- const char *name = openpgp_oid_to_curve (curve, 0);
+ curve = openpgp_oid_to_str (pk->pkey[0]);
+ name = openpgp_oid_to_curve (curve, 0);
if (name)
snprintf (buffer, bufsize, "%s", name);
@@ -303,6 +332,30 @@ do_hash_public_key (gcry_md_hd_t md, PKT_public_key *pk, int use_v5)
pp[i] = NULL;
nn[i] = 0;
}
+ else if (pk->pubkey_algo == PUBKEY_ALGO_KYBER && i == 2)
+ {
+ /* Ugly: We need to re-construct the wire format of the
+ * key parameter. It would be easier to use a second
+ * index for pp and nn which we could bump independet of
+ * i. */
+ const char *p;
+
+ p = gcry_mpi_get_opaque (pk->pkey[i], &nbits);
+ nn[i] = (nbits+7)/8;
+ pp[i] = xmalloc (4 + nn[i] + 1);
+ if (p)
+ {
+ 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;
+ n += nn[i];
+ }
else if (gcry_mpi_get_flag (pk->pkey[i], GCRYMPI_FLAG_OPAQUE))
{
const char *p;
@@ -800,11 +853,28 @@ namehash_from_uid (PKT_user_id *uid)
/*
- * Return the number of bits used in PK.
+ * Return the number of bits used in PK. For Kyber we return the
+ * octet count of the Kyber part and not of the ECC (thus likely
+ * values are 768 or 1024).
*/
unsigned int
nbits_from_pk (PKT_public_key *pk)
{
+ if (pk->pubkey_algo == PUBKEY_ALGO_KYBER)
+ {
+ unsigned int nbits;
+ if (!gcry_mpi_get_opaque (pk->pkey[2], &nbits))
+ return 0;
+ switch (nbits/8)
+ {
+ case 800: nbits = 512; break;
+ case 1184: nbits = 768; break;
+ case 1568: nbits = 1024; break;
+ default: nbits = 0; break; /* Unkown version. */
+ }
+ return nbits;
+ }
+ else
return pubkey_nbits (pk->pubkey_algo, pk->pkey);
}
@@ -1230,16 +1300,22 @@ format_hexfingerprint (const char *fingerprint, char *buffer, size_t buflen)
/* Return the so called KEYGRIP which is the SHA-1 hash of the public
- key parameters expressed as an canonical encoded S-Exp. ARRAY must
- be 20 bytes long. Returns 0 on success or an error code. */
+ * key parameters expressed as an canonical encoded S-Exp. ARRAY must
+ * be 20 bytes long. Returns 0 on success or an error code. If
+ * GET_SECOND Is one and PK has dual algorithm, the keygrip of the
+ * second algorithm is return; GPG_ERR_FALSE is returned if the algo
+ * is not a dual algorithm. */
gpg_error_t
-keygrip_from_pk (PKT_public_key *pk, unsigned char *array)
+keygrip_from_pk (PKT_public_key *pk, unsigned char *array, int get_second)
{
gpg_error_t err;
gcry_sexp_t s_pkey;
if (DBG_PACKET)
- log_debug ("get_keygrip for public key\n");
+ log_debug ("get_keygrip for public key%s\n", get_second?" (second)":"");
+
+ if (get_second && pk->pubkey_algo != PUBKEY_ALGO_KYBER)
+ return gpg_error (GPG_ERR_FALSE);
switch (pk->pubkey_algo)
{
@@ -1287,6 +1363,33 @@ keygrip_from_pk (PKT_public_key *pk, unsigned char *array)
}
break;
+ case PUBKEY_ALGO_KYBER:
+ if (get_second)
+ {
+ char tmpname[15];
+
+ snprintf (tmpname, sizeof tmpname, "kyber%u", nbits_from_pk (pk));
+ err = gcry_sexp_build (&s_pkey, NULL,
+ "(public-key(%s(p%m)))",
+ tmpname, pk->pkey[2]);
+ }
+ else
+ {
+ char *curve = openpgp_oid_to_str (pk->pkey[0]);
+ if (!curve)
+ err = gpg_error_from_syserror ();
+ else
+ {
+ err = gcry_sexp_build (&s_pkey, NULL,
+ openpgp_oid_is_cv25519 (pk->pkey[0])
+ ? "(public-key(ecc(curve%s)(flags djb-tweak)(q%m)))"
+ : "(public-key(ecc(curve%s)(q%m)))",
+ curve, pk->pkey[1]);
+ xfree (curve);
+ }
+ }
+ break;
+
default:
err = gpg_error (GPG_ERR_PUBKEY_ALGO);
break;
@@ -1319,26 +1422,45 @@ keygrip_from_pk (PKT_public_key *pk, unsigned char *array)
/* Store an allocated buffer with the keygrip of PK encoded as a
- hexstring at r_GRIP. Returns 0 on success. */
+ * hexstring at r_GRIP. Returns 0 on success. For dual algorithms
+ * the keygrips are delimited by a comma. */
gpg_error_t
hexkeygrip_from_pk (PKT_public_key *pk, char **r_grip)
{
gpg_error_t err;
+ char *buf;
unsigned char grip[KEYGRIP_LEN];
+ unsigned char grip2[KEYGRIP_LEN];
*r_grip = NULL;
- err = keygrip_from_pk (pk, grip);
+ err = keygrip_from_pk (pk, grip, 0);
if (!err)
{
- char * buf = xtrymalloc (KEYGRIP_LEN * 2 + 1);
- if (!buf)
- err = gpg_error_from_syserror ();
+ if (pk->pubkey_algo == PUBKEY_ALGO_KYBER)
+ {
+ err = keygrip_from_pk (pk, grip2, 1);
+ if (err)
+ goto leave;
+ buf = xtrymalloc (2 * KEYGRIP_LEN * 2 + 1 + 1);
+ }
else
+ buf = xtrymalloc (KEYGRIP_LEN * 2 + 1);
+
+ if (!buf)
+ {
+ err = gpg_error_from_syserror ();
+ goto leave;
+ }
+
+ bin2hex (grip, KEYGRIP_LEN, buf);
+ if (pk->pubkey_algo == PUBKEY_ALGO_KYBER)
{
- bin2hex (grip, KEYGRIP_LEN, buf);
- *r_grip = buf;
+ buf[2*KEYGRIP_LEN] = ',';
+ bin2hex (grip2, KEYGRIP_LEN, buf+2*KEYGRIP_LEN+1);
}
+ *r_grip = buf;
}
+ leave:
return err;
}
diff --git a/g10/keylist.c b/g10/keylist.c
index cc1e23d7f..81d6805a5 100644
--- a/g10/keylist.c
+++ b/g10/keylist.c
@@ -82,7 +82,7 @@ static estream_t attrib_fp;
-static void list_keyblock (ctrl_t ctrl,
+static gpg_error_t list_keyblock (ctrl_t ctrl,
kbnode_t keyblock, int secret, int has_secret,
int fpr, struct keylist_context *listctx);
@@ -745,6 +745,7 @@ list_all (ctrl_t ctrl, int secret, int mark_secret)
int any_secret;
const char *lastresname, *resname;
struct keylist_context listctx;
+ gpg_error_t listerr = 0;
memset (&listctx, 0, sizeof (listctx));
if (opt.check_sigs)
@@ -802,13 +803,13 @@ list_all (ctrl_t ctrl, int secret, int mark_secret)
}
}
merge_keys_and_selfsig (ctrl, keyblock);
- list_keyblock (ctrl, keyblock, secret, any_secret, opt.fingerprint,
- &listctx);
+ listerr = list_keyblock (ctrl, keyblock, secret, any_secret,
+ opt.fingerprint, &listctx);
}
release_kbnode (keyblock);
keyblock = NULL;
}
- while (!(rc = keydb_search_next (hd)));
+ while (!listerr && !(rc = keydb_search_next (hd)));
es_fflush (es_stdout);
if (rc && gpg_err_code (rc) != GPG_ERR_NOT_FOUND)
log_error ("keydb_search_next failed: %s\n", gpg_strerror (rc));
@@ -839,6 +840,7 @@ list_one (ctrl_t ctrl, strlist_t names, int secret, int mark_secret)
const char *keyring_str = _("Keyring");
int i;
struct keylist_context listctx;
+ gpg_error_t listerr = 0;
memset (&listctx, 0, sizeof (listctx));
if (!secret && opt.check_sigs)
@@ -887,12 +889,12 @@ list_one (ctrl_t ctrl, strlist_t names, int secret, int mark_secret)
es_putc ('-', es_stdout);
es_putc ('\n', es_stdout);
}
- list_keyblock (ctrl, keyblock, secret, any_secret,
- opt.fingerprint, &listctx);
+ listerr = list_keyblock (ctrl, keyblock, secret, any_secret,
+ opt.fingerprint, &listctx);
}
release_kbnode (keyblock);
}
- while (!getkey_next (ctrl, ctx, NULL, &keyblock));
+ while (!listerr && !getkey_next (ctrl, ctx, NULL, &keyblock));
getkey_end (ctrl, ctx);
if (opt.check_sigs && !opt.with_colons)
@@ -910,12 +912,13 @@ locate_one (ctrl_t ctrl, strlist_t names, int no_local)
GETKEY_CTX ctx = NULL;
KBNODE keyblock = NULL;
struct keylist_context listctx;
+ gpg_error_t listerr = 0;
memset (&listctx, 0, sizeof (listctx));
if (opt.check_sigs)
listctx.check_sigs = 1;
- for (sl = names; sl; sl = sl->next)
+ for (sl = names; sl && !listerr; sl = sl->next)
{
rc = get_best_pubkey_byname (ctrl,
no_local? GET_PUBKEY_NO_LOCAL
@@ -933,10 +936,11 @@ locate_one (ctrl_t ctrl, strlist_t names, int no_local)
{
do
{
- list_keyblock (ctrl, keyblock, 0, 0, opt.fingerprint, &listctx);
+ listerr = list_keyblock (ctrl, keyblock, 0, 0,
+ opt.fingerprint, &listctx);
release_kbnode (keyblock);
}
- while (ctx && !getkey_next (ctrl, ctx, NULL, &keyblock));
+ while (!listerr && ctx && !getkey_next (ctrl, ctx, NULL, &keyblock));
getkey_end (ctrl, ctx);
ctx = NULL;
}
@@ -1171,6 +1175,77 @@ dump_attribs (const PKT_user_id *uid, PKT_public_key *pk)
}
+static void
+print_keygrip (const char *keygrip)
+{
+ const char *s;
+
+ s = strchr (keygrip, ',');
+ if (s)
+ es_fprintf (es_stdout, " Keygrip = %.*s,\n%*s%s\n",
+ (int)(s-keygrip), keygrip, 16, "", s+1);
+ else
+ es_fprintf (es_stdout, " Keygrip = %s\n", keygrip);
+}
+
+
+/* If PK is given the output is written to a new file instead of
+ * stdout. */
+static void
+print_x509_notations (struct notation *nots, PKT_public_key *pk)
+{
+ gpg_error_t err;
+ gpgrt_b64state_t state = NULL;
+ char hexfpr[2*4 + 1 + 2*MAX_FINGERPRINT_LEN+4+1];
+ char sha1[20];
+ estream_t fp;
+
+ for (; nots; nots = nots->next)
+ {
+ if (pk)
+ {
+ gcry_md_hash_buffer (GCRY_MD_SHA1, sha1, nots->bdat, nots->blen);
+ bin2hex (sha1+16, 4, hexfpr);
+ hexfpr[2*4] = '-';
+ hexfingerprint (pk, hexfpr + 2*4+1, 2*MAX_FINGERPRINT_LEN);
+ strcat (hexfpr, ".pem");
+ fp = es_fopen (hexfpr, "w");
+ if (!fp)
+ {
+ err = gpg_err_code_from_syserror ();
+ goto b64fail;
+ }
+ }
+ else
+ fp = es_stdout;
+ state = gpgrt_b64enc_start (fp, "CERTIFICATE");
+ if (!state)
+ {
+ err = gpg_err_code_from_syserror ();
+ goto b64fail;
+ }
+ err = gpgrt_b64enc_write (state, nots->bdat, nots->blen);
+ if (err)
+ goto b64fail;
+ err = gpgrt_b64enc_finish (state);
+ if (err)
+ goto b64fail;
+ if (fp != es_stdout)
+ {
+ es_fclose (fp);
+ fp = NULL;
+ }
+ }
+ return;
+
+ b64fail:
+ log_error ("error writing base64 encoded notation: %s\n", gpg_strerror (err));
+ gpgrt_b64enc_finish (state);
+ if (fp && fp != es_stdout)
+ gpgrt_fcancel (fp);
+}
+
+
/* Order two signatures. We first order by keyid and then by creation
* time. */
int
@@ -1220,170 +1295,186 @@ cmp_signodes (const void *av, const void *bv)
* NODFLG_MARK_B to indicate self-signatures. */
static void
list_signature_print (ctrl_t ctrl, kbnode_t keyblock, kbnode_t node,
- struct keylist_context *listctx)
+ struct keylist_context *listctx, PKT_public_key *lastpk)
{
- /* (extra indentation to keep the diff history short) */
- PKT_signature *sig = node->pkt->pkt.signature;
- int rc, sigrc;
- char *sigstr;
- char *reason_text = NULL;
- char *reason_comment = NULL;
- size_t reason_commentlen;
- int reason_code = 0;
+ PKT_signature *sig = node->pkt->pkt.signature;
+ int rc, sigrc;
+ char *sigstr;
+ char *reason_text = NULL;
+ char *reason_comment = NULL;
+ size_t reason_commentlen;
+ int reason_code = 0;
+
+ if (listctx->check_sigs)
+ {
+ rc = check_key_signature (ctrl, keyblock, node, NULL);
+ switch (gpg_err_code (rc))
+ {
+ case 0:
+ listctx->good_sigs++;
+ sigrc = '!';
+ break;
+ case GPG_ERR_BAD_SIGNATURE:
+ listctx->inv_sigs++;
+ sigrc = '-';
+ break;
+ case GPG_ERR_NO_PUBKEY:
+ case GPG_ERR_UNUSABLE_PUBKEY:
+ listctx->no_key++;
+ return;
+ case GPG_ERR_DIGEST_ALGO:
+ case GPG_ERR_PUBKEY_ALGO:
+ if (!(opt.list_options & LIST_SHOW_UNUSABLE_SIGS))
+ return;
+ /* fallthru. */
+ default:
+ listctx->oth_err++;
+ sigrc = '%';
+ break;
+ }
- if (listctx->check_sigs)
- {
- rc = check_key_signature (ctrl, keyblock, node, NULL);
- switch (gpg_err_code (rc))
- {
- case 0:
- listctx->good_sigs++;
- sigrc = '!';
- break;
- case GPG_ERR_BAD_SIGNATURE:
- listctx->inv_sigs++;
- sigrc = '-';
- break;
- case GPG_ERR_NO_PUBKEY:
- case GPG_ERR_UNUSABLE_PUBKEY:
- listctx->no_key++;
- return;
- case GPG_ERR_DIGEST_ALGO:
- case GPG_ERR_PUBKEY_ALGO:
- if (!(opt.list_options & LIST_SHOW_UNUSABLE_SIGS))
- return;
- /* fallthru. */
- default:
- listctx->oth_err++;
- sigrc = '%';
- break;
- }
+ /* TODO: Make sure a cached sig record here still has
+ the pk that issued it. See also
+ keyedit.c:print_and_check_one_sig */
+ }
+ else
+ {
+ if (!(opt.list_options & LIST_SHOW_UNUSABLE_SIGS)
+ && (gpg_err_code (openpgp_pk_test_algo (sig->pubkey_algo)
+ == GPG_ERR_PUBKEY_ALGO)
+ || gpg_err_code (openpgp_md_test_algo (sig->digest_algo)
+ == GPG_ERR_DIGEST_ALGO)
+ || (sig->digest_algo == DIGEST_ALGO_SHA1
+ && !(node->flag & NODFLG_MARK_B) /*no selfsig*/
+ && !opt.flags.allow_weak_key_signatures)))
+ return;
+ rc = 0;
+ sigrc = ' ';
+ }
- /* TODO: Make sure a cached sig record here still has
- the pk that issued it. See also
- keyedit.c:print_and_check_one_sig */
- }
- else
- {
- if (!(opt.list_options & LIST_SHOW_UNUSABLE_SIGS)
- && (gpg_err_code (openpgp_pk_test_algo (sig->pubkey_algo)
- == GPG_ERR_PUBKEY_ALGO)
- || gpg_err_code (openpgp_md_test_algo (sig->digest_algo)
- == GPG_ERR_DIGEST_ALGO)
- || (sig->digest_algo == DIGEST_ALGO_SHA1
- && !(node->flag & NODFLG_MARK_B) /*no selfsig*/
- && !opt.flags.allow_weak_key_signatures)))
- return;
- rc = 0;
- sigrc = ' ';
- }
+ if (IS_KEY_REV (sig) || IS_SUBKEY_REV (sig) || IS_UID_REV (sig))
+ {
+ sigstr = "rev";
+ reason_code = get_revocation_reason (sig, &reason_text,
+ &reason_comment,
+ &reason_commentlen);
+ }
+ else if (IS_UID_SIG (sig))
+ sigstr = "sig";
+ else if (IS_SUBKEY_SIG (sig))
+ sigstr = "sig";
+ else if (IS_KEY_SIG (sig))
+ sigstr = "sig";
+ else
+ {
+ es_fprintf (es_stdout, "sig "
+ "[unexpected signature class 0x%02x]\n",
+ sig->sig_class);
+ return;
+ }
- if (sig->sig_class == 0x20 || sig->sig_class == 0x28
- || sig->sig_class == 0x30)
- {
- sigstr = "rev";
- reason_code = get_revocation_reason (sig, &reason_text,
- &reason_comment,
- &reason_commentlen);
- }
- else if ((sig->sig_class & ~3) == 0x10)
- sigstr = "sig";
- else if (sig->sig_class == 0x18)
- sigstr = "sig";
- else if (sig->sig_class == 0x1F)
- sigstr = "sig";
- else
- {
- es_fprintf (es_stdout, "sig "
- "[unexpected signature class 0x%02x]\n",
- sig->sig_class);
- return;
- }
+ es_fputs (sigstr, es_stdout);
+ es_fprintf (es_stdout, "%c%c %c%c%c%c%c%c %s %s",
+ sigrc, (sig->sig_class - 0x10 > 0 &&
+ sig->sig_class - 0x10 <
+ 4) ? '0' + sig->sig_class - 0x10 : ' ',
+ sig->flags.exportable ? ' ' : 'L',
+ sig->flags.revocable ? ' ' : 'R',
+ sig->flags.policy_url ? 'P' : ' ',
+ sig->flags.notation ? 'N' : ' ',
+ sig->flags.expired ? 'X' : ' ',
+ (sig->trust_depth > 9) ? 'T' : (sig->trust_depth >
+ 0) ? '0' +
+ sig->trust_depth : ' ', keystr (sig->keyid),
+ datestr_from_sig (sig));
+ if (opt.list_options & LIST_SHOW_SIG_EXPIRE)
+ es_fprintf (es_stdout, " %s", expirestr_from_sig (sig));
+ es_fprintf (es_stdout, " ");
+ if (sigrc == '%')
+ es_fprintf (es_stdout, "[%s] ", gpg_strerror (rc));
+ else if (sigrc == '?')
+ ;
+ else if ((node->flag & NODFLG_MARK_B))
+ es_fputs (_("[self-signature]"), es_stdout);
+ else if (!opt.fast_list_mode )
+ {
+ size_t n;
+ char *p = get_user_id (ctrl, sig->keyid, &n, NULL);
+ print_utf8_buffer (es_stdout, p, n);
+ xfree (p);
+ }
+ es_putc ('\n', es_stdout);
- es_fputs (sigstr, es_stdout);
- es_fprintf (es_stdout, "%c%c %c%c%c%c%c%c %s %s",
- sigrc, (sig->sig_class - 0x10 > 0 &&
- sig->sig_class - 0x10 <
- 4) ? '0' + sig->sig_class - 0x10 : ' ',
- sig->flags.exportable ? ' ' : 'L',
- sig->flags.revocable ? ' ' : 'R',
- sig->flags.policy_url ? 'P' : ' ',
- sig->flags.notation ? 'N' : ' ',
- sig->flags.expired ? 'X' : ' ',
- (sig->trust_depth > 9) ? 'T' : (sig->trust_depth >
- 0) ? '0' +
- sig->trust_depth : ' ', keystr (sig->keyid),
- datestr_from_sig (sig));
- if (opt.list_options & LIST_SHOW_SIG_EXPIRE)
- es_fprintf (es_stdout, " %s", expirestr_from_sig (sig));
- es_fprintf (es_stdout, " ");
- if (sigrc == '%')
- es_fprintf (es_stdout, "[%s] ", gpg_strerror (rc));
- else if (sigrc == '?')
- ;
- else if ((node->flag & NODFLG_MARK_B))
- es_fputs (_("[self-signature]"), es_stdout);
- else if (!opt.fast_list_mode )
- {
- size_t n;
- char *p = get_user_id (ctrl, sig->keyid, &n, NULL);
- print_utf8_buffer (es_stdout, p, n);
- xfree (p);
- }
- es_putc ('\n', es_stdout);
+ if (sig->flags.policy_url
+ && (opt.list_options & LIST_SHOW_POLICY_URLS))
+ show_policy_url (sig, 3, 0);
+
+ if (sig->flags.notation && (opt.list_options & LIST_SHOW_NOTATIONS))
+ show_notation (sig, 3, 0,
+ ((opt.
+ list_options & LIST_SHOW_STD_NOTATIONS) ? 1 : 0)
+ +
+ ((opt.
+ list_options & LIST_SHOW_USER_NOTATIONS) ? 2 :
+ 0));
+
+ if (sig->flags.notation
+ && (opt.list_options
+ & (LIST_SHOW_X509_NOTATIONS|LIST_STORE_X509_NOTATIONS)))
+ {
+ struct notation *nots;
- if (sig->flags.policy_url
- && (opt.list_options & LIST_SHOW_POLICY_URLS))
- show_policy_url (sig, 3, 0);
+ if ((IS_KEY_SIG (sig) || IS_SUBKEY_SIG (sig))
+ && (nots = search_sig_notations (sig,
+ {
+ if ((opt.list_options & LIST_STORE_X509_NOTATIONS))
+ print_x509_notations (nots, lastpk);
+ else
+ print_x509_notations (nots, NULL);
+ free_notation (nots);
+ }
+ }
- if (sig->flags.notation && (opt.list_options & LIST_SHOW_NOTATIONS))
- show_notation (sig, 3, 0,
- ((opt.
- list_options & LIST_SHOW_STD_NOTATIONS) ? 1 : 0)
- +
- ((opt.
- list_options & LIST_SHOW_USER_NOTATIONS) ? 2 :
- 0));
+ if (sig->flags.pref_ks
+ && (opt.list_options & LIST_SHOW_KEYSERVER_URLS))
+ show_keyserver_url (sig, 3, 0);
- if (sig->flags.pref_ks
- && (opt.list_options & LIST_SHOW_KEYSERVER_URLS))
- show_keyserver_url (sig, 3, 0);
+ if (reason_text && (reason_code || reason_comment))
+ {
+ es_fprintf (es_stdout, " %s%s\n",
+ _("reason for revocation: "), reason_text);
+ if (reason_comment)
+ {
+ const byte *s, *s_lf;
+ size_t n, n_lf;
- if (reason_text && (reason_code || reason_comment))
+ s = reason_comment;
+ n = reason_commentlen;
+ s_lf = NULL;
+ do
{
- es_fprintf (es_stdout, " %s%s\n",
- _("reason for revocation: "), reason_text);
- if (reason_comment)
+ /* We don't want any empty lines, so we skip them. */
+ for (;n && *s == '\n'; s++, n--)
+ ;
+ if (n)
{
- const byte *s, *s_lf;
- size_t n, n_lf;
-
- s = reason_comment;
- n = reason_commentlen;
- s_lf = NULL;
- do
- {
- /* We don't want any empty lines, so we skip them. */
- for (;n && *s == '\n'; s++, n--)
- ;
- if (n)
- {
- s_lf = memchr (s, '\n', n);
- n_lf = s_lf? s_lf - s : n;
- es_fprintf (es_stdout, " %s",
- _("revocation comment: "));
- es_write_sanitized (es_stdout, s, n_lf, NULL, NULL);
- es_putc ('\n', es_stdout);
- s += n_lf; n -= n_lf;
- }
- } while (s_lf);
+ s_lf = memchr (s, '\n', n);
+ n_lf = s_lf? s_lf - s : n;
+ es_fprintf (es_stdout, " %s",
+ _("revocation comment: "));
+ es_write_sanitized (es_stdout, s, n_lf, NULL, NULL);
+ es_putc ('\n', es_stdout);
+ s += n_lf; n -= n_lf;
}
- }
+ } while (s_lf);
+ }
+ }
- xfree (reason_text);
- xfree (reason_comment);
+ xfree (reason_text);
+ xfree (reason_comment);
- /* fixme: check or list other sigs here */
+ /* fixme: check or list other sigs here */
}
@@ -1394,6 +1485,7 @@ list_keyblock_print (ctrl_t ctrl, kbnode_t keyblock, int secret, int fpr,
int rc;
kbnode_t node;
PKT_public_key *pk;
+ PKT_public_key *lastpk;
u32 *mainkid;
int skip_sigs = 0;
char *hexgrip = NULL;
@@ -1410,6 +1502,7 @@ list_keyblock_print (ctrl_t ctrl, kbnode_t keyblock, int secret, int fpr,
pk = node->pkt->pkt.public_key;
mainkid = pk_keyid (pk);
+ lastpk = pk;
if (secret || opt.with_keygrip)
{
@@ -1437,7 +1530,7 @@ list_keyblock_print (ctrl_t ctrl, kbnode_t keyblock, int secret, int fpr,
print_fingerprint (ctrl, NULL, pk, 0);
if (opt.with_keygrip && hexgrip)
- es_fprintf (es_stdout, " Keygrip = %s\n", hexgrip);
+ print_keygrip (hexgrip);
if (serialno)
print_card_serialno (serialno);
@@ -1558,6 +1651,7 @@ list_keyblock_print (ctrl_t ctrl, kbnode_t keyblock, int secret, int fpr,
{
PKT_public_key *pk2 = node->pkt->pkt.public_key;
+ lastpk = pk2;
if ((pk2->flags.revoked || pk2->has_expired)
&& !(opt.list_options & LIST_SHOW_UNUSABLE_SUBKEYS))
{
@@ -1593,13 +1687,15 @@ list_keyblock_print (ctrl_t ctrl, kbnode_t keyblock, int secret, int fpr,
print_card_serialno (serialno);
}
if (opt.with_keygrip && hexgrip)
- es_fprintf (es_stdout, " Keygrip = %s\n", hexgrip);
+ print_keygrip (hexgrip);
if (opt.with_key_data)
print_key_data (pk2);
if (opt.with_key_screening)
print_pk_screening (pk2, 0);
}
- else if (opt.list_sigs
+ else if ((opt.list_sigs
+ || (opt.list_options
+ & (LIST_SHOW_X509_NOTATIONS|LIST_STORE_X509_NOTATIONS)))
&& node->pkt->pkttype == PKT_SIGNATURE && !skip_sigs)
{
kbnode_t n;
@@ -1627,7 +1723,8 @@ list_keyblock_print (ctrl_t ctrl, kbnode_t keyblock, int secret, int fpr,
qsort (sigarray, sigcount, sizeof *sigarray, cmp_signodes);
for (idx=0; idx < sigcount; idx++)
- list_signature_print (ctrl, keyblock, sigarray[idx], listctx);
+ list_signature_print (ctrl, keyblock, sigarray[idx], listctx,
+ lastpk);
xfree (sigarray);
}
}
@@ -2232,11 +2329,18 @@ reorder_keyblock (KBNODE keyblock)
}
-static void
+/* Note: If this function returns an error the caller is expected to
+ * honor this and stop all further processing. Any error returned
+ * will be a write error (to stdout) and a diagnostics is always
+ * printed using log_error. */
+static gpg_error_t
list_keyblock (ctrl_t ctrl,
KBNODE keyblock, int secret, int has_secret, int fpr,
struct keylist_context *listctx)
{
+ gpg_error_t err = 0;
+
+ es_clearerr (es_stdout);
reorder_keyblock (keyblock);
if (list_filter.selkey)
@@ -2254,7 +2358,7 @@ list_keyblock (ctrl_t ctrl,
}
}
if (!selected)
- return; /* Skip this one. */
+ return 0; /* Skip this one. */
}
if (opt.with_colons)
@@ -2268,24 +2372,34 @@ list_keyblock (ctrl_t ctrl,
else
list_keyblock_print (ctrl, keyblock, secret, fpr, listctx);
- if (secret)
- es_fflush (es_stdout);
+ if (es_ferror (es_stdout))
+ err = gpg_error_from_syserror ();
+
+ if (secret && es_fflush (es_stdout) && !err)
+ err = gpg_error_from_syserror ();
+
+ if (err)
+ log_error (_("error writing to stdout: %s\n"), gpg_strerror (err));
+
+ return err;
}
/* Public function used by keygen to list a keyblock. If NO_VALIDITY
* is set the validity of a key is never shown. */
-void
+gpg_error_t
list_keyblock_direct (ctrl_t ctrl,
kbnode_t keyblock, int secret, int has_secret, int fpr,
int no_validity)
{
struct keylist_context listctx;
+ gpg_error_t err;
memset (&listctx, 0, sizeof (listctx));
listctx.no_validity = !!no_validity;
- list_keyblock (ctrl, keyblock, secret, has_secret, fpr, &listctx);
+ err = list_keyblock (ctrl, keyblock, secret, has_secret, fpr, &listctx);
keylist_context_release (&listctx);
+ return err;
}
diff --git a/g10/keyring.c b/g10/keyring.c
index baddf5d54..0fe8bcd9c 100644
--- a/g10/keyring.c
+++ b/g10/keyring.c
@@ -1148,7 +1148,7 @@ keyring_search (KEYRING_HANDLE hd, KEYDB_SEARCH_DESC *desc,
if (need_keyid)
keyid_from_pk (pk, aki);
if (need_grip)
- keygrip_from_pk (pk, grip);
+ keygrip_from_pk (pk, grip, 0);
if (use_key_present_hash
&& !key_present_hash_ready
diff --git a/g10/main.h b/g10/main.h
index 2482fbde2..2443aa7fe 100644
--- a/g10/main.h
+++ b/g10/main.h
@@ -108,7 +108,7 @@ char *make_radix64_string( const byte *data, size_t len );
void trap_unaligned(void);
void register_secured_file (const char *fname);
void unregister_secured_file (const char *fname);
-int is_secured_file (int fd);
+int is_secured_file (gnupg_fd_t fd);
int is_secured_filename (const char *fname);
u16 checksum_u16( unsigned n );
u16 checksum( const byte *p, unsigned n );
@@ -243,9 +243,9 @@ aead_algo_t use_aead (pk_list_t pk_list, int algo);
int use_mdc (pk_list_t pk_list,int algo);
int encrypt_symmetric (const char *filename );
int encrypt_store (const char *filename );
-int encrypt_crypt (ctrl_t ctrl, int filefd, const char *filename,
+int encrypt_crypt (ctrl_t ctrl, gnupg_fd_t filefd, const char *filename,
strlist_t remusr, int use_symkey, pk_list_t provided_keys,
- int outputfd);
+ gnupg_fd_t outputfd);
void encrypt_crypt_files (ctrl_t ctrl,
int nfiles, char **files, strlist_t remusr);
int encrypt_filter (void *opaque, int control,
@@ -341,7 +341,7 @@ gpg_error_t generate_card_subkeypair (ctrl_t ctrl, kbnode_t pub_keyblock,
int overwrite_filep( const char *fname );
char *make_outfile_name( const char *iname );
char *ask_outfile_name( const char *name, size_t namelen );
-int open_outfile (int out_fd, const char *iname, int mode,
+int open_outfile (gnupg_fd_t out_fd, const char *iname, int mode,
int restrictedperm, iobuf_t *a);
char *get_matching_datafile (const char *sigfilename);
iobuf_t open_sigfile (const char *sigfilename, progress_filter_context_t *pfx);
@@ -470,8 +470,8 @@ void secret_key_list (ctrl_t ctrl, strlist_t list );
gpg_error_t parse_and_set_list_filter (const char *string);
void print_subpackets_colon(PKT_signature *sig);
void reorder_keyblock (KBNODE keyblock);
-void list_keyblock_direct (ctrl_t ctrl, kbnode_t keyblock, int secret,
- int has_secret, int fpr, int no_validity);
+gpg_error_t list_keyblock_direct (ctrl_t ctrl, kbnode_t keyblock, int secret,
+ int has_secret, int fpr, int no_validity);
int cmp_signodes (const void *av, const void *bv);
void print_fingerprint (ctrl_t ctrl, estream_t fp,
PKT_public_key *pk, int mode);
@@ -493,20 +493,22 @@ void print_key_line (ctrl_t ctrl, estream_t fp, PKT_public_key *pk, int secret);
void print_file_status( int status, const char *name, int what );
int verify_signatures (ctrl_t ctrl, int nfiles, char **files );
int verify_files (ctrl_t ctrl, int nfiles, char **files );
-int gpg_verify (ctrl_t ctrl, int sig_fd, int data_fd, estream_t out_fp);
+int gpg_verify (ctrl_t ctrl, gnupg_fd_t sig_fd, gnupg_fd_t data_fd,
+ estream_t out_fp);
void check_assert_signer_list (const char *mainpkhex, const char *pkhex);
void check_assert_pubkey_algo (const char *algostr, const char *pkhex);
/*-- decrypt.c --*/
int decrypt_message (ctrl_t ctrl, const char *filename );
-gpg_error_t decrypt_message_fd (ctrl_t ctrl, int input_fd, int output_fd);
+gpg_error_t decrypt_message_fd (ctrl_t ctrl, gnupg_fd_t input_fd,
+ gnupg_fd_t output_fd);
void decrypt_messages (ctrl_t ctrl, int nfiles, char *files[]);
/*-- plaintext.c --*/
int hash_datafiles( gcry_md_hd_t md, gcry_md_hd_t md2,
strlist_t files, const char *sigfilename, int textmode);
-int hash_datafile_by_fd ( gcry_md_hd_t md, gcry_md_hd_t md2, int data_fd,
- int textmode );
+int hash_datafile_by_fd (gcry_md_hd_t md, gcry_md_hd_t md2,
+ gnupg_fd_t data_fd, int textmode);
PKT_plaintext *setup_plaintext_name(const char *filename,IOBUF iobuf);
/*-- server.c --*/
diff --git a/g10/mainproc.c b/g10/mainproc.c
index e722618ca..91ababbb6 100644
--- a/g10/mainproc.c
+++ b/g10/mainproc.c
@@ -81,7 +81,7 @@ struct mainproc_context
struct
{
/* A file descriptor of the signed data. Only used if not -1. */
- int data_fd;
+ gnupg_fd_t data_fd;
/* A list of filenames with the data files or NULL. This is only
used if DATA_FD is -1. */
strlist_t data_names;
@@ -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,14 @@ 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->seskey_algo = enc->seskey_algo;
+ 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;
@@ -573,6 +578,10 @@ print_pkenc_list (ctrl_t ctrl, struct pubkey_enc_list *list)
openpgp_pk_algo_name (list->pubkey_algo),
keystr(list->keyid));
+ if (opt.flags.require_pqc_encryption
+ && pk->pubkey_algo != PUBKEY_ALGO_KYBER)
+ log_info (_("WARNING: key is not quantum-resistant\n"));
+
free_public_key (pk);
}
}
@@ -1097,7 +1106,7 @@ static int
proc_compressed_cb (iobuf_t a, void *info)
{
if ( ((CTX)info)->signed_data.used
- && ((CTX)info)->signed_data.data_fd != -1)
+ && ((CTX)info)->signed_data.data_fd != GNUPG_INVALID_FD)
return proc_signature_packets_by_fd (((CTX)info)->ctrl, info, a,
((CTX)info)->signed_data.data_fd);
else
@@ -1519,7 +1528,7 @@ proc_signature_packets (ctrl_t ctrl, void *anchor, iobuf_t a,
c->anchor = anchor;
c->sigs_only = 1;
- c->signed_data.data_fd = -1;
+ c->signed_data.data_fd = GNUPG_INVALID_FD;
c->signed_data.data_names = signedfiles;
c->signed_data.used = !!signedfiles;
@@ -1549,8 +1558,8 @@ proc_signature_packets (ctrl_t ctrl, void *anchor, iobuf_t a,
int
-proc_signature_packets_by_fd (ctrl_t ctrl,
- void *anchor, iobuf_t a, int signed_data_fd )
+proc_signature_packets_by_fd (ctrl_t ctrl, void *anchor, iobuf_t a,
+ gnupg_fd_t signed_data_fd)
{
int rc;
CTX c;
@@ -1565,7 +1574,7 @@ proc_signature_packets_by_fd (ctrl_t ctrl,
c->signed_data.data_fd = signed_data_fd;
c->signed_data.data_names = NULL;
- c->signed_data.used = (signed_data_fd != -1);
+ c->signed_data.used = (signed_data_fd != GNUPG_INVALID_FD);
rc = do_proc_packets (c, a);
@@ -2549,8 +2558,6 @@ check_sig_and_print (CTX c, kbnode_t node)
release_kbnode( keyblock );
if (rc)
g10_errors_seen = 1;
- if (opt.batch && rc)
- g10_exit (1);
}
else /* Error checking the signature. (neither Good nor Bad). */
{
@@ -2636,7 +2643,8 @@ proc_tree (CTX c, kbnode_t node)
/* Ask for file and hash it. */
if (c->sigs_only)
{
- if (c->signed_data.used && c->signed_data.data_fd != -1)
+ if (c->signed_data.used
+ && c->signed_data.data_fd != GNUPG_INVALID_FD)
rc = hash_datafile_by_fd (c->mfx.md, NULL,
c->signed_data.data_fd,
use_textmode);
@@ -2667,7 +2675,8 @@ proc_tree (CTX c, kbnode_t node)
}
for (n1 = node; (n1 = find_next_kbnode (n1, PKT_SIGNATURE));)
- check_sig_and_print (c, n1);
+ if (check_sig_and_print (c, n1) && opt.batch)
+ break;
}
else if (node->pkt->pkttype == PKT_GPG_CONTROL
@@ -2686,8 +2695,8 @@ proc_tree (CTX c, kbnode_t node)
}
for (n1 = node; (n1 = find_next_kbnode (n1, PKT_SIGNATURE));)
- check_sig_and_print (c, n1);
-
+ if (check_sig_and_print (c, n1) && opt.batch)
+ break;
}
else if (node->pkt->pkttype == PKT_SIGNATURE)
{
@@ -2779,7 +2788,8 @@ proc_tree (CTX c, kbnode_t node)
if (c->sigs_only)
{
- if (c->signed_data.used && c->signed_data.data_fd != -1)
+ if (c->signed_data.used
+ && c->signed_data.data_fd != GNUPG_INVALID_FD)
rc = hash_datafile_by_fd (c->mfx.md, c->mfx.md2,
c->signed_data.data_fd,
(sig->sig_class == 0x01));
@@ -2814,7 +2824,8 @@ proc_tree (CTX c, kbnode_t node)
if (multiple_ok)
{
for (n1 = node; n1; (n1 = find_next_kbnode(n1, PKT_SIGNATURE)))
- check_sig_and_print (c, n1);
+ if (check_sig_and_print (c, n1) && opt.batch)
+ break;
}
else
check_sig_and_print (c, node);
diff --git a/g10/mdfilter.c b/g10/mdfilter.c
index f3318f15c..a655d6d72 100644
--- a/g10/mdfilter.c
+++ b/g10/mdfilter.c
@@ -22,6 +22,7 @@
#include <stdlib.h>
#include <string.h>
#include <errno.h>
+#include <npth.h>
#include "gpg.h"
#include "../common/status.h"
@@ -71,3 +72,297 @@ free_md_filter_context( md_filter_context_t *mfx )
mfx->md2 = NULL;
mfx->maxbuf_size = 0;
}
+
+
+/****************
+ * Threaded implementation for hashing.
+ */
+
+struct md_thd_filter_context {
+ gcry_md_hd_t md;
+ npth_t thd;
+ /**/
+ npth_mutex_t mutex;
+ npth_cond_t cond;
+ size_t bufsize;
+ unsigned int produce : 1;
+ unsigned int consume : 1;
+ ssize_t written0;
+ ssize_t written1;
+ unsigned char buf[1];
+};
+
+
+static void
+lock_md (struct md_thd_filter_context *mfx)
+{
+ int rc = npth_mutex_lock (&mfx->mutex);
+ if (rc)
+ log_fatal ("%s: failed to acquire mutex: %s\n", __func__,
+ gpg_strerror (gpg_error_from_errno (rc)));
+}
+
+
+static void
+unlock_md (struct md_thd_filter_context * mfx)
+{
+ int rc = npth_mutex_unlock (&mfx->mutex);
+ if (rc)
+ log_fatal ("%s: failed to release mutex: %s\n", __func__,
+ gpg_strerror (gpg_error_from_errno (rc)));
+}
+
+static int
+get_buffer_to_hash (struct md_thd_filter_context *mfx,
+ unsigned char **r_buf, size_t *r_len)
+{
+ int rc = 0;
+
+ lock_md (mfx);
+
+ if ((mfx->consume == 0 && mfx->written0 < 0)
+ || (mfx->consume != 0 && mfx->written1 < 0))
+ {
+ rc = npth_cond_wait (&mfx->cond, &mfx->mutex);
+ if (rc)
+ {
+ unlock_md (mfx);
+ return -1;
+ }
+ }
+
+ if (mfx->consume == 0)
+ {
+ *r_buf = mfx->buf;
+ *r_len = mfx->written0;
+ }
+ else
+ {
+ *r_buf = mfx->buf + mfx->bufsize;
+ *r_len = mfx->written1;
+ }
+
+ unlock_md (mfx);
+
+ return 0;
+}
+
+static int
+put_buffer_to_recv (struct md_thd_filter_context *mfx)
+{
+ int rc = 0;
+
+ lock_md (mfx);
+ if (mfx->consume == 0)
+ {
+ mfx->written0 = -1;
+ mfx->consume = 1;
+ }
+ else
+ {
+ mfx->written1 = -1;
+ mfx->consume = 0;
+ }
+
+ rc = npth_cond_signal (&mfx->cond);
+ if (rc)
+ {
+ unlock_md (mfx);
+ return -1;
+ }
+
+ unlock_md (mfx);
+ return 0;
+}
+
+static int
+get_buffer_to_fill (struct md_thd_filter_context *mfx,
+ unsigned char **r_buf, size_t len)
+{
+ lock_md (mfx);
+
+ if (len > mfx->bufsize)
+ {
+ unlock_md (mfx);
+ return GPG_ERR_BUFFER_TOO_SHORT;
+ }
+
+ if ((mfx->produce == 0 && mfx->written0 >= 0)
+ || (mfx->produce != 0 && mfx->written1 >= 0))
+ {
+ int rc = npth_cond_wait (&mfx->cond, &mfx->mutex);
+ if (rc)
+ {
+ unlock_md (mfx);
+ return gpg_error_from_errno (rc);
+ }
+ }
+
+ if (mfx->produce == 0)
+ *r_buf = mfx->buf;
+ else
+ *r_buf = mfx->buf + mfx->bufsize;
+ unlock_md (mfx);
+ return 0;
+}
+
+static int
+put_buffer_to_send (struct md_thd_filter_context *mfx, size_t len)
+{
+ int rc;
+
+ lock_md (mfx);
+ if (mfx->produce == 0)
+ {
+ mfx->written0 = len;
+ mfx->produce = 1;
+ }
+ else
+ {
+ mfx->written1 = len;
+ mfx->produce = 0;
+ }
+
+ rc = npth_cond_signal (&mfx->cond);
+ if (rc)
+ {
+ unlock_md (mfx);
+ return gpg_error_from_errno (rc);
+ }
+
+ unlock_md (mfx);
+
+ /* Yield to the md_thread to let it compute the hash in parallel */
+ npth_usleep (0);
+ return 0;
+}
+
+
+static void *
+md_thread (void *arg)
+{
+ struct md_thd_filter_context *mfx = arg;
+
+ while (1)
+ {
+ unsigned char *buf;
+ size_t len;
+
+ if (get_buffer_to_hash (mfx, &buf, &len) < 0)
+ /* Error */
+ return NULL;
+
+ if (len == 0)
+ break;
+
+ npth_unprotect ();
+ gcry_md_write (mfx->md, buf, len);
+ npth_protect ();
+
+ if (put_buffer_to_recv (mfx) < 0)
+ /* Error */
+ return NULL;
+ }
+
+ return NULL;
+}
+
+int
+md_thd_filter (void *opaque, int control,
+ IOBUF a, byte *buf, size_t *ret_len)
+{
+ size_t size = *ret_len;
+ struct md_thd_filter_context **r_mfx = opaque;
+ struct md_thd_filter_context *mfx = *r_mfx;
+ int rc=0;
+
+ if (control == IOBUFCTRL_INIT)
+ {
+ npth_attr_t tattr;
+ size_t n;
+
+ n = 2 * iobuf_set_buffer_size (0) * 1024;
+ mfx = xtrymalloc (n + offsetof (struct md_thd_filter_context, buf));
+ if (!mfx)
+ return gpg_error_from_syserror ();
+ *r_mfx = mfx;
+ mfx->bufsize = n / 2;
+ mfx->consume = mfx->produce = 0;
+ mfx->written0 = -1;
+ mfx->written1 = -1;
+
+ rc = npth_mutex_init (&mfx->mutex, NULL);
+ if (rc)
+ {
+ return gpg_error_from_errno (rc);
+ }
+ rc = npth_cond_init (&mfx->cond, NULL);
+ if (rc)
+ {
+ npth_mutex_destroy (&mfx->mutex);
+ return gpg_error_from_errno (rc);
+ }
+ rc = npth_attr_init (&tattr);
+ if (rc)
+ {
+ npth_cond_destroy (&mfx->cond);
+ npth_mutex_destroy (&mfx->mutex);
+ return gpg_error_from_errno (rc);
+ }
+ npth_attr_setdetachstate (&tattr, NPTH_CREATE_JOINABLE);
+ rc = npth_create (&mfx->thd, &tattr, md_thread, mfx);
+ if (rc)
+ {
+ npth_cond_destroy (&mfx->cond);
+ npth_mutex_destroy (&mfx->mutex);
+ npth_attr_destroy (&tattr);
+ return gpg_error_from_errno (rc);
+ }
+ npth_attr_destroy (&tattr);
+ }
+ else if (control == IOBUFCTRL_UNDERFLOW)
+ {
+ int i;
+ unsigned char *md_buf = NULL;
+
+ i = iobuf_read (a, buf, size);
+ if (i == -1)
+ i = 0;
+
+ rc = get_buffer_to_fill (mfx, &md_buf, i);
+ if (rc)
+ return rc;
+
+ if (i)
+ memcpy (md_buf, buf, i);
+
+ rc = put_buffer_to_send (mfx, i);
+ if (rc)
+ return rc;
+
+ if (i == 0)
+ {
+ npth_join (mfx->thd, NULL);
+ rc = -1; /* eof */
+ }
+
+ *ret_len = i;
+ }
+ else if (control == IOBUFCTRL_FREE)
+ {
+ npth_cond_destroy (&mfx->cond);
+ npth_mutex_destroy (&mfx->mutex);
+ xfree (mfx);
+ *r_mfx = NULL;
+ }
+ else if (control == IOBUFCTRL_DESC)
+ mem2str (buf, "md_thd_filter", *ret_len);
+
+ return rc;
+}
+
+void
+md_thd_filter_set_md (struct md_thd_filter_context *mfx, gcry_md_hd_t md)
+{
+ mfx->md = md;
+}
diff --git a/g10/misc.c b/g10/misc.c
index 2f4b452dd..c52091830 100644
--- a/g10/misc.c
+++ b/g10/misc.c
@@ -160,7 +160,7 @@ unregister_secured_file (const char *fname)
/* Return true if FD is corresponds to a secured file. Using -1 for
FS is allowed and will return false. */
int
-is_secured_file (int fd)
+is_secured_file (gnupg_fd_t fd)
{
#ifdef ENABLE_SELINUX_HACKS
struct stat buf;
@@ -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;
}
@@ -799,6 +801,18 @@ openpgp_pk_algo_usage ( int algo )
case PUBKEY_ALGO_ECDSA:
case PUBKEY_ALGO_EDDSA:
use = PUBKEY_USAGE_CERT | PUBKEY_USAGE_SIG | PUBKEY_USAGE_AUTH;
+ break;
+
+ case PUBKEY_ALGO_KYBER:
+ use = PUBKEY_USAGE_ENC | PUBKEY_USAGE_RENC;
+ break;
+
+ case PUBKEY_ALGO_DIL3_25519:
+ case PUBKEY_ALGO_DIL5_448:
+ case PUBKEY_ALGO_SPHINX_SHA2:
+ use = PUBKEY_USAGE_CERT | PUBKEY_USAGE_SIG;
+ break;
+
default:
break;
}
@@ -822,6 +836,7 @@ openpgp_pk_algo_name (pubkey_algo_t algo)
case PUBKEY_ALGO_ECDH: return "ECDH";
case PUBKEY_ALGO_ECDSA: return "ECDSA";
case PUBKEY_ALGO_EDDSA: return "EDDSA";
+ case PUBKEY_ALGO_KYBER: return "Kyber";
default: return "?";
}
}
@@ -1711,6 +1726,7 @@ pubkey_get_npkey (pubkey_algo_t algo)
case PUBKEY_ALGO_ECDSA: return 2;
case PUBKEY_ALGO_ELGAMAL: return 3;
case PUBKEY_ALGO_EDDSA: return 2;
+ case PUBKEY_ALGO_KYBER: return 3;
default: return 0;
}
}
@@ -1731,6 +1747,7 @@ pubkey_get_nskey (pubkey_algo_t algo)
case PUBKEY_ALGO_ECDSA: return 3;
case PUBKEY_ALGO_ELGAMAL: return 4;
case PUBKEY_ALGO_EDDSA: return 3;
+ case PUBKEY_ALGO_KYBER: return 5;
default: return 0;
}
}
@@ -1770,6 +1787,7 @@ pubkey_get_nenc (pubkey_algo_t algo)
case PUBKEY_ALGO_ECDSA: return 0;
case PUBKEY_ALGO_ELGAMAL: return 2;
case PUBKEY_ALGO_EDDSA: return 0;
+ case PUBKEY_ALGO_KYBER: return 3;
default: return 0;
}
}
diff --git a/g10/openfile.c b/g10/openfile.c
index 5ca168a13..01f323399 100644
--- a/g10/openfile.c
+++ b/g10/openfile.c
@@ -179,13 +179,13 @@ ask_outfile_name( const char *name, size_t namelen )
* be closed if the returned IOBUF is closed. This is used for gpg's
* --server mode. */
int
-open_outfile (int out_fd, const char *iname, int mode, int restrictedperm,
- iobuf_t *a)
+open_outfile (gnupg_fd_t out_fd, const char *iname, int mode,
+ int restrictedperm, iobuf_t *a)
{
int rc = 0;
*a = NULL;
- if (out_fd != -1)
+ if (out_fd != GNUPG_INVALID_FD)
{
char xname[64];
@@ -193,12 +193,12 @@ open_outfile (int out_fd, const char *iname, int mode, int restrictedperm,
if (!*a)
{
rc = gpg_error_from_syserror ();
- snprintf (xname, sizeof xname, "[fd %d]", out_fd);
+ snprintf (xname, sizeof xname, "[fd %d]", FD_DBG (out_fd));
log_error (_("can't open '%s': %s\n"), xname, gpg_strerror (rc));
}
else if (opt.verbose)
{
- snprintf (xname, sizeof xname, "[fd %d]", out_fd);
+ snprintf (xname, sizeof xname, "[fd %d]", FD_DBG (out_fd));
log_info (_("writing to '%s'\n"), xname);
}
}
diff --git a/g10/options.h b/g10/options.h
index 50fa4ad86..ae429fcc1 100644
--- a/g10/options.h
+++ b/g10/options.h
@@ -283,6 +283,7 @@ struct
/* Fail if an operation can't be done in the requested compliance
* mode. */
unsigned int require_compliance:1;
+ unsigned int require_pqc_encryption:1;
} flags;
/* Linked list of ways to find a key if the key isn't on the local
@@ -378,7 +379,8 @@ EXTERN_UNLESS_MAIN_MODULE int memory_debug_mode;
EXTERN_UNLESS_MAIN_MODULE int memory_stat_debug_mode;
/* Compatibility flags */
-/* #define COMPAT_FOO 1 */
+#define COMPAT_PARALLELIZED 1 /* Use threaded hashing for signatures. */
+#define COMPAT_T7014_OLD 2 /* Use initial T7014 test data. */
/* Compliance test macors. */
@@ -442,6 +444,8 @@ EXTERN_UNLESS_MAIN_MODULE int memory_stat_debug_mode;
#define LIST_SHOW_PREF (1<<14)
#define LIST_SHOW_PREF_VERBOSE (1<<15)
#define LIST_SHOW_UNUSABLE_SIGS (1<<16)
+#define LIST_SHOW_X509_NOTATIONS (1<<17)
+#define LIST_STORE_X509_NOTATIONS (1<<18)
#define LIST_SHOW_OWNERTRUST (1<<19)
#define VERIFY_SHOW_PHOTOS (1<<0)
diff --git a/g10/packet.h b/g10/packet.h
index 39dab96c9..459e38dda 100644
--- a/g10/packet.h
+++ b/g10/packet.h
@@ -137,6 +137,8 @@ typedef struct {
byte version;
/* The algorithm used for the public key encryption scheme. */
byte pubkey_algo;
+ /* The session key algorithm used by some pubkey algos. */
+ byte seskey_algo;
/* Whether to hide the key id. This value is not directly
serialized. */
byte throw_keyid;
@@ -151,6 +153,7 @@ struct pubkey_enc_list
struct pubkey_enc_list *next;
u32 keyid[2];
int pubkey_algo;
+ int seskey_algo;
int result;
gcry_mpi_t data[PUBKEY_MAX_NENC];
};
@@ -342,11 +345,11 @@ struct revoke_info
/* Information pertaining to secret keys. */
struct seckey_info
{
- int is_protected:1; /* The secret info is protected and must */
+ unsigned int is_protected:1; /* The secret info is protected and must */
/* be decrypted before use, the protected */
/* MPIs are simply (void*) pointers to memory */
/* and should never be passed to a mpi_xxx() */
- int sha1chk:1; /* SHA1 is used instead of a 16 bit checksum */
+ unsigned int sha1chk:1; /* SHA1 is used instead of a 16 bit checksum */
u16 csum; /* Checksum for old protection modes. */
byte algo; /* Cipher used to protect the secret information. */
STRING2KEY s2k; /* S2K parameter. */
@@ -602,8 +605,8 @@ struct notation
/* Sometimes we want to %-expand the value. In these cases, we save
that transformed value here. */
char *altvalue;
- /* If the notation is not human readable, then the value is stored
- here. */
+ /* If the notation is not human readable or the function does not
+ want to distinguish that, then the value is stored here. */
unsigned char *bdat;
/* The amount of data stored in BDAT.
@@ -634,8 +637,8 @@ void reset_literals_seen(void);
int proc_packets (ctrl_t ctrl, void *ctx, iobuf_t a );
int proc_signature_packets (ctrl_t ctrl, void *ctx, iobuf_t a,
strlist_t signedfiles, const char *sigfile );
-int proc_signature_packets_by_fd (ctrl_t ctrl,
- void *anchor, IOBUF a, int signed_data_fd );
+int proc_signature_packets_by_fd (ctrl_t ctrl, void *anchor, IOBUF a,
+ gnupg_fd_t signed_data_fd);
int proc_encryption_packets (ctrl_t ctrl, void *ctx, iobuf_t a);
int list_packets( iobuf_t a );
@@ -863,7 +866,9 @@ gpg_error_t build_keyblock_image (kbnode_t keyblock, iobuf_t *r_iobuf);
int build_packet (iobuf_t out, PACKET *pkt);
gpg_error_t build_packet_and_meta (iobuf_t out, PACKET *pkt);
gpg_error_t gpg_mpi_write (iobuf_t out, gcry_mpi_t a, unsigned int *t_nwritten);
-gpg_error_t gpg_mpi_write_nohdr (iobuf_t out, gcry_mpi_t a);
+gpg_error_t gpg_mpi_write_opaque_nohdr (iobuf_t out, gcry_mpi_t a);
+gpg_error_t gpg_mpi_write_opaque_32 (iobuf_t out, gcry_mpi_t a,
+ unsigned int *r_nwritten);
u32 calc_packet_length( PACKET *pkt );
void build_sig_subpkt( PKT_signature *sig, sigsubpkttype_t type,
const byte *buffer, size_t buflen );
@@ -877,7 +882,8 @@ struct notation *string_to_notation(const char *string,int is_utf8);
struct notation *blob_to_notation(const char *name,
const char *data, size_t len);
struct notation *sig_to_notation(PKT_signature *sig);
-void free_notation(struct notation *notation);
+struct notation *search_sig_notations (PKT_signature *sig, const char *name);
+void free_notation (struct notation *notation);
/*-- free-packet.c --*/
void free_symkey_enc( PKT_symkey_enc *enc );
diff --git a/g10/parse-packet.c b/g10/parse-packet.c
index aa6bac9da..8bd283b4b 100644
--- a/g10/parse-packet.c
+++ b/g10/parse-packet.c
@@ -188,6 +188,109 @@ mpi_read (iobuf_t inp, unsigned int *ret_nread, int secure)
}
+/* If NLENGTH is zero read an octet string of length NBYTES from INP
+ * and return it at R_DATA.
+ *
+ * If NLENGTH is either 1, 2, or 4 and NLENGTH is zero read an
+ * NLENGTH-octet count and use this count number octets from INP and
+ * return it at R_DATA.
+ *
+ * On error return an error code and store NULL at R_DATA. PKTLEN
+ * shall give the current length of the packet and is updated with
+ * each read. If SECURE is true, the integer is stored in secure
+ * memory (allocated using gcry_xmalloc_secure).
+ */
+static gpg_error_t
+read_octet_string (iobuf_t inp, unsigned long *pktlen,
+ unsigned int nlength, unsigned int nbytes,
+ int secure, gcry_mpi_t *r_data)
+{
+ gpg_error_t err;
+ int c, i;
+ byte *buf = NULL;
+ byte *p;
+
+ *r_data = NULL;
+
+ if ((nbytes && nlength)
+ || (!nbytes && !(nlength == 1 || nlength == 2 || nlength == 4)))
+ {
+ err = gpg_error (GPG_ERR_INV_ARG);
+ goto leave;
+ }
+
+ if (nlength)
+ {
+ for (i = 0; i < nlength; i++)
+ {
+ if (!*pktlen)
+ {
+ err = gpg_error (GPG_ERR_INV_PACKET);
+ goto leave;
+ }
+ c = iobuf_readbyte (inp);
+ if (c < 0)
+ {
+ err = gpg_error (GPG_ERR_INV_PACKET);
+ goto leave;
+ }
+ --*pktlen;
+ nbytes <<= 8;
+ nbytes |= c;
+ }
+
+ if (!nbytes)
+ {
+ err = gpg_error (GPG_ERR_INV_PACKET);
+ goto leave;
+ }
+ }
+
+ if (nbytes*8 > (nbytes==4? MAX_EXTERN_KEYPARM_BITS:MAX_EXTERN_MPI_BITS)
+ || (nbytes*8 < nbytes))
+ {
+ log_error ("octet string too large (%u octets)\n", nbytes);
+ err = gpg_error (GPG_ERR_TOO_LARGE);
+ goto leave;
+ }
+
+ if (nbytes > *pktlen)
+ {
+ log_error ("octet string larger than packet (%u octets)\n", nbytes);
+ err = gpg_error (GPG_ERR_INV_PACKET);
+ goto leave;
+ }
+
+ buf = secure ? gcry_malloc_secure (nbytes) : gcry_malloc (nbytes);
+ if (!buf)
+ {
+ err = gpg_error_from_syserror ();
+ goto leave;
+ }
+ p = buf;
+ for (i = 0; i < nbytes; i++)
+ {
+ c = iobuf_get (inp);
+ if (c == -1)
+ {
+ err = gpg_error (GPG_ERR_INV_PACKET);
+ goto leave;
+ }
+
+ p[i] = c;
+ --*pktlen;
+ }
+
+ *r_data = gcry_mpi_set_opaque (NULL, buf, nbytes*8);
+ gcry_mpi_set_flag (*r_data, GCRYMPI_FLAG_USER2);
+ return 0;
+
+ leave:
+ gcry_free (buf);
+ return err;
+}
+
+
/* Read an external representation of an SOS and return the opaque MPI
with GCRYMPI_FLAG_USER2. The external format is a 16-bit unsigned
value stored in network byte order giving information for the
@@ -1102,32 +1205,29 @@ read_rest (IOBUF inp, size_t pktlen)
/* Read a special size+body from INP. On success store an opaque MPI
- with it at R_DATA. On error return an error code and store NULL at
- R_DATA. Even in the error case store the number of read bytes at
- R_NREAD. The caller shall pass the remaining size of the packet in
- PKTLEN. */
+ * with it at R_DATA. The caller shall store the remaining size of
+ * the packet at PKTLEN. On error return an error code and store NULL
+ * at R_DATA. Even in the error case store the number of read bytes
+ * at PKTLEN is updated. */
static gpg_error_t
-read_size_body (iobuf_t inp, int pktlen, size_t *r_nread,
- gcry_mpi_t *r_data)
+read_sized_octet_string (iobuf_t inp, unsigned long *pktlen, gcry_mpi_t *r_data)
{
char buffer[256];
char *tmpbuf;
int i, c, nbytes;
- *r_nread = 0;
*r_data = NULL;
- if (!pktlen)
+ if (!*pktlen)
return gpg_error (GPG_ERR_INV_PACKET);
c = iobuf_readbyte (inp);
if (c < 0)
return gpg_error (GPG_ERR_INV_PACKET);
- pktlen--;
- ++*r_nread;
+ --*pktlen;
nbytes = c;
if (nbytes < 2 || nbytes > 254)
return gpg_error (GPG_ERR_INV_PACKET);
- if (nbytes > pktlen)
+ if (nbytes > *pktlen)
return gpg_error (GPG_ERR_INV_PACKET);
buffer[0] = nbytes;
@@ -1137,7 +1237,7 @@ read_size_body (iobuf_t inp, int pktlen, size_t *r_nread,
c = iobuf_get (inp);
if (c < 0)
return gpg_error (GPG_ERR_INV_PACKET);
- ++*r_nread;
+ --*pktlen;
buffer[1+i] = c;
}
@@ -1344,12 +1444,14 @@ 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)
{
int rc = 0;
int i, ndata;
+ unsigned int n;
PKT_pubkey_enc *k;
k = packet->pkt.pubkey_enc = xmalloc_clear (sizeof *packet->pkt.pubkey_enc);
@@ -1392,46 +1494,78 @@ parse_pubkeyenc (IOBUF inp, int pkttype, unsigned long pktlen,
unknown_pubkey_warning (k->pubkey_algo);
k->data[0] = NULL; /* No need to store the encrypted data. */
}
+ else if (k->pubkey_algo == PUBKEY_ALGO_ECDH)
+ {
+ log_assert (ndata == 2);
+ /* Get the ephemeral public key. */
+ 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 wrapped symmetric key. */
+ rc = read_sized_octet_string (inp, &pktlen, k->data + 1);
+ if (rc)
+ goto leave;
+ }
+ else if (k->pubkey_algo == PUBKEY_ALGO_KYBER)
+ {
+ log_assert (ndata == 3);
+ /* Get the ephemeral public key. */
+ 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)
+ goto leave;
+ /* Get the algorithm id for the session key. */
+ if (!pktlen)
+ {
+ rc = gpg_error (GPG_ERR_INV_PACKET);
+ goto leave;
+ }
+ k->seskey_algo = iobuf_get_noeof (inp);
+ pktlen--;
+ /* Get the encrypted symmetric key. */
+ rc = read_octet_string (inp, &pktlen, 1, 0, 0, k->data + 2);
+ if (rc)
+ goto leave;
+ }
else
{
for (i = 0; i < ndata; i++)
{
- if (k->pubkey_algo == PUBKEY_ALGO_ECDH)
- {
- if (i == 1)
- {
- size_t n;
- rc = read_size_body (inp, pktlen, &n, k->data+i);
- pktlen -= n;
- }
- else
- {
- int n = pktlen;
- k->data[i] = sos_read (inp, &n, 0);
- pktlen -= n;
- if (!k->data[i])
- rc = gpg_error (GPG_ERR_INV_PACKET);
- }
- }
- else
- {
- int n = pktlen;
- k->data[i] = mpi_read (inp, &n, 0);
- pktlen -= n;
- if (!k->data[i])
- rc = gpg_error (GPG_ERR_INV_PACKET);
- }
- if (rc)
- goto leave;
- if (list_mode)
- {
- es_fprintf (listfp, "\tdata: ");
- mpi_print (listfp, k->data[i], mpi_print_mode);
- es_putc ('\n', listfp);
- }
+ n = pktlen;
+ k->data[i] = mpi_read (inp, &n, 0);
+ pktlen -= n;
+ if (!k->data[i])
+ rc = gpg_error (GPG_ERR_INV_PACKET);
+ }
+ if (rc)
+ goto leave;
+ }
+ if (list_mode)
+ {
+ if (k->seskey_algo)
+ es_fprintf (listfp, "\tsession key algo: %d\n", k->seskey_algo);
+ for (i = 0; i < ndata; i++)
+ {
+ es_fprintf (listfp, "\tdata: ");
+ mpi_print (listfp, k->data[i], mpi_print_mode);
+ es_putc ('\n', listfp);
}
}
+
leave:
iobuf_skip_rest (inp, pktlen, 0);
return rc;
@@ -2598,19 +2732,25 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
{
if ( (algorithm == PUBKEY_ALGO_ECDSA && (i == 0))
|| (algorithm == PUBKEY_ALGO_EDDSA && (i == 0))
- || (algorithm == PUBKEY_ALGO_ECDH && (i == 0 || i == 2)))
+ || (algorithm == PUBKEY_ALGO_ECDH && (i == 0 || i == 2))
+ || (algorithm == PUBKEY_ALGO_KYBER && (i == 0)))
{
/* Read the OID (i==0) or the KDF params (i==2). */
- size_t n;
- err = read_size_body (inp, pktlen, &n, pk->pkey+i);
- pktlen -= n;
+ err = read_sized_octet_string (inp, &pktlen, pk->pkey+i);
+ }
+ else if (algorithm == PUBKEY_ALGO_KYBER && i == 2)
+ {
+ /* Read the four-octet count prefixed Kyber public key. */
+ err = read_octet_string (inp, &pktlen, 4, 0, 0, pk->pkey+i);
}
else
{
+ /* Read MPI or SOS. */
unsigned int n = pktlen;
if (algorithm == PUBKEY_ALGO_ECDSA
|| algorithm == PUBKEY_ALGO_EDDSA
- || algorithm == PUBKEY_ALGO_ECDH)
+ || algorithm == PUBKEY_ALGO_ECDH
+ || algorithm == PUBKEY_ALGO_KYBER)
pk->pkey[i] = sos_read (inp, &n, 0);
else
pk->pkey[i] = mpi_read (inp, &n, 0);
@@ -2626,7 +2766,8 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
mpi_print (listfp, pk->pkey[i], mpi_print_mode);
if ((algorithm == PUBKEY_ALGO_ECDSA
|| algorithm == PUBKEY_ALGO_EDDSA
- || algorithm == PUBKEY_ALGO_ECDH) && i==0)
+ || algorithm == PUBKEY_ALGO_ECDH
+ || algorithm == PUBKEY_ALGO_KYBER) && i==0)
{
char *curve = openpgp_oid_to_str (pk->pkey[0]);
const char *name = openpgp_oid_to_curve (curve, 0);
@@ -2963,21 +3104,32 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
/* Not encrypted. */
for (i = npkey; i < nskey; i++)
{
- unsigned int n;
if (pktlen < 2) /* At least two bytes for the length. */
{
err = gpg_error (GPG_ERR_INV_PACKET);
goto leave;
}
- n = pktlen;
- if (algorithm == PUBKEY_ALGO_ECDSA
- || algorithm == PUBKEY_ALGO_EDDSA
- || algorithm == PUBKEY_ALGO_ECDH)
- pk->pkey[i] = sos_read (inp, &n, 0);
+ if (algorithm == PUBKEY_ALGO_KYBER && i == npkey+1)
+ {
+ err = read_octet_string (inp, &pktlen, 4, 0, 1, pk->pkey+i);
+ if (err)
+ goto leave;
+ }
else
- pk->pkey[i] = mpi_read (inp, &n, 0);
- pktlen -= n;
+ {
+ unsigned int n = pktlen;
+
+ if (algorithm == PUBKEY_ALGO_ECDSA
+ || algorithm == PUBKEY_ALGO_EDDSA
+ || algorithm == PUBKEY_ALGO_ECDH
+ || algorithm == PUBKEY_ALGO_KYBER)
+ pk->pkey[i] = sos_read (inp, &n, 0);
+ else
+ pk->pkey[i] = mpi_read (inp, &n, 0);
+ pktlen -= n;
+ }
+
if (list_mode)
{
es_fprintf (listfp, "\tskey[%d]: ", i);
diff --git a/g10/photoid.c b/g10/photoid.c
index fc8866121..8cc7e3a20 100644
--- a/g10/photoid.c
+++ b/g10/photoid.c
@@ -27,9 +27,6 @@
# include <winsock2.h>
# endif
# include <windows.h>
-# ifndef VER_PLATFORM_WIN32_WINDOWS
-# define VER_PLATFORM_WIN32_WINDOWS 1
-# endif
#endif
#include "gpg.h"
@@ -95,8 +92,15 @@ w32_system (const char *command)
return -1;
}
if (DBG_EXTPROG)
- log_debug ("ShellExecuteEx succeeded (hProcess=%p,hInstApp=%d)\n",
- see.hProcess, (int)see.hInstApp);
+ {
+ /* hInstApp has HINSTANCE type. The documentations says
+ that it's not a true HINSTANCE and it can be cast only to
+ an int. */
+ int hinstance = (intptr_t)see.hInstApp;
+
+ log_debug ("ShellExecuteEx succeeded (hProcess=%p,hInstApp=%d)\n",
+ see.hProcess, hinstance);
+ }
if (!see.hProcess)
{
@@ -381,16 +385,7 @@ static const char *
get_default_photo_command(void)
{
#if defined(_WIN32)
- OSVERSIONINFO osvi;
-
- memset(&osvi,0,sizeof(osvi));
- osvi.dwOSVersionInfoSize=sizeof(osvi);
- GetVersionEx(&osvi);
-
- if(osvi.dwPlatformId==VER_PLATFORM_WIN32_WINDOWS)
- return "start /w %i";
- else
- return "!ShellExecute 400 %i";
+ return "!ShellExecute 400 %i";
#elif defined(__APPLE__)
/* OS X. This really needs more than just __APPLE__. */
return "open %I";
@@ -600,34 +595,35 @@ run_with_pipe (struct spawn_info *info, const void *image, u32 len)
" external programs\n"));
return;
#else /* !EXEC_TEMPFILE_ONLY */
- int to[2];
- pid_t pid;
gpg_error_t err;
const char *argv[4];
-
- err = gnupg_create_pipe (to);
- if (err)
- return;
+ gnupg_process_t proc;
fill_command_argv (argv, info->command);
- err = gnupg_spawn_process_fd (argv[0], argv+1, to[0], -1, -1, &pid);
-
- close (to[0]);
-
+ err = gnupg_process_spawn (argv[0], argv+1, GNUPG_PROCESS_STDIN_PIPE,
+ NULL, NULL, &proc);
if (err)
- {
- log_error (_("unable to execute shell '%s': %s\n"),
- argv[0], gpg_strerror (err));
- close (to[1]);
- }
+ log_error (_("unable to execute shell '%s': %s\n"),
+ argv[0], gpg_strerror (err));
else
{
- write (to[1], image, len);
- close (to[1]);
+ int fd_in;
+
+ err = gnupg_process_get_fds (proc, 0, &fd_in, NULL, NULL);
+ if (err)
+ log_error ("unable to get pipe connection '%s': %s\n",
+ argv[2], gpg_strerror (err));
+ else
+ {
+ write (fd_in, image, len);
+ close (fd_in);
+ }
- err = gnupg_wait_process (argv[0], pid, 1, NULL);
+ err = gnupg_process_wait (proc, 1);
if (err)
log_error (_("unnatural exit of external program\n"));
+
+ gnupg_process_release (proc);
}
#endif /* !EXEC_TEMPFILE_ONLY */
}
@@ -695,14 +691,11 @@ show_photo (const char *command, const char *name, const void *image, u32 len)
log_error (_("system error while calling external program: %s\n"),
strerror (errno));
#else
- pid_t pid;
gpg_error_t err;
const char *argv[4];
fill_command_argv (argv, spawn->command);
- err = gnupg_spawn_process_fd (argv[0], argv+1, -1, -1, -1, &pid);
- if (!err)
- err = gnupg_wait_process (argv[0], pid, 1, NULL);
+ err = gnupg_process_spawn (argv[0], argv+1, 0, NULL, NULL, NULL);
if (err)
log_error (_("unnatural exit of external program\n"));
#endif
diff --git a/g10/pkglue.c b/g10/pkglue.c
index f18313913..f4efa8fc5 100644
--- a/g10/pkglue.c
+++ b/g10/pkglue.c
@@ -1,6 +1,7 @@
/* 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.
*
@@ -16,6 +17,7 @@
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <https://www.gnu.org/licenses/>.
+ * SPDX-License-Identifier: GPL-3.0-or-later
*/
#include <config.h>
@@ -30,6 +32,12 @@
#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
@@ -415,140 +423,505 @@ pk_verify (pubkey_algo_t pkalgo, gcry_mpi_t hash,
}
+#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
-
-/****************
- * Emulate our old PK interface here - sometime in the future we might
- * change the internal design to directly fit to libgcrypt.
- * PK is only required to compute the fingerprint for ECDH.
- */
-int
-pk_encrypt (pubkey_algo_t algo, gcry_mpi_t *resarr, gcry_mpi_t data,
- PKT_public_key *pk, gcry_mpi_t *pkey)
+/* 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)
{
- gcry_sexp_t s_ciph = NULL;
+ gpg_error_t err;
+ int i;
+ unsigned int nbits, n;
gcry_sexp_t s_data = NULL;
- gcry_sexp_t s_pkey = NULL;
- int rc;
-
- /* Make a sexp from pkey. */
- if (algo == PUBKEY_ALGO_ELGAMAL || algo == PUBKEY_ALGO_ELGAMAL_E)
- {
- rc = gcry_sexp_build (&s_pkey, NULL,
- "(public-key(elg(p%m)(g%m)(y%m)))",
- pkey[0], pkey[1], pkey[2]);
- /* Put DATA into a simplified S-expression. */
- if (!rc)
- rc = gcry_sexp_build (&s_data, NULL, "%m", data);
- }
- else if (algo == PUBKEY_ALGO_RSA || algo == PUBKEY_ALGO_RSA_E)
+ 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)
{
- rc = gcry_sexp_build (&s_pkey, NULL,
- "(public-key(rsa(n%m)(e%m)))",
- pkey[0], pkey[1]);
- /* Put DATA into a simplified S-expression. */
- if (!rc)
- rc = gcry_sexp_build (&s_data, NULL, "%m", data);
+ err = gpg_error_from_syserror ();
+ log_error ("%s: error getting OID for ECC key\n", __func__);
+ goto leave;
}
- else if (algo == PUBKEY_ALGO_ECDH)
+ ecc_algo = openpgp_oid_to_kem_algo (ecc_oid);
+ if (ecc_algo == GCRY_KEM_RAW_X25519)
{
- gcry_mpi_t k;
-
- rc = pk_ecdh_generate_ephemeral_key (pkey, &k);
- if (!rc)
+ 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)
{
- char *curve;
-
- curve = openpgp_oid_to_str (pkey[0]);
- if (!curve)
- rc = gpg_error_from_syserror ();
- else
- {
- int with_djb_tweak_flag = openpgp_oid_is_cv25519 (pkey[0]);
-
- /* Now use the ephemeral secret to compute the shared point. */
- rc = 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]);
- xfree (curve);
- /* Put K into a simplified S-expression. */
- if (!rc)
- rc = gcry_sexp_build (&s_data, NULL, "%m", k);
- }
- gcry_mpi_release (k);
+ ecc_pubkey++; /* Remove the 0x40 prefix. */
+ ecc_pubkey_len--;
}
- }
- else
- rc = gpg_error (GPG_ERR_PUBKEY_ALGO);
-
- /* Pass it to libgcrypt. */
- if (!rc)
- rc = gcry_pk_encrypt (&s_ciph, s_data, s_pkey);
-
- gcry_sexp_release (s_data);
- gcry_sexp_release (s_pkey);
-
- if (rc)
- ;
- else if (algo == PUBKEY_ALGO_ECDH)
- {
- gcry_mpi_t public, result;
- byte fp[MAX_FINGERPRINT_LEN];
- byte *shared;
- size_t nshared;
-
- /* Get the shared point and the ephemeral public key. */
- shared = get_data_from_sexp (s_ciph, "s", &nshared);
- if (!shared)
+ if (ecc_pubkey_len != 32)
{
- rc = gpg_error_from_syserror ();
+ 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;
}
- rc = sexp_extract_param_sos (s_ciph, "e", &public);
- gcry_sexp_release (s_ciph);
- s_ciph = NULL;
- if (DBG_CRYPTO)
+ 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)
{
- log_debug ("ECDH ephemeral key:");
- gcry_mpi_dump (public);
- log_printf ("\n");
+ 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;
}
-
- result = NULL;
- fingerprint_from_pk (pk, fp, NULL);
-
- if (!rc)
+ 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)
{
- unsigned int nbits;
- byte *p = gcry_mpi_get_opaque (data, &nbits);
- rc = pk_ecdh_encrypt_with_shared_point (shared, nshared, fp, p,
- (nbits+7)/8, pkey, &result);
+ 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;
}
- xfree (shared);
- if (!rc)
+ 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)
{
- resarr[0] = public;
- resarr[1] = result;
+ 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;
}
- else
+ 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)
{
- gcry_mpi_release (public);
- gcry_mpi_release (result);
+ 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 /* Elgamal or RSA case. */
- { /* Fixme: Add better error handling or make gnupg use
- S-expressions directly. */
- 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);
+ 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);
- return rc;
+ 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);
}
diff --git a/g10/pkglue.h b/g10/pkglue.h
index abeddb811..2b5c8b143 100644
--- a/g10/pkglue.h
+++ b/g10/pkglue.h
@@ -31,8 +31,8 @@ gpg_error_t sexp_extract_param_sos_nlz (gcry_sexp_t sexp, const char *param,
int pk_verify (pubkey_algo_t algo, gcry_mpi_t hash, gcry_mpi_t *data,
gcry_mpi_t *pkey);
-int pk_encrypt (pubkey_algo_t algo, gcry_mpi_t *resarr, gcry_mpi_t data,
- PKT_public_key *pk, gcry_mpi_t *pkey);
+gpg_error_t pk_encrypt (PKT_public_key *pk, gcry_mpi_t data, int seskey_algo,
+ gcry_mpi_t *resarr);
int pk_check_secret_key (pubkey_algo_t algo, gcry_mpi_t *skey);
diff --git a/g10/plaintext.c b/g10/plaintext.c
index 5c21dd7f6..a96214994 100644
--- a/g10/plaintext.c
+++ b/g10/plaintext.c
@@ -111,20 +111,20 @@ get_output_file (const byte *embedded_name, int embedded_namelen,
{
/* Special file name, no filename, or "-" given; write to the
* file descriptor or to stdout. */
- int fd;
+ gnupg_fd_t fd;
char xname[64];
- fd = check_special_filename (fname, 1, 0);
- if (fd == -1)
+ fd = gnupg_check_special_filename (fname);
+ if (fd == GNUPG_INVALID_FD)
{
/* Not a special filename, thus we want stdout. */
fp = es_stdout;
es_set_binary (fp);
}
- else if (!(fp = es_fdopen_nc (fd, "wb")))
+ else if (!(fp = open_stream_nc (fd, "wb")))
{
err = gpg_error_from_syserror ();
- snprintf (xname, sizeof xname, "[fd %d]", fd);
+ snprintf (xname, sizeof xname, "[fd %d]", FD_DBG (fd));
log_error (_("can't open '%s': %s\n"), xname, gpg_strerror (err));
goto leave;
}
@@ -137,8 +137,7 @@ get_output_file (const byte *embedded_name, int embedded_namelen,
if (!tmp || !*tmp)
{
xfree (tmp);
- /* FIXME: Below used to be GPG_ERR_CREATE_FILE */
- err = gpg_error (GPG_ERR_GENERAL);
+ err = gpg_error (GPG_ERR_EEXIST);
goto leave;
}
xfree (fname);
@@ -146,13 +145,7 @@ get_output_file (const byte *embedded_name, int embedded_namelen,
}
}
- if (opt.outfp && is_secured_file (es_fileno (opt.outfp)))
- {
- err = gpg_error (GPG_ERR_EPERM);
- log_error (_("error creating '%s': %s\n"), fname, gpg_strerror (err));
- goto leave;
- }
- else if (fp || nooutput)
+ if (fp || nooutput)
;
else if (is_secured_filename (fname))
{
@@ -729,8 +722,8 @@ hash_datafiles (gcry_md_hd_t md, gcry_md_hd_t md2, strlist_t files,
/* Hash the data from file descriptor DATA_FD and append the hash to hash
contexts MD and MD2. */
int
-hash_datafile_by_fd (gcry_md_hd_t md, gcry_md_hd_t md2, int data_fd,
- int textmode)
+hash_datafile_by_fd (gcry_md_hd_t md, gcry_md_hd_t md2,
+ gnupg_fd_t data_fd, int textmode)
{
progress_filter_context_t *pfx = new_progress_context ();
iobuf_t fp;
@@ -747,7 +740,7 @@ hash_datafile_by_fd (gcry_md_hd_t md, gcry_md_hd_t md2, int data_fd,
{
int rc = gpg_error_from_syserror ();
log_error (_("can't open signed data fd=%d: %s\n"),
- data_fd, strerror (errno));
+ FD_DBG (data_fd), strerror (errno));
release_progress_context (pfx);
return rc;
}
diff --git a/g10/pubkey-enc.c b/g10/pubkey-enc.c
index 6e1b0898e..563077803 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))
@@ -193,7 +194,7 @@ get_it (ctrl_t ctrl,
{
gpg_error_t err;
byte *frame = NULL;
- unsigned int n;
+ unsigned int frameidx;
size_t nframe;
u16 csum, csum2;
int padding;
@@ -237,6 +238,32 @@ 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)
+ {
+ char fixedinfo[1+MAX_FINGERPRINT_LEN];
+ int fixedlen;
+
+ if ((opt.compat_flags & COMPAT_T7014_OLD))
+ {
+ /* Temporary use for tests with original test vectors. */
+ fixedinfo[0] = 0x69;
+ fixedlen = 1;
+ }
+ else
+ {
+ fixedinfo[0] = enc->seskey_algo;
+ v5_fingerprint_from_pk (sk, fixedinfo+1, NULL);
+ fixedlen = 33;
+ }
+
+ if (!enc->data[0] || !enc->data[1] || !enc->data[2])
+ err = gpg_error (GPG_ERR_BAD_MPI);
+ else
+ err = gcry_sexp_build (&s_data, NULL,
+ "(enc-val(pqc(e%m)(k%m)(s%m)(c%d)(fixed-info%b)))",
+ enc->data[0], enc->data[1], enc->data[2],
+ enc->seskey_algo, fixedlen, fixedinfo);
+ }
else
err = gpg_error (GPG_ERR_BUG);
@@ -248,6 +275,7 @@ get_it (ctrl_t ctrl,
/* Decrypt. */
desc = gpg_format_keydesc (ctrl, sk, FORMAT_KEYDESC_NORMAL, 1);
+
err = agent_pkdecrypt (NULL, keygrip,
desc, sk->keyid, sk->main_keyid, sk->pubkey_algo,
s_data, &frame, &nframe, &padding);
@@ -275,9 +303,22 @@ get_it (ctrl_t ctrl,
*/
if (DBG_CRYPTO)
log_printhex (frame, nframe, "DEK frame:");
- n = 0;
+ frameidx = 0;
- if (sk->pubkey_algo == PUBKEY_ALGO_ECDH)
+ if (sk->pubkey_algo == PUBKEY_ALGO_KYBER)
+ {
+ /* We expect a 32 byte session key. We should not see this
+ * error here because due to the KEM mode the agent_pkdecrypt
+ * should have already failed. */
+ if (nframe != 32)
+ {
+ err = gpg_error (GPG_ERR_WRONG_SECKEY);
+ goto leave;
+ }
+ dek->keylen = nframe;
+ dek->algo = enc->seskey_algo;
+ }
+ else if (sk->pubkey_algo == PUBKEY_ALGO_ECDH)
{
gcry_mpi_t decoded;
@@ -301,13 +342,21 @@ get_it (ctrl_t ctrl,
goto leave;
}
nframe -= frame[nframe-1]; /* Remove padding. */
- log_assert (!n); /* (used just below) */
+ if (4 > nframe)
+ {
+ err = gpg_error (GPG_ERR_WRONG_SECKEY);
+ goto leave;
+ }
+
+ dek->keylen = nframe - 3;
+ dek->algo = frame[0];
+ frameidx = 1;
}
else
{
if (padding)
{
- if (n + 7 > nframe)
+ if (7 > nframe)
{
err = gpg_error (GPG_ERR_WRONG_SECKEY);
goto leave;
@@ -319,34 +368,38 @@ get_it (ctrl_t ctrl,
* using a Smartcard we are doing it the right way and
* therefore we have to skip the zero. This should be fixed
* in gpg-agent of course. */
- if (!frame[n])
- n++;
+ frameidx = 0;
+ if (!frame[frameidx])
+ frameidx++;
- if (frame[n] == 1 && frame[nframe - 1] == 2)
+ if (frame[frameidx] == 1 && frame[nframe - 1] == 2)
{
log_info (_("old encoding of the DEK is not supported\n"));
err = gpg_error (GPG_ERR_CIPHER_ALGO);
goto leave;
}
- if (frame[n] != 2) /* Something went wrong. */
+ if (frame[frameidx] != 2) /* Something went wrong. */
{
err = gpg_error (GPG_ERR_WRONG_SECKEY);
goto leave;
}
- for (n++; n < nframe && frame[n]; n++) /* Skip the random bytes. */
+ /* Skip the random bytes. */
+ for (frameidx++; frameidx < nframe && frame[frameidx]; frameidx++)
;
- n++; /* Skip the zero byte. */
+ frameidx++; /* Skip the zero byte. */
}
- }
- if (n + 4 > nframe)
- {
- err = gpg_error (GPG_ERR_WRONG_SECKEY);
- goto leave;
+ if (frameidx + 4 > nframe)
+ {
+ err = gpg_error (GPG_ERR_WRONG_SECKEY);
+ goto leave;
+ }
+
+ dek->keylen = nframe - (frameidx + 1) - 2;
+ dek->algo = frame[frameidx++];
}
- dek->keylen = nframe - (n + 1) - 2;
- dek->algo = frame[n++];
+ /* Check whether we support the ago. */
err = openpgp_cipher_test_algo (dek->algo);
if (err)
{
@@ -365,16 +418,21 @@ get_it (ctrl_t ctrl,
goto leave;
}
- /* Copy the key to DEK and compare the checksum. */
- csum = buf16_to_u16 (frame+nframe-2);
- memcpy (dek->key, frame + n, dek->keylen);
- for (csum2 = 0, n = 0; n < dek->keylen; n++)
- csum2 += dek->key[n];
- if (csum != csum2)
+ /* Copy the key to DEK and compare the checksum if needed. */
+ /* We use the frameidx as flag for the need of a checksum. */
+ memcpy (dek->key, frame + frameidx, dek->keylen);
+ if (frameidx)
{
- err = gpg_error (GPG_ERR_WRONG_SECKEY);
- goto leave;
+ csum = buf16_to_u16 (frame+nframe-2);
+ for (csum2 = 0, frameidx = 0; frameidx < dek->keylen; frameidx++)
+ csum2 += dek->key[frameidx];
+ if (csum != csum2)
+ {
+ err = gpg_error (GPG_ERR_WRONG_SECKEY);
+ goto leave;
+ }
}
+
if (DBG_CLOCK)
log_clock ("decryption ready");
if (DBG_CRYPTO)
@@ -399,6 +457,9 @@ get_it (ctrl_t ctrl,
log_info (_("WARNING: cipher algorithm %s not found in recipient"
" preferences\n"), openpgp_cipher_algo_name (dek->algo));
+ /* if (!err && 25519 && openpgp_oidbuf_is_ed25519 (curve, len)) */
+ /* log_info ("Note: legacy OID was used for cv25519\n"); */
+
if (!err)
{
kbnode_t k;
diff --git a/g10/revoke.c b/g10/revoke.c
index d6cbf93cb..ef5bb4d78 100644
--- a/g10/revoke.c
+++ b/g10/revoke.c
@@ -333,7 +333,7 @@ gen_desig_revoke (ctrl_t ctrl, const char *uname, strlist_t locusr)
if( !opt.armor )
tty_printf(_("ASCII armored output forced.\n"));
- if( (rc = open_outfile (-1, NULL, 0, 1, &out )) )
+ if( (rc = open_outfile (GNUPG_INVALID_FD, NULL, 0, 1, &out )) )
goto leave;
afx->what = 1;
@@ -464,7 +464,7 @@ create_revocation (ctrl_t ctrl,
afx = new_armor_context ();
- if ((rc = open_outfile (-1, filename, suffix, 1, &out)))
+ if ((rc = open_outfile (GNUPG_INVALID_FD, filename, suffix, 1, &out)))
goto leave;
if (leadintext )
diff --git a/g10/server.c b/g10/server.c
index 60b447c41..24e525e7f 100644
--- a/g10/server.c
+++ b/g10/server.c
@@ -265,7 +265,7 @@ cmd_encrypt (assuan_context_t ctx, char *line)
{
ctrl_t ctrl = assuan_get_pointer (ctx);
gpg_error_t err;
- int inp_fd, out_fd;
+ gnupg_fd_t inp_fd, out_fd;
(void)line; /* LINE is not used. */
@@ -276,14 +276,14 @@ cmd_encrypt (assuan_context_t ctx, char *line)
goto leave;
}
- inp_fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
- if (inp_fd == -1)
+ inp_fd = assuan_get_input_fd (ctx);
+ if (inp_fd == GNUPG_INVALID_FD)
{
err = set_error (GPG_ERR_ASS_NO_INPUT, NULL);
goto leave;
}
- out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
- if (out_fd == -1)
+ out_fd = assuan_get_output_fd (ctx);
+ if (out_fd == GNUPG_INVALID_FD)
{
err = set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
goto leave;
@@ -327,15 +327,15 @@ cmd_decrypt (assuan_context_t ctx, char *line)
{
ctrl_t ctrl = assuan_get_pointer (ctx);
gpg_error_t err;
- int inp_fd, out_fd;
+ gnupg_fd_t inp_fd, out_fd;
(void)line; /* LINE is not used. */
- inp_fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
- if (inp_fd == -1)
+ inp_fd = assuan_get_input_fd (ctx);
+ if (inp_fd == GNUPG_INVALID_FD)
return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
- out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
- if (out_fd == -1)
+ out_fd = assuan_get_output_fd (ctx);
+ if (out_fd == GNUPG_INVALID_FD)
return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
glo_ctrl.lasterr = 0;
@@ -388,16 +388,7 @@ cmd_verify (assuan_context_t ctx, char *line)
if (out_fd != GNUPG_INVALID_FD)
{
- es_syshd_t syshd;
-
-#ifdef HAVE_W32_SYSTEM
- syshd.type = ES_SYSHD_HANDLE;
- syshd.u.handle = out_fd;
-#else
- syshd.type = ES_SYSHD_FD;
- syshd.u.fd = out_fd;
-#endif
- out_fp = es_sysopen_nc (&syshd, "w");
+ out_fp = open_stream_nc (fd, "w");
if (!out_fp)
return set_error (gpg_err_code_from_syserror (), "fdopen() failed");
}
diff --git a/g10/seskey.c b/g10/seskey.c
index 15c210b78..2fe8e9de7 100644
--- a/g10/seskey.c
+++ b/g10/seskey.c
@@ -86,6 +86,22 @@ encode_session_key (int openpgp_pk_algo, DEK *dek, unsigned int nbits)
if (DBG_CRYPTO)
log_debug ("encode_session_key: encoding %d byte DEK", dek->keylen);
+ if (openpgp_pk_algo == PUBKEY_ALGO_KYBER)
+ {
+ /* Straightforward encoding w/o extra checksum as used by ECDH. */
+ nframe = dek->keylen;
+ log_assert (nframe > 4); /*(for the log_debug)*/
+ frame = xmalloc_secure (nframe);
+ memcpy (frame, dek->key, nframe);
+ if (DBG_CRYPTO)
+ log_debug ("encode_session_key: "
+ "[%d] %02x %02x %02x ... %02x %02x %02x\n",
+ (int) dek->keylen, frame[0], frame[1], frame[2],
+ frame[nframe-3], frame[nframe-2], frame[nframe-1]);
+
+ return gcry_mpi_set_opaque (NULL, frame, 8*nframe);
+ }
+
csum = 0;
for (p = dek->key, i=0; i < dek->keylen; i++)
csum += *p++;
diff --git a/g10/sign.c b/g10/sign.c
index b00bdfefd..67ea5a038 100644
--- a/g10/sign.c
+++ b/g10/sign.c
@@ -495,6 +495,7 @@ do_sign (ctrl_t ctrl, PKT_public_key *pksk, PKT_signature *sig,
gcry_sexp_t s_sigval;
desc = gpg_format_keydesc (ctrl, pksk, FORMAT_KEYDESC_NORMAL, 1);
+ /* FIXME: Eventually support dual keys. */
err = agent_pksign (NULL/*ctrl*/, cache_nonce, hexgrip, desc,
pksk->keyid, pksk->main_keyid, pksk->pubkey_algo,
dp, gcry_md_get_algo_dlen (mdalgo), mdalgo,
@@ -580,6 +581,7 @@ openpgp_card_v1_p (PKT_public_key *pk)
{
char *hexgrip;
+ /* Note: No need to care about dual keys for non-RSA keys. */
err = hexkeygrip_from_pk (pk, &hexgrip);
if (err)
{
@@ -1022,7 +1024,9 @@ sign_file (ctrl_t ctrl, strlist_t filenames, int detached, strlist_t locusr,
const char *fname;
armor_filter_context_t *afx;
compress_filter_context_t zfx;
+ gcry_md_hd_t md = NULL;
md_filter_context_t mfx;
+ md_thd_filter_context_t mfx2 = NULL;
text_filter_context_t tfx;
progress_filter_context_t *pfx;
encrypt_filter_context_t efx;
@@ -1115,7 +1119,7 @@ sign_file (ctrl_t ctrl, strlist_t filenames, int detached, strlist_t locusr,
else if (opt.verbose)
log_info (_("writing to '%s'\n"), outfile);
}
- else if ((rc = open_outfile (-1, fname,
+ else if ((rc = open_outfile (GNUPG_INVALID_FD, fname,
opt.armor? 1 : detached? 2 : 0, 0, &out)))
{
goto leave;
@@ -1128,10 +1132,10 @@ sign_file (ctrl_t ctrl, strlist_t filenames, int detached, strlist_t locusr,
iobuf_push_filter (inp, text_filter, &tfx);
}
- if (gcry_md_open (&mfx.md, 0, 0))
+ if (gcry_md_open (&md, 0, 0))
BUG ();
if (DBG_HASHING)
- gcry_md_debug (mfx.md, "sign");
+ gcry_md_debug (md, "sign");
/* If we're encrypting and signing, it is reasonable to pick the
* hash algorithm to use out of the recipient key prefs. This is
@@ -1228,10 +1232,21 @@ sign_file (ctrl_t ctrl, strlist_t filenames, int detached, strlist_t locusr,
}
for (sk_rover = sk_list; sk_rover; sk_rover = sk_rover->next)
- gcry_md_enable (mfx.md, hash_for (sk_rover->pk));
+ gcry_md_enable (md, hash_for (sk_rover->pk));
if (!multifile)
- iobuf_push_filter (inp, md_filter, &mfx);
+ {
+ if (encryptflag && (opt.compat_flags & COMPAT_PARALLELIZED))
+ {
+ iobuf_push_filter (inp, md_thd_filter, &mfx2);
+ md_thd_filter_set_md (mfx2, md);
+ }
+ else
+ {
+ iobuf_push_filter (inp, md_filter, &mfx);
+ mfx.md = md;
+ }
+ }
if (detached && !encryptflag)
afx->what = 2;
@@ -1294,7 +1309,7 @@ sign_file (ctrl_t ctrl, strlist_t filenames, int detached, strlist_t locusr,
goto leave;
}
- write_status_begin_signing (mfx.md);
+ write_status_begin_signing (md);
/* Setup the inner packet. */
if (detached)
@@ -1334,7 +1349,16 @@ sign_file (ctrl_t ctrl, strlist_t filenames, int detached, strlist_t locusr,
memset (&tfx, 0, sizeof tfx);
iobuf_push_filter (inp, text_filter, &tfx);
}
- iobuf_push_filter (inp, md_filter, &mfx);
+ if (encryptflag && (opt.compat_flags & COMPAT_PARALLELIZED))
+ {
+ iobuf_push_filter (inp, md_thd_filter, &mfx2);
+ md_thd_filter_set_md (mfx2, md);
+ }
+ else
+ {
+ iobuf_push_filter (inp, md_filter, &mfx);
+ mfx.md = md;
+ }
while (iobuf_read (inp, NULL, iobuf_size) != -1)
;
iobuf_close (inp);
@@ -1363,7 +1387,7 @@ sign_file (ctrl_t ctrl, strlist_t filenames, int detached, strlist_t locusr,
goto leave;
/* Write the signatures. */
- rc = write_signature_packets (ctrl, sk_list, out, mfx.md, extrahash,
+ rc = write_signature_packets (ctrl, sk_list, out, md, extrahash,
opt.textmode && !outfile? 0x01 : 0x00,
0, duration, detached ? 'D':'S', NULL);
if (rc)
@@ -1380,7 +1404,7 @@ sign_file (ctrl_t ctrl, strlist_t filenames, int detached, strlist_t locusr,
write_status (STATUS_END_ENCRYPTION);
}
iobuf_close (inp);
- gcry_md_close (mfx.md);
+ gcry_md_close (md);
release_sk_list (sk_list);
release_pk_list (pk_list);
recipient_digest_algo = 0;
@@ -1461,7 +1485,7 @@ clearsign_file (ctrl_t ctrl,
log_info (_("writing to '%s'\n"), outfile);
}
- else if ((rc = open_outfile (-1, fname, 1, 0, &out)))
+ else if ((rc = open_outfile (GNUPG_INVALID_FD, fname, 1, 0, &out)))
{
goto leave;
}
@@ -1563,6 +1587,8 @@ sign_symencrypt_file (ctrl_t ctrl, const char *fname, strlist_t locusr)
progress_filter_context_t *pfx;
compress_filter_context_t zfx;
md_filter_context_t mfx;
+ md_thd_filter_context_t mfx2 = NULL;
+ gcry_md_hd_t md = NULL;
text_filter_context_t tfx;
cipher_filter_context_t cfx;
iobuf_t inp = NULL;
@@ -1639,22 +1665,32 @@ sign_symencrypt_file (ctrl_t ctrl, const char *fname, strlist_t locusr)
/**/ : "CFB");
/* Now create the outfile. */
- rc = open_outfile (-1, fname, opt.armor? 1:0, 0, &out);
+ rc = open_outfile (GNUPG_INVALID_FD, fname, opt.armor? 1:0, 0, &out);
if (rc)
goto leave;
/* Prepare to calculate the MD over the input. */
if (opt.textmode)
iobuf_push_filter (inp, text_filter, &tfx);
- if (gcry_md_open (&mfx.md, 0, 0))
+ if (gcry_md_open (&md, 0, 0))
BUG ();
if (DBG_HASHING)
- gcry_md_debug (mfx.md, "symc-sign");
+ gcry_md_debug (md, "symc-sign");
for (sk_rover = sk_list; sk_rover; sk_rover = sk_rover->next)
- gcry_md_enable (mfx.md, hash_for (sk_rover->pk));
+ gcry_md_enable (md, hash_for (sk_rover->pk));
+
+ if ((opt.compat_flags & COMPAT_PARALLELIZED))
+ {
+ iobuf_push_filter (inp, md_thd_filter, &mfx2);
+ md_thd_filter_set_md (mfx2, md);
+ }
+ else
+ {
+ iobuf_push_filter (inp, md_filter, &mfx);
+ mfx.md = md;
+ }
- iobuf_push_filter (inp, md_filter, &mfx);
/* Push armor output filter */
if (opt.armor)
@@ -1696,7 +1732,7 @@ sign_symencrypt_file (ctrl_t ctrl, const char *fname, strlist_t locusr)
if (rc)
goto leave;
- write_status_begin_signing (mfx.md);
+ write_status_begin_signing (md);
/* Pipe data through all filters; i.e. write the signed stuff. */
/* (current filters: zip - encrypt - armor) */
@@ -1708,7 +1744,7 @@ sign_symencrypt_file (ctrl_t ctrl, const char *fname, strlist_t locusr)
/* Write the signatures. */
/* (current filters: zip - encrypt - armor) */
- rc = write_signature_packets (ctrl, sk_list, out, mfx.md, extrahash,
+ rc = write_signature_packets (ctrl, sk_list, out, md, extrahash,
opt.textmode? 0x01 : 0x00,
0, duration, 'S', NULL);
if (rc)
@@ -1725,7 +1761,7 @@ sign_symencrypt_file (ctrl_t ctrl, const char *fname, strlist_t locusr)
}
iobuf_close (inp);
release_sk_list (sk_list);
- gcry_md_close (mfx.md);
+ gcry_md_close (md);
xfree (cfx.dek);
xfree (s2k);
release_progress_context (pfx);
diff --git a/g10/tdbdump.c b/g10/tdbdump.c
index 058ab5cf6..99f135678 100644
--- a/g10/tdbdump.c
+++ b/g10/tdbdump.c
@@ -141,19 +141,16 @@ import_ownertrust (ctrl_t ctrl, const char *fname )
fname = "[stdin]";
is_stdin = 1;
}
+ else if (is_secured_filename (fname)) {
+ gpg_err_set_errno (EPERM);
+ log_error (_("can't open '%s': %s\n"), fname, strerror(errno) );
+ return;
+ }
else if( !(fp = es_fopen( fname, "r" )) ) {
log_error ( _("can't open '%s': %s\n"), fname, strerror(errno) );
return;
}
- if (is_secured_file (es_fileno (fp)))
- {
- es_fclose (fp);
- gpg_err_set_errno (EPERM);
- log_error (_("can't open '%s': %s\n"), fname, strerror(errno) );
- return;
- }
-
while (es_fgets (line, DIM(line)-1, fp)) {
TRUSTREC rec;
diff --git a/g10/verify.c b/g10/verify.c
index 1c3de767c..c2c63255c 100644
--- a/g10/verify.c
+++ b/g10/verify.c
@@ -240,7 +240,8 @@ verify_files (ctrl_t ctrl, int nfiles, char **files )
FIXME: OUTFP is not yet implemented.
*/
int
-gpg_verify (ctrl_t ctrl, int sig_fd, int data_fd, estream_t out_fp)
+gpg_verify (ctrl_t ctrl, gnupg_fd_t sig_fd, gnupg_fd_t data_fd,
+ estream_t out_fp)
{
int rc;
iobuf_t fp;
@@ -260,7 +261,8 @@ gpg_verify (ctrl_t ctrl, int sig_fd, int data_fd, estream_t out_fp)
if (!fp)
{
rc = gpg_error_from_syserror ();
- log_error (_("can't open fd %d: %s\n"), sig_fd, strerror (errno));
+ log_error (_("can't open fd %d: %s\n"), FD_DBG (sig_fd),
+ strerror (errno));
goto leave;
}