Skip to content

Commit

Permalink
feat: add cert key preferences (#4434)
Browse files Browse the repository at this point in the history
  • Loading branch information
jmayclin authored Feb 23, 2024
1 parent df4c0e6 commit a56e9bf
Show file tree
Hide file tree
Showing 13 changed files with 502 additions and 94 deletions.
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;
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);
RESULT_ENSURE(pubkey != NULL, S2N_ERR_DECODE_CERTIFICATE);

info->public_key_bits = EVP_PKEY_bits(pubkey);
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);
/* 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

0 comments on commit a56e9bf

Please sign in to comment.