1
0
mirror of git://git.gnupg.org/gnupg.git synced 2024-05-28 21:50:02 +02:00

ssh: Simplify the curve name lookup.

* agent/command-ssh.c (struct ssh_key_type_spec): Add field
alt_curve_name.
(ssh_key_types): Add some alternate curve names.
(ssh_identifier_from_curve_name): Lookup also bey alternative names
and return the canonical name.
(ssh_key_to_blob): Simplify the ECDSA case by using gcry_pk_get_curve
instead of the explicit mapping.
(ssh_receive_key): Likewise.  Use ssh_identifier_from_curve_name to
validate the curve name.  Remove the reverse mapping because since
GnuPG-2.2 Libgcrypt 1.7 is required.
(ssh_handler_request_identities): Log an error message.
--

This change will make it easier to support other curves, in particular
those from tokens.  Libgcrypt has a large list of alias names which we
now use to to make the mapping more flexible.

Signed-off-by: Werner Koch <wk@gnupg.org>
(cherry picked from commit d93797c8a7)
This commit is contained in:
Werner Koch 2019-01-17 15:42:33 +01:00
parent f5d3b982e4
commit 11a65159f9
No known key found for this signature in database
GPG Key ID: E3FDFF218E45B72B

View File

@ -195,9 +195,14 @@ struct ssh_key_type_spec
algorithm. */ algorithm. */
ssh_signature_encoder_t signature_encoder; ssh_signature_encoder_t signature_encoder;
/* The name of the ECC curve or NULL. */ /* The name of the ECC curve or NULL for non-ECC algos. This is the
* canonical name for the curve as specified by RFC-5656. */
const char *curve_name; const char *curve_name;
/* An alias for curve_name or NULL. Actually this is Libcgrypt's
* primary name of the curve. */
const char *alt_curve_name;
/* The hash algorithm to be used with this key. 0 for using the /* The hash algorithm to be used with this key. 0 for using the
default. */ default. */
int hash_algo; int hash_algo;
@ -292,68 +297,71 @@ static const ssh_key_type_spec_t ssh_key_types[] =
{ {
"ssh-ed25519", "Ed25519", GCRY_PK_EDDSA, "qd", "q", "rs", "qd", "ssh-ed25519", "Ed25519", GCRY_PK_EDDSA, "qd", "q", "rs", "qd",
NULL, ssh_signature_encoder_eddsa, NULL, ssh_signature_encoder_eddsa,
"Ed25519", 0, SPEC_FLAG_IS_EdDSA "Ed25519", NULL, 0, SPEC_FLAG_IS_EdDSA
}, },
{ {
"ssh-rsa", "RSA", GCRY_PK_RSA, "nedupq", "en", "s", "nedpqu", "ssh-rsa", "RSA", GCRY_PK_RSA, "nedupq", "en", "s", "nedpqu",
ssh_key_modifier_rsa, ssh_signature_encoder_rsa, ssh_key_modifier_rsa, ssh_signature_encoder_rsa,
NULL, 0, SPEC_FLAG_USE_PKCS1V2 NULL, NULL, 0, SPEC_FLAG_USE_PKCS1V2
}, },
{ {
"ssh-dss", "DSA", GCRY_PK_DSA, "pqgyx", "pqgy", "rs", "pqgyx", "ssh-dss", "DSA", GCRY_PK_DSA, "pqgyx", "pqgy", "rs", "pqgyx",
NULL, ssh_signature_encoder_dsa, NULL, ssh_signature_encoder_dsa,
NULL, 0, 0 NULL, NULL, 0, 0
}, },
{ {
"ecdsa-sha2-nistp256", "ECDSA", GCRY_PK_ECC, "qd", "q", "rs", "qd", "ecdsa-sha2-nistp256", "ECDSA", GCRY_PK_ECC, "qd", "q", "rs", "qd",
NULL, ssh_signature_encoder_ecdsa, NULL, ssh_signature_encoder_ecdsa,
"nistp256", GCRY_MD_SHA256, SPEC_FLAG_IS_ECDSA "nistp256", "NIST P-256", GCRY_MD_SHA256, SPEC_FLAG_IS_ECDSA
}, },
{ {
"ecdsa-sha2-nistp384", "ECDSA", GCRY_PK_ECC, "qd", "q", "rs", "qd", "ecdsa-sha2-nistp384", "ECDSA", GCRY_PK_ECC, "qd", "q", "rs", "qd",
NULL, ssh_signature_encoder_ecdsa, NULL, ssh_signature_encoder_ecdsa,
"nistp384", GCRY_MD_SHA384, SPEC_FLAG_IS_ECDSA "nistp384", "NIST P-384", GCRY_MD_SHA384, SPEC_FLAG_IS_ECDSA
}, },
{ {
"ecdsa-sha2-nistp521", "ECDSA", GCRY_PK_ECC, "qd", "q", "rs", "qd", "ecdsa-sha2-nistp521", "ECDSA", GCRY_PK_ECC, "qd", "q", "rs", "qd",
NULL, ssh_signature_encoder_ecdsa, NULL, ssh_signature_encoder_ecdsa,
"nistp521", GCRY_MD_SHA512, SPEC_FLAG_IS_ECDSA "nistp521", "NIST P-521", GCRY_MD_SHA512, SPEC_FLAG_IS_ECDSA
}, },
{ {
"ssh-ed25519-cert-v01@openssh.com", "Ed25519", "ssh-ed25519-cert-v01@openssh.com", "Ed25519",
GCRY_PK_EDDSA, "qd", "q", "rs", "qd", GCRY_PK_EDDSA, "qd", "q", "rs", "qd",
NULL, ssh_signature_encoder_eddsa, NULL, ssh_signature_encoder_eddsa,
"Ed25519", 0, SPEC_FLAG_IS_EdDSA | SPEC_FLAG_WITH_CERT "Ed25519", NULL, 0, SPEC_FLAG_IS_EdDSA | SPEC_FLAG_WITH_CERT
}, },
{ {
"ssh-rsa-cert-v01@openssh.com", "RSA", "ssh-rsa-cert-v01@openssh.com", "RSA",
GCRY_PK_RSA, "nedupq", "en", "s", "nedpqu", GCRY_PK_RSA, "nedupq", "en", "s", "nedpqu",
ssh_key_modifier_rsa, ssh_signature_encoder_rsa, ssh_key_modifier_rsa, ssh_signature_encoder_rsa,
NULL, 0, SPEC_FLAG_USE_PKCS1V2 | SPEC_FLAG_WITH_CERT NULL, NULL, 0, SPEC_FLAG_USE_PKCS1V2 | SPEC_FLAG_WITH_CERT
}, },
{ {
"ssh-dss-cert-v01@openssh.com", "DSA", "ssh-dss-cert-v01@openssh.com", "DSA",
GCRY_PK_DSA, "pqgyx", "pqgy", "rs", "pqgyx", GCRY_PK_DSA, "pqgyx", "pqgy", "rs", "pqgyx",
NULL, ssh_signature_encoder_dsa, NULL, ssh_signature_encoder_dsa,
NULL, 0, SPEC_FLAG_WITH_CERT | SPEC_FLAG_WITH_CERT NULL, NULL, 0, SPEC_FLAG_WITH_CERT | SPEC_FLAG_WITH_CERT
}, },
{ {
"ecdsa-sha2-nistp256-cert-v01@openssh.com", "ECDSA", "ecdsa-sha2-nistp256-cert-v01@openssh.com", "ECDSA",
GCRY_PK_ECC, "qd", "q", "rs", "qd", GCRY_PK_ECC, "qd", "q", "rs", "qd",
NULL, ssh_signature_encoder_ecdsa, NULL, ssh_signature_encoder_ecdsa,
"nistp256", GCRY_MD_SHA256, SPEC_FLAG_IS_ECDSA | SPEC_FLAG_WITH_CERT "nistp256", "NIST P-256", GCRY_MD_SHA256,
SPEC_FLAG_IS_ECDSA | SPEC_FLAG_WITH_CERT
}, },
{ {
"ecdsa-sha2-nistp384-cert-v01@openssh.com", "ECDSA", "ecdsa-sha2-nistp384-cert-v01@openssh.com", "ECDSA",
GCRY_PK_ECC, "qd", "q", "rs", "qd", GCRY_PK_ECC, "qd", "q", "rs", "qd",
NULL, ssh_signature_encoder_ecdsa, NULL, ssh_signature_encoder_ecdsa,
"nistp384", GCRY_MD_SHA384, SPEC_FLAG_IS_ECDSA | SPEC_FLAG_WITH_CERT "nistp384", "NIST P-384", GCRY_MD_SHA384,
SPEC_FLAG_IS_ECDSA | SPEC_FLAG_WITH_CERT
}, },
{ {
"ecdsa-sha2-nistp521-cert-v01@openssh.com", "ECDSA", "ecdsa-sha2-nistp521-cert-v01@openssh.com", "ECDSA",
GCRY_PK_ECC, "qd", "q", "rs", "qd", GCRY_PK_ECC, "qd", "q", "rs", "qd",
NULL, ssh_signature_encoder_ecdsa, NULL, ssh_signature_encoder_ecdsa,
"nistp521", GCRY_MD_SHA512, SPEC_FLAG_IS_ECDSA | SPEC_FLAG_WITH_CERT "nistp521", "NIST P-521", GCRY_MD_SHA512,
SPEC_FLAG_IS_ECDSA | SPEC_FLAG_WITH_CERT
} }
}; };
@ -384,16 +392,24 @@ realloc_secure (void *a, size_t n)
/* Lookup the ssh-identifier for the ECC curve CURVE_NAME. Returns /* Lookup the ssh-identifier for the ECC curve CURVE_NAME. Returns
NULL if not found. */ * NULL if not found. If found the ssh indetifier is returned and a
* pointer to the canonical curve name as specified for ssh is stored
* at R_CANON_NAME. */
static const char * static const char *
ssh_identifier_from_curve_name (const char *curve_name) ssh_identifier_from_curve_name (const char *curve_name,
const char **r_canon_name)
{ {
int i; int i;
for (i = 0; i < DIM (ssh_key_types); i++) for (i = 0; i < DIM (ssh_key_types); i++)
if (ssh_key_types[i].curve_name if (ssh_key_types[i].curve_name
&& !strcmp (ssh_key_types[i].curve_name, curve_name)) && (!strcmp (ssh_key_types[i].curve_name, curve_name)
return ssh_key_types[i].ssh_identifier; || (ssh_key_types[i].alt_curve_name
&& !strcmp (ssh_key_types[i].alt_curve_name, curve_name))))
{
*r_canon_name = ssh_key_types[i].curve_name;
return ssh_key_types[i].ssh_identifier;
}
return NULL; return NULL;
} }
@ -1844,7 +1860,6 @@ ssh_key_to_blob (gcry_sexp_t sexp, int with_secret,
gpg_error_t err = 0; gpg_error_t err = 0;
gcry_sexp_t value_list = NULL; gcry_sexp_t value_list = NULL;
gcry_sexp_t value_pair = NULL; gcry_sexp_t value_pair = NULL;
char *curve_name = NULL;
estream_t stream = NULL; estream_t stream = NULL;
void *blob = NULL; void *blob = NULL;
size_t blob_size; size_t blob_size;
@ -1862,7 +1877,7 @@ ssh_key_to_blob (gcry_sexp_t sexp, int with_secret,
goto out; goto out;
} }
/* Get the type of the key extpression. */ /* Get the type of the key expression. */
data = gcry_sexp_nth_data (sexp, 0, &datalen); data = gcry_sexp_nth_data (sexp, 0, &datalen);
if (!data) if (!data)
{ {
@ -1893,49 +1908,17 @@ ssh_key_to_blob (gcry_sexp_t sexp, int with_secret,
/* Write the ssh algorithm identifier. */ /* Write the ssh algorithm identifier. */
if ((key_spec.flags & SPEC_FLAG_IS_ECDSA)) if ((key_spec.flags & SPEC_FLAG_IS_ECDSA))
{ {
/* Parse the "curve" parameter. We currently expect the curve /* Map the curve name to the ssh name. */
name for ECC and not the parameters of the curve. This can const char *name, *sshname, *canon_name;
easily be changed but then we need to find the curve name
from the parameters using gcry_pk_get_curve. */
const char *mapped;
const char *sshname;
gcry_sexp_release (value_pair); name = gcry_pk_get_curve (sexp, 0, NULL);
value_pair = gcry_sexp_find_token (value_list, "curve", 5); if (!name)
if (!value_pair)
{
err = gpg_error (GPG_ERR_INV_CURVE);
goto out;
}
curve_name = gcry_sexp_nth_string (value_pair, 1);
if (!curve_name)
{
err = gpg_error (GPG_ERR_INV_CURVE); /* (Or out of core.) */
goto out;
}
/* Fixme: The mapping should be done by using gcry_pk_get_curve
et al to iterate over all name aliases. */
if (!strcmp (curve_name, "NIST P-256"))
mapped = "nistp256";
else if (!strcmp (curve_name, "NIST P-384"))
mapped = "nistp384";
else if (!strcmp (curve_name, "NIST P-521"))
mapped = "nistp521";
else
mapped = NULL;
if (mapped)
{ {
xfree (curve_name); err = gpg_error (GPG_ERR_INV_CURVE);
curve_name = xtrystrdup (mapped); goto out;
if (!curve_name)
{
err = gpg_error_from_syserror ();
goto out;
}
} }
sshname = ssh_identifier_from_curve_name (curve_name); sshname = ssh_identifier_from_curve_name (name, &canon_name);
if (!sshname) if (!sshname)
{ {
err = gpg_error (GPG_ERR_UNKNOWN_CURVE); err = gpg_error (GPG_ERR_UNKNOWN_CURVE);
@ -1944,7 +1927,7 @@ ssh_key_to_blob (gcry_sexp_t sexp, int with_secret,
err = stream_write_cstring (stream, sshname); err = stream_write_cstring (stream, sshname);
if (err) if (err)
goto out; goto out;
err = stream_write_cstring (stream, curve_name); err = stream_write_cstring (stream, canon_name);
if (err) if (err)
goto out; goto out;
} }
@ -2017,7 +2000,6 @@ ssh_key_to_blob (gcry_sexp_t sexp, int with_secret,
out: out:
gcry_sexp_release (value_list); gcry_sexp_release (value_list);
gcry_sexp_release (value_pair); gcry_sexp_release (value_pair);
xfree (curve_name);
es_fclose (stream); es_fclose (stream);
es_free (blob); es_free (blob);
@ -2076,7 +2058,7 @@ ssh_receive_key (estream_t stream, gcry_sexp_t *key_new, int secret,
ssh_key_type_spec_t spec; ssh_key_type_spec_t spec;
gcry_mpi_t *mpi_list = NULL; gcry_mpi_t *mpi_list = NULL;
const char *elems; const char *elems;
char *curve_name = NULL; const char *curve_name = NULL;
err = stream_read_cstring (stream, &key_type); err = stream_read_cstring (stream, &key_type);
@ -2199,34 +2181,19 @@ ssh_receive_key (estream_t stream, gcry_sexp_t *key_new, int secret,
* certificate. * certificate.
*/ */
unsigned char *buffer; unsigned char *buffer;
const char *mapped;
err = stream_read_string (cert? cert : stream, 0, &buffer, NULL); err = stream_read_string (cert? cert : stream, 0, &buffer, NULL);
if (err) if (err)
goto out; goto out;
curve_name = buffer; /* Get the canonical name. Should be the same as the read
/* Fixme: Check that curve_name matches the keytype. */ * string but we use this mapping to validate that name. */
/* Because Libgcrypt < 1.6 has no support for the "nistpNNN" if (!ssh_identifier_from_curve_name (buffer, &curve_name))
curve names, we need to translate them here to Libgcrypt's
native names. */
if (!strcmp (curve_name, "nistp256"))
mapped = "NIST P-256";
else if (!strcmp (curve_name, "nistp384"))
mapped = "NIST P-384";
else if (!strcmp (curve_name, "nistp521"))
mapped = "NIST P-521";
else
mapped = NULL;
if (mapped)
{ {
xfree (curve_name); err = gpg_error (GPG_ERR_UNKNOWN_CURVE);
curve_name = xtrystrdup (mapped); xfree (buffer);
if (!curve_name) goto out;
{
err = gpg_error_from_syserror ();
goto out;
}
} }
xfree (buffer);
err = ssh_receive_mpint_list (stream, secret, &spec, cert, &mpi_list); err = ssh_receive_mpint_list (stream, secret, &spec, cert, &mpi_list);
if (err) if (err)
@ -2294,7 +2261,6 @@ ssh_receive_key (estream_t stream, gcry_sexp_t *key_new, int secret,
out: out:
es_fclose (cert); es_fclose (cert);
mpint_list_free (mpi_list); mpint_list_free (mpi_list);
xfree (curve_name);
xfree (key_type); xfree (key_type);
xfree (comment); xfree (comment);
@ -2642,6 +2608,8 @@ ssh_handler_request_identities (ctrl_t ctrl,
continue; continue;
err = ssh_send_key_public (key_blobs, key_public, cardsn); err = ssh_send_key_public (key_blobs, key_public, cardsn);
if (err && opt.verbose)
gcry_log_debugsxp ("pubkey", key_public);
gcry_sexp_release (key_public); gcry_sexp_release (key_public);
key_public = NULL; key_public = NULL;
xfree (cardsn); xfree (cardsn);
@ -2717,6 +2685,8 @@ ssh_handler_request_identities (ctrl_t ctrl,
} }
else else
{ {
log_error ("ssh request identities failed: %s <%s>\n",
gpg_strerror (err), gpg_strsource (err));
ret_err = stream_write_byte (response, SSH_RESPONSE_FAILURE); ret_err = stream_write_byte (response, SSH_RESPONSE_FAILURE);
} }