Подключение к веб-службам
Пакет SDK для Azure Sphere включает библиотеку libcurl, которую высокоуровневые приложения могут использовать для подключения и проверки подлинности с помощью веб-служб HTTP и HTTPS. Проверка подлинности сервера и клиента поддерживается, поэтому приложения могут убедиться, что они обмениваются данными с ожидаемым сервером, и могут доказать серверу, что их устройство и каталог Azure Sphere являются допустимыми. Взаимная проверка подлинности объединяет эти два элемента.
Репозиторий примеров Azure Sphere на GitHub включает следующие примеры curl:
- HTTPS_Curl_Easy использует синхронный (блокирующий) API для проверки подлинности сервера.
- HTTPS_Curl_Multi примере используется асинхронный (неблокирующий) API для проверки подлинности сервера.
Хотя синхронный подход к проверке подлинности сервера в HTTPS_Curl_Easy довольно прост, приложениям Azure Sphere, как правило, следует использовать более сложный асинхронный метод, показанный в примере HTTPS_Curl_Multi, а также шаблон на основе однопотоковых событий на основе epoll.
На веб-сайте libcurl представлена подробная документация по API libcurl C и множество примеров. Ниже перечислены различия между библиотекой cURL и библиотекой среды выполнения пакета SDK для Azure Sphere.
Имя константы (определение) |
ограничения диапазона cURL | Ограничения диапазона Azure Sphere |
---|---|---|
CURLOPT_BUFFERSIZE (размер буфера) |
По умолчанию: 16 КБ | По умолчанию: 1536 КБ |
CURLOPT_UPLOAD_BUFFERSIZE (размер буфера отправки) |
По умолчанию: 64 КБ Максимум: 2 МБ Минимум: 16 КБ |
По умолчанию: 1536 КБ Максимум: 64 КБ Минимум: 1536 КБ |
CURLOPT_HEADERFUNCTION (полный заголовок HTTP, переданный этой функции) |
Максимум: 100 КБ | Максимум: 16 КБ |
CURLOPT_DNS_CACHE_TIMEOUT | По умолчанию: кэшировать результаты в течение 60 секунд Максимум: кэшировать результаты навсегда Минимум: 0 (не кэшировать результаты) |
Все значения переопределяются на 0, а результаты не кэшируются. |
Требования для приложений, использующих curl
Приложения, использующие библиотеку curl, должны включать соответствующие файлы заголовков и предоставлять UUID клиента Azure Sphere (устаревшей версии) и сведения об узле интернета в манифесте приложения.
Файлы заголовков
Чтобы использовать curl, включите в приложение следующие файлы заголовков:
#include <applibs/storage.h> // required only if you supply a certificate in the image package
#include <tlsutils/deviceauth_curl.h> // required only for mutual authentication
#include <curl/curl.h>
#include <applibs/networking_curl.h> // required only if using proxy to connect to the internet
Файл заголовка storage.h требуется только в том случае, если вы предоставляете один или несколько сертификатов в пакете образа приложения. Для выполнения взаимной проверки подлинности требуется заголовок deviceauth_curl.h. Если приложение использует прокси-сервер для подключения к Интернету, требуется заголовок networking_curl.h.
Манифест приложения
В поле AllowedConnections манифеста приложения должны быть указаны узлы, к которым подключается приложение. Он также должен содержать имя каждого домена, с которым может столкнуться подключение при перенаправлении. Например, для приложения, которое подключается к домашней странице Майкрософт, требуется и microsoft.com
www.microsoft.com
.
Если приложение использует взаимную проверку подлинности, поле DeviceAuthentication манифеста должно содержать UUID клиента Azure Sphere (устаревшая версия). Сертификаты проверки подлинности устройств выдаются только в том случае, если каталог устройства связан с UUID клиента Azure Sphere (устаревшей версии), который соответствует идентификатору UUID клиента в манифесте приложения. Это ограничение обеспечивает глубинную защиту: приложение, работающее на устройстве в другом каталоге (например, другого клиента или изгоев сущности), не может пройти проверку подлинности на сервере.
Во время разработки можно найти устаревший идентификатор UUID клиента с помощью команды az sphere catalog show и извлечения MigratedCatalogId
значения из tags
объекта .
Если приложение использует прокси-сервер, поле ReadNetworkProxyConfig указывает, имеет ли приложение разрешение на получение конфигурации прокси-сервера.
В следующем примере поле AllowedConnections указывает, что приложение подключается только к www.example.com
, в поле DeviceAuthentication указывается UUID клиента Azure Sphere (устаревшая версия), что позволяет приложению использовать сертификат устройства для взаимной проверки подлинности, а поле ReadNetworkProxyConfig указывает, что приложение может получать сведения о конфигурации прокси-сервера.
"Capabilities": {
"AllowedConnections": [ "www.example.com" ],
"Gpio": [],
"Uart": [],
"WifiConfig": false,
"DeviceAuthentication": "00000000-0000-0000-0000-000000000000",
"ReadNetworkProxyConfig": true
}
Поддерживаемые функции
Libcurl для Azure Sphere поддерживает только протоколы HTTP и HTTPS. Кроме того, ОС Azure Sphere не поддерживает некоторые функции, такие как записываемые файлы (файлы cookie) или сокеты UNIX. Функции, которые не будут поддерживаться в будущих выпусках libcurl, например семейство mprintf(), недоступны.
Libcurl для Azure Sphere поддерживает ПРОТОКОЛы TLS 1.2 и TLS 1.3, а также использует протоколы TLS 1.0 и TLS 1.1 в соответствии с более широкой стратегией безопасности Microsoft TLS.
Ниже приведены поддерживаемые наборы шифров:
- TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
- TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
- TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
- TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
- TLS_DHE_RSA_WITH_AES_256_GCM_SHA384
- TLS_DHE_RSA_WITH_AES_128_GCM_SHA256
- TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
- TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
- TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
- TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384
- TLS_DHE_RSA_WITH_AES_256_CBC_SHA256
- TLS_DHE_RSA_WITH_AES_128_CBC_SHA256
Попытки использовать неподдерживаемую версию TLS возвращают ошибку CyaSSL does not support <version>
.
Проверка подлинности сервера
Azure Sphere поддерживает проверку подлинности сервера с помощью libcurl. Сертификат сервера должен быть подписан центром сертификации (ЦС), которому доверяет устройство. Для проверки подлинности сервера libcurl приложение должно предоставить путь к файлу ЦС.
Добавление сертификатов ЦС в пакет образа
Чтобы использовать один или несколько центров сертификации, необходимо добавить сертификаты в пакет образа. Каждый сертификат должен быть закодирован в кодировке Base-64. Самый простой подход — создать один файл, содержащий все дополнительные сертификаты. Файл должен иметь расширение PEM-файла. Чтобы добавить сертификаты, выполните следующее:
- Создайте папку certs в папке проекта для приложения. Папка проекта содержит файл CMakeLists для приложения.
- В папке certs создайте текстовый файл с расширением PEM, скопируйте в него каждый сертификат и сохраните файл.
- В файле CMakeLists.txt добавьте файл сертификата в пакет образа в качестве файла ресурсов. Например:
azsphere_target_add_image_package(${PROJECT_NAME} RESOURCE_FILES "certs/DigiCertGlobalRootCA.pem")
Теперь файл сертификата должен появиться в папке certs в пакете образа.
Настройка расположений сертификатов
В приложении используйте параметры CURLOPT_CAPATH и CURLOPT_CAINFO , чтобы задать расположение сертификатов. Вызовите Storage_GetAbsolutePathInImagePackage , чтобы получить абсолютный путь к сертификатам в пакете образа, а затем вызовите curl_easy_setopt.
CURLOPT_CAPATH задает папку по умолчанию для сертификатов. Например, следующий код указывает curl на поиск сертификатов в папке certs на изображении:
char *path = Storage_GetAbsolutePathInImagePackage("certs");
curl_easy_setopt(curl_handle, CURLOPT_CAPATH, path);
CURLOPT_CAINFO задает путь к файлу, который содержит один или несколько сертификатов. Curl выполняет поиск в этом файле в дополнение к папке по умолчанию, заданной в CURLOPT_CAPATH. Например:
char *path = Storage_GetAbsolutePathInImagePackage("CAs/mycertificates.pem");
curl_easy_setopt(curl_handle, CURLOPT_CAINFO, path);
Этот код указывает curl доверять всем ЦС, определенным в файле mycertificates.pem, в дополнение к ЦС, определенным в каталоге, наборе CURLOPT_CAPATH.
Взаимная проверка подлинности
Взаимная проверка подлинности проверяет, что сервер и клиентское устройство являются допустимыми. Это многоэтапный процесс:
- Приложение выполняет проверку подлинности сервера с помощью сертификата ЦС, как описано в разделе Проверка подлинности сервера.
- Приложение предоставляет серверу сертификат проверки подлинности клиента x509, чтобы сервер смог проверить подлинность устройства.
- Сервер использует цепочку сертификатов каталога Azure Sphere для проверки принадлежности устройства к каталогу.
Приложение может настроить сторону проверки подлинности устройства для взаимной проверки подлинности двумя способами:
- Настройте функцию Azure Sphere DeviceAuth_CurlSslFunc в качестве функции SSL, которая выполняет проверку подлинности.
- Создайте пользовательскую функцию SSL, которая вызывает функцию Azure Sphere DeviceAuth_SslCtxFunc для проверки подлинности.
Примечание
Azure Sphere не поддерживает повторное согласование SSL/TLS.
Перед использованием любой из функций необходимо обновить файл CMakeLists.txt приложения, чтобы добавить curl и tlsutils в TARGET_LINK_LIBRARIES:
TARGET_LINK_LIBRARIES(${PROJECT_NAME} applibs pthread gcc_s c curl tlsutils)
Использование DeviceAuth_CurlSslFunc
Самый простой способ проверки подлинности устройства — настроить DeviceAuth_CurlSslFunc в качестве функции обратного вызова для проверки подлинности CURL SSL:
// Set DeviceAuth_CurlSslFunc to perform authentication
CURLcode err = curl_easy_setopt(_curl, CURLOPT_SSL_CTX_FUNCTION, DeviceAuth_CurlSslFunc);
if (err) {
// Set ssl function failed
return err;
}
Функция DeviceAuth_CurlSslFunc извлекает цепочку сертификатов для текущего каталога Azure Sphere и настраивает соединение curl для выполнения взаимной проверки подлинности. Если проверка подлинности завершается ошибкой, функция возвращает CURLE_SSL_CERTPROBLEM.
Использование DeviceAuth_SslCtxFunc
Приложение также может использовать пользовательскую функцию обратного вызова SSL, которая вызывает функцию azure Sphere DeviceAuth_SslCtxFunc для проверки подлинности.
Пользовательская функция SSL должна вызывать DeviceAuth_SslCtxFunc для проверки подлинности, но может выполнять и другие задачи, связанные с проверкой подлинности.
DeviceAuth_SslCtxFunc возвращает значение перечисления DeviceAuthSslResult
, которое предоставляет подробные сведения о сбое. Например:
static CURLcode MyCallback(CURL *curl, void *sslctx, void *userCtx)
{
int err = DeviceAuth_SslCtxFunc(sslctx);
Log_Debug("ssl func callback error %d\n", err);
if (err) {
// detailed error handling code goes here
}
return CURLE_OK;
}
...
err = curl_easy_setopt(curl, CURLOPT_SSL_CTX_FUNCTION, MyCallback);
if (err) {
goto cleanupLabel;
}
Использование цепочки сертификатов каталога на сервере
Чтобы выполнить взаимную проверку подлинности, сервер должен быть в состоянии убедиться, что устройство принадлежит к каталогу Azure Sphere и что сам каталог является допустимым. Для выполнения этой проверки подлинности серверу требуется цепочка сертификатов каталога Azure Sphere, которая подписывает все ваши устройства Azure Sphere:
Чтобы получить цепочку сертификатов для каталога, скачайте ее в P7B-файл, как показано в следующем примере:
az sphere ca-certificate download-chain --destination CA-cert-chain.p7b
Затем можно использовать P7B-файл на сервере.
Дополнительные советы по использованию curl
Ниже приведены некоторые дополнительные советы по использованию curl в приложении Azure Sphere.
Если вы планируете хранить содержимое страницы в ОЗУ или флэш-памяти, помните, что хранилище на устройстве Azure Sphere ограничено.
Чтобы убедиться, что curl следует за перенаправлениями, добавьте в код следующее:
curl_easy_setopt(curl_handle, CURLOPT_FOLLOWLOCATION, 1L);
Чтобы добавить подробные сведения об операциях curl, которые могут быть полезны во время отладки:
curl_easy_setopt(curl_handle, CURLOPT_VERBOSE, 1L);
Некоторые серверы возвращают ошибки, если запрос не содержит агента пользователя. Чтобы задать агент пользователя, выполните приведенные далее действия.
curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "libcurl-agent/1.0");
При обработке обратных вызовов таймера curl_multi избегайте рекурсивных вызовов, когда сообщаемое время ожидания равно 0 мс, так как это может привести к непредсказуемому поведению. Вместо этого обрабатывайте 0ms как 1 мс путем активации EventLoopTimer (0 мс EventLoopTimers также являются рекурсивными и их следует избегать).
static int CurlTimerCallback(CURLM *multi, long timeoutMillis, void *unused) { // A value of -1 means the timer does not need to be started. if (timeoutMillis != -1) { if (timeoutMillis == 0) { // We cannot queue an event for 0ms in the future (the timer never fires) // So defer it very slightly (see https://curl.se/libcurl/c/multi-event.html) timeoutMillis = 1; } // Start a single shot timer with the period as provided by cURL. // The timer handler will invoke cURL to process the web transfers. const struct timespec timeout = {.tv_sec = timeoutMillis / 1000, .tv_nsec = (timeoutMillis % 1000) * 1000000}; SetEventLoopTimerOneShot(curlTimer, &timeout); } return 0; }