=================================================================== RCS file: /cvsrepo/anoncvs/cvs/src/usr.bin/ssh/ssh-keygen.c,v retrieving revision 1.292 retrieving revision 1.303 diff -u -r1.292 -r1.303 --- src/usr.bin/ssh/ssh-keygen.c 2016/09/12 03:29:16 1.292 +++ src/usr.bin/ssh/ssh-keygen.c 2017/05/07 23:15:59 1.303 @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-keygen.c,v 1.292 2016/09/12 03:29:16 dtucker Exp $ */ +/* $OpenBSD: ssh-keygen.c,v 1.303 2017/05/07 23:15:59 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1994 Tatu Ylonen , Espoo, Finland @@ -28,6 +28,7 @@ #include #include #include +#include #include "xmalloc.h" #include "sshkey.h" @@ -47,6 +48,7 @@ #include "atomicio.h" #include "krl.h" #include "digest.h" +#include "utf8.h" #ifdef ENABLE_PKCS11 #include "ssh-pkcs11.h" @@ -141,6 +143,15 @@ char *certflags_command = NULL; char *certflags_src_addr = NULL; +/* Arbitrary extensions specified by user */ +struct cert_userext { + char *key; + char *val; + int crit; +}; +struct cert_userext *cert_userext; +size_t ncert_userext; + /* Conversion to/from various formats */ int convert_to = 0; int convert_from = 0; @@ -209,13 +220,21 @@ OPENSSL_DSA_MAX_MODULUS_BITS : OPENSSL_RSA_MAX_MODULUS_BITS; if (*bitsp > maxbits) fatal("key bits exceeds maximum %d", maxbits); - if (type == KEY_DSA && *bitsp != 1024) - fatal("DSA keys must be 1024 bits"); - else if (type != KEY_ECDSA && type != KEY_ED25519 && *bitsp < 1024) - fatal("Key must at least be 1024 bits"); - else if (type == KEY_ECDSA && sshkey_ecdsa_bits_to_nid(*bitsp) == -1) - fatal("Invalid ECDSA key length - valid lengths are " - "256, 384 or 521 bits"); + switch (type) { + case KEY_DSA: + if (*bitsp != 1024) + fatal("Invalid DSA key length: must be 1024 bits"); + break; + case KEY_RSA: + if (*bitsp < SSH_RSA_MINIMUM_MODULUS_SIZE) + fatal("Invalid RSA key length: minimum is %d bits", + SSH_RSA_MINIMUM_MODULUS_SIZE); + break; + case KEY_ECDSA: + if (sshkey_ecdsa_bits_to_nid(*bitsp) == -1) + fatal("Invalid ECDSA key length: valid lengths are " + "256, 384 or 521 bits"); + } #endif } @@ -229,9 +248,6 @@ name = _PATH_SSH_CLIENT_ID_RSA; else { switch (sshkey_type_from_name(key_type_name)) { - case KEY_RSA1: - name = _PATH_SSH_CLIENT_IDENTITY; - break; case KEY_DSA_CERT: case KEY_DSA: name = _PATH_SSH_CLIENT_ID_DSA; @@ -301,8 +317,6 @@ char comment[61]; int r; - if (k->type == KEY_RSA1) - fatal("version 1 keys are not supported"); if ((r = sshkey_to_blob(k, &blob, &len)) != 0) fatal("key_to_blob failed: %s", ssh_err(r)); /* Comment + surrounds must fit into 72 chars (RFC 4716 sec 3.3) */ @@ -324,7 +338,6 @@ do_convert_to_pkcs8(struct sshkey *k) { switch (sshkey_type_plain(k->type)) { - case KEY_RSA1: case KEY_RSA: if (!PEM_write_RSA_PUBKEY(stdout, k->rsa)) fatal("PEM_write_RSA_PUBKEY failed"); @@ -347,7 +360,6 @@ do_convert_to_pem(struct sshkey *k) { switch (sshkey_type_plain(k->type)) { - case KEY_RSA1: case KEY_RSA: if (!PEM_write_RSAPublicKey(stdout, k->rsa)) fatal("PEM_write_RSAPublicKey failed"); @@ -800,13 +812,6 @@ struct sshkey *ret; int r; - if ((ret = sshkey_new(KEY_RSA1)) == NULL) - fatal("sshkey_new failed"); - /* Try RSA1 */ - if ((r = sshkey_read(ret, cpp)) == 0) - return ret; - /* Try modern */ - sshkey_free(ret); if ((ret = sshkey_new(KEY_UNSPEC)) == NULL) fatal("sshkey_new failed"); if ((r = sshkey_read(ret, cpp)) == 0) @@ -829,7 +834,7 @@ ra = sshkey_fingerprint(public, fingerprint_hash, SSH_FP_RANDOMART); if (fp == NULL || ra == NULL) fatal("%s: sshkey_fingerprint failed", __func__); - printf("%u %s %s (%s)\n", sshkey_size(public), fp, + mprintf("%u %s %s (%s)\n", sshkey_size(public), fp, comment ? comment : "no comment", sshkey_type(public)); if (log_level >= SYSLOG_LEVEL_VERBOSE) printf("%s\n", ra); @@ -962,9 +967,6 @@ char *path; } key_types[] = { #ifdef WITH_OPENSSL -#ifdef WITH_SSH1 - { "rsa1", "RSA1", _PATH_HOST_KEY_FILE }, -#endif /* WITH_SSH1 */ { "rsa", "RSA" ,_PATH_HOST_RSA_KEY_FILE }, { "dsa", "DSA", _PATH_HOST_DSA_KEY_FILE }, { "ecdsa", "ECDSA",_PATH_HOST_ECDSA_KEY_FILE }, @@ -1066,6 +1068,7 @@ struct known_hosts_ctx *ctx = (struct known_hosts_ctx *)_ctx; char *hashed, *cp, *hosts, *ohosts; int has_wild = l->hosts && strcspn(l->hosts, "*?!") != strlen(l->hosts); + int was_hashed = l->hosts && l->hosts[0] == HASH_DELIM; switch (l->status) { case HKF_STATUS_OK: @@ -1074,11 +1077,10 @@ * Don't hash hosts already already hashed, with wildcard * characters or a CA/revocation marker. */ - if ((l->match & HKF_MATCH_HOST_HASHED) != 0 || - has_wild || l->marker != MRK_NONE) { + if (was_hashed || has_wild || l->marker != MRK_NONE) { fprintf(ctx->out, "%s\n", l->line); if (has_wild && !find_host) { - logit("%s:%ld: ignoring host name " + logit("%s:%lu: ignoring host name " "with wildcard: %.64s", l->path, l->linenum, l->hosts); } @@ -1090,6 +1092,7 @@ */ ohosts = hosts = xstrdup(l->hosts); while ((cp = strsep(&hosts, ",")) != NULL && *cp != '\0') { + lowercase(cp); if ((hashed = host_hash(cp, NULL, 0)) == NULL) fatal("hash_host failed"); fprintf(ctx->out, "%s %s\n", hashed, l->rawkey); @@ -1100,7 +1103,7 @@ case HKF_STATUS_INVALID: /* Retain invalid lines, but mark file as invalid. */ ctx->invalid = 1; - logit("%s:%ld: invalid line", l->path, l->linenum); + logit("%s:%lu: invalid line", l->path, l->linenum); /* FALLTHROUGH */ default: fprintf(ctx->out, "%s\n", l->line); @@ -1134,14 +1137,14 @@ */ ctx->found_key = 1; if (!quiet) - printf("# Host %s found: line %ld\n", + printf("# Host %s found: line %lu\n", ctx->host, l->linenum); } return 0; } else if (find_host) { ctx->found_key = 1; if (!quiet) { - printf("# Host %s found: line %ld %s\n", + printf("# Host %s found: line %lu %s\n", ctx->host, l->linenum, l->marker == MRK_CA ? "CA" : (l->marker == MRK_REVOKE ? "REVOKED" : "")); @@ -1150,7 +1153,7 @@ known_hosts_hash(l, ctx); else if (print_fingerprint) { fp = sshkey_fingerprint(l->key, fptype, rep); - printf("%s %s %s %s\n", ctx->host, + mprintf("%s %s %s %s\n", ctx->host, sshkey_type(l->key), fp, l->comment); free(fp); } else @@ -1161,7 +1164,7 @@ /* Retain non-matching hosts when deleting */ if (l->status == HKF_STATUS_INVALID) { ctx->invalid = 1; - logit("%s:%ld: invalid line", l->path, l->linenum); + logit("%s:%lu: invalid line", l->path, l->linenum); } fprintf(ctx->out, "%s\n", l->line); } @@ -1301,7 +1304,7 @@ fatal("Failed to load key %s: %s", identity_file, ssh_err(r)); } if (comment) - printf("Key has comment '%s'\n", comment); + mprintf("Key has comment '%s'\n", comment); /* Ask the new passphrase (twice). */ if (identity_new_passphrase) { @@ -1417,15 +1420,17 @@ } } - if (private->type != KEY_RSA1 && private->type != KEY_ED25519 && - !use_new_format) { - error("Comments are only supported for RSA1 or keys stored in " + if (private->type != KEY_ED25519 && !use_new_format) { + error("Comments are only supported for keys stored in " "the new format (-o)."); explicit_bzero(passphrase, strlen(passphrase)); sshkey_free(private); exit(1); } - printf("Key now has comment '%s'\n", comment); + if (comment) + printf("Key now has comment '%s'\n", comment); + else + printf("Key now has no comment\n"); if (identity_comment) { strlcpy(new_comment, identity_comment, sizeof(new_comment)); @@ -1509,6 +1514,8 @@ static void prepare_options_buf(struct sshbuf *c, int which) { + size_t i; + sshbuf_reset(c); if ((which & OPTIONS_CRITICAL) != 0 && certflags_command != NULL) @@ -1531,6 +1538,17 @@ if ((which & OPTIONS_CRITICAL) != 0 && certflags_src_addr != NULL) add_string_option(c, "source-address", certflags_src_addr); + for (i = 0; i < ncert_userext; i++) { + if ((cert_userext[i].crit && (which & OPTIONS_EXTENSIONS)) || + (!cert_userext[i].crit && (which & OPTIONS_CRITICAL))) + continue; + if (cert_userext[i].val == NULL) + add_flag_option(c, cert_userext[i].key); + else { + add_string_option(c, cert_userext[i].key, + cert_userext[i].val); + } + } } static struct sshkey * @@ -1767,7 +1785,8 @@ static void add_cert_option(char *opt) { - char *val; + char *val, *cp; + int iscrit = 0; if (strcasecmp(opt, "clear") == 0) certflags_flags = 0; @@ -1807,6 +1826,18 @@ if (addr_match_cidr_list(NULL, val) != 0) fatal("Invalid source-address list"); certflags_src_addr = xstrdup(val); + } else if (strncasecmp(opt, "extension:", 10) == 0 || + (iscrit = (strncasecmp(opt, "critical:", 9) == 0))) { + val = xstrdup(strchr(opt, ':') + 1); + if ((cp = strchr(val, '=')) != NULL) + *cp++ = '\0'; + cert_userext = xreallocarray(cert_userext, ncert_userext + 1, + sizeof(*cert_userext)); + cert_userext[ncert_userext].key = val; + cert_userext[ncert_userext].val = cp == NULL ? + NULL : xstrdup(cp); + cert_userext[ncert_userext].crit = iscrit; + ncert_userext++; } else fatal("Unsupported certificate option \"%s\"", opt); } @@ -2193,7 +2224,7 @@ usage(void) { fprintf(stderr, - "usage: ssh-keygen [-q] [-b bits] [-t dsa | ecdsa | ed25519 | rsa | rsa1]\n" + "usage: ssh-keygen [-q] [-b bits] [-t dsa | ecdsa | ed25519 | rsa]\n" " [-N new_passphrase] [-C comment] [-f output_keyfile]\n" " ssh-keygen -p [-P old_passphrase] [-N new_passphrase] [-f keyfile]\n" " ssh-keygen -i [-m key_format] [-f input_keyfile]\n" @@ -2259,6 +2290,8 @@ OpenSSL_add_all_algorithms(); log_init(argv[0], SYSLOG_LEVEL_INFO, SYSLOG_FACILITY_USER, 1); + + setlocale(LC_CTYPE, ""); /* we need this for the home * directory. */ pw = getpwuid(getuid());