https_client sample: connection refused

Hi,

We are working on a project in which data must be sent to server using NB-Iot.

We are struggling establishing an HTTPS connection with a server using the NRF9160 development kit.

As a starting point I copied some parts of the https_client sample from the sdk-nrf repo (v3.2.2). Here is the code:

static int Test()
{
	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 */
	err = cert_provision();
	if (err) {
		return 0;
	}

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

	/* Resend connection status if the sample is built for NATIVE_SIM.
	 * This is necessary because the network interface is automatically brought up
	 * at SYS_INIT() before main() is called.
	 * This means that NET_EVENT_L4_CONNECTED fires before the
	 * appropriate handler l4_event_handler() is registered.
	 */
	if (IS_ENABLED(CONFIG_BOARD_NATIVE_SIM)) {
		conn_mgr_mon_resend_status();
	}

	k_sem_take(&network_connected_sem, K_FOREVER);

	send_http_request();

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

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 to the modem\n");

	/*  Provision certificate to the modem */
	err = modem_key_mgmt_write(TLS_SEC_TAG, MODEM_KEY_MGMT_CRED_TYPE_CA_CHAIN, cert,
				   sizeof(cert));
	if (err) {
		printk("Failed to provision certificate, err %d\n", err);
		return err;
	}
#else /* CONFIG_MODEM_KEY_MGMT */
	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;
}

int tls_setup(int fd)
{
	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 */
	enum {
		NONE = 0,
		OPTIONAL = 1,
		REQUIRED = 2,
	};

	verify = REQUIRED;

	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,
			CONFIG_HTTPS_HOSTNAME,
			sizeof(CONFIG_HTTPS_HOSTNAME) - 1);
	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,
			     uint64_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,
				       uint64_t event,
				       struct net_if *iface)
{
	if (event == NET_EVENT_CONN_IF_FATAL_ERROR) {
		printk("Fatal error received from the connectivity layer\n");
		return;
	}
}

I am getting this warning and error : 

<wrn> modem_key_mgmt: Failed to retrieve CMEE status, err -1
Failed to check for certificates err -1

I noticed that in this example the function nrf_modem_lib_init() is never called, i don't really understand why it use in some examples and not in others.
I thought that maybe the problem was coming from the project configuration so secondly I used directly the sample by cloning it on my computer.
Now I am getting this log:

HTTPS client sample started
Bringing network interface up
Provisioning certificate
Certificate match
Connecting to the network
+CEREG: 2,"BD84","09A19608",7
+CSCON: 1
+CGEV: ME PDN ACT 0,0
+CNEC_ESM: 50,0
%MDMEV: SEARCH STATUS 2
+CEREG: 5,"BD84","09A19608",7,,,"11100000","11100000"
Network connectivity established and IP address assigned
Looking up example.com
Resolved 172.66.147.243 (AF_INET)
Connecting to example.com:443
connect() failed, err: 111
+CGEV: ME PDN DEACT 0
+CEREG: 0
+CGEV: ME DETACH
+CSCON: 0
Network connectivity lost
Disconnected from the network

connect() returns 111 (connection refused).

I must admit I am quite lost on which libraries to use (zephyr vs nrf) to setup Nb-IOT vs Lte-M and TLS.

I just want to make a simple HTTPS POST request via NB-IOT.

Any help would be greatly appreciated.

Thank you,

Arthur

Parents
  • Hi,

    It looks the network is registering, DNS resolves, and the modem is fine. The only reason the sample failed against example.com is a certificate mismatch with that specific server. Since you are connecting to an AWS endpoint, here is what you need:

    First download the Amazon Root CA 1 certificate: https://www.amazontrust.com/repository/AmazonRootCA1.pem, place it in the cert/ folder, replacing DigiCertGlobalG3.pem.

    Then update CMakeLists.txt, change the cert filename from DigiCertGlobalG3.pem to AmazonRootCA1.pem (and the .inc name to match). Also update src/main.c line 47, change the #include to "AmazonRootCA1.pem.inc".

    Moreover you would need to add CONFIG_HTTPS_HOSTNAME="*******.eu-west-1.amazonaws.com" (your actual server hostname) to prj.conf

    You may try getting the connection working on LTE-M first with these changes. Once that is confirmed, switching to NB-IoT is just one additional line in prj.conf (CONFIG_LTE_NETWORK_MODE_NBIOT=y), but first check that your iBASIS SIM has NB-IoT coverage in your country here: https://ibasis.com/solutions/iot-connectivity/network-coverage/

    Point to note that France shows LTE-M only on the iBASIS coverage map, I am afraid that for NB-IoT you may need a different SIM (maybe from French operator). The iBASIS test SIM won't work for NB-IoT in France. 

    Let us know how it goes.

    Best Regards,
    Syed Maysum

  • Hi Syed,

    Thank you very much for this thorough response, I tried changing the certificate, setting CONFIG_HTTPS_HOSTNAME in prj.conf as you proposed.

    I am getting this log:

    *** Booting nRF Connect SDK v3.2.2-74845e169be2 ***
    *** Using Zephyr OS v4.2.99-fe4f0106803e ***
    HTTPS client sample started
    Bringing network interface up
    Provisioning certificate
    Certificate match
    Connecting to the network
    +CEREG: 2,"BD84","09A19608",7
    +CSCON: 1
    +CGEV: ME PDN ACT 0,0
    +CNEC_ESM: 50,0
    %MDMEV: SEARCH STATUS 2
    +CEREG: 5,"BD84","09A19608",7,,,"11100000","11100000"
    +CSCON: 0

    It looks like the code is stucked on taking the network connected semaphore (NET_EVENT_L4_CONNECTED is never triggered).

    I had a question concerning the modem initialization: how to choose if initialization is done at startup or by calling "nrf_modem_lib_init"? I don't see any particular line in the https_client example prj.conf file.

    Thank you,

    Arthur

  • Hi,

    Thanks for your response. First of all can you please confirm if you did pristine build after making the changes in prj.conf to make sure the issue is not related to stale build. Secondly your log shows +CNEC_ESM: 50,0 means your network is providing IPv4 only, no IPv6. But the sample is configured for dual-stack (IPv4 + IPv6 by default), so it waits for an IPv6 address that never arrive and may be resulting in a non-deterministic behavior.

    So if it still hangs after pristine build, you may tell the modem to request IPv4 only, by adding the overlay, using any of the two ways below:

    1. Pass it at build time:
     

    west build -b nrf9160dk/nrf9160/ns -- -DEXTRA_CONF_FILE=overlay-pdn-nrf91-ipv4.conf

    2. Add the two lines directly to prj.conf:

    CONFIG_LTE_LC_PDN_DEFAULTS_OVERRIDE=y
    CONFIG_LTE_LC_PDN_DEFAULT_FAM_IPV4=y

    Try these and let us know if it works. Thanks

    Best Regards,
    Syed Maysum

  • Hi Syed,

    I did a pristine build and it didn't change the result.

    Adding the two lines you gave in the prj.conf, the log is now:

    HTTPS client sample started
    Bringing network interface up
    Provisioning certificate
    Certificate match
    Connecting to the network
    +CEREG: 2,"79CD","07E42508",7
    +CSCON: 1
    +CGEV: ME PDN ACT 0
    %MDMEV: SEARCH STATUS 2
    +CEREG: 5,"79CD","07E42508",7,,,"11100000","11100000"
    +CSCON: 0

    Thank you for your help.

    Best regards,


    Arthur

  • Hi,

    Apologies for a late response. Even though you've set CONFIG_LTE_LC_PDN_DEFAULT_FAM_IPV4=y to request an IPv4 only, your prj.conf still may have both CONFIG_NET_IPV4=y and CONFIG_NET_IPV6=y. The Connection Manager may be waiting for an IPv6 address that will never arrive.

    So before any other changes can you try adding CONFIG_NET_IPV6=n to prj.conf and pristine build. Let us know if it works. Thanks

    Best Regards,
    Syed Maysum

Reply
  • Hi,

    Apologies for a late response. Even though you've set CONFIG_LTE_LC_PDN_DEFAULT_FAM_IPV4=y to request an IPv4 only, your prj.conf still may have both CONFIG_NET_IPV4=y and CONFIG_NET_IPV6=y. The Connection Manager may be waiting for an IPv6 address that will never arrive.

    So before any other changes can you try adding CONFIG_NET_IPV6=n to prj.conf and pristine build. Let us know if it works. Thanks

    Best Regards,
    Syed Maysum

Children
No Data
Related