summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTom Joseph <tomjoseph@in.ibm.com>2017-01-30 19:25:06 +0530
committerPatrick Williams <patrick@stwcx.xyz>2017-02-28 17:00:32 +0000
commit1e5a76a058dda15ec234483152f5fb9b5109589e (patch)
tree9506f67e27c237fff10f3f4351a35c29b1ced5a0
parent1e7aa196037367c44fc7e61903890505a1104615 (diff)
downloadphosphor-net-ipmid-1e5a76a058dda15ec234483152f5fb9b5109589e.tar.gz
phosphor-net-ipmid-1e5a76a058dda15ec234483152f5fb9b5109589e.zip
Enable gtest and write testcases for Integrity & Conf algorithms
Resolves openbmc/openbmc#870 Resolves openbmc/openbmc#447 Change-Id: Idfeaf7b0c458faefc0e825419539f9500ee3ae8c Signed-off-by: Tom Joseph <tomjoseph@in.ibm.com>
-rw-r--r--Makefile.am2
-rw-r--r--configure.ac23
-rw-r--r--test/Makefile.am14
-rw-r--r--test/cipher.cpp336
4 files changed, 374 insertions, 1 deletions
diff --git a/Makefile.am b/Makefile.am
index f4d7856..fbd2116 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -45,3 +45,5 @@ netipmid_CPPFLAGS = -DNET_IPMID_LIB_PATH=\"/usr/lib/net-ipmid/\"
netipmid_LDFLAGS = $(SYSTEMD_LIBS) $(CRYPTO_LIBS) $(libmapper_LIBS) $(LIBADD_DLOPEN) -export-dynamic
netipmid_CXXFLAGS = $(SYSTEMD_CFLAGS) $(libmapper_CFLAGS)
+SUBDIRS = test
+
diff --git a/configure.ac b/configure.ac
index a16ddc8..715bf56 100644
--- a/configure.ac
+++ b/configure.ac
@@ -14,6 +14,27 @@ AC_PROG_MAKE_SET
# Surpress the --with-libtool-sysroot error
LT_INIT
+# Check/set gtest specific functions.
+AX_PTHREAD([GTEST_CPPFLAGS="-DGTEST_HAS_PTHREAD=1"],[GTEST_CPPFLAGS="-DGTEST_HAS_PTHREAD=0"])
+AC_SUBST(GTEST_CPPFLAGS)
+AC_ARG_ENABLE([oe-sdk],
+ AS_HELP_STRING([--enable-oe-sdk], [Link testcases absolutely against OE SDK so they can be ran within it.])
+)
+AC_ARG_VAR(OECORE_TARGET_SYSROOT,
+ [Path to the OE SDK SYSROOT])
+AS_IF([test "x$enable_oe_sdk" == "xyes"],
+ AS_IF([test "x$OECORE_TARGET_SYSROOT" == "x"],
+ AC_MSG_ERROR([OECORE_TARGET_SYSROOT must be set with --enable-oe-sdk])
+ )
+ AC_MSG_NOTICE([Enabling OE-SDK at $OECORE_TARGET_SYSROOT])
+ [
+ testcase_flags="-Wl,-rpath,\${OECORE_TARGET_SYSROOT}/lib"
+ testcase_flags="${testcase_flags} -Wl,-rpath,\${OECORE_TARGET_SYSROOT}/usr/lib"
+ testcase_flags="${testcase_flags} -Wl,-dynamic-linker,`find \${OECORE_TARGET_SYSROOT}/lib/ld-*.so | sort -r -n | head -n1`"
+ ]
+ AC_SUBST([OESDK_TESTCASE_FLAGS], [$testcase_flags])
+)
+
# Checks for typedefs, structures, and compiler characteristics.
AX_CXX_COMPILE_STDCXX_14([noext])
AX_APPEND_COMPILE_FLAGS([-Wall -Werror], [CXXFLAGS])
@@ -31,5 +52,5 @@ AC_CHECK_HEADER(host-ipmid/ipmid-api.h, ,[AC_MSG_ERROR([Could not find host-ipmi
LT_INIT([dlopen disable-static shared])
LT_LIB_DLLOAD
-AC_CONFIG_FILES([Makefile])
+AC_CONFIG_FILES([Makefile test/Makefile])
AC_OUTPUT
diff --git a/test/Makefile.am b/test/Makefile.am
new file mode 100644
index 0000000..b4996d0
--- /dev/null
+++ b/test/Makefile.am
@@ -0,0 +1,14 @@
+AM_CPPFLAGS = -I$(top_srcdir)
+
+# Run all 'check' test programs
+TESTS = $(check_PROGRAMS)
+
+# # Build/add utest to test suite
+check_PROGRAMS = utest
+utest_CPPFLAGS = -Igtest $(GTEST_CPPFLAGS) $(AM_CPPFLAGS)
+utest_CXXFLAGS = $(PTHREAD_CFLAGS)
+utest_LDFLAGS = -lgtest_main -lgtest $(PTHREAD_LIBS) $(OESDK_TESTCASE_FLAGS) $(CRYPTO_LIBS)
+utest_SOURCES = cipher.cpp
+utest_LDADD = \
+ $(top_builddir)/integrity_algo.cpp \
+ $(top_builddir)/crypt_algo.cpp \ No newline at end of file
diff --git a/test/cipher.cpp b/test/cipher.cpp
new file mode 100644
index 0000000..84929d6
--- /dev/null
+++ b/test/cipher.cpp
@@ -0,0 +1,336 @@
+#include <openssl/evp.h>
+#include <openssl/hmac.h>
+#include <openssl/rand.h>
+#include <openssl/sha.h>
+#include <iostream>
+#include <vector>
+#include "crypt_algo.hpp"
+#include "integrity_algo.hpp"
+#include "message_parsers.hpp"
+#include <gtest/gtest.h>
+
+TEST(IntegrityAlgo, HMAC_SHA1_96_GenerateIntegrityDataCheck)
+{
+ /*
+ * Step-1 Generate Integrity Data for the packet, using the implemented API
+ */
+ // Packet = RMCP Session Header (4 bytes) + Packet (8 bytes)
+ std::vector<uint8_t> packet = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };
+
+ // Hardcoded Session Integrity Key
+ std::vector<uint8_t> sik = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
+ 13, 14, 15, 16};
+
+ auto algoPtr = std::make_unique<cipher::integrity::AlgoSHA1>(sik);
+
+ ASSERT_EQ(true, (algoPtr != NULL));
+
+ // Generate the Integrity Data
+ auto response = algoPtr->generateIntegrityData(packet);
+
+ EXPECT_EQ(true, (response.size() ==
+ cipher::integrity::AlgoSHA1::SHA1_96_AUTHCODE_LENGTH));
+
+ /*
+ * Step-2 Generate Integrity data using OpenSSL SHA1 algorithm
+ */
+ cipher::integrity::Key K1;
+ constexpr cipher::integrity::Key const1 = { 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01
+ };
+
+ // Generated K1 for the integrity algorithm with the additional key keyed
+ // with SIK.
+ unsigned int mdLen = 0;
+ if (HMAC(EVP_sha1(), sik.data(), sik.size(), const1.data(),
+ const1.size(), K1.data(), &mdLen) == NULL)
+ {
+ FAIL() << "Generating Key1 failed";
+ }
+
+ mdLen = 0;
+ cipher::integrity::Buffer output(SHA_DIGEST_LENGTH);
+ size_t length = packet.size() - message::parser::RMCP_SESSION_HEADER_SIZE;
+
+ if (HMAC(EVP_sha1(), K1.data(), K1.size(),
+ packet.data() + message::parser::RMCP_SESSION_HEADER_SIZE,
+ length,
+ output.data(), &mdLen) == NULL)
+ {
+ FAIL() << "Generating integrity data failed";
+ }
+
+ output.resize(cipher::integrity::AlgoSHA1::SHA1_96_AUTHCODE_LENGTH);
+
+ /*
+ * Step-3 Check if the integrity data we generated using the implemented API
+ * matches with one generated by OpenSSL SHA1 algorithm.
+ */
+ auto check = std::equal(output.begin(), output.end(), response.begin());
+ EXPECT_EQ(true, check);
+}
+
+TEST(IntegrityAlgo, HMAC_SHA1_96_VerifyIntegrityDataPass)
+{
+ /*
+ * Step-1 Generate Integrity data using OpenSSL SHA1 algorithm
+ */
+
+ // Packet = RMCP Session Header (4 bytes) + Packet (8 bytes)
+ std::vector<uint8_t> packet = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };
+
+ // Hardcoded Session Integrity Key
+ std::vector<uint8_t> sik = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
+ 13, 14, 15, 16};
+
+ cipher::integrity::Key K1;
+ constexpr cipher::integrity::Key const1 = { 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01
+ };
+
+ // Generated K1 for the integrity algorithm with the additional key keyed
+ // with SIK.
+ unsigned int mdLen = 0;
+ if (HMAC(EVP_sha1(), sik.data(), sik.size(), const1.data(),
+ const1.size(), K1.data(), &mdLen) == NULL)
+ {
+ FAIL() << "Generating Key1 failed";
+ }
+
+ mdLen = 0;
+ cipher::integrity::Buffer output(SHA_DIGEST_LENGTH);
+ size_t length = packet.size() - message::parser::RMCP_SESSION_HEADER_SIZE;
+
+ if (HMAC(EVP_sha1(), K1.data(), K1.size(),
+ packet.data() + message::parser::RMCP_SESSION_HEADER_SIZE,
+ length,
+ output.data(), &mdLen) == NULL)
+ {
+ FAIL() << "Generating integrity data failed";
+ }
+
+ output.resize(cipher::integrity::AlgoSHA1::SHA1_96_AUTHCODE_LENGTH);
+
+ /*
+ * Step-2 Insert the integrity data into the packet
+ */
+ auto packetSize = packet.size();
+ packet.insert(packet.end(), output.begin(), output.end());
+
+ // Point to the integrity data in the packet
+ auto integrityIter = packet.cbegin();
+ std::advance(integrityIter, packetSize);
+
+ /*
+ * Step-3 Invoke the verifyIntegrityData API and validate the response
+ */
+
+ auto algoPtr = std::make_unique<cipher::integrity::AlgoSHA1>(sik);
+ ASSERT_EQ(true, (algoPtr != NULL));
+
+ auto check = algoPtr->verifyIntegrityData(
+ packet,
+ packetSize - message::parser::RMCP_SESSION_HEADER_SIZE,
+ integrityIter);
+
+ EXPECT_EQ(true, check);
+}
+
+TEST(IntegrityAlgo, HMAC_SHA1_96_VerifyIntegrityDataFail)
+{
+ /*
+ * Step-1 Add hardcoded Integrity data to the packet
+ */
+
+ // Packet = RMCP Session Header (4 bytes) + Packet (8 bytes)
+ std::vector<uint8_t> packet = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };
+
+ std::vector<uint8_t> integrity = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };
+
+ packet.insert(packet.end(), integrity.begin(), integrity.end());
+
+ // Point to the integrity data in the packet
+ auto integrityIter = packet.cbegin();
+ std::advance(integrityIter, packet.size());
+
+ /*
+ * Step-2 Invoke the verifyIntegrityData API and validate the response
+ */
+
+ // Hardcoded Session Integrity Key
+ std::vector<uint8_t> sik = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
+ 13, 14, 15, 16};
+
+ auto algoPtr = std::make_unique<cipher::integrity::AlgoSHA1>(sik);
+
+ ASSERT_EQ(true, (algoPtr != NULL));
+
+
+ // Verify the Integrity Data
+ auto check = algoPtr->verifyIntegrityData(
+ packet,
+ packet.size() - message::parser::RMCP_SESSION_HEADER_SIZE,
+ integrityIter);
+
+ EXPECT_EQ(false, check);
+}
+
+TEST(CryptAlgo, AES_CBC_128_EncryptPayloadValidate)
+{
+ /*
+ * Step-1 Generate the encrypted data using the implemented API for
+ * AES-CBC-128
+ */
+ std::vector<uint8_t> payload = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };
+
+ // Hardcoded Session Integrity Key
+ std::vector<uint8_t> sik = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
+ 13, 14, 15, 16};
+
+ auto cryptPtr = std::make_unique<cipher::crypt::AlgoAES128>(sik);
+
+ ASSERT_EQ(true, (cryptPtr != NULL));
+
+ auto cipher = cryptPtr->encryptPayload(payload);
+
+ /*
+ * Step-2 Decrypt the encrypted payload using OpenSSL EVP_aes_128_cbc()
+ * implementation
+ */
+
+ EVP_CIPHER_CTX ctx;
+ EVP_CIPHER_CTX_init(&ctx);
+ cipher::crypt::key k2;
+ unsigned int mdLen = 0;
+ constexpr cipher::crypt::key const1 = { 0x02, 0x02, 0x02, 0x02, 0x02,
+ 0x02, 0x02, 0x02, 0x02, 0x02,
+ 0x02, 0x02, 0x02, 0x02, 0x02,
+ 0x02, 0x02, 0x02, 0x02, 0x02
+ };
+
+ // Generated K2 for the confidentiality algorithm with the additional key
+ // keyed with SIK.
+ if (HMAC(EVP_sha1(), sik.data(), sik.size(), const1.data(),
+ const1.size(), k2.data(), &mdLen) == NULL)
+ {
+ FAIL() << "Generating K2 for confidentiality algorithm failed";
+ }
+
+ if (!EVP_DecryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL, k2.data(),
+ cipher.data()))
+ {
+ EVP_CIPHER_CTX_cleanup(&ctx);
+ FAIL() << "EVP_DecryptInit_ex failed for type AES-CBC-128";
+ }
+
+ EVP_CIPHER_CTX_set_padding(&ctx, 0);
+ std::vector<uint8_t> output(
+ cipher.size() + cipher::crypt::AlgoAES128::AESCBC128BlockSize);
+ int outputLen = 0;
+
+ if (!EVP_DecryptUpdate(&ctx, output.data(), &outputLen,
+ cipher.data() +
+ cipher::crypt::AlgoAES128::AESCBC128ConfHeader,
+ cipher.size() -
+ cipher::crypt::AlgoAES128::AESCBC128ConfHeader))
+ {
+ EVP_CIPHER_CTX_cleanup(&ctx);
+ FAIL() << "EVP_DecryptUpdate failed";
+ }
+
+ output.resize(outputLen);
+ EVP_CIPHER_CTX_cleanup(&ctx);
+
+ /*
+ * Step -3 Check if the plain payload matches with the decrypted one
+ */
+ auto check = std::equal(payload.begin(), payload.end(), output.begin());
+ EXPECT_EQ(true, check);
+}
+
+TEST(CryptAlgo, AES_CBC_128_DecryptPayloadValidate)
+{
+ /*
+ * Step-1 Encrypt the payload using OpenSSL EVP_aes_128_cbc()
+ * implementation
+ */
+
+ std::vector<uint8_t> payload = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
+ 13, 14, 15, 16};
+ payload.resize(payload.size() + 1);
+ payload.back() = 0;
+
+ // Hardcoded Session Integrity Key
+ std::vector<uint8_t> sik = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
+ 13, 14, 15, 16};
+ EVP_CIPHER_CTX ctx;
+ EVP_CIPHER_CTX_init(&ctx);
+ cipher::crypt::key k2;
+ unsigned int mdLen = 0;
+ constexpr cipher::crypt::key const1 = { 0x02, 0x02, 0x02, 0x02, 0x02,
+ 0x02, 0x02, 0x02, 0x02, 0x02,
+ 0x02, 0x02, 0x02, 0x02, 0x02,
+ 0x02, 0x02, 0x02, 0x02, 0x02
+ };
+ std::vector<uint8_t> output(
+ payload.size() + cipher::crypt::AlgoAES128::AESCBC128BlockSize);
+
+ if (!RAND_bytes(output.data(),
+ cipher::crypt::AlgoAES128::AESCBC128ConfHeader))
+ {
+ FAIL() << "RAND_bytes failed";
+ }
+
+ // Generated K2 for the confidentiality algorithm with the additional key
+ // keyed with SIK.
+ if (HMAC(EVP_sha1(), sik.data(), sik.size(), const1.data(),
+ const1.size(), k2.data(), &mdLen) == NULL)
+ {
+ FAIL() << "Generating K2 for confidentiality algorithm failed";
+ }
+
+ if (!EVP_EncryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL, k2.data(),
+ output.data()))
+ {
+ EVP_CIPHER_CTX_cleanup(&ctx);
+ FAIL() << "EVP_EncryptInit_ex failed for type AES-CBC-128";
+ }
+
+ EVP_CIPHER_CTX_set_padding(&ctx, 0);
+ int outputLen = 0;
+
+ if (!EVP_EncryptUpdate(&ctx,
+ output.data() +
+ cipher::crypt::AlgoAES128::AESCBC128ConfHeader,
+ &outputLen,
+ payload.data(),
+ payload.size()))
+ {
+ EVP_CIPHER_CTX_cleanup(&ctx);
+ FAIL() << "EVP_EncryptUpdate failed";
+ }
+
+ output.resize(cipher::crypt::AlgoAES128::AESCBC128ConfHeader + outputLen);
+ EVP_CIPHER_CTX_cleanup(&ctx);
+
+ /*
+ * Step-2 Decrypt the encrypted payload using the implemented API for
+ * AES-CBC-128
+ */
+
+ auto cryptPtr = std::make_unique<cipher::crypt::AlgoAES128>(sik);
+
+ ASSERT_EQ(true, (cryptPtr != NULL));
+
+ auto plain = cryptPtr->decryptPayload(output, 0, output.size());
+
+ /*
+ * Step -3 Check if the plain payload matches with the decrypted one
+ */
+ auto check = std::equal(payload.begin(), payload.end(), plain.begin());
+ EXPECT_EQ(true, check);
+}
OpenPOWER on IntegriCloud