common-algo.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580
  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. #include "includes.h"
  26. #include "algo.h"
  27. #include "session.h"
  28. #include "dbutil.h"
  29. #include "dh_groups.h"
  30. #include "ltc_prng.h"
  31. #include "ecc.h"
  32. /* This file (algo.c) organises the ciphers which can be used, and is used to
  33. * decide which ciphers/hashes/compression/signing to use during key exchange*/
  34. static int void_cipher(const unsigned char* in, unsigned char* out,
  35. unsigned long len, void* UNUSED(cipher_state)) {
  36. if (in != out) {
  37. memmove(out, in, len);
  38. }
  39. return CRYPT_OK;
  40. }
  41. static int void_start(int UNUSED(cipher), const unsigned char* UNUSED(IV),
  42. const unsigned char* UNUSED(key),
  43. int UNUSED(keylen), int UNUSED(num_rounds), void* UNUSED(cipher_state)) {
  44. return CRYPT_OK;
  45. }
  46. /* Mappings for ciphers, parameters are
  47. {&cipher_desc, keysize, blocksize} */
  48. /* Remember to add new ciphers/hashes to regciphers/reghashes too */
  49. #ifdef DROPBEAR_AES256
  50. static const struct dropbear_cipher dropbear_aes256 =
  51. {&aes_desc, 32, 16};
  52. #endif
  53. #ifdef DROPBEAR_AES128
  54. static const struct dropbear_cipher dropbear_aes128 =
  55. {&aes_desc, 16, 16};
  56. #endif
  57. #ifdef DROPBEAR_BLOWFISH
  58. static const struct dropbear_cipher dropbear_blowfish =
  59. {&blowfish_desc, 16, 8};
  60. #endif
  61. #ifdef DROPBEAR_TWOFISH256
  62. static const struct dropbear_cipher dropbear_twofish256 =
  63. {&twofish_desc, 32, 16};
  64. #endif
  65. #ifdef DROPBEAR_TWOFISH128
  66. static const struct dropbear_cipher dropbear_twofish128 =
  67. {&twofish_desc, 16, 16};
  68. #endif
  69. #ifdef DROPBEAR_3DES
  70. static const struct dropbear_cipher dropbear_3des =
  71. {&des3_desc, 24, 8};
  72. #endif
  73. /* used to indicate no encryption, as defined in rfc2410 */
  74. const struct dropbear_cipher dropbear_nocipher =
  75. {NULL, 16, 8};
  76. /* A few void* s are required to silence warnings
  77. * about the symmetric_CBC vs symmetric_CTR cipher_state pointer */
  78. #ifdef DROPBEAR_ENABLE_CBC_MODE
  79. const struct dropbear_cipher_mode dropbear_mode_cbc =
  80. {(void*)cbc_start, (void*)cbc_encrypt, (void*)cbc_decrypt};
  81. #endif /* DROPBEAR_ENABLE_CBC_MODE */
  82. const struct dropbear_cipher_mode dropbear_mode_none =
  83. {void_start, void_cipher, void_cipher};
  84. #ifdef DROPBEAR_ENABLE_CTR_MODE
  85. /* a wrapper to make ctr_start and cbc_start look the same */
  86. static int dropbear_big_endian_ctr_start(int cipher,
  87. const unsigned char *IV,
  88. const unsigned char *key, int keylen,
  89. int num_rounds, symmetric_CTR *ctr) {
  90. return ctr_start(cipher, IV, key, keylen, num_rounds, CTR_COUNTER_BIG_ENDIAN, ctr);
  91. }
  92. const struct dropbear_cipher_mode dropbear_mode_ctr =
  93. {(void*)dropbear_big_endian_ctr_start, (void*)ctr_encrypt, (void*)ctr_decrypt};
  94. #endif /* DROPBEAR_ENABLE_CTR_MODE */
  95. /* Mapping of ssh hashes to libtomcrypt hashes, including keysize etc.
  96. {&hash_desc, keysize, hashsize} */
  97. #ifdef DROPBEAR_SHA1_HMAC
  98. static const struct dropbear_hash dropbear_sha1 =
  99. {&sha1_desc, 20, 20};
  100. #endif
  101. #ifdef DROPBEAR_SHA1_96_HMAC
  102. static const struct dropbear_hash dropbear_sha1_96 =
  103. {&sha1_desc, 20, 12};
  104. #endif
  105. #ifdef DROPBEAR_SHA2_256_HMAC
  106. static const struct dropbear_hash dropbear_sha2_256 =
  107. {&sha256_desc, 32, 32};
  108. #endif
  109. #ifdef DROPBEAR_SHA2_512_HMAC
  110. static const struct dropbear_hash dropbear_sha2_512 =
  111. {&sha512_desc, 64, 64};
  112. #endif
  113. #ifdef DROPBEAR_MD5_HMAC
  114. static const struct dropbear_hash dropbear_md5 =
  115. {&md5_desc, 16, 16};
  116. #endif
  117. const struct dropbear_hash dropbear_nohash =
  118. {NULL, 16, 0}; /* used initially */
  119. /* The following map ssh names to internal values.
  120. * The ordering here is important for the client - the first mode
  121. * that is also supported by the server will get used. */
  122. algo_type sshciphers[] = {
  123. #ifdef DROPBEAR_ENABLE_CTR_MODE
  124. #ifdef DROPBEAR_AES128
  125. {"aes128-ctr", 0, &dropbear_aes128, 1, &dropbear_mode_ctr},
  126. #endif
  127. #ifdef DROPBEAR_AES256
  128. {"aes256-ctr", 0, &dropbear_aes256, 1, &dropbear_mode_ctr},
  129. #endif
  130. #ifdef DROPBEAR_TWOFISH_CTR
  131. /* twofish ctr is conditional as it hasn't been tested for interoperability, see options.h */
  132. #ifdef DROPBEAR_TWOFISH256
  133. {"twofish256-ctr", 0, &dropbear_twofish256, 1, &dropbear_mode_ctr},
  134. #endif
  135. #ifdef DROPBEAR_TWOFISH128
  136. {"twofish128-ctr", 0, &dropbear_twofish128, 1, &dropbear_mode_ctr},
  137. #endif
  138. #endif /* DROPBEAR_TWOFISH_CTR */
  139. #endif /* DROPBEAR_ENABLE_CTR_MODE */
  140. #ifdef DROPBEAR_ENABLE_CBC_MODE
  141. #ifdef DROPBEAR_AES128
  142. {"aes128-cbc", 0, &dropbear_aes128, 1, &dropbear_mode_cbc},
  143. #endif
  144. #ifdef DROPBEAR_AES256
  145. {"aes256-cbc", 0, &dropbear_aes256, 1, &dropbear_mode_cbc},
  146. #endif
  147. #ifdef DROPBEAR_TWOFISH256
  148. {"twofish256-cbc", 0, &dropbear_twofish256, 1, &dropbear_mode_cbc},
  149. {"twofish-cbc", 0, &dropbear_twofish256, 1, &dropbear_mode_cbc},
  150. #endif
  151. #ifdef DROPBEAR_TWOFISH128
  152. {"twofish128-cbc", 0, &dropbear_twofish128, 1, &dropbear_mode_cbc},
  153. #endif
  154. #ifdef DROPBEAR_3DES
  155. {"3des-ctr", 0, &dropbear_3des, 1, &dropbear_mode_ctr},
  156. #endif
  157. #ifdef DROPBEAR_3DES
  158. {"3des-cbc", 0, &dropbear_3des, 1, &dropbear_mode_cbc},
  159. #endif
  160. #ifdef DROPBEAR_BLOWFISH
  161. {"blowfish-cbc", 0, &dropbear_blowfish, 1, &dropbear_mode_cbc},
  162. #endif
  163. #endif /* DROPBEAR_ENABLE_CBC_MODE */
  164. #ifdef DROPBEAR_NONE_CIPHER
  165. {"none", 0, (void*)&dropbear_nocipher, 1, &dropbear_mode_none},
  166. #endif
  167. {NULL, 0, NULL, 0, NULL}
  168. };
  169. algo_type sshhashes[] = {
  170. #ifdef DROPBEAR_SHA1_96_HMAC
  171. {"hmac-sha1-96", 0, &dropbear_sha1_96, 1, NULL},
  172. #endif
  173. #ifdef DROPBEAR_SHA1_HMAC
  174. {"hmac-sha1", 0, &dropbear_sha1, 1, NULL},
  175. #endif
  176. #ifdef DROPBEAR_SHA2_256_HMAC
  177. {"hmac-sha2-256", 0, &dropbear_sha2_256, 1, NULL},
  178. #endif
  179. #ifdef DROPBEAR_SHA2_512_HMAC
  180. {"hmac-sha2-512", 0, &dropbear_sha2_512, 1, NULL},
  181. #endif
  182. #ifdef DROPBEAR_MD5_HMAC
  183. {"hmac-md5", 0, (void*)&dropbear_md5, 1, NULL},
  184. #endif
  185. #ifdef DROPBEAR_NONE_INTEGRITY
  186. {"none", 0, (void*)&dropbear_nohash, 1, NULL},
  187. #endif
  188. {NULL, 0, NULL, 0, NULL}
  189. };
  190. #ifndef DISABLE_ZLIB
  191. algo_type ssh_compress[] = {
  192. {"zlib@openssh.com", DROPBEAR_COMP_ZLIB_DELAY, NULL, 1, NULL},
  193. {"zlib", DROPBEAR_COMP_ZLIB, NULL, 1, NULL},
  194. {"none", DROPBEAR_COMP_NONE, NULL, 1, NULL},
  195. {NULL, 0, NULL, 0, NULL}
  196. };
  197. algo_type ssh_delaycompress[] = {
  198. {"zlib@openssh.com", DROPBEAR_COMP_ZLIB_DELAY, NULL, 1, NULL},
  199. {"none", DROPBEAR_COMP_NONE, NULL, 1, NULL},
  200. {NULL, 0, NULL, 0, NULL}
  201. };
  202. #endif
  203. algo_type ssh_nocompress[] = {
  204. {"none", DROPBEAR_COMP_NONE, NULL, 1, NULL},
  205. {NULL, 0, NULL, 0, NULL}
  206. };
  207. algo_type sshhostkey[] = {
  208. #ifdef DROPBEAR_ECDSA
  209. #ifdef DROPBEAR_ECC_256
  210. {"ecdsa-sha2-nistp256", DROPBEAR_SIGNKEY_ECDSA_NISTP256, NULL, 1, NULL},
  211. #endif
  212. #ifdef DROPBEAR_ECC_384
  213. {"ecdsa-sha2-nistp384", DROPBEAR_SIGNKEY_ECDSA_NISTP384, NULL, 1, NULL},
  214. #endif
  215. #ifdef DROPBEAR_ECC_521
  216. {"ecdsa-sha2-nistp521", DROPBEAR_SIGNKEY_ECDSA_NISTP521, NULL, 1, NULL},
  217. #endif
  218. #endif
  219. #ifdef DROPBEAR_RSA
  220. {"ssh-rsa", DROPBEAR_SIGNKEY_RSA, NULL, 1, NULL},
  221. #endif
  222. #ifdef DROPBEAR_DSS
  223. {"ssh-dss", DROPBEAR_SIGNKEY_DSS, NULL, 1, NULL},
  224. #endif
  225. {NULL, 0, NULL, 0, NULL}
  226. };
  227. #if DROPBEAR_DH_GROUP1
  228. static const struct dropbear_kex kex_dh_group1 = {DROPBEAR_KEX_NORMAL_DH, dh_p_1, DH_P_1_LEN, NULL, &sha1_desc };
  229. #endif
  230. #if DROPBEAR_DH_GROUP14
  231. static const struct dropbear_kex kex_dh_group14_sha1 = {DROPBEAR_KEX_NORMAL_DH, dh_p_14, DH_P_14_LEN, NULL, &sha1_desc };
  232. #if DROPBEAR_DH_GROUP14_256
  233. static const struct dropbear_kex kex_dh_group14_sha256 = {DROPBEAR_KEX_NORMAL_DH, dh_p_14, DH_P_14_LEN, NULL, &sha256_desc };
  234. #endif
  235. #endif
  236. #if DROPBEAR_DH_GROUP16
  237. static const struct dropbear_kex kex_dh_group16_sha512 = {DROPBEAR_KEX_NORMAL_DH, dh_p_16, DH_P_16_LEN, NULL, &sha512_desc };
  238. #endif
  239. /* These can't be const since dropbear_ecc_fill_dp() fills out
  240. ecc_curve at runtime */
  241. #ifdef DROPBEAR_ECDH
  242. #ifdef DROPBEAR_ECC_256
  243. static const struct dropbear_kex kex_ecdh_nistp256 = {DROPBEAR_KEX_ECDH, NULL, 0, &ecc_curve_nistp256, &sha256_desc };
  244. #endif
  245. #ifdef DROPBEAR_ECC_384
  246. static const struct dropbear_kex kex_ecdh_nistp384 = {DROPBEAR_KEX_ECDH, NULL, 0, &ecc_curve_nistp384, &sha384_desc };
  247. #endif
  248. #ifdef DROPBEAR_ECC_521
  249. static const struct dropbear_kex kex_ecdh_nistp521 = {DROPBEAR_KEX_ECDH, NULL, 0, &ecc_curve_nistp521, &sha512_desc };
  250. #endif
  251. #endif /* DROPBEAR_ECDH */
  252. #ifdef DROPBEAR_CURVE25519
  253. /* Referred to directly */
  254. static const struct dropbear_kex kex_curve25519 = {DROPBEAR_KEX_CURVE25519, NULL, 0, NULL, &sha256_desc };
  255. #endif
  256. algo_type sshkex[] = {
  257. #ifdef DROPBEAR_CURVE25519
  258. {"curve25519-sha256@libssh.org", 0, &kex_curve25519, 1, NULL},
  259. #endif
  260. #ifdef DROPBEAR_ECDH
  261. #ifdef DROPBEAR_ECC_521
  262. {"ecdh-sha2-nistp521", 0, &kex_ecdh_nistp521, 1, NULL},
  263. #endif
  264. #ifdef DROPBEAR_ECC_384
  265. {"ecdh-sha2-nistp384", 0, &kex_ecdh_nistp384, 1, NULL},
  266. #endif
  267. #ifdef DROPBEAR_ECC_256
  268. {"ecdh-sha2-nistp256", 0, &kex_ecdh_nistp256, 1, NULL},
  269. #endif
  270. #endif
  271. #if DROPBEAR_DH_GROUP14
  272. #if DROPBEAR_DH_GROUP14_256
  273. {"diffie-hellman-group14-sha256", 0, &kex_dh_group14_sha256, 1, NULL},
  274. #endif
  275. {"diffie-hellman-group14-sha1", 0, &kex_dh_group14_sha1, 1, NULL},
  276. #endif
  277. #if DROPBEAR_DH_GROUP1
  278. {"diffie-hellman-group1-sha1", 0, &kex_dh_group1, 1, NULL},
  279. #endif
  280. #if DROPBEAR_DH_GROUP16
  281. {"diffie-hellman-group16-sha512", 0, &kex_dh_group16_sha512, 1, NULL},
  282. #endif
  283. #ifdef USE_KEXGUESS2
  284. {KEXGUESS2_ALGO_NAME, KEXGUESS2_ALGO_ID, NULL, 1, NULL},
  285. #endif
  286. {NULL, 0, NULL, 0, NULL}
  287. };
  288. /* algolen specifies the length of algo, algos is our local list to match
  289. * against.
  290. * Returns DROPBEAR_SUCCESS if we have a match for algo, DROPBEAR_FAILURE
  291. * otherwise */
  292. int have_algo(char* algo, size_t algolen, algo_type algos[]) {
  293. int i;
  294. for (i = 0; algos[i].name != NULL; i++) {
  295. if (strlen(algos[i].name) == algolen
  296. && (strncmp(algos[i].name, algo, algolen) == 0)) {
  297. return DROPBEAR_SUCCESS;
  298. }
  299. }
  300. return DROPBEAR_FAILURE;
  301. }
  302. /* Output a comma separated list of algorithms to a buffer */
  303. void buf_put_algolist(buffer * buf, algo_type localalgos[]) {
  304. unsigned int i, len;
  305. unsigned int donefirst = 0;
  306. buffer *algolist = NULL;
  307. algolist = buf_new(300);
  308. for (i = 0; localalgos[i].name != NULL; i++) {
  309. if (localalgos[i].usable) {
  310. if (donefirst)
  311. buf_putbyte(algolist, ',');
  312. donefirst = 1;
  313. len = strlen(localalgos[i].name);
  314. buf_putbytes(algolist, (const unsigned char *) localalgos[i].name, len);
  315. }
  316. }
  317. buf_putstring(buf, (const char*)algolist->data, algolist->len);
  318. buf_free(algolist);
  319. }
  320. /* match the first algorithm in the comma-separated list in buf which is
  321. * also in localalgos[], or return NULL on failure.
  322. * (*goodguess) is set to 1 if the preferred client/server algos match,
  323. * 0 otherwise. This is used for checking if the kexalgo/hostkeyalgos are
  324. * guessed correctly */
  325. algo_type * buf_match_algo(buffer* buf, algo_type localalgos[],
  326. enum kexguess2_used *kexguess2, int *goodguess)
  327. {
  328. char * algolist = NULL;
  329. const char *remotenames[MAX_PROPOSED_ALGO], *localnames[MAX_PROPOSED_ALGO];
  330. unsigned int len;
  331. unsigned int remotecount, localcount, clicount, servcount, i, j;
  332. algo_type * ret = NULL;
  333. const char **clinames, **servnames;
  334. if (goodguess) {
  335. *goodguess = 0;
  336. }
  337. /* get the comma-separated list from the buffer ie "algo1,algo2,algo3" */
  338. algolist = buf_getstring(buf, &len);
  339. TRACE(("buf_match_algo: %s", algolist))
  340. if (len > MAX_PROPOSED_ALGO*(MAX_NAME_LEN+1)) {
  341. goto out;
  342. }
  343. /* remotenames will contain a list of the strings parsed out */
  344. /* We will have at least one string (even if it's just "") */
  345. remotenames[0] = algolist;
  346. remotecount = 1;
  347. for (i = 0; i < len; i++) {
  348. if (algolist[i] == '\0') {
  349. /* someone is trying something strange */
  350. goto out;
  351. }
  352. if (algolist[i] == ',') {
  353. algolist[i] = '\0';
  354. remotenames[remotecount] = &algolist[i+1];
  355. remotecount++;
  356. }
  357. if (remotecount >= MAX_PROPOSED_ALGO) {
  358. break;
  359. }
  360. }
  361. if (kexguess2 && *kexguess2 == KEXGUESS2_LOOK) {
  362. for (i = 0; i < remotecount; i++)
  363. {
  364. if (strcmp(remotenames[i], KEXGUESS2_ALGO_NAME) == 0) {
  365. *kexguess2 = KEXGUESS2_YES;
  366. break;
  367. }
  368. }
  369. if (*kexguess2 == KEXGUESS2_LOOK) {
  370. *kexguess2 = KEXGUESS2_NO;
  371. }
  372. }
  373. for (i = 0; localalgos[i].name != NULL; i++) {
  374. if (localalgos[i].usable) {
  375. localnames[i] = localalgos[i].name;
  376. } else {
  377. localnames[i] = NULL;
  378. }
  379. }
  380. localcount = i;
  381. if (IS_DROPBEAR_SERVER) {
  382. clinames = remotenames;
  383. clicount = remotecount;
  384. servnames = localnames;
  385. servcount = localcount;
  386. } else {
  387. clinames = localnames;
  388. clicount = localcount;
  389. servnames = remotenames;
  390. servcount = remotecount;
  391. }
  392. /* iterate and find the first match */
  393. for (i = 0; i < clicount; i++) {
  394. for (j = 0; j < servcount; j++) {
  395. if (!(servnames[j] && clinames[i])) {
  396. /* unusable algos are NULL */
  397. continue;
  398. }
  399. if (strcmp(servnames[j], clinames[i]) == 0) {
  400. /* set if it was a good guess */
  401. if (goodguess && kexguess2) {
  402. if (*kexguess2 == KEXGUESS2_YES) {
  403. if (i == 0) {
  404. *goodguess = 1;
  405. }
  406. } else {
  407. if (i == 0 && j == 0) {
  408. *goodguess = 1;
  409. }
  410. }
  411. }
  412. /* set the algo to return */
  413. if (IS_DROPBEAR_SERVER) {
  414. ret = &localalgos[j];
  415. } else {
  416. ret = &localalgos[i];
  417. }
  418. goto out;
  419. }
  420. }
  421. }
  422. out:
  423. m_free(algolist);
  424. return ret;
  425. }
  426. #ifdef DROPBEAR_NONE_CIPHER
  427. void
  428. set_algo_usable(algo_type algos[], const char * algo_name, int usable)
  429. {
  430. algo_type *a;
  431. for (a = algos; a->name != NULL; a++)
  432. {
  433. if (strcmp(a->name, algo_name) == 0)
  434. {
  435. a->usable = usable;
  436. return;
  437. }
  438. }
  439. }
  440. int
  441. get_algo_usable(algo_type algos[], const char * algo_name)
  442. {
  443. algo_type *a;
  444. for (a = algos; a->name != NULL; a++)
  445. {
  446. if (strcmp(a->name, algo_name) == 0)
  447. {
  448. return a->usable;
  449. }
  450. }
  451. return 0;
  452. }
  453. #endif /* DROPBEAR_NONE_CIPHER */
  454. #ifdef ENABLE_USER_ALGO_LIST
  455. char *
  456. algolist_string(algo_type algos[])
  457. {
  458. char *ret_list;
  459. buffer *b = buf_new(200);
  460. buf_put_algolist(b, algos);
  461. buf_setpos(b, b->len);
  462. buf_putbyte(b, '\0');
  463. buf_setpos(b, 4);
  464. ret_list = m_strdup((const char *) buf_getptr(b, b->len - b->pos));
  465. buf_free(b);
  466. return ret_list;
  467. }
  468. static algo_type*
  469. check_algo(const char* algo_name, algo_type *algos)
  470. {
  471. algo_type *a;
  472. for (a = algos; a->name != NULL; a++)
  473. {
  474. if (strcmp(a->name, algo_name) == 0)
  475. {
  476. return a;
  477. }
  478. }
  479. return NULL;
  480. }
  481. /* Checks a user provided comma-separated algorithm list for available
  482. * options. Any that are not acceptable are removed in-place. Returns the
  483. * number of valid algorithms. */
  484. int
  485. check_user_algos(const char* user_algo_list, algo_type * algos,
  486. const char *algo_desc)
  487. {
  488. algo_type new_algos[MAX_PROPOSED_ALGO+1];
  489. char *work_list = m_strdup(user_algo_list);
  490. char *start = work_list;
  491. char *c;
  492. int n;
  493. /* So we can iterate and look for null terminator */
  494. memset(new_algos, 0x0, sizeof(new_algos));
  495. for (c = work_list, n = 0; ; c++)
  496. {
  497. char oc = *c;
  498. if (n >= MAX_PROPOSED_ALGO) {
  499. dropbear_exit("Too many algorithms '%s'", user_algo_list);
  500. }
  501. if (*c == ',' || *c == '\0') {
  502. algo_type *match_algo = NULL;
  503. *c = '\0';
  504. match_algo = check_algo(start, algos);
  505. if (match_algo) {
  506. if (check_algo(start, new_algos)) {
  507. TRACE(("Skip repeated algorithm '%s'", start))
  508. } else {
  509. new_algos[n] = *match_algo;
  510. n++;
  511. }
  512. } else {
  513. dropbear_log(LOG_WARNING, "This Dropbear program does not support '%s' %s algorithm", start, algo_desc);
  514. }
  515. c++;
  516. start = c;
  517. }
  518. if (oc == '\0') {
  519. break;
  520. }
  521. }
  522. m_free(work_list);
  523. /* n+1 to include a null terminator */
  524. memcpy(algos, new_algos, sizeof(*new_algos) * (n+1));
  525. return n;
  526. }
  527. #endif /* ENABLE_USER_ALGO_LIST */