bool FleetProvisioning::CreateCertificateUsingCSR()

in source/fleetprovisioning/FleetProvisioning.cpp [204:362]


bool FleetProvisioning::CreateCertificateUsingCSR(Iotidentity::IotIdentityClient identityClient)
{
    LOG_INFO(TAG, "Provisioning new device certificate using CreateCertificateFromCsr API");
    auto onCsrAcceptedSubAck = [&](int ioErr) {
        if (ioErr != AWS_OP_SUCCESS)
        {
            LOGM_ERROR(
                TAG,
                "*** %s: Error subscribing to CreateCertificateFromCsr accepted topic: %s. ***",
                DeviceClient::DC_FATAL_ERROR,
                ErrorDebugString(ioErr));
        }
        csrAcceptedCompletedPromise.set_value(ioErr == AWS_OP_SUCCESS);
    };

    auto onCsrRejectedSubAck = [&](int ioErr) {
        if (ioErr != AWS_OP_SUCCESS)
        {
            LOGM_ERROR(
                TAG,
                "*** %s: Error subscribing to CreateCertificateFromCsr rejected topic: %s. ***",
                DeviceClient::DC_FATAL_ERROR,
                ErrorDebugString(ioErr));
        }
        csrRejectedCompletedPromise.set_value(ioErr == AWS_OP_SUCCESS);
    };

    auto onCsrPublishSubAck = [&](int ioErr) {
        if (ioErr != AWS_OP_SUCCESS)
        {
            LOGM_ERROR(
                TAG,
                "*** %s: Error publishing to CreateCertificateFromCsr topic: %s. ***",
                DeviceClient::DC_FATAL_ERROR,
                ErrorDebugString(ioErr));
        }
        csrPublishCompletedPromise.set_value(ioErr == AWS_OP_SUCCESS);
    };

    auto onCsrAccepted = [&](CreateCertificateFromCsrResponse *response, int ioErr) {
        if (ioErr == AWS_OP_SUCCESS)
        {
            LOGM_INFO(TAG, "CreateCertificateFromCsrResponse certificateId: %s. ***", response->CertificateId->c_str());
            certificateOwnershipToken = *response->CertificateOwnershipToken;
            Aws::Crt::String certificateID = response->CertificateId->c_str();

            ostringstream certPathStream;
            certPathStream << keyDir << certificateID << "-certificate.pem.crt";
            certPath = FileUtils::ExtractExpandedPath(certPathStream.str().c_str()).c_str();

            if (FileUtils::StoreValueInFile(response->CertificatePem->c_str(), certPath.c_str()))
            {
                LOGM_INFO(TAG, "Stored certificate in %s file", certPath.c_str());

                LOG_INFO(TAG, "Attempting to set permissions for certificate...");
                chmod(certPath.c_str(), S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
                if (FileUtils::ValidateFilePermissions(certPath.c_str(), Permissions::PUBLIC_CERT))
                {
                    LOG_INFO(TAG, "Successfully set permissions on provisioned public certificate");
                    csrCreationCompletedPromise.set_value(true);
                }
                else
                {
                    csrCreationCompletedPromise.set_value(false);
                }
            }
            else
            {
                LOGM_ERROR(TAG, "Failed to store public certificate in file %s", certPath.c_str());
                csrCreationCompletedPromise.set_value(false);
            }
        }
        else
        {
            LOGM_ERROR(
                TAG,
                "*** %s: Error on CreateCertificateFromCsr subscription: %s. ***",
                DeviceClient::DC_FATAL_ERROR,
                ErrorDebugString(ioErr));
            csrCreationCompletedPromise.set_value(false);
        }
    };

    auto onCsrRejected = [&](ErrorResponse *error, int ioErr) {
        if (ioErr == AWS_OP_SUCCESS)
        {
            LOGM_ERROR(
                TAG,
                "*** %s: CreateCertificateFromCsr 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 to CreateCertificateFromCsr Rejected topic: %s. ***",
                DeviceClient::DC_FATAL_ERROR,
                ErrorDebugString(ioErr));
        }
        csrCreationCompletedPromise.set_value(false);
    };

    /*
     * CreateCertificateFromCSR workflow
     */

    LOG_INFO(TAG, "Subscribing to CreateCertificateFromCsr Accepted and Rejected topics");
    CreateCertificateFromCsrSubscriptionRequest csrSubscriptionRequest;
    identityClient.SubscribeToCreateCertificateFromCsrAccepted(
        csrSubscriptionRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, onCsrAccepted, onCsrAcceptedSubAck);

    identityClient.SubscribeToCreateCertificateFromCsrRejected(
        csrSubscriptionRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, onCsrRejected, onCsrRejectedSubAck);

    auto futureValCsrAcceptedCompletedPromise = csrAcceptedCompletedPromise.get_future();
    auto futureValCsrRejectedCompletedPromise = csrRejectedCompletedPromise.get_future();
    if (futureValCsrAcceptedCompletedPromise.wait_for(std::chrono::seconds(DEFAULT_WAIT_TIME_SECONDS)) ==
            future_status::timeout ||
        futureValCsrRejectedCompletedPromise.wait_for(std::chrono::seconds(DEFAULT_WAIT_TIME_SECONDS)) ==
            future_status::timeout)
    {
        LOGM_ERROR(
            TAG,
            "*** %s: Subscribing to CreateCertificateFromCsr Accepted and Rejected topics timed out. ***",
            DeviceClient::DC_FATAL_ERROR);
        return false;
    }
    if (!futureValCsrAcceptedCompletedPromise.get() || !futureValCsrRejectedCompletedPromise.get())
    {
        return false;
    }

    LOG_INFO(TAG, "Publishing to CreateCertificateFromCsr topic");
    CreateCertificateFromCsrRequest createCertificateFromCsrRequest;
    createCertificateFromCsrRequest.CertificateSigningRequest = csrFile.c_str();
    identityClient.PublishCreateCertificateFromCsr(
        createCertificateFromCsrRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, onCsrPublishSubAck);

    auto futureValCsrPublishCompletedPromise = csrPublishCompletedPromise.get_future();
    auto futureValCsrCreationCompletedPromise = csrCreationCompletedPromise.get_future();
    if (futureValCsrPublishCompletedPromise.wait_for(std::chrono::seconds(DEFAULT_WAIT_TIME_SECONDS)) ==
        future_status::timeout)
    {
        LOGM_ERROR(
            TAG, "*** %s: Publishing to CreateCertificateFromCsr topic timed out. ***", DeviceClient::DC_FATAL_ERROR);
        return false;
    }
    if (futureValCsrCreationCompletedPromise.wait_for(std::chrono::seconds(DEFAULT_WAIT_TIME_SECONDS)) ==
        future_status::timeout)
    {
        LOGM_ERROR(TAG, "*** %s: CreateCertificateFromCsr request timed out. ***", DeviceClient::DC_FATAL_ERROR);
        return false;
    }

    return futureValCsrPublishCompletedPromise.get() && futureValCsrCreationCompletedPromise.get();
}