Coverage Report

Created: 2025-07-18 06:52

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