comparison common-algo.c @ 1683:41bf8f216644

merge rsa-sha256
author Matt Johnston <matt@ucc.asn.au>
date Tue, 26 May 2020 00:24:02 +0800
parents e0871128e61f 435cfb9ec96e
children c2c0f43ff827
comparison
equal deleted inserted replaced
1673:e0871128e61f 1683:41bf8f216644
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 "gcm.h" 33 #include "gcm.h"
34 #include "chachapoly.h" 34 #include "chachapoly.h"
35 #include "ssh.h"
35 36
36 /* This file (algo.c) organises the ciphers which can be used, and is used to 37 /* This file (algo.c) organises the ciphers which can be used, and is used to
37 * decide which ciphers/hashes/compression/signing to use during key exchange*/ 38 * decide which ciphers/hashes/compression/signing to use during key exchange*/
38 39
39 static int void_cipher(const unsigned char* in, unsigned char* out, 40 static int void_cipher(const unsigned char* in, unsigned char* out,
240 algo_type ssh_nocompress[] = { 241 algo_type ssh_nocompress[] = {
241 {"none", DROPBEAR_COMP_NONE, NULL, 1, NULL}, 242 {"none", DROPBEAR_COMP_NONE, NULL, 1, NULL},
242 {NULL, 0, NULL, 0, NULL} 243 {NULL, 0, NULL, 0, NULL}
243 }; 244 };
244 245
245 algo_type sshhostkey[] = { 246 algo_type sigalgs[] = {
246 #if DROPBEAR_ED25519 247 #if DROPBEAR_ED25519
247 {"ssh-ed25519", DROPBEAR_SIGNKEY_ED25519, NULL, 1, NULL}, 248 {"ssh-ed25519", DROPBEAR_SIGNATURE_ED25519, NULL, 1, NULL},
248 #endif 249 #endif
249 #if DROPBEAR_ECDSA 250 #if DROPBEAR_ECDSA
250 #if DROPBEAR_ECC_256 251 #if DROPBEAR_ECC_256
251 {"ecdsa-sha2-nistp256", DROPBEAR_SIGNKEY_ECDSA_NISTP256, NULL, 1, NULL}, 252 {"ecdsa-sha2-nistp256", DROPBEAR_SIGNATURE_ECDSA_NISTP256, NULL, 1, NULL},
252 #endif 253 #endif
253 #if DROPBEAR_ECC_384 254 #if DROPBEAR_ECC_384
254 {"ecdsa-sha2-nistp384", DROPBEAR_SIGNKEY_ECDSA_NISTP384, NULL, 1, NULL}, 255 {"ecdsa-sha2-nistp384", DROPBEAR_SIGNATURE_ECDSA_NISTP384, NULL, 1, NULL},
255 #endif 256 #endif
256 #if DROPBEAR_ECC_521 257 #if DROPBEAR_ECC_521
257 {"ecdsa-sha2-nistp521", DROPBEAR_SIGNKEY_ECDSA_NISTP521, NULL, 1, NULL}, 258 {"ecdsa-sha2-nistp521", DROPBEAR_SIGNATURE_ECDSA_NISTP521, NULL, 1, NULL},
258 #endif 259 #endif
259 #endif 260 #endif
260 #if DROPBEAR_RSA 261 #if DROPBEAR_RSA
261 {"ssh-rsa", DROPBEAR_SIGNKEY_RSA, NULL, 1, NULL}, 262 #if DROPBEAR_RSA_SHA256
263 {"rsa-sha2-256", DROPBEAR_SIGNATURE_RSA_SHA256, NULL, 1, NULL},
264 #endif
265 #if DROPBEAR_RSA_SHA1
266 {"ssh-rsa", DROPBEAR_SIGNATURE_RSA_SHA1, NULL, 1, NULL},
267 #endif
262 #endif 268 #endif
263 #if DROPBEAR_DSS 269 #if DROPBEAR_DSS
264 {"ssh-dss", DROPBEAR_SIGNKEY_DSS, NULL, 1, NULL}, 270 {"ssh-dss", DROPBEAR_SIGNATURE_DSS, NULL, 1, NULL},
265 #endif 271 #endif
266 {NULL, 0, NULL, 0, NULL} 272 {NULL, 0, NULL, 0, NULL}
267 }; 273 };
268 274
269 #if DROPBEAR_DH_GROUP1 275 #if DROPBEAR_DH_GROUP1
277 #endif 283 #endif
278 #if DROPBEAR_DH_GROUP16 284 #if DROPBEAR_DH_GROUP16
279 static const struct dropbear_kex kex_dh_group16_sha512 = {DROPBEAR_KEX_NORMAL_DH, dh_p_16, DH_P_16_LEN, NULL, &sha512_desc }; 285 static const struct dropbear_kex kex_dh_group16_sha512 = {DROPBEAR_KEX_NORMAL_DH, dh_p_16, DH_P_16_LEN, NULL, &sha512_desc };
280 #endif 286 #endif
281 287
282 /* These can't be const since dropbear_ecc_fill_dp() fills out
283 ecc_curve at runtime */
284 #if DROPBEAR_ECDH 288 #if DROPBEAR_ECDH
285 #if DROPBEAR_ECC_256 289 #if DROPBEAR_ECC_256
286 static const struct dropbear_kex kex_ecdh_nistp256 = {DROPBEAR_KEX_ECDH, NULL, 0, &ecc_curve_nistp256, &sha256_desc }; 290 static const struct dropbear_kex kex_ecdh_nistp256 = {DROPBEAR_KEX_ECDH, NULL, 0, &ecc_curve_nistp256, &sha256_desc };
287 #endif 291 #endif
288 #if DROPBEAR_ECC_384 292 #if DROPBEAR_ECC_384
296 #if DROPBEAR_CURVE25519 300 #if DROPBEAR_CURVE25519
297 /* Referred to directly */ 301 /* Referred to directly */
298 static const struct dropbear_kex kex_curve25519 = {DROPBEAR_KEX_CURVE25519, NULL, 0, NULL, &sha256_desc }; 302 static const struct dropbear_kex kex_curve25519 = {DROPBEAR_KEX_CURVE25519, NULL, 0, NULL, &sha256_desc };
299 #endif 303 #endif
300 304
305 /* data == NULL for non-kex algorithm identifiers */
301 algo_type sshkex[] = { 306 algo_type sshkex[] = {
302 #if DROPBEAR_CURVE25519 307 #if DROPBEAR_CURVE25519
303 {"curve25519-sha256", 0, &kex_curve25519, 1, NULL}, 308 {"curve25519-sha256", 0, &kex_curve25519, 1, NULL},
304 {"[email protected]", 0, &kex_curve25519, 1, NULL}, 309 {"[email protected]", 0, &kex_curve25519, 1, NULL},
305 #endif 310 #endif
325 #endif 330 #endif
326 #if DROPBEAR_DH_GROUP16 331 #if DROPBEAR_DH_GROUP16
327 {"diffie-hellman-group16-sha512", 0, &kex_dh_group16_sha512, 1, NULL}, 332 {"diffie-hellman-group16-sha512", 0, &kex_dh_group16_sha512, 1, NULL},
328 #endif 333 #endif
329 #if DROPBEAR_KEXGUESS2 334 #if DROPBEAR_KEXGUESS2
330 {KEXGUESS2_ALGO_NAME, KEXGUESS2_ALGO_ID, NULL, 1, NULL}, 335 {KEXGUESS2_ALGO_NAME, 0, NULL, 1, NULL},
336 #endif
337 #if DROPBEAR_EXT_INFO
338 #if DROPBEAR_CLIENT
339 /* Set unusable by svr_algos_initialise() */
340 {SSH_EXT_INFO_C, 0, NULL, 1, NULL},
341 #endif
331 #endif 342 #endif
332 {NULL, 0, NULL, 0, NULL} 343 {NULL, 0, NULL, 0, NULL}
333 }; 344 };
334 345
335 /* algolen specifies the length of algo, algos is our local list to match
336 * against.
337 * Returns DROPBEAR_SUCCESS if we have a match for algo, DROPBEAR_FAILURE
338 * otherwise */
339 int have_algo(const char* algo, size_t algolen, const algo_type algos[]) {
340
341 int i;
342
343 for (i = 0; algos[i].name != NULL; i++) {
344 if (strlen(algos[i].name) == algolen
345 && (strncmp(algos[i].name, algo, algolen) == 0)) {
346 return DROPBEAR_SUCCESS;
347 }
348 }
349
350 return DROPBEAR_FAILURE;
351 }
352
353 /* Output a comma separated list of algorithms to a buffer */ 346 /* Output a comma separated list of algorithms to a buffer */
354 void buf_put_algolist(buffer * buf, const algo_type localalgos[]) { 347 void buf_put_algolist_all(buffer * buf, const algo_type localalgos[], int useall) {
355
356 unsigned int i, len; 348 unsigned int i, len;
357 unsigned int donefirst = 0; 349 unsigned int donefirst = 0;
358 buffer *algolist = NULL; 350 unsigned int startpos;
359 351
360 algolist = buf_new(300); 352 startpos = buf->pos;
353 /* Placeholder for length */
354 buf_putint(buf, 0);
361 for (i = 0; localalgos[i].name != NULL; i++) { 355 for (i = 0; localalgos[i].name != NULL; i++) {
362 if (localalgos[i].usable) { 356 if (localalgos[i].usable || useall) {
363 if (donefirst) 357 if (donefirst) {
364 buf_putbyte(algolist, ','); 358 buf_putbyte(buf, ',');
359 }
365 donefirst = 1; 360 donefirst = 1;
366 len = strlen(localalgos[i].name); 361 len = strlen(localalgos[i].name);
367 buf_putbytes(algolist, (const unsigned char *) localalgos[i].name, len); 362 buf_putbytes(buf, (const unsigned char *) localalgos[i].name, len);
368 } 363 }
369 } 364 }
370 buf_putstring(buf, (const char*)algolist->data, algolist->len); 365 /* Fill out the length */
371 TRACE(("algolist add '%*s'", algolist->len, algolist->data)) 366 len = buf->pos - startpos - 4;
372 buf_free(algolist); 367 buf_setpos(buf, startpos);
368 buf_putint(buf, len);
369 TRACE(("algolist add %d '%*s'", len, len, buf_getptr(buf, len)))
370 buf_incrwritepos(buf, len);
371 }
372
373 void buf_put_algolist(buffer * buf, const algo_type localalgos[]) {
374 buf_put_algolist_all(buf, localalgos, 0);
375 }
376
377 /* returns a list of pointers into algolist, of null-terminated names.
378 ret_list should be passed in with space for *ret_count elements,
379 on return *ret_count has the number of names filled.
380 algolist is modified. */
381 static void get_algolist(char* algolist, unsigned int algolist_len,
382 const char* *ret_list, unsigned int *ret_count) {
383 unsigned int max_count = *ret_count;
384 unsigned int i;
385
386 if (*ret_count == 0) {
387 return;
388 }
389 if (algolist_len > MAX_PROPOSED_ALGO*(MAX_NAME_LEN+1)) {
390 *ret_count = 0;
391 }
392
393 /* ret_list will contain a list of the strings parsed out.
394 We will have at least one string (even if it's just "") */
395 ret_list[0] = algolist;
396 *ret_count = 1;
397 for (i = 0; i < algolist_len; i++) {
398 if (algolist[i] == '\0') {
399 /* someone is trying something strange */
400 *ret_count = 0;
401 return;
402 }
403
404 if (algolist[i] == ',') {
405 if (*ret_count >= max_count) {
406 /* Too many */
407 *ret_count = 0;
408 return;
409 }
410 algolist[i] = '\0';
411 ret_list[*ret_count] = &algolist[i+1];
412 (*ret_count)++;
413 }
414 }
415 }
416
417 /* Return DROPBEAR_SUCCESS if the namelist contains algo,
418 DROPBEAR_FAILURE otherwise. buf position is not incremented. */
419 int buf_has_algo(buffer *buf, const char *algo) {
420 unsigned char* algolist = NULL;
421 unsigned int orig_pos = buf->pos;
422 unsigned int len, remotecount, i;
423 const char *remotenames[MAX_PROPOSED_ALGO];
424 int ret = DROPBEAR_FAILURE;
425
426 algolist = buf_getstring(buf, &len);
427 remotecount = MAX_PROPOSED_ALGO;
428 get_algolist(algolist, len, remotenames, &remotecount);
429 for (i = 0; i < remotecount; i++)
430 {
431 if (strcmp(remotenames[i], algo) == 0) {
432 ret = DROPBEAR_SUCCESS;
433 break;
434 }
435 }
436 if (algolist) {
437 m_free(algolist);
438 }
439 buf_setpos(buf, orig_pos);
440 return ret;
441 }
442
443 algo_type * first_usable_algo(algo_type algos[]) {
444 int i;
445 for (i = 0; algos[i].name != NULL; i++) {
446 if (algos[i].usable) {
447 return &algos[i];
448 }
449 }
450 return NULL;
373 } 451 }
374 452
375 /* match the first algorithm in the comma-separated list in buf which is 453 /* match the first algorithm in the comma-separated list in buf which is
376 * also in localalgos[], or return NULL on failure. 454 * also in localalgos[], or return NULL on failure.
377 * (*goodguess) is set to 1 if the preferred client/server algos match, 455 * (*goodguess) is set to 1 if the preferred client/server algos match,
378 * 0 otherwise. This is used for checking if the kexalgo/hostkeyalgos are 456 * 0 otherwise. This is used for checking if the kexalgo/hostkeyalgos are
379 * guessed correctly */ 457 * guessed correctly */
380 algo_type * buf_match_algo(buffer* buf, algo_type localalgos[], 458 algo_type * buf_match_algo(buffer* buf, algo_type localalgos[],
381 enum kexguess2_used *kexguess2, int *goodguess) 459 int kexguess2, int *goodguess) {
382 {
383
384 char * algolist = NULL; 460 char * algolist = NULL;
385 const char *remotenames[MAX_PROPOSED_ALGO], *localnames[MAX_PROPOSED_ALGO]; 461 const char *remotenames[MAX_PROPOSED_ALGO], *localnames[MAX_PROPOSED_ALGO];
386 unsigned int len; 462 unsigned int len;
387 unsigned int remotecount, localcount, clicount, servcount, i, j; 463 unsigned int remotecount, localcount, clicount, servcount, i, j;
388 algo_type * ret = NULL; 464 algo_type * ret = NULL;
393 } 469 }
394 470
395 /* get the comma-separated list from the buffer ie "algo1,algo2,algo3" */ 471 /* get the comma-separated list from the buffer ie "algo1,algo2,algo3" */
396 algolist = buf_getstring(buf, &len); 472 algolist = buf_getstring(buf, &len);
397 TRACE(("buf_match_algo: %s", algolist)) 473 TRACE(("buf_match_algo: %s", algolist))
398 if (len > MAX_PROPOSED_ALGO*(MAX_NAME_LEN+1)) { 474 remotecount = MAX_PROPOSED_ALGO;
399 goto out; 475 get_algolist(algolist, len, remotenames, &remotecount);
400 }
401
402 /* remotenames will contain a list of the strings parsed out */
403 /* We will have at least one string (even if it's just "") */
404 remotenames[0] = algolist;
405 remotecount = 1;
406 for (i = 0; i < len; i++) {
407 if (algolist[i] == '\0') {
408 /* someone is trying something strange */
409 goto out;
410 }
411 if (algolist[i] == ',') {
412 algolist[i] = '\0';
413 remotenames[remotecount] = &algolist[i+1];
414 remotecount++;
415 }
416 if (remotecount >= MAX_PROPOSED_ALGO) {
417 break;
418 }
419 }
420 if (kexguess2 && *kexguess2 == KEXGUESS2_LOOK) {
421 for (i = 0; i < remotecount; i++)
422 {
423 if (strcmp(remotenames[i], KEXGUESS2_ALGO_NAME) == 0) {
424 *kexguess2 = KEXGUESS2_YES;
425 break;
426 }
427 }
428 if (*kexguess2 == KEXGUESS2_LOOK) {
429 *kexguess2 = KEXGUESS2_NO;
430 }
431 }
432 476
433 for (i = 0; localalgos[i].name != NULL; i++) { 477 for (i = 0; localalgos[i].name != NULL; i++) {
434 if (localalgos[i].usable) { 478 if (localalgos[i].usable) {
435 localnames[i] = localalgos[i].name; 479 localnames[i] = localalgos[i].name;
436 } else { 480 } else {
458 /* unusable algos are NULL */ 502 /* unusable algos are NULL */
459 continue; 503 continue;
460 } 504 }
461 if (strcmp(servnames[j], clinames[i]) == 0) { 505 if (strcmp(servnames[j], clinames[i]) == 0) {
462 /* set if it was a good guess */ 506 /* set if it was a good guess */
463 if (goodguess && kexguess2) { 507 if (goodguess != NULL) {
464 if (*kexguess2 == KEXGUESS2_YES) { 508 if (kexguess2) {
465 if (i == 0) { 509 if (i == 0) {
466 *goodguess = 1; 510 *goodguess = 1;
467 } 511 }
468
469 } else { 512 } else {
470 if (i == 0 && j == 0) { 513 if (i == 0 && j == 0) {
471 *goodguess = 1; 514 *goodguess = 1;
472 } 515 }
473 } 516 }