From d61b0dc7ccea8d8cac5bb037d2357ea7f221fbaa Mon Sep 17 00:00:00 2001 From: Jakub Jelen Date: Fri, 12 Dec 2025 17:43:13 +0100 Subject: [PATCH] tests: Improve test coverage of comparing certificates Signed-off-by: Jakub Jelen Reviewed-by: Andreas Schneider (cherry picked from commit 701a2155a793e210203fe24d5f8d806c17dc297c) --- tests/unittests/torture_pki_ecdsa.c | 73 ++++++++++++++++++++++++- tests/unittests/torture_pki_ed25519.c | 78 ++++++++++++++++++++++++++- tests/unittests/torture_pki_rsa.c | 18 +++++++ 3 files changed, 165 insertions(+), 4 deletions(-) diff --git a/tests/unittests/torture_pki_ecdsa.c b/tests/unittests/torture_pki_ecdsa.c index f6b17e8a..e3879792 100644 --- a/tests/unittests/torture_pki_ecdsa.c +++ b/tests/unittests/torture_pki_ecdsa.c @@ -367,10 +367,14 @@ static void torture_pki_ecdsa_publickey_from_privatekey(void **state) static void torture_pki_ecdsa_import_cert_file(void **state) { int rc; + ssh_key pubkey = NULL; + ssh_key privkey = NULL; ssh_key cert = NULL; - enum ssh_keytypes_e type; + enum ssh_keytypes_e type, exp_cert_type; struct pki_st *test_state = *((struct pki_st **)state); + exp_cert_type = test_state->type + 3; + /* Importing public key as cert should fail */ rc = ssh_pki_import_cert_file(LIBSSH_ECDSA_TESTKEY ".pub", &cert); assert_int_equal(rc, SSH_ERROR); @@ -380,13 +384,78 @@ static void torture_pki_ecdsa_import_cert_file(void **state) assert_int_equal(rc, 0); assert_non_null(cert); + rc = ssh_pki_import_pubkey_file(LIBSSH_ECDSA_TESTKEY ".pub", &pubkey); + assert_return_code(rc, errno); + assert_non_null(pubkey); + type = ssh_key_type(cert); - assert_int_equal(type, test_state->type+3); + assert_int_equal(type, exp_cert_type); rc = ssh_key_is_public(cert); assert_int_equal(rc, 1); + /* Import matching private key file and verify the pubkey matches */ + rc = ssh_pki_import_privkey_file(LIBSSH_ECDSA_TESTKEY, + NULL, + NULL, + NULL, + &privkey); + assert_return_code(rc, errno); + assert_non_null(privkey); + + type = ssh_key_type(privkey); + assert_true(type == test_state->type); + + /* Basic sanity. */ + rc = ssh_pki_copy_cert_to_privkey(NULL, privkey); + assert_int_equal(rc, SSH_ERROR); + + rc = ssh_pki_copy_cert_to_privkey(pubkey, NULL); + assert_int_equal(rc, SSH_ERROR); + + /* A public key doesn't have a cert, copy should fail. */ + assert_null(pubkey->cert); + rc = ssh_pki_copy_cert_to_privkey(pubkey, privkey); + assert_int_equal(rc, SSH_ERROR); + + /* Copying the cert to non-cert keys should work fine. */ + rc = ssh_pki_copy_cert_to_privkey(cert, pubkey); + assert_return_code(rc, errno); + assert_non_null(pubkey->cert); + rc = ssh_pki_copy_cert_to_privkey(cert, privkey); + assert_return_code(rc, errno); + assert_non_null(privkey->cert); + assert_true(privkey->cert_type == exp_cert_type); + + assert_int_equal(ssh_key_cmp(privkey, cert, SSH_KEY_CMP_PUBLIC), 0); + assert_int_equal(ssh_key_cmp(cert, privkey, SSH_KEY_CMP_PUBLIC), 0); + + /* The private key's cert is already set, another copy should fail. */ + rc = ssh_pki_copy_cert_to_privkey(cert, privkey); + assert_int_equal(rc, SSH_ERROR); + + SSH_KEY_FREE(privkey); + SSH_KEY_FREE(pubkey); + + /* Generate different key and try to assign it this certificate */ + rc = ssh_pki_generate(test_state->type, 256, &privkey); + assert_return_code(rc, errno); + assert_non_null(privkey); + rc = ssh_pki_export_privkey_to_pubkey(privkey, &pubkey); + assert_return_code(rc, errno); + assert_non_null(pubkey); + + rc = ssh_pki_copy_cert_to_privkey(cert, privkey); + assert_int_equal(rc, SSH_ERROR); + rc = ssh_pki_copy_cert_to_privkey(cert, pubkey); + assert_int_equal(rc, SSH_ERROR); + + assert_int_equal(ssh_key_cmp(privkey, cert, SSH_KEY_CMP_PUBLIC), 1); + assert_int_equal(ssh_key_cmp(cert, privkey, SSH_KEY_CMP_PUBLIC), 1); + SSH_KEY_FREE(cert); + SSH_KEY_FREE(privkey); + SSH_KEY_FREE(pubkey); } static void torture_pki_ecdsa_publickey_base64(void **state) diff --git a/tests/unittests/torture_pki_ed25519.c b/tests/unittests/torture_pki_ed25519.c index 0142fbe3..ead10850 100644 --- a/tests/unittests/torture_pki_ed25519.c +++ b/tests/unittests/torture_pki_ed25519.c @@ -312,6 +312,8 @@ static void torture_pki_ed25519_publickey_from_privatekey(void **state) static void torture_pki_ed25519_import_cert_file(void **state) { int rc; + ssh_key pubkey = NULL; + ssh_key privkey = NULL; ssh_key cert = NULL; enum ssh_keytypes_e type; @@ -323,16 +325,88 @@ static void torture_pki_ed25519_import_cert_file(void **state) assert_null(cert); rc = ssh_pki_import_cert_file(LIBSSH_ED25519_TESTKEY "-cert.pub", &cert); - assert_true(rc == 0); + assert_return_code(rc, errno); assert_non_null(cert); + rc = ssh_pki_import_pubkey_file(LIBSSH_ED25519_TESTKEY ".pub", &pubkey); + assert_return_code(rc, errno); + assert_non_null(pubkey); + type = ssh_key_type(cert); assert_true(type == SSH_KEYTYPE_ED25519_CERT01); rc = ssh_key_is_public(cert); - assert_true(rc == 1); + assert_int_equal(rc, 1); + + /* Skip test if in FIPS mode */ + if (ssh_fips_mode()) { + SSH_KEY_FREE(cert); + SSH_KEY_FREE(pubkey); + skip(); + } + + /* Import matching private key file and verify the pubkey matches */ + rc = ssh_pki_import_privkey_file(LIBSSH_ED25519_TESTKEY, + NULL, + NULL, + NULL, + &privkey); + assert_return_code(rc, errno); + assert_non_null(privkey); + + type = ssh_key_type(privkey); + assert_true(type == SSH_KEYTYPE_ED25519); + + /* Basic sanity. */ + rc = ssh_pki_copy_cert_to_privkey(NULL, privkey); + assert_int_equal(rc, SSH_ERROR); + + rc = ssh_pki_copy_cert_to_privkey(pubkey, NULL); + assert_int_equal(rc, SSH_ERROR); + + /* A public key doesn't have a cert, copy should fail. */ + assert_null(pubkey->cert); + rc = ssh_pki_copy_cert_to_privkey(pubkey, privkey); + assert_int_equal(rc, SSH_ERROR); + + /* Copying the cert to non-cert keys should work fine. */ + rc = ssh_pki_copy_cert_to_privkey(cert, pubkey); + assert_return_code(rc, errno); + assert_non_null(pubkey->cert); + rc = ssh_pki_copy_cert_to_privkey(cert, privkey); + assert_return_code(rc, errno); + assert_non_null(privkey->cert); + assert_true(privkey->cert_type == SSH_KEYTYPE_ED25519_CERT01); + + assert_int_equal(ssh_key_cmp(privkey, cert, SSH_KEY_CMP_PUBLIC), 0); + assert_int_equal(ssh_key_cmp(cert, privkey, SSH_KEY_CMP_PUBLIC), 0); + + /* The private key's cert is already set, another copy should fail. */ + rc = ssh_pki_copy_cert_to_privkey(cert, privkey); + assert_int_equal(rc, SSH_ERROR); + + SSH_KEY_FREE(privkey); + SSH_KEY_FREE(pubkey); + + /* Generate different key and try to assign it this certificate */ + rc = ssh_pki_generate(SSH_KEYTYPE_ED25519, 0, &privkey); + assert_return_code(rc, errno); + assert_non_null(privkey); + rc = ssh_pki_export_privkey_to_pubkey(privkey, &pubkey); + assert_return_code(rc, errno); + assert_non_null(pubkey); + + rc = ssh_pki_copy_cert_to_privkey(cert, privkey); + assert_int_equal(rc, SSH_ERROR); + rc = ssh_pki_copy_cert_to_privkey(cert, pubkey); + assert_int_equal(rc, SSH_ERROR); + + assert_int_equal(ssh_key_cmp(privkey, cert, SSH_KEY_CMP_PUBLIC), 1); + assert_int_equal(ssh_key_cmp(cert, privkey, SSH_KEY_CMP_PUBLIC), 1); SSH_KEY_FREE(cert); + SSH_KEY_FREE(privkey); + SSH_KEY_FREE(pubkey); } static void torture_pki_ed25519_publickey_base64(void **state) diff --git a/tests/unittests/torture_pki_rsa.c b/tests/unittests/torture_pki_rsa.c index 4da6b148..d9e98e46 100644 --- a/tests/unittests/torture_pki_rsa.c +++ b/tests/unittests/torture_pki_rsa.c @@ -373,6 +373,7 @@ static void torture_pki_rsa_copy_cert_to_privkey(void **state) ssh_key pubkey = NULL; ssh_key privkey = NULL; ssh_key cert = NULL; + enum ssh_keytypes_e type; (void)state; /* unused */ @@ -389,6 +390,13 @@ static void torture_pki_rsa_copy_cert_to_privkey(void **state) assert_return_code(rc, errno); assert_non_null(pubkey); + type = ssh_key_type(cert); + assert_true(type == SSH_KEYTYPE_RSA_CERT01); + + rc = ssh_key_is_public(cert); + assert_int_equal(rc, 1); + + /* Import matching private key file and verify the pubkey matches */ rc = ssh_pki_import_privkey_base64(torture_get_testkey(SSH_KEYTYPE_RSA, 0), passphrase, NULL, @@ -397,6 +405,9 @@ static void torture_pki_rsa_copy_cert_to_privkey(void **state) assert_return_code(rc, errno); assert_non_null(privkey); + type = ssh_key_type(privkey); + assert_true(type == SSH_KEYTYPE_RSA); + /* Basic sanity. */ rc = ssh_pki_copy_cert_to_privkey(NULL, privkey); assert_int_equal(rc, SSH_ERROR); @@ -416,6 +427,10 @@ static void torture_pki_rsa_copy_cert_to_privkey(void **state) rc = ssh_pki_copy_cert_to_privkey(cert, privkey); assert_return_code(rc, errno); assert_non_null(privkey->cert); + assert_true(privkey->cert_type == SSH_KEYTYPE_RSA_CERT01); + + assert_int_equal(ssh_key_cmp(privkey, cert, SSH_KEY_CMP_PUBLIC), 0); + assert_int_equal(ssh_key_cmp(cert, privkey, SSH_KEY_CMP_PUBLIC), 0); /* The private key's cert is already set, another copy should fail. */ rc = ssh_pki_copy_cert_to_privkey(cert, privkey); @@ -437,6 +452,9 @@ static void torture_pki_rsa_copy_cert_to_privkey(void **state) rc = ssh_pki_copy_cert_to_privkey(cert, pubkey); assert_int_equal(rc, SSH_ERROR); + assert_int_equal(ssh_key_cmp(privkey, cert, SSH_KEY_CMP_PUBLIC), 1); + assert_int_equal(ssh_key_cmp(cert, privkey, SSH_KEY_CMP_PUBLIC), 1); + SSH_KEY_FREE(cert); SSH_KEY_FREE(privkey); SSH_KEY_FREE(pubkey);