1 |
|
|
/* $OpenBSD: cipher.c,v 1.108 2017/11/03 02:22:41 djm Exp $ */ |
2 |
|
|
/* |
3 |
|
|
* Author: Tatu Ylonen <ylo@cs.hut.fi> |
4 |
|
|
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
5 |
|
|
* All rights reserved |
6 |
|
|
* |
7 |
|
|
* As far as I am concerned, the code I have written for this software |
8 |
|
|
* can be used freely for any purpose. Any derived versions of this |
9 |
|
|
* software must be clearly marked as such, and if the derived work is |
10 |
|
|
* incompatible with the protocol description in the RFC file, it must be |
11 |
|
|
* called by a name other than "ssh" or "Secure Shell". |
12 |
|
|
* |
13 |
|
|
* |
14 |
|
|
* Copyright (c) 1999 Niels Provos. All rights reserved. |
15 |
|
|
* Copyright (c) 1999, 2000 Markus Friedl. All rights reserved. |
16 |
|
|
* |
17 |
|
|
* Redistribution and use in source and binary forms, with or without |
18 |
|
|
* modification, are permitted provided that the following conditions |
19 |
|
|
* are met: |
20 |
|
|
* 1. Redistributions of source code must retain the above copyright |
21 |
|
|
* notice, this list of conditions and the following disclaimer. |
22 |
|
|
* 2. Redistributions in binary form must reproduce the above copyright |
23 |
|
|
* notice, this list of conditions and the following disclaimer in the |
24 |
|
|
* documentation and/or other materials provided with the distribution. |
25 |
|
|
* |
26 |
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
27 |
|
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
28 |
|
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
29 |
|
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
30 |
|
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
31 |
|
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
32 |
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
33 |
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
34 |
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
35 |
|
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
36 |
|
|
*/ |
37 |
|
|
|
38 |
|
|
#include <sys/types.h> |
39 |
|
|
|
40 |
|
|
#include <string.h> |
41 |
|
|
#include <stdarg.h> |
42 |
|
|
#include <stdio.h> |
43 |
|
|
|
44 |
|
|
#include "cipher.h" |
45 |
|
|
#include "misc.h" |
46 |
|
|
#include "sshbuf.h" |
47 |
|
|
#include "ssherr.h" |
48 |
|
|
#include "digest.h" |
49 |
|
|
|
50 |
|
|
|
51 |
|
|
struct sshcipher_ctx { |
52 |
|
|
int plaintext; |
53 |
|
|
int encrypt; |
54 |
|
|
EVP_CIPHER_CTX *evp; |
55 |
|
|
struct chachapoly_ctx cp_ctx; /* XXX union with evp? */ |
56 |
|
|
struct aesctr_ctx ac_ctx; /* XXX union with evp? */ |
57 |
|
|
const struct sshcipher *cipher; |
58 |
|
|
}; |
59 |
|
|
|
60 |
|
|
struct sshcipher { |
61 |
|
|
char *name; |
62 |
|
|
u_int block_size; |
63 |
|
|
u_int key_len; |
64 |
|
|
u_int iv_len; /* defaults to block_size */ |
65 |
|
|
u_int auth_len; |
66 |
|
|
u_int flags; |
67 |
|
|
#define CFLAG_CBC (1<<0) |
68 |
|
|
#define CFLAG_CHACHAPOLY (1<<1) |
69 |
|
|
#define CFLAG_AESCTR (1<<2) |
70 |
|
|
#define CFLAG_NONE (1<<3) |
71 |
|
|
#define CFLAG_INTERNAL CFLAG_NONE /* Don't use "none" for packets */ |
72 |
|
|
#ifdef WITH_OPENSSL |
73 |
|
|
const EVP_CIPHER *(*evptype)(void); |
74 |
|
|
#else |
75 |
|
|
void *ignored; |
76 |
|
|
#endif |
77 |
|
|
}; |
78 |
|
|
|
79 |
|
|
static const struct sshcipher ciphers[] = { |
80 |
|
|
#ifdef WITH_OPENSSL |
81 |
|
|
{ "3des-cbc", 8, 24, 0, 0, CFLAG_CBC, EVP_des_ede3_cbc }, |
82 |
|
|
{ "aes128-cbc", 16, 16, 0, 0, CFLAG_CBC, EVP_aes_128_cbc }, |
83 |
|
|
{ "aes192-cbc", 16, 24, 0, 0, CFLAG_CBC, EVP_aes_192_cbc }, |
84 |
|
|
{ "aes256-cbc", 16, 32, 0, 0, CFLAG_CBC, EVP_aes_256_cbc }, |
85 |
|
|
{ "rijndael-cbc@lysator.liu.se", |
86 |
|
|
16, 32, 0, 0, CFLAG_CBC, EVP_aes_256_cbc }, |
87 |
|
|
{ "aes128-ctr", 16, 16, 0, 0, 0, EVP_aes_128_ctr }, |
88 |
|
|
{ "aes192-ctr", 16, 24, 0, 0, 0, EVP_aes_192_ctr }, |
89 |
|
|
{ "aes256-ctr", 16, 32, 0, 0, 0, EVP_aes_256_ctr }, |
90 |
|
|
{ "aes128-gcm@openssh.com", |
91 |
|
|
16, 16, 12, 16, 0, EVP_aes_128_gcm }, |
92 |
|
|
{ "aes256-gcm@openssh.com", |
93 |
|
|
16, 32, 12, 16, 0, EVP_aes_256_gcm }, |
94 |
|
|
#else |
95 |
|
|
{ "aes128-ctr", 16, 16, 0, 0, CFLAG_AESCTR, NULL }, |
96 |
|
|
{ "aes192-ctr", 16, 24, 0, 0, CFLAG_AESCTR, NULL }, |
97 |
|
|
{ "aes256-ctr", 16, 32, 0, 0, CFLAG_AESCTR, NULL }, |
98 |
|
|
#endif |
99 |
|
|
{ "chacha20-poly1305@openssh.com", |
100 |
|
|
8, 64, 0, 16, CFLAG_CHACHAPOLY, NULL }, |
101 |
|
|
{ "none", 8, 0, 0, 0, CFLAG_NONE, NULL }, |
102 |
|
|
|
103 |
|
|
{ NULL, 0, 0, 0, 0, 0, NULL } |
104 |
|
|
}; |
105 |
|
|
|
106 |
|
|
/*--*/ |
107 |
|
|
|
108 |
|
|
/* Returns a comma-separated list of supported ciphers. */ |
109 |
|
|
char * |
110 |
|
|
cipher_alg_list(char sep, int auth_only) |
111 |
|
|
{ |
112 |
|
|
char *tmp, *ret = NULL; |
113 |
|
|
size_t nlen, rlen = 0; |
114 |
|
|
const struct sshcipher *c; |
115 |
|
|
|
116 |
|
|
for (c = ciphers; c->name != NULL; c++) { |
117 |
|
|
if ((c->flags & CFLAG_INTERNAL) != 0) |
118 |
|
|
continue; |
119 |
|
|
if (auth_only && c->auth_len == 0) |
120 |
|
|
continue; |
121 |
|
|
if (ret != NULL) |
122 |
|
|
ret[rlen++] = sep; |
123 |
|
|
nlen = strlen(c->name); |
124 |
|
|
if ((tmp = realloc(ret, rlen + nlen + 2)) == NULL) { |
125 |
|
|
free(ret); |
126 |
|
|
return NULL; |
127 |
|
|
} |
128 |
|
|
ret = tmp; |
129 |
|
|
memcpy(ret + rlen, c->name, nlen + 1); |
130 |
|
|
rlen += nlen; |
131 |
|
|
} |
132 |
|
|
return ret; |
133 |
|
|
} |
134 |
|
|
|
135 |
|
|
u_int |
136 |
|
|
cipher_blocksize(const struct sshcipher *c) |
137 |
|
|
{ |
138 |
|
|
return (c->block_size); |
139 |
|
|
} |
140 |
|
|
|
141 |
|
|
u_int |
142 |
|
|
cipher_keylen(const struct sshcipher *c) |
143 |
|
|
{ |
144 |
|
|
return (c->key_len); |
145 |
|
|
} |
146 |
|
|
|
147 |
|
|
u_int |
148 |
|
|
cipher_seclen(const struct sshcipher *c) |
149 |
|
|
{ |
150 |
|
|
if (strcmp("3des-cbc", c->name) == 0) |
151 |
|
|
return 14; |
152 |
|
|
return cipher_keylen(c); |
153 |
|
|
} |
154 |
|
|
|
155 |
|
|
u_int |
156 |
|
|
cipher_authlen(const struct sshcipher *c) |
157 |
|
|
{ |
158 |
|
|
return (c->auth_len); |
159 |
|
|
} |
160 |
|
|
|
161 |
|
|
u_int |
162 |
|
|
cipher_ivlen(const struct sshcipher *c) |
163 |
|
|
{ |
164 |
|
|
/* |
165 |
|
|
* Default is cipher block size, except for chacha20+poly1305 that |
166 |
|
|
* needs no IV. XXX make iv_len == -1 default? |
167 |
|
|
*/ |
168 |
|
|
return (c->iv_len != 0 || (c->flags & CFLAG_CHACHAPOLY) != 0) ? |
169 |
|
|
c->iv_len : c->block_size; |
170 |
|
|
} |
171 |
|
|
|
172 |
|
|
u_int |
173 |
|
|
cipher_is_cbc(const struct sshcipher *c) |
174 |
|
|
{ |
175 |
|
|
return (c->flags & CFLAG_CBC) != 0; |
176 |
|
|
} |
177 |
|
|
|
178 |
|
|
u_int |
179 |
|
|
cipher_ctx_is_plaintext(struct sshcipher_ctx *cc) |
180 |
|
|
{ |
181 |
|
|
return cc->plaintext; |
182 |
|
|
} |
183 |
|
|
|
184 |
|
|
const struct sshcipher * |
185 |
|
|
cipher_by_name(const char *name) |
186 |
|
|
{ |
187 |
|
|
const struct sshcipher *c; |
188 |
|
|
for (c = ciphers; c->name != NULL; c++) |
189 |
|
|
if (strcmp(c->name, name) == 0) |
190 |
|
|
return c; |
191 |
|
|
return NULL; |
192 |
|
|
} |
193 |
|
|
|
194 |
|
|
#define CIPHER_SEP "," |
195 |
|
|
int |
196 |
|
|
ciphers_valid(const char *names) |
197 |
|
|
{ |
198 |
|
|
const struct sshcipher *c; |
199 |
|
|
char *cipher_list, *cp; |
200 |
|
|
char *p; |
201 |
|
|
|
202 |
|
|
if (names == NULL || strcmp(names, "") == 0) |
203 |
|
|
return 0; |
204 |
|
|
if ((cipher_list = cp = strdup(names)) == NULL) |
205 |
|
|
return 0; |
206 |
|
|
for ((p = strsep(&cp, CIPHER_SEP)); p && *p != '\0'; |
207 |
|
|
(p = strsep(&cp, CIPHER_SEP))) { |
208 |
|
|
c = cipher_by_name(p); |
209 |
|
|
if (c == NULL || (c->flags & CFLAG_INTERNAL) != 0) { |
210 |
|
|
free(cipher_list); |
211 |
|
|
return 0; |
212 |
|
|
} |
213 |
|
|
} |
214 |
|
|
free(cipher_list); |
215 |
|
|
return 1; |
216 |
|
|
} |
217 |
|
|
|
218 |
|
|
const char * |
219 |
|
|
cipher_warning_message(const struct sshcipher_ctx *cc) |
220 |
|
|
{ |
221 |
|
|
if (cc == NULL || cc->cipher == NULL) |
222 |
|
|
return NULL; |
223 |
|
|
/* XXX repurpose for CBC warning */ |
224 |
|
|
return NULL; |
225 |
|
|
} |
226 |
|
|
|
227 |
|
|
int |
228 |
|
|
cipher_init(struct sshcipher_ctx **ccp, const struct sshcipher *cipher, |
229 |
|
|
const u_char *key, u_int keylen, const u_char *iv, u_int ivlen, |
230 |
|
|
int do_encrypt) |
231 |
|
|
{ |
232 |
|
|
struct sshcipher_ctx *cc = NULL; |
233 |
|
|
int ret = SSH_ERR_INTERNAL_ERROR; |
234 |
|
|
#ifdef WITH_OPENSSL |
235 |
|
|
const EVP_CIPHER *type; |
236 |
|
|
int klen; |
237 |
|
|
#endif |
238 |
|
|
|
239 |
|
|
*ccp = NULL; |
240 |
|
|
if ((cc = calloc(sizeof(*cc), 1)) == NULL) |
241 |
|
|
return SSH_ERR_ALLOC_FAIL; |
242 |
|
|
|
243 |
|
|
cc->plaintext = (cipher->flags & CFLAG_NONE) != 0; |
244 |
|
|
cc->encrypt = do_encrypt; |
245 |
|
|
|
246 |
|
|
if (keylen < cipher->key_len || |
247 |
|
|
(iv != NULL && ivlen < cipher_ivlen(cipher))) { |
248 |
|
|
ret = SSH_ERR_INVALID_ARGUMENT; |
249 |
|
|
goto out; |
250 |
|
|
} |
251 |
|
|
|
252 |
|
|
cc->cipher = cipher; |
253 |
|
|
if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0) { |
254 |
|
|
ret = chachapoly_init(&cc->cp_ctx, key, keylen); |
255 |
|
|
goto out; |
256 |
|
|
} |
257 |
|
|
if ((cc->cipher->flags & CFLAG_NONE) != 0) { |
258 |
|
|
ret = 0; |
259 |
|
|
goto out; |
260 |
|
|
} |
261 |
|
|
#ifndef WITH_OPENSSL |
262 |
|
|
if ((cc->cipher->flags & CFLAG_AESCTR) != 0) { |
263 |
|
|
aesctr_keysetup(&cc->ac_ctx, key, 8 * keylen, 8 * ivlen); |
264 |
|
|
aesctr_ivsetup(&cc->ac_ctx, iv); |
265 |
|
|
ret = 0; |
266 |
|
|
goto out; |
267 |
|
|
} |
268 |
|
|
ret = SSH_ERR_INVALID_ARGUMENT; |
269 |
|
|
goto out; |
270 |
|
|
#else /* WITH_OPENSSL */ |
271 |
|
|
type = (*cipher->evptype)(); |
272 |
|
|
if ((cc->evp = EVP_CIPHER_CTX_new()) == NULL) { |
273 |
|
|
ret = SSH_ERR_ALLOC_FAIL; |
274 |
|
|
goto out; |
275 |
|
|
} |
276 |
|
|
if (EVP_CipherInit(cc->evp, type, NULL, (u_char *)iv, |
277 |
|
|
(do_encrypt == CIPHER_ENCRYPT)) == 0) { |
278 |
|
|
ret = SSH_ERR_LIBCRYPTO_ERROR; |
279 |
|
|
goto out; |
280 |
|
|
} |
281 |
|
|
if (cipher_authlen(cipher) && |
282 |
|
|
!EVP_CIPHER_CTX_ctrl(cc->evp, EVP_CTRL_GCM_SET_IV_FIXED, |
283 |
|
|
-1, (u_char *)iv)) { |
284 |
|
|
ret = SSH_ERR_LIBCRYPTO_ERROR; |
285 |
|
|
goto out; |
286 |
|
|
} |
287 |
|
|
klen = EVP_CIPHER_CTX_key_length(cc->evp); |
288 |
|
|
if (klen > 0 && keylen != (u_int)klen) { |
289 |
|
|
if (EVP_CIPHER_CTX_set_key_length(cc->evp, keylen) == 0) { |
290 |
|
|
ret = SSH_ERR_LIBCRYPTO_ERROR; |
291 |
|
|
goto out; |
292 |
|
|
} |
293 |
|
|
} |
294 |
|
|
if (EVP_CipherInit(cc->evp, NULL, (u_char *)key, NULL, -1) == 0) { |
295 |
|
|
ret = SSH_ERR_LIBCRYPTO_ERROR; |
296 |
|
|
goto out; |
297 |
|
|
} |
298 |
|
|
ret = 0; |
299 |
|
|
#endif /* WITH_OPENSSL */ |
300 |
|
|
out: |
301 |
|
|
if (ret == 0) { |
302 |
|
|
/* success */ |
303 |
|
|
*ccp = cc; |
304 |
|
|
} else { |
305 |
|
|
if (cc != NULL) { |
306 |
|
|
#ifdef WITH_OPENSSL |
307 |
|
|
if (cc->evp != NULL) |
308 |
|
|
EVP_CIPHER_CTX_free(cc->evp); |
309 |
|
|
#endif /* WITH_OPENSSL */ |
310 |
|
|
explicit_bzero(cc, sizeof(*cc)); |
311 |
|
|
free(cc); |
312 |
|
|
} |
313 |
|
|
} |
314 |
|
|
return ret; |
315 |
|
|
} |
316 |
|
|
|
317 |
|
|
/* |
318 |
|
|
* cipher_crypt() operates as following: |
319 |
|
|
* Copy 'aadlen' bytes (without en/decryption) from 'src' to 'dest'. |
320 |
|
|
* Theses bytes are treated as additional authenticated data for |
321 |
|
|
* authenticated encryption modes. |
322 |
|
|
* En/Decrypt 'len' bytes at offset 'aadlen' from 'src' to 'dest'. |
323 |
|
|
* Use 'authlen' bytes at offset 'len'+'aadlen' as the authentication tag. |
324 |
|
|
* This tag is written on encryption and verified on decryption. |
325 |
|
|
* Both 'aadlen' and 'authlen' can be set to 0. |
326 |
|
|
*/ |
327 |
|
|
int |
328 |
|
|
cipher_crypt(struct sshcipher_ctx *cc, u_int seqnr, u_char *dest, |
329 |
|
|
const u_char *src, u_int len, u_int aadlen, u_int authlen) |
330 |
|
|
{ |
331 |
|
|
if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0) { |
332 |
|
|
return chachapoly_crypt(&cc->cp_ctx, seqnr, dest, src, |
333 |
|
|
len, aadlen, authlen, cc->encrypt); |
334 |
|
|
} |
335 |
|
|
if ((cc->cipher->flags & CFLAG_NONE) != 0) { |
336 |
|
|
memcpy(dest, src, aadlen + len); |
337 |
|
|
return 0; |
338 |
|
|
} |
339 |
|
|
#ifndef WITH_OPENSSL |
340 |
|
|
if ((cc->cipher->flags & CFLAG_AESCTR) != 0) { |
341 |
|
|
if (aadlen) |
342 |
|
|
memcpy(dest, src, aadlen); |
343 |
|
|
aesctr_encrypt_bytes(&cc->ac_ctx, src + aadlen, |
344 |
|
|
dest + aadlen, len); |
345 |
|
|
return 0; |
346 |
|
|
} |
347 |
|
|
return SSH_ERR_INVALID_ARGUMENT; |
348 |
|
|
#else |
349 |
|
|
if (authlen) { |
350 |
|
|
u_char lastiv[1]; |
351 |
|
|
|
352 |
|
|
if (authlen != cipher_authlen(cc->cipher)) |
353 |
|
|
return SSH_ERR_INVALID_ARGUMENT; |
354 |
|
|
/* increment IV */ |
355 |
|
|
if (!EVP_CIPHER_CTX_ctrl(cc->evp, EVP_CTRL_GCM_IV_GEN, |
356 |
|
|
1, lastiv)) |
357 |
|
|
return SSH_ERR_LIBCRYPTO_ERROR; |
358 |
|
|
/* set tag on decyption */ |
359 |
|
|
if (!cc->encrypt && |
360 |
|
|
!EVP_CIPHER_CTX_ctrl(cc->evp, EVP_CTRL_GCM_SET_TAG, |
361 |
|
|
authlen, (u_char *)src + aadlen + len)) |
362 |
|
|
return SSH_ERR_LIBCRYPTO_ERROR; |
363 |
|
|
} |
364 |
|
|
if (aadlen) { |
365 |
|
|
if (authlen && |
366 |
|
|
EVP_Cipher(cc->evp, NULL, (u_char *)src, aadlen) < 0) |
367 |
|
|
return SSH_ERR_LIBCRYPTO_ERROR; |
368 |
|
|
memcpy(dest, src, aadlen); |
369 |
|
|
} |
370 |
|
|
if (len % cc->cipher->block_size) |
371 |
|
|
return SSH_ERR_INVALID_ARGUMENT; |
372 |
|
|
if (EVP_Cipher(cc->evp, dest + aadlen, (u_char *)src + aadlen, |
373 |
|
|
len) < 0) |
374 |
|
|
return SSH_ERR_LIBCRYPTO_ERROR; |
375 |
|
|
if (authlen) { |
376 |
|
|
/* compute tag (on encrypt) or verify tag (on decrypt) */ |
377 |
|
|
if (EVP_Cipher(cc->evp, NULL, NULL, 0) < 0) |
378 |
|
|
return cc->encrypt ? |
379 |
|
|
SSH_ERR_LIBCRYPTO_ERROR : SSH_ERR_MAC_INVALID; |
380 |
|
|
if (cc->encrypt && |
381 |
|
|
!EVP_CIPHER_CTX_ctrl(cc->evp, EVP_CTRL_GCM_GET_TAG, |
382 |
|
|
authlen, dest + aadlen + len)) |
383 |
|
|
return SSH_ERR_LIBCRYPTO_ERROR; |
384 |
|
|
} |
385 |
|
|
return 0; |
386 |
|
|
#endif |
387 |
|
|
} |
388 |
|
|
|
389 |
|
|
/* Extract the packet length, including any decryption necessary beforehand */ |
390 |
|
|
int |
391 |
|
|
cipher_get_length(struct sshcipher_ctx *cc, u_int *plenp, u_int seqnr, |
392 |
|
|
const u_char *cp, u_int len) |
393 |
|
|
{ |
394 |
|
|
if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0) |
395 |
|
|
return chachapoly_get_length(&cc->cp_ctx, plenp, seqnr, |
396 |
|
|
cp, len); |
397 |
|
|
if (len < 4) |
398 |
|
|
return SSH_ERR_MESSAGE_INCOMPLETE; |
399 |
|
|
*plenp = get_u32(cp); |
400 |
|
|
return 0; |
401 |
|
|
} |
402 |
|
|
|
403 |
|
|
void |
404 |
|
|
cipher_free(struct sshcipher_ctx *cc) |
405 |
|
|
{ |
406 |
|
|
if (cc == NULL) |
407 |
|
|
return; |
408 |
|
|
if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0) |
409 |
|
|
explicit_bzero(&cc->cp_ctx, sizeof(cc->cp_ctx)); |
410 |
|
|
else if ((cc->cipher->flags & CFLAG_AESCTR) != 0) |
411 |
|
|
explicit_bzero(&cc->ac_ctx, sizeof(cc->ac_ctx)); |
412 |
|
|
#ifdef WITH_OPENSSL |
413 |
|
|
if (cc->evp != NULL) { |
414 |
|
|
EVP_CIPHER_CTX_free(cc->evp); |
415 |
|
|
cc->evp = NULL; |
416 |
|
|
} |
417 |
|
|
#endif |
418 |
|
|
explicit_bzero(cc, sizeof(*cc)); |
419 |
|
|
free(cc); |
420 |
|
|
} |
421 |
|
|
|
422 |
|
|
/* |
423 |
|
|
* Exports an IV from the sshcipher_ctx required to export the key |
424 |
|
|
* state back from the unprivileged child to the privileged parent |
425 |
|
|
* process. |
426 |
|
|
*/ |
427 |
|
|
int |
428 |
|
|
cipher_get_keyiv_len(const struct sshcipher_ctx *cc) |
429 |
|
|
{ |
430 |
|
|
const struct sshcipher *c = cc->cipher; |
431 |
|
|
|
432 |
|
|
if ((c->flags & CFLAG_CHACHAPOLY) != 0) |
433 |
|
|
return 0; |
434 |
|
|
else if ((c->flags & CFLAG_AESCTR) != 0) |
435 |
|
|
return sizeof(cc->ac_ctx.ctr); |
436 |
|
|
#ifdef WITH_OPENSSL |
437 |
|
|
return EVP_CIPHER_CTX_iv_length(cc->evp); |
438 |
|
|
#else |
439 |
|
|
return 0; |
440 |
|
|
#endif |
441 |
|
|
} |
442 |
|
|
|
443 |
|
|
int |
444 |
|
|
cipher_get_keyiv(struct sshcipher_ctx *cc, u_char *iv, u_int len) |
445 |
|
|
{ |
446 |
|
|
#ifdef WITH_OPENSSL |
447 |
|
|
const struct sshcipher *c = cc->cipher; |
448 |
|
|
int evplen; |
449 |
|
|
#endif |
450 |
|
|
|
451 |
|
|
if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0) { |
452 |
|
|
if (len != 0) |
453 |
|
|
return SSH_ERR_INVALID_ARGUMENT; |
454 |
|
|
return 0; |
455 |
|
|
} |
456 |
|
|
if ((cc->cipher->flags & CFLAG_AESCTR) != 0) { |
457 |
|
|
if (len != sizeof(cc->ac_ctx.ctr)) |
458 |
|
|
return SSH_ERR_INVALID_ARGUMENT; |
459 |
|
|
memcpy(iv, cc->ac_ctx.ctr, len); |
460 |
|
|
return 0; |
461 |
|
|
} |
462 |
|
|
if ((cc->cipher->flags & CFLAG_NONE) != 0) |
463 |
|
|
return 0; |
464 |
|
|
|
465 |
|
|
#ifdef WITH_OPENSSL |
466 |
|
|
evplen = EVP_CIPHER_CTX_iv_length(cc->evp); |
467 |
|
|
if (evplen == 0) |
468 |
|
|
return 0; |
469 |
|
|
else if (evplen < 0) |
470 |
|
|
return SSH_ERR_LIBCRYPTO_ERROR; |
471 |
|
|
if ((u_int)evplen != len) |
472 |
|
|
return SSH_ERR_INVALID_ARGUMENT; |
473 |
|
|
if (cipher_authlen(c)) { |
474 |
|
|
if (!EVP_CIPHER_CTX_ctrl(cc->evp, EVP_CTRL_GCM_IV_GEN, |
475 |
|
|
len, iv)) |
476 |
|
|
return SSH_ERR_LIBCRYPTO_ERROR; |
477 |
|
|
} else |
478 |
|
|
memcpy(iv, cc->evp->iv, len); |
479 |
|
|
#endif |
480 |
|
|
return 0; |
481 |
|
|
} |
482 |
|
|
|
483 |
|
|
int |
484 |
|
|
cipher_set_keyiv(struct sshcipher_ctx *cc, const u_char *iv) |
485 |
|
|
{ |
486 |
|
|
#ifdef WITH_OPENSSL |
487 |
|
|
const struct sshcipher *c = cc->cipher; |
488 |
|
|
int evplen = 0; |
489 |
|
|
#endif |
490 |
|
|
|
491 |
|
|
if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0) |
492 |
|
|
return 0; |
493 |
|
|
if ((cc->cipher->flags & CFLAG_NONE) != 0) |
494 |
|
|
return 0; |
495 |
|
|
|
496 |
|
|
#ifdef WITH_OPENSSL |
497 |
|
|
evplen = EVP_CIPHER_CTX_iv_length(cc->evp); |
498 |
|
|
if (evplen <= 0) |
499 |
|
|
return SSH_ERR_LIBCRYPTO_ERROR; |
500 |
|
|
if (cipher_authlen(c)) { |
501 |
|
|
/* XXX iv arg is const, but EVP_CIPHER_CTX_ctrl isn't */ |
502 |
|
|
if (!EVP_CIPHER_CTX_ctrl(cc->evp, |
503 |
|
|
EVP_CTRL_GCM_SET_IV_FIXED, -1, (void *)iv)) |
504 |
|
|
return SSH_ERR_LIBCRYPTO_ERROR; |
505 |
|
|
} else |
506 |
|
|
memcpy(cc->evp->iv, iv, evplen); |
507 |
|
|
#endif |
508 |
|
|
return 0; |
509 |
|
|
} |
510 |
|
|
|