agent: Cleanups to prepare implementation of Ed25519.

* agent/cvt-openpgp.c: Remove.
(convert_to_openpgp): Use gcry_sexp_extract_param.
* agent/findkey.c (is_eddsa): New.
(agent_is_dsa_key, agent_is_eddsa_key): Check whether ecc means EdDSA.
* agent/pksign.c (agent_pksign_do): Add args OVERRIDEDATA and
OVERRIDEDATALEN.

* common/ssh-utils.c (is_eddsa): New.
(get_fingerprint): Take care or EdDSA.
This commit is contained in:
Werner Koch 2014-03-22 20:51:16 +01:00
parent 6376227a31
commit a77ed0f266
7 changed files with 240 additions and 119 deletions

View File

@ -368,7 +368,8 @@ char *agent_get_cache (const char *key, cache_mode_t cache_mode);
int agent_pksign_do (ctrl_t ctrl, const char *cache_nonce,
const char *desc_text,
gcry_sexp_t *signature_sexp,
cache_mode_t cache_mode, lookup_ttl_t lookup_ttl);
cache_mode_t cache_mode, lookup_ttl_t lookup_ttl,
const void *overridedata, size_t overridedatalen);
int agent_pksign (ctrl_t ctrl, const char *cache_nonce,
const char *desc_text,
membuf_t *outbuf, cache_mode_t cache_mode);

View File

@ -2515,7 +2515,8 @@ data_sign (ctrl_t ctrl, ssh_key_type_spec_t *spec,
_("Please enter the passphrase "
"for the ssh key%%0A %F%%0A (%c)"),
&signature_sexp,
CACHE_MODE_SSH, ttl_from_sshcontrol);
CACHE_MODE_SSH, ttl_from_sshcontrol,
NULL, 0);
ctrl->use_auth_call = 0;
if (err)
goto out;

View File

@ -2147,7 +2147,7 @@ cmd_export_key (assuan_context_t ctx, char *line)
if (!ctrl->server_local->export_key)
{
err = gpg_error (GPG_ERR_MISSING_KEY);
err = set_error (GPG_ERR_MISSING_KEY, "did you run KEYWRAP_KEY");
goto leave;
}

View File

@ -1030,46 +1030,6 @@ convert_from_openpgp_native (ctrl_t ctrl,
}
static gpg_error_t
key_from_sexp (gcry_sexp_t sexp, const char *elems, gcry_mpi_t *array)
{
gpg_error_t err = 0;
gcry_sexp_t l2;
int idx;
for (idx=0; *elems; elems++, idx++)
{
l2 = gcry_sexp_find_token (sexp, elems, 1);
if (!l2)
{
err = gpg_error (GPG_ERR_NO_OBJ); /* Required parameter not found. */
goto leave;
}
array[idx] = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG);
gcry_sexp_release (l2);
if (!array[idx])
{
err = gpg_error (GPG_ERR_INV_OBJ); /* Required parameter invalid. */
goto leave;
}
}
leave:
if (err)
{
int i;
for (i=0; i < idx; i++)
{
gcry_mpi_release (array[i]);
array[i] = NULL;
}
}
return err;
}
/* Given an ARRAY of mpis with the key parameters, protect the secret
parameters in that array and replace them by one opaque encoded
mpi. NPKEY is the number of public key parameters and NSKEY is
@ -1173,7 +1133,6 @@ convert_to_openpgp (ctrl_t ctrl, gcry_sexp_t s_key, const char *passphrase,
gpg_error_t err;
gcry_sexp_t list, l2;
char *name;
int algo;
const char *algoname;
const char *elems;
int npkey, nskey;
@ -1203,26 +1162,63 @@ convert_to_openpgp (ctrl_t ctrl, gcry_sexp_t s_key, const char *passphrase,
return gpg_error (GPG_ERR_INV_OBJ); /* Invalid structure of object. */
}
algo = gcry_pk_map_name (name);
xfree (name);
switch (algo)
/* Map NAME to a name as used by Libgcrypt. We do not use the
Libgcrypt function here because we need a lowercase name and
require special treatment for some algorithms. */
strlwr (name);
if (!strcmp (name, "rsa"))
{
case GCRY_PK_RSA: algoname = "rsa"; npkey = 2; elems = "nedpqu"; break;
case GCRY_PK_ELG: algoname = "elg"; npkey = 3; elems = "pgyx"; break;
case GCRY_PK_ELG_E: algoname = "elg"; npkey = 3; elems = "pgyx"; break;
case GCRY_PK_DSA: algoname = "dsa"; npkey = 4; elems = "pqgyx"; break;
case GCRY_PK_ECDSA: algoname = "ecdsa"; npkey = 6; elems = "pabgnqd"; break;
case GCRY_PK_ECDH: algoname = "ecdh"; npkey = 6; elems = "pabgnqd"; break;
default: algoname = ""; npkey = 0; elems = NULL; break;
algoname = "rsa";
npkey = 2;
elems = "nedpqu";
}
else if (!strcmp (name, "elg"))
{
algoname = "elg";
npkey = 3;
elems = "pgyx";
}
else if (!strcmp (name, "dsa"))
{
algoname = "dsa";
npkey = 4;
elems = "pqgyx";
}
else if (!strcmp (name, "ecc"))
{
algoname = "?"; /* Decide later by checking the usage. */
npkey = 6;
elems = "pabgnqd";
}
else if (!strcmp (name, "ecdsa"))
{
algoname = "ecdsa";
npkey = 6;
elems = "pabgnqd";
}
else if (!strcmp (name, "ecdh"))
{
algoname = "ecdh";
npkey = 6;
elems = "pabgnqd";
}
else
{
algoname = "";
npkey = 0;
elems = NULL;
}
xfree (name);
assert (!elems || strlen (elems) < DIM (array) );
nskey = elems? strlen (elems) : 0;
/* Extract the parameters and put them into an array. */
if (!elems)
err = gpg_error (GPG_ERR_PUBKEY_ALGO);
else
err = key_from_sexp (list, elems, array);
err = gcry_sexp_extract_param (list, NULL, elems,
array+0, array+1, array+2, array+3, array+4,
array+5, array+6, NULL);
gcry_sexp_release (list);
if (err)
return err;

View File

@ -688,7 +688,7 @@ agent_key_from_file (ctrl_t ctrl, const char *cache_nonce,
string describing the names of the parameters. ALGONAMESIZE and
ELEMSSIZE give the allocated size of the provided buffers. The
buffers may be NULL if not required. If R_LIST is not NULL the top
level list will be stored tehre; the caller needs to release it in
level list will be stored there; the caller needs to release it in
this case. */
static gpg_error_t
key_parms_from_sexp (gcry_sexp_t s_key, gcry_sexp_t *r_list,
@ -776,27 +776,65 @@ key_parms_from_sexp (gcry_sexp_t s_key, gcry_sexp_t *r_list,
}
/* Return true if KEYPARMS holds an EdDSA key. */
static int
is_eddsa (gcry_sexp_t keyparms)
{
int result = 0;
gcry_sexp_t list;
const char *s;
size_t n;
int i;
list = gcry_sexp_find_token (keyparms, "flags", 0);
for (i = list ? gcry_sexp_length (list)-1 : 0; i > 0; i--)
{
s = gcry_sexp_nth_data (list, i, &n);
if (!s)
continue; /* Not a data element. */
if (n == 5 && !memcmp (s, "eddsa", 5))
{
result = 1;
break;
}
}
gcry_sexp_release (list);
return result;
}
/* Return the public key algorithm number if S_KEY is a DSA style key.
If it is not a DSA style key, return 0. */
int
agent_is_dsa_key (gcry_sexp_t s_key)
{
int result;
gcry_sexp_t list;
char algoname[6];
if (!s_key)
return 0;
if (key_parms_from_sexp (s_key, NULL, algoname, sizeof algoname, NULL, 0))
if (key_parms_from_sexp (s_key, &list, algoname, sizeof algoname, NULL, 0))
return 0; /* Error - assume it is not an DSA key. */
if (!strcmp (algoname, "dsa"))
return GCRY_PK_DSA;
result = GCRY_PK_DSA;
else if (!strcmp (algoname, "ecc"))
return GCRY_PK_ECDSA; /* FIXME: Check for the EdDSA flag. */
{
if (is_eddsa (list))
result = 0;
else
result = GCRY_PK_ECDSA;
}
else if (!strcmp (algoname, "ecdsa"))
return GCRY_PK_ECDSA;
result = GCRY_PK_ECDSA;
else
return 0;
result = 0;
gcry_sexp_release (list);
return result;
}
@ -804,18 +842,25 @@ agent_is_dsa_key (gcry_sexp_t s_key)
int
agent_is_eddsa_key (gcry_sexp_t s_key)
{
int result;
gcry_sexp_t list;
char algoname[6];
if (!s_key)
return 0;
if (key_parms_from_sexp (s_key, NULL, algoname, sizeof algoname, NULL, 0))
if (key_parms_from_sexp (s_key, &list, algoname, sizeof algoname, NULL, 0))
return 0; /* Error - assume it is not an EdDSA key. */
if (!strcmp (algoname, "eddsa"))
return 1;
if (!strcmp (algoname, "ecc") && is_eddsa (list))
result = 1;
else if (!strcmp (algoname, "eddsa")) /* backward compatibility. */
result = 1;
else
return 0;
result = 0;
gcry_sexp_release (list);
return result;
}

View File

@ -276,18 +276,35 @@ do_encode_raw_pkcs1 (const byte *md, size_t mdlen, unsigned int nbits,
the signature S-expression. LOOKUP is an optional function to
provide a way for lower layers to ask for the caching TTL. If a
CACHE_NONCE is given that cache item is first tried to get a
passphrase. */
passphrase. If OVERRIDEDATA is not NULL, OVERRIDEDATALEN bytes
from this buffer are used instead of the data in CTRL. The
override feature is required to allow the use of Ed25519 with ssh
because Ed25519 dies the hashing itself. */
int
agent_pksign_do (ctrl_t ctrl, const char *cache_nonce,
const char *desc_text,
gcry_sexp_t *signature_sexp,
cache_mode_t cache_mode, lookup_ttl_t lookup_ttl)
cache_mode_t cache_mode, lookup_ttl_t lookup_ttl,
const void *overridedata, size_t overridedatalen)
{
gcry_sexp_t s_skey = NULL, s_sig = NULL;
unsigned char *shadow_info = NULL;
unsigned int rc = 0; /* FIXME: gpg-error? */
const unsigned char *data;
int datalen;
if (! ctrl->have_keygrip)
if (overridedata)
{
data = overridedata;
datalen = overridedatalen;
}
else
{
data = ctrl->digest.value;
datalen = ctrl->digest.valuelen;
}
if (!ctrl->have_keygrip)
return gpg_error (GPG_ERR_NO_SECKEY);
rc = agent_key_from_file (ctrl, cache_nonce, desc_text, ctrl->keygrip,
@ -315,8 +332,7 @@ agent_pksign_do (ctrl_t ctrl, const char *cache_nonce,
is_ECDSA = 1;
rc = divert_pksign (ctrl,
ctrl->digest.value,
ctrl->digest.valuelen,
data, datalen,
ctrl->digest.algo,
shadow_info, &buf, &len);
if (rc)
@ -405,22 +421,18 @@ agent_pksign_do (ctrl_t ctrl, const char *cache_nonce,
/* Put the hash into a sexp */
if (agent_is_eddsa_key (s_skey))
rc = do_encode_eddsa (ctrl->digest.value,
ctrl->digest.valuelen,
rc = do_encode_eddsa (data, datalen,
&s_hash);
else if (ctrl->digest.algo == MD_USER_TLS_MD5SHA1)
rc = do_encode_raw_pkcs1 (ctrl->digest.value,
ctrl->digest.valuelen,
rc = do_encode_raw_pkcs1 (data, datalen,
gcry_pk_get_nbits (s_skey),
&s_hash);
else if ( (dsaalgo = agent_is_dsa_key (s_skey)) )
rc = do_encode_dsa (ctrl->digest.value,
ctrl->digest.valuelen,
rc = do_encode_dsa (data, datalen,
dsaalgo, s_skey,
&s_hash);
else
rc = do_encode_md (ctrl->digest.value,
ctrl->digest.valuelen,
rc = do_encode_md (data, datalen,
ctrl->digest.algo,
&s_hash,
ctrl->digest.raw_value);
@ -468,7 +480,8 @@ agent_pksign (ctrl_t ctrl, const char *cache_nonce, const char *desc_text,
size_t len = 0;
int rc = 0;
rc = agent_pksign_do (ctrl, cache_nonce, desc_text, &s_sig, cache_mode, NULL);
rc = agent_pksign_do (ctrl, cache_nonce, desc_text, &s_sig, cache_mode, NULL,
NULL, 0);
if (rc)
goto leave;

View File

@ -37,6 +37,33 @@
#include "ssh-utils.h"
/* Return true if KEYPARMS holds an EdDSA key. */
static int
is_eddsa (gcry_sexp_t keyparms)
{
int result = 0;
gcry_sexp_t list;
const char *s;
size_t n;
int i;
list = gcry_sexp_find_token (keyparms, "flags", 0);
for (i = list ? gcry_sexp_length (list)-1 : 0; i > 0; i--)
{
s = gcry_sexp_nth_data (list, i, &n);
if (!s)
continue; /* Not a data element. */
if (n == 5 && !memcmp (s, "eddsa", 5))
{
result = 1;
break;
}
}
gcry_sexp_release (list);
return result;
}
/* Return the Secure Shell type fingerprint for KEY. The length of
the fingerprint is returned at R_LEN and the fingerprint itself at
@ -53,6 +80,7 @@ get_fingerprint (gcry_sexp_t key, void **r_fpr, size_t *r_len, int as_string)
int idx;
const char *elems;
gcry_md_hd_t md = NULL;
int blobmode = 0;
*r_fpr = NULL;
*r_len = 0;
@ -93,38 +121,52 @@ get_fingerprint (gcry_sexp_t key, void **r_fpr, size_t *r_len, int as_string)
elems = "en";
gcry_md_write (md, "\0\0\0\x07ssh-rsa", 11);
break;
case GCRY_PK_DSA:
elems = "pqgy";
gcry_md_write (md, "\0\0\0\x07ssh-dss", 11);
break;
case GCRY_PK_ECDSA:
/* We only support the 3 standard curves for now. It is just a
quick hack. */
elems = "q";
gcry_md_write (md, "\0\0\0\x13" "ecdsa-sha2-nistp", 20);
l2 = gcry_sexp_find_token (list, "curve", 0);
if (!l2)
elems = "";
case GCRY_PK_ECC:
if (is_eddsa (list))
{
elems = "q";
blobmode = 1;
/* For now there is just one curve, thus no need to switch
on it. */
gcry_md_write (md, "\0\0\0\x0b" "ssh-ed25519", 15);
}
else
{
gcry_free (name);
name = gcry_sexp_nth_string (l2, 1);
gcry_sexp_release (l2);
l2 = NULL;
if (!name)
/* We only support the 3 standard curves for now. It is
just a quick hack. */
elems = "q";
gcry_md_write (md, "\0\0\0\x13" "ecdsa-sha2-nistp", 20);
l2 = gcry_sexp_find_token (list, "curve", 0);
if (!l2)
elems = "";
else if (!strcmp (name, "NIST P-256") || !strcmp (name, "nistp256"))
gcry_md_write (md, "256\0\0\0\x08nistp256", 15);
else if (!strcmp (name, "NIST P-384") || !strcmp (name, "nistp384"))
gcry_md_write (md, "384\0\0\0\x08nistp521", 15);
else if (!strcmp (name, "NIST P-521") || !strcmp (name, "nistp521"))
gcry_md_write (md, "521\0\0\0\x08nistp521", 15);
else
elems = "";
{
gcry_free (name);
name = gcry_sexp_nth_string (l2, 1);
gcry_sexp_release (l2);
l2 = NULL;
if (!name)
elems = "";
else if (!strcmp (name, "NIST P-256")||!strcmp (name, "nistp256"))
gcry_md_write (md, "256\0\0\0\x08nistp256", 15);
else if (!strcmp (name, "NIST P-384")||!strcmp (name, "nistp384"))
gcry_md_write (md, "384\0\0\0\x08nistp521", 15);
else if (!strcmp (name, "NIST P-521")||!strcmp (name, "nistp521"))
gcry_md_write (md, "521\0\0\0\x08nistp521", 15);
else
elems = "";
}
if (!*elems)
err = gpg_err_make (default_errsource, GPG_ERR_UNKNOWN_CURVE);
}
if (!*elems)
err = gpg_err_make (default_errsource, GPG_ERR_UNKNOWN_CURVE);
break;
default:
elems = "";
err = gpg_err_make (default_errsource, GPG_ERR_PUBKEY_ALGO);
@ -133,33 +175,56 @@ get_fingerprint (gcry_sexp_t key, void **r_fpr, size_t *r_len, int as_string)
if (err)
goto leave;
for (idx = 0, s = elems; *s; s++, idx++)
{
gcry_mpi_t a;
unsigned char *buf;
size_t buflen;
l2 = gcry_sexp_find_token (list, s, 1);
if (!l2)
{
err = gpg_err_make (default_errsource, GPG_ERR_INV_SEXP);
goto leave;
}
a = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG);
gcry_sexp_release (l2);
l2 = NULL;
if (!a)
if (blobmode)
{
err = gpg_err_make (default_errsource, GPG_ERR_INV_SEXP);
goto leave;
}
const char *blob;
size_t bloblen;
unsigned char lenbuf[4];
err = gcry_mpi_aprint (GCRYMPI_FMT_SSH, &buf, &buflen, a);
gcry_mpi_release (a);
if (err)
goto leave;
gcry_md_write (md, buf, buflen);
gcry_free (buf);
blob = gcry_sexp_nth_data (l2, 1, &bloblen);
if (!blob)
{
err = gpg_err_make (default_errsource, GPG_ERR_INV_SEXP);
goto leave;
}
lenbuf[0] = bloblen >> 24;
lenbuf[1] = bloblen >> 16;
lenbuf[2] = bloblen >> 8;
lenbuf[3] = bloblen;
gcry_md_write (md, lenbuf, 4);
gcry_md_write (md, blob, bloblen);
}
else
{
gcry_mpi_t a;
unsigned char *buf;
size_t buflen;
a = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG);
gcry_sexp_release (l2);
l2 = NULL;
if (!a)
{
err = gpg_err_make (default_errsource, GPG_ERR_INV_SEXP);
goto leave;
}
err = gcry_mpi_aprint (GCRYMPI_FMT_SSH, &buf, &buflen, a);
gcry_mpi_release (a);
if (err)
goto leave;
gcry_md_write (md, buf, buflen);
gcry_free (buf);
}
}
*r_fpr = gcry_malloc (as_string? 61:20);