Verbinding maken met webservices

De Azure Sphere SDK bevat de libcurl-bibliotheek, die toepassingen op hoog niveau kunnen gebruiken om verbinding te maken en te verifiëren met HTTP- en HTTPS-webservices. Zowel server- als clientverificatie worden ondersteund, zodat toepassingen kunnen controleren of ze communiceren met de verwachte server en aan de server kunnen bewijzen dat hun apparaat en Azure Sphere-tenant legitiem zijn. Wederzijdse verificatie combineert deze twee.

De Azure Sphere-voorbeeldopslagplaats op GitHub bevat de volgende curl-voorbeelden:

Hoewel de synchrone benadering van serververificatie in HTTPS_Curl_Easy vrij eenvoudig is, moeten Azure Sphere-toepassingen over het algemeen de complexere asynchrone techniek gebruiken die wordt weergegeven in het HTTPS_Curl_Multi voorbeeld, samen met een op epoll gebaseerd, gebeurtenisgestuurd patroon met één thread.

De libcurl-website biedt uitgebreide documentatie van de libcurl C-API en vele voorbeelden. De verschillen tussen de cURL-bibliotheek en de Azure Sphere SDK-runtimebibliotheek zijn als volgt:

Constante naam
(definitie)
Limieten voor cURL-bereik Limieten voor Azure Sphere-bereik
CURLOPT_BUFFERSIZE
(buffergrootte)
Standaardinstelling: 16 kB Standaardinstelling: 1536 kB
CURLOPT_UPLOAD_BUFFERSIZE
(buffergrootte uploaden)
Standaardinstelling: 64 kB
Maximum: 2 MB
Minimaal: 16 kB
Standaardinstelling: 1536 kB
Maximaal: 64 kB
Minimaal: 1536 kB
CURLOPT_HEADERFUNCTION
(volledige HTTP-header doorgegeven aan deze functie)
Maximum: 100 KB Maximaal: 16 kB
CURLOPT_DNS_CACHE_TIMEOUT Standaardinstelling: resultaten gedurende 60 seconden in de cache opslaan
Maximum: resultaten voor altijd in cache opslaan
Minimaal: 0 (geen resultaten opslaan in de cache)
Alle waarden worden overschreven op 0 en resultaten worden niet in de cache opgeslagen.

Vereisten voor toepassingen die gebruikmaken van curl

Toepassingen die gebruikmaken van de curl-bibliotheek moeten de juiste headerbestanden bevatten en tenant- en internethostgegevens opgeven in het toepassingsmanifest.

Koptekstbestanden

Als u curl wilt gebruiken, neemt u deze headerbestanden op in uw toepassing:

#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

Het headerbestand storage.h is alleen vereist als u een of meer certificaten opgeeft in het toepassingsinstallatiekopiepakket. De header deviceauth_curl.h is vereist voor het uitvoeren van wederzijdse verificatie. De header networking_curl.h is vereist als de toepassing een proxy gebruikt om verbinding te maken met internet.

Toepassingsmanifest

Het veld AllowedConnections van het toepassingsmanifest moet de hosts opgeven waarmee de toepassing verbinding maakt. Het moet ook de naam bevatten van elk domein dat de verbinding kan tegenkomen als deze wordt omgeleid. Zowel als microsoft.comwww.microsoft.com zijn bijvoorbeeld vereist voor een toepassing die verbinding maakt met de Startpagina van Microsoft.

Als de toepassing gebruikmaakt van wederzijdse verificatie, moet het veld DeviceAuthentication van het manifest de Azure Sphere-tenant-id bevatten. Apparaatverificatiecertificaten worden alleen uitgegeven als de tenant-id van het apparaat overeenkomt met de tenant-id in het toepassingsmanifest. Deze beperking biedt diepgaande verdediging: een toepassing die wordt uitgevoerd op een apparaat in een andere tenant (bijvoorbeeld die van een andere klant of een rogue-entiteit) kan niet worden geverifieerd bij de server.

Als de toepassing een proxy gebruikt, geeft het veld ReadNetworkProxyConfig aan of de toepassing gemachtigd is om de proxyconfiguratie op te halen.

Tijdens de ontwikkeling kunt u de id van de huidige Azure Sphere-tenant vinden met behulp van de opdracht azsphere tenant show-selected .

In het volgende voorbeeld geeft het veld AllowedConnections aan dat de toepassing alleen www.example.comverbinding maakt met , geeft het veld DeviceAuthentication de tenant-id van Azure Sphere op, waardoor de toepassing het apparaatcertificaat kan gebruiken voor wederzijdse verificatie en het veld ReadNetworkProxyConfig geeft aan dat de toepassing proxyconfiguratiegegevens kan ophalen.

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

Ondersteunde functionaliteit

Libcurl voor Azure Sphere ondersteunt alleen de HTTP- en HTTPS-protocollen. Bovendien biedt het Azure Sphere-besturingssysteem geen ondersteuning voor bepaalde functies, zoals beschrijfbare bestanden (cookies) of UNIX-sockets. Functies die niet worden ondersteund in toekomstige libcurl-releases, zoals de mprintf() -familie, zijn niet beschikbaar.

Libcurl voor Azure Sphere ondersteunt TLS 1.2 en TLS 1.3 en heeft TLS 1.0 en TLS 1.1 buiten gebruik gesteld in overeenstemming met de bredere Microsoft TLS-beveiligingsstrategie.

Hier volgen de ondersteunde coderingssuites:

  • 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

Pogingen om een niet-ondersteunde versie van TLS te gebruiken, retourneren de fout CyaSSL does not support <version>.

Serververificatie

Azure Sphere ondersteunt serververificatie via libcurl. Het certificaat van de server moet zijn ondertekend door een certificeringsinstantie (CA) die het apparaat vertrouwt. Libcurl kan een server alleen verifiëren als de toepassing het pad naar het CA-bestand opgeeft.

CA-certificaten toevoegen aan het installatiekopieënpakket

Als u een of meer CA's wilt gebruiken, moet u de certificaten toevoegen aan uw installatiekopieënpakket. Elk certificaat moet een base-64-codering hebben. De eenvoudigste aanpak is om één bestand te maken dat alle aanvullende certificaten bevat. Het bestand moet de bestandsnaamextensie .pem hebben. Certificaten toevoegen:

  1. Maak een map met certificaten in de projectmap voor uw toepassing. De projectmap bevat het bestand CMakeLists voor uw toepassing.
  2. Maak in de map certificaten een tekstbestand met de extensie .pem, kopieer elk certificaat naar het bestand en sla het bestand op.
  3. Voeg in het CMakeLists.txt-bestand het certificaatbestand als een resourcebestand toe aan het installatiekopieënpakket. Bijvoorbeeld:
azsphere_target_add_image_package(${PROJECT_NAME} RESOURCE_FILES "certs/DigiCertGlobalRootCA.pem")

Het certificaatbestand moet nu worden weergegeven in de map certs in het installatiekopieënpakket.

Certificaatlocaties instellen

Gebruik in uw toepassing de opties CURLOPT_CAPATH en CURLOPT_CAINFO om de locaties van de certificaten in te stellen. Roep Storage_GetAbsolutePathInImagePackage aan om het absolute pad naar de certificaten in het installatiekopieënpakket op te halen en roep vervolgens curl_easy_setopt aan.

CURLOPT_CAPATH stelt een standaardmap in voor de certificaten. De volgende code vertelt curl bijvoorbeeld om te zoeken naar certificaten in de map certs in de afbeelding:

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

CURLOPT_CAINFO stelt een pad in naar een bestand dat een of meer certificaten bevat. Curl doorzoekt dit bestand naast de standaardmap die is ingesteld in CURLOPT_CAPATH. Bijvoorbeeld:

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

Deze code vertelt curl om alle CA's te vertrouwen die zijn gedefinieerd in het bestand mycertificates.pem, naast CA's die zijn gedefinieerd in de mapset in CURLOPT_CAPATH.

Wederzijdse verificatie

Wederzijdse verificatie controleert of zowel de server als het clientapparaat legitiem zijn. Het is een proces met meerdere stappen:

  1. De toepassing verifieert de server met behulp van een CA-certificaat, zoals beschreven in Serververificatie.
  2. De toepassing presenteert een x509-clientverificatiecertificaat aan de server, zodat de server het apparaat kan verifiëren.
  3. De server gebruikt de certificaatketen van de Azure Sphere-tenant om te controleren of het apparaat tot de tenant behoort.

Een toepassing kan de apparaatverificatiezijde van wederzijdse verificatie op twee manieren instellen:

  • Configureer de functie Azure Sphere DeviceAuth_CurlSslFunc als de SSL-functie waarmee verificatie wordt uitgevoerd.
  • Maak een aangepaste SSL-functie die de functie Azure Sphere DeviceAuth_SslCtxFunc aanroept voor verificatie.

Opmerking

Azure Sphere biedt geen ondersteuning voor opnieuw onderhandelen over SSL/TLS.

Voordat u een van beide functies gebruikt, moet u het CMakeLists.txt-bestand voor uw toepassing bijwerken om curl- en tlsutils toe te voegen aan TARGET_LINK_LIBRARIES:

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

Gebruik DeviceAuth_CurlSslFunc

De eenvoudigste manier om apparaatverificatie uit te voeren, is door DeviceAuth_CurlSslFunc te configureren als de callback-functie voor curl SSL-verificatie:

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

De functie DeviceAuth_CurlSslFunc haalt de certificaatketen op voor de huidige Azure Sphere-tenant en stelt de curl-verbinding in om wederzijdse verificatie uit te voeren. Als verificatie mislukt, retourneert de functie CURLE_SSL_CERTPROBLEM.

Gebruik DeviceAuth_SslCtxFunc

Een toepassing kan ook een aangepaste SSL-callback-functie gebruiken die de functie Azure Sphere DeviceAuth_SslCtxFunc aanroept voor verificatie.

Uw aangepaste SSL-functie moet DeviceAuth_SslCtxFunc aanroepen om de verificatie uit te voeren, maar kan ook andere taken met betrekking tot verificatie uitvoeren. DeviceAuth_SslCtxFunc retourneert een waarde van de DeviceAuthSslResult opsomming, die gedetailleerde informatie over de fout bevat. Bijvoorbeeld:

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

De tenantcertificaatketen op uw server gebruiken

Als u wederzijdse verificatie wilt uitvoeren, moet de server kunnen controleren of het apparaat deel uitmaakt van uw Azure Sphere-tenant en dat de tenant zelf legitiem is. Voor deze verificatie heeft de server de certificaatketen van de Azure Sphere-tenant nodig, waarmee al uw Azure Sphere-apparaten worden ondertekend:

Als u de certificaatketen voor uw tenant wilt ophalen, downloadt u deze naar een .p7b-bestand, zoals in het volgende voorbeeld:

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

Vervolgens kunt u het .p7b-bestand op uw server gebruiken.

Aanvullende tips voor het gebruik van curl

Hier volgen enkele aanvullende tips voor het gebruik van curl in een Azure Sphere-toepassing.

  • Als u van plan bent om pagina-inhoud op te slaan in RAM of Flash, moet u er rekening mee houden dat de opslag op het Azure Sphere-apparaat beperkt is.

  • Om ervoor te zorgen dat curl omleidingen volgt, voegt u het volgende toe aan uw code:

    curl_easy_setopt(curl_handle, CURLOPT_FOLLOWLOCATION, 1L);
    
  • Uitgebreide informatie toevoegen over curl-bewerkingen die nuttig kunnen zijn tijdens foutopsporing:

    curl_easy_setopt(curl_handle, CURLOPT_VERBOSE, 1L);
    
  • Sommige servers retourneren fouten als een aanvraag geen gebruikersagent bevat. Een gebruikersagent instellen:

    curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "libcurl-agent/1.0");
    
  • Wanneer u curl_multi timer callbacks verwerkt, vermijdt u recursieve oproepen wanneer de gerapporteerde time-out 0 ms is, omdat dit kan leiden tot onvoorspelbaar gedrag. Behandel in plaats daarvan 0 ms als 1 ms door een EventLoopTimer te activeren (0 ms EventLoopTimers zijn ook recursief en moeten worden vermeden).

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