diff options
Diffstat (limited to 'kexc25519.c')
-rw-r--r-- | kexc25519.c | 182 |
1 files changed, 124 insertions, 58 deletions
diff --git a/kexc25519.c b/kexc25519.c index 0897b8c51..f13d766d7 100644 --- a/kexc25519.c +++ b/kexc25519.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* $OpenBSD: kexc25519.c,v 1.10 2016/05/02 08:49:03 djm Exp $ */ | 1 | /* $OpenBSD: kexc25519.c,v 1.17 2019/01/21 10:40:11 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2001, 2013 Markus Friedl. All rights reserved. | 3 | * Copyright (c) 2019 Markus Friedl. All rights reserved. |
4 | * Copyright (c) 2010 Damien Miller. All rights reserved. | 4 | * Copyright (c) 2010 Damien Miller. All rights reserved. |
5 | * Copyright (c) 2013 Aris Adamantiadis. All rights reserved. | 5 | * Copyright (c) 2013 Aris Adamantiadis. All rights reserved. |
6 | * | 6 | * |
@@ -29,20 +29,16 @@ | |||
29 | 29 | ||
30 | #include <sys/types.h> | 30 | #include <sys/types.h> |
31 | 31 | ||
32 | #include <signal.h> | 32 | #include <stdio.h> |
33 | #include <string.h> | 33 | #include <string.h> |
34 | #include <signal.h> | ||
34 | 35 | ||
35 | #include <openssl/bn.h> | ||
36 | #include <openssl/evp.h> | ||
37 | |||
38 | #include "sshbuf.h" | ||
39 | #include "ssh2.h" | ||
40 | #include "sshkey.h" | 36 | #include "sshkey.h" |
41 | #include "cipher.h" | ||
42 | #include "kex.h" | 37 | #include "kex.h" |
43 | #include "log.h" | 38 | #include "sshbuf.h" |
44 | #include "digest.h" | 39 | #include "digest.h" |
45 | #include "ssherr.h" | 40 | #include "ssherr.h" |
41 | #include "ssh2.h" | ||
46 | 42 | ||
47 | extern int crypto_scalarmult_curve25519(u_char a[CURVE25519_SIZE], | 43 | extern int crypto_scalarmult_curve25519(u_char a[CURVE25519_SIZE], |
48 | const u_char b[CURVE25519_SIZE], const u_char c[CURVE25519_SIZE]) | 44 | const u_char b[CURVE25519_SIZE], const u_char c[CURVE25519_SIZE]) |
@@ -60,74 +56,144 @@ kexc25519_keygen(u_char key[CURVE25519_SIZE], u_char pub[CURVE25519_SIZE]) | |||
60 | } | 56 | } |
61 | 57 | ||
62 | int | 58 | int |
63 | kexc25519_shared_key(const u_char key[CURVE25519_SIZE], | 59 | kexc25519_shared_key_ext(const u_char key[CURVE25519_SIZE], |
64 | const u_char pub[CURVE25519_SIZE], struct sshbuf *out) | 60 | const u_char pub[CURVE25519_SIZE], struct sshbuf *out, int raw) |
65 | { | 61 | { |
66 | u_char shared_key[CURVE25519_SIZE]; | 62 | u_char shared_key[CURVE25519_SIZE]; |
63 | u_char zero[CURVE25519_SIZE]; | ||
67 | int r; | 64 | int r; |
68 | 65 | ||
69 | /* Check for all-zero public key */ | 66 | crypto_scalarmult_curve25519(shared_key, key, pub); |
70 | explicit_bzero(shared_key, CURVE25519_SIZE); | 67 | |
71 | if (timingsafe_bcmp(pub, shared_key, CURVE25519_SIZE) == 0) | 68 | /* Check for all-zero shared secret */ |
69 | explicit_bzero(zero, CURVE25519_SIZE); | ||
70 | if (timingsafe_bcmp(zero, shared_key, CURVE25519_SIZE) == 0) | ||
72 | return SSH_ERR_KEY_INVALID_EC_VALUE; | 71 | return SSH_ERR_KEY_INVALID_EC_VALUE; |
73 | 72 | ||
74 | crypto_scalarmult_curve25519(shared_key, key, pub); | ||
75 | #ifdef DEBUG_KEXECDH | 73 | #ifdef DEBUG_KEXECDH |
76 | dump_digest("shared secret", shared_key, CURVE25519_SIZE); | 74 | dump_digest("shared secret", shared_key, CURVE25519_SIZE); |
77 | #endif | 75 | #endif |
78 | sshbuf_reset(out); | 76 | if (raw) |
79 | r = sshbuf_put_bignum2_bytes(out, shared_key, CURVE25519_SIZE); | 77 | r = sshbuf_put(out, shared_key, CURVE25519_SIZE); |
78 | else | ||
79 | r = sshbuf_put_bignum2_bytes(out, shared_key, CURVE25519_SIZE); | ||
80 | explicit_bzero(shared_key, CURVE25519_SIZE); | 80 | explicit_bzero(shared_key, CURVE25519_SIZE); |
81 | return r; | 81 | return r; |
82 | } | 82 | } |
83 | 83 | ||
84 | int | 84 | int |
85 | kex_c25519_hash( | 85 | kexc25519_shared_key(const u_char key[CURVE25519_SIZE], |
86 | int hash_alg, | 86 | const u_char pub[CURVE25519_SIZE], struct sshbuf *out) |
87 | const char *client_version_string, | 87 | { |
88 | const char *server_version_string, | 88 | return kexc25519_shared_key_ext(key, pub, out, 0); |
89 | const u_char *ckexinit, size_t ckexinitlen, | 89 | } |
90 | const u_char *skexinit, size_t skexinitlen, | 90 | |
91 | const u_char *serverhostkeyblob, size_t sbloblen, | 91 | int |
92 | const u_char client_dh_pub[CURVE25519_SIZE], | 92 | kex_c25519_keypair(struct kex *kex) |
93 | const u_char server_dh_pub[CURVE25519_SIZE], | ||
94 | const u_char *shared_secret, size_t secretlen, | ||
95 | u_char *hash, size_t *hashlen) | ||
96 | { | 93 | { |
97 | struct sshbuf *b; | 94 | struct sshbuf *buf = NULL; |
95 | u_char *cp = NULL; | ||
98 | int r; | 96 | int r; |
99 | 97 | ||
100 | if (*hashlen < ssh_digest_bytes(hash_alg)) | 98 | if ((buf = sshbuf_new()) == NULL) |
101 | return SSH_ERR_INVALID_ARGUMENT; | ||
102 | if ((b = sshbuf_new()) == NULL) | ||
103 | return SSH_ERR_ALLOC_FAIL; | 99 | return SSH_ERR_ALLOC_FAIL; |
104 | if ((r = sshbuf_put_cstring(b, client_version_string)) < 0 || | 100 | if ((r = sshbuf_reserve(buf, CURVE25519_SIZE, &cp)) != 0) |
105 | (r = sshbuf_put_cstring(b, server_version_string)) < 0 || | 101 | goto out; |
106 | /* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */ | 102 | kexc25519_keygen(kex->c25519_client_key, cp); |
107 | (r = sshbuf_put_u32(b, ckexinitlen+1)) < 0 || | 103 | #ifdef DEBUG_KEXECDH |
108 | (r = sshbuf_put_u8(b, SSH2_MSG_KEXINIT)) < 0 || | 104 | dump_digest("client public key c25519:", cp, CURVE25519_SIZE); |
109 | (r = sshbuf_put(b, ckexinit, ckexinitlen)) < 0 || | 105 | #endif |
110 | (r = sshbuf_put_u32(b, skexinitlen+1)) < 0 || | 106 | kex->client_pub = buf; |
111 | (r = sshbuf_put_u8(b, SSH2_MSG_KEXINIT)) < 0 || | 107 | buf = NULL; |
112 | (r = sshbuf_put(b, skexinit, skexinitlen)) < 0 || | 108 | out: |
113 | (r = sshbuf_put_string(b, serverhostkeyblob, sbloblen)) < 0 || | 109 | sshbuf_free(buf); |
114 | (r = sshbuf_put_string(b, client_dh_pub, CURVE25519_SIZE)) < 0 || | 110 | return r; |
115 | (r = sshbuf_put_string(b, server_dh_pub, CURVE25519_SIZE)) < 0 || | 111 | } |
116 | (r = sshbuf_put(b, shared_secret, secretlen)) < 0) { | 112 | |
117 | sshbuf_free(b); | 113 | int |
118 | return r; | 114 | kex_c25519_enc(struct kex *kex, const struct sshbuf *client_blob, |
115 | struct sshbuf **server_blobp, struct sshbuf **shared_secretp) | ||
116 | { | ||
117 | struct sshbuf *server_blob = NULL; | ||
118 | struct sshbuf *buf = NULL; | ||
119 | const u_char *client_pub; | ||
120 | u_char *server_pub; | ||
121 | u_char server_key[CURVE25519_SIZE]; | ||
122 | int r; | ||
123 | |||
124 | *server_blobp = NULL; | ||
125 | *shared_secretp = NULL; | ||
126 | |||
127 | if (sshbuf_len(client_blob) != CURVE25519_SIZE) { | ||
128 | r = SSH_ERR_SIGNATURE_INVALID; | ||
129 | goto out; | ||
119 | } | 130 | } |
120 | #ifdef DEBUG_KEX | 131 | client_pub = sshbuf_ptr(client_blob); |
121 | sshbuf_dump(b, stderr); | 132 | #ifdef DEBUG_KEXECDH |
133 | dump_digest("client public key 25519:", client_pub, CURVE25519_SIZE); | ||
122 | #endif | 134 | #endif |
123 | if (ssh_digest_buffer(hash_alg, b, hash, *hashlen) != 0) { | 135 | /* allocate space for encrypted KEM key and ECDH pub key */ |
124 | sshbuf_free(b); | 136 | if ((server_blob = sshbuf_new()) == NULL) { |
125 | return SSH_ERR_LIBCRYPTO_ERROR; | 137 | r = SSH_ERR_ALLOC_FAIL; |
138 | goto out; | ||
126 | } | 139 | } |
127 | sshbuf_free(b); | 140 | if ((r = sshbuf_reserve(server_blob, CURVE25519_SIZE, &server_pub)) != 0) |
128 | *hashlen = ssh_digest_bytes(hash_alg); | 141 | goto out; |
129 | #ifdef DEBUG_KEX | 142 | kexc25519_keygen(server_key, server_pub); |
130 | dump_digest("hash", hash, *hashlen); | 143 | /* allocate shared secret */ |
144 | if ((buf = sshbuf_new()) == NULL) { | ||
145 | r = SSH_ERR_ALLOC_FAIL; | ||
146 | goto out; | ||
147 | } | ||
148 | if ((r = kexc25519_shared_key_ext(server_key, client_pub, buf, 0)) < 0) | ||
149 | goto out; | ||
150 | #ifdef DEBUG_KEXECDH | ||
151 | dump_digest("server public key 25519:", server_pub, CURVE25519_SIZE); | ||
152 | dump_digest("encoded shared secret:", sshbuf_ptr(buf), sshbuf_len(buf)); | ||
131 | #endif | 153 | #endif |
132 | return 0; | 154 | *server_blobp = server_blob; |
155 | *shared_secretp = buf; | ||
156 | server_blob = NULL; | ||
157 | buf = NULL; | ||
158 | out: | ||
159 | explicit_bzero(server_key, sizeof(server_key)); | ||
160 | sshbuf_free(server_blob); | ||
161 | sshbuf_free(buf); | ||
162 | return r; | ||
163 | } | ||
164 | |||
165 | int | ||
166 | kex_c25519_dec(struct kex *kex, const struct sshbuf *server_blob, | ||
167 | struct sshbuf **shared_secretp) | ||
168 | { | ||
169 | struct sshbuf *buf = NULL; | ||
170 | const u_char *server_pub; | ||
171 | int r; | ||
172 | |||
173 | *shared_secretp = NULL; | ||
174 | |||
175 | if (sshbuf_len(server_blob) != CURVE25519_SIZE) { | ||
176 | r = SSH_ERR_SIGNATURE_INVALID; | ||
177 | goto out; | ||
178 | } | ||
179 | server_pub = sshbuf_ptr(server_blob); | ||
180 | #ifdef DEBUG_KEXECDH | ||
181 | dump_digest("server public key c25519:", server_pub, CURVE25519_SIZE); | ||
182 | #endif | ||
183 | /* shared secret */ | ||
184 | if ((buf = sshbuf_new()) == NULL) { | ||
185 | r = SSH_ERR_ALLOC_FAIL; | ||
186 | goto out; | ||
187 | } | ||
188 | if ((r = kexc25519_shared_key_ext(kex->c25519_client_key, server_pub, | ||
189 | buf, 0)) < 0) | ||
190 | goto out; | ||
191 | #ifdef DEBUG_KEXECDH | ||
192 | dump_digest("encoded shared secret:", sshbuf_ptr(buf), sshbuf_len(buf)); | ||
193 | #endif | ||
194 | *shared_secretp = buf; | ||
195 | buf = NULL; | ||
196 | out: | ||
197 | sshbuf_free(buf); | ||
198 | return r; | ||
133 | } | 199 | } |