- 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@
diff --git a/key.c b/key.c
index c09f43f..236e026 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 @@
 	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 @@
 		/* 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 @@
 	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 @@
 		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 @@
 		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 @@
 	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 @@
 	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 @@
 	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 @@
 #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 @@
 			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 @@
 	{ 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 @@
 	    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 @@
 }
 
 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 @@
 	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 @@
 	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 @@
 	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 @@
 		    (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 @@
 {
 	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 @@
 #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 @@
  out:
 	free(ktype);
 	free(curve);
+	free(pk);
 #ifdef OPENSSL_HAS_ECC
 	if (q != NULL)
 		EC_POINT_free(q);
@@ -1603,6 +1689,7 @@
 	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 @@
 		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 @@
 	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 @@
 	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 @@
 	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 @@
 			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 @@
 		return KEY_DSA;
 	case KEY_ECDSA_CERT:
 		return KEY_ECDSA;
+	case KEY_ED25519_CERT:
+		return KEY_ED25519;
 	default:
 		return type;
 	}
@@ -1822,6 +1933,13 @@
 		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 @@
 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 @@
 	}
 
 	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 @@
 		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 @@
 		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 @@
 	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 @@
 		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);