Implemenation of the RAKP Authentication Algorithms

This patch contains the implementation of the RAKP-HMAC_SHA1 algorithm
for Authentication.OpenSSL is used for the HMAC operation.

Change-Id: I7e926aca9010443939e32f476c37ac1481cd2476
Signed-off-by: Tom Joseph <tomjoseph@in.ibm.com>
diff --git a/auth_algo.cpp b/auth_algo.cpp
new file mode 100644
index 0000000..d2acebf
--- /dev/null
+++ b/auth_algo.cpp
@@ -0,0 +1,46 @@
+#include "auth_algo.hpp"
+
+#include <openssl/hmac.h>
+#include <openssl/sha.h>
+
+#include <iostream>
+
+namespace cipher
+{
+
+namespace rakp_auth
+{
+
+std::vector<uint8_t> AlgoSHA1::generateHMAC(std::vector<uint8_t>& input) const
+{
+    std::vector<uint8_t> output(SHA_DIGEST_LENGTH);
+    unsigned int mdLen = 0;
+
+    if (HMAC(EVP_sha1(), userKey.data(), userKey.size(), input.data(),
+             input.size(), output.data(), &mdLen) == NULL)
+    {
+        std::cerr << "Generate HMAC failed\n";
+        output.resize(0);
+    }
+
+    return output;
+}
+
+std::vector<uint8_t> AlgoSHA1::generateICV(std::vector<uint8_t>& input) const
+{
+    std::vector<uint8_t> output(SHA_DIGEST_LENGTH);
+    unsigned int mdLen = 0;
+
+    if (HMAC(EVP_sha1(), sessionIntegrityKey.data(), SHA_DIGEST_LENGTH,
+             input.data(), input.size(), output.data(), &mdLen) == NULL)
+    {
+        std::cerr << "Generate Session Integrity Key failed\n";
+        output.resize(0);
+    }
+
+    return output;
+}
+
+} // namespace auth
+
+} // namespace cipher
diff --git a/auth_algo.hpp b/auth_algo.hpp
new file mode 100644
index 0000000..a905778
--- /dev/null
+++ b/auth_algo.hpp
@@ -0,0 +1,132 @@
+#pragma once
+
+#include <array>
+#include <vector>
+
+namespace cipher
+{
+namespace rakp_auth
+{
+
+constexpr size_t USER_KEY_MAX_LENGTH = 20;
+constexpr size_t BMC_RANDOM_NUMBER_LEN = 16;
+constexpr size_t REMOTE_CONSOLE_RANDOM_NUMBER_LEN = 16;
+
+/*
+ * @enum RAKP Authentication Algorithms
+ *
+ * RMCP+ Authenticated Key-Exchange Protocol (RAKP)
+ *
+ * RAKP-None is not supported as per the following recommendation
+ * (https://www.us-cert.gov/ncas/alerts/TA13-207A)
+ * ("cipher 0" is an option enabled by default on many IPMI enabled devices that
+ * allows authentication to be bypassed.  Disable "cipher 0" to prevent
+ * attackers from bypassing authentication and sending arbitrary IPMI commands.)
+ */
+enum class Algorithms : uint8_t
+{
+    RAKP_NONE = 0,              // Mandatory
+    RAKP_HMAC_SHA1,             // Mandatory
+    RAKP_HMAC_MD5,              // Optional
+    RAKP_HMAC_SHA256,           // Optional
+    // Reserved used to indicate an invalid authentication algorithm
+    RAKP_HMAC_INVALID = 0xB0
+};
+
+/*
+ * @class Interface
+ *
+ * Interface is the base class for the Authentication Algorithms.
+ * The Authentication Algorithm specifies the type of authentication “handshake”
+ * process that is used and identifies any particular variations of hashing or
+ * signature algorithm that is used as part of the process.
+ *
+ */
+class Interface
+{
+    public:
+        Interface() = default;
+        virtual ~Interface() = default;
+        Interface(const Interface&) = default;
+        Interface& operator=(const Interface&) = default;
+        Interface(Interface&&) = default;
+        Interface& operator=(Interface&&) = default;
+
+        /*
+         * @brief Generate the Hash Message Authentication Code
+         *
+         * This API is invoked to generate the Key Exchange Authentication Code
+         * in the RAKP2 and RAKP4 sequence and for generating the Session
+         * Integrity Key.
+         *
+         * @param input message
+         *
+         * @return hash output
+         *
+         * @note The user key which is the secret key for the hash operation
+         *        needs to be set before this operation.
+         */
+        std::vector<uint8_t> virtual generateHMAC(
+            std::vector<uint8_t>& input) const = 0;
+
+        /*
+         * @brief Generate the Integrity Check Value
+         *
+         * This API is invoked in the RAKP4 sequence for generating the
+         * Integrity Check Value.
+         *
+         * @param input message
+         *
+         * @return hash output
+         *
+         * @note The session integrity key which is the secret key for the
+         *        hash operation needs to be set before this operation.
+         */
+        std::vector<uint8_t> virtual generateICV(
+            std::vector<uint8_t>& input) const = 0;
+
+        // User Key is hardcoded to PASSW0RD till the IPMI User account
+        // management is in place.
+        std::array<uint8_t, USER_KEY_MAX_LENGTH> userKey = {"PASSW0RD"};
+
+        // Managed System Random Number
+        std::array<uint8_t, BMC_RANDOM_NUMBER_LEN> bmcRandomNum;
+
+        // Remote Console Random Number
+        std::array<uint8_t, REMOTE_CONSOLE_RANDOM_NUMBER_LEN> rcRandomNum;
+
+        // Session Integrity Key
+        std::vector<uint8_t> sessionIntegrityKey;
+};
+
+/*
+ * @class AlgoSHA1
+ *
+ * RAKP-HMAC-SHA1 specifies the use of RAKP messages for the key exchange
+ * portion of establishing the session, and that HMAC-SHA1 (per [RFC2104]) is
+ * used to create 20-byte Key Exchange Authentication Code fields in RAKP
+ * Message 2 and RAKP Message 3. HMAC-SHA1-96(per [RFC2404]) is used for
+ * generating a 12-byte Integrity Check Value field for RAKP Message 4.
+ */
+
+class AlgoSHA1 : public Interface
+{
+    public:
+        AlgoSHA1() = default;
+        ~AlgoSHA1() = default;
+        AlgoSHA1(const AlgoSHA1&) = default;
+        AlgoSHA1& operator=(const AlgoSHA1&) = default;
+        AlgoSHA1(AlgoSHA1&&) = default;
+        AlgoSHA1& operator=(AlgoSHA1&&) = default;
+
+        std::vector<uint8_t> generateHMAC(std::vector<uint8_t>& input) const
+        override;
+
+        std::vector<uint8_t> generateICV(std::vector<uint8_t>& input) const
+        override;
+};
+
+}// namespace auth
+
+}// namespace cipher
+