version 1.445, 2022/01/05 04:50:11 |
version 1.455, 2022/07/20 03:13:04 |
|
|
#define CERTOPT_PTY (1<<3) |
#define CERTOPT_PTY (1<<3) |
#define CERTOPT_USER_RC (1<<4) |
#define CERTOPT_USER_RC (1<<4) |
#define CERTOPT_NO_REQUIRE_USER_PRESENCE (1<<5) |
#define CERTOPT_NO_REQUIRE_USER_PRESENCE (1<<5) |
|
#define CERTOPT_REQUIRE_VERIFY (1<<6) |
#define CERTOPT_DEFAULT (CERTOPT_X_FWD|CERTOPT_AGENT_FWD| \ |
#define CERTOPT_DEFAULT (CERTOPT_X_FWD|CERTOPT_AGENT_FWD| \ |
CERTOPT_PORT_FWD|CERTOPT_PTY|CERTOPT_USER_RC) |
CERTOPT_PORT_FWD|CERTOPT_PTY|CERTOPT_USER_RC) |
static u_int32_t certflags_flags = CERTOPT_DEFAULT; |
static u_int32_t certflags_flags = CERTOPT_DEFAULT; |
|
|
error_f("remaining bytes in key blob %d", rlen); |
error_f("remaining bytes in key blob %d", rlen); |
|
|
/* try the key */ |
/* try the key */ |
if (sshkey_sign(key, &sig, &slen, data, sizeof(data), |
if ((r = sshkey_sign(key, &sig, &slen, data, sizeof(data), |
NULL, NULL, NULL, 0) != 0 || |
NULL, NULL, NULL, 0)) != 0) |
sshkey_verify(key, sig, slen, data, sizeof(data), |
error_fr(r, "signing with converted key failed"); |
NULL, 0, NULL) != 0) { |
else if ((r = sshkey_verify(key, sig, slen, data, sizeof(data), |
|
NULL, 0, NULL)) != 0) |
|
error_fr(r, "verification with converted key failed"); |
|
if (r != 0) { |
sshkey_free(key); |
sshkey_free(key); |
free(sig); |
free(sig); |
return NULL; |
return NULL; |
|
|
} key_types[] = { |
} key_types[] = { |
#ifdef WITH_OPENSSL |
#ifdef WITH_OPENSSL |
{ "rsa", "RSA" ,_PATH_HOST_RSA_KEY_FILE }, |
{ "rsa", "RSA" ,_PATH_HOST_RSA_KEY_FILE }, |
{ "dsa", "DSA", _PATH_HOST_DSA_KEY_FILE }, |
|
{ "ecdsa", "ECDSA",_PATH_HOST_ECDSA_KEY_FILE }, |
{ "ecdsa", "ECDSA",_PATH_HOST_ECDSA_KEY_FILE }, |
#endif /* WITH_OPENSSL */ |
#endif /* WITH_OPENSSL */ |
{ "ed25519", "ED25519",_PATH_HOST_ED25519_KEY_FILE }, |
{ "ed25519", "ED25519",_PATH_HOST_ED25519_KEY_FILE }, |
|
|
cert_ext_add("force-command", certflags_command, 1); |
cert_ext_add("force-command", certflags_command, 1); |
if (certflags_src_addr != NULL) |
if (certflags_src_addr != NULL) |
cert_ext_add("source-address", certflags_src_addr, 1); |
cert_ext_add("source-address", certflags_src_addr, 1); |
|
if ((certflags_flags & CERTOPT_REQUIRE_VERIFY) != 0) |
|
cert_ext_add("verify-required", NULL, 1); |
/* extensions */ |
/* extensions */ |
if ((certflags_flags & CERTOPT_X_FWD) != 0) |
if ((certflags_flags & CERTOPT_X_FWD) != 0) |
cert_ext_add("permit-X11-forwarding", NULL, 0); |
cert_ext_add("permit-X11-forwarding", NULL, 0); |
|
|
certflags_flags &= ~CERTOPT_NO_REQUIRE_USER_PRESENCE; |
certflags_flags &= ~CERTOPT_NO_REQUIRE_USER_PRESENCE; |
else if (strcasecmp(opt, "no-touch-required") == 0) |
else if (strcasecmp(opt, "no-touch-required") == 0) |
certflags_flags |= CERTOPT_NO_REQUIRE_USER_PRESENCE; |
certflags_flags |= CERTOPT_NO_REQUIRE_USER_PRESENCE; |
|
else if (strcasecmp(opt, "no-verify-required") == 0) |
|
certflags_flags &= ~CERTOPT_REQUIRE_VERIFY; |
|
else if (strcasecmp(opt, "verify-required") == 0) |
|
certflags_flags |= CERTOPT_REQUIRE_VERIFY; |
else if (strncasecmp(opt, "force-command=", 14) == 0) { |
else if (strncasecmp(opt, "force-command=", 14) == 0) { |
val = opt + 14; |
val = opt + 14; |
if (*val == '\0') |
if (*val == '\0') |
|
|
fatal_fr(r, "parse critical"); |
fatal_fr(r, "parse critical"); |
printf(" %s\n", arg); |
printf(" %s\n", arg); |
free(arg); |
free(arg); |
|
} else if (in_critical && |
|
strcmp(name, "verify-required") == 0) { |
|
printf("\n"); |
} else if (sshbuf_len(option) > 0) { |
} else if (sshbuf_len(option) > 0) { |
hex = sshbuf_dtob16(option); |
hex = sshbuf_dtob16(option); |
printf(" UNKNOWN OPTION: %s (len %zu)\n", |
printf(" UNKNOWN OPTION: %s (len %zu)\n", |
|
|
{ |
{ |
size_t i, slen, plen = strlen(keypath); |
size_t i, slen, plen = strlen(keypath); |
char *privpath = xstrdup(keypath); |
char *privpath = xstrdup(keypath); |
const char *suffixes[] = { "-cert.pub", ".pub", NULL }; |
static const char * const suffixes[] = { "-cert.pub", ".pub", NULL }; |
struct sshkey *ret = NULL, *privkey = NULL; |
struct sshkey *ret = NULL, *privkey = NULL; |
int r; |
int r, waspub = 0; |
|
struct stat st; |
|
|
/* |
/* |
* If passed a public key filename, then try to locate the corresponding |
* If passed a public key filename, then try to locate the corresponding |
|
|
privpath[plen - slen] = '\0'; |
privpath[plen - slen] = '\0'; |
debug_f("%s looks like a public key, using private key " |
debug_f("%s looks like a public key, using private key " |
"path %s instead", keypath, privpath); |
"path %s instead", keypath, privpath); |
|
waspub = 1; |
} |
} |
if ((privkey = load_identity(privpath, NULL)) == NULL) { |
if (waspub && stat(privpath, &st) != 0 && errno == ENOENT) |
error("Couldn't load identity %s", keypath); |
fatal("No private key found for public key \"%s\"", keypath); |
goto done; |
if ((r = sshkey_load_private(privpath, "", &privkey, NULL)) != 0 && |
} |
(r != SSH_ERR_KEY_WRONG_PASSPHRASE)) { |
|
debug_fr(r, "load private key \"%s\"", privpath); |
|
fatal("No private key found for \"%s\"", privpath); |
|
} else if (privkey == NULL) |
|
privkey = load_identity(privpath, NULL); |
|
|
if (!sshkey_equal_public(pubkey, privkey)) { |
if (!sshkey_equal_public(pubkey, privkey)) { |
error("Public key %s doesn't match private %s", |
error("Public key %s doesn't match private %s", |
keypath, privpath); |
keypath, privpath); |
|
|
|
|
|
|
static int |
static int |
sig_sign(const char *keypath, const char *sig_namespace, int argc, char **argv, |
sig_sign(const char *keypath, const char *sig_namespace, int require_agent, |
char * const *opts, size_t nopts) |
int argc, char **argv, char * const *opts, size_t nopts) |
{ |
{ |
int i, fd = -1, r, ret = -1; |
int i, fd = -1, r, ret = -1; |
int agent_fd = -1; |
int agent_fd = -1; |
|
|
goto done; |
goto done; |
} |
} |
|
|
if ((r = ssh_get_authentication_socket(&agent_fd)) != 0) |
if ((r = ssh_get_authentication_socket(&agent_fd)) != 0) { |
|
if (require_agent) |
|
fatal("Couldn't get agent socket"); |
debug_r(r, "Couldn't get agent socket"); |
debug_r(r, "Couldn't get agent socket"); |
else { |
} else { |
if ((r = ssh_agent_has_key(agent_fd, pubkey)) == 0) |
if ((r = ssh_agent_has_key(agent_fd, pubkey)) == 0) |
signer = agent_signer; |
signer = agent_signer; |
else |
else { |
|
if (require_agent) |
|
fatal("Couldn't find key in agent"); |
debug_r(r, "Couldn't find key in agent"); |
debug_r(r, "Couldn't find key in agent"); |
|
} |
} |
} |
|
|
if (signer == NULL) { |
if (signer == NULL) { |
|
|
#endif /* WITH_OPENSSL */ |
#endif /* WITH_OPENSSL */ |
} |
} |
|
|
|
/* Read and confirm a passphrase */ |
static char * |
static char * |
private_key_passphrase(void) |
read_check_passphrase(const char *prompt1, const char *prompt2, |
|
const char *retry_prompt) |
{ |
{ |
char *passphrase1, *passphrase2; |
char *passphrase1, *passphrase2; |
|
|
/* Ask for a passphrase (twice). */ |
for (;;) { |
if (identity_passphrase) |
passphrase1 = read_passphrase(prompt1, RP_ALLOW_STDIN); |
passphrase1 = xstrdup(identity_passphrase); |
passphrase2 = read_passphrase(prompt2, RP_ALLOW_STDIN); |
else if (identity_new_passphrase) |
if (strcmp(passphrase1, passphrase2) == 0) { |
passphrase1 = xstrdup(identity_new_passphrase); |
|
else { |
|
passphrase_again: |
|
passphrase1 = |
|
read_passphrase("Enter passphrase (empty for no " |
|
"passphrase): ", RP_ALLOW_STDIN); |
|
passphrase2 = read_passphrase("Enter same passphrase again: ", |
|
RP_ALLOW_STDIN); |
|
if (strcmp(passphrase1, passphrase2) != 0) { |
|
/* |
|
* The passphrases do not match. Clear them and |
|
* retry. |
|
*/ |
|
freezero(passphrase1, strlen(passphrase1)); |
|
freezero(passphrase2, strlen(passphrase2)); |
freezero(passphrase2, strlen(passphrase2)); |
printf("Passphrases do not match. Try again.\n"); |
return passphrase1; |
goto passphrase_again; |
|
} |
} |
/* Clear the other copy of the passphrase. */ |
/* The passphrases do not match. Clear them and retry. */ |
|
freezero(passphrase1, strlen(passphrase1)); |
freezero(passphrase2, strlen(passphrase2)); |
freezero(passphrase2, strlen(passphrase2)); |
|
fputs(retry_prompt, stdout); |
|
fputc('\n', stdout); |
|
fflush(stdout); |
} |
} |
return passphrase1; |
/* NOTREACHED */ |
|
return NULL; |
} |
} |
|
|
static char * |
static char * |
|
private_key_passphrase(void) |
|
{ |
|
if (identity_passphrase) |
|
return xstrdup(identity_passphrase); |
|
if (identity_new_passphrase) |
|
return xstrdup(identity_new_passphrase); |
|
|
|
return read_check_passphrase( |
|
"Enter passphrase (empty for no passphrase): ", |
|
"Enter same passphrase again: ", |
|
"Passphrases do not match. Try again."); |
|
} |
|
|
|
static char * |
sk_suffix(const char *application, const uint8_t *user, size_t userlen) |
sk_suffix(const char *application, const uint8_t *user, size_t userlen) |
{ |
{ |
char *ret, *cp; |
char *ret, *cp; |
|
|
return sig_match_principals(identity_file, cert_key_id, |
return sig_match_principals(identity_file, cert_key_id, |
opts, nopts); |
opts, nopts); |
} else if (strncmp(sign_op, "sign", 4) == 0) { |
} else if (strncmp(sign_op, "sign", 4) == 0) { |
|
/* NB. cert_principals is actually namespace, via -n */ |
if (cert_principals == NULL || |
if (cert_principals == NULL || |
*cert_principals == '\0') { |
*cert_principals == '\0') { |
error("Too few arguments for sign: " |
error("Too few arguments for sign: " |
|
|
exit(1); |
exit(1); |
} |
} |
return sig_sign(identity_file, cert_principals, |
return sig_sign(identity_file, cert_principals, |
argc, argv, opts, nopts); |
prefer_agent, argc, argv, opts, nopts); |
} else if (strncmp(sign_op, "check-novalidate", 16) == 0) { |
} else if (strncmp(sign_op, "check-novalidate", 16) == 0) { |
|
/* NB. cert_principals is actually namespace, via -n */ |
|
if (cert_principals == NULL || |
|
*cert_principals == '\0') { |
|
error("Too few arguments for check-novalidate: " |
|
"missing namespace"); |
|
exit(1); |
|
} |
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"); |
|
|
return sig_verify(ca_key_path, cert_principals, |
return sig_verify(ca_key_path, cert_principals, |
NULL, NULL, NULL, opts, nopts); |
NULL, NULL, NULL, opts, nopts); |
} else if (strncmp(sign_op, "verify", 6) == 0) { |
} else if (strncmp(sign_op, "verify", 6) == 0) { |
|
/* NB. cert_principals is actually namespace, via -n */ |
if (cert_principals == NULL || |
if (cert_principals == NULL || |
*cert_principals == '\0') { |
*cert_principals == '\0') { |
error("Too few arguments for verify: " |
error("Too few arguments for verify: " |
|
|
} |
} |
if (cert_key_id == NULL) { |
if (cert_key_id == NULL) { |
error("Too few arguments for verify: " |
error("Too few arguments for verify: " |
"missing principal ID"); |
"missing principal identity"); |
exit(1); |
exit(1); |
} |
} |
return sig_verify(ca_key_path, cert_principals, |
return sig_verify(ca_key_path, cert_principals, |