aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJustus Winter <justus@g10code.com>2016-05-02 16:00:25 +0200
committerAndreas Schneider <asn@cryptomilk.org>2016-11-03 15:20:30 +0100
commitf62cded9f0bc2d08afe0ef2d79e247951f193559 (patch)
treef4e325a50af6f6b42f96b66170c2ab8f9a136f82
parent7e315629b9b70aae3b2a686def5cd053729652bd (diff)
downloadlibssh-f62cded9f0bc2d08afe0ef2d79e247951f193559.tar.gz
libssh-f62cded9f0bc2d08afe0ef2d79e247951f193559.tar.xz
libssh-f62cded9f0bc2d08afe0ef2d79e247951f193559.zip
pki_gcrypt: Handle ECDSA keys and signatures
* ConfigureChecks.cmake: Set 'HAVE_ECC' and 'HAVE_GCRYPT_ECC' if applicable. * include/libssh/pki.h (struct ssh_key_struct): Fix type of field 'ecdsa'. (struct ssh_signature_struct): Likewise for 'ecdsa_sig'. * src/pki.c (ssh_pki_key_ecdsa_name): Relax guard now that the used function is also provided by the gcrypt backend. (ssh_signature_free): Free ecdsa signature. * src/pki_gcrypt.c (ECDSA_HEADER_{BEGIN,END}): New macros. (privatekey_string_to_buffer): Handle ECDSA keys. (pki_key_ecdsa_to_nid): New function. (pki_key_ecdsa_nid_to_gcrypt_name): Likewise. (pki_key_ecdsa_nid_to_name): Likewise. (pki_key_ecdsa_nid_to_char): Likewise. (pki_key_ecdsa_nid_from_name): Implement. (asn1_oi_to_nid): New function. (b64decode_ecdsa_privatekey): Likewise. (pki_private_key_from_base64): Handle ECDSA keys. (pki_pubkey_build_ecdsa): Implement. (pki_key_dup): Handle ECDSA keys. (pki_key_generate): Likewise. (pki_key_generate_ecdsa): Implement. (pki_key_compare): Handle ECDSA keys. (pki_publickey_to_blob): Likewise. (pki_signature_from_blob): Likewise. (pki_signature_verify): Likewise. (pki_do_sign): Likewise. (pki_do_sign_sessionid): Likewise. Signed-off-by: Justus Winter <justus@g10code.com> Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
-rw-r--r--ConfigureChecks.cmake4
-rw-r--r--include/libssh/pki.h4
-rw-r--r--src/pki.c6
-rw-r--r--src/pki_gcrypt.c567
4 files changed, 570 insertions, 11 deletions
diff --git a/ConfigureChecks.cmake b/ConfigureChecks.cmake
index 1f4c8376..1917ce21 100644
--- a/ConfigureChecks.cmake
+++ b/ConfigureChecks.cmake
@@ -199,8 +199,8 @@ endif (OPENSSL_FOUND)
if (GCRYPT_FOUND)
set(HAVE_LIBGCRYPT 1)
if (GCRYPT_VERSION VERSION_GREATER "1.4.6")
- #set(HAVE_GCRYPT_ECC 1)
- #set(HAVE_ECC 1)
+ set(HAVE_GCRYPT_ECC 1)
+ set(HAVE_ECC 1)
endif (GCRYPT_VERSION VERSION_GREATER "1.4.6")
endif (GCRYPT_FOUND)
diff --git a/include/libssh/pki.h b/include/libssh/pki.h
index 905956b3..e0e30f1a 100644
--- a/include/libssh/pki.h
+++ b/include/libssh/pki.h
@@ -47,7 +47,7 @@ struct ssh_key_struct {
#ifdef HAVE_LIBGCRYPT
gcry_sexp_t dsa;
gcry_sexp_t rsa;
- void *ecdsa;
+ gcry_sexp_t ecdsa;
#elif HAVE_LIBCRYPTO
DSA *dsa;
RSA *rsa;
@@ -69,7 +69,7 @@ struct ssh_signature_struct {
#ifdef HAVE_LIBGCRYPT
gcry_sexp_t dsa_sig;
gcry_sexp_t rsa_sig;
- void *ecdsa_sig;
+ gcry_sexp_t ecdsa_sig;
#elif defined HAVE_LIBCRYPTO
DSA_SIG *dsa_sig;
ssh_string rsa_sig;
diff --git a/src/pki.c b/src/pki.c
index 2d48d255..1469a68d 100644
--- a/src/pki.c
+++ b/src/pki.c
@@ -91,7 +91,7 @@ enum ssh_keytypes_e pki_privatekey_type_from_string(const char *privkey) {
*/
const char *ssh_pki_key_ecdsa_name(const ssh_key key)
{
-#ifdef HAVE_OPENSSL_ECC /* FIXME Better ECC check needed */
+#ifdef HAVE_ECC /* FIXME Better ECC check needed */
return pki_key_ecdsa_nid_to_name(key->ecdsa_nid);
#else
(void) key; /* unused */
@@ -357,7 +357,9 @@ void ssh_signature_free(ssh_signature sig)
#endif
break;
case SSH_KEYTYPE_ECDSA:
-#if defined(HAVE_LIBCRYPTO) && defined(HAVE_OPENSSL_ECC)
+#ifdef HAVE_LIBGCRYPT_ECC
+ gcry_sexp_release(sig->ecdsa_sig);
+#elif defined(HAVE_LIBCRYPTO) && defined(HAVE_OPENSSL_ECC)
ECDSA_SIG_free(sig->ecdsa_sig);
#endif
break;
diff --git a/src/pki_gcrypt.c b/src/pki_gcrypt.c
index fefc0c13..e3ae06d5 100644
--- a/src/pki_gcrypt.c
+++ b/src/pki_gcrypt.c
@@ -27,6 +27,7 @@
#ifdef HAVE_LIBGCRYPT
+#include <assert.h>
#include <string.h>
#include <stdlib.h>
#include <gcrypt.h>
@@ -45,6 +46,8 @@
#define RSA_HEADER_END "-----END RSA PRIVATE KEY-----"
#define DSA_HEADER_BEGIN "-----BEGIN DSA PRIVATE KEY-----"
#define DSA_HEADER_END "-----END DSA PRIVATE KEY-----"
+#define ECDSA_HEADER_BEGIN "-----BEGIN EC PRIVATE KEY-----"
+#define ECDSA_HEADER_END "-----END EC PRIVATE KEY-----"
#define MAX_KEY_SIZE 32
#define MAX_PASSPHRASE_SIZE 1024
@@ -422,6 +425,10 @@ static ssh_buffer privatekey_string_to_buffer(const char *pkey, int type,
header_begin = RSA_HEADER_BEGIN;
header_end = RSA_HEADER_END;
break;
+ case SSH_KEYTYPE_ECDSA:
+ header_begin = ECDSA_HEADER_BEGIN;
+ header_end = ECDSA_HEADER_END;
+ break;
default:
ssh_buffer_free(buffer);
return NULL;
@@ -676,10 +683,210 @@ error:
}
#ifdef HAVE_GCRYPT_ECC
+static int pki_key_ecdsa_to_nid(gcry_sexp_t k)
+{
+ gcry_sexp_t sexp;
+ const char *tmp;
+ size_t size;
+
+ sexp = gcry_sexp_find_token(k, "curve", 0);
+ if (sexp == NULL) {
+ return -1;
+ }
+
+ tmp = gcry_sexp_nth_data(sexp, 1, &size);
+
+ if (size == 10) {
+ int cmp;
+
+ cmp = memcmp("NIST P-256", tmp, size);
+ if (cmp == 0) {
+ return NID_gcrypt_nistp256;
+ }
+
+ cmp = memcmp("NIST P-384", tmp, size);
+ if (cmp == 0) {
+ return NID_gcrypt_nistp384;
+ }
+
+ cmp = memcmp("NIST P-521", tmp, size);
+ if (cmp == 0) {
+ return NID_gcrypt_nistp521;
+ }
+ }
+
+ return -1;
+}
+
+static const char *pki_key_ecdsa_nid_to_gcrypt_name(int nid)
+{
+ switch (nid) {
+ case NID_gcrypt_nistp256:
+ return "NIST P-256";
+ case NID_gcrypt_nistp384:
+ return "NIST P-384";
+ case NID_gcrypt_nistp521:
+ return "NIST P-521";
+ }
+
+ return "unknown";
+}
+
+
+const char *pki_key_ecdsa_nid_to_name(int nid)
+{
+ switch (nid) {
+ case NID_gcrypt_nistp256:
+ return "ecdsa-sha2-nistp256";
+ case NID_gcrypt_nistp384:
+ return "ecdsa-sha2-nistp384";
+ case NID_gcrypt_nistp521:
+ return "ecdsa-sha2-nistp521";
+ }
+
+ return "unknown";
+}
+
+static const char *pki_key_ecdsa_nid_to_char(int nid)
+{
+ switch (nid) {
+ case NID_gcrypt_nistp256:
+ return "nistp256";
+ case NID_gcrypt_nistp384:
+ return "nistp384";
+ case NID_gcrypt_nistp521:
+ return "nistp521";
+ default:
+ break;
+ }
+
+ return "unknown";
+}
+
int pki_key_ecdsa_nid_from_name(const char *name)
{
+ int cmp;
+
+ cmp = strcmp(name, "nistp256");
+ if (cmp == 0) {
+ return NID_gcrypt_nistp256;
+ }
+
+ cmp = strcmp(name, "nistp384");
+ if (cmp == 0) {
+ return NID_gcrypt_nistp384;
+ }
+
+ cmp = strcmp(name, "nistp521");
+ if (cmp == 0) {
+ return NID_gcrypt_nistp521;
+ }
+
return -1;
}
+
+static int asn1_oi_to_nid(const ssh_string oi)
+{
+ static const struct {
+ int nid;
+ size_t length;
+ const char *identifier;
+ } *e, mapping[] = {
+ {NID_gcrypt_nistp256, 8, "\x2a\x86\x48\xce\x3d\x03\x01\x07"},
+ {NID_gcrypt_nistp384, 5, "\x2b\x81\x04\x00\x22"},
+ {NID_gcrypt_nistp521, 5, "\x2b\x81\x04\x00\x23"},
+ {0},
+ };
+ size_t len = ssh_string_len(oi);
+ for (e = mapping; e->length; e++) {
+ if (len == e->length
+ && memcmp(ssh_string_data(oi), e->identifier, len) == 0) {
+ return e->nid;
+ }
+ }
+ return -1;
+}
+
+static int b64decode_ecdsa_privatekey(const char *pkey, gcry_sexp_t *r,
+ ssh_auth_callback cb,
+ void *userdata,
+ const char *desc)
+{
+ const unsigned char *data;
+ ssh_buffer buffer = NULL;
+ gcry_error_t err = 0;
+ ssh_string v = NULL;
+ ssh_string d = NULL;
+ ssh_string oi = NULL;
+ int nid;
+ ssh_string q = NULL;
+ int valid = 0;
+ int ok;
+
+ buffer = privatekey_string_to_buffer(pkey,
+ SSH_KEYTYPE_ECDSA,
+ cb,
+ userdata,
+ desc);
+ if (buffer == NULL) {
+ goto error;
+ }
+
+ ok = asn1_check_sequence(buffer);
+ if (!ok) {
+ goto error;
+ }
+
+ /* RFC5915 specifies version 1. */
+ v = asn1_get_int(buffer);
+ if (v == NULL) {
+ goto error;
+ }
+
+ data = ssh_string_data(v);
+ if (ssh_string_len(v) != 1 || data[0] != 1) {
+ goto error;
+ }
+
+ d = asn1_get(buffer, ASN1_OCTET_STRING);
+ if (!asn1_check_tag(buffer, 0xa0)) {
+ goto error;
+ }
+ oi = asn1_get(buffer, ASN1_OBJECT_IDENTIFIER);
+ nid = asn1_oi_to_nid(oi);
+ ok = asn1_check_tag(buffer, 0xa1);
+ if (!ok) {
+ goto error;
+ }
+ q = asn1_get_bit_string(buffer);
+
+ if (d == NULL || oi == NULL || nid == -1 || q == NULL) {
+ goto error;
+ }
+
+ err = gcry_sexp_build(r,
+ NULL,
+ "(private-key(ecdsa(curve %s)(d %b)(q %b)))",
+ pki_key_ecdsa_nid_to_gcrypt_name(nid),
+ ssh_string_len(d),
+ ssh_string_data(d),
+ ssh_string_len(q),
+ ssh_string_data(q));
+ if (err == 0) {
+ valid = 1;
+ }
+
+ error:
+ ssh_buffer_free(buffer);
+ ssh_string_free(v);
+ ssh_string_burn(d);
+ ssh_string_free(d);
+ ssh_string_free(oi);
+ ssh_string_burn(q);
+ ssh_string_free(q);
+
+ return valid;
+}
#endif
ssh_string pki_private_key_to_pem(const ssh_key key,
@@ -702,6 +909,7 @@ ssh_key pki_private_key_from_base64(const char *b64_key,
{
gcry_sexp_t dsa = NULL;
gcry_sexp_t rsa = NULL;
+ gcry_sexp_t ecdsa = NULL;
ssh_key key = NULL;
enum ssh_keytypes_e type;
int valid;
@@ -757,9 +965,38 @@ ssh_key pki_private_key_from_base64(const char *b64_key,
goto fail;
}
break;
+ case SSH_KEYTYPE_ECDSA:
+#if HAVE_GCRYPT_ECC
+ if (passphrase == NULL) {
+ if (auth_fn != NULL) {
+ valid = b64decode_ecdsa_privatekey(b64_key,
+ &ecdsa,
+ auth_fn,
+ auth_data,
+ "Passphrase for private key:");
+ } else {
+ valid = b64decode_ecdsa_privatekey(b64_key,
+ &ecdsa,
+ NULL,
+ NULL,
+ NULL);
+ }
+ } else {
+ valid = b64decode_ecdsa_privatekey(b64_key,
+ &ecdsa,
+ NULL,
+ (void *)passphrase,
+ NULL);
+ }
+
+ if (!valid) {
+ SSH_LOG(SSH_LOG_WARN, "Parsing private key");
+ goto fail;
+ }
+ break;
+#endif
case SSH_KEYTYPE_ED25519:
/* Cannot open ed25519 keys with libgcrypt */
- case SSH_KEYTYPE_ECDSA:
case SSH_KEYTYPE_UNKNOWN:
default:
SSH_LOG(SSH_LOG_WARN, "Unkown or invalid private key type %d", type);
@@ -776,12 +1013,20 @@ ssh_key pki_private_key_from_base64(const char *b64_key,
key->flags = SSH_KEY_FLAG_PRIVATE | SSH_KEY_FLAG_PUBLIC;
key->dsa = dsa;
key->rsa = rsa;
+ key->ecdsa = ecdsa;
+#ifdef HAVE_GCRYPT_ECC
+ if (key->type == SSH_KEYTYPE_ECDSA) {
+ key->ecdsa_nid = pki_key_ecdsa_to_nid(key->ecdsa);
+ key->type_c = pki_key_ecdsa_nid_to_name(key->ecdsa_nid);
+ }
+#endif
return key;
fail:
ssh_key_free(key);
gcry_sexp_release(dsa);
gcry_sexp_release(rsa);
+ gcry_sexp_release(ecdsa);
return NULL;
}
@@ -821,7 +1066,20 @@ int pki_pubkey_build_rsa(ssh_key key,
#ifdef HAVE_GCRYPT_ECC
int pki_pubkey_build_ecdsa(ssh_key key, int nid, ssh_string e)
{
- return -1;
+ gpg_error_t err;
+
+ key->ecdsa_nid = nid;
+ key->type_c = pki_key_ecdsa_nid_to_name(nid);
+
+ err = gcry_sexp_build(&key->ecdsa, NULL,
+ "(public-key(ecdsa(curve %s)(q %b)))",
+ pki_key_ecdsa_nid_to_gcrypt_name(nid),
+ ssh_string_len(e), ssh_string_data(e));
+ if (err) {
+ return SSH_ERROR;
+ }
+
+ return SSH_OK;
}
#endif
@@ -842,6 +1100,8 @@ ssh_key pki_key_dup(const ssh_key key, int demote)
gcry_mpi_t d = NULL;
gcry_mpi_t u = NULL;
+ gcry_sexp_t curve = NULL;
+
new = ssh_key_new();
if (new == NULL) {
return NULL;
@@ -918,6 +1178,40 @@ ssh_key pki_key_dup(const ssh_key key, int demote)
break;
case SSH_KEYTYPE_ECDSA:
+#ifdef HAVE_GCRYPT_ECC
+ new->ecdsa_nid = key->ecdsa_nid;
+
+ err = gcry_sexp_extract_param(key->ecdsa,
+ NULL,
+ "qd?",
+ &q,
+ &d,
+ NULL);
+ if (err) {
+ break;
+ }
+
+ curve = gcry_sexp_find_token(key->ecdsa, "curve", 0);
+ if (curve == NULL) {
+ break;
+ }
+
+ if (!demote && (key->flags & SSH_KEY_FLAG_PRIVATE)) {
+ err = gcry_sexp_build(&new->ecdsa,
+ NULL,
+ "(private-key(ecdsa %S (d %m)(q %m)))",
+ curve,
+ d,
+ q);
+ } else {
+ err = gcry_sexp_build(&new->ecdsa,
+ NULL,
+ "(private-key(ecdsa %S (q %m)))",
+ curve,
+ q);
+ }
+ break;
+#endif
case SSH_KEYTYPE_UNKNOWN:
default:
ssh_key_free(new);
@@ -940,6 +1234,8 @@ ssh_key pki_key_dup(const ssh_key key, int demote)
gcry_mpi_release(d);
gcry_mpi_release(u);
+ gcry_sexp_release(curve);
+
return new;
}
@@ -953,10 +1249,19 @@ static int pki_key_generate(ssh_key key, int parameter, const char *type_s, int
parameter);
if (rc != 0)
return SSH_ERROR;
- if(type == SSH_KEYTYPE_RSA)
+ switch (type) {
+ case SSH_KEYTYPE_RSA:
rc = gcry_pk_genkey(&key->rsa, parms);
- else
+ break;
+ case SSH_KEYTYPE_DSS:
rc = gcry_pk_genkey(&key->dsa, parms);
+ break;
+ case SSH_KEYTYPE_ECDSA:
+ rc = gcry_pk_genkey(&key->ecdsa, parms);
+ break;
+ default:
+ assert (! "reached");
+ }
gcry_sexp_release(parms);
if (rc != 0)
return SSH_ERROR;
@@ -972,7 +1277,22 @@ int pki_key_generate_dss(ssh_key key, int parameter){
#ifdef HAVE_GCRYPT_ECC
int pki_key_generate_ecdsa(ssh_key key, int parameter) {
- return -1;
+ int nid;
+
+ switch (parameter) {
+ case 384:
+ nid = NID_gcrypt_nistp384;
+ break;
+ case 512:
+ nid = NID_gcrypt_nistp521;
+ break;
+ case 256:
+ default:
+ nid = NID_gcrypt_nistp256;
+ }
+
+ key->ecdsa_nid = nid;
+ return pki_key_generate(key, parameter, "ecdsa", SSH_KEYTYPE_ECDSA);
}
#endif
@@ -1073,6 +1393,20 @@ int pki_key_compare(const ssh_key k1,
/* ed25519 keys handled globaly */
return 0;
case SSH_KEYTYPE_ECDSA:
+#ifdef HAVE_GCRYPT_ECC
+ if (k1->ecdsa_nid != k2->ecdsa_nid) {
+ return 1;
+ }
+
+ if (_bignum_cmp(k1->ecdsa, k2->ecdsa, "q") != 0) {
+ return 1;
+ }
+
+ if (_bignum_cmp(k1->ecdsa, k2->ecdsa, "d") != 0) {
+ return 1;
+ }
+ break;
+#endif
case SSH_KEYTYPE_DSS_CERT01:
case SSH_KEYTYPE_RSA_CERT01:
case SSH_KEYTYPE_UNKNOWN:
@@ -1222,6 +1556,38 @@ ssh_string pki_publickey_to_blob(const ssh_key key)
}
break;
case SSH_KEYTYPE_ECDSA:
+#ifdef HAVE_GCRYPT_ECC
+ type_s = ssh_string_from_char(
+ pki_key_ecdsa_nid_to_char(key->ecdsa_nid));
+ if (type_s == NULL) {
+ ssh_buffer_free(buffer);
+ return NULL;
+ }
+
+ rc = ssh_buffer_add_ssh_string(buffer, type_s);
+ ssh_string_free(type_s);
+ if (rc < 0) {
+ ssh_buffer_free(buffer);
+ return NULL;
+ }
+
+ e = ssh_sexp_extract_mpi(key->ecdsa, "q", GCRYMPI_FMT_STD,
+ GCRYMPI_FMT_STD);
+ if (e == NULL) {
+ ssh_buffer_free(buffer);
+ return NULL;
+ }
+
+ rc = ssh_buffer_add_ssh_string(buffer, e);
+ if (rc < 0) {
+ goto fail;
+ }
+
+ ssh_string_burn(e);
+ ssh_string_free(e);
+ e = NULL;
+ break;
+#endif
case SSH_KEYTYPE_UNKNOWN:
default:
goto fail;
@@ -1374,6 +1740,58 @@ ssh_string pki_signature_to_blob(const ssh_signature sig)
sig_blob = pki_ed25519_sig_to_blob(sig);
break;
case SSH_KEYTYPE_ECDSA:
+#ifdef HAVE_GCRYPT_ECC
+ {
+ ssh_string R;
+ ssh_string S;
+ ssh_buffer b;
+ int rc;
+
+ b = ssh_buffer_new();
+ if (b == NULL) {
+ return NULL;
+ }
+
+ R = ssh_sexp_extract_mpi(sig->ecdsa_sig, "r",
+ GCRYMPI_FMT_USG, GCRYMPI_FMT_STD);
+ if (R == NULL) {
+ ssh_buffer_free(b);
+ return NULL;
+ }
+
+ rc = ssh_buffer_add_ssh_string(b, R);
+ ssh_string_free(R);
+ if (rc < 0) {
+ ssh_buffer_free(b);
+ return NULL;
+ }
+
+ S = ssh_sexp_extract_mpi(sig->ecdsa_sig, "s",
+ GCRYMPI_FMT_USG, GCRYMPI_FMT_STD);
+ if (S == NULL) {
+ ssh_buffer_free(b);
+ return NULL;
+ }
+
+ rc = ssh_buffer_add_ssh_string(b, S);
+ ssh_string_free(S);
+ if (rc < 0) {
+ ssh_buffer_free(b);
+ return NULL;
+ }
+
+ sig_blob = ssh_string_new(ssh_buffer_get_len(b));
+ if (sig_blob == NULL) {
+ ssh_buffer_free(b);
+ return NULL;
+ }
+
+ ssh_string_fill(sig_blob,
+ ssh_buffer_get(b), ssh_buffer_get_len(b));
+ ssh_buffer_free(b);
+ break;
+ }
+#endif
case SSH_KEYTYPE_UNKNOWN:
default:
SSH_LOG(SSH_LOG_WARN, "Unknown signature key type: %d", sig->type);
@@ -1475,6 +1893,80 @@ ssh_signature pki_signature_from_blob(const ssh_key pubkey,
}
break;
case SSH_KEYTYPE_ECDSA:
+#ifdef HAVE_GCRYPT_ECC
+ { /* build ecdsa siganature */
+ ssh_buffer b;
+ ssh_string r, s;
+ uint32_t rlen;
+
+ b = ssh_buffer_new();
+ if (b == NULL) {
+ ssh_signature_free(sig);
+ return NULL;
+ }
+
+ rc = ssh_buffer_add_data(b,
+ ssh_string_data(sig_blob),
+ ssh_string_len(sig_blob));
+ if (rc < 0) {
+ ssh_buffer_free(b);
+ ssh_signature_free(sig);
+ return NULL;
+ }
+
+ r = ssh_buffer_get_ssh_string(b);
+ if (r == NULL) {
+ ssh_buffer_free(b);
+ ssh_signature_free(sig);
+ return NULL;
+ }
+
+ s = ssh_buffer_get_ssh_string(b);
+ rlen = ssh_buffer_get_len(b);
+ ssh_buffer_free(b);
+ if (s == NULL) {
+ ssh_string_burn(r);
+ ssh_string_free(r);
+ ssh_signature_free(sig);
+ return NULL;
+ }
+
+ if (rlen != 0) {
+ SSH_LOG(SSH_LOG_WARN,
+ "Signature has remaining bytes in inner "
+ "sigblob: %lu",
+ (unsigned long)rlen);
+ ssh_string_burn(r);
+ ssh_string_free(r);
+ ssh_string_burn(s);
+ ssh_string_free(s);
+ ssh_signature_free(sig);
+ return NULL;
+ }
+
+#ifdef DEBUG_CRYPTO
+ ssh_print_hexa("r", ssh_string_data(r), ssh_string_len(r));
+ ssh_print_hexa("s", ssh_string_data(s), ssh_string_len(s));
+#endif
+
+ err = gcry_sexp_build(&sig->ecdsa_sig,
+ NULL,
+ "(sig-val(ecdsa(r %b)(s %b)))",
+ ssh_string_len(r),
+ ssh_string_data(r),
+ ssh_string_len(s),
+ ssh_string_data(s));
+ ssh_string_burn(r);
+ ssh_string_free(r);
+ ssh_string_burn(s);
+ ssh_string_free(s);
+ if (err) {
+ ssh_signature_free(sig);
+ return NULL;
+ }
+ }
+ break;
+#endif
case SSH_KEYTYPE_UNKNOWN:
default:
SSH_LOG(SSH_LOG_WARN, "Unknown signature type");
@@ -1558,6 +2050,34 @@ int pki_signature_verify(ssh_session session,
}
break;
case SSH_KEYTYPE_ECDSA:
+#ifdef HAVE_GCRYPT_ECC
+ err = gcry_sexp_build(&sexp,
+ NULL,
+ "(data(flags raw)(value %b))",
+ hlen,
+ hash);
+ if (err) {
+ ssh_set_error(session,
+ SSH_FATAL,
+ "ECDSA hash error: %s",
+ gcry_strerror(err));
+ return SSH_ERROR;
+ }
+ err = gcry_pk_verify(sig->ecdsa_sig, sexp, key->ecdsa);
+ gcry_sexp_release(sexp);
+ if (err) {
+ ssh_set_error(session, SSH_FATAL, "Invalid ECDSA signature");
+ abort();
+ if (gcry_err_code(err) != GPG_ERR_BAD_SIGNATURE) {
+ ssh_set_error(session,
+ SSH_FATAL,
+ "ECDSA verify error: %s",
+ gcry_strerror(err));
+ }
+ return SSH_ERROR;
+ }
+ break;
+#endif
case SSH_KEYTYPE_UNKNOWN:
default:
ssh_set_error(session, SSH_FATAL, "Unknown public key type");
@@ -1631,6 +2151,25 @@ ssh_signature pki_do_sign(const ssh_key privkey,
}
break;
case SSH_KEYTYPE_ECDSA:
+#ifdef HAVE_GCRYPT_ECC
+ err = gcry_sexp_build(&sexp,
+ NULL,
+ "(data(flags raw)(value %b))",
+ hlen,
+ hash);
+ if (err) {
+ ssh_signature_free(sig);
+ return NULL;
+ }
+
+ err = gcry_pk_sign(&sig->ecdsa_sig, sexp, privkey->ecdsa);
+ gcry_sexp_release(sexp);
+ if (err) {
+ ssh_signature_free(sig);
+ return NULL;
+ }
+ break;
+#endif
case SSH_KEYTYPE_UNKNOWN:
default:
ssh_signature_free(sig);
@@ -1700,6 +2239,24 @@ ssh_signature pki_do_sign_sessionid(const ssh_key key,
case SSH_KEYTYPE_ED25519:
/* ED25519 handled in caller */
case SSH_KEYTYPE_ECDSA:
+#ifdef HAVE_GCRYPT_ECC
+ err = gcry_sexp_build(&sexp,
+ NULL,
+ "(data(flags raw)(value %b))",
+ hlen,
+ hash);
+ if (err) {
+ ssh_signature_free(sig);
+ return NULL;
+ }
+ err = gcry_pk_sign(&sig->ecdsa_sig, sexp, key->ecdsa);
+ gcry_sexp_release(sexp);
+ if (err) {
+ ssh_signature_free(sig);
+ return NULL;
+ }
+ break;
+#endif
case SSH_KEYTYPE_UNKNOWN:
default:
return NULL;