From 094003f5454a9f5a607674b2739824a7e91835f4 Mon Sep 17 00:00:00 2001 From: Damien Miller Date: Mon, 4 Nov 2013 22:59:27 +1100 Subject: - (djm) [kexc25519.c kexc25519c.c kexc25519s.c] Import missed files from KEX/curve25519 change --- kexc25519.c | 127 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 127 insertions(+) create mode 100644 kexc25519.c (limited to 'kexc25519.c') diff --git a/kexc25519.c b/kexc25519.c new file mode 100644 index 000000000..348a7d50d --- /dev/null +++ b/kexc25519.c @@ -0,0 +1,127 @@ +/* $OpenBSD: kexc25519.c,v 1.2 2013/11/02 22:02:14 markus Exp $ */ +/* + * Copyright (c) 2001, 2013 Markus Friedl. All rights reserved. + * Copyright (c) 2010 Damien Miller. All rights reserved. + * Copyright (c) 2013 Aris Adamantiadis. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "includes.h" + +#include + +#include +#include + +#include +#include + +#include "buffer.h" +#include "ssh2.h" +#include "key.h" +#include "cipher.h" +#include "kex.h" +#include "log.h" + +extern int crypto_scalarmult_curve25519(u_char a[CURVE25519_SIZE], + const u_char b[CURVE25519_SIZE], const u_char c[CURVE25519_SIZE]) + __attribute__((__bounded__(__minbytes__, 1, CURVE25519_SIZE))) + __attribute__((__bounded__(__minbytes__, 2, CURVE25519_SIZE))) + __attribute__((__bounded__(__minbytes__, 3, CURVE25519_SIZE))); + +void +kexc25519_keygen(u_char key[CURVE25519_SIZE], u_char pub[CURVE25519_SIZE]) +{ + static const u_char basepoint[CURVE25519_SIZE] = {9}; + + arc4random_buf(key, CURVE25519_SIZE); + crypto_scalarmult_curve25519(pub, key, basepoint); +} + +BIGNUM * +kexc25519_shared_key(const u_char key[CURVE25519_SIZE], + const u_char pub[CURVE25519_SIZE]) +{ + 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__); + memset(shared_key, 0, CURVE25519_SIZE); /* XXX explicit_bzero() */ + return (shared_secret); +} + +void +kex_c25519_hash( + const EVP_MD *evp_md, + char *client_version_string, + char *server_version_string, + char *ckexinit, int ckexinitlen, + char *skexinit, int skexinitlen, + 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, + u_char **hash, u_int *hashlen) +{ + Buffer b; + EVP_MD_CTX md; + static u_char digest[EVP_MAX_MD_SIZE]; + + buffer_init(&b); + buffer_put_cstring(&b, client_version_string); + buffer_put_cstring(&b, server_version_string); + + /* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */ + buffer_put_int(&b, ckexinitlen+1); + buffer_put_char(&b, SSH2_MSG_KEXINIT); + buffer_append(&b, ckexinit, ckexinitlen); + buffer_put_int(&b, skexinitlen+1); + buffer_put_char(&b, SSH2_MSG_KEXINIT); + buffer_append(&b, skexinit, skexinitlen); + + 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); + +#ifdef DEBUG_KEX + buffer_dump(&b); +#endif + EVP_DigestInit(&md, evp_md); + EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b)); + EVP_DigestFinal(&md, digest, NULL); + + buffer_free(&b); + +#ifdef DEBUG_KEX + dump_digest("hash", digest, EVP_MD_size(evp_md)); +#endif + *hash = digest; + *hashlen = EVP_MD_size(evp_md); +} -- cgit v1.2.3 From b3051d01e505c9c2dc00faab472a0d06fa6b0e65 Mon Sep 17 00:00:00 2001 From: Damien Miller Date: Fri, 10 Jan 2014 10:58:53 +1100 Subject: - djm@cvs.openbsd.org 2014/01/09 23:20:00 [digest.c digest.h hostfile.c kex.c kex.h kexc25519.c kexc25519c.c] [kexc25519s.c kexdh.c kexecdh.c kexecdhc.c kexecdhs.c kexgex.c kexgexc.c] [kexgexs.c key.c key.h roaming_client.c roaming_common.c schnorr.c] [schnorr.h ssh-dss.c ssh-ecdsa.c ssh-rsa.c sshconnect2.c] Introduce digest API and use it to perform all hashing operations rather than calling OpenSSL EVP_Digest* directly. Will make it easier to build a reduced-feature OpenSSH without OpenSSL in future; feedback, ok markus@ --- ChangeLog | 9 ++++ Makefile.in | 4 +- digest.c | 148 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ digest.h | 55 +++++++++++++++++++++ hostfile.c | 3 +- kex.c | 94 ++++++++++++++++++++--------------- kex.h | 10 ++-- kexc25519.c | 17 +++---- kexc25519c.c | 4 +- kexc25519s.c | 4 +- kexdh.c | 17 +++---- kexecdh.c | 18 +++---- kexecdhc.c | 4 +- kexecdhs.c | 4 +- kexgex.c | 24 ++++----- kexgexc.c | 4 +- kexgexs.c | 4 +- key.c | 42 ++++++++-------- key.h | 4 +- roaming_client.c | 14 +++--- roaming_common.c | 14 +++--- schnorr.c | 57 +++++++++------------ schnorr.h | 8 +-- ssh-dss.c | 31 ++++++------ ssh-ecdsa.c | 42 ++++++++++------ ssh-rsa.c | 54 +++++++++++--------- sshconnect2.c | 4 +- 27 files changed, 458 insertions(+), 235 deletions(-) create mode 100644 digest.c create mode 100644 digest.h (limited to 'kexc25519.c') diff --git a/ChangeLog b/ChangeLog index df1d5ea6a..a1d37bc25 100644 --- a/ChangeLog +++ b/ChangeLog @@ -9,6 +9,15 @@ with the year, and rearrange a comparison to avoid a potentional signed arithmetic overflow that would give the wrong result. ok djm@ + - djm@cvs.openbsd.org 2014/01/09 23:20:00 + [digest.c digest.h hostfile.c kex.c kex.h kexc25519.c kexc25519c.c] + [kexc25519s.c kexdh.c kexecdh.c kexecdhc.c kexecdhs.c kexgex.c kexgexc.c] + [kexgexs.c key.c key.h roaming_client.c roaming_common.c schnorr.c] + [schnorr.h ssh-dss.c ssh-ecdsa.c ssh-rsa.c sshconnect2.c] + Introduce digest API and use it to perform all hashing operations + rather than calling OpenSSL EVP_Digest* directly. Will make it easier + to build a reduced-feature OpenSSH without OpenSSL in future; + feedback, ok markus@ 20140108 - (djm) [regress/.cvsignore] Ignore regress test droppings; ok dtucker@ diff --git a/Makefile.in b/Makefile.in index e789b476a..4a930c665 100644 --- a/Makefile.in +++ b/Makefile.in @@ -1,4 +1,4 @@ -# $Id: Makefile.in,v 1.348 2013/12/08 04:53:28 djm Exp $ +# $Id: Makefile.in,v 1.349 2014/01/09 23:58:53 djm Exp $ # uncomment if you run a non bourne compatable shell. Ie. csh #SHELL = @SH@ @@ -75,7 +75,7 @@ LIBSSH_OBJS=authfd.o authfile.o bufaux.o bufbn.o buffer.o \ msg.o progressmeter.o dns.o entropy.o gss-genr.o umac.o umac128.o \ jpake.o schnorr.o ssh-pkcs11.o krl.o smult_curve25519_ref.o \ kexc25519.o kexc25519c.o poly1305.o chacha.o cipher-chachapoly.o \ - ssh-ed25519.o \ + ssh-ed25519.o digest.o \ sc25519.o ge25519.o fe25519.o ed25519.o verify.o hash.o blocks.o \ SSHOBJS= ssh.o readconf.o clientloop.o sshtty.o \ diff --git a/digest.c b/digest.c new file mode 100644 index 000000000..59a8ffe0d --- /dev/null +++ b/digest.c @@ -0,0 +1,148 @@ +/* $OpenBSD: digest.c,v 1.1 2014/01/09 23:20:00 djm Exp $ */ +/* + * Copyright (c) 2013 Damien Miller + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "includes.h" + +#include +#include +#include +#include + +#include /* for buffer.h */ +#include /* for buffer.h */ +#include + +#include "buffer.h" +#include "digest.h" + +struct ssh_digest_ctx { + int alg; + EVP_MD_CTX mdctx; +}; + +struct ssh_digest { + int id; + const char *name; + size_t digest_len; + const EVP_MD *(*mdfunc)(void); +}; + +/* NB. Indexed directly by algorithm number */ +const struct ssh_digest digests[] = { + { SSH_DIGEST_MD5, "MD5", 16, EVP_md5 }, + { SSH_DIGEST_RIPEMD160, "RIPEMD160", 20, EVP_ripemd160 }, + { SSH_DIGEST_SHA1, "SHA1", 20, EVP_sha1 }, +#ifdef HAVE_EVP_SHA256 /* XXX replace with local if missing */ + { SSH_DIGEST_SHA256, "SHA256", 32, EVP_sha256 }, + { SSH_DIGEST_SHA384, "SHA384", 48, EVP_sha384 }, + { SSH_DIGEST_SHA512, "SHA512", 64, EVP_sha512 }, +#endif + { -1, NULL, 0, NULL }, +}; + +static const struct ssh_digest * +ssh_digest_by_alg(int alg) +{ + if (alg < 0 || alg >= SSH_DIGEST_MAX) + return NULL; + if (digests[alg].id != alg) /* sanity */ + return NULL; + return &(digests[alg]); +} + +size_t +ssh_digest_bytes(int alg) +{ + const struct ssh_digest *digest = ssh_digest_by_alg(alg); + + return digest == NULL ? 0 : digest->digest_len; +} + +struct ssh_digest_ctx * +ssh_digest_start(int alg) +{ + const struct ssh_digest *digest = ssh_digest_by_alg(alg); + struct ssh_digest_ctx *ret; + + if (digest == NULL || ((ret = calloc(1, sizeof(*ret))) == NULL)) + return NULL; + ret->alg = alg; + EVP_MD_CTX_init(&ret->mdctx); + if (EVP_DigestInit_ex(&ret->mdctx, digest->mdfunc(), NULL) != 1) { + free(ret); + return NULL; + } + return ret; +} + +int +ssh_digest_update(struct ssh_digest_ctx *ctx, const void *m, size_t mlen) +{ + if (EVP_DigestUpdate(&ctx->mdctx, m, mlen) != 1) + return -1; + return 0; +} + +int +ssh_digest_update_buffer(struct ssh_digest_ctx *ctx, const Buffer *b) +{ + return ssh_digest_update(ctx, buffer_ptr(b), buffer_len(b)); +} + +int +ssh_digest_final(struct ssh_digest_ctx *ctx, u_char *d, size_t dlen) +{ + const struct ssh_digest *digest = ssh_digest_by_alg(ctx->alg); + u_int l = dlen; + + if (dlen > UINT_MAX) + return -1; + if (dlen < digest->digest_len) /* No truncation allowed */ + return -1; + if (EVP_DigestFinal_ex(&ctx->mdctx, d, &l) != 1) + return -1; + if (l != digest->digest_len) /* sanity */ + return -1; + return 0; +} + +void +ssh_digest_free(struct ssh_digest_ctx *ctx) +{ + EVP_MD_CTX_cleanup(&ctx->mdctx); + memset(ctx, 0, sizeof(*ctx)); +} + +int +ssh_digest_memory(int alg, const void *m, size_t mlen, u_char *d, size_t dlen) +{ + struct ssh_digest_ctx *ctx = ssh_digest_start(alg); + + if (ctx == NULL) + return -1; + if (ssh_digest_update(ctx, m, mlen) != 0 || + ssh_digest_final(ctx, d, dlen) != 0) + return -1; + ssh_digest_free(ctx); + return 0; +} + +int +ssh_digest_buffer(int alg, const Buffer *b, u_char *d, size_t dlen) +{ + return ssh_digest_memory(alg, buffer_ptr(b), buffer_len(b), d, dlen); +} diff --git a/digest.h b/digest.h new file mode 100644 index 000000000..faefda3f5 --- /dev/null +++ b/digest.h @@ -0,0 +1,55 @@ +/* $OpenBSD: digest.h,v 1.1 2014/01/09 23:20:00 djm Exp $ */ +/* + * Copyright (c) 2013 Damien Miller + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _DIGEST_H +#define _DIGEST_H + +/* Maximum digest output length */ +#define SSH_DIGEST_MAX_LENGTH 64 + +/* Digest algorithms */ +#define SSH_DIGEST_MD5 0 +#define SSH_DIGEST_RIPEMD160 1 +#define SSH_DIGEST_SHA1 2 +#define SSH_DIGEST_SHA256 3 +#define SSH_DIGEST_SHA384 4 +#define SSH_DIGEST_SHA512 5 +#define SSH_DIGEST_MAX 6 + +/* Returns the algorithm's digest length in bytes or 0 for invalid algorithm */ +size_t ssh_digest_bytes(int alg); + +/* One-shot API */ +int ssh_digest_memory(int alg, const void *m, size_t mlen, + u_char *d, size_t dlen) + __attribute__((__bounded__(__buffer__, 2, 3))) + __attribute__((__bounded__(__buffer__, 4, 5))); +int ssh_digest_buffer(int alg, const Buffer *b, u_char *d, size_t dlen) + __attribute__((__bounded__(__buffer__, 3, 4))); + +/* Update API */ +struct ssh_digest_ctx; +struct ssh_digest_ctx *ssh_digest_start(int alg); +int ssh_digest_update(struct ssh_digest_ctx *ctx, const void *m, size_t mlen) + __attribute__((__bounded__(__buffer__, 2, 3))); +int ssh_digest_update_buffer(struct ssh_digest_ctx *ctx, const Buffer *b); +int ssh_digest_final(struct ssh_digest_ctx *ctx, u_char *d, size_t dlen) + __attribute__((__bounded__(__buffer__, 2, 3))); +void ssh_digest_free(struct ssh_digest_ctx *ctx); + +#endif /* _DIGEST_H */ + diff --git a/hostfile.c b/hostfile.c index 2ff4c48b4..2778fb5df 100644 --- a/hostfile.c +++ b/hostfile.c @@ -1,4 +1,4 @@ -/* $OpenBSD: hostfile.c,v 1.52 2013/07/12 00:19:58 djm Exp $ */ +/* $OpenBSD: hostfile.c,v 1.53 2014/01/09 23:20:00 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -57,6 +57,7 @@ #include "hostfile.h" #include "log.h" #include "misc.h" +#include "digest.h" struct hostkeys { struct hostkey_entry *entries; diff --git a/kex.c b/kex.c index b38bae0f0..dbb1a9816 100644 --- a/kex.c +++ b/kex.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kex.c,v 1.93 2013/11/07 11:58:27 dtucker Exp $ */ +/* $OpenBSD: kex.c,v 1.94 2014/01/09 23:20:00 djm Exp $ */ /* * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. * @@ -49,6 +49,7 @@ #include "dispatch.h" #include "monitor.h" #include "roaming.h" +#include "digest.h" #if OPENSSL_VERSION_NUMBER >= 0x00907000L # if defined(HAVE_EVP_SHA256) @@ -66,26 +67,30 @@ struct kexalg { char *name; int type; int ec_nid; - const EVP_MD *(*mdfunc)(void); + int hash_alg; }; static const struct kexalg kexalgs[] = { - { KEX_DH1, KEX_DH_GRP1_SHA1, 0, EVP_sha1 }, - { KEX_DH14, KEX_DH_GRP14_SHA1, 0, EVP_sha1 }, - { KEX_DHGEX_SHA1, KEX_DH_GEX_SHA1, 0, EVP_sha1 }, + { KEX_DH1, KEX_DH_GRP1_SHA1, 0, SSH_DIGEST_SHA1 }, + { KEX_DH14, KEX_DH_GRP14_SHA1, 0, SSH_DIGEST_SHA1 }, + { KEX_DHGEX_SHA1, KEX_DH_GEX_SHA1, 0, SSH_DIGEST_SHA1 }, #ifdef HAVE_EVP_SHA256 - { KEX_DHGEX_SHA256, KEX_DH_GEX_SHA256, 0, EVP_sha256 }, + { KEX_DHGEX_SHA256, KEX_DH_GEX_SHA256, 0, SSH_DIGEST_SHA256 }, #endif #ifdef OPENSSL_HAS_ECC - { KEX_ECDH_SHA2_NISTP256, KEX_ECDH_SHA2, NID_X9_62_prime256v1, EVP_sha256 }, - { KEX_ECDH_SHA2_NISTP384, KEX_ECDH_SHA2, NID_secp384r1, EVP_sha384 }, + { KEX_ECDH_SHA2_NISTP256, KEX_ECDH_SHA2, + NID_X9_62_prime256v1, SSH_DIGEST_SHA256 }, + { KEX_ECDH_SHA2_NISTP384, KEX_ECDH_SHA2, NID_secp384r1, + SSH_DIGEST_SHA384 }, # ifdef OPENSSL_HAS_NISTP521 - { KEX_ECDH_SHA2_NISTP521, KEX_ECDH_SHA2, NID_secp521r1, EVP_sha512 }, + { KEX_ECDH_SHA2_NISTP521, KEX_ECDH_SHA2, NID_secp521r1, + SSH_DIGEST_SHA512 }, # endif #endif + { KEX_DH1, KEX_DH_GRP1_SHA1, 0, SSH_DIGEST_SHA1 }, #ifdef HAVE_EVP_SHA256 - { KEX_CURVE25519_SHA256, KEX_C25519_SHA256, 0, EVP_sha256 }, + { KEX_CURVE25519_SHA256, KEX_C25519_SHA256, 0, SSH_DIGEST_SHA256 }, #endif - { NULL, -1, -1, NULL}, + { NULL, -1, -1, -1}, }; char * @@ -406,7 +411,7 @@ choose_kex(Kex *k, char *client, char *server) if ((kexalg = kex_alg_by_name(k->name)) == NULL) fatal("unsupported kex alg %s", k->name); k->kex_type = kexalg->type; - k->evp_md = kexalg->mdfunc(); + k->hash_alg = kexalg->hash_alg; k->ec_nid = kexalg->ec_nid; } @@ -532,27 +537,31 @@ derive_key(Kex *kex, int id, u_int need, u_char *hash, u_int hashlen, BIGNUM *shared_secret) { Buffer b; - EVP_MD_CTX md; + struct ssh_digest_ctx *hashctx; char c = id; u_int have; - int mdsz; + size_t mdsz; u_char *digest; - if ((mdsz = EVP_MD_size(kex->evp_md)) <= 0) - fatal("bad kex md size %d", mdsz); + if ((mdsz = ssh_digest_bytes(kex->hash_alg)) == 0) + fatal("bad kex md size %zu", mdsz); digest = xmalloc(roundup(need, mdsz)); buffer_init(&b); buffer_put_bignum2(&b, shared_secret); /* K1 = HASH(K || H || "A" || session_id) */ - EVP_DigestInit(&md, kex->evp_md); - if (!(datafellows & SSH_BUG_DERIVEKEY)) - EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b)); - EVP_DigestUpdate(&md, hash, hashlen); - EVP_DigestUpdate(&md, &c, 1); - EVP_DigestUpdate(&md, kex->session_id, kex->session_id_len); - EVP_DigestFinal(&md, digest, NULL); + if ((hashctx = ssh_digest_start(kex->hash_alg)) == NULL) + fatal("%s: ssh_digest_start failed", __func__); + if (ssh_digest_update_buffer(hashctx, &b) != 0 || + ssh_digest_update(hashctx, hash, hashlen) != 0 || + ssh_digest_update(hashctx, &c, 1) != 0 || + ssh_digest_update(hashctx, kex->session_id, + kex->session_id_len) != 0) + fatal("%s: ssh_digest_update failed", __func__); + if (ssh_digest_final(hashctx, digest, mdsz) != 0) + fatal("%s: ssh_digest_final failed", __func__); + ssh_digest_free(hashctx); /* * expand key: @@ -560,12 +569,15 @@ derive_key(Kex *kex, int id, u_int need, u_char *hash, u_int hashlen, * Key = K1 || K2 || ... || Kn */ for (have = mdsz; need > have; have += mdsz) { - EVP_DigestInit(&md, kex->evp_md); - if (!(datafellows & SSH_BUG_DERIVEKEY)) - EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b)); - EVP_DigestUpdate(&md, hash, hashlen); - EVP_DigestUpdate(&md, digest, have); - EVP_DigestFinal(&md, digest + have, NULL); + if ((hashctx = ssh_digest_start(kex->hash_alg)) == NULL) + fatal("%s: ssh_digest_start failed", __func__); + if (ssh_digest_update_buffer(hashctx, &b) != 0 || + ssh_digest_update(hashctx, hash, hashlen) != 0 || + ssh_digest_update(hashctx, digest, have) != 0) + fatal("%s: ssh_digest_update failed", __func__); + if (ssh_digest_final(hashctx, digest + have, mdsz) != 0) + fatal("%s: ssh_digest_final failed", __func__); + ssh_digest_free(hashctx); } buffer_free(&b); #ifdef DEBUG_KEX @@ -615,33 +627,33 @@ void derive_ssh1_session_id(BIGNUM *host_modulus, BIGNUM *server_modulus, u_int8_t cookie[8], u_int8_t id[16]) { - const EVP_MD *evp_md = EVP_md5(); - EVP_MD_CTX md; - u_int8_t nbuf[2048], obuf[EVP_MAX_MD_SIZE]; + u_int8_t nbuf[2048], obuf[SSH_DIGEST_MAX_LENGTH]; int len; + struct ssh_digest_ctx *hashctx; - EVP_DigestInit(&md, evp_md); + if ((hashctx = ssh_digest_start(SSH_DIGEST_MD5)) == NULL) + fatal("%s: ssh_digest_start", __func__); len = BN_num_bytes(host_modulus); if (len < (512 / 8) || (u_int)len > sizeof(nbuf)) fatal("%s: bad host modulus (len %d)", __func__, len); BN_bn2bin(host_modulus, nbuf); - EVP_DigestUpdate(&md, nbuf, len); + if (ssh_digest_update(hashctx, nbuf, len) != 0) + fatal("%s: ssh_digest_update failed", __func__); len = BN_num_bytes(server_modulus); if (len < (512 / 8) || (u_int)len > sizeof(nbuf)) fatal("%s: bad server modulus (len %d)", __func__, len); BN_bn2bin(server_modulus, nbuf); - EVP_DigestUpdate(&md, nbuf, len); - - EVP_DigestUpdate(&md, cookie, 8); - - EVP_DigestFinal(&md, obuf, NULL); - memcpy(id, obuf, 16); + if (ssh_digest_update(hashctx, nbuf, len) != 0 || + ssh_digest_update(hashctx, cookie, 8) != 0) + fatal("%s: ssh_digest_update failed", __func__); + if (ssh_digest_final(hashctx, obuf, sizeof(obuf)) != 0) + fatal("%s: ssh_digest_final failed", __func__); + memcpy(id, obuf, ssh_digest_bytes(SSH_DIGEST_MD5)); memset(nbuf, 0, sizeof(nbuf)); memset(obuf, 0, sizeof(obuf)); - memset(&md, 0, sizeof(md)); } #if defined(DEBUG_KEX) || defined(DEBUG_KEXDH) || defined(DEBUG_KEXECDH) diff --git a/kex.h b/kex.h index 800a69233..fbe4940e8 100644 --- a/kex.h +++ b/kex.h @@ -1,4 +1,4 @@ -/* $OpenBSD: kex.h,v 1.58 2013/11/07 11:58:27 dtucker Exp $ */ +/* $OpenBSD: kex.h,v 1.59 2014/01/09 23:20:00 djm Exp $ */ /* * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. @@ -133,7 +133,7 @@ struct Kex { Buffer peer; sig_atomic_t done; int flags; - const EVP_MD *evp_md; + int hash_alg; int ec_nid; char *client_version_string; char *server_version_string; @@ -170,17 +170,17 @@ void kex_dh_hash(char *, char *, char *, int, char *, int, u_char *, int, BIGNUM *, BIGNUM *, BIGNUM *, u_char **, u_int *); void -kexgex_hash(const EVP_MD *, char *, char *, char *, int, char *, +kexgex_hash(int, 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, +kex_ecdh_hash(int, const EC_GROUP *, char *, char *, char *, int, char *, int, u_char *, int, const EC_POINT *, const EC_POINT *, const BIGNUM *, u_char **, u_int *); #endif void -kex_c25519_hash(const EVP_MD *, char *, char *, char *, int, +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 *); diff --git a/kexc25519.c b/kexc25519.c index 348a7d50d..8dd363991 100644 --- a/kexc25519.c +++ b/kexc25519.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kexc25519.c,v 1.2 2013/11/02 22:02:14 markus Exp $ */ +/* $OpenBSD: kexc25519.c,v 1.3 2014/01/09 23:20:00 djm Exp $ */ /* * Copyright (c) 2001, 2013 Markus Friedl. All rights reserved. * Copyright (c) 2010 Damien Miller. All rights reserved. @@ -41,6 +41,7 @@ #include "cipher.h" #include "kex.h" #include "log.h" +#include "digest.h" extern int crypto_scalarmult_curve25519(u_char a[CURVE25519_SIZE], const u_char b[CURVE25519_SIZE], const u_char c[CURVE25519_SIZE]) @@ -78,7 +79,7 @@ kexc25519_shared_key(const u_char key[CURVE25519_SIZE], void kex_c25519_hash( - const EVP_MD *evp_md, + int hash_alg, char *client_version_string, char *server_version_string, char *ckexinit, int ckexinitlen, @@ -90,8 +91,7 @@ kex_c25519_hash( u_char **hash, u_int *hashlen) { Buffer b; - EVP_MD_CTX md; - static u_char digest[EVP_MAX_MD_SIZE]; + static u_char digest[SSH_DIGEST_MAX_LENGTH]; buffer_init(&b); buffer_put_cstring(&b, client_version_string); @@ -113,15 +113,14 @@ kex_c25519_hash( #ifdef DEBUG_KEX buffer_dump(&b); #endif - EVP_DigestInit(&md, evp_md); - EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b)); - EVP_DigestFinal(&md, digest, NULL); + if (ssh_digest_buffer(hash_alg, &b, digest, sizeof(digest)) != 0) + fatal("%s: digest_buffer failed", __func__); buffer_free(&b); #ifdef DEBUG_KEX - dump_digest("hash", digest, EVP_MD_size(evp_md)); + dump_digest("hash", digest, ssh_digest_bytes(hash_alg)); #endif *hash = digest; - *hashlen = EVP_MD_size(evp_md); + *hashlen = ssh_digest_bytes(hash_alg); } diff --git a/kexc25519c.c b/kexc25519c.c index f741566cc..4655c2542 100644 --- a/kexc25519c.c +++ b/kexc25519c.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kexc25519c.c,v 1.2 2013/11/02 22:02:14 markus Exp $ */ +/* $OpenBSD: kexc25519c.c,v 1.3 2014/01/09 23:20:00 djm Exp $ */ /* * Copyright (c) 2001 Markus Friedl. All rights reserved. * Copyright (c) 2010 Damien Miller. All rights reserved. @@ -97,7 +97,7 @@ kexc25519_client(Kex *kex) /* calc and verify H */ kex_c25519_hash( - kex->evp_md, + kex->hash_alg, kex->client_version_string, kex->server_version_string, buffer_ptr(&kex->my), buffer_len(&kex->my), diff --git a/kexc25519s.c b/kexc25519s.c index 784841b82..dc4f56c80 100644 --- a/kexc25519s.c +++ b/kexc25519s.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kexc25519s.c,v 1.2 2013/11/02 22:02:14 markus Exp $ */ +/* $OpenBSD: kexc25519s.c,v 1.3 2014/01/09 23:20:00 djm Exp $ */ /* * Copyright (c) 2001 Markus Friedl. All rights reserved. * Copyright (c) 2010 Damien Miller. All rights reserved. @@ -81,7 +81,7 @@ kexc25519_server(Kex *kex) /* calc H */ key_to_blob(server_host_public, &server_host_key_blob, &sbloblen); kex_c25519_hash( - kex->evp_md, + kex->hash_alg, kex->client_version_string, kex->server_version_string, buffer_ptr(&kex->peer), buffer_len(&kex->peer), diff --git a/kexdh.c b/kexdh.c index 56e22f5bc..e7cdadc90 100644 --- a/kexdh.c +++ b/kexdh.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kexdh.c,v 1.23 2006/08/03 03:34:42 deraadt Exp $ */ +/* $OpenBSD: kexdh.c,v 1.24 2014/01/09 23:20:00 djm Exp $ */ /* * Copyright (c) 2001 Markus Friedl. All rights reserved. * @@ -36,6 +36,8 @@ #include "key.h" #include "cipher.h" #include "kex.h" +#include "digest.h" +#include "log.h" void kex_dh_hash( @@ -50,9 +52,7 @@ kex_dh_hash( u_char **hash, u_int *hashlen) { Buffer b; - static u_char digest[EVP_MAX_MD_SIZE]; - const EVP_MD *evp_md = EVP_sha1(); - EVP_MD_CTX md; + static u_char digest[SSH_DIGEST_MAX_LENGTH]; buffer_init(&b); buffer_put_cstring(&b, client_version_string); @@ -74,15 +74,14 @@ kex_dh_hash( #ifdef DEBUG_KEX buffer_dump(&b); #endif - EVP_DigestInit(&md, evp_md); - EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b)); - EVP_DigestFinal(&md, digest, NULL); + if (ssh_digest_buffer(SSH_DIGEST_SHA1, &b, digest, sizeof(digest)) != 0) + fatal("%s: ssh_digest_buffer failed", __func__); buffer_free(&b); #ifdef DEBUG_KEX - dump_digest("hash", digest, EVP_MD_size(evp_md)); + dump_digest("hash", digest, ssh_digest_bytes(SSH_DIGEST_SHA1)); #endif *hash = digest; - *hashlen = EVP_MD_size(evp_md); + *hashlen = ssh_digest_bytes(SSH_DIGEST_SHA1); } diff --git a/kexecdh.c b/kexecdh.c index c948fe20a..c52c5e234 100644 --- a/kexecdh.c +++ b/kexecdh.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kexecdh.c,v 1.4 2013/04/19 01:06:50 djm Exp $ */ +/* $OpenBSD: kexecdh.c,v 1.5 2014/01/09 23:20:00 djm Exp $ */ /* * Copyright (c) 2001 Markus Friedl. All rights reserved. * Copyright (c) 2010 Damien Miller. All rights reserved. @@ -44,10 +44,11 @@ #include "cipher.h" #include "kex.h" #include "log.h" +#include "digest.h" void kex_ecdh_hash( - const EVP_MD *evp_md, + int hash_alg, const EC_GROUP *ec_group, char *client_version_string, char *server_version_string, @@ -60,8 +61,7 @@ kex_ecdh_hash( u_char **hash, u_int *hashlen) { Buffer b; - EVP_MD_CTX md; - static u_char digest[EVP_MAX_MD_SIZE]; + static u_char digest[SSH_DIGEST_MAX_LENGTH]; buffer_init(&b); buffer_put_cstring(&b, client_version_string); @@ -83,17 +83,15 @@ kex_ecdh_hash( #ifdef DEBUG_KEX buffer_dump(&b); #endif - EVP_DigestInit(&md, evp_md); - EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b)); - EVP_DigestFinal(&md, digest, NULL); + if (ssh_digest_buffer(hash_alg, &b, digest, sizeof(digest)) != 0) + fatal("%s: ssh_digest_buffer failed", __func__); buffer_free(&b); #ifdef DEBUG_KEX - dump_digest("hash", digest, EVP_MD_size(evp_md)); + dump_digest("hash", digest, ssh_digest_bytes(hash_alg)); #endif *hash = digest; - *hashlen = EVP_MD_size(evp_md); + *hashlen = ssh_digest_bytes(hash_alg); } - #endif /* OPENSSL_HAS_ECC */ diff --git a/kexecdhc.c b/kexecdhc.c index 6193836c7..fc62cec55 100644 --- a/kexecdhc.c +++ b/kexecdhc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kexecdhc.c,v 1.4 2013/05/17 00:13:13 djm Exp $ */ +/* $OpenBSD: kexecdhc.c,v 1.5 2014/01/09 23:20:00 djm Exp $ */ /* * Copyright (c) 2001 Markus Friedl. All rights reserved. * Copyright (c) 2010 Damien Miller. All rights reserved. @@ -124,7 +124,7 @@ kexecdh_client(Kex *kex) /* calc and verify H */ kex_ecdh_hash( - kex->evp_md, + kex->hash_alg, group, kex->client_version_string, kex->server_version_string, diff --git a/kexecdhs.c b/kexecdhs.c index 431fd2c2c..d1dd8c7fb 100644 --- a/kexecdhs.c +++ b/kexecdhs.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kexecdhs.c,v 1.7 2013/11/02 22:24:24 markus Exp $ */ +/* $OpenBSD: kexecdhs.c,v 1.8 2014/01/09 23:20:00 djm Exp $ */ /* * Copyright (c) 2001 Markus Friedl. All rights reserved. * Copyright (c) 2010 Damien Miller. All rights reserved. @@ -109,7 +109,7 @@ kexecdh_server(Kex *kex) /* calc H */ key_to_blob(server_host_public, &server_host_key_blob, &sbloblen); kex_ecdh_hash( - kex->evp_md, + kex->hash_alg, group, kex->client_version_string, kex->server_version_string, diff --git a/kexgex.c b/kexgex.c index b60ab5c53..c2e6bc16d 100644 --- a/kexgex.c +++ b/kexgex.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kexgex.c,v 1.27 2006/08/03 03:34:42 deraadt Exp $ */ +/* $OpenBSD: kexgex.c,v 1.28 2014/01/09 23:20:00 djm Exp $ */ /* * Copyright (c) 2000 Niels Provos. All rights reserved. * Copyright (c) 2001 Markus Friedl. All rights reserved. @@ -36,10 +36,12 @@ #include "cipher.h" #include "kex.h" #include "ssh2.h" +#include "digest.h" +#include "log.h" void kexgex_hash( - const EVP_MD *evp_md, + int hash_alg, char *client_version_string, char *server_version_string, char *ckexinit, int ckexinitlen, @@ -52,8 +54,7 @@ kexgex_hash( u_char **hash, u_int *hashlen) { Buffer b; - static u_char digest[EVP_MAX_MD_SIZE]; - EVP_MD_CTX md; + static u_char digest[SSH_DIGEST_MAX_LENGTH]; buffer_init(&b); buffer_put_cstring(&b, client_version_string); @@ -84,15 +85,14 @@ kexgex_hash( #ifdef DEBUG_KEXDH buffer_dump(&b); #endif - - EVP_DigestInit(&md, evp_md); - EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b)); - EVP_DigestFinal(&md, digest, NULL); + if (ssh_digest_buffer(hash_alg, &b, digest, sizeof(digest)) != 0) + fatal("%s: ssh_digest_buffer failed", __func__); buffer_free(&b); - *hash = digest; - *hashlen = EVP_MD_size(evp_md); -#ifdef DEBUG_KEXDH - dump_digest("hash", digest, *hashlen); + +#ifdef DEBUG_KEX + dump_digest("hash", digest, ssh_digest_bytes(hash_alg)); #endif + *hash = digest; + *hashlen = ssh_digest_bytes(hash_alg); } diff --git a/kexgexc.c b/kexgexc.c index 5a3be2005..ca771edfe 100644 --- a/kexgexc.c +++ b/kexgexc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kexgexc.c,v 1.13 2013/05/17 00:13:13 djm Exp $ */ +/* $OpenBSD: kexgexc.c,v 1.14 2014/01/09 23:20:00 djm Exp $ */ /* * Copyright (c) 2000 Niels Provos. All rights reserved. * Copyright (c) 2001 Markus Friedl. All rights reserved. @@ -170,7 +170,7 @@ kexgex_client(Kex *kex) /* calc and verify H */ kexgex_hash( - kex->evp_md, + kex->hash_alg, kex->client_version_string, kex->server_version_string, buffer_ptr(&kex->my), buffer_len(&kex->my), diff --git a/kexgexs.c b/kexgexs.c index 4e473fc73..90853403e 100644 --- a/kexgexs.c +++ b/kexgexs.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kexgexs.c,v 1.16 2013/07/19 07:37:48 markus Exp $ */ +/* $OpenBSD: kexgexs.c,v 1.17 2014/01/09 23:20:00 djm Exp $ */ /* * Copyright (c) 2000 Niels Provos. All rights reserved. * Copyright (c) 2001 Markus Friedl. All rights reserved. @@ -160,7 +160,7 @@ kexgex_server(Kex *kex) /* calc H */ kexgex_hash( - kex->evp_md, + kex->hash_alg, kex->client_version_string, kex->server_version_string, buffer_ptr(&kex->peer), buffer_len(&kex->peer), diff --git a/key.c b/key.c index b0bb46f3d..914233808 100644 --- a/key.c +++ b/key.c @@ -1,4 +1,4 @@ -/* $OpenBSD: key.c,v 1.114 2013/12/29 04:20:04 djm Exp $ */ +/* $OpenBSD: key.c,v 1.115 2014/01/09 23:20:00 djm Exp $ */ /* * read_bignum(): * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -56,6 +56,7 @@ #include "log.h" #include "misc.h" #include "ssh2.h" +#include "digest.h" static int to_blob(const Key *, u_char **, u_int *, int); static Key *key_from_blob2(const u_char *, u_int, int); @@ -358,30 +359,26 @@ u_char* key_fingerprint_raw(const Key *k, enum fp_type dgst_type, u_int *dgst_raw_length) { - const EVP_MD *md = NULL; - EVP_MD_CTX ctx; u_char *blob = NULL; u_char *retval = NULL; u_int len = 0; - int nlen, elen; + int nlen, elen, hash_alg = -1; *dgst_raw_length = 0; + /* XXX switch to DIGEST_* directly? */ switch (dgst_type) { case SSH_FP_MD5: - md = EVP_md5(); + hash_alg = SSH_DIGEST_MD5; break; case SSH_FP_SHA1: - md = EVP_sha1(); + hash_alg = SSH_DIGEST_SHA1; break; -#ifdef HAVE_EVP_SHA256 case SSH_FP_SHA256: - md = EVP_sha256(); + hash_alg = SSH_DIGEST_SHA256; break; -#endif default: - fatal("key_fingerprint_raw: bad digest type %d", - dgst_type); + fatal("%s: bad digest type %d", __func__, dgst_type); } switch (k->type) { case KEY_RSA1: @@ -410,18 +407,19 @@ key_fingerprint_raw(const Key *k, enum fp_type dgst_type, case KEY_UNSPEC: return retval; default: - fatal("key_fingerprint_raw: bad key type %d", k->type); + fatal("%s: bad key type %d", __func__, k->type); break; } if (blob != NULL) { - retval = xmalloc(EVP_MAX_MD_SIZE); - EVP_DigestInit(&ctx, md); - EVP_DigestUpdate(&ctx, blob, len); - EVP_DigestFinal(&ctx, retval, dgst_raw_length); + retval = xmalloc(SSH_DIGEST_MAX_LENGTH); + if ((ssh_digest_memory(hash_alg, blob, len, + retval, SSH_DIGEST_MAX_LENGTH)) != 0) + fatal("%s: digest_memory failed", __func__); memset(blob, 0, len); free(blob); + *dgst_raw_length = ssh_digest_bytes(hash_alg); } else { - fatal("key_fingerprint_raw: blob is null"); + fatal("%s: blob is null", __func__); } return retval; } @@ -2211,8 +2209,8 @@ key_curve_nid_to_name(int nid) } #ifdef OPENSSL_HAS_ECC -const EVP_MD * -key_ec_nid_to_evpmd(int nid) +int +key_ec_nid_to_hash_alg(int nid) { int kbits = key_curve_nid_to_bits(nid); @@ -2220,11 +2218,11 @@ key_ec_nid_to_evpmd(int nid) fatal("%s: invalid nid %d", __func__, nid); /* RFC5656 section 6.2.1 */ if (kbits <= 256) - return EVP_sha256(); + return SSH_DIGEST_SHA256; else if (kbits <= 384) - return EVP_sha384(); + return SSH_DIGEST_SHA384; else - return EVP_sha512(); + return SSH_DIGEST_SHA512; } int diff --git a/key.h b/key.h index 6a049d277..d8ad13d08 100644 --- a/key.h +++ b/key.h @@ -1,4 +1,4 @@ -/* $OpenBSD: key.h,v 1.40 2013/12/06 13:39:49 markus Exp $ */ +/* $OpenBSD: key.h,v 1.41 2014/01/09 23:20:00 djm Exp $ */ /* * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. @@ -131,7 +131,7 @@ u_int key_curve_nid_to_bits(int); int key_ecdsa_bits_to_nid(int); #ifdef OPENSSL_HAS_ECC int key_ecdsa_key_to_nid(EC_KEY *); -const EVP_MD *key_ec_nid_to_evpmd(int nid); +int key_ec_nid_to_hash_alg(int nid); int key_ec_validate_public(const EC_GROUP *, const EC_POINT *); int key_ec_validate_private(const EC_KEY *); #endif diff --git a/roaming_client.c b/roaming_client.c index 2fb623121..de049cdc1 100644 --- a/roaming_client.c +++ b/roaming_client.c @@ -1,4 +1,4 @@ -/* $OpenBSD: roaming_client.c,v 1.6 2013/10/16 02:31:46 djm Exp $ */ +/* $OpenBSD: roaming_client.c,v 1.7 2014/01/09 23:20:00 djm Exp $ */ /* * Copyright (c) 2004-2009 AppGate Network Security AB * @@ -48,6 +48,7 @@ #include "roaming.h" #include "ssh2.h" #include "sshconnect.h" +#include "digest.h" /* import */ extern Options options; @@ -90,10 +91,8 @@ request_roaming(void) static void roaming_auth_required(void) { - u_char digest[SHA_DIGEST_LENGTH]; - EVP_MD_CTX md; + u_char digest[SSH_DIGEST_MAX_LENGTH]; Buffer b; - const EVP_MD *evp_md = EVP_sha1(); u_int64_t chall, oldchall; chall = packet_get_int64(); @@ -107,14 +106,13 @@ roaming_auth_required(void) buffer_init(&b); buffer_put_int64(&b, cookie); buffer_put_int64(&b, chall); - EVP_DigestInit(&md, evp_md); - EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b)); - EVP_DigestFinal(&md, digest, NULL); + if (ssh_digest_buffer(SSH_DIGEST_SHA1, &b, digest, sizeof(digest)) != 0) + fatal("%s: ssh_digest_buffer failed", __func__); buffer_free(&b); packet_start(SSH2_MSG_KEX_ROAMING_AUTH); packet_put_int64(key1 ^ get_recv_bytes()); - packet_put_raw(digest, sizeof(digest)); + packet_put_raw(digest, ssh_digest_bytes(SSH_DIGEST_SHA1)); packet_send(); oldkey1 = key1; diff --git a/roaming_common.c b/roaming_common.c index 86b3372ef..787bef04a 100644 --- a/roaming_common.c +++ b/roaming_common.c @@ -1,4 +1,4 @@ -/* $OpenBSD: roaming_common.c,v 1.11 2013/11/03 10:37:19 djm Exp $ */ +/* $OpenBSD: roaming_common.c,v 1.12 2014/01/09 23:20:00 djm Exp $ */ /* * Copyright (c) 2004-2009 AppGate Network Security AB * @@ -36,6 +36,7 @@ #include "cipher.h" #include "buffer.h" #include "roaming.h" +#include "digest.h" static size_t out_buf_size = 0; static char *out_buf = NULL; @@ -225,9 +226,7 @@ resend_bytes(int fd, u_int64_t *offset) void calculate_new_key(u_int64_t *key, u_int64_t cookie, u_int64_t challenge) { - const EVP_MD *md = EVP_sha1(); - EVP_MD_CTX ctx; - u_char hash[EVP_MAX_MD_SIZE]; + u_char hash[SSH_DIGEST_MAX_LENGTH]; Buffer b; buffer_init(&b); @@ -235,12 +234,11 @@ calculate_new_key(u_int64_t *key, u_int64_t cookie, u_int64_t challenge) buffer_put_int64(&b, cookie); buffer_put_int64(&b, challenge); - EVP_DigestInit(&ctx, md); - EVP_DigestUpdate(&ctx, buffer_ptr(&b), buffer_len(&b)); - EVP_DigestFinal(&ctx, hash, NULL); + if (ssh_digest_buffer(SSH_DIGEST_SHA1, &b, hash, sizeof(hash)) != 0) + fatal("%s: digest_buffer failed", __func__); buffer_clear(&b); - buffer_append(&b, hash, EVP_MD_size(md)); + buffer_append(&b, hash, ssh_digest_bytes(SSH_DIGEST_SHA1)); *key = buffer_get_int64(&b); buffer_free(&b); } diff --git a/schnorr.c b/schnorr.c index 93822fed4..aa3a57770 100644 --- a/schnorr.c +++ b/schnorr.c @@ -1,4 +1,4 @@ -/* $OpenBSD: schnorr.c,v 1.8 2013/11/08 00:39:15 djm Exp $ */ +/* $OpenBSD: schnorr.c,v 1.9 2014/01/09 23:20:00 djm Exp $ */ /* * Copyright (c) 2008 Damien Miller. All rights reserved. * @@ -41,6 +41,7 @@ #include "log.h" #include "schnorr.h" +#include "digest.h" #include "openbsd-compat/openssl-compat.h" @@ -57,12 +58,12 @@ /* * Calculate hash component of Schnorr signature H(g || g^v || g^x || id) - * using the hash function defined by "evp_md". Returns signature as + * using the hash function defined by "hash_alg". Returns signature as * bignum or NULL on error. */ static BIGNUM * schnorr_hash(const BIGNUM *p, const BIGNUM *q, const BIGNUM *g, - const EVP_MD *evp_md, const BIGNUM *g_v, const BIGNUM *g_x, + int hash_alg, const BIGNUM *g_v, const BIGNUM *g_x, const u_char *id, u_int idlen) { u_char *digest; @@ -88,7 +89,7 @@ schnorr_hash(const BIGNUM *p, const BIGNUM *q, const BIGNUM *g, SCHNORR_DEBUG_BUF((buffer_ptr(&b), buffer_len(&b), "%s: hashblob", __func__)); - if (hash_buffer(buffer_ptr(&b), buffer_len(&b), evp_md, + if (hash_buffer(buffer_ptr(&b), buffer_len(&b), hash_alg, &digest, &digest_len) != 0) { error("%s: hash_buffer", __func__); goto out; @@ -113,7 +114,7 @@ schnorr_hash(const BIGNUM *p, const BIGNUM *q, const BIGNUM *g, /* * Generate Schnorr signature to prove knowledge of private value 'x' used * in public exponent g^x, under group defined by 'grp_p', 'grp_q' and 'grp_g' - * using the hash function "evp_md". + * using the hash function "hash_alg". * 'idlen' bytes from 'id' will be included in the signature hash as an anti- * replay salt. * @@ -123,7 +124,7 @@ schnorr_hash(const BIGNUM *p, const BIGNUM *q, const BIGNUM *g, */ int schnorr_sign(const BIGNUM *grp_p, const BIGNUM *grp_q, const BIGNUM *grp_g, - const EVP_MD *evp_md, const BIGNUM *x, const BIGNUM *g_x, + int hash_alg, const BIGNUM *x, const BIGNUM *g_x, const u_char *id, u_int idlen, BIGNUM **r_p, BIGNUM **e_p) { int success = -1; @@ -173,7 +174,7 @@ schnorr_sign(const BIGNUM *grp_p, const BIGNUM *grp_q, const BIGNUM *grp_g, SCHNORR_DEBUG_BN((g_v, "%s: g_v = ", __func__)); /* h = H(g || g^v || g^x || id) */ - if ((h = schnorr_hash(grp_p, grp_q, grp_g, evp_md, g_v, g_x, + if ((h = schnorr_hash(grp_p, grp_q, grp_g, hash_alg, g_v, g_x, id, idlen)) == NULL) { error("%s: schnorr_hash failed", __func__); goto out; @@ -223,7 +224,7 @@ schnorr_sign_buf(const BIGNUM *grp_p, const BIGNUM *grp_q, const BIGNUM *grp_g, Buffer b; BIGNUM *r, *e; - if (schnorr_sign(grp_p, grp_q, grp_g, EVP_sha256(), + if (schnorr_sign(grp_p, grp_q, grp_g, SSH_DIGEST_SHA256, x, g_x, id, idlen, &r, &e) != 0) return -1; @@ -248,13 +249,13 @@ schnorr_sign_buf(const BIGNUM *grp_p, const BIGNUM *grp_q, const BIGNUM *grp_g, /* * Verify Schnorr signature { r (v - xh mod q), e (g^v mod p) } against * public exponent g_x (g^x) under group defined by 'grp_p', 'grp_q' and - * 'grp_g' using hash "evp_md". + * 'grp_g' using hash "hash_alg". * Signature hash will be salted with 'idlen' bytes from 'id'. * Returns -1 on failure, 0 on incorrect signature or 1 on matching signature. */ int schnorr_verify(const BIGNUM *grp_p, const BIGNUM *grp_q, const BIGNUM *grp_g, - const EVP_MD *evp_md, const BIGNUM *g_x, const u_char *id, u_int idlen, + int hash_alg, const BIGNUM *g_x, const u_char *id, u_int idlen, const BIGNUM *r, const BIGNUM *e) { int success = -1; @@ -302,7 +303,7 @@ schnorr_verify(const BIGNUM *grp_p, const BIGNUM *grp_q, const BIGNUM *grp_g, SCHNORR_DEBUG_BN((g_xh, "%s: g_xh = ", __func__)); /* h = H(g || g^v || g^x || id) */ - if ((h = schnorr_hash(grp_p, grp_q, grp_g, evp_md, e, g_x, + if ((h = schnorr_hash(grp_p, grp_q, grp_g, hash_alg, e, g_x, id, idlen)) == NULL) { error("%s: schnorr_hash failed", __func__); goto out; @@ -385,7 +386,7 @@ schnorr_verify_buf(const BIGNUM *grp_p, const BIGNUM *grp_q, goto out; } - ret = schnorr_verify(grp_p, grp_q, grp_g, EVP_sha256(), + ret = schnorr_verify(grp_p, grp_q, grp_g, SSH_DIGEST_SHA256, g_x, id, idlen, r, e); out: BN_clear_free(e); @@ -443,43 +444,33 @@ bn_rand_range_gt_one(const BIGNUM *high) return NULL; } +/* XXX convert all callers of this to use ssh_digest_memory() directly */ /* * Hash contents of buffer 'b' with hash 'md'. Returns 0 on success, * with digest via 'digestp' (caller to free) and length via 'lenp'. * Returns -1 on failure. */ int -hash_buffer(const u_char *buf, u_int len, const EVP_MD *md, +hash_buffer(const u_char *buf, u_int len, int hash_alg, u_char **digestp, u_int *lenp) { - u_char digest[EVP_MAX_MD_SIZE]; - u_int digest_len; - EVP_MD_CTX evp_md_ctx; - int success = -1; + u_char digest[SSH_DIGEST_MAX_LENGTH]; + u_int digest_len = ssh_digest_bytes(hash_alg); - EVP_MD_CTX_init(&evp_md_ctx); - - if (EVP_DigestInit_ex(&evp_md_ctx, md, NULL) != 1) { - error("%s: EVP_DigestInit_ex", __func__); - goto out; - } - if (EVP_DigestUpdate(&evp_md_ctx, buf, len) != 1) { - error("%s: EVP_DigestUpdate", __func__); - goto out; + if (digest_len == 0) { + error("%s: invalid hash", __func__); + return -1; } - if (EVP_DigestFinal_ex(&evp_md_ctx, digest, &digest_len) != 1) { - error("%s: EVP_DigestFinal_ex", __func__); - goto out; + if (ssh_digest_memory(hash_alg, buf, len, digest, digest_len) != 0) { + error("%s: digest_memory failed", __func__); + return -1; } *digestp = xmalloc(digest_len); *lenp = digest_len; memcpy(*digestp, digest, *lenp); - success = 0; - out: - EVP_MD_CTX_cleanup(&evp_md_ctx); bzero(digest, sizeof(digest)); digest_len = 0; - return success; + return 0; } /* print formatted string followed by bignum */ diff --git a/schnorr.h b/schnorr.h index 9730b47ce..e2405c102 100644 --- a/schnorr.h +++ b/schnorr.h @@ -1,4 +1,4 @@ -/* $OpenBSD: schnorr.h,v 1.1 2009/03/05 07:18:19 djm Exp $ */ +/* $OpenBSD: schnorr.h,v 1.2 2014/01/09 23:20:00 djm Exp $ */ /* * Copyright (c) 2009 Damien Miller. All rights reserved. * @@ -27,7 +27,7 @@ struct modp_group { }; BIGNUM *bn_rand_range_gt_one(const BIGNUM *high); -int hash_buffer(const u_char *, u_int, const EVP_MD *, u_char **, u_int *); +int hash_buffer(const u_char *, u_int, int, u_char **, u_int *); void debug3_bn(const BIGNUM *, const char *, ...) __attribute__((__nonnull__ (2))) __attribute__((format(printf, 2, 3))); @@ -40,7 +40,7 @@ void modp_group_free(struct modp_group *); /* Signature and verification functions */ int schnorr_sign(const BIGNUM *grp_p, const BIGNUM *grp_q, const BIGNUM *grp_g, - const EVP_MD *evp_md, const BIGNUM *x, const BIGNUM *g_x, + int hash_alg, const BIGNUM *x, const BIGNUM *g_x, const u_char *id, u_int idlen, BIGNUM **r_p, BIGNUM **e_p); int schnorr_sign_buf(const BIGNUM *grp_p, const BIGNUM *grp_q, const BIGNUM *grp_g, @@ -48,7 +48,7 @@ schnorr_sign_buf(const BIGNUM *grp_p, const BIGNUM *grp_q, const BIGNUM *grp_g, u_char **sig, u_int *siglen); int schnorr_verify(const BIGNUM *grp_p, const BIGNUM *grp_q, const BIGNUM *grp_g, - const EVP_MD *evp_md, const BIGNUM *g_x, const u_char *id, u_int idlen, + int hash_alg, const BIGNUM *g_x, const u_char *id, u_int idlen, const BIGNUM *r, const BIGNUM *e); int schnorr_verify_buf(const BIGNUM *grp_p, const BIGNUM *grp_q, diff --git a/ssh-dss.c b/ssh-dss.c index a6292aa84..7b897475c 100644 --- a/ssh-dss.c +++ b/ssh-dss.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-dss.c,v 1.29 2013/12/27 22:30:17 djm Exp $ */ +/* $OpenBSD: ssh-dss.c,v 1.30 2014/01/09 23:20:00 djm Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. * @@ -38,6 +38,7 @@ #include "compat.h" #include "log.h" #include "key.h" +#include "digest.h" #define INTBLOB_LEN 20 #define SIGBLOB_LEN (2*INTBLOB_LEN) @@ -47,10 +48,8 @@ ssh_dss_sign(const Key *key, u_char **sigp, u_int *lenp, const u_char *data, u_int datalen) { DSA_SIG *sig; - const EVP_MD *evp_md = EVP_sha1(); - EVP_MD_CTX md; - u_char digest[EVP_MAX_MD_SIZE], sigblob[SIGBLOB_LEN]; - u_int rlen, slen, len, dlen; + u_char digest[SSH_DIGEST_MAX_LENGTH], sigblob[SIGBLOB_LEN]; + u_int rlen, slen, len, dlen = ssh_digest_bytes(SSH_DIGEST_SHA1); Buffer b; if (key == NULL || key_type_plain(key->type) != KEY_DSA || @@ -59,9 +58,11 @@ ssh_dss_sign(const Key *key, u_char **sigp, u_int *lenp, return -1; } - EVP_DigestInit(&md, evp_md); - EVP_DigestUpdate(&md, data, datalen); - EVP_DigestFinal(&md, digest, &dlen); + if (ssh_digest_memory(SSH_DIGEST_SHA1, data, datalen, + digest, sizeof(digest)) != 0) { + error("%s: ssh_digest_memory failed", __func__); + return -1; + } sig = DSA_do_sign(digest, dlen, key->dsa); memset(digest, 'd', sizeof(digest)); @@ -111,10 +112,8 @@ ssh_dss_verify(const Key *key, const u_char *signature, u_int signaturelen, const u_char *data, u_int datalen) { DSA_SIG *sig; - const EVP_MD *evp_md = EVP_sha1(); - EVP_MD_CTX md; - u_char digest[EVP_MAX_MD_SIZE], *sigblob; - u_int len, dlen; + u_char digest[SSH_DIGEST_MAX_LENGTH], *sigblob; + u_int len, dlen = ssh_digest_bytes(SSH_DIGEST_SHA1); int rlen, ret; Buffer b; @@ -173,9 +172,11 @@ ssh_dss_verify(const Key *key, const u_char *signature, u_int signaturelen, free(sigblob); /* sha1 the data */ - EVP_DigestInit(&md, evp_md); - EVP_DigestUpdate(&md, data, datalen); - EVP_DigestFinal(&md, digest, &dlen); + if (ssh_digest_memory(SSH_DIGEST_SHA1, data, datalen, + digest, sizeof(digest)) != 0) { + error("%s: digest_memory failed", __func__); + return -1; + } ret = DSA_do_verify(digest, dlen, sig, key->dsa); memset(digest, 'd', sizeof(digest)); diff --git a/ssh-ecdsa.c b/ssh-ecdsa.c index 52f9e74c0..10ad9da60 100644 --- a/ssh-ecdsa.c +++ b/ssh-ecdsa.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-ecdsa.c,v 1.7 2013/12/27 22:30:17 djm Exp $ */ +/* $OpenBSD: ssh-ecdsa.c,v 1.8 2014/01/09 23:20:00 djm Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. * Copyright (c) 2010 Damien Miller. All rights reserved. @@ -42,15 +42,15 @@ #include "compat.h" #include "log.h" #include "key.h" +#include "digest.h" int ssh_ecdsa_sign(const Key *key, u_char **sigp, u_int *lenp, const u_char *data, u_int datalen) { ECDSA_SIG *sig; - const EVP_MD *evp_md; - EVP_MD_CTX md; - u_char digest[EVP_MAX_MD_SIZE]; + int hash_alg; + u_char digest[SSH_DIGEST_MAX_LENGTH]; u_int len, dlen; Buffer b, bb; @@ -60,10 +60,16 @@ ssh_ecdsa_sign(const Key *key, u_char **sigp, u_int *lenp, return -1; } - evp_md = key_ec_nid_to_evpmd(key->ecdsa_nid); - EVP_DigestInit(&md, evp_md); - EVP_DigestUpdate(&md, data, datalen); - EVP_DigestFinal(&md, digest, &dlen); + hash_alg = key_ec_nid_to_hash_alg(key->ecdsa_nid); + if ((dlen = ssh_digest_bytes(hash_alg)) == 0) { + error("%s: bad hash algorithm %d", __func__, hash_alg); + return -1; + } + if (ssh_digest_memory(hash_alg, data, datalen, + digest, sizeof(digest)) != 0) { + error("%s: digest_memory failed", __func__); + return -1; + } sig = ECDSA_do_sign(digest, dlen, key->ecdsa); memset(digest, 'd', sizeof(digest)); @@ -98,9 +104,8 @@ ssh_ecdsa_verify(const Key *key, const u_char *signature, u_int signaturelen, const u_char *data, u_int datalen) { ECDSA_SIG *sig; - const EVP_MD *evp_md; - EVP_MD_CTX md; - u_char digest[EVP_MAX_MD_SIZE], *sigblob; + int hash_alg; + u_char digest[SSH_DIGEST_MAX_LENGTH], *sigblob; u_int len, dlen; int rlen, ret; Buffer b, bb; @@ -112,8 +117,6 @@ ssh_ecdsa_verify(const Key *key, const u_char *signature, u_int signaturelen, return -1; } - evp_md = key_ec_nid_to_evpmd(key->ecdsa_nid); - /* fetch signature */ buffer_init(&b); buffer_append(&b, signature, signaturelen); @@ -154,9 +157,16 @@ ssh_ecdsa_verify(const Key *key, const u_char *signature, u_int signaturelen, free(sigblob); /* hash the data */ - EVP_DigestInit(&md, evp_md); - EVP_DigestUpdate(&md, data, datalen); - EVP_DigestFinal(&md, digest, &dlen); + hash_alg = key_ec_nid_to_hash_alg(key->ecdsa_nid); + if ((dlen = ssh_digest_bytes(hash_alg)) == 0) { + error("%s: bad hash algorithm %d", __func__, hash_alg); + return -1; + } + if (ssh_digest_memory(hash_alg, data, datalen, + digest, sizeof(digest)) != 0) { + error("%s: digest_memory failed", __func__); + return -1; + } ret = ECDSA_do_verify(digest, dlen, sig, key->ecdsa); memset(digest, 'd', sizeof(digest)); diff --git a/ssh-rsa.c b/ssh-rsa.c index b1ac50b31..a2112d033 100644 --- a/ssh-rsa.c +++ b/ssh-rsa.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-rsa.c,v 1.49 2013/12/30 23:52:27 djm Exp $ */ +/* $OpenBSD: ssh-rsa.c,v 1.50 2014/01/09 23:20:00 djm Exp $ */ /* * Copyright (c) 2000, 2003 Markus Friedl * @@ -32,6 +32,7 @@ #include "compat.h" #include "misc.h" #include "ssh.h" +#include "digest.h" static int openssh_RSA_verify(int, u_char *, u_int, u_char *, u_int, RSA *); @@ -40,9 +41,8 @@ int ssh_rsa_sign(const Key *key, u_char **sigp, u_int *lenp, const u_char *data, u_int datalen) { - const EVP_MD *evp_md; - EVP_MD_CTX md; - u_char digest[EVP_MAX_MD_SIZE], *sig; + int hash_alg; + u_char digest[SSH_DIGEST_MAX_LENGTH], *sig; u_int slen, dlen, len; int ok, nid; Buffer b; @@ -53,14 +53,18 @@ ssh_rsa_sign(const Key *key, u_char **sigp, u_int *lenp, return -1; } + /* hash the data */ + hash_alg = SSH_DIGEST_SHA1; nid = NID_sha1; - if ((evp_md = EVP_get_digestbynid(nid)) == NULL) { - error("%s: EVP_get_digestbynid %d failed", __func__, nid); + if ((dlen = ssh_digest_bytes(hash_alg)) == 0) { + error("%s: bad hash algorithm %d", __func__, hash_alg); + return -1; + } + if (ssh_digest_memory(hash_alg, data, datalen, + digest, sizeof(digest)) != 0) { + error("%s: ssh_digest_memory failed", __func__); return -1; } - EVP_DigestInit(&md, evp_md); - EVP_DigestUpdate(&md, data, datalen); - EVP_DigestFinal(&md, digest, &dlen); slen = RSA_size(key->rsa); sig = xmalloc(slen); @@ -109,12 +113,11 @@ ssh_rsa_verify(const Key *key, const u_char *signature, u_int signaturelen, const u_char *data, u_int datalen) { Buffer b; - const EVP_MD *evp_md; - EVP_MD_CTX md; + int hash_alg; char *ktype; - u_char digest[EVP_MAX_MD_SIZE], *sigblob; + u_char digest[SSH_DIGEST_MAX_LENGTH], *sigblob; u_int len, dlen, modlen; - int rlen, ret, nid; + int rlen, ret; if (key == NULL || key_type_plain(key->type) != KEY_RSA || key->rsa == NULL) { @@ -161,17 +164,20 @@ ssh_rsa_verify(const Key *key, const u_char *signature, u_int signaturelen, memset(sigblob, 0, diff); len = modlen; } - nid = NID_sha1; - if ((evp_md = EVP_get_digestbynid(nid)) == NULL) { - error("%s: EVP_get_digestbynid %d failed", __func__, nid); - free(sigblob); + /* hash the data */ + hash_alg = SSH_DIGEST_SHA1; + if ((dlen = ssh_digest_bytes(hash_alg)) == 0) { + error("%s: bad hash algorithm %d", __func__, hash_alg); + return -1; + } + if (ssh_digest_memory(hash_alg, data, datalen, + digest, sizeof(digest)) != 0) { + error("%s: ssh_digest_memory failed", __func__); return -1; } - EVP_DigestInit(&md, evp_md); - EVP_DigestUpdate(&md, data, datalen); - EVP_DigestFinal(&md, digest, &dlen); - ret = openssh_RSA_verify(nid, digest, dlen, sigblob, len, key->rsa); + ret = openssh_RSA_verify(hash_alg, digest, dlen, sigblob, len, + key->rsa); memset(digest, 'd', sizeof(digest)); memset(sigblob, 's', len); free(sigblob); @@ -198,7 +204,7 @@ static const u_char id_sha1[] = { }; static int -openssh_RSA_verify(int type, u_char *hash, u_int hashlen, +openssh_RSA_verify(int hash_alg, u_char *hash, u_int hashlen, u_char *sigbuf, u_int siglen, RSA *rsa) { u_int ret, rsasize, oidlen = 0, hlen = 0; @@ -207,8 +213,8 @@ openssh_RSA_verify(int type, u_char *hash, u_int hashlen, u_char *decrypted = NULL; ret = 0; - switch (type) { - case NID_sha1: + switch (hash_alg) { + case SSH_DIGEST_SHA1: oid = id_sha1; oidlen = sizeof(id_sha1); hlen = 20; diff --git a/sshconnect2.c b/sshconnect2.c index 0d339b9c5..8acffc5c3 100644 --- a/sshconnect2.c +++ b/sshconnect2.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sshconnect2.c,v 1.200 2013/12/30 23:52:28 djm Exp $ */ +/* $OpenBSD: sshconnect2.c,v 1.201 2014/01/09 23:20:00 djm Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. * Copyright (c) 2008 Damien Miller. All rights reserved. @@ -1006,7 +1006,7 @@ jpake_password_to_secret(Authctxt *authctxt, const char *crypt_scheme, debug3("%s: crypted = %s", __func__, crypted); #endif - if (hash_buffer(crypted, strlen(crypted), EVP_sha256(), + if (hash_buffer(crypted, strlen(crypted), SSH_DIGEST_SHA1, &secret, &secret_len) != 0) fatal("%s: hash_buffer", __func__); -- cgit v1.2.3 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(-) (limited to 'kexc25519.c') 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