?revision_form?Rev ?revision_input??revision_submit??revision_endform?
Rev 64 |
Rev 80 |
Go to most recent revision |
Blame |
Compare with Previous |
Last modification |
View Log
| RSS feed
Author: Magnus Holmgren <holmgren@debian.org>
Description: Check keys against openssh-blacklist
Check keys before accepting for pubkey authentication as well as on conversion
by lsh-writekey and lsh-decode-key.
.
blacklist.c code copied from the openssh package and adapted for LSH.
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -69,7 +69,8 @@ liblsh_a_SOURCES = abstract_io.c abstrac
unix_interact.c unix_process.c unix_random.c unix_user.c \
userauth.c \
werror.c write_buffer.c write_packet.c \
- xalloc.c xauth.c zlib.c
+ xalloc.c xauth.c zlib.c \
+ blacklist.c
liblsh_a_LIBADD = @LIBOBJS@
--- a/src/abstract_crypto.h
+++ b/src/abstract_crypto.h
@@ -162,7 +162,9 @@ MAC_DIGEST((instance), lsh_string_alloc(
(public_key method (string))
; Returns (public-key (<pub-sig-alg-id> <s-expr>*))
- (public_spki_key method (string) "int transport")))
+ (public_spki_key method (string) "int transport")
+
+ (key_size method uint32_t)))
*/
#define VERIFY(verifier, algorithm, length, data, slength, sdata) \
@@ -170,7 +172,7 @@ MAC_DIGEST((instance), lsh_string_alloc(
#define PUBLIC_KEY(verifier) ((verifier)->public_key((verifier)))
#define PUBLIC_SPKI_KEY(verifier, t) ((verifier)->public_spki_key((verifier), (t)))
-
+#define KEY_SIZE(verifier) ((verifier)->key_size((verifier)))
/* GABA:
(class
--- a/src/abstract_crypto.h.x
+++ b/src/abstract_crypto.h.x
@@ -161,6 +161,7 @@ struct verifier
int (*(verify))(struct verifier *self,int algorithm,uint32_t length,const uint8_t *data,uint32_t signature_length,const uint8_t *signature_data);
struct lsh_string *(*(public_key))(struct verifier *self);
struct lsh_string *(*(public_spki_key))(struct verifier *self,int transport);
+ uint32_t *(*(key_size))(struct verifier *self);
};
extern struct lsh_class verifier_class;
#endif /* !GABA_DEFINE */
--- /dev/null
+++ b/src/blacklist.c
@@ -0,0 +1,150 @@
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <assert.h>
+
+#include "atoms.h"
+#include "format.h"
+#include "lsh_string.h"
+#include "werror.h"
+#include "crypto.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+
+int blacklisted_key(struct verifier *v, int method);
+
+/* Scan a blacklist of known-vulnerable keys in blacklist_file. */
+static int
+blacklisted_key_in_file(struct lsh_string *lsh_hash, struct lsh_string *blacklist_file)
+{
+ int fd = -1;
+ const char *hash = 0;
+ uint32_t line_len;
+ struct stat st;
+ char buf[256];
+ off_t start, lower, upper;
+ int ret = 0;
+
+ debug("Checking blacklist file %S\n", blacklist_file);
+ fd = open(lsh_get_cstring(blacklist_file), O_RDONLY);
+ if (fd < 0) {
+ ret = -1;
+ goto out;
+ }
+
+ hash = lsh_get_cstring(lsh_hash) + 12;
+ line_len = strlen(hash);
+ if (line_len != 20)
+ goto out;
+
+ /* Skip leading comments */
+ start = 0;
+ for (;;) {
+ ssize_t r;
+ char *newline;
+
+ r = read(fd, buf, sizeof(buf));
+ if (r <= 0)
+ goto out;
+ if (buf[0] != '#')
+ break;
+
+ newline = memchr(buf, '\n', sizeof(buf));
+ if (!newline)
+ goto out;
+ start += newline + 1 - buf;
+ if (lseek(fd, start, SEEK_SET) < 0)
+ goto out;
+ }
+
+ /* Initialise binary search record numbers */
+ if (fstat(fd, &st) < 0)
+ goto out;
+ lower = 0;
+ upper = (st.st_size - start) / (line_len + 1);
+
+ while (lower != upper) {
+ off_t cur;
+ int cmp;
+
+ cur = lower + (upper - lower) / 2;
+
+ /* Read this line and compare to digest; this is
+ * overflow-safe since cur < max(off_t) / (line_len + 1) */
+ if (lseek(fd, start + cur * (line_len + 1), SEEK_SET) < 0)
+ break;
+ if (read(fd, buf, line_len) != line_len)
+ break;
+ cmp = memcmp(buf, hash, line_len);
+ if (cmp < 0) {
+ if (cur == lower)
+ break;
+ lower = cur;
+ } else if (cmp > 0) {
+ if (cur == upper)
+ break;
+ upper = cur;
+ } else {
+ ret = 1;
+ break;
+ }
+ }
+
+out:
+ if (fd >= 0)
+ close(fd);
+ return ret;
+}
+
+/*
+ * Scan blacklists of known-vulnerable keys. If a vulnerable key is found,
+ * its fingerprint is returned in *fp, unless fp is NULL.
+ */
+int
+blacklisted_key(struct verifier *v, int method)
+{
+ const char *keytype;
+ int ret = -1;
+ const char *paths[] = { "/usr/share/ssh/blacklist", "/etc/ssh/blacklist", NULL };
+ const char **pp;
+ struct lsh_string *lsh_hash = ssh_format("%lfxS",
+ hash_string(&crypto_md5_algorithm,
+ PUBLIC_KEY(v), 1));
+ uint32_t keysize = KEY_SIZE(v);
+
+ switch (method)
+ {
+ case ATOM_SSH_DSS:
+ case ATOM_DSA:
+ keytype = "DSA";
+ break;
+ case ATOM_SSH_RSA:
+ case ATOM_RSA_PKCS1_SHA1:
+ case ATOM_RSA_PKCS1_MD5:
+ case ATOM_RSA_PKCS1:
+ keytype = "RSA";
+ break;
+ default:
+ werror("Unrecognized key type");
+ return -1;
+ }
+
+ for (pp = paths; *pp && ret <= 0; pp++) {
+ struct lsh_string *blacklist_file = ssh_format("%lz.%lz-%di",
+ *pp, keytype, keysize);
+ int r = blacklisted_key_in_file(lsh_hash, blacklist_file);
+ lsh_string_free(blacklist_file);
+ if (r > ret) ret = r;
+ }
+
+ if (ret > 0) {
+ werror("Key is compromised: %z %i %fS\n", keytype, keysize,
+ lsh_string_colonize(lsh_hash, 2, 0));
+ }
+ return ret;
+}
--- a/src/dsa.c
+++ b/src/dsa.c
@@ -189,6 +189,14 @@ do_dsa_public_spki_key(struct verifier *
"y", self->key.y);
}
+static uint32_t
+do_dsa_key_size(struct verifier *v)
+{
+ CAST(dsa_verifier, self, v);
+
+ return mpz_sizeinbase(self->key.p, 2);
+}
+
static void
init_dsa_verifier(struct dsa_verifier *self)
{
@@ -199,6 +207,7 @@ init_dsa_verifier(struct dsa_verifier *s
self->super.verify = do_dsa_verify;
self->super.public_spki_key = do_dsa_public_spki_key;
self->super.public_key = do_dsa_public_key;
+ self->super.key_size = do_dsa_key_size;
}
--- a/src/lsh-decode-key.c
+++ b/src/lsh-decode-key.c
@@ -133,6 +133,10 @@ lsh_decode_key(struct lsh_string *conten
werror("Invalid dsa key.\n");
return NULL;
}
+ else if (blacklisted_key(v, type))
+ {
+ return NULL;
+ }
else
return PUBLIC_SPKI_KEY(v, 1);
}
@@ -150,6 +154,10 @@ lsh_decode_key(struct lsh_string *conten
werror("Invalid rsa key.\n");
return NULL;
}
+ else if (blacklisted_key(v, type))
+ {
+ return NULL;
+ }
else
return PUBLIC_SPKI_KEY(v, 1);
}
--- a/src/lsh-writekey.c
+++ b/src/lsh-writekey.c
@@ -397,14 +397,18 @@ process_public(const struct lsh_string *
{
struct signer *s;
struct verifier *v;
+ int algorithm_name;
- s = spki_make_signer(options->signature_algorithms, key, NULL);
+ s = spki_make_signer(options->signature_algorithms, key, &algorithm_name);
if (!s)
return NULL;
v = SIGNER_GET_VERIFIER(s);
assert(v);
+ if (blacklisted_key(v, algorithm_name)) {
+ return NULL;
+ }
return PUBLIC_SPKI_KEY(v, 1);
}
@@ -416,7 +420,8 @@ main(int argc, char **argv)
int private_fd;
int public_fd;
struct lsh_string *input;
- struct lsh_string *output;
+ struct lsh_string *priv_output;
+ struct lsh_string *pub_output;
const struct exception *e;
argp_parse(&main_argp, argc, argv, 0, NULL, options);
@@ -439,16 +444,22 @@ main(int argc, char **argv)
return EXIT_FAILURE;
}
- output = process_private(input, options);
- if (!output)
+ pub_output = process_public(input, options);
+ if (!pub_output)
+ return EXIT_FAILURE;
+
+ priv_output = process_private(input, options);
+ if (!priv_output)
return EXIT_FAILURE;
+ lsh_string_free(input);
+
private_fd = open_file(options->private_file);
if (private_fd < 0)
return EXIT_FAILURE;
- e = write_raw(private_fd, STRING_LD(output));
- lsh_string_free(output);
+ e = write_raw(private_fd, STRING_LD(priv_output));
+ lsh_string_free(priv_output);
if (e)
{
@@ -457,18 +468,12 @@ main(int argc, char **argv)
return EXIT_FAILURE;
}
- output = process_public(input, options);
- lsh_string_free(input);
-
- if (!output)
- return EXIT_FAILURE;
-
public_fd = open_file(options->public_file);
if (public_fd < 0)
return EXIT_FAILURE;
- e = write_raw(public_fd, STRING_LD(output));
- lsh_string_free(output);
+ e = write_raw(public_fd, STRING_LD(pub_output));
+ lsh_string_free(pub_output);
if (e)
{
--- a/src/publickey_crypto.h
+++ b/src/publickey_crypto.h
@@ -203,5 +203,7 @@ parse_ssh_dss_public(struct simple_buffe
struct verifier *
make_ssh_dss_verifier(const struct lsh_string *public);
+int
+blacklisted_key(struct verifier *v, int method);
#endif /* LSH_PUBLICKEY_CRYPTO_H_INCLUDED */
--- a/src/rsa.c
+++ b/src/rsa.c
@@ -167,6 +167,14 @@ do_rsa_public_spki_key(struct verifier *
self->key.n, self->key.e);
}
+static uint32_t
+do_rsa_key_size(struct verifier *v)
+{
+ CAST(rsa_verifier, self, v);
+
+ return mpz_sizeinbase(self->key.n, 2);
+}
+
/* NOTE: To initialize an rsa verifier, one must
*
@@ -184,6 +192,7 @@ init_rsa_verifier(struct rsa_verifier *s
self->super.verify = do_rsa_verify;
self->super.public_key = do_rsa_public_key;
self->super.public_spki_key = do_rsa_public_spki_key;
+ self->super.key_size = do_rsa_key_size;
}
/* Alternative constructor using a key of type ssh-rsa, when the atom
--- a/src/server_authorization.c
+++ b/src/server_authorization.c
@@ -93,7 +93,8 @@ do_key_lookup(struct lookup_verifier *c,
PUBLIC_SPKI_KEY(v, 0),
1));
- if (USER_FILE_EXISTS(keyholder, filename, 1))
+ if (USER_FILE_EXISTS(keyholder, filename, 1)
+ && blacklisted_key(v, method) < 1)
return v;
return NULL;