[Midnightbsd-cvs] src: crypto/openssh: add the vulnkey util
laffer1 at midnightbsd.org
laffer1 at midnightbsd.org
Fri May 16 16:19:20 EDT 2008
Log Message:
-----------
add the vulnkey util
Added Files:
-----------
src/crypto/openssh:
ssh-vulnkey.1 (r1.1)
ssh-vulnkey.c (r1.1)
-------------- next part --------------
--- /dev/null
+++ crypto/openssh/ssh-vulnkey.1
@@ -0,0 +1,187 @@
+.\" Copyright (c) 2008 Canonical Ltd. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.Dd $Mdocdate: May 12 2008 $
+.Dt SSH-VULNKEY 1
+.Os
+.Sh NAME
+.Nm ssh-vulnkey
+.Nd check blacklist of compromised keys
+.Sh SYNOPSIS
+.Nm
+.Op Fl q
+.Ar file ...
+.Nm
+.Fl a
+.Sh DESCRIPTION
+.Nm
+checks a key against a blacklist of compromised keys.
+.Pp
+A substantial number of keys are known to have been generated using a broken
+version of OpenSSL distributed by Debian which failed to seed its random
+number generator correctly.
+Keys generated using these OpenSSL versions should be assumed to be
+compromised.
+This tool may be useful in checking for such keys.
+.Pp
+Keys that are compromised cannot be repaired; replacements must be generated
+using
+.Xr ssh-keygen 1 .
+Make sure to update
+.Pa authorized_keys
+files on all systems where compromised keys were permitted to authenticate.
+.Pp
+The argument list will be interpreted as a list of paths to public key files
+or
+.Pa authorized_keys
+files.
+If no suitable file is found at a given path,
+.Nm
+will append
+.Pa .pub
+and retry, in case it was given a private key file.
+If no files are given as arguments,
+.Nm
+will check
+.Pa ~/.ssh/id_rsa ,
+.Pa ~/.ssh/id_dsa ,
+.Pa ~/.ssh/identity ,
+.Pa ~/.ssh/authorized_keys
+and
+.Pa ~/.ssh/authorized_keys2 ,
+as well as the system's host keys if readable.
+.Pp
+If
+.Dq -
+is given as an argument,
+.Nm
+will read from standard input.
+This can be used to process output from
+.Xr ssh-keyscan 1 ,
+for example:
+.Pp
+.Dl $ ssh-keyscan -t rsa remote.example.org | ssh-vulnkey -
+.Pp
+.Nm
+will exit zero if any of the given keys were in the compromised list,
+otherwise non-zero.
+.Pp
+Unless the
+.Cm PermitBlacklistedKeys
+option is used,
+.Xr sshd 8
+will reject attempts to authenticate with keys in the compromised list.
+.Pp
+The options are as follows:
+.Bl -tag -width Ds
+.It Fl a
+Check keys of all users on the system.
+You will typically need to run
+.Nm
+as root to use this option.
+For each user,
+.Nm
+will check
+.Pa ~/.ssh/id_rsa ,
+.Pa ~/.ssh/id_dsa ,
+.Pa ~/.ssh/identity ,
+.Pa ~/.ssh/authorized_keys
+and
+.Pa ~/.ssh/authorized_keys2 .
+It will also check the system's host keys.
+.It Fl q
+Quiet mode.
+Normally,
+.Nm
+outputs the fingerprint of each key scanned, with a description of its
+status.
+This option suppresses that output.
+.El
+.Sh BLACKLIST FILE FORMAT
+The blacklist file may start with comments, on lines starting with
+.Dq # .
+After these initial comments, it must follow a strict format:
+.Pp
+.Bl -bullet -offset indent -compact
+.It
+All the lines must be exactly the same length (20 characters followed by a
+newline) and must be in sorted order.
+.It
+Each line must consist of the lower-case hexadecimal MD5 key fingerprint,
+without colons, and with the first 12 characters removed (that is, the least
+significant 80 bits of the fingerprint).
+.El
+.Pp
+The key fingerprint may be generated using
+.Xr ssh-keygen 1 :
+.Pp
+.Dl $ ssh-keygen -l -f /path/to/key
+.Pp
+This strict format is necessary to allow the blacklist file to be checked
+quickly, using a binary-search algorithm.
+.Sh FILES
+.Bl -tag -width Ds
+.It Pa ~/.ssh/id_rsa
+If present, contains the protocol version 2 RSA authentication identity of
+the user.
+.It Pa ~/.ssh/id_dsa
+If present, contains the protocol version 2 DSA authentication identity of
+the user.
+.It Pa ~/.ssh/identity
+If present, contains the protocol version 1 RSA authentication identity of
+the user.
+.It Pa ~/.ssh/authorized_keys
+If present, lists the public keys (RSA/DSA) that can be used for logging in
+as this user.
+.It Pa ~/.ssh/authorized_keys2
+Obsolete name for
+.Pa ~/.ssh/authorized_keys .
+This file may still be present on some old systems, but should not be
+created if it is missing.
+.It Pa /etc/ssh/ssh_host_rsa_key
+If present, contains the protocol version 2 RSA identity of the system.
+.It Pa /etc/ssh/ssh_host_dsa_key
+If present, contains the protocol version 2 DSA identity of the system.
+.It Pa /etc/ssh/ssh_host_key
+If present, contains the protocol version 1 RSA identity of the system.
+.It Pa /etc/ssh/blacklist. Ns Ar TYPE Ns Pa - Ns Ar LENGTH
+If present, lists the blacklisted keys of type
+.Ar TYPE
+.Pf ( Dq RSA1 ,
+.Dq RSA ,
+or
+.Dq DSA )
+and bit length
+.Ar LENGTH .
+The format of this file is described above.
+.El
+.Sh SEE ALSO
+.Xr ssh-keygen 1 ,
+.Xr sshd 8
+.Sh AUTHORS
+.An -nosplit
+.An Colin Watson Aq cjwatson at ubuntu.com
+.Pp
+Florian Weimer suggested the option to check keys of all users, and the idea
+of processing
+.Xr ssh-keyscan 1
+output.
--- /dev/null
+++ crypto/openssh/ssh-vulnkey.c
@@ -0,0 +1,325 @@
+/*
+ * Copyright (c) 2008 Canonical Ltd. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "includes.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <string.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <openssl/evp.h>
+
+#include "xmalloc.h"
+#include "ssh.h"
+#include "log.h"
+#include "key.h"
+#include "authfile.h"
+#include "pathnames.h"
+#include "misc.h"
+
+extern char *__progname;
+
+/* Default files to check */
+static char *default_host_files[] = {
+ _PATH_HOST_RSA_KEY_FILE,
+ _PATH_HOST_DSA_KEY_FILE,
+ _PATH_HOST_KEY_FILE,
+ NULL
+};
+static char *default_files[] = {
+ _PATH_SSH_CLIENT_ID_RSA,
+ _PATH_SSH_CLIENT_ID_DSA,
+ _PATH_SSH_CLIENT_IDENTITY,
+ _PATH_SSH_USER_PERMITTED_KEYS,
+ _PATH_SSH_USER_PERMITTED_KEYS2,
+ NULL
+};
+
+static int quiet = 0;
+
+static void
+usage(void)
+{
+ fprintf(stderr, "usage: %s [-aq] [file ...]\n", __progname);
+ fprintf(stderr, "Options:\n");
+ fprintf(stderr, " -a Check keys of all users.\n");
+ fprintf(stderr, " -q Quiet mode.\n");
+ exit(1);
+}
+
+void
+describe_key(const char *msg, const Key *key, const char *comment)
+{
+ char *fp;
+
+ fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
+ if (!quiet)
+ printf("%s: %u %s %s\n", msg, key_size(key), fp, comment);
+ xfree(fp);
+}
+
+int
+do_key(const Key *key, const char *comment)
+{
+ char *blacklist_file;
+ struct stat st;
+ int ret = 1;
+
+ blacklist_file = blacklist_filename(key);
+ if (stat(blacklist_file, &st) < 0)
+ describe_key("Unknown (no blacklist information)",
+ key, comment);
+ else if (blacklisted_key(key)) {
+ describe_key("COMPROMISED", key, comment);
+ ret = 0;
+ } else
+ describe_key("Not blacklisted", key, comment);
+ xfree(blacklist_file);
+
+ return ret;
+}
+
+int
+do_filename(const char *filename, int quiet_open)
+{
+ FILE *f;
+ char line[SSH_MAX_PUBKEY_BYTES];
+ char *cp;
+ u_long linenum = 0;
+ Key *key;
+ char *comment = NULL;
+ int found = 0, ret = 1;
+
+ /* Copy much of key_load_public's logic here so that we can read
+ * several keys from a single file (e.g. authorized_keys).
+ */
+
+ if (strcmp(filename, "-") != 0) {
+ f = fopen(filename, "r");
+ if (!f) {
+ char pubfile[MAXPATHLEN];
+ if (strlcpy(pubfile, filename, sizeof pubfile) <
+ sizeof(pubfile) &&
+ strlcat(pubfile, ".pub", sizeof pubfile) <
+ sizeof(pubfile))
+ f = fopen(pubfile, "r");
+ }
+ if (!f) {
+ if (!quiet_open)
+ perror(filename);
+ return -1;
+ }
+ } else
+ f = stdin;
+ while (read_keyfile_line(f, filename, line, sizeof(line),
+ &linenum) != -1) {
+ int i;
+ char *space;
+ int type;
+
+ /* Chop trailing newline. */
+ i = strlen(line) - 1;
+ if (line[i] == '\n')
+ line[i] = '\0';
+
+ /* Skip leading whitespace, empty and comment lines. */
+ for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
+ ;
+ if (!*cp || *cp == '\n' || *cp == '#')
+ continue;
+
+ /* Cope with ssh-keyscan output and options in
+ * authorized_keys files.
+ */
+ space = strchr(cp, ' ');
+ if (!space)
+ continue;
+ *space = '\0';
+ type = key_type_from_name(cp);
+ *space = ' ';
+ /* Leading number (RSA1) or valid type (RSA/DSA) indicates
+ * that we have no host name or options to skip.
+ */
+ if (atoi(cp) == 0 && type == KEY_UNSPEC) {
+ int quoted = 0;
+
+ for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) {
+ if (*cp == '\\' && cp[1] == '"')
+ cp++; /* Skip both */
+ else if (*cp == '"')
+ quoted = !quoted;
+ }
+ /* Skip remaining whitespace. */
+ for (; *cp == ' ' || *cp == '\t'; cp++)
+ ;
+ if (!*cp)
+ continue;
+ }
+
+ /* Read and process the key itself. */
+ key = key_new(KEY_RSA1);
+ if (key_read(key, &cp) == 1) {
+ while (*cp == ' ' || *cp == '\t')
+ cp++;
+ if (!do_key(key, *cp ? cp : filename))
+ ret = 0;
+ found = 1;
+ } else {
+ key_free(key);
+ key = key_new(KEY_UNSPEC);
+ if (key_read(key, &cp) == 1) {
+ while (*cp == ' ' || *cp == '\t')
+ cp++;
+ if (!do_key(key, *cp ? cp : filename))
+ ret = 0;
+ found = 1;
+ }
+ }
+ key_free(key);
+ }
+ if (f != stdin)
+ fclose(f);
+
+ if (!found && filename) {
+ key = key_load_public(filename, &comment);
+ if (key) {
+ if (!do_key(key, comment))
+ ret = 0;
+ found = 1;
+ }
+ if (comment)
+ xfree(comment);
+ }
+
+ return ret;
+}
+
+int
+do_host(void)
+{
+ int i;
+ struct stat st;
+ int ret = 1;
+
+ for (i = 0; default_host_files[i]; i++) {
+ if (stat(default_host_files[i], &st) < 0)
+ continue;
+ if (!do_filename(default_host_files[i], 1))
+ ret = 0;
+ }
+
+ return ret;
+}
+
+int
+do_user(const char *dir)
+{
+ int i;
+ char buf[MAXPATHLEN];
+ struct stat st;
+ int ret = 1;
+
+ for (i = 0; default_files[i]; i++) {
+ snprintf(buf, sizeof(buf), "%s/%s", dir, default_files[i]);
+ if (stat(buf, &st) < 0)
+ continue;
+ if (!do_filename(buf, 0))
+ ret = 0;
+ }
+
+ return ret;
+}
+
+int
+main(int argc, char **argv)
+{
+ int opt, all_users = 0;
+ int ret = 1;
+ extern int optind;
+
+ /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
+ sanitise_stdfd();
+
+ __progname = ssh_get_progname(argv[0]);
+
+ SSLeay_add_all_algorithms();
+ log_init(argv[0], SYSLOG_LEVEL_INFO, SYSLOG_FACILITY_USER, 1);
+
+ /* We don't need the RNG ourselves, but symbol references here allow
+ * ld to link us properly.
+ */
+ init_rng();
+ seed_rng();
+
+ while ((opt = getopt(argc, argv, "ahq")) != -1) {
+ switch (opt) {
+ case 'a':
+ all_users = 1;
+ break;
+ case 'q':
+ quiet = 1;
+ break;
+ case 'h':
+ default:
+ usage();
+ }
+ }
+
+ if (all_users) {
+ struct passwd *pw;
+
+ if (!do_host())
+ ret = 0;
+
+ while ((pw = getpwent()) != NULL) {
+ if (pw->pw_dir) {
+ if (!do_user(pw->pw_dir))
+ ret = 0;
+ }
+ }
+ } else if (optind == argc) {
+ struct passwd *pw;
+
+ if (!do_host())
+ ret = 0;
+
+ if ((pw = getpwuid(getuid())) == NULL)
+ fprintf(stderr, "No user found with uid %u\n",
+ (u_int)getuid());
+ else {
+ if (!do_user(pw->pw_dir))
+ ret = 0;
+ }
+ } else {
+ while (optind < argc)
+ if (!do_filename(argv[optind++], 0))
+ ret = 0;
+ }
+
+ return ret;
+}
More information about the Midnightbsd-cvs
mailing list