Interface for the Integrity Algorithm

This patch defines the interfaces for the integrity algorithm.
It provides the API to verify integrity data of the incoming packet
and to generate integrity data for the outgoing packet.

Change-Id: Ibd645c0ab0d9f4ec26f085353d141f7a3262ab2e
Signed-off-by: Tom Joseph <tomjoseph@in.ibm.com>
diff --git a/Makefile.am b/Makefile.am
index c92b2fc..31e7a87 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -33,7 +33,9 @@
 	comm_module.hpp \
 	comm_module.cpp \
 	main.hpp \
-	main.cpp
+	main.cpp \
+	integrity_algo.hpp \
+	integrity_algo.cpp
 
 netipmid_LDFLAGS = $(SYSTEMD_LIBS) $(CRYPTO_LIBS) $(libmapper_LIBS)
 netipmid_CXXFLAGS = $(SYSTEMD_CFLAGS) $(libmapper_CFLAGS)
diff --git a/integrity_algo.cpp b/integrity_algo.cpp
new file mode 100644
index 0000000..b765e06
--- /dev/null
+++ b/integrity_algo.cpp
@@ -0,0 +1,30 @@
+#include <openssl/hmac.h>
+#include <openssl/sha.h>
+#include "integrity_algo.hpp"
+#include "message_parsers.hpp"
+
+namespace cipher
+{
+
+namespace integrity
+{
+
+Interface::Interface(const Buffer& sik, const Key& addKey, size_t authLength)
+{
+    unsigned int mdLen = 0;
+
+    // Generated K1 for the integrity algorithm with the additional key keyed
+    // with SIK.
+    if (HMAC(EVP_sha1(), sik.data(), sik.size(), addKey.data(),
+             addKey.size(), K1.data(), &mdLen) == NULL)
+    {
+        throw std::runtime_error("Generating Key1 for integrity "
+                                 "algorithm failed");
+    }
+
+    authCodeLength = authLength;
+}
+
+}// namespace integrity
+
+}// namespace cipher
diff --git a/integrity_algo.hpp b/integrity_algo.hpp
new file mode 100644
index 0000000..b9d935a
--- /dev/null
+++ b/integrity_algo.hpp
@@ -0,0 +1,121 @@
+#pragma once
+
+#include <openssl/sha.h>
+#include <array>
+#include <vector>
+
+namespace cipher
+{
+
+namespace integrity
+{
+
+using Buffer = std::vector<uint8_t>;
+using Key = std::array<uint8_t, SHA_DIGEST_LENGTH>;
+
+/*
+ * RSP needs more keying material than can be provided by session integrity key
+ * alone. As a result all keying material for the RSP integrity algorithms
+ * will be generated by processing a pre-defined set of constants using HMAC per
+ * [RFC2104], keyed by SIK. These constants are constructed using a hexadecimal
+ * octet value repeated up to the HMAC block size in length starting with the
+ * constant 01h. This mechanism can be used to derive up to 255
+ * HMAC-block-length pieces of keying material from a single SIK. For the
+ * mandatory integrity algorithm HMAC-SHA1-96, processing the following
+ * constant will generate the required amount of keying material.
+ */
+constexpr Key const1 = { 0x01, 0x01, 0x01, 0x01, 0x01,
+                         0x01, 0x01, 0x01, 0x01, 0x01,
+                         0x01, 0x01, 0x01, 0x01, 0x01,
+                         0x01, 0x01, 0x01, 0x01, 0x01
+                       };
+
+/*
+ * @enum Integrity Algorithms
+ *
+ * The Integrity Algorithm Number specifies the algorithm used to generate the
+ * contents for the AuthCode “signature” field that accompanies authenticated
+ * IPMI v2.0/RMCP+ messages once the session has been established. If the
+ * Integrity Algorithm is none the AuthCode value is not calculated and the
+ * AuthCode field in the message is not present.
+ */
+enum class Algorithms : uint8_t
+{
+    NONE,                  // Mandatory
+    HMAC_SHA1_96,          // Mandatory
+    HMAC_MD5_128,          // Optional
+    MD5_128,               // Optional
+    HMAC_SHA256_128,       // Optional
+};
+
+/*
+ * @class Interface
+ *
+ * Interface is the base class for the Integrity Algorithms.
+ * Unless otherwise specified, the integrity algorithm is applied to the packet
+ * data starting with the AuthType/Format field up to and including the field
+ * that immediately precedes the AuthCode field itself.
+ */
+class Interface
+{
+    public:
+        /*
+         * @brief Constructor for Interface
+         *
+         * @param[in] - Session Integrity Key to generate K1
+         * @param[in] - Additional keying material to generate K1
+         * @param[in] - AuthCode length
+         */
+        explicit Interface(const Buffer& sik,
+                           const Key& addKey,
+                           size_t authLength);
+
+        Interface() = delete;
+        virtual ~Interface() = default;
+        Interface(const Interface&) = default;
+        Interface& operator=(const Interface&) = default;
+        Interface(Interface&&) = default;
+        Interface& operator=(Interface&&) = default;
+
+        /*
+         * @brief Verify the integrity data of the packet
+         *
+         * @param[in] packet - Incoming IPMI packet
+         * @param[in] packetLen - Packet length excluding authCode
+         * @param[in] integrityData - Iterator to the authCode in the packet
+         *
+         * @return true if authcode in the packet is equal to one generated
+         *         using integrity algorithm on the packet data, false otherwise
+         */
+        bool virtual verifyIntegrityData(
+                const Buffer& packet,
+                const size_t packetLen,
+                Buffer::const_iterator integrityData) const = 0;
+
+        /*
+         * @brief Generate integrity data for the outgoing IPMI packet
+         *
+         * @param[in] input - Outgoing IPMI packet
+         *
+         * @return authcode for the outgoing IPMI packet
+         *
+         */
+        Buffer virtual generateIntegrityData(const Buffer& input) const = 0;
+
+        /*
+         * AuthCode field length varies based on the integrity algorithm, for
+         * HMAC-SHA1-96 the authcode field is 12 bytes. For HMAC-SHA256-128 and
+         * HMAC-MD5-128 the authcode field is 16 bytes.
+         */
+        size_t authCodeLength;
+
+    protected:
+
+        // K1 key used to generated the integrity data
+        Key K1;
+};
+
+}// namespace integrity
+
+}// namespace cipher
+