Subversion Repositories

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

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