Connettersi ai servizi Web
Azure Sphere SDK include la libreria libcurl, che le applicazioni di alto livello possono usare per connettersi e autenticarsi con i servizi Web HTTP e HTTPS. Sono supportate sia l'autenticazione server che quella client, in modo che le applicazioni possano verificare che stiano comunicando con il server previsto e dimostrare al server che il loro dispositivo e il catalogo Azure Sphere sono legittimi. L'autenticazione reciproca combina i due.
Il repository campioni di Azure Sphere su GitHub include i seguenti campioni di ricciolo:
- HTTPS_Curl_Easy usa un'API sincrona (blocco) per l'autenticazione server.
- HTTPS_Curl_Multi esempio usa un'API asincrona (non di blocco) per l'autenticazione server.
Sebbene l'approccio sincrono all'autenticazione server in HTTPS_Curl_Easy sia piuttosto semplice, le applicazioni Azure Sphere dovrebbero in genere usare la tecnica asincrona più complessa illustrata nell'esempio di HTTPS_Curl_Multi, insieme a un modello basato su epoll basato su un singolo thread basato su eventi.
Il sito Web libcurl fornisce una documentazione dettagliata dell'API C libcurl e molti esempi. Le differenze tra la libreria cURL e la libreria di runtime di Azure Sphere SDK sono le seguenti:
Nome costante (definizione) |
limiti dell'intervallo cURL | Limiti della portata di Azure Sphere |
---|---|---|
CURLOPT_BUFFERSIZE (dimensione buffer) |
Impostazione predefinita: 16 KB | Impostazione predefinita: 1536 KB |
CURLOPT_UPLOAD_BUFFERSIZE (dimensione buffer caricamento) |
Impostazione predefinita: 64 KB Massimo: 2 MB Minimo: 16 KB |
Impostazione predefinita: 1536 KB Massimo: 64 KB Minimo: 1536 KB |
CURLOPT_HEADERFUNCTION (intestazione HTTP completa passata a questa funzione) |
Massimo: 100 KB | Massimo: 16 KB |
CURLOPT_DNS_CACHE_TIMEOUT | Impostazione predefinita: risultati della cache per 60 secondi Massimo: risultati della cache per sempre Minimo: 0 (non memorizzare i risultati nella cache) |
Tutti i valori vengono sostituiti con 0 e i risultati non vengono memorizzati nella cache. |
Requisiti per le applicazioni che utilizzano curl
Le applicazioni che usano la libreria curl devono includere i file di intestazione appropriati e fornire informazioni sull'UUID del tenant Azure Sphere (legacy) e sull'host Internet nel manifesto dell'applicazione.
File di intestazione
Per usare curl, includere questi file di intestazione nell'applicazione:
#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
Il file di intestazione storage.h è obbligatorio solo se si specificano uno o più certificati nel pacchetto di immagini dell'applicazione. L'intestazione deviceauth_curl.h è necessaria per eseguire l'autenticazione reciproca. L'intestazione networking_curl.h è necessaria se l'applicazione usa un proxy per connettersi a Internet.
Manifesto dell'applicazione
Il campo AllowedConnections del manifesto dell'applicazione deve specificare gli host a cui si connette l'applicazione. Deve contenere anche il nome di ogni dominio che la connessione può riscontrare se reindirizzato. Ad esempio, entrambi microsoft.com
e www.microsoft.com
sono necessari per un'applicazione che si connette alla home page di Microsoft.
Se l'applicazione usa l'autenticazione reciproca, il campo DeviceAuthentication del manifesto deve includere l'UUID del tenant Azure Sphere (legacy). I certificati di autenticazione del dispositivo vengono rilasciati solo se il catalogo del dispositivo è collegato a un UUID del tenant Azure Sphere (legacy) che corrisponde all'UUID del tenant nel manifesto dell'applicazione. Questa restrizione fornisce una difesa approfondita: un'applicazione in esecuzione su un dispositivo in un catalogo diverso (ad esempio, quella di un cliente diverso o di un'entità canaglia) non può eseguire l'autenticazione nel server.
Durante lo sviluppo, puoi trovare l'UUID del tenant legacy utilizzando il comando show del catalogo di sfere az ed estraendo il MigratedCatalogId
valore dall'oggetto tags
.
Se l'applicazione usa un proxy, il campo ReadNetworkProxyConfig indica se l'applicazione dispone dell'autorizzazione per recuperare la configurazione del proxy.
Nell'esempio seguente il campo AllowedConnections specifica che l'applicazione si connette solo a www.example.com
, il campo DeviceAuthentication specifica l'UUID del tenant Azure Sphere (legacy), consentendo all'applicazione di usare il certificato di dispositivo per l'autenticazione reciproca e il campo ReadNetworkProxyConfig specifica che l'applicazione può reindirizzare le informazioni di configurazione del proxy.
"Capabilities": {
"AllowedConnections": [ "www.example.com" ],
"Gpio": [],
"Uart": [],
"WifiConfig": false,
"DeviceAuthentication": "00000000-0000-0000-0000-000000000000",
"ReadNetworkProxyConfig": true
}
Funzionalità supportate
Libcurl per Azure Sphere supporta solo i protocolli HTTP e HTTPS. Inoltre, il sistema operativo Azure Sphere non supporta alcune funzionalità, ad esempio file scrivibili (cookie) o socket UNIX. Le funzionalità che non saranno supportate nelle versioni libcurl future, ad esempio la famiglia mprintf( ), non sono disponibili.
Libcurl per Azure Sphere supporta TLS 1.2 e TLS 1.3 e ha ritirato TLS 1.0 e TLS 1.1 in linea con la strategia di sicurezza più ampia di Microsoft TLS.
Di seguito sono elencati i pacchetti di crittografia supportati:
- 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
I tentativi di utilizzare una versione non supportata di TLS restituiscono l'errore CyaSSL does not support <version>
.
Autenticazione server
Azure Sphere supporta l'autenticazione server tramite libcurl. Il certificato del server deve essere firmato da un'autorità di certificazione (CA) attendibile dal dispositivo. Per l'autenticazione di un server da parte di libcurl, l'applicazione deve fornire il percorso del file CA.
Aggiungere certificati CA al pacchetto di immagini
Per usare uno o più CA, è necessario aggiungere i certificati al pacchetto di immagini. Ogni certificato deve essere codificato in base 64. L'approccio più semplice consiste nel creare un singolo file contenente tutti i certificati aggiuntivi. Il file deve avere l'estensione pem. Per aggiungere certificati:
- Creare una cartella certs nella cartella del progetto per l'applicazione. La cartella di progetto contiene il file CMakeLists per l'applicazione.
- Nella cartella certs creare un file di testo con estensione pem, copiare ogni certificato e salvare il file.
- Nel file di CMakeLists.txt aggiungere il file di certificato al pacchetto immagine come file di risorse. Per esempio:
azsphere_target_add_image_package(${PROJECT_NAME} RESOURCE_FILES "certs/DigiCertGlobalRootCA.pem")
Il file del certificato dovrebbe ora essere visualizzato nella cartella certs del pacchetto di immagini.
Impostare le posizioni dei certificati
Nell'applicazione usare le opzioni CURLOPT_CAPATH e CURLOPT_CAINFO per impostare le posizioni dei certificati. Chiamare Storage_GetAbsolutePathInImagePackage per recuperare il percorso assoluto dei certificati nel pacchetto di immagini e quindi chiamare curl_easy_setopt.
CURLOPT_CAPATH imposta una cartella predefinita per i certificati. Ad esempio, il codice seguente indica a Curl di cercare i certificati nella cartella certs nell'immagine:
char *path = Storage_GetAbsolutePathInImagePackage("certs");
curl_easy_setopt(curl_handle, CURLOPT_CAPATH, path);
CURLOPT_CAINFO imposta un percorso a un file contenente uno o più certificati. Curl cerca in questo file oltre alla cartella predefinita impostata in CURLOPT_CAPATH. Per esempio:
char *path = Storage_GetAbsolutePathInImagePackage("CAs/mycertificates.pem");
curl_easy_setopt(curl_handle, CURLOPT_CAINFO, path);
Questo codice indica a Curl di considerare attendibili tutte le CA definite nel file mycertificates.pem, oltre alle CA definite nel set di directory in CURLOPT_CAPATH.
Autenticazione reciproca
L'autenticazione reciproca verifica che il server e il dispositivo client siano legittimi. Si tratta di un processo in più passaggi:
- L'applicazione autentica il server usando un certificato CA, come descritto in Autenticazione server.
- L'applicazione presenta un certificato di autenticazione client x509 al server in modo che il server possa autenticare il dispositivo.
- Il server utilizza la catena di certificati del catalogo Azure Sphere per verificare che il dispositivo appartenga al catalogo.
Un'applicazione può configurare il lato autenticazione dispositivo dell'autenticazione reciproca in uno dei due modi seguenti:
- Configurare la funzione DeviceAuth_CurlSslFunc Azure Sphere come funzione SSL che esegue l'autenticazione.
- Creare una funzione SSL personalizzata che chiama la funzione di DeviceAuth_SslCtxFunc Azure Sphere per l'autenticazione.
Nota
Azure Sphere non supporta la rinegoziazione SSL/TLS.
Prima di usare una delle due funzioni, è necessario aggiornare il file di CMakeLists.txt per l'applicazione per aggiungere curl e tlsutils a TARGET_LINK_LIBRARIES:
TARGET_LINK_LIBRARIES(${PROJECT_NAME} applibs pthread gcc_s c curl tlsutils)
Usare DeviceAuth_CurlSslFunc
Il modo più semplice per eseguire l'autenticazione del dispositivo consiste nel configurare DeviceAuth_CurlSslFunc come funzione di callback per l'autenticazione SSL arricciata:
// 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;
}
La funzione DeviceAuth_CurlSslFunc recupera la catena di certificati per il catalogo azure sphere corrente e imposta la connessione a curl per eseguire l'autenticazione reciproca. Se l'autenticazione non riesce, la funzione restituisce CURLE_SSL_CERTPROBLEM.
Usare DeviceAuth_SslCtxFunc
Un'applicazione può anche usare una funzione di callback SSL personalizzata che chiama la funzione DeviceAuth_SslCtxFunc Azure Sphere per l'autenticazione.
La funzione SSL personalizzata deve chiamare DeviceAuth_SslCtxFunc per eseguire l'autenticazione, ma può anche eseguire altre attività correlate all'autenticazione.
DeviceAuth_SslCtxFunc restituisce un valore dell'enumerazione DeviceAuthSslResult
, che fornisce informazioni dettagliate sull'errore. Per esempio:
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;
}
Usare la catena di certificati del catalogo nel server
Per eseguire l'autenticazione reciproca, il server deve essere in grado di verificare che il dispositivo appartenga al catalogo Azure Sphere e che il catalogo stesso sia legittimo. Per eseguire questa autenticazione, il server richiede la catena di certificati del catalogo Azure Sphere, che firma tutti i dispositivi Azure Sphere:
Per ottenere la catena di certificati per il catalogo, scaricarla in un file P7B, come nell'esempio seguente:
az sphere ca-certificate download-chain --destination CA-cert-chain.p7b
È quindi possibile usare il file p7b nel server.
Altri suggerimenti per l'uso del ricciolo
Ecco alcuni suggerimenti aggiuntivi per l'uso del curl in un'applicazione Azure Sphere.
Se prevedi di archiviare il contenuto della pagina in RAM o flash, tieni presente che lo spazio di archiviazione nel dispositivo Azure Sphere è limitato.
Per assicurarti che curl segua i reindirizzamenti, aggiungi quanto segue al codice:
curl_easy_setopt(curl_handle, CURLOPT_FOLLOWLOCATION, 1L);
Per aggiungere informazioni dettagliate sulle operazioni di curl che potrebbero essere utili durante il debug:
curl_easy_setopt(curl_handle, CURLOPT_VERBOSE, 1L);
Alcuni server restituiscono errori se una richiesta non contiene un agente utente. Per impostare un agente utente:
curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "libcurl-agent/1.0");
Quando si gestiscono curl_multi callback del timer, evitare chiamate ricorsive quando il timeout segnalato è 0ms, in quanto ciò può portare a comportamenti imprevedibili. Considera invece 0ms come 1ms attivando un EventoLoopTimer (anche 0ms EventLoopTimers sono ricorsivi e devono essere evitati).
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; }