diff options
Diffstat (limited to 'security/nss/gtests/cryptohi_gtest/cryptohi_unittest.cc')
-rw-r--r-- | security/nss/gtests/cryptohi_gtest/cryptohi_unittest.cc | 373 |
1 files changed, 373 insertions, 0 deletions
diff --git a/security/nss/gtests/cryptohi_gtest/cryptohi_unittest.cc b/security/nss/gtests/cryptohi_gtest/cryptohi_unittest.cc new file mode 100644 index 000000000..ab553ee01 --- /dev/null +++ b/security/nss/gtests/cryptohi_gtest/cryptohi_unittest.cc @@ -0,0 +1,373 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include <string> + +#include "gtest/gtest.h" + +#include "scoped_ptrs.h" +#include "cryptohi.h" +#include "secitem.h" +#include "secerr.h" + +namespace nss_test { + +class SignParamsTestF : public ::testing::Test { + protected: + ScopedPLArenaPool arena_; + ScopedSECKEYPrivateKey privk_; + ScopedSECKEYPublicKey pubk_; + ScopedSECKEYPrivateKey ecPrivk_; + ScopedSECKEYPublicKey ecPubk_; + + void SetUp() { + arena_.reset(PORT_NewArena(2048)); + + SECKEYPublicKey *pubk; + SECKEYPrivateKey *privk = SECKEY_CreateRSAPrivateKey(1024, &pubk, NULL); + ASSERT_NE(nullptr, pubk); + pubk_.reset(pubk); + ASSERT_NE(nullptr, privk); + privk_.reset(privk); + + SECKEYECParams ecParams = {siBuffer, NULL, 0}; + SECOidData *oidData; + oidData = SECOID_FindOIDByTag(SEC_OID_CURVE25519); + ASSERT_NE(nullptr, oidData); + ASSERT_NE(nullptr, + SECITEM_AllocItem(NULL, &ecParams, (2 + oidData->oid.len))) + << "Couldn't allocate memory for OID."; + ecParams.data[0] = SEC_ASN1_OBJECT_ID; /* we have to prepend 0x06 */ + ecParams.data[1] = oidData->oid.len; + memcpy(ecParams.data + 2, oidData->oid.data, oidData->oid.len); + SECKEYPublicKey *ecPubk; + SECKEYPrivateKey *ecPrivk = + SECKEY_CreateECPrivateKey(&ecParams, &ecPubk, NULL); + ASSERT_NE(nullptr, ecPubk); + ecPubk_.reset(ecPubk); + ASSERT_NE(nullptr, ecPrivk); + ecPrivk_.reset(ecPrivk); + } + + void CreatePssParams(SECKEYRSAPSSParams *params, SECOidTag hashAlgTag) { + PORT_Memset(params, 0, sizeof(SECKEYRSAPSSParams)); + + params->hashAlg = (SECAlgorithmID *)PORT_ArenaZAlloc( + arena_.get(), sizeof(SECAlgorithmID)); + ASSERT_NE(nullptr, params->hashAlg); + SECStatus rv = + SECOID_SetAlgorithmID(arena_.get(), params->hashAlg, hashAlgTag, NULL); + ASSERT_EQ(SECSuccess, rv); + } + + void CreatePssParams(SECKEYRSAPSSParams *params, SECOidTag hashAlgTag, + SECOidTag maskHashAlgTag) { + CreatePssParams(params, hashAlgTag); + + SECAlgorithmID maskHashAlg; + PORT_Memset(&maskHashAlg, 0, sizeof(maskHashAlg)); + SECStatus rv = + SECOID_SetAlgorithmID(arena_.get(), &maskHashAlg, maskHashAlgTag, NULL); + ASSERT_EQ(SECSuccess, rv); + + SECItem *maskHashAlgItem = + SEC_ASN1EncodeItem(arena_.get(), NULL, &maskHashAlg, + SEC_ASN1_GET(SECOID_AlgorithmIDTemplate)); + + params->maskAlg = (SECAlgorithmID *)PORT_ArenaZAlloc( + arena_.get(), sizeof(SECAlgorithmID)); + ASSERT_NE(nullptr, params->maskAlg); + + rv = SECOID_SetAlgorithmID(arena_.get(), params->maskAlg, + SEC_OID_PKCS1_MGF1, maskHashAlgItem); + ASSERT_EQ(SECSuccess, rv); + } + + void CreatePssParams(SECKEYRSAPSSParams *params, SECOidTag hashAlgTag, + SECOidTag maskHashAlgTag, unsigned long saltLength) { + CreatePssParams(params, hashAlgTag, maskHashAlgTag); + + SECItem *saltLengthItem = + SEC_ASN1EncodeInteger(arena_.get(), ¶ms->saltLength, saltLength); + ASSERT_EQ(¶ms->saltLength, saltLengthItem); + } + + void CheckHashAlg(SECKEYRSAPSSParams *params, SECOidTag hashAlgTag) { + // If hash algorithm is SHA-1, it must be omitted in the parameters + if (hashAlgTag == SEC_OID_SHA1) { + EXPECT_EQ(nullptr, params->hashAlg); + } else { + EXPECT_NE(nullptr, params->hashAlg); + EXPECT_EQ(hashAlgTag, SECOID_GetAlgorithmTag(params->hashAlg)); + } + } + + void CheckMaskAlg(SECKEYRSAPSSParams *params, SECOidTag hashAlgTag) { + SECStatus rv; + + // If hash algorithm is SHA-1, it must be omitted in the parameters + if (hashAlgTag == SEC_OID_SHA1) + EXPECT_EQ(nullptr, params->hashAlg); + else { + EXPECT_NE(nullptr, params->maskAlg); + EXPECT_EQ(SEC_OID_PKCS1_MGF1, SECOID_GetAlgorithmTag(params->maskAlg)); + + SECAlgorithmID hashAlg; + rv = SEC_QuickDERDecodeItem(arena_.get(), &hashAlg, + SEC_ASN1_GET(SECOID_AlgorithmIDTemplate), + ¶ms->maskAlg->parameters); + ASSERT_EQ(SECSuccess, rv); + + EXPECT_EQ(hashAlgTag, SECOID_GetAlgorithmTag(&hashAlg)); + } + } + + void CheckSaltLength(SECKEYRSAPSSParams *params, SECOidTag hashAlg) { + // If the salt length parameter is missing, that means it is 20 (default) + if (!params->saltLength.data) { + return; + } + + unsigned long value; + SECStatus rv = SEC_ASN1DecodeInteger(¶ms->saltLength, &value); + ASSERT_EQ(SECSuccess, rv); + + // The salt length are usually the same as the hash length, + // except for the case where the hash length exceeds the limit + // set by the key length + switch (hashAlg) { + case SEC_OID_SHA1: + EXPECT_EQ(20UL, value); + break; + case SEC_OID_SHA224: + EXPECT_EQ(28UL, value); + break; + case SEC_OID_SHA256: + EXPECT_EQ(32UL, value); + break; + case SEC_OID_SHA384: + EXPECT_EQ(48UL, value); + break; + case SEC_OID_SHA512: + // Truncated from 64, because our private key is 1024-bit + EXPECT_EQ(62UL, value); + break; + default: + FAIL(); + } + } +}; + +class SignParamsTest + : public SignParamsTestF, + public ::testing::WithParamInterface<std::tuple<SECOidTag, SECOidTag>> {}; + +class SignParamsSourceTest : public SignParamsTestF, + public ::testing::WithParamInterface<SECOidTag> {}; + +TEST_P(SignParamsTest, CreateRsa) { + SECOidTag hashAlg = std::get<0>(GetParam()); + SECOidTag srcHashAlg = std::get<1>(GetParam()); + + SECItem *srcParams; + if (srcHashAlg != SEC_OID_UNKNOWN) { + SECKEYRSAPSSParams pssParams; + ASSERT_NO_FATAL_FAILURE( + CreatePssParams(&pssParams, srcHashAlg, srcHashAlg)); + srcParams = SEC_ASN1EncodeItem(arena_.get(), nullptr, &pssParams, + SEC_ASN1_GET(SECKEY_RSAPSSParamsTemplate)); + ASSERT_NE(nullptr, srcParams); + } else { + srcParams = NULL; + } + + SECItem *params = SEC_CreateSignatureAlgorithmParameters( + arena_.get(), nullptr, SEC_OID_PKCS1_RSA_ENCRYPTION, hashAlg, srcParams, + privk_.get()); + + // PKCS#1 RSA actually doesn't take any parameters, but if it is + // given, return a copy of it + if (srcHashAlg != SEC_OID_UNKNOWN) { + EXPECT_EQ(srcParams->len, params->len); + EXPECT_EQ(0, memcmp(params->data, srcParams->data, srcParams->len)); + } else { + EXPECT_EQ(nullptr, params); + } +} + +TEST_P(SignParamsTest, CreateRsaPss) { + SECOidTag hashAlg = std::get<0>(GetParam()); + SECOidTag srcHashAlg = std::get<1>(GetParam()); + + SECItem *srcParams; + if (srcHashAlg != SEC_OID_UNKNOWN) { + SECKEYRSAPSSParams pssParams; + ASSERT_NO_FATAL_FAILURE( + CreatePssParams(&pssParams, srcHashAlg, srcHashAlg)); + srcParams = SEC_ASN1EncodeItem(arena_.get(), nullptr, &pssParams, + SEC_ASN1_GET(SECKEY_RSAPSSParamsTemplate)); + ASSERT_NE(nullptr, srcParams); + } else { + srcParams = NULL; + } + + SECItem *params = SEC_CreateSignatureAlgorithmParameters( + arena_.get(), nullptr, SEC_OID_PKCS1_RSA_PSS_SIGNATURE, hashAlg, + srcParams, privk_.get()); + + if (hashAlg != SEC_OID_UNKNOWN && srcHashAlg != SEC_OID_UNKNOWN && + hashAlg != srcHashAlg) { + EXPECT_EQ(nullptr, params); + return; + } + + EXPECT_NE(nullptr, params); + + SECKEYRSAPSSParams pssParams; + PORT_Memset(&pssParams, 0, sizeof(pssParams)); + SECStatus rv = + SEC_QuickDERDecodeItem(arena_.get(), &pssParams, + SEC_ASN1_GET(SECKEY_RSAPSSParamsTemplate), params); + ASSERT_EQ(SECSuccess, rv); + + if (hashAlg == SEC_OID_UNKNOWN) { + if (!pssParams.hashAlg) { + hashAlg = SEC_OID_SHA1; + } else { + hashAlg = SECOID_GetAlgorithmTag(pssParams.hashAlg); + } + + if (srcHashAlg == SEC_OID_UNKNOWN) { + // If both hashAlg and srcHashAlg is unset, NSS will decide the hash + // algorithm based on the key length; in this case it's SHA256 + EXPECT_EQ(SEC_OID_SHA256, hashAlg); + } else { + EXPECT_EQ(srcHashAlg, hashAlg); + } + } + + ASSERT_NO_FATAL_FAILURE(CheckHashAlg(&pssParams, hashAlg)); + ASSERT_NO_FATAL_FAILURE(CheckMaskAlg(&pssParams, hashAlg)); + ASSERT_NO_FATAL_FAILURE(CheckSaltLength(&pssParams, hashAlg)); + + // The default trailer field (1) must be omitted + EXPECT_EQ(nullptr, pssParams.trailerField.data); +} + +TEST_P(SignParamsTest, CreateRsaPssWithECPrivateKey) { + SECOidTag hashAlg = std::get<0>(GetParam()); + SECOidTag srcHashAlg = std::get<1>(GetParam()); + + SECItem *srcParams; + if (srcHashAlg != SEC_OID_UNKNOWN) { + SECKEYRSAPSSParams pssParams; + ASSERT_NO_FATAL_FAILURE( + CreatePssParams(&pssParams, srcHashAlg, srcHashAlg)); + srcParams = SEC_ASN1EncodeItem(arena_.get(), nullptr, &pssParams, + SEC_ASN1_GET(SECKEY_RSAPSSParamsTemplate)); + ASSERT_NE(nullptr, srcParams); + } else { + srcParams = NULL; + } + + SECItem *params = SEC_CreateSignatureAlgorithmParameters( + arena_.get(), nullptr, SEC_OID_PKCS1_RSA_PSS_SIGNATURE, hashAlg, + srcParams, ecPrivk_.get()); + + EXPECT_EQ(nullptr, params); +} + +TEST_P(SignParamsTest, CreateRsaPssWithInvalidHashAlg) { + SECOidTag srcHashAlg = std::get<1>(GetParam()); + + SECItem *srcParams; + if (srcHashAlg != SEC_OID_UNKNOWN) { + SECKEYRSAPSSParams pssParams; + ASSERT_NO_FATAL_FAILURE( + CreatePssParams(&pssParams, srcHashAlg, srcHashAlg)); + srcParams = SEC_ASN1EncodeItem(arena_.get(), nullptr, &pssParams, + SEC_ASN1_GET(SECKEY_RSAPSSParamsTemplate)); + ASSERT_NE(nullptr, srcParams); + } else { + srcParams = NULL; + } + + SECItem *params = SEC_CreateSignatureAlgorithmParameters( + arena_.get(), nullptr, SEC_OID_PKCS1_RSA_PSS_SIGNATURE, SEC_OID_MD5, + srcParams, privk_.get()); + + EXPECT_EQ(nullptr, params); +} + +TEST_P(SignParamsSourceTest, CreateRsaPssWithInvalidHashAlg) { + SECOidTag hashAlg = GetParam(); + + SECItem *srcParams; + SECKEYRSAPSSParams pssParams; + ASSERT_NO_FATAL_FAILURE( + CreatePssParams(&pssParams, SEC_OID_MD5, SEC_OID_MD5)); + srcParams = SEC_ASN1EncodeItem(arena_.get(), nullptr, &pssParams, + SEC_ASN1_GET(SECKEY_RSAPSSParamsTemplate)); + ASSERT_NE(nullptr, srcParams); + + SECItem *params = SEC_CreateSignatureAlgorithmParameters( + arena_.get(), nullptr, SEC_OID_PKCS1_RSA_PSS_SIGNATURE, hashAlg, + srcParams, privk_.get()); + + EXPECT_EQ(nullptr, params); +} + +TEST_P(SignParamsSourceTest, CreateRsaPssWithInvalidSaltLength) { + SECOidTag hashAlg = GetParam(); + + SECItem *srcParams; + SECKEYRSAPSSParams pssParams; + ASSERT_NO_FATAL_FAILURE( + CreatePssParams(&pssParams, SEC_OID_SHA512, SEC_OID_SHA512, 100)); + srcParams = SEC_ASN1EncodeItem(arena_.get(), nullptr, &pssParams, + SEC_ASN1_GET(SECKEY_RSAPSSParamsTemplate)); + ASSERT_NE(nullptr, srcParams); + + SECItem *params = SEC_CreateSignatureAlgorithmParameters( + arena_.get(), nullptr, SEC_OID_PKCS1_RSA_PSS_SIGNATURE, hashAlg, + srcParams, privk_.get()); + + EXPECT_EQ(nullptr, params); +} + +TEST_P(SignParamsSourceTest, CreateRsaPssWithHashMismatch) { + SECOidTag hashAlg = GetParam(); + + SECItem *srcParams; + SECKEYRSAPSSParams pssParams; + ASSERT_NO_FATAL_FAILURE( + CreatePssParams(&pssParams, SEC_OID_SHA256, SEC_OID_SHA512)); + srcParams = SEC_ASN1EncodeItem(arena_.get(), nullptr, &pssParams, + SEC_ASN1_GET(SECKEY_RSAPSSParamsTemplate)); + ASSERT_NE(nullptr, srcParams); + + SECItem *params = SEC_CreateSignatureAlgorithmParameters( + arena_.get(), nullptr, SEC_OID_PKCS1_RSA_PSS_SIGNATURE, hashAlg, + srcParams, privk_.get()); + + EXPECT_EQ(nullptr, params); +} + +INSTANTIATE_TEST_CASE_P( + SignParamsTestCases, SignParamsTest, + ::testing::Combine(::testing::Values(SEC_OID_UNKNOWN, SEC_OID_SHA1, + SEC_OID_SHA224, SEC_OID_SHA256, + SEC_OID_SHA384, SEC_OID_SHA512), + ::testing::Values(SEC_OID_UNKNOWN, SEC_OID_SHA1, + SEC_OID_SHA224, SEC_OID_SHA256, + SEC_OID_SHA384, SEC_OID_SHA512))); + +INSTANTIATE_TEST_CASE_P(SignParamsSourceTestCases, SignParamsSourceTest, + ::testing::Values(SEC_OID_UNKNOWN, SEC_OID_SHA1, + SEC_OID_SHA224, SEC_OID_SHA256, + SEC_OID_SHA384, SEC_OID_SHA512)); + +} // namespace nss_test |