1 /*
2  * Dropbear SSH
3  *
4  * Copyright (c) 2002,2003 Matt Johnston
5  * Copyright (c) 2004 by Mihnea Stoenescu
6  * All rights reserved.
7  *
8  * Permission is hereby granted, free of charge, to any person obtaining a copy
9  * of this software and associated documentation files (the "Software"), to deal
10  * in the Software without restriction, including without limitation the rights
11  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12  * copies of the Software, and to permit persons to whom the Software is
13  * furnished to do so, subject to the following conditions:
14  *
15  * The above copyright notice and this permission notice shall be included in
16  * all copies or substantial portions of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24  * SOFTWARE. */
25 
26 #include "includes.h"
27 #include "algo.h"
28 #include "session.h"
29 #include "dbutil.h"
30 #include "dh_groups.h"
31 #include "ltc_prng.h"
32 #include "ecc.h"
33 #include "gcm.h"
34 #include "chachapoly.h"
35 #include "ssh.h"
36 
37 /* This file (algo.c) organises the ciphers which can be used, and is used to
38  * decide which ciphers/hashes/compression/signing to use during key exchange*/
39 
void_cipher(const unsigned char * in,unsigned char * out,unsigned long len,void * UNUSED (cipher_state))40 static int void_cipher(const unsigned char* in, unsigned char* out,
41 		unsigned long len, void* UNUSED(cipher_state)) {
42 	if (in != out) {
43 		memmove(out, in, len);
44 	}
45 	return CRYPT_OK;
46 }
47 
void_start(int UNUSED (cipher),const unsigned char * UNUSED (IV),const unsigned char * UNUSED (key),int UNUSED (keylen),int UNUSED (num_rounds),void * UNUSED (cipher_state))48 static int void_start(int UNUSED(cipher), const unsigned char* UNUSED(IV),
49 			const unsigned char* UNUSED(key),
50 			int UNUSED(keylen), int UNUSED(num_rounds), void* UNUSED(cipher_state)) {
51 	return CRYPT_OK;
52 }
53 
54 /* Mappings for ciphers, parameters are
55    {&cipher_desc, keysize, blocksize} */
56 
57 /* Remember to add new ciphers/hashes to regciphers/reghashes too */
58 
59 #if DROPBEAR_AES256
60 static const struct dropbear_cipher dropbear_aes256 =
61 	{&aes_desc, 32, 16};
62 #endif
63 #if DROPBEAR_AES128
64 static const struct dropbear_cipher dropbear_aes128 =
65 	{&aes_desc, 16, 16};
66 #endif
67 #if DROPBEAR_TWOFISH256
68 static const struct dropbear_cipher dropbear_twofish256 =
69 	{&twofish_desc, 32, 16};
70 #endif
71 #if DROPBEAR_TWOFISH128
72 static const struct dropbear_cipher dropbear_twofish128 =
73 	{&twofish_desc, 16, 16};
74 #endif
75 #if DROPBEAR_3DES
76 static const struct dropbear_cipher dropbear_3des =
77 	{&des3_desc, 24, 8};
78 #endif
79 
80 /* used to indicate no encryption, as defined in rfc2410 */
81 const struct dropbear_cipher dropbear_nocipher =
82 	{NULL, 16, 8};
83 
84 /* A few void* s are required to silence warnings
85  * about the symmetric_CBC vs symmetric_CTR cipher_state pointer */
86 #if DROPBEAR_ENABLE_CBC_MODE
87 const struct dropbear_cipher_mode dropbear_mode_cbc =
88 	{(void*)cbc_start, (void*)cbc_encrypt, (void*)cbc_decrypt, NULL, NULL, NULL};
89 #endif /* DROPBEAR_ENABLE_CBC_MODE */
90 
91 const struct dropbear_cipher_mode dropbear_mode_none =
92 	{void_start, void_cipher, void_cipher, NULL, NULL, NULL};
93 
94 #if DROPBEAR_ENABLE_CTR_MODE
95 /* a wrapper to make ctr_start and cbc_start look the same */
dropbear_big_endian_ctr_start(int cipher,const unsigned char * IV,const unsigned char * key,int keylen,int num_rounds,symmetric_CTR * ctr)96 static int dropbear_big_endian_ctr_start(int cipher,
97 		const unsigned char *IV,
98 		const unsigned char *key, int keylen,
99 		int num_rounds, symmetric_CTR *ctr) {
100 	return ctr_start(cipher, IV, key, keylen, num_rounds, CTR_COUNTER_BIG_ENDIAN, ctr);
101 }
102 const struct dropbear_cipher_mode dropbear_mode_ctr =
103 	{(void*)dropbear_big_endian_ctr_start, (void*)ctr_encrypt, (void*)ctr_decrypt, NULL, NULL, NULL};
104 #endif /* DROPBEAR_ENABLE_CTR_MODE */
105 
106 /* Mapping of ssh hashes to libtomcrypt hashes, including keysize etc.
107    {&hash_desc, keysize, hashsize} */
108 
109 #if DROPBEAR_SHA1_HMAC
110 static const struct dropbear_hash dropbear_sha1 =
111 	{&sha1_desc, 20, 20};
112 #endif
113 #if DROPBEAR_SHA1_96_HMAC
114 static const struct dropbear_hash dropbear_sha1_96 =
115 	{&sha1_desc, 20, 12};
116 #endif
117 #if DROPBEAR_SHA2_256_HMAC
118 static const struct dropbear_hash dropbear_sha2_256 =
119 	{&sha256_desc, 32, 32};
120 #endif
121 #if DROPBEAR_SHA2_512_HMAC
122 static const struct dropbear_hash dropbear_sha2_512 =
123 	{&sha512_desc, 64, 64};
124 #endif
125 #if DROPBEAR_MD5_HMAC
126 static const struct dropbear_hash dropbear_md5 =
127 	{&md5_desc, 16, 16};
128 #endif
129 
130 const struct dropbear_hash dropbear_nohash =
131 	{NULL, 16, 0}; /* used initially */
132 
133 
134 /* The following map ssh names to internal values.
135  * The ordering here is important for the client - the first mode
136  * that is also supported by the server will get used. */
137 
138 algo_type sshciphers[] = {
139 #if DROPBEAR_CHACHA20POLY1305
140 	{"chacha20-poly1305@openssh.com", 0, &dropbear_chachapoly, 1, &dropbear_mode_chachapoly},
141 #endif
142 
143 #if DROPBEAR_ENABLE_GCM_MODE
144 #if DROPBEAR_AES128
145 	{"aes128-gcm@openssh.com", 0, &dropbear_aes128, 1, &dropbear_mode_gcm},
146 #endif
147 #if DROPBEAR_AES256
148 	{"aes256-gcm@openssh.com", 0, &dropbear_aes256, 1, &dropbear_mode_gcm},
149 #endif
150 #endif /* DROPBEAR_ENABLE_GCM_MODE */
151 
152 #if DROPBEAR_ENABLE_CTR_MODE
153 #if DROPBEAR_AES128
154 	{"aes128-ctr", 0, &dropbear_aes128, 1, &dropbear_mode_ctr},
155 #endif
156 #if DROPBEAR_AES256
157 	{"aes256-ctr", 0, &dropbear_aes256, 1, &dropbear_mode_ctr},
158 #endif
159 #if DROPBEAR_TWOFISH_CTR
160 /* twofish ctr is conditional as it hasn't been tested for interoperability, see options.h */
161 #if DROPBEAR_TWOFISH256
162 	{"twofish256-ctr", 0, &dropbear_twofish256, 1, &dropbear_mode_ctr},
163 #endif
164 #if DROPBEAR_TWOFISH128
165 	{"twofish128-ctr", 0, &dropbear_twofish128, 1, &dropbear_mode_ctr},
166 #endif
167 #endif /* DROPBEAR_TWOFISH_CTR */
168 #endif /* DROPBEAR_ENABLE_CTR_MODE */
169 
170 #if DROPBEAR_ENABLE_CBC_MODE
171 #if DROPBEAR_AES128
172 	{"aes128-cbc", 0, &dropbear_aes128, 1, &dropbear_mode_cbc},
173 #endif
174 #if DROPBEAR_AES256
175 	{"aes256-cbc", 0, &dropbear_aes256, 1, &dropbear_mode_cbc},
176 #endif
177 #if DROPBEAR_TWOFISH256
178 	{"twofish256-cbc", 0, &dropbear_twofish256, 1, &dropbear_mode_cbc},
179 	{"twofish-cbc", 0, &dropbear_twofish256, 1, &dropbear_mode_cbc},
180 #endif
181 #if DROPBEAR_TWOFISH128
182 	{"twofish128-cbc", 0, &dropbear_twofish128, 1, &dropbear_mode_cbc},
183 #endif
184 #endif /* DROPBEAR_ENABLE_CBC_MODE */
185 
186 #if DROPBEAR_3DES
187 #if DROPBEAR_ENABLE_CTR_MODE
188 	{"3des-ctr", 0, &dropbear_3des, 1, &dropbear_mode_ctr},
189 #endif
190 #if DROPBEAR_ENABLE_CBC_MODE
191 	{"3des-cbc", 0, &dropbear_3des, 1, &dropbear_mode_cbc},
192 #endif
193 #endif /* DROPBEAR_3DES */
194 
195 #if DROPBEAR_ENABLE_CBC_MODE
196 #endif /* DROPBEAR_ENABLE_CBC_MODE */
197 	{NULL, 0, NULL, 0, NULL}
198 };
199 
200 algo_type sshhashes[] = {
201 #if DROPBEAR_SHA1_96_HMAC
202 	{"hmac-sha1-96", 0, &dropbear_sha1_96, 1, NULL},
203 #endif
204 #if DROPBEAR_SHA1_HMAC
205 	{"hmac-sha1", 0, &dropbear_sha1, 1, NULL},
206 #endif
207 #if DROPBEAR_SHA2_256_HMAC
208 	{"hmac-sha2-256", 0, &dropbear_sha2_256, 1, NULL},
209 #endif
210 #if DROPBEAR_SHA2_512_HMAC
211 	{"hmac-sha2-512", 0, &dropbear_sha2_512, 1, NULL},
212 #endif
213 #if DROPBEAR_MD5_HMAC
214 	{"hmac-md5", 0, (void*)&dropbear_md5, 1, NULL},
215 #endif
216 	{NULL, 0, NULL, 0, NULL}
217 };
218 
219 #ifndef DISABLE_ZLIB
220 algo_type ssh_compress[] = {
221 	{"zlib@openssh.com", DROPBEAR_COMP_ZLIB_DELAY, NULL, 1, NULL},
222 	{"zlib", DROPBEAR_COMP_ZLIB, NULL, 1, NULL},
223 	{"none", DROPBEAR_COMP_NONE, NULL, 1, NULL},
224 	{NULL, 0, NULL, 0, NULL}
225 };
226 
227 algo_type ssh_delaycompress[] = {
228 	{"zlib@openssh.com", DROPBEAR_COMP_ZLIB_DELAY, NULL, 1, NULL},
229 	{"none", DROPBEAR_COMP_NONE, NULL, 1, NULL},
230 	{NULL, 0, NULL, 0, NULL}
231 };
232 #endif
233 
234 algo_type ssh_nocompress[] = {
235 	{"none", DROPBEAR_COMP_NONE, NULL, 1, NULL},
236 	{NULL, 0, NULL, 0, NULL}
237 };
238 
239 algo_type sigalgs[] = {
240 #if DROPBEAR_ED25519
241 	{"ssh-ed25519", DROPBEAR_SIGNATURE_ED25519, NULL, 1, NULL},
242 #endif
243 #if DROPBEAR_ECDSA
244 #if DROPBEAR_ECC_256
245 	{"ecdsa-sha2-nistp256", DROPBEAR_SIGNATURE_ECDSA_NISTP256, NULL, 1, NULL},
246 #endif
247 #if DROPBEAR_ECC_384
248 	{"ecdsa-sha2-nistp384", DROPBEAR_SIGNATURE_ECDSA_NISTP384, NULL, 1, NULL},
249 #endif
250 #if DROPBEAR_ECC_521
251 	{"ecdsa-sha2-nistp521", DROPBEAR_SIGNATURE_ECDSA_NISTP521, NULL, 1, NULL},
252 #endif
253 #endif
254 #if DROPBEAR_RSA
255 #if DROPBEAR_RSA_SHA256
256 	{"rsa-sha2-256", DROPBEAR_SIGNATURE_RSA_SHA256, NULL, 1, NULL},
257 #endif
258 #if DROPBEAR_RSA_SHA1
259 	{"ssh-rsa", DROPBEAR_SIGNATURE_RSA_SHA1, NULL, 1, NULL},
260 #endif
261 #endif
262 #if DROPBEAR_DSS
263 	{"ssh-dss", DROPBEAR_SIGNATURE_DSS, NULL, 1, NULL},
264 #endif
265 	{NULL, 0, NULL, 0, NULL}
266 };
267 
268 #if DROPBEAR_DH_GROUP1
269 static const struct dropbear_kex kex_dh_group1 = {DROPBEAR_KEX_NORMAL_DH, dh_p_1, DH_P_1_LEN, NULL, &sha1_desc };
270 #endif
271 #if DROPBEAR_DH_GROUP14_SHA1
272 static const struct dropbear_kex kex_dh_group14_sha1 = {DROPBEAR_KEX_NORMAL_DH, dh_p_14, DH_P_14_LEN, NULL, &sha1_desc };
273 #endif
274 #if DROPBEAR_DH_GROUP14_SHA256
275 static const struct dropbear_kex kex_dh_group14_sha256 = {DROPBEAR_KEX_NORMAL_DH, dh_p_14, DH_P_14_LEN, NULL, &sha256_desc };
276 #endif
277 #if DROPBEAR_DH_GROUP16
278 static const struct dropbear_kex kex_dh_group16_sha512 = {DROPBEAR_KEX_NORMAL_DH, dh_p_16, DH_P_16_LEN, NULL, &sha512_desc };
279 #endif
280 
281 #if DROPBEAR_ECDH
282 #if DROPBEAR_ECC_256
283 static const struct dropbear_kex kex_ecdh_nistp256 = {DROPBEAR_KEX_ECDH, NULL, 0, &ecc_curve_nistp256, &sha256_desc };
284 #endif
285 #if DROPBEAR_ECC_384
286 static const struct dropbear_kex kex_ecdh_nistp384 = {DROPBEAR_KEX_ECDH, NULL, 0, &ecc_curve_nistp384, &sha384_desc };
287 #endif
288 #if DROPBEAR_ECC_521
289 static const struct dropbear_kex kex_ecdh_nistp521 = {DROPBEAR_KEX_ECDH, NULL, 0, &ecc_curve_nistp521, &sha512_desc };
290 #endif
291 #endif /* DROPBEAR_ECDH */
292 
293 #if DROPBEAR_CURVE25519
294 /* Referred to directly */
295 static const struct dropbear_kex kex_curve25519 = {DROPBEAR_KEX_CURVE25519, NULL, 0, NULL, &sha256_desc };
296 #endif
297 
298 /* data == NULL for non-kex algorithm identifiers */
299 algo_type sshkex[] = {
300 #if DROPBEAR_CURVE25519
301 	{"curve25519-sha256", 0, &kex_curve25519, 1, NULL},
302 	{"curve25519-sha256@libssh.org", 0, &kex_curve25519, 1, NULL},
303 #endif
304 #if DROPBEAR_ECDH
305 #if DROPBEAR_ECC_521
306 	{"ecdh-sha2-nistp521", 0, &kex_ecdh_nistp521, 1, NULL},
307 #endif
308 #if DROPBEAR_ECC_384
309 	{"ecdh-sha2-nistp384", 0, &kex_ecdh_nistp384, 1, NULL},
310 #endif
311 #if DROPBEAR_ECC_256
312 	{"ecdh-sha2-nistp256", 0, &kex_ecdh_nistp256, 1, NULL},
313 #endif
314 #endif
315 #if DROPBEAR_DH_GROUP14_SHA256
316 	{"diffie-hellman-group14-sha256", 0, &kex_dh_group14_sha256, 1, NULL},
317 #endif
318 #if DROPBEAR_DH_GROUP14_SHA1
319 	{"diffie-hellman-group14-sha1", 0, &kex_dh_group14_sha1, 1, NULL},
320 #endif
321 #if DROPBEAR_DH_GROUP1
322 	{"diffie-hellman-group1-sha1", 0, &kex_dh_group1, 1, NULL},
323 #endif
324 #if DROPBEAR_DH_GROUP16
325 	{"diffie-hellman-group16-sha512", 0, &kex_dh_group16_sha512, 1, NULL},
326 #endif
327 #if DROPBEAR_KEXGUESS2
328 	{KEXGUESS2_ALGO_NAME, 0, NULL, 1, NULL},
329 #endif
330 #if DROPBEAR_EXT_INFO
331 #if DROPBEAR_CLIENT
332 	/* Set unusable by svr_algos_initialise() */
333 	{SSH_EXT_INFO_C, 0, NULL, 1, NULL},
334 #endif
335 #endif
336 	{NULL, 0, NULL, 0, NULL}
337 };
338 
339 /* Output a comma separated list of algorithms to a buffer */
buf_put_algolist_all(buffer * buf,const algo_type localalgos[],int useall)340 void buf_put_algolist_all(buffer * buf, const algo_type localalgos[], int useall) {
341 	unsigned int i, len;
342 	unsigned int donefirst = 0;
343 	unsigned int startpos;
344 
345 	startpos = buf->pos;
346 	/* Placeholder for length */
347 	buf_putint(buf, 0);
348 	for (i = 0; localalgos[i].name != NULL; i++) {
349 		if (localalgos[i].usable || useall) {
350 			if (donefirst) {
351 				buf_putbyte(buf, ',');
352 			}
353 			donefirst = 1;
354 			len = strlen(localalgos[i].name);
355 			buf_putbytes(buf, (const unsigned char *) localalgos[i].name, len);
356 		}
357 	}
358 	/* Fill out the length */
359 	len = buf->pos - startpos - 4;
360 	buf_setpos(buf, startpos);
361 	buf_putint(buf, len);
362 	TRACE(("algolist add %d '%*s'", len, len, buf_getptr(buf, len)))
363 	buf_incrwritepos(buf, len);
364 }
365 
buf_put_algolist(buffer * buf,const algo_type localalgos[])366 void buf_put_algolist(buffer * buf, const algo_type localalgos[]) {
367 	buf_put_algolist_all(buf, localalgos, 0);
368 }
369 
370 /* returns a list of pointers into algolist, of null-terminated names.
371    ret_list should be passed in with space for *ret_count elements,
372    on return *ret_count has the number of names filled.
373    algolist is modified. */
get_algolist(char * algolist,unsigned int algolist_len,const char ** ret_list,unsigned int * ret_count)374 static void get_algolist(char* algolist, unsigned int algolist_len,
375 				const char* *ret_list, unsigned int *ret_count) {
376 	unsigned int max_count = *ret_count;
377 	unsigned int i;
378 
379 	if (*ret_count == 0) {
380 		return;
381 	}
382 	if (algolist_len > MAX_PROPOSED_ALGO*(MAX_NAME_LEN+1)) {
383 		*ret_count = 0;
384 	}
385 
386 	/* ret_list will contain a list of the strings parsed out.
387 	   We will have at least one string (even if it's just "") */
388 	ret_list[0] = algolist;
389 	*ret_count = 1;
390 	for (i = 0; i < algolist_len; i++) {
391 		if (algolist[i] == '\0') {
392 			/* someone is trying something strange */
393 			*ret_count = 0;
394 			return;
395 		}
396 
397 		if (algolist[i] == ',') {
398 			if (*ret_count >= max_count) {
399 				dropbear_exit("Too many remote algorithms");
400 				*ret_count = 0;
401 				return;
402 			}
403 			algolist[i] = '\0';
404 			ret_list[*ret_count] = &algolist[i+1];
405 			(*ret_count)++;
406 		}
407 	}
408 }
409 
410 /* Return DROPBEAR_SUCCESS if the namelist contains algo,
411 DROPBEAR_FAILURE otherwise. buf position is not incremented. */
buf_has_algo(buffer * buf,const char * algo)412 int buf_has_algo(buffer *buf, const char *algo) {
413 	unsigned char* algolist = NULL;
414 	unsigned int orig_pos = buf->pos;
415 	unsigned int len, remotecount, i;
416 	const char *remotenames[MAX_PROPOSED_ALGO];
417 	int ret = DROPBEAR_FAILURE;
418 
419 	algolist = buf_getstring(buf, &len);
420 	remotecount = MAX_PROPOSED_ALGO;
421 	get_algolist(algolist, len, remotenames, &remotecount);
422 	for (i = 0; i < remotecount; i++)
423 	{
424 		if (strcmp(remotenames[i], algo) == 0) {
425 			ret = DROPBEAR_SUCCESS;
426 			break;
427 		}
428 	}
429 	if (algolist) {
430 		m_free(algolist);
431 	}
432 	buf_setpos(buf, orig_pos);
433 	return ret;
434 }
435 
first_usable_algo(algo_type algos[])436 algo_type * first_usable_algo(algo_type algos[]) {
437 	int i;
438 	for (i = 0; algos[i].name != NULL; i++) {
439 		if (algos[i].usable) {
440 			return &algos[i];
441 		}
442 	}
443 	return NULL;
444 }
445 
446 /* match the first algorithm in the comma-separated list in buf which is
447  * also in localalgos[], or return NULL on failure.
448  * (*goodguess) is set to 1 if the preferred client/server algos match,
449  * 0 otherwise. This is used for checking if the kexalgo/hostkeyalgos are
450  * guessed correctly */
buf_match_algo(buffer * buf,algo_type localalgos[],int kexguess2,int * goodguess)451 algo_type * buf_match_algo(buffer* buf, algo_type localalgos[],
452 		int kexguess2, int *goodguess) {
453 	char * algolist = NULL;
454 	const char *remotenames[MAX_PROPOSED_ALGO], *localnames[MAX_PROPOSED_ALGO];
455 	unsigned int len;
456 	unsigned int remotecount, localcount, clicount, servcount, i, j;
457 	algo_type * ret = NULL;
458 	const char **clinames, **servnames;
459 
460 	if (goodguess) {
461 		*goodguess = 0;
462 	}
463 
464 	/* get the comma-separated list from the buffer ie "algo1,algo2,algo3" */
465 	algolist = buf_getstring(buf, &len);
466 	TRACE(("buf_match_algo: %s", algolist))
467 	remotecount = MAX_PROPOSED_ALGO;
468 	get_algolist(algolist, len, remotenames, &remotecount);
469 
470 	for (i = 0; localalgos[i].name != NULL; i++) {
471 		if (localalgos[i].usable) {
472 			localnames[i] = localalgos[i].name;
473 		} else {
474 			localnames[i] = NULL;
475 		}
476 	}
477 	localcount = i;
478 
479 	if (IS_DROPBEAR_SERVER) {
480 		clinames = remotenames;
481 		clicount = remotecount;
482 		servnames = localnames;
483 		servcount = localcount;
484 	} else {
485 		clinames = localnames;
486 		clicount = localcount;
487 		servnames = remotenames;
488 		servcount = remotecount;
489 	}
490 
491 	/* iterate and find the first match */
492 	for (i = 0; i < clicount; i++) {
493 		for (j = 0; j < servcount; j++) {
494 			if (!(servnames[j] && clinames[i])) {
495 				/* unusable algos are NULL */
496 				continue;
497 			}
498 			if (strcmp(servnames[j], clinames[i]) == 0) {
499 				/* set if it was a good guess */
500 				if (goodguess != NULL) {
501 					if (kexguess2) {
502 						if (i == 0) {
503 							*goodguess = 1;
504 						}
505 					} else {
506 						if (i == 0 && j == 0) {
507 							*goodguess = 1;
508 						}
509 					}
510 				}
511 				/* set the algo to return */
512 				if (IS_DROPBEAR_SERVER) {
513 					ret = &localalgos[j];
514 				} else {
515 					ret = &localalgos[i];
516 				}
517 				goto out;
518 			}
519 		}
520 	}
521 
522 out:
523 	m_free(algolist);
524 	return ret;
525 }
526 
527 #if DROPBEAR_USER_ALGO_LIST
528 
529 char *
algolist_string(const algo_type algos[])530 algolist_string(const algo_type algos[])
531 {
532 	char *ret_list;
533 	buffer *b = buf_new(200);
534 	buf_put_algolist(b, algos);
535 	buf_setpos(b, b->len);
536 	buf_putbyte(b, '\0');
537 	buf_setpos(b, 4);
538 	ret_list = m_strdup((const char *) buf_getptr(b, b->len - b->pos));
539 	buf_free(b);
540 	return ret_list;
541 }
542 
543 static algo_type*
check_algo(const char * algo_name,algo_type * algos)544 check_algo(const char* algo_name, algo_type *algos)
545 {
546 	algo_type *a;
547 	for (a = algos; a->name != NULL; a++)
548 	{
549 		if (strcmp(a->name, algo_name) == 0)
550 		{
551 			return a;
552 		}
553 	}
554 
555 	return NULL;
556 }
557 
558 /* Checks a user provided comma-separated algorithm list for available
559  * options. Any that are not acceptable are removed in-place. Returns the
560  * number of valid algorithms. */
561 int
check_user_algos(const char * user_algo_list,algo_type * algos,const char * algo_desc)562 check_user_algos(const char* user_algo_list, algo_type * algos,
563 		const char *algo_desc)
564 {
565 	algo_type new_algos[MAX_PROPOSED_ALGO+1];
566 	char *work_list = m_strdup(user_algo_list);
567 	char *start = work_list;
568 	char *c;
569 	int n;
570 	/* So we can iterate and look for null terminator */
571 	memset(new_algos, 0x0, sizeof(new_algos));
572 	for (c = work_list, n = 0; ; c++)
573 	{
574 		char oc = *c;
575 		if (n >= MAX_PROPOSED_ALGO) {
576 			dropbear_exit("Too many algorithms '%s'", user_algo_list);
577 		}
578 		if (*c == ',' || *c == '\0') {
579 			algo_type *match_algo = NULL;
580 			*c = '\0';
581 			match_algo = check_algo(start, algos);
582 			if (match_algo) {
583 				if (check_algo(start, new_algos)) {
584 					TRACE(("Skip repeated algorithm '%s'", start))
585 				} else {
586 					new_algos[n] = *match_algo;
587 					n++;
588 				}
589 			} else {
590 				dropbear_log(LOG_WARNING, "This Dropbear program does not support '%s' %s algorithm", start, algo_desc);
591 			}
592 			c++;
593 			start = c;
594 		}
595 		if (oc == '\0') {
596 			break;
597 		}
598 	}
599 	m_free(work_list);
600 	/* n+1 to include a null terminator */
601 	memcpy(algos, new_algos, sizeof(*new_algos) * (n+1));
602 	return n;
603 }
604 #endif /* DROPBEAR_USER_ALGO_LIST */
605