第 2 章 - 安装和使用 Azure RTOS NetX Secure

本章描述了与安装、设置和使用 Azure RTOS NetX Secure 组件相关的各种问题。

产品版本号

用户可以通过在 nx_secure_tls.h 中查找以下符号来验证产品版本号:

NETX_SECURE_MAJOR_VERSION

NETX_SECURE_MINOR_VERSION

Service Pack 版本中定义了以下符号来指示服务包数:

NETX_SECURE_SERVICE_PACK_VERSION

产品分发

可于 https://github.com/azure-rtos/netx 获取 NetX Secure。 软件包中提供有源文件、包含文件和一个包含本文档的 PDF 文件,如下所示:

  • nx_secure_tls_api.h:NetX Secure TLS 的公共 API 头文件
  • nx_secure_tls_user.h:NetX Secure TLS 的用户定义的头文件
  • nx_secure_tls_port.h:NetX Secure 的特定于平台的定义
  • nx_secure_tls.h:NetX Secure TLS 的头文件
  • nx_secure_tls*.c/h:NetX Secure TLS 的 C/H 源文件
  • nx_crypto*.c/h:NetX Secure Cryptography 的 C/H 源文件
  • nx_secure_x509*.c/h:X.509 数字证书的 C/H 源文件。
  • demo_netx_secure_tls.c:NetX Secure TLS Demo 的 C 源文件
  • NetX_Secure_User_Guide.pdf:NetX Secure 产品的 PDF 说明

注意

NetX Secure 父目录的子目录中提供 nx_crypto* 文件以用于不同的硬件平台。

安装 NetX Secure

若要使用 NetX Secure,应将之前提到的整个分发包复制到 NetX 的安装目录级别。 例如,如果 NetX 安装在“\threadx\arm7\NetX”目录中,则应将 nx_secure*.* 目录复制到“\threadx\arm7\NetXSecure”中。

使用 NetX Secure

NetX Secure TLS 使用起来非常简单。 大致来说,应用程序代码中必须先添加 tx_api.h 和 nx_api.h,然后添加 nx_secure_tls_api.h,才能使用 ThreadX 和 NetX 。 添加 nx_secure_tls_api.h 后,应用程序代码即可调用本指南后文指定的 NetX Secure 函数。 应用程序还必须将 nx_secure*.* 文件导入到 NetXSecure 库中,并将特定于平台的 nx_crypto*.* 文件导入到 NetXCrypto 库中。

小型示例系统(TLS 客户端)

下面的图 1.1 举例说明了 NetX Secure 是多么易于使用。 此示例展示了一个简单的 TLS 客户端,使用软件加密模块(非特定硬件)进行加密。 它旨在与 OpenSSL 反向回显服务器 (openssl s_server -rev) 配合使用。

请注意,要运行此示例,需要使用 X.509 CA 证书来对目标服务器的证书进行身份验证。 对于 OpenSSL 示例,一个简单的 2 级 PKI(根 CA 证书->>服务器证书)就足够了。 需要使用 CA 证书的 DER 编码二进制版本填写“trusted_ca_data”数组,并更新“trusted_ca_length”变量以反映证书的实际长度。

还需要为硬件提供网络驱动程序(在 nx_ip_create 调用中替换“nx_driver_xx”参数)。

#include "tx_api.h"
#include "nx_api.h"
#include "nx_secure_tls_api.h"
#include "nx_secure_x509.h"

/* Define the size of our application stack. */
#define     DEMO_STACK_SIZE         	4096

/* Define the remote server IP address using NetX IP_ADDRESS macro. */
#define     REMOTE_SERVER_IP_ADDRESS  	IP_ADDRESS(192, 168, 1, 1)

/* Define the IP address for this device. */
#define     DEVICE_IP_ADDRESS         	IP_ADDRESS(192, 168, 1, 2)

/* Define the remote server port. 443 is the HTTPS default. */
#define     REMOTE_SERVER_PORT       	443

/* Define the ThreadX and NetX object control blocks...  */

NX_PACKET_POOL          pool_0;
NX_IP                   ip_0;
NX_TCP_SOCKET tcp_socket;
NX_SECURE_TLS_SESSION tls_session;
NX_SECURE_X509_CERT certificate;

/* Define an HTTP request to be sent to the HTTPS web server not defined here but
  represented by the ellipsis. */
UCHAR http_request[] = { "GET /example.html HTTP/1.1"  };

/* Define the IP thread's stack area.  */
ULONG ip_thread_stack[3 * 1024 / sizeof(ULONG)];

/* Define packet pool for the demonstration.  */
#define NX_PACKET_POOL_SIZE ((1536 + sizeof(NX_PACKET)) * 32)

ULONG packet_pool_area[NX_PACKET_POOL_SIZE/sizeof(ULONG) + 64 / sizeof(ULONG)];

/* Define the ARP cache area.  */
ULONG arp_space_area[512 / sizeof(ULONG)];

/* Define the TLS Client thread.  */
ULONG             tls_client_thread_stack[6 * 1024 / sizeof(ULONG)];
TX_THREAD         tls_client_thread;
void              client_thread_entry(ULONG thread_input);

/* Define the TLS packet reassembly buffer. */
UCHAR tls_packet_buffer[18000];

/* Define the metadata area for TLS cryptography. The actual size needed can be
   Ascertained by calling nx_secure_tls_metadata_size_calculate.
*/
UCHAR tls_crypto_metadata[18000];

/* Pointer to the TLS ciphersuite table that is included in the platform-specific
   cryptography subdirectory. The table maps the cryptographic routines for the
   platform to function pointers usable by the TLS library.
*/
extern const NX_SECURE_TLS_CRYPTO nx_crypto_tls_ciphers_ecc;
extern const USHORT nx_crypto_ecc_supported_groups[];
extern const NX_CRYPTO_METHOD *nx_crypto_ecc_curves[];
extern const UINT nx_crypto_ecc_supported_groups_size;

/* Binary data for the TLS Client X.509 trusted root CA certificate, ASN.1 DER-
   encoded. A trusted certificate must be provided for TLS Client applications
   (unless X.509 authentication is disabled) or TLS will treat all certificates as
   untrusted and the handshake will fail.
*/

/* DER-encoded binary certificate, not defined here but represented by the ellipsis,
   for the sake of brevity. */
const UCHAR trusted_ca_data[] = { … };
const UINT trusted_ca_length = 0x574;

/* Define the application – initialize drivers and TCP/IP setup.
   NOTE: the variable “status” should be checked after every API call. Most error
         checking has been omitted for clarity. */
void    tx_application_define(void *first_unused_memory)
{
UINT  status;

   /* Initialize the NetX system.  */
   nx_system_initialize();

   /* Create a packet pool. Check status for errors. */
   status =  nx_packet_pool_create(&pool_0, "NetX Main Packet Pool", 1536,
                                   (ULONG*)(((int)packet_pool_area + 64) & ~63) ,
                                   NX_PACKET_POOL_SIZE);

   /* Create an IP instance for the specific target. Check status for errors. This
      call is not completely defined. Please see other demo files for proper usage
      of the nx_ip_create call. */
   status = nx_ip_create(&ip_0, "NetX IP Instance 0",
                         DEVICE_IP_ADDRESS ,
                         0xFFFFFF00UL,
                         &pool_0, nx_driver_xx,
                         (UCHAR*)ip_thread_stack,
                         sizeof(ip_thread_stack),
                         1);

   /* Enable ARP and supply ARP cache memory for IP Instance 0. Check status for
 	   errors. */
   status =  nx_arp_enable(&ip_0, (void *)arp_space_area, sizeof(arp_space_area));

   /* Enable TCP traffic. Check status for errors. */
   status =  nx_tcp_enable(&ip_0);

   status =  nx_ip_fragment_enable(&ip_0);

   /* Initialize the NetX Secure TLS system.  */
   nx_secure_tls_initialize();

	/* Create the TLS client thread to start handling incoming requests. */
   tx_thread_create(&tls_client_thread, "TLS Client thread", client_thread_entry, 0,
            	     tls_client_thread_stack, sizeof(tls_client_thread_stack),
            	     16, 16, 4, TX_AUTO_START);
   return;
}

/* Thread to handle the TLS Client instance. */
void client_thread_entry(ULONG thread_input)
{
UINT       status;
ULONG       actual_status;
NX_PACKET *send_packet;
NX_PACKET *receive_packet;
UCHAR receive_buffer[100];
ULONG bytes;
ULONG server_ipv4_address;

	/* We are not using the thread input parameter so suppress compiler warning. */
    NX_PARAMETER_NOT_USED(thread_input);

   /* Ensure the IP instance has been initialized.  */
   status =  nx_ip_status_check(&ip_0, NX_IP_INITIALIZE_DONE, &actual_status,
                                 NX_IP_PERIODIC_RATE);

   /* Create a TCP socket to use for our TLS session.  */
   status =  nx_tcp_socket_create(&ip_0, &tcp_socket, "TLS Client Socket",
                                  NX_IP_NORMAL, NX_FRAGMENT_OKAY,
                                  NX_IP_TIME_TO_LIVE, 8192, NX_NULL, NX_NULL);

   /* Create a TLS session for our socket. This sets up the TLS session object for
          later use */
   status =  nx_secure_tls_session_create(&tls_session,
                                          &nx_crypto_tls_ciphers_ecc,
                                          tls_crypto_metadata,
                                          sizeof(tls_crypto_metadata));

   /* Initialize ECC parameters for this session. */
   status = nx_secure_tls_ecc_initialize(&tls_session,
                                             nx_crypto_ecc_supported_groups,
                                             nx_crypto_ecc_supported_groups_size,
                                             nx_crypto_ecc_curves);

   /* Set the packet reassembly buffer for this TLS session. */
   status = nx_secure_tls_session_packet_buffer_set(&tls_session, tls_packet_buffer,
                                                    sizeof(tls_packet_buffer));

   /* Initialize an X.509 certificate with our CA root certificate data. */
   nx_secure_x509_certificate_initialize(&certificate, trusted_ca_data,
                                         trusted_ca_length, NX_NULL, 0, NX_NULL, 0,
                                         NX_SECURE_X509_KEY_TYPE_NONE);

   /* Add the initialized certificate as a trusted root certificate. */
   nx_secure_tls_trusted_certificate_add(&tls_session, &certificate);

   /* Setup this thread to open a connection on the TCP socket to a remote server.
      The IP address can be used directly or it can be obtained via DNS or other
      means.*/
   server_ipv4_address = REMOTE_SERVER_IP_ADDRESS;
   status = nx_tcp_client_socket_connect(&tcp_socket, server_ipv4_address,
                                         REMOTE_SERVER_PORT, NX_WAIT_FOREVER);

   /* Start the TLS Session using the connected TCP socket. This function will
      ascertain from the TCP socket state that this is a TLS Client session. */
   status = nx_secure_tls_session_start(&tls_session, &tcp_socket,
                                         NX_WAIT_FOREVER);

	/* Allocate a TLS packet to send an HTTP request over TLS (HTTPS). */
    status = nx_secure_tls_packet_allocate(&tls_session, &pool_0, &send_packet,
                                          NX_WAIT_FOREVER);

	/* Populate the packet with our HTTP request. */
    nx_packet_data_append(send_packet, http_request, sizeof(http_request), &pool_0,
                          NX_WAIT_FOREVER);


   /* Send the HTTP request over the TLS Session, turning it into HTTPS. */
   status = nx_secure_tls_session_send(&tls_session, send_packet, NX_WAIT_FOREVER);

   /* If the send fails, you must release the packet.  */
   if (status != NX_SUCCESS)
   {
         /* Release the packet since the packet was not sent.  */
         nx_packet_release(send_packet);
   }

   /* Receive the HTTP response and any data from the server. */
   status = nx_secure_tls_session_receive(&tls_session, &receive_packet,
   NX_WAIT_FOREVER);
   if (status == NX_SUCCESS)
   {
       /* Extract the data we received from the remote server. */
       status = nx_packet_data_extract_offset(receive_packet, 0, receive_buffer,
                                             100,  &bytes);
	    /* Display the response data. */
       receive_buffer[bytes] = 0;
       printf("Received data: %s\n", receive_buffer);

	    /* Release the packet when done with it. */
       nx_packet_release(receive_packet);
   }

   /* End the TLS session now that we have received our HTTPS/HTML response. */
   status = nx_secure_tls_session_end(&tls_session, NX_WAIT_FOREVER);

   /* Check for errors to make sure the session ended cleanly. */

   /* Disconnect the TCP socket. */
   status =  nx_tcp_socket_disconnect(&tcp_socket, NX_WAIT_FOREVER);

}

图 1.1 与 NetX 配合使用的 NetX Secure 示例

小型示例系统(TLS Web 服务器)

NetX Secure 使用起来非常简单,示例如下方图 1.1 所示,该示例演示了一个简单的 TLS Web 服务器 (HTTPS)。

请注意,要运行此示例,需要使用 X.509 证书将服务器标识为 TLS 客户端。 对于大多数 Web 浏览器,简单的自签名证书已经足够。 你的浏览器将无法对服务器进行身份验证,并且在某些情况下可能无法与服务器 3 建立 TLS/HTTPS 连接。 需要使用服务器证书的 DER 编码二进制版本填写“certificate_data”数组,并更新“certificate_length”变量以反映证书的实际长度。 还需要在“private_key”数组中填写证书私钥的 DER 编码版本,并使用 PKCS #1(针对 RSA 密钥)和 RFC 5915(针对 ECC 密钥)进行格式设置。 在“private_key_length”变量中填入密钥数据的实际长度。

重要

某些浏览器(特别是某些版本的 Chrome 浏览器)可能会拒绝自签名证书。 这种情况下,可以使用用于对服务器证书进行签名的根 CA 证书来创建一个 2 级 PKI。 在这里,根 CA 证书将作为受信任的根证书安装在你的浏览器中。 !!! 重要提示:完成后,请在浏览器中删除根 CA 证书,并且不要将其用于任何生产应用程序!!!

还需要为硬件提供网络驱动程序(在 nx_ip_create 调用中替换“nx_driver_xx”参数)。

#include "tx_api.h"
#include "nx_api.h"
#include "nx_secure_tls_api.h"
#include "nx_secure_x509.h"

#define     DEMO_STACK_SIZE         4096

/* Define the IP address for this device. */
#define     DEVICE_IP_ADDRESS             IP_ADDRESS(192, 168, 1, 2)

/* Define the ThreadX and NetX object control blocks...  */

NX_PACKET_POOL          pool_0;
NX_IP                   ip_0;
NX_TCP_SOCKET tcp_socket;
NX_SECURE_TLS_SESSION tls_session;
NX_SECURE_X509_CERT certificate;

/* Define the IP thread's stack area.  */
ULONG ip_thread_stack[3 * 1024 / sizeof(ULONG)];

/* Define packet pool for the demonstration.  */
#define NX_PACKET_POOL_SIZE ((1536 + sizeof(NX_PACKET)) * 32)

ULONG packet_pool_area[NX_PACKET_POOL_SIZE/sizeof(ULONG) + 64 / sizeof(ULONG)];

/* Define the ARP cache area.  */
ULONG arp_space_area[512 / sizeof(ULONG)];


/* Define the TLS Server thread.  */
ULONG             tls_server_thread_stack[6 * 1024 / sizeof(ULONG)];
TX_THREAD         tls_server_thread;
void              server_thread_entry(ULONG thread_input);

/* Define the TLS packet reassembly buffer. */
UCHAR tls_packet_buffer[18000];

/* Define the metadata area for TLS cryptography. The actual size needed can be
   Ascertained by calling nx_secure_tls_metadata_size_calculate.
*/
UCHAR tls_crypto_metadata[18000];

/* Pointer to the TLS ciphersuite table that is included in the platform-specific
   cryptography subdirectory. The table maps the cryptographic routines for the
   platform to function pointers usable by the TLS library.
*/
extern const NX_SECURE_TLS_CRYPTO nx_crypto_tls_ciphers_ecc;
extern const USHORT nx_crypto_ecc_supported_groups[];
extern const NX_CRYPTO_METHOD *nx_crypto_ecc_curves[];
extern const UINT nx_crypto_ecc_supported_groups_size;

/* Binary data for the TLS Server X.509 certificate, ASN.1 DER-encoded. Note that the
   certificate data and private key data is represented by an ellipsis for the sake
   of brevity.
*/
const UCHAR certificate_data[] = { … }; /* DER-encoded binary certificate. */
const UINT certificate_length = 0x574;

/* Binary data for the TLS Server Private Key, from private key
   file generated at the time of the X.509 certificate creation. ASN.1 DER-encoded. */
const UCHAR private_key[] = { … }; /* DER-encoded private key file (PKCS#1 RSA or ECC) */
const UINT private_key_length = 0x40;

/* Define some HTML data (web page) with an HTTPS header to serve to connecting
   clients. */
UCHAR html_data[] = { "HTTP/1.1 200 OK\r\n" \
        "Date: Tue, 19 May 2020 23:59:59 GMT\r\n" \
        "Content-Type: text/html\r\n" \
        "Content-Length: 200\r\n\r\n" \
        "<html>\r\n"\
        "<body>\r\n"\
        "<b>Hello NetX Secure User!</b>\r\n"\
        "This is a simple webpage\r\n"\
        "served up using NetX Secure!\r\n"\
        "</body>\r\n"\
        "</html>\r\n" };

/* Define the application – initialize drivers and TCP/IP setup.  */
void    tx_application_define(void *first_unused_memory)
{
UINT  status;


    /* Initialize the NetX system.  */
    nx_system_initialize();

    /* Create a packet pool. Check status for errors. */
    status =  nx_packet_pool_create(&pool_0, "NetX Main Packet Pool", 1536,
                                    (ULONG*)(((int)packet_pool_area + 64) & ~63) ,
                                    NX_PACKET_POOL_SIZE);

    /* Create an IP instance for the specific target. Check status for errors. */
    status = nx_ip_create(&ip_0, "NetX IP Instance 0",
                          DEVICE_IP_ADDRESS,
                          0xFFFFFF00UL,
                          &pool_0, nx_driver_xx,
                          (UCHAR*)ip_thread_stack,
                          sizeof(ip_thread_stack),
                          1);

    /* Enable ARP and supply ARP cache memory for IP Instance 0. Check status for
         errors. */
    status =  nx_arp_enable(&ip_0, (void *)arp_space_area, sizeof(arp_space_area));

    /* Enable TCP traffic. Check status for errors. */
    status =  nx_tcp_enable(&ip_0);

    status =  nx_ip_fragment_enable(&ip_0);

    /* Initialize the NetX Secure TLS system.  */
    nx_secure_tls_initialize();

    /* Create the TLS server thread to start handling incoming requests. */
    tx_thread_create(&tls_server_thread, "TLS Server thread", server_thread_entry, 0,
                   tls_server_thread_stack, sizeof(tls_server_thread_stack),
                   16, 16, 4, TX_AUTO_START);
    return;
}

/* Thread to handle the TLS Server instance. */
void server_thread_entry(ULONG thread_input)
{
UINT       status;
ULONG      actual_status;
NX_PACKET *send_packet;
NX_PACKET *receive_packet;
UCHAR receive_buffer[100];
ULONG bytes;

    NX_PARAMETER_NOT_USED(thread_input);

    /* Ensure the IP instance has been initialized.  */
    status =  nx_ip_status_check(&ip_0, NX_IP_INITIALIZE_DONE, &actual_status,
                                 NX_IP_PERIODIC_RATE);

    /* Create a TCP socket to use for our TLS session.  */
    status =  nx_tcp_socket_create(&ip_0, &tcp_socket, "TLS Server Socket",
                                   NX_IP_NORMAL, NX_FRAGMENT_OKAY,
                                   NX_IP_TIME_TO_LIVE, 8192, NX_NULL, NX_NULL);

    /* Create a TLS session for our socket.  */
    status =  nx_secure_tls_session_create(&tls_session,
                                        &nx_crypto_tls_ciphers_ecc,
                                        tls_crypto_metadata,
                                        sizeof(tls_crypto_metadata));

    status = nx_secure_tls_ecc_initialize(&tls_session,
                                          nx_crypto_ecc_supported_groups,
                                          nx_crypto_ecc_supported_groups_size,
                                          nx_crypto_ecc_curves);

     /* Set the packet reassembly buffer for this TLS session. */
     status = nx_secure_tls_session_packet_buffer_set(&tls_session, tls_packet_buffer,
                                                      sizeof(tls_packet_buffer));

    /* Initialize an X.509 certificate and private ECC key for our TLS Session. */
    nx_secure_x509_certificate_initialize(&certificate, certificate_data, NX_NULL, 0,
                                          certificate_length, private_key,
                                          private_key_length,
                                          NX_SECURE_X509_KEY_TYPE_EC_DER);

    /* Add the initialized certificate as a local identity certificate. */
    nx_secure_tls_local_certificate_add(&tls_session, &certificate);


    /* Setup this thread to listen on the TCP socket.
       Port 443 is standard for HTTPS. */
    status =  nx_tcp_server_socket_listen(&ip_0, 443, &tcp_socket, 5, NX_NULL);

    while(1)
     {
         /* Accept a client TCP socket connection.  */
         status =  nx_tcp_server_socket_accept(&tcp_socket, NX_WAIT_FOREVER);

         /* Start the TLS Session using the connected TCP socket. */
         status = nx_secure_tls_session_start(&tls_session, &tcp_socket,
                                              NX_WAIT_FOREVER);

         /* Receive the HTTPS request. */
         status = nx_secure_tls_session_receive(&tls_session, &receive_packet,
                                                NX_WAIT_FOREVER);

if (status == NX_SUCCESS)
      {
         /* Extract the HTTP request information from the HTTPS request. */
            status = nx_packet_data_extract_offset(receive_packet, 0, receive_buffer,
                                                  100, &bytes);
         /* Display the HTTP request data. */
            receive_buffer[bytes] = 0;
            printf("Received data: %s\n", receive_buffer);

         /* Release the packet when done with it */
            nx_packet_release(receive_packet);
      }

         /* Allocate a TLS packet to send HTML data back to client. */
         status = nx_secure_tls_packet_allocate(&tls_session, &pool_0, &send_packet,
                                                NX_WAIT_FOREVER);

         /* Populate the packet with our HTTP response and HTML web page data. */
         nx_packet_data_append(send_packet, html_data, sizeof(html_data), &pool_0,
                               NX_WAIT_FOREVER);

         /* Send the HTTP response over the TLS Session, turning it into HTTPS. */
         status = nx_secure_tls_session_send(&tls_session, send_packet,
                                                 NX_WAIT_FOREVER);

         /* If the send fails, you must release the packet.  */
         if (status != NX_SUCCESS)
         {
              /* Release the packet since it was not sent.  */
              nx_packet_release(send_packet);
         }

         /* End the TLS session now that we have sent our HTTPS/HTML response. */
         status = nx_secure_tls_session_end(&tls_session, NX_WAIT_FOREVER);

         /* Check for errors to make sure the session ended cleanly! */

         /* Disconnect the TCP socket so we can be ready for the next request. */
         status =  nx_tcp_socket_disconnect(&tcp_socket, NX_WAIT_FOREVER);

         /* Unaccept the server socket.  */
         status =  nx_tcp_server_socket_unaccept(&tcp_socket);

         /* Setup server socket for listening again.  */
         status =  nx_tcp_server_socket_relisten(&ip_0, 443, &tcp_socket);
     }
}

图 1.2 与 NetX 配合使用的 NetX Secure 示例

有关 TLS 会话错误恢复的说明

上面所述的示例系统分别显示了 TLS 客户端和服务器的基本大纲,但为清楚起见,省略了错误处理。 但是,TLS 提供的部分安全性取决于对错误条件的正确处理。 一般而言,最严重的潜在问题将在 TLS 堆栈自身内进行处理,但对于 TLS 应用程序来说,正确响应和恢复 TLS 实现中没有处理的 TLS 错误非常重要。

为了说明正确处理错误的必要逻辑,下面的函数演示了一个典型的 API 服务集合,这些服务可用于正确处理 TLS 错误,并在遇到错误情况后彻底重置 TLS 状态。 除了上面提到的部分,逻辑也适用于 TLS 客户端和 TLS 服务器实例。

请注意,函数中最重要的 API 调用是 nx_secure_tls_session_end 和 nx_secure_tls_session_reset 服务,前者彻底关闭 TLS 会话或握手,后者清除 TLS 会话状态,以便让新的 TLS 会话重用 tls_session 控制结构实例 。 另请注意,nx_secure_tls_session_reset 不会清除用户配置的状态(如证书或分配的缓冲区),从而允许重新使用会话,而无需再次调用 nx_secure_tls_session_create 。 若要完全清除所有 TLS 会话状态,可以改为使用 nx_secure_tls_session_delete 服务。

/* Define a helper function to clean up a broken TLS session (to be called on any
   error from nx_secure_tls_session_start onwards). Note that the variables
   tls_session, tcp_socket, and ip_0 are global in the above examples. */
VOID tls_session_error_cleanup(VOID)
{
UINT status;
UINT alert_level, alert_value;

      /* If we got an error back from a TLS API call, there may be an alert from the
         remote host. Extract the alert level and value to print out. Note that the TLS
         API will return NX_SECURE_TLS_ALERT_RECEIVED (0x114) if an alert was received.
         For other error codes the alert value and level are not valid. */
      status = nx_secure_tls_session_alert_value_get(&tls_session, &alert_level,
                                                     &alert_value);
      if(status)
      {
         printf("Pointer error in getting alert value.\n");
      }
      else
      {
         printf("Alert received. Value: %d, Level: %d\n", alert_value, alert_level);
      }

      /* End the TLS session. This is required to properly shut down the TLS
         connection. */
      status = nx_secure_tls_session_end(&tls_session, NX_WAIT_FOREVER);

      /* If the session did not shut down cleanly, this is a possible security issue. */
      if (status)
      {
         printf("Error in TLS session end: %x\n", status);
      }

      /* Reset the TLS session to re-use the control structure for the next connection.
         This API service resets the TLS session state but does not remove user-
         configured options such as certificates, PSKs, buffers, and cipher routines. */
      nx_secure_tls_session_reset(&tls_session);

      /* Disconnect the TCP socket, closing the connection. */
      status =  nx_tcp_socket_disconnect(&tcp_socket, NX_WAIT_FOREVER);

      /* Check for error.  */
      if (status)
      {
           printf("Error in TCP socket close: %x\n", status);
      }

   /* The following code applies only to a TLS server instance. */
   #if NX_SECURE_TLS_SERVER
      /* Unaccept the server socket.  */
      status =  nx_tcp_server_socket_unaccept(&tcp_socket);

      /* Check for error.  */
      if (status)
      {
           printf("Error in TCP socket unaccept: %x\n", status);
      }

      /* Setup server socket for listening again.  */
      status =  nx_tcp_server_socket_relisten(&ip_0, DEVICE_SERVER_PORT, &tcp_socket);

      /* Check for error.  */
      if (status)
      {
           printf("Error in TCP socket relisten: %x\n", status);
      }
#endif
} /* End function. */

配置选项

有多个配置选项用于生成 NetX Secure。 下面是所有选项的列表,其中包含每个选项的详细说明:

定义 含义
NX_SECURE_DISABLE_ERROR_CHECKING 定义此选项后,将删除基本的 NetX Secure 错误检查。 通常会在调试应用程序后使用此选项。
NX_CRYPTO_MAX_RSA_MODULUS_SIZE 定义后,此选项用于提供预期的最大 RSA 模数,以位为单位。 默认值为 4096,表示 4096 位的模数。 其他值可以是 3072、2048 或 1024(不推荐)。
NX_SECURE_ALLOW_SELF_SIGNED_CERTIFICATES 定义后,此选项允许 TLS 接受来自远程主机的自签名证书。 默认情况下,作为一项安全预防措施,TLS 将拒绝自签名的服务器证书。 如果定义了此宏,还必须将自签名证书添加到受信任的存储区中才能被接受。
NX_SECURE_ENABLE_CLIENT_CERTIFICATE_VERIFY 定义后,此选项用于为 TLS 服务器 4 启用可选的 X.509 客户端证书验证。
NX_SECURE_ENABLE_PSK_CIPHERSUITES 定义此选项后,将启用预共享密钥 (PSK) 功能。 此选项不会禁用数字证书。
NX_SECURE_TLS_MAX_PSK_ID_SIZE 定义后,此选项提供 PSK ID 的最大大小。
NX_SECURE_TLS_MAX_PSK_KEYS 定义后,此选项提供 PSK 密钥的最大数目。
NX_SECURE_TLS_MAX_PSK_SIZE 定义后,此选项提供 PSK 的最大大小。
NX_SECURE_TLS_CLIENT_DISABLED 定义后,此选项用于删除与 TLS 客户端模式相关的所有 TLS 堆栈代码,从而减少代码和数据的使用。
NX_SECURE_TLS_SERVER_DISABLED 定义后,此选项用于删除与 TLS 服务器模式相关的所有 TLS 堆栈代码,从而减少代码和数据使用。
NX_SECURE_DISABLE_ECC_CIPHERSUITE 定义后,此选项用于删除椭圆曲线加密 (ECC) 密码套件的所有 TLS 逻辑。 这些密码套件在 TLS 1.2 和更早版本中是可选的,禁用它们可以使代码和数据大小大大减少。
NX_SECURE_TLS_ENABLE_TLS_1_3 定义后,此选项用于启用 TLSv1.3 模式。 TLS 1.3 是最新版本的 TLS,默认情况下处于禁用状态。
NX_SECURE_TLS_ENABLE_TLS_1_0 定义后,此选项用于启用旧的 TLSv1.0 模式。 TLSv1.0 被视为已过时,只应在与较旧的应用程序向后兼容时启用它。
NX_SECURE_TLS_ENABLE_TLS_1_1 定义后,此选项用于启用旧的 TLSv1.1 模式。 TLSv1.1 被视为已过时,只应在与较旧的应用程序向后兼容时启用它。
NX_SECURE_TLS_DISABLE_PROTOCOL_VERSION_DOWNGRADE 定义后,此选项禁用 TLS 客户端的协议版本降级。
NX_SECURE_AEAD_CIPHER_CHECK 定义后,它允许检测除 AES-CCM 或 AES-GCM 以外的用户实现的 AEAD 算法。 可如下对其进行定义:#define NX_SECURE_AEAD_CIPHER_CHECK(a) ((a) == NEW_ALGORITHM_ID)。 仅当定义了 NX_SECURE_ENABLE_AEAD_CIPHER 时,它才有效。
NX_SECURE_ENABLE_AEAD_CIPHER 定义后,此选项将启用 AEAD 密码套件。
NX_SECURE_TLS_MINIMUM_CERTIFICATE_SIZE 定义后,此选项为 TLS X509 证书提供最小合理大小。 这用于检查分配证书空间时的错误。 大小通过假设 512 位 RSA 密钥、MD5 哈希和对其他数据的粗略估计得以确定。 从理论上讲,实际证书可能更小,但在这种情况下,通过重新定义此宏来绕过错误检查。 大约:64 (RSA) + 16 (MD5) + 176(ASN.1 + 文本数据、公用名等)。
NX_SECURE_TLS_MINIMUM_MESSAGE_BUFFER_SIZE 定义后,此选项为 TLS 消息缓冲区提供最小大小。 它由许多因素决定,但主要是 TLS 握手证书消息(由 TLS 服务器发送)的预期大小,该消息可能包含多个各为 1-2KB 的证书。 上限为 64KB,由 TLS 标头中的长度字段(16 位)确定。
NX_SECURE_TLS_PREMASTER_SIZE 定义后,此选项提供预主密钥的最大大小。
NX_SECURE_TLS_SNI_EXTENSION_DISABLED 定义后,此选项禁用服务器名称指示 (SNI) 扩展。
NX_SECURE_TLS_USE_SCSV_CIPHPERSUITE 定义后,此选项在 ClientHello 消息中启用 SCSV 密码套件。
NX_SECURE_TLS_DISABLE_SECURE_RENEGOTIATION 定义后,此选项禁用安全会话重新协商扩展 (RFC 5746)。
NX_SECURE_TLS_REQUIRE_RENEGOTIATION_EXT 定义后,此选项将在初始握手期间未能接收到安全重新协商扩展时立即终止连接。
NX_SECURE_TLS_DISABLE_CLIENT_INITIATED_RENEGOTIATION 定义后,此选项禁用 TLS 服务器的客户端发起的重新协商。 在某些情况下,客户端发起的重新协商会成为可能的拒绝服务漏洞。
NX_SECURE_HASH_METADATA_CLONE 定义后,此选项允许在握手状态下进行自定义哈希克隆。
NX_SECURE_HASH_CLONE_CLEANUP 定义后,此选项允许在握手状态下进行自定义哈希清理。
NX_SECURE_KEY_CLEAR 定义后,此选项可在不再使用密钥相关材料时对其进行清理。
NX_SECURE_MEMCMP 定义后,此选项在 TLS 中映射内存比较函数。
NX_SECURE_MEMCPY 定义后,此选项在 TLS 中映射内存复制函数。
NX_SECURE_MEMMOVE 定义后,此选项在 TLS 中映射内存移动函数。
NX_SECURE_MEMSET 定义后,此选项在 TLS 中映射内存集函数。
NX_SECURE_MEMSET 定义后,此选项在 TLS 中映射内存集函数。
NX_SECURE_POWER_ON_SELF_TEST_MODULE_INTEGRITY_CHECK 定义后,此选项启用模块完整性自测试。
NX_SECURE_RNG_CHECK_COUNT 定义后,此选项提供了完整性自测试期间重复检查的最大随机数数量。
NX_SECURE_X509_USE_EXTENDED_DISTINGUISHED_NAMES 定义后,此选项用于启用可选的“X.509 可分辨名称”字段,但代价是 X.509 证书需要使用额外内存。
NX_SECURE_X509_DISABLE_CRL 定义后,此选项禁用 X509 证书吊销列表检查。
NX_SECURE_X509_STRICT_NAME_COMPARE 定义后,此选项对所有字段启用严格的 X509 比较。
  1. 请注意,此选项仅允许将代码链接到应用程序。 此功能需要使用 API 服务 nx_secure_tls_session_client_verify_enable 来启用,或者使用 nx_secure_tls_session_x509_client_verify_configure 进行配置,才能使用客户端证书验证。