kexecdh.c revision 218767
1236769Sobrien/* $OpenBSD: kexecdh.c,v 1.3 2010/09/22 05:01:29 djm Exp $ */
2236769Sobrien/*
3236769Sobrien * Copyright (c) 2001 Markus Friedl.  All rights reserved.
4236769Sobrien * Copyright (c) 2010 Damien Miller.  All rights reserved.
5236769Sobrien *
6236769Sobrien * Redistribution and use in source and binary forms, with or without
7236769Sobrien * modification, are permitted provided that the following conditions
8236769Sobrien * are met:
9236769Sobrien * 1. Redistributions of source code must retain the above copyright
10236769Sobrien *    notice, this list of conditions and the following disclaimer.
11236769Sobrien * 2. Redistributions in binary form must reproduce the above copyright
12236769Sobrien *    notice, this list of conditions and the following disclaimer in the
13236769Sobrien *    documentation and/or other materials provided with the distribution.
14236769Sobrien *
15236769Sobrien * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16236769Sobrien * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17236769Sobrien * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18236769Sobrien * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19236769Sobrien * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20236769Sobrien * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21236769Sobrien * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22236769Sobrien * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23236769Sobrien * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24236769Sobrien * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25236769Sobrien */
26236769Sobrien
27236769Sobrien#include "includes.h"
28236769Sobrien
29236769Sobrien#ifdef OPENSSL_HAS_ECC
30236769Sobrien
31236769Sobrien#include <sys/types.h>
32236769Sobrien
33236769Sobrien#include <signal.h>
34236769Sobrien#include <string.h>
35236769Sobrien
36236769Sobrien#include <openssl/bn.h>
37236769Sobrien#include <openssl/evp.h>
38236769Sobrien#include <openssl/ec.h>
39236769Sobrien#include <openssl/ecdh.h>
40236769Sobrien
41236769Sobrien#include "buffer.h"
42236769Sobrien#include "ssh2.h"
43236769Sobrien#include "key.h"
44236769Sobrien#include "cipher.h"
45236769Sobrien#include "kex.h"
46236769Sobrien#include "log.h"
47236769Sobrien
48236769Sobrienint
49236769Sobrienkex_ecdh_name_to_nid(const char *kexname)
50236769Sobrien{
51236769Sobrien	if (strlen(kexname) < sizeof(KEX_ECDH_SHA2_STEM) - 1)
52236769Sobrien		fatal("%s: kexname too short \"%s\"", __func__, kexname);
53236769Sobrien	return key_curve_name_to_nid(kexname + sizeof(KEX_ECDH_SHA2_STEM) - 1);
54236769Sobrien}
55236769Sobrien
56236769Sobrienconst EVP_MD *
57236769Sobrienkex_ecdh_name_to_evpmd(const char *kexname)
58236769Sobrien{
59236769Sobrien	int nid = kex_ecdh_name_to_nid(kexname);
60236769Sobrien
61236769Sobrien	if (nid == -1)
62236769Sobrien		fatal("%s: unsupported ECDH curve \"%s\"", __func__, kexname);
63236769Sobrien	return key_ec_nid_to_evpmd(nid);
64236769Sobrien}
65236769Sobrien
66236769Sobrienvoid
67236769Sobrienkex_ecdh_hash(
68236769Sobrien    const EVP_MD *evp_md,
69236769Sobrien    const EC_GROUP *ec_group,
70236769Sobrien    char *client_version_string,
71236769Sobrien    char *server_version_string,
72236769Sobrien    char *ckexinit, int ckexinitlen,
73236769Sobrien    char *skexinit, int skexinitlen,
74236769Sobrien    u_char *serverhostkeyblob, int sbloblen,
75236769Sobrien    const EC_POINT *client_dh_pub,
76236769Sobrien    const EC_POINT *server_dh_pub,
77236769Sobrien    const BIGNUM *shared_secret,
78236769Sobrien    u_char **hash, u_int *hashlen)
79236769Sobrien{
80236769Sobrien	Buffer b;
81236769Sobrien	EVP_MD_CTX md;
82236769Sobrien	static u_char digest[EVP_MAX_MD_SIZE];
83236769Sobrien
84236769Sobrien	buffer_init(&b);
85236769Sobrien	buffer_put_cstring(&b, client_version_string);
86236769Sobrien	buffer_put_cstring(&b, server_version_string);
87236769Sobrien
88236769Sobrien	/* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */
89236769Sobrien	buffer_put_int(&b, ckexinitlen+1);
90236769Sobrien	buffer_put_char(&b, SSH2_MSG_KEXINIT);
91236769Sobrien	buffer_append(&b, ckexinit, ckexinitlen);
92236769Sobrien	buffer_put_int(&b, skexinitlen+1);
93236769Sobrien	buffer_put_char(&b, SSH2_MSG_KEXINIT);
94236769Sobrien	buffer_append(&b, skexinit, skexinitlen);
95236769Sobrien
96236769Sobrien	buffer_put_string(&b, serverhostkeyblob, sbloblen);
97236769Sobrien	buffer_put_ecpoint(&b, ec_group, client_dh_pub);
98236769Sobrien	buffer_put_ecpoint(&b, ec_group, server_dh_pub);
99236769Sobrien	buffer_put_bignum2(&b, shared_secret);
100236769Sobrien
101236769Sobrien#ifdef DEBUG_KEX
102236769Sobrien	buffer_dump(&b);
103236769Sobrien#endif
104236769Sobrien	EVP_DigestInit(&md, evp_md);
105236769Sobrien	EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));
106236769Sobrien	EVP_DigestFinal(&md, digest, NULL);
107236769Sobrien
108236769Sobrien	buffer_free(&b);
109236769Sobrien
110236769Sobrien#ifdef DEBUG_KEX
111236769Sobrien	dump_digest("hash", digest, EVP_MD_size(evp_md));
112236769Sobrien#endif
113236769Sobrien	*hash = digest;
114236769Sobrien	*hashlen = EVP_MD_size(evp_md);
115236769Sobrien}
116236769Sobrien
117236769Sobrien#endif /* OPENSSL_HAS_ECC */
118236769Sobrien