=================================================================== RCS file: /cvsrepo/anoncvs/cvs/src/usr.bin/ssh/ssh-keygen.c,v retrieving revision 1.185 retrieving revision 1.189 diff -u -r1.185 -r1.189 --- src/usr.bin/ssh/ssh-keygen.c 2010/03/15 19:40:02 1.185 +++ src/usr.bin/ssh/ssh-keygen.c 2010/04/23 22:48:31 1.189 @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-keygen.c,v 1.185 2010/03/15 19:40:02 stevesk Exp $ */ +/* $OpenBSD: ssh-keygen.c,v 1.189 2010/04/23 22:48:31 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1994 Tatu Ylonen , Espoo, Finland @@ -97,6 +97,9 @@ /* Path to CA key when certifying keys. */ char *ca_key_path = NULL; +/* Certificate serial number */ +long long cert_serial = 0; + /* Key type when certifying */ u_int cert_key_type = SSH2_CERT_TYPE_USER; @@ -110,18 +113,18 @@ u_int64_t cert_valid_from = 0; u_int64_t cert_valid_to = ~0ULL; -/* Certificate constraints */ -#define CONSTRAINT_X_FWD (1) -#define CONSTRAINT_AGENT_FWD (1<<1) -#define CONSTRAINT_PORT_FWD (1<<2) -#define CONSTRAINT_PTY (1<<3) -#define CONSTRAINT_USER_RC (1<<4) -#define CONSTRAINT_DEFAULT (CONSTRAINT_X_FWD|CONSTRAINT_AGENT_FWD| \ - CONSTRAINT_PORT_FWD|CONSTRAINT_PTY| \ - CONSTRAINT_USER_RC) -u_int32_t constraint_flags = CONSTRAINT_DEFAULT; -char *constraint_command = NULL; -char *constraint_src_addr = NULL; +/* Certificate options */ +#define CRITOPT_X_FWD (1) +#define CRITOPT_AGENT_FWD (1<<1) +#define CRITOPT_PORT_FWD (1<<2) +#define CRITOPT_PTY (1<<3) +#define CRITOPT_USER_RC (1<<4) +#define CRITOPT_DEFAULT (CRITOPT_X_FWD|CRITOPT_AGENT_FWD| \ + CRITOPT_PORT_FWD|CRITOPT_PTY| \ + CRITOPT_USER_RC) +u_int32_t critical_flags = CRITOPT_DEFAULT; +char *critical_command = NULL; +char *critical_src_addr = NULL; /* Dump public key file in format used by real and the original SSH 2 */ int convert_to_ssh2 = 0; @@ -153,9 +156,13 @@ case KEY_RSA1: name = _PATH_SSH_CLIENT_IDENTITY; break; + case KEY_DSA_CERT: + case KEY_DSA_CERT_V00: case KEY_DSA: name = _PATH_SSH_CLIENT_ID_DSA; break; + case KEY_RSA_CERT: + case KEY_RSA_CERT_V00: case KEY_RSA: name = _PATH_SSH_CLIENT_ID_RSA; break; @@ -1096,7 +1103,7 @@ } static void -add_flag_constraint(Buffer *c, const char *name) +add_flag_option(Buffer *c, const char *name) { debug3("%s: %s", __func__, name); buffer_put_cstring(c, name); @@ -1104,7 +1111,7 @@ } static void -add_string_constraint(Buffer *c, const char *name, const char *value) +add_string_option(Buffer *c, const char *name, const char *value) { Buffer b; @@ -1119,24 +1126,23 @@ } static void -prepare_constraint_buf(Buffer *c) +prepare_options_buf(Buffer *c) { - buffer_clear(c); - if ((constraint_flags & CONSTRAINT_X_FWD) != 0) - add_flag_constraint(c, "permit-X11-forwarding"); - if ((constraint_flags & CONSTRAINT_AGENT_FWD) != 0) - add_flag_constraint(c, "permit-agent-forwarding"); - if ((constraint_flags & CONSTRAINT_PORT_FWD) != 0) - add_flag_constraint(c, "permit-port-forwarding"); - if ((constraint_flags & CONSTRAINT_PTY) != 0) - add_flag_constraint(c, "permit-pty"); - if ((constraint_flags & CONSTRAINT_USER_RC) != 0) - add_flag_constraint(c, "permit-user-rc"); - if (constraint_command != NULL) - add_string_constraint(c, "force-command", constraint_command); - if (constraint_src_addr != NULL) - add_string_constraint(c, "source-address", constraint_src_addr); + if ((critical_flags & CRITOPT_X_FWD) != 0) + add_flag_option(c, "permit-X11-forwarding"); + if ((critical_flags & CRITOPT_AGENT_FWD) != 0) + add_flag_option(c, "permit-agent-forwarding"); + if ((critical_flags & CRITOPT_PORT_FWD) != 0) + add_flag_option(c, "permit-port-forwarding"); + if ((critical_flags & CRITOPT_PTY) != 0) + add_flag_option(c, "permit-pty"); + if ((critical_flags & CRITOPT_USER_RC) != 0) + add_flag_option(c, "permit-user-rc"); + if (critical_command != NULL) + add_string_option(c, "force-command", critical_command); + if (critical_src_addr != NULL) + add_string_option(c, "source-address", critical_src_addr); } static void @@ -1147,12 +1153,32 @@ Key *ca, *public; char *otmp, *tmp, *cp, *out, *comment, **plist = NULL; FILE *f; + int v00 = 0; /* legacy keys */ tmp = tilde_expand_filename(ca_key_path, pw->pw_uid); if ((ca = load_identity(tmp)) == NULL) fatal("Couldn't load CA key \"%s\"", tmp); xfree(tmp); + if (key_type_name != NULL) { + switch (key_type_from_name(key_type_name)) { + case KEY_RSA_CERT_V00: + case KEY_DSA_CERT_V00: + v00 = 1; + break; + case KEY_UNSPEC: + if (strcasecmp(key_type_name, "v00") == 0) { + v00 = 1; + break; + } else if (strcasecmp(key_type_name, "v01") == 0) + break; + /* FALLTHROUGH */ + default: + fprintf(stderr, "unknown key type %s\n", key_type_name); + exit(1); + } + } + for (i = 0; i < argc; i++) { /* Split list of principals */ n = 0; @@ -1175,15 +1201,16 @@ __func__, tmp, key_type(public)); /* Prepare certificate to sign */ - if (key_to_certified(public) != 0) + if (key_to_certified(public, v00) != 0) fatal("Could not upgrade key %s to certificate", tmp); public->cert->type = cert_key_type; + public->cert->serial = (u_int64_t)cert_serial; public->cert->key_id = xstrdup(cert_key_id); public->cert->nprincipals = n; public->cert->principals = plist; public->cert->valid_after = cert_valid_from; public->cert->valid_before = cert_valid_to; - prepare_constraint_buf(&public->cert->constraints); + prepare_options_buf(&public->cert->critical); public->cert->signature_key = key_from_private(ca); if (key_certify(public, ca) != 0) @@ -1204,13 +1231,14 @@ fprintf(f, " %s\n", comment); fclose(f); - if (!quiet) - logit("Signed %s key %s: id \"%s\"%s%s valid %s", - cert_key_type == SSH2_CERT_TYPE_USER?"user":"host", - out, cert_key_id, + if (!quiet) { + logit("Signed %s key %s: id \"%s\" serial %llu%s%s " + "valid %s", key_cert_type(public), + out, public->cert->key_id, public->cert->serial, cert_principals != NULL ? " for " : "", cert_principals != NULL ? cert_principals : "", fmt_validity(cert_valid_from, cert_valid_to)); + } key_free(public); xfree(out); @@ -1313,50 +1341,50 @@ } static void -add_cert_constraint(char *opt) +add_cert_option(char *opt) { char *val; if (strcmp(opt, "clear") == 0) - constraint_flags = 0; + critical_flags = 0; else if (strcasecmp(opt, "no-x11-forwarding") == 0) - constraint_flags &= ~CONSTRAINT_X_FWD; + critical_flags &= ~CRITOPT_X_FWD; else if (strcasecmp(opt, "permit-x11-forwarding") == 0) - constraint_flags |= CONSTRAINT_X_FWD; + critical_flags |= CRITOPT_X_FWD; else if (strcasecmp(opt, "no-agent-forwarding") == 0) - constraint_flags &= ~CONSTRAINT_AGENT_FWD; + critical_flags &= ~CRITOPT_AGENT_FWD; else if (strcasecmp(opt, "permit-agent-forwarding") == 0) - constraint_flags |= CONSTRAINT_AGENT_FWD; + critical_flags |= CRITOPT_AGENT_FWD; else if (strcasecmp(opt, "no-port-forwarding") == 0) - constraint_flags &= ~CONSTRAINT_PORT_FWD; + critical_flags &= ~CRITOPT_PORT_FWD; else if (strcasecmp(opt, "permit-port-forwarding") == 0) - constraint_flags |= CONSTRAINT_PORT_FWD; + critical_flags |= CRITOPT_PORT_FWD; else if (strcasecmp(opt, "no-pty") == 0) - constraint_flags &= ~CONSTRAINT_PTY; + critical_flags &= ~CRITOPT_PTY; else if (strcasecmp(opt, "permit-pty") == 0) - constraint_flags |= CONSTRAINT_PTY; + critical_flags |= CRITOPT_PTY; else if (strcasecmp(opt, "no-user-rc") == 0) - constraint_flags &= ~CONSTRAINT_USER_RC; + critical_flags &= ~CRITOPT_USER_RC; else if (strcasecmp(opt, "permit-user-rc") == 0) - constraint_flags |= CONSTRAINT_USER_RC; + critical_flags |= CRITOPT_USER_RC; else if (strncasecmp(opt, "force-command=", 14) == 0) { val = opt + 14; if (*val == '\0') - fatal("Empty force-command constraint"); - if (constraint_command != NULL) + fatal("Empty force-command option"); + if (critical_command != NULL) fatal("force-command already specified"); - constraint_command = xstrdup(val); + critical_command = xstrdup(val); } else if (strncasecmp(opt, "source-address=", 15) == 0) { val = opt + 15; if (*val == '\0') - fatal("Empty source-address constraint"); - if (constraint_src_addr != NULL) + fatal("Empty source-address option"); + if (critical_src_addr != NULL) fatal("source-address already specified"); if (addr_match_cidr_list(NULL, val) != 0) fatal("Invalid source-address list"); - constraint_src_addr = xstrdup(val); + critical_src_addr = xstrdup(val); } else - fatal("Unsupported certificate constraint \"%s\"", opt); + fatal("Unsupported certificate option \"%s\"", opt); } static void @@ -1365,9 +1393,9 @@ Key *key; struct stat st; char *key_fp, *ca_fp; - Buffer constraints, constraint; + Buffer options, option; u_char *name, *data; - u_int i, dlen; + u_int i, dlen, v00; if (!have_identity) ask_filename(pw, "Enter file in which the key is"); @@ -1379,17 +1407,21 @@ fatal("%s is not a public key", identity_file); if (!key_is_cert(key)) fatal("%s is not a certificate", identity_file); - + v00 = key->type == KEY_RSA_CERT_V00 || key->type == KEY_DSA_CERT_V00; + key_fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX); ca_fp = key_fingerprint(key->cert->signature_key, SSH_FP_MD5, SSH_FP_HEX); printf("%s:\n", identity_file); - printf(" %s %s certificate %s\n", key_type(key), - key_cert_type(key), key_fp); - printf(" Signed by %s CA %s\n", + printf(" Type: %s %s certificate\n", key_ssh_name(key), + key_cert_type(key)); + printf(" Public key: %s %s\n", key_type(key), key_fp); + printf(" Signing CA: %s %s\n", key_type(key->cert->signature_key), ca_fp); - printf(" Key ID \"%s\"\n", key->cert->key_id); + printf(" Key ID: \"%s\"\n", key->cert->key_id); + if (!v00) + printf(" Serial: %llu\n", key->cert->serial); printf(" Valid: %s\n", fmt_validity(key->cert->valid_after, key->cert->valid_before)); printf(" Principals: "); @@ -1401,20 +1433,20 @@ key->cert->principals[i]); printf("\n"); } - printf(" Constraints: "); - if (buffer_len(&key->cert->constraints) == 0) + printf(" Critical Options: "); + if (buffer_len(&key->cert->critical) == 0) printf("(none)\n"); else { printf("\n"); - buffer_init(&constraints); - buffer_append(&constraints, - buffer_ptr(&key->cert->constraints), - buffer_len(&key->cert->constraints)); - buffer_init(&constraint); - while (buffer_len(&constraints) != 0) { - name = buffer_get_string(&constraints, NULL); - data = buffer_get_string_ptr(&constraints, &dlen); - buffer_append(&constraint, data, dlen); + buffer_init(&options); + buffer_append(&options, + buffer_ptr(&key->cert->critical), + buffer_len(&key->cert->critical)); + buffer_init(&option); + while (buffer_len(&options) != 0) { + name = buffer_get_string(&options, NULL); + data = buffer_get_string_ptr(&options, &dlen); + buffer_append(&option, data, dlen); printf(" %s", name); if (strcmp(name, "permit-X11-forwarding") == 0 || strcmp(name, "permit-agent-forwarding") == 0 || @@ -1424,22 +1456,43 @@ printf("\n"); else if (strcmp(name, "force-command") == 0 || strcmp(name, "source-address") == 0) { - data = buffer_get_string(&constraint, NULL); + data = buffer_get_string(&option, NULL); printf(" %s\n", data); xfree(data); } else { - printf(" UNKNOWN CONSTRAINT (len %u)\n", - buffer_len(&constraint)); - buffer_clear(&constraint); + printf(" UNKNOWN OPTION (len %u)\n", + buffer_len(&option)); + buffer_clear(&option); } xfree(name); - if (buffer_len(&constraint) != 0) - fatal("Constraint corrupt: extra data at end"); + if (buffer_len(&option) != 0) + fatal("Option corrupt: extra data at end"); } - buffer_free(&constraint); - buffer_free(&constraints); + buffer_free(&option); + buffer_free(&options); } - + if (!v00) { + printf(" Extensions: "); + if (buffer_len(&key->cert->extensions) == 0) + printf("(none)\n"); + else { + printf("\n"); + buffer_init(&options); + buffer_append(&options, + buffer_ptr(&key->cert->extensions), + buffer_len(&key->cert->extensions)); + buffer_init(&option); + while (buffer_len(&options) != 0) { + name = buffer_get_string(&options, NULL); + (void)buffer_get_string_ptr(&options, &dlen); + printf(" %s UNKNOWN OPTION " + "(len %u)\n", name, dlen); + xfree(name); + } + buffer_free(&option); + buffer_free(&options); + } + } exit(0); } @@ -1470,7 +1523,7 @@ fprintf(stderr, " -M memory Amount of memory (MB) to use for generating DH-GEX moduli.\n"); fprintf(stderr, " -n name,... User/host principal names to include in certificate\n"); fprintf(stderr, " -N phrase Provide new passphrase.\n"); - fprintf(stderr, " -O cnstr Specify a certificate constraint.\n"); + 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 Quiet.\n"); @@ -1484,6 +1537,7 @@ fprintf(stderr, " -v Verbose.\n"); fprintf(stderr, " -W gen Generator to use for generating DH-GEX moduli.\n"); fprintf(stderr, " -y Read private key file and print public key.\n"); + fprintf(stderr, " -z serial Specify a serial number.\n"); exit(1); } @@ -1501,6 +1555,7 @@ struct passwd *pw; struct stat st; int opt, type, fd; + u_int maxbits; u_int32_t memory = 0, generator_wanted = 0, trials = 100; int do_gen_candidates = 0, do_screen_candidates = 0; BIGNUM *start = NULL; @@ -1528,7 +1583,7 @@ } while ((opt = getopt(argc, argv, "degiqpclBHLhvxXyF:b:f:t:D:I:P:N:n:" - "O:C:r:g:R:T:G:M:S:s:a:V:W:")) != -1) { + "O:C:r:g:R:T:G:M:S:s:a:V:W:z:")) != -1) { switch (opt) { case 'b': bits = (u_int32_t)strtonum(optarg, 768, 32768, &errstr); @@ -1584,7 +1639,7 @@ identity_new_passphrase = optarg; break; case 'O': - add_cert_constraint(optarg); + add_cert_option(optarg); break; case 'C': identity_comment = optarg; @@ -1599,7 +1654,7 @@ break; case 'h': cert_key_type = SSH2_CERT_TYPE_HOST; - constraint_flags = 0; + critical_flags = 0; break; case 'i': case 'X': @@ -1648,9 +1703,8 @@ break; case 'M': memory = (u_int32_t)strtonum(optarg, 1, UINT_MAX, &errstr); - if (errstr) { + if (errstr) fatal("Memory limit is %s: %s", errstr, optarg); - } break; case 'G': do_gen_candidates = 1; @@ -1672,6 +1726,11 @@ case 'V': parse_cert_times(optarg); break; + case 'z': + cert_serial = strtonum(optarg, 0, LLONG_MAX, &errstr); + if (errstr) + fatal("Invalid serial number: %s", errstr); + break; case '?': default: usage(); @@ -1798,6 +1857,12 @@ } if (bits == 0) bits = (type == KEY_DSA) ? DEFAULT_BITS_DSA : DEFAULT_BITS; + maxbits = (type == KEY_DSA) ? + OPENSSL_DSA_MAX_MODULUS_BITS : OPENSSL_RSA_MAX_MODULUS_BITS; + if (bits > maxbits) { + fprintf(stderr, "key bits exceeds maximum %d\n", maxbits); + exit(1); + } if (type == KEY_DSA && bits != 1024) fatal("DSA keys must be 1024 bits"); if (!quiet) @@ -1813,13 +1878,19 @@ ask_filename(pw, "Enter file in which to save the key"); /* Create ~/.ssh directory if it doesn't already exist. */ - snprintf(dotsshdir, sizeof dotsshdir, "%s/%s", pw->pw_dir, _PATH_SSH_USER_DIR); - if (strstr(identity_file, dotsshdir) != NULL && - stat(dotsshdir, &st) < 0) { - if (mkdir(dotsshdir, 0700) < 0) - error("Could not create directory '%s'.", dotsshdir); - else if (!quiet) - printf("Created directory '%s'.\n", dotsshdir); + snprintf(dotsshdir, sizeof dotsshdir, "%s/%s", + pw->pw_dir, _PATH_SSH_USER_DIR); + if (strstr(identity_file, dotsshdir) != NULL) { + if (stat(dotsshdir, &st) < 0) { + if (errno != ENOENT) { + error("Could not stat %s: %s", dotsshdir, + strerror(errno)); + } else if (mkdir(dotsshdir, 0700) < 0) { + error("Could not create directory '%s': %s", + dotsshdir, strerror(errno)); + } else if (!quiet) + printf("Created directory '%s'.\n", dotsshdir); + } } /* If the file already exists, ask the user to confirm. */ if (stat(identity_file, &st) >= 0) {