summaryrefslogtreecommitdiff
path: root/kexecdh.c
diff options
context:
space:
mode:
authordjm@openbsd.org <djm@openbsd.org>2019-01-21 10:29:56 +0000
committerDamien Miller <djm@mindrot.org>2019-01-21 23:13:02 +1100
commit92dda34e373832f34a1944e5d9ebbebb184dedc1 (patch)
tree8aa632912cb292c095c6eaedc7056e8d5ecfa0ba /kexecdh.c
parentb72357217cbe510a3ae155307a7be6b9181f1d1b (diff)
upstream: use KEM API for vanilla ECDH
from markus@ ok djm@ OpenBSD-Commit-ID: 6fbff96339a929835536b5730585d1d6057a352c
Diffstat (limited to 'kexecdh.c')
-rw-r--r--kexecdh.c213
1 files changed, 163 insertions, 50 deletions
diff --git a/kexecdh.c b/kexecdh.c
index 4380427ea..263f9fd87 100644
--- a/kexecdh.c
+++ b/kexecdh.c
@@ -1,7 +1,7 @@
1/* $OpenBSD: kexecdh.c,v 1.7 2018/12/27 03:25:25 djm Exp $ */ 1/* $OpenBSD: kexecdh.c,v 1.8 2019/01/21 10:29:56 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,184 @@
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 u_char *, size_t, 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, 51{
52 const EC_GROUP *ec_group, 52 EC_KEY *client_key = NULL;
53 const struct sshbuf *client_version, 53 const EC_GROUP *group;
54 const struct sshbuf *server_version, 54 const EC_POINT *public_key;
55 const u_char *ckexinit, size_t ckexinitlen, 55 struct sshbuf *buf = NULL;
56 const u_char *skexinit, size_t skexinitlen, 56 int r;
57 const u_char *serverhostkeyblob, size_t sbloblen, 57
58 const EC_POINT *client_dh_pub, 58 if ((client_key = EC_KEY_new_by_curve_name(kex->ec_nid)) == NULL) {
59 const EC_POINT *server_dh_pub, 59 r = SSH_ERR_ALLOC_FAIL;
60 const BIGNUM *shared_secret, 60 goto out;
61 u_char *hash, size_t *hashlen) 61 }
62 if (EC_KEY_generate_key(client_key) != 1) {
63 r = SSH_ERR_LIBCRYPTO_ERROR;
64 goto out;
65 }
66 group = EC_KEY_get0_group(client_key);
67 public_key = EC_KEY_get0_public_key(client_key);
68
69 if ((buf = sshbuf_new()) == NULL) {
70 r = SSH_ERR_ALLOC_FAIL;
71 goto out;
72 }
73 if ((r = sshbuf_put_ec(buf, public_key, group)) != 0 ||
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);
79#endif
80 kex->ec_client_key = client_key;
81 kex->ec_group = group;
82 client_key = NULL; /* owned by the kex */
83 kex->kem_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 u_char *pkblob, size_t pklen,
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;
107 }
108 if (EC_KEY_generate_key(server_key) != 1) {
109 r = SSH_ERR_LIBCRYPTO_ERROR;
110 goto out;
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);
117#endif
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, pkblob, pklen, 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 u_char *pkblob, size_t pklen,
139 EC_KEY *key, const EC_GROUP *group, struct sshbuf **shared_secretp)
62{ 140{
63 struct sshbuf *b; 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;
64 int r; 146 int r;
65 147
66 if (*hashlen < ssh_digest_bytes(hash_alg)) 148 *shared_secretp = NULL;
67 return SSH_ERR_INVALID_ARGUMENT; 149
68 if ((b = sshbuf_new()) == NULL) 150 if ((buf = sshbuf_new()) == NULL) {
69 return SSH_ERR_ALLOC_FAIL; 151 r = SSH_ERR_ALLOC_FAIL;
70 if ((r = sshbuf_put_stringb(b, client_version)) < 0 || 152 goto out;
71 (r = sshbuf_put_stringb(b, server_version)) < 0 || 153 }
72 /* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */ 154 if ((r = sshbuf_put_u32(buf, pklen)) != 0 ||
73 (r = sshbuf_put_u32(b, ckexinitlen+1)) != 0 || 155 (r = sshbuf_put(buf, pkblob, pklen)) != 0) {
74 (r = sshbuf_put_u8(b, SSH2_MSG_KEXINIT)) != 0 || 156 goto out;
75 (r = sshbuf_put(b, ckexinit, ckexinitlen)) != 0 || 157 }
76 (r = sshbuf_put_u32(b, skexinitlen+1)) != 0 || 158 if ((dh_pub = EC_POINT_new(group)) == NULL) {
77 (r = sshbuf_put_u8(b, SSH2_MSG_KEXINIT)) != 0 || 159 r = SSH_ERR_ALLOC_FAIL;
78 (r = sshbuf_put(b, skexinit, skexinitlen)) != 0 || 160 goto out;
79 (r = sshbuf_put_string(b, serverhostkeyblob, sbloblen)) != 0 || 161 }
80 (r = sshbuf_put_ec(b, client_dh_pub, ec_group)) != 0 || 162 if ((r = sshbuf_get_ec(buf, dh_pub, group)) != 0) {
81 (r = sshbuf_put_ec(b, server_dh_pub, ec_group)) != 0 || 163 goto out;
82 (r = sshbuf_put_bignum2(b, shared_secret)) != 0) {
83 sshbuf_free(b);
84 return r;
85 } 164 }
86#ifdef DEBUG_KEX 165 sshbuf_reset(buf);
87 sshbuf_dump(b, stderr); 166
167#ifdef DEBUG_KEXECDH
168 fputs("public key:\n", stderr);
169 sshkey_dump_ec_point(group, dh_pub);
88#endif 170#endif
89 if (ssh_digest_buffer(hash_alg, b, hash, *hashlen) != 0) { 171 if (sshkey_ec_validate_public(group, dh_pub) != 0) {
90 sshbuf_free(b); 172 r = SSH_ERR_MESSAGE_INCOMPLETE;
91 return SSH_ERR_LIBCRYPTO_ERROR; 173 goto out;
174 }
175 klen = (EC_GROUP_get_degree(group) + 7) / 8;
176 if ((kbuf = malloc(klen)) == NULL ||
177 (shared_secret = BN_new()) == NULL) {
178 r = SSH_ERR_ALLOC_FAIL;
179 goto out;
180 }
181 if (ECDH_compute_key(kbuf, klen, dh_pub, key, NULL) != (int)klen ||
182 BN_bin2bn(kbuf, klen, shared_secret) == NULL) {
183 r = SSH_ERR_LIBCRYPTO_ERROR;
184 goto out;
92 } 185 }
93 sshbuf_free(b); 186#ifdef DEBUG_KEXECDH
94 *hashlen = ssh_digest_bytes(hash_alg); 187 dump_digest("shared secret", kbuf, klen);
95#ifdef DEBUG_KEX
96 dump_digest("hash", hash, *hashlen);
97#endif 188#endif
98 return 0; 189 if ((r = sshbuf_put_bignum2(buf, shared_secret)) != 0)
190 goto out;
191 *shared_secretp = buf;
192 buf = NULL;
193 out:
194 EC_POINT_clear_free(dh_pub);
195 BN_clear_free(shared_secret);
196 freezero(kbuf, klen);
197 sshbuf_free(buf);
198 return r;
199}
200
201int
202kex_ecdh_dec(struct kex *kex, const u_char *pkblob, size_t pklen,
203 struct sshbuf **shared_secretp)
204{
205 int r;
206
207 r = kex_ecdh_dec_key_group(kex, pkblob, pklen, kex->ec_client_key,
208 kex->ec_group, shared_secretp);
209 EC_KEY_free(kex->ec_client_key);
210 kex->ec_client_key = NULL;
211 return r;
99} 212}
100#endif /* defined(WITH_OPENSSL) && defined(OPENSSL_HAS_ECC) */ 213#endif /* defined(WITH_OPENSSL) && defined(OPENSSL_HAS_ECC) */