From eb8b60e320cdade9f4c07e2abacfb92c52e01348 Mon Sep 17 00:00:00 2001 From: Damien Miller Date: Tue, 31 Aug 2010 22:41:14 +1000 Subject: - djm@cvs.openbsd.org 2010/08/31 11:54:45 [PROTOCOL PROTOCOL.agent PROTOCOL.certkeys auth2-jpake.c authfd.c] [authfile.c buffer.h dns.c kex.c kex.h key.c key.h monitor.c] [monitor_wrap.c myproposal.h packet.c packet.h pathnames.h readconf.c] [ssh-add.1 ssh-add.c ssh-agent.1 ssh-agent.c ssh-keygen.1 ssh-keygen.c] [ssh-keyscan.1 ssh-keyscan.c ssh-keysign.8 ssh.1 ssh.c ssh2.h] [ssh_config.5 sshconnect.c sshconnect2.c sshd.8 sshd.c sshd_config.5] [uuencode.c uuencode.h bufec.c kexecdh.c kexecdhc.c kexecdhs.c ssh-ecdsa.c] Implement Elliptic Curve Cryptography modes for key exchange (ECDH) and host/user keys (ECDSA) as specified by RFC5656. ECDH and ECDSA offer better performance than plain DH and DSA at the same equivalent symmetric key length, as well as much shorter keys. Only the mandatory sections of RFC5656 are implemented, specifically the three REQUIRED curves nistp256, nistp384 and nistp521 and only ECDH and ECDSA. Point compression (optional in RFC5656 is NOT implemented). Certificate host and user keys using the new ECDSA key types are supported. Note that this code has not been tested for interoperability and may be subject to change. feedback and ok markus@ --- authfile.c | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) (limited to 'authfile.c') diff --git a/authfile.c b/authfile.c index 2bd887845..865e7faf9 100644 --- a/authfile.c +++ b/authfile.c @@ -1,4 +1,4 @@ -/* $OpenBSD: authfile.c,v 1.82 2010/08/04 05:49:22 djm Exp $ */ +/* $OpenBSD: authfile.c,v 1.83 2010/08/31 11:54:45 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -213,6 +213,10 @@ key_save_private_pem(Key *key, const char *filename, const char *_passphrase, success = PEM_write_DSAPrivateKey(fp, key->dsa, cipher, passphrase, len, NULL, NULL); break; + case KEY_ECDSA: + success = PEM_write_ECPrivateKey(fp, key->ecdsa, + cipher, passphrase, len, NULL, NULL); + break; case KEY_RSA: success = PEM_write_RSAPrivateKey(fp, key->rsa, cipher, passphrase, len, NULL, NULL); @@ -231,6 +235,7 @@ key_save_private(Key *key, const char *filename, const char *passphrase, return key_save_private_rsa1(key, filename, passphrase, comment); case KEY_DSA: + case KEY_ECDSA: case KEY_RSA: return key_save_private_pem(key, filename, passphrase, comment); @@ -509,6 +514,29 @@ key_load_private_pem(int fd, int type, const char *passphrase, name = "dsa w/o comment"; #ifdef DEBUG_PK DSA_print_fp(stderr, prv->dsa, 8); +#endif + } else if (pk->type == EVP_PKEY_EC && + (type == KEY_UNSPEC||type==KEY_ECDSA)) { + prv = key_new(KEY_UNSPEC); + prv->ecdsa = EVP_PKEY_get1_EC_KEY(pk); + prv->type = KEY_ECDSA; + prv->ecdsa_nid = key_ecdsa_group_to_nid( + EC_KEY_get0_group(prv->ecdsa)); + if (key_curve_nid_to_name(prv->ecdsa_nid) == NULL) { + key_free(prv); + prv = NULL; + } + if (key_ec_validate_public(EC_KEY_get0_group(prv->ecdsa), + EC_KEY_get0_public_key(prv->ecdsa)) != 0 || + key_ec_validate_private(prv->ecdsa) != 0) { + error("%s: bad ECDSA key", __func__); + key_free(prv); + prv = NULL; + } + name = "dsa w/o comment"; +#ifdef DEBUG_PK + if (prv->ecdsa != NULL) + key_dump_ec_key(prv->ecdsa); #endif } else { error("PEM_read_PrivateKey: mismatch or " @@ -581,6 +609,7 @@ key_load_private_type(int type, const char *filename, const char *passphrase, commentp); /* closes fd */ case KEY_DSA: + case KEY_ECDSA: case KEY_RSA: case KEY_UNSPEC: return key_load_private_pem(fd, type, passphrase, commentp); @@ -721,6 +750,7 @@ key_load_private_cert(int type, const char *filename, const char *passphrase, switch (type) { case KEY_RSA: case KEY_DSA: + case KEY_ECDSA: break; default: error("%s: unsupported key type", __func__); -- cgit v1.2.3 From bf0423e550e47bc4b3a40fe165da4e5c68b4aa5c Mon Sep 17 00:00:00 2001 From: Damien Miller Date: Fri, 10 Sep 2010 11:20:38 +1000 Subject: - djm@cvs.openbsd.org 2010/09/08 03:54:36 [authfile.c] typo --- ChangeLog | 3 +++ authfile.c | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'authfile.c') diff --git a/ChangeLog b/ChangeLog index 318d5d3fd..5dac860fa 100644 --- a/ChangeLog +++ b/ChangeLog @@ -40,6 +40,9 @@ add ssh_host_ecdsa_key to /etc; from Mattieu Baptiste ok deraadt@ + - djm@cvs.openbsd.org 2010/09/08 03:54:36 + [authfile.c] + typo 20100831 - OpenBSD CVS Sync diff --git a/authfile.c b/authfile.c index 865e7faf9..20ac8c76d 100644 --- a/authfile.c +++ b/authfile.c @@ -1,4 +1,4 @@ -/* $OpenBSD: authfile.c,v 1.83 2010/08/31 11:54:45 djm Exp $ */ +/* $OpenBSD: authfile.c,v 1.84 2010/09/08 03:54:36 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -533,7 +533,7 @@ key_load_private_pem(int fd, int type, const char *passphrase, key_free(prv); prv = NULL; } - name = "dsa w/o comment"; + name = "ecdsa w/o comment"; #ifdef DEBUG_PK if (prv->ecdsa != NULL) key_dump_ec_key(prv->ecdsa); -- cgit v1.2.3 From 6af914a15c0c33e8b5bab5ca61919b8562ff1db9 Mon Sep 17 00:00:00 2001 From: Damien Miller Date: Fri, 10 Sep 2010 11:39:26 +1000 Subject: - (djm) [authfd.c authfile.c bufec.c buffer.h configure.ac kex.h kexecdh.c] [kexecdhc.c kexecdhs.c key.c key.h myproposal.h packet.c readconf.c] [ssh-agent.c ssh-ecdsa.c ssh-keygen.c ssh.c] Disable ECDH and ECDSA on platforms that don't have the requisite OpenSSL support. ok dtucker@ --- ChangeLog | 4 ++++ authfd.c | 2 ++ authfile.c | 4 ++++ bufec.c | 3 +++ buffer.h | 2 ++ configure.ac | 26 +++++++++++++++++++++-- kex.h | 5 ++++- kexecdh.c | 3 +++ kexecdhc.c | 13 ++++++++++-- kexecdhs.c | 13 ++++++++++-- key.c | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- key.h | 10 ++++++++- myproposal.h | 53 +++++++++++++++++++++++++---------------------- packet.c | 4 ++++ readconf.c | 3 ++- ssh-agent.c | 4 ++++ ssh-ecdsa.c | 4 ++++ ssh-keygen.c | 6 ++++++ ssh.c | 10 +++++++++ 19 files changed, 200 insertions(+), 36 deletions(-) (limited to 'authfile.c') diff --git a/ChangeLog b/ChangeLog index 87fee3bf0..742e966c5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -62,6 +62,10 @@ client. ok naddy@ + - (djm) [authfd.c authfile.c bufec.c buffer.h configure.ac kex.h kexecdh.c] + [kexecdhc.c kexecdhs.c key.c key.h myproposal.h packet.c readconf.c] + [ssh-agent.c ssh-ecdsa.c ssh-keygen.c ssh.c] Disable ECDH and ECDSA on + platforms that don't have the requisite OpenSSL support. ok dtucker@ 20100831 - OpenBSD CVS Sync diff --git a/authfd.c b/authfd.c index ec537d2e9..c11c3f5a8 100644 --- a/authfd.c +++ b/authfd.c @@ -509,6 +509,7 @@ ssh_encode_identity_ssh2(Buffer *b, Key *key, const char *comment) buffer_len(&key->cert->certblob)); buffer_put_bignum2(b, key->dsa->priv_key); break; +#ifdef OPENSSL_HAS_ECC case KEY_ECDSA: buffer_put_cstring(b, key_curve_nid_to_name(key->ecdsa_nid)); buffer_put_ecpoint(b, EC_KEY_get0_group(key->ecdsa), @@ -522,6 +523,7 @@ ssh_encode_identity_ssh2(Buffer *b, Key *key, const char *comment) buffer_len(&key->cert->certblob)); buffer_put_bignum2(b, EC_KEY_get0_private_key(key->ecdsa)); break; +#endif } buffer_put_cstring(b, comment); } diff --git a/authfile.c b/authfile.c index 20ac8c76d..b1e3eda5c 100644 --- a/authfile.c +++ b/authfile.c @@ -213,10 +213,12 @@ key_save_private_pem(Key *key, const char *filename, const char *_passphrase, success = PEM_write_DSAPrivateKey(fp, key->dsa, cipher, passphrase, len, NULL, NULL); break; +#ifdef OPENSSL_HAS_ECC case KEY_ECDSA: success = PEM_write_ECPrivateKey(fp, key->ecdsa, cipher, passphrase, len, NULL, NULL); break; +#endif case KEY_RSA: success = PEM_write_RSAPrivateKey(fp, key->rsa, cipher, passphrase, len, NULL, NULL); @@ -515,6 +517,7 @@ key_load_private_pem(int fd, int type, const char *passphrase, #ifdef DEBUG_PK DSA_print_fp(stderr, prv->dsa, 8); #endif +#ifdef OPENSSL_HAS_ECC } else if (pk->type == EVP_PKEY_EC && (type == KEY_UNSPEC||type==KEY_ECDSA)) { prv = key_new(KEY_UNSPEC); @@ -538,6 +541,7 @@ key_load_private_pem(int fd, int type, const char *passphrase, if (prv->ecdsa != NULL) key_dump_ec_key(prv->ecdsa); #endif +#endif /* OPENSSL_HAS_ECC */ } else { error("PEM_read_PrivateKey: mismatch or " "unknown EVP_PKEY save_type %d", pk->save_type); diff --git a/bufec.c b/bufec.c index c77d1ecb9..3dcb49477 100644 --- a/bufec.c +++ b/bufec.c @@ -17,6 +17,8 @@ #include "includes.h" +#ifdef OPENSSL_HAS_ECC + #include #include @@ -141,3 +143,4 @@ buffer_get_ecpoint(Buffer *buffer, const EC_GROUP *curve, fatal("%s: buffer error", __func__); } +#endif /* OPENSSL_HAS_ECC */ diff --git a/buffer.h b/buffer.h index 1fb3f1666..e2a9dd100 100644 --- a/buffer.h +++ b/buffer.h @@ -86,11 +86,13 @@ char *buffer_get_cstring_ret(Buffer *, u_int *); void *buffer_get_string_ptr_ret(Buffer *, u_int *); int buffer_get_char_ret(char *, Buffer *); +#ifdef OPENSSL_HAS_ECC #include int buffer_put_ecpoint_ret(Buffer *, const EC_GROUP *, const EC_POINT *); void buffer_put_ecpoint(Buffer *, const EC_GROUP *, const EC_POINT *); int buffer_get_ecpoint_ret(Buffer *, const EC_GROUP *, EC_POINT *); void buffer_get_ecpoint(Buffer *, const EC_GROUP *, EC_POINT *); +#endif #endif /* BUFFER_H */ diff --git a/configure.ac b/configure.ac index 637e7b536..d267ba2b1 100644 --- a/configure.ac +++ b/configure.ac @@ -1,4 +1,4 @@ -# $Id: configure.ac,v 1.451 2010/08/16 03:15:23 dtucker Exp $ +# $Id: configure.ac,v 1.452 2010/09/10 01:39:27 djm Exp $ # # Copyright (c) 1999-2004 Damien Miller # @@ -15,7 +15,7 @@ # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. AC_INIT(OpenSSH, Portable, openssh-unix-dev@mindrot.org) -AC_REVISION($Revision: 1.451 $) +AC_REVISION($Revision: 1.452 $) AC_CONFIG_SRCDIR([ssh.c]) AC_CONFIG_HEADER(config.h) @@ -2158,6 +2158,28 @@ fi # Search for SHA256 support in libc and/or OpenSSL AC_CHECK_FUNCS(SHA256_Update EVP_sha256) +# Check complete ECC support in OpenSSL +AC_MSG_CHECKING([whether OpenSSL has complete ECC support]) +AC_LINK_IFELSE( + [AC_LANG_SOURCE([[ +#include +#include +#include +int main(void) { + EC_KEY *e = EC_KEY_new_by_curve_name(NID_secp521r1); + const EVP_MD *m = EVP_sha512(); /* We need this too */ +} + ]])], + [ + AC_MSG_RESULT(yes) + AC_DEFINE(OPENSSL_HAS_ECC, 1, + [libcrypto includes complete ECC support]) + ], + [ + AC_MSG_RESULT(no) + ] +) + saved_LIBS="$LIBS" AC_CHECK_LIB(iaf, ia_openinfo, [ LIBS="$LIBS -liaf" diff --git a/kex.h b/kex.h index f5dcc8791..06914756a 100644 --- a/kex.h +++ b/kex.h @@ -159,13 +159,16 @@ void kexgex_hash(const EVP_MD *, char *, char *, char *, int, char *, int, u_char *, int, int, int, int, BIGNUM *, BIGNUM *, BIGNUM *, BIGNUM *, BIGNUM *, u_char **, u_int *); +#ifdef OPENSSL_HAS_ECC void kex_ecdh_hash(const EVP_MD *, const EC_GROUP *, char *, char *, char *, int, char *, int, u_char *, int, const EC_POINT *, const EC_POINT *, const BIGNUM *, u_char **, u_int *); - int kex_ecdh_name_to_nid(const char *); const EVP_MD *kex_ecdh_name_to_evpmd(const char *); +#else +# define kex_ecdh_name_to_evpmd(x) NULL +#endif void derive_ssh1_session_id(BIGNUM *, BIGNUM *, u_int8_t[8], u_int8_t[16]); diff --git a/kexecdh.c b/kexecdh.c index f59d7b903..4c58a5122 100644 --- a/kexecdh.c +++ b/kexecdh.c @@ -26,6 +26,8 @@ #include "includes.h" +#ifdef OPENSSL_HAS_ECC + #include #include @@ -116,3 +118,4 @@ kex_ecdh_hash( *hashlen = EVP_MD_size(evp_md); } +#endif /* OPENSSL_HAS_ECC */ diff --git a/kexecdhc.c b/kexecdhc.c index 7ac7b1ee2..297a0e5a9 100644 --- a/kexecdhc.c +++ b/kexecdhc.c @@ -32,8 +32,6 @@ #include #include -#include - #include "xmalloc.h" #include "buffer.h" #include "key.h" @@ -44,6 +42,10 @@ #include "dh.h" #include "ssh2.h" +#ifdef OPENSSL_HAS_ECC + +#include + void kexecdh_client(Kex *kex) { @@ -156,3 +158,10 @@ kexecdh_client(Kex *kex) BN_clear_free(shared_secret); kex_finish(kex); } +#else /* OPENSSL_HAS_ECC */ +void +kexecdh_client(Kex *kex) +{ + fatal("ECC support is not enabled"); +} +#endif /* OPENSSL_HAS_ECC */ diff --git a/kexecdhs.c b/kexecdhs.c index e49a0ef37..d2c3feb09 100644 --- a/kexecdhs.c +++ b/kexecdhs.c @@ -30,8 +30,6 @@ #include #include -#include - #include "xmalloc.h" #include "buffer.h" #include "key.h" @@ -46,6 +44,10 @@ #endif #include "monitor_wrap.h" +#ifdef OPENSSL_HAS_ECC + +#include + void kexecdh_server(Kex *kex) { @@ -161,3 +163,10 @@ kexecdh_server(Kex *kex) BN_clear_free(shared_secret); kex_finish(kex); } +#else /* OPENSSL_HAS_ECC */ +void +kexecdh_server(Kex *kex) +{ + fatal("ECC support is not enabled"); +} +#endif /* OPENSSL_HAS_ECC */ diff --git a/key.c b/key.c index b9dc2355b..3cda8f2cb 100644 --- a/key.c +++ b/key.c @@ -111,10 +111,12 @@ key_new(int type) fatal("key_new: BN_new failed"); k->dsa = dsa; break; +#ifdef OPENSSL_HAS_ECC case KEY_ECDSA: case KEY_ECDSA_CERT: /* Cannot do anything until we know the group */ break; +#endif case KEY_UNSPEC: break; default: @@ -214,12 +216,14 @@ key_free(Key *k) DSA_free(k->dsa); k->dsa = NULL; break; +#ifdef OPENSSL_HAS_ECC case KEY_ECDSA: case KEY_ECDSA_CERT: if (k->ecdsa != NULL) EC_KEY_free(k->ecdsa); k->ecdsa = NULL; break; +#endif case KEY_UNSPEC: break; default: @@ -279,6 +283,7 @@ key_equal_public(const Key *a, const Key *b) BN_cmp(a->dsa->q, b->dsa->q) == 0 && BN_cmp(a->dsa->g, b->dsa->g) == 0 && BN_cmp(a->dsa->pub_key, b->dsa->pub_key) == 0; +#ifdef OPENSSL_HAS_ECC case KEY_ECDSA_CERT: case KEY_ECDSA: if (a->ecdsa == NULL || b->ecdsa == NULL || @@ -297,6 +302,7 @@ key_equal_public(const Key *a, const Key *b) } BN_CTX_free(bnctx); return 1; +#endif /* OPENSSL_HAS_ECC */ default: fatal("key_equal: bad key type %d", a->type); } @@ -695,11 +701,13 @@ key_read(Key *ret, char **cpp) } *space = '\0'; type = key_type_from_name(cp); +#ifdef OPENSSL_HAS_ECC if (key_type_plain(type) == KEY_ECDSA && (curve_nid = key_ecdsa_nid_from_name(cp)) == -1) { debug("key_read: invalid curve"); return -1; } +#endif *space = ' '; if (type == KEY_UNSPEC) { debug3("key_read: missing keytype"); @@ -736,12 +744,14 @@ key_read(Key *ret, char **cpp) key_free(k); return -1; } +#ifdef OPENSSL_HAS_ECC if (key_type_plain(type) == KEY_ECDSA && curve_nid != k->ecdsa_nid) { error("key_read: type mismatch: EC curve mismatch"); key_free(k); return -1; } +#endif /*XXXX*/ if (key_is_cert(ret)) { if (!key_is_cert(k)) { @@ -772,6 +782,7 @@ key_read(Key *ret, char **cpp) DSA_print_fp(stderr, ret->dsa, 8); #endif } +#ifdef OPENSSL_HAS_ECC if (key_type_plain(ret->type) == KEY_ECDSA) { if (ret->ecdsa != NULL) EC_KEY_free(ret->ecdsa); @@ -783,6 +794,7 @@ key_read(Key *ret, char **cpp) key_dump_ec_key(ret->ecdsa); #endif } +#endif success = 1; /*XXXX*/ key_free(k); @@ -839,11 +851,13 @@ key_write(const Key *key, FILE *f) if (key->dsa == NULL) return 0; break; +#ifdef OPENSSL_HAS_ECC case KEY_ECDSA: case KEY_ECDSA_CERT: if (key->ecdsa == NULL) return 0; break; +#endif case KEY_RSA: case KEY_RSA_CERT_V00: case KEY_RSA_CERT: @@ -877,8 +891,10 @@ key_type(const Key *k) return "RSA"; case KEY_DSA: return "DSA"; +#ifdef OPENSSL_HAS_ECC case KEY_ECDSA: return "ECDSA"; +#endif case KEY_RSA_CERT_V00: return "RSA-CERT-V00"; case KEY_DSA_CERT_V00: @@ -887,8 +903,10 @@ key_type(const Key *k) return "RSA-CERT"; case KEY_DSA_CERT: return "DSA-CERT"; +#ifdef OPENSSL_HAS_ECC case KEY_ECDSA_CERT: return "ECDSA-CERT"; +#endif } return "unknown"; } @@ -922,6 +940,7 @@ key_ssh_name_from_type_nid(int type, int nid) return "ssh-rsa-cert-v01@openssh.com"; case KEY_DSA_CERT: return "ssh-dss-cert-v01@openssh.com"; +#ifdef OPENSSL_HAS_ECC case KEY_ECDSA: switch (nid) { case NID_X9_62_prime256v1: @@ -946,6 +965,7 @@ key_ssh_name_from_type_nid(int type, int nid) break; } break; +#endif /* OPENSSL_HAS_ECC */ } return "ssh-unknown"; } @@ -976,9 +996,11 @@ key_size(const Key *k) case KEY_DSA_CERT_V00: case KEY_DSA_CERT: return BN_num_bits(k->dsa->p); +#ifdef OPENSSL_HAS_ECC case KEY_ECDSA: case KEY_ECDSA_CERT: return key_curve_nid_to_bits(k->ecdsa_nid); +#endif } return 0; } @@ -1012,17 +1034,20 @@ int key_ecdsa_bits_to_nid(int bits) { switch (bits) { +#ifdef OPENSSL_HAS_ECC case 256: return NID_X9_62_prime256v1; case 384: return NID_secp384r1; case 521: return NID_secp521r1; +#endif default: return -1; } } +#ifdef OPENSSL_HAS_ECC /* * This is horrid, but OpenSSL's PEM_read_PrivateKey seems not to restore * the EC_GROUP nid when loading a key... @@ -1070,6 +1095,7 @@ ecdsa_generate_private_key(u_int bits, int *nid) fatal("%s: EC_KEY_generate_key failed", __func__); return private; } +#endif /* OPENSSL_HAS_ECC */ Key * key_generate(int type, u_int bits) @@ -1079,9 +1105,11 @@ key_generate(int type, u_int bits) case KEY_DSA: k->dsa = dsa_generate_private_key(bits); break; +#ifdef OPENSSL_HAS_ECC case KEY_ECDSA: k->ecdsa = ecdsa_generate_private_key(bits, &k->ecdsa_nid); break; +#endif case KEY_RSA: case KEY_RSA1: k->rsa = rsa_generate_private_key(bits); @@ -1158,6 +1186,7 @@ key_from_private(const Key *k) (BN_copy(n->dsa->pub_key, k->dsa->pub_key) == NULL)) fatal("key_from_private: BN_copy failed"); break; +#ifdef OPENSSL_HAS_ECC case KEY_ECDSA: case KEY_ECDSA_CERT: n = key_new(k->type); @@ -1168,6 +1197,7 @@ key_from_private(const Key *k) EC_KEY_get0_public_key(k->ecdsa)) != 1) fatal("%s: EC_KEY_set_public_key failed", __func__); break; +#endif case KEY_RSA: case KEY_RSA1: case KEY_RSA_CERT_V00: @@ -1199,11 +1229,13 @@ key_type_from_name(char *name) return KEY_RSA; } else if (strcmp(name, "ssh-dss") == 0) { return KEY_DSA; +#ifdef OPENSSL_HAS_ECC } else if (strcmp(name, "ecdsa") == 0 || strcmp(name, "ecdsa-sha2-nistp256") == 0 || strcmp(name, "ecdsa-sha2-nistp384") == 0 || strcmp(name, "ecdsa-sha2-nistp521") == 0) { return KEY_ECDSA; +#endif } else if (strcmp(name, "ssh-rsa-cert-v00@openssh.com") == 0) { return KEY_RSA_CERT_V00; } else if (strcmp(name, "ssh-dss-cert-v00@openssh.com") == 0) { @@ -1212,10 +1244,13 @@ key_type_from_name(char *name) return KEY_RSA_CERT; } else if (strcmp(name, "ssh-dss-cert-v01@openssh.com") == 0) { return KEY_DSA_CERT; +#ifdef OPENSSL_HAS_ECC } else if (strcmp(name, "ecdsa-sha2-nistp256-cert-v01@openssh.com") == 0 || strcmp(name, "ecdsa-sha2-nistp384-cert-v01@openssh.com") == 0 || - strcmp(name, "ecdsa-sha2-nistp521-cert-v01@openssh.com") == 0) + strcmp(name, "ecdsa-sha2-nistp521-cert-v01@openssh.com") == 0) { return KEY_ECDSA_CERT; +#endif + } debug2("key_type_from_name: unknown key type '%s'", name); return KEY_UNSPEC; @@ -1224,6 +1259,7 @@ key_type_from_name(char *name) int key_ecdsa_nid_from_name(const char *name) { +#ifdef OPENSSL_HAS_ECC if (strcmp(name, "ecdsa-sha2-nistp256") == 0 || strcmp(name, "ecdsa-sha2-nistp256-cert-v01@openssh.com") == 0) return NID_X9_62_prime256v1; @@ -1233,6 +1269,7 @@ key_ecdsa_nid_from_name(const char *name) if (strcmp(name, "ecdsa-sha2-nistp521") == 0 || strcmp(name, "ecdsa-sha2-nistp521-cert-v01@openssh.com") == 0) return NID_secp521r1; +#endif /* OPENSSL_HAS_ECC */ debug2("%s: unknown/non-ECDSA key type '%s'", __func__, name); return -1; @@ -1403,7 +1440,9 @@ key_from_blob(const u_char *blob, u_int blen) int rlen, type, nid = -1; char *ktype = NULL, *curve = NULL; Key *key = NULL; +#ifdef OPENSSL_HAS_ECC EC_POINT *q = NULL; +#endif #ifdef DEBUG_PK dump_base64(stderr, blob, blen); @@ -1416,8 +1455,10 @@ key_from_blob(const u_char *blob, u_int blen) } type = key_type_from_name(ktype); +#ifdef OPENSSL_HAS_ECC if (key_type_plain(type) == KEY_ECDSA) nid = key_ecdsa_nid_from_name(ktype); +#endif switch (type) { case KEY_RSA_CERT: @@ -1455,6 +1496,7 @@ key_from_blob(const u_char *blob, u_int blen) DSA_print_fp(stderr, key->dsa, 8); #endif break; +#ifdef OPENSSL_HAS_ECC case KEY_ECDSA_CERT: (void)buffer_get_string_ptr_ret(&b, NULL); /* Skip nonce */ /* FALLTHROUGH */ @@ -1490,6 +1532,7 @@ key_from_blob(const u_char *blob, u_int blen) key_dump_ec_point(EC_KEY_get0_group(key->ecdsa), q); #endif break; +#endif /* OPENSSL_HAS_ECC */ case KEY_UNSPEC: key = key_new(type); break; @@ -1509,8 +1552,10 @@ key_from_blob(const u_char *blob, u_int blen) xfree(ktype); if (curve != NULL) xfree(curve); +#ifdef OPENSSL_HAS_ECC if (q != NULL) EC_POINT_free(q); +#endif buffer_free(&b); return key; } @@ -1543,12 +1588,14 @@ key_to_blob(const Key *key, u_char **blobp, u_int *lenp) buffer_put_bignum2(&b, key->dsa->g); buffer_put_bignum2(&b, key->dsa->pub_key); break; +#ifdef OPENSSL_HAS_ECC case KEY_ECDSA: buffer_put_cstring(&b, key_ssh_name(key)); buffer_put_cstring(&b, key_curve_nid_to_name(key->ecdsa_nid)); buffer_put_ecpoint(&b, EC_KEY_get0_group(key->ecdsa), EC_KEY_get0_public_key(key->ecdsa)); break; +#endif case KEY_RSA: buffer_put_cstring(&b, key_ssh_name(key)); buffer_put_bignum2(&b, key->rsa->e); @@ -1582,9 +1629,11 @@ key_sign( case KEY_DSA_CERT: case KEY_DSA: return ssh_dss_sign(key, sigp, lenp, data, datalen); +#ifdef OPENSSL_HAS_ECC case KEY_ECDSA_CERT: case KEY_ECDSA: return ssh_ecdsa_sign(key, sigp, lenp, data, datalen); +#endif case KEY_RSA_CERT_V00: case KEY_RSA_CERT: case KEY_RSA: @@ -1613,9 +1662,11 @@ key_verify( case KEY_DSA_CERT: case KEY_DSA: return ssh_dss_verify(key, signature, signaturelen, data, datalen); +#ifdef OPENSSL_HAS_ECC case KEY_ECDSA_CERT: case KEY_ECDSA: return ssh_ecdsa_verify(key, signature, signaturelen, data, datalen); +#endif case KEY_RSA_CERT_V00: case KEY_RSA_CERT: case KEY_RSA: @@ -1670,6 +1721,7 @@ key_demote(const Key *k) if ((pk->dsa->pub_key = BN_dup(k->dsa->pub_key)) == NULL) fatal("key_demote: BN_dup failed"); break; +#ifdef OPENSSL_HAS_ECC case KEY_ECDSA_CERT: key_cert_copy(k, pk); /* FALLTHROUGH */ @@ -1680,6 +1732,7 @@ key_demote(const Key *k) EC_KEY_get0_public_key(k->ecdsa)) != 1) fatal("key_demote: EC_KEY_set_public_key failed"); break; +#endif default: fatal("key_free: bad key type %d", k->type); break; @@ -1819,6 +1872,7 @@ key_certify(Key *k, Key *ca) buffer_put_bignum2(&k->cert->certblob, k->dsa->g); buffer_put_bignum2(&k->cert->certblob, k->dsa->pub_key); break; +#ifdef OPENSSL_HAS_ECC case KEY_ECDSA_CERT: buffer_put_cstring(&k->cert->certblob, key_curve_nid_to_name(k->ecdsa_nid)); @@ -1826,6 +1880,7 @@ key_certify(Key *k, Key *ca) EC_KEY_get0_group(k->ecdsa), EC_KEY_get0_public_key(k->ecdsa)); break; +#endif case KEY_RSA_CERT_V00: case KEY_RSA_CERT: buffer_put_bignum2(&k->cert->certblob, k->rsa->e); @@ -1955,12 +2010,14 @@ key_cert_is_legacy(Key *k) int key_curve_name_to_nid(const char *name) { +#ifdef OPENSSL_HAS_ECC if (strcmp(name, "nistp256") == 0) return NID_X9_62_prime256v1; else if (strcmp(name, "nistp384") == 0) return NID_secp384r1; else if (strcmp(name, "nistp521") == 0) return NID_secp521r1; +#endif debug("%s: unsupported EC curve name \"%.100s\"", __func__, name); return -1; @@ -1970,12 +2027,14 @@ u_int key_curve_nid_to_bits(int nid) { switch (nid) { +#ifdef OPENSSL_HAS_ECC case NID_X9_62_prime256v1: return 256; case NID_secp384r1: return 384; case NID_secp521r1: return 521; +#endif default: error("%s: unsupported EC curve nid %d", __func__, nid); return 0; @@ -1985,17 +2044,19 @@ key_curve_nid_to_bits(int nid) const char * key_curve_nid_to_name(int nid) { +#ifdef OPENSSL_HAS_ECC if (nid == NID_X9_62_prime256v1) return "nistp256"; else if (nid == NID_secp384r1) return "nistp384"; else if (nid == NID_secp521r1) return "nistp521"; - +#endif error("%s: unsupported EC curve nid %d", __func__, nid); return NULL; } +#ifdef OPENSSL_HAS_ECC const EVP_MD * key_ec_nid_to_evpmd(int nid) { @@ -2180,4 +2241,4 @@ key_dump_ec_key(const EC_KEY *key) fputs("\n", stderr); } #endif /* defined(DEBUG_KEXECDH) || defined(DEBUG_PK) */ - +#endif /* OPENSSL_HAS_ECC */ diff --git a/key.h b/key.h index ba1a20c07..86a1d889c 100644 --- a/key.h +++ b/key.h @@ -29,7 +29,9 @@ #include "buffer.h" #include #include +#ifdef OPENSSL_HAS_ECC #include +#endif typedef struct Key Key; enum types { @@ -77,7 +79,11 @@ struct Key { RSA *rsa; DSA *dsa; int ecdsa_nid; /* NID of curve */ +#ifdef OPENSSL_HAS_ECC EC_KEY *ecdsa; +#else + void *ecdsa; +#endif struct KeyCert *cert; }; @@ -114,10 +120,12 @@ int key_curve_name_to_nid(const char *); const char * key_curve_nid_to_name(int); u_int key_curve_nid_to_bits(int); int key_ecdsa_bits_to_nid(int); +#ifdef OPENSSL_HAS_ECC int key_ecdsa_group_to_nid(const EC_GROUP *); const EVP_MD * key_ec_nid_to_evpmd(int nid); int key_ec_validate_public(const EC_GROUP *, const EC_POINT *); int key_ec_validate_private(const EC_KEY *); +#endif Key *key_from_blob(const u_char *, u_int); int key_to_blob(const Key *, u_char **, u_int *); @@ -135,7 +143,7 @@ int ssh_ecdsa_verify(const Key *, const u_char *, u_int, const u_char *, u_int) int ssh_rsa_sign(const Key *, u_char **, u_int *, const u_char *, u_int); int ssh_rsa_verify(const Key *, const u_char *, u_int, const u_char *, u_int); -#if defined(DEBUG_KEXECDH) || defined(DEBUG_PK) +#if defined(OPENSSL_HAS_ECC) && (defined(DEBUG_KEXECDH) || defined(DEBUG_PK)) void key_dump_ec_point(const EC_GROUP *, const EC_POINT *); void key_dump_ec_key(const EC_KEY *); #endif diff --git a/myproposal.h b/myproposal.h index 5daca533b..893190788 100644 --- a/myproposal.h +++ b/myproposal.h @@ -26,44 +26,49 @@ #include +#ifdef OPENSSL_HAS_ECC +# define KEX_ECDH_METHODS \ + "ecdh-sha2-nistp256," \ + "ecdh-sha2-nistp384," \ + "ecdh-sha2-nistp521," +# define HOSTKEY_ECDSA_CERT_METHODS \ + "ecdsa-sha2-nistp256-cert-v01@openssh.com," \ + "ecdsa-sha2-nistp384-cert-v01@openssh.com," \ + "ecdsa-sha2-nistp521-cert-v01@openssh.com," +# define HOSTKEY_ECDSA_METHODS \ + "ecdsa-sha2-nistp256," \ + "ecdsa-sha2-nistp384," \ + "ecdsa-sha2-nistp521," +#else +# define KEX_ECDH_METHODS +# define HOSTKEY_ECDSA_CERT_METHODS +# define HOSTKEY_ECDSA_METHODS +#endif + /* Old OpenSSL doesn't support what we need for DHGEX-sha256 */ #if OPENSSL_VERSION_NUMBER < 0x00907000L -# define KEX_DEFAULT_KEX \ - "diffie-hellman-group-exchange-sha1," \ - "diffie-hellman-group14-sha1," \ - "diffie-hellman-group1-sha1" - -#define KEX_DEFAULT_PK_ALG \ - "ssh-rsa-cert-v01@openssh.com," \ - "ssh-dss-cert-v01@openssh.com," \ - "ssh-rsa-cert-v00@openssh.com," \ - "ssh-dss-cert-v00@openssh.com," \ - "ssh-rsa," \ - "ssh-dss" +# define KEX_SHA256_METHODS \ + "diffie-hellman-group-exchange-sha1," #else -# define KEX_DEFAULT_KEX \ - "ecdh-sha2-nistp256," \ - "ecdh-sha2-nistp384," \ - "ecdh-sha2-nistp521," \ - "diffie-hellman-group-exchange-sha256," \ +# define KEX_SHA256_METHODS +#endif + +# define KEX_DEFAULT_KEX \ + KEX_ECDH_METHODS \ + KEX_SHA256_METHODS \ "diffie-hellman-group-exchange-sha1," \ "diffie-hellman-group14-sha1," \ "diffie-hellman-group1-sha1" #define KEX_DEFAULT_PK_ALG \ - "ecdsa-sha2-nistp256-cert-v01@openssh.com," \ - "ecdsa-sha2-nistp384-cert-v01@openssh.com," \ - "ecdsa-sha2-nistp521-cert-v01@openssh.com," \ + HOSTKEY_ECDSA_CERT_METHODS \ "ssh-rsa-cert-v01@openssh.com," \ "ssh-dss-cert-v01@openssh.com," \ "ssh-rsa-cert-v00@openssh.com," \ "ssh-dss-cert-v00@openssh.com," \ - "ecdsa-sha2-nistp256," \ - "ecdsa-sha2-nistp384," \ - "ecdsa-sha2-nistp521," \ + HOSTKEY_ECDSA_METHODS \ "ssh-rsa," \ "ssh-dss" -#endif #define KEX_DEFAULT_ENCRYPT \ "aes128-ctr,aes192-ctr,aes256-ctr," \ diff --git a/packet.c b/packet.c index a06c5e3ef..0018d5839 100644 --- a/packet.c +++ b/packet.c @@ -641,11 +641,13 @@ packet_put_bignum2(BIGNUM * value) buffer_put_bignum2(&active_state->outgoing_packet, value); } +#ifdef OPENSSL_HAS_ECC void packet_put_ecpoint(const EC_GROUP *curve, const EC_POINT *point) { buffer_put_ecpoint(&active_state->outgoing_packet, curve, point); } +#endif /* * Finalizes and sends the packet. If the encryption key has been set, @@ -1517,11 +1519,13 @@ packet_get_bignum2(BIGNUM * value) buffer_get_bignum2(&active_state->incoming_packet, value); } +#ifdef OPENSSL_HAS_ECC void packet_get_ecpoint(const EC_GROUP *curve, EC_POINT *point) { buffer_get_ecpoint(&active_state->incoming_packet, curve, point); } +#endif void * packet_get_raw(u_int *length_ptr) diff --git a/readconf.c b/readconf.c index 98ce3017f..586422930 100644 --- a/readconf.c +++ b/readconf.c @@ -1214,12 +1214,13 @@ fill_default_options(Options * options) xmalloc(len); snprintf(options->identity_files[options->num_identity_files++], len, "~/%.100s", _PATH_SSH_CLIENT_ID_DSA); - +#ifdef OPENSSL_HAS_ECC len = 2 + strlen(_PATH_SSH_CLIENT_ID_ECDSA) + 1; options->identity_files[options->num_identity_files] = xmalloc(len); snprintf(options->identity_files[options->num_identity_files++], len, "~/%.100s", _PATH_SSH_CLIENT_ID_ECDSA); +#endif } } if (options->escape_char == -1) diff --git a/ssh-agent.c b/ssh-agent.c index 87939b2b6..8f19fb157 100644 --- a/ssh-agent.c +++ b/ssh-agent.c @@ -468,8 +468,10 @@ process_add_identity(SocketEntry *e, int version) int type, success = 0, death = 0, confirm = 0; char *type_name, *comment, *curve; Key *k = NULL; +#ifdef OPENSSL_HAS_ECC BIGNUM *exponent; EC_POINT *q; +#endif u_char *cert; u_int len; @@ -510,6 +512,7 @@ process_add_identity(SocketEntry *e, int version) key_add_private(k); buffer_get_bignum2(&e->request, k->dsa->priv_key); break; +#ifdef OPENSSL_HAS_ECC case KEY_ECDSA: k = key_new_private(type); k->ecdsa_nid = key_ecdsa_nid_from_name(type_name); @@ -561,6 +564,7 @@ process_add_identity(SocketEntry *e, int version) fatal("%s: bad ECDSA key", __func__); BN_clear_free(exponent); break; +#endif /* OPENSSL_HAS_ECC */ case KEY_RSA: k = key_new_private(type); buffer_get_bignum2(&e->request, k->rsa->n); diff --git a/ssh-ecdsa.c b/ssh-ecdsa.c index 5c4ce2311..c8276b460 100644 --- a/ssh-ecdsa.c +++ b/ssh-ecdsa.c @@ -26,6 +26,8 @@ #include "includes.h" +#ifdef OPENSSL_HAS_ECC + #include #include @@ -162,3 +164,5 @@ ssh_ecdsa_verify(const Key *key, const u_char *signature, u_int signaturelen, ret == 1 ? "correct" : ret == 0 ? "incorrect" : "error"); return ret; } + +#endif /* OPENSSL_HAS_ECC */ diff --git a/ssh-keygen.c b/ssh-keygen.c index 43b8c7f97..bbd434b0b 100644 --- a/ssh-keygen.c +++ b/ssh-keygen.c @@ -265,10 +265,12 @@ do_convert_to_pkcs8(Key *k) if (!PEM_write_DSA_PUBKEY(stdout, k->dsa)) fatal("PEM_write_DSA_PUBKEY failed"); break; +#ifdef OPENSSL_HAS_ECC case KEY_ECDSA: if (!PEM_write_EC_PUBKEY(stdout, k->ecdsa)) fatal("PEM_write_EC_PUBKEY failed"); break; +#endif default: fatal("%s: unsupported key type %s", __func__, key_type(k)); } @@ -549,6 +551,7 @@ do_convert_from_pkcs8(Key **k, int *private) (*k)->type = KEY_DSA; (*k)->dsa = EVP_PKEY_get1_DSA(pubkey); break; +#ifdef OPENSSL_HAS_ECC case EVP_PKEY_EC: *k = key_new(KEY_UNSPEC); (*k)->type = KEY_ECDSA; @@ -556,6 +559,7 @@ do_convert_from_pkcs8(Key **k, int *private) (*k)->ecdsa_nid = key_ecdsa_group_to_nid( EC_KEY_get0_group((*k)->ecdsa)); break; +#endif default: fatal("%s: unsupported pubkey type %d", __func__, EVP_PKEY_type(pubkey->type)); @@ -632,10 +636,12 @@ do_convert_from(struct passwd *pw) ok = PEM_write_DSAPrivateKey(stdout, k->dsa, NULL, NULL, 0, NULL, NULL); break; +#ifdef OPENSSL_HAS_ECC case KEY_ECDSA: ok = PEM_write_ECPrivateKey(stdout, k->ecdsa, NULL, NULL, 0, NULL, NULL); break; +#endif case KEY_RSA: ok = PEM_write_RSAPrivateKey(stdout, k->rsa, NULL, NULL, 0, NULL, NULL); diff --git a/ssh.c b/ssh.c index 51c68d7da..3ade744b6 100644 --- a/ssh.c +++ b/ssh.c @@ -783,20 +783,26 @@ main(int ac, char **av) sensitive_data.nkeys = 7; sensitive_data.keys = xcalloc(sensitive_data.nkeys, sizeof(Key)); + for (i = 0; i < sensitive_data.nkeys; i++) + sensitive_data.keys[i] = NULL; PRIV_START; sensitive_data.keys[0] = key_load_private_type(KEY_RSA1, _PATH_HOST_KEY_FILE, "", NULL, NULL); sensitive_data.keys[1] = key_load_private_cert(KEY_DSA, _PATH_HOST_DSA_KEY_FILE, "", NULL); +#ifdef OPENSSL_HAS_ECC sensitive_data.keys[2] = key_load_private_cert(KEY_ECDSA, _PATH_HOST_ECDSA_KEY_FILE, "", NULL); +#endif sensitive_data.keys[3] = key_load_private_cert(KEY_RSA, _PATH_HOST_RSA_KEY_FILE, "", NULL); sensitive_data.keys[4] = key_load_private_type(KEY_DSA, _PATH_HOST_DSA_KEY_FILE, "", NULL, NULL); +#ifdef OPENSSL_HAS_ECC sensitive_data.keys[5] = key_load_private_type(KEY_ECDSA, _PATH_HOST_ECDSA_KEY_FILE, "", NULL, NULL); +#endif sensitive_data.keys[6] = key_load_private_type(KEY_RSA, _PATH_HOST_RSA_KEY_FILE, "", NULL, NULL); PRIV_END; @@ -808,14 +814,18 @@ main(int ac, char **av) sensitive_data.keys[6] == NULL) { sensitive_data.keys[1] = key_load_cert( _PATH_HOST_DSA_KEY_FILE); +#ifdef OPENSSL_HAS_ECC sensitive_data.keys[2] = key_load_cert( _PATH_HOST_ECDSA_KEY_FILE); +#endif sensitive_data.keys[3] = key_load_cert( _PATH_HOST_RSA_KEY_FILE); sensitive_data.keys[4] = key_load_public( _PATH_HOST_DSA_KEY_FILE, NULL); +#ifdef OPENSSL_HAS_ECC sensitive_data.keys[5] = key_load_public( _PATH_HOST_ECDSA_KEY_FILE, NULL); +#endif sensitive_data.keys[6] = key_load_public( _PATH_HOST_RSA_KEY_FILE, NULL); sensitive_data.external_keysign = 1; -- cgit v1.2.3 From b472a90d4ceca15620aa525099bf4b2d5ba8a59b Mon Sep 17 00:00:00 2001 From: Damien Miller Date: Fri, 5 Nov 2010 10:19:49 +1100 Subject: - djm@cvs.openbsd.org 2010/10/28 11:22:09 [authfile.c key.c key.h ssh-keygen.c] fix a possible NULL deref on loading a corrupt ECDH key store ECDH group information in private keys files as "named groups" rather than as a set of explicit group parameters (by setting the OPENSSL_EC_NAMED_CURVE flag). This makes for shorter key files and retrieves the group's OpenSSL NID that we need for various things. --- ChangeLog | 8 ++++++++ authfile.c | 14 +++++--------- key.c | 31 ++++++++++++++++++++++--------- key.h | 4 ++-- ssh-keygen.c | 5 ++--- 5 files changed, 39 insertions(+), 23 deletions(-) (limited to 'authfile.c') diff --git a/ChangeLog b/ChangeLog index 2e7f92c94..79419367e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -3,6 +3,14 @@ - djm@cvs.openbsd.org 2010/09/22 12:26:05 [regress/Makefile regress/kextype.sh] regress test for each of the key exchange algorithms that we support + - djm@cvs.openbsd.org 2010/10/28 11:22:09 + [authfile.c key.c key.h ssh-keygen.c] + fix a possible NULL deref on loading a corrupt ECDH key + + store ECDH group information in private keys files as "named groups" + rather than as a set of explicit group parameters (by setting + the OPENSSL_EC_NAMED_CURVE flag). This makes for shorter key files and + retrieves the group's OpenSSL NID that we need for various things. 20101025 - (tim) [openbsd-compat/glob.h] Remove sys/cdefs.h include that came with diff --git a/authfile.c b/authfile.c index b1e3eda5c..7f98ab547 100644 --- a/authfile.c +++ b/authfile.c @@ -1,4 +1,4 @@ -/* $OpenBSD: authfile.c,v 1.84 2010/09/08 03:54:36 djm Exp $ */ +/* $OpenBSD: authfile.c,v 1.85 2010/10/28 11:22:09 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -523,13 +523,9 @@ key_load_private_pem(int fd, int type, const char *passphrase, prv = key_new(KEY_UNSPEC); prv->ecdsa = EVP_PKEY_get1_EC_KEY(pk); prv->type = KEY_ECDSA; - prv->ecdsa_nid = key_ecdsa_group_to_nid( - EC_KEY_get0_group(prv->ecdsa)); - if (key_curve_nid_to_name(prv->ecdsa_nid) == NULL) { - key_free(prv); - prv = NULL; - } - if (key_ec_validate_public(EC_KEY_get0_group(prv->ecdsa), + if ((prv->ecdsa_nid = key_ecdsa_key_to_nid(prv->ecdsa)) == -1 || + key_curve_nid_to_name(prv->ecdsa_nid) == NULL || + key_ec_validate_public(EC_KEY_get0_group(prv->ecdsa), EC_KEY_get0_public_key(prv->ecdsa)) != 0 || key_ec_validate_private(prv->ecdsa) != 0) { error("%s: bad ECDSA key", __func__); @@ -538,7 +534,7 @@ key_load_private_pem(int fd, int type, const char *passphrase, } name = "ecdsa w/o comment"; #ifdef DEBUG_PK - if (prv->ecdsa != NULL) + if (prv != NULL && prv->ecdsa != NULL) key_dump_ec_key(prv->ecdsa); #endif #endif /* OPENSSL_HAS_ECC */ diff --git a/key.c b/key.c index 196092de5..c71bf5b0a 100644 --- a/key.c +++ b/key.c @@ -1,4 +1,4 @@ -/* $OpenBSD: key.c,v 1.93 2010/09/09 10:45:45 djm Exp $ */ +/* $OpenBSD: key.c,v 1.94 2010/10/28 11:22:09 djm Exp $ */ /* * read_bignum(): * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -1053,12 +1053,8 @@ key_ecdsa_bits_to_nid(int bits) } #ifdef OPENSSL_HAS_ECC -/* - * This is horrid, but OpenSSL's PEM_read_PrivateKey seems not to restore - * the EC_GROUP nid when loading a key... - */ int -key_ecdsa_group_to_nid(const EC_GROUP *g) +key_ecdsa_key_to_nid(EC_KEY *k) { EC_GROUP *eg; int nids[] = { @@ -1067,23 +1063,39 @@ key_ecdsa_group_to_nid(const EC_GROUP *g) NID_secp521r1, -1 }; + int nid; u_int i; BN_CTX *bnctx; + const EC_GROUP *g = EC_KEY_get0_group(k); + /* + * The group may be stored in a ASN.1 encoded private key in one of two + * ways: as a "named group", which is reconstituted by ASN.1 object ID + * or explicit group parameters encoded into the key blob. Only the + * "named group" case sets the group NID for us, but we can figure + * it out for the other case by comparing against all the groups that + * are supported. + */ + if ((nid = EC_GROUP_get_curve_name(g)) > 0) + return nid; if ((bnctx = BN_CTX_new()) == NULL) fatal("%s: BN_CTX_new() failed", __func__); for (i = 0; nids[i] != -1; i++) { if ((eg = EC_GROUP_new_by_curve_name(nids[i])) == NULL) fatal("%s: EC_GROUP_new_by_curve_name failed", __func__); - if (EC_GROUP_cmp(g, eg, bnctx) == 0) { - EC_GROUP_free(eg); + if (EC_GROUP_cmp(g, eg, bnctx) == 0) break; - } EC_GROUP_free(eg); } BN_CTX_free(bnctx); debug3("%s: nid = %d", __func__, nids[i]); + if (nids[i] != -1) { + /* Use the group with the NID attached */ + EC_GROUP_set_asn1_flag(eg, OPENSSL_EC_NAMED_CURVE); + if (EC_KEY_set_group(k, eg) != 1) + fatal("%s: EC_KEY_set_group", __func__); + } return nids[i]; } @@ -1098,6 +1110,7 @@ ecdsa_generate_private_key(u_int bits, int *nid) fatal("%s: EC_KEY_new_by_curve_name failed", __func__); if (EC_KEY_generate_key(private) != 1) fatal("%s: EC_KEY_generate_key failed", __func__); + EC_KEY_set_asn1_flag(private, OPENSSL_EC_NAMED_CURVE); return private; } #endif /* OPENSSL_HAS_ECC */ diff --git a/key.h b/key.h index 86a1d889c..ec5ac5eb8 100644 --- a/key.h +++ b/key.h @@ -1,4 +1,4 @@ -/* $OpenBSD: key.h,v 1.32 2010/09/09 10:45:45 djm Exp $ */ +/* $OpenBSD: key.h,v 1.33 2010/10/28 11:22:09 djm Exp $ */ /* * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. @@ -121,7 +121,7 @@ const char * key_curve_nid_to_name(int); u_int key_curve_nid_to_bits(int); int key_ecdsa_bits_to_nid(int); #ifdef OPENSSL_HAS_ECC -int key_ecdsa_group_to_nid(const EC_GROUP *); +int key_ecdsa_key_to_nid(EC_KEY *); const EVP_MD * key_ec_nid_to_evpmd(int nid); int key_ec_validate_public(const EC_GROUP *, const EC_POINT *); int key_ec_validate_private(const EC_KEY *); diff --git a/ssh-keygen.c b/ssh-keygen.c index bbd434b0b..560c4818a 100644 --- a/ssh-keygen.c +++ b/ssh-keygen.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-keygen.c,v 1.203 2010/09/02 17:21:50 naddy Exp $ */ +/* $OpenBSD: ssh-keygen.c,v 1.204 2010/10/28 11:22:09 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1994 Tatu Ylonen , Espoo, Finland @@ -556,8 +556,7 @@ do_convert_from_pkcs8(Key **k, int *private) *k = key_new(KEY_UNSPEC); (*k)->type = KEY_ECDSA; (*k)->ecdsa = EVP_PKEY_get1_EC_KEY(pubkey); - (*k)->ecdsa_nid = key_ecdsa_group_to_nid( - EC_KEY_get0_group((*k)->ecdsa)); + (*k)->ecdsa_nid = key_ecdsa_key_to_nid((*k)->ecdsa); break; #endif default: -- cgit v1.2.3 From a232792783655659395f445c0f265d4f9444bb7c Mon Sep 17 00:00:00 2001 From: Damien Miller Date: Wed, 1 Dec 2010 12:01:21 +1100 Subject: - djm@cvs.openbsd.org 2010/11/21 10:57:07 [authfile.c] Refactor internals of private key loading and saving to work on memory buffers rather than directly on files. This will make a few things easier to do in the future; ok markus@ --- ChangeLog | 5 + authfile.c | 447 +++++++++++++++++++++++++++++++++++-------------------------- 2 files changed, 259 insertions(+), 193 deletions(-) (limited to 'authfile.c') diff --git a/ChangeLog b/ChangeLog index 09e5ee805..1b1cd5242 100644 --- a/ChangeLog +++ b/ChangeLog @@ -7,6 +7,11 @@ [clientloop.c misc.c misc.h ssh-agent.1 ssh-agent.c] honour $TMPDIR for client xauth and ssh-agent temporary directories; feedback and ok markus@ + - djm@cvs.openbsd.org 2010/11/21 10:57:07 + [authfile.c] + Refactor internals of private key loading and saving to work on memory + buffers rather than directly on files. This will make a few things + easier to do in the future; ok markus@ 20101124 - (dtucker) [platform.c session.c] Move the getluid call out of session.c and diff --git a/authfile.c b/authfile.c index 7f98ab547..f75c273fc 100644 --- a/authfile.c +++ b/authfile.c @@ -1,4 +1,4 @@ -/* $OpenBSD: authfile.c,v 1.85 2010/10/28 11:22:09 djm Exp $ */ +/* $OpenBSD: authfile.c,v 1.86 2010/11/21 10:57:07 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -74,19 +74,18 @@ static const char authfile_id_string[] = "SSH PRIVATE KEY FILE FORMAT 1.1\n"; /* - * Saves the authentication (private) key in a file, encrypting it with - * passphrase. The identification of the file (lowest 64 bits of n) will + * Serialises the authentication (private) key to a blob, encrypting it with + * passphrase. The identification of the blob (lowest 64 bits of n) will * precede the key to provide identification of the key without needing a * passphrase. */ - static int -key_save_private_rsa1(Key *key, const char *filename, const char *passphrase, +key_private_rsa1_to_blob(Key *key, Buffer *blob, const char *passphrase, const char *comment) { Buffer buffer, encrypted; u_char buf[100], *cp; - int fd, i, cipher_num; + int i, cipher_num; CipherContext ciphercontext; Cipher *cipher; u_int32_t rnd; @@ -157,163 +156,222 @@ key_save_private_rsa1(Key *key, const char *filename, const char *passphrase, memset(buf, 0, sizeof(buf)); buffer_free(&buffer); - fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600); - if (fd < 0) { - error("open %s failed: %s.", filename, strerror(errno)); - buffer_free(&encrypted); - return 0; - } - if (atomicio(vwrite, fd, buffer_ptr(&encrypted), - buffer_len(&encrypted)) != buffer_len(&encrypted)) { - error("write to key file %s failed: %s", filename, - strerror(errno)); - buffer_free(&encrypted); - close(fd); - unlink(filename); - return 0; - } - close(fd); + buffer_append(blob, buffer_ptr(&encrypted), buffer_len(&encrypted)); buffer_free(&encrypted); + return 1; } -/* save SSH v2 key in OpenSSL PEM format */ +/* convert SSH v2 key in OpenSSL PEM format */ static int -key_save_private_pem(Key *key, const char *filename, const char *_passphrase, +key_private_pem_to_blob(Key *key, Buffer *blob, const char *_passphrase, const char *comment) { - FILE *fp; - int fd; int success = 0; - int len = strlen(_passphrase); + int blen, len = strlen(_passphrase); u_char *passphrase = (len > 0) ? (u_char *)_passphrase : NULL; #if (OPENSSL_VERSION_NUMBER < 0x00907000L) const EVP_CIPHER *cipher = (len > 0) ? EVP_des_ede3_cbc() : NULL; #else const EVP_CIPHER *cipher = (len > 0) ? EVP_aes_128_cbc() : NULL; #endif + const u_char *bptr; + BIO *bio; if (len > 0 && len <= 4) { error("passphrase too short: have %d bytes, need > 4", len); return 0; } - fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600); - if (fd < 0) { - error("open %s failed: %s.", filename, strerror(errno)); - return 0; - } - fp = fdopen(fd, "w"); - if (fp == NULL) { - error("fdopen %s failed: %s.", filename, strerror(errno)); - close(fd); + if ((bio = BIO_new(BIO_s_mem())) == NULL) { + error("%s: BIO_new failed", __func__); return 0; } switch (key->type) { case KEY_DSA: - success = PEM_write_DSAPrivateKey(fp, key->dsa, + success = PEM_write_bio_DSAPrivateKey(bio, key->dsa, cipher, passphrase, len, NULL, NULL); break; #ifdef OPENSSL_HAS_ECC case KEY_ECDSA: - success = PEM_write_ECPrivateKey(fp, key->ecdsa, + success = PEM_write_bio_ECPrivateKey(bio, key->ecdsa, cipher, passphrase, len, NULL, NULL); break; #endif case KEY_RSA: - success = PEM_write_RSAPrivateKey(fp, key->rsa, + success = PEM_write_bio_RSAPrivateKey(bio, key->rsa, cipher, passphrase, len, NULL, NULL); break; } - fclose(fp); + if (success) { + if ((blen = BIO_get_mem_data(bio, &bptr)) <= 0) + success = 0; + else + buffer_append(blob, bptr, blen); + } + BIO_free(bio); return success; } -int -key_save_private(Key *key, const char *filename, const char *passphrase, +/* Save a key blob to a file */ +static int +key_save_private_blob(Buffer *keybuf, const char *filename) +{ + int fd; + + if ((fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600)) < 0) { + error("open %s failed: %s.", filename, strerror(errno)); + return 0; + } + if (atomicio(vwrite, fd, buffer_ptr(keybuf), + buffer_len(keybuf)) != buffer_len(keybuf)) { + error("write to key file %s failed: %s", filename, + strerror(errno)); + close(fd); + unlink(filename); + return 0; + } + close(fd); + return 1; +} + +/* Serialise "key" to buffer "blob" */ +static int +key_private_to_blob(Key *key, Buffer *blob, const char *passphrase, const char *comment) { switch (key->type) { case KEY_RSA1: - return key_save_private_rsa1(key, filename, passphrase, - comment); + return key_private_rsa1_to_blob(key, blob, passphrase, comment); case KEY_DSA: case KEY_ECDSA: case KEY_RSA: - return key_save_private_pem(key, filename, passphrase, - comment); + return key_private_pem_to_blob(key, blob, passphrase, comment); default: - break; + error("%s: cannot save key type %d", __func__, key->type); + return 0; } - error("key_save_private: cannot save key type %d", key->type); - return 0; +} + +int +key_save_private(Key *key, const char *filename, const char *passphrase, + const char *comment) +{ + Buffer keyblob; + int success = 0; + + buffer_init(&keyblob); + if (!key_private_to_blob(key, &keyblob, passphrase, comment)) + goto out; + if (!key_save_private_blob(&keyblob, filename)) + goto out; + success = 1; + out: + buffer_free(&keyblob); + return success; } /* - * Loads the public part of the ssh v1 key file. Returns NULL if an error was - * encountered (the file does not exist or is not readable), and the key - * otherwise. + * Parse the public, unencrypted portion of a RSA1 key. */ - static Key * -key_load_public_rsa1(int fd, const char *filename, char **commentp) +key_parse_public_rsa1(Buffer *blob, char **commentp) { - Buffer buffer; Key *pub; - struct stat st; - char *cp; - u_int i; + + /* Check that it is at least big enough to contain the ID string. */ + if (buffer_len(blob) < sizeof(authfile_id_string)) { + debug3("Truncated RSA1 identifier"); + return NULL; + } + + /* + * Make sure it begins with the id string. Consume the id string + * from the buffer. + */ + if (memcmp(buffer_ptr(blob), authfile_id_string, + sizeof(authfile_id_string)) != 0) { + debug3("Incorrect RSA1 identifier"); + return NULL; + } + buffer_consume(blob, sizeof(authfile_id_string)); + + /* Skip cipher type and reserved data. */ + (void) buffer_get_char(blob); /* cipher type */ + (void) buffer_get_int(blob); /* reserved */ + + /* Read the public key from the buffer. */ + (void) buffer_get_int(blob); + pub = key_new(KEY_RSA1); + buffer_get_bignum(blob, pub->rsa->n); + buffer_get_bignum(blob, pub->rsa->e); + if (commentp) + *commentp = buffer_get_string(blob, NULL); + /* The encrypted private part is not parsed by this function. */ + buffer_clear(blob); + + return pub; +} + +/* Load the contents of a key file into a buffer */ +static int +key_load_file(int fd, const char *filename, Buffer *blob) +{ size_t len; + u_char *cp; + struct stat st; if (fstat(fd, &st) < 0) { - error("fstat for key file %.200s failed: %.100s", - filename, strerror(errno)); - return NULL; + error("%s: fstat of key file %.200s%sfailed: %.100s", __func__, + filename == NULL ? "" : filename, + filename == NULL ? "" : " ", + strerror(errno)); + close(fd); + return 0; } if (st.st_size > 1*1024*1024) { - error("key file %.200s too large", filename); - return NULL; + error("%s: key file %.200s%stoo large", __func__, + filename == NULL ? "" : filename, + filename == NULL ? "" : " "); + close(fd); + return 0; } len = (size_t)st.st_size; /* truncated */ - buffer_init(&buffer); - cp = buffer_append_space(&buffer, len); + buffer_init(blob); + cp = buffer_append_space(blob, len); if (atomicio(read, fd, cp, len) != len) { - debug("Read from key file %.200s failed: %.100s", filename, + debug("%s: read from key file %.200s%sfailed: %.100s", __func__, + filename == NULL ? "" : filename, + filename == NULL ? "" : " ", strerror(errno)); - buffer_free(&buffer); - return NULL; + buffer_clear(blob); + close(fd); + return 0; } + return 1; +} - /* Check that it is at least big enough to contain the ID string. */ - if (len < sizeof(authfile_id_string)) { - debug3("Not a RSA1 key file %.200s.", filename); +/* + * Loads the public part of the ssh v1 key file. Returns NULL if an error was + * encountered (the file does not exist or is not readable), and the key + * otherwise. + */ +static Key * +key_load_public_rsa1(int fd, const char *filename, char **commentp) +{ + Buffer buffer; + Key *pub; + + buffer_init(&buffer); + if (!key_load_file(fd, filename, &buffer)) { buffer_free(&buffer); return NULL; } - /* - * Make sure it begins with the id string. Consume the id string - * from the buffer. - */ - for (i = 0; i < sizeof(authfile_id_string); i++) - if (buffer_get_char(&buffer) != authfile_id_string[i]) { - debug3("Not a RSA1 key file %.200s.", filename); - buffer_free(&buffer); - return NULL; - } - /* Skip cipher type and reserved data. */ - (void) buffer_get_char(&buffer); /* cipher type */ - (void) buffer_get_int(&buffer); /* reserved */ - - /* Read the public key from the buffer. */ - (void) buffer_get_int(&buffer); - pub = key_new(KEY_RSA1); - buffer_get_bignum(&buffer, pub->rsa->n); - buffer_get_bignum(&buffer, pub->rsa->e); - if (commentp) - *commentp = buffer_get_string(&buffer, NULL); - /* The encrypted private part is not parsed by this function. */ + pub = key_parse_public_rsa1(&buffer, commentp); + if (pub == NULL) + debug3("Could not load \"%s\" as a RSA1 public key", filename); buffer_free(&buffer); return pub; } @@ -336,113 +394,73 @@ key_load_public_type(int type, const char *filename, char **commentp) return NULL; } -/* - * Loads the private key from the file. Returns 0 if an error is encountered - * (file does not exist or is not readable, or passphrase is bad). This - * initializes the private key. - * Assumes we are called under uid of the owner of the file. - */ - static Key * -key_load_private_rsa1(int fd, const char *filename, const char *passphrase, - char **commentp) +key_parse_private_rsa1(Buffer *blob, const char *passphrase, char **commentp) { - u_int i; int check1, check2, cipher_type; - size_t len; - Buffer buffer, decrypted; + Buffer decrypted; u_char *cp; CipherContext ciphercontext; Cipher *cipher; Key *prv = NULL; - struct stat st; - - if (fstat(fd, &st) < 0) { - error("fstat for key file %.200s failed: %.100s", - filename, strerror(errno)); - close(fd); - return NULL; - } - if (st.st_size > 1*1024*1024) { - error("key file %.200s too large", filename); - close(fd); - return (NULL); - } - len = (size_t)st.st_size; /* truncated */ - - buffer_init(&buffer); - cp = buffer_append_space(&buffer, len); - - if (atomicio(read, fd, cp, len) != len) { - debug("Read from key file %.200s failed: %.100s", filename, - strerror(errno)); - buffer_free(&buffer); - close(fd); - return NULL; - } /* Check that it is at least big enough to contain the ID string. */ - if (len < sizeof(authfile_id_string)) { - debug3("Not a RSA1 key file %.200s.", filename); - buffer_free(&buffer); - close(fd); + if (buffer_len(blob) < sizeof(authfile_id_string)) { + debug3("Truncated RSA1 identifier"); return NULL; } + /* * Make sure it begins with the id string. Consume the id string * from the buffer. */ - for (i = 0; i < sizeof(authfile_id_string); i++) - if (buffer_get_char(&buffer) != authfile_id_string[i]) { - debug3("Not a RSA1 key file %.200s.", filename); - buffer_free(&buffer); - close(fd); - return NULL; - } + if (memcmp(buffer_ptr(blob), authfile_id_string, + sizeof(authfile_id_string)) != 0) { + debug3("Incorrect RSA1 identifier"); + return NULL; + } + buffer_consume(blob, sizeof(authfile_id_string)); /* Read cipher type. */ - cipher_type = buffer_get_char(&buffer); - (void) buffer_get_int(&buffer); /* Reserved data. */ + cipher_type = buffer_get_char(blob); + (void) buffer_get_int(blob); /* Reserved data. */ /* Read the public key from the buffer. */ - (void) buffer_get_int(&buffer); + (void) buffer_get_int(blob); prv = key_new_private(KEY_RSA1); - buffer_get_bignum(&buffer, prv->rsa->n); - buffer_get_bignum(&buffer, prv->rsa->e); + buffer_get_bignum(blob, prv->rsa->n); + buffer_get_bignum(blob, prv->rsa->e); if (commentp) - *commentp = buffer_get_string(&buffer, NULL); + *commentp = buffer_get_string(blob, NULL); else - xfree(buffer_get_string(&buffer, NULL)); + (void)buffer_get_string_ptr(blob, NULL); /* Check that it is a supported cipher. */ cipher = cipher_by_number(cipher_type); if (cipher == NULL) { - debug("Unsupported cipher %d used in key file %.200s.", - cipher_type, filename); - buffer_free(&buffer); + debug("Unsupported RSA1 cipher %d", cipher_type); goto fail; } /* Initialize space for decrypted data. */ buffer_init(&decrypted); - cp = buffer_append_space(&decrypted, buffer_len(&buffer)); + cp = buffer_append_space(&decrypted, buffer_len(blob)); /* Rest of the buffer is encrypted. Decrypt it using the passphrase. */ cipher_set_key_string(&ciphercontext, cipher, passphrase, CIPHER_DECRYPT); cipher_crypt(&ciphercontext, cp, - buffer_ptr(&buffer), buffer_len(&buffer)); + buffer_ptr(blob), buffer_len(blob)); cipher_cleanup(&ciphercontext); memset(&ciphercontext, 0, sizeof(ciphercontext)); - buffer_free(&buffer); + buffer_clear(blob); check1 = buffer_get_char(&decrypted); check2 = buffer_get_char(&decrypted); if (check1 != buffer_get_char(&decrypted) || check2 != buffer_get_char(&decrypted)) { if (strcmp(passphrase, "") != 0) - debug("Bad passphrase supplied for key file %.200s.", - filename); + debug("Bad passphrase supplied for RSA1 key"); /* Bad passphrase. */ buffer_free(&decrypted); goto fail; @@ -461,38 +479,37 @@ key_load_private_rsa1(int fd, const char *filename, const char *passphrase, /* enable blinding */ if (RSA_blinding_on(prv->rsa, NULL) != 1) { - error("key_load_private_rsa1: RSA_blinding_on failed"); + error("%s: RSA_blinding_on failed", __func__); goto fail; } - close(fd); return prv; fail: if (commentp) xfree(*commentp); - close(fd); key_free(prv); return NULL; } -Key * -key_load_private_pem(int fd, int type, const char *passphrase, +static Key * +key_parse_private_pem(Buffer *blob, int type, const char *passphrase, char **commentp) { - FILE *fp; EVP_PKEY *pk = NULL; Key *prv = NULL; char *name = ""; + BIO *bio; - fp = fdopen(fd, "r"); - if (fp == NULL) { - error("fdopen failed: %s", strerror(errno)); - close(fd); + if ((bio = BIO_new_mem_buf(buffer_ptr(blob), + buffer_len(blob))) == NULL) { + error("%s: BIO_new_mem_buf failed", __func__); return NULL; } - pk = PEM_read_PrivateKey(fp, NULL, NULL, (char *)passphrase); + + pk = PEM_read_bio_PrivateKey(bio, NULL, NULL, (char *)passphrase); + BIO_free(bio); if (pk == NULL) { - debug("PEM_read_PrivateKey failed"); + debug("%s: PEM_read_PrivateKey failed", __func__); (void)ERR_get_error(); } else if (pk->type == EVP_PKEY_RSA && (type == KEY_UNSPEC||type==KEY_RSA)) { @@ -504,7 +521,7 @@ key_load_private_pem(int fd, int type, const char *passphrase, RSA_print_fp(stderr, prv->rsa, 8); #endif if (RSA_blinding_on(prv->rsa, NULL) != 1) { - error("key_load_private_pem: RSA_blinding_on failed"); + error("%s: RSA_blinding_on failed", __func__); key_free(prv); prv = NULL; } @@ -539,10 +556,9 @@ key_load_private_pem(int fd, int type, const char *passphrase, #endif #endif /* OPENSSL_HAS_ECC */ } else { - error("PEM_read_PrivateKey: mismatch or " - "unknown EVP_PKEY save_type %d", pk->save_type); + error("%s: PEM_read_PrivateKey: mismatch or " + "unknown EVP_PKEY save_type %d", __func__, pk->save_type); } - fclose(fp); if (pk != NULL) EVP_PKEY_free(pk); if (prv != NULL && commentp) @@ -552,6 +568,23 @@ key_load_private_pem(int fd, int type, const char *passphrase, return prv; } +Key * +key_load_private_pem(int fd, int type, const char *passphrase, + char **commentp) +{ + Buffer buffer; + Key *prv; + + buffer_init(&buffer); + if (!key_load_file(fd, NULL, &buffer)) { + buffer_free(&buffer); + return NULL; + } + prv = key_parse_private_pem(&buffer, type, passphrase, commentp); + buffer_free(&buffer); + return prv; +} + int key_perm_ok(int fd, const char *filename) { @@ -580,11 +613,31 @@ key_perm_ok(int fd, const char *filename) return 1; } +static Key * +key_parse_private_type(Buffer *blob, int type, const char *passphrase, + char **commentp) +{ + switch (type) { + case KEY_RSA1: + return key_parse_private_rsa1(blob, passphrase, commentp); + case KEY_DSA: + case KEY_ECDSA: + case KEY_RSA: + case KEY_UNSPEC: + return key_parse_private_pem(blob, type, passphrase, commentp); + default: + break; + } + return NULL; +} + Key * key_load_private_type(int type, const char *filename, const char *passphrase, char **commentp, int *perm_ok) { int fd; + Key *ret; + Buffer buffer; fd = open(filename, O_RDONLY); if (fd < 0) { @@ -603,22 +656,17 @@ key_load_private_type(int type, const char *filename, const char *passphrase, } if (perm_ok != NULL) *perm_ok = 1; - switch (type) { - case KEY_RSA1: - return key_load_private_rsa1(fd, filename, passphrase, - commentp); - /* closes fd */ - case KEY_DSA: - case KEY_ECDSA: - case KEY_RSA: - case KEY_UNSPEC: - return key_load_private_pem(fd, type, passphrase, commentp); - /* closes fd */ - default: + + buffer_init(&buffer); + if (!key_load_file(fd, filename, &buffer)) { + buffer_free(&buffer); close(fd); - break; + return NULL; } - return NULL; + close(fd); + ret = key_parse_private_type(&buffer, type, passphrase, commentp); + buffer_free(&buffer); + return ret; } Key * @@ -626,6 +674,7 @@ key_load_private(const char *filename, const char *passphrase, char **commentp) { Key *pub, *prv; + Buffer buffer, pubcopy; int fd; fd = open(filename, O_RDONLY); @@ -639,20 +688,32 @@ key_load_private(const char *filename, const char *passphrase, close(fd); return NULL; } - pub = key_load_public_rsa1(fd, filename, commentp); - lseek(fd, (off_t) 0, SEEK_SET); /* rewind */ + + buffer_init(&buffer); + if (!key_load_file(fd, filename, &buffer)) { + buffer_free(&buffer); + close(fd); + return NULL; + } + close(fd); + + buffer_init(&pubcopy); + buffer_append(&pubcopy, buffer_ptr(&buffer), buffer_len(&buffer)); + /* it's a SSH v1 key if the public key part is readable */ + pub = key_parse_public_rsa1(&pubcopy, commentp); + buffer_free(&pubcopy); if (pub == NULL) { - /* closes fd */ - prv = key_load_private_pem(fd, KEY_UNSPEC, passphrase, NULL); + prv = key_parse_private_type(&buffer, KEY_UNSPEC, + passphrase, NULL); /* use the filename as a comment for PEM */ if (commentp && prv) *commentp = xstrdup(filename); } else { - /* it's a SSH v1 key if the public key part is readable */ key_free(pub); - /* closes fd */ - prv = key_load_private_rsa1(fd, filename, passphrase, NULL); + prv = key_parse_private_type(&buffer, KEY_RSA1, passphrase, + commentp); } + buffer_free(&buffer); return prv; } -- cgit v1.2.3 From 03c0e533de56a1fc55ec1885d35c3197fdefbf94 Mon Sep 17 00:00:00 2001 From: Damien Miller Date: Wed, 1 Dec 2010 12:03:39 +1100 Subject: - markus@cvs.openbsd.org 2010/11/29 18:57:04 [authfile.c] correctly load comment for encrypted rsa1 keys; report/fix Joachim Schipper; ok djm@ --- ChangeLog | 4 ++++ authfile.c | 5 +++-- 2 files changed, 7 insertions(+), 2 deletions(-) (limited to 'authfile.c') diff --git a/ChangeLog b/ChangeLog index 7c7297731..44e45eb8a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -34,6 +34,10 @@ Pass through ssh command-line flags and options when doing remote-remote transfers, e.g. to enable agent forwarding which is particularly useful in this case; bz#1837 ok dtucker@ + - markus@cvs.openbsd.org 2010/11/29 18:57:04 + [authfile.c] + correctly load comment for encrypted rsa1 keys; + report/fix Joachim Schipper; ok djm@ 20101124 - (dtucker) [platform.c session.c] Move the getluid call out of session.c and diff --git a/authfile.c b/authfile.c index f75c273fc..f2aec267a 100644 --- a/authfile.c +++ b/authfile.c @@ -1,4 +1,4 @@ -/* $OpenBSD: authfile.c,v 1.86 2010/11/21 10:57:07 djm Exp $ */ +/* $OpenBSD: authfile.c,v 1.87 2010/11/29 18:57:04 markus Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -710,8 +710,9 @@ key_load_private(const char *filename, const char *passphrase, *commentp = xstrdup(filename); } else { key_free(pub); + /* key_parse_public_rsa1() has already loaded the comment */ prv = key_parse_private_type(&buffer, KEY_RSA1, passphrase, - commentp); + NULL); } buffer_free(&buffer); return prv; -- cgit v1.2.3