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>
Этот коммит содержится в:
родитель
7e315629b9
Коммит
f62cded9f0
@ -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)
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
567
src/pki_gcrypt.c
567
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;
|
||||
|
Загрузка…
Ссылка в новой задаче
Block a user