Skip to content

Commit

Permalink
Bug 1666891 - Add PK11_Pub{Wrap,Unwrap}SymKeyWithMechanism r=mt,rrelyea
Browse files Browse the repository at this point in the history
Summary

This is useful for RSA-OAEP support.

The CKM_RSA_PKCS_OAEP mechanism requires a CK_RSA_PKCS_OAEP_PARAMS
be present for PKCS#11 calls. This provides required context for OAEP.
However, PK11_PubWrapSymKey lacks a way of providing this context and
historically silently converted CKM_RSA_PKCS_OAEP to CKM_RSA_PKCS when
a RSA key is provided. Introducing a new call will let us indicate
parameters and potentially support other mechanisms in the future.
This call mirrors the earlier calls introduced for RSA-PSS:
PK11_SignWithMechanism and PK11_VerifyWithMechanism.

The CKM_RSA_PKCS_OAEP mechanism requires a CK_RSA_PKCS_OAEP_PARAMS
be present for PKCS#11 calls. This provides required context for OAEP.
However, PK11_PubUnwrapSymKey lacks a way of providing this context,
and additionally lacked a way of indicating which mechanism type to use
for the unwrap operation (instead detecting it by key type). Introducing
a new call will let us indicate parameters and potentially support other
mechanisms in the future.

Signed-off-by: Alexander Scheel <ascheel@redhat.com>

Differential Revision: https://phabricator.services.mozilla.com/D93424
  • Loading branch information
rjrelyea committed Oct 23, 2020
1 parent 97a762f commit ec5afba
Show file tree
Hide file tree
Showing 5 changed files with 125 additions and 12 deletions.
5 changes: 4 additions & 1 deletion automation/abi-check/expected-report-libnss3.so.txt
@@ -1,5 +1,8 @@

2 Added functions:
4 Added functions:

[A] 'function SECStatus CERT_AddCertToListHeadWithData(CERTCertList*, CERTCertificate*, void*)' {CERT_AddCertToListHeadWithData@@NSS_3.59}
[A] 'function SECStatus CERT_AddCertToListTailWithData(CERTCertList*, CERTCertificate*, void*)' {CERT_AddCertToListTailWithData@@NSS_3.59}
[A] 'function PK11SymKey* PK11_PubUnwrapSymKeyWithMechanism(SECKEYPrivateKey*, CK_MECHANISM_TYPE, SECItem*, SECItem*, CK_MECHANISM_TYPE, CK_ATTRIBUTE_TYPE, int)' {PK11_PubUnwrapSymKeyWithMechanism@@NSS_3.59}
[A] 'function SECStatus PK11_PubWrapSymKeyWithMechanism(SECKEYPublicKey*, CK_MECHANISM_TYPE, SECItem*, PK11SymKey*, SECItem*)' {PK11_PubWrapSymKeyWithMechanism@@NSS_3.59}

67 changes: 67 additions & 0 deletions gtests/pk11_gtest/pk11_rsaoaep_unittest.cc
Expand Up @@ -116,4 +116,71 @@ INSTANTIATE_TEST_CASE_P(
INSTANTIATE_TEST_CASE_P(
WycheproofOaep2048Sha512Sha512Test, RsaOaepWycheproofTest,
::testing::ValuesIn(kRsaOaep2048Sha512Mgf1Sha512WycheproofVectors));

TEST(Pkcs11RsaOaepTest, TestOaepWrapUnwrap) {
const size_t kRsaKeyBits = 2048;
const size_t kwrappedBufLen = 4096;

SECStatus rv = SECFailure;

ScopedSECKEYPrivateKey priv;
ScopedSECKEYPublicKey pub;
PK11RSAGenParams rsa_params;
rsa_params.keySizeInBits = kRsaKeyBits;
rsa_params.pe = 65537;

ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
ASSERT_NE(slot, nullptr);

SECKEYPublicKey* p_pub_tmp = nullptr;
priv.reset(PK11_GenerateKeyPair(slot.get(), CKM_RSA_PKCS_KEY_PAIR_GEN,
&rsa_params, &p_pub_tmp, false, false,
nullptr));
pub.reset(p_pub_tmp);

ASSERT_NE(priv.get(), nullptr);
ASSERT_NE(pub.get(), nullptr);

ScopedPK11SymKey to_wrap(
PK11_KeyGen(slot.get(), CKM_AES_CBC, nullptr, 16, nullptr));

CK_RSA_PKCS_OAEP_PARAMS oaep_params = {CKM_SHA256, CKG_MGF1_SHA256,
CKZ_DATA_SPECIFIED, NULL, 0};

SECItem param = {siBuffer, (unsigned char*)&oaep_params, sizeof(oaep_params)};

ScopedSECItem wrapped(SECITEM_AllocItem(nullptr, nullptr, kwrappedBufLen));
rv = PK11_PubWrapSymKeyWithMechanism(pub.get(), CKM_RSA_PKCS_OAEP, &param,
to_wrap.get(), wrapped.get());
ASSERT_EQ(rv, SECSuccess);

PK11SymKey* p_unwrapped_tmp = nullptr;

// This fails because this method is broken and assumes CKM_RSA_PKCS and
// doesn't understand OAEP.
p_unwrapped_tmp = PK11_PubUnwrapSymKey(priv.get(), wrapped.get(), CKM_AES_CBC,
CKA_DECRYPT, 16);
ASSERT_EQ(p_unwrapped_tmp, nullptr);

ScopedPK11SymKey unwrapped;
p_unwrapped_tmp = PK11_PubUnwrapSymKeyWithMechanism(
priv.get(), CKM_RSA_PKCS_OAEP, &param, wrapped.get(), CKM_AES_CBC,
CKA_DECRYPT, 16);
ASSERT_NE(p_unwrapped_tmp, nullptr);

unwrapped.reset(p_unwrapped_tmp);

// Extract key's value in order to validate decryption worked.
rv = PK11_ExtractKeyValue(to_wrap.get());
ASSERT_EQ(rv, SECSuccess);

rv = PK11_ExtractKeyValue(unwrapped.get());
ASSERT_EQ(rv, SECSuccess);

// References owned by PKCS#11 layer; no need to scope and free.
SECItem* expectedItem = PK11_GetKeyData(to_wrap.get());
SECItem* actualItem = PK11_GetKeyData(unwrapped.get());

ASSERT_EQ(SECITEM_CompareItem(actualItem, expectedItem), 0);
}
} // namespace nss_test
2 changes: 2 additions & 0 deletions lib/nss/nss.def
Expand Up @@ -1208,6 +1208,8 @@ PK11_ImportDataKey;
;+ global:
CERT_AddCertToListHeadWithData;
CERT_AddCertToListTailWithData;
PK11_PubWrapSymKeyWithMechanism;
PK11_PubUnwrapSymKeyWithMechanism;
;+ local:
;+ *;
;+};
12 changes: 12 additions & 0 deletions lib/pk11wrap/pk11pub.h
Expand Up @@ -357,6 +357,11 @@ void *PK11_GetSymKeyUserData(PK11SymKey *symKey);

SECStatus PK11_PubWrapSymKey(CK_MECHANISM_TYPE type, SECKEYPublicKey *pubKey,
PK11SymKey *symKey, SECItem *wrappedKey);
SECStatus PK11_PubWrapSymKeyWithMechanism(SECKEYPublicKey *pubKey,
CK_MECHANISM_TYPE mechType,
SECItem *param,
PK11SymKey *symKey,
SECItem *wrappedKey);
SECStatus PK11_WrapSymKey(CK_MECHANISM_TYPE type, SECItem *params,
PK11SymKey *wrappingKey, PK11SymKey *symKey, SECItem *wrappedKey);
/* move a key to 'slot' optionally set the key attributes according to either
Expand Down Expand Up @@ -451,6 +456,13 @@ PK11SymKey *PK11_UnwrapSymKeyWithFlagsPerm(PK11SymKey *wrappingKey,
*/
PK11SymKey *PK11_PubUnwrapSymKey(SECKEYPrivateKey *key, SECItem *wrapppedKey,
CK_MECHANISM_TYPE target, CK_ATTRIBUTE_TYPE operation, int keySize);
PK11SymKey *PK11_PubUnwrapSymKeyWithMechanism(SECKEYPrivateKey *key,
CK_MECHANISM_TYPE mechType,
SECItem *param,
SECItem *wrapppedKey,
CK_MECHANISM_TYPE target,
CK_ATTRIBUTE_TYPE operation,
int keySize);
PK11SymKey *PK11_PubUnwrapSymKeyWithFlagsPerm(SECKEYPrivateKey *wrappingKey,
SECItem *wrappedKey, CK_MECHANISM_TYPE target,
CK_ATTRIBUTE_TYPE operation, int keySize,
Expand Down
51 changes: 40 additions & 11 deletions lib/pk11wrap/pk11skey.c
Expand Up @@ -1275,13 +1275,23 @@ PK11_ConvertSessionSymKeyToTokenSymKey(PK11SymKey *symk, void *wincx)
symk->type, newKeyID, PR_FALSE /*owner*/, NULL /*wincx*/);
}

/*
* This function does a straight public key wrap (which only RSA can do).
* Use PK11_PubGenKey and PK11_WrapSymKey to implement the FORTEZZA and
* Diffie-Hellman Ciphers. */
/* This function does a straight public key wrap with the CKM_RSA_PKCS
* mechanism. */
SECStatus
PK11_PubWrapSymKey(CK_MECHANISM_TYPE type, SECKEYPublicKey *pubKey,
PK11SymKey *symKey, SECItem *wrappedKey)
{
CK_MECHANISM_TYPE inferred = pk11_mapWrapKeyType(pubKey->keyType);
return PK11_PubWrapSymKeyWithMechanism(pubKey, inferred, NULL, symKey,
wrappedKey);
}

/* This function wraps a symmetric key with a public key, such as with the
* CKM_RSA_PKCS and CKM_RSA_PKCS_OAEP mechanisms. */
SECStatus
PK11_PubWrapSymKeyWithMechanism(SECKEYPublicKey *pubKey,
CK_MECHANISM_TYPE mechType, SECItem *param,
PK11SymKey *symKey, SECItem *wrappedKey)
{
PK11SlotInfo *slot;
CK_ULONG len = wrappedKey->len;
Expand All @@ -1298,7 +1308,7 @@ PK11_PubWrapSymKey(CK_MECHANISM_TYPE type, SECKEYPublicKey *pubKey,
}

/* if this slot doesn't support the mechanism, go to a slot that does */
newKey = pk11_ForceSlot(symKey, type, CKA_ENCRYPT);
newKey = pk11_ForceSlot(symKey, mechType, CKA_ENCRYPT);
if (newKey != NULL) {
symKey = newKey;
}
Expand All @@ -1309,9 +1319,15 @@ PK11_PubWrapSymKey(CK_MECHANISM_TYPE type, SECKEYPublicKey *pubKey,
}

slot = symKey->slot;
mechanism.mechanism = pk11_mapWrapKeyType(pubKey->keyType);
mechanism.pParameter = NULL;
mechanism.ulParameterLen = 0;

mechanism.mechanism = mechType;
if (param == NULL) {
mechanism.pParameter = NULL;
mechanism.ulParameterLen = 0;
} else {
mechanism.pParameter = param->data;
mechanism.ulParameterLen = param->len;
}

id = PK11_ImportPublicKey(slot, pubKey, PR_FALSE);
if (id == CK_INVALID_HANDLE) {
Expand Down Expand Up @@ -2883,20 +2899,33 @@ PK11_UnwrapSymKeyWithFlagsPerm(PK11SymKey *wrappingKey,
wrappingKey->cx, keyTemplate, templateCount, isPerm);
}

/* unwrap a symetric key with a private key. */
/* unwrap a symmetric key with a private key. Only supports CKM_RSA_PKCS. */
PK11SymKey *
PK11_PubUnwrapSymKey(SECKEYPrivateKey *wrappingKey, SECItem *wrappedKey,
CK_MECHANISM_TYPE target, CK_ATTRIBUTE_TYPE operation, int keySize)
{
CK_MECHANISM_TYPE wrapType = pk11_mapWrapKeyType(wrappingKey->keyType);

return PK11_PubUnwrapSymKeyWithMechanism(wrappingKey, wrapType, NULL,
wrappedKey, target, operation,
keySize);
}

/* unwrap a symmetric key with a private key with the given parameters. */
PK11SymKey *
PK11_PubUnwrapSymKeyWithMechanism(SECKEYPrivateKey *wrappingKey,
CK_MECHANISM_TYPE mechType, SECItem *param,
SECItem *wrappedKey, CK_MECHANISM_TYPE target,
CK_ATTRIBUTE_TYPE operation, int keySize)
{
PK11SlotInfo *slot = wrappingKey->pkcs11Slot;

if (SECKEY_HAS_ATTRIBUTE_SET(wrappingKey, CKA_PRIVATE)) {
PK11_HandlePasswordCheck(slot, wrappingKey->wincx);
}

return pk11_AnyUnwrapKey(slot, wrappingKey->pkcs11ID,
wrapType, NULL, wrappedKey, target, operation, keySize,
return pk11_AnyUnwrapKey(slot, wrappingKey->pkcs11ID, mechType, param,
wrappedKey, target, operation, keySize,
wrappingKey->wincx, NULL, 0, PR_FALSE);
}

Expand Down

0 comments on commit ec5afba

Please sign in to comment.