diff options
author | Markus Friedl <markus@cvs.openbsd.org> | 2013-12-06 13:39:50 +0000 |
---|---|---|
committer | Markus Friedl <markus@cvs.openbsd.org> | 2013-12-06 13:39:50 +0000 |
commit | a290ddcba332424443fa2507428cf4bdfd415bac (patch) | |
tree | 77d1dc09898f6b40a269e48d8520cffd5bb31dc0 /usr.bin/ssh/key.c | |
parent | 4b5b44f5080b9b0bd2e297236bde454a7b1d32aa (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.c | 194 |
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); |