19768ca48f57aaf035f508a473421d210b5145e99Greg Hartman/* $OpenBSD: kexecdhs.c,v 1.15 2015/12/04 16:41:28 markus Exp $ */
2bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman/*
3bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * Copyright (c) 2001 Markus Friedl.  All rights reserved.
4bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * Copyright (c) 2010 Damien Miller.  All rights reserved.
5bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman *
6bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * Redistribution and use in source and binary forms, with or without
7bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * modification, are permitted provided that the following conditions
8bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * are met:
9bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * 1. Redistributions of source code must retain the above copyright
10bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman *    notice, this list of conditions and the following disclaimer.
11bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * 2. Redistributions in binary form must reproduce the above copyright
12bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman *    notice, this list of conditions and the following disclaimer in the
13bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman *    documentation and/or other materials provided with the distribution.
14bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman *
15bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman */
26bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
27bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "includes.h"
28bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
29d059297112922cabb0c674840589be8db821fd9aAdam Langley#if defined(WITH_OPENSSL) && defined(OPENSSL_HAS_ECC)
30d059297112922cabb0c674840589be8db821fd9aAdam Langley
31bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include <sys/types.h>
32bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include <string.h>
33bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include <signal.h>
34bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
35d059297112922cabb0c674840589be8db821fd9aAdam Langley#include <openssl/ecdh.h>
36d059297112922cabb0c674840589be8db821fd9aAdam Langley
37d059297112922cabb0c674840589be8db821fd9aAdam Langley#include "sshkey.h"
38bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "cipher.h"
39d059297112922cabb0c674840589be8db821fd9aAdam Langley#include "digest.h"
40bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "kex.h"
41bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "log.h"
42bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "packet.h"
43bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "ssh2.h"
44bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
45d059297112922cabb0c674840589be8db821fd9aAdam Langley#include "dispatch.h"
46d059297112922cabb0c674840589be8db821fd9aAdam Langley#include "compat.h"
47d059297112922cabb0c674840589be8db821fd9aAdam Langley#include "ssherr.h"
48d059297112922cabb0c674840589be8db821fd9aAdam Langley#include "sshbuf.h"
49bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
50d059297112922cabb0c674840589be8db821fd9aAdam Langleystatic int input_kex_ecdh_init(int, u_int32_t, void *);
51d059297112922cabb0c674840589be8db821fd9aAdam Langley
52d059297112922cabb0c674840589be8db821fd9aAdam Langleyint
53d059297112922cabb0c674840589be8db821fd9aAdam Langleykexecdh_server(struct ssh *ssh)
54d059297112922cabb0c674840589be8db821fd9aAdam Langley{
55d059297112922cabb0c674840589be8db821fd9aAdam Langley	debug("expecting SSH2_MSG_KEX_ECDH_INIT");
56d059297112922cabb0c674840589be8db821fd9aAdam Langley	ssh_dispatch_set(ssh, SSH2_MSG_KEX_ECDH_INIT, &input_kex_ecdh_init);
57d059297112922cabb0c674840589be8db821fd9aAdam Langley	return 0;
58d059297112922cabb0c674840589be8db821fd9aAdam Langley}
59bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
60d059297112922cabb0c674840589be8db821fd9aAdam Langleystatic int
61d059297112922cabb0c674840589be8db821fd9aAdam Langleyinput_kex_ecdh_init(int type, u_int32_t seq, void *ctxt)
62bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{
63d059297112922cabb0c674840589be8db821fd9aAdam Langley	struct ssh *ssh = ctxt;
64d059297112922cabb0c674840589be8db821fd9aAdam Langley	struct kex *kex = ssh->kex;
65bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	EC_POINT *client_public;
66d059297112922cabb0c674840589be8db821fd9aAdam Langley	EC_KEY *server_key = NULL;
67bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	const EC_GROUP *group;
68d059297112922cabb0c674840589be8db821fd9aAdam Langley	const EC_POINT *public_key;
69d059297112922cabb0c674840589be8db821fd9aAdam Langley	BIGNUM *shared_secret = NULL;
70d059297112922cabb0c674840589be8db821fd9aAdam Langley	struct sshkey *server_host_private, *server_host_public;
71bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	u_char *server_host_key_blob = NULL, *signature = NULL;
72d059297112922cabb0c674840589be8db821fd9aAdam Langley	u_char *kbuf = NULL;
73d059297112922cabb0c674840589be8db821fd9aAdam Langley	u_char hash[SSH_DIGEST_MAX_LENGTH];
74d059297112922cabb0c674840589be8db821fd9aAdam Langley	size_t slen, sbloblen;
75d059297112922cabb0c674840589be8db821fd9aAdam Langley	size_t klen = 0, hashlen;
76d059297112922cabb0c674840589be8db821fd9aAdam Langley	int r;
77d059297112922cabb0c674840589be8db821fd9aAdam Langley
78d059297112922cabb0c674840589be8db821fd9aAdam Langley	if ((server_key = EC_KEY_new_by_curve_name(kex->ec_nid)) == NULL) {
79d059297112922cabb0c674840589be8db821fd9aAdam Langley		r = SSH_ERR_ALLOC_FAIL;
80d059297112922cabb0c674840589be8db821fd9aAdam Langley		goto out;
81d059297112922cabb0c674840589be8db821fd9aAdam Langley	}
82d059297112922cabb0c674840589be8db821fd9aAdam Langley	if (EC_KEY_generate_key(server_key) != 1) {
83d059297112922cabb0c674840589be8db821fd9aAdam Langley		r = SSH_ERR_LIBCRYPTO_ERROR;
84d059297112922cabb0c674840589be8db821fd9aAdam Langley		goto out;
85d059297112922cabb0c674840589be8db821fd9aAdam Langley	}
86bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	group = EC_KEY_get0_group(server_key);
87bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
88bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#ifdef DEBUG_KEXECDH
89bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	fputs("server private key:\n", stderr);
90d059297112922cabb0c674840589be8db821fd9aAdam Langley	sshkey_dump_ec_key(server_key);
91bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#endif
92bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
93bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	if (kex->load_host_public_key == NULL ||
94d059297112922cabb0c674840589be8db821fd9aAdam Langley	    kex->load_host_private_key == NULL) {
95d059297112922cabb0c674840589be8db821fd9aAdam Langley		r = SSH_ERR_INVALID_ARGUMENT;
96d059297112922cabb0c674840589be8db821fd9aAdam Langley		goto out;
97d059297112922cabb0c674840589be8db821fd9aAdam Langley	}
98d059297112922cabb0c674840589be8db821fd9aAdam Langley	server_host_public = kex->load_host_public_key(kex->hostkey_type,
99d059297112922cabb0c674840589be8db821fd9aAdam Langley	    kex->hostkey_nid, ssh);
100d059297112922cabb0c674840589be8db821fd9aAdam Langley	server_host_private = kex->load_host_private_key(kex->hostkey_type,
101d059297112922cabb0c674840589be8db821fd9aAdam Langley	    kex->hostkey_nid, ssh);
102d059297112922cabb0c674840589be8db821fd9aAdam Langley	if (server_host_public == NULL) {
103d059297112922cabb0c674840589be8db821fd9aAdam Langley		r = SSH_ERR_NO_HOSTKEY_LOADED;
104d059297112922cabb0c674840589be8db821fd9aAdam Langley		goto out;
105d059297112922cabb0c674840589be8db821fd9aAdam Langley	}
106d059297112922cabb0c674840589be8db821fd9aAdam Langley	if ((client_public = EC_POINT_new(group)) == NULL) {
107d059297112922cabb0c674840589be8db821fd9aAdam Langley		r = SSH_ERR_ALLOC_FAIL;
108d059297112922cabb0c674840589be8db821fd9aAdam Langley		goto out;
109d059297112922cabb0c674840589be8db821fd9aAdam Langley	}
110d059297112922cabb0c674840589be8db821fd9aAdam Langley	if ((r = sshpkt_get_ec(ssh, client_public, group)) != 0 ||
111d059297112922cabb0c674840589be8db821fd9aAdam Langley	    (r = sshpkt_get_end(ssh)) != 0)
112d059297112922cabb0c674840589be8db821fd9aAdam Langley		goto out;
113bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
114bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#ifdef DEBUG_KEXECDH
115bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	fputs("client public key:\n", stderr);
116d059297112922cabb0c674840589be8db821fd9aAdam Langley	sshkey_dump_ec_point(group, client_public);
117bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#endif
118d059297112922cabb0c674840589be8db821fd9aAdam Langley	if (sshkey_ec_validate_public(group, client_public) != 0) {
119d059297112922cabb0c674840589be8db821fd9aAdam Langley		sshpkt_disconnect(ssh, "invalid client public key");
120d059297112922cabb0c674840589be8db821fd9aAdam Langley		r = SSH_ERR_MESSAGE_INCOMPLETE;
121d059297112922cabb0c674840589be8db821fd9aAdam Langley		goto out;
122d059297112922cabb0c674840589be8db821fd9aAdam Langley	}
123bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
124bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	/* Calculate shared_secret */
125bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	klen = (EC_GROUP_get_degree(group) + 7) / 8;
126d059297112922cabb0c674840589be8db821fd9aAdam Langley	if ((kbuf = malloc(klen)) == NULL ||
127d059297112922cabb0c674840589be8db821fd9aAdam Langley	    (shared_secret = BN_new()) == NULL) {
128d059297112922cabb0c674840589be8db821fd9aAdam Langley		r = SSH_ERR_ALLOC_FAIL;
129d059297112922cabb0c674840589be8db821fd9aAdam Langley		goto out;
130d059297112922cabb0c674840589be8db821fd9aAdam Langley	}
131bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	if (ECDH_compute_key(kbuf, klen, client_public,
132d059297112922cabb0c674840589be8db821fd9aAdam Langley	    server_key, NULL) != (int)klen ||
133d059297112922cabb0c674840589be8db821fd9aAdam Langley	    BN_bin2bn(kbuf, klen, shared_secret) == NULL) {
134d059297112922cabb0c674840589be8db821fd9aAdam Langley		r = SSH_ERR_LIBCRYPTO_ERROR;
135d059297112922cabb0c674840589be8db821fd9aAdam Langley		goto out;
136d059297112922cabb0c674840589be8db821fd9aAdam Langley	}
137bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
138d059297112922cabb0c674840589be8db821fd9aAdam Langley#ifdef DEBUG_KEXECDH
139bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	dump_digest("shared secret", kbuf, klen);
140bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#endif
141bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	/* calc H */
142d059297112922cabb0c674840589be8db821fd9aAdam Langley	if ((r = sshkey_to_blob(server_host_public, &server_host_key_blob,
143d059297112922cabb0c674840589be8db821fd9aAdam Langley	    &sbloblen)) != 0)
144d059297112922cabb0c674840589be8db821fd9aAdam Langley		goto out;
145d059297112922cabb0c674840589be8db821fd9aAdam Langley	hashlen = sizeof(hash);
146d059297112922cabb0c674840589be8db821fd9aAdam Langley	if ((r = kex_ecdh_hash(
147d059297112922cabb0c674840589be8db821fd9aAdam Langley	    kex->hash_alg,
148bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	    group,
149bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	    kex->client_version_string,
150bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	    kex->server_version_string,
151d059297112922cabb0c674840589be8db821fd9aAdam Langley	    sshbuf_ptr(kex->peer), sshbuf_len(kex->peer),
152d059297112922cabb0c674840589be8db821fd9aAdam Langley	    sshbuf_ptr(kex->my), sshbuf_len(kex->my),
153bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	    server_host_key_blob, sbloblen,
154bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	    client_public,
155bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	    EC_KEY_get0_public_key(server_key),
156bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	    shared_secret,
157d059297112922cabb0c674840589be8db821fd9aAdam Langley	    hash, &hashlen)) != 0)
158d059297112922cabb0c674840589be8db821fd9aAdam Langley		goto out;
159bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
160bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	/* save session id := H */
161bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	if (kex->session_id == NULL) {
162bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		kex->session_id_len = hashlen;
163d059297112922cabb0c674840589be8db821fd9aAdam Langley		kex->session_id = malloc(kex->session_id_len);
164d059297112922cabb0c674840589be8db821fd9aAdam Langley		if (kex->session_id == NULL) {
165d059297112922cabb0c674840589be8db821fd9aAdam Langley			r = SSH_ERR_ALLOC_FAIL;
166d059297112922cabb0c674840589be8db821fd9aAdam Langley			goto out;
167d059297112922cabb0c674840589be8db821fd9aAdam Langley		}
168bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		memcpy(kex->session_id, hash, kex->session_id_len);
169bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	}
170bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
171bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	/* sign H */
1729768ca48f57aaf035f508a473421d210b5145e99Greg Hartman	if ((r = kex->sign(server_host_private, server_host_public, &signature,
1739768ca48f57aaf035f508a473421d210b5145e99Greg Hartman	     &slen, hash, hashlen, kex->hostkey_alg, ssh->compat)) < 0)
174d059297112922cabb0c674840589be8db821fd9aAdam Langley		goto out;
175bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
176bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	/* destroy_sensitive_data(); */
177bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
178d059297112922cabb0c674840589be8db821fd9aAdam Langley	public_key = EC_KEY_get0_public_key(server_key);
179bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	/* send server hostkey, ECDH pubkey 'Q_S' and signed H */
180d059297112922cabb0c674840589be8db821fd9aAdam Langley	if ((r = sshpkt_start(ssh, SSH2_MSG_KEX_ECDH_REPLY)) != 0 ||
181d059297112922cabb0c674840589be8db821fd9aAdam Langley	    (r = sshpkt_put_string(ssh, server_host_key_blob, sbloblen)) != 0 ||
182d059297112922cabb0c674840589be8db821fd9aAdam Langley	    (r = sshpkt_put_ec(ssh, public_key, group)) != 0 ||
183d059297112922cabb0c674840589be8db821fd9aAdam Langley	    (r = sshpkt_put_string(ssh, signature, slen)) != 0 ||
184d059297112922cabb0c674840589be8db821fd9aAdam Langley	    (r = sshpkt_send(ssh)) != 0)
185d059297112922cabb0c674840589be8db821fd9aAdam Langley		goto out;
186d059297112922cabb0c674840589be8db821fd9aAdam Langley
187d059297112922cabb0c674840589be8db821fd9aAdam Langley	if ((r = kex_derive_keys_bn(ssh, hash, hashlen, shared_secret)) == 0)
188d059297112922cabb0c674840589be8db821fd9aAdam Langley		r = kex_send_newkeys(ssh);
189d059297112922cabb0c674840589be8db821fd9aAdam Langley out:
190d059297112922cabb0c674840589be8db821fd9aAdam Langley	explicit_bzero(hash, sizeof(hash));
191d059297112922cabb0c674840589be8db821fd9aAdam Langley	if (kex->ec_client_key) {
192d059297112922cabb0c674840589be8db821fd9aAdam Langley		EC_KEY_free(kex->ec_client_key);
193d059297112922cabb0c674840589be8db821fd9aAdam Langley		kex->ec_client_key = NULL;
194d059297112922cabb0c674840589be8db821fd9aAdam Langley	}
195d059297112922cabb0c674840589be8db821fd9aAdam Langley	if (server_key)
196d059297112922cabb0c674840589be8db821fd9aAdam Langley		EC_KEY_free(server_key);
197d059297112922cabb0c674840589be8db821fd9aAdam Langley	if (kbuf) {
198d059297112922cabb0c674840589be8db821fd9aAdam Langley		explicit_bzero(kbuf, klen);
199d059297112922cabb0c674840589be8db821fd9aAdam Langley		free(kbuf);
200d059297112922cabb0c674840589be8db821fd9aAdam Langley	}
201d059297112922cabb0c674840589be8db821fd9aAdam Langley	if (shared_secret)
202d059297112922cabb0c674840589be8db821fd9aAdam Langley		BN_clear_free(shared_secret);
203d059297112922cabb0c674840589be8db821fd9aAdam Langley	free(server_host_key_blob);
204d059297112922cabb0c674840589be8db821fd9aAdam Langley	free(signature);
205d059297112922cabb0c674840589be8db821fd9aAdam Langley	return r;
206bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman}
207d059297112922cabb0c674840589be8db821fd9aAdam Langley#endif /* defined(WITH_OPENSSL) && defined(OPENSSL_HAS_ECC) */
208d059297112922cabb0c674840589be8db821fd9aAdam Langley
209