Skip to content

Commit 7fc0851

Browse files
plskeggsnordicjm
authored andcommitted
net: lib: nrf_cloud: check relative size of root CA
Add two new Kconfig symbols to define thresholds for approximate size of the CoAP root CA and the size of combined CoAP + AWS root CAs. Retrieve size of configured sec_tag's root CA. Compare the size to the thresholds, display which root CA(s) are likely present, and use this to judge whether a cloud connection will likely succeed. If connection seems possible, proceed with connection as before. Jira: IRIS-9151 Signed-off-by: Pete Skeggs <[email protected]>
1 parent 22441bc commit 7fc0851

File tree

4 files changed

+116
-5
lines changed

4 files changed

+116
-5
lines changed

include/net/nrf_cloud.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -582,9 +582,12 @@ struct nrf_cloud_gnss_pvt {
582582
struct nrf_cloud_credentials_status {
583583
/* Configured sec_tag for nRF Cloud */
584584
uint32_t sec_tag;
585+
size_t ca_size;
585586

586587
/* Flags to indicate if the specified credentials exist */
587588
uint8_t ca:1;
589+
uint8_t ca_coap:1;
590+
uint8_t ca_aws:1;
588591
uint8_t client_cert:1;
589592
uint8_t prv_key:1;
590593
};
@@ -1179,11 +1182,14 @@ int nrf_cloud_credentials_check(struct nrf_cloud_credentials_status *const cs);
11791182
/**
11801183
* @brief Check if the credentials required for connecting to nRF Cloud exist.
11811184
* The application's configuration is used to determine which credentials
1182-
* are required.
1185+
* are required. Check the size of the root CA certificates installed
1186+
* and return an error code if the size of the root CA certificate(s) is not
1187+
* appropriate for the configured transport type.
11831188
*
11841189
* @retval 0 Required credentials exist.
11851190
* @retval -EIO Error checking if credentials exists.
11861191
* @retval -ENOTSUP Required credentials do not exist.
1192+
* @retval -ENOPROTOOPT Size of root CA is not appropriate for the configured transport type.
11871193
* @return A negative value indicates an error.
11881194
*/
11891195
int nrf_cloud_credentials_configured_check(void);

subsys/net/lib/nrf_cloud/Kconfig

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,23 @@ config NRF_CLOUD_JWT_SOURCE_CUSTOM
107107
help
108108
JWTs are created and signed by the nRF Cloud library, not the modem.
109109
The signing key is obtained from the TLS credentials module.
110+
111+
config NRF_CLOUD_AWS_CA_CERT_SIZE_THRESHOLD
112+
int "Root CA size above which AWS cert is likely present"
113+
default 1150
114+
help
115+
This value is necessarily inexact as the underlying PEM data varies
116+
a bit in size when credentials are rotated or replaced. This is useful
117+
to determine if a sectag likely contains only an AWS root CA
118+
certificate.
119+
120+
config NRF_CLOUD_COAP_CA_CERT_SIZE_THRESHOLD
121+
int "Root CA size above which a CoAP cert is likely present"
122+
default 550
123+
help
124+
This necessarily inexact value is useful to determine if a sectag
125+
likely contains only a CoAP root CA certificate.
126+
110127
endmenu # "Credentials"
111128

112129
rsource "Kconfig.nrf_cloud_client_id"

subsys/net/lib/nrf_cloud/src/nrf_cloud_credentials.c

Lines changed: 82 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,30 @@ int nrf_cloud_credentials_configured_check(void)
147147
}
148148
}
149149

150+
if (IS_ENABLED(CONFIG_NRF_CLOUD_MQTT) || IS_ENABLED(CONFIG_NRF_CLOUD_REST)) {
151+
if (!cs.ca_aws && cs.ca_coap) {
152+
/* There is a CA, but not large enough to be correct */
153+
LOG_WRN("Connection using MQTT or REST may fail as the size of the CA "
154+
"cert indicates it is a CoAP root CA.");
155+
ret = -ENOPROTOOPT;
156+
}
157+
}
158+
159+
if (IS_ENABLED(CONFIG_NRF_CLOUD_COAP)) {
160+
if (!cs.ca_coap && cs.ca_aws) {
161+
LOG_WRN("Connection using CoAP "
162+
"may fail as the size of the CA cert indicates "
163+
"CoAP CA certificate is missing but AWS CA is present.");
164+
ret = -ENOPROTOOPT;
165+
} else if (!IS_ENABLED(CONFIG_NRF_CLOUD_COAP_DOWNLOADS)) {
166+
if (cs.ca && (!cs.ca_coap || !cs.ca_aws)) {
167+
LOG_WRN("Connection using CoAP and downloading using HTTP "
168+
"may fail as the size of the CA cert indicates both "
169+
"CoAP and AWS root CA certs are not present.");
170+
ret = -ENOPROTOOPT;
171+
}
172+
}
173+
}
150174
return ret;
151175
}
152176

@@ -177,6 +201,34 @@ static int cred_exists(uint32_t sec_tag, int type, bool *exists)
177201
return err;
178202
}
179203

204+
static int cred_size_get(uint32_t sec_tag, int type, size_t *cred_sz)
205+
{
206+
int err;
207+
208+
*cred_sz = 0; /* We just want to determine the size */
209+
210+
#if defined(CONFIG_NRF_CLOUD_CREDENTIALS_MGMT_MODEM)
211+
uint8_t buf[1];
212+
213+
err = modem_key_mgmt_read(sec_tag, (enum modem_key_mgmt_cred_type)cred_type[type],
214+
buf, cred_sz);
215+
if (err && (err != -ENOMEM)) {
216+
LOG_ERR("modem_key_mgmt_read() failed for type %d in sec tag %u, error: %d",
217+
(enum modem_key_mgmt_cred_type)cred_type[type], sec_tag, err);
218+
} else {
219+
err = 0;
220+
}
221+
#else
222+
err = tls_credential_get(sec_tag, (enum tls_credential_type)cred_type[type],
223+
NULL, cred_sz);
224+
if (err == -EFBIG) { /* Error expected since we only want the size */
225+
err = 0;
226+
}
227+
#endif
228+
229+
return err;
230+
}
231+
180232
int nrf_cloud_credentials_check(struct nrf_cloud_credentials_status *const cs)
181233
{
182234
if (!cs) {
@@ -192,27 +244,56 @@ int nrf_cloud_credentials_check(struct nrf_cloud_credentials_status *const cs)
192244

193245
ret = cred_exists(cs->sec_tag, CA_CERT, &exists);
194246
if (ret < 0) {
247+
LOG_ERR("Error checking CA exists");
195248
return -EIO;
196249
}
197250
cs->ca = exists;
251+
if (exists) {
252+
ret = cred_size_get(cs->sec_tag, CA_CERT, &cs->ca_size);
253+
if (ret < 0) {
254+
LOG_ERR("Error checking CA size");
255+
return -EIO;
256+
}
257+
/* These flags are approximate and only useful for logging to help diagnose
258+
* possible provisioning mistakes.
259+
*/
260+
size_t coap_min_sz = CONFIG_NRF_CLOUD_COAP_CA_CERT_SIZE_THRESHOLD;
261+
size_t aws_min_sz = CONFIG_NRF_CLOUD_AWS_CA_CERT_SIZE_THRESHOLD;
262+
size_t combined_min_sz = aws_min_sz + coap_min_sz;
263+
264+
if (cs->ca_size > combined_min_sz) {
265+
cs->ca_aws = true;
266+
cs->ca_coap = true;
267+
} else if (cs->ca_size > aws_min_sz) {
268+
cs->ca_aws = true;
269+
} else if (cs->ca_size > coap_min_sz) {
270+
cs->ca_coap = true;
271+
}
272+
}
198273

199274
ret = cred_exists(cs->sec_tag, CLIENT_CERT, &exists);
200275
if (ret < 0) {
276+
LOG_ERR("Error checking client cert exists");
201277
return -EIO;
202278
}
203279
cs->client_cert = exists;
204280

205281
ret = cred_exists(cs->sec_tag, PRIVATE_KEY, &exists);
206282
if (ret < 0) {
283+
LOG_ERR("Error checking private key exists");
207284
return -EIO;
208285
}
209286
cs->prv_key = exists;
210287

211-
LOG_DBG("Sec Tag: %u, CA: %s, Client Cert: %s, Private Key: %s",
288+
LOG_INF("Sec Tag: %u; CA: %s, Client Cert: %s, Private Key: %s",
212289
cs->sec_tag,
213290
cs->ca ? "Yes" : "No",
214291
cs->client_cert ? "Yes" : "No",
215292
cs->prv_key ? "Yes" : "No");
293+
LOG_INF("CA Size: %zd, AWS: %s, CoAP: %s",
294+
cs->ca_size,
295+
cs->ca_aws ? "Likely" : "Unlikely",
296+
cs->ca_coap ? "Likely" : "Unlikely");
216297

217298
return 0;
218299
}

subsys/net/lib/nrf_cloud/src/nrf_cloud_info.c

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ int nrf_cloud_print_details(void)
106106
#if defined(CONFIG_NRF_CLOUD_VERBOSE_DETAILS)
107107
const char *protocol = "Unknown";
108108
const char *host_name = "Unknown";
109+
const char *download_protocol;
109110
char buf[100];
110111

111112
err = nrf_cloud_get_imei(buf, sizeof(buf));
@@ -137,9 +138,15 @@ int nrf_cloud_print_details(void)
137138
protocol = "REST";
138139
host_name = CONFIG_NRF_CLOUD_REST_HOST_NAME;
139140
#endif
140-
LOG_INF("Protocol: %s", protocol);
141-
LOG_INF("Sec tag: %d", nrf_cloud_sec_tag_get());
142-
LOG_INF("Host name: %s", host_name);
141+
#if defined(CONFIG_NRF_CLOUD_COAP_DOWNLOADS)
142+
download_protocol = "CoAP";
143+
#else
144+
download_protocol = "HTTPS";
145+
#endif
146+
LOG_INF("Protocol: %s", protocol);
147+
LOG_INF("Download protocol: %s", download_protocol);
148+
LOG_INF("Sec tag: %d", nrf_cloud_sec_tag_get());
149+
LOG_INF("Host name: %s", host_name);
143150

144151
#endif /* CONFIG_NRF_CLOUD_VERBOSE_DETAILS */
145152

0 commit comments

Comments
 (0)