2018-09-06 13:47:33 +00:00
|
|
|
/**
|
|
|
|
* Copyright (C) 2017-2018, U.S. Government
|
|
|
|
*/
|
|
|
|
#include <HirsRuntimeException.h>
|
|
|
|
#include <RestfulClientProvisioner.h>
|
|
|
|
#include <Utils.h>
|
|
|
|
#include <Properties.h>
|
|
|
|
|
|
|
|
#include <cpr/cpr.h>
|
|
|
|
|
|
|
|
#include <sstream>
|
|
|
|
#include <string>
|
|
|
|
#include <utility>
|
|
|
|
|
|
|
|
using hirs::exception::HirsRuntimeException;
|
|
|
|
using hirs::log::Logger;
|
|
|
|
using hirs::pb::IdentityClaim;
|
|
|
|
using hirs::pb::IdentityClaimResponse;
|
|
|
|
using hirs::pb::CertificateRequest;
|
|
|
|
using hirs::pb::CertificateResponse;
|
|
|
|
using hirs::properties::Properties;
|
2018-10-12 02:03:25 +00:00
|
|
|
using hirs::json_utils::JSONFieldParser;
|
2018-09-06 13:47:33 +00:00
|
|
|
using hirs::string_utils::binaryToHex;
|
|
|
|
using std::string;
|
|
|
|
using std::stringstream;
|
|
|
|
using std::to_string;
|
|
|
|
|
|
|
|
const Logger RestfulClientProvisioner::LOGGER = Logger::getDefaultLogger();
|
|
|
|
const char * const RestfulClientProvisioner::PROP_FILE_LOC =
|
|
|
|
"/etc/hirs/hirs-site.config";
|
|
|
|
const char * const RestfulClientProvisioner::PROP_ACA_FQDN
|
|
|
|
= "ATTESTATION_CA_FQDN";
|
|
|
|
const char * const RestfulClientProvisioner::PROP_ACA_PORT
|
|
|
|
= "ATTESTATION_CA_PORT";
|
2018-10-12 02:03:25 +00:00
|
|
|
const char * const RestfulClientProvisioner::ACA_ERROR_FIELDNAME
|
|
|
|
= "error";
|
2018-09-06 13:47:33 +00:00
|
|
|
|
|
|
|
RestfulClientProvisioner::RestfulClientProvisioner() {
|
|
|
|
Properties props(PROP_FILE_LOC);
|
|
|
|
acaAddress = props.get(PROP_ACA_FQDN, "localhost");
|
|
|
|
port = std::stoi(props.get(PROP_ACA_PORT, "8443"));
|
|
|
|
}
|
|
|
|
|
|
|
|
RestfulClientProvisioner::RestfulClientProvisioner(
|
|
|
|
const std::string& acaAddress, int acaPort)
|
|
|
|
: acaAddress(acaAddress), port(acaPort) {
|
|
|
|
}
|
|
|
|
|
|
|
|
string RestfulClientProvisioner::getAcaAddress() {
|
|
|
|
return acaAddress;
|
|
|
|
}
|
|
|
|
|
|
|
|
string RestfulClientProvisioner::sendIdentityClaim(
|
|
|
|
IdentityClaim identityClaim) {
|
|
|
|
{
|
|
|
|
stringstream logStream;
|
|
|
|
logStream << "Sending the identity claim to " << acaAddress
|
|
|
|
<< " on port " << port;
|
|
|
|
LOGGER.info(logStream.str());
|
|
|
|
}
|
|
|
|
|
|
|
|
string identityClaimByteString;
|
|
|
|
identityClaim.SerializeToString(&identityClaimByteString);
|
|
|
|
|
|
|
|
// Send serialized Identity Claim to ACA
|
|
|
|
LOGGER.info("Sending Serialized Identity Claim Binary");
|
|
|
|
auto r = cpr::Post(cpr::Url{"https://" + acaAddress + ":" + to_string(port)
|
2023-09-14 13:14:11 +00:00
|
|
|
+ "/HIRS_AttestationCA/portal/"
|
|
|
|
+ "client/identity-claim-tpm2/"
|
2018-09-06 13:47:33 +00:00
|
|
|
+ "process"},
|
|
|
|
cpr::Body{identityClaimByteString},
|
|
|
|
cpr::Header{{"Content-Type",
|
2018-10-12 02:03:25 +00:00
|
|
|
"application/octet-stream"},
|
|
|
|
{"Accept",
|
|
|
|
"application/octet-stream, application/json"}},
|
2018-09-06 13:47:33 +00:00
|
|
|
cpr::VerifySsl{false});
|
|
|
|
|
|
|
|
// Check ACA response, should be 200 if successful
|
|
|
|
if (r.status_code == 200) {
|
|
|
|
if (r.text.size() == 0) {
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
|
|
|
IdentityClaimResponse response;
|
2021-11-24 03:01:16 +00:00
|
|
|
try {
|
|
|
|
response.ParseFromString(r.text);
|
|
|
|
} catch (const google::protobuf::FatalException& e) {
|
|
|
|
LOGGER.error(e.what());
|
|
|
|
stringstream errormsg;
|
|
|
|
errormsg << "Provisioning failed. IdentityClaimResponse "
|
|
|
|
<< "did not contain credential_blob.";
|
|
|
|
throw HirsRuntimeException(errormsg.str(),
|
|
|
|
"RestfulClientProvisioner::sendIdentityClaim");
|
2018-09-06 13:47:33 +00:00
|
|
|
}
|
|
|
|
|
2021-11-24 03:01:16 +00:00
|
|
|
// Convert the nonce blob to hex for logging
|
|
|
|
string blobHex = binaryToHex(response.credential_blob());
|
|
|
|
stringstream logStream;
|
|
|
|
logStream << "Received nonce blob: " << blobHex;
|
|
|
|
LOGGER.info(logStream.str());
|
|
|
|
|
|
|
|
// Return the response
|
|
|
|
return response.SerializeAsString();
|
2018-09-06 13:47:33 +00:00
|
|
|
|
|
|
|
} else {
|
|
|
|
stringstream errormsg;
|
2018-10-12 02:03:25 +00:00
|
|
|
errormsg << "Error communicating with ACA server. "
|
|
|
|
<< "Received response code: " << to_string(r.status_code)
|
2020-08-25 15:36:37 +00:00
|
|
|
<< "\n\nError message from ACA was: "
|
2018-10-12 02:03:25 +00:00
|
|
|
<< JSONFieldParser::parseJsonStringField(r.text,
|
|
|
|
ACA_ERROR_FIELDNAME);
|
2018-09-06 13:47:33 +00:00
|
|
|
throw HirsRuntimeException(errormsg.str(),
|
|
|
|
"RestfulClientProvisioner::sendIdentityClaim");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
string RestfulClientProvisioner::sendAttestationCertificateRequest(
|
|
|
|
CertificateRequest certificateRequest) {
|
|
|
|
string certificateRequestByteString;
|
|
|
|
certificateRequest.SerializeToString(&certificateRequestByteString);
|
|
|
|
|
|
|
|
// Send serialized certificate request to ACA
|
|
|
|
LOGGER.info("Sending Serialized DeviceInfo Binary");
|
|
|
|
auto r = cpr::Post(cpr::Url{"https://" + acaAddress + ":" + to_string(port)
|
2023-09-14 13:14:11 +00:00
|
|
|
+ "/HIRS_AttestationCA/portal/client"
|
2018-09-06 13:47:33 +00:00
|
|
|
+ "/request-certificate-tpm2"},
|
|
|
|
cpr::Body{certificateRequestByteString},
|
|
|
|
cpr::Header{{"Content-Type",
|
2018-10-12 02:03:25 +00:00
|
|
|
"application/octet-stream"},
|
|
|
|
{"Accept",
|
|
|
|
"application/octet-stream, application/json"}},
|
2018-09-06 13:47:33 +00:00
|
|
|
cpr::VerifySsl{false});
|
|
|
|
|
|
|
|
// Check ACA response, should be 200 if successful
|
|
|
|
if (r.status_code == 200) {
|
|
|
|
CertificateResponse response;
|
|
|
|
response.ParseFromString(r.text);
|
|
|
|
|
|
|
|
{
|
|
|
|
// Convert the certificate to hex for logging
|
|
|
|
string certificateHex = binaryToHex(response.certificate());
|
|
|
|
stringstream logStream;
|
|
|
|
logStream << "Received public certificate: " << certificateHex;
|
|
|
|
LOGGER.info(logStream.str());
|
|
|
|
}
|
|
|
|
|
|
|
|
// Return the public attestation certificate
|
2022-02-28 19:18:48 +00:00
|
|
|
// return response.certificate();
|
|
|
|
return response.SerializeAsString();
|
2018-09-06 13:47:33 +00:00
|
|
|
|
|
|
|
} else {
|
|
|
|
stringstream errormsg;
|
2018-10-12 02:03:25 +00:00
|
|
|
errormsg << "Error communicating with ACA server. "
|
2018-09-06 13:47:33 +00:00
|
|
|
<< "Received response code: " << to_string(r.status_code)
|
2018-10-12 02:03:25 +00:00
|
|
|
<< "\n\nError message from ACA was: "
|
|
|
|
<< JSONFieldParser::parseJsonStringField(r.text,
|
|
|
|
ACA_ERROR_FIELDNAME);
|
2018-09-06 13:47:33 +00:00
|
|
|
throw HirsRuntimeException(errormsg.str(),
|
|
|
|
"RestfulClientProvisioner::sendAttestationCertificateRequest");
|
|
|
|
}
|
|
|
|
}
|