summaryrefslogtreecommitdiff
path: root/kexdhc.c
diff options
context:
space:
mode:
Diffstat (limited to 'kexdhc.c')
-rw-r--r--kexdhc.c199
1 files changed, 125 insertions, 74 deletions
diff --git a/kexdhc.c b/kexdhc.c
index f7a19fc13..af259f16a 100644
--- a/kexdhc.c
+++ b/kexdhc.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: kexdhc.c,v 1.15 2014/02/02 03:44:31 djm Exp $ */ 1/* $OpenBSD: kexdhc.c,v 1.18 2015/01/26 06:10:03 djm Exp $ */
2/* 2/*
3 * Copyright (c) 2001 Markus Friedl. All rights reserved. 3 * Copyright (c) 2001 Markus Friedl. All rights reserved.
4 * 4 *
@@ -25,6 +25,8 @@
25 25
26#include "includes.h" 26#include "includes.h"
27 27
28#ifdef WITH_OPENSSL
29
28#include <sys/types.h> 30#include <sys/types.h>
29 31
30#include <openssl/dh.h> 32#include <openssl/dh.h>
@@ -34,128 +36,177 @@
34#include <string.h> 36#include <string.h>
35#include <signal.h> 37#include <signal.h>
36 38
37#include "xmalloc.h" 39#include "sshkey.h"
38#include "buffer.h"
39#include "key.h"
40#include "cipher.h" 40#include "cipher.h"
41#include "digest.h"
41#include "kex.h" 42#include "kex.h"
42#include "log.h" 43#include "log.h"
43#include "packet.h" 44#include "packet.h"
44#include "dh.h" 45#include "dh.h"
45#include "ssh2.h" 46#include "ssh2.h"
47#include "dispatch.h"
48#include "compat.h"
49#include "ssherr.h"
50#include "sshbuf.h"
51
52static int input_kex_dh(int, u_int32_t, void *);
46 53
47void 54int
48kexdh_client(Kex *kex) 55kexdh_client(struct ssh *ssh)
49{ 56{
50 BIGNUM *dh_server_pub = NULL, *shared_secret = NULL; 57 struct kex *kex = ssh->kex;
51 DH *dh; 58 int r;
52 Key *server_host_key;
53 u_char *server_host_key_blob = NULL, *signature = NULL;
54 u_char *kbuf, *hash;
55 u_int klen, slen, sbloblen, hashlen;
56 int kout;
57 59
58 /* generate and send 'e', client DH public key */ 60 /* generate and send 'e', client DH public key */
59 switch (kex->kex_type) { 61 switch (kex->kex_type) {
60 case KEX_DH_GRP1_SHA1: 62 case KEX_DH_GRP1_SHA1:
61 dh = dh_new_group1(); 63 kex->dh = dh_new_group1();
62 break; 64 break;
63 case KEX_DH_GRP14_SHA1: 65 case KEX_DH_GRP14_SHA1:
64 dh = dh_new_group14(); 66 kex->dh = dh_new_group14();
65 break; 67 break;
66 default: 68 default:
67 fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type); 69 r = SSH_ERR_INVALID_ARGUMENT;
70 goto out;
71 }
72 if (kex->dh == NULL) {
73 r = SSH_ERR_ALLOC_FAIL;
74 goto out;
68 } 75 }
69 dh_gen_key(dh, kex->we_need * 8);
70 packet_start(SSH2_MSG_KEXDH_INIT);
71 packet_put_bignum2(dh->pub_key);
72 packet_send();
73
74 debug("sending SSH2_MSG_KEXDH_INIT"); 76 debug("sending SSH2_MSG_KEXDH_INIT");
77 if ((r = dh_gen_key(kex->dh, kex->we_need * 8)) != 0 ||
78 (r = sshpkt_start(ssh, SSH2_MSG_KEXDH_INIT)) != 0 ||
79 (r = sshpkt_put_bignum2(ssh, kex->dh->pub_key)) != 0 ||
80 (r = sshpkt_send(ssh)) != 0)
81 goto out;
75#ifdef DEBUG_KEXDH 82#ifdef DEBUG_KEXDH
76 DHparams_print_fp(stderr, dh); 83 DHparams_print_fp(stderr, kex->dh);
77 fprintf(stderr, "pub= "); 84 fprintf(stderr, "pub= ");
78 BN_print_fp(stderr, dh->pub_key); 85 BN_print_fp(stderr, kex->dh->pub_key);
79 fprintf(stderr, "\n"); 86 fprintf(stderr, "\n");
80#endif 87#endif
81
82 debug("expecting SSH2_MSG_KEXDH_REPLY"); 88 debug("expecting SSH2_MSG_KEXDH_REPLY");
83 packet_read_expect(SSH2_MSG_KEXDH_REPLY); 89 ssh_dispatch_set(ssh, SSH2_MSG_KEXDH_REPLY, &input_kex_dh);
90 r = 0;
91 out:
92 return r;
93}
84 94
95static int
96input_kex_dh(int type, u_int32_t seq, void *ctxt)
97{
98 struct ssh *ssh = ctxt;
99 struct kex *kex = ssh->kex;
100 BIGNUM *dh_server_pub = NULL, *shared_secret = NULL;
101 struct sshkey *server_host_key = NULL;
102 u_char *kbuf = NULL, *server_host_key_blob = NULL, *signature = NULL;
103 u_char hash[SSH_DIGEST_MAX_LENGTH];
104 size_t klen = 0, slen, sbloblen, hashlen;
105 int kout, r;
106
107 if (kex->verify_host_key == NULL) {
108 r = SSH_ERR_INVALID_ARGUMENT;
109 goto out;
110 }
85 /* key, cert */ 111 /* key, cert */
86 server_host_key_blob = packet_get_string(&sbloblen); 112 if ((r = sshpkt_get_string(ssh, &server_host_key_blob,
87 server_host_key = key_from_blob(server_host_key_blob, sbloblen); 113 &sbloblen)) != 0 ||
88 if (server_host_key == NULL) 114 (r = sshkey_from_blob(server_host_key_blob, sbloblen,
89 fatal("cannot decode server_host_key_blob"); 115 &server_host_key)) != 0)
90 if (server_host_key->type != kex->hostkey_type) 116 goto out;
91 fatal("type mismatch for decoded server_host_key_blob"); 117 if (server_host_key->type != kex->hostkey_type ||
92 if (kex->verify_host_key == NULL) 118 (kex->hostkey_type == KEY_ECDSA &&
93 fatal("cannot verify server_host_key"); 119 server_host_key->ecdsa_nid != kex->hostkey_nid)) {
94 if (kex->verify_host_key(server_host_key) == -1) 120 r = SSH_ERR_KEY_TYPE_MISMATCH;
95 fatal("server_host_key verification failed"); 121 goto out;
96 122 }
123 if (kex->verify_host_key(server_host_key, ssh) == -1) {
124 r = SSH_ERR_SIGNATURE_INVALID;
125 goto out;
126 }
97 /* DH parameter f, server public DH key */ 127 /* DH parameter f, server public DH key */
98 if ((dh_server_pub = BN_new()) == NULL) 128 if ((dh_server_pub = BN_new()) == NULL) {
99 fatal("dh_server_pub == NULL"); 129 r = SSH_ERR_ALLOC_FAIL;
100 packet_get_bignum2(dh_server_pub); 130 goto out;
101 131 }
132 /* signed H */
133 if ((r = sshpkt_get_bignum2(ssh, dh_server_pub)) != 0 ||
134 (r = sshpkt_get_string(ssh, &signature, &slen)) != 0 ||
135 (r = sshpkt_get_end(ssh)) != 0)
136 goto out;
102#ifdef DEBUG_KEXDH 137#ifdef DEBUG_KEXDH
103 fprintf(stderr, "dh_server_pub= "); 138 fprintf(stderr, "dh_server_pub= ");
104 BN_print_fp(stderr, dh_server_pub); 139 BN_print_fp(stderr, dh_server_pub);
105 fprintf(stderr, "\n"); 140 fprintf(stderr, "\n");
106 debug("bits %d", BN_num_bits(dh_server_pub)); 141 debug("bits %d", BN_num_bits(dh_server_pub));
107#endif 142#endif
143 if (!dh_pub_is_valid(kex->dh, dh_server_pub)) {
144 sshpkt_disconnect(ssh, "bad server public DH value");
145 r = SSH_ERR_MESSAGE_INCOMPLETE;
146 goto out;
147 }
108 148
109 /* signed H */ 149 klen = DH_size(kex->dh);
110 signature = packet_get_string(&slen); 150 if ((kbuf = malloc(klen)) == NULL ||
111 packet_check_eom(); 151 (shared_secret = BN_new()) == NULL) {
112 152 r = SSH_ERR_ALLOC_FAIL;
113 if (!dh_pub_is_valid(dh, dh_server_pub)) 153 goto out;
114 packet_disconnect("bad server public DH value"); 154 }
115 155 if ((kout = DH_compute_key(kbuf, dh_server_pub, kex->dh)) < 0 ||
116 klen = DH_size(dh); 156 BN_bin2bn(kbuf, kout, shared_secret) == NULL) {
117 kbuf = xmalloc(klen); 157 r = SSH_ERR_LIBCRYPTO_ERROR;
118 if ((kout = DH_compute_key(kbuf, dh_server_pub, dh)) < 0) 158 goto out;
119 fatal("DH_compute_key: failed"); 159 }
120#ifdef DEBUG_KEXDH 160#ifdef DEBUG_KEXDH
121 dump_digest("shared secret", kbuf, kout); 161 dump_digest("shared secret", kbuf, kout);
122#endif 162#endif
123 if ((shared_secret = BN_new()) == NULL)
124 fatal("kexdh_client: BN_new failed");
125 if (BN_bin2bn(kbuf, kout, shared_secret) == NULL)
126 fatal("kexdh_client: BN_bin2bn failed");
127 explicit_bzero(kbuf, klen);
128 free(kbuf);
129 163
130 /* calc and verify H */ 164 /* calc and verify H */
131 kex_dh_hash( 165 hashlen = sizeof(hash);
166 if ((r = kex_dh_hash(
132 kex->client_version_string, 167 kex->client_version_string,
133 kex->server_version_string, 168 kex->server_version_string,
134 buffer_ptr(&kex->my), buffer_len(&kex->my), 169 sshbuf_ptr(kex->my), sshbuf_len(kex->my),
135 buffer_ptr(&kex->peer), buffer_len(&kex->peer), 170 sshbuf_ptr(kex->peer), sshbuf_len(kex->peer),
136 server_host_key_blob, sbloblen, 171 server_host_key_blob, sbloblen,
137 dh->pub_key, 172 kex->dh->pub_key,
138 dh_server_pub, 173 dh_server_pub,
139 shared_secret, 174 shared_secret,
140 &hash, &hashlen 175 hash, &hashlen)) != 0)
141 ); 176 goto out;
142 free(server_host_key_blob);
143 BN_clear_free(dh_server_pub);
144 DH_free(dh);
145 177
146 if (key_verify(server_host_key, signature, slen, hash, hashlen) != 1) 178 if ((r = sshkey_verify(server_host_key, signature, slen, hash, hashlen,
147 fatal("key_verify failed for server_host_key"); 179 ssh->compat)) != 0)
148 key_free(server_host_key); 180 goto out;
149 free(signature);
150 181
151 /* save session id */ 182 /* save session id */
152 if (kex->session_id == NULL) { 183 if (kex->session_id == NULL) {
153 kex->session_id_len = hashlen; 184 kex->session_id_len = hashlen;
154 kex->session_id = xmalloc(kex->session_id_len); 185 kex->session_id = malloc(kex->session_id_len);
186 if (kex->session_id == NULL) {
187 r = SSH_ERR_ALLOC_FAIL;
188 goto out;
189 }
155 memcpy(kex->session_id, hash, kex->session_id_len); 190 memcpy(kex->session_id, hash, kex->session_id_len);
156 } 191 }
157 192
158 kex_derive_keys_bn(kex, hash, hashlen, shared_secret); 193 if ((r = kex_derive_keys_bn(ssh, hash, hashlen, shared_secret)) == 0)
159 BN_clear_free(shared_secret); 194 r = kex_send_newkeys(ssh);
160 kex_finish(kex); 195 out:
196 explicit_bzero(hash, sizeof(hash));
197 DH_free(kex->dh);
198 kex->dh = NULL;
199 if (dh_server_pub)
200 BN_clear_free(dh_server_pub);
201 if (kbuf) {
202 explicit_bzero(kbuf, klen);
203 free(kbuf);
204 }
205 if (shared_secret)
206 BN_clear_free(shared_secret);
207 sshkey_free(server_host_key);
208 free(server_host_key_blob);
209 free(signature);
210 return r;
161} 211}
212#endif /* WITH_OPENSSL */