summaryrefslogtreecommitdiffstats
path: root/key.c
diff options
context:
space:
mode:
authorDamien Miller <djm@mindrot.org>2013-12-07 11:24:01 +1100
committerDamien Miller <djm@mindrot.org>2013-12-07 11:24:01 +1100
commit5be9d9e3cbd9c66f24745d25bf2e809c1d158ee0 (patch)
treed2086d37436014ea44f0f024396a1a8638640b00 /key.c
parentbcd00abd8451f36142ae2ee10cc657202149201e (diff)
- markus@cvs.openbsd.org 2013/12/06 13:39:49
[authfd.c authfile.c key.c key.h myproposal.h pathnames.h readconf.c] [servconf.c ssh-agent.c ssh-keygen.c ssh-keyscan.1 ssh-keyscan.c] [ssh-keysign.c ssh.c ssh_config.5 sshd.8 sshd.c verify.c ssh-ed25519.c] [sc25519.h sc25519.c hash.c ge25519_base.data ge25519.h ge25519.c] [fe25519.h fe25519.c ed25519.c crypto_api.h blocks.c] 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 'key.c')
-rw-r--r--key.c193
1 files changed, 169 insertions, 24 deletions
diff --git a/key.c b/key.c
index c09f43f1..236e0267 100644
--- a/key.c
+++ b/key.c
@@ -39,6 +39,8 @@
#include <sys/param.h>
#include <sys/types.h>
+#include "crypto_api.h"
+
#include <openssl/evp.h>
#include <openbsd-compat/openssl-compat.h>
@@ -86,6 +88,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:
@@ -120,6 +124,10 @@ key_new(int type)
/* Cannot do anything until we know the group */
break;
#endif
+ case KEY_ED25519:
+ case KEY_ED25519_CERT:
+ /* no need to prealloc */
+ break;
case KEY_UNSPEC:
break;
default:
@@ -164,6 +172,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:
@@ -226,6 +238,19 @@ key_free(Key *k)
k->ecdsa = NULL;
break;
#endif
+ 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:
@@ -307,6 +332,10 @@ key_equal_public(const Key *a, const Key *b)
BN_CTX_free(bnctx);
return 1;
#endif /* OPENSSL_HAS_ECC */
+ 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);
}
@@ -366,6 +395,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:
@@ -373,6 +403,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;
@@ -699,11 +730,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");
@@ -805,6 +838,14 @@ key_read(Key *ret, char **cpp)
#endif
}
#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);
@@ -868,6 +909,11 @@ key_write(const Key *key, FILE *f)
return 0;
break;
#endif
+ 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:
@@ -915,6 +961,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 },
#ifdef OPENSSL_HAS_ECC
{ "ecdsa-sha2-nistp256", "ECDSA", KEY_ECDSA, NID_X9_62_prime256v1, 0 },
{ "ecdsa-sha2-nistp384", "ECDSA", KEY_ECDSA, NID_secp384r1, 0 },
@@ -938,6 +985,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 }
};
@@ -1009,7 +1058,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;
@@ -1018,6 +1067,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);
@@ -1053,6 +1104,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 */
#ifdef OPENSSL_HAS_ECC
case KEY_ECDSA:
case KEY_ECDSA_CERT:
@@ -1196,6 +1249,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:
@@ -1289,6 +1347,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;
@@ -1451,7 +1517,9 @@ key_from_blob2(const u_char *blob, u_int blen, int allow_cert)
{
Buffer b;
int rlen, type;
+ u_int len;
char *ktype = NULL, *curve = NULL;
+ u_char *pk = NULL;
Key *key = NULL;
#ifdef OPENSSL_HAS_ECC
EC_POINT *q = NULL;
@@ -1550,6 +1618,23 @@ key_from_blob2(const u_char *blob, u_int blen, int allow_cert)
#endif
break;
#endif /* OPENSSL_HAS_ECC */
+ 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;
@@ -1567,6 +1652,7 @@ key_from_blob2(const u_char *blob, u_int blen, int allow_cert)
out:
free(ktype);
free(curve);
+ free(pk);
#ifdef OPENSSL_HAS_ECC
if (q != NULL)
EC_POINT_free(q);
@@ -1603,6 +1689,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));
@@ -1630,6 +1717,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);
@@ -1673,6 +1765,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;
@@ -1706,6 +1801,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;
@@ -1725,6 +1823,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:
@@ -1768,8 +1868,17 @@ key_demote(const Key *k)
fatal("key_demote: EC_KEY_set_public_key failed");
break;
#endif
+ 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;
}
@@ -1797,6 +1906,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;
}
@@ -1822,6 +1933,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;
@@ -1832,31 +1950,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)
{
@@ -1876,7 +1979,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;
@@ -1915,6 +2018,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);
@@ -2332,6 +2439,18 @@ key_private_serialize(const Key *key, Buffer *b)
buffer_put_bignum2(b, EC_KEY_get0_private_key(key->ecdsa));
break;
#endif /* OPENSSL_HAS_ECC */
+ 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;
}
}
@@ -2341,7 +2460,7 @@ key_private_deserialize(Buffer *blob)
char *type_name;
Key *k = NULL;
u_char *cert;
- u_int len;
+ u_int len, pklen, sklen;
int type;
#ifdef OPENSSL_HAS_ECC
char *curve;
@@ -2446,6 +2565,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);