Mercurial > dropbear
comparison common-algo.c @ 1676:d5cdc60db08e
ext-info handling for server-sig-algs
only client side is handled
author | Matt Johnston <matt@ucc.asn.au> |
---|---|
date | Tue, 19 May 2020 00:31:41 +0800 |
parents | ae41624c2198 |
children | 4b4cfc92c5b7 |
comparison
equal
deleted
inserted
replaced
1675:ae41624c2198 | 1676:d5cdc60db08e |
---|---|
28 #include "session.h" | 28 #include "session.h" |
29 #include "dbutil.h" | 29 #include "dbutil.h" |
30 #include "dh_groups.h" | 30 #include "dh_groups.h" |
31 #include "ltc_prng.h" | 31 #include "ltc_prng.h" |
32 #include "ecc.h" | 32 #include "ecc.h" |
33 #include "ssh.h" | |
33 | 34 |
34 /* This file (algo.c) organises the ciphers which can be used, and is used to | 35 /* This file (algo.c) organises the ciphers which can be used, and is used to |
35 * decide which ciphers/hashes/compression/signing to use during key exchange*/ | 36 * decide which ciphers/hashes/compression/signing to use during key exchange*/ |
36 | 37 |
37 static int void_cipher(const unsigned char* in, unsigned char* out, | 38 static int void_cipher(const unsigned char* in, unsigned char* out, |
278 #if DROPBEAR_CURVE25519 | 279 #if DROPBEAR_CURVE25519 |
279 /* Referred to directly */ | 280 /* Referred to directly */ |
280 static const struct dropbear_kex kex_curve25519 = {DROPBEAR_KEX_CURVE25519, NULL, 0, NULL, &sha256_desc }; | 281 static const struct dropbear_kex kex_curve25519 = {DROPBEAR_KEX_CURVE25519, NULL, 0, NULL, &sha256_desc }; |
281 #endif | 282 #endif |
282 | 283 |
284 /* data == NULL for non-kex algorithm identifiers */ | |
283 algo_type sshkex[] = { | 285 algo_type sshkex[] = { |
284 #if DROPBEAR_CURVE25519 | 286 #if DROPBEAR_CURVE25519 |
285 {"curve25519-sha256", 0, &kex_curve25519, 1, NULL}, | 287 {"curve25519-sha256", 0, &kex_curve25519, 1, NULL}, |
286 {"[email protected]", 0, &kex_curve25519, 1, NULL}, | 288 {"[email protected]", 0, &kex_curve25519, 1, NULL}, |
287 #endif | 289 #endif |
307 #endif | 309 #endif |
308 #if DROPBEAR_DH_GROUP16 | 310 #if DROPBEAR_DH_GROUP16 |
309 {"diffie-hellman-group16-sha512", 0, &kex_dh_group16_sha512, 1, NULL}, | 311 {"diffie-hellman-group16-sha512", 0, &kex_dh_group16_sha512, 1, NULL}, |
310 #endif | 312 #endif |
311 #if DROPBEAR_KEXGUESS2 | 313 #if DROPBEAR_KEXGUESS2 |
312 {KEXGUESS2_ALGO_NAME, KEXGUESS2_ALGO_ID, NULL, 1, NULL}, | 314 {KEXGUESS2_ALGO_NAME, 0, NULL, 1, NULL}, |
315 #endif | |
316 #if DROPBEAR_CLIENT | |
317 /* Set unusable by svr_algos_initialise() */ | |
318 {SSH_EXT_INFO_C, 0, NULL, 1, NULL}, | |
313 #endif | 319 #endif |
314 {NULL, 0, NULL, 0, NULL} | 320 {NULL, 0, NULL, 0, NULL} |
315 }; | 321 }; |
316 | 322 |
317 /* Output a comma separated list of algorithms to a buffer */ | 323 /* Output a comma separated list of algorithms to a buffer */ |
334 buf_putstring(buf, (const char*)algolist->data, algolist->len); | 340 buf_putstring(buf, (const char*)algolist->data, algolist->len); |
335 TRACE(("algolist add '%*s'", algolist->len, algolist->data)) | 341 TRACE(("algolist add '%*s'", algolist->len, algolist->data)) |
336 buf_free(algolist); | 342 buf_free(algolist); |
337 } | 343 } |
338 | 344 |
345 /* returns a list of pointers into algolist, of null-terminated names. | |
346 ret_list should be passed in with space for *ret_count elements, | |
347 on return *ret_count has the number of names filled. | |
348 algolist is modified. */ | |
349 static void get_algolist(char* algolist, unsigned int algolist_len, | |
350 const char* *ret_list, unsigned int *ret_count) { | |
351 unsigned int max_count = *ret_count; | |
352 unsigned int i; | |
353 | |
354 if (*ret_count == 0) { | |
355 return; | |
356 } | |
357 if (algolist_len > MAX_PROPOSED_ALGO*(MAX_NAME_LEN+1)) { | |
358 *ret_count = 0; | |
359 } | |
360 | |
361 /* ret_list will contain a list of the strings parsed out. | |
362 We will have at least one string (even if it's just "") */ | |
363 ret_list[0] = algolist; | |
364 *ret_count = 1; | |
365 for (i = 0; i < algolist_len; i++) { | |
366 if (algolist[i] == '\0') { | |
367 /* someone is trying something strange */ | |
368 *ret_count = 0; | |
369 return; | |
370 } | |
371 | |
372 if (algolist[i] == ',') { | |
373 if (*ret_count >= max_count) { | |
374 /* Too many */ | |
375 *ret_count = 0; | |
376 return; | |
377 } | |
378 algolist[i] = '\0'; | |
379 ret_list[*ret_count] = &algolist[i+1]; | |
380 (*ret_count)++; | |
381 } | |
382 } | |
383 } | |
384 | |
385 /* Return DROPBEAR_SUCCESS if the namelist contains algo, | |
386 DROPBEAR_FAILURE otherwise. buf position is not incremented. */ | |
387 int buf_has_algo(buffer *buf, const char *algo) { | |
388 unsigned char* algolist = NULL; | |
389 unsigned int orig_pos = buf->pos; | |
390 unsigned int len, remotecount, i; | |
391 const char *remotenames[MAX_PROPOSED_ALGO]; | |
392 int ret = DROPBEAR_FAILURE; | |
393 | |
394 algolist = buf_getstring(buf, &len); | |
395 remotecount = MAX_PROPOSED_ALGO; | |
396 get_algolist(algolist, len, remotenames, &remotecount); | |
397 for (i = 0; i < remotecount; i++) | |
398 { | |
399 if (strcmp(remotenames[i], algo) == 0) { | |
400 ret = DROPBEAR_SUCCESS; | |
401 break; | |
402 } | |
403 } | |
404 if (algolist) { | |
405 m_free(algolist); | |
406 } | |
407 buf_setpos(buf, orig_pos); | |
408 return ret; | |
409 } | |
410 | |
339 /* match the first algorithm in the comma-separated list in buf which is | 411 /* match the first algorithm in the comma-separated list in buf which is |
340 * also in localalgos[], or return NULL on failure. | 412 * also in localalgos[], or return NULL on failure. |
341 * (*goodguess) is set to 1 if the preferred client/server algos match, | 413 * (*goodguess) is set to 1 if the preferred client/server algos match, |
342 * 0 otherwise. This is used for checking if the kexalgo/hostkeyalgos are | 414 * 0 otherwise. This is used for checking if the kexalgo/hostkeyalgos are |
343 * guessed correctly */ | 415 * guessed correctly */ |
344 algo_type * buf_match_algo(buffer* buf, algo_type localalgos[], | 416 algo_type * buf_match_algo(buffer* buf, algo_type localalgos[], |
345 enum kexguess2_used *kexguess2, int *goodguess) | 417 int kexguess2, int *goodguess) { |
346 { | |
347 | |
348 char * algolist = NULL; | 418 char * algolist = NULL; |
349 const char *remotenames[MAX_PROPOSED_ALGO], *localnames[MAX_PROPOSED_ALGO]; | 419 const char *remotenames[MAX_PROPOSED_ALGO], *localnames[MAX_PROPOSED_ALGO]; |
350 unsigned int len; | 420 unsigned int len; |
351 unsigned int remotecount, localcount, clicount, servcount, i, j; | 421 unsigned int remotecount, localcount, clicount, servcount, i, j; |
352 algo_type * ret = NULL; | 422 algo_type * ret = NULL; |
357 } | 427 } |
358 | 428 |
359 /* get the comma-separated list from the buffer ie "algo1,algo2,algo3" */ | 429 /* get the comma-separated list from the buffer ie "algo1,algo2,algo3" */ |
360 algolist = buf_getstring(buf, &len); | 430 algolist = buf_getstring(buf, &len); |
361 TRACE(("buf_match_algo: %s", algolist)) | 431 TRACE(("buf_match_algo: %s", algolist)) |
362 if (len > MAX_PROPOSED_ALGO*(MAX_NAME_LEN+1)) { | 432 remotecount = MAX_PROPOSED_ALGO; |
363 goto out; | 433 get_algolist(algolist, len, remotenames, &remotecount); |
364 } | |
365 | |
366 /* remotenames will contain a list of the strings parsed out */ | |
367 /* We will have at least one string (even if it's just "") */ | |
368 remotenames[0] = algolist; | |
369 remotecount = 1; | |
370 for (i = 0; i < len; i++) { | |
371 if (algolist[i] == '\0') { | |
372 /* someone is trying something strange */ | |
373 goto out; | |
374 } | |
375 if (algolist[i] == ',') { | |
376 algolist[i] = '\0'; | |
377 remotenames[remotecount] = &algolist[i+1]; | |
378 remotecount++; | |
379 } | |
380 if (remotecount >= MAX_PROPOSED_ALGO) { | |
381 break; | |
382 } | |
383 } | |
384 if (kexguess2 && *kexguess2 == KEXGUESS2_LOOK) { | |
385 for (i = 0; i < remotecount; i++) | |
386 { | |
387 if (strcmp(remotenames[i], KEXGUESS2_ALGO_NAME) == 0) { | |
388 *kexguess2 = KEXGUESS2_YES; | |
389 break; | |
390 } | |
391 } | |
392 if (*kexguess2 == KEXGUESS2_LOOK) { | |
393 *kexguess2 = KEXGUESS2_NO; | |
394 } | |
395 } | |
396 | 434 |
397 for (i = 0; localalgos[i].name != NULL; i++) { | 435 for (i = 0; localalgos[i].name != NULL; i++) { |
398 if (localalgos[i].usable) { | 436 if (localalgos[i].usable) { |
399 localnames[i] = localalgos[i].name; | 437 localnames[i] = localalgos[i].name; |
400 } else { | 438 } else { |
422 /* unusable algos are NULL */ | 460 /* unusable algos are NULL */ |
423 continue; | 461 continue; |
424 } | 462 } |
425 if (strcmp(servnames[j], clinames[i]) == 0) { | 463 if (strcmp(servnames[j], clinames[i]) == 0) { |
426 /* set if it was a good guess */ | 464 /* set if it was a good guess */ |
427 if (goodguess && kexguess2) { | 465 if (goodguess != NULL) { |
428 if (*kexguess2 == KEXGUESS2_YES) { | 466 if (kexguess2) { |
429 if (i == 0) { | 467 if (i == 0) { |
430 *goodguess = 1; | 468 *goodguess = 1; |
431 } | 469 } |
432 | |
433 } else { | 470 } else { |
434 if (i == 0 && j == 0) { | 471 if (i == 0 && j == 0) { |
435 *goodguess = 1; | 472 *goodguess = 1; |
436 } | 473 } |
437 } | 474 } |