0,0 → 1,382 |
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,152 @@ |
+#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)); |
+ } else if (ret < 0) { |
+ verbose("No blacklist for key type %z size %i", keytype, keysize); |
+ } |
+ return ret; |
+} |
--- a/src/dsa.c |
+++ b/src/dsa.c |
@@ -187,6 +187,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) |
{ |
@@ -197,6 +205,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) > 0) |
+ { |
+ 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) > 0) |
+ { |
+ 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) > 0) { |
+ 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; |
Property changes: |
Added: svn:executable |
## -0,0 +1 ## |
+* |
\ No newline at end of property |