Partilhar via


Ligar a serviços Web

O SDK do Azure Sphere inclui a biblioteca libcurl, que as aplicações de alto nível podem utilizar para ligar e autenticar com serviços Web HTTP e HTTPS. Tanto a autenticação do servidor como do cliente são suportadas, para que as aplicações possam verificar se estão a comunicar com o servidor esperado e possam provar ao servidor que o respetivo dispositivo e catálogo 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 no HTTPS_Curl_Easy seja bastante simples, as aplicações do Azure Sphere devem geralmente utilizar a técnica assíncrona mais complexa mostrada no exemplo de HTTPS_Curl_Multi, juntamente com um padrão baseado em epoll e baseado em eventos de thread único.

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

Nome Constante
(definição)
Limites do intervalo cURL Limites de intervalo do Azure Sphere
CURLOPT_BUFFERSIZE
(tamanho da memória intermédia)
Predefinição: 16 KB Predefinição: 1536 KB
CURLOPT_UPLOAD_BUFFERSIZE
(carregar tamanho da memória intermédia)
Predefinição: 64 KB
Máximo: 2 MB
Mínimo: 16 KB
Predefinição: 1536 KB
Máximo: 64 KB
Mínimo: 1536 KB
CURLOPT_HEADERFUNCTION
(cabeçalho HTTP completo transmitido para esta função)
Máximo: 100 KB Máximo: 16 KB
CURLOPT_DNS_CACHE_TIMEOUT Predefinição: resultados da cache durante 60 segundos
Máximo: resultados da cache para sempre
Mínimo: 0 (não colocar resultados em cache)
Todos os valores são substituídos para 0 e os resultados não são colocados em cache.

Requisitos para aplicações que utilizam curl

As aplicações que utilizam a biblioteca curl têm de incluir os ficheiros de cabeçalho adequados e fornecer o UUID do inquilino do Azure Sphere (Legado) e as informações do anfitrião da Internet no manifesto da aplicação.

Ficheiros de cabeçalho

Para utilizar o curl, inclua estes ficheiros de cabeçalho na sua aplicação:

#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 ficheiro de cabeçalho storage.h só é necessário se fornecer um ou mais certificados no pacote de imagem da aplicação. O cabeçalho deviceauth_curl.h é necessário para efetuar a autenticação mútua. O cabeçalho networking_curl.h é necessário se a aplicação estiver a utilizar um proxy para ligar à Internet.

Manifesto da aplicação

O campo AllowedConnections do manifesto da aplicação tem de especificar os anfitriões aos quais a aplicação se liga. Também tem de conter o nome de cada domínio que a ligação possa encontrar se for redirecionada. Por exemplo, e microsoft.comwww.microsoft.com são necessários para uma aplicação que se liga à home page da Microsoft.

Se a aplicação utilizar autenticação mútua, o campo DeviceAuthentication do manifesto tem de incluir o UUID do inquilino do Azure Sphere (Legado). Os certificados de autenticação de dispositivos só são emitidos se o catálogo do dispositivo estiver ligado a um UUID de inquilino do Azure Sphere (Legado) que corresponda ao UUID do inquilino no manifesto da aplicação. Esta restrição fornece defesa em profundidade: uma aplicação em execução num dispositivo num catálogo diferente (por exemplo, a de um cliente diferente ou de uma entidade não autorizado) não pode autenticar-se no servidor.

Durante o desenvolvimento, pode encontrar o UUID do inquilino legado com o comando az sphere catalog show e extrair o MigratedCatalogId valor do tags objeto.

Se a aplicação utilizar um proxy, o campo ReadNetworkProxyConfig indica se a aplicação tem permissão para obter a configuração do proxy.

No exemplo seguinte, o campo AllowedConnections especifica que a aplicação se liga apenas a www.example.com, o campo DeviceAuthentication especifica o UUID do inquilino do Azure Sphere (Legado), permitindo que a aplicação utilize o certificado de dispositivo para autenticação mútua e o campo ReadNetworkProxyConfig especifica que a aplicação pode obter informações de configuração de proxy novamente.

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

Funcionalidade suportada

O Libcurl para o Azure Sphere suporta apenas os protocolos HTTP e HTTPS. Além disso, o SO do Azure Sphere não suporta algumas funcionalidades, como ficheiros graváveis (cookies) ou sockets UNIX. As funcionalidades que não serão suportadas em versões libcurl futuras, como a família mprintf(), não estão disponíveis.

O Libcurl para o Azure Sphere suporta o TLS 1.2 e o TLS 1.3 e retirou o TLS 1.0 e o TLS 1.1 em conformidade com a estratégia de segurança mais ampla do Microsoft TLS.

Seguem-se os conjuntos de cifras suportados:

  • 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 utilizar uma versão não suportada do TLS devolvem o erro CyaSSL does not support <version>.

Autenticação do servidor

O Azure Sphere suporta a autenticação de servidor através de libcurl. O certificado do servidor tem de ser assinado por uma Autoridade de Certificação (AC) em que o dispositivo confie. Para que o libcurl autentique um servidor, a aplicação tem de fornecer o caminho para o ficheiro de AC.

Adicionar certificados de AC ao pacote de imagem

Para utilizar uma ou mais ACs, tem de adicionar os certificados ao pacote de imagem. Cada certificado tem de ter codificação base 64. A abordagem mais simples é criar um único ficheiro que contenha todos os certificados adicionais. O ficheiro tem de ter a extensão de nome de ficheiro .pem. Para adicionar certificados:

  1. Crie uma pasta de certificados na pasta do projeto para a sua aplicação. A pasta do projeto contém o ficheiro CMakeLists da sua aplicação.
  2. Na pasta certs, crie um ficheiro de texto com a extensão .pem, copie cada certificado para o mesmo e guarde o ficheiro.
  3. No ficheiro CMakeLists.txt, adicione o ficheiro de certificado ao pacote de imagem como um ficheiro de recursos. Por exemplo:
azsphere_target_add_image_package(${PROJECT_NAME} RESOURCE_FILES "certs/DigiCertGlobalRootCA.pem")

O ficheiro de certificado deverá agora aparecer na pasta certs no pacote de imagem.

Definir localizações de certificados

Na sua aplicação, utilize as opções CURLOPT_CAPATH e CURLOPT_CAINFO para definir as localizações dos certificados. Chame Storage_GetAbsolutePathInImagePackage para obter o caminho absoluto para os certificados no pacote de imagem e, em seguida, chame curl_easy_setopt.

CURLOPT_CAPATH define uma pasta predefinida para os certificados. Por exemplo, o código seguinte indica ao curl para procurar certificados na pasta certs na imagem:

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

CURLOPT_CAINFO define um caminho para um ficheiro que contém um ou mais certificados. O Curl procura este ficheiro para além da pasta predefinida definida no CURLOPT_CAPATH. Por exemplo:

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

Este código indica ao curl para confiar em quaisquer ACs definidas no ficheiro mycertificates.pem, além das ACs definidas no diretório definido no CURLOPT_CAPATH.

Autenticação mútua

A autenticação mútua verifica se o servidor e o dispositivo cliente são legítimos. É um processo com vários passos:

  1. A aplicação autentica o servidor com um certificado de AC, conforme descrito em Autenticação do servidor.
  2. A aplicação apresenta um certificado de autenticação de cliente x509 ao servidor para que o servidor possa autenticar o dispositivo.
  3. O servidor utiliza a cadeia de certificados do catálogo do Azure Sphere para verificar se o dispositivo pertence ao catálogo.

Uma aplicação pode configurar o lado da autenticação do dispositivo da autenticação mútua de uma das duas formas:

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

Nota

O Azure Sphere não suporta a renegociação SSL/TLS.

Antes de utilizar qualquer uma das funções, tem de atualizar o ficheiro de CMakeLists.txt da aplicação para adicionar curl e tlsutils a TARGET_LINK_LIBRARIES:

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

Utilizar DeviceAuth_CurlSslFunc

A forma mais simples de efetuar a autenticação do dispositivo é configurar DeviceAuth_CurlSslFunc como função de chamada de retorno para a autenticação SSL 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 obtém a cadeia de certificados para o catálogo atual do Azure Sphere e configura a ligação curl para efetuar a autenticação mútua. Se a autenticação falhar, a função devolve CURLE_SSL_CERTPROBLEM.

Utilizar DeviceAuth_SslCtxFunc

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

A função SSL personalizada tem de chamar DeviceAuth_SslCtxFunc para efetuar a autenticação, mas também pode realizar outras tarefas relacionadas com a autenticação. DeviceAuth_SslCtxFunc devolve um valor da DeviceAuthSslResult enumeração, 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;
    }

Utilizar a cadeia de certificados de catálogo no servidor

Para efetuar a autenticação mútua, o servidor tem de ser capaz de verificar se o dispositivo pertence ao catálogo do Azure Sphere e se o próprio catálogo é legítimo. Para efetuar esta autenticação, o servidor requer a cadeia de certificados do catálogo do Azure Sphere, que assina todos os seus dispositivos do Azure Sphere:

Para obter a cadeia de certificados do seu catálogo, transfira-a para um ficheiro .p7b, como no exemplo seguinte:

az sphere ca-certificate download-chain --destination CA-cert-chain.p7b

Em seguida, pode utilizar o ficheiro .p7b no servidor.

Sugestões adicionais para utilizar o curl

Seguem-se algumas sugestões adicionais para utilizar curl numa aplicação do Azure Sphere.

  • Se planear armazenar conteúdo de página na RAM ou flash, tenha em atenção que o armazenamento no dispositivo do Azure Sphere é limitado.

  • Para garantir que o curl segue os redirecionamentos, adicione o seguinte ao código:

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

    curl_easy_setopt(curl_handle, CURLOPT_VERBOSE, 1L);
    
  • Alguns servidores devolvem erros se um pedido não contiver um agente de utilizador. Para definir um agente de utilizador:

    curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "libcurl-agent/1.0");
    
  • Ao lidar com chamadas de retorno de temporizador curl_multi, evite chamadas recursivas quando o tempo limite comunicado for de 0 ms, uma vez que isso pode levar a comportamentos imprevisíveis. Em vez disso, trate os 0ms como 1 ms ao acionar 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;
    }