in source/fleetprovisioning/FleetProvisioning.cpp [37:202]
bool FleetProvisioning::CreateCertificateAndKey(Iotidentity::IotIdentityClient identityClient)
{
LOG_INFO(TAG, "Provisioning new device certificate and private key using CreateKeysAndCertificate API");
auto onKeysAcceptedSubAck = [&](int ioErr) {
if (ioErr != AWS_OP_SUCCESS)
{
LOGM_ERROR(
TAG,
"*** %s: Error subscribing to CreateKeysAndCertificate accepted topic: %s. ***",
DeviceClient::DC_FATAL_ERROR,
ErrorDebugString(ioErr));
}
keysAcceptedCompletedPromise.set_value(ioErr == AWS_OP_SUCCESS);
};
auto onKeysRejectedSubAck = [&](int ioErr) {
if (ioErr != AWS_OP_SUCCESS)
{
LOGM_ERROR(
TAG,
"*** %s: Error subscribing to CreateKeysAndCertificate rejected topic: %s. ***",
DeviceClient::DC_FATAL_ERROR,
ErrorDebugString(ioErr));
}
keysRejectedCompletedPromise.set_value(ioErr == AWS_OP_SUCCESS);
};
auto onKeysPublishSubAck = [&](int ioErr) {
if (ioErr != AWS_OP_SUCCESS)
{
LOGM_ERROR(
TAG,
"*** %s: Error publishing to CreateKeysAndCertificate topic: %s. ***",
DeviceClient::DC_FATAL_ERROR,
ErrorDebugString(ioErr));
}
keysPublishCompletedPromise.set_value(ioErr == AWS_OP_SUCCESS);
};
auto onKeysAccepted = [&](CreateKeysAndCertificateResponse *response, int ioErr) {
if (ioErr == AWS_OP_SUCCESS)
{
LOGM_INFO(TAG, "CreateKeysAndCertificateResponse certificateId: %s.", response->CertificateId->c_str());
certificateOwnershipToken = *response->CertificateOwnershipToken;
Aws::Crt::String certificateID = response->CertificateId->c_str();
ostringstream certPathStream, keyPathStream;
certPathStream << keyDir << certificateID << "-certificate.pem.crt";
keyPathStream << keyDir << certificateID << "-private.pem.key";
certPath = FileUtils::ExtractExpandedPath(certPathStream.str().c_str()).c_str();
keyPath = FileUtils::ExtractExpandedPath(keyPathStream.str().c_str()).c_str();
if (FileUtils::StoreValueInFile(response->CertificatePem->c_str(), certPath.c_str()) &&
FileUtils::StoreValueInFile(response->PrivateKey->c_str(), keyPath.c_str()))
{
LOGM_INFO(
TAG, "Stored certificate and private key in %s and %s files", certPath.c_str(), keyPath.c_str());
LOG_INFO(TAG, "Attempting to set permissions for certificate and private key...");
chmod(certPath.c_str(), S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
chmod(keyPath.c_str(), S_IRUSR | S_IWUSR);
if (FileUtils::ValidateFilePermissions(certPath.c_str(), Permissions::PUBLIC_CERT) &&
FileUtils::ValidateFilePermissions(keyPath.c_str(), Permissions::PRIVATE_KEY))
{
LOG_INFO(TAG, "Successfully set permissions on provisioned public certificate and private key");
keysCreationCompletedPromise.set_value(true);
}
else
{
keysCreationCompletedPromise.set_value(false);
}
}
else
{
LOGM_ERROR(
TAG,
"Failed to store public certificate and private key in files %s and %s",
certPath.c_str(),
keyPath.c_str());
keysCreationCompletedPromise.set_value(false);
}
}
else
{
LOGM_ERROR(
TAG,
"*** %s: Error on CreateKeysAndCertificate subscription: %s. ***",
DeviceClient::DC_FATAL_ERROR,
ErrorDebugString(ioErr));
keysCreationCompletedPromise.set_value(false);
}
};
auto onKeysRejected = [&](ErrorResponse *error, int ioErr) {
if (ioErr == AWS_OP_SUCCESS)
{
LOGM_ERROR(
TAG,
"*** %s: CreateKeysAndCertificate failed with statusCode %d, errorMessage %s and errorCode %s. ***",
DeviceClient::DC_FATAL_ERROR,
*error->StatusCode,
error->ErrorMessage->c_str(),
error->ErrorCode->c_str());
}
else
{
LOGM_ERROR(
TAG, "*** %s: Error on subscription: %s. ***", DeviceClient::DC_FATAL_ERROR, ErrorDebugString(ioErr));
}
keysCreationCompletedPromise.set_value(false);
};
/*
* CreateKeysAndCertificate workflow
*/
LOG_INFO(TAG, "Subscribing to CreateKeysAndCertificate Accepted and Rejected topics");
CreateKeysAndCertificateSubscriptionRequest keySubscriptionRequest;
identityClient.SubscribeToCreateKeysAndCertificateAccepted(
keySubscriptionRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, onKeysAccepted, onKeysAcceptedSubAck);
identityClient.SubscribeToCreateKeysAndCertificateRejected(
keySubscriptionRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, onKeysRejected, onKeysRejectedSubAck);
auto futureValKeysAcceptedCompletedPromise = keysAcceptedCompletedPromise.get_future();
auto futureValKeysRejectedCompletedPromise = keysRejectedCompletedPromise.get_future();
if (futureValKeysAcceptedCompletedPromise.wait_for(std::chrono::seconds(DEFAULT_WAIT_TIME_SECONDS)) ==
future_status::timeout ||
futureValKeysRejectedCompletedPromise.wait_for(std::chrono::seconds(DEFAULT_WAIT_TIME_SECONDS)) ==
future_status::timeout)
{
LOGM_ERROR(
TAG,
"*** %s: Subscribing to CreateKeysAndCertificate Accepted and Rejected topics timed out. ***",
DeviceClient::DC_FATAL_ERROR);
return false;
}
if (!futureValKeysAcceptedCompletedPromise.get() || !futureValKeysRejectedCompletedPromise.get())
{
return false;
}
LOG_INFO(TAG, "Publishing to CreateKeysAndCertificate topic");
CreateKeysAndCertificateRequest createKeysAndCertificateRequest;
identityClient.PublishCreateKeysAndCertificate(
createKeysAndCertificateRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, onKeysPublishSubAck);
auto futureValKeysPublishCompletedPromise = keysPublishCompletedPromise.get_future();
auto futureValKeysCreationCompletedPromise = keysCreationCompletedPromise.get_future();
if (futureValKeysPublishCompletedPromise.wait_for(std::chrono::seconds(DEFAULT_WAIT_TIME_SECONDS)) ==
future_status::timeout)
{
LOGM_ERROR(
TAG, "*** %s: Publishing to CreateKeysAndCertificate topic timed out. ***", DeviceClient::DC_FATAL_ERROR);
return false;
}
if (futureValKeysCreationCompletedPromise.wait_for(std::chrono::seconds(DEFAULT_WAIT_TIME_SECONDS)) ==
future_status::timeout)
{
LOGM_ERROR(TAG, "*** %s: Create Keys and Certificate request timed out. ***", DeviceClient::DC_FATAL_ERROR);
return false;
}
return futureValKeysPublishCompletedPromise.get() && futureValKeysCreationCompletedPromise.get();
}