summaryrefslogtreecommitdiff
path: root/usr.bin/ssh/key.c
diff options
context:
space:
mode:
authorMarkus Friedl <markus@cvs.openbsd.org>2013-12-06 13:39:50 +0000
committerMarkus Friedl <markus@cvs.openbsd.org>2013-12-06 13:39:50 +0000
commita290ddcba332424443fa2507428cf4bdfd415bac (patch)
tree77d1dc09898f6b40a269e48d8520cffd5bb31dc0 /usr.bin/ssh/key.c
parent4b5b44f5080b9b0bd2e297236bde454a7b1d32aa (diff)
support ed25519 keys (hostkeys and user identities) using the public domain
ed25519 reference code from SUPERCOP, see http://ed25519.cr.yp.to/software.html feedback, help & ok djm@
Diffstat (limited to 'usr.bin/ssh/key.c')
-rw-r--r--usr.bin/ssh/key.c194
1 files changed, 169 insertions, 25 deletions
diff --git a/usr.bin/ssh/key.c b/usr.bin/ssh/key.c
index 17bf1636189..5add51594db 100644
--- a/usr.bin/ssh/key.c
+++ b/usr.bin/ssh/key.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: key.c,v 1.108 2013/12/06 13:34:54 markus Exp $ */
+/* $OpenBSD: key.c,v 1.109 2013/12/06 13:39:49 markus Exp $ */
/*
* read_bignum():
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -38,6 +38,7 @@
#include <sys/types.h>
#include <openssl/evp.h>
+#include "crypto_api.h"
#include <stdio.h>
#include <string.h>
@@ -82,6 +83,8 @@ key_new(int type)
k->dsa = NULL;
k->rsa = NULL;
k->cert = NULL;
+ k->ed25519_sk = NULL;
+ k->ed25519_pk = NULL;
switch (k->type) {
case KEY_RSA1:
case KEY_RSA:
@@ -114,6 +117,10 @@ key_new(int type)
case KEY_ECDSA_CERT:
/* Cannot do anything until we know the group */
break;
+ case KEY_ED25519:
+ case KEY_ED25519_CERT:
+ /* no need to prealloc */
+ break;
case KEY_UNSPEC:
break;
default:
@@ -158,6 +165,10 @@ key_add_private(Key *k)
case KEY_ECDSA_CERT:
/* Cannot do anything until we know the group */
break;
+ case KEY_ED25519:
+ case KEY_ED25519_CERT:
+ /* no need to prealloc */
+ break;
case KEY_UNSPEC:
break;
default:
@@ -218,6 +229,19 @@ key_free(Key *k)
EC_KEY_free(k->ecdsa);
k->ecdsa = NULL;
break;
+ case KEY_ED25519:
+ case KEY_ED25519_CERT:
+ if (k->ed25519_pk) {
+ memset(k->ed25519_pk, 0, ED25519_PK_SZ);
+ free(k->ed25519_pk);
+ k->ed25519_pk = NULL;
+ }
+ if (k->ed25519_sk) {
+ memset(k->ed25519_sk, 0, ED25519_SK_SZ);
+ free(k->ed25519_sk);
+ k->ed25519_sk = NULL;
+ }
+ break;
case KEY_UNSPEC:
break;
default:
@@ -295,6 +319,10 @@ key_equal_public(const Key *a, const Key *b)
}
BN_CTX_free(bnctx);
return 1;
+ case KEY_ED25519:
+ case KEY_ED25519_CERT:
+ return a->ed25519_pk != NULL && b->ed25519_pk != NULL &&
+ memcmp(a->ed25519_pk, b->ed25519_pk, ED25519_PK_SZ) == 0;
default:
fatal("key_equal: bad key type %d", a->type);
}
@@ -352,6 +380,7 @@ key_fingerprint_raw(const Key *k, enum fp_type dgst_type,
case KEY_DSA:
case KEY_ECDSA:
case KEY_RSA:
+ case KEY_ED25519:
key_to_blob(k, &blob, &len);
break;
case KEY_DSA_CERT_V00:
@@ -359,6 +388,7 @@ key_fingerprint_raw(const Key *k, enum fp_type dgst_type,
case KEY_DSA_CERT:
case KEY_ECDSA_CERT:
case KEY_RSA_CERT:
+ case KEY_ED25519_CERT:
/* We want a fingerprint of the _key_ not of the cert */
to_blob(k, &blob, &len, 1);
break;
@@ -682,11 +712,13 @@ key_read(Key *ret, char **cpp)
case KEY_RSA:
case KEY_DSA:
case KEY_ECDSA:
+ case KEY_ED25519:
case KEY_DSA_CERT_V00:
case KEY_RSA_CERT_V00:
case KEY_DSA_CERT:
case KEY_ECDSA_CERT:
case KEY_RSA_CERT:
+ case KEY_ED25519_CERT:
space = strchr(cp, ' ');
if (space == NULL) {
debug3("key_read: missing whitespace");
@@ -782,6 +814,14 @@ key_read(Key *ret, char **cpp)
key_dump_ec_key(ret->ecdsa);
#endif
}
+ if (key_type_plain(ret->type) == KEY_ED25519) {
+ free(ret->ed25519_pk);
+ ret->ed25519_pk = k->ed25519_pk;
+ k->ed25519_pk = NULL;
+#ifdef DEBUG_PK
+ /* XXX */
+#endif
+ }
success = 1;
/*XXXX*/
key_free(k);
@@ -843,6 +883,11 @@ key_write(const Key *key, FILE *f)
if (key->ecdsa == NULL)
return 0;
break;
+ case KEY_ED25519:
+ case KEY_ED25519_CERT:
+ if (key->ed25519_pk == NULL)
+ return 0;
+ break;
case KEY_RSA:
case KEY_RSA_CERT_V00:
case KEY_RSA_CERT:
@@ -890,6 +935,7 @@ static const struct keytype keytypes[] = {
{ NULL, "RSA1", KEY_RSA1, 0, 0 },
{ "ssh-rsa", "RSA", KEY_RSA, 0, 0 },
{ "ssh-dss", "DSA", KEY_DSA, 0, 0 },
+ { "ssh-ed25519", "ED25519", KEY_ED25519, 0, 0 },
{ "ecdsa-sha2-nistp256", "ECDSA", KEY_ECDSA, NID_X9_62_prime256v1, 0 },
{ "ecdsa-sha2-nistp384", "ECDSA", KEY_ECDSA, NID_secp384r1, 0 },
{ "ecdsa-sha2-nistp521", "ECDSA", KEY_ECDSA, NID_secp521r1, 0 },
@@ -905,6 +951,8 @@ static const struct keytype keytypes[] = {
KEY_RSA_CERT_V00, 0, 1 },
{ "ssh-dss-cert-v00@openssh.com", "DSA-CERT-V00",
KEY_DSA_CERT_V00, 0, 1 },
+ { "ssh-ed25519-cert-v01@openssh.com", "ED25519-CERT",
+ KEY_ED25519_CERT, 0, 1 },
{ NULL, NULL, -1, -1, 0 }
};
@@ -976,7 +1024,7 @@ key_ecdsa_nid_from_name(const char *name)
}
char *
-key_alg_list(void)
+key_alg_list(int certs_only, int plain_only)
{
char *ret = NULL;
size_t nlen, rlen = 0;
@@ -985,6 +1033,8 @@ key_alg_list(void)
for (kt = keytypes; kt->type != -1; kt++) {
if (kt->name == NULL)
continue;
+ if ((certs_only && !kt->cert) || (plain_only && kt->cert))
+ continue;
if (ret != NULL)
ret[rlen++] = '\n';
nlen = strlen(kt->name);
@@ -1020,6 +1070,8 @@ key_size(const Key *k)
case KEY_DSA_CERT_V00:
case KEY_DSA_CERT:
return BN_num_bits(k->dsa->p);
+ case KEY_ED25519:
+ return 256; /* XXX */
case KEY_ECDSA:
case KEY_ECDSA_CERT:
return key_curve_nid_to_bits(k->ecdsa_nid);
@@ -1151,6 +1203,11 @@ key_generate(int type, u_int bits)
case KEY_RSA1:
k->rsa = rsa_generate_private_key(bits);
break;
+ case KEY_ED25519:
+ k->ed25519_pk = xmalloc(ED25519_PK_SZ);
+ k->ed25519_sk = xmalloc(ED25519_SK_SZ);
+ crypto_sign_ed25519_keypair(k->ed25519_pk, k->ed25519_sk);
+ break;
case KEY_RSA_CERT_V00:
case KEY_DSA_CERT_V00:
case KEY_RSA_CERT:
@@ -1242,6 +1299,14 @@ key_from_private(const Key *k)
(BN_copy(n->rsa->e, k->rsa->e) == NULL))
fatal("key_from_private: BN_copy failed");
break;
+ case KEY_ED25519:
+ case KEY_ED25519_CERT:
+ n = key_new(k->type);
+ if (k->ed25519_pk != NULL) {
+ n->ed25519_pk = xmalloc(ED25519_PK_SZ);
+ memcpy(n->ed25519_pk, k->ed25519_pk, ED25519_PK_SZ);
+ }
+ break;
default:
fatal("key_from_private: unknown type %d", k->type);
break;
@@ -1404,7 +1469,9 @@ key_from_blob2(const u_char *blob, u_int blen, int allow_cert)
{
Buffer b;
int rlen, type, nid = -1;
+ u_int len;
char *ktype = NULL, *curve = NULL;
+ u_char *pk = NULL;
Key *key = NULL;
EC_POINT *q = NULL;
@@ -1496,6 +1563,23 @@ key_from_blob2(const u_char *blob, u_int blen, int allow_cert)
key_dump_ec_point(EC_KEY_get0_group(key->ecdsa), q);
#endif
break;
+ case KEY_ED25519_CERT:
+ (void)buffer_get_string_ptr_ret(&b, NULL); /* Skip nonce */
+ /* FALLTHROUGH */
+ case KEY_ED25519:
+ if ((pk = buffer_get_string_ret(&b, &len)) == NULL) {
+ error("key_from_blob: can't read ed25519 key");
+ goto badkey;
+ }
+ if (len != ED25519_PK_SZ) {
+ error("key_from_blob: ed25519 len %d != %d",
+ len, ED25519_PK_SZ);
+ goto badkey;
+ }
+ key = key_new(type);
+ key->ed25519_pk = pk;
+ pk = NULL;
+ break;
case KEY_UNSPEC:
key = key_new(type);
break;
@@ -1513,6 +1597,7 @@ key_from_blob2(const u_char *blob, u_int blen, int allow_cert)
out:
free(ktype);
free(curve);
+ free(pk);
if (q != NULL)
EC_POINT_free(q);
buffer_free(&b);
@@ -1547,6 +1632,7 @@ to_blob(const Key *key, u_char **blobp, u_int *lenp, int force_plain)
case KEY_DSA_CERT:
case KEY_ECDSA_CERT:
case KEY_RSA_CERT:
+ case KEY_ED25519_CERT:
/* Use the existing blob */
buffer_append(&b, buffer_ptr(&key->cert->certblob),
buffer_len(&key->cert->certblob));
@@ -1572,6 +1658,11 @@ to_blob(const Key *key, u_char **blobp, u_int *lenp, int force_plain)
buffer_put_bignum2(&b, key->rsa->e);
buffer_put_bignum2(&b, key->rsa->n);
break;
+ case KEY_ED25519:
+ buffer_put_cstring(&b,
+ key_ssh_name_from_type_nid(type, key->ecdsa_nid));
+ buffer_put_string(&b, key->ed25519_pk, ED25519_PK_SZ);
+ break;
default:
error("key_to_blob: unsupported key type %d", key->type);
buffer_free(&b);
@@ -1613,6 +1704,9 @@ key_sign(
case KEY_RSA_CERT:
case KEY_RSA:
return ssh_rsa_sign(key, sigp, lenp, data, datalen);
+ case KEY_ED25519:
+ case KEY_ED25519_CERT:
+ return ssh_ed25519_sign(key, sigp, lenp, data, datalen);
default:
error("key_sign: invalid key type %d", key->type);
return -1;
@@ -1644,6 +1738,9 @@ key_verify(
case KEY_RSA_CERT:
case KEY_RSA:
return ssh_rsa_verify(key, signature, signaturelen, data, datalen);
+ case KEY_ED25519:
+ case KEY_ED25519_CERT:
+ return ssh_ed25519_verify(key, signature, signaturelen, data, datalen);
default:
error("key_verify: invalid key type %d", key->type);
return -1;
@@ -1663,6 +1760,8 @@ key_demote(const Key *k)
pk->dsa = NULL;
pk->ecdsa = NULL;
pk->rsa = NULL;
+ pk->ed25519_pk = NULL;
+ pk->ed25519_sk = NULL;
switch (k->type) {
case KEY_RSA_CERT_V00:
@@ -1704,8 +1803,17 @@ key_demote(const Key *k)
EC_KEY_get0_public_key(k->ecdsa)) != 1)
fatal("key_demote: EC_KEY_set_public_key failed");
break;
+ case KEY_ED25519_CERT:
+ key_cert_copy(k, pk);
+ /* FALLTHROUGH */
+ case KEY_ED25519:
+ if (k->ed25519_pk != NULL) {
+ pk->ed25519_pk = xmalloc(ED25519_PK_SZ);
+ memcpy(pk->ed25519_pk, k->ed25519_pk, ED25519_PK_SZ);
+ }
+ break;
default:
- fatal("key_free: bad key type %d", k->type);
+ fatal("key_demote: bad key type %d", k->type);
break;
}
@@ -1733,6 +1841,8 @@ key_type_plain(int type)
return KEY_DSA;
case KEY_ECDSA_CERT:
return KEY_ECDSA;
+ case KEY_ED25519_CERT:
+ return KEY_ED25519;
default:
return type;
}
@@ -1758,6 +1868,13 @@ key_to_certified(Key *k, int legacy)
k->cert = cert_new();
k->type = KEY_ECDSA_CERT;
return 0;
+ case KEY_ED25519:
+ if (legacy)
+ fatal("%s: legacy ED25519 certificates are not "
+ "supported", __func__);
+ k->cert = cert_new();
+ k->type = KEY_ED25519_CERT;
+ return 0;
default:
error("%s: key has incorrect type %s", __func__, key_type(k));
return -1;
@@ -1768,31 +1885,16 @@ key_to_certified(Key *k, int legacy)
int
key_drop_cert(Key *k)
{
- switch (k->type) {
- case KEY_RSA_CERT_V00:
- case KEY_RSA_CERT:
- cert_free(k->cert);
- k->type = KEY_RSA;
- return 0;
- case KEY_DSA_CERT_V00:
- case KEY_DSA_CERT:
- cert_free(k->cert);
- k->type = KEY_DSA;
- return 0;
- case KEY_ECDSA_CERT:
- cert_free(k->cert);
- k->type = KEY_ECDSA;
- return 0;
- default:
+ if (!key_type_is_cert(k->type)) {
error("%s: key has incorrect type %s", __func__, key_type(k));
return -1;
}
+ cert_free(k->cert);
+ k->type = key_type_plain(k->type);
+ return 0;
}
-/*
- * Sign a KEY_RSA_CERT, KEY_DSA_CERT or KEY_ECDSA_CERT, (re-)generating
- * the signed certblob
- */
+/* Sign a certified key, (re-)generating the signed certblob. */
int
key_certify(Key *k, Key *ca)
{
@@ -1812,7 +1914,7 @@ key_certify(Key *k, Key *ca)
}
if (ca->type != KEY_RSA && ca->type != KEY_DSA &&
- ca->type != KEY_ECDSA) {
+ ca->type != KEY_ECDSA && ca->type != KEY_ED25519) {
error("%s: CA key has unsupported type %s", __func__,
key_type(ca));
return -1;
@@ -1849,6 +1951,10 @@ key_certify(Key *k, Key *ca)
buffer_put_bignum2(&k->cert->certblob, k->rsa->e);
buffer_put_bignum2(&k->cert->certblob, k->rsa->n);
break;
+ case KEY_ED25519_CERT:
+ buffer_put_string(&k->cert->certblob,
+ k->ed25519_pk, ED25519_PK_SZ);
+ break;
default:
error("%s: key has incorrect type %s", __func__, key_type(k));
buffer_clear(&k->cert->certblob);
@@ -2251,6 +2357,18 @@ key_private_serialize(const Key *key, Buffer *b)
buffer_len(&key->cert->certblob));
buffer_put_bignum2(b, EC_KEY_get0_private_key(key->ecdsa));
break;
+ case KEY_ED25519:
+ buffer_put_string(b, key->ed25519_pk, ED25519_PK_SZ);
+ buffer_put_string(b, key->ed25519_sk, ED25519_SK_SZ);
+ break;
+ case KEY_ED25519_CERT:
+ if (key->cert == NULL || buffer_len(&key->cert->certblob) == 0)
+ fatal("%s: no cert/certblob", __func__);
+ buffer_put_string(b, buffer_ptr(&key->cert->certblob),
+ buffer_len(&key->cert->certblob));
+ buffer_put_string(b, key->ed25519_pk, ED25519_PK_SZ);
+ buffer_put_string(b, key->ed25519_sk, ED25519_SK_SZ);
+ break;
}
}
@@ -2262,7 +2380,7 @@ key_private_deserialize(Buffer *blob)
BIGNUM *exponent;
EC_POINT *q;
u_char *cert;
- u_int len;
+ u_int len, pklen, sklen;
int type;
type_name = buffer_get_string(blob, NULL);
@@ -2360,6 +2478,32 @@ key_private_deserialize(Buffer *blob)
buffer_get_bignum2(blob, k->rsa->p);
buffer_get_bignum2(blob, k->rsa->q);
break;
+ case KEY_ED25519:
+ k = key_new_private(type);
+ k->ed25519_pk = buffer_get_string(blob, &pklen);
+ k->ed25519_sk = buffer_get_string(blob, &sklen);
+ if (pklen != ED25519_PK_SZ)
+ fatal("%s: ed25519 pklen %d != %d",
+ __func__, pklen, ED25519_PK_SZ);
+ if (sklen != ED25519_SK_SZ)
+ fatal("%s: ed25519 sklen %d != %d",
+ __func__, sklen, ED25519_SK_SZ);
+ break;
+ case KEY_ED25519_CERT:
+ cert = buffer_get_string(blob, &len);
+ if ((k = key_from_blob(cert, len)) == NULL)
+ fatal("Certificate parse failed");
+ free(cert);
+ key_add_private(k);
+ k->ed25519_pk = buffer_get_string(blob, &pklen);
+ k->ed25519_sk = buffer_get_string(blob, &sklen);
+ if (pklen != ED25519_PK_SZ)
+ fatal("%s: ed25519 pklen %d != %d",
+ __func__, pklen, ED25519_PK_SZ);
+ if (sklen != ED25519_SK_SZ)
+ fatal("%s: ed25519 sklen %d != %d",
+ __func__, sklen, ED25519_SK_SZ);
+ break;
default:
free(type_name);
buffer_clear(blob);