version 1.302, 2017/04/30 23:18:44 |
version 1.305, 2017/06/28 01:09:22 |
|
|
#include "krl.h" |
#include "krl.h" |
#include "digest.h" |
#include "digest.h" |
#include "utf8.h" |
#include "utf8.h" |
|
#include "authfd.h" |
|
|
#ifdef ENABLE_PKCS11 |
#ifdef ENABLE_PKCS11 |
#include "ssh-pkcs11.h" |
#include "ssh-pkcs11.h" |
|
|
/* Path to CA key when certifying keys. */ |
/* Path to CA key when certifying keys. */ |
char *ca_key_path = NULL; |
char *ca_key_path = NULL; |
|
|
|
/* Prefer to use agent keys for CA signing */ |
|
int prefer_agent = 0; |
|
|
/* Certificate serial number */ |
/* Certificate serial number */ |
unsigned long long cert_serial = 0; |
unsigned long long cert_serial = 0; |
|
|
|
|
OPENSSL_DSA_MAX_MODULUS_BITS : OPENSSL_RSA_MAX_MODULUS_BITS; |
OPENSSL_DSA_MAX_MODULUS_BITS : OPENSSL_RSA_MAX_MODULUS_BITS; |
if (*bitsp > maxbits) |
if (*bitsp > maxbits) |
fatal("key bits exceeds maximum %d", maxbits); |
fatal("key bits exceeds maximum %d", maxbits); |
if (type == KEY_DSA && *bitsp != 1024) |
switch (type) { |
fatal("DSA keys must be 1024 bits"); |
case KEY_DSA: |
else if (type != KEY_ECDSA && type != KEY_ED25519 && *bitsp < 1024) |
if (*bitsp != 1024) |
fatal("Key must at least be 1024 bits"); |
fatal("Invalid DSA key length: must be 1024 bits"); |
else if (type == KEY_ECDSA && sshkey_ecdsa_bits_to_nid(*bitsp) == -1) |
break; |
fatal("Invalid ECDSA key length - valid lengths are " |
case KEY_RSA: |
"256, 384 or 521 bits"); |
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 |
#endif |
} |
} |
|
|
|
|
return NULL; |
return NULL; |
} |
} |
if ((key = sshkey_new_private(ktype)) == NULL) |
if ((key = sshkey_new_private(ktype)) == NULL) |
fatal("key_new_private failed"); |
fatal("sshkey_new_private failed"); |
free(type); |
free(type); |
|
|
switch (key->type) { |
switch (key->type) { |
|
|
fatal("%s: %s", identity_file, strerror(errno)); |
fatal("%s: %s", identity_file, strerror(errno)); |
prv = load_identity(identity_file); |
prv = load_identity(identity_file); |
if ((r = sshkey_write(prv, stdout)) != 0) |
if ((r = sshkey_write(prv, stdout)) != 0) |
error("key_write failed: %s", ssh_err(r)); |
error("sshkey_write failed: %s", ssh_err(r)); |
sshkey_free(prv); |
sshkey_free(prv); |
fprintf(stdout, "\n"); |
fprintf(stdout, "\n"); |
exit(0); |
exit(0); |
|
|
bits = 0; |
bits = 0; |
type_bits_valid(type, NULL, &bits); |
type_bits_valid(type, NULL, &bits); |
if ((r = sshkey_generate(type, bits, &private)) != 0) { |
if ((r = sshkey_generate(type, bits, &private)) != 0) { |
error("key_generate failed: %s", ssh_err(r)); |
error("sshkey_generate failed: %s", ssh_err(r)); |
first = 0; |
first = 0; |
continue; |
continue; |
} |
} |
|
|
explicit_bzero(passphrase, strlen(passphrase)); |
explicit_bzero(passphrase, strlen(passphrase)); |
free(passphrase); |
free(passphrase); |
if ((r = sshkey_from_private(private, &public)) != 0) |
if ((r = sshkey_from_private(private, &public)) != 0) |
fatal("key_from_private failed: %s", ssh_err(r)); |
fatal("sshkey_from_private failed: %s", ssh_err(r)); |
sshkey_free(private); |
sshkey_free(private); |
|
|
strlcat(identity_file, ".pub", sizeof(identity_file)); |
strlcat(identity_file, ".pub", sizeof(identity_file)); |
|
|
#endif /* ENABLE_PKCS11 */ |
#endif /* ENABLE_PKCS11 */ |
} |
} |
|
|
|
/* Signer for sshkey_certify_custom that uses the agent */ |
|
static int |
|
agent_signer(const struct sshkey *key, u_char **sigp, size_t *lenp, |
|
const u_char *data, size_t datalen, |
|
const char *alg, u_int compat, void *ctx) |
|
{ |
|
int *agent_fdp = (int *)ctx; |
|
|
|
return ssh_agent_sign(*agent_fdp, key, sigp, lenp, |
|
data, datalen, alg, compat); |
|
} |
|
|
static void |
static void |
do_ca_sign(struct passwd *pw, int argc, char **argv) |
do_ca_sign(struct passwd *pw, int argc, char **argv) |
{ |
{ |
int r, i, fd; |
int r, i, fd, found, agent_fd = -1; |
u_int n; |
u_int n; |
struct sshkey *ca, *public; |
struct sshkey *ca, *public; |
char valid[64], *otmp, *tmp, *cp, *out, *comment, **plist = NULL; |
char valid[64], *otmp, *tmp, *cp, *out, *comment, **plist = NULL; |
FILE *f; |
FILE *f; |
|
struct ssh_identitylist *agent_ids; |
|
size_t j; |
|
|
#ifdef ENABLE_PKCS11 |
#ifdef ENABLE_PKCS11 |
pkcs11_init(1); |
pkcs11_init(1); |
#endif |
#endif |
tmp = tilde_expand_filename(ca_key_path, pw->pw_uid); |
tmp = tilde_expand_filename(ca_key_path, pw->pw_uid); |
if (pkcs11provider != NULL) { |
if (pkcs11provider != NULL) { |
|
/* If a PKCS#11 token was specified then try to use it */ |
if ((ca = load_pkcs11_key(tmp)) == NULL) |
if ((ca = load_pkcs11_key(tmp)) == NULL) |
fatal("No PKCS#11 key matching %s found", ca_key_path); |
fatal("No PKCS#11 key matching %s found", ca_key_path); |
} else |
} else if (prefer_agent) { |
|
/* |
|
* Agent signature requested. Try to use agent after making |
|
* sure the public key specified is actually present in the |
|
* agent. |
|
*/ |
|
if ((r = sshkey_load_public(tmp, &ca, NULL)) != 0) |
|
fatal("Cannot load CA public key %s: %s", |
|
tmp, ssh_err(r)); |
|
if ((r = ssh_get_authentication_socket(&agent_fd)) != 0) |
|
fatal("Cannot use public key for CA signature: %s", |
|
ssh_err(r)); |
|
if ((r = ssh_fetch_identitylist(agent_fd, &agent_ids)) != 0) |
|
fatal("Retrieve agent key list: %s", ssh_err(r)); |
|
found = 0; |
|
for (j = 0; j < agent_ids->nkeys; j++) { |
|
if (sshkey_equal(ca, agent_ids->keys[j])) { |
|
found = 1; |
|
break; |
|
} |
|
} |
|
if (!found) |
|
fatal("CA key %s not found in agent", tmp); |
|
ssh_free_identitylist(agent_ids); |
|
ca->flags |= SSHKEY_FLAG_EXT; |
|
} else { |
|
/* CA key is assumed to be a private key on the filesystem */ |
ca = load_identity(tmp); |
ca = load_identity(tmp); |
|
} |
free(tmp); |
free(tmp); |
|
|
if (key_type_name != NULL && |
if (key_type_name != NULL && |
|
|
OPTIONS_EXTENSIONS); |
OPTIONS_EXTENSIONS); |
if ((r = sshkey_from_private(ca, |
if ((r = sshkey_from_private(ca, |
&public->cert->signature_key)) != 0) |
&public->cert->signature_key)) != 0) |
fatal("key_from_private (ca key): %s", ssh_err(r)); |
fatal("sshkey_from_private (ca key): %s", ssh_err(r)); |
|
|
if ((r = sshkey_certify(public, ca, key_type_name)) != 0) |
if (agent_fd != -1 && (ca->flags & SSHKEY_FLAG_EXT) != 0) { |
fatal("Couldn't certify key %s: %s", tmp, ssh_err(r)); |
if ((r = sshkey_certify_custom(public, ca, |
|
key_type_name, agent_signer, &agent_fd)) != 0) |
|
fatal("Couldn't certify key %s via agent: %s", |
|
tmp, ssh_err(r)); |
|
} else { |
|
if ((sshkey_certify(public, ca, key_type_name)) != 0) |
|
fatal("Couldn't certify key %s: %s", |
|
tmp, ssh_err(r)); |
|
} |
|
|
if ((cp = strrchr(tmp, '.')) != NULL && strcmp(cp, ".pub") == 0) |
if ((cp = strrchr(tmp, '.')) != NULL && strcmp(cp, ".pub") == 0) |
*cp = '\0'; |
*cp = '\0'; |
|
|
if (*cp == '#' || *cp == '\0') |
if (*cp == '#' || *cp == '\0') |
continue; |
continue; |
if ((key = sshkey_new(KEY_UNSPEC)) == NULL) |
if ((key = sshkey_new(KEY_UNSPEC)) == NULL) |
fatal("key_new"); |
fatal("sshkey_new"); |
if ((r = sshkey_read(key, &cp)) != 0) { |
if ((r = sshkey_read(key, &cp)) != 0) { |
error("%s:%lu: invalid key: %s", path, |
error("%s:%lu: invalid key: %s", path, |
lnum, ssh_err(r)); |
lnum, ssh_err(r)); |
|
|
*/ |
*/ |
} |
} |
if ((key = sshkey_new(KEY_UNSPEC)) == NULL) |
if ((key = sshkey_new(KEY_UNSPEC)) == NULL) |
fatal("key_new"); |
fatal("sshkey_new"); |
if ((r = sshkey_read(key, &cp)) != 0) |
if ((r = sshkey_read(key, &cp)) != 0) |
fatal("%s:%lu: invalid key: %s", |
fatal("%s:%lu: invalid key: %s", |
path, lnum, ssh_err(r)); |
path, lnum, ssh_err(r)); |
|
|
" ssh-keygen -T output_file -f input_file [-v] [-a rounds] [-J num_lines]\n" |
" ssh-keygen -T output_file -f input_file [-v] [-a rounds] [-J num_lines]\n" |
" [-j start_line] [-K checkpt] [-W generator]\n" |
" [-j start_line] [-K checkpt] [-W generator]\n" |
#endif |
#endif |
" ssh-keygen -s ca_key -I certificate_identity [-h] [-n principals]\n" |
" ssh-keygen -s ca_key -I certificate_identity [-h] [-U]\n" |
" [-O option] [-V validity_interval] [-z serial_number] file ...\n" |
" [-D pkcs11_provider] [-n principals] [-O option]\n" |
|
" [-V validity_interval] [-z serial_number] file ...\n" |
" ssh-keygen -L [-f input_keyfile]\n" |
" ssh-keygen -L [-f input_keyfile]\n" |
" ssh-keygen -A\n" |
" ssh-keygen -A\n" |
" ssh-keygen -k -f krl_file [-u] [-s ca_public] [-z version_number]\n" |
" ssh-keygen -k -f krl_file [-u] [-s ca_public] [-z version_number]\n" |
|
|
if (gethostname(hostname, sizeof(hostname)) < 0) |
if (gethostname(hostname, sizeof(hostname)) < 0) |
fatal("gethostname: %s", strerror(errno)); |
fatal("gethostname: %s", strerror(errno)); |
|
|
/* Remaining characters: UYdw */ |
/* Remaining characters: Ydw */ |
while ((opt = getopt(argc, argv, "ABHLQXceghiklopquvxy" |
while ((opt = getopt(argc, argv, "ABHLQUXceghiklopquvxy" |
"C:D:E:F:G:I:J:K:M:N:O:P:R:S:T:V:W:Z:" |
"C:D:E:F:G:I:J:K:M:N:O:P:R:S:T:V:W:Z:" |
"a:b:f:g:j:m:n:r:s:t:z:")) != -1) { |
"a:b:f:g:j:m:n:r:s:t:z:")) != -1) { |
switch (opt) { |
switch (opt) { |
|
|
case 'D': |
case 'D': |
pkcs11provider = optarg; |
pkcs11provider = optarg; |
break; |
break; |
|
case 'U': |
|
prefer_agent = 1; |
|
break; |
case 'u': |
case 'u': |
update_krl = 1; |
update_krl = 1; |
break; |
break; |
|
|
printf("Generating public/private %s key pair.\n", |
printf("Generating public/private %s key pair.\n", |
key_type_name); |
key_type_name); |
if ((r = sshkey_generate(type, bits, &private)) != 0) |
if ((r = sshkey_generate(type, bits, &private)) != 0) |
fatal("key_generate failed"); |
fatal("sshkey_generate failed"); |
if ((r = sshkey_from_private(private, &public)) != 0) |
if ((r = sshkey_from_private(private, &public)) != 0) |
fatal("key_from_private failed: %s\n", ssh_err(r)); |
fatal("sshkey_from_private failed: %s\n", ssh_err(r)); |
|
|
if (!have_identity) |
if (!have_identity) |
ask_filename(pw, "Enter file in which to save the key"); |
ask_filename(pw, "Enter file in which to save the key"); |