Subversion Repositories

?revision_form?Rev ?revision_input??revision_submit??revision_endform?

Rev 63 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
60 magnus 1
#! /bin/sh /usr/share/dpatch/dpatch-run
2
## blacklist.dpatch by Magnus Holmgren <holmgren@debian.org>
64 magnus 3
## blacklist.c code copied from the openssh package and adapted for LSH.
60 magnus 4
##
5
## DP: Check keys against openssh-blacklist before accepting for
6
## DP: pubkey authentication as well as on conversion by lsh-writekey
7
## DP: and lsh-decode-key.
8
 
9
@DPATCH@
10
diff -urNad trunk~/src/Makefile.am trunk/src/Makefile.am
11
--- trunk~/src/Makefile.am	2004-11-18 22:52:16.000000000 +0100
63 magnus 12
+++ trunk/src/Makefile.am	2009-11-0 23:57:07.000000000 +0100
60 magnus 13
@@ -72,7 +72,8 @@
14
 	unix_interact.c unix_process.c unix_random.c unix_user.c \
15
 	userauth.c \
16
 	werror.c write_buffer.c write_packet.c \
17
-	xalloc.c xauth.c zlib.c
18
+	xalloc.c xauth.c zlib.c \
19
+	blacklist.c
20
 
21
 liblsh_a_LIBADD = @LIBOBJS@
22
 
23
diff -urNad trunk~/src/Makefile.in trunk/src/Makefile.in
63 magnus 24
--- trunk~/src/Makefile.in	2009-11-07 23:57:06.000000000 +0100
25
+++ trunk/src/Makefile.in	2009-11-07 23:57:07.000000000 +0100
60 magnus 26
@@ -91,7 +91,8 @@
27
 	tty.$(OBJEXT) unix_interact.$(OBJEXT) unix_process.$(OBJEXT) \
28
 	unix_random.$(OBJEXT) unix_user.$(OBJEXT) userauth.$(OBJEXT) \
29
 	werror.$(OBJEXT) write_buffer.$(OBJEXT) write_packet.$(OBJEXT) \
30
-	xalloc.$(OBJEXT) xauth.$(OBJEXT) zlib.$(OBJEXT)
31
+	xalloc.$(OBJEXT) xauth.$(OBJEXT) zlib.$(OBJEXT) \
32
+	blacklist.$(OBJEXT)
33
 liblsh_a_OBJECTS = $(am_liblsh_a_OBJECTS)
34
 am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(sbindir)" \
35
 	"$(DESTDIR)$(bindir)"
36
@@ -510,7 +511,8 @@
37
 	unix_interact.c unix_process.c unix_random.c unix_user.c \
38
 	userauth.c \
39
 	werror.c write_buffer.c write_packet.c \
40
-	xalloc.c xauth.c zlib.c
41
+	xalloc.c xauth.c zlib.c \
42
+	blacklist.c
43
 
44
 liblsh_a_LIBADD = @LIBOBJS@
45
 
46
@@ -705,6 +707,7 @@
47
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/algorithms.Po@am__quote@
48
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/alist.Po@am__quote@
49
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/atoms.Po@am__quote@
50
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/blacklist.Po@am__quote@
51
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/channel.Po@am__quote@
52
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/channel_commands.Po@am__quote@
53
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/channel_forward.Po@am__quote@
63 magnus 54
diff -urNad trunk~/src/abstract_crypto.h trunk/src/abstract_crypto.h
55
--- trunk~/src/abstract_crypto.h	2003-11-16 19:10:30.000000000 +0100
56
+++ trunk/src/abstract_crypto.h	2009-11-07 23:57:37.000000000 +0100
57
@@ -162,7 +162,9 @@
58
        (public_key method (string))
59
 
60
        ; Returns (public-key (<pub-sig-alg-id> <s-expr>*))
61
-       (public_spki_key method (string) "int transport")))
62
+       (public_spki_key method (string) "int transport")
63
+
64
+       (key_size method uint32_t)))
65
 */
66
 
67
 #define VERIFY(verifier, algorithm, length, data, slength, sdata) \
68
@@ -170,7 +172,7 @@
69
 
70
 #define PUBLIC_KEY(verifier) ((verifier)->public_key((verifier)))
71
 #define PUBLIC_SPKI_KEY(verifier, t) ((verifier)->public_spki_key((verifier), (t)))
72
-
73
+#define KEY_SIZE(verifier) ((verifier)->key_size((verifier)))
74
 
75
 /* GABA:
76
    (class
77
diff -urNad trunk~/src/abstract_crypto.h.x trunk/src/abstract_crypto.h.x
78
--- trunk~/src/abstract_crypto.h.x	2007-06-04 22:18:39.000000000 +0200
79
+++ trunk/src/abstract_crypto.h.x	2009-11-07 23:57:07.000000000 +0100
80
@@ -161,6 +161,7 @@
81
   int (*(verify))(struct verifier *self,int algorithm,uint32_t length,const uint8_t *data,uint32_t signature_length,const uint8_t *signature_data);
82
   struct lsh_string *(*(public_key))(struct verifier *self);
83
   struct lsh_string *(*(public_spki_key))(struct verifier *self,int transport);
84
+  uint32_t *(*(key_size))(struct verifier *self);
85
 };
86
 extern struct lsh_class verifier_class;
87
 #endif /* !GABA_DEFINE */
60 magnus 88
diff -urNad trunk~/src/blacklist.c trunk/src/blacklist.c
89
--- trunk~/src/blacklist.c	1970-01-01 01:00:00.000000000 +0100
63 magnus 90
+++ trunk/src/blacklist.c	2009-11-07 23:57:07.000000000 +0100
91
@@ -0,0 +1,150 @@
60 magnus 92
+#if HAVE_CONFIG_H
93
+#include "config.h"
94
+#endif
95
+
96
+#include <assert.h>
97
+
98
+#include "atoms.h"
99
+#include "format.h"
100
+#include "lsh_string.h"
101
+#include "werror.h"
102
+#include "crypto.h"
103
+
104
+#include <sys/types.h>
105
+#include <sys/stat.h>
106
+#include <unistd.h>
107
+#include <fcntl.h>
108
+#include <string.h>
109
+
63 magnus 110
+int blacklisted_key(struct verifier *v, int method);
111
+
60 magnus 112
+/* Scan a blacklist of known-vulnerable keys in blacklist_file. */
113
+static int
114
+blacklisted_key_in_file(struct lsh_string *lsh_hash, struct lsh_string *blacklist_file)
115
+{
116
+  int fd = -1;
117
+  const char *hash = 0;
118
+  uint32_t line_len;
119
+  struct stat st;
120
+  char buf[256];
121
+  off_t start, lower, upper;
122
+  int ret = 0;
123
+
124
+  debug("Checking blacklist file %S\n", blacklist_file);
125
+  fd = open(lsh_get_cstring(blacklist_file), O_RDONLY);
126
+  if (fd < 0) {
127
+    ret = -1;
128
+    goto out;
129
+  }
130
+
131
+  hash = lsh_get_cstring(lsh_hash) + 12;
132
+  line_len = strlen(hash);
133
+  if (line_len != 20)
134
+    goto out;
135
+
136
+  /* Skip leading comments */
137
+  start = 0;
138
+  for (;;) {
139
+    ssize_t r;
140
+    char *newline;
141
+
142
+    r = read(fd, buf, sizeof(buf));
143
+    if (r <= 0)
144
+      goto out;
145
+    if (buf[0] != '#')
146
+      break;
147
+
148
+    newline = memchr(buf, '\n', sizeof(buf));
149
+    if (!newline)
150
+      goto out;
151
+    start += newline + 1 - buf;
152
+    if (lseek(fd, start, SEEK_SET) < 0)
153
+      goto out;
154
+  }
155
+
156
+  /* Initialise binary search record numbers */
157
+  if (fstat(fd, &st) < 0)
158
+    goto out;
159
+  lower = 0;
160
+  upper = (st.st_size - start) / (line_len + 1);
161
+
162
+  while (lower != upper) {
163
+    off_t cur;
164
+    int cmp;
165
+
166
+    cur = lower + (upper - lower) / 2;
167
+
168
+    /* Read this line and compare to digest; this is
169
+     * overflow-safe since cur < max(off_t) / (line_len + 1) */
170
+    if (lseek(fd, start + cur * (line_len + 1), SEEK_SET) < 0)
171
+      break;
172
+    if (read(fd, buf, line_len) != line_len)
173
+      break;
174
+    cmp = memcmp(buf, hash, line_len);
175
+    if (cmp < 0) {
176
+      if (cur == lower)
177
+	break;
178
+      lower = cur;
179
+    } else if (cmp > 0) {
180
+      if (cur == upper)
181
+	break;
182
+      upper = cur;
183
+    } else {
184
+      ret = 1;
185
+      break;
186
+    }
187
+  }
188
+
189
+out:
190
+  if (fd >= 0)
191
+    close(fd);
192
+  return ret;
193
+}
194
+
195
+/*
196
+ * Scan blacklists of known-vulnerable keys. If a vulnerable key is found,
197
+ * its fingerprint is returned in *fp, unless fp is NULL.
198
+ */
199
+int
200
+blacklisted_key(struct verifier *v, int method)
201
+{
202
+    const char *keytype;
203
+    int ret = -1;
204
+    const char *paths[] = { "/usr/share/ssh/blacklist", "/etc/ssh/blacklist", NULL };
205
+    const char **pp;
206
+    struct lsh_string *lsh_hash = ssh_format("%lfxS",
207
+					     hash_string(&crypto_md5_algorithm,
208
+							 PUBLIC_KEY(v), 1));
63 magnus 209
+    uint32_t keysize = KEY_SIZE(v);
60 magnus 210
+
211
+    switch (method)
212
+      {
213
+      case ATOM_SSH_DSS:
214
+      case ATOM_DSA:
215
+	  keytype = "DSA";
63 magnus 216
+	  break;
60 magnus 217
+      case ATOM_SSH_RSA:
218
+      case ATOM_RSA_PKCS1_SHA1:
219
+      case ATOM_RSA_PKCS1_MD5:
220
+      case ATOM_RSA_PKCS1:
221
+	  keytype = "RSA";
63 magnus 222
+	  break;
60 magnus 223
+      default:
224
+	  werror("Unrecognized key type");
63 magnus 225
+	  return -1;
60 magnus 226
+      }
227
+
228
+    for (pp = paths; *pp && ret <= 0; pp++) {
229
+      struct lsh_string *blacklist_file = ssh_format("%lz.%lz-%di",
230
+						     *pp, keytype, keysize);
231
+      int r = blacklisted_key_in_file(lsh_hash, blacklist_file);
232
+      lsh_string_free(blacklist_file);
233
+      if (r > ret) ret = r;
234
+    }
235
+
236
+    if (ret > 0) {
237
+	werror("Key is compromised: %z %i %fS\n", keytype, keysize,
238
+	       lsh_string_colonize(lsh_hash, 2, 0));
239
+    }
240
+    return ret;
241
+}
63 magnus 242
diff -urNad trunk~/src/dsa.c trunk/src/dsa.c
243
--- trunk~/src/dsa.c	2004-06-08 20:00:45.000000000 +0200
244
+++ trunk/src/dsa.c	2009-11-07 23:57:07.000000000 +0100
245
@@ -189,6 +189,14 @@
246
 				"y", self->key.y);
247
 }
248
 
249
+static uint32_t
250
+do_dsa_key_size(struct verifier *v)
251
+{
252
+  CAST(dsa_verifier, self, v);
253
+
254
+  return mpz_sizeinbase(self->key.p, 2);
255
+}
256
+
257
 static void
258
 init_dsa_verifier(struct dsa_verifier *self)
259
 {
260
@@ -199,6 +207,7 @@
261
   self->super.verify = do_dsa_verify;
262
   self->super.public_spki_key = do_dsa_public_spki_key;
263
   self->super.public_key = do_dsa_public_key;
264
+  self->super.key_size = do_dsa_key_size;
265
 }
266
 
267
 
60 magnus 268
diff -urNad trunk~/src/lsh-decode-key.c trunk/src/lsh-decode-key.c
269
--- trunk~/src/lsh-decode-key.c	2005-09-06 14:43:15.000000000 +0200
63 magnus 270
+++ trunk/src/lsh-decode-key.c	2009-11-07 23:57:07.000000000 +0100
60 magnus 271
@@ -133,6 +133,10 @@
272
             werror("Invalid dsa key.\n");
273
             return NULL;
274
           }
275
+        else if (blacklisted_key(v, type))
276
+          {
277
+            return NULL;
278
+          }
279
         else
280
           return PUBLIC_SPKI_KEY(v, 1);
281
       }
282
@@ -150,6 +154,10 @@
283
               werror("Invalid rsa key.\n");
284
               return NULL;
285
             }
286
+          else if (blacklisted_key(v, type))
287
+            {
288
+              return NULL;
289
+            }
290
           else
291
             return PUBLIC_SPKI_KEY(v, 1);
292
       }
293
diff -urNad trunk~/src/lsh-writekey.c trunk/src/lsh-writekey.c
294
--- trunk~/src/lsh-writekey.c	2004-11-17 11:55:11.000000000 +0100
63 magnus 295
+++ trunk/src/lsh-writekey.c	2009-11-07 23:57:07.000000000 +0100
60 magnus 296
@@ -397,14 +397,18 @@
297
 {
298
   struct signer *s;
299
   struct verifier *v;
300
+  int algorithm_name;
301
 
302
-  s = spki_make_signer(options->signature_algorithms, key, NULL);
303
+  s = spki_make_signer(options->signature_algorithms, key, &algorithm_name);
304
 
305
   if (!s)
306
     return NULL;
307
 
308
   v = SIGNER_GET_VERIFIER(s);
309
   assert(v);
310
+  if (blacklisted_key(v, algorithm_name)) {
311
+    return NULL;
312
+  }
313
 
314
   return PUBLIC_SPKI_KEY(v, 1);
315
 }
316
@@ -416,7 +420,8 @@
317
   int private_fd;
318
   int public_fd;
319
   struct lsh_string *input;
320
-  struct lsh_string *output;
321
+  struct lsh_string *priv_output;
322
+  struct lsh_string *pub_output;
323
   const struct exception *e;
324
 
325
   argp_parse(&main_argp, argc, argv, 0, NULL, options);
326
@@ -439,16 +444,22 @@
327
       return EXIT_FAILURE;
328
     }
329
 
330
-  output = process_private(input, options);
331
-  if (!output)
332
+  pub_output = process_public(input, options);
333
+  if (!pub_output)
334
+    return EXIT_FAILURE;
335
+
336
+  priv_output = process_private(input, options);
337
+  if (!priv_output)
338
     return EXIT_FAILURE;
339
 
340
+  lsh_string_free(input);
341
+
342
   private_fd = open_file(options->private_file);
343
   if (private_fd < 0)
344
     return EXIT_FAILURE;
345
 
346
-  e = write_raw(private_fd, STRING_LD(output));
347
-  lsh_string_free(output);
348
+  e = write_raw(private_fd, STRING_LD(priv_output));
349
+  lsh_string_free(priv_output);
350
 
351
   if (e)
352
     {
353
@@ -457,18 +468,12 @@
354
       return EXIT_FAILURE;
355
     }
356
 
357
-  output = process_public(input, options);
358
-  lsh_string_free(input);
359
-
360
-  if (!output)
361
-    return EXIT_FAILURE;
362
-
363
   public_fd = open_file(options->public_file);
364
   if (public_fd < 0)
365
     return EXIT_FAILURE;
366
 
367
-  e = write_raw(public_fd, STRING_LD(output));
368
-  lsh_string_free(output);
369
+  e = write_raw(public_fd, STRING_LD(pub_output));
370
+  lsh_string_free(pub_output);
371
 
372
   if (e)
373
     {
374
diff -urNad trunk~/src/publickey_crypto.h trunk/src/publickey_crypto.h
375
--- trunk~/src/publickey_crypto.h	2004-06-15 13:32:51.000000000 +0200
63 magnus 376
+++ trunk/src/publickey_crypto.h	2009-11-07 23:57:07.000000000 +0100
60 magnus 377
@@ -203,5 +203,7 @@
378
 struct verifier *
379
 make_ssh_dss_verifier(const struct lsh_string *public);
380
 
381
+int
382
+blacklisted_key(struct verifier *v, int method);
383
 
384
 #endif /* LSH_PUBLICKEY_CRYPTO_H_INCLUDED */
63 magnus 385
diff -urNad trunk~/src/rsa.c trunk/src/rsa.c
386
--- trunk~/src/rsa.c	2003-11-16 19:49:12.000000000 +0100
387
+++ trunk/src/rsa.c	2009-11-07 23:57:07.000000000 +0100
388
@@ -167,6 +167,14 @@
389
 				self->key.n, self->key.e);
390
 }
391
 
392
+static uint32_t
393
+do_rsa_key_size(struct verifier *v)
394
+{
395
+  CAST(rsa_verifier, self, v);
396
+
397
+  return mpz_sizeinbase(self->key.n, 2);
398
+}
399
+
400
 
401
 /* NOTE: To initialize an rsa verifier, one must
402
  *
403
@@ -184,6 +192,7 @@
404
   self->super.verify = do_rsa_verify;
405
   self->super.public_key = do_rsa_public_key;
406
   self->super.public_spki_key = do_rsa_public_spki_key;
407
+  self->super.key_size = do_rsa_key_size;
408
 }
409
 
410
 /* Alternative constructor using a key of type ssh-rsa, when the atom
60 magnus 411
diff -urNad trunk~/src/server_authorization.c trunk/src/server_authorization.c
412
--- trunk~/src/server_authorization.c	2004-06-08 20:01:15.000000000 +0200
63 magnus 413
+++ trunk/src/server_authorization.c	2009-11-07 23:57:07.000000000 +0100
60 magnus 414
@@ -93,7 +93,8 @@
415
 				    PUBLIC_SPKI_KEY(v, 0),
416
 				    1));
417
 
418
-  if (USER_FILE_EXISTS(keyholder, filename, 1))
419
+  if (USER_FILE_EXISTS(keyholder, filename, 1)
420
+      && blacklisted_key(v, method) < 1)
421
     return v;
422
 
423
   return NULL;