version 1.194, 2010/06/30 07:26:03 |
version 1.208, 2011/03/24 22:14:54 |
|
|
/* Number of bits in the RSA/DSA key. This value can be set on the command line. */ |
/* Number of bits in the RSA/DSA key. This value can be set on the command line. */ |
#define DEFAULT_BITS 2048 |
#define DEFAULT_BITS 2048 |
#define DEFAULT_BITS_DSA 1024 |
#define DEFAULT_BITS_DSA 1024 |
|
#define DEFAULT_BITS_ECDSA 256 |
u_int32_t bits = 0; |
u_int32_t bits = 0; |
|
|
/* |
/* |
|
|
|
|
char *key_type_name = NULL; |
char *key_type_name = NULL; |
|
|
|
/* Load key from this PKCS#11 provider */ |
|
char *pkcs11provider = NULL; |
|
|
/* argv0 */ |
/* argv0 */ |
extern char *__progname; |
extern char *__progname; |
|
|
int prime_test(FILE *, FILE *, u_int32_t, u_int32_t); |
int prime_test(FILE *, FILE *, u_int32_t, u_int32_t); |
|
|
static void |
static void |
|
type_bits_valid(int type, u_int32_t *bits) |
|
{ |
|
u_int maxbits; |
|
|
|
if (type == KEY_UNSPEC) { |
|
fprintf(stderr, "unknown key type %s\n", key_type_name); |
|
exit(1); |
|
} |
|
if (*bits == 0) { |
|
if (type == KEY_DSA) |
|
*bits = DEFAULT_BITS_DSA; |
|
else if (type == KEY_ECDSA) |
|
*bits = DEFAULT_BITS_ECDSA; |
|
else |
|
*bits = 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"); |
|
else if (type != KEY_ECDSA && *bits < 768) |
|
fatal("Key must at least be 768 bits"); |
|
else if (type == KEY_ECDSA && key_ecdsa_bits_to_nid(*bits) == -1) |
|
fatal("Invalid ECDSA key length - valid lengths are " |
|
"256, 384 or 521 bits"); |
|
} |
|
|
|
static void |
ask_filename(struct passwd *pw, const char *prompt) |
ask_filename(struct passwd *pw, const char *prompt) |
{ |
{ |
char buf[1024]; |
char buf[1024]; |
|
|
case KEY_DSA: |
case KEY_DSA: |
name = _PATH_SSH_CLIENT_ID_DSA; |
name = _PATH_SSH_CLIENT_ID_DSA; |
break; |
break; |
|
case KEY_ECDSA_CERT: |
|
case KEY_ECDSA: |
|
name = _PATH_SSH_CLIENT_ID_ECDSA; |
|
break; |
case KEY_RSA_CERT: |
case KEY_RSA_CERT: |
case KEY_RSA_CERT_V00: |
case KEY_RSA_CERT_V00: |
case KEY_RSA: |
case KEY_RSA: |
|
|
if (!PEM_write_DSA_PUBKEY(stdout, k->dsa)) |
if (!PEM_write_DSA_PUBKEY(stdout, k->dsa)) |
fatal("PEM_write_DSA_PUBKEY failed"); |
fatal("PEM_write_DSA_PUBKEY failed"); |
break; |
break; |
|
case KEY_ECDSA: |
|
if (!PEM_write_EC_PUBKEY(stdout, k->ecdsa)) |
|
fatal("PEM_write_EC_PUBKEY failed"); |
|
break; |
default: |
default: |
fatal("%s: unsupported key type %s", __func__, key_type(k)); |
fatal("%s: unsupported key type %s", __func__, key_type(k)); |
} |
} |
|
|
fatal("PEM_write_DSAPublicKey failed"); |
fatal("PEM_write_DSAPublicKey failed"); |
break; |
break; |
#endif |
#endif |
|
/* XXX ECDSA? */ |
default: |
default: |
fatal("%s: unsupported key type %s", __func__, key_type(k)); |
fatal("%s: unsupported key type %s", __func__, key_type(k)); |
} |
} |
|
|
(*k)->type = KEY_DSA; |
(*k)->type = KEY_DSA; |
(*k)->dsa = EVP_PKEY_get1_DSA(pubkey); |
(*k)->dsa = EVP_PKEY_get1_DSA(pubkey); |
break; |
break; |
|
case EVP_PKEY_EC: |
|
*k = key_new(KEY_UNSPEC); |
|
(*k)->type = KEY_ECDSA; |
|
(*k)->ecdsa = EVP_PKEY_get1_EC_KEY(pubkey); |
|
(*k)->ecdsa_nid = key_ecdsa_key_to_nid((*k)->ecdsa); |
|
break; |
default: |
default: |
fatal("%s: unsupported pubkey type %d", __func__, |
fatal("%s: unsupported pubkey type %d", __func__, |
EVP_PKEY_type(pubkey->type)); |
EVP_PKEY_type(pubkey->type)); |
|
|
fclose(fp); |
fclose(fp); |
return; |
return; |
} |
} |
|
/* XXX ECDSA */ |
#endif |
#endif |
fatal("%s: unrecognised raw private key format", __func__); |
fatal("%s: unrecognised raw private key format", __func__); |
} |
} |
|
|
do_convert_from(struct passwd *pw) |
do_convert_from(struct passwd *pw) |
{ |
{ |
Key *k = NULL; |
Key *k = NULL; |
int private = 0, ok; |
int private = 0, ok = 0; |
struct stat st; |
struct stat st; |
|
|
if (!have_identity) |
if (!have_identity) |
|
|
ok = PEM_write_DSAPrivateKey(stdout, k->dsa, NULL, |
ok = PEM_write_DSAPrivateKey(stdout, k->dsa, NULL, |
NULL, 0, NULL, NULL); |
NULL, 0, NULL, NULL); |
break; |
break; |
|
case KEY_ECDSA: |
|
ok = PEM_write_ECPrivateKey(stdout, k->ecdsa, NULL, |
|
NULL, 0, NULL, NULL); |
|
break; |
case KEY_RSA: |
case KEY_RSA: |
ok = PEM_write_RSAPrivateKey(stdout, k->rsa, NULL, |
ok = PEM_write_RSAPrivateKey(stdout, k->rsa, NULL, |
NULL, 0, NULL, NULL); |
NULL, 0, NULL, NULL); |
|
|
} |
} |
|
|
static void |
static void |
do_download(struct passwd *pw, char *pkcs11provider) |
do_download(struct passwd *pw) |
{ |
{ |
#ifdef ENABLE_PKCS11 |
#ifdef ENABLE_PKCS11 |
Key **keys = NULL; |
Key **keys = NULL; |
|
|
} |
} |
|
|
static void |
static void |
|
do_gen_all_hostkeys(struct passwd *pw) |
|
{ |
|
struct { |
|
char *key_type; |
|
char *key_type_display; |
|
char *path; |
|
} key_types[] = { |
|
{ "rsa1", "RSA1", _PATH_HOST_KEY_FILE }, |
|
{ "rsa", "RSA" ,_PATH_HOST_RSA_KEY_FILE }, |
|
{ "dsa", "DSA", _PATH_HOST_DSA_KEY_FILE }, |
|
{ "ecdsa", "ECDSA",_PATH_HOST_ECDSA_KEY_FILE }, |
|
{ NULL, NULL, NULL } |
|
}; |
|
|
|
int first = 0; |
|
struct stat st; |
|
Key *private, *public; |
|
char comment[1024]; |
|
int i, type, fd; |
|
FILE *f; |
|
|
|
for (i = 0; key_types[i].key_type; i++) { |
|
if (stat(key_types[i].path, &st) == 0) |
|
continue; |
|
if (errno != ENOENT) { |
|
printf("Could not stat %s: %s", key_types[i].path, |
|
strerror(errno)); |
|
first = 0; |
|
continue; |
|
} |
|
|
|
if (first == 0) { |
|
first = 1; |
|
printf("%s: generating new host keys: ", __progname); |
|
} |
|
printf("%s ", key_types[i].key_type_display); |
|
fflush(stdout); |
|
arc4random_stir(); |
|
type = key_type_from_name(key_types[i].key_type); |
|
strlcpy(identity_file, key_types[i].path, sizeof(identity_file)); |
|
bits = 0; |
|
type_bits_valid(type, &bits); |
|
private = key_generate(type, bits); |
|
if (private == NULL) { |
|
fprintf(stderr, "key_generate failed\n"); |
|
first = 0; |
|
continue; |
|
} |
|
public = key_from_private(private); |
|
snprintf(comment, sizeof comment, "%s@%s", pw->pw_name, |
|
hostname); |
|
if (!key_save_private(private, identity_file, "", comment)) { |
|
printf("Saving the key failed: %s.\n", identity_file); |
|
key_free(private); |
|
key_free(public); |
|
first = 0; |
|
continue; |
|
} |
|
key_free(private); |
|
arc4random_stir(); |
|
strlcat(identity_file, ".pub", sizeof(identity_file)); |
|
fd = open(identity_file, O_WRONLY | O_CREAT | O_TRUNC, 0644); |
|
if (fd == -1) { |
|
printf("Could not save your public key in %s\n", |
|
identity_file); |
|
key_free(public); |
|
first = 0; |
|
continue; |
|
} |
|
f = fdopen(fd, "w"); |
|
if (f == NULL) { |
|
printf("fdopen %s failed\n", identity_file); |
|
key_free(public); |
|
first = 0; |
|
continue; |
|
} |
|
if (!key_write(public, f)) { |
|
fprintf(stderr, "write key failed\n"); |
|
key_free(public); |
|
first = 0; |
|
continue; |
|
} |
|
fprintf(f, " %s\n", comment); |
|
fclose(f); |
|
key_free(public); |
|
|
|
} |
|
if (first != 0) |
|
printf("\n"); |
|
} |
|
|
|
static void |
printhost(FILE *f, const char *name, Key *public, int ca, int hash) |
printhost(FILE *f, const char *name, Key *public, int ca, int hash) |
{ |
{ |
if (print_fingerprint) { |
if (print_fingerprint) { |
|
|
prepare_options_buf(Buffer *c, int which) |
prepare_options_buf(Buffer *c, int which) |
{ |
{ |
buffer_clear(c); |
buffer_clear(c); |
|
if ((which & OPTIONS_CRITICAL) != 0 && |
|
certflags_command != NULL) |
|
add_string_option(c, "force-command", certflags_command); |
if ((which & OPTIONS_EXTENSIONS) != 0 && |
if ((which & OPTIONS_EXTENSIONS) != 0 && |
(certflags_flags & CERTOPT_X_FWD) != 0) |
|
add_flag_option(c, "permit-X11-forwarding"); |
|
if ((which & OPTIONS_EXTENSIONS) != 0 && |
|
(certflags_flags & CERTOPT_AGENT_FWD) != 0) |
(certflags_flags & CERTOPT_AGENT_FWD) != 0) |
add_flag_option(c, "permit-agent-forwarding"); |
add_flag_option(c, "permit-agent-forwarding"); |
if ((which & OPTIONS_EXTENSIONS) != 0 && |
if ((which & OPTIONS_EXTENSIONS) != 0 && |
|
|
if ((which & OPTIONS_EXTENSIONS) != 0 && |
if ((which & OPTIONS_EXTENSIONS) != 0 && |
(certflags_flags & CERTOPT_USER_RC) != 0) |
(certflags_flags & CERTOPT_USER_RC) != 0) |
add_flag_option(c, "permit-user-rc"); |
add_flag_option(c, "permit-user-rc"); |
|
if ((which & OPTIONS_EXTENSIONS) != 0 && |
|
(certflags_flags & CERTOPT_X_FWD) != 0) |
|
add_flag_option(c, "permit-X11-forwarding"); |
if ((which & OPTIONS_CRITICAL) != 0 && |
if ((which & OPTIONS_CRITICAL) != 0 && |
certflags_command != NULL) |
|
add_string_option(c, "force-command", certflags_command); |
|
if ((which & OPTIONS_CRITICAL) != 0 && |
|
certflags_src_addr != NULL) |
certflags_src_addr != NULL) |
add_string_option(c, "source-address", certflags_src_addr); |
add_string_option(c, "source-address", certflags_src_addr); |
} |
} |
|
|
|
static Key * |
|
load_pkcs11_key(char *path) |
|
{ |
|
#ifdef ENABLE_PKCS11 |
|
Key **keys = NULL, *public, *private = NULL; |
|
int i, nkeys; |
|
|
|
if ((public = key_load_public(path, NULL)) == NULL) |
|
fatal("Couldn't load CA public key \"%s\"", path); |
|
|
|
nkeys = pkcs11_add_provider(pkcs11provider, identity_passphrase, &keys); |
|
debug3("%s: %d keys", __func__, nkeys); |
|
if (nkeys <= 0) |
|
fatal("cannot read public key from pkcs11"); |
|
for (i = 0; i < nkeys; i++) { |
|
if (key_equal_public(public, keys[i])) { |
|
private = keys[i]; |
|
continue; |
|
} |
|
key_free(keys[i]); |
|
} |
|
xfree(keys); |
|
key_free(public); |
|
return private; |
|
#else |
|
fatal("no pkcs11 support"); |
|
#endif /* ENABLE_PKCS11 */ |
|
} |
|
|
static void |
static void |
do_ca_sign(struct passwd *pw, int argc, char **argv) |
do_ca_sign(struct passwd *pw, int argc, char **argv) |
{ |
{ |
|
|
FILE *f; |
FILE *f; |
int v00 = 0; /* legacy keys */ |
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) { |
if (key_type_name != NULL) { |
switch (key_type_from_name(key_type_name)) { |
switch (key_type_from_name(key_type_name)) { |
case KEY_RSA_CERT_V00: |
case KEY_RSA_CERT_V00: |
|
|
} |
} |
} |
} |
|
|
|
pkcs11_init(1); |
|
tmp = tilde_expand_filename(ca_key_path, pw->pw_uid); |
|
if (pkcs11provider != NULL) { |
|
if ((ca = load_pkcs11_key(tmp)) == NULL) |
|
fatal("No PKCS#11 key matching %s found", ca_key_path); |
|
} else if ((ca = load_identity(tmp)) == NULL) |
|
fatal("Couldn't load CA key \"%s\"", tmp); |
|
xfree(tmp); |
|
|
for (i = 0; i < argc; i++) { |
for (i = 0; i < argc; i++) { |
/* Split list of principals */ |
/* Split list of principals */ |
n = 0; |
n = 0; |
|
|
tmp = tilde_expand_filename(argv[i], pw->pw_uid); |
tmp = tilde_expand_filename(argv[i], pw->pw_uid); |
if ((public = key_load_public(tmp, &comment)) == NULL) |
if ((public = key_load_public(tmp, &comment)) == NULL) |
fatal("%s: unable to open \"%s\"", __func__, tmp); |
fatal("%s: unable to open \"%s\"", __func__, tmp); |
if (public->type != KEY_RSA && public->type != KEY_DSA) |
if (public->type != KEY_RSA && public->type != KEY_DSA && |
|
public->type != KEY_ECDSA) |
fatal("%s: key \"%s\" type %s cannot be certified", |
fatal("%s: key \"%s\" type %s cannot be certified", |
__func__, tmp, key_type(public)); |
__func__, tmp, key_type(public)); |
|
|
|
|
if (!quiet) { |
if (!quiet) { |
logit("Signed %s key %s: id \"%s\" serial %llu%s%s " |
logit("Signed %s key %s: id \"%s\" serial %llu%s%s " |
"valid %s", key_cert_type(public), |
"valid %s", key_cert_type(public), |
out, public->cert->key_id, public->cert->serial, |
out, public->cert->key_id, |
|
(unsigned long long)public->cert->serial, |
cert_principals != NULL ? " for " : "", |
cert_principals != NULL ? " for " : "", |
cert_principals != NULL ? cert_principals : "", |
cert_principals != NULL ? cert_principals : "", |
fmt_validity(cert_valid_from, cert_valid_to)); |
fmt_validity(cert_valid_from, cert_valid_to)); |
|
|
key_free(public); |
key_free(public); |
xfree(out); |
xfree(out); |
} |
} |
|
pkcs11_terminate(); |
exit(0); |
exit(0); |
} |
} |
|
|
|
|
{ |
{ |
char *val; |
char *val; |
|
|
if (strcmp(opt, "clear") == 0) |
if (strcasecmp(opt, "clear") == 0) |
certflags_flags = 0; |
certflags_flags = 0; |
else if (strcasecmp(opt, "no-x11-forwarding") == 0) |
else if (strcasecmp(opt, "no-x11-forwarding") == 0) |
certflags_flags &= ~CERTOPT_X_FWD; |
certflags_flags &= ~CERTOPT_X_FWD; |
|
|
printf(" Signing CA: %s %s\n", |
printf(" Signing CA: %s %s\n", |
key_type(key->cert->signature_key), ca_fp); |
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) |
if (!v00) { |
printf(" Serial: %llu\n", key->cert->serial); |
printf(" Serial: %llu\n", |
|
(unsigned long long)key->cert->serial); |
|
} |
printf(" Valid: %s\n", |
printf(" Valid: %s\n", |
fmt_validity(key->cert->valid_after, key->cert->valid_before)); |
fmt_validity(key->cert->valid_after, key->cert->valid_before)); |
printf(" Principals: "); |
printf(" Principals: "); |
|
|
{ |
{ |
fprintf(stderr, "usage: %s [options]\n", __progname); |
fprintf(stderr, "usage: %s [options]\n", __progname); |
fprintf(stderr, "Options:\n"); |
fprintf(stderr, "Options:\n"); |
|
fprintf(stderr, " -A Generate non-existent host keys for all key types.\n"); |
fprintf(stderr, " -a trials Number of trials for screening DH-GEX moduli.\n"); |
fprintf(stderr, " -a trials Number of trials for screening DH-GEX moduli.\n"); |
fprintf(stderr, " -B Show bubblebabble digest of key file.\n"); |
fprintf(stderr, " -B Show bubblebabble digest of key file.\n"); |
fprintf(stderr, " -b bits Number of bits in the key to create.\n"); |
fprintf(stderr, " -b bits Number of bits in the key to create.\n"); |
|
|
main(int argc, char **argv) |
main(int argc, char **argv) |
{ |
{ |
char dotsshdir[MAXPATHLEN], comment[1024], *passphrase1, *passphrase2; |
char dotsshdir[MAXPATHLEN], comment[1024], *passphrase1, *passphrase2; |
char out_file[MAXPATHLEN], *pkcs11provider = NULL; |
char out_file[MAXPATHLEN], *rr_hostname = NULL; |
char *rr_hostname = NULL; |
|
Key *private, *public; |
Key *private, *public; |
struct passwd *pw; |
struct passwd *pw; |
struct stat st; |
struct stat st; |
int opt, type, fd; |
int opt, type, fd; |
u_int maxbits; |
|
u_int32_t memory = 0, generator_wanted = 0, trials = 100; |
u_int32_t memory = 0, generator_wanted = 0, trials = 100; |
int do_gen_candidates = 0, do_screen_candidates = 0; |
int do_gen_candidates = 0, do_screen_candidates = 0; |
|
int gen_all_hostkeys = 0; |
BIGNUM *start = NULL; |
BIGNUM *start = NULL; |
FILE *f; |
FILE *f; |
const char *errstr; |
const char *errstr; |
|
|
/* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */ |
/* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */ |
sanitise_stdfd(); |
sanitise_stdfd(); |
|
|
SSLeay_add_all_algorithms(); |
OpenSSL_add_all_algorithms(); |
log_init(argv[0], SYSLOG_LEVEL_INFO, SYSLOG_FACILITY_USER, 1); |
log_init(argv[0], SYSLOG_LEVEL_INFO, SYSLOG_FACILITY_USER, 1); |
|
|
/* we need this for the home * directory. */ |
/* we need this for the home * directory. */ |
|
|
exit(1); |
exit(1); |
} |
} |
|
|
while ((opt = getopt(argc, argv, "degiqpclBHLhvxXyF:b:f:t:D:I:P:m:N:n:" |
while ((opt = getopt(argc, argv, "AegiqpclBHLhvxXyF:b:f:t:D:I:P:m:N:n:" |
"O:C:r:g:R:T:G:M:S:s:a:V:W:z:")) != -1) { |
"O:C:r:g:R:T:G:M:S:s:a:V:W:z:")) != -1) { |
switch (opt) { |
switch (opt) { |
|
case 'A': |
|
gen_all_hostkeys = 1; |
|
break; |
case 'b': |
case 'b': |
bits = (u_int32_t)strtonum(optarg, 768, 32768, &errstr); |
bits = (u_int32_t)strtonum(optarg, 256, 32768, &errstr); |
if (errstr) |
if (errstr) |
fatal("Bits has bad value %s (%s)", |
fatal("Bits has bad value %s (%s)", |
optarg, errstr); |
optarg, errstr); |
|
|
case 'y': |
case 'y': |
print_public = 1; |
print_public = 1; |
break; |
break; |
case 'd': |
|
key_type_name = "dsa"; |
|
break; |
|
case 's': |
case 's': |
ca_key_path = optarg; |
ca_key_path = optarg; |
break; |
break; |
|
|
} |
} |
} |
} |
if (pkcs11provider != NULL) |
if (pkcs11provider != NULL) |
do_download(pw, pkcs11provider); |
do_download(pw); |
|
|
if (do_gen_candidates) { |
if (do_gen_candidates) { |
FILE *out = fopen(out_file, "w"); |
FILE *out = fopen(out_file, "w"); |
|
|
return (0); |
return (0); |
} |
} |
|
|
|
if (gen_all_hostkeys) { |
|
do_gen_all_hostkeys(pw); |
|
return (0); |
|
} |
|
|
arc4random_stir(); |
arc4random_stir(); |
|
|
if (key_type_name == NULL) |
if (key_type_name == NULL) |
key_type_name = "rsa"; |
key_type_name = "rsa"; |
|
|
type = key_type_from_name(key_type_name); |
type = key_type_from_name(key_type_name); |
if (type == KEY_UNSPEC) { |
type_bits_valid(type, &bits); |
fprintf(stderr, "unknown key type %s\n", key_type_name); |
|
exit(1); |
|
} |
|
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) |
if (!quiet) |
printf("Generating public/private %s key pair.\n", key_type_name); |
printf("Generating public/private %s key pair.\n", key_type_name); |
private = key_generate(type, bits); |
private = key_generate(type, bits); |