sample code: https client
sdl version: 2.6.2
board: 7002dk
question: https client cannot connect to iot.cht.com.tw
log:
*** Booting nRF Connect SDK v3.5.99-ncs1-2 ***
HTTPS client sample started
Bringing network interface up
Connecting to the network
[00:00:02.183,166] <inf> wifi_mgmt_ext: Connection requested
[00:00:06.844,177] <inf> net_dhcpv4: Received: 192.168.0.31
Network connectivity established and IP address assigned
SNTP time: 1739958786.977459479
Now: Wed Feb 19 09:53:06 2025
Provisioning certificate
delete sec tag(0): 42
Looking up iot.cht.com.tw...20.188.24.130 (AF_INET)
Connecting to iot.cht.com.tw:443
[00:00:12.823,394] <err> net_sock_tls: TLS handshake error: -0x7080
connect() failed, err: 113
Looking up example.com...23.215.0.138 (AF_INET)
Connecting to example.com:443
Sent 85 bytes
Received 345 bytes
> HTTP/1.1 200 OK
Finished, closing socket.
Network connectivity lost
Disconnected from the network
modifications:
1. change pem file because I doubt it is out of date. (in fact it is not. and I did not change back)
CMakeLists.txt:
then I use openssl to check, date valid
% openssl x509 -noout -text -in cert/DigiCertGlobalRootG2.pem
Certificate:
Data:
Version: 3 (0x2)
Serial Number:
68:69:4e:10:01:fb:a7:b1:72:a6:b4:8d:10:74:c7:dd:8c:b7:fb:ca
Signature Algorithm: sha256WithRSAEncryption
Issuer: C=AU, ST=Some-State, O=Internet Widgits Pty Ltd, CN=192.0.2.2
Validity
Not Before: Aug 9 07:48:39 2022 GMT
Not After : Dec 25 07:48:39 2049 GMT
and curl to test iot.cht.com.tw, it can be connected
% curl -v -I https://iot.cht.com.tw
* Host iot.cht.com.tw:443 was resolved.
* IPv6: (none)
* IPv4: 20.188.24.130
* Trying 20.188.24.130:443...
* Connected to iot.cht.com.tw (20.188.24.130) port 443
* ALPN: curl offers h2,http/1.1
* (304) (OUT), TLS handshake, Client hello (1):
* CAfile: /etc/ssl/cert.pem
* CApath: none
* (304) (IN), TLS handshake, Server hello (2):
* (304) (IN), TLS handshake, Unknown (8):
* (304) (IN), TLS handshake, Certificate (11):
* (304) (IN), TLS handshake, CERT verify (15):
* (304) (IN), TLS handshake, Finished (20):
* (304) (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / AEAD-AES256-GCM-SHA384 / [blank] / UNDEF
* ALPN: server accepted h2
* Server certificate:
* subject: C=TW; L=\U81FA\U5317\U5E02; O=\U4E2D\U83EF\U96FB\U4FE1\U80A1\U4EFD\U6709\U9650\U516C\U53F8; CN=*.iot.cht.com.tw
* start date: Dec 16 09:45:19 2024 GMT
* expire date: Dec 16 09:45:19 2025 GMT
* subjectAltName: host "iot.cht.com.tw" matched cert's "iot.cht.com.tw"
* issuer: C=TW; O=Chunghwa Telecom Co., Ltd.; CN=HiPKI OV TLS CA - G1
* SSL certificate verify ok.
* using HTTP/2
* [HTTP/2] [1] OPENED stream for https://iot.cht.com.tw/
* [HTTP/2] [1] [:method: HEAD]
* [HTTP/2] [1] [:scheme: https]
* [HTTP/2] [1] [:authority: iot.cht.com.tw]
* [HTTP/2] [1] [:path: /]
* [HTTP/2] [1] [user-agent: curl/8.7.1]
* [HTTP/2] [1] [accept: */*]
> HEAD / HTTP/2
> Host: iot.cht.com.tw
> User-Agent: curl/8.7.1
> Accept: */*
>
* Request completely sent off
< HTTP/2 403
HTTP/2 403
< server: nginx
server: nginx
< date: Thu, 20 Feb 2025 10:29:44 GMT
date: Thu, 20 Feb 2025 10:29:44 GMT
< content-type: text/html; charset=utf-8
content-type: text/html; charset=utf-8
< content-length: 146
content-length: 146
< strict-transport-security: max-age=31536000; includeSubDomains; preload
strict-transport-security: max-age=31536000; includeSubDomains; preload
<
* Connection #0 to host iot.cht.com.tw left intact
/* * Copyright (c) 2020 Nordic Semiconductor ASA * * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause */ #include <zephyr/kernel.h> //44:K_SEM_DEFINE() #include <zephyr/net/tls_credentials.h> //109:tls_credential_delete() #include <zephyr/net/socket.h> //140:TLS_PEER_VERIFY_OPTIONAL; #include <zephyr/net/conn_mgr_connectivity.h> //197:NET_EVENT_CONN_IF_FATAL_ERROR #include <zephyr/net/sntp.h> //343:struct sntp_time #include <zephyr/posix/time.h> //350:clock_settime() #include <date_time.h> //date_time_set() #if CONFIG_MODEM_KEY_MGMT #include <modem/modem_key_mgmt.h> #endif #define HTTP_HEAD \ "HEAD %s HTTP/1.1\r\n" \ "Host: %s:%s\r\n" \ "Connection: close\r\n\r\n" #define HTTP_POST \ "POST %s HTTP/1.1\r\n" \ "Host: %s:%s\r\n" \ "\r\n%s\r\n" #define HTTP_HDR_END "\r\n\r\n" #define RECV_BUF_SIZE 2048 #define TLS_SEC_TAG 42 /* Macros used to subscribe to specific Zephyr NET management events. */ #define L4_EVENT_MASK (NET_EVENT_L4_CONNECTED | NET_EVENT_L4_DISCONNECTED) #define CONN_LAYER_EVENT_MASK (NET_EVENT_CONN_IF_FATAL_ERROR) static char send_buf[256] = HTTP_HEAD; static char recv_buf[RECV_BUF_SIZE]; static K_SEM_DEFINE(network_connected_sem, 0, 1); /* Certificate for `example.com` */ static const char cert[] = { #include "DigiCertGlobalG2.pem.inc" /* Null terminate certificate if running Mbed TLS on the application core. * Required by TLS credentials API. */ IF_ENABLED(CONFIG_TLS_CREDENTIALS, (0x00)) }; /* Zephyr NET management event callback structures. */ static struct net_mgmt_event_callback l4_cb; static struct net_mgmt_event_callback conn_cb; BUILD_ASSERT(sizeof(cert) < KB(4), "Certificate too large"); /* Provision certificate to modem */ int cert_provision(void) { int err; printk("Provisioning certificate\n"); #if CONFIG_MODEM_KEY_MGMT bool exists; int mismatch; /* It may be sufficient for you application to check whether the correct * certificate is provisioned with a given tag directly using modem_key_mgmt_cmp(). * Here, for the sake of the completeness, we check that a certificate exists * before comparing it with what we expect it to be. */ err = modem_key_mgmt_exists(TLS_SEC_TAG, MODEM_KEY_MGMT_CRED_TYPE_CA_CHAIN, &exists); if (err) { printk("Failed to check for certificates err %d\n", err); return err; } if (exists) { mismatch = modem_key_mgmt_cmp(TLS_SEC_TAG, MODEM_KEY_MGMT_CRED_TYPE_CA_CHAIN, cert, sizeof(cert)); if (!mismatch) { printk("Certificate match\n"); return 0; } printk("Certificate mismatch\n"); err = modem_key_mgmt_delete(TLS_SEC_TAG, MODEM_KEY_MGMT_CRED_TYPE_CA_CHAIN); if (err) { printk("Failed to delete existing certificate, err %d\n", err); } } printk("Provisioning certificate\n"); /* Provision certificate to the modem */ err = modem_key_mgmt_write(TLS_SEC_TAG, MODEM_KEY_MGMT_CRED_TYPE_CA_CHAIN, cert, sizeof(cert) - 1); if (err) { printk("Failed to provision certificate, err %d\n", err); return err; } #else /* CONFIG_MODEM_KEY_MGMT */ err = tls_credential_delete(TLS_SEC_TAG, TLS_CREDENTIAL_CA_CERTIFICATE); printk("delete sec tag(%d): %d\n", err, TLS_SEC_TAG); k_msleep(10); // Wait for 10 milliseconds err = tls_credential_add(TLS_SEC_TAG, TLS_CREDENTIAL_CA_CERTIFICATE, cert, sizeof(cert)); if (err == -EEXIST) { printk("CA certificate already exists, sec tag: %d\n", TLS_SEC_TAG); } else if (err < 0) { printk("Failed to register CA certificate: %d\n", err); return err; } #endif /* !CONFIG_MODEM_KEY_MGMT */ return 0; } /* Setup TLS options on a given socket */ int tls_setup(int fd, const char *server) { int err; int verify; /* Security tag that we have provisioned the certificate with */ const sec_tag_t tls_sec_tag[] = { TLS_SEC_TAG, }; /* Set up TLS peer verification */ verify = TLS_PEER_VERIFY_OPTIONAL; //OPTIONAL REQUIRED fail err = setsockopt(fd, SOL_TLS, TLS_PEER_VERIFY, &verify, sizeof(verify)); if (err) { printk("Failed to setup peer verification, err %d\n", errno); return err; } /* Associate the socket with the security tag * we have provisioned the certificate with. */ err = setsockopt(fd, SOL_TLS, TLS_SEC_TAG_LIST, tls_sec_tag, sizeof(tls_sec_tag)); if (err) { printk("Failed to setup TLS sec tag, err %d\n", errno); return err; } err = setsockopt(fd, SOL_TLS, TLS_HOSTNAME, server, strlen(server)); if (err) { printk("Failed to setup TLS hostname, err %d\n", errno); return err; } return 0; } static void on_net_event_l4_disconnected(void) { printk("Disconnected from the network\n"); } static void on_net_event_l4_connected(void) { k_sem_give(&network_connected_sem); } static void l4_event_handler(struct net_mgmt_event_callback *cb, uint32_t event, struct net_if *iface) { switch (event) { case NET_EVENT_L4_CONNECTED: printk("Network connectivity established and IP address assigned\n"); on_net_event_l4_connected(); break; case NET_EVENT_L4_DISCONNECTED: printk("Network connectivity lost\n"); on_net_event_l4_disconnected(); break; default: break; } } static void connectivity_event_handler(struct net_mgmt_event_callback *cb, uint32_t event, struct net_if *iface) { if (event == NET_EVENT_CONN_IF_FATAL_ERROR) { printk("Fatal error received from the connectivity layer\n"); return; } } static void send_http_request(const char *server, const char *port, const char *endpoint) { int err; int fd; char *p; int bytes; size_t off; struct addrinfo *res; struct addrinfo hints = { .ai_flags = AI_NUMERICSERV, /* Let getaddrinfo() set port */ .ai_socktype = SOCK_STREAM, }; char peer_addr[INET6_ADDRSTRLEN]; printk("Looking up %s...", server); err = getaddrinfo(server, port, &hints, &res); if (err) { printk("getaddrinfo() failed, err %d\n", errno); return; } inet_ntop(res->ai_family, &((struct sockaddr_in *)(res->ai_addr))->sin_addr, peer_addr, INET6_ADDRSTRLEN); printk("%s (%s)\n", peer_addr, net_family2str(res->ai_family)); fd = socket(res->ai_family, IS_ENABLED(CONFIG_SAMPLE_TFM_MBEDTLS) ? SOCK_STREAM | SOCK_NATIVE_TLS : SOCK_STREAM, IPPROTO_TLS_1_2); if (fd == -1) { printk("Failed to open socket!\n"); goto clean_up; } /* Setup TLS socket options */ err = tls_setup(fd, server); if (err) { goto clean_up; } printk("Connecting to %s:%d\n", server, ntohs(((struct sockaddr_in *)(res->ai_addr))->sin_port)); err = connect(fd, res->ai_addr, res->ai_addrlen); if (err) { printk("connect() failed, err: %d\n", errno); goto clean_up; } off = 0; #if 1 int len = snprintk(send_buf, sizeof(send_buf), HTTP_HEAD, endpoint, server, port); #else int len = snprintk(send_buf, sizeof(send_buf), HTTP_POST, endpoint, server, port , "[{\"id\":\"acusense_gateway\",\"time\":\"2025-2-14T12:00:00Z\",\"value\":[\"{}\"]]}"); #endif do { bytes = send(fd, &send_buf[off], len - off, 0); if (bytes < 0) { printk("send() failed, err %d\n", errno); goto clean_up; } off += bytes; } while (off < len); printk("Sent %d bytes\n", off); off = 0; do { bytes = recv(fd, &recv_buf[off], RECV_BUF_SIZE - off, 0); if (bytes < 0) { printk("recv() failed, err %d\n", errno); goto clean_up; } off += bytes; } while (bytes != 0 /* peer closed connection */); printk("Received %d bytes\n", off); /* Make sure recv_buf is NULL terminated (for safe use with strstr) */ if (off < sizeof(recv_buf)) { recv_buf[off] = '\0'; } else { recv_buf[sizeof(recv_buf) - 1] = '\0'; } /* Print HTTP response */ p = strstr(recv_buf, "\r\n"); if (p) { off = p - recv_buf; recv_buf[off + 1] = '\0'; printk("\n>\t %s\n\n", recv_buf); } printk("Finished, closing socket.\n"); clean_up: freeaddrinfo(res); (void)close(fd); } int main(void) { int err; printk("HTTPS client sample started\n\r"); /* Setup handler for Zephyr NET Connection Manager events. */ net_mgmt_init_event_callback(&l4_cb, l4_event_handler, L4_EVENT_MASK); net_mgmt_add_event_callback(&l4_cb); /* Setup handler for Zephyr NET Connection Manager Connectivity layer. */ net_mgmt_init_event_callback(&conn_cb, connectivity_event_handler, CONN_LAYER_EVENT_MASK); net_mgmt_add_event_callback(&conn_cb); printk("Bringing network interface up\n"); /* Connecting to the configured connectivity layer. * Wi-Fi or LTE depending on the board that the sample was built for. */ err = conn_mgr_all_if_up(true); if (err) { printk("conn_mgr_all_if_up, error: %d\n", err); return err; } /* Provision certificates before connecting to the network */ printk("Connecting to the network\n"); err = conn_mgr_all_if_connect(true); if (err) { printk("conn_mgr_all_if_connect, error: %d\n", err); return 0; } k_sem_take(&network_connected_sem, K_FOREVER); #if 1 //network connected, sync time struct sntp_time sntp_time; int ret; ret = sntp_simple("pool.ntp.org", 10000, &sntp_time); if (ret == 0) { printk("SNTP time: %lld.%09u\n", sntp_time.seconds, sntp_time.fraction); #if 0 struct tm *tm = localtime(&sntp_time.seconds); date_time_set(tm); #else clock_settime(CLOCK_REALTIME, (struct timespec *)&sntp_time); #endif time_t t = time(NULL); printk("Now: %s", ctime(&t)); } else { printk("SNTP request failed: %d\n", ret); } #endif err = cert_provision(); if (err) { return 0; } send_http_request("iot.cht.com.tw", "443", "/iot/v1/device/38818145566/rawdata"); send_http_request("example.com", "443", "/"); /* A small delay for the TCP connection teardown */ k_sleep(K_SECONDS(1)); /* The HTTP transaction is done, take the network connection down */ err = conn_mgr_all_if_disconnect(true); if (err) { printk("conn_mgr_all_if_disconnect, error: %d\n", err); } err = conn_mgr_all_if_down(true); if (err) { printk("conn_mgr_all_if_down, error: %d\n", err); } return 0; }