version 1.384, 2020/01/21 11:06:09 |
version 1.401, 2020/03/06 18:15:04 |
|
|
else |
else |
pass = read_passphrase("Enter passphrase: ", RP_ALLOW_STDIN); |
pass = read_passphrase("Enter passphrase: ", RP_ALLOW_STDIN); |
r = sshkey_load_private(filename, pass, &prv, commentp); |
r = sshkey_load_private(filename, pass, &prv, commentp); |
explicit_bzero(pass, strlen(pass)); |
freezero(pass, strlen(pass)); |
free(pass); |
|
if (r != 0) |
if (r != 0) |
fatal("Load key \"%s\": %s", filename, ssh_err(r)); |
fatal("Load key \"%s\": %s", filename, ssh_err(r)); |
return prv; |
return prv; |
|
|
if (!PEM_write_RSAPublicKey(stdout, k->rsa)) |
if (!PEM_write_RSAPublicKey(stdout, k->rsa)) |
fatal("PEM_write_RSAPublicKey failed"); |
fatal("PEM_write_RSAPublicKey failed"); |
break; |
break; |
|
case KEY_DSA: |
|
if (!PEM_write_DSA_PUBKEY(stdout, k->dsa)) |
|
fatal("PEM_write_DSA_PUBKEY failed"); |
|
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__, sshkey_type(k)); |
fatal("%s: unsupported key type %s", __func__, sshkey_type(k)); |
} |
} |
|
|
int i, nkeys; |
int i, nkeys; |
enum sshkey_fp_rep rep; |
enum sshkey_fp_rep rep; |
int fptype; |
int fptype; |
char *fp, *ra; |
char *fp, *ra, **comments = NULL; |
|
|
fptype = print_bubblebabble ? SSH_DIGEST_SHA1 : fingerprint_hash; |
fptype = print_bubblebabble ? SSH_DIGEST_SHA1 : fingerprint_hash; |
rep = print_bubblebabble ? SSH_FP_BUBBLEBABBLE : SSH_FP_DEFAULT; |
rep = print_bubblebabble ? SSH_FP_BUBBLEBABBLE : SSH_FP_DEFAULT; |
|
|
pkcs11_init(1); |
pkcs11_init(1); |
nkeys = pkcs11_add_provider(pkcs11provider, NULL, &keys); |
nkeys = pkcs11_add_provider(pkcs11provider, NULL, &keys, &comments); |
if (nkeys <= 0) |
if (nkeys <= 0) |
fatal("cannot read public key from pkcs11"); |
fatal("cannot read public key from pkcs11"); |
for (i = 0; i < nkeys; i++) { |
for (i = 0; i < nkeys; i++) { |
|
|
free(fp); |
free(fp); |
} else { |
} else { |
(void) sshkey_write(keys[i], stdout); /* XXX check */ |
(void) sshkey_write(keys[i], stdout); /* XXX check */ |
fprintf(stdout, "\n"); |
fprintf(stdout, "%s%s\n", |
|
*(comments[i]) == '\0' ? "" : " ", comments[i]); |
} |
} |
|
free(comments[i]); |
sshkey_free(keys[i]); |
sshkey_free(keys[i]); |
} |
} |
|
free(comments); |
free(keys); |
free(keys); |
pkcs11_terminate(); |
pkcs11_terminate(); |
exit(0); |
exit(0); |
|
|
if (fp == NULL || ra == NULL) |
if (fp == NULL || ra == NULL) |
fatal("%s: sshkey_fingerprint failed", |
fatal("%s: sshkey_fingerprint failed", |
__func__); |
__func__); |
mprintf("%s %s %s %s\n", ctx->host, |
mprintf("%s %s %s%s%s\n", ctx->host, |
sshkey_type(l->key), fp, l->comment); |
sshkey_type(l->key), fp, |
|
l->comment[0] ? " " : "", |
|
l->comment); |
if (log_level_get() >= SYSLOG_LEVEL_VERBOSE) |
if (log_level_get() >= SYSLOG_LEVEL_VERBOSE) |
printf("%s\n", ra); |
printf("%s\n", ra); |
free(ra); |
free(ra); |
|
|
RP_ALLOW_STDIN); |
RP_ALLOW_STDIN); |
r = sshkey_load_private(identity_file, old_passphrase, |
r = sshkey_load_private(identity_file, old_passphrase, |
&private, &comment); |
&private, &comment); |
explicit_bzero(old_passphrase, strlen(old_passphrase)); |
freezero(old_passphrase, strlen(old_passphrase)); |
free(old_passphrase); |
|
if (r != 0) |
if (r != 0) |
goto badkey; |
goto badkey; |
} else if (r != 0) { |
} else if (r != 0) { |
|
|
exit(1); |
exit(1); |
} |
} |
/* Destroy the other copy. */ |
/* Destroy the other copy. */ |
explicit_bzero(passphrase2, strlen(passphrase2)); |
freezero(passphrase2, strlen(passphrase2)); |
free(passphrase2); |
|
} |
} |
|
|
/* Save the file using the new passphrase. */ |
/* Save the file using the new passphrase. */ |
|
|
comment, private_key_format, openssh_format_cipher, rounds)) != 0) { |
comment, private_key_format, openssh_format_cipher, rounds)) != 0) { |
error("Saving key \"%s\" failed: %s.", |
error("Saving key \"%s\" failed: %s.", |
identity_file, ssh_err(r)); |
identity_file, ssh_err(r)); |
explicit_bzero(passphrase1, strlen(passphrase1)); |
freezero(passphrase1, strlen(passphrase1)); |
free(passphrase1); |
|
sshkey_free(private); |
sshkey_free(private); |
free(comment); |
free(comment); |
exit(1); |
exit(1); |
} |
} |
/* Destroy the passphrase and the copy of the key in memory. */ |
/* Destroy the passphrase and the copy of the key in memory. */ |
explicit_bzero(passphrase1, strlen(passphrase1)); |
freezero(passphrase1, strlen(passphrase1)); |
free(passphrase1); |
|
sshkey_free(private); /* Destroys contents */ |
sshkey_free(private); /* Destroys contents */ |
free(comment); |
free(comment); |
|
|
|
|
/* Try to load using the passphrase. */ |
/* Try to load using the passphrase. */ |
if ((r = sshkey_load_private(identity_file, passphrase, |
if ((r = sshkey_load_private(identity_file, passphrase, |
&private, &comment)) != 0) { |
&private, &comment)) != 0) { |
explicit_bzero(passphrase, strlen(passphrase)); |
freezero(passphrase, strlen(passphrase)); |
free(passphrase); |
|
fatal("Cannot load private key \"%s\": %s.", |
fatal("Cannot load private key \"%s\": %s.", |
identity_file, ssh_err(r)); |
identity_file, ssh_err(r)); |
} |
} |
|
|
rounds)) != 0) { |
rounds)) != 0) { |
error("Saving key \"%s\" failed: %s", |
error("Saving key \"%s\" failed: %s", |
identity_file, ssh_err(r)); |
identity_file, ssh_err(r)); |
explicit_bzero(passphrase, strlen(passphrase)); |
freezero(passphrase, strlen(passphrase)); |
free(passphrase); |
|
sshkey_free(private); |
sshkey_free(private); |
free(comment); |
free(comment); |
exit(1); |
exit(1); |
} |
} |
explicit_bzero(passphrase, strlen(passphrase)); |
freezero(passphrase, strlen(passphrase)); |
free(passphrase); |
|
if ((r = sshkey_from_private(private, &public)) != 0) |
if ((r = sshkey_from_private(private, &public)) != 0) |
fatal("sshkey_from_private failed: %s", ssh_err(r)); |
fatal("sshkey_from_private failed: %s", ssh_err(r)); |
sshkey_free(private); |
sshkey_free(private); |
|
|
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_CRITICAL) != 0 && |
if ((which & OPTIONS_EXTENSIONS) != 0 && |
(certflags_flags & CERTOPT_NO_REQUIRE_USER_PRESENCE) != 0) |
(certflags_flags & CERTOPT_NO_REQUIRE_USER_PRESENCE) != 0) |
add_flag_option(c, "no-touch-required"); |
add_flag_option(c, "no-touch-required"); |
if ((which & OPTIONS_CRITICAL) != 0 && |
if ((which & OPTIONS_CRITICAL) != 0 && |
|
|
fatal("Couldn't load CA public key \"%s\": %s", |
fatal("Couldn't load CA public key \"%s\": %s", |
path, ssh_err(r)); |
path, ssh_err(r)); |
|
|
nkeys = pkcs11_add_provider(pkcs11provider, identity_passphrase, &keys); |
nkeys = pkcs11_add_provider(pkcs11provider, identity_passphrase, |
|
&keys, NULL); |
debug3("%s: %d keys", __func__, nkeys); |
debug3("%s: %d keys", __func__, nkeys); |
if (nkeys <= 0) |
if (nkeys <= 0) |
fatal("cannot read public key from pkcs11"); |
fatal("cannot read public key from pkcs11"); |
|
|
} |
} |
free(tmp); |
free(tmp); |
|
|
if (key_type_name != NULL && |
if (key_type_name != NULL) { |
sshkey_type_from_name(key_type_name) != ca->type) { |
if (sshkey_type_from_name(key_type_name) != ca->type) { |
fatal("CA key type %s doesn't match specified %s", |
fatal("CA key type %s doesn't match specified %s", |
sshkey_ssh_name(ca), key_type_name); |
sshkey_ssh_name(ca), key_type_name); |
|
} |
|
} else if (ca->type == KEY_RSA) { |
|
/* Default to a good signature algorithm */ |
|
key_type_name = "rsa-sha2-512"; |
} |
} |
ca_fp = sshkey_fingerprint(ca, fingerprint_hash, SSH_FP_DEFAULT); |
ca_fp = sshkey_fingerprint(ca, fingerprint_hash, SSH_FP_DEFAULT); |
|
|
|
|
load_krl(const char *path, struct ssh_krl **krlp) |
load_krl(const char *path, struct ssh_krl **krlp) |
{ |
{ |
struct sshbuf *krlbuf; |
struct sshbuf *krlbuf; |
int r, fd; |
int r; |
|
|
if ((krlbuf = sshbuf_new()) == NULL) |
if ((r = sshbuf_load_file(path, &krlbuf)) != 0) |
fatal("sshbuf_new failed"); |
|
if ((fd = open(path, O_RDONLY)) == -1) |
|
fatal("open %s: %s", path, strerror(errno)); |
|
if ((r = sshkey_load_file(fd, krlbuf)) != 0) |
|
fatal("Unable to load KRL: %s", ssh_err(r)); |
fatal("Unable to load KRL: %s", ssh_err(r)); |
close(fd); |
|
/* XXX check sigs */ |
/* XXX check sigs */ |
if ((r = ssh_krl_from_blob(krlbuf, krlp, NULL, 0)) != 0 || |
if ((r = ssh_krl_from_blob(krlbuf, krlp, NULL, 0)) != 0 || |
*krlp == NULL) |
*krlp == NULL) |
|
|
cp = cp + strspn(cp, " \t"); |
cp = cp + strspn(cp, " \t"); |
hash_to_blob(cp, &blob, &blen, file, lnum); |
hash_to_blob(cp, &blob, &blen, file, lnum); |
r = ssh_krl_revoke_key_sha256(krl, blob, blen); |
r = ssh_krl_revoke_key_sha256(krl, blob, blen); |
|
if (r != 0) |
|
fatal("%s: revoke key failed: %s", |
|
__func__, ssh_err(r)); |
} else { |
} else { |
if (strncasecmp(cp, "key:", 4) == 0) { |
if (strncasecmp(cp, "key:", 4) == 0) { |
cp += 4; |
cp += 4; |
|
|
struct ssh_krl *krl; |
struct ssh_krl *krl; |
struct stat sb; |
struct stat sb; |
struct sshkey *ca = NULL; |
struct sshkey *ca = NULL; |
int fd, i, r, wild_ca = 0; |
int i, r, wild_ca = 0; |
char *tmp; |
char *tmp; |
struct sshbuf *kbuf; |
struct sshbuf *kbuf; |
|
|
|
|
fatal("sshbuf_new failed"); |
fatal("sshbuf_new failed"); |
if (ssh_krl_to_blob(krl, kbuf, NULL, 0) != 0) |
if (ssh_krl_to_blob(krl, kbuf, NULL, 0) != 0) |
fatal("Couldn't generate KRL"); |
fatal("Couldn't generate KRL"); |
if ((fd = open(identity_file, O_WRONLY|O_CREAT|O_TRUNC, 0644)) == -1) |
if ((r = sshbuf_write_file(identity_file, kbuf)) != 0) |
fatal("open %s: %s", identity_file, strerror(errno)); |
|
if (atomicio(vwrite, fd, sshbuf_mutable_ptr(kbuf), sshbuf_len(kbuf)) != |
|
sshbuf_len(kbuf)) |
|
fatal("write %s: %s", identity_file, strerror(errno)); |
fatal("write %s: %s", identity_file, strerror(errno)); |
close(fd); |
|
sshbuf_free(kbuf); |
sshbuf_free(kbuf); |
ssh_krl_free(krl); |
ssh_krl_free(krl); |
sshkey_free(ca); |
sshkey_free(ca); |
|
|
} |
} |
|
|
static int |
static int |
sign(const char *keypath, const char *sig_namespace, int argc, char **argv) |
sig_sign(const char *keypath, const char *sig_namespace, int argc, char **argv) |
{ |
{ |
int i, fd = -1, r, ret = -1; |
int i, fd = -1, r, ret = -1; |
int agent_fd = -1; |
int agent_fd = -1; |
|
|
} |
} |
|
|
static int |
static int |
verify(const char *signature, const char *sig_namespace, const char *principal, |
sig_verify(const char *signature, const char *sig_namespace, |
const char *allowed_keys, const char *revoked_keys) |
const char *principal, const char *allowed_keys, const char *revoked_keys) |
{ |
{ |
int r, ret = -1, sigfd = -1; |
int r, ret = -1; |
struct sshbuf *sigbuf = NULL, *abuf = NULL; |
struct sshbuf *sigbuf = NULL, *abuf = NULL; |
struct sshkey *sign_key = NULL; |
struct sshkey *sign_key = NULL; |
char *fp = NULL; |
char *fp = NULL; |
struct sshkey_sig_details *sig_details = NULL; |
struct sshkey_sig_details *sig_details = NULL; |
|
|
memset(&sig_details, 0, sizeof(sig_details)); |
memset(&sig_details, 0, sizeof(sig_details)); |
if ((abuf = sshbuf_new()) == NULL) |
if ((r = sshbuf_load_file(signature, &abuf)) != 0) { |
fatal("%s: sshbuf_new() failed", __func__); |
|
|
|
if ((sigfd = open(signature, O_RDONLY)) < 0) { |
|
error("Couldn't open signature file %s", signature); |
|
goto done; |
|
} |
|
|
|
if ((r = sshkey_load_file(sigfd, abuf)) != 0) { |
|
error("Couldn't read signature file: %s", ssh_err(r)); |
error("Couldn't read signature file: %s", ssh_err(r)); |
goto done; |
goto done; |
} |
} |
|
|
if ((r = sshsig_dearmor(abuf, &sigbuf)) != 0) { |
if ((r = sshsig_dearmor(abuf, &sigbuf)) != 0) { |
error("%s: sshsig_armor: %s", __func__, ssh_err(r)); |
error("%s: sshsig_armor: %s", __func__, ssh_err(r)); |
return r; |
goto done; |
} |
} |
if ((r = sshsig_verify_fd(sigbuf, STDIN_FILENO, sig_namespace, |
if ((r = sshsig_verify_fd(sigbuf, STDIN_FILENO, sig_namespace, |
&sign_key, &sig_details)) != 0) |
&sign_key, &sig_details)) != 0) |
|
|
printf("Could not verify signature.\n"); |
printf("Could not verify signature.\n"); |
} |
} |
} |
} |
if (sigfd != -1) |
|
close(sigfd); |
|
sshbuf_free(sigbuf); |
sshbuf_free(sigbuf); |
sshbuf_free(abuf); |
sshbuf_free(abuf); |
sshkey_free(sign_key); |
sshkey_free(sign_key); |
|
|
return ret; |
return ret; |
} |
} |
|
|
|
static int |
|
sig_find_principals(const char *signature, const char *allowed_keys) { |
|
int r, ret = -1; |
|
struct sshbuf *sigbuf = NULL, *abuf = NULL; |
|
struct sshkey *sign_key = NULL; |
|
char *principals = NULL, *cp, *tmp; |
|
|
|
if ((r = sshbuf_load_file(signature, &abuf)) != 0) { |
|
error("Couldn't read signature file: %s", ssh_err(r)); |
|
goto done; |
|
} |
|
if ((r = sshsig_dearmor(abuf, &sigbuf)) != 0) { |
|
error("%s: sshsig_armor: %s", __func__, ssh_err(r)); |
|
goto done; |
|
} |
|
if ((r = sshsig_get_pubkey(sigbuf, &sign_key)) != 0) { |
|
error("%s: sshsig_get_pubkey: %s", |
|
__func__, ssh_err(r)); |
|
goto done; |
|
} |
|
if ((r = sshsig_find_principals(allowed_keys, sign_key, |
|
&principals)) != 0) { |
|
error("%s: sshsig_get_principal: %s", |
|
__func__, ssh_err(r)); |
|
goto done; |
|
} |
|
ret = 0; |
|
done: |
|
if (ret == 0 ) { |
|
/* Emit matching principals one per line */ |
|
tmp = principals; |
|
while ((cp = strsep(&tmp, ",")) != NULL && *cp != '\0') |
|
puts(cp); |
|
} else { |
|
fprintf(stderr, "No principal matched.\n"); |
|
} |
|
sshbuf_free(sigbuf); |
|
sshbuf_free(abuf); |
|
sshkey_free(sign_key); |
|
free(principals); |
|
return ret; |
|
} |
|
|
static void |
static void |
do_moduli_gen(const char *out_file, char **opts, size_t nopts) |
do_moduli_gen(const char *out_file, char **opts, size_t nopts) |
{ |
{ |
|
|
if (skprovider == NULL) |
if (skprovider == NULL) |
fatal("Cannot download keys without provider"); |
fatal("Cannot download keys without provider"); |
|
|
pin = read_passphrase("Enter PIN for security key: ", RP_ALLOW_STDIN); |
pin = read_passphrase("Enter PIN for authenticator: ", RP_ALLOW_STDIN); |
if ((r = sshsk_load_resident(skprovider, device, pin, |
if ((r = sshsk_load_resident(skprovider, device, pin, |
&keys, &nkeys)) != 0) { |
&keys, &nkeys)) != 0) { |
freezero(pin, strlen(pin)); |
freezero(pin, strlen(pin)); |
|
|
" 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" |
" file ...\n" |
" file ...\n" |
" ssh-keygen -Q -f krl_file file ...\n" |
" ssh-keygen -Q -f krl_file file ...\n" |
|
" ssh-keygen -Y find-principals -s signature_file -f allowed_signers_file\n" |
" ssh-keygen -Y check-novalidate -n namespace -s signature_file\n" |
" ssh-keygen -Y check-novalidate -n namespace -s signature_file\n" |
" ssh-keygen -Y sign -f key_file -n namespace file ...\n" |
" ssh-keygen -Y sign -f key_file -n namespace file ...\n" |
" ssh-keygen -Y verify -f allowed_signers_file -I signer_identity\n" |
" ssh-keygen -Y verify -f allowed_signers_file -I signer_identity\n" |
|
|
unsigned long long cert_serial = 0; |
unsigned long long cert_serial = 0; |
char *identity_comment = NULL, *ca_key_path = NULL, **opts = NULL; |
char *identity_comment = NULL, *ca_key_path = NULL, **opts = NULL; |
char *sk_application = NULL, *sk_device = NULL, *sk_user = NULL; |
char *sk_application = NULL, *sk_device = NULL, *sk_user = NULL; |
|
char *sk_attestaion_path = NULL; |
|
struct sshbuf *challenge = NULL, *attest = NULL; |
size_t i, nopts = 0; |
size_t i, nopts = 0; |
u_int32_t bits = 0; |
u_int32_t bits = 0; |
uint8_t sk_flags = SSH_SK_USER_PRESENCE_REQD; |
uint8_t sk_flags = SSH_SK_USER_PRESENCE_REQD; |
|
|
argc -= optind; |
argc -= optind; |
|
|
if (sign_op != NULL) { |
if (sign_op != NULL) { |
if (cert_principals == NULL || *cert_principals == '\0') { |
if (strncmp(sign_op, "find-principals", 15) == 0) { |
error("Too few arguments for sign/verify: " |
if (ca_key_path == NULL) { |
"missing namespace"); |
error("Too few arguments for find-principals:" |
exit(1); |
"missing signature file"); |
} |
exit(1); |
if (strncmp(sign_op, "sign", 4) == 0) { |
} |
if (!have_identity) { |
if (!have_identity) { |
|
error("Too few arguments for find-principals:" |
|
"missing allowed keys file"); |
|
exit(1); |
|
} |
|
return sig_find_principals(ca_key_path, identity_file); |
|
} else if (strncmp(sign_op, "sign", 4) == 0) { |
|
if (cert_principals == NULL || |
|
*cert_principals == '\0') { |
error("Too few arguments for sign: " |
error("Too few arguments for sign: " |
|
"missing namespace"); |
|
exit(1); |
|
} |
|
if (!have_identity) { |
|
error("Too few arguments for sign: " |
"missing key"); |
"missing key"); |
exit(1); |
exit(1); |
} |
} |
return sign(identity_file, cert_principals, argc, argv); |
return sig_sign(identity_file, cert_principals, |
|
argc, argv); |
} else if (strncmp(sign_op, "check-novalidate", 16) == 0) { |
} else if (strncmp(sign_op, "check-novalidate", 16) == 0) { |
if (ca_key_path == NULL) { |
if (ca_key_path == NULL) { |
error("Too few arguments for check-novalidate: " |
error("Too few arguments for check-novalidate: " |
"missing signature file"); |
"missing signature file"); |
exit(1); |
exit(1); |
} |
} |
return verify(ca_key_path, cert_principals, |
return sig_verify(ca_key_path, cert_principals, |
NULL, NULL, NULL); |
NULL, NULL, NULL); |
} else if (strncmp(sign_op, "verify", 6) == 0) { |
} else if (strncmp(sign_op, "verify", 6) == 0) { |
|
if (cert_principals == NULL || |
|
*cert_principals == '\0') { |
|
error("Too few arguments for verify: " |
|
"missing namespace"); |
|
exit(1); |
|
} |
if (ca_key_path == NULL) { |
if (ca_key_path == NULL) { |
error("Too few arguments for verify: " |
error("Too few arguments for verify: " |
"missing signature file"); |
"missing signature file"); |
|
|
"missing principal ID"); |
"missing principal ID"); |
exit(1); |
exit(1); |
} |
} |
return verify(ca_key_path, cert_principals, |
return sig_verify(ca_key_path, cert_principals, |
cert_key_id, identity_file, rr_hostname); |
cert_key_id, identity_file, rr_hostname); |
} |
} |
|
error("Unsupported operation for -Y: \"%s\"", sign_op); |
usage(); |
usage(); |
/* NOTREACHED */ |
/* NOTREACHED */ |
} |
} |
|
|
sk_device = xstrdup(opts[i] + 7); |
sk_device = xstrdup(opts[i] + 7); |
} else if (strncasecmp(opts[i], "user=", 5) == 0) { |
} else if (strncasecmp(opts[i], "user=", 5) == 0) { |
sk_user = xstrdup(opts[i] + 5); |
sk_user = xstrdup(opts[i] + 5); |
|
} else if (strncasecmp(opts[i], "challenge=", 10) == 0) { |
|
if ((r = sshbuf_load_file(opts[i] + 10, |
|
&challenge)) != 0) { |
|
fatal("Unable to load FIDO enrollment " |
|
"challenge \"%s\": %s", |
|
opts[i] + 10, ssh_err(r)); |
|
} |
} else if (strncasecmp(opts[i], |
} else if (strncasecmp(opts[i], |
|
"write-attestation=", 18) == 0) { |
|
sk_attestaion_path = opts[i] + 18; |
|
} else if (strncasecmp(opts[i], |
"application=", 12) == 0) { |
"application=", 12) == 0) { |
sk_application = xstrdup(opts[i] + 12); |
sk_application = xstrdup(opts[i] + 12); |
|
if (strncmp(sk_application, "ssh:", 4) != 0) { |
|
fatal("FIDO application string must " |
|
"begin with \"ssh:\""); |
|
} |
} else { |
} else { |
fatal("Option \"%s\" is unsupported for " |
fatal("Option \"%s\" is unsupported for " |
"FIDO authenticator enrollment", opts[i]); |
"FIDO authenticator enrollment", opts[i]); |
} |
} |
} |
} |
if (!quiet) { |
if (!quiet) { |
printf("You may need to touch your security key " |
printf("You may need to touch your authenticator " |
"to authorize key generation.\n"); |
"to authorize key generation.\n"); |
} |
} |
passphrase = NULL; |
passphrase = NULL; |
for (i = 0 ; i < 3; i++) { |
if ((attest = sshbuf_new()) == NULL) |
|
fatal("sshbuf_new failed"); |
|
for (i = 0 ; ; i++) { |
fflush(stdout); |
fflush(stdout); |
r = sshsk_enroll(type, sk_provider, sk_device, |
r = sshsk_enroll(type, sk_provider, sk_device, |
sk_application == NULL ? "ssh:" : sk_application, |
sk_application == NULL ? "ssh:" : sk_application, |
sk_user, sk_flags, passphrase, NULL, |
sk_user, sk_flags, passphrase, challenge, |
&private, NULL); |
&private, attest); |
if (r == 0) |
if (r == 0) |
break; |
break; |
if (r != SSH_ERR_KEY_WRONG_PASSPHRASE) |
if (r != SSH_ERR_KEY_WRONG_PASSPHRASE) |
exit(1); /* error message already printed */ |
fatal("Key enrollment failed: %s", ssh_err(r)); |
if (passphrase != NULL) |
else if (i > 0) |
|
error("PIN incorrect"); |
|
if (passphrase != NULL) { |
freezero(passphrase, strlen(passphrase)); |
freezero(passphrase, strlen(passphrase)); |
passphrase = read_passphrase("Enter PIN for security " |
passphrase = NULL; |
"key: ", RP_ALLOW_STDIN); |
} |
|
if (i >= 3) |
|
fatal("Too many incorrect PINs"); |
|
passphrase = read_passphrase("Enter PIN for " |
|
"authenticator: ", RP_ALLOW_STDIN); |
} |
} |
if (passphrase != NULL) |
if (passphrase != NULL) { |
freezero(passphrase, strlen(passphrase)); |
freezero(passphrase, strlen(passphrase)); |
if (i > 3) |
passphrase = NULL; |
fatal("Too many incorrect PINs"); |
} |
break; |
break; |
default: |
default: |
if ((r = sshkey_generate(type, bits, &private)) != 0) |
if ((r = sshkey_generate(type, bits, &private)) != 0) |
|
|
sshkey_free(private); |
sshkey_free(private); |
|
|
if (!quiet) { |
if (!quiet) { |
printf("Your identification has been saved in %s.\n", |
printf("Your identification has been saved in %s\n", |
identity_file); |
identity_file); |
} |
} |
|
|
|
|
SSH_FP_RANDOMART); |
SSH_FP_RANDOMART); |
if (fp == NULL || ra == NULL) |
if (fp == NULL || ra == NULL) |
fatal("sshkey_fingerprint failed"); |
fatal("sshkey_fingerprint failed"); |
printf("Your public key has been saved in %s.\n", |
printf("Your public key has been saved in %s\n", |
identity_file); |
identity_file); |
printf("The key fingerprint is:\n"); |
printf("The key fingerprint is:\n"); |
printf("%s %s\n", fp, comment); |
printf("%s %s\n", fp, comment); |
|
|
free(fp); |
free(fp); |
} |
} |
|
|
|
if (sk_attestaion_path != NULL) { |
|
if (attest == NULL || sshbuf_len(attest) == 0) { |
|
fatal("Enrollment did not return attestation " |
|
"certificate"); |
|
} |
|
if ((r = sshbuf_write_file(sk_attestaion_path, attest)) != 0) { |
|
fatal("Unable to write attestation certificate " |
|
"\"%s\": %s", sk_attestaion_path, ssh_err(r)); |
|
} |
|
if (!quiet) { |
|
printf("Your FIDO attestation certificate has been " |
|
"saved in %s\n", sk_attestaion_path); |
|
} |
|
} |
|
sshbuf_free(attest); |
sshkey_free(public); |
sshkey_free(public); |
|
|
exit(0); |
exit(0); |
} |
} |