Compartir vía


Conexión a servicios web

Importante

Esta es la documentación de Azure Sphere (heredado). Azure Sphere (heredado) se retira el 27 de septiembre de 2027 y los usuarios deben migrar a Azure Sphere (integrado) en este momento. Use el selector de versiones situado encima de la TOC para ver la documentación de Azure Sphere (integrado).

El SDK de Azure Sphere incluye la biblioteca de libcurl, que las aplicaciones de alto nivel pueden usar para conectarse y autenticarse con servicios web HTTP y HTTPS. Se admiten tanto la autenticación de servidor como la autenticación de cliente, de modo que las aplicaciones puedan comprobar que se están comunicando con el servidor esperado y puedan demostrar al servidor que su dispositivo e inquilino de Azure Sphere son legítimos. La autenticación mutua combina las dos.

En el repositorio de ejemplos de Azure Sphere en GitHub se incluyen los siguientes ejemplos de CURL:

  • HTTPS_Curl_Easy usa una API sincrónica (de bloqueo) para la autenticación de servidor.
  • HTTPS_Curl_Multi usa una API asincrónica (sin bloqueo) para la autenticación de servidor.

Aunque el enfoque sincrónico para la autenticación de servidor en HTTPS_Curl_Easy es bastante sencillo, por lo general, las aplicaciones de Azure Sphere deben usar la técnica asincrónica más compleja que se muestra en el ejemplo HTTPS_Curl_Multi, junto con un patrón basado en epoll en un único subproceso controlado por eventos.

El sitio web de libcurl proporciona documentación detallada de C API de libcurl y muchos ejemplos más. Las diferencias entre la biblioteca cURL y la biblioteca en tiempo de ejecución del SDK de Azure Sphere son las siguientes:

Nombre de constante
(definición)
Límites de intervalos de cURL Límites de intervalos de Azure Sphere
CURLOPT_BUFFERSIZE
(tamaño del búfer)
Valor predeterminado: 16 KB Valor predeterminado: 1536 KB
CURLOPT_UPLOAD_BUFFERSIZE
(tamaño del búfer de carga)
Valor predeterminado: 64 KB
Máximo: 2 MB
Mínimo: 16 KB
Valor predeterminado: 1536 KB
Máximo: 64 KB
Mínimo: 1536 KB
CURLOPT_HEADERFUNCTION
(encabezado HTTP completo pasado a esta función)
Máximo: 100 KB Máximo: 16 KB
CURLOPT_DNS_CACHE_TIMEOUT Valor predeterminado: resultados de caché durante 60 segundos
Máximo: resultados de caché para siempre
Mínimo: 0 (no almacenar en caché los resultados)
Todos los valores se invalidan en 0 y los resultados no se almacenan en caché.

Requisitos para las aplicaciones que usan CURL

Las aplicaciones que usan la biblioteca de CURL deben incluir los archivos de encabezado adecuados y proporcionar información del inquilino y del host de Internet en el manifiesto de aplicación.

Archivos de encabezado

Para usar CURL, incluya estos archivos de encabezado en la aplicación:

#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

El archivo de encabezado storage.h solo es necesario si se proporcionan uno o varios certificados en el paquete de imágenes de la aplicación. El encabezado deviceauth_curl.h es necesario para realizar la autenticación mutua. El encabezado networking_curl.h es necesario si la aplicación usa un proxy para conectarse a Internet.

Manifiesto de aplicación

El campo AllowedConnections del manifiesto de aplicación debe especificar los hosts a los que se conecta la aplicación. También debe contener el nombre de cada dominio que puede encontrar la conexión si se redirige. Por ejemplo, microsoft.com y www.microsoft.com son necesarios para que una aplicación se conecte a la página principal de Microsoft.

Si la aplicación usa la autenticación mutua, el campo DeviceAuthentication del manifiesto debe incluir el identificador de inquilino de Azure Sphere. Los certificados de autenticación de dispositivo solo se emiten si el identificador de inquilino del dispositivo coincide con el identificador de inquilino en el manifiesto de aplicación. Esta restricción proporciona defensa en profundidad: una aplicación que se ejecuta en un dispositivo en un inquilino diferente (por ejemplo, de otro cliente o de una entidad no autorizada) no se puede autenticar en el servidor.

Si la aplicación usa un proxy, el campo ReadNetworkProxyConfig indica si la aplicación tiene permiso para recuperar la configuración del proxy.

Durante el desarrollo, puede encontrar el identificador del inquilino actual de Azure Sphere mediante el comando azsphere tenant show-selected.

En el ejemplo siguiente, el campo AllowedConnections especifica que la aplicación se conecta solo a www.example.com, el campo DeviceAuthentication especifica el identificador de inquilino de Azure Sphere, lo que permite que la aplicación use el certificado de dispositivo para la autenticación mutua y el campo ReadNetworkProxyConfig especifica que la aplicación puede recuperar información de configuración de proxy.

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

Funcionalidad admitida

Libcurl para Azure Sphere admite los protocolos HTTP y HTTPS. Además, el sistema operativo Azure Sphere no admite algunas funcionalidades como, por ejemplo, los archivos editables (cookies) o los sockets de UNIX. Asimismo, aquellas características que no se admitirán en versiones futuras de libcurl, como la familia mprintf(), no están disponibles.

Libcurl para Azure Sphere admite TLS 1.2 y TLS 1.3 y ha retirado TLS 1.0 y TLS 1.1 en consonancia con la estrategia de seguridad de Microsoft TLS más amplia.

Estos son los conjuntos de cifrado admitidos:

  • 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

Los intentos de usar una versión no admitida de TLS devuelven el error CyaSSL does not support <version>.

Autenticación de servidor

Azure Sphere admite la autenticación de servidor mediante libcurl. Recuerde que el certificado del servidor debe firmarlo una entidad de certificación (CA) en la que confíe el dispositivo. Para que libcurl autentique un servidor, la aplicación debe proporcionar la ruta de acceso al archivo de la entidad de certificación.

Adición de certificados de entidad de certificación al paquete de imágenes

Para usar una o más entidades de certificación, debe agregar los certificados al paquete de imágenes. Cada certificado debe estar codificado en Base 64. El enfoque más sencillo es crear un único archivo que contenga todos los certificados adicionales. El archivo debe tener la extensión de nombre de archivo .pem. Para agregar los certificados:

  1. Cree una carpeta de certificados en la carpeta del proyecto de la aplicación. La carpeta del proyecto contiene el archivo CMakeLists de la aplicación.
  2. En la carpeta de certificados, cree un archivo de texto con la extensión .pem, copie cada certificado y guarde el archivo.
  3. En el archivo CMakeLists.txt, agregue el archivo de certificado al paquete de imágenes como un archivo de recursos. Por ejemplo:
azsphere_target_add_image_package(${PROJECT_NAME} RESOURCE_FILES "certs/DigiCertGlobalRootCA.pem")

El archivo de certificado debería aparecer en la carpeta de certificados en el paquete de imágenes.

Establecimiento de las ubicaciones de los certificados

En la aplicación, utilice las opciones CURLOPT_CAPATH y CURLOPT_CAINFO para establecer las ubicaciones de los certificados. Llame a Storage_GetAbsolutePathInImagePackage para recuperar la ruta de acceso absoluta a los certificados en el paquete de imágenes y, a continuación, llame a curl_easy_setopt.

CURLOPT_CAPATH establece una carpeta predeterminada para los certificados. Por ejemplo, el código siguiente indica a CURL que busque los certificados en la carpeta de certificados de la imagen:

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

CURLOPT_CAINFO establece una ruta de acceso a un archivo que contiene uno o varios certificados. Curl busca este archivo además de la carpeta predeterminada establecida en CURLOPT_CAPATH. Por ejemplo:

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

Este código indica a CURL que puede confiar en cualquier entidad de certificación que se defina en el archivo mycertificates.pem y en las entidades de certificación que se definan en el directorio configurado en CURLOPT_CAPATH.

Autenticación mutua

La autenticación mutua comprueba que el servidor y el dispositivo cliente son legítimos. Es un proceso compuesto por varios pasos:

  1. La aplicación autentica el servidor con un certificado de entidad de certificación, como se describe en Autenticación de servidor.
  2. La aplicación presenta un certificado de autenticación del cliente x509 al servidor para que el servidor pueda autenticar el dispositivo.
  3. El servidor usa la cadena de certificados del inquilino de Azure Sphere para comprobar que el dispositivo pertenece al inquilino.

Una aplicación puede configurar el lado de autenticación del dispositivo de la autenticación mutua de cualquiera de estas dos maneras:

  • Configure la función DeviceAuth_CurlSslFunc de Azure Sphere como la función SSL que realiza la autenticación.
  • Cree una función SSL personalizada que llame a la función DeviceAuth_SslCtxFunc de Azure Sphere para la autenticación.

Nota:

Azure Sphere no admite la renegociación de SSL/TLS.

Antes de utilizar cualquiera de las dos funciones, debe actualizar el archivo CMakeLists.txt de la aplicación para agregar curl y tlsutils a TARGET_LINK_LIBRARIES:

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

Usar DeviceAuth_CurlSslFunc

La manera más sencilla de realizar la autenticación de dispositivo es configurar DeviceAuth_CurlSslFunc como función de devolución de llamada para la autenticación SSL de 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;
}

La función DeviceAuth_CurlSslFunc recupera la cadena de certificados para el inquilino de Azure Sphere actual y configura la conexión de CURL para realizar la autenticación mutua. Si se produce un error en la autenticación, la función devuelve CURLE_SSL_CERTPROBLEM.

Uso de DeviceAuth_SslCtxFunc

Una aplicación también puede utilizar una función de devolución de llamada SSL personalizada que llame a la función DeviceAuth_SslCtxFunc de Azure Sphere para la autenticación.

La función SSL personalizada debe llamar a DeviceAuth_SslCtxFunc para realizar la autenticación, pero también puede realizar otras tareas relacionadas con la autenticación. DeviceAuth_SslCtxFunc devuelve un valor de la enumeración DeviceAuthSslResult, que proporciona información detallada sobre el error. Por ejemplo:

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

Uso de la cadena de certificados del inquilino en el servidor

Para realizar la autenticación mutua, el servidor debe ser capaz de comprobar que el dispositivo pertenece a su inquilino de Azure Sphere y que el propio inquilino es legítimo. Para llevar a cabo esta autenticación, el servidor necesita la cadena de certificados del inquilino de Azure Sphere, que firma todos los dispositivos de Azure Sphere:

Para obtener la cadena de certificados del inquilino, descárguela en un archivo .p7b, como en el ejemplo siguiente:

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

Después, puede usar el archivo .p7b en el servidor.

Sugerencias adicionales para usar CURL

Estas son algunas sugerencias adicionales para usar CURL en una aplicación de Azure Sphere.

  • Si va a almacenar contenido de la página en la memoria RAM o en una unidad flash, tenga en cuenta que el almacenamiento en el dispositivo de Azure Sphere es limitado.

  • Para asegurarse de que CURL sigue las acciones de redirección, agregue lo siguiente al código:

    curl_easy_setopt(curl_handle, CURLOPT_FOLLOWLOCATION, 1L);
    
  • Para agregar información detallada sobre las operaciones de CURL que pueden resultarle útiles durante la depuración:

    curl_easy_setopt(curl_handle, CURLOPT_VERBOSE, 1L);
    
  • Algunos servidores devuelven errores si una solicitud no contiene un agente de usuario. Para configurar un agente de usuario:

    curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "libcurl-agent/1.0");
    
  • Al controlar curl_multi devoluciones de llamada del temporizador, evite llamadas recursivas cuando el tiempo de espera notificado sea de 0 ms, ya que esto puede provocar un comportamiento impredecible. En su lugar, trate 0 ms como 1ms mediante el desencadenamiento de EventLoopTimer (0ms EventLoopTimers también son recursivos y deben evitarse).

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