Skip to content

Commit

Permalink
Bug 1678398 - Add Export/Import functions for HPKE context. r=mt
Browse files Browse the repository at this point in the history
This patch adds and exports two new HPKE functions: `PK11_HPKE_ExportContext` and
`PK11_HPKE_ImportContext`, which are used to export a serialized HPKE context,
then later reimport that context and resume Open and Export operations. Only receiver
contexts are currently supported for export (see the rationale in pk11pub.h).

One other change introduced here is that `PK11_HPKE_GetEncapPubKey` now works as
expected on the receiver side.

If the `wrapKey` argument is provided to the Export/Import functions, then the
symmetric keys are wrapped with AES Key Wrap with Padding (SP800-38F, 6.3)
prior to serialization.

Differential Revision: https://phabricator.services.mozilla.com/D99277

--HG--
extra : moz-landing-system : lando
  • Loading branch information
Kevin Jacobs committed Jan 25, 2021
1 parent e252851 commit 10afb43
Show file tree
Hide file tree
Showing 5 changed files with 432 additions and 1 deletion.
5 changes: 5 additions & 0 deletions automation/abi-check/expected-report-libnss3.so.txt
@@ -0,0 +1,5 @@

2 Added functions:

[A] 'function SECStatus PK11_HPKE_ExportContext(const HpkeContext*, PK11SymKey*, SECItem**)' {PK11_HPKE_ExportContext@@NSS_3.62}
[A] 'function HpkeContext* PK11_HPKE_ImportContext(const SECItem*, PK11SymKey*)' {PK11_HPKE_ImportContext@@NSS_3.62}
125 changes: 125 additions & 0 deletions gtests/pk11_gtest/pk11_hpke_unittest.cc
Expand Up @@ -116,6 +116,32 @@ class HpkeTest {
EXPECT_EQ(msg, opened);
}

void ExportSecret(const ScopedHpkeContext &receiver,
ScopedPK11SymKey &exported) {
std::vector<uint8_t> context = {'c', 't', 'x', 't'};
SECItem context_item = {siBuffer, context.data(),
static_cast<unsigned int>(context.size())};
PK11SymKey *tmp_exported = nullptr;
ASSERT_EQ(SECSuccess, PK11_HPKE_ExportSecret(receiver.get(), &context_item,
64, &tmp_exported));
exported.reset(tmp_exported);
}

void ExportImportRecvContext(ScopedHpkeContext &scoped_cx,
PK11SymKey *wrapping_key) {
SECItem *tmp_exported = nullptr;
EXPECT_EQ(SECSuccess, PK11_HPKE_ExportContext(scoped_cx.get(), wrapping_key,
&tmp_exported));
EXPECT_NE(nullptr, tmp_exported);
ScopedSECItem context(tmp_exported);
scoped_cx.reset();

HpkeContext *tmp_imported =
PK11_HPKE_ImportContext(context.get(), wrapping_key);
EXPECT_NE(nullptr, tmp_imported);
scoped_cx.reset(tmp_imported);
}

bool GenerateKeyPair(ScopedSECKEYPublicKey &pub_key,
ScopedSECKEYPrivateKey &priv_key) {
ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
Expand Down Expand Up @@ -437,6 +463,105 @@ TEST_F(ModeParameterizedTest, BadEncapsulatedPubKey) {
EXPECT_EQ(SEC_ERROR_INVALID_ARGS, PORT_GetError());
}

TEST_P(ModeParameterizedTest, ContextExportImportEncrypt) {
std::vector<uint8_t> msg = {'s', 'e', 'c', 'r', 'e', 't'};
std::vector<uint8_t> aad = {'a', 'a', 'd'};

ScopedHpkeContext sender;
ScopedHpkeContext receiver;
SetUpEphemeralContexts(sender, receiver, std::get<0>(GetParam()),
std::get<1>(GetParam()), std::get<2>(GetParam()),
std::get<3>(GetParam()));
SealOpen(sender, receiver, msg, aad, nullptr);
ExportImportRecvContext(receiver, nullptr);
SealOpen(sender, receiver, msg, aad, nullptr);
}

TEST_P(ModeParameterizedTest, ContextExportImportExport) {
ScopedHpkeContext sender;
ScopedHpkeContext receiver;
ScopedPK11SymKey sender_export;
ScopedPK11SymKey receiver_export;
ScopedPK11SymKey receiver_reexport;
SetUpEphemeralContexts(sender, receiver, std::get<0>(GetParam()),
std::get<1>(GetParam()), std::get<2>(GetParam()),
std::get<3>(GetParam()));
ExportSecret(sender, sender_export);
ExportSecret(receiver, receiver_export);
CheckEquality(sender_export.get(), receiver_export.get());
ExportImportRecvContext(receiver, nullptr);
ExportSecret(receiver, receiver_reexport);
CheckEquality(receiver_export.get(), receiver_reexport.get());
}

TEST_P(ModeParameterizedTest, ContextExportImportWithWrap) {
std::vector<uint8_t> msg = {'s', 'e', 'c', 'r', 'e', 't'};
std::vector<uint8_t> aad = {'a', 'a', 'd'};

// Generate a wrapping key, then use it for export.
ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
ASSERT_TRUE(slot);
ScopedPK11SymKey kek(
PK11_KeyGen(slot.get(), CKM_AES_CBC, nullptr, 16, nullptr));
ASSERT_NE(nullptr, kek);

ScopedHpkeContext sender;
ScopedHpkeContext receiver;
SetUpEphemeralContexts(sender, receiver, std::get<0>(GetParam()),
std::get<1>(GetParam()), std::get<2>(GetParam()),
std::get<3>(GetParam()));
SealOpen(sender, receiver, msg, aad, nullptr);
ExportImportRecvContext(receiver, kek.get());
SealOpen(sender, receiver, msg, aad, nullptr);
}

TEST_P(ModeParameterizedTest, ExportSenderContext) {
std::vector<uint8_t> msg = {'s', 'e', 'c', 'r', 'e', 't'};
std::vector<uint8_t> aad = {'a', 'a', 'd'};

ScopedHpkeContext sender;
ScopedHpkeContext receiver;
SetUpEphemeralContexts(sender, receiver, std::get<0>(GetParam()),
std::get<1>(GetParam()), std::get<2>(GetParam()),
std::get<3>(GetParam()));

SECItem *tmp_exported = nullptr;
EXPECT_EQ(SECFailure,
PK11_HPKE_ExportContext(sender.get(), nullptr, &tmp_exported));
EXPECT_EQ(nullptr, tmp_exported);
EXPECT_EQ(SEC_ERROR_NOT_A_RECIPIENT, PORT_GetError());
}

TEST_P(ModeParameterizedTest, ContextUnwrapBadKey) {
std::vector<uint8_t> msg = {'s', 'e', 'c', 'r', 'e', 't'};
std::vector<uint8_t> aad = {'a', 'a', 'd'};

// Generate a wrapping key, then use it for export.
ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
ASSERT_TRUE(slot);
ScopedPK11SymKey kek(
PK11_KeyGen(slot.get(), CKM_AES_CBC, nullptr, 16, nullptr));
ASSERT_NE(nullptr, kek);
ScopedPK11SymKey not_kek(
PK11_KeyGen(slot.get(), CKM_AES_CBC, nullptr, 16, nullptr));
ASSERT_NE(nullptr, not_kek);
ScopedHpkeContext sender;
ScopedHpkeContext receiver;

SetUpEphemeralContexts(sender, receiver, std::get<0>(GetParam()),
std::get<1>(GetParam()), std::get<2>(GetParam()),
std::get<3>(GetParam()));

SECItem *tmp_exported = nullptr;
EXPECT_EQ(SECSuccess,
PK11_HPKE_ExportContext(receiver.get(), kek.get(), &tmp_exported));
EXPECT_NE(nullptr, tmp_exported);
ScopedSECItem context(tmp_exported);

EXPECT_EQ(nullptr, PK11_HPKE_ImportContext(context.get(), not_kek.get()));
EXPECT_EQ(SEC_ERROR_BAD_DATA, PORT_GetError());
}

TEST_P(ModeParameterizedTest, EphemeralKeys) {
std::vector<uint8_t> msg = {'s', 'e', 'c', 'r', 'e', 't'};
std::vector<uint8_t> aad = {'a', 'a', 'd'};
Expand Down
7 changes: 7 additions & 0 deletions lib/nss/nss.def
Expand Up @@ -1213,3 +1213,10 @@ PK11_PubUnwrapSymKeyWithMechanism;
;+ local:
;+ *;
;+};
;+NSS_3.62 { # NSS 3.62 release
;+ global:
PK11_HPKE_ExportContext;
PK11_HPKE_ImportContext;
;+ local:
;+ *;
;+};

0 comments on commit 10afb43

Please sign in to comment.