https client error 113

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:

generate_inc_file_for_target(
app
cert/DigiCertGlobalRootG2.pem
${gen_dir}/DigiCertGlobalG2.pem.inc
)

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

Parents
  • using the same pem file

    % curl -v -I --cacert cert/DigiCertGlobalRootG2.pem 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: cert/DigiCertGlobalRootG2.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:51:46 GMT
    date: Thu, 20 Feb 2025 10:51:46 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

Reply
  • using the same pem file

    % curl -v -I --cacert cert/DigiCertGlobalRootG2.pem 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: cert/DigiCertGlobalRootG2.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:51:46 GMT
    date: Thu, 20 Feb 2025 10:51:46 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

Children
Related