summaryrefslogtreecommitdiff
path: root/kexecdh.c
diff options
context:
space:
mode:
Diffstat (limited to 'kexecdh.c')
-rw-r--r--kexecdh.c211
1 files changed, 161 insertions, 50 deletions
diff --git a/kexecdh.c b/kexecdh.c
index 2a4fec6b1..0aeab2e9b 100644
--- a/kexecdh.c
+++ b/kexecdh.c
@@ -1,7 +1,7 @@
1/* $OpenBSD: kexecdh.c,v 1.6 2015/01/19 20:16:15 markus Exp $ */ 1/* $OpenBSD: kexecdh.c,v 1.10 2019/01/21 10:40:11 djm Exp $ */
2/* 2/*
3 * Copyright (c) 2001 Markus Friedl. All rights reserved.
4 * Copyright (c) 2010 Damien Miller. All rights reserved. 3 * Copyright (c) 2010 Damien Miller. All rights reserved.
4 * Copyright (c) 2019 Markus Friedl. All rights reserved.
5 * 5 *
6 * Redistribution and use in source and binary forms, with or without 6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions 7 * modification, are permitted provided that the following conditions
@@ -30,71 +30,182 @@
30 30
31#include <sys/types.h> 31#include <sys/types.h>
32 32
33#include <signal.h> 33#include <stdio.h>
34#include <string.h> 34#include <string.h>
35#include <signal.h>
35 36
36#include <openssl/bn.h>
37#include <openssl/evp.h>
38#include <openssl/ec.h>
39#include <openssl/ecdh.h> 37#include <openssl/ecdh.h>
40 38
41#include "ssh2.h"
42#include "sshkey.h" 39#include "sshkey.h"
43#include "cipher.h"
44#include "kex.h" 40#include "kex.h"
45#include "sshbuf.h" 41#include "sshbuf.h"
46#include "digest.h" 42#include "digest.h"
47#include "ssherr.h" 43#include "ssherr.h"
48 44
45static int
46kex_ecdh_dec_key_group(struct kex *, const struct sshbuf *, EC_KEY *key,
47 const EC_GROUP *, struct sshbuf **);
48
49int 49int
50kex_ecdh_hash( 50kex_ecdh_keypair(struct kex *kex)
51 int hash_alg,
52 const EC_GROUP *ec_group,
53 const char *client_version_string,
54 const char *server_version_string,
55 const u_char *ckexinit, size_t ckexinitlen,
56 const u_char *skexinit, size_t skexinitlen,
57 const u_char *serverhostkeyblob, size_t sbloblen,
58 const EC_POINT *client_dh_pub,
59 const EC_POINT *server_dh_pub,
60 const BIGNUM *shared_secret,
61 u_char *hash, size_t *hashlen)
62{ 51{
63 struct sshbuf *b; 52 EC_KEY *client_key = NULL;
53 const EC_GROUP *group;
54 const EC_POINT *public_key;
55 struct sshbuf *buf = NULL;
64 int r; 56 int r;
65 57
66 if (*hashlen < ssh_digest_bytes(hash_alg)) 58 if ((client_key = EC_KEY_new_by_curve_name(kex->ec_nid)) == NULL) {
67 return SSH_ERR_INVALID_ARGUMENT; 59 r = SSH_ERR_ALLOC_FAIL;
68 if ((b = sshbuf_new()) == NULL) 60 goto out;
69 return SSH_ERR_ALLOC_FAIL; 61 }
70 if ((r = sshbuf_put_cstring(b, client_version_string)) != 0 || 62 if (EC_KEY_generate_key(client_key) != 1) {
71 (r = sshbuf_put_cstring(b, server_version_string)) != 0 || 63 r = SSH_ERR_LIBCRYPTO_ERROR;
72 /* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */ 64 goto out;
73 (r = sshbuf_put_u32(b, ckexinitlen+1)) != 0 || 65 }
74 (r = sshbuf_put_u8(b, SSH2_MSG_KEXINIT)) != 0 || 66 group = EC_KEY_get0_group(client_key);
75 (r = sshbuf_put(b, ckexinit, ckexinitlen)) != 0 || 67 public_key = EC_KEY_get0_public_key(client_key);
76 (r = sshbuf_put_u32(b, skexinitlen+1)) != 0 || 68
77 (r = sshbuf_put_u8(b, SSH2_MSG_KEXINIT)) != 0 || 69 if ((buf = sshbuf_new()) == NULL) {
78 (r = sshbuf_put(b, skexinit, skexinitlen)) != 0 || 70 r = SSH_ERR_ALLOC_FAIL;
79 (r = sshbuf_put_string(b, serverhostkeyblob, sbloblen)) != 0 || 71 goto out;
80 (r = sshbuf_put_ec(b, client_dh_pub, ec_group)) != 0 ||
81 (r = sshbuf_put_ec(b, server_dh_pub, ec_group)) != 0 ||
82 (r = sshbuf_put_bignum2(b, shared_secret)) != 0) {
83 sshbuf_free(b);
84 return r;
85 } 72 }
86#ifdef DEBUG_KEX 73 if ((r = sshbuf_put_ec(buf, public_key, group)) != 0 ||
87 sshbuf_dump(b, stderr); 74 (r = sshbuf_get_u32(buf, NULL)) != 0)
75 goto out;
76#ifdef DEBUG_KEXECDH
77 fputs("client private key:\n", stderr);
78 sshkey_dump_ec_key(client_key);
88#endif 79#endif
89 if (ssh_digest_buffer(hash_alg, b, hash, *hashlen) != 0) { 80 kex->ec_client_key = client_key;
90 sshbuf_free(b); 81 kex->ec_group = group;
91 return SSH_ERR_LIBCRYPTO_ERROR; 82 client_key = NULL; /* owned by the kex */
83 kex->client_pub = buf;
84 buf = NULL;
85 out:
86 EC_KEY_free(client_key);
87 sshbuf_free(buf);
88 return r;
89}
90
91int
92kex_ecdh_enc(struct kex *kex, const struct sshbuf *client_blob,
93 struct sshbuf **server_blobp, struct sshbuf **shared_secretp)
94{
95 const EC_GROUP *group;
96 const EC_POINT *pub_key;
97 EC_KEY *server_key = NULL;
98 struct sshbuf *server_blob = NULL;
99 int r;
100
101 *server_blobp = NULL;
102 *shared_secretp = NULL;
103
104 if ((server_key = EC_KEY_new_by_curve_name(kex->ec_nid)) == NULL) {
105 r = SSH_ERR_ALLOC_FAIL;
106 goto out;
92 } 107 }
93 sshbuf_free(b); 108 if (EC_KEY_generate_key(server_key) != 1) {
94 *hashlen = ssh_digest_bytes(hash_alg); 109 r = SSH_ERR_LIBCRYPTO_ERROR;
95#ifdef DEBUG_KEX 110 goto out;
96 dump_digest("hash", hash, *hashlen); 111 }
112 group = EC_KEY_get0_group(server_key);
113
114#ifdef DEBUG_KEXECDH
115 fputs("server private key:\n", stderr);
116 sshkey_dump_ec_key(server_key);
97#endif 117#endif
98 return 0; 118 pub_key = EC_KEY_get0_public_key(server_key);
119 if ((server_blob = sshbuf_new()) == NULL) {
120 r = SSH_ERR_ALLOC_FAIL;
121 goto out;
122 }
123 if ((r = sshbuf_put_ec(server_blob, pub_key, group)) != 0 ||
124 (r = sshbuf_get_u32(server_blob, NULL)) != 0)
125 goto out;
126 if ((r = kex_ecdh_dec_key_group(kex, client_blob, server_key, group,
127 shared_secretp)) != 0)
128 goto out;
129 *server_blobp = server_blob;
130 server_blob = NULL;
131 out:
132 EC_KEY_free(server_key);
133 sshbuf_free(server_blob);
134 return r;
135}
136
137static int
138kex_ecdh_dec_key_group(struct kex *kex, const struct sshbuf *ec_blob,
139 EC_KEY *key, const EC_GROUP *group, struct sshbuf **shared_secretp)
140{
141 struct sshbuf *buf = NULL;
142 BIGNUM *shared_secret = NULL;
143 EC_POINT *dh_pub = NULL;
144 u_char *kbuf = NULL;
145 size_t klen = 0;
146 int r;
147
148 *shared_secretp = NULL;
149
150 if ((buf = sshbuf_new()) == NULL) {
151 r = SSH_ERR_ALLOC_FAIL;
152 goto out;
153 }
154 if ((r = sshbuf_put_stringb(buf, ec_blob)) != 0)
155 goto out;
156 if ((dh_pub = EC_POINT_new(group)) == NULL) {
157 r = SSH_ERR_ALLOC_FAIL;
158 goto out;
159 }
160 if ((r = sshbuf_get_ec(buf, dh_pub, group)) != 0) {
161 goto out;
162 }
163 sshbuf_reset(buf);
164
165#ifdef DEBUG_KEXECDH
166 fputs("public key:\n", stderr);
167 sshkey_dump_ec_point(group, dh_pub);
168#endif
169 if (sshkey_ec_validate_public(group, dh_pub) != 0) {
170 r = SSH_ERR_MESSAGE_INCOMPLETE;
171 goto out;
172 }
173 klen = (EC_GROUP_get_degree(group) + 7) / 8;
174 if ((kbuf = malloc(klen)) == NULL ||
175 (shared_secret = BN_new()) == NULL) {
176 r = SSH_ERR_ALLOC_FAIL;
177 goto out;
178 }
179 if (ECDH_compute_key(kbuf, klen, dh_pub, key, NULL) != (int)klen ||
180 BN_bin2bn(kbuf, klen, shared_secret) == NULL) {
181 r = SSH_ERR_LIBCRYPTO_ERROR;
182 goto out;
183 }
184#ifdef DEBUG_KEXECDH
185 dump_digest("shared secret", kbuf, klen);
186#endif
187 if ((r = sshbuf_put_bignum2(buf, shared_secret)) != 0)
188 goto out;
189 *shared_secretp = buf;
190 buf = NULL;
191 out:
192 EC_POINT_clear_free(dh_pub);
193 BN_clear_free(shared_secret);
194 freezero(kbuf, klen);
195 sshbuf_free(buf);
196 return r;
197}
198
199int
200kex_ecdh_dec(struct kex *kex, const struct sshbuf *server_blob,
201 struct sshbuf **shared_secretp)
202{
203 int r;
204
205 r = kex_ecdh_dec_key_group(kex, server_blob, kex->ec_client_key,
206 kex->ec_group, shared_secretp);
207 EC_KEY_free(kex->ec_client_key);
208 kex->ec_client_key = NULL;
209 return r;
99} 210}
100#endif /* defined(WITH_OPENSSL) && defined(OPENSSL_HAS_ECC) */ 211#endif /* defined(WITH_OPENSSL) && defined(OPENSSL_HAS_ECC) */