version 1.122, 2022/09/17 10:30:45 |
version 1.123, 2022/10/28 00:35:40 |
|
|
struct sshkey **keyp, int allow_cert); |
struct sshkey **keyp, int allow_cert); |
|
|
/* Supported key types */ |
/* Supported key types */ |
struct keytype { |
extern const struct sshkey_impl sshkey_ed25519_impl; |
const char *name; |
extern const struct sshkey_impl sshkey_ed25519_cert_impl; |
const char *shortname; |
extern const struct sshkey_impl sshkey_ed25519_sk_impl; |
const char *sigalg; |
extern const struct sshkey_impl sshkey_ed25519_sk_cert_impl; |
int type; |
#ifdef WITH_OPENSSL |
int nid; |
extern const struct sshkey_impl sshkey_ecdsa_sk_impl; |
int cert; |
extern const struct sshkey_impl sshkey_ecdsa_sk_cert_impl; |
int sigonly; |
extern const struct sshkey_impl sshkey_ecdsa_sk_webauthn_impl; |
}; |
extern const struct sshkey_impl sshkey_ecdsa_nistp256_impl; |
static const struct keytype keytypes[] = { |
extern const struct sshkey_impl sshkey_ecdsa_nistp256_cert_impl; |
{ "ssh-ed25519", "ED25519", NULL, KEY_ED25519, 0, 0, 0 }, |
extern const struct sshkey_impl sshkey_ecdsa_nistp384_impl; |
{ "ssh-ed25519-cert-v01@openssh.com", "ED25519-CERT", NULL, |
extern const struct sshkey_impl sshkey_ecdsa_nistp384_cert_impl; |
KEY_ED25519_CERT, 0, 1, 0 }, |
extern const struct sshkey_impl sshkey_ecdsa_nistp521_impl; |
{ "sk-ssh-ed25519@openssh.com", "ED25519-SK", NULL, |
extern const struct sshkey_impl sshkey_ecdsa_nistp521_cert_impl; |
KEY_ED25519_SK, 0, 0, 0 }, |
extern const struct sshkey_impl sshkey_rsa_impl; |
{ "sk-ssh-ed25519-cert-v01@openssh.com", "ED25519-SK-CERT", NULL, |
extern const struct sshkey_impl sshkey_rsa_cert_impl; |
KEY_ED25519_SK_CERT, 0, 1, 0 }, |
extern const struct sshkey_impl sshkey_rsa_sha256_impl; |
|
extern const struct sshkey_impl sshkey_rsa_sha256_cert_impl; |
|
extern const struct sshkey_impl sshkey_rsa_sha512_impl; |
|
extern const struct sshkey_impl sshkey_rsa_sha512_cert_impl; |
|
extern const struct sshkey_impl sshkey_dss_impl; |
|
extern const struct sshkey_impl sshkey_dsa_cert_impl; |
|
#endif /* WITH_OPENSSL */ |
#ifdef WITH_XMSS |
#ifdef WITH_XMSS |
{ "ssh-xmss@openssh.com", "XMSS", NULL, KEY_XMSS, 0, 0, 0 }, |
extern const struct sshkey_impl sshkey_xmss_impl; |
{ "ssh-xmss-cert-v01@openssh.com", "XMSS-CERT", NULL, |
extern const struct sshkey_impl sshkey_xmss_cert_impl; |
KEY_XMSS_CERT, 0, 1, 0 }, |
#endif |
#endif /* WITH_XMSS */ |
|
|
const struct sshkey_impl * const keyimpls[] = { |
|
&sshkey_ed25519_impl, |
|
&sshkey_ed25519_cert_impl, |
|
&sshkey_ed25519_sk_impl, |
|
&sshkey_ed25519_sk_cert_impl, |
#ifdef WITH_OPENSSL |
#ifdef WITH_OPENSSL |
{ "ssh-rsa", "RSA", NULL, KEY_RSA, 0, 0, 0 }, |
&sshkey_ecdsa_nistp256_impl, |
{ "rsa-sha2-256", "RSA", NULL, KEY_RSA, 0, 0, 1 }, |
&sshkey_ecdsa_nistp256_cert_impl, |
{ "rsa-sha2-512", "RSA", NULL, KEY_RSA, 0, 0, 1 }, |
&sshkey_ecdsa_nistp384_impl, |
{ "ssh-dss", "DSA", NULL, KEY_DSA, 0, 0, 0 }, |
&sshkey_ecdsa_nistp384_cert_impl, |
{ "ecdsa-sha2-nistp256", "ECDSA", NULL, |
&sshkey_ecdsa_nistp521_impl, |
KEY_ECDSA, NID_X9_62_prime256v1, 0, 0 }, |
&sshkey_ecdsa_nistp521_cert_impl, |
{ "ecdsa-sha2-nistp384", "ECDSA", NULL, |
&sshkey_ecdsa_sk_impl, |
KEY_ECDSA, NID_secp384r1, 0, 0 }, |
&sshkey_ecdsa_sk_cert_impl, |
{ "ecdsa-sha2-nistp521", "ECDSA", NULL, |
&sshkey_ecdsa_sk_webauthn_impl, |
KEY_ECDSA, NID_secp521r1, 0, 0 }, |
&sshkey_dss_impl, |
{ "sk-ecdsa-sha2-nistp256@openssh.com", "ECDSA-SK", NULL, |
&sshkey_dsa_cert_impl, |
KEY_ECDSA_SK, NID_X9_62_prime256v1, 0, 0 }, |
&sshkey_rsa_impl, |
{ "webauthn-sk-ecdsa-sha2-nistp256@openssh.com", "ECDSA-SK", NULL, |
&sshkey_rsa_cert_impl, |
KEY_ECDSA_SK, NID_X9_62_prime256v1, 0, 1 }, |
&sshkey_rsa_sha256_impl, |
{ "ssh-rsa-cert-v01@openssh.com", "RSA-CERT", NULL, |
&sshkey_rsa_sha256_cert_impl, |
KEY_RSA_CERT, 0, 1, 0 }, |
&sshkey_rsa_sha512_impl, |
{ "rsa-sha2-256-cert-v01@openssh.com", "RSA-CERT", |
&sshkey_rsa_sha512_cert_impl, |
"rsa-sha2-256", KEY_RSA_CERT, 0, 1, 1 }, |
|
{ "rsa-sha2-512-cert-v01@openssh.com", "RSA-CERT", |
|
"rsa-sha2-512", KEY_RSA_CERT, 0, 1, 1 }, |
|
{ "ssh-dss-cert-v01@openssh.com", "DSA-CERT", NULL, |
|
KEY_DSA_CERT, 0, 1, 0 }, |
|
{ "ecdsa-sha2-nistp256-cert-v01@openssh.com", "ECDSA-CERT", NULL, |
|
KEY_ECDSA_CERT, NID_X9_62_prime256v1, 1, 0 }, |
|
{ "ecdsa-sha2-nistp384-cert-v01@openssh.com", "ECDSA-CERT", NULL, |
|
KEY_ECDSA_CERT, NID_secp384r1, 1, 0 }, |
|
{ "ecdsa-sha2-nistp521-cert-v01@openssh.com", "ECDSA-CERT", NULL, |
|
KEY_ECDSA_CERT, NID_secp521r1, 1, 0 }, |
|
{ "sk-ecdsa-sha2-nistp256-cert-v01@openssh.com", "ECDSA-SK-CERT", NULL, |
|
KEY_ECDSA_SK_CERT, NID_X9_62_prime256v1, 1, 0 }, |
|
#endif /* WITH_OPENSSL */ |
#endif /* WITH_OPENSSL */ |
{ NULL, NULL, NULL, -1, -1, 0, 0 } |
#ifdef WITH_XMSS |
|
&sshkey_xmss_impl, |
|
&sshkey_xmss_cert_impl, |
|
#endif |
|
NULL |
}; |
}; |
|
|
|
static const struct sshkey_impl * |
|
sshkey_impl_from_type(int type) |
|
{ |
|
int i; |
|
|
|
for (i = 0; keyimpls[i] != NULL; i++) { |
|
if (keyimpls[i]->type == type) |
|
return keyimpls[i]; |
|
} |
|
return NULL; |
|
} |
|
|
|
static const struct sshkey_impl * |
|
sshkey_impl_from_type_nid(int type, int nid) |
|
{ |
|
int i; |
|
|
|
for (i = 0; keyimpls[i] != NULL; i++) { |
|
if (keyimpls[i]->type == type && |
|
(keyimpls[i]->nid == 0 || keyimpls[i]->nid == nid)) |
|
return keyimpls[i]; |
|
} |
|
return NULL; |
|
} |
|
|
const char * |
const char * |
sshkey_type(const struct sshkey *k) |
sshkey_type(const struct sshkey *k) |
{ |
{ |
const struct keytype *kt; |
const struct sshkey_impl *impl; |
|
|
for (kt = keytypes; kt->type != -1; kt++) { |
if ((impl = sshkey_impl_from_type(k->type)) == NULL) |
if (kt->type == k->type) |
return "unknown"; |
return kt->shortname; |
return impl->shortname; |
} |
|
return "unknown"; |
|
} |
} |
|
|
static const char * |
static const char * |
sshkey_ssh_name_from_type_nid(int type, int nid) |
sshkey_ssh_name_from_type_nid(int type, int nid) |
{ |
{ |
const struct keytype *kt; |
const struct sshkey_impl *impl; |
|
|
for (kt = keytypes; kt->type != -1; kt++) { |
if ((impl = sshkey_impl_from_type_nid(type, nid)) == NULL) |
if (kt->type == type && (kt->nid == 0 || kt->nid == nid)) |
return "ssh-unknown"; |
return kt->name; |
return impl->name; |
} |
|
return "ssh-unknown"; |
|
} |
} |
|
|
int |
int |
sshkey_type_is_cert(int type) |
sshkey_type_is_cert(int type) |
{ |
{ |
const struct keytype *kt; |
const struct sshkey_impl *impl; |
|
|
for (kt = keytypes; kt->type != -1; kt++) { |
if ((impl = sshkey_impl_from_type(type)) == NULL) |
if (kt->type == type) |
return 0; |
return kt->cert; |
return impl->cert; |
} |
|
return 0; |
|
} |
} |
|
|
const char * |
const char * |
|
|
int |
int |
sshkey_type_from_name(const char *name) |
sshkey_type_from_name(const char *name) |
{ |
{ |
const struct keytype *kt; |
int i; |
|
const struct sshkey_impl *impl; |
|
|
for (kt = keytypes; kt->type != -1; kt++) { |
for (i = 0; keyimpls[i] != NULL; i++) { |
|
impl = keyimpls[i]; |
/* Only allow shortname matches for plain key types */ |
/* Only allow shortname matches for plain key types */ |
if ((kt->name != NULL && strcmp(name, kt->name) == 0) || |
if ((impl->name != NULL && strcmp(name, impl->name) == 0) || |
(!kt->cert && strcasecmp(kt->shortname, name) == 0)) |
(!impl->cert && strcasecmp(impl->shortname, name) == 0)) |
return kt->type; |
return impl->type; |
} |
} |
return KEY_UNSPEC; |
return KEY_UNSPEC; |
} |
} |
|
|
int |
int |
sshkey_ecdsa_nid_from_name(const char *name) |
sshkey_ecdsa_nid_from_name(const char *name) |
{ |
{ |
const struct keytype *kt; |
int i; |
|
|
for (kt = keytypes; kt->type != -1; kt++) { |
for (i = 0; keyimpls[i] != NULL; i++) { |
if (!key_type_is_ecdsa_variant(kt->type)) |
if (!key_type_is_ecdsa_variant(keyimpls[i]->type)) |
continue; |
continue; |
if (kt->name != NULL && strcmp(name, kt->name) == 0) |
if (keyimpls[i]->name != NULL && |
return kt->nid; |
strcmp(name, keyimpls[i]->name) == 0) |
|
return keyimpls[i]->nid; |
} |
} |
return -1; |
return -1; |
} |
} |
|
|
sshkey_alg_list(int certs_only, int plain_only, int include_sigonly, char sep) |
sshkey_alg_list(int certs_only, int plain_only, int include_sigonly, char sep) |
{ |
{ |
char *tmp, *ret = NULL; |
char *tmp, *ret = NULL; |
size_t nlen, rlen = 0; |
size_t i, nlen, rlen = 0; |
const struct keytype *kt; |
const struct sshkey_impl *impl; |
|
|
for (kt = keytypes; kt->type != -1; kt++) { |
for (i = 0; keyimpls[i] != NULL; i++) { |
if (kt->name == NULL) |
impl = keyimpls[i]; |
|
if (impl->name == NULL) |
continue; |
continue; |
if (!include_sigonly && kt->sigonly) |
if (!include_sigonly && impl->sigonly) |
continue; |
continue; |
if ((certs_only && !kt->cert) || (plain_only && kt->cert)) |
if ((certs_only && !impl->cert) || (plain_only && impl->cert)) |
continue; |
continue; |
if (ret != NULL) |
if (ret != NULL) |
ret[rlen++] = sep; |
ret[rlen++] = sep; |
nlen = strlen(kt->name); |
nlen = strlen(impl->name); |
if ((tmp = realloc(ret, rlen + nlen + 2)) == NULL) { |
if ((tmp = realloc(ret, rlen + nlen + 2)) == NULL) { |
free(ret); |
free(ret); |
return NULL; |
return NULL; |
} |
} |
ret = tmp; |
ret = tmp; |
memcpy(ret + rlen, kt->name, nlen + 1); |
memcpy(ret + rlen, impl->name, nlen + 1); |
rlen += nlen; |
rlen += nlen; |
} |
} |
return ret; |
return ret; |
|
|
sshkey_names_valid2(const char *names, int allow_wildcard) |
sshkey_names_valid2(const char *names, int allow_wildcard) |
{ |
{ |
char *s, *cp, *p; |
char *s, *cp, *p; |
const struct keytype *kt; |
const struct sshkey_impl *impl; |
int type; |
int i, type; |
|
|
if (names == NULL || strcmp(names, "") == 0) |
if (names == NULL || strcmp(names, "") == 0) |
return 0; |
return 0; |
|
|
* If any has a positive or negative match then |
* If any has a positive or negative match then |
* the component is accepted. |
* the component is accepted. |
*/ |
*/ |
for (kt = keytypes; kt->type != -1; kt++) { |
impl = NULL; |
if (match_pattern_list(kt->name, |
for (i = 0; keyimpls[i] != NULL; i++) { |
p, 0) != 0) |
if (match_pattern_list( |
|
keyimpls[i]->name, p, 0) != 0) { |
|
impl = keyimpls[i]; |
break; |
break; |
|
} |
} |
} |
if (kt->type != -1) |
if (impl != NULL) |
continue; |
continue; |
} |
} |
free(s); |
free(s); |
|
|
u_int |
u_int |
sshkey_size(const struct sshkey *k) |
sshkey_size(const struct sshkey *k) |
{ |
{ |
#ifdef WITH_OPENSSL |
const struct sshkey_impl *impl; |
const BIGNUM *rsa_n, *dsa_p; |
|
#endif /* WITH_OPENSSL */ |
|
|
|
switch (k->type) { |
if ((impl = sshkey_impl_from_type_nid(k->type, k->ecdsa_nid)) == NULL) |
#ifdef WITH_OPENSSL |
return 0; |
case KEY_RSA: |
if (impl->funcs->size != NULL) |
case KEY_RSA_CERT: |
return impl->funcs->size(k); |
if (k->rsa == NULL) |
return impl->keybits; |
return 0; |
|
RSA_get0_key(k->rsa, &rsa_n, NULL, NULL); |
|
return BN_num_bits(rsa_n); |
|
case KEY_DSA: |
|
case KEY_DSA_CERT: |
|
if (k->dsa == NULL) |
|
return 0; |
|
DSA_get0_pqg(k->dsa, &dsa_p, NULL, NULL); |
|
return BN_num_bits(dsa_p); |
|
case KEY_ECDSA: |
|
case KEY_ECDSA_CERT: |
|
case KEY_ECDSA_SK: |
|
case KEY_ECDSA_SK_CERT: |
|
return sshkey_curve_nid_to_bits(k->ecdsa_nid); |
|
#endif /* WITH_OPENSSL */ |
|
case KEY_ED25519: |
|
case KEY_ED25519_CERT: |
|
case KEY_ED25519_SK: |
|
case KEY_ED25519_SK_CERT: |
|
case KEY_XMSS: |
|
case KEY_XMSS_CERT: |
|
return 256; /* XXX */ |
|
} |
|
return 0; |
|
} |
} |
|
|
static int |
static int |
sshkey_type_is_valid_ca(int type) |
sshkey_type_is_valid_ca(int type) |
{ |
{ |
switch (type) { |
const struct sshkey_impl *impl; |
case KEY_RSA: |
|
case KEY_DSA: |
if ((impl = sshkey_impl_from_type(type)) == NULL) |
case KEY_ECDSA: |
|
case KEY_ECDSA_SK: |
|
case KEY_ED25519: |
|
case KEY_ED25519_SK: |
|
case KEY_XMSS: |
|
return 1; |
|
default: |
|
return 0; |
return 0; |
} |
/* All non-certificate types may act as CAs */ |
|
return !impl->cert; |
} |
} |
|
|
int |
int |
|
|
sshkey_new(int type) |
sshkey_new(int type) |
{ |
{ |
struct sshkey *k; |
struct sshkey *k; |
#ifdef WITH_OPENSSL |
const struct sshkey_impl *impl = NULL; |
RSA *rsa; |
|
DSA *dsa; |
|
#endif /* WITH_OPENSSL */ |
|
|
|
|
if (type != KEY_UNSPEC && |
|
(impl = sshkey_impl_from_type(type)) == NULL) |
|
return NULL; |
|
|
|
/* All non-certificate types may act as CAs */ |
if ((k = calloc(1, sizeof(*k))) == NULL) |
if ((k = calloc(1, sizeof(*k))) == NULL) |
return NULL; |
return NULL; |
k->type = type; |
k->type = type; |
k->ecdsa = NULL; |
|
k->ecdsa_nid = -1; |
k->ecdsa_nid = -1; |
k->dsa = NULL; |
if (impl != NULL && impl->funcs->alloc != NULL) { |
k->rsa = NULL; |
if (impl->funcs->alloc(k) != 0) { |
k->cert = NULL; |
|
k->ed25519_sk = NULL; |
|
k->ed25519_pk = NULL; |
|
k->xmss_sk = NULL; |
|
k->xmss_pk = NULL; |
|
switch (k->type) { |
|
#ifdef WITH_OPENSSL |
|
case KEY_RSA: |
|
case KEY_RSA_CERT: |
|
if ((rsa = RSA_new()) == NULL) { |
|
free(k); |
free(k); |
return NULL; |
return NULL; |
} |
} |
k->rsa = rsa; |
|
break; |
|
case KEY_DSA: |
|
case KEY_DSA_CERT: |
|
if ((dsa = DSA_new()) == NULL) { |
|
free(k); |
|
return NULL; |
|
} |
|
k->dsa = dsa; |
|
break; |
|
case KEY_ECDSA: |
|
case KEY_ECDSA_CERT: |
|
case KEY_ECDSA_SK: |
|
case KEY_ECDSA_SK_CERT: |
|
/* Cannot do anything until we know the group */ |
|
break; |
|
#endif /* WITH_OPENSSL */ |
|
case KEY_ED25519: |
|
case KEY_ED25519_CERT: |
|
case KEY_ED25519_SK: |
|
case KEY_ED25519_SK_CERT: |
|
case KEY_XMSS: |
|
case KEY_XMSS_CERT: |
|
/* no need to prealloc */ |
|
break; |
|
case KEY_UNSPEC: |
|
break; |
|
default: |
|
free(k); |
|
return NULL; |
|
} |
} |
|
|
if (sshkey_is_cert(k)) { |
if (sshkey_is_cert(k)) { |
if ((k->cert = cert_new()) == NULL) { |
if ((k->cert = cert_new()) == NULL) { |
sshkey_free(k); |
sshkey_free(k); |
|
|
void |
void |
sshkey_free(struct sshkey *k) |
sshkey_free(struct sshkey *k) |
{ |
{ |
|
const struct sshkey_impl *impl; |
|
|
if (k == NULL) |
if (k == NULL) |
return; |
return; |
switch (k->type) { |
if ((impl = sshkey_impl_from_type(k->type)) != NULL && |
#ifdef WITH_OPENSSL |
impl->funcs->cleanup != NULL) |
case KEY_RSA: |
impl->funcs->cleanup(k); |
case KEY_RSA_CERT: |
|
RSA_free(k->rsa); |
|
k->rsa = NULL; |
|
break; |
|
case KEY_DSA: |
|
case KEY_DSA_CERT: |
|
DSA_free(k->dsa); |
|
k->dsa = NULL; |
|
break; |
|
case KEY_ECDSA_SK: |
|
case KEY_ECDSA_SK_CERT: |
|
free(k->sk_application); |
|
sshbuf_free(k->sk_key_handle); |
|
sshbuf_free(k->sk_reserved); |
|
/* FALLTHROUGH */ |
|
case KEY_ECDSA: |
|
case KEY_ECDSA_CERT: |
|
EC_KEY_free(k->ecdsa); |
|
k->ecdsa = NULL; |
|
break; |
|
#endif /* WITH_OPENSSL */ |
|
case KEY_ED25519_SK: |
|
case KEY_ED25519_SK_CERT: |
|
free(k->sk_application); |
|
sshbuf_free(k->sk_key_handle); |
|
sshbuf_free(k->sk_reserved); |
|
/* FALLTHROUGH */ |
|
case KEY_ED25519: |
|
case KEY_ED25519_CERT: |
|
freezero(k->ed25519_pk, ED25519_PK_SZ); |
|
k->ed25519_pk = NULL; |
|
freezero(k->ed25519_sk, ED25519_SK_SZ); |
|
k->ed25519_sk = NULL; |
|
break; |
|
#ifdef WITH_XMSS |
|
case KEY_XMSS: |
|
case KEY_XMSS_CERT: |
|
freezero(k->xmss_pk, sshkey_xmss_pklen(k)); |
|
k->xmss_pk = NULL; |
|
freezero(k->xmss_sk, sshkey_xmss_sklen(k)); |
|
k->xmss_sk = NULL; |
|
sshkey_xmss_free_state(k); |
|
free(k->xmss_name); |
|
k->xmss_name = NULL; |
|
free(k->xmss_filename); |
|
k->xmss_filename = NULL; |
|
break; |
|
#endif /* WITH_XMSS */ |
|
case KEY_UNSPEC: |
|
break; |
|
default: |
|
break; |
|
} |
|
if (sshkey_is_cert(k)) |
if (sshkey_is_cert(k)) |
cert_free(k->cert); |
cert_free(k->cert); |
freezero(k->shielded_private, k->shielded_len); |
freezero(k->shielded_private, k->shielded_len); |
|
|
static int |
static int |
peek_type_nid(const char *s, size_t l, int *nid) |
peek_type_nid(const char *s, size_t l, int *nid) |
{ |
{ |
const struct keytype *kt; |
const struct sshkey_impl *impl; |
|
int i; |
|
|
for (kt = keytypes; kt->type != -1; kt++) { |
for (i = 0; keyimpls[i] != NULL; i++) { |
if (kt->name == NULL || strlen(kt->name) != l) |
impl = keyimpls[i]; |
|
if (impl->name == NULL || strlen(impl->name) != l) |
continue; |
continue; |
if (memcmp(s, kt->name, l) == 0) { |
if (memcmp(s, impl->name, l) == 0) { |
*nid = -1; |
*nid = -1; |
if (key_type_is_ecdsa_variant(kt->type)) |
if (key_type_is_ecdsa_variant(impl->type)) |
*nid = kt->nid; |
*nid = impl->nid; |
return kt->type; |
return impl->type; |
} |
} |
} |
} |
return KEY_UNSPEC; |
return KEY_UNSPEC; |
|
|
const char * |
const char * |
sshkey_sigalg_by_name(const char *name) |
sshkey_sigalg_by_name(const char *name) |
{ |
{ |
const struct keytype *kt; |
const struct sshkey_impl *impl; |
|
int i; |
|
|
for (kt = keytypes; kt->type != -1; kt++) { |
for (i = 0; keyimpls[i] != NULL; i++) { |
if (strcmp(kt->name, name) != 0) |
impl = keyimpls[i]; |
|
if (strcmp(impl->name, name) != 0) |
continue; |
continue; |
if (kt->sigalg != NULL) |
if (impl->sigalg != NULL) |
return kt->sigalg; |
return impl->sigalg; |
if (!kt->cert) |
if (!impl->cert) |
return kt->name; |
return impl->name; |
return sshkey_ssh_name_from_type_nid( |
return sshkey_ssh_name_from_type_nid( |
sshkey_type_plain(kt->type), kt->nid); |
sshkey_type_plain(impl->type), impl->nid); |
} |
} |
return NULL; |
return NULL; |
} |
} |