EISUtilityResult RequestConnectionStringFromEISWithExpiry()

in src/utils/eis_utils/src/eis_utils.c [435:704]


EISUtilityResult RequestConnectionStringFromEISWithExpiry(
    const time_t expirySecsSinceEpoch, uint32_t timeoutMS, ADUC_ConnectionInfo* provisioningInfo)
{
    EISUtilityResult result = { EISErr_Failed, EISService_Utils };

    if (provisioningInfo == NULL)
    {
        result.err = EISErr_InvalidArg;
        return result;
    }

    if (expirySecsSinceEpoch <= time(NULL) || timeoutMS == 0)
    {
        result.err = EISErr_InvalidArg;
        return result;
    }

    memset(provisioningInfo, 0, sizeof(*provisioningInfo));

    bool success = false;

    char* connectionStr = NULL;

    char* keyHandlePtr = NULL;
    ADUC_ConnType connType = ADUC_ConnType_NotSet;
    ADUC_AuthType authType = ADUC_AuthType_NotSet;

    char* resourceUri = NULL;
    char* sharedSignatureStr = NULL;

    char* identityResponseStr = NULL;
    JSON_Value* identityResponseJson = NULL;

    char* certResponseStr = NULL;
    JSON_Value* certResponseJson = NULL;
    char* certString = NULL;

    EISErr identityResult = RequestIdentitiesFromEIS(timeoutMS, &identityResponseStr);

    if (identityResult != EISErr_Ok)
    {
        result.service = EISService_IdentityService;
        result.err = identityResult;
        goto done;
    }

    identityResponseJson = json_parse_string(identityResponseStr);

    if (identityResponseJson == NULL)
    {
        result.err = EISErr_InvalidJsonRespErr;
        result.service = EISService_IdentityService;
        goto done;
    }

    const JSON_Object* identityResponseJsonObj = json_value_get_object(identityResponseJson);

    if (identityResponseJsonObj == NULL)
    {
        goto done;
    }

    const JSON_Object* specJson =
        json_value_get_object(json_object_get_value(identityResponseJsonObj, EIS_IDENTITY_RESP_SPEC_FIELD));

    if (specJson == NULL)
    {
        result.err = EISErr_InvalidJsonRespErr;
        result.service = EISService_IdentityService;
        goto done;
    }

    const char* hubName = json_object_get_string(specJson, EIS_IDENTITY_RESP_HUBNAME_FIELD);

    if (hubName == NULL)
    {
        result.err = EISErr_InvalidJsonRespErr;
        result.service = EISService_IdentityService;
        goto done;
    }

    const char* deviceId = json_object_get_string(specJson, EIS_IDENTITY_RESP_DEVICEID_FIELD);

    if (deviceId == NULL)
    {
        result.err = EISErr_InvalidJsonRespErr;
        result.service = EISService_IdentityService;
        goto done;
    }

    connType = ADUC_ConnType_Device;

    const char* moduleId = json_object_get_string(specJson, EIS_IDENTITY_RESP_MODULEID_FIELD);

    if (moduleId != NULL)
    {
        connType = ADUC_ConnType_Module;
    }

    // Build request for the signature
    if (connType == ADUC_ConnType_Device)
    {
        resourceUri = ADUC_StringFormat("%s/devices/%s", hubName, deviceId);
    }
    else if (connType == ADUC_ConnType_Module)
    {
        resourceUri = ADUC_StringFormat("%s/devices/%s/modules/%s", hubName, deviceId, moduleId);
    }
    else
    {
        goto done;
    }

    if (resourceUri == NULL)
    {
        goto done;
    }

    const char* gatewayHostName = json_object_get_string(specJson, EIS_IDENTITY_RESP_GATEWAYHOSTNAME_FIELD);

    const JSON_Object* authJson = json_value_get_object(json_object_get_value(specJson, EIS_IDENTITY_RESP_AUTH_FIELD));

    if (authJson == NULL)
    {
        result.err = EISErr_InvalidJsonRespErr;
        result.service = EISService_IdentityService;
        goto done;
    }

    const char* authTypeStr = json_object_get_string(authJson, EIS_IDENTITY_RESP_AUTH_TYPE_FIELD);

    if (authTypeStr == NULL)
    {
        result.err = EISErr_InvalidJsonRespErr;
        result.service = EISService_IdentityService;
        goto done;
    }

    const char* keyHandle = json_object_get_string(authJson, EIS_IDENTITY_RESP_AUTH_KEYHANDLE_FIELD);

    if (keyHandle == NULL)
    {
        result.err = EISErr_InvalidJsonRespErr;
        result.service = EISService_KeyService;
        goto done;
    }

    if (strcmp(authTypeStr, "sas") == 0)
    {
        authType = ADUC_AuthType_SASToken;

        result =
            BuildSharedAccessSignature(resourceUri, keyHandle, expirySecsSinceEpoch, timeoutMS, &sharedSignatureStr);

        if (result.err != EISErr_Ok)
        {
            goto done;
        }

        result.err = BuildSasTokenConnectionString(
            hubName, deviceId, moduleId, connType, sharedSignatureStr, gatewayHostName, &connectionStr);

        if (result.err != EISErr_Ok)
        {
            goto done;
        }
    }
    else if (strcmp(authTypeStr, "x509") == 0)
    {
        authType = ADUC_AuthType_SASCert;

        if (mallocAndStrcpy_s(&keyHandlePtr, keyHandle) != 0)
        {
            result.err = EISErr_ContentAllocErr;
            goto done;
        }

        const char* certId = json_object_get_string(authJson, EIS_IDENTITY_RESP_AUTH_CERTID_FIELD);

        if (certId == NULL)
        {
            result.err = EISErr_InvalidJsonRespErr;
            result.service = EISService_IdentityService;
            goto done;
        }

        EISErr certResult = RequestCertificateFromEIS(certId, timeoutMS, &certResponseStr);

        if (certResult != EISErr_Ok)
        {
            result.err = certResult;
            result.service = EISService_CertService;
            goto done;
        }

        certResponseJson = json_parse_string(certResponseStr);

        if (certResponseJson == NULL)
        {
            result.err = EISErr_InvalidJsonRespErr;
            result.service = EISService_CertService;
            goto done;
        }

        const JSON_Object* certResponseJsonObj = json_value_get_object(certResponseJson);

        const char* certificateStr = json_object_get_string(certResponseJsonObj, EIS_CERT_RESP_PEM);

        if (certificateStr == NULL)
        {
            result.err = EISErr_InvalidJsonRespErr;
            result.service = EISService_CertService;
            goto done;
        }

        if (mallocAndStrcpy_s(&certString, certificateStr) != 0)
        {
            result.err = EISErr_ContentAllocErr;
            goto done;
        }

        result.err =
            BuildSasCertConnectionString(hubName, deviceId, moduleId, connType, gatewayHostName, &connectionStr);

        if (result.err != EISErr_Ok)
        {
            goto done;
        }
    }
    else
    {
        // Authentication type not supported
        result.err = EISErr_RecvInvalidValueErr;
        result.service = EISService_IdentityService;
        goto done;
    }

    success = true;
    result.err = EISErr_Ok;
done:

    json_value_free(identityResponseJson);

    free(resourceUri);

    free(sharedSignatureStr);

    free(identityResponseStr);

    provisioningInfo->connectionString = connectionStr;
    provisioningInfo->certificateString = certString;
    provisioningInfo->opensslPrivateKey = keyHandlePtr;
    provisioningInfo->connType = connType;
    provisioningInfo->authType = authType;

    if (provisioningInfo->authType == ADUC_AuthType_SASCert && provisioningInfo->certificateString != NULL)
    {
        if (mallocAndStrcpy_s(&provisioningInfo->opensslEngine, EIS_OPENSSL_KEY_ENGINE_ID) != 0)
        {
            success = false;
        }
    }

    if (!success)
    {
        ADUC_ConnectionInfo_DeAlloc(provisioningInfo);
    }

    return result;
}