Připojení k webovým službám

Sada Azure Sphere SDK obsahuje knihovnu libcurl, kterou můžou aplikace vysoké úrovně používat k připojení a ověřování pomocí webových služeb HTTP a HTTPS. Podporuje se ověřování serveru i klienta, takže aplikace můžou ověřit, že komunikují s očekávaným serverem, a můžou serveru prokázat, že jejich zařízení a katalog Azure Sphere jsou legitimní. Vzájemné ověřování kombinuje tyto dvě možnosti.

Úložiště ukázek Azure Sphere na GitHubu obsahuje následující ukázky curl:

  • HTTPS_Curl_Easy používá k ověřování serveru synchronní (blokující) rozhraní API.
  • HTTPS_Curl_Multi ukázka používá pro ověřování serveru asynchronní (neblokující) rozhraní API.

I když je synchronní přístup k ověřování serveru v HTTPS_Curl_Easy poměrně jednoduchý, aplikace Azure Sphere by obecně měly používat složitější asynchronní techniku uvedenou v ukázce HTTPS_Curl_Multi spolu se vzorem událostí založeným na epolu a s jedním vláknem.

Web libcurl poskytuje podrobnou dokumentaci k rozhraní LIBCURL C API a mnoho příkladů. Rozdíly mezi knihovnou cURL a knihovnou modulu runtime sady Azure Sphere SDK jsou následující:

Název konstanty
(definice)
Omezení rozsahu cURL Limity rozsahu Azure Sphere
CURLOPT_BUFFERSIZE
(velikost vyrovnávací paměti)
Výchozí hodnota: 16 kB Výchozí: 1536 kB
CURLOPT_UPLOAD_BUFFERSIZE
(velikost vyrovnávací paměti pro nahrávání)
Výchozí: 64 kB
Maximum: 2 MB
Minimum: 16 KB
Výchozí: 1536 kB
Maximálně: 64 kB
Minimum: 1536 KB
CURLOPT_HEADERFUNCTION
(úplná hlavička HTTP předaná této funkci)
Maximálně: 100 kB Maximálně: 16 kB
CURLOPT_DNS_CACHE_TIMEOUT Výchozí: Výsledky ukládání výsledků do mezipaměti po dobu 60 sekund
Maximum: Výsledky mezipaměti navždy
Minimum: 0 (výsledky neuklyšovat do mezipaměti)
Všechny hodnoty jsou přepsány na 0 a výsledky se neukládají do mezipaměti.

Požadavky na aplikace, které používají curl

Aplikace, které používají knihovnu curl, musí obsahovat příslušné soubory hlaviček a v manifestu aplikace musí poskytovat UUID tenanta Azure Sphere (starší verze) a informace o internetovém hostiteli.

Soubory hlaviček

Pokud chcete použít curl, zahrňte do aplikace tyto soubory hlaviček:

#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

Soubor hlaviček storage.h se vyžaduje pouze v případě, že v balíčku bitové kopie aplikace zadáte jeden nebo více certifikátů. Hlavička deviceauth_curl.h se vyžaduje pro vzájemné ověřování. Hlavička networking_curl.h se vyžaduje, pokud aplikace pro připojení k internetu používá proxy server.

Manifest aplikace

Pole AllowedConnections manifestu aplikace musí určovat hostitele, ke kterým se aplikace připojuje. Musí také obsahovat názvy jednotlivých domén, se kterými se může připojení setkat v případě přesměrování. Například pro aplikaci, která se připojuje k domovské stránce Microsoftu, se vyžadují obě microsoft.comwww.microsoft.com a.

Pokud aplikace používá vzájemné ověřování, musí pole DeviceAuthentication manifestu obsahovat UUID tenanta Azure Sphere (starší verze). Certifikáty pro ověřování zařízení se vydávají jenom v případě, že je katalog zařízení propojený s UUID tenanta Azure Sphere (starší verze), které odpovídá identifikátoru UUID tenanta v manifestu aplikace. Toto omezení poskytuje hloubkovou ochranu: aplikace běžící na zařízení v jiném katalogu (například jiného zákazníka nebo podvodné entity) se nemůže ověřit na serveru.

Během vývoje můžete zjistit UUID starší verze tenanta pomocí příkazu az sphere catalog show a extrahováním MigratedCatalogId hodnoty z objektu tags .

Pokud aplikace používá proxy server, pole ReadNetworkProxyConfig označuje, jestli má aplikace oprávnění k načtení konfigurace proxy serveru.

V následujícím příkladu pole AllowedConnections určuje, že se aplikace připojuje pouze k www.example.com, pole DeviceAuthentication určuje UUID tenanta Azure Sphere (starší verze) a umožňuje aplikaci používat certifikát zařízení pro vzájemné ověřování a pole ReadNetworkProxyConfig určuje, že aplikace může znovu získat informace o konfiguraci proxy serveru.

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

Podporované funkce

Libcurl pro Azure Sphere podporuje pouze protokoly HTTP a HTTPS. Operační systém Azure Sphere navíc nepodporuje některé funkce, jako jsou zapisovatelné soubory (soubory cookie) nebo sokety systému UNIX. Funkce, které nebudou podporovány v budoucích verzích knihovny libcurl, jako je řada mprintf(), nejsou k dispozici.

Libcurl pro Azure Sphere podporuje protokoly TLS 1.2 a TLS 1.3 a vyřadil protokoly TLS 1.0 a TLS 1.1 v souladu s širší strategií zabezpečení tls od Microsoftu.

Podporované šifrovací sady jsou následující:

  • 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

Při pokusu o použití nepodporované verze protokolu TLS se zobrazí chyba CyaSSL does not support <version>.

Ověřování serveru

Azure Sphere podporuje ověřování serveru prostřednictvím knihovny libcurl. Certifikát serveru musí být podepsaný certifikační autoritou (CA), které zařízení důvěřuje. Aby služba libcurl ověřila server, musí aplikace zadat cestu k souboru certifikační autority.

Přidání certifikátů certifikační autority do balíčku imagí

Pokud chcete použít jednu nebo více certifikačních autorit, musíte certifikáty přidat do balíčku image. Každý certifikát musí mít kódování base-64. Nejjednodušším způsobem je vytvořit jeden soubor, který bude obsahovat všechny další certifikáty. Soubor musí mít příponu souboru .pem. Přidání certifikátů:

  1. Ve složce projektu pro vaši aplikaci vytvořte složku certs. Složka projektu obsahuje soubor CMakeLists pro vaši aplikaci.
  2. Ve složce certs vytvořte textový soubor s příponou .pem, zkopírujte do něj jednotlivé certifikáty a soubor uložte.
  3. V souboru CMakeLists.txt přidejte soubor certifikátu do balíčku bitové kopie jako soubor prostředků. Příklad:
azsphere_target_add_image_package(${PROJECT_NAME} RESOURCE_FILES "certs/DigiCertGlobalRootCA.pem")

Soubor certifikátu by se teď měl zobrazit ve složce certs v balíčku image.

Nastavení umístění certifikátů

V aplikaci použijte možnosti CURLOPT_CAPATH a CURLOPT_CAINFO k nastavení umístění certifikátů. Voláním Storage_GetAbsolutePathInImagePackage načtěte absolutní cestu k certifikátům v balíčku image a pak zavolejte curl_easy_setopt.

CURLOPT_CAPATH nastaví výchozí složku pro certifikáty. Například následující kód říká curl, aby hledal certifikáty ve složce certs na obrázku:

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

CURLOPT_CAINFO nastaví cestu k souboru, který obsahuje jeden nebo více certifikátů. Curl prohledá tento soubor kromě výchozí složky nastavené v CURLOPT_CAPATH. Příklad:

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

Tento kód říká curl, aby důvěřoval všem certifikačním autoritám definovaným v souboru mycertificates.pem kromě certifikačních autorit, které jsou definované v adresáři nastaveném v CURLOPT_CAPATH.

Vzájemné ověřování

Vzájemné ověřování ověřuje, že server i klientské zařízení jsou legitimní. Jedná se o vícekrokový proces:

  1. Aplikace ověřuje server pomocí certifikátu certifikační autority, jak je popsáno v tématu Ověřování serveru.
  2. Aplikace předloží serveru certifikát ověřování klienta x509, aby server mohl zařízení ověřit.
  3. Server používá řetěz certifikátů katalogu Azure Sphere k ověření, že zařízení patří do katalogu.

Aplikace může nastavit stránku ověřování zařízení při vzájemném ověřování jedním ze dvou způsobů:

  • Nakonfigurujte funkci DeviceAuth_CurlSslFunc Azure Sphere jako funkci SSL, která provádí ověřování.
  • Vytvořte vlastní funkci SSL, která volá funkci DeviceAuth_SslCtxFunc Azure Sphere pro ověření.

Poznámka

Azure Sphere nepodporuje opětovné vyjednávání SSL/TLS.

Než použijete některou z funkcí, musíte aktualizovat soubor CMakeLists.txt pro vaši aplikaci tak, aby do TARGET_LINK_LIBRARIES přidal nástroje curl a tlsutils:

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

Použití DeviceAuth_CurlSslFunc

Nejjednodušší způsob, jak provést ověřování zařízení, je nakonfigurovat DeviceAuth_CurlSslFunc jako funkci zpětného volání pro ověřování 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;
}

Funkce DeviceAuth_CurlSslFunc načte řetěz certifikátů pro aktuální katalog Azure Sphere a nastaví připojení curl pro vzájemné ověřování. Pokud ověřování selže, vrátí funkce CURLE_SSL_CERTPROBLEM.

Použití DeviceAuth_SslCtxFunc

Aplikace může také použít vlastní funkci zpětného volání SSL, která volá funkci azure sphere DeviceAuth_SslCtxFunc pro ověření.

Vaše vlastní funkce SSL musí za účelem ověření volat DeviceAuth_SslCtxFunc , ale může také provádět další úlohy související s ověřováním. DeviceAuth_SslCtxFunc vrátí hodnotu výčtu DeviceAuthSslResult , která poskytuje podrobné informace o selhání. Příklad:

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

Použití řetězu certifikátů katalogu na serveru

Aby bylo možné provést vzájemné ověřování, musí být server schopný ověřit, že zařízení patří do vašeho katalogu Azure Sphere a že samotný katalog je legitimní. K provedení tohoto ověřování server vyžaduje řetěz certifikátů katalogu Azure Sphere, který podepisuje všechna vaše zařízení Azure Sphere:

Pokud chcete získat řetěz certifikátů pro váš katalog, stáhněte si ho do souboru .p7b, jak je znázorněno v následujícím příkladu:

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

Potom můžete na serveru použít soubor .p7b.

Další tipy pro používání curl

Tady je několik dalších tipů pro použití curl v aplikaci Azure Sphere.

  • Pokud plánujete ukládat obsah stránky v paměti RAM nebo flash, mějte na paměti, že úložiště na zařízení Azure Sphere je omezené.

  • Abyste měli jistotu, že curl sleduje přesměrování, přidejte do kódu následující:

    curl_easy_setopt(curl_handle, CURLOPT_FOLLOWLOCATION, 1L);
    
  • Pokud chcete přidat podrobné informace o operacích curl, které by mohly být užitečné při ladění:

    curl_easy_setopt(curl_handle, CURLOPT_VERBOSE, 1L);
    
  • Některé servery vrací chyby, pokud požadavek neobsahuje uživatelského agenta. Nastavení uživatelského agenta:

    curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "libcurl-agent/1.0");
    
  • Při zpracování zpětných volání časovače curl_multi se vyhněte rekurzivním voláním, když je nahlášený časový limit 0ms, protože to může vést k nepředvídatelnému chování. Místo toho 0ms považovat za 1ms aktivací EventLoopTimer (0ms EventLoopTimer je také rekurzivní a měli byste se jim vyhnout).

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