From 91b580e4bec55118bf96ab3cdbe5a50839e75d0a Mon Sep 17 00:00:00 2001 From: Damien Miller Date: Sun, 12 Jan 2014 19:21:22 +1100 Subject: - djm@cvs.openbsd.org 2014/01/12 08:13:13 [bufaux.c buffer.h kex.c kex.h kexc25519.c kexc25519c.c kexc25519s.c] [kexdhc.c kexdhs.c kexecdhc.c kexecdhs.c kexgexc.c kexgexs.c] avoid use of OpenSSL BIGNUM type and functions for KEX with Curve25519 by adding a buffer_put_bignum2_from_string() that stores a string using the bignum encoding rules. Will make it easier to build a reduced-feature OpenSSH without OpenSSL in the future; ok markus@ --- ChangeLog | 8 +++++++ bufaux.c | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- buffer.h | 6 ++++- kex.c | 23 +++++++++++++++---- kex.h | 11 +++++---- kexc25519.c | 18 ++++++--------- kexc25519c.c | 15 ++++++------ kexc25519s.c | 15 +++++++----- kexdhc.c | 4 ++-- kexdhs.c | 4 ++-- kexecdhc.c | 4 ++-- kexecdhs.c | 4 ++-- kexgexc.c | 4 ++-- kexgexs.c | 4 ++-- 14 files changed, 147 insertions(+), 48 deletions(-) diff --git a/ChangeLog b/ChangeLog index 99b846e3c..e30cec1a4 100644 --- a/ChangeLog +++ b/ChangeLog @@ -3,6 +3,14 @@ - djm@cvs.openbsd.org 2014/01/10 05:59:19 [sshd_config] the /etc/ssh/ssh_host_ed25519_key is loaded by default too + - djm@cvs.openbsd.org 2014/01/12 08:13:13 + [bufaux.c buffer.h kex.c kex.h kexc25519.c kexc25519c.c kexc25519s.c] + [kexdhc.c kexdhs.c kexecdhc.c kexecdhs.c kexgexc.c kexgexs.c] + avoid use of OpenSSL BIGNUM type and functions for KEX with + Curve25519 by adding a buffer_put_bignum2_from_string() that stores + a string using the bignum encoding rules. Will make it easier to + build a reduced-feature OpenSSH without OpenSSL in the future; + ok markus@ 20140110 - (djm) OpenBSD CVS Sync diff --git a/bufaux.c b/bufaux.c index 3e70b8d90..9401fe1d0 100644 --- a/bufaux.c +++ b/bufaux.c @@ -1,4 +1,4 @@ -/* $OpenBSD: bufaux.c,v 1.53 2013/11/08 11:15:19 dtucker Exp $ */ +/* $OpenBSD: bufaux.c,v 1.54 2014/01/12 08:13:13 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -315,3 +315,76 @@ buffer_put_char(Buffer *buffer, int value) buffer_append(buffer, &ch, 1); } + +/* Pseudo bignum functions */ + +void * +buffer_get_bignum2_as_string_ret(Buffer *buffer, u_int *length_ptr) +{ + u_int len; + u_char *bin, *p, *ret; + + if ((p = bin = buffer_get_string_ret(buffer, &len)) == NULL) { + error("%s: invalid bignum", __func__); + return NULL; + } + + if (len > 0 && (bin[0] & 0x80)) { + error("%s: negative numbers not supported", __func__); + free(bin); + return NULL; + } + if (len > 8 * 1024) { + error("%s: cannot handle BN of size %d", __func__, len); + free(bin); + return NULL; + } + /* Skip zero prefix on numbers with the MSB set */ + if (len > 1 && bin[0] == 0x00 && (bin[1] & 0x80) != 0) { + p++; + len--; + } + ret = xmalloc(len); + memcpy(ret, p, len); + memset(p, '\0', len); + free(bin); + return ret; +} + +void * +buffer_get_bignum2_as_string(Buffer *buffer, u_int *l) +{ + void *ret = buffer_get_bignum2_as_string_ret(buffer, l); + + if (ret == NULL) + fatal("%s: buffer error", __func__); + return ret; +} + +/* + * Stores a string using the bignum encoding rules (\0 pad if MSB set). + */ +void +buffer_put_bignum2_from_string(Buffer *buffer, const u_char *s, u_int l) +{ + u_char *buf, *p; + int pad = 0; + + if (l > 8 * 1024) + fatal("%s: length %u too long", __func__, l); + p = buf = xmalloc(l + 1); + /* + * If most significant bit is set then prepend a zero byte to + * avoid interpretation as a negative number. + */ + if (l > 0 && (s[0] & 0x80) != 0) { + *p++ = '\0'; + pad = 1; + } + memcpy(p, s, l); + buffer_put_string(buffer, buf, l + pad); + memset(buf, '\0', l + pad); + free(buf); +} + + diff --git a/buffer.h b/buffer.h index 4fa2ca112..7df8a38fa 100644 --- a/buffer.h +++ b/buffer.h @@ -1,4 +1,4 @@ -/* $OpenBSD: buffer.h,v 1.22 2013/07/12 00:19:58 djm Exp $ */ +/* $OpenBSD: buffer.h,v 1.23 2014/01/12 08:13:13 djm Exp $ */ /* * Author: Tatu Ylonen @@ -86,6 +86,10 @@ char *buffer_get_cstring_ret(Buffer *, u_int *); void *buffer_get_string_ptr_ret(Buffer *, u_int *); int buffer_get_char_ret(u_char *, Buffer *); +void *buffer_get_bignum2_as_string_ret(Buffer *, u_int *); +void *buffer_get_bignum2_as_string(Buffer *, u_int *); +void buffer_put_bignum2_from_string(Buffer *, const u_char *, u_int); + #ifdef OPENSSL_HAS_ECC #include diff --git a/kex.c b/kex.c index dbb1a9816..7d054cdcb 100644 --- a/kex.c +++ b/kex.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kex.c,v 1.94 2014/01/09 23:20:00 djm Exp $ */ +/* $OpenBSD: kex.c,v 1.95 2014/01/12 08:13:13 djm Exp $ */ /* * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. * @@ -534,7 +534,7 @@ kex_choose_conf(Kex *kex) static u_char * derive_key(Kex *kex, int id, u_int need, u_char *hash, u_int hashlen, - BIGNUM *shared_secret) + const u_char *shared_secret, u_int slen) { Buffer b; struct ssh_digest_ctx *hashctx; @@ -548,7 +548,7 @@ derive_key(Kex *kex, int id, u_int need, u_char *hash, u_int hashlen, digest = xmalloc(roundup(need, mdsz)); buffer_init(&b); - buffer_put_bignum2(&b, shared_secret); + buffer_append(&b, shared_secret, slen); /* K1 = HASH(K || H || "A" || session_id) */ if ((hashctx = ssh_digest_start(kex->hash_alg)) == NULL) @@ -591,14 +591,15 @@ Newkeys *current_keys[MODE_MAX]; #define NKEYS 6 void -kex_derive_keys(Kex *kex, u_char *hash, u_int hashlen, BIGNUM *shared_secret) +kex_derive_keys(Kex *kex, u_char *hash, u_int hashlen, + const u_char *shared_secret, u_int slen) { u_char *keys[NKEYS]; u_int i, mode, ctos; for (i = 0; i < NKEYS; i++) { keys[i] = derive_key(kex, 'A'+i, kex->we_need, hash, hashlen, - shared_secret); + shared_secret, slen); } debug2("kex_derive_keys"); @@ -613,6 +614,18 @@ kex_derive_keys(Kex *kex, u_char *hash, u_int hashlen, BIGNUM *shared_secret) } } +void +kex_derive_keys_bn(Kex *kex, u_char *hash, u_int hashlen, const BIGNUM *secret) +{ + Buffer shared_secret; + + buffer_init(&shared_secret); + buffer_put_bignum2(&shared_secret, secret); + kex_derive_keys(kex, hash, hashlen, + buffer_ptr(&shared_secret), buffer_len(&shared_secret)); + buffer_free(&shared_secret); +} + Newkeys * kex_get_newkeys(int mode) { diff --git a/kex.h b/kex.h index fbe4940e8..7e2878f70 100644 --- a/kex.h +++ b/kex.h @@ -1,4 +1,4 @@ -/* $OpenBSD: kex.h,v 1.59 2014/01/09 23:20:00 djm Exp $ */ +/* $OpenBSD: kex.h,v 1.60 2014/01/12 08:13:13 djm Exp $ */ /* * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. @@ -153,7 +153,8 @@ void kex_finish(Kex *); void kex_send_kexinit(Kex *); void kex_input_kexinit(int, u_int32_t, void *); -void kex_derive_keys(Kex *, u_char *, u_int, BIGNUM *); +void kex_derive_keys(Kex *, u_char *, u_int, const u_char *, u_int); +void kex_derive_keys_bn(Kex *, u_char *, u_int, const BIGNUM *); Newkeys *kex_get_newkeys(int); @@ -182,14 +183,14 @@ kex_ecdh_hash(int, const EC_GROUP *, char *, char *, char *, int, void kex_c25519_hash(int, char *, char *, char *, int, char *, int, u_char *, int, const u_char *, const u_char *, - const BIGNUM *, u_char **, u_int *); + const u_char *, u_int, u_char **, u_int *); #define CURVE25519_SIZE 32 void kexc25519_keygen(u_char[CURVE25519_SIZE], u_char[CURVE25519_SIZE]) __attribute__((__bounded__(__minbytes__, 1, CURVE25519_SIZE))) __attribute__((__bounded__(__minbytes__, 2, CURVE25519_SIZE))); -BIGNUM *kexc25519_shared_key(const u_char[CURVE25519_SIZE], - const u_char[CURVE25519_SIZE]) +void kexc25519_shared_key(const u_char key[CURVE25519_SIZE], + const u_char pub[CURVE25519_SIZE], Buffer *out) __attribute__((__bounded__(__minbytes__, 1, CURVE25519_SIZE))) __attribute__((__bounded__(__minbytes__, 2, CURVE25519_SIZE))); diff --git a/kexc25519.c b/kexc25519.c index 8dd363991..48ca4aaa2 100644 --- a/kexc25519.c +++ b/kexc25519.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kexc25519.c,v 1.3 2014/01/09 23:20:00 djm Exp $ */ +/* $OpenBSD: kexc25519.c,v 1.4 2014/01/12 08:13:13 djm Exp $ */ /* * Copyright (c) 2001, 2013 Markus Friedl. All rights reserved. * Copyright (c) 2010 Damien Miller. All rights reserved. @@ -58,23 +58,19 @@ kexc25519_keygen(u_char key[CURVE25519_SIZE], u_char pub[CURVE25519_SIZE]) crypto_scalarmult_curve25519(pub, key, basepoint); } -BIGNUM * +void kexc25519_shared_key(const u_char key[CURVE25519_SIZE], - const u_char pub[CURVE25519_SIZE]) + const u_char pub[CURVE25519_SIZE], Buffer *out) { u_char shared_key[CURVE25519_SIZE]; - BIGNUM *shared_secret; crypto_scalarmult_curve25519(shared_key, key, pub); #ifdef DEBUG_KEXECDH dump_digest("shared secret", shared_key, CURVE25519_SIZE); #endif - if ((shared_secret = BN_new()) == NULL) - fatal("%s: BN_new failed", __func__); - if (BN_bin2bn(shared_key, sizeof(shared_key), shared_secret) == NULL) - fatal("%s: BN_bin2bn failed", __func__); + buffer_clear(out); + buffer_put_bignum2_from_string(out, shared_key, CURVE25519_SIZE); memset(shared_key, 0, CURVE25519_SIZE); /* XXX explicit_bzero() */ - return (shared_secret); } void @@ -87,7 +83,7 @@ kex_c25519_hash( u_char *serverhostkeyblob, int sbloblen, const u_char client_dh_pub[CURVE25519_SIZE], const u_char server_dh_pub[CURVE25519_SIZE], - const BIGNUM *shared_secret, + const u_char *shared_secret, u_int secretlen, u_char **hash, u_int *hashlen) { Buffer b; @@ -108,7 +104,7 @@ kex_c25519_hash( buffer_put_string(&b, serverhostkeyblob, sbloblen); buffer_put_string(&b, client_dh_pub, CURVE25519_SIZE); buffer_put_string(&b, server_dh_pub, CURVE25519_SIZE); - buffer_put_bignum2(&b, shared_secret); + buffer_append(&b, shared_secret, secretlen); #ifdef DEBUG_KEX buffer_dump(&b); diff --git a/kexc25519c.c b/kexc25519c.c index 4655c2542..a80678af6 100644 --- a/kexc25519c.c +++ b/kexc25519c.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kexc25519c.c,v 1.3 2014/01/09 23:20:00 djm Exp $ */ +/* $OpenBSD: kexc25519c.c,v 1.4 2014/01/12 08:13:13 djm Exp $ */ /* * Copyright (c) 2001 Markus Friedl. All rights reserved. * Copyright (c) 2010 Damien Miller. All rights reserved. @@ -45,7 +45,6 @@ void kexc25519_client(Kex *kex) { - BIGNUM *shared_secret; Key *server_host_key; u_char client_key[CURVE25519_SIZE]; u_char client_pubkey[CURVE25519_SIZE]; @@ -53,6 +52,7 @@ kexc25519_client(Kex *kex) u_char *server_host_key_blob = NULL, *signature = NULL; u_char *hash; u_int slen, sbloblen, hashlen; + Buffer shared_secret; kexc25519_keygen(client_key, client_pubkey); @@ -93,7 +93,8 @@ kexc25519_client(Kex *kex) signature = packet_get_string(&slen); packet_check_eom(); - shared_secret = kexc25519_shared_key(client_key, server_pubkey); + buffer_init(&shared_secret); + kexc25519_shared_key(client_key, server_pubkey, &shared_secret); /* calc and verify H */ kex_c25519_hash( @@ -105,7 +106,7 @@ kexc25519_client(Kex *kex) server_host_key_blob, sbloblen, client_pubkey, server_pubkey, - shared_secret, + buffer_ptr(&shared_secret), buffer_len(&shared_secret), &hash, &hashlen ); free(server_host_key_blob); @@ -121,8 +122,8 @@ kexc25519_client(Kex *kex) kex->session_id = xmalloc(kex->session_id_len); memcpy(kex->session_id, hash, kex->session_id_len); } - - kex_derive_keys(kex, hash, hashlen, shared_secret); - BN_clear_free(shared_secret); + kex_derive_keys(kex, hash, hashlen, + buffer_ptr(&shared_secret), buffer_len(&shared_secret)); + buffer_free(&shared_secret); kex_finish(kex); } diff --git a/kexc25519s.c b/kexc25519s.c index dc4f56c80..2b8e8efa1 100644 --- a/kexc25519s.c +++ b/kexc25519s.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kexc25519s.c,v 1.3 2014/01/09 23:20:00 djm Exp $ */ +/* $OpenBSD: kexc25519s.c,v 1.4 2014/01/12 08:13:13 djm Exp $ */ /* * Copyright (c) 2001 Markus Friedl. All rights reserved. * Copyright (c) 2010 Damien Miller. All rights reserved. @@ -42,7 +42,6 @@ void kexc25519_server(Kex *kex) { - BIGNUM *shared_secret; Key *server_host_private, *server_host_public; u_char *server_host_key_blob = NULL, *signature = NULL; u_char server_key[CURVE25519_SIZE]; @@ -50,6 +49,7 @@ kexc25519_server(Kex *kex) u_char server_pubkey[CURVE25519_SIZE]; u_char *hash; u_int slen, sbloblen, hashlen; + Buffer shared_secret; /* generate private key */ kexc25519_keygen(server_key, server_pubkey); @@ -76,7 +76,8 @@ kexc25519_server(Kex *kex) dump_digest("client public key:", client_pubkey, CURVE25519_SIZE); #endif - shared_secret = kexc25519_shared_key(server_key, client_pubkey); + buffer_init(&shared_secret); + kexc25519_shared_key(server_key, client_pubkey, &shared_secret); /* calc H */ key_to_blob(server_host_public, &server_host_key_blob, &sbloblen); @@ -89,7 +90,7 @@ kexc25519_server(Kex *kex) server_host_key_blob, sbloblen, client_pubkey, server_pubkey, - shared_secret, + buffer_ptr(&shared_secret), buffer_len(&shared_secret), &hash, &hashlen ); @@ -117,7 +118,9 @@ kexc25519_server(Kex *kex) free(server_host_key_blob); /* have keys, free server key */ free(client_pubkey); - kex_derive_keys(kex, hash, hashlen, shared_secret); - BN_clear_free(shared_secret); + + kex_derive_keys(kex, hash, hashlen, + buffer_ptr(&shared_secret), buffer_len(&shared_secret)); + buffer_free(&shared_secret); kex_finish(kex); } diff --git a/kexdhc.c b/kexdhc.c index ccd137cac..78509af21 100644 --- a/kexdhc.c +++ b/kexdhc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kexdhc.c,v 1.13 2013/05/17 00:13:13 djm Exp $ */ +/* $OpenBSD: kexdhc.c,v 1.14 2014/01/12 08:13:13 djm Exp $ */ /* * Copyright (c) 2001 Markus Friedl. All rights reserved. * @@ -155,7 +155,7 @@ kexdh_client(Kex *kex) memcpy(kex->session_id, hash, kex->session_id_len); } - kex_derive_keys(kex, hash, hashlen, shared_secret); + kex_derive_keys_bn(kex, hash, hashlen, shared_secret); BN_clear_free(shared_secret); kex_finish(kex); } diff --git a/kexdhs.c b/kexdhs.c index 39b9aba54..d2c7adc96 100644 --- a/kexdhs.c +++ b/kexdhs.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kexdhs.c,v 1.16 2013/11/02 22:24:24 markus Exp $ */ +/* $OpenBSD: kexdhs.c,v 1.17 2014/01/12 08:13:13 djm Exp $ */ /* * Copyright (c) 2001 Markus Friedl. All rights reserved. * @@ -154,7 +154,7 @@ kexdh_server(Kex *kex) /* have keys, free DH */ DH_free(dh); - kex_derive_keys(kex, hash, hashlen, shared_secret); + kex_derive_keys_bn(kex, hash, hashlen, shared_secret); BN_clear_free(shared_secret); kex_finish(kex); } diff --git a/kexecdhc.c b/kexecdhc.c index fc62cec55..e3d1cf5f9 100644 --- a/kexecdhc.c +++ b/kexecdhc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kexecdhc.c,v 1.5 2014/01/09 23:20:00 djm Exp $ */ +/* $OpenBSD: kexecdhc.c,v 1.6 2014/01/12 08:13:13 djm Exp $ */ /* * Copyright (c) 2001 Markus Friedl. All rights reserved. * Copyright (c) 2010 Damien Miller. All rights reserved. @@ -152,7 +152,7 @@ kexecdh_client(Kex *kex) memcpy(kex->session_id, hash, kex->session_id_len); } - kex_derive_keys(kex, hash, hashlen, shared_secret); + kex_derive_keys_bn(kex, hash, hashlen, shared_secret); BN_clear_free(shared_secret); kex_finish(kex); } diff --git a/kexecdhs.c b/kexecdhs.c index d1dd8c7fb..6fbb79c9d 100644 --- a/kexecdhs.c +++ b/kexecdhs.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kexecdhs.c,v 1.8 2014/01/09 23:20:00 djm Exp $ */ +/* $OpenBSD: kexecdhs.c,v 1.9 2014/01/12 08:13:13 djm Exp $ */ /* * Copyright (c) 2001 Markus Friedl. All rights reserved. * Copyright (c) 2010 Damien Miller. All rights reserved. @@ -148,7 +148,7 @@ kexecdh_server(Kex *kex) /* have keys, free server key */ EC_KEY_free(server_key); - kex_derive_keys(kex, hash, hashlen, shared_secret); + kex_derive_keys_bn(kex, hash, hashlen, shared_secret); BN_clear_free(shared_secret); kex_finish(kex); } diff --git a/kexgexc.c b/kexgexc.c index ca771edfe..a69ff2705 100644 --- a/kexgexc.c +++ b/kexgexc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kexgexc.c,v 1.14 2014/01/09 23:20:00 djm Exp $ */ +/* $OpenBSD: kexgexc.c,v 1.15 2014/01/12 08:13:13 djm Exp $ */ /* * Copyright (c) 2000 Niels Provos. All rights reserved. * Copyright (c) 2001 Markus Friedl. All rights reserved. @@ -200,7 +200,7 @@ kexgex_client(Kex *kex) kex->session_id = xmalloc(kex->session_id_len); memcpy(kex->session_id, hash, kex->session_id_len); } - kex_derive_keys(kex, hash, hashlen, shared_secret); + kex_derive_keys_bn(kex, hash, hashlen, shared_secret); BN_clear_free(shared_secret); kex_finish(kex); diff --git a/kexgexs.c b/kexgexs.c index 90853403e..8773778ed 100644 --- a/kexgexs.c +++ b/kexgexs.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kexgexs.c,v 1.17 2014/01/09 23:20:00 djm Exp $ */ +/* $OpenBSD: kexgexs.c,v 1.18 2014/01/12 08:13:13 djm Exp $ */ /* * Copyright (c) 2000 Niels Provos. All rights reserved. * Copyright (c) 2001 Markus Friedl. All rights reserved. @@ -201,7 +201,7 @@ kexgex_server(Kex *kex) /* have keys, free DH */ DH_free(dh); - kex_derive_keys(kex, hash, hashlen, shared_secret); + kex_derive_keys_bn(kex, hash, hashlen, shared_secret); BN_clear_free(shared_secret); kex_finish(kex); -- cgit v1.2.3