common-algo.c 16 KB

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