Conectar aos serviços Web

Importante

Esta é a documentação do Azure Sphere (herdado). O Azure Sphere (herdado) será desativado em 27 de setembro de 2027 e os usuários devem migrar para o Azure Sphere (integrado) até esse momento. Use o seletor de versão localizado acima do sumário para exibir a documentação do Azure Sphere (Integrado).

O SDK do Azure Sphere inclui a biblioteca libcurl, que os aplicativos de alto nível podem usar para conectar serviços Web HTTP e HTTPS e autenticar-se neles. Há suporte para a autenticação de servidores e clientes para que os aplicativos possam verificar se eles estão se comunicando com o servidor esperado e se podem provar para o servidor que seu dispositivo e locatário do Azure Sphere são legítimos. A autenticação mútua combina os dois.

O repositório de exemplos do Azure Sphere no GitHub inclui os seguintes exemplos de curl:

Embora a abordagem síncrona à autenticação do servidor em HTTPS_Curl_Easy seja bem simples, os aplicativos Azure Sphere devem usar geralmente a técnica assíncrona mais complexa mostrada no exemplo HTTPS_Curl_Multi, juntamente com o padrão orientado a eventos de thread único com base em epoll.

O site da libcurl fornece a documentação completa da API libcurl em C e vários exemplos. As diferenças entre a Biblioteca cURL e a biblioteca de runtime do SDK do Azure Sphere são as seguintes:

Nome da Constante
(definição)
Limites de intervalo de cURL Limites de intervalo do Azure Sphere
CURLOPT_BUFFERSIZE
(tamanho do buffer)
Padrão: 16 KB Padrão: 1536 KB
CURLOPT_UPLOAD_BUFFERSIZE
(tamanho do buffer de upload)
Padrão: 64 KB
Máximo: 2MB
Mínimo: 16 KB
Padrão: 1536 KB
Máximo: 64 KB
Mínimo: 1536 KB
CURLOPT_HEADERFUNCTION
(cabeçalho HTTP completo passado para esta função)
Máximo: 100 KB Máximo: 16 KB
CURLOPT_DNS_CACHE_TIMEOUT Padrão: resultados do cache por 60 segundos
Máximo: resultados do cache para sempre
Mínimo: 0 (não armazenar resultados em cache)
Todos os valores são substituídos por 0 e os resultados não são armazenados em cache.

Requisitos para aplicativos que usam o curl

Os aplicativos que usam a biblioteca curl devem incluir os arquivos de cabeçalho adequados e fornecer ao locatário e ao host da Internet informações no manifesto do aplicativo.

Arquivos de cabeçalho

Para usar o curl, inclua estes arquivos de cabeçalho no aplicativo:

#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

O arquivo de cabeçalho storage.h será necessário somente se você fornecer um ou mais certificados no pacote de imagem do aplicativo. O cabeçalho deviceauth_curl.h header é necessário para realizar autenticação mútua. O cabeçalho networking_curl.h será necessário se o aplicativo estiver usando um proxy para se conectar à Internet.

Manifesto do aplicativo

O campo AllowedConnections do manifesto do aplicativo deve especificar os host com os quais o aplicativo se conecta. Ele também deve conter o nome de cada domínio que a conexão poderá encontrar se for redirecionada. Por exemplo, microsoft.com e www.microsoft.com são necessários para um aplicativo que se conecta à home page da Microsoft.

Se o aplicativo usar a autenticação mútua, o campo DeviceAuthentication do manifesto deverá incluir a ID de locatário do Azure Sphere. Os certificados de autenticação de dispositivo serão emitidos somente se a ID de locatário do dispositivo corresponder à ID do locatário no manifesto do aplicativo. Essa restrição fornece defesa profunda: um aplicativo em execução em um dispositivo em um locatário diferente (digamos, de um cliente diferente ou uma entidade não autorizada) não pode se autenticar no servidor.

Se o aplicativo usar um proxy, o campo ReadNetworkProxyConfig indicará se o aplicativo tem permissão para recuperar a configuração de proxy.

Durante o desenvolvimento, você pode encontrar a ID do locatário atual do Azure Sphere usando o comando azsphere tenant show-selected.

No exemplo a seguir, o campo AllowedConnections especifica que o aplicativo se conecta somente a www.example.com, o campo DeviceAuthentication especifica a ID do locatário do Azure Sphere, permitindo que o aplicativo use o certificado do dispositivo para autenticação mútua, e o campo ReadNetworkProxyConfig especifica que o aplicativo pode recuperar informações de configuração de proxy.

  "Capabilities": {
    "AllowedConnections": [ "www.example.com" ],
    "Gpio": [],
    "Uart": [],
    "WifiConfig": false,
    "DeviceAuthentication": "00000000-0000-0000-0000-000000000000",
    "ReadNetworkProxyConfig": true
  }

Funcionalidade com suporte

A libcurl do Azure Sphere dá suporte apenas aos protocolos HTTP e HTTPS. Além disso, o sistema operacional do Azure Sphere não é compatível com algumas funcionalidades, como arquivos graváveis (cookies) ou soquetes do UNIX. Os recursos que não terão suporte nas versões futuras da libcurl, como a família mprintf(), não estão disponíveis.

O Libcurl para Azure Sphere dá suporte ao TLS 1.2 e ao TLS 1.3 e desativou o TLS 1.0 e o TLS 1.1 em alinhamento com a estratégia de segurança TLS mais ampla da Microsoft.

A seguir estão os conjuntos de criptografia compatíveis:

  • 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

As tentativas de usar uma versão sem suporte do TLS retornam o erro CyaSSL does not support <version>.

Autenticação do servidor

O Azure Sphere dá suporte à autenticação de servidor por meio de libcurl. O certificado do servidor precisa ser assinado por uma AC (autoridade de certificação) na qual o dispositivo confie. Para que a libcurl autentique um servidor, o aplicativo precisa fornecer o caminho para o arquivo de AC.

Adicionar certificados de AC ao pacote de imagens

Para usar uma ou mais ACs, você deve adicionar os certificados ao seu pacote de imagem. Cada certificado precisa ser codificado em Base 64. A abordagem mais simples é criar um único arquivo contendo todos os certificados adicionais. O arquivo precisa ter a extensão de nome de arquivo .pem. Para adicionar certificados:

  1. Crie uma pasta de certificados na pasta do projeto do aplicativo. A pasta do projeto contém o arquivo ou o arquivo CMakeLists do aplicativo.
  2. Na pasta de certificados, crie um arquivo de texto com a extensão .pem, copie cada certificado para ele e salve-o.
  3. No arquivo CMakeLists.txt, adicione o arquivo de certificado ao pacote de imagens como um arquivo de recurso. Por exemplo:
azsphere_target_add_image_package(${PROJECT_NAME} RESOURCE_FILES "certs/DigiCertGlobalRootCA.pem")

O arquivo de certificado agora deve aparecer na pasta de certificados no pacote de imagem.

Definir locais de certificado

Em seu aplicativo, use as opções CURLOPT_CAPATH e CURLOPT_CAINFO para definir os locais dos certificados. Chame Storage_GetAbsolutePathInImagePackage para recuperar o caminho absoluto para os certificados no pacote de imagens e, em seguida, chame curl_easy_setopt.

CURLOPT_CAPATH define uma pasta padrão para os certificados. Por exemplo, o código a seguir informa ao curl que ele deve examinar certificados na pasta de certificados na imagem:

char *path = Storage_GetAbsolutePathInImagePackage("certs");
curl_easy_setopt(curl_handle, CURLOPT_CAPATH, path);

CURLOPT_CAINFO define um caminho para um arquivo que contém um ou mais certificados. O curl procura esse arquivo, além do conjunto de pasta padrão no CURLOPT_CAPATH. Por exemplo:

char *path = Storage_GetAbsolutePathInImagePackage("CAs/mycertificates.pem");
curl_easy_setopt(curl_handle, CURLOPT_CAINFO, path);

Esse código informa ao curl que ele deve confiar em todas as ACs definidas no arquivo mycertificates.pem, além daquelas que estão presentes no diretório definido em CURLOPT_CAPATH.

Autenticação mútua

A autenticação mútua verifica se o servidor e o dispositivo do cliente são legítimos. É um processo de várias etapas:

  1. O aplicativo autentica o servidor usando um certificado de autoridade de certificação, conforme descrito em Autenticação do servidor.
  2. O aplicativo apresenta um certificado de autenticação de cliente x509 ao servidor para que ele possa autenticar o dispositivo.
  3. O servidor usa a cadeia de certificados do locatário do Azure Sphere para verificar se o dispositivo pertence ao locatário.

Um aplicativo pode configurar o lado da autenticação do dispositivo de autenticação mútua de duas maneiras:

  • Configure a função DeviceAuth_CurlSslFunc do Azure Sphere como a função SSL que realiza a autenticação.
  • Crie uma função SSL personalizada que chama a função DeviceAuth_SslCtxFunc do Azure Sphere para autenticação.

Observação

O Azure Sphere não dá suporte à renegociação SSL/TLS.

Antes de usar uma das funções, você deve atualizar o arquivo CMakeLists.txt do seu aplicativo para adicionar curl e tlsutils a TARGET_LINK_LIBRARIES:

TARGET_LINK_LIBRARIES(${PROJECT_NAME} applibs pthread gcc_s c curl tlsutils)

Usar DeviceAuth_CurlSslFunc

A maneira mais simples de executar a autenticação do dispositivo é configurar DeviceAuth_CurlSslFunc como a função de retorno de chamada para a autenticação SSL do curl:

// 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;
}

A função DeviceAuth_CurlSslFunc recupera a cadeia de certificados do locatário atual do Azure Sphere e configura a conexão do cURL para executar a autenticação mútua. Se a autenticação falhar, a função retornará CURLE_SSL_CERTPROBLEM.

Use DeviceAuth_SslCtxFunc

Uma chamada de aplicativo também pode usar uma função de retorno de chamada SSL personalizada que chama a função DeviceAuth_SslCtxFunc do Azure Sphere para autenticação.

Sua função SSL personalizada deve chamar DeviceAuth_SslCtxFunc para executar a autenticação, mas também pode realizar outras tarefas relacionadas à autenticação. DeviceAuth_SslCtxFunc retorna um valor da enumeração DeviceAuthSslResult, que fornece informações detalhadas sobre a falha. Por exemplo:

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

Usar a cadeia de certificados do locatário no servidor

Para executar a autenticação mútua, o servidor precisa conseguir verificar se o dispositivo pertence ao seu locatário do Azure Sphere e se o próprio locatário é legítimo. Para executar essa autenticação, o servidor exige a cadeia de certificados do locatário do Azure Sphere, que assina todos os seus dispositivos Azure Sphere:

Para obter a cadeia de certificados do seu locatário, baixe-o em um arquivo .p7b, como no seguinte exemplo:

azsphere ca-certificate download-chain --destination CA-cert-chain.p7b

Em seguida, use o arquivo .p7b no servidor.

Dicas adicionais para usar o curl

Aqui estão algumas outras dicas para usar o curl em um aplicativo do Azure Sphere.

  • Se você planeja armazenar o conteúdo da página na RAM ou em flash, saiba que o armazenamento no dispositivo do Azure Sphere é limitado.

  • Para garantir que o cURL siga os redirecionamentos, adicione o seguinte ao código:

    curl_easy_setopt(curl_handle, CURLOPT_FOLLOWLOCATION, 1L);
    
  • Para adicionar informações detalhadas sobre as operações do curl que possam ser úteis durante a depuração:

    curl_easy_setopt(curl_handle, CURLOPT_VERBOSE, 1L);
    
  • Alguns servidores retornam erros quando uma solicitação não contém um agente do usuário. Para definir um agente do usuário:

    curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "libcurl-agent/1.0");
    
  • Ao lidar com retornos de chamada de temporizador de curl_multi, evite chamadas recursivas quando o tempo limite relatado for de 0 ms, pois isso pode levar a um comportamento imprevisível. Em vez disso, trate 0ms como 1ms disparando um EventLoopTimer (0ms EventLoopTimers também são recursivos e devem ser evitados).

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