summaryrefslogtreecommitdiff
path: root/kexdh.c
diff options
context:
space:
mode:
Diffstat (limited to 'kexdh.c')
-rw-r--r--kexdh.c213
1 files changed, 164 insertions, 49 deletions
diff --git a/kexdh.c b/kexdh.c
index e6925b186..edaa46762 100644
--- a/kexdh.c
+++ b/kexdh.c
@@ -1,6 +1,6 @@
1/* $OpenBSD: kexdh.c,v 1.26 2016/05/02 10:26:04 djm Exp $ */ 1/* $OpenBSD: kexdh.c,v 1.32 2019/01/21 10:40:11 djm Exp $ */
2/* 2/*
3 * Copyright (c) 2001 Markus Friedl. All rights reserved. 3 * Copyright (c) 2019 Markus Friedl. All rights reserved.
4 * 4 *
5 * Redistribution and use in source and binary forms, with or without 5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions 6 * modification, are permitted provided that the following conditions
@@ -30,67 +30,182 @@
30#include <sys/types.h> 30#include <sys/types.h>
31 31
32#include <signal.h> 32#include <signal.h>
33 33#include <stdio.h>
34#include <openssl/evp.h> 34#include <string.h>
35 35
36#include "openbsd-compat/openssl-compat.h" 36#include "openbsd-compat/openssl-compat.h"
37#include <openssl/dh.h>
37 38
38#include "ssh2.h"
39#include "sshkey.h" 39#include "sshkey.h"
40#include "cipher.h"
41#include "kex.h" 40#include "kex.h"
42#include "ssherr.h"
43#include "sshbuf.h" 41#include "sshbuf.h"
44#include "digest.h" 42#include "digest.h"
43#include "ssherr.h"
44#include "dh.h"
45 45
46int 46int
47kex_dh_hash( 47kex_dh_keygen(struct kex *kex)
48 int hash_alg,
49 const char *client_version_string,
50 const char *server_version_string,
51 const u_char *ckexinit, size_t ckexinitlen,
52 const u_char *skexinit, size_t skexinitlen,
53 const u_char *serverhostkeyblob, size_t sbloblen,
54 const BIGNUM *client_dh_pub,
55 const BIGNUM *server_dh_pub,
56 const BIGNUM *shared_secret,
57 u_char *hash, size_t *hashlen)
58{ 48{
59 struct sshbuf *b; 49 switch (kex->kex_type) {
60 int r; 50 case KEX_DH_GRP1_SHA1:
61 51#ifdef GSSAPI
62 if (*hashlen < ssh_digest_bytes(hash_alg)) 52 case KEX_GSS_GRP1_SHA1:
53#endif
54 kex->dh = dh_new_group1();
55 break;
56 case KEX_DH_GRP14_SHA1:
57 case KEX_DH_GRP14_SHA256:
58#ifdef GSSAPI
59 case KEX_GSS_GRP14_SHA1:
60 case KEX_GSS_GRP14_SHA256:
61#endif
62 kex->dh = dh_new_group14();
63 break;
64 case KEX_DH_GRP16_SHA512:
65#ifdef GSSAPI
66 case KEX_GSS_GRP16_SHA512:
67#endif
68 kex->dh = dh_new_group16();
69 break;
70 case KEX_DH_GRP18_SHA512:
71 kex->dh = dh_new_group18();
72 break;
73 default:
63 return SSH_ERR_INVALID_ARGUMENT; 74 return SSH_ERR_INVALID_ARGUMENT;
64 if ((b = sshbuf_new()) == NULL)
65 return SSH_ERR_ALLOC_FAIL;
66 if ((r = sshbuf_put_cstring(b, client_version_string)) != 0 ||
67 (r = sshbuf_put_cstring(b, server_version_string)) != 0 ||
68 /* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */
69 (r = sshbuf_put_u32(b, ckexinitlen+1)) != 0 ||
70 (r = sshbuf_put_u8(b, SSH2_MSG_KEXINIT)) != 0 ||
71 (r = sshbuf_put(b, ckexinit, ckexinitlen)) != 0 ||
72 (r = sshbuf_put_u32(b, skexinitlen+1)) != 0 ||
73 (r = sshbuf_put_u8(b, SSH2_MSG_KEXINIT)) != 0 ||
74 (r = sshbuf_put(b, skexinit, skexinitlen)) != 0 ||
75 (r = sshbuf_put_string(b, serverhostkeyblob, sbloblen)) != 0 ||
76 (r = sshbuf_put_bignum2(b, client_dh_pub)) != 0 ||
77 (r = sshbuf_put_bignum2(b, server_dh_pub)) != 0 ||
78 (r = sshbuf_put_bignum2(b, shared_secret)) != 0) {
79 sshbuf_free(b);
80 return r;
81 } 75 }
82#ifdef DEBUG_KEX 76 if (kex->dh == NULL)
83 sshbuf_dump(b, stderr); 77 return SSH_ERR_ALLOC_FAIL;
78 return (dh_gen_key(kex->dh, kex->we_need * 8));
79}
80
81int
82kex_dh_compute_key(struct kex *kex, BIGNUM *dh_pub, struct sshbuf *out)
83{
84 BIGNUM *shared_secret = NULL;
85 u_char *kbuf = NULL;
86 size_t klen = 0;
87 int kout, r;
88
89#ifdef DEBUG_KEXDH
90 fprintf(stderr, "dh_pub= ");
91 BN_print_fp(stderr, dh_pub);
92 fprintf(stderr, "\n");
93 debug("bits %d", BN_num_bits(dh_pub));
94 DHparams_print_fp(stderr, kex->dh);
95 fprintf(stderr, "\n");
84#endif 96#endif
85 if (ssh_digest_buffer(hash_alg, b, hash, *hashlen) != 0) { 97
86 sshbuf_free(b); 98 if (!dh_pub_is_valid(kex->dh, dh_pub)) {
87 return SSH_ERR_LIBCRYPTO_ERROR; 99 r = SSH_ERR_MESSAGE_INCOMPLETE;
100 goto out;
88 } 101 }
89 sshbuf_free(b); 102 klen = DH_size(kex->dh);
90 *hashlen = ssh_digest_bytes(hash_alg); 103 if ((kbuf = malloc(klen)) == NULL ||
91#ifdef DEBUG_KEX 104 (shared_secret = BN_new()) == NULL) {
92 dump_digest("hash", hash, *hashlen); 105 r = SSH_ERR_ALLOC_FAIL;
106 goto out;
107 }
108 if ((kout = DH_compute_key(kbuf, dh_pub, kex->dh)) < 0 ||
109 BN_bin2bn(kbuf, kout, shared_secret) == NULL) {
110 r = SSH_ERR_LIBCRYPTO_ERROR;
111 goto out;
112 }
113#ifdef DEBUG_KEXDH
114 dump_digest("shared secret", kbuf, kout);
115#endif
116 r = sshbuf_put_bignum2(out, shared_secret);
117 out:
118 freezero(kbuf, klen);
119 BN_clear_free(shared_secret);
120 return r;
121}
122
123int
124kex_dh_keypair(struct kex *kex)
125{
126 const BIGNUM *pub_key;
127 struct sshbuf *buf = NULL;
128 int r;
129
130 if ((r = kex_dh_keygen(kex)) != 0)
131 return r;
132 DH_get0_key(kex->dh, &pub_key, NULL);
133 if ((buf = sshbuf_new()) == NULL)
134 return SSH_ERR_ALLOC_FAIL;
135 if ((r = sshbuf_put_bignum2(buf, pub_key)) != 0 ||
136 (r = sshbuf_get_u32(buf, NULL)) != 0)
137 goto out;
138#ifdef DEBUG_KEXDH
139 DHparams_print_fp(stderr, kex->dh);
140 fprintf(stderr, "pub= ");
141 BN_print_fp(stderr, pub_key);
142 fprintf(stderr, "\n");
93#endif 143#endif
94 return 0; 144 kex->client_pub = buf;
145 buf = NULL;
146 out:
147 sshbuf_free(buf);
148 return r;
149}
150
151int
152kex_dh_enc(struct kex *kex, const struct sshbuf *client_blob,
153 struct sshbuf **server_blobp, struct sshbuf **shared_secretp)
154{
155 const BIGNUM *pub_key;
156 struct sshbuf *server_blob = NULL;
157 int r;
158
159 *server_blobp = NULL;
160 *shared_secretp = NULL;
161
162 if ((r = kex_dh_keygen(kex)) != 0)
163 goto out;
164 DH_get0_key(kex->dh, &pub_key, NULL);
165 if ((server_blob = sshbuf_new()) == NULL) {
166 r = SSH_ERR_ALLOC_FAIL;
167 goto out;
168 }
169 if ((r = sshbuf_put_bignum2(server_blob, pub_key)) != 0 ||
170 (r = sshbuf_get_u32(server_blob, NULL)) != 0)
171 goto out;
172 if ((r = kex_dh_dec(kex, client_blob, shared_secretp)) != 0)
173 goto out;
174 *server_blobp = server_blob;
175 server_blob = NULL;
176 out:
177 DH_free(kex->dh);
178 kex->dh = NULL;
179 sshbuf_free(server_blob);
180 return r;
181}
182
183int
184kex_dh_dec(struct kex *kex, const struct sshbuf *dh_blob,
185 struct sshbuf **shared_secretp)
186{
187 struct sshbuf *buf = NULL;
188 BIGNUM *dh_pub = NULL;
189 int r;
190
191 *shared_secretp = NULL;
192
193 if ((buf = sshbuf_new()) == NULL) {
194 r = SSH_ERR_ALLOC_FAIL;
195 goto out;
196 }
197 if ((r = sshbuf_put_stringb(buf, dh_blob)) != 0 ||
198 (r = sshbuf_get_bignum2(buf, &dh_pub)) != 0)
199 goto out;
200 sshbuf_reset(buf);
201 if ((r = kex_dh_compute_key(kex, dh_pub, buf)) != 0)
202 goto out;
203 *shared_secretp = buf;
204 buf = NULL;
205 out:
206 DH_free(kex->dh);
207 kex->dh = NULL;
208 sshbuf_free(buf);
209 return r;
95} 210}
96#endif /* WITH_OPENSSL */ 211#endif /* WITH_OPENSSL */