summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWerner Koch <wk@gnupg.org>2020-05-18 19:24:41 +0200
committerWerner Koch <wk@gnupg.org>2020-05-18 19:24:41 +0200
commitb18fb0264abdb6cb0a99ba0ba941dc9a6e35f74a (patch)
tree28758d568244d5c5dd0c0adabd0022e55d370d5b
parentsm: Support import and verification of EdDSA certificates. (diff)
downloadgnupg2-b18fb0264abdb6cb0a99ba0ba941dc9a6e35f74a.tar.xz
gnupg2-b18fb0264abdb6cb0a99ba0ba941dc9a6e35f74a.zip
agent: Allow to use SETHASH for arbitrary data.
* agent/agent.h (struct server_control_s): Add field digest.data. * agent/gpg-agent.c (agent_deinit_default_ctrl): Free that field. * agent/command.c (reset_notify): Ditto. (start_command_handler): ditto. (cmd_sethash): Add new option --inquire. * agent/call-scd.c (agent_card_pksign): For now return an error if inquire mode was used. * agent/command-ssh.c (ssh_handler_sign_request): Make sure digest.data is cleared. * agent/divert-scd.c (divert_pksign): Implement inquire mode. * agent/pksign.c (agent_pksign_do): Ditto. -- This is required to support EdDSA according to RFC8410. GnuPG-bug-id: 4888
-rw-r--r--agent/agent.h5
-rw-r--r--agent/call-scd.c5
-rw-r--r--agent/command-ssh.c2
-rw-r--r--agent/command.c104
-rw-r--r--agent/divert-scd.c9
-rw-r--r--agent/gpg-agent.c2
-rw-r--r--agent/pksign.c5
7 files changed, 102 insertions, 30 deletions
diff --git a/agent/agent.h b/agent/agent.h
index eb819a0ff..90d8f5c73 100644
--- a/agent/agent.h
+++ b/agent/agent.h
@@ -245,9 +245,12 @@ struct server_control_s
/* Information on the currently used digest (for signing commands). */
struct {
+ char *data; /* NULL or malloced data of length VALUELEN. If
+ this is set The other fields are ignored. Used
+ for PureEdDSA. */
+ int valuelen;
int algo;
unsigned char value[MAX_DIGEST_LEN];
- int valuelen;
int raw_value: 1;
} digest;
unsigned char keygrip[20];
diff --git a/agent/call-scd.c b/agent/call-scd.c
index 60365c980..67b2f31ae 100644
--- a/agent/call-scd.c
+++ b/agent/call-scd.c
@@ -1001,6 +1001,11 @@ agent_card_pksign (ctrl_t ctrl,
if (rc)
return rc;
+ /* FIXME: In the mdalgo case (INDATA,INDATALEN) might be long and
+ * thus we can't convey it on a single Assuan line. */
+ if (!mdalgo)
+ gpg_error (GPG_ERR_NOT_IMPLEMENTED);
+
if (indatalen*2 + 50 > DIM(line))
return unlock_scd (ctrl, gpg_error (GPG_ERR_GENERAL));
diff --git a/agent/command-ssh.c b/agent/command-ssh.c
index 51f37e18b..881f9372a 100644
--- a/agent/command-ssh.c
+++ b/agent/command-ssh.c
@@ -2809,6 +2809,8 @@ ssh_handler_sign_request (ctrl_t ctrl, estream_t request, estream_t response)
if (!hash_algo)
hash_algo = GCRY_MD_SHA1; /* Use the default. */
ctrl->digest.algo = hash_algo;
+ xfree (ctrl->digest.data);
+ ctrl->digest.data = NULL;
if ((spec.flags & SPEC_FLAG_USE_PKCS1V2))
ctrl->digest.raw_value = 0;
else
diff --git a/agent/command.c b/agent/command.c
index 6f179cb08..d374fd06f 100644
--- a/agent/command.c
+++ b/agent/command.c
@@ -243,6 +243,8 @@ reset_notify (assuan_context_t ctx, char *line)
memset (ctrl->keygrip, 0, 20);
ctrl->have_keygrip = 0;
ctrl->digest.valuelen = 0;
+ xfree (ctrl->digest.data);
+ ctrl->digest.data = NULL;
xfree (ctrl->server_local->keydesc);
ctrl->server_local->keydesc = NULL;
@@ -704,20 +706,23 @@ cmd_setkeydesc (assuan_context_t ctx, char *line)
static const char hlp_sethash[] =
- "SETHASH (--hash=<name>)|(<algonumber>) <hexstring>\n"
+ "SETHASH (--hash=<name>)|(<algonumber>) <hexstring>]\n"
+ "SETHASH --inquire\n"
"\n"
"The client can use this command to tell the server about the data\n"
- "(which usually is a hash) to be signed.";
+ "(which usually is a hash) to be signed. The option --inquire is\n"
+ "used to ask back for to-be-signed data in case of PureEdDSA";
static gpg_error_t
cmd_sethash (assuan_context_t ctx, char *line)
{
- int rc;
+ gpg_error_t err;
size_t n;
char *p;
ctrl_t ctrl = assuan_get_pointer (ctx);
unsigned char *buf;
char *endp;
int algo;
+ int opt_inquire;
/* Parse the alternative hash options which may be used instead of
the algo number. */
@@ -740,47 +745,89 @@ cmd_sethash (assuan_context_t ctx, char *line)
else if (has_option (line, "--hash=tls-md5sha1"))
algo = MD_USER_TLS_MD5SHA1;
else
- return set_error (GPG_ERR_ASS_PARAMETER, "invalid hash algorithm");
+ {
+ err = set_error (GPG_ERR_ASS_PARAMETER, "invalid hash algorithm");
+ goto leave;
+ }
}
else
algo = 0;
+ opt_inquire = has_option (line, "--inquire");
line = skip_options (line);
- if (!algo)
+ if (!algo && !opt_inquire)
{
/* No hash option has been given: require an algo number instead */
algo = (int)strtoul (line, &endp, 10);
for (line = endp; *line == ' ' || *line == '\t'; line++)
;
if (!algo || gcry_md_test_algo (algo))
- return set_error (GPG_ERR_UNSUPPORTED_ALGORITHM, NULL);
+ {
+ err = set_error (GPG_ERR_UNSUPPORTED_ALGORITHM, NULL);
+ goto leave;
+ }
}
+ xfree (ctrl->digest.data);
+ ctrl->digest.data = NULL;
ctrl->digest.algo = algo;
ctrl->digest.raw_value = 0;
- /* Parse the hash value. */
- n = 0;
- rc = parse_hexstring (ctx, line, &n);
- if (rc)
- return rc;
- n /= 2;
- if (algo == MD_USER_TLS_MD5SHA1 && n == 36)
- ;
- else if (n != 16 && n != 20 && n != 24
- && n != 28 && n != 32 && n != 48 && n != 64)
- return set_error (GPG_ERR_ASS_PARAMETER, "unsupported length of hash");
-
- if (n > MAX_DIGEST_LEN)
- return set_error (GPG_ERR_ASS_PARAMETER, "hash value to long");
-
- buf = ctrl->digest.value;
- ctrl->digest.valuelen = n;
- for (p=line, n=0; n < ctrl->digest.valuelen; p += 2, n++)
- buf[n] = xtoi_2 (p);
- for (; n < ctrl->digest.valuelen; n++)
- buf[n] = 0;
- return 0;
+ if (opt_inquire)
+ {
+ /* We limit the to-be-signed data to some reasonable size which
+ * may eventually allow us to pass that even to smartcards. */
+ size_t maxlen = 2048;
+
+ if (algo)
+ {
+ err = set_error (GPG_ERR_ASS_PARAMETER,
+ "both --inquire and an algo are specified");
+ goto leave;
+ }
+
+ err = print_assuan_status (ctx, "INQUIRE_MAXLEN", "%zu", maxlen);
+ if (!err)
+ err = assuan_inquire (ctx, "TBSDATA", &buf, &n, maxlen);
+ if (err)
+ goto leave;
+
+ ctrl->digest.data = buf;
+ ctrl->digest.valuelen = n;
+ }
+ else
+ {
+ /* Parse the hash value. */
+ n = 0;
+ err = parse_hexstring (ctx, line, &n);
+ if (err)
+ goto leave;
+ n /= 2;
+ if (algo == MD_USER_TLS_MD5SHA1 && n == 36)
+ ;
+ else if (n != 16 && n != 20 && n != 24
+ && n != 28 && n != 32 && n != 48 && n != 64)
+ {
+ err = set_error (GPG_ERR_ASS_PARAMETER, "unsupported length of hash");
+ goto leave;
+ }
+
+ if (n > MAX_DIGEST_LEN)
+ {
+ err = set_error (GPG_ERR_ASS_PARAMETER, "hash value to long");
+ goto leave;
+ }
+
+ buf = ctrl->digest.value;
+ ctrl->digest.valuelen = n;
+ for (p=line, n=0; n < ctrl->digest.valuelen; p += 2, n++)
+ buf[n] = xtoi_2 (p);
+ for (; n < ctrl->digest.valuelen; n++)
+ buf[n] = 0;
+ }
+
+ leave:
+ return leave_cmd (ctx, err);
}
@@ -3627,6 +3674,7 @@ start_command_handler (ctrl_t ctrl, gnupg_fd_t listen_fd, gnupg_fd_t fd)
ctrl->server_local->assuan_ctx = ctx;
ctrl->server_local->use_cache_for_signing = 1;
+ ctrl->digest.data = NULL;
ctrl->digest.raw_value = 0;
assuan_set_io_monitor (ctx, io_monitor, NULL);
diff --git a/agent/divert-scd.c b/agent/divert-scd.c
index d8076d158..7587d4478 100644
--- a/agent/divert-scd.c
+++ b/agent/divert-scd.c
@@ -437,7 +437,14 @@ divert_pksign (ctrl_t ctrl, const char *desc_text, const unsigned char *grip,
/* Note that the KID may be an keyref or a keygrip. The signing
* functions handle both. */
- if (algo == MD_USER_TLS_MD5SHA1)
+ if (!algo)
+ {
+ /* This is the PureEdDSA case. (DIGEST,DIGESTLEN) this the
+ * entire data which will be signed. */
+ rc = agent_card_pksign (ctrl, kid, getpin_cb, ctrl, NULL,
+ 0, digest, digestlen, &sigval, &siglen);
+ }
+ else if (algo == MD_USER_TLS_MD5SHA1)
{
int save = ctrl->use_auth_call;
ctrl->use_auth_call = 1;
diff --git a/agent/gpg-agent.c b/agent/gpg-agent.c
index a7573c2ab..4466389a3 100644
--- a/agent/gpg-agent.c
+++ b/agent/gpg-agent.c
@@ -1937,6 +1937,8 @@ agent_deinit_default_ctrl (ctrl_t ctrl)
unregister_progress_cb ();
session_env_release (ctrl->session_env);
+ xfree (ctrl->digest.data);
+ ctrl->digest.data = NULL;
if (ctrl->lc_ctype)
xfree (ctrl->lc_ctype);
if (ctrl->lc_messages)
diff --git a/agent/pksign.c b/agent/pksign.c
index 3474f9434..76b0c3f85 100644
--- a/agent/pksign.c
+++ b/agent/pksign.c
@@ -304,6 +304,11 @@ agent_pksign_do (ctrl_t ctrl, const char *cache_nonce,
data = overridedata;
datalen = overridedatalen;
}
+ else if (ctrl->digest.data)
+ {
+ data = ctrl->digest.data;
+ datalen = ctrl->digest.valuelen;
+ }
else
{
data = ctrl->digest.value;