1
0
mirror of https://git.libssh.org/projects/libssh.git synced 2025-12-11 03:42:35 +03:00

pki: add security key fields to ssh_key_struct and update compare, copying and cleaning functions

Signed-off-by: Praneeth Sarode <praneethsarode@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
This commit is contained in:
Praneeth Sarode
2025-07-05 22:31:35 +05:30
parent 09155adb19
commit 22c1b6970c
6 changed files with 129 additions and 49 deletions

View File

@@ -86,6 +86,11 @@ struct ssh_key_struct {
ssh_string sk_application; ssh_string sk_application;
ssh_buffer cert; ssh_buffer cert;
enum ssh_keytypes_e cert_type; enum ssh_keytypes_e cert_type;
/* Security Key specific private data */
uint8_t sk_flags;
ssh_string sk_key_handle;
ssh_string sk_reserved;
}; };
struct ssh_signature_struct { struct ssh_signature_struct {
@@ -137,6 +142,11 @@ enum ssh_digest_e ssh_key_hash_from_name(const char *name);
((kt) >= SSH_KEYTYPE_ECDSA_P256_CERT01 &&\ ((kt) >= SSH_KEYTYPE_ECDSA_P256_CERT01 &&\
(kt) <= SSH_KEYTYPE_ED25519_CERT01)) (kt) <= SSH_KEYTYPE_ED25519_CERT01))
#define is_sk_key_type(kt) \
((kt) == SSH_KEYTYPE_SK_ECDSA || (kt) == SSH_KEYTYPE_SK_ED25519 || \
(kt) == SSH_KEYTYPE_SK_ECDSA_CERT01 || \
(kt) == SSH_KEYTYPE_SK_ED25519_CERT01)
/* SSH Signature Functions */ /* SSH Signature Functions */
ssh_signature ssh_signature_new(void); ssh_signature ssh_signature_new(void);
void ssh_signature_free(ssh_signature sign); void ssh_signature_free(ssh_signature sign);

View File

@@ -61,6 +61,7 @@ enum ssh_digest_e ssh_key_type_to_hash(ssh_session session,
enum ssh_keytypes_e type); enum ssh_keytypes_e type);
/* SSH Key Functions */ /* SSH Key Functions */
ssh_key pki_key_dup_common_init(const ssh_key key, int demote);
ssh_key pki_key_dup(const ssh_key key, int demote); ssh_key pki_key_dup(const ssh_key key, int demote);
int pki_key_generate_rsa(ssh_key key, int parameter); int pki_key_generate_rsa(ssh_key key, int parameter);
int pki_key_generate_ecdsa(ssh_key key, int parameter); int pki_key_generate_ecdsa(ssh_key key, int parameter);

114
src/pki.c
View File

@@ -116,6 +116,78 @@ ssh_key ssh_key_new (void)
return ptr; return ptr;
} }
/**
* @internal
*
* @brief Initialize a new SSH key by duplicating common fields from an existing
* key.
*
* This function creates a new SSH key and copies the common fields from the
* source key, including the key type, type string, flags, and security key
* fields if applicable. This is a helper function used by key duplication
* routines.
*
* @param[in] key The source ssh_key to copy common fields from.
* @param[in] demote Whether to demote the new key to public only. If non-zero,
* only the public fields will be copied and the flags will
* be set accordingly.
*
* @return A new ssh_key with common fields initialized, or NULL on
* error.
*
* @note The caller is responsible for freeing the returned key with
* ssh_key_free().
*/
ssh_key pki_key_dup_common_init(const ssh_key key, int demote)
{
ssh_key new = NULL;
if (key == NULL) {
return NULL;
}
new = ssh_key_new();
if (new == NULL) {
return NULL;
}
new->type = key->type;
new->type_c = key->type_c;
if (demote) {
new->flags = SSH_KEY_FLAG_PUBLIC;
} else {
new->flags = key->flags;
}
/* Copy security key fields if present */
if (is_sk_key_type(key->type)) {
new->sk_application = ssh_string_copy(key->sk_application);
if (new->sk_application == NULL) {
goto fail;
}
if (!demote) {
new->sk_flags = key->sk_flags;
new->sk_key_handle = ssh_string_copy(key->sk_key_handle);
if (new->sk_key_handle == NULL) {
goto fail;
}
new->sk_reserved = ssh_string_copy(key->sk_reserved);
if (new->sk_reserved == NULL) {
goto fail;
}
}
}
return new;
fail:
SSH_KEY_FREE(new);
return NULL;
}
/** /**
* @brief duplicates the key * @brief duplicates the key
* *
@@ -153,12 +225,14 @@ void ssh_key_clean (ssh_key key)
if (key->cert != NULL) { if (key->cert != NULL) {
SSH_BUFFER_FREE(key->cert); SSH_BUFFER_FREE(key->cert);
} }
if (key->type == SSH_KEYTYPE_SK_ECDSA || if (is_sk_key_type(key->type)) {
key->type == SSH_KEYTYPE_SK_ED25519 ||
key->type == SSH_KEYTYPE_SK_ECDSA_CERT01 ||
key->type == SSH_KEYTYPE_SK_ED25519_CERT01) {
ssh_string_burn(key->sk_application); ssh_string_burn(key->sk_application);
ssh_string_free(key->sk_application); ssh_string_free(key->sk_application);
ssh_string_burn(key->sk_key_handle);
ssh_string_free(key->sk_key_handle);
ssh_string_burn(key->sk_reserved);
ssh_string_free(key->sk_reserved);
key->sk_flags = 0;
} }
key->cert_type = SSH_KEYTYPE_UNKNOWN; key->cert_type = SSH_KEYTYPE_UNKNOWN;
key->flags = SSH_KEY_FLAG_EMPTY; key->flags = SSH_KEY_FLAG_EMPTY;
@@ -706,13 +780,24 @@ int ssh_key_cmp(const ssh_key k1,
} }
} }
if (k1->type == SSH_KEYTYPE_SK_ECDSA || if (is_sk_key_type(k1->type)) {
k1->type == SSH_KEYTYPE_SK_ED25519) { if (ssh_string_cmp(k1->sk_application, k2->sk_application) != 0) {
if (strncmp(ssh_string_get_char(k1->sk_application),
ssh_string_get_char(k2->sk_application),
ssh_string_len(k2->sk_application)) != 0) {
return 1; return 1;
} }
if (what == SSH_KEY_CMP_PRIVATE) {
if (k1->sk_flags != k2->sk_flags) {
return 1;
}
if (ssh_string_cmp(k1->sk_key_handle, k2->sk_key_handle) != 0) {
return 1;
}
if (ssh_string_cmp(k1->sk_reserved, k2->sk_reserved) != 0) {
return 1;
}
}
} }
if (what == SSH_KEY_CMP_CERTIFICATE) { if (what == SSH_KEY_CMP_CERTIFICATE) {
@@ -732,9 +817,10 @@ int ssh_key_cmp(const ssh_key k1,
} }
#ifndef HAVE_LIBCRYPTO #ifndef HAVE_LIBCRYPTO
if (k1->type == SSH_KEYTYPE_ED25519 || if (k1->type == SSH_KEYTYPE_ED25519) {
k1->type == SSH_KEYTYPE_SK_ED25519) {
return pki_ed25519_key_cmp(k1, k2, what); return pki_ed25519_key_cmp(k1, k2, what);
} else if (k1->type == SSH_KEYTYPE_SK_ED25519) {
return pki_ed25519_key_cmp(k1, k2, SSH_KEY_CMP_PUBLIC);
} }
#endif #endif
@@ -2635,11 +2721,7 @@ int ssh_pki_signature_verify(ssh_session session,
return SSH_ERROR; return SSH_ERROR;
} }
if (key->type == SSH_KEYTYPE_SK_ECDSA || if (is_sk_key_type(key->type)) {
key->type == SSH_KEYTYPE_SK_ECDSA_CERT01 ||
key->type == SSH_KEYTYPE_SK_ED25519 ||
key->type == SSH_KEYTYPE_SK_ED25519_CERT01) {
ssh_buffer sk_buffer = NULL; ssh_buffer sk_buffer = NULL;
SHA256CTX ctx = NULL; SHA256CTX ctx = NULL;
unsigned char application_hash[SHA256_DIGEST_LEN] = {0}; unsigned char application_hash[SHA256_DIGEST_LEN] = {0};

View File

@@ -485,19 +485,11 @@ ssh_key pki_key_dup(const ssh_key key, int demote)
ssh_key new = NULL; ssh_key new = NULL;
int rc; int rc;
new = ssh_key_new(); new = pki_key_dup_common_init(key, demote);
if (new == NULL) { if (new == NULL) {
return NULL; return NULL;
} }
new->type = key->type;
new->type_c = key->type_c;
if (demote) {
new->flags = SSH_KEY_FLAG_PUBLIC;
} else {
new->flags = key->flags;
}
switch (key->type) { switch (key->type) {
case SSH_KEYTYPE_RSA: case SSH_KEYTYPE_RSA:
case SSH_KEYTYPE_RSA1: { case SSH_KEYTYPE_RSA1: {
@@ -646,6 +638,7 @@ ssh_key pki_key_dup(const ssh_key key, int demote)
case SSH_KEYTYPE_ECDSA_P256: case SSH_KEYTYPE_ECDSA_P256:
case SSH_KEYTYPE_ECDSA_P384: case SSH_KEYTYPE_ECDSA_P384:
case SSH_KEYTYPE_ECDSA_P521: case SSH_KEYTYPE_ECDSA_P521:
case SSH_KEYTYPE_SK_ECDSA:
#ifdef HAVE_OPENSSL_ECC #ifdef HAVE_OPENSSL_ECC
new->ecdsa_nid = key->ecdsa_nid; new->ecdsa_nid = key->ecdsa_nid;
#ifdef WITH_PKCS11_URI #ifdef WITH_PKCS11_URI
@@ -715,7 +708,8 @@ ssh_key pki_key_dup(const ssh_key key, int demote)
#endif /* OPENSSL_VERSION_NUMBER */ #endif /* OPENSSL_VERSION_NUMBER */
break; break;
#endif /* HAVE_OPENSSL_ECC */ #endif /* HAVE_OPENSSL_ECC */
case SSH_KEYTYPE_ED25519: { case SSH_KEYTYPE_ED25519:
case SSH_KEYTYPE_SK_ED25519: {
#if OPENSSL_VERSION_NUMBER < 0x30000000L #if OPENSSL_VERSION_NUMBER < 0x30000000L
/* Take the PKCS#11 keys as they are */ /* Take the PKCS#11 keys as they are */
if (key->flags & SSH_KEY_FLAG_PKCS11_URI && !demote) { if (key->flags & SSH_KEY_FLAG_PKCS11_URI && !demote) {
@@ -727,7 +721,8 @@ ssh_key pki_key_dup(const ssh_key key, int demote)
return new; return new;
} }
if (!demote && (key->flags & SSH_KEY_FLAG_PRIVATE)) { if (!demote && (key->flags & SSH_KEY_FLAG_PRIVATE) &&
key->type == SSH_KEYTYPE_ED25519) {
unsigned char *ed25519_privkey = NULL; unsigned char *ed25519_privkey = NULL;
size_t key_len = 0; size_t key_len = 0;
@@ -1019,7 +1014,7 @@ int pki_key_compare(const ssh_key k1, const ssh_key k2, enum ssh_keycmp_e what)
return 1; return 1;
} }
if (what == SSH_KEY_CMP_PRIVATE) { if (what == SSH_KEY_CMP_PRIVATE && !is_sk_key_type(k1->type)) {
if (bignum_cmp(EC_KEY_get0_private_key(ec1), if (bignum_cmp(EC_KEY_get0_private_key(ec1),
EC_KEY_get0_private_key(ec2))) { EC_KEY_get0_private_key(ec2))) {
return 1; return 1;

View File

@@ -1155,17 +1155,10 @@ ssh_key pki_key_dup(const ssh_key key, int demote)
gcry_sexp_t curve = NULL; gcry_sexp_t curve = NULL;
new = ssh_key_new(); new = pki_key_dup_common_init(key, demote);
if (new == NULL) { if (new == NULL) {
return NULL; return NULL;
} }
new->type = key->type;
new->type_c = key->type_c;
if (demote) {
new->flags = SSH_KEY_FLAG_PUBLIC;
} else {
new->flags = key->flags;
}
switch (key->type) { switch (key->type) {
case SSH_KEYTYPE_RSA: case SSH_KEYTYPE_RSA:
@@ -1203,6 +1196,7 @@ ssh_key pki_key_dup(const ssh_key key, int demote)
} }
break; break;
case SSH_KEYTYPE_ED25519: case SSH_KEYTYPE_ED25519:
case SSH_KEYTYPE_SK_ED25519:
rc = pki_ed25519_key_dup(new, key); rc = pki_ed25519_key_dup(new, key);
if (rc != SSH_OK) { if (rc != SSH_OK) {
ssh_key_free(new); ssh_key_free(new);
@@ -1213,6 +1207,7 @@ ssh_key pki_key_dup(const ssh_key key, int demote)
case SSH_KEYTYPE_ECDSA_P256: case SSH_KEYTYPE_ECDSA_P256:
case SSH_KEYTYPE_ECDSA_P384: case SSH_KEYTYPE_ECDSA_P384:
case SSH_KEYTYPE_ECDSA_P521: case SSH_KEYTYPE_ECDSA_P521:
case SSH_KEYTYPE_SK_ECDSA:
#ifdef HAVE_GCRYPT_ECC #ifdef HAVE_GCRYPT_ECC
new->ecdsa_nid = key->ecdsa_nid; new->ecdsa_nid = key->ecdsa_nid;
@@ -1226,7 +1221,8 @@ ssh_key pki_key_dup(const ssh_key key, int demote)
break; break;
} }
if (!demote && (key->flags & SSH_KEY_FLAG_PRIVATE)) { if (!demote && (key->flags & SSH_KEY_FLAG_PRIVATE) &&
!is_sk_key_type(key->type)) {
err = gcry_sexp_build(&new->ecdsa, err = gcry_sexp_build(&new->ecdsa,
NULL, NULL,
"(private-key(ecdsa %S (d %m)(q %m)))", "(private-key(ecdsa %S (d %m)(q %m)))",
@@ -1427,7 +1423,7 @@ int pki_key_compare(const ssh_key k1, const ssh_key k2, enum ssh_keycmp_e what)
return 1; return 1;
} }
if (what == SSH_KEY_CMP_PRIVATE) { if (what == SSH_KEY_CMP_PRIVATE && !is_sk_key_type(k1->type)) {
if (_bignum_cmp(k1->ecdsa, k2->ecdsa, "d") != 0) { if (_bignum_cmp(k1->ecdsa, k2->ecdsa, "d") != 0) {
return 1; return 1;
} }

View File

@@ -380,19 +380,11 @@ ssh_key pki_key_dup(const ssh_key key, int demote)
mbedtls_mpi Q; mbedtls_mpi Q;
#endif #endif
new = ssh_key_new(); new = pki_key_dup_common_init(key, demote);
if (new == NULL) { if (new == NULL) {
return NULL; return NULL;
} }
new->type = key->type;
new->type_c = key->type_c;
if (demote) {
new->flags = SSH_KEY_FLAG_PUBLIC;
} else {
new->flags = key->flags;
}
#if MBEDTLS_VERSION_MAJOR > 2 #if MBEDTLS_VERSION_MAJOR > 2
mbedtls_mpi_init(&N); mbedtls_mpi_init(&N);
mbedtls_mpi_init(&E); mbedtls_mpi_init(&E);
@@ -512,6 +504,7 @@ ssh_key pki_key_dup(const ssh_key key, int demote)
case SSH_KEYTYPE_ECDSA_P256: case SSH_KEYTYPE_ECDSA_P256:
case SSH_KEYTYPE_ECDSA_P384: case SSH_KEYTYPE_ECDSA_P384:
case SSH_KEYTYPE_ECDSA_P521: case SSH_KEYTYPE_ECDSA_P521:
case SSH_KEYTYPE_SK_ECDSA:
new->ecdsa_nid = key->ecdsa_nid; new->ecdsa_nid = key->ecdsa_nid;
new->ecdsa = malloc(sizeof(mbedtls_ecdsa_context)); new->ecdsa = malloc(sizeof(mbedtls_ecdsa_context));
@@ -522,7 +515,8 @@ ssh_key pki_key_dup(const ssh_key key, int demote)
mbedtls_ecdsa_init(new->ecdsa); mbedtls_ecdsa_init(new->ecdsa);
if (demote && ssh_key_is_private(key)) { if ((demote && ssh_key_is_private(key)) ||
is_sk_key_type(key->type)) {
rc = mbedtls_ecp_copy(&new->ecdsa->MBEDTLS_PRIVATE(Q), rc = mbedtls_ecp_copy(&new->ecdsa->MBEDTLS_PRIVATE(Q),
&key->ecdsa->MBEDTLS_PRIVATE(Q)); &key->ecdsa->MBEDTLS_PRIVATE(Q));
if (rc != 0) { if (rc != 0) {
@@ -540,6 +534,7 @@ ssh_key pki_key_dup(const ssh_key key, int demote)
break; break;
case SSH_KEYTYPE_ED25519: case SSH_KEYTYPE_ED25519:
case SSH_KEYTYPE_SK_ED25519:
rc = pki_ed25519_key_dup(new, key); rc = pki_ed25519_key_dup(new, key);
if (rc != SSH_OK) { if (rc != SSH_OK) {
goto fail; goto fail;
@@ -768,7 +763,8 @@ int pki_key_compare(const ssh_key k1, const ssh_key k2, enum ssh_keycmp_e what)
goto cleanup; goto cleanup;
} }
if (what == SSH_KEY_CMP_PRIVATE) { if (what == SSH_KEY_CMP_PRIVATE &&
k1->type != SSH_KEYTYPE_SK_ECDSA) {
if (mbedtls_mpi_cmp_mpi(&ecdsa1->MBEDTLS_PRIVATE(d), if (mbedtls_mpi_cmp_mpi(&ecdsa1->MBEDTLS_PRIVATE(d),
&ecdsa2->MBEDTLS_PRIVATE(d))) &ecdsa2->MBEDTLS_PRIVATE(d)))
{ {