xref: /openbmc/phosphor-net-ipmid/command/rakp34.cpp (revision 818d07013f15e80ee3a8e11a68e39c6ac6582abc)
150fb50a9STom Joseph #include "rakp34.hpp"
250fb50a9STom Joseph 
350fb50a9STom Joseph #include <algorithm>
450fb50a9STom Joseph #include <cstring>
550fb50a9STom Joseph #include <iostream>
650fb50a9STom Joseph 
750fb50a9STom Joseph #include "comm_module.hpp"
850fb50a9STom Joseph #include "endian.hpp"
950fb50a9STom Joseph #include "guid.hpp"
1050fb50a9STom Joseph #include "main.hpp"
1150fb50a9STom Joseph 
1250fb50a9STom Joseph namespace command
1350fb50a9STom Joseph {
1450fb50a9STom Joseph 
1550fb50a9STom Joseph std::vector<uint8_t> RAKP34(std::vector<uint8_t>& inPayload,
1650fb50a9STom Joseph                             const message::Handler& handler)
1750fb50a9STom Joseph {
1850fb50a9STom Joseph     std::cout << ">> RAKP34\n";
1950fb50a9STom Joseph 
2050fb50a9STom Joseph     std::vector<uint8_t> outPayload(sizeof(RAKP4response));
2150fb50a9STom Joseph     auto request = reinterpret_cast<RAKP3request*>(inPayload.data());
2250fb50a9STom Joseph     auto response = reinterpret_cast<RAKP4response*>(outPayload.data());
2350fb50a9STom Joseph 
2450fb50a9STom Joseph     // Check if the RAKP3 Payload Length is as expected
2550fb50a9STom Joseph     if(inPayload.size() != sizeof(RAKP3request))
2650fb50a9STom Joseph     {
2750fb50a9STom Joseph         std::cerr << "RAKP34: Invalid RAKP3 request\n";
2850fb50a9STom Joseph         response->rmcpStatusCode =
2950fb50a9STom Joseph             static_cast<uint8_t>(RAKP_ReturnCode::INVALID_INTEGRITY_VALUE);
3050fb50a9STom Joseph         return outPayload;
3150fb50a9STom Joseph     }
3250fb50a9STom Joseph 
3350fb50a9STom Joseph     // Session ID zero is reserved for Session Setup
3450fb50a9STom Joseph     if(endian::from_ipmi(request->managedSystemSessionID) ==
3550fb50a9STom Joseph                          session::SESSION_ZERO)
3650fb50a9STom Joseph     {
3750fb50a9STom Joseph         std::cerr << "RAKP34: BMC invalid Session ID\n";
3850fb50a9STom Joseph         response->rmcpStatusCode =
3950fb50a9STom Joseph             static_cast<uint8_t>(RAKP_ReturnCode::INVALID_SESSION_ID);
4050fb50a9STom Joseph         return outPayload;
4150fb50a9STom Joseph     }
4250fb50a9STom Joseph 
4350fb50a9STom Joseph     std::shared_ptr<session::Session> session;
4450fb50a9STom Joseph     try
4550fb50a9STom Joseph     {
4650fb50a9STom Joseph         session = (std::get<session::Manager&>(singletonPool).getSession(
4750fb50a9STom Joseph             endian::from_ipmi(request->managedSystemSessionID))).lock();
4850fb50a9STom Joseph     }
4950fb50a9STom Joseph     catch (std::exception& e)
5050fb50a9STom Joseph     {
5150fb50a9STom Joseph         std::cerr << e.what() << "\n";
5250fb50a9STom Joseph         response->rmcpStatusCode =
5350fb50a9STom Joseph             static_cast<uint8_t>(RAKP_ReturnCode::INVALID_SESSION_ID);
5450fb50a9STom Joseph         return outPayload;
5550fb50a9STom Joseph     }
5650fb50a9STom Joseph 
5750fb50a9STom Joseph     session->updateLastTransactionTime();
5850fb50a9STom Joseph 
5950fb50a9STom Joseph     auto authAlgo = session->getAuthAlgo();
6050fb50a9STom Joseph     /*
6150fb50a9STom Joseph      * Key Authentication Code - RAKP 3
6250fb50a9STom Joseph      *
6350fb50a9STom Joseph      * 1) Managed System Random Number - 16 bytes
6450fb50a9STom Joseph      * 2) Remote Console Session ID - 4 bytes
6550fb50a9STom Joseph      * 3) Session Privilege Level - 1 byte
6650fb50a9STom Joseph      * 4) User Name Length Byte - 1 byte (0 for 'null' username)
6750fb50a9STom Joseph      * 5) User Name - variable (absent for 'null' username)
6850fb50a9STom Joseph      */
6950fb50a9STom Joseph 
7050fb50a9STom Joseph     // Remote Console Session ID
7150fb50a9STom Joseph     auto rcSessionID = endian::to_ipmi(session->getRCSessionID());
7250fb50a9STom Joseph 
7350fb50a9STom Joseph     // Session Privilege Level
7450fb50a9STom Joseph     auto sessPrivLevel = static_cast<uint8_t>(session->curPrivLevel);
7550fb50a9STom Joseph 
7650fb50a9STom Joseph     // User Name Length Byte
7750fb50a9STom Joseph     uint8_t userLength = 0;
7850fb50a9STom Joseph 
7950fb50a9STom Joseph     std::vector<uint8_t> input;
8050fb50a9STom Joseph     input.resize(cipher::rakp_auth::BMC_RANDOM_NUMBER_LEN +
8150fb50a9STom Joseph                  sizeof(rcSessionID) + sizeof(sessPrivLevel) +
8250fb50a9STom Joseph                  sizeof(userLength));
8350fb50a9STom Joseph 
8450fb50a9STom Joseph     auto iter = input.begin();
8550fb50a9STom Joseph 
8650fb50a9STom Joseph     // Managed System Random Number
8750fb50a9STom Joseph     std::copy(authAlgo->bmcRandomNum.begin(), authAlgo->bmcRandomNum.end(),
8850fb50a9STom Joseph               iter);
8950fb50a9STom Joseph     std::advance(iter, cipher::rakp_auth::BMC_RANDOM_NUMBER_LEN);
9050fb50a9STom Joseph 
9150fb50a9STom Joseph     // Remote Console Session ID
9250fb50a9STom Joseph     std::copy_n(reinterpret_cast<uint8_t*>(&rcSessionID), sizeof(rcSessionID),
9350fb50a9STom Joseph                 iter);
9450fb50a9STom Joseph     std::advance(iter, sizeof(rcSessionID));
9550fb50a9STom Joseph 
9650fb50a9STom Joseph     // Session Privilege Level
9750fb50a9STom Joseph     std::copy_n(reinterpret_cast<uint8_t*>(&sessPrivLevel),
9850fb50a9STom Joseph                 sizeof(sessPrivLevel), iter);
9950fb50a9STom Joseph     std::advance(iter, sizeof(sessPrivLevel));
10050fb50a9STom Joseph 
10150fb50a9STom Joseph     // User Name Length Byte
10250fb50a9STom Joseph     std::copy_n(&userLength, sizeof(userLength), iter);
10350fb50a9STom Joseph 
10450fb50a9STom Joseph     // Generate Key Exchange Authentication Code - RAKP2
10550fb50a9STom Joseph     auto output = authAlgo->generateHMAC(input);
10650fb50a9STom Joseph 
10750fb50a9STom Joseph     if (std::memcmp(output.data(), request->keyExchangeAuthCode,
10850fb50a9STom Joseph                     output.size()))
10950fb50a9STom Joseph     {
11050fb50a9STom Joseph         std::cerr << "Mismatch in HMAC sent by remote console\n";
11150fb50a9STom Joseph 
11250fb50a9STom Joseph         response->messageTag = request->messageTag;
11350fb50a9STom Joseph         response->rmcpStatusCode = static_cast<uint8_t>
11450fb50a9STom Joseph                                    (RAKP_ReturnCode::INVALID_INTEGRITY_VALUE);
11550fb50a9STom Joseph         response->reserved = 0;
11650fb50a9STom Joseph         response->remoteConsoleSessionID = rcSessionID;
11750fb50a9STom Joseph 
11850fb50a9STom Joseph         //close the session
11950fb50a9STom Joseph         std::get<session::Manager&>(singletonPool).stopSession(
12050fb50a9STom Joseph             session->getBMCSessionID());
12150fb50a9STom Joseph 
12250fb50a9STom Joseph         return outPayload;
12350fb50a9STom Joseph     }
12450fb50a9STom Joseph 
12550fb50a9STom Joseph     /*
12650fb50a9STom Joseph      * Session Integrity Key
12750fb50a9STom Joseph      *
12850fb50a9STom Joseph      * 1) Remote Console Random Number - 16 bytes
12950fb50a9STom Joseph      * 2) Managed System Random Number - 16 bytes
13050fb50a9STom Joseph      * 3) Session Privilege Level - 1 byte
13150fb50a9STom Joseph      * 4) User Name Length Byte - 1 byte (0 for 'null' username)
13250fb50a9STom Joseph      * 5) User Name - variable (absent for 'null' username)
13350fb50a9STom Joseph      */
13450fb50a9STom Joseph 
13550fb50a9STom Joseph     input.clear();
13650fb50a9STom Joseph 
13750fb50a9STom Joseph     input.resize(cipher::rakp_auth::REMOTE_CONSOLE_RANDOM_NUMBER_LEN +
13850fb50a9STom Joseph                  cipher::rakp_auth::BMC_RANDOM_NUMBER_LEN +
13950fb50a9STom Joseph                  sizeof(sessPrivLevel) + sizeof(userLength));
14050fb50a9STom Joseph     iter = input.begin();
14150fb50a9STom Joseph 
14250fb50a9STom Joseph     // Remote Console Random Number
14350fb50a9STom Joseph     std::copy(authAlgo->rcRandomNum.begin(), authAlgo->rcRandomNum.end(),
14450fb50a9STom Joseph               iter);
14550fb50a9STom Joseph     std::advance(iter, cipher::rakp_auth::REMOTE_CONSOLE_RANDOM_NUMBER_LEN);
14650fb50a9STom Joseph 
14750fb50a9STom Joseph     // Managed Console Random Number
14850fb50a9STom Joseph     std::copy(authAlgo->bmcRandomNum.begin(), authAlgo->bmcRandomNum.end(),
14950fb50a9STom Joseph               iter);
15050fb50a9STom Joseph     std::advance(iter, cipher::rakp_auth::BMC_RANDOM_NUMBER_LEN);
15150fb50a9STom Joseph 
15250fb50a9STom Joseph     // Session Privilege Level
15350fb50a9STom Joseph     std::copy_n(reinterpret_cast<uint8_t*>(&sessPrivLevel),
15450fb50a9STom Joseph                 sizeof(sessPrivLevel), iter);
15550fb50a9STom Joseph     std::advance(iter, sizeof(sessPrivLevel));
15650fb50a9STom Joseph 
15750fb50a9STom Joseph     // User Name Length Byte
15850fb50a9STom Joseph     std::copy_n(&userLength, sizeof(userLength), iter);
15950fb50a9STom Joseph 
16050fb50a9STom Joseph     // Generate Session Integrity Key
16150fb50a9STom Joseph     auto sikOutput = authAlgo->generateHMAC(input);
16250fb50a9STom Joseph 
16350fb50a9STom Joseph     // Update the SIK in the Authentication Algo Interface
16450fb50a9STom Joseph     authAlgo->sessionIntegrityKey.insert(authAlgo->sessionIntegrityKey.begin(),
16550fb50a9STom Joseph                                          sikOutput.begin(), sikOutput.end());
16650fb50a9STom Joseph 
16750fb50a9STom Joseph     /*
16850fb50a9STom Joseph      * Integrity Check Value
16950fb50a9STom Joseph      *
17050fb50a9STom Joseph      * 1) Remote Console Random Number - 16 bytes
17150fb50a9STom Joseph      * 2) Managed System Session ID - 4 bytes
17250fb50a9STom Joseph      * 3) Managed System GUID - 16 bytes
17350fb50a9STom Joseph      */
17450fb50a9STom Joseph 
17550fb50a9STom Joseph     // Get Managed System Session ID
17650fb50a9STom Joseph     auto bmcSessionID = endian::to_ipmi(session->getBMCSessionID());
17750fb50a9STom Joseph 
17850fb50a9STom Joseph     input.clear();
17950fb50a9STom Joseph 
18050fb50a9STom Joseph     input.resize(cipher::rakp_auth::REMOTE_CONSOLE_RANDOM_NUMBER_LEN +
18150fb50a9STom Joseph                  sizeof(bmcSessionID) + BMC_GUID_LEN);
18250fb50a9STom Joseph     iter = input.begin();
18350fb50a9STom Joseph 
18450fb50a9STom Joseph     // Remote Console Random Number
18550fb50a9STom Joseph     std::copy(authAlgo->rcRandomNum.begin(), authAlgo->rcRandomNum.end(),
18650fb50a9STom Joseph               iter);
18750fb50a9STom Joseph     std::advance(iter, cipher::rakp_auth::REMOTE_CONSOLE_RANDOM_NUMBER_LEN);
18850fb50a9STom Joseph 
18950fb50a9STom Joseph     // Managed System Session ID
19050fb50a9STom Joseph     std::copy_n(reinterpret_cast<uint8_t*>(&bmcSessionID), sizeof(bmcSessionID),
19150fb50a9STom Joseph                 iter);
19250fb50a9STom Joseph     std::advance(iter, sizeof(bmcSessionID));
19350fb50a9STom Joseph 
19450fb50a9STom Joseph     // Managed System GUID
19550fb50a9STom Joseph     auto guid = getSystemGUID();
19650fb50a9STom Joseph     std::copy_n(guid.data(), guid.size(), iter);
19750fb50a9STom Joseph 
19850fb50a9STom Joseph     // Integrity Check Value
19950fb50a9STom Joseph     auto icv = authAlgo->generateICV(input);
20050fb50a9STom Joseph 
20150fb50a9STom Joseph     outPayload.resize(sizeof(RAKP4response));
20250fb50a9STom Joseph 
20350fb50a9STom Joseph     response->messageTag = request->messageTag;
20450fb50a9STom Joseph     response->rmcpStatusCode = static_cast<uint8_t>(RAKP_ReturnCode::NO_ERROR);
20550fb50a9STom Joseph     response->reserved = 0;
20650fb50a9STom Joseph     response->remoteConsoleSessionID = rcSessionID;
20750fb50a9STom Joseph 
20850fb50a9STom Joseph     // Insert the HMAC output into the payload
20950fb50a9STom Joseph     outPayload.insert(outPayload.end(), icv.begin(), icv.end());
21050fb50a9STom Joseph 
211*818d0701STom Joseph     // Set the Authentication Algorithm to RAKP_HMAC_SHA1
212*818d0701STom Joseph     switch (authAlgo->intAlgo)
213*818d0701STom Joseph     {
214*818d0701STom Joseph         case cipher::integrity::Algorithms::HMAC_SHA1_96:
215*818d0701STom Joseph         {
216*818d0701STom Joseph             session->setIntegrityAlgo(
217*818d0701STom Joseph                     std::make_unique<cipher::integrity::AlgoSHA1>(sikOutput));
218*818d0701STom Joseph             break;
219*818d0701STom Joseph         }
220*818d0701STom Joseph         default:
221*818d0701STom Joseph             break;
222*818d0701STom Joseph     }
223*818d0701STom Joseph 
22450fb50a9STom Joseph     session->state = session::State::ACTIVE;
22550fb50a9STom Joseph 
22650fb50a9STom Joseph     std::cout << "<< RAKP34\n";
22750fb50a9STom Joseph     return outPayload;
22850fb50a9STom Joseph }
22950fb50a9STom Joseph 
23050fb50a9STom Joseph } // namespace command
231