summaryrefslogtreecommitdiffstats
path: root/integrity_algo.hpp
blob: ac06e069ca69a0b09601eade5775406394ce2ed0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
#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;
};

/*
 * @class AlgoSHA1
 *
 * @brief Implementation of the HMAC-SHA1-96 Integrity algorithm
 *
 * HMAC-SHA1-96 take the Session Integrity Key and use it to generate K1. K1 is
 * then used as the key for use in HMAC to produce the AuthCode field.
 * For “one-key” logins, the user’s key (password) is used in the creation of
 * the Session Integrity Key. When the HMAC-SHA1-96 Integrity Algorithm is used
 * the resulting AuthCode field is 12 bytes (96 bits).
 */
class AlgoSHA1 final : public Interface
{
    public:
        static constexpr size_t SHA1_96_AUTHCODE_LENGTH = 12;

        /*
         * @brief Constructor for AlgoSHA1
         *
         * @param[in] - Session Integrity Key
         */
        explicit AlgoSHA1(const Buffer& sik) :
            Interface(sik, const1, SHA1_96_AUTHCODE_LENGTH) {}

        AlgoSHA1() = delete;
        ~AlgoSHA1() = default;
        AlgoSHA1(const AlgoSHA1&) = default;
        AlgoSHA1& operator=(const AlgoSHA1&) = default;
        AlgoSHA1(AlgoSHA1&&) = default;
        AlgoSHA1& operator=(AlgoSHA1&&) = default;

        /*
         * @brief Verify the integrity data of the packet
         *
         * @param[in] packet - Incoming IPMI packet
         * @param[in] length - Length of the data in the packet to calculate
         *                     the integrity data
         * @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 verifyIntegrityData(
                const Buffer& packet,
                const size_t length,
                Buffer::const_iterator integrityData) const override;

        /*
         * @brief Generate integrity data for the outgoing IPMI packet
         *
         * @param[in] input - Outgoing IPMI packet
         *
         * @return on success return the integrity data for the outgoing IPMI
         *         packet
         */
        Buffer generateIntegrityData(const Buffer& packet) const override;

    private:
        /*
         * @brief Generate HMAC based on HMAC-SHA1-96 algorithm
         *
         * @param[in] input - pointer to the message
         * @param[in] length - length of the message
         *
         * @return on success returns the message authentication code
         *
         */
        Buffer generateHMAC(const uint8_t* input, const size_t len) const;
};

}// namespace integrity

}// namespace cipher

OpenPOWER on IntegriCloud