mirror of
https://git.libssh.org/projects/libssh.git
synced 2026-02-04 12:20:42 +09:00
Compare commits
7 Commits
09155adb19
...
cc667021e5
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cc667021e5 | ||
|
|
f9f8c939bc | ||
|
|
aab6ce364a | ||
|
|
0cec257077 | ||
|
|
957efe51a2 | ||
|
|
bb85492d4f | ||
|
|
22c1b6970c |
@@ -86,6 +86,11 @@ struct ssh_key_struct {
|
||||
ssh_string sk_application;
|
||||
ssh_buffer cert;
|
||||
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 {
|
||||
@@ -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_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 ssh_signature_new(void);
|
||||
void ssh_signature_free(ssh_signature sign);
|
||||
|
||||
@@ -61,6 +61,7 @@ enum ssh_digest_e ssh_key_type_to_hash(ssh_session session,
|
||||
enum ssh_keytypes_e type);
|
||||
|
||||
/* 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);
|
||||
int pki_key_generate_rsa(ssh_key key, int parameter);
|
||||
int pki_key_generate_ecdsa(ssh_key key, int parameter);
|
||||
@@ -163,6 +164,11 @@ int pki_uri_import(const char *uri_name, ssh_key *key, enum ssh_key_e key_type);
|
||||
#endif /* WITH_PKCS11_URI */
|
||||
|
||||
bool ssh_key_size_allowed_rsa(int min_size, ssh_key key);
|
||||
|
||||
/* Security Key Helper Functions */
|
||||
int pki_buffer_pack_sk_priv_data(ssh_buffer buffer, const ssh_key key);
|
||||
int pki_buffer_unpack_sk_priv_data(ssh_buffer buffer, ssh_key key);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
489
src/pki.c
489
src/pki.c
@@ -116,6 +116,78 @@ ssh_key ssh_key_new (void)
|
||||
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
|
||||
*
|
||||
@@ -153,12 +225,14 @@ void ssh_key_clean (ssh_key key)
|
||||
if (key->cert != NULL) {
|
||||
SSH_BUFFER_FREE(key->cert);
|
||||
}
|
||||
if (key->type == SSH_KEYTYPE_SK_ECDSA ||
|
||||
key->type == SSH_KEYTYPE_SK_ED25519 ||
|
||||
key->type == SSH_KEYTYPE_SK_ECDSA_CERT01 ||
|
||||
key->type == SSH_KEYTYPE_SK_ED25519_CERT01) {
|
||||
if (is_sk_key_type(key->type)) {
|
||||
ssh_string_burn(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->flags = SSH_KEY_FLAG_EMPTY;
|
||||
@@ -432,6 +506,7 @@ static enum ssh_digest_e key_type_to_hash(enum ssh_keytypes_e type)
|
||||
return SSH_DIGEST_SHA512;
|
||||
case SSH_KEYTYPE_ECDSA_P256_CERT01:
|
||||
case SSH_KEYTYPE_ECDSA_P256:
|
||||
case SSH_KEYTYPE_SK_ECDSA:
|
||||
return SSH_DIGEST_SHA256;
|
||||
case SSH_KEYTYPE_ECDSA_P384_CERT01:
|
||||
case SSH_KEYTYPE_ECDSA_P384:
|
||||
@@ -441,6 +516,7 @@ static enum ssh_digest_e key_type_to_hash(enum ssh_keytypes_e type)
|
||||
return SSH_DIGEST_SHA512;
|
||||
case SSH_KEYTYPE_ED25519_CERT01:
|
||||
case SSH_KEYTYPE_ED25519:
|
||||
case SSH_KEYTYPE_SK_ED25519:
|
||||
return SSH_DIGEST_AUTO;
|
||||
case SSH_KEYTYPE_RSA1:
|
||||
case SSH_KEYTYPE_DSS: /* deprecated */
|
||||
@@ -706,13 +782,24 @@ int ssh_key_cmp(const ssh_key k1,
|
||||
}
|
||||
}
|
||||
|
||||
if (k1->type == SSH_KEYTYPE_SK_ECDSA ||
|
||||
k1->type == SSH_KEYTYPE_SK_ED25519) {
|
||||
if (strncmp(ssh_string_get_char(k1->sk_application),
|
||||
ssh_string_get_char(k2->sk_application),
|
||||
ssh_string_len(k2->sk_application)) != 0) {
|
||||
if (is_sk_key_type(k1->type)) {
|
||||
if (ssh_string_cmp(k1->sk_application, k2->sk_application) != 0) {
|
||||
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) {
|
||||
@@ -732,9 +819,10 @@ int ssh_key_cmp(const ssh_key k1,
|
||||
}
|
||||
|
||||
#ifndef HAVE_LIBCRYPTO
|
||||
if (k1->type == SSH_KEYTYPE_ED25519 ||
|
||||
k1->type == SSH_KEYTYPE_SK_ED25519) {
|
||||
if (k1->type == SSH_KEYTYPE_ED25519) {
|
||||
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
|
||||
|
||||
@@ -909,10 +997,15 @@ ssh_pki_export_privkey_base64_format(const ssh_key privkey,
|
||||
/*
|
||||
* For historic reasons, the Ed25519 keys are exported in OpenSSH file
|
||||
* format by default also when built with OpenSSL.
|
||||
*
|
||||
* The FIDO2/U2F security keys are an extension to the SSH protocol
|
||||
* proposed by OpenSSH, and do not have any representation in PEM format.
|
||||
* So, they are always exported in the OpenSSH file format.
|
||||
*/
|
||||
#ifdef HAVE_LIBCRYPTO
|
||||
if (format == SSH_FILE_FORMAT_DEFAULT &&
|
||||
privkey->type != SSH_KEYTYPE_ED25519) {
|
||||
privkey->type != SSH_KEYTYPE_ED25519 &&
|
||||
!is_sk_key_type(privkey->type)) {
|
||||
format = SSH_FILE_FORMAT_PEM;
|
||||
}
|
||||
#endif /* HAVE_LIBCRYPTO */
|
||||
@@ -1136,10 +1229,16 @@ ssh_pki_export_privkey_file_format(const ssh_key privkey,
|
||||
/*
|
||||
* For historic reasons, the Ed25519 keys are exported in OpenSSH file
|
||||
* format by default also when built with OpenSSL.
|
||||
*
|
||||
* The FIDO2/U2F security keys are an extension to the SSH protocol
|
||||
* proposed by OpenSSH, and do not have any representation in PEM format.
|
||||
* So, they are always exported in the OpenSSH file format.
|
||||
*/
|
||||
#ifdef HAVE_LIBCRYPTO
|
||||
if (format == SSH_FILE_FORMAT_DEFAULT &&
|
||||
privkey->type != SSH_KEYTYPE_ED25519) {
|
||||
privkey->type != SSH_KEYTYPE_ED25519 &&
|
||||
!is_sk_key_type(privkey->type)) {
|
||||
|
||||
format = SSH_FILE_FORMAT_PEM;
|
||||
}
|
||||
#endif /* HAVE_LIBCRYPTO */
|
||||
@@ -1288,129 +1387,178 @@ int pki_import_privkey_buffer(enum ssh_keytypes_e type,
|
||||
key->flags = SSH_KEY_FLAG_PRIVATE | SSH_KEY_FLAG_PUBLIC;
|
||||
|
||||
switch (type) {
|
||||
case SSH_KEYTYPE_RSA:
|
||||
{
|
||||
ssh_string n = NULL;
|
||||
ssh_string e = NULL;
|
||||
ssh_string d = NULL;
|
||||
ssh_string iqmp = NULL;
|
||||
ssh_string p = NULL;
|
||||
ssh_string q = NULL;
|
||||
case SSH_KEYTYPE_RSA: {
|
||||
ssh_string n = NULL;
|
||||
ssh_string e = NULL;
|
||||
ssh_string d = NULL;
|
||||
ssh_string iqmp = NULL;
|
||||
ssh_string p = NULL;
|
||||
ssh_string q = NULL;
|
||||
|
||||
rc = ssh_buffer_unpack(buffer, "SSSSSS", &n, &e, &d,
|
||||
&iqmp, &p, &q);
|
||||
if (rc != SSH_OK) {
|
||||
SSH_LOG(SSH_LOG_TRACE, "Unpack error");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
rc = pki_privkey_build_rsa(key, n, e, d, iqmp, p, q);
|
||||
#ifdef DEBUG_CRYPTO
|
||||
ssh_log_hexdump("n", ssh_string_data(n), ssh_string_len(n));
|
||||
ssh_log_hexdump("e", ssh_string_data(e), ssh_string_len(e));
|
||||
ssh_log_hexdump("d", ssh_string_data(d), ssh_string_len(d));
|
||||
ssh_log_hexdump("iqmp",
|
||||
ssh_string_data(iqmp),
|
||||
ssh_string_len(iqmp));
|
||||
ssh_log_hexdump("p", ssh_string_data(p), ssh_string_len(p));
|
||||
ssh_log_hexdump("q", ssh_string_data(q), ssh_string_len(q));
|
||||
#endif /* DEBUG_CRYPTO */
|
||||
ssh_string_burn(n);
|
||||
SSH_STRING_FREE(n);
|
||||
ssh_string_burn(e);
|
||||
SSH_STRING_FREE(e);
|
||||
ssh_string_burn(d);
|
||||
SSH_STRING_FREE(d);
|
||||
ssh_string_burn(iqmp);
|
||||
SSH_STRING_FREE(iqmp);
|
||||
ssh_string_burn(p);
|
||||
SSH_STRING_FREE(p);
|
||||
ssh_string_burn(q);
|
||||
SSH_STRING_FREE(q);
|
||||
if (rc == SSH_ERROR) {
|
||||
SSH_LOG(SSH_LOG_TRACE, "Failed to build RSA private key");
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
break;
|
||||
#ifdef HAVE_ECC
|
||||
case SSH_KEYTYPE_ECDSA_P256:
|
||||
case SSH_KEYTYPE_ECDSA_P384:
|
||||
case SSH_KEYTYPE_ECDSA_P521:
|
||||
{
|
||||
ssh_string e = NULL;
|
||||
ssh_string exp = NULL;
|
||||
ssh_string i = NULL;
|
||||
int nid;
|
||||
|
||||
rc = ssh_buffer_unpack(buffer, "SSS", &i, &e, &exp);
|
||||
if (rc != SSH_OK) {
|
||||
SSH_LOG(SSH_LOG_TRACE, "Unpack error");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
nid = pki_key_ecdsa_nid_from_name(ssh_string_get_char(i));
|
||||
SSH_STRING_FREE(i);
|
||||
if (nid == -1) {
|
||||
ssh_string_burn(e);
|
||||
SSH_STRING_FREE(e);
|
||||
ssh_string_burn(exp);
|
||||
SSH_STRING_FREE(exp);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
rc = pki_privkey_build_ecdsa(key, nid, e, exp);
|
||||
ssh_string_burn(e);
|
||||
SSH_STRING_FREE(e);
|
||||
ssh_string_burn(exp);
|
||||
SSH_STRING_FREE(exp);
|
||||
if (rc < 0) {
|
||||
SSH_LOG(SSH_LOG_TRACE, "Failed to build ECDSA private key");
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif /* HAVE_ECC */
|
||||
case SSH_KEYTYPE_ED25519:
|
||||
{
|
||||
ssh_string pubkey = NULL, privkey = NULL;
|
||||
|
||||
if (ssh_fips_mode()) {
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Ed25519 keys not supported in FIPS mode");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
rc = ssh_buffer_unpack(buffer, "SS", &pubkey, &privkey);
|
||||
if (rc != SSH_OK){
|
||||
SSH_LOG(SSH_LOG_TRACE, "Unpack error");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
rc = pki_privkey_build_ed25519(key, pubkey, privkey);
|
||||
ssh_string_burn(privkey);
|
||||
SSH_STRING_FREE(privkey);
|
||||
SSH_STRING_FREE(pubkey);
|
||||
if (rc != SSH_OK) {
|
||||
SSH_LOG(SSH_LOG_TRACE, "Failed to build ed25519 key");
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SSH_KEYTYPE_RSA_CERT01:
|
||||
case SSH_KEYTYPE_ECDSA_P256_CERT01:
|
||||
case SSH_KEYTYPE_ECDSA_P384_CERT01:
|
||||
case SSH_KEYTYPE_ECDSA_P521_CERT01:
|
||||
case SSH_KEYTYPE_ED25519_CERT01:
|
||||
case SSH_KEYTYPE_SK_ECDSA:
|
||||
case SSH_KEYTYPE_SK_ECDSA_CERT01:
|
||||
case SSH_KEYTYPE_SK_ED25519:
|
||||
case SSH_KEYTYPE_SK_ED25519_CERT01:
|
||||
case SSH_KEYTYPE_RSA1:
|
||||
case SSH_KEYTYPE_UNKNOWN:
|
||||
default:
|
||||
SSH_LOG(SSH_LOG_TRACE, "Unknown private key type (%d)", type);
|
||||
rc = ssh_buffer_unpack(buffer, "SSSSSS", &n, &e, &d, &iqmp, &p, &q);
|
||||
if (rc != SSH_OK) {
|
||||
SSH_LOG(SSH_LOG_TRACE, "Unpack error");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
rc = pki_privkey_build_rsa(key, n, e, d, iqmp, p, q);
|
||||
#ifdef DEBUG_CRYPTO
|
||||
ssh_log_hexdump("n", ssh_string_data(n), ssh_string_len(n));
|
||||
ssh_log_hexdump("e", ssh_string_data(e), ssh_string_len(e));
|
||||
ssh_log_hexdump("d", ssh_string_data(d), ssh_string_len(d));
|
||||
ssh_log_hexdump("iqmp", ssh_string_data(iqmp), ssh_string_len(iqmp));
|
||||
ssh_log_hexdump("p", ssh_string_data(p), ssh_string_len(p));
|
||||
ssh_log_hexdump("q", ssh_string_data(q), ssh_string_len(q));
|
||||
#endif /* DEBUG_CRYPTO */
|
||||
ssh_string_burn(n);
|
||||
SSH_STRING_FREE(n);
|
||||
ssh_string_burn(e);
|
||||
SSH_STRING_FREE(e);
|
||||
ssh_string_burn(d);
|
||||
SSH_STRING_FREE(d);
|
||||
ssh_string_burn(iqmp);
|
||||
SSH_STRING_FREE(iqmp);
|
||||
ssh_string_burn(p);
|
||||
SSH_STRING_FREE(p);
|
||||
ssh_string_burn(q);
|
||||
SSH_STRING_FREE(q);
|
||||
if (rc == SSH_ERROR) {
|
||||
SSH_LOG(SSH_LOG_TRACE, "Failed to build RSA private key");
|
||||
goto fail;
|
||||
}
|
||||
break;
|
||||
}
|
||||
#ifdef HAVE_ECC
|
||||
case SSH_KEYTYPE_ECDSA_P256:
|
||||
case SSH_KEYTYPE_ECDSA_P384:
|
||||
case SSH_KEYTYPE_ECDSA_P521: {
|
||||
ssh_string e = NULL;
|
||||
ssh_string exp = NULL;
|
||||
ssh_string i = NULL;
|
||||
int nid;
|
||||
|
||||
rc = ssh_buffer_unpack(buffer, "SSS", &i, &e, &exp);
|
||||
if (rc != SSH_OK) {
|
||||
SSH_LOG(SSH_LOG_TRACE, "Unpack error");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
nid = pki_key_ecdsa_nid_from_name(ssh_string_get_char(i));
|
||||
SSH_STRING_FREE(i);
|
||||
if (nid == -1) {
|
||||
ssh_string_burn(e);
|
||||
SSH_STRING_FREE(e);
|
||||
ssh_string_burn(exp);
|
||||
SSH_STRING_FREE(exp);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
rc = pki_privkey_build_ecdsa(key, nid, e, exp);
|
||||
ssh_string_burn(e);
|
||||
SSH_STRING_FREE(e);
|
||||
ssh_string_burn(exp);
|
||||
SSH_STRING_FREE(exp);
|
||||
if (rc < 0) {
|
||||
SSH_LOG(SSH_LOG_TRACE, "Failed to build ECDSA private key");
|
||||
goto fail;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SSH_KEYTYPE_SK_ECDSA: {
|
||||
ssh_string type_str = NULL;
|
||||
ssh_string pubkey = NULL;
|
||||
int nid;
|
||||
|
||||
rc = ssh_buffer_unpack(buffer, "SS", &type_str, &pubkey);
|
||||
if (rc != SSH_OK) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
rc = pki_buffer_unpack_sk_priv_data(buffer, key);
|
||||
if (rc != SSH_OK) {
|
||||
SSH_STRING_FREE(type_str);
|
||||
SSH_STRING_FREE(pubkey);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
nid = pki_key_ecdsa_nid_from_name(ssh_string_get_char(type_str));
|
||||
SSH_STRING_FREE(type_str);
|
||||
|
||||
if (nid == -1) {
|
||||
SSH_STRING_FREE(pubkey);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
rc = pki_pubkey_build_ecdsa(key, nid, pubkey);
|
||||
SSH_STRING_FREE(pubkey);
|
||||
if (rc != SSH_OK) {
|
||||
goto fail;
|
||||
}
|
||||
break;
|
||||
}
|
||||
#endif /* HAVE_ECC */
|
||||
case SSH_KEYTYPE_ED25519: {
|
||||
ssh_string pubkey = NULL, privkey = NULL;
|
||||
|
||||
if (ssh_fips_mode()) {
|
||||
SSH_LOG(SSH_LOG_TRACE, "Ed25519 keys not supported in FIPS mode");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
rc = ssh_buffer_unpack(buffer, "SS", &pubkey, &privkey);
|
||||
if (rc != SSH_OK) {
|
||||
SSH_LOG(SSH_LOG_TRACE, "Unpack error");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
rc = pki_privkey_build_ed25519(key, pubkey, privkey);
|
||||
ssh_string_burn(privkey);
|
||||
SSH_STRING_FREE(privkey);
|
||||
SSH_STRING_FREE(pubkey);
|
||||
if (rc != SSH_OK) {
|
||||
SSH_LOG(SSH_LOG_TRACE, "Failed to build ed25519 key");
|
||||
goto fail;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SSH_KEYTYPE_SK_ED25519: {
|
||||
ssh_string pubkey = NULL;
|
||||
|
||||
if (ssh_fips_mode()) {
|
||||
SSH_LOG(SSH_LOG_TRACE, "Ed25519 keys not supported in FIPS mode");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
rc = ssh_buffer_unpack(buffer, "S", &pubkey);
|
||||
if (rc != SSH_OK) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
rc = pki_buffer_unpack_sk_priv_data(buffer, key);
|
||||
if (rc != SSH_OK) {
|
||||
SSH_STRING_FREE(pubkey);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
rc = pki_pubkey_build_ed25519(key, pubkey);
|
||||
SSH_STRING_FREE(pubkey);
|
||||
if (rc != SSH_OK) {
|
||||
goto fail;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SSH_KEYTYPE_RSA_CERT01:
|
||||
case SSH_KEYTYPE_ECDSA_P256_CERT01:
|
||||
case SSH_KEYTYPE_ECDSA_P384_CERT01:
|
||||
case SSH_KEYTYPE_ECDSA_P521_CERT01:
|
||||
case SSH_KEYTYPE_ED25519_CERT01:
|
||||
case SSH_KEYTYPE_SK_ECDSA_CERT01:
|
||||
case SSH_KEYTYPE_SK_ED25519_CERT01:
|
||||
case SSH_KEYTYPE_RSA1:
|
||||
case SSH_KEYTYPE_UNKNOWN:
|
||||
default:
|
||||
SSH_LOG(SSH_LOG_TRACE, "Unknown private key type (%d)", type);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
*pkey = key;
|
||||
@@ -2151,6 +2299,64 @@ int ssh_pki_export_privkey_to_pubkey(const ssh_key privkey,
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @brief Pack security key private data into a buffer.
|
||||
*
|
||||
* This function packs the common security key fields (application, flags,
|
||||
* key handle, and reserved data) into a buffer.
|
||||
* This is used for both ECDSA and Ed25519 security keys when exporting
|
||||
* private key data.
|
||||
*
|
||||
* @param[in] buffer The buffer to pack the security key data into.
|
||||
*
|
||||
* @param[in] key The security key containing the data to pack.
|
||||
* Must be a security key type (SK_ECDSA or SK_ED25519).
|
||||
*
|
||||
* @return SSH_OK on success, SSH_ERROR on error.
|
||||
*
|
||||
* @see ssh_buffer_pack()
|
||||
*/
|
||||
int pki_buffer_pack_sk_priv_data(ssh_buffer buffer, ssh_key key)
|
||||
{
|
||||
return ssh_buffer_pack(buffer,
|
||||
"SbSS",
|
||||
key->sk_application,
|
||||
key->sk_flags,
|
||||
key->sk_key_handle,
|
||||
key->sk_reserved);
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @brief Unpack security key private data from a buffer.
|
||||
*
|
||||
* This function unpacks the common security key fields (application, flags,
|
||||
* key handle, and reserved data) from a buffer.
|
||||
* This is used for both ECDSA and Ed25519 security keys when importing
|
||||
* private key data.
|
||||
*
|
||||
* @param[in] buffer The buffer to unpack the security key data from.
|
||||
*
|
||||
* @param[in] key The security key to store the unpacked data into.
|
||||
* Must be a security key type (SK_ECDSA or SK_ED25519).
|
||||
*
|
||||
* @return SSH_OK on success, SSH_ERROR on error.
|
||||
*
|
||||
* @see ssh_buffer_unpack()
|
||||
*/
|
||||
int pki_buffer_unpack_sk_priv_data(ssh_buffer buffer, ssh_key key)
|
||||
{
|
||||
return ssh_buffer_unpack(buffer,
|
||||
"SbSS",
|
||||
&key->sk_application,
|
||||
&key->sk_flags,
|
||||
&key->sk_key_handle,
|
||||
&key->sk_reserved);
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
@@ -2422,6 +2628,15 @@ int ssh_pki_export_signature_blob(const ssh_signature sig,
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
if (is_sk_key_type(sig->type)) {
|
||||
/* Add flags and counter for SK keys */
|
||||
rc = ssh_buffer_pack(buf, "bd", sig->sk_flags, sig->sk_counter);
|
||||
if (rc < 0) {
|
||||
SSH_BUFFER_FREE(buf);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
str = ssh_string_new(ssh_buffer_get_len(buf));
|
||||
if (str == NULL) {
|
||||
SSH_BUFFER_FREE(buf);
|
||||
@@ -2635,11 +2850,7 @@ int ssh_pki_signature_verify(ssh_session session,
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
if (key->type == SSH_KEYTYPE_SK_ECDSA ||
|
||||
key->type == SSH_KEYTYPE_SK_ECDSA_CERT01 ||
|
||||
key->type == SSH_KEYTYPE_SK_ED25519 ||
|
||||
key->type == SSH_KEYTYPE_SK_ED25519_CERT01) {
|
||||
|
||||
if (is_sk_key_type(key->type)) {
|
||||
ssh_buffer sk_buffer = NULL;
|
||||
SHA256CTX ctx = NULL;
|
||||
unsigned char application_hash[SHA256_DIGEST_LEN] = {0};
|
||||
|
||||
@@ -485,19 +485,11 @@ ssh_key pki_key_dup(const ssh_key key, int demote)
|
||||
ssh_key new = NULL;
|
||||
int rc;
|
||||
|
||||
new = ssh_key_new();
|
||||
new = pki_key_dup_common_init(key, demote);
|
||||
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;
|
||||
}
|
||||
|
||||
switch (key->type) {
|
||||
case SSH_KEYTYPE_RSA:
|
||||
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_P384:
|
||||
case SSH_KEYTYPE_ECDSA_P521:
|
||||
case SSH_KEYTYPE_SK_ECDSA:
|
||||
#ifdef HAVE_OPENSSL_ECC
|
||||
new->ecdsa_nid = key->ecdsa_nid;
|
||||
#ifdef WITH_PKCS11_URI
|
||||
@@ -715,7 +708,8 @@ ssh_key pki_key_dup(const ssh_key key, int demote)
|
||||
#endif /* OPENSSL_VERSION_NUMBER */
|
||||
break;
|
||||
#endif /* HAVE_OPENSSL_ECC */
|
||||
case SSH_KEYTYPE_ED25519: {
|
||||
case SSH_KEYTYPE_ED25519:
|
||||
case SSH_KEYTYPE_SK_ED25519: {
|
||||
#if OPENSSL_VERSION_NUMBER < 0x30000000L
|
||||
/* Take the PKCS#11 keys as they are */
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
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),
|
||||
EC_KEY_get0_private_key(ec2))) {
|
||||
return 1;
|
||||
@@ -1790,7 +1785,7 @@ ssh_string pki_key_to_blob(const ssh_key key, enum ssh_key_e type)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (type == SSH_KEY_PRIVATE) {
|
||||
if (type == SSH_KEY_PRIVATE && key->type == SSH_KEYTYPE_ED25519) {
|
||||
key_len = 0;
|
||||
rc = EVP_PKEY_get_raw_private_key(key->key, NULL, &key_len);
|
||||
if (rc != 1) {
|
||||
@@ -1836,15 +1831,22 @@ ssh_string pki_key_to_blob(const ssh_key key, enum ssh_key_e type)
|
||||
}
|
||||
explicit_bzero(ed25519_privkey, ED25519_KEY_LEN);
|
||||
SAFE_FREE(ed25519_privkey);
|
||||
} else {
|
||||
} else if (type == SSH_KEY_PRIVATE &&
|
||||
key->type == SSH_KEYTYPE_SK_ED25519) {
|
||||
|
||||
rc = pki_buffer_pack_sk_priv_data(buffer, key);
|
||||
if (rc == SSH_ERROR) {
|
||||
goto fail;
|
||||
}
|
||||
} else if (type == SSH_KEY_PUBLIC &&
|
||||
key->type == SSH_KEYTYPE_SK_ED25519) {
|
||||
/* public key can contain certificate sk information */
|
||||
if (key->type == SSH_KEYTYPE_SK_ED25519) {
|
||||
rc = ssh_buffer_add_ssh_string(buffer, key->sk_application);
|
||||
if (rc < 0) {
|
||||
goto fail;
|
||||
}
|
||||
rc = ssh_buffer_add_ssh_string(buffer, key->sk_application);
|
||||
if (rc != SSH_OK) {
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
SAFE_FREE(ed25519_pubkey);
|
||||
break;
|
||||
case SSH_KEYTYPE_ECDSA_P256:
|
||||
@@ -1949,7 +1951,8 @@ ssh_string pki_key_to_blob(const ssh_key key, enum ssh_key_e type)
|
||||
ssh_string_burn(e);
|
||||
SSH_STRING_FREE(e);
|
||||
e = NULL;
|
||||
if (type == SSH_KEY_PRIVATE) {
|
||||
|
||||
if (type == SSH_KEY_PRIVATE && key->type != SSH_KEYTYPE_SK_ECDSA) {
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
|
||||
OSSL_PARAM_free(params);
|
||||
rc = EVP_PKEY_todata(key->key, EVP_PKEY_KEYPAIR, ¶ms);
|
||||
@@ -1986,10 +1989,18 @@ ssh_string pki_key_to_blob(const ssh_key key, enum ssh_key_e type)
|
||||
ssh_string_burn(d);
|
||||
SSH_STRING_FREE(d);
|
||||
d = NULL;
|
||||
} else if (key->type == SSH_KEYTYPE_SK_ECDSA) {
|
||||
} else if (type == SSH_KEY_PRIVATE &&
|
||||
key->type == SSH_KEYTYPE_SK_ECDSA) {
|
||||
|
||||
rc = pki_buffer_pack_sk_priv_data(buffer, key);
|
||||
if (rc == SSH_ERROR) {
|
||||
goto fail;
|
||||
}
|
||||
} else if (type == SSH_KEY_PUBLIC &&
|
||||
key->type == SSH_KEYTYPE_SK_ECDSA) {
|
||||
/* public key can contain certificate sk information */
|
||||
rc = ssh_buffer_add_ssh_string(buffer, key->sk_application);
|
||||
if (rc < 0) {
|
||||
if (rc != SSH_OK) {
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
@@ -2163,6 +2174,11 @@ ssh_string pki_signature_to_blob(const ssh_signature sig)
|
||||
sig_blob = pki_ecdsa_signature_to_blob(sig);
|
||||
break;
|
||||
#endif /* HAVE_OPENSSL_ECC */
|
||||
case SSH_KEYTYPE_SK_ECDSA:
|
||||
case SSH_KEYTYPE_SK_ED25519:
|
||||
/* For SK keys, signature data is already in raw_sig */
|
||||
sig_blob = ssh_string_copy(sig->raw_sig);
|
||||
break;
|
||||
default:
|
||||
case SSH_KEYTYPE_UNKNOWN:
|
||||
SSH_LOG(SSH_LOG_TRACE, "Unknown signature key type: %s", sig->type_c);
|
||||
|
||||
@@ -1155,17 +1155,10 @@ ssh_key pki_key_dup(const ssh_key key, int demote)
|
||||
|
||||
gcry_sexp_t curve = NULL;
|
||||
|
||||
new = ssh_key_new();
|
||||
new = pki_key_dup_common_init(key, demote);
|
||||
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;
|
||||
}
|
||||
|
||||
switch (key->type) {
|
||||
case SSH_KEYTYPE_RSA:
|
||||
@@ -1203,6 +1196,7 @@ ssh_key pki_key_dup(const ssh_key key, int demote)
|
||||
}
|
||||
break;
|
||||
case SSH_KEYTYPE_ED25519:
|
||||
case SSH_KEYTYPE_SK_ED25519:
|
||||
rc = pki_ed25519_key_dup(new, key);
|
||||
if (rc != SSH_OK) {
|
||||
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_P384:
|
||||
case SSH_KEYTYPE_ECDSA_P521:
|
||||
case SSH_KEYTYPE_SK_ECDSA:
|
||||
#ifdef HAVE_GCRYPT_ECC
|
||||
new->ecdsa_nid = key->ecdsa_nid;
|
||||
|
||||
@@ -1226,7 +1221,8 @@ ssh_key pki_key_dup(const ssh_key key, int demote)
|
||||
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,
|
||||
NULL,
|
||||
"(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;
|
||||
}
|
||||
|
||||
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) {
|
||||
return 1;
|
||||
}
|
||||
@@ -1604,9 +1600,21 @@ ssh_string pki_key_to_blob(const ssh_key key, enum ssh_key_e type)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
rc = pki_ed25519_private_key_to_blob(buffer, key);
|
||||
if (rc == SSH_ERROR) {
|
||||
goto fail;
|
||||
if (key->type == SSH_KEYTYPE_SK_ED25519) {
|
||||
rc = pki_ed25519_public_key_to_blob(buffer, key);
|
||||
if (rc == SSH_ERROR) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
rc = pki_buffer_pack_sk_priv_data(buffer, key);
|
||||
if (rc == SSH_ERROR) {
|
||||
goto fail;
|
||||
}
|
||||
} else {
|
||||
rc = pki_ed25519_private_key_to_blob(buffer, key);
|
||||
if (rc == SSH_ERROR) {
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -1644,7 +1652,7 @@ ssh_string pki_key_to_blob(const ssh_key key, enum ssh_key_e type)
|
||||
SSH_STRING_FREE(e);
|
||||
e = NULL;
|
||||
|
||||
if (type == SSH_KEY_PRIVATE) {
|
||||
if (type == SSH_KEY_PRIVATE && !is_sk_key_type(key->type)) {
|
||||
d = ssh_sexp_extract_mpi(key->ecdsa,
|
||||
"d",
|
||||
GCRYMPI_FMT_STD,
|
||||
@@ -1661,7 +1669,14 @@ ssh_string pki_key_to_blob(const ssh_key key, enum ssh_key_e type)
|
||||
ssh_string_burn(d);
|
||||
SSH_STRING_FREE(d);
|
||||
d = NULL;
|
||||
} else if (key->type == SSH_KEYTYPE_SK_ECDSA) {
|
||||
} else if (type == SSH_KEY_PRIVATE && is_sk_key_type(key->type)) {
|
||||
/* Add security key private data for SK_ECDSA */
|
||||
rc = pki_buffer_pack_sk_priv_data(buffer, key);
|
||||
if (rc == SSH_ERROR) {
|
||||
goto fail;
|
||||
}
|
||||
} else if (type == SSH_KEY_PUBLIC &&
|
||||
key->type == SSH_KEYTYPE_SK_ECDSA) {
|
||||
/* public key can contain certificate sk information */
|
||||
rc = ssh_buffer_add_ssh_string(buffer, key->sk_application);
|
||||
if (rc < 0) {
|
||||
@@ -1813,6 +1828,11 @@ ssh_string pki_signature_to_blob(const ssh_signature sig)
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
case SSH_KEYTYPE_SK_ECDSA:
|
||||
case SSH_KEYTYPE_SK_ED25519:
|
||||
/* For SK keys, signature data is already in raw_sig */
|
||||
sig_blob = ssh_string_copy(sig->raw_sig);
|
||||
break;
|
||||
case SSH_KEYTYPE_RSA1:
|
||||
case SSH_KEYTYPE_UNKNOWN:
|
||||
default:
|
||||
|
||||
@@ -380,19 +380,11 @@ ssh_key pki_key_dup(const ssh_key key, int demote)
|
||||
mbedtls_mpi Q;
|
||||
#endif
|
||||
|
||||
new = ssh_key_new();
|
||||
new = pki_key_dup_common_init(key, demote);
|
||||
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;
|
||||
}
|
||||
|
||||
#if MBEDTLS_VERSION_MAJOR > 2
|
||||
mbedtls_mpi_init(&N);
|
||||
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_P384:
|
||||
case SSH_KEYTYPE_ECDSA_P521:
|
||||
case SSH_KEYTYPE_SK_ECDSA:
|
||||
new->ecdsa_nid = key->ecdsa_nid;
|
||||
|
||||
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);
|
||||
|
||||
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),
|
||||
&key->ecdsa->MBEDTLS_PRIVATE(Q));
|
||||
if (rc != 0) {
|
||||
@@ -540,6 +534,7 @@ ssh_key pki_key_dup(const ssh_key key, int demote)
|
||||
|
||||
break;
|
||||
case SSH_KEYTYPE_ED25519:
|
||||
case SSH_KEYTYPE_SK_ED25519:
|
||||
rc = pki_ed25519_key_dup(new, key);
|
||||
if (rc != SSH_OK) {
|
||||
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;
|
||||
}
|
||||
|
||||
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),
|
||||
&ecdsa2->MBEDTLS_PRIVATE(d)))
|
||||
{
|
||||
@@ -1070,7 +1066,7 @@ ssh_string pki_key_to_blob(const ssh_key key, enum ssh_key_e type)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (type == SSH_KEY_PRIVATE) {
|
||||
if (type == SSH_KEY_PRIVATE && key->type != SSH_KEYTYPE_SK_ECDSA) {
|
||||
d = ssh_make_bignum_string(&key->ecdsa->MBEDTLS_PRIVATE(d));
|
||||
|
||||
if (d == NULL) {
|
||||
@@ -1082,7 +1078,14 @@ ssh_string pki_key_to_blob(const ssh_key key, enum ssh_key_e type)
|
||||
if (rc < 0) {
|
||||
goto out;
|
||||
}
|
||||
} else if (key->type == SSH_KEYTYPE_SK_ECDSA) {
|
||||
} else if (type == SSH_KEY_PRIVATE &&
|
||||
key->type == SSH_KEYTYPE_SK_ECDSA) {
|
||||
rc = pki_buffer_pack_sk_priv_data(buffer, key);
|
||||
if (rc != SSH_OK) {
|
||||
goto out;
|
||||
}
|
||||
} else if (type == SSH_KEY_PUBLIC &&
|
||||
key->type == SSH_KEYTYPE_SK_ECDSA) {
|
||||
/* public key can contain certificate sk information */
|
||||
rc = ssh_buffer_add_ssh_string(buffer, key->sk_application);
|
||||
if (rc < 0) {
|
||||
@@ -1105,9 +1108,21 @@ ssh_string pki_key_to_blob(const ssh_key key, enum ssh_key_e type)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
rc = pki_ed25519_private_key_to_blob(buffer, key);
|
||||
if (rc == SSH_ERROR) {
|
||||
goto out;
|
||||
if (key->type == SSH_KEYTYPE_SK_ED25519) {
|
||||
rc = pki_ed25519_public_key_to_blob(buffer, key);
|
||||
if (rc == SSH_ERROR) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = pki_buffer_pack_sk_priv_data(buffer, key);
|
||||
if (rc == SSH_ERROR) {
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
rc = pki_ed25519_private_key_to_blob(buffer, key);
|
||||
if (rc == SSH_ERROR) {
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -1219,6 +1234,11 @@ ssh_string pki_signature_to_blob(const ssh_signature sig)
|
||||
case SSH_KEYTYPE_ED25519:
|
||||
sig_blob = pki_ed25519_signature_to_blob(sig);
|
||||
break;
|
||||
case SSH_KEYTYPE_SK_ECDSA:
|
||||
case SSH_KEYTYPE_SK_ED25519:
|
||||
/* For SK keys, signature data is already in raw_sig */
|
||||
sig_blob = ssh_string_copy(sig->raw_sig);
|
||||
break;
|
||||
default:
|
||||
SSH_LOG(SSH_LOG_TRACE, "Unknown signature key type: %s",
|
||||
sig->type_c);
|
||||
|
||||
@@ -37,6 +37,7 @@ add_library(${TORTURE_LIBRARY}
|
||||
torture.c
|
||||
torture_key.c
|
||||
torture_pki.c
|
||||
torture_sk.c
|
||||
torture_cmocka.c)
|
||||
target_link_libraries(${TORTURE_LIBRARY} PRIVATE ${TORTURE_LINK_LIBRARIES})
|
||||
target_compile_options(${TORTURE_LIBRARY} PRIVATE
|
||||
@@ -77,6 +78,7 @@ if (CLIENT_TESTING)
|
||||
torture.c
|
||||
torture_key.c
|
||||
torture_pki.c
|
||||
torture_sk.c
|
||||
torture_cmocka.c
|
||||
)
|
||||
target_link_libraries(${TORTURE_SHARED_LIBRARY} PUBLIC
|
||||
|
||||
@@ -700,6 +700,37 @@ static const char torture_ecdsa521_testkey_cert[] =
|
||||
"PKJ0pHVLZEx3FMZI3SfwS9mVm+oojLkZ2hr8X0xn28zbN045d8daB7BB1mHMGNT+YA"
|
||||
"= ./ec521.pub";
|
||||
|
||||
static const char torture_ecdsa_sk_private_openssh_testkey[] =
|
||||
"-----BEGIN OPENSSH PRIVATE KEY-----\n"
|
||||
"b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAfwAAACJzay1lY2\n"
|
||||
"RzYS1zaGEyLW5pc3RwMjU2QG9wZW5zc2guY29tAAAACG5pc3RwMjU2AAAAQQRUfa1IVvak\n"
|
||||
"xFQZudDtXVlTtw6SiuAgfTpqZBuMdcK55kgy3o7V2z02/XClN1zpvSydzdjGWVgLj6WE9Q\n"
|
||||
"6xEOhQAAAABHNzaDoAAADoWSfkhlkn5IYAAAAic2stZWNkc2Etc2hhMi1uaXN0cDI1NkBv\n"
|
||||
"cGVuc3NoLmNvbQAAAAhuaXN0cDI1NgAAAEEEVH2tSFb2pMRUGbnQ7V1ZU7cOkorgIH06am\n"
|
||||
"QbjHXCueZIMt6O1ds9Nv1wpTdc6b0snc3YxllYC4+lhPUOsRDoUAAAAARzc2g6AQAAAEBS\n"
|
||||
"Smuf/sZP2WxVdlqgSMN7E8VLFdZI717mTi/svHahGy3wcFp2tPPylCaIG9aKAQrfVt+pOJ\n"
|
||||
"U+OPsm8rphRRM1AAAAAAAAABJwaG9lbml4QHBob2VuaXgtcGMBAg==\n"
|
||||
"-----END OPENSSH PRIVATE KEY-----\n";
|
||||
|
||||
static const char torture_ecdsa_sk_private_openssh_testkey_passphrase[] =
|
||||
"-----BEGIN OPENSSH PRIVATE KEY-----\n"
|
||||
"b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jdHIAAAAGYmNyeXB0AAAAGAAAABCzS672qr\n"
|
||||
"+0DRopx7VjkjCnAAAAGAAAAAEAAAB/AAAAInNrLWVjZHNhLXNoYTItbmlzdHAyNTZAb3Bl\n"
|
||||
"bnNzaC5jb20AAAAIbmlzdHAyNTYAAABBBFR9rUhW9qTEVBm50O1dWVO3DpKK4CB9OmpkG4\n"
|
||||
"x1wrnmSDLejtXbPTb9cKU3XOm9LJ3N2MZZWAuPpYT1DrEQ6FAAAAAEc3NoOgAAAPDoWSmM\n"
|
||||
"ki/XGLXidNxyLy2uRGejaZTOI3Ran10b7UF2ddRCrmBc6eVEXzgJ+BzB0sO0/uc1Q7QJhy\n"
|
||||
"fGR9bz1rvwJd5RpLLw9cSoTHbDiap4tkQu2snQt7AF/E6MOgQ3mvdhDDYoTYvxNIiwZTH1\n"
|
||||
"/Cxl2ZcRBKwSl6yp3JOxIVgttmJmNTqpt2U/uYwag9N1o6wxhWy1aamKZd1qHtPVC7MPL8\n"
|
||||
"/Q96mBlCEIe3vd4Hge4wgDa24F4Lwat7IA0/NGNFISIQH7x4VaGHAiTeMFL1NOVyw52xWr\n"
|
||||
"aAgXfkyplffxlB7ZfCf7RLsiCZDinMCE9y8=\n"
|
||||
"-----END OPENSSH PRIVATE KEY-----\n";
|
||||
|
||||
static const char torture_ecdsa_sk_public_testkey[] =
|
||||
"sk-ecdsa-sha2-nistp256@openssh.com "
|
||||
"AAAAInNrLWVjZHNhLXNoYTItbmlzdHAyNTZAb3BlbnNzaC5jb20AAAAIbmlzdHAyNTYAAABBBF"
|
||||
"R9rUhW9qTEVBm50O1dWVO3DpKK4CB9OmpkG4x1wrnmSDLejtXbPTb9cKU3XOm9LJ3N2MZZWAuP"
|
||||
"pYT1DrEQ6FAAAAAEc3NoOg== phoenix@phoenix-pc";
|
||||
|
||||
/****************************************************************************
|
||||
* ED25519 KEYS
|
||||
****************************************************************************/
|
||||
@@ -757,6 +788,35 @@ static const char torture_ed25519_testkey_cert[] =
|
||||
"d8AogGWM6njfejbazFVyfnjNiWqatx6IV3Nnqc3LjCiPY19fqIPe2YJSzytHwLTD5X"
|
||||
"IjD2bJpq2ZfjQwXpO0J ./ed.pub";
|
||||
|
||||
static const char torture_ed25519_sk_private_openssh_testkey[] =
|
||||
"-----BEGIN OPENSSH PRIVATE KEY-----\n"
|
||||
"b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAASgAAABpzay1zc2\n"
|
||||
"gtZWQyNTUxOUBvcGVuc3NoLmNvbQAAACCihqLlueARJOQCZMYRHefNkQ3WBHlhlUOuG7a/\n"
|
||||
"ivCkaQAAAARzc2g6AAAA+OivRKLor0SiAAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY2\n"
|
||||
"9tAAAAIKKGouW54BEk5AJkxhEd582RDdYEeWGVQ64btr+K8KRpAAAABHNzaDoBAAAAgNxc\n"
|
||||
"Q6pfw2S2fpCEB1UGO4Fy8O5gXZDbw3Vj8EHTcUDucNmk/iaI/GTPcUQK5cgPJH8AaB+lIZ\n"
|
||||
"GasyHd28mghgpaztG2cYmxrF3ZuvNdEZJecflgMOJDXZwoYvKpb7rZWjQgf8AeDy2u2dpl\n"
|
||||
"XCKHH8/LkJHdo4MABojarKofgaGzAAAAAAAAABJwaG9lbml4QHBob2VuaXgtcGMBAgMEBQ\n"
|
||||
"YH\n"
|
||||
"-----END OPENSSH PRIVATE KEY-----\n";
|
||||
|
||||
static const char torture_ed25519_sk_private_openssh_testkey_passphrase[] =
|
||||
"-----BEGIN OPENSSH PRIVATE KEY-----\n"
|
||||
"b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jdHIAAAAGYmNyeXB0AAAAGAAAABAkfYBhph\n"
|
||||
"EvYRpuOO6V4wihAAAAGAAAAAEAAABKAAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29t\n"
|
||||
"AAAAIKKGouW54BEk5AJkxhEd582RDdYEeWGVQ64btr+K8KRpAAAABHNzaDoAAAEA2WmpuB\n"
|
||||
"2ip0Bq4XJ9c2C33fE5twVYvK3WrJfAJKzih7bFXxbt5NmUFs121SD/x+3xZLwBJWGOIhdf\n"
|
||||
"idOD4gy9VWWAGCdJ0v87T/WaBYzEACr32hd99cD+Ki7VmmAxOKxx2/+/gg+WkbgygNns3c\n"
|
||||
"7YoYW5SSJm7WlhtmHFCKHtSh0fd8X1Q7gLHWTdd4B+3U9PyGpVgCKe2s2IOoTIcWOHlDW3\n"
|
||||
"KbEdlKELKCUEb0kof5m3hu8cktn0J/YIe1Y98YVjv472P6CO0Jw92jHSEPiTGn8JdSPkBY\n"
|
||||
"Qcoq18tszucoR2gp+sf5UvQhW8iOALDxO72Yq6HINAXNbpCB22U++GJw==\n"
|
||||
"-----END OPENSSH PRIVATE KEY-----\n";
|
||||
|
||||
static const char torture_ed25519_sk_public_testkey[] =
|
||||
"sk-ssh-ed25519@openssh.com "
|
||||
"AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAIKKGouW54BEk5AJkxhEd582RDdYEeW"
|
||||
"GVQ64btr+K8KRpAAAABHNzaDo= phoenix@phoenix-pc";
|
||||
|
||||
static const char *
|
||||
torture_get_testkey_public_internal(enum ssh_keytypes_e type,
|
||||
enum torture_format_e format)
|
||||
@@ -801,11 +861,19 @@ torture_get_testkey_public_internal(enum ssh_keytypes_e type,
|
||||
return torture_ecdsa521_testkey_cert;
|
||||
case SSH_KEYTYPE_ED25519_CERT01:
|
||||
return torture_ed25519_testkey_cert;
|
||||
case SSH_KEYTYPE_SK_ECDSA:
|
||||
if (format == FORMAT_OPENSSH) {
|
||||
return torture_ecdsa_sk_public_testkey;
|
||||
}
|
||||
return NULL;
|
||||
case SSH_KEYTYPE_SK_ED25519:
|
||||
if (format == FORMAT_OPENSSH) {
|
||||
return torture_ed25519_sk_public_testkey;
|
||||
}
|
||||
return NULL;
|
||||
case SSH_KEYTYPE_RSA1:
|
||||
case SSH_KEYTYPE_ECDSA:
|
||||
case SSH_KEYTYPE_SK_ECDSA:
|
||||
case SSH_KEYTYPE_SK_ECDSA_CERT01:
|
||||
case SSH_KEYTYPE_SK_ED25519:
|
||||
case SSH_KEYTYPE_SK_ED25519_CERT01:
|
||||
case SSH_KEYTYPE_UNKNOWN:
|
||||
return NULL;
|
||||
@@ -880,6 +948,26 @@ torture_get_testkey_encrypted_internal(enum ssh_keytypes_e type,
|
||||
return NULL;
|
||||
}
|
||||
return NULL;
|
||||
case SSH_KEYTYPE_SK_ECDSA:
|
||||
switch (format) {
|
||||
case FORMAT_OPENSSH:
|
||||
return torture_ecdsa_sk_private_openssh_testkey_passphrase;
|
||||
case FORMAT_PKCS8:
|
||||
case FORMAT_PEM:
|
||||
/* SK keys are not available in PKCS8 or PEM format */
|
||||
return NULL;
|
||||
}
|
||||
return NULL;
|
||||
case SSH_KEYTYPE_SK_ED25519:
|
||||
switch (format) {
|
||||
case FORMAT_OPENSSH:
|
||||
return torture_ed25519_sk_private_openssh_testkey_passphrase;
|
||||
case FORMAT_PKCS8:
|
||||
case FORMAT_PEM:
|
||||
/* SK keys are not available in PKCS8 or PEM format */
|
||||
return NULL;
|
||||
}
|
||||
return NULL;
|
||||
case SSH_KEYTYPE_DSS_CERT01:
|
||||
case SSH_KEYTYPE_RSA_CERT01:
|
||||
case SSH_KEYTYPE_ECDSA_P256_CERT01:
|
||||
@@ -888,9 +976,7 @@ torture_get_testkey_encrypted_internal(enum ssh_keytypes_e type,
|
||||
case SSH_KEYTYPE_ED25519_CERT01:
|
||||
case SSH_KEYTYPE_RSA1:
|
||||
case SSH_KEYTYPE_ECDSA:
|
||||
case SSH_KEYTYPE_SK_ECDSA:
|
||||
case SSH_KEYTYPE_SK_ECDSA_CERT01:
|
||||
case SSH_KEYTYPE_SK_ED25519:
|
||||
case SSH_KEYTYPE_SK_ED25519_CERT01:
|
||||
case SSH_KEYTYPE_UNKNOWN:
|
||||
return NULL;
|
||||
@@ -965,6 +1051,24 @@ torture_get_testkey_internal(enum ssh_keytypes_e type,
|
||||
return NULL;
|
||||
}
|
||||
return NULL;
|
||||
case SSH_KEYTYPE_SK_ECDSA:
|
||||
switch (format) {
|
||||
case FORMAT_OPENSSH:
|
||||
return torture_ecdsa_sk_private_openssh_testkey;
|
||||
case FORMAT_PKCS8:
|
||||
case FORMAT_PEM:
|
||||
return NULL;
|
||||
}
|
||||
return NULL;
|
||||
case SSH_KEYTYPE_SK_ED25519:
|
||||
switch (format) {
|
||||
case FORMAT_OPENSSH:
|
||||
return torture_ed25519_sk_private_openssh_testkey;
|
||||
case FORMAT_PKCS8:
|
||||
case FORMAT_PEM:
|
||||
return NULL;
|
||||
}
|
||||
return NULL;
|
||||
case SSH_KEYTYPE_DSS_CERT01:
|
||||
case SSH_KEYTYPE_RSA_CERT01:
|
||||
case SSH_KEYTYPE_ECDSA_P256_CERT01:
|
||||
@@ -973,9 +1077,7 @@ torture_get_testkey_internal(enum ssh_keytypes_e type,
|
||||
case SSH_KEYTYPE_ED25519_CERT01:
|
||||
case SSH_KEYTYPE_RSA1:
|
||||
case SSH_KEYTYPE_ECDSA:
|
||||
case SSH_KEYTYPE_SK_ECDSA:
|
||||
case SSH_KEYTYPE_SK_ECDSA_CERT01:
|
||||
case SSH_KEYTYPE_SK_ED25519:
|
||||
case SSH_KEYTYPE_SK_ED25519_CERT01:
|
||||
case SSH_KEYTYPE_UNKNOWN:
|
||||
return NULL;
|
||||
|
||||
96
tests/torture_sk.c
Normal file
96
tests/torture_sk.c
Normal file
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* torture_sk.c - torture library for testing security keys
|
||||
*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2025 Praneeth Sarode <praneethsarode@gmail.com>
|
||||
*
|
||||
* The SSH Library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* The SSH Library is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with the SSH Library; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
* MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "torture_sk.h"
|
||||
#include "libssh/pki.h"
|
||||
#include "torture.h"
|
||||
|
||||
/* Helper function to validate ssh_key structure for security keys */
|
||||
void assert_sk_key_valid(ssh_key key,
|
||||
enum ssh_keytypes_e expected_type,
|
||||
bool private)
|
||||
{
|
||||
char *app_str = NULL;
|
||||
const char *expected_type_str = NULL;
|
||||
|
||||
assert_non_null(key);
|
||||
assert_true(is_sk_key_type(expected_type));
|
||||
assert_int_equal(key->type, expected_type);
|
||||
|
||||
if (private) {
|
||||
assert_int_equal(key->flags,
|
||||
SSH_KEY_FLAG_PRIVATE | SSH_KEY_FLAG_PUBLIC);
|
||||
} else {
|
||||
assert_int_equal(key->flags, SSH_KEY_FLAG_PUBLIC);
|
||||
}
|
||||
|
||||
expected_type_str = ssh_key_type_to_char(expected_type);
|
||||
assert_non_null(expected_type_str);
|
||||
|
||||
assert_non_null(key->type_c);
|
||||
assert_string_equal(key->type_c, expected_type_str);
|
||||
|
||||
/* Validate security key specific fields */
|
||||
assert_non_null(key->sk_application);
|
||||
|
||||
/* Validate application string format and content */
|
||||
app_str = ssh_string_to_char(key->sk_application);
|
||||
assert_non_null(app_str);
|
||||
|
||||
assert_true(ssh_string_len(key->sk_application) >= 4);
|
||||
assert_true(strncmp(app_str, "ssh:", 4) == 0);
|
||||
ssh_string_free_char(app_str);
|
||||
|
||||
if (private) {
|
||||
assert_non_null(key->sk_key_handle);
|
||||
assert_true(ssh_string_len(key->sk_key_handle) > 0);
|
||||
}
|
||||
|
||||
/* TODO: Check for sk_flags */
|
||||
|
||||
/* Validate underlying cryptographic key exists based on type */
|
||||
switch (expected_type) {
|
||||
case SSH_KEYTYPE_SK_ECDSA:
|
||||
#if defined(HAVE_LIBGCRYPT)
|
||||
assert_non_null(key->ecdsa);
|
||||
#elif defined(HAVE_LIBMBEDCRYPTO)
|
||||
assert_non_null(key->ecdsa);
|
||||
#elif defined(HAVE_LIBCRYPTO)
|
||||
assert_non_null(key->key);
|
||||
#endif
|
||||
break;
|
||||
|
||||
case SSH_KEYTYPE_SK_ED25519:
|
||||
#if defined(HAVE_LIBCRYPTO)
|
||||
assert_non_null(key->key);
|
||||
#elif !defined(HAVE_LIBCRYPTO)
|
||||
assert_non_null(key->ed25519_pubkey);
|
||||
#endif
|
||||
break;
|
||||
|
||||
default:
|
||||
/* Should not reach here */
|
||||
assert_true(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
40
tests/torture_sk.h
Normal file
40
tests/torture_sk.h
Normal file
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* torture_sk.h - torture library for testing security keys
|
||||
*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2025 Praneeth Sarode <praneethsarode@gmail.com>
|
||||
*
|
||||
* The SSH Library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* The SSH Library is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with the SSH Library; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
* MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef _TORTURE_SK_H
|
||||
#define _TORTURE_SK_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#define LIBSSH_STATIC
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "torture.h"
|
||||
#include "torture_pki.h"
|
||||
|
||||
void assert_sk_key_valid(ssh_key key,
|
||||
enum ssh_keytypes_e expected_type,
|
||||
bool private);
|
||||
|
||||
#endif /* _TORTURE_SK_H */
|
||||
@@ -47,6 +47,7 @@ if (UNIX AND NOT WIN32)
|
||||
torture_pki_rsa
|
||||
torture_pki_dsa
|
||||
torture_pki_ed25519
|
||||
torture_pki_sk_ed25519
|
||||
torture_pki_sshsig
|
||||
# requires /dev/null
|
||||
torture_channel
|
||||
@@ -91,6 +92,7 @@ if (UNIX AND NOT WIN32)
|
||||
set(LIBSSH_UNIT_TESTS
|
||||
${LIBSSH_UNIT_TESTS}
|
||||
torture_pki_ecdsa
|
||||
torture_pki_sk_ecdsa
|
||||
)
|
||||
endif()
|
||||
|
||||
|
||||
487
tests/unittests/torture_pki_sk_ecdsa.c
Normal file
487
tests/unittests/torture_pki_sk_ecdsa.c
Normal file
@@ -0,0 +1,487 @@
|
||||
/*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2025 Praneeth Sarode <praneethsarode@gmail.com>
|
||||
*
|
||||
* The SSH Library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* The SSH Library is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with the SSH Library; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
* MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#define LIBSSH_STATIC
|
||||
|
||||
#include "pki.c"
|
||||
#include "torture.h"
|
||||
#include "torture_key.h"
|
||||
#include "torture_pki.h"
|
||||
#include "torture_sk.h"
|
||||
|
||||
/* Test constants */
|
||||
#define LIBSSH_SK_ECDSA_TESTKEY "libssh_testkey.id_ecdsa_sk"
|
||||
#define LIBSSH_SK_ECDSA_TESTKEY_PASSPHRASE \
|
||||
"libssh_testkey_passphrase.id_ecdsa_sk"
|
||||
|
||||
const char template[] = "temp_dir_XXXXXX";
|
||||
|
||||
struct pki_st {
|
||||
char *cwd;
|
||||
char *temp_dir;
|
||||
};
|
||||
|
||||
static int setup_sk_ecdsa_key(void **state)
|
||||
{
|
||||
const char *keystring = NULL;
|
||||
struct pki_st *test_state = NULL;
|
||||
char *cwd = NULL;
|
||||
char *tmp_dir = NULL;
|
||||
int rc = 0;
|
||||
|
||||
test_state = (struct pki_st *)malloc(sizeof(struct pki_st));
|
||||
assert_non_null(test_state);
|
||||
|
||||
cwd = torture_get_current_working_dir();
|
||||
assert_non_null(cwd);
|
||||
|
||||
tmp_dir = torture_make_temp_dir(template);
|
||||
assert_non_null(tmp_dir);
|
||||
|
||||
test_state->cwd = cwd;
|
||||
test_state->temp_dir = tmp_dir;
|
||||
|
||||
*state = test_state;
|
||||
|
||||
rc = torture_change_dir(tmp_dir);
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
printf("Changed directory to: %s\n", tmp_dir);
|
||||
|
||||
keystring = torture_get_openssh_testkey(SSH_KEYTYPE_SK_ECDSA, 0);
|
||||
torture_write_file(LIBSSH_SK_ECDSA_TESTKEY, keystring);
|
||||
|
||||
keystring = torture_get_openssh_testkey(SSH_KEYTYPE_SK_ECDSA, 1);
|
||||
torture_write_file(LIBSSH_SK_ECDSA_TESTKEY_PASSPHRASE, keystring);
|
||||
|
||||
keystring = torture_get_testkey_pub(SSH_KEYTYPE_SK_ECDSA);
|
||||
torture_write_file(LIBSSH_SK_ECDSA_TESTKEY ".pub", keystring);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int teardown(void **state)
|
||||
{
|
||||
struct pki_st *test_state = NULL;
|
||||
int rc = 0;
|
||||
|
||||
test_state = *((struct pki_st **)state);
|
||||
|
||||
assert_non_null(test_state);
|
||||
assert_non_null(test_state->cwd);
|
||||
assert_non_null(test_state->temp_dir);
|
||||
|
||||
rc = torture_change_dir(test_state->cwd);
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
rc = torture_rmdirs(test_state->temp_dir);
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
SAFE_FREE(test_state->temp_dir);
|
||||
SAFE_FREE(test_state->cwd);
|
||||
SAFE_FREE(test_state);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void torture_pki_sk_ecdsa_import_pubkey_file(void **state)
|
||||
{
|
||||
ssh_key pubkey = NULL;
|
||||
int rc;
|
||||
|
||||
(void)state; /* unused */
|
||||
|
||||
rc = ssh_pki_import_pubkey_file(LIBSSH_SK_ECDSA_TESTKEY ".pub", &pubkey);
|
||||
assert_return_code(rc, errno);
|
||||
assert_sk_key_valid(pubkey, SSH_KEYTYPE_SK_ECDSA, false);
|
||||
|
||||
SSH_KEY_FREE(pubkey);
|
||||
}
|
||||
|
||||
static void
|
||||
torture_pki_sk_ecdsa_import_pubkey_from_openssh_privkey(void **state)
|
||||
{
|
||||
ssh_key pubkey = NULL;
|
||||
int rc;
|
||||
|
||||
(void)state; /* unused */
|
||||
|
||||
rc =
|
||||
ssh_pki_import_pubkey_file(LIBSSH_SK_ECDSA_TESTKEY_PASSPHRASE, &pubkey);
|
||||
assert_return_code(rc, errno);
|
||||
assert_non_null(pubkey);
|
||||
assert_sk_key_valid(pubkey, SSH_KEYTYPE_SK_ECDSA, false);
|
||||
|
||||
SSH_KEY_FREE(pubkey);
|
||||
}
|
||||
|
||||
static void torture_pki_sk_ecdsa_import_privkey_base64(void **state)
|
||||
{
|
||||
ssh_key privkey = NULL;
|
||||
char *keystring = NULL;
|
||||
int rc;
|
||||
|
||||
(void)state; /* unused */
|
||||
|
||||
keystring = torture_pki_read_file(LIBSSH_SK_ECDSA_TESTKEY);
|
||||
assert_non_null(keystring);
|
||||
|
||||
rc = ssh_pki_import_privkey_base64(keystring,
|
||||
NULL, /* no passphrase */
|
||||
NULL, /* no auth callback */
|
||||
NULL, /* no auth data */
|
||||
&privkey);
|
||||
assert_return_code(rc, errno);
|
||||
assert_sk_key_valid(privkey, SSH_KEYTYPE_SK_ECDSA, true);
|
||||
|
||||
SAFE_FREE(keystring);
|
||||
SSH_KEY_FREE(privkey);
|
||||
}
|
||||
|
||||
static void torture_pki_sk_ecdsa_import_privkey_base64_comment(void **state)
|
||||
{
|
||||
int rc, file_str_len;
|
||||
const char *comment_str = "#this is line-comment\n#this is another\n";
|
||||
char *file_str = NULL;
|
||||
ssh_key key = NULL;
|
||||
char *keystring = NULL;
|
||||
|
||||
(void)state; /* unused */
|
||||
|
||||
keystring = torture_pki_read_file(LIBSSH_SK_ECDSA_TESTKEY);
|
||||
assert_non_null(keystring);
|
||||
|
||||
file_str_len = strlen(comment_str) + strlen(keystring) + 1;
|
||||
file_str = malloc(file_str_len);
|
||||
assert_non_null(file_str);
|
||||
rc = snprintf(file_str, file_str_len, "%s%s", comment_str, keystring);
|
||||
assert_int_equal(rc, file_str_len - 1);
|
||||
|
||||
rc = ssh_pki_import_privkey_base64(file_str, NULL, NULL, NULL, &key);
|
||||
assert_return_code(rc, errno);
|
||||
assert_sk_key_valid(key, SSH_KEYTYPE_SK_ECDSA, true);
|
||||
|
||||
SAFE_FREE(keystring);
|
||||
SAFE_FREE(file_str);
|
||||
SSH_KEY_FREE(key);
|
||||
}
|
||||
|
||||
static void torture_pki_sk_ecdsa_import_privkey_base64_whitespace(void **state)
|
||||
{
|
||||
int rc, file_str_len;
|
||||
const char *whitespace_str = " \t\t\t\n\n\n";
|
||||
char *file_str = NULL;
|
||||
ssh_key key = NULL;
|
||||
char *keystring = NULL;
|
||||
|
||||
(void)state; /* unused */
|
||||
|
||||
keystring = torture_pki_read_file(LIBSSH_SK_ECDSA_TESTKEY);
|
||||
assert_non_null(keystring);
|
||||
|
||||
file_str_len = 2 * strlen(whitespace_str) + strlen(keystring) + 1;
|
||||
file_str = malloc(file_str_len);
|
||||
assert_non_null(file_str);
|
||||
rc = snprintf(file_str,
|
||||
file_str_len,
|
||||
"%s%s%s",
|
||||
whitespace_str,
|
||||
keystring,
|
||||
whitespace_str);
|
||||
assert_int_equal(rc, file_str_len - 1);
|
||||
|
||||
rc = ssh_pki_import_privkey_base64(file_str, NULL, NULL, NULL, &key);
|
||||
assert_return_code(rc, errno);
|
||||
assert_sk_key_valid(key, SSH_KEYTYPE_SK_ECDSA, true);
|
||||
|
||||
SAFE_FREE(keystring);
|
||||
SAFE_FREE(file_str);
|
||||
SSH_KEY_FREE(key);
|
||||
}
|
||||
|
||||
static void torture_pki_sk_ecdsa_import_export_privkey_base64(void **state)
|
||||
{
|
||||
ssh_key origkey = NULL;
|
||||
ssh_key privkey = NULL;
|
||||
char *key_buf = NULL;
|
||||
const char *keystring = NULL;
|
||||
int rc;
|
||||
|
||||
(void)state; /* unused */
|
||||
|
||||
keystring = torture_get_openssh_testkey(SSH_KEYTYPE_SK_ECDSA, 0);
|
||||
assert_non_null(keystring);
|
||||
|
||||
rc = ssh_pki_import_privkey_base64(keystring, NULL, NULL, NULL, &origkey);
|
||||
assert_return_code(rc, errno);
|
||||
assert_sk_key_valid(origkey, SSH_KEYTYPE_SK_ECDSA, true);
|
||||
|
||||
rc = ssh_pki_export_privkey_base64(origkey, NULL, NULL, NULL, &key_buf);
|
||||
assert_return_code(rc, errno);
|
||||
assert_non_null(key_buf);
|
||||
|
||||
rc = ssh_pki_import_privkey_base64(key_buf, NULL, NULL, NULL, &privkey);
|
||||
assert_return_code(rc, errno);
|
||||
assert_sk_key_valid(privkey, SSH_KEYTYPE_SK_ECDSA, true);
|
||||
|
||||
rc = ssh_key_cmp(origkey, privkey, SSH_KEY_CMP_PRIVATE);
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
SSH_KEY_FREE(origkey);
|
||||
SSH_KEY_FREE(privkey);
|
||||
SSH_STRING_FREE_CHAR(key_buf);
|
||||
}
|
||||
|
||||
static void torture_pki_sk_ecdsa_publickey_from_privatekey(void **state)
|
||||
{
|
||||
ssh_key privkey = NULL;
|
||||
ssh_key pubkey = NULL;
|
||||
const char *keystring = NULL;
|
||||
int rc;
|
||||
|
||||
(void)state; /* unused */
|
||||
|
||||
keystring = torture_get_openssh_testkey(SSH_KEYTYPE_SK_ECDSA, 0);
|
||||
assert_non_null(keystring);
|
||||
|
||||
rc = ssh_pki_import_privkey_base64(keystring,
|
||||
NULL, /* no passphrase */
|
||||
NULL, /* no auth callback */
|
||||
NULL, /* no auth data */
|
||||
&privkey);
|
||||
assert_return_code(rc, errno);
|
||||
assert_sk_key_valid(privkey, SSH_KEYTYPE_SK_ECDSA, true);
|
||||
|
||||
rc = ssh_pki_export_privkey_to_pubkey(privkey, &pubkey);
|
||||
assert_return_code(rc, errno);
|
||||
assert_sk_key_valid(pubkey, SSH_KEYTYPE_SK_ECDSA, false);
|
||||
|
||||
rc = ssh_key_cmp(privkey, pubkey, SSH_KEY_CMP_PUBLIC);
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
SSH_KEY_FREE(privkey);
|
||||
SSH_KEY_FREE(pubkey);
|
||||
}
|
||||
|
||||
static void torture_pki_sk_ecdsa_import_privkey_base64_passphrase(void **state)
|
||||
{
|
||||
ssh_key privkey = NULL;
|
||||
const char *keystring = NULL;
|
||||
const char *passphrase = NULL;
|
||||
int rc;
|
||||
|
||||
(void)state; /* unused */
|
||||
|
||||
keystring = torture_get_openssh_testkey(SSH_KEYTYPE_SK_ECDSA, 1);
|
||||
assert_non_null(keystring);
|
||||
|
||||
passphrase = torture_get_testkey_passphrase();
|
||||
assert_non_null(passphrase);
|
||||
|
||||
/* Import with a passphrase */
|
||||
rc = ssh_pki_import_privkey_base64(keystring,
|
||||
passphrase,
|
||||
NULL,
|
||||
NULL,
|
||||
&privkey);
|
||||
assert_return_code(rc, errno);
|
||||
assert_sk_key_valid(privkey, SSH_KEYTYPE_SK_ECDSA, true);
|
||||
SSH_KEY_FREE(privkey);
|
||||
|
||||
rc = ssh_pki_import_privkey_base64(keystring,
|
||||
"wrong passphrase",
|
||||
NULL,
|
||||
NULL,
|
||||
&privkey);
|
||||
assert_int_equal(rc, SSH_ERROR);
|
||||
assert_null(privkey);
|
||||
}
|
||||
|
||||
static void torture_pki_sk_ecdsa_duplicate_key(void **state)
|
||||
{
|
||||
ssh_key privkey = NULL;
|
||||
ssh_key duplicated = NULL;
|
||||
const char *keystring = NULL;
|
||||
int rc;
|
||||
|
||||
(void)state; /* unused */
|
||||
|
||||
keystring = torture_get_openssh_testkey(SSH_KEYTYPE_SK_ECDSA, 0);
|
||||
assert_non_null(keystring);
|
||||
|
||||
rc = ssh_pki_import_privkey_base64(keystring,
|
||||
NULL, /* no passphrase */
|
||||
NULL, /* no auth callback */
|
||||
NULL, /* no auth data */
|
||||
&privkey);
|
||||
assert_return_code(rc, errno);
|
||||
assert_sk_key_valid(privkey, SSH_KEYTYPE_SK_ECDSA, true);
|
||||
|
||||
duplicated = ssh_key_dup(privkey);
|
||||
assert_sk_key_valid(duplicated, SSH_KEYTYPE_SK_ECDSA, true);
|
||||
|
||||
rc = ssh_key_cmp(privkey, duplicated, SSH_KEY_CMP_PRIVATE);
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
SSH_KEY_FREE(privkey);
|
||||
SSH_KEY_FREE(duplicated);
|
||||
}
|
||||
|
||||
static void torture_pki_sk_ecdsa_import_pubkey_base64(void **state)
|
||||
{
|
||||
ssh_key key = NULL;
|
||||
ssh_key pubkey = NULL;
|
||||
char *b64_key = NULL;
|
||||
const char *keystring = NULL;
|
||||
int rc;
|
||||
|
||||
(void)state; /* unused */
|
||||
|
||||
keystring = torture_get_openssh_testkey(SSH_KEYTYPE_SK_ECDSA, 0);
|
||||
assert_non_null(keystring);
|
||||
|
||||
/* Import private key to extract public key */
|
||||
rc = ssh_pki_import_privkey_base64(keystring, NULL, NULL, NULL, &key);
|
||||
assert_return_code(rc, errno);
|
||||
assert_sk_key_valid(key, SSH_KEYTYPE_SK_ECDSA, true);
|
||||
|
||||
rc = ssh_pki_export_privkey_to_pubkey(key, &pubkey);
|
||||
assert_return_code(rc, errno);
|
||||
assert_sk_key_valid(pubkey, SSH_KEYTYPE_SK_ECDSA, false);
|
||||
|
||||
/* Export public key to base64 */
|
||||
rc = ssh_pki_export_pubkey_base64(pubkey, &b64_key);
|
||||
assert_return_code(rc, errno);
|
||||
assert_non_null(b64_key);
|
||||
|
||||
SSH_KEY_FREE(key);
|
||||
SSH_KEY_FREE(pubkey);
|
||||
|
||||
/* Import public key from base64 */
|
||||
rc = ssh_pki_import_pubkey_base64(b64_key, SSH_KEYTYPE_SK_ECDSA, &pubkey);
|
||||
assert_return_code(rc, errno);
|
||||
assert_sk_key_valid(pubkey, SSH_KEYTYPE_SK_ECDSA, false);
|
||||
|
||||
SSH_KEY_FREE(pubkey);
|
||||
SSH_STRING_FREE_CHAR(b64_key);
|
||||
}
|
||||
|
||||
static void torture_pki_sk_ecdsa_pubkey_blob(void **state)
|
||||
{
|
||||
ssh_key privkey = NULL;
|
||||
ssh_key pubkey = NULL;
|
||||
ssh_key imported_pubkey = NULL;
|
||||
ssh_string pub_blob = NULL;
|
||||
const char *keystring = NULL;
|
||||
int rc;
|
||||
|
||||
(void)state; /* unused */
|
||||
|
||||
keystring = torture_get_openssh_testkey(SSH_KEYTYPE_SK_ECDSA, 0);
|
||||
assert_non_null(keystring);
|
||||
|
||||
rc = ssh_pki_import_privkey_base64(keystring, NULL, NULL, NULL, &privkey);
|
||||
assert_return_code(rc, errno);
|
||||
assert_sk_key_valid(privkey, SSH_KEYTYPE_SK_ECDSA, true);
|
||||
|
||||
rc = ssh_pki_export_privkey_to_pubkey(privkey, &pubkey);
|
||||
assert_return_code(rc, errno);
|
||||
assert_sk_key_valid(pubkey, SSH_KEYTYPE_SK_ECDSA, false);
|
||||
|
||||
/* Export public key to blob */
|
||||
rc = ssh_pki_export_pubkey_blob(pubkey, &pub_blob);
|
||||
assert_int_equal(rc, SSH_OK);
|
||||
assert_non_null(pub_blob);
|
||||
|
||||
/* Import public key from blob */
|
||||
rc = ssh_pki_import_pubkey_blob(pub_blob, &imported_pubkey);
|
||||
assert_int_equal(rc, SSH_OK);
|
||||
assert_sk_key_valid(imported_pubkey, SSH_KEYTYPE_SK_ECDSA, false);
|
||||
|
||||
/* Compare keys */
|
||||
rc = ssh_key_cmp(pubkey, imported_pubkey, SSH_KEY_CMP_PUBLIC);
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
ssh_string_free(pub_blob);
|
||||
SSH_KEY_FREE(privkey);
|
||||
SSH_KEY_FREE(pubkey);
|
||||
SSH_KEY_FREE(imported_pubkey);
|
||||
}
|
||||
|
||||
int torture_run_tests(void)
|
||||
{
|
||||
int rc;
|
||||
|
||||
struct CMUnitTest tests[] = {
|
||||
cmocka_unit_test_setup_teardown(torture_pki_sk_ecdsa_import_pubkey_file,
|
||||
setup_sk_ecdsa_key,
|
||||
teardown),
|
||||
cmocka_unit_test_setup_teardown(
|
||||
torture_pki_sk_ecdsa_import_pubkey_from_openssh_privkey,
|
||||
setup_sk_ecdsa_key,
|
||||
teardown),
|
||||
cmocka_unit_test_setup_teardown(
|
||||
torture_pki_sk_ecdsa_import_privkey_base64,
|
||||
setup_sk_ecdsa_key,
|
||||
teardown),
|
||||
cmocka_unit_test_setup_teardown(
|
||||
torture_pki_sk_ecdsa_import_privkey_base64_comment,
|
||||
setup_sk_ecdsa_key,
|
||||
teardown),
|
||||
cmocka_unit_test_setup_teardown(
|
||||
torture_pki_sk_ecdsa_import_privkey_base64_whitespace,
|
||||
setup_sk_ecdsa_key,
|
||||
teardown),
|
||||
cmocka_unit_test_setup_teardown(
|
||||
torture_pki_sk_ecdsa_import_export_privkey_base64,
|
||||
setup_sk_ecdsa_key,
|
||||
teardown),
|
||||
cmocka_unit_test_setup_teardown(
|
||||
torture_pki_sk_ecdsa_publickey_from_privatekey,
|
||||
setup_sk_ecdsa_key,
|
||||
teardown),
|
||||
cmocka_unit_test_setup_teardown(
|
||||
torture_pki_sk_ecdsa_import_pubkey_base64,
|
||||
setup_sk_ecdsa_key,
|
||||
teardown),
|
||||
cmocka_unit_test_setup_teardown(
|
||||
torture_pki_sk_ecdsa_import_privkey_base64_passphrase,
|
||||
setup_sk_ecdsa_key,
|
||||
teardown),
|
||||
cmocka_unit_test_setup_teardown(torture_pki_sk_ecdsa_duplicate_key,
|
||||
setup_sk_ecdsa_key,
|
||||
teardown),
|
||||
|
||||
cmocka_unit_test_setup_teardown(torture_pki_sk_ecdsa_pubkey_blob,
|
||||
setup_sk_ecdsa_key,
|
||||
teardown),
|
||||
|
||||
};
|
||||
|
||||
ssh_init();
|
||||
torture_filter_tests(tests);
|
||||
rc = cmocka_run_group_tests(tests, NULL, NULL);
|
||||
ssh_finalize();
|
||||
|
||||
return rc;
|
||||
}
|
||||
543
tests/unittests/torture_pki_sk_ed25519.c
Normal file
543
tests/unittests/torture_pki_sk_ed25519.c
Normal file
@@ -0,0 +1,543 @@
|
||||
/*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2025 Praneeth Sarode <praneethsarode@gmail.com>
|
||||
*
|
||||
* The SSH Library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* The SSH Library is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with the SSH Library; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
* MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#define LIBSSH_STATIC
|
||||
|
||||
#include "pki.c"
|
||||
#include "torture.h"
|
||||
#include "torture_key.h"
|
||||
#include "torture_pki.h"
|
||||
#include "torture_sk.h"
|
||||
|
||||
/* Test constants */
|
||||
#define LIBSSH_SK_ED25519_TESTKEY "libssh_testkey.id_ed25519_sk"
|
||||
#define LIBSSH_SK_ED25519_TESTKEY_PASSPHRASE \
|
||||
"libssh_testkey_passphrase.id_ed25519_sk"
|
||||
|
||||
const char template[] = "temp_dir_XXXXXX";
|
||||
|
||||
struct pki_st {
|
||||
char *cwd;
|
||||
char *temp_dir;
|
||||
};
|
||||
|
||||
static int setup_sk_ed25519_key(void **state)
|
||||
{
|
||||
const char *keystring = NULL;
|
||||
struct pki_st *test_state = NULL;
|
||||
char *cwd = NULL;
|
||||
char *tmp_dir = NULL;
|
||||
int rc = 0;
|
||||
|
||||
test_state = (struct pki_st *)malloc(sizeof(struct pki_st));
|
||||
assert_non_null(test_state);
|
||||
|
||||
cwd = torture_get_current_working_dir();
|
||||
assert_non_null(cwd);
|
||||
|
||||
tmp_dir = torture_make_temp_dir(template);
|
||||
assert_non_null(tmp_dir);
|
||||
|
||||
test_state->cwd = cwd;
|
||||
test_state->temp_dir = tmp_dir;
|
||||
|
||||
*state = test_state;
|
||||
|
||||
rc = torture_change_dir(tmp_dir);
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
printf("Changed directory to: %s\n", tmp_dir);
|
||||
|
||||
keystring = torture_get_openssh_testkey(SSH_KEYTYPE_SK_ED25519, 0);
|
||||
torture_write_file(LIBSSH_SK_ED25519_TESTKEY, keystring);
|
||||
|
||||
keystring = torture_get_openssh_testkey(SSH_KEYTYPE_SK_ED25519, 1);
|
||||
torture_write_file(LIBSSH_SK_ED25519_TESTKEY_PASSPHRASE, keystring);
|
||||
|
||||
keystring = torture_get_testkey_pub(SSH_KEYTYPE_SK_ED25519);
|
||||
torture_write_file(LIBSSH_SK_ED25519_TESTKEY ".pub", keystring);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int teardown(void **state)
|
||||
{
|
||||
struct pki_st *test_state = NULL;
|
||||
int rc = 0;
|
||||
|
||||
test_state = *((struct pki_st **)state);
|
||||
|
||||
assert_non_null(test_state);
|
||||
assert_non_null(test_state->cwd);
|
||||
assert_non_null(test_state->temp_dir);
|
||||
|
||||
rc = torture_change_dir(test_state->cwd);
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
rc = torture_rmdirs(test_state->temp_dir);
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
SAFE_FREE(test_state->temp_dir);
|
||||
SAFE_FREE(test_state->cwd);
|
||||
SAFE_FREE(test_state);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void torture_pki_sk_ed25519_import_pubkey_file(void **state)
|
||||
{
|
||||
ssh_key pubkey = NULL;
|
||||
int rc;
|
||||
|
||||
(void)state; /* unused */
|
||||
|
||||
/* Skip test if in FIPS mode */
|
||||
if (ssh_fips_mode()) {
|
||||
skip();
|
||||
}
|
||||
|
||||
rc = ssh_pki_import_pubkey_file(LIBSSH_SK_ED25519_TESTKEY ".pub", &pubkey);
|
||||
assert_return_code(rc, errno);
|
||||
assert_sk_key_valid(pubkey, SSH_KEYTYPE_SK_ED25519, false);
|
||||
|
||||
SSH_KEY_FREE(pubkey);
|
||||
}
|
||||
|
||||
static void
|
||||
torture_pki_sk_ed25519_import_pubkey_from_openssh_privkey(void **state)
|
||||
{
|
||||
ssh_key pubkey = NULL;
|
||||
int rc;
|
||||
|
||||
(void)state; /* unused */
|
||||
|
||||
/* Skip test if in FIPS mode */
|
||||
if (ssh_fips_mode()) {
|
||||
skip();
|
||||
}
|
||||
|
||||
rc = ssh_pki_import_pubkey_file(LIBSSH_SK_ED25519_TESTKEY_PASSPHRASE,
|
||||
&pubkey);
|
||||
assert_return_code(rc, errno);
|
||||
assert_non_null(pubkey);
|
||||
assert_sk_key_valid(pubkey, SSH_KEYTYPE_SK_ED25519, false);
|
||||
|
||||
SSH_KEY_FREE(pubkey);
|
||||
}
|
||||
|
||||
static void torture_pki_sk_ed25519_import_privkey_base64(void **state)
|
||||
{
|
||||
ssh_key privkey = NULL;
|
||||
char *keystring = NULL;
|
||||
int rc;
|
||||
|
||||
(void)state; /* unused */
|
||||
|
||||
/* Skip test if in FIPS mode */
|
||||
if (ssh_fips_mode()) {
|
||||
skip();
|
||||
}
|
||||
|
||||
keystring = torture_pki_read_file(LIBSSH_SK_ED25519_TESTKEY);
|
||||
assert_non_null(keystring);
|
||||
|
||||
rc = ssh_pki_import_privkey_base64(keystring,
|
||||
NULL, /* no passphrase */
|
||||
NULL, /* no auth callback */
|
||||
NULL, /* no auth data */
|
||||
&privkey);
|
||||
assert_return_code(rc, errno);
|
||||
assert_sk_key_valid(privkey, SSH_KEYTYPE_SK_ED25519, true);
|
||||
|
||||
SAFE_FREE(keystring);
|
||||
SSH_KEY_FREE(privkey);
|
||||
}
|
||||
|
||||
static void torture_pki_sk_ed25519_import_privkey_base64_comment(void **state)
|
||||
{
|
||||
int rc, file_str_len;
|
||||
const char *comment_str = "#this is line-comment\n#this is another\n";
|
||||
char *file_str = NULL;
|
||||
ssh_key key = NULL;
|
||||
char *keystring = NULL;
|
||||
|
||||
(void)state; /* unused */
|
||||
|
||||
/* Skip test if in FIPS mode */
|
||||
if (ssh_fips_mode()) {
|
||||
skip();
|
||||
}
|
||||
|
||||
keystring = torture_pki_read_file(LIBSSH_SK_ED25519_TESTKEY);
|
||||
assert_non_null(keystring);
|
||||
|
||||
file_str_len = strlen(comment_str) + strlen(keystring) + 1;
|
||||
file_str = malloc(file_str_len);
|
||||
assert_non_null(file_str);
|
||||
rc = snprintf(file_str, file_str_len, "%s%s", comment_str, keystring);
|
||||
assert_int_equal(rc, file_str_len - 1);
|
||||
|
||||
rc = ssh_pki_import_privkey_base64(file_str, NULL, NULL, NULL, &key);
|
||||
assert_return_code(rc, errno);
|
||||
assert_sk_key_valid(key, SSH_KEYTYPE_SK_ED25519, true);
|
||||
|
||||
SAFE_FREE(keystring);
|
||||
SAFE_FREE(file_str);
|
||||
SSH_KEY_FREE(key);
|
||||
}
|
||||
|
||||
static void
|
||||
torture_pki_sk_ed25519_import_privkey_base64_whitespace(void **state)
|
||||
{
|
||||
int rc, file_str_len;
|
||||
const char *whitespace_str = " \t\t\t\n\n\n";
|
||||
char *file_str = NULL;
|
||||
ssh_key key = NULL;
|
||||
char *keystring = NULL;
|
||||
|
||||
(void)state; /* unused */
|
||||
|
||||
/* Skip test if in FIPS mode */
|
||||
if (ssh_fips_mode()) {
|
||||
skip();
|
||||
}
|
||||
|
||||
keystring = torture_pki_read_file(LIBSSH_SK_ED25519_TESTKEY);
|
||||
assert_non_null(keystring);
|
||||
|
||||
file_str_len = 2 * strlen(whitespace_str) + strlen(keystring) + 1;
|
||||
file_str = malloc(file_str_len);
|
||||
assert_non_null(file_str);
|
||||
rc = snprintf(file_str,
|
||||
file_str_len,
|
||||
"%s%s%s",
|
||||
whitespace_str,
|
||||
keystring,
|
||||
whitespace_str);
|
||||
assert_int_equal(rc, file_str_len - 1);
|
||||
|
||||
rc = ssh_pki_import_privkey_base64(file_str, NULL, NULL, NULL, &key);
|
||||
assert_return_code(rc, errno);
|
||||
assert_sk_key_valid(key, SSH_KEYTYPE_SK_ED25519, true);
|
||||
|
||||
SAFE_FREE(keystring);
|
||||
SAFE_FREE(file_str);
|
||||
SSH_KEY_FREE(key);
|
||||
}
|
||||
|
||||
static void torture_pki_sk_ed25519_import_export_privkey_base64(void **state)
|
||||
{
|
||||
ssh_key origkey = NULL;
|
||||
ssh_key privkey = NULL;
|
||||
char *key_buf = NULL;
|
||||
const char *keystring = NULL;
|
||||
int rc;
|
||||
|
||||
(void)state; /* unused */
|
||||
|
||||
/* Skip test if in FIPS mode */
|
||||
if (ssh_fips_mode()) {
|
||||
skip();
|
||||
}
|
||||
|
||||
keystring = torture_get_openssh_testkey(SSH_KEYTYPE_SK_ED25519, 0);
|
||||
assert_non_null(keystring);
|
||||
|
||||
rc = ssh_pki_import_privkey_base64(keystring, NULL, NULL, NULL, &origkey);
|
||||
assert_return_code(rc, errno);
|
||||
assert_sk_key_valid(origkey, SSH_KEYTYPE_SK_ED25519, true);
|
||||
|
||||
rc = ssh_pki_export_privkey_base64(origkey, NULL, NULL, NULL, &key_buf);
|
||||
assert_return_code(rc, errno);
|
||||
assert_non_null(key_buf);
|
||||
|
||||
rc = ssh_pki_import_privkey_base64(key_buf, NULL, NULL, NULL, &privkey);
|
||||
assert_return_code(rc, errno);
|
||||
assert_sk_key_valid(privkey, SSH_KEYTYPE_SK_ED25519, true);
|
||||
|
||||
rc = ssh_key_cmp(origkey, privkey, SSH_KEY_CMP_PRIVATE);
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
SSH_KEY_FREE(origkey);
|
||||
SSH_KEY_FREE(privkey);
|
||||
SSH_STRING_FREE_CHAR(key_buf);
|
||||
}
|
||||
|
||||
static void torture_pki_sk_ed25519_publickey_from_privatekey(void **state)
|
||||
{
|
||||
ssh_key privkey = NULL;
|
||||
ssh_key pubkey = NULL;
|
||||
const char *keystring = NULL;
|
||||
int rc;
|
||||
|
||||
(void)state; /* unused */
|
||||
|
||||
/* Skip test if in FIPS mode */
|
||||
if (ssh_fips_mode()) {
|
||||
skip();
|
||||
}
|
||||
|
||||
keystring = torture_get_openssh_testkey(SSH_KEYTYPE_SK_ED25519, 0);
|
||||
assert_non_null(keystring);
|
||||
|
||||
rc = ssh_pki_import_privkey_base64(keystring,
|
||||
NULL, /* no passphrase */
|
||||
NULL, /* no auth callback */
|
||||
NULL, /* no auth data */
|
||||
&privkey);
|
||||
assert_return_code(rc, errno);
|
||||
assert_sk_key_valid(privkey, SSH_KEYTYPE_SK_ED25519, true);
|
||||
|
||||
rc = ssh_pki_export_privkey_to_pubkey(privkey, &pubkey);
|
||||
assert_return_code(rc, errno);
|
||||
assert_sk_key_valid(pubkey, SSH_KEYTYPE_SK_ED25519, false);
|
||||
|
||||
rc = ssh_key_cmp(privkey, pubkey, SSH_KEY_CMP_PUBLIC);
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
SSH_KEY_FREE(privkey);
|
||||
SSH_KEY_FREE(pubkey);
|
||||
}
|
||||
|
||||
static void
|
||||
torture_pki_sk_ed25519_import_privkey_base64_passphrase(void **state)
|
||||
{
|
||||
ssh_key privkey = NULL;
|
||||
const char *keystring = NULL;
|
||||
const char *passphrase = NULL;
|
||||
int rc;
|
||||
|
||||
(void)state; /* unused */
|
||||
|
||||
/* Skip test if in FIPS mode */
|
||||
if (ssh_fips_mode()) {
|
||||
skip();
|
||||
}
|
||||
|
||||
keystring = torture_get_openssh_testkey(SSH_KEYTYPE_SK_ED25519, 1);
|
||||
assert_non_null(keystring);
|
||||
|
||||
passphrase = torture_get_testkey_passphrase();
|
||||
assert_non_null(passphrase);
|
||||
|
||||
/* Import with a passphrase */
|
||||
rc = ssh_pki_import_privkey_base64(keystring,
|
||||
passphrase,
|
||||
NULL,
|
||||
NULL,
|
||||
&privkey);
|
||||
assert_return_code(rc, errno);
|
||||
assert_sk_key_valid(privkey, SSH_KEYTYPE_SK_ED25519, true);
|
||||
SSH_KEY_FREE(privkey);
|
||||
|
||||
rc = ssh_pki_import_privkey_base64(keystring,
|
||||
"wrong passphrase",
|
||||
NULL,
|
||||
NULL,
|
||||
&privkey);
|
||||
assert_int_equal(rc, SSH_ERROR);
|
||||
assert_null(privkey);
|
||||
}
|
||||
|
||||
static void torture_pki_sk_ed25519_duplicate_key(void **state)
|
||||
{
|
||||
ssh_key privkey = NULL;
|
||||
ssh_key duplicated = NULL;
|
||||
const char *keystring = NULL;
|
||||
int rc;
|
||||
|
||||
(void)state; /* unused */
|
||||
|
||||
/* Skip test if in FIPS mode */
|
||||
if (ssh_fips_mode()) {
|
||||
skip();
|
||||
}
|
||||
|
||||
keystring = torture_get_openssh_testkey(SSH_KEYTYPE_SK_ED25519, 0);
|
||||
assert_non_null(keystring);
|
||||
|
||||
rc = ssh_pki_import_privkey_base64(keystring,
|
||||
NULL, /* no passphrase */
|
||||
NULL, /* no auth callback */
|
||||
NULL, /* no auth data */
|
||||
&privkey);
|
||||
assert_return_code(rc, errno);
|
||||
assert_sk_key_valid(privkey, SSH_KEYTYPE_SK_ED25519, true);
|
||||
|
||||
duplicated = ssh_key_dup(privkey);
|
||||
assert_sk_key_valid(duplicated, SSH_KEYTYPE_SK_ED25519, true);
|
||||
|
||||
rc = ssh_key_cmp(privkey, duplicated, SSH_KEY_CMP_PRIVATE);
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
SSH_KEY_FREE(privkey);
|
||||
SSH_KEY_FREE(duplicated);
|
||||
}
|
||||
|
||||
static void torture_pki_sk_ed25519_import_pubkey_base64(void **state)
|
||||
{
|
||||
ssh_key key = NULL;
|
||||
ssh_key pubkey = NULL;
|
||||
char *b64_key = NULL;
|
||||
const char *keystring = NULL;
|
||||
int rc;
|
||||
|
||||
(void)state; /* unused */
|
||||
|
||||
/* Skip test if in FIPS mode */
|
||||
if (ssh_fips_mode()) {
|
||||
skip();
|
||||
}
|
||||
|
||||
keystring = torture_get_openssh_testkey(SSH_KEYTYPE_SK_ED25519, 0);
|
||||
assert_non_null(keystring);
|
||||
|
||||
/* Import private key to extract public key */
|
||||
rc = ssh_pki_import_privkey_base64(keystring, NULL, NULL, NULL, &key);
|
||||
assert_return_code(rc, errno);
|
||||
assert_sk_key_valid(key, SSH_KEYTYPE_SK_ED25519, true);
|
||||
|
||||
rc = ssh_pki_export_privkey_to_pubkey(key, &pubkey);
|
||||
assert_return_code(rc, errno);
|
||||
assert_sk_key_valid(pubkey, SSH_KEYTYPE_SK_ED25519, false);
|
||||
|
||||
/* Export public key to base64 */
|
||||
rc = ssh_pki_export_pubkey_base64(pubkey, &b64_key);
|
||||
assert_return_code(rc, errno);
|
||||
assert_non_null(b64_key);
|
||||
|
||||
SSH_KEY_FREE(key);
|
||||
SSH_KEY_FREE(pubkey);
|
||||
|
||||
/* Import public key from base64 */
|
||||
rc = ssh_pki_import_pubkey_base64(b64_key, SSH_KEYTYPE_SK_ED25519, &pubkey);
|
||||
assert_return_code(rc, errno);
|
||||
assert_sk_key_valid(pubkey, SSH_KEYTYPE_SK_ED25519, false);
|
||||
|
||||
SSH_KEY_FREE(pubkey);
|
||||
SSH_STRING_FREE_CHAR(b64_key);
|
||||
}
|
||||
|
||||
static void torture_pki_sk_ed25519_pubkey_blob(void **state)
|
||||
{
|
||||
ssh_key privkey = NULL;
|
||||
ssh_key pubkey = NULL;
|
||||
ssh_key imported_pubkey = NULL;
|
||||
ssh_string pub_blob = NULL;
|
||||
const char *keystring = NULL;
|
||||
int rc;
|
||||
|
||||
(void)state; /* unused */
|
||||
|
||||
/* Skip test if in FIPS mode */
|
||||
if (ssh_fips_mode()) {
|
||||
skip();
|
||||
}
|
||||
|
||||
keystring = torture_get_openssh_testkey(SSH_KEYTYPE_SK_ED25519, 0);
|
||||
assert_non_null(keystring);
|
||||
|
||||
rc = ssh_pki_import_privkey_base64(keystring, NULL, NULL, NULL, &privkey);
|
||||
assert_return_code(rc, errno);
|
||||
assert_sk_key_valid(privkey, SSH_KEYTYPE_SK_ED25519, true);
|
||||
|
||||
rc = ssh_pki_export_privkey_to_pubkey(privkey, &pubkey);
|
||||
assert_return_code(rc, errno);
|
||||
assert_sk_key_valid(pubkey, SSH_KEYTYPE_SK_ED25519, false);
|
||||
|
||||
/* Export public key to blob */
|
||||
rc = ssh_pki_export_pubkey_blob(pubkey, &pub_blob);
|
||||
assert_int_equal(rc, SSH_OK);
|
||||
assert_non_null(pub_blob);
|
||||
|
||||
/* Import public key from blob */
|
||||
rc = ssh_pki_import_pubkey_blob(pub_blob, &imported_pubkey);
|
||||
assert_int_equal(rc, SSH_OK);
|
||||
assert_sk_key_valid(imported_pubkey, SSH_KEYTYPE_SK_ED25519, false);
|
||||
|
||||
/* Compare keys */
|
||||
rc = ssh_key_cmp(pubkey, imported_pubkey, SSH_KEY_CMP_PUBLIC);
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
ssh_string_free(pub_blob);
|
||||
SSH_KEY_FREE(privkey);
|
||||
SSH_KEY_FREE(pubkey);
|
||||
SSH_KEY_FREE(imported_pubkey);
|
||||
}
|
||||
|
||||
int torture_run_tests(void)
|
||||
{
|
||||
int rc;
|
||||
|
||||
struct CMUnitTest tests[] = {
|
||||
cmocka_unit_test_setup_teardown(
|
||||
torture_pki_sk_ed25519_import_pubkey_file,
|
||||
setup_sk_ed25519_key,
|
||||
teardown),
|
||||
cmocka_unit_test_setup_teardown(
|
||||
torture_pki_sk_ed25519_import_pubkey_from_openssh_privkey,
|
||||
setup_sk_ed25519_key,
|
||||
teardown),
|
||||
cmocka_unit_test_setup_teardown(
|
||||
torture_pki_sk_ed25519_import_privkey_base64,
|
||||
setup_sk_ed25519_key,
|
||||
teardown),
|
||||
cmocka_unit_test_setup_teardown(
|
||||
torture_pki_sk_ed25519_import_privkey_base64_comment,
|
||||
setup_sk_ed25519_key,
|
||||
teardown),
|
||||
cmocka_unit_test_setup_teardown(
|
||||
torture_pki_sk_ed25519_import_privkey_base64_whitespace,
|
||||
setup_sk_ed25519_key,
|
||||
teardown),
|
||||
cmocka_unit_test_setup_teardown(
|
||||
torture_pki_sk_ed25519_import_export_privkey_base64,
|
||||
setup_sk_ed25519_key,
|
||||
teardown),
|
||||
cmocka_unit_test_setup_teardown(
|
||||
torture_pki_sk_ed25519_publickey_from_privatekey,
|
||||
setup_sk_ed25519_key,
|
||||
teardown),
|
||||
cmocka_unit_test_setup_teardown(
|
||||
torture_pki_sk_ed25519_import_pubkey_base64,
|
||||
setup_sk_ed25519_key,
|
||||
teardown),
|
||||
cmocka_unit_test_setup_teardown(
|
||||
torture_pki_sk_ed25519_import_privkey_base64_passphrase,
|
||||
setup_sk_ed25519_key,
|
||||
teardown),
|
||||
cmocka_unit_test_setup_teardown(torture_pki_sk_ed25519_duplicate_key,
|
||||
setup_sk_ed25519_key,
|
||||
teardown),
|
||||
cmocka_unit_test_setup_teardown(torture_pki_sk_ed25519_pubkey_blob,
|
||||
setup_sk_ed25519_key,
|
||||
teardown),
|
||||
};
|
||||
|
||||
ssh_init();
|
||||
torture_filter_tests(tests);
|
||||
rc = cmocka_run_group_tests(tests, NULL, NULL);
|
||||
ssh_finalize();
|
||||
|
||||
return rc;
|
||||
}
|
||||
Reference in New Issue
Block a user