Subversion Repositories

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

Rev 79 | Rev 82 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

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