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