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

Add support for PKCS12_set_mac #2128

Merged
merged 4 commits into from
Feb 5, 2025
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
129 changes: 86 additions & 43 deletions crypto/pkcs8/pkcs12_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -395,6 +395,33 @@ static void TestRoundTrip(const char *password, const char *name,
ASSERT_TRUE(certs2);
ASSERT_TRUE(PKCS12_get_key_and_certs(&key2, certs2.get(), &cbs, password));
bssl::UniquePtr<EVP_PKEY> free_key2(key2);

// Check that writing to a |BIO| does the same thing.
bssl::UniquePtr<BIO> bio(BIO_new(BIO_s_mem()));
ASSERT_TRUE(bio);
ASSERT_TRUE(i2d_PKCS12_bio(bio.get(), pkcs12.get()));
const uint8_t *bio_data;
size_t bio_len;
ASSERT_TRUE(BIO_mem_contents(bio.get(), &bio_data, &bio_len));
EXPECT_EQ(Bytes(bio_data, bio_len), Bytes(der, len));

// Check that the result round-trips with |PKCS12_set_mac| as well. The
// resulting bytes will be different due to the regenerated salt, but |pkcs12|
// should still be in a usable state with the same certs and keys encoded.
uint8_t *der2 = nullptr;
EXPECT_TRUE(PKCS12_set_mac(pkcs12.get(), password, strlen(password), nullptr,
0, mac_iterations, nullptr));
len = i2d_PKCS12(pkcs12.get(), &der2);
ASSERT_GT(len, 0);
bssl::UniquePtr<uint8_t> free_der2(der2);

CBS_init(&cbs, der2, len);
EVP_PKEY *key3 = nullptr;
certs2.reset(sk_X509_new_null());
ASSERT_TRUE(certs2);
ASSERT_TRUE(PKCS12_get_key_and_certs(&key3, certs2.get(), &cbs, password));
bssl::UniquePtr<EVP_PKEY> free_key3(key3);

// Note |EVP_PKEY_cmp| returns one for equality while |X509_cmp| returns zero.
if (key) {
EXPECT_EQ(1, EVP_PKEY_cmp(key2, key.get()));
Expand All @@ -421,15 +448,6 @@ static void TestRoundTrip(const char *password, const char *name,
static_cast<size_t>(actual_name_len)));
}
}

// Check that writing to a |BIO| does the same thing.
bssl::UniquePtr<BIO> bio(BIO_new(BIO_s_mem()));
ASSERT_TRUE(bio);
ASSERT_TRUE(i2d_PKCS12_bio(bio.get(), pkcs12.get()));
const uint8_t *bio_data;
size_t bio_len;
ASSERT_TRUE(BIO_mem_contents(bio.get(), &bio_data, &bio_len));
EXPECT_EQ(Bytes(bio_data, bio_len), Bytes(der, len));
}

TEST(PKCS12Test, RoundTrip) {
Expand Down Expand Up @@ -533,7 +551,7 @@ static bssl::UniquePtr<X509> MakeTestCert(EVP_PKEY *key) {
return x509;
}

static bool PKCS12CreateVector(std::vector<uint8_t> *out, EVP_PKEY *pkey,
static bool PKCS12CreateVector(bssl::UniquePtr<PKCS12> &p12, EVP_PKEY *pkey,
const std::vector<X509 *> &certs) {
bssl::UniquePtr<STACK_OF(X509)> chain(sk_X509_new_null());
if (!chain) {
Expand All @@ -546,31 +564,17 @@ static bool PKCS12CreateVector(std::vector<uint8_t> *out, EVP_PKEY *pkey,
}
}

bssl::UniquePtr<PKCS12> p12(PKCS12_create(kPassword, nullptr /* name */, pkey,
nullptr /* cert */, chain.get(), 0,
0, 0, 0, 0));
p12.reset(PKCS12_create(kPassword, nullptr /* name */, pkey,
nullptr /* cert */, chain.get(), 0, 0, 0, 0, 0));
if (!p12) {
return false;
}

int len = i2d_PKCS12(p12.get(), nullptr);
if (len < 0) {
return false;
}
out->resize(static_cast<size_t>(len));
uint8_t *ptr = out->data();
return i2d_PKCS12(p12.get(), &ptr) == len;
return true;
}

static void ExpectPKCS12Parse(bssl::Span<const uint8_t> in,
static void ExpectPKCS12Parse(bssl::UniquePtr<PKCS12> &p12,
EVP_PKEY *expect_key, X509 *expect_cert,
const std::vector<X509 *> &expect_ca_certs) {
bssl::UniquePtr<BIO> bio(BIO_new_mem_buf(in.data(), in.size()));
ASSERT_TRUE(bio);

bssl::UniquePtr<PKCS12> p12(d2i_PKCS12_bio(bio.get(), nullptr));
ASSERT_TRUE(p12);

EVP_PKEY *key = nullptr;
X509 *cert = nullptr;
STACK_OF(X509) *ca_certs = nullptr;
Expand Down Expand Up @@ -618,33 +622,32 @@ TEST(PKCS12Test, Order) {
ASSERT_TRUE(cert3);

// PKCS12_parse uses the key to select the main certificate.
std::vector<uint8_t> p12;
ASSERT_TRUE(PKCS12CreateVector(&p12, key1.get(),
bssl::UniquePtr<PKCS12> p12;
ASSERT_TRUE(PKCS12CreateVector(p12, key1.get(),
{cert1.get(), cert2.get(), cert3.get()}));
ExpectPKCS12Parse(p12, key1.get(), cert1.get(), {cert2.get(), cert3.get()});

ASSERT_TRUE(PKCS12CreateVector(&p12, key1.get(),
ASSERT_TRUE(PKCS12CreateVector(p12, key1.get(),
{cert3.get(), cert1.get(), cert2.get()}));
ExpectPKCS12Parse(p12, key1.get(), cert1.get(), {cert3.get(), cert2.get()});

ASSERT_TRUE(PKCS12CreateVector(&p12, key1.get(),
ASSERT_TRUE(PKCS12CreateVector(p12, key1.get(),
{cert2.get(), cert3.get(), cert1.get()}));
ExpectPKCS12Parse(p12, key1.get(), cert1.get(), {cert2.get(), cert3.get()});

// In case of duplicates, the last one is selected. (It is unlikely anything
// depends on which is selected, but we match OpenSSL.)
ASSERT_TRUE(
PKCS12CreateVector(&p12, key1.get(), {cert1.get(), cert1b.get()}));
ASSERT_TRUE(PKCS12CreateVector(p12, key1.get(), {cert1.get(), cert1b.get()}));
ExpectPKCS12Parse(p12, key1.get(), cert1b.get(), {cert1.get()});

// If there is no key, all certificates are returned as "CA" certificates.
ASSERT_TRUE(PKCS12CreateVector(&p12, nullptr,
ASSERT_TRUE(PKCS12CreateVector(p12, nullptr,
{cert1.get(), cert2.get(), cert3.get()}));
ExpectPKCS12Parse(p12, nullptr, nullptr,
{cert1.get(), cert2.get(), cert3.get()});

// The same happens if there is a key, but it does not match any certificate.
ASSERT_TRUE(PKCS12CreateVector(&p12, key1.get(), {cert2.get(), cert3.get()}));
ASSERT_TRUE(PKCS12CreateVector(p12, key1.get(), {cert2.get(), cert3.get()}));
ExpectPKCS12Parse(p12, key1.get(), nullptr, {cert2.get(), cert3.get()});
}

Expand All @@ -663,13 +666,8 @@ TEST(PKCS12Test, CreateWithAlias) {
ASSERT_EQ(res, 1);

std::vector<X509 *> certs = {cert1.get(), cert2.get()};
std::vector<uint8_t> der;
ASSERT_TRUE(PKCS12CreateVector(&der, key.get(), certs));

bssl::UniquePtr<BIO> bio(BIO_new_mem_buf(der.data(), der.size()));
ASSERT_TRUE(bio);
bssl::UniquePtr<PKCS12> p12(d2i_PKCS12_bio(bio.get(), nullptr));
ASSERT_TRUE(p12);
bssl::UniquePtr<PKCS12> p12;
ASSERT_TRUE(PKCS12CreateVector(p12, key.get(), certs));

EVP_PKEY *parsed_key = nullptr;
X509 *parsed_cert = nullptr;
Expand All @@ -695,3 +693,48 @@ TEST(PKCS12Test, BasicAlloc) {
bssl::UniquePtr<PKCS12> p12(PKCS12_new());
ASSERT_TRUE(p12);
}

TEST(PKCS12Test, SetMac) {
bssl::UniquePtr<EVP_PKEY> key1 = MakeTestKey();
ASSERT_TRUE(key1);
bssl::UniquePtr<X509> cert1 = MakeTestCert(key1.get());
ASSERT_TRUE(cert1);
bssl::UniquePtr<X509> cert1b = MakeTestCert(key1.get());
ASSERT_TRUE(cert1b);
bssl::UniquePtr<EVP_PKEY> key2 = MakeTestKey();
ASSERT_TRUE(key2);
bssl::UniquePtr<X509> cert2 = MakeTestCert(key2.get());
ASSERT_TRUE(cert2);
bssl::UniquePtr<EVP_PKEY> key3 = MakeTestKey();
ASSERT_TRUE(key3);
bssl::UniquePtr<X509> cert3 = MakeTestCert(key3.get());
ASSERT_TRUE(cert3);

// PKCS12_parse uses the key to select the main certificate.
bssl::UniquePtr<PKCS12> p12;
ASSERT_TRUE(PKCS12CreateVector(p12, key1.get(),
{cert1.get(), cert2.get(), cert3.get()}));
EXPECT_TRUE(PKCS12_set_mac(p12.get(), kPassword, strlen(kPassword), nullptr,
0, 0, nullptr));
ExpectPKCS12Parse(p12, key1.get(), cert1.get(), {cert2.get(), cert3.get()});

ASSERT_TRUE(PKCS12CreateVector(p12, key1.get(),
{cert3.get(), cert1.get(), cert2.get()}));
EXPECT_TRUE(PKCS12_set_mac(p12.get(), kPassword, strlen(kPassword), nullptr,
0, 0, nullptr));
ExpectPKCS12Parse(p12, key1.get(), cert1.get(), {cert3.get(), cert2.get()});

ASSERT_TRUE(PKCS12CreateVector(p12, key1.get(),
{cert2.get(), cert3.get(), cert1.get()}));
EXPECT_TRUE(PKCS12_set_mac(p12.get(), kPassword, strlen(kPassword), nullptr,
0, 0, nullptr));
ExpectPKCS12Parse(p12, key1.get(), cert1.get(), {cert2.get(), cert3.get()});

// The same password should be used with |PKCS12_create| and |PKCS12_set_mac|.
ASSERT_TRUE(PKCS12CreateVector(p12, key1.get(),
{cert1.get(), cert2.get(), cert3.get()}));
EXPECT_FALSE(PKCS12_set_mac(p12.get(), kUnicodePassword,
strlen(kUnicodePassword), nullptr, 0, 0,
nullptr));
}

Loading
Loading