From 00b020acc5a4c747721a5e4e73880dc69d32942b Mon Sep 17 00:00:00 2001 From: "J.C. Jones" Date: Mon, 10 Dec 2018 08:01:16 -0700 Subject: [PATCH] Bug 1521174 - Add some initial S/MIME gtests r=mt Differential Revision: https://phabricator.services.mozilla.com/D17014 --HG-- extra : rebase_source : dcb36675ef858a789669d7bf25642c477327b63a extra : amend_source : 2086c0420366268f7c79d4cc5e40c8455e98a6af --- cpputil/scoped_ptrs_smime.h | 34 +++++++ gtests/manifest.mn | 1 + gtests/smime_gtest/Makefile | 43 +++++++++ gtests/smime_gtest/manifest.mn | 22 +++++ gtests/smime_gtest/smime_gtest.gyp | 30 ++++++ gtests/smime_gtest/smime_unittest.cc | 137 +++++++++++++++++++++++++++ nss.gyp | 1 + tests/gtests/gtests.sh | 2 +- 8 files changed, 269 insertions(+), 1 deletion(-) create mode 100644 cpputil/scoped_ptrs_smime.h create mode 100644 gtests/smime_gtest/Makefile create mode 100644 gtests/smime_gtest/manifest.mn create mode 100644 gtests/smime_gtest/smime_gtest.gyp create mode 100644 gtests/smime_gtest/smime_unittest.cc diff --git a/cpputil/scoped_ptrs_smime.h b/cpputil/scoped_ptrs_smime.h new file mode 100644 index 0000000000..fc235f7ebe --- /dev/null +++ b/cpputil/scoped_ptrs_smime.h @@ -0,0 +1,34 @@ +/* -*- 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/. */ + +#ifndef scoped_ptrs_smime_h__ +#define scoped_ptrs_smime_h__ + +#include +#include "smime.h" + +struct ScopedDeleteSmime { + void operator()(NSSCMSMessage* id) { NSS_CMSMessage_Destroy(id); } +}; + +template +struct ScopedMaybeDeleteSmime { + void operator()(T* ptr) { + if (ptr) { + ScopedDeleteSmime del; + del(ptr); + } + } +}; + +#define SCOPED(x) \ + typedef std::unique_ptr > Scoped##x + +SCOPED(NSSCMSMessage); + +#undef SCOPED + +#endif // scoped_ptrs_smime_h__ diff --git a/gtests/manifest.mn b/gtests/manifest.mn index 18adb3d7db..24d4ce14fb 100644 --- a/gtests/manifest.mn +++ b/gtests/manifest.mn @@ -24,6 +24,7 @@ NSS_SRCDIRS = \ cryptohi_gtest \ der_gtest \ pk11_gtest \ + smime_gtest \ softoken_gtest \ ssl_gtest \ $(SYSINIT_GTEST) \ diff --git a/gtests/smime_gtest/Makefile b/gtests/smime_gtest/Makefile new file mode 100644 index 0000000000..0d547e0803 --- /dev/null +++ b/gtests/smime_gtest/Makefile @@ -0,0 +1,43 @@ +#! gmake +# +# 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/. + +####################################################################### +# (1) Include initial platform-independent assignments (MANDATORY). # +####################################################################### + +include manifest.mn + +####################################################################### +# (2) Include "global" configuration information. (OPTIONAL) # +####################################################################### + +include $(CORE_DEPTH)/coreconf/config.mk + +####################################################################### +# (3) Include "component" configuration information. (OPTIONAL) # +####################################################################### + + +####################################################################### +# (4) Include "local" platform-dependent assignments (OPTIONAL). # +####################################################################### + +include ../common/gtest.mk + +####################################################################### +# (5) Execute "global" rules. (OPTIONAL) # +####################################################################### + +include $(CORE_DEPTH)/coreconf/rules.mk + +####################################################################### +# (6) Execute "component" rules. (OPTIONAL) # +####################################################################### + + +####################################################################### +# (7) Execute "local" rules. (OPTIONAL). # +####################################################################### diff --git a/gtests/smime_gtest/manifest.mn b/gtests/smime_gtest/manifest.mn new file mode 100644 index 0000000000..d3e982ccae --- /dev/null +++ b/gtests/smime_gtest/manifest.mn @@ -0,0 +1,22 @@ +# +# 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/. +CORE_DEPTH = ../.. +DEPTH = ../.. +MODULE = nss + +CPPSRCS = \ + smime_unittest.cc \ + $(NULL) + +INCLUDES += -I$(CORE_DEPTH)/gtests/google_test/gtest/include \ + -I$(CORE_DEPTH)/gtests/common \ + -I$(CORE_DEPTH)/cpputil + +REQUIRES = nspr gtest + +PROGRAM = smime_gtest + +EXTRA_LIBS = $(DIST)/lib/$(LIB_PREFIX)gtest.$(LIB_SUFFIX) $(EXTRA_OBJS) \ + $(DIST)/lib/$(LIB_PREFIX)gtestutil.$(LIB_SUFFIX) diff --git a/gtests/smime_gtest/smime_gtest.gyp b/gtests/smime_gtest/smime_gtest.gyp new file mode 100644 index 0000000000..0ff2804f82 --- /dev/null +++ b/gtests/smime_gtest/smime_gtest.gyp @@ -0,0 +1,30 @@ +# 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/. +{ + 'includes': [ + '../../coreconf/config.gypi', + '../common/gtest.gypi', + ], + 'targets': [ + { + 'target_name': 'smime_gtest', + 'type': 'executable', + 'sources': [ + 'smime_unittest.cc', + '<(DEPTH)/gtests/common/gtests.cc' + ], + 'dependencies': [ + '<(DEPTH)/exports.gyp:nss_exports', + '<(DEPTH)/gtests/google_test/google_test.gyp:gtest', + '<(DEPTH)/lib/util/util.gyp:nssutil3', + '<(DEPTH)/lib/nss/nss.gyp:nss3', + '<(DEPTH)/lib/smime/smime.gyp:smime', + '<(DEPTH)/lib/ssl/ssl.gyp:ssl3', + ] + } + ], + 'variables': { + 'module': 'nss' + } +} diff --git a/gtests/smime_gtest/smime_unittest.cc b/gtests/smime_gtest/smime_unittest.cc new file mode 100644 index 0000000000..385e19a97e --- /dev/null +++ b/gtests/smime_gtest/smime_unittest.cc @@ -0,0 +1,137 @@ +/* -*- 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 + +#include "gtest/gtest.h" + +#include "scoped_ptrs_smime.h" +#include "smime.h" + +namespace nss_test { + +// See bug 1507174; this is a CMS serialization (RFC 5652) that claims to be +// 12336 bytes long, which ensures CMS validates the streaming decoder's +// incorrect length. +static const unsigned char kHugeLenAsn1[] = { + 0x30, 0x82, 0x30, 0x30, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, + 0x0D, 0x01, 0x07, 0x02, 0xA0, 0x82, 0x02, 0x30, 0x30, 0x30, 0x02, + 0x01, 0x30, 0x31, 0x0F, 0x30, 0x0D, 0x06, 0x09, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x00, 0x30, 0x0B, 0x06, + 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x05}; + +// secp256r1 signature with no certs and no attrs +static unsigned char kValidSignature[] = { + 0x30, 0x81, 0xFE, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, + 0x07, 0x02, 0xA0, 0x81, 0xF0, 0x30, 0x81, 0xED, 0x02, 0x01, 0x01, 0x31, + 0x0F, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, + 0x02, 0x01, 0x05, 0x00, 0x30, 0x0B, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, + 0xF7, 0x0D, 0x01, 0x07, 0x01, 0x31, 0x81, 0xC9, 0x30, 0x81, 0xC6, 0x02, + 0x01, 0x01, 0x30, 0x5D, 0x30, 0x45, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, + 0x55, 0x04, 0x06, 0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11, 0x06, + 0x03, 0x55, 0x04, 0x08, 0x0C, 0x0A, 0x53, 0x6F, 0x6D, 0x65, 0x2D, 0x53, + 0x74, 0x61, 0x74, 0x65, 0x31, 0x21, 0x30, 0x1F, 0x06, 0x03, 0x55, 0x04, + 0x0A, 0x0C, 0x18, 0x49, 0x6E, 0x74, 0x65, 0x72, 0x6E, 0x65, 0x74, 0x20, + 0x57, 0x69, 0x64, 0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, + 0x4C, 0x74, 0x64, 0x02, 0x14, 0x6B, 0x22, 0xCA, 0x91, 0xE0, 0x71, 0x97, + 0xEB, 0x45, 0x0D, 0x68, 0xC0, 0xD4, 0xB6, 0xE9, 0x45, 0x38, 0x4C, 0xDD, + 0xA3, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, + 0x02, 0x01, 0x05, 0x00, 0x30, 0x0A, 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, + 0x3D, 0x04, 0x03, 0x02, 0x04, 0x47, 0x30, 0x45, 0x02, 0x20, 0x48, 0xEB, + 0xE6, 0xBA, 0xFC, 0xFD, 0x83, 0xB3, 0xA2, 0xB5, 0x59, 0x35, 0x0C, 0xA1, + 0x31, 0x0E, 0x2F, 0xE3, 0x8D, 0x81, 0xD8, 0xF5, 0x33, 0xE4, 0x83, 0x87, + 0xB1, 0xFD, 0x43, 0x9D, 0x95, 0x7D, 0x02, 0x21, 0x00, 0xD0, 0x05, 0x0E, + 0x05, 0xA6, 0x80, 0x3C, 0x1A, 0xFE, 0x51, 0xFC, 0x4D, 0x1A, 0x25, 0x05, + 0x78, 0xB5, 0x42, 0xF5, 0xDE, 0x4E, 0x8A, 0xF8, 0xE3, 0xD8, 0x52, 0xDC, + 0x2B, 0x73, 0x80, 0x4A, 0x1A}; + +// See bug 1507135; this is a CMS signature that contains only the OID +static unsigned char kTruncatedSignature[] = {0x30, 0x0B, 0x06, 0x09, 0x2A, + 0x86, 0x48, 0x86, 0xF7, 0x0D, + 0x01, 0x07, 0x02}; + +// secp256r1 signature that's truncated by one byte. +static unsigned char kSlightlyTruncatedSignature[] = { + 0x30, 0x81, 0xFE, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, + 0x07, 0x02, 0xA0, 0x81, 0xF0, 0x30, 0x81, 0xED, 0x02, 0x01, 0x01, 0x31, + 0x0F, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, + 0x02, 0x01, 0x05, 0x00, 0x30, 0x0B, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, + 0xF7, 0x0D, 0x01, 0x07, 0x01, 0x31, 0x81, 0xC9, 0x30, 0x81, 0xC6, 0x02, + 0x01, 0x01, 0x30, 0x5D, 0x30, 0x45, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, + 0x55, 0x04, 0x06, 0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11, 0x06, + 0x03, 0x55, 0x04, 0x08, 0x0C, 0x0A, 0x53, 0x6F, 0x6D, 0x65, 0x2D, 0x53, + 0x74, 0x61, 0x74, 0x65, 0x31, 0x21, 0x30, 0x1F, 0x06, 0x03, 0x55, 0x04, + 0x0A, 0x0C, 0x18, 0x49, 0x6E, 0x74, 0x65, 0x72, 0x6E, 0x65, 0x74, 0x20, + 0x57, 0x69, 0x64, 0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, + 0x4C, 0x74, 0x64, 0x02, 0x14, 0x6B, 0x22, 0xCA, 0x91, 0xE0, 0x71, 0x97, + 0xEB, 0x45, 0x0D, 0x68, 0xC0, 0xD4, 0xB6, 0xE9, 0x45, 0x38, 0x4C, 0xDD, + 0xA3, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, + 0x02, 0x01, 0x05, 0x00, 0x30, 0x0A, 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, + 0x3D, 0x04, 0x03, 0x02, 0x04, 0x47, 0x30, 0x45, 0x02, 0x20, 0x48, 0xEB, + 0xE6, 0xBA, 0xFC, 0xFD, 0x83, 0xB3, 0xA2, 0xB5, 0x59, 0x35, 0x0C, 0xA1, + 0x31, 0x0E, 0x2F, 0xE3, 0x8D, 0x81, 0xD8, 0xF5, 0x33, 0xE4, 0x83, 0x87, + 0xB1, 0xFD, 0x43, 0x9D, 0x95, 0x7D, 0x02, 0x21, 0x00, 0xD0, 0x05, 0x0E, + 0x05, 0xA6, 0x80, 0x3C, 0x1A, 0xFE, 0x51, 0xFC, 0x4D, 0x1A, 0x25, 0x05, + 0x78, 0xB5, 0x42, 0xF5, 0xDE, 0x4E, 0x8A, 0xF8, 0xE3, 0xD8, 0x52, 0xDC, + 0x2B, 0x73, 0x80, 0x4A}; + +class SMimeTest : public ::testing::Test {}; + +TEST_F(SMimeTest, InvalidDER) { + PK11SymKey* bulk_key = nullptr; + NSSCMSDecoderContext* dcx = + NSS_CMSDecoder_Start(nullptr, nullptr, nullptr, /* content callback */ + nullptr, nullptr, /* password callback */ + nullptr, /* key callback */ + bulk_key); + ASSERT_NE(nullptr, dcx); + EXPECT_EQ(SECSuccess, NSS_CMSDecoder_Update( + dcx, reinterpret_cast(kHugeLenAsn1), + sizeof(kHugeLenAsn1))); + EXPECT_EQ(nullptr, bulk_key); + ASSERT_FALSE(NSS_CMSDecoder_Finish(dcx)); +} + +TEST_F(SMimeTest, IsSignedValid) { + SECItem sig_der_item = {siBuffer, kValidSignature, sizeof(kValidSignature)}; + + ScopedNSSCMSMessage cms_msg(NSS_CMSMessage_CreateFromDER( + &sig_der_item, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr)); + + ASSERT_TRUE(cms_msg); + + ASSERT_TRUE(NSS_CMSMessage_IsSigned(cms_msg.get())); +} + +TEST_F(SMimeTest, TruncatedCmsSignature) { + SECItem sig_der_item = {siBuffer, kTruncatedSignature, + sizeof(kTruncatedSignature)}; + + ScopedNSSCMSMessage cms_msg(NSS_CMSMessage_CreateFromDER( + &sig_der_item, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr)); + + ASSERT_TRUE(cms_msg); + + ASSERT_FALSE(NSS_CMSMessage_IsSigned(cms_msg.get())); +} + +TEST_F(SMimeTest, SlightlyTruncatedCmsSignature) { + SECItem sig_der_item = {siBuffer, kSlightlyTruncatedSignature, + sizeof(kSlightlyTruncatedSignature)}; + + ScopedNSSCMSMessage cms_msg(NSS_CMSMessage_CreateFromDER( + &sig_der_item, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr)); + + ASSERT_FALSE(cms_msg); + + ASSERT_FALSE(NSS_CMSMessage_IsSigned(cms_msg.get())); +} + +TEST_F(SMimeTest, IsSignedNull) { + ASSERT_FALSE(NSS_CMSMessage_IsSigned(nullptr)); +} + +} // namespace nss_test diff --git a/nss.gyp b/nss.gyp index f328157f14..bd96c837b3 100644 --- a/nss.gyp +++ b/nss.gyp @@ -203,6 +203,7 @@ 'gtests/mozpkix_gtest/mozpkix_gtest.gyp:mozpkix_gtest', 'gtests/nss_bogo_shim/nss_bogo_shim.gyp:nss_bogo_shim', 'gtests/pk11_gtest/pk11_gtest.gyp:pk11_gtest', + 'gtests/smime_gtest/smime_gtest.gyp:smime_gtest', 'gtests/softoken_gtest/softoken_gtest.gyp:softoken_gtest', 'gtests/ssl_gtest/ssl_gtest.gyp:ssl_gtest', 'gtests/util_gtest/util_gtest.gyp:util_gtest', diff --git a/tests/gtests/gtests.sh b/tests/gtests/gtests.sh index 1731de0eb4..f9f3ca81c2 100755 --- a/tests/gtests/gtests.sh +++ b/tests/gtests/gtests.sh @@ -87,7 +87,7 @@ gtest_cleanup() } ################## main ################################################# -GTESTS="${GTESTS:-prng_gtest certhigh_gtest certdb_gtest der_gtest pk11_gtest util_gtest freebl_gtest softoken_gtest sysinit_gtest blake2b_gtest}" +GTESTS="${GTESTS:-prng_gtest certhigh_gtest certdb_gtest der_gtest pk11_gtest util_gtest freebl_gtest softoken_gtest sysinit_gtest blake2b_gtest smime_gtest}" gtest_init "$0" gtest_start gtest_cleanup