=================================================================== RCS file: /cvsrepo/anoncvs/cvs/src/usr.bin/ssh/ssh-keygen.c,v retrieving revision 1.374 retrieving revision 1.377 diff -u -r1.374 -r1.377 --- src/usr.bin/ssh/ssh-keygen.c 2019/12/10 22:37:20 1.374 +++ src/usr.bin/ssh/ssh-keygen.c 2019/12/30 09:19:52 1.377 @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-keygen.c,v 1.374 2019/12/10 22:37:20 djm Exp $ */ +/* $OpenBSD: ssh-keygen.c,v 1.377 2019/12/30 09:19:52 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1994 Tatu Ylonen , Espoo, Finland @@ -156,10 +156,7 @@ /* Cipher for new-format private keys */ static char *openssh_format_cipher = NULL; -/* - * Number of KDF rounds to derive new format keys / - * number of primality trials when screening moduli. - */ +/* Number of KDF rounds to derive new format keys. */ static int rounds = 0; /* argv0 */ @@ -2741,6 +2738,122 @@ } static void +do_moduli_gen(const char *out_file, char **opts, size_t nopts) +{ +#ifdef WITH_OPENSSL + /* Moduli generation/screening */ + u_int32_t memory = 0; + BIGNUM *start = NULL; + int moduli_bits = 0; + FILE *out; + size_t i; + const char *errstr; + + /* Parse options */ + for (i = 0; i < nopts; i++) { + if (strncmp(opts[i], "memory=", 7) == 0) { + memory = (u_int32_t)strtonum(opts[i]+7, 1, + UINT_MAX, &errstr); + if (errstr) { + fatal("Memory limit is %s: %s", + errstr, opts[i]+7); + } + } else if (strncmp(opts[i], "start=", 6) == 0) { + /* XXX - also compare length against bits */ + if (BN_hex2bn(&start, opts[i]+6) == 0) + fatal("Invalid start point."); + } else if (strncmp(opts[i], "bits=", 5) == 0) { + moduli_bits = (int)strtonum(opts[i]+5, 1, + INT_MAX, &errstr); + if (errstr) { + fatal("Invalid number: %s (%s)", + opts[i]+12, errstr); + } + } else { + fatal("Option \"%s\" is unsupported for moduli " + "generation", opts[i]); + } + } + + if ((out = fopen(out_file, "w")) == NULL) { + fatal("Couldn't open modulus candidate file \"%s\": %s", + out_file, strerror(errno)); + } + setvbuf(out, NULL, _IOLBF, 0); + + if (moduli_bits == 0) + moduli_bits = DEFAULT_BITS; + if (gen_candidates(out, memory, moduli_bits, start) != 0) + fatal("modulus candidate generation failed"); +#else /* WITH_OPENSSL */ + fatal("Moduli generation is not supported"); +#endif /* WITH_OPENSSL */ +} + +static void +do_moduli_screen(const char *out_file, char **opts, size_t nopts) +{ +#ifdef WITH_OPENSSL + /* Moduli generation/screening */ + char *checkpoint = NULL; + u_int32_t generator_wanted = 0; + unsigned long start_lineno = 0, lines_to_process = 0; + int prime_tests = 0; + FILE *out, *in = stdin; + size_t i; + const char *errstr; + + /* Parse options */ + for (i = 0; i < nopts; i++) { + if (strncmp(opts[i], "lines=", 6) == 0) { + lines_to_process = strtoul(opts[i]+6, NULL, 10); + } else if (strncmp(opts[i], "start-line=", 11) == 0) { + start_lineno = strtoul(opts[i]+11, NULL, 10); + } else if (strncmp(opts[i], "checkpoint=", 11) == 0) { + checkpoint = xstrdup(opts[i]+11); + } else if (strncmp(opts[i], "generator=", 10) == 0) { + generator_wanted = (u_int32_t)strtonum( + opts[i]+10, 1, UINT_MAX, &errstr); + if (errstr != NULL) { + fatal("Generator invalid: %s (%s)", + opts[i]+10, errstr); + } + } else if (strncmp(opts[i], "prime-tests=", 12) == 0) { + prime_tests = (int)strtonum(opts[i]+12, 1, + INT_MAX, &errstr); + if (errstr) { + fatal("Invalid number: %s (%s)", + opts[i]+12, errstr); + } + } else { + fatal("Option \"%s\" is unsupported for moduli " + "screening", opts[i]); + } + } + + if (have_identity && strcmp(identity_file, "-") != 0) { + if ((in = fopen(identity_file, "r")) == NULL) { + fatal("Couldn't open modulus candidate " + "file \"%s\": %s", identity_file, + strerror(errno)); + } + } + + if ((out = fopen(out_file, "a")) == NULL) { + fatal("Couldn't open moduli file \"%s\": %s", + out_file, strerror(errno)); + } + setvbuf(out, NULL, _IOLBF, 0); + if (prime_test(in, out, prime_tests == 0 ? 100 : prime_tests, + generator_wanted, checkpoint, + start_lineno, lines_to_process) != 0) + fatal("modulus screening failed"); +#else /* WITH_OPENSSL */ + fatal("Moduli screening is not supported"); +#endif /* WITH_OPENSSL */ +} + +static void usage(void) { fprintf(stderr, @@ -2765,9 +2878,8 @@ " ssh-keygen -R hostname [-f known_hosts_file]\n" " ssh-keygen -r hostname [-g] [-f input_keyfile]\n" #ifdef WITH_OPENSSL - " ssh-keygen -G output_file [-v] [-b bits] [-M memory] [-S start_point]\n" - " ssh-keygen -f input_file -T output_file [-v] [-a rounds] [-J num_lines]\n" - " [-j start_line] [-K checkpt] [-W generator]\n" + " ssh-keygen -M generate [-O option] output\n" + " ssh-keygen -M screen [-f input_file] [-O option] [-a rounds] output_file\n" #endif " ssh-keygen -I certificate_identity -s ca_key [-hU] [-D pkcs11_provider]\n" " [-n principals] [-O option] [-V validity_interval]\n" @@ -2801,22 +2913,16 @@ int gen_all_hostkeys = 0, gen_krl = 0, update_krl = 0, check_krl = 0; int prefer_agent = 0, convert_to = 0, convert_from = 0; int print_public = 0, print_generic = 0, cert_serial_autoinc = 0; + int do_gen_candidates = 0, do_screen_candidates = 0; unsigned long long ull, cert_serial = 0; - char *identity_comment = NULL, *ca_key_path = NULL; + char *identity_comment = NULL, *ca_key_path = NULL, **opts = NULL; + size_t i, nopts = 0; u_int32_t bits = 0; uint8_t sk_flags = SSH_SK_USER_PRESENCE_REQD; FILE *f; const char *errstr; int log_level = SYSLOG_LEVEL_INFO; char *sign_op = NULL; -#ifdef WITH_OPENSSL - /* Moduli generation/screening */ - char out_file[PATH_MAX], *checkpoint = NULL; - u_int32_t memory = 0, generator_wanted = 0; - int do_gen_candidates = 0, do_screen_candidates = 0; - unsigned long start_lineno = 0, lines_to_process = 0; - BIGNUM *start = NULL; -#endif extern int optind; extern char *optarg; @@ -2840,10 +2946,10 @@ sk_provider = getenv("SSH_SK_PROVIDER"); - /* Remaining character: d */ + /* Remaining characters: dGjJKSTW */ while ((opt = getopt(argc, argv, "ABHLQUXceghiklopquvy" - "C:D:E:F:G:I:J:K:M:N:O:P:R:S:T:V:W:Y:Z:" - "a:b:f:g:j:m:n:r:s:t:w:x:z:")) != -1) { + "C:D:E:F:I:M:N:O:P:R:V:Y:Z:" + "a:b:f:g:m:n:r:s:t:w:x:z:")) != -1) { switch (opt) { case 'A': gen_all_hostkeys = 1; @@ -2931,7 +3037,9 @@ check_krl = 1; break; case 'O': - add_cert_option(optarg); + opts = xrecallocarray(opts, nopts, nopts + 1, + sizeof(*opts)); + opts[nopts++] = xstrdup(optarg); break; case 'Z': openssh_format_cipher = optarg; @@ -3008,6 +3116,8 @@ fatal("Missing security key flags"); if (strcasecmp(optarg, "no-touch-required") == 0) sk_flags &= ~SSH_SK_USER_PRESENCE_REQD; + else if (strcasecmp(optarg, "resident") == 0) + sk_flags |= SSH_SK_RESIDENT_KEY; else { ull = strtoull(optarg, &ep, 0); if (*ep != '\0') @@ -3031,50 +3141,14 @@ (errno == ERANGE && cert_serial == ULLONG_MAX)) fatal("Invalid serial number \"%s\"", optarg); break; -#ifdef WITH_OPENSSL - /* Moduli generation/screening */ - case 'G': - do_gen_candidates = 1; - if (strlcpy(out_file, optarg, sizeof(out_file)) >= - sizeof(out_file)) - fatal("Output filename too long"); - break; - case 'J': - lines_to_process = strtoul(optarg, NULL, 10); - break; - case 'j': - start_lineno = strtoul(optarg, NULL, 10); - break; - case 'K': - if (strlen(optarg) >= PATH_MAX) - fatal("Checkpoint filename too long"); - checkpoint = xstrdup(optarg); - break; case 'M': - memory = (u_int32_t)strtonum(optarg, 1, UINT_MAX, - &errstr); - if (errstr) - fatal("Memory limit is %s: %s", errstr, optarg); + if (strcmp(optarg, "generate") == 0) + do_gen_candidates = 1; + else if (strcmp(optarg, "screen") == 0) + do_screen_candidates = 1; + else + fatal("Unsupported moduli option %s", optarg); break; - case 'S': - /* XXX - also compare length against bits */ - if (BN_hex2bn(&start, optarg) == 0) - fatal("Invalid start point."); - break; - case 'T': - do_screen_candidates = 1; - if (strlcpy(out_file, optarg, sizeof(out_file)) >= - sizeof(out_file)) - fatal("Output filename too long"); - break; - case 'W': - generator_wanted = (u_int32_t)strtonum(optarg, 1, - UINT_MAX, &errstr); - if (errstr != NULL) - fatal("Desired generator invalid: %s (%s)", - optarg, errstr); - break; -#endif /* WITH_OPENSSL */ case '?': default: usage(); @@ -3139,7 +3213,8 @@ error("Too few arguments."); usage(); } - } else if (argc > 0 && !gen_krl && !check_krl) { + } else if (argc > 0 && !gen_krl && !check_krl && + !do_gen_candidates && !do_screen_candidates) { error("Too many arguments."); usage(); } @@ -3151,20 +3226,28 @@ error("Cannot use -l with -H or -R."); usage(); } -#ifdef WITH_OPENSSL if (gen_krl) { +#ifdef WITH_OPENSSL do_gen_krl(pw, update_krl, ca_key_path, cert_serial, identity_comment, argc, argv); return (0); +#else + fatal("KRL generation not supported"); +#endif } if (check_krl) { +#ifdef WITH_OPENSSL do_check_krl(pw, argc, argv); return (0); - } +#else + fatal("KRL checking not supported"); #endif + } if (ca_key_path != NULL) { if (cert_key_id == NULL) fatal("Must specify key id (-I) when certifying"); + for (i = 0; i < nopts; i++) + add_cert_option(opts[i]); do_ca_sign(pw, ca_key_path, prefer_agent, cert_serial, cert_serial_autoinc, argc, argv); } @@ -3225,47 +3308,20 @@ } } -#ifdef WITH_OPENSSL + if (do_gen_candidates || do_screen_candidates) { + if (argc <= 0) + fatal("No output file specified"); + else if (argc > 1) + fatal("Too many output files specified"); + } if (do_gen_candidates) { - FILE *out = fopen(out_file, "w"); - - if (out == NULL) { - error("Couldn't open modulus candidate file \"%s\": %s", - out_file, strerror(errno)); - return (1); - } - if (bits == 0) - bits = DEFAULT_BITS; - if (gen_candidates(out, memory, bits, start) != 0) - fatal("modulus candidate generation failed"); - - return (0); + do_moduli_gen(argv[0], opts, nopts); + return 0; } - if (do_screen_candidates) { - FILE *in; - FILE *out = fopen(out_file, "a"); - - if (have_identity && strcmp(identity_file, "-") != 0) { - if ((in = fopen(identity_file, "r")) == NULL) { - fatal("Couldn't open modulus candidate " - "file \"%s\": %s", identity_file, - strerror(errno)); - } - } else - in = stdin; - - if (out == NULL) { - fatal("Couldn't open moduli file \"%s\": %s", - out_file, strerror(errno)); - } - if (prime_test(in, out, rounds == 0 ? 100 : rounds, - generator_wanted, checkpoint, - start_lineno, lines_to_process) != 0) - fatal("modulus screening failed"); - return (0); + do_moduli_screen(argv[0], opts, nopts); + return 0; } -#endif if (gen_all_hostkeys) { do_gen_all_hostkeys(pw);