1
0
Fork 0
mirror of git://git.gnupg.org/gnupg.git synced 2025-07-02 22:46:30 +02:00

ssh: Support ECDSA keys.

* agent/command-ssh.c (SPEC_FLAG_IS_ECDSA): New.
(struct ssh_key_type_spec): Add fields CURVE_NAME and HASH_ALGO.
(ssh_key_types): Add types ecdsa-sha2-nistp{256,384,521}.
(ssh_signature_encoder_t): Add arg spec and adjust all callers.
(ssh_signature_encoder_ecdsa): New.
(sexp_key_construct, sexp_key_extract, ssh_receive_key)
(ssh_convert_key_to_blob): Support ecdsa.
(ssh_identifier_from_curve_name): New.
(ssh_send_key_public): Retrieve and pass the curve_name.
(key_secret_to_public): Ditto.
(data_sign): Add arg SPEC and change callers to pass it.
(ssh_handler_sign_request): Get the hash algo from SPEC.
* common/ssh-utils.c (get_fingerprint): Support ecdsa.

* agent/protect.c (protect_info): Add flag ECC_HACK.
(agent_protect): Allow the use of the "curve" parameter.
* agent/t-protect.c (test_agent_protect): Add a test case for ecdsa.

* agent/command-ssh.c (ssh_key_grip): Print a better error code.
--

The 3 standard curves are now supported in gpg-agent's ssh-agent
protocol implementation.  I tested this with all 3 curves and keys
generated by OpenSSH 5.9p1.

Using existing non-ssh generated keys will likely fail for now. To fix
this, the code should first undergo some more cleanup; then the fixes
are pretty straightforward.  And yes, the data structures are way too
complicated.
This commit is contained in:
Werner Koch 2012-12-12 18:47:21 +01:00
parent f76a0312c3
commit 649b31c663
4 changed files with 384 additions and 106 deletions

View file

@ -51,13 +51,14 @@ static struct {
const char *algo;
const char *parmlist;
int prot_from, prot_to;
int ecc_hack;
} protect_info[] = {
{ "rsa", "nedpqu", 2, 5 },
{ "dsa", "pqgyx", 4, 4 },
{ "elg", "pgyx", 3, 3 },
{ "ecdsa","pabgnqd", 6, 6 },
{ "ecdh", "pabgnqd", 6, 6 },
{ "ecc", "pabgnqd", 6, 6 },
{ "ecdsa","pabgnqd", 6, 6, 1 },
{ "ecdh", "pabgnqd", 6, 6, 1 },
{ "ecc", "pabgnqd", 6, 6, 1 },
{ NULL }
};
@ -450,6 +451,8 @@ agent_protect (const unsigned char *plainkey, const char *passphrase,
unsigned long s2k_count)
{
int rc;
const char *parmlist;
int prot_from_idx, prot_to_idx;
const unsigned char *s;
const unsigned char *hash_begin, *hash_end;
const unsigned char *prot_begin, *prot_end, *real_end;
@ -494,10 +497,13 @@ agent_protect (const unsigned char *plainkey, const char *passphrase,
if (!protect_info[infidx].algo)
return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM);
parmlist = protect_info[infidx].parmlist;
prot_from_idx = protect_info[infidx].prot_from;
prot_to_idx = protect_info[infidx].prot_to;
prot_begin = prot_end = NULL;
for (i=0; (c=protect_info[infidx].parmlist[i]); i++)
for (i=0; (c=parmlist[i]); i++)
{
if (i == protect_info[infidx].prot_from)
if (i == prot_from_idx)
prot_begin = s;
if (*s != '(')
return gpg_error (GPG_ERR_INV_SEXP);
@ -507,7 +513,20 @@ agent_protect (const unsigned char *plainkey, const char *passphrase,
if (!n)
return gpg_error (GPG_ERR_INV_SEXP);
if (n != 1 || c != *s)
return gpg_error (GPG_ERR_INV_SEXP);
{
if (n == 5 && !memcmp (s, "curve", 5)
&& !i && protect_info[infidx].ecc_hack)
{
/* This is a private ECC key but the first parameter is
the name of the curve. We change the parameter list
here to the one we expect in this case. */
parmlist = "?qd";
prot_from_idx = 2;
prot_to_idx = 2;
}
else
return gpg_error (GPG_ERR_INV_SEXP);
}
s += n;
n = snext (&s);
if (!n)
@ -516,7 +535,7 @@ agent_protect (const unsigned char *plainkey, const char *passphrase,
if (*s != ')')
return gpg_error (GPG_ERR_INV_SEXP);
depth--;
if (i == protect_info[infidx].prot_to)
if (i == prot_to_idx)
prot_end = s;
s++;
}
@ -533,7 +552,6 @@ agent_protect (const unsigned char *plainkey, const char *passphrase,
assert (!depth);
real_end = s-1;
/* Hash the stuff. Because the timestamp_exp won't get protected,
we can't simply hash a continuous buffer but need to use several
md_writes. */