bool FleetProvisioning::CreateCertificateAndKey()

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();
}