algorithms.c 15.3 KB
Newer Older
Niels Möller's avatar
Niels Möller committed
1
2
3
4
/* algorithms.c
 *
 * Translate algorithm identifiers (or names) to algorithm objects.
 *
5
 */
Niels Möller's avatar
Niels Möller committed
6
7
8

/* lsh, an implementation of the ssh protocol
 *
Niels Möller's avatar
Niels Möller committed
9
 * Copyright (C) 1998 Niels Möller
Niels Möller's avatar
Niels Möller committed
10
11
12
13
14
15
16
17
18
19
20
21
22
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
23
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301  USA
Niels Möller's avatar
Niels Möller committed
24
25
 */

26
27
28
29
#if HAVE_CONFIG_H
#include "config.h"
#endif

Niels Möller's avatar
Niels Möller committed
30
31
32
33
34
#include "algorithms.h"

#include "atoms.h"
#include "compress.h"
#include "crypto.h"
35
36
37
#include "xalloc.h"

#include "lsh_argp.h"
Niels Möller's avatar
Niels Möller committed
38

39
#include <assert.h>
Niels Möller's avatar
Niels Möller committed
40
#include <stdarg.h>
41
#include <string.h>
Niels Möller's avatar
Niels Möller committed
42

43
44
45
46
#define GABA_DEFINE
#include "algorithms.h.x"
#undef GABA_DEFINE

47
struct alist *
48
all_symmetric_algorithms()
Niels Möller's avatar
Niels Möller committed
49
{
50
  return make_alist(14
Niels Möller's avatar
Niels Möller committed
51
#if WITH_ZLIB
52
		    +1
Niels Möller's avatar
Niels Möller committed
53
#endif
54
55
		    ,
		    ATOM_ARCFOUR, &crypto_arcfour_algorithm,
56
		    ATOM_BLOWFISH_CBC, &crypto_blowfish_cbc_algorithm,
57
		    ATOM_TWOFISH_CBC, &crypto_twofish256_cbc_algorithm,
58
59
                    ATOM_AES128_CBC, &crypto_aes128_cbc_algorithm,
                    ATOM_AES128_CTR, &crypto_aes128_ctr_algorithm,
60
                    ATOM_AES256_CBC, &crypto_aes256_cbc_algorithm,
61
                    ATOM_AES256_CTR, &crypto_aes256_ctr_algorithm,
62
		    ATOM_SERPENT256_CBC, &crypto_serpent256_cbc_algorithm,
63
		    ATOM_3DES_CBC, &crypto_des3_cbc_algorithm,
Niels Möller's avatar
Niels Möller committed
64
		    ATOM_3DES_CTR, &crypto_des3_ctr_algorithm,
Niels Möller's avatar
Niels Möller committed
65
		    ATOM_CAST128_CBC, &crypto_cast128_cbc_algorithm,
66
		    ATOM_HMAC_SHA1,
Niels Möller's avatar
Niels Möller committed
67
		      make_hmac_algorithm(&nettle_sha1),
68
69
70
71
		    ATOM_HMAC_SHA2_256,
		      make_hmac_algorithm(&nettle_sha256),
		    ATOM_HMAC_SHA2_512,
		      make_hmac_algorithm(&nettle_sha512),
Niels Möller's avatar
Niels Möller committed
72
#if WITH_ZLIB
73
		    ATOM_ZLIB, make_zlib(),
Niels Möller's avatar
Niels Möller committed
74
#endif
75
76
77
		    -1);
}

78
79
/* This is used for spki operations, and should therefore use spki names.
 * Note that md5 signatures are not currently supported. */
80
struct alist *
81
all_signature_algorithms(void)
82
83
{
  return make_alist(3,
84
85
86
		    ATOM_DSA, &dsa_algorithm,
		    ATOM_RSA_PKCS1, &rsa_sha1_algorithm,
		    ATOM_RSA_PKCS1_SHA1, &rsa_sha1_algorithm,
87
88
89
90
91
		    -1);
}

/* Forward declaration */
struct int_list *
92
filter_algorithms_l(const struct alist *algorithms, unsigned n, ...);
93
94
95

/* Includes only reasonably old algorithms and well studied
 * algorithms. */
96
struct int_list *
97
default_crypto_algorithms(const struct alist *algorithms)
98
{
99
  return filter_algorithms_l(algorithms, 4,
100
			     ATOM_AES128_CTR,
101
102
103
			     ATOM_3DES_CBC,
			     ATOM_BLOWFISH_CBC,
			     ATOM_ARCFOUR, -1);
Niels Möller's avatar
Niels Möller committed
104
105
}

106
107
108
/* Includes all supported algorithms, except none. In effect, the
 * peer is trusted in choosing an adequate algorithm. */
static struct int_list *
109
all_crypto_algorithms(const struct alist *algorithms)
110
{
Niels Möller's avatar
Niels Möller committed
111
  return filter_algorithms_l(algorithms, 11,
112
113
                             ATOM_AES128_CBC,
                             ATOM_AES128_CTR,
114
                             ATOM_AES256_CBC,
115
                             ATOM_AES256_CTR,
116
			     ATOM_3DES_CBC,
Niels Möller's avatar
Niels Möller committed
117
			     ATOM_3DES_CTR,
118
			     ATOM_TWOFISH_CBC, 
119
			     ATOM_CAST128_CBC,
120
			     ATOM_SERPENT256_CBC,
121
122
123
124
			     ATOM_BLOWFISH_CBC,
			     ATOM_ARCFOUR, -1);
}

125
struct int_list *
126
default_mac_algorithms(const struct alist *algorithms)
127
{
128
  return filter_algorithms_l(algorithms, 3, ATOM_HMAC_SHA2_256, ATOM_HMAC_SHA2_512, ATOM_HMAC_SHA1, -1);
129
130
}

131
struct int_list *
132
default_compression_algorithms(const struct alist *algorithms)
133
134
135
136
{
  return filter_algorithms_l(algorithms, 2, ATOM_NONE, ATOM_ZLIB, -1);
}

137
138
139
140
141
142
143
/* NOTE: Unfiltered */
struct int_list *
default_hostkey_algorithms(void)
{
  return make_int_list(2, ATOM_SSH_RSA, ATOM_SSH_DSS, -1);
}

144
145
146
struct int_list *
default_kex_algorithms(void)
{
147
148
  return make_int_list(3, ATOM_DIFFIE_HELLMAN_GROUP14_SHA1,
		       ATOM_DIFFIE_HELLMAN_GROUP14_SHA256,
149
150
151
		       ATOM_DIFFIE_HELLMAN_GROUP1_SHA1, -1);
}

152
153
154
155
156
157
158
static struct int_list *
prefer_compression_algorithms(struct alist *algorithms)
{
  return filter_algorithms_l(algorithms, 2, ATOM_ZLIB, ATOM_NONE, -1);
}


Niels Möller's avatar
Niels Möller committed
159
/* This is not really efficient, but it doesn't matter. */
160
static int strcasecmp_list(const char *name, ...)
Niels Möller's avatar
Niels Möller committed
161
162
163
164
165
166
167
168
{
  va_list args;
  char *s;
  int res = 0;
  
  va_start(args, name);
  while ( (s = va_arg(args, char *)) )
    {
169
      if (!strcasecmp(name, s))
Niels Möller's avatar
Niels Möller committed
170
171
172
173
174
175
176
177
178
179
	{
	  res = 1;
	  break;
	}
    }
  va_end(args);

  return res;
}
    
180
int
181
lookup_crypto(struct alist *algorithms, const char *name, struct crypto_algorithm **ap)
Niels Möller's avatar
Niels Möller committed
182
183
184
{
  int atom;

185
  if (!strcasecmp(name, "none"))
186
187
188
    {
      if (ap)
	*ap = NULL;
189
      
190
191
      return ATOM_NONE;
    }
192
  else if (strcasecmp_list(name, "arcfour", NULL))
Niels Möller's avatar
Niels Möller committed
193
    atom = ATOM_ARCFOUR;
194
  else if (strcasecmp_list(name, "twofish-cbc", "twofish", NULL))
J.H.M. Dassen's avatar
J.H.M. Dassen committed
195
    atom = ATOM_TWOFISH_CBC;
196
  else if (strcasecmp_list(name, "blowfish-cbc", "blowfish", NULL))
Niels Möller's avatar
Niels Möller committed
197
    atom = ATOM_BLOWFISH_CBC;
Niels Möller's avatar
Niels Möller committed
198
  else if (strcasecmp_list(name, "3des-cbc", NULL))
Niels Möller's avatar
Niels Möller committed
199
    atom = ATOM_3DES_CBC;
Niels Möller's avatar
Niels Möller committed
200
201
  else if (strcasecmp_list(name, "3des-ctr", "3des", NULL))
    atom = ATOM_3DES_CTR;
202
203
204
205
206
  else if (strcasecmp_list(name, "aes128-cbc", "aes-cbc", NULL))
    atom = ATOM_AES128_CBC;
  else if (strcasecmp_list(name, "aes128-ctr", "aes-ctr", "aes", "aes128", NULL))
    atom = ATOM_AES128_CTR;
  else if (strcasecmp_list(name, "aes256-cbc", NULL))
207
    atom = ATOM_AES256_CBC;
208
  else if (strcasecmp_list(name, "aes256-ctr", NULL))
209
    atom = ATOM_AES256_CTR;
210
  else if (strcasecmp_list(name, "serpent256-cbc",
211
			   "serpent-cbc", "serpent", NULL))
212
    atom = ATOM_SERPENT256_CBC;
213
  else if (strcasecmp_list(name, "cast128-cbc", "cast",
214
			   "cast-cbc", "cast128", NULL))
Niels Möller's avatar
Niels Möller committed
215
216
217
218
219
    atom = ATOM_CAST128_CBC;
  else
    return 0;

  /* Is this crypto supported? */
220
221
222
223
224
225
  {
    CAST_SUBTYPE(crypto_algorithm, a, ALIST_GET(algorithms, atom));
    if (a)
      {
	if (ap)
	  *ap = a;
226

227
228
229
230
231
	return atom;
      }
    else
      return 0;
  }
Niels Möller's avatar
Niels Möller committed
232
233
}

234
int
235
lookup_mac(struct alist *algorithms, const char *name, struct mac_algorithm **ap)
Niels Möller's avatar
Niels Möller committed
236
237
238
{
  int atom;

239
  if (!strcasecmp(name, "none"))
240
241
242
243
244
245
    {
      if (ap)
	*ap = NULL;

      return ATOM_NONE;
    }
246
  if (strcasecmp_list(name, "hmac-sha1", "sha1", NULL))
Niels Möller's avatar
Niels Möller committed
247
    atom = ATOM_HMAC_SHA1;
248
249
250
251
  else if (strcasecmp_list(name, "hmac-sha256", "sha256", NULL))
    atom = ATOM_HMAC_SHA2_256;
  else if (strcasecmp_list(name, "hmac-sha512", "sha512", NULL))
    atom = ATOM_HMAC_SHA2_512;
Niels Möller's avatar
Niels Möller committed
252
253
254
255
  else
    return 0;
  
  /* Is this mac supported? */
256
257
258
259
260
261
  {
    CAST_SUBTYPE(mac_algorithm, a, ALIST_GET(algorithms, atom));
    if (a)
      {
	if (ap)
	  *ap = a;
262

Niels Möller's avatar
Niels Möller committed
263
	return atom;
264
265
266
267
      }
    else
      return 0;
  }
Niels Möller's avatar
Niels Möller committed
268
269
}

270
int
271
lookup_compression(struct alist *algorithms, const char *name, struct compress_algorithm **ap)
Niels Möller's avatar
Niels Möller committed
272
273
274
{
  int atom;

275
  if (!strcasecmp(name, "none"))
276
277
278
    {
      if (ap)
	*ap = NULL;
279

280
281
      return ATOM_NONE;
    }
282
  if (strcasecmp_list(name, "zlib", "z", NULL))
Niels Möller's avatar
Niels Möller committed
283
284
285
286
287
    atom = ATOM_ZLIB;
  else
    return 0;
  
  /* Is this compression algorithm supported? */
288
289
290
291
292
293
  {
    CAST_SUBTYPE(compress_algorithm, a, ALIST_GET(algorithms, atom));
    if (a)
      {
	if (ap)
	  *ap = a;
294

295
296
297
298
299
	return atom;
      }
    else
      return 0;
  }
Niels Möller's avatar
Niels Möller committed
300
301
}

302
303
304
305
306
307
308
int
lookup_hostkey_algorithm(const char *name)
{
  if (!strcasecmp(name, "none"))
    return ATOM_NONE;
  else if (strcasecmp_list(name, "ssh-dss", "dsa", "dss", NULL))
    return ATOM_SSH_DSS;
309
310
311
  else if (strcasecmp_list(name, "ssh-dsa-sha256", "dsa-sha256",
			   "dsa2", NULL))
    return ATOM_SSH_DSA_SHA256_LOCAL;
312
313
314
315
316
  else if (strcasecmp_list(name, "spki-sign-rsa", "spki-rsa", NULL))
    return ATOM_SPKI_SIGN_RSA;
  else if (strcasecmp_list(name, "spki-sign-dss", "spki-dss",
			   "spki-sign-dsa", "spki-dsa", NULL))
    return ATOM_SPKI_SIGN_DSS;
317
318
319
320
  else
    return 0;
}

321
322
323
324
325
326
327
int
lookup_kex_algorithm(const char *name)
{
  if (strcasecmp_list(name, "diffie-hellman-group1-sha1",
		       "dh-group1-sha1", "dh-group1", NULL))
    return ATOM_DIFFIE_HELLMAN_GROUP1_SHA1;
  else if (strcasecmp_list(name, "diffie-hellman-group14-sha1",
328
			    "dh-group14-sha1", NULL))
329
    return ATOM_DIFFIE_HELLMAN_GROUP14_SHA1;
330
331
332
  else if (strcasecmp_list(name, "diffie-hellman-group14-sha256",
			    "dh-group14-sha256", "dh-group14", NULL))
    return ATOM_DIFFIE_HELLMAN_GROUP14_SHA256;
333
334
335
336
  else
    return 0;
}

337
338
339
340
/* Return an int list containing the elements of CANDIDATES
 * that have associated values in ALGORITHMS.
 * Returns a non-empty list or NULL. */
 
Niels Möller's avatar
Niels Möller committed
341
struct int_list *
342
filter_algorithms(const struct alist *algorithms,
343
		  const struct int_list *candidates)
Niels Möller's avatar
Niels Möller committed
344
{
345
346
347
348
349
350
351
352
353
354
355
  struct int_list *l;
  unsigned i, j;
  unsigned supported;
  
  for (i = 0, supported = 0; i < LIST_LENGTH(candidates); i++)
    {
      int atom = LIST(candidates)[i];
      if (ALIST_GET(algorithms, atom)
	  || (atom == ATOM_NONE))
	supported++;
    }
356

357
358
  if (!supported)
    return NULL;
359
  
360
  l = alloc_int_list(supported);
361

362
  for (i = j = 0; i < LIST_LENGTH(candidates); i++)
363
    {
364
365
366
      int atom = LIST(candidates)[i];
      if (ALIST_GET(algorithms, atom)
	  || (atom == ATOM_NONE))
367
	{
368
369
	  assert(j < supported);
	  LIST(l)[j++] = atom;
370
371
	}
    }
372
373
374
  assert(j == supported);

  return l;
375
376
}

377
378

struct int_list *
379
filter_algorithms_l(const struct alist *algorithms, unsigned n, ...)
380
381
{
  va_list args;
382
383
  struct int_list *l;
  struct int_list *candidates;
384
385
  
  va_start(args, n);
386
  candidates = make_int_listv(n, args);
387
  va_end(args);
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
  
  l = filter_algorithms(algorithms, candidates);

  assert(LIST_LENGTH(l));
  
  KILL(candidates);
  return l;
}


static void
list_algorithms(const struct argp_state *state,
		char *prefix,
		struct int_list *algorithms,
		int none)
{
  unsigned i;
  int separate;
  
  fprintf(state->out_stream, "%s", prefix);

  for (i = 0, separate = 0; i<LIST_LENGTH(algorithms); i++)
    {
      if (separate)
	fprintf(state->out_stream, ", ");
      
      fprintf(state->out_stream, "%s",
	      /* NOTE: This is the only place where we use that
	       * atom names are NUL-terminated. */
	      get_atom_name(LIST(algorithms)[i]));
      separate = 1;
    }

  if (none)
    {
      if (separate)
	fprintf(state->out_stream, ", ");
      fprintf(state->out_stream, "none");
    }
427
428

  fprintf(state->out_stream, "\n");
429
430
}

431
void
432
433
434
list_crypto_algorithms(const struct argp_state *state,
		       struct alist *algorithms)
{
435
436
437
438
  list_algorithms(state,
		  "Supported crypto algorithms: ",
		  all_crypto_algorithms(algorithms),
		  1);
439
440
}

441
void
442
443
444
list_mac_algorithms(const struct argp_state *state,
		    struct alist *algorithms)
{
445
446
447
448
  list_algorithms(state,
		  "Supported MAC algorithms: ",
		  default_mac_algorithms(algorithms),
		  1);
449
450
}

451
void
452
453
454
list_compression_algorithms(const struct argp_state *state,
			    struct alist *algorithms)
{
455
456
457
458
459
460
461
462
463
  list_algorithms(state, 
		  "Supported compression algorithms: ",
		  default_compression_algorithms(algorithms),
		  0);
}

void
list_hostkey_algorithms(const struct argp_state *state)
{
464
  fprintf(state->out_stream, "%s", "Supported hostkey algorithms: ssh-dss, spki, none\n");
465
466
}

467
468
469
void
list_kex_algorithms(const struct argp_state *state)
{
470
471
  fprintf(state->out_stream, "%s",
	  "Supported key exchange algorithms: dh-group1-sha1, dh-group14-sha1\n");
472
473
}

474
475

#define OPT_LIST_ALGORITHMS 0x100
476
#define OPT_HOSTKEY_ALGORITHMS 0x101
477
#define OPT_KEX_ALGORITHM 0x102
478

479
480
481
482
483
static const struct argp_option
algorithms_options[] =
{
  /* Name, key, arg-name, flags, doc, group */
  { NULL, 0, NULL, 0, "Algorithm selection:", 0},
484
485
  { "crypto", 'c', "ALGORITHM", 0, "", 0 },
  { "compression", 'z', "ALGORITHM",
486
    OPTION_ARG_OPTIONAL, "Default is zlib.", 0 },
487
  { "mac", 'm', "ALGORITHM", 0, "", 0 },
488
489
  { "hostkey-algorithm", OPT_HOSTKEY_ALGORITHMS, "ALGORITHM", 0, "", 0 },
  { "kex-algorithm", OPT_KEX_ALGORITHM, "ALGORITHM", 0, "", 0 },
490
491
  { "list-algorithms", OPT_LIST_ALGORITHMS, NULL, 0,
    "List supported algorithms.", 0 },
492
493
494
  { NULL, 0, NULL, 0, NULL, 0 }  
};

495
496
497
void
init_algorithms_options(struct algorithms_options *self,
			struct alist *algorithms)
498
499
500
501
502
503
{
  self->algorithms = algorithms;

  self->crypto_algorithms = NULL;
  self->mac_algorithms = NULL;
  self->compression_algorithms = NULL;
504
  self->hostkey_algorithms = NULL;
505
  self->kex_algorithms = NULL;
506
507
}

508
509
510
511
512
513
514
515
516
struct algorithms_options *
make_algorithms_options(struct alist *algorithms)
{
  NEW(algorithms_options, self);
  init_algorithms_options(self, algorithms);

  return self;
}

517
518
519
520
521
522
523
524
525
526
527
static error_t
algorithms_argp_parser(int key, char *arg, struct argp_state *state)
{
  CAST_SUBTYPE(algorithms_options, self, state->input);
  
  switch(key)
    {
    default:
      return ARGP_ERR_UNKNOWN;
    case ARGP_KEY_END:
      if (!self->crypto_algorithms)
528
	self->crypto_algorithms = default_crypto_algorithms(self->algorithms);
529
      if (!self->mac_algorithms)
530
	self->mac_algorithms = default_mac_algorithms(self->algorithms);
531
      if (!self->compression_algorithms)
532
533
	self->compression_algorithms = default_compression_algorithms(self->algorithms);
      if (!self->hostkey_algorithms)
534
	self->hostkey_algorithms = default_hostkey_algorithms();
535
536
      if (!self->kex_algorithms)
	self->kex_algorithms = default_kex_algorithms();
537
538
539
      break;
    case 'c':
      {
540
	int crypto = lookup_crypto(self->algorithms, arg, NULL);
541

542
543
	if (crypto)
	  self->crypto_algorithms = make_int_list(1, crypto, -1);
544
545
546
	else if (strcasecmp_list(arg, "all", "any", NULL))
	  self->crypto_algorithms = all_crypto_algorithms(self->algorithms);
	
547
	else
548
549
550
551
	  {
	    list_crypto_algorithms(state, self->algorithms);
	    argp_error(state, "Unknown crypto algorithm '%s'.", arg);
	  }
552
553
554
555
	break;
      }
    case 'm':
      {
556
	int mac = lookup_mac(self->algorithms, arg, NULL);
557
558
559
	if (mac)
	  self->mac_algorithms = make_int_list(1, mac, -1);
	else
560
561
562
563
	  {
	    list_mac_algorithms(state, self->algorithms);
	    argp_error(state, "Unknown message authentication algorithm '%s'.", arg);
	  }	
564
565
566
567
568
	break;
      }
    case 'z':
      {
	if (!arg)
569
	  self->compression_algorithms = prefer_compression_algorithms(self->algorithms);
570
	else
571
	  {
572
	    int compression = lookup_compression(self->algorithms, arg, NULL);
573
574
575
576
577
578
579
580
	    if (compression)
	      self->compression_algorithms = make_int_list(1, compression, -1);
	    else
	      {
		list_compression_algorithms(state, self->algorithms);
		argp_error(state, "Unknown compression algorithm '%s'.", arg);
	      }
	  }
581
	break;
582
      }
583
584
585
586
587
588
589
590
591
592
593
    case OPT_HOSTKEY_ALGORITHMS:
      {
	int algorithm = lookup_hostkey_algorithm(arg);
	if (algorithm)
	  self->hostkey_algorithms = make_int_list(1, algorithm, -1);
	else
	  {
	    list_hostkey_algorithms(state);
	    argp_error(state, "Unknown hostkey algorithm '%s'.", arg);
	  }	
	break;
594
      }
595
	
596
597
598
599
600
601
602
603
604
605
606
    case OPT_KEX_ALGORITHM:
      {
	int algorithm = lookup_kex_algorithm(arg);
	if (algorithm)
	  self->kex_algorithms = make_int_list(1, algorithm, -1);
	else
	  {
	    list_kex_algorithms(state);
	    argp_error(state, "Unknown hostkey algorithm '%s'.", arg);
	  }	
	break;
607
608
      }
      
609
610
611
612
    case OPT_LIST_ALGORITHMS:
      list_crypto_algorithms(state, self->algorithms);
      list_compression_algorithms(state, self->algorithms);
      list_mac_algorithms(state, self->algorithms);
613
      list_hostkey_algorithms(state);
614
      list_kex_algorithms(state);
615
      
616
617
      if (! (state->flags & ARGP_NO_EXIT))
	exit (0);
618
619
620
621
622
623
624
625
    }
  return 0;
}

const struct argp algorithms_argp =
{
  algorithms_options,
  algorithms_argp_parser,
626
  NULL, NULL, NULL, NULL, NULL
627
};