mirror of
https://git.libssh.org/projects/libssh.git
synced 2026-02-04 12:20:42 +09:00
feat(torture_sk): add functions to validate security key signatures and to create PKI context
Signed-off-by: Praneeth Sarode <praneethsarode@gmail.com> Reviewed-by: Jakub Jelen <jjelen@redhat.com> Reviewed-by: Eshan Kelkar <eshankelkar@galorithm.com>
This commit is contained in:
@@ -23,6 +23,7 @@
|
||||
|
||||
#include "torture_sk.h"
|
||||
#include "libssh/pki.h"
|
||||
#include "libssh/pki_priv.h"
|
||||
#include "libssh/sk_api.h" /* For SSH_SK_* flag definitions */
|
||||
|
||||
void assert_sk_key_valid(ssh_key key,
|
||||
@@ -100,6 +101,150 @@ void assert_sk_key_valid(ssh_key key,
|
||||
}
|
||||
}
|
||||
|
||||
void assert_sk_signature_valid(ssh_signature signature,
|
||||
enum ssh_keytypes_e expected_type,
|
||||
ssh_key signing_key,
|
||||
const uint8_t *data,
|
||||
size_t data_len)
|
||||
{
|
||||
uint8_t valid_flags;
|
||||
const char *expected_type_str = NULL;
|
||||
ssh_string sig_blob = NULL;
|
||||
ssh_signature reconstructed = NULL;
|
||||
ssh_buffer sk_sig_buffer = NULL;
|
||||
int rc;
|
||||
|
||||
/* Basic null and type validation */
|
||||
assert_non_null(signature);
|
||||
assert_int_equal(signature->type, expected_type);
|
||||
|
||||
/* Validate hash type is appropriate for security keys */
|
||||
switch (expected_type) {
|
||||
case SSH_KEYTYPE_SK_ECDSA:
|
||||
assert_int_equal(signature->hash_type, SSH_DIGEST_SHA256);
|
||||
break;
|
||||
case SSH_KEYTYPE_SK_ED25519:
|
||||
assert_int_equal(signature->hash_type, SSH_DIGEST_AUTO);
|
||||
break;
|
||||
default:
|
||||
/* Should not reach here */
|
||||
assert_true(0);
|
||||
break;
|
||||
}
|
||||
|
||||
expected_type_str = ssh_key_type_to_char(expected_type);
|
||||
assert_non_null(signature->type_c);
|
||||
assert_string_equal(signature->type_c, expected_type_str);
|
||||
|
||||
/* Check that only valid SK flags are set */
|
||||
valid_flags = SSH_SK_USER_PRESENCE_REQD | SSH_SK_USER_VERIFICATION_REQD;
|
||||
assert_int_equal(signature->sk_flags & ~valid_flags, 0);
|
||||
|
||||
assert_true(signature->sk_flags & SSH_SK_USER_PRESENCE_REQD);
|
||||
assert_true(signature->sk_counter > 0);
|
||||
|
||||
assert_non_null(signature->raw_sig);
|
||||
assert_true(ssh_string_len(signature->raw_sig) > 0);
|
||||
|
||||
rc = ssh_pki_export_signature_blob(signature, &sig_blob);
|
||||
assert_int_equal(rc, SSH_OK);
|
||||
assert_non_null(sig_blob);
|
||||
|
||||
assert_non_null(signing_key);
|
||||
rc = ssh_pki_import_signature_blob(sig_blob, signing_key, &reconstructed);
|
||||
assert_int_equal(rc, SSH_OK);
|
||||
assert_non_null(reconstructed);
|
||||
|
||||
rc = pki_sk_signature_buffer_prepare(signing_key,
|
||||
reconstructed,
|
||||
data,
|
||||
data_len,
|
||||
&sk_sig_buffer);
|
||||
assert_int_equal(rc, SSH_OK);
|
||||
assert_non_null(sk_sig_buffer);
|
||||
|
||||
rc = pki_verify_data_signature(reconstructed,
|
||||
signing_key,
|
||||
ssh_buffer_get(sk_sig_buffer),
|
||||
ssh_buffer_get_len(sk_sig_buffer));
|
||||
assert_int_equal(rc, SSH_OK);
|
||||
|
||||
SSH_BUFFER_FREE(sk_sig_buffer);
|
||||
|
||||
ssh_signature_free(reconstructed);
|
||||
ssh_string_free(sig_blob);
|
||||
}
|
||||
|
||||
ssh_pki_ctx
|
||||
torture_create_sk_pki_ctx(const char *application,
|
||||
uint8_t flags,
|
||||
const void *challenge_data,
|
||||
size_t challenge_len,
|
||||
ssh_auth_callback pin_callback,
|
||||
const char *device_path,
|
||||
const char *user_id,
|
||||
const struct ssh_sk_callbacks_struct *sk_callbacks)
|
||||
{
|
||||
ssh_pki_ctx ctx = NULL;
|
||||
ssh_buffer challenge_buffer = NULL;
|
||||
int rc;
|
||||
|
||||
ctx = ssh_pki_ctx_new();
|
||||
assert_non_null(ctx);
|
||||
|
||||
rc = ssh_pki_ctx_options_set(ctx,
|
||||
SSH_PKI_OPTION_SK_APPLICATION,
|
||||
application);
|
||||
assert_int_equal(rc, SSH_OK);
|
||||
|
||||
rc = ssh_pki_ctx_options_set(ctx, SSH_PKI_OPTION_SK_FLAGS, &flags);
|
||||
assert_int_equal(rc, SSH_OK);
|
||||
|
||||
if (challenge_data != NULL && challenge_len > 0) {
|
||||
challenge_buffer = ssh_buffer_new();
|
||||
assert_non_null(challenge_buffer);
|
||||
|
||||
rc = ssh_buffer_add_data(challenge_buffer,
|
||||
challenge_data,
|
||||
challenge_len);
|
||||
assert_int_equal(rc, SSH_OK);
|
||||
}
|
||||
|
||||
rc = ssh_pki_ctx_options_set(ctx,
|
||||
SSH_PKI_OPTION_SK_CHALLENGE,
|
||||
challenge_buffer);
|
||||
assert_int_equal(rc, SSH_OK);
|
||||
|
||||
SSH_BUFFER_FREE(challenge_buffer);
|
||||
|
||||
rc = ssh_pki_ctx_set_sk_pin_callback(ctx, pin_callback, NULL);
|
||||
assert_int_equal(rc, SSH_OK);
|
||||
|
||||
if (device_path != NULL) {
|
||||
rc = ssh_pki_ctx_sk_callbacks_option_set(ctx,
|
||||
SSH_SK_OPTION_NAME_DEVICE_PATH,
|
||||
device_path,
|
||||
false);
|
||||
assert_int_equal(rc, SSH_OK);
|
||||
}
|
||||
if (user_id != NULL) {
|
||||
rc = ssh_pki_ctx_sk_callbacks_option_set(ctx,
|
||||
SSH_SK_OPTION_NAME_USER_ID,
|
||||
user_id,
|
||||
false);
|
||||
assert_int_equal(rc, SSH_OK);
|
||||
}
|
||||
|
||||
if (sk_callbacks != NULL) {
|
||||
rc = ssh_pki_ctx_options_set(ctx,
|
||||
SSH_PKI_OPTION_SK_CALLBACKS,
|
||||
sk_callbacks);
|
||||
assert_int_equal(rc, SSH_OK);
|
||||
}
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
void assert_sk_enroll_response(struct sk_enroll_response *response, int flags)
|
||||
{
|
||||
assert_non_null(response);
|
||||
|
||||
@@ -28,9 +28,10 @@
|
||||
|
||||
#define LIBSSH_STATIC
|
||||
|
||||
#include "torture.h"
|
||||
|
||||
#include "libssh/callbacks.h"
|
||||
#include "libssh/pki.h"
|
||||
#include "torture.h"
|
||||
#include "torture_pki.h"
|
||||
|
||||
/**
|
||||
* @brief Validate a security key (ssh_key) structure
|
||||
@@ -46,6 +47,51 @@ void assert_sk_key_valid(ssh_key key,
|
||||
enum ssh_keytypes_e expected_type,
|
||||
bool private);
|
||||
|
||||
/**
|
||||
* @brief Validate a security key signature structure
|
||||
*
|
||||
* Checks that the signature is not NULL, matches the expected key type, and
|
||||
* other internal fields. Also verifies that the signature was produced by the
|
||||
* given signing key.
|
||||
*
|
||||
* @param[in] signature The signature to validate
|
||||
* @param[in] expected_type The expected key type (e.g., SSH_KEYTYPE_SK_ECDSA)
|
||||
* @param[in] signing_key The key that should have produced the signature
|
||||
* @param[in] data The signed data buffer
|
||||
* @param[in] data_len Length of the signed data
|
||||
*/
|
||||
void assert_sk_signature_valid(ssh_signature signature,
|
||||
enum ssh_keytypes_e expected_type,
|
||||
ssh_key signing_key,
|
||||
const uint8_t *data,
|
||||
size_t data_len);
|
||||
|
||||
/**
|
||||
* @brief Create and initialize a PKI context configured for security key
|
||||
* operations.
|
||||
*
|
||||
* Parameters:
|
||||
* @param[in] application Application string
|
||||
* @param[in] flags SK flags
|
||||
* @param[in] challenge_data Optional challenge bytes (may be NULL)
|
||||
* @param[in] challenge_len Length of challenge_data
|
||||
* @param[in] pin_callback Callback used to obtain the PIN (may be NULL)
|
||||
* @param[in] device_path Optional device path (may be NULL)
|
||||
* @param[in] user_id Optional user_id string (may be NULL)
|
||||
* @param[in] sk_callbacks Pointer to SK callbacks (may be NULL)
|
||||
*
|
||||
* @return A configured ssh_pki_ctx on success, or NULL on allocation failure.
|
||||
*/
|
||||
ssh_pki_ctx
|
||||
torture_create_sk_pki_ctx(const char *application,
|
||||
uint8_t flags,
|
||||
const void *challenge_data,
|
||||
size_t challenge_len,
|
||||
ssh_auth_callback pin_callback,
|
||||
const char *device_path,
|
||||
const char *user_id,
|
||||
const struct ssh_sk_callbacks_struct *sk_callbacks);
|
||||
|
||||
/**
|
||||
* @brief Validate a security key enrollment response structure
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user