=================================================================== RCS file: /cvsrepo/anoncvs/cvs/src/usr.bin/ssh/ssh-keygen.c,v retrieving revision 1.221 retrieving revision 1.226 diff -u -r1.221 -r1.226 --- src/usr.bin/ssh/ssh-keygen.c 2013/01/03 23:22:58 1.221 +++ src/usr.bin/ssh/ssh-keygen.c 2013/04/19 01:01:00 1.226 @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-keygen.c,v 1.221 2013/01/03 23:22:58 djm Exp $ */ +/* $OpenBSD: ssh-keygen.c,v 1.226 2013/04/19 01:01:00 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1994 Tatu Ylonen , Espoo, Finland @@ -40,7 +40,10 @@ #include "match.h" #include "hostfile.h" #include "dns.h" +#include "ssh.h" #include "ssh2.h" +#include "atomicio.h" +#include "krl.h" #ifdef ENABLE_PKCS11 #include "ssh-pkcs11.h" @@ -714,6 +717,9 @@ enum fp_type fptype; char *fp, *ra; + fptype = print_bubblebabble ? SSH_FP_SHA1 : SSH_FP_MD5; + rep = print_bubblebabble ? SSH_FP_BUBBLEBABBLE : SSH_FP_HEX; + pkcs11_init(0); nkeys = pkcs11_add_provider(pkcs11provider, NULL, &keys); if (nkeys <= 0) @@ -1879,6 +1885,229 @@ } static void +load_krl(const char *path, struct ssh_krl **krlp) +{ + Buffer krlbuf; + int fd; + + buffer_init(&krlbuf); + if ((fd = open(path, O_RDONLY)) == -1) + fatal("open %s: %s", path, strerror(errno)); + if (!key_load_file(fd, path, &krlbuf)) + fatal("Unable to load KRL"); + close(fd); + /* XXX check sigs */ + if (ssh_krl_from_blob(&krlbuf, krlp, NULL, 0) != 0 || + *krlp == NULL) + fatal("Invalid KRL file"); + buffer_free(&krlbuf); +} + +static void +update_krl_from_file(struct passwd *pw, const char *file, const Key *ca, + struct ssh_krl *krl) +{ + Key *key = NULL; + u_long lnum = 0; + char *path, *cp, *ep, line[SSH_MAX_PUBKEY_BYTES]; + unsigned long long serial, serial2; + int i, was_explicit_key, was_sha1, r; + FILE *krl_spec; + + path = tilde_expand_filename(file, pw->pw_uid); + if (strcmp(path, "-") == 0) { + krl_spec = stdin; + free(path); + path = xstrdup("(standard input)"); + } else if ((krl_spec = fopen(path, "r")) == NULL) + fatal("fopen %s: %s", path, strerror(errno)); + + if (!quiet) + printf("Revoking from %s\n", path); + while (read_keyfile_line(krl_spec, path, line, sizeof(line), + &lnum) == 0) { + was_explicit_key = was_sha1 = 0; + cp = line + strspn(line, " \t"); + /* Trim trailing space, comments and strip \n */ + for (i = 0, r = -1; cp[i] != '\0'; i++) { + if (cp[i] == '#' || cp[i] == '\n') { + cp[i] = '\0'; + break; + } + if (cp[i] == ' ' || cp[i] == '\t') { + /* Remember the start of a span of whitespace */ + if (r == -1) + r = i; + } else + r = -1; + } + if (r != -1) + cp[r] = '\0'; + if (*cp == '\0') + continue; + if (strncasecmp(cp, "serial:", 7) == 0) { + if (ca == NULL) { + fatal("revoking certificated by serial number " + "requires specification of a CA key"); + } + cp += 7; + cp = cp + strspn(cp, " \t"); + errno = 0; + serial = strtoull(cp, &ep, 0); + if (*cp == '\0' || (*ep != '\0' && *ep != '-')) + fatal("%s:%lu: invalid serial \"%s\"", + path, lnum, cp); + if (errno == ERANGE && serial == ULLONG_MAX) + fatal("%s:%lu: serial out of range", + path, lnum); + serial2 = serial; + if (*ep == '-') { + cp = ep + 1; + errno = 0; + serial2 = strtoull(cp, &ep, 0); + if (*cp == '\0' || *ep != '\0') + fatal("%s:%lu: invalid serial \"%s\"", + path, lnum, cp); + if (errno == ERANGE && serial2 == ULLONG_MAX) + fatal("%s:%lu: serial out of range", + path, lnum); + if (serial2 <= serial) + fatal("%s:%lu: invalid serial range " + "%llu:%llu", path, lnum, + (unsigned long long)serial, + (unsigned long long)serial2); + } + if (ssh_krl_revoke_cert_by_serial_range(krl, + ca, serial, serial2) != 0) { + fatal("%s: revoke serial failed", + __func__); + } + } else if (strncasecmp(cp, "id:", 3) == 0) { + if (ca == NULL) { + fatal("revoking certificated by key ID " + "requires specification of a CA key"); + } + cp += 3; + cp = cp + strspn(cp, " \t"); + if (ssh_krl_revoke_cert_by_key_id(krl, ca, cp) != 0) + fatal("%s: revoke key ID failed", __func__); + } else { + if (strncasecmp(cp, "key:", 4) == 0) { + cp += 4; + cp = cp + strspn(cp, " \t"); + was_explicit_key = 1; + } else if (strncasecmp(cp, "sha1:", 5) == 0) { + cp += 5; + cp = cp + strspn(cp, " \t"); + was_sha1 = 1; + } else { + /* + * Just try to process the line as a key. + * Parsing will fail if it isn't. + */ + } + if ((key = key_new(KEY_UNSPEC)) == NULL) + fatal("key_new"); + if (key_read(key, &cp) != 1) + fatal("%s:%lu: invalid key", path, lnum); + if (was_explicit_key) + r = ssh_krl_revoke_key_explicit(krl, key); + else if (was_sha1) + r = ssh_krl_revoke_key_sha1(krl, key); + else + r = ssh_krl_revoke_key(krl, key); + if (r != 0) + fatal("%s: revoke key failed", __func__); + key_free(key); + } + } + if (strcmp(path, "-") != 0) + fclose(krl_spec); + free(path); +} + +static void +do_gen_krl(struct passwd *pw, int updating, int argc, char **argv) +{ + struct ssh_krl *krl; + struct stat sb; + Key *ca = NULL; + int fd, i; + char *tmp; + Buffer kbuf; + + if (*identity_file == '\0') + fatal("KRL generation requires an output file"); + if (stat(identity_file, &sb) == -1) { + if (errno != ENOENT) + fatal("Cannot access KRL \"%s\": %s", + identity_file, strerror(errno)); + if (updating) + fatal("KRL \"%s\" does not exist", identity_file); + } + if (ca_key_path != NULL) { + tmp = tilde_expand_filename(ca_key_path, pw->pw_uid); + if ((ca = key_load_public(tmp, NULL)) == NULL) + fatal("Cannot load CA public key %s", tmp); + xfree(tmp); + } + + if (updating) + load_krl(identity_file, &krl); + else if ((krl = ssh_krl_init()) == NULL) + fatal("couldn't create KRL"); + + if (cert_serial != 0) + ssh_krl_set_version(krl, cert_serial); + if (identity_comment != NULL) + ssh_krl_set_comment(krl, identity_comment); + + for (i = 0; i < argc; i++) + update_krl_from_file(pw, argv[i], ca, krl); + + buffer_init(&kbuf); + if (ssh_krl_to_blob(krl, &kbuf, NULL, 0) != 0) + fatal("Couldn't generate KRL"); + if ((fd = open(identity_file, O_WRONLY|O_CREAT|O_TRUNC, 0644)) == -1) + fatal("open %s: %s", identity_file, strerror(errno)); + if (atomicio(vwrite, fd, buffer_ptr(&kbuf), buffer_len(&kbuf)) != + buffer_len(&kbuf)) + fatal("write %s: %s", identity_file, strerror(errno)); + close(fd); + buffer_free(&kbuf); + ssh_krl_free(krl); + if (ca != NULL) + key_free(ca); +} + +static void +do_check_krl(struct passwd *pw, int argc, char **argv) +{ + int i, r, ret = 0; + char *comment; + struct ssh_krl *krl; + Key *k; + + if (*identity_file == '\0') + fatal("KRL checking requires an input file"); + load_krl(identity_file, &krl); + for (i = 0; i < argc; i++) { + if ((k = key_load_public(argv[i], &comment)) == NULL) + fatal("Cannot load public key %s", argv[i]); + r = ssh_krl_check_key(krl, k); + printf("%s%s%s%s: %s\n", argv[i], + *comment ? " (" : "", comment, *comment ? ")" : "", + r == 0 ? "ok" : "REVOKED"); + if (r != 0) + ret = 1; + key_free(k); + free(comment); + } + ssh_krl_free(krl); + exit(ret); +} + +static void usage(void) { fprintf(stderr, "usage: %s [options]\n", __progname); @@ -1904,6 +2133,7 @@ fprintf(stderr, " -J number Screen this number of moduli lines.\n"); fprintf(stderr, " -j number Start screening moduli at specified line.\n"); fprintf(stderr, " -K checkpt Write checkpoints to this file.\n"); + fprintf(stderr, " -k Generate a KRL file.\n"); fprintf(stderr, " -L Print the contents of a certificate.\n"); fprintf(stderr, " -l Show fingerprint of key file.\n"); fprintf(stderr, " -M memory Amount of memory (MB) to use for generating DH-GEX moduli.\n"); @@ -1913,6 +2143,7 @@ fprintf(stderr, " -O option Specify a certificate option.\n"); fprintf(stderr, " -P phrase Provide old passphrase.\n"); fprintf(stderr, " -p Change passphrase of private key file.\n"); + fprintf(stderr, " -Q Test whether key(s) are revoked in KRL.\n"); fprintf(stderr, " -q Quiet.\n"); fprintf(stderr, " -R hostname Remove host from known_hosts file.\n"); fprintf(stderr, " -r hostname Print DNS resource record.\n"); @@ -1920,6 +2151,7 @@ fprintf(stderr, " -s ca_key Certify keys with CA key.\n"); fprintf(stderr, " -T file Screen candidates for DH-GEX moduli.\n"); fprintf(stderr, " -t type Specify type of key to create.\n"); + fprintf(stderr, " -u Update KRL rather than creating a new one.\n"); fprintf(stderr, " -V from:to Specify certificate validity interval.\n"); fprintf(stderr, " -v Verbose.\n"); fprintf(stderr, " -W gen Generator to use for generating DH-GEX moduli.\n"); @@ -1937,14 +2169,14 @@ { char dotsshdir[MAXPATHLEN], comment[1024], *passphrase1, *passphrase2; char *checkpoint = NULL; - char out_file[MAXPATHLEN], *rr_hostname = NULL, *ep; + char out_file[MAXPATHLEN], *ep, *rr_hostname = NULL; Key *private, *public; struct passwd *pw; struct stat st; int opt, type, fd; u_int32_t memory = 0, generator_wanted = 0, trials = 100; int do_gen_candidates = 0, do_screen_candidates = 0; - int gen_all_hostkeys = 0; + int gen_all_hostkeys = 0, gen_krl = 0, update_krl = 0, check_krl = 0; unsigned long start_lineno = 0, lines_to_process = 0; BIGNUM *start = NULL; FILE *f; @@ -1970,8 +2202,8 @@ exit(1); } - while ((opt = getopt(argc, argv, "AegiqpclBHLhvxXyF:b:f:t:D:I:J:j:K:P:" - "m:N:n:O:C:r:g:R:T:G:M:S:s:a:V:W:z:")) != -1) { + while ((opt = getopt(argc, argv, "ABHLQXceghiklpquvxy" + "C:D:F:G:I:J:K:M:N:O:P:R:S:T:V:W:a:b:f:g:j:m:n:r:s:t:z:")) != -1) { switch (opt) { case 'A': gen_all_hostkeys = 1; @@ -2050,6 +2282,9 @@ case 'N': identity_new_passphrase = optarg; break; + case 'Q': + check_krl = 1; + break; case 'O': add_cert_option(optarg); break; @@ -2068,6 +2303,9 @@ cert_key_type = SSH2_CERT_TYPE_HOST; certflags_flags = 0; break; + case 'k': + gen_krl = 1; + break; case 'i': case 'X': /* import key */ @@ -2085,6 +2323,9 @@ case 'D': pkcs11provider = optarg; break; + case 'u': + update_krl = 1; + break; case 'v': if (log_level == SYSLOG_LEVEL_INFO) log_level = SYSLOG_LEVEL_DEBUG1; @@ -2160,11 +2401,11 @@ argc -= optind; if (ca_key_path != NULL) { - if (argc < 1) { + if (argc < 1 && !gen_krl) { printf("Too few arguments.\n"); usage(); } - } else if (argc > 0) { + } else if (argc > 0 && !gen_krl && !check_krl) { printf("Too many arguments.\n"); usage(); } @@ -2176,6 +2417,14 @@ printf("Cannot use -l with -H or -R.\n"); usage(); } + if (gen_krl) { + do_gen_krl(pw, update_krl, argc, argv); + return (0); + } + if (check_krl) { + do_check_krl(pw, argc, argv); + return (0); + } if (ca_key_path != NULL) { if (cert_key_id == NULL) fatal("Must specify key id (-I) when certifying"); @@ -2243,7 +2492,7 @@ if (do_screen_candidates) { FILE *in; - FILE *out = fopen(out_file, "w"); + FILE *out = fopen(out_file, "a"); if (have_identity && strcmp(identity_file, "-") != 0) { if ((in = fopen(identity_file, "r")) == NULL) {