Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add cert key preferences #4434

Merged
merged 21 commits into from
Feb 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 0 additions & 8 deletions crypto/s2n_certificate.c
Original file line number Diff line number Diff line change
Expand Up @@ -376,14 +376,6 @@ int s2n_cert_chain_and_key_load(struct s2n_cert_chain_and_key *chain_and_key)
/* Populate name information from the SAN/CN for the leaf certificate */
POSIX_GUARD(s2n_cert_chain_and_key_set_names(chain_and_key, leaf_cert));

/* Populate ec curve libcrypto nid */
if (pkey_type == S2N_PKEY_TYPE_ECDSA) {
int nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(public_key.key.ecdsa_key.ec_key));
POSIX_ENSURE(nid > 0, S2N_ERR_CERT_TYPE_UNSUPPORTED);
POSIX_ENSURE(nid < UINT16_MAX, S2N_ERR_CERT_TYPE_UNSUPPORTED);
head->ec_curve_nid = nid;
}

/* populate libcrypto nid's required for cert restrictions */
struct s2n_cert *current = head->next;
while (current != NULL) {
Expand Down
6 changes: 5 additions & 1 deletion crypto/s2n_certificate.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,16 @@ struct s2n_cert_info {
int signature_nid;
/* This field is not populated for RSA_PSS signatures */
int signature_digest_nid;
/* For EC certs this field is the curve (e.g. NID_secp521r1) and not the generic
* EC key NID (NID_X9_62_id_ecPublicKey)
*/
int public_key_nid;
jmayclin marked this conversation as resolved.
Show resolved Hide resolved
int public_key_bits;
bool self_signed;
};

struct s2n_cert {
s2n_pkey_type pkey_type;
uint16_t ec_curve_nid;
s2n_cert_public_key public_key;
struct s2n_cert_info info;
struct s2n_blob raw;
Expand Down
20 changes: 20 additions & 0 deletions crypto/s2n_openssl_x509.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@

#include "api/s2n.h"

DEFINE_POINTER_CLEANUP_FUNC(EVP_PKEY *, EVP_PKEY_free);
DEFINE_POINTER_CLEANUP_FUNC(EC_KEY *, EC_KEY_free);

S2N_CLEANUP_RESULT s2n_openssl_x509_stack_pop_free(STACK_OF(X509) **cert_chain)
{
RESULT_ENSURE_REF(*cert_chain);
Expand Down Expand Up @@ -114,5 +117,22 @@ S2N_RESULT s2n_openssl_x509_get_cert_info(X509 *cert, struct s2n_cert_info *info
RESULT_GUARD_OSSL(OBJ_find_sigid_algs(info->signature_nid, &info->signature_digest_nid, NULL),
S2N_ERR_CERT_TYPE_UNSUPPORTED);

DEFER_CLEANUP(EVP_PKEY *pubkey = X509_get_pubkey(cert), EVP_PKEY_free_pointer);
jmayclin marked this conversation as resolved.
Show resolved Hide resolved
RESULT_ENSURE(pubkey != NULL, S2N_ERR_DECODE_CERTIFICATE);

info->public_key_bits = EVP_PKEY_bits(pubkey);
jmayclin marked this conversation as resolved.
Show resolved Hide resolved
RESULT_ENSURE(info->public_key_bits > 0, S2N_ERR_CERT_TYPE_UNSUPPORTED);

if (EVP_PKEY_base_id(pubkey) == EVP_PKEY_EC) {
DEFER_CLEANUP(EC_KEY *ec_key = EVP_PKEY_get1_EC_KEY(pubkey), EC_KEY_free_pointer);
RESULT_ENSURE_REF(ec_key);
const EC_GROUP *ec_group = EC_KEY_get0_group(ec_key);
RESULT_ENSURE_REF(ec_group);
info->public_key_nid = EC_GROUP_get_curve_name(ec_group);
} else {
info->public_key_nid = EVP_PKEY_id(pubkey);
}
RESULT_ENSURE(info->public_key_nid != NID_undef, S2N_ERR_CERT_TYPE_UNSUPPORTED);

return S2N_RESULT_OK;
}
2 changes: 1 addition & 1 deletion tests/unit/s2n_config_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -1124,7 +1124,7 @@ int main(int argc, char **argv)
{
DEFER_CLEANUP(struct s2n_config *config = s2n_config_new(), s2n_config_ptr_free);
EXPECT_SUCCESS(s2n_config_add_cert_chain_and_key_to_store(config, valid_cert));
EXPECT_OK(s2n_config_validate_loaded_certificates(config, &security_policy_rfc9151));
EXPECT_OK(s2n_config_validate_loaded_certificates(config, &rfc9151_applied_locally));
};

/* when cert preferences don't apply locally, invalid certs are accepted */
Expand Down
57 changes: 44 additions & 13 deletions tests/unit/s2n_openssl_x509_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,24 @@
#include <openssl/pem.h>
#include <openssl/x509.h>

#include "crypto/s2n_rsa_pss.h"
#include "s2n_test.h"
#include "testlib/s2n_testlib.h"

S2N_RESULT s2n_x509_validator_read_asn1_cert(struct s2n_stuffer *cert_chain_in_stuffer,
struct s2n_blob *asn1_cert);

static S2N_RESULT s2n_test_assert_s2n_cert_info_equality(const struct s2n_cert_info *info_a,
const struct s2n_cert_info *info_b)
{
RESULT_ENSURE_EQ(info_a->public_key_bits, info_b->public_key_bits);
RESULT_ENSURE_EQ(info_a->public_key_nid, info_b->public_key_nid);
RESULT_ENSURE_EQ(info_a->signature_nid, info_b->signature_nid);
RESULT_ENSURE_EQ(info_a->signature_digest_nid, info_b->signature_digest_nid);
RESULT_ENSURE_EQ(info_a->self_signed, info_b->self_signed);
return S2N_RESULT_OK;
}

int main(int argc, char **argv)
{
BEGIN_TEST();
Expand Down Expand Up @@ -87,6 +99,8 @@ int main(int argc, char **argv)
const char *digest;
int expected_signature_nid;
int expected_digest_nid;
int expected_public_key_nid;
int expected_public_key_bits;
} test_cases[] = {
{
.key_type = "ec",
Expand All @@ -95,6 +109,8 @@ int main(int argc, char **argv)
.digest = "sha256",
.expected_signature_nid = NID_ecdsa_with_SHA256,
.expected_digest_nid = NID_sha256,
.expected_public_key_nid = NID_secp384r1,
.expected_public_key_bits = 384,
},
{
.key_type = "ec",
Expand All @@ -103,6 +119,8 @@ int main(int argc, char **argv)
.digest = "sha384",
.expected_signature_nid = NID_ecdsa_with_SHA384,
.expected_digest_nid = NID_sha384,
.expected_public_key_nid = NID_X9_62_prime256v1,
.expected_public_key_bits = 256,
},
{
.key_type = "ec",
Expand All @@ -111,6 +129,8 @@ int main(int argc, char **argv)
.digest = "sha512",
.expected_signature_nid = NID_ecdsa_with_SHA512,
.expected_digest_nid = NID_sha512,
.expected_public_key_nid = NID_secp521r1,
.expected_public_key_bits = 521,
},
{
.key_type = "rsae",
Expand All @@ -119,6 +139,8 @@ int main(int argc, char **argv)
.digest = "sha1",
.expected_signature_nid = NID_sha1WithRSAEncryption,
.expected_digest_nid = NID_sha1,
.expected_public_key_nid = NID_rsaEncryption,
.expected_public_key_bits = 2048,
},
{
.key_type = "rsae",
Expand All @@ -127,6 +149,8 @@ int main(int argc, char **argv)
.digest = "sha224",
.expected_signature_nid = NID_sha224WithRSAEncryption,
.expected_digest_nid = NID_sha224,
.expected_public_key_nid = NID_rsaEncryption,
.expected_public_key_bits = 2048,
},
{
.key_type = "rsae",
Expand All @@ -135,16 +159,19 @@ int main(int argc, char **argv)
.digest = "sha384",
.expected_signature_nid = NID_sha384WithRSAEncryption,
.expected_digest_nid = NID_sha384,
.expected_public_key_nid = NID_rsaEncryption,
.expected_public_key_bits = 3072,
},
/* openssl 1.0.* does not support rsapss signatures */
#if S2N_OPENSSL_VERSION_AT_LEAST(1, 1, 0)
#if RSA_PSS_CERTS_SUPPORTED
{
.key_type = "rsae",
.signature = "pss",
.key_size = "4096",
.digest = "sha384",
.expected_signature_nid = NID_rsassaPss,
.expected_digest_nid = NID_undef,
.expected_public_key_nid = NID_rsaEncryption,
.expected_public_key_bits = 4096,
},
{
.key_type = "rsapss",
Expand All @@ -153,6 +180,8 @@ int main(int argc, char **argv)
.digest = "sha256",
.expected_signature_nid = NID_rsassaPss,
.expected_digest_nid = NID_undef,
.expected_public_key_nid = NID_rsassaPss,
.expected_public_key_bits = 2048,
},
#endif
};
Expand Down Expand Up @@ -189,18 +218,20 @@ int main(int argc, char **argv)
EXPECT_OK(s2n_openssl_x509_get_cert_info(intermediate, &intermediate_info));
EXPECT_OK(s2n_openssl_x509_get_cert_info(root, &root_info));

/* assert that cert info matches expected values */
EXPECT_EQUAL(leaf_info.signature_nid, test_cases[i].expected_signature_nid);
EXPECT_EQUAL(leaf_info.signature_digest_nid, test_cases[i].expected_digest_nid);
EXPECT_EQUAL(leaf_info.self_signed, false);

/* leaf and intermediate should have the same infos */
EXPECT_EQUAL(memcmp(&leaf_info, &intermediate_info, sizeof(struct s2n_cert_info)), 0);
struct s2n_cert_info expected_info = {
.signature_nid = test_cases[i].expected_signature_nid,
.signature_digest_nid = test_cases[i].expected_digest_nid,
.public_key_nid = test_cases[i].expected_public_key_nid,
.public_key_bits = test_cases[i].expected_public_key_bits,
.self_signed = false,
};

/* root should be self-signed */
EXPECT_EQUAL(root_info.signature_nid, test_cases[i].expected_signature_nid);
EXPECT_EQUAL(root_info.signature_digest_nid, test_cases[i].expected_digest_nid);
EXPECT_EQUAL(root_info.self_signed, true);
jmayclin marked this conversation as resolved.
Show resolved Hide resolved
/* assert that cert info matches expected values */
EXPECT_OK(s2n_test_assert_s2n_cert_info_equality(&leaf_info, &expected_info));
EXPECT_OK(s2n_test_assert_s2n_cert_info_equality(&intermediate_info, &expected_info));
/* root should be self-signed, but otherwise equal */
expected_info.self_signed = true;
EXPECT_OK(s2n_test_assert_s2n_cert_info_equality(&root_info, &expected_info));
}

END_TEST();
Expand Down
Loading
Loading