in EAP-TLS_Solution/EAP-TLS Client/lib/web_api_client.c [201:382]
EapTlsResult EapTls_CallWebApi(const char *url, const char *queryString, const char *putString, const char *webApiRootCACertRelativePath, MemoryBlock *responseBlock)
{
EapTlsResult iRes = EapTlsResult_Error;
if (NULL != url && NULL != webApiRootCACertRelativePath && NULL != responseBlock)
{
// https://curl.haxx.se/libcurl/c/https.html
curl_global_init(CURL_GLOBAL_ALL);
CURL *curlHandle = curl_easy_init();
if (curlHandle)
{
CURLcode res;
// Set up for DAA mutual authentication
// Device: https://learn.microsoft.com/en-us/azure-sphere/app-development/curl
// WebAPI: https://learn.microsoft.com/en-us/azure/app-service/app-service-web-configure-tls-mutual-auth#special-considerations-for-certificate-validation
// Set up the WebAPI's URL with the proper GET query
char call_url[MAX_URL_LEN + 1];
memset(call_url, 0, sizeof(call_url));
if (NULL != queryString)
{
snprintf(call_url, sizeof(call_url), "%s?%s", url, queryString);
}
else
{
strncpy(call_url, url, sizeof(call_url) - 1);
}
// Activate verbose logging
if ((res = curl_easy_setopt(curlHandle, CURLOPT_VERBOSE, 1L)) != CURLE_OK)
{
LogCurlError("FAILED curl_easy_setopt CURLOPT_VERBOSE", res);
}
if ((res = curl_easy_setopt(curlHandle, CURLOPT_URL, call_url)) != CURLE_OK)
{
LogCurlError(" FAILED curl_easy_setopt CURLOPT_URL", res);
}
else
{
// Set up the PUT fields, if any
if (NULL != putString)
{
if ((res = curl_easy_setopt(curlHandle, CURLOPT_POST, 1L)) != CURLE_OK)
{
LogCurlError(" FAILED curl_easy_setopt CURLOPT_POST", res);
}
else
{
struct curl_slist *hs = NULL;
hs = curl_slist_append(hs, "Content-Type: application/json");
if ((res = curl_easy_setopt(curlHandle, CURLOPT_HTTPHEADER, hs)) != CURLE_OK)
{
LogCurlError(" FAILED curl_easy_setopt CURLOPT_HTTPHEADER", res);
}
else
{
char hdrTemp[MAX_URL_LEN + 1];
snprintf(hdrTemp, sizeof(hdrTemp), "Content-Length: %zd", strlen(putString));
hs = curl_slist_append(hs, hdrTemp);
if ((res = curl_easy_setopt(curlHandle, CURLOPT_HTTPHEADER, hs)) != CURLE_OK)
{
LogCurlError(" FAILED curl_easy_setopt CURLOPT_HTTPHEADER", res);
}
else
{
if ((res = curl_easy_setopt(curlHandle, CURLOPT_POSTFIELDS, putString)) != CURLE_OK)
{
LogCurlError(" FAILED curl_easy_setopt CURLOPT_POSTFIELDS", res);
}
}
}
}
}
//if ((res = curl_easy_setopt(curlHandle, CURLOPT_SSL_VERIFYHOST, 0)) != CURLE_OK)
//{
// LogCurlError("curl_easy_setopt CURLOPT_SSL_VERIFYHOST", res);
//}
if ((res = curl_easy_setopt(curlHandle, CURLOPT_SSL_VERIFYPEER, 0)) != CURLE_OK)
{
LogCurlError("FAILED curl_easy_setopt CURLOPT_SSL_VERIFYPEER", res);
}
else
{
// The simplest way to perform device authentication is to configure DeviceAuth_CurlSslFunc as the callback function for curl SSL authentication
if ((res = curl_easy_setopt(curlHandle, CURLOPT_SSL_CTX_FUNCTION, EapTls_DeviceAuth_CurlSslFunc)) != CURLE_OK)
{
LogCurlError("curl_easy_setopt CURLOPT_SSL_CTX_FUNCTION", res);
}
else
{
// libcurl on Azure Sphere supports TLS 1.2 and has deprecated TLS 1.0 and TLS 1.1 in alignment with the broader Microsoft TLS security strategy
if ((res = curl_easy_setopt(curlHandle, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2)) != CURLE_OK)
{
LogCurlError("FAILED curl_easy_setopt CURLOPT_SSLVERSION", res);
}
else
{
// Get the full path to the certificate file used to authenticate the WebAPI's server identity
// #NOTE: currently APIs do not support passing libcurl a certificate Id
char *certificatePath = Storage_GetAbsolutePathInImagePackage(webApiRootCACertRelativePath);
if (certificatePath == NULL)
{
Log_Debug("The certificate path could not be resolved: errno=%d (%s)\n", errno, strerror(errno));
}
else
{
// Set the path for the certificate file that cURL uses to validate the server certificate
if ((res = curl_easy_setopt(curlHandle, CURLOPT_CAINFO, certificatePath)) != CURLE_OK)
{
LogCurlError("curl_easy_setopt CURLOPT_CAINFO", res);
}
else
{
// Let cURL follow any HTTP 3xx redirects. Important: any redirection to different domain names
// requires that domain name to be added to app_manifest.json
if ((res = curl_easy_setopt(curlHandle, CURLOPT_FOLLOWLOCATION, 1L)) != CURLE_OK)
{
LogCurlError("FAILED curl_easy_setopt CURLOPT_FOLLOWLOCATION", res);
}
else
{
// Specify a user agent
if ((res = curl_easy_setopt(curlHandle, CURLOPT_USERAGENT, "libcurl-agent/1.0")) != CURLE_OK)
{
LogCurlError("FAILED curl_easy_setopt CURLOPT_USERAGENT", res);
}
else
{
// Set the custom parameter of the callback to the memory block
if ((res = curl_easy_setopt(curlHandle, CURLOPT_WRITEDATA, (void *)responseBlock)) != CURLE_OK)
{
LogCurlError("FAILED curl_easy_setopt CURLOPT_WRITEDATA", res);
}
else
{
// Set up callback for cURL to use when downloading data
if ((res = curl_easy_setopt(curlHandle, CURLOPT_WRITEFUNCTION, EapTls_StoreDownloadedDataCallback)) != CURLE_OK)
{
LogCurlError("FAILED curl_easy_setopt CURLOPT_FOLLOWLOCATION", res);
}
else
{
Log_Debug("Connecting to %s...\n", call_url);
if ((res = curl_easy_perform(curlHandle)) == CURLE_OK)
{
// #NOTE: SSL renegotiation is not currently supported by Azure Sphere
Log_Debug("\n -===- Downloaded content (%zu bytes): -===-\n", responseBlock->size);
Log_Debug("%s\n", responseBlock->data);
iRes = EapTlsResult_Success;
}
else
{
LogCurlError("FAILED curl_easy_perform", res);
iRes = EapTlsResult_FailedConnectingToMdmWebApi;
}
}
}
}
}
}
}
}
}
}
}
curl_easy_cleanup(curlHandle);
}
else
{
Log_Debug("FAILED initializing cURL!");
iRes = EapTlsResult_Error;
}
}
else
{
Log_Debug("ERROR: bad parameters!");
iRes = EapTlsResult_BadParameters;
}
return iRes;
}