150fb50a9STom Joseph #include "rakp34.hpp"
250fb50a9STom Joseph
350fb50a9STom Joseph #include "comm_module.hpp"
450fb50a9STom Joseph #include "endian.hpp"
550fb50a9STom Joseph #include "guid.hpp"
69b307be6SVernon Mauery #include "rmcp.hpp"
72085ae07SVernon Mauery #include "sessions_manager.hpp"
850fb50a9STom Joseph
97b7f25f7SGeorge Liu #include <phosphor-logging/lg2.hpp>
10bc8958feSGeorge Liu
119e801a2bSVernon Mauery #include <algorithm>
129e801a2bSVernon Mauery #include <cstring>
13fc37e59eSVernon Mauery
1450fb50a9STom Joseph namespace command
1550fb50a9STom Joseph {
1650fb50a9STom Joseph
applyIntegrityAlgo(const uint32_t bmcSessionID)17ef02fb3dSTom Joseph void applyIntegrityAlgo(const uint32_t bmcSessionID)
18ef02fb3dSTom Joseph {
192085ae07SVernon Mauery auto session = session::Manager::get().getSession(bmcSessionID);
20ef02fb3dSTom Joseph
21ef02fb3dSTom Joseph auto authAlgo = session->getAuthAlgo();
22ef02fb3dSTom Joseph
23ef02fb3dSTom Joseph switch (authAlgo->intAlgo)
24ef02fb3dSTom Joseph {
25ef02fb3dSTom Joseph case cipher::integrity::Algorithms::HMAC_SHA1_96:
26ef02fb3dSTom Joseph {
27ef02fb3dSTom Joseph session->setIntegrityAlgo(
28ef02fb3dSTom Joseph std::make_unique<cipher::integrity::AlgoSHA1>(
29ef02fb3dSTom Joseph authAlgo->sessionIntegrityKey));
30ef02fb3dSTom Joseph break;
31ef02fb3dSTom Joseph }
327e9e2ef6SVernon Mauery case cipher::integrity::Algorithms::HMAC_SHA256_128:
337e9e2ef6SVernon Mauery {
347e9e2ef6SVernon Mauery session->setIntegrityAlgo(
357e9e2ef6SVernon Mauery std::make_unique<cipher::integrity::AlgoSHA256>(
367e9e2ef6SVernon Mauery authAlgo->sessionIntegrityKey));
377e9e2ef6SVernon Mauery break;
387e9e2ef6SVernon Mauery }
39ef02fb3dSTom Joseph default:
40ef02fb3dSTom Joseph break;
41ef02fb3dSTom Joseph }
42ef02fb3dSTom Joseph }
43ef02fb3dSTom Joseph
applyCryptAlgo(const uint32_t bmcSessionID)444c766eb1STom Joseph void applyCryptAlgo(const uint32_t bmcSessionID)
454c766eb1STom Joseph {
462085ae07SVernon Mauery auto session = session::Manager::get().getSession(bmcSessionID);
474c766eb1STom Joseph
484c766eb1STom Joseph auto authAlgo = session->getAuthAlgo();
494c766eb1STom Joseph
504c766eb1STom Joseph switch (authAlgo->cryptAlgo)
514c766eb1STom Joseph {
524c766eb1STom Joseph case cipher::crypt::Algorithms::AES_CBC_128:
534c766eb1STom Joseph {
549b307be6SVernon Mauery auto intAlgo = session->getIntegrityAlgo();
559e801a2bSVernon Mauery auto k2 = intAlgo->generateKn(authAlgo->sessionIntegrityKey,
569e801a2bSVernon Mauery rmcp::const_2);
579b307be6SVernon Mauery session->setCryptAlgo(
589b307be6SVernon Mauery std::make_unique<cipher::crypt::AlgoAES128>(k2));
594c766eb1STom Joseph break;
604c766eb1STom Joseph }
614c766eb1STom Joseph default:
624c766eb1STom Joseph break;
634c766eb1STom Joseph }
644c766eb1STom Joseph }
654c766eb1STom Joseph
RAKP34(const std::vector<uint8_t> & inPayload,std::shared_ptr<message::Handler> &)6618a45e9dSTom Joseph std::vector<uint8_t> RAKP34(const std::vector<uint8_t>& inPayload,
67be1470ccSGeorge Liu std::shared_ptr<message::Handler>& /* handler */)
6850fb50a9STom Joseph {
6950fb50a9STom Joseph std::vector<uint8_t> outPayload(sizeof(RAKP4response));
7018a45e9dSTom Joseph auto request = reinterpret_cast<const RAKP3request*>(inPayload.data());
7150fb50a9STom Joseph auto response = reinterpret_cast<RAKP4response*>(outPayload.data());
7250fb50a9STom Joseph
7350fb50a9STom Joseph // Check if the RAKP3 Payload Length is as expected
749b307be6SVernon Mauery if (inPayload.size() < sizeof(RAKP3request))
7550fb50a9STom Joseph {
767b7f25f7SGeorge Liu lg2::info("RAKP34: Invalid RAKP3 request");
7750fb50a9STom Joseph response->rmcpStatusCode =
7850fb50a9STom Joseph static_cast<uint8_t>(RAKP_ReturnCode::INVALID_INTEGRITY_VALUE);
7950fb50a9STom Joseph return outPayload;
8050fb50a9STom Joseph }
8150fb50a9STom Joseph
8250fb50a9STom Joseph // Session ID zero is reserved for Session Setup
8350fb50a9STom Joseph if (endian::from_ipmi(request->managedSystemSessionID) ==
84f8a34fc4SSuryakanth Sekar session::sessionZero)
8550fb50a9STom Joseph {
867b7f25f7SGeorge Liu lg2::info("RAKP34: BMC invalid Session ID");
8750fb50a9STom Joseph response->rmcpStatusCode =
8850fb50a9STom Joseph static_cast<uint8_t>(RAKP_ReturnCode::INVALID_SESSION_ID);
8950fb50a9STom Joseph return outPayload;
9050fb50a9STom Joseph }
9150fb50a9STom Joseph
9250fb50a9STom Joseph std::shared_ptr<session::Session> session;
9350fb50a9STom Joseph try
9450fb50a9STom Joseph {
95ae1fda44SVernon Mauery session =
962085ae07SVernon Mauery session::Manager::get().getSession(request->managedSystemSessionID);
9750fb50a9STom Joseph }
9812d199b2SPatrick Williams catch (const std::exception& e)
9950fb50a9STom Joseph {
1007b7f25f7SGeorge Liu lg2::error("RAKP12 : session not found: {ERROR}", "ERROR", e);
10150fb50a9STom Joseph response->rmcpStatusCode =
10250fb50a9STom Joseph static_cast<uint8_t>(RAKP_ReturnCode::INVALID_SESSION_ID);
10350fb50a9STom Joseph return outPayload;
10450fb50a9STom Joseph }
10550fb50a9STom Joseph
10650fb50a9STom Joseph session->updateLastTransactionTime();
10750fb50a9STom Joseph
10850fb50a9STom Joseph auto authAlgo = session->getAuthAlgo();
10950fb50a9STom Joseph /*
11050fb50a9STom Joseph * Key Authentication Code - RAKP 3
11150fb50a9STom Joseph *
11250fb50a9STom Joseph * 1) Managed System Random Number - 16 bytes
11350fb50a9STom Joseph * 2) Remote Console Session ID - 4 bytes
11450fb50a9STom Joseph * 3) Session Privilege Level - 1 byte
11550fb50a9STom Joseph * 4) User Name Length Byte - 1 byte (0 for 'null' username)
11650fb50a9STom Joseph * 5) User Name - variable (absent for 'null' username)
11750fb50a9STom Joseph */
11850fb50a9STom Joseph
11950fb50a9STom Joseph // Remote Console Session ID
12050fb50a9STom Joseph auto rcSessionID = endian::to_ipmi(session->getRCSessionID());
12150fb50a9STom Joseph
12250fb50a9STom Joseph // Session Privilege Level
1234021b1f7STom Joseph auto sessPrivLevel = static_cast<uint8_t>(session->reqMaxPrivLevel);
12450fb50a9STom Joseph
12550fb50a9STom Joseph // User Name Length Byte
12656527b93STom Joseph auto userLength = static_cast<uint8_t>(session->userName.size());
12750fb50a9STom Joseph
12850fb50a9STom Joseph std::vector<uint8_t> input;
12950fb50a9STom Joseph input.resize(cipher::rakp_auth::BMC_RANDOM_NUMBER_LEN +
13050fb50a9STom Joseph sizeof(rcSessionID) + sizeof(sessPrivLevel) +
13156527b93STom Joseph sizeof(userLength) + userLength);
13250fb50a9STom Joseph
13350fb50a9STom Joseph auto iter = input.begin();
13450fb50a9STom Joseph
13550fb50a9STom Joseph // Managed System Random Number
13650fb50a9STom Joseph std::copy(authAlgo->bmcRandomNum.begin(), authAlgo->bmcRandomNum.end(),
13750fb50a9STom Joseph iter);
13850fb50a9STom Joseph std::advance(iter, cipher::rakp_auth::BMC_RANDOM_NUMBER_LEN);
13950fb50a9STom Joseph
14050fb50a9STom Joseph // Remote Console Session ID
14150fb50a9STom Joseph std::copy_n(reinterpret_cast<uint8_t*>(&rcSessionID), sizeof(rcSessionID),
14250fb50a9STom Joseph iter);
14350fb50a9STom Joseph std::advance(iter, sizeof(rcSessionID));
14450fb50a9STom Joseph
14550fb50a9STom Joseph // Session Privilege Level
14650fb50a9STom Joseph std::copy_n(reinterpret_cast<uint8_t*>(&sessPrivLevel),
14750fb50a9STom Joseph sizeof(sessPrivLevel), iter);
14850fb50a9STom Joseph std::advance(iter, sizeof(sessPrivLevel));
14950fb50a9STom Joseph
15050fb50a9STom Joseph // User Name Length Byte
15150fb50a9STom Joseph std::copy_n(&userLength, sizeof(userLength), iter);
15256527b93STom Joseph std::advance(iter, sizeof(userLength));
15356527b93STom Joseph
15456527b93STom Joseph std::copy_n(session->userName.data(), userLength, iter);
15550fb50a9STom Joseph
15650fb50a9STom Joseph // Generate Key Exchange Authentication Code - RAKP2
15750fb50a9STom Joseph auto output = authAlgo->generateHMAC(input);
15850fb50a9STom Joseph
1599b307be6SVernon Mauery if (inPayload.size() != (sizeof(RAKP3request) + output.size()) ||
1609b307be6SVernon Mauery std::memcmp(output.data(), request + 1, output.size()))
16150fb50a9STom Joseph {
1627b7f25f7SGeorge Liu lg2::info("Mismatch in HMAC sent by remote console");
16350fb50a9STom Joseph
16450fb50a9STom Joseph response->messageTag = request->messageTag;
1659e801a2bSVernon Mauery response->rmcpStatusCode =
1669e801a2bSVernon Mauery static_cast<uint8_t>(RAKP_ReturnCode::INVALID_INTEGRITY_VALUE);
16750fb50a9STom Joseph response->reserved = 0;
16850fb50a9STom Joseph response->remoteConsoleSessionID = rcSessionID;
16950fb50a9STom Joseph
17050fb50a9STom Joseph // close the session
1712085ae07SVernon Mauery session::Manager::get().stopSession(session->getBMCSessionID());
17250fb50a9STom Joseph
17350fb50a9STom Joseph return outPayload;
17450fb50a9STom Joseph }
17550fb50a9STom Joseph
17650fb50a9STom Joseph /*
17750fb50a9STom Joseph * Session Integrity Key
17850fb50a9STom Joseph *
17950fb50a9STom Joseph * 1) Remote Console Random Number - 16 bytes
18050fb50a9STom Joseph * 2) Managed System Random Number - 16 bytes
18150fb50a9STom Joseph * 3) Session Privilege Level - 1 byte
18250fb50a9STom Joseph * 4) User Name Length Byte - 1 byte (0 for 'null' username)
18350fb50a9STom Joseph * 5) User Name - variable (absent for 'null' username)
18450fb50a9STom Joseph */
18550fb50a9STom Joseph
18650fb50a9STom Joseph input.clear();
18750fb50a9STom Joseph
18850fb50a9STom Joseph input.resize(cipher::rakp_auth::REMOTE_CONSOLE_RANDOM_NUMBER_LEN +
18950fb50a9STom Joseph cipher::rakp_auth::BMC_RANDOM_NUMBER_LEN +
19056527b93STom Joseph sizeof(sessPrivLevel) + sizeof(userLength) + userLength);
19150fb50a9STom Joseph iter = input.begin();
19250fb50a9STom Joseph
19350fb50a9STom Joseph // Remote Console Random Number
1949e801a2bSVernon Mauery std::copy(authAlgo->rcRandomNum.begin(), authAlgo->rcRandomNum.end(), iter);
19550fb50a9STom Joseph std::advance(iter, cipher::rakp_auth::REMOTE_CONSOLE_RANDOM_NUMBER_LEN);
19650fb50a9STom Joseph
19750fb50a9STom Joseph // Managed Console Random Number
19850fb50a9STom Joseph std::copy(authAlgo->bmcRandomNum.begin(), authAlgo->bmcRandomNum.end(),
19950fb50a9STom Joseph iter);
20050fb50a9STom Joseph std::advance(iter, cipher::rakp_auth::BMC_RANDOM_NUMBER_LEN);
20150fb50a9STom Joseph
20250fb50a9STom Joseph // Session Privilege Level
20350fb50a9STom Joseph std::copy_n(reinterpret_cast<uint8_t*>(&sessPrivLevel),
20450fb50a9STom Joseph sizeof(sessPrivLevel), iter);
20550fb50a9STom Joseph std::advance(iter, sizeof(sessPrivLevel));
20650fb50a9STom Joseph
20750fb50a9STom Joseph // User Name Length Byte
20850fb50a9STom Joseph std::copy_n(&userLength, sizeof(userLength), iter);
20956527b93STom Joseph std::advance(iter, sizeof(userLength));
21056527b93STom Joseph
21156527b93STom Joseph std::copy_n(session->userName.data(), userLength, iter);
21250fb50a9STom Joseph
21350fb50a9STom Joseph // Generate Session Integrity Key
21450fb50a9STom Joseph auto sikOutput = authAlgo->generateHMAC(input);
21550fb50a9STom Joseph
21650fb50a9STom Joseph // Update the SIK in the Authentication Algo Interface
21750fb50a9STom Joseph authAlgo->sessionIntegrityKey.insert(authAlgo->sessionIntegrityKey.begin(),
21850fb50a9STom Joseph sikOutput.begin(), sikOutput.end());
21950fb50a9STom Joseph
22050fb50a9STom Joseph /*
22150fb50a9STom Joseph * Integrity Check Value
22250fb50a9STom Joseph *
22350fb50a9STom Joseph * 1) Remote Console Random Number - 16 bytes
22450fb50a9STom Joseph * 2) Managed System Session ID - 4 bytes
22550fb50a9STom Joseph * 3) Managed System GUID - 16 bytes
22650fb50a9STom Joseph */
22750fb50a9STom Joseph
22850fb50a9STom Joseph // Get Managed System Session ID
22950fb50a9STom Joseph auto bmcSessionID = endian::to_ipmi(session->getBMCSessionID());
23050fb50a9STom Joseph
23150fb50a9STom Joseph input.clear();
23250fb50a9STom Joseph
23350fb50a9STom Joseph input.resize(cipher::rakp_auth::REMOTE_CONSOLE_RANDOM_NUMBER_LEN +
23450fb50a9STom Joseph sizeof(bmcSessionID) + BMC_GUID_LEN);
23550fb50a9STom Joseph iter = input.begin();
23650fb50a9STom Joseph
23750fb50a9STom Joseph // Remote Console Random Number
2389e801a2bSVernon Mauery std::copy(authAlgo->rcRandomNum.begin(), authAlgo->rcRandomNum.end(), iter);
23950fb50a9STom Joseph std::advance(iter, cipher::rakp_auth::REMOTE_CONSOLE_RANDOM_NUMBER_LEN);
24050fb50a9STom Joseph
24150fb50a9STom Joseph // Managed System Session ID
24250fb50a9STom Joseph std::copy_n(reinterpret_cast<uint8_t*>(&bmcSessionID), sizeof(bmcSessionID),
24350fb50a9STom Joseph iter);
24450fb50a9STom Joseph std::advance(iter, sizeof(bmcSessionID));
24550fb50a9STom Joseph
24650fb50a9STom Joseph // Managed System GUID
247*36e3c539SVernon Mauery const Guid& guid = command::getSystemGUID();
248*36e3c539SVernon Mauery std::copy_n(guid.data(), guid.size(), iter);
24950fb50a9STom Joseph
25050fb50a9STom Joseph // Integrity Check Value
25150fb50a9STom Joseph auto icv = authAlgo->generateICV(input);
25250fb50a9STom Joseph
25350fb50a9STom Joseph outPayload.resize(sizeof(RAKP4response));
25450fb50a9STom Joseph
25550fb50a9STom Joseph response->messageTag = request->messageTag;
25650fb50a9STom Joseph response->rmcpStatusCode = static_cast<uint8_t>(RAKP_ReturnCode::NO_ERROR);
25750fb50a9STom Joseph response->reserved = 0;
25850fb50a9STom Joseph response->remoteConsoleSessionID = rcSessionID;
25950fb50a9STom Joseph
26050fb50a9STom Joseph // Insert the HMAC output into the payload
26150fb50a9STom Joseph outPayload.insert(outPayload.end(), icv.begin(), icv.end());
26250fb50a9STom Joseph
263ef02fb3dSTom Joseph // Set the Integrity Algorithm
264ef02fb3dSTom Joseph applyIntegrityAlgo(session->getBMCSessionID());
265818d0701STom Joseph
2664c766eb1STom Joseph // Set the Confidentiality Algorithm
2674c766eb1STom Joseph applyCryptAlgo(session->getBMCSessionID());
2684c766eb1STom Joseph
269f8a34fc4SSuryakanth Sekar session->state(static_cast<uint8_t>(session::State::active));
27050fb50a9STom Joseph return outPayload;
27150fb50a9STom Joseph }
27250fb50a9STom Joseph
27350fb50a9STom Joseph } // namespace command
274