Skip to content

Commit cd2848e

Browse files
author
Mika Leppänen
committed
Added support for calculating the length of the TLS send message buffer
TLS security protocol now calculates the size for send buffer based on the length of the own certificate chain. This allows that variable length own certificate chains can be supported on TLS negotiation.
1 parent f255931 commit cd2848e

File tree

8 files changed

+115
-4
lines changed

8 files changed

+115
-4
lines changed

source/6LoWPAN/ws/ws_pae_controller.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -776,6 +776,9 @@ int8_t ws_pae_controller_certificate_chain_set(const arm_certificate_chain_entry
776776
}
777777
}
778778
}
779+
780+
// Updates the length of own certificates
781+
entry->certs.own_cert_chain_len = sec_prot_certs_cert_chain_entry_len_get(&entry->certs.own_cert_chain);
779782
}
780783

781784
return 0;
@@ -801,6 +804,8 @@ int8_t ws_pae_controller_own_certificate_add(const arm_certificate_entry_s *cert
801804
break;
802805
}
803806
}
807+
// Updates the length of own certificates
808+
entry->certs.own_cert_chain_len = sec_prot_certs_cert_chain_entry_len_get(&entry->certs.own_cert_chain);
804809
}
805810

806811
return ret;
@@ -810,6 +815,7 @@ int8_t ws_pae_controller_own_certificates_remove(void)
810815
{
811816
ns_list_foreach(pae_controller_t, entry, &pae_controller_list) {
812817
sec_prot_certs_chain_entry_init(&entry->certs.own_cert_chain);
818+
entry->certs.own_cert_chain_len = 0;
813819
}
814820

815821
return 0;

source/Security/protocols/eap_tls_sec_prot/eap_tls_sec_prot_lib.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,23 @@ int8_t eap_tls_sec_prot_lib_message_allocate(tls_data_t *data, uint8_t head_len,
5959
return 0;
6060
}
6161

62+
int8_t eap_tls_sec_prot_lib_message_realloc(tls_data_t *data, uint8_t head_len, uint16_t new_len)
63+
{
64+
tls_data_t new_tls_send;
65+
66+
eap_tls_sec_prot_lib_message_init(&new_tls_send);
67+
if (eap_tls_sec_prot_lib_message_allocate(&new_tls_send, head_len, new_len) < 0) {
68+
return -1;
69+
}
70+
memcpy(new_tls_send.data + head_len, data->data + head_len, data->handled_len);
71+
new_tls_send.handled_len = data->handled_len;
72+
eap_tls_sec_prot_lib_message_free(data);
73+
74+
*data = new_tls_send;
75+
76+
return 0;
77+
}
78+
6279
void eap_tls_sec_prot_lib_message_free(tls_data_t *data)
6380
{
6481
ns_dyn_mem_free(data->data);

source/Security/protocols/eap_tls_sec_prot/eap_tls_sec_prot_lib.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,19 @@ extern const uint8_t eap_msg_trace[4][10];
7272
*/
7373
int8_t eap_tls_sec_prot_lib_message_allocate(tls_data_t *data, uint8_t head_len, uint16_t len);
7474

75+
/**
76+
* eap_tls_sec_prot_lib_message_realloc allocates larger message buffer and copies existing data to it
77+
*
78+
* \param data data buffer which length is increased
79+
* \param head_len header length
80+
* \param new_len new length for the buffer
81+
*
82+
* \return < 0 failure
83+
* \return >= 0 success
84+
*
85+
*/
86+
int8_t eap_tls_sec_prot_lib_message_realloc(tls_data_t *data, uint8_t head_len, uint16_t new_len);
87+
7588
/**
7689
* eap_tls_sec_prot_lib_message_free free message buffer
7790
*

source/Security/protocols/sec_prot_certs.c

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@
3232

3333
#define TRACE_GROUP "spce"
3434

35+
// Length for PEM coded certificate's begin and end certificate text strings
36+
#define SEC_PROT_CERT_PEM_HEADER_FOOTER_LEN 52
37+
#define SEC_PROT_CERT_PEM_HEADER_STR "-----BEGIN CERTIFICATE-----"
38+
3539
int8_t sec_prot_certs_init(sec_prot_certs_t *certs)
3640
{
3741
if (!certs) {
@@ -41,6 +45,7 @@ int8_t sec_prot_certs_init(sec_prot_certs_t *certs)
4145
sec_prot_certs_chain_entry_init(&certs->own_cert_chain);
4246
ns_list_init(&certs->trusted_cert_chain_list);
4347
ns_list_init(&certs->cert_revocat_lists);
48+
certs->own_cert_chain_len = 0;
4449
certs->ext_cert_valid_enabled = false;
4550

4651
return 0;
@@ -73,6 +78,11 @@ bool sec_prot_certs_ext_certificate_validation_get(const sec_prot_certs_t *certs
7378
return certs->ext_cert_valid_enabled;
7479
}
7580

81+
uint16_t sec_prot_certs_own_cert_chain_len_get(const sec_prot_certs_t *certs)
82+
{
83+
return certs->own_cert_chain_len;
84+
}
85+
7686
cert_chain_entry_t *sec_prot_certs_chain_entry_create(void)
7787
{
7888
cert_chain_entry_t *entry = ns_dyn_mem_alloc(sizeof(cert_chain_entry_t));
@@ -115,6 +125,28 @@ uint8_t *sec_prot_certs_cert_get(const cert_chain_entry_t *entry, uint8_t index,
115125
return entry->cert[index];
116126
}
117127

128+
uint16_t sec_prot_certs_cert_chain_entry_len_get(const cert_chain_entry_t *entry)
129+
{
130+
uint16_t chain_length = 0;
131+
for (uint8_t index = 0; index < SEC_PROT_CERT_CHAIN_DEPTH; index++) {
132+
if (entry->cert[index]) {
133+
uint16_t cert_length = entry->cert_len[index];
134+
// Checks if certificate is in PEM base64 format
135+
if (cert_length > SEC_PROT_CERT_PEM_HEADER_FOOTER_LEN &&
136+
entry->cert[index][cert_length - 1] == '\0' &&
137+
strstr((const char *)entry->cert[index], SEC_PROT_CERT_PEM_HEADER_STR) != NULL) {
138+
cert_length -= SEC_PROT_CERT_PEM_HEADER_FOOTER_LEN;
139+
/* 4 base64 chars encode 3 bytes (ignores line endings and possible paddings in the
140+
calculation i.e they are counted to length) */
141+
chain_length += (cert_length / 4) * 3;
142+
} else {
143+
chain_length += cert_length;
144+
}
145+
}
146+
}
147+
return chain_length;
148+
}
149+
118150
int8_t sec_prot_certs_priv_key_set(cert_chain_entry_t *entry, uint8_t *key, uint8_t key_len)
119151
{
120152
if (!entry) {

source/Security/protocols/sec_prot_certs.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ typedef struct {
5858
cert_chain_entry_t own_cert_chain; /**< Own certificate chain */
5959
cert_chain_list_t trusted_cert_chain_list; /**< Trusted certificate chain lists */
6060
cert_revocat_lists_t cert_revocat_lists; /**< Certificate Revocation Lists */
61+
uint16_t own_cert_chain_len; /**< Own certificate chain certificates length */
6162
bool ext_cert_valid_enabled : 1; /**< Extended certificate validation enabled */
6263
} sec_prot_certs_t;
6364

@@ -101,6 +102,15 @@ int8_t sec_prot_certs_ext_certificate_validation_set(sec_prot_certs_t *certs, bo
101102
*/
102103
bool sec_prot_certs_ext_certificate_validation_get(const sec_prot_certs_t *certs);
103104

105+
/**
106+
* sec_prot_certs_own_cert_chain_len_get get length of own certificate chain
107+
*
108+
* \param certs certificate information
109+
*
110+
* \return length of all the certificates in the own certificate chain
111+
*/
112+
uint16_t sec_prot_certs_own_cert_chain_len_get(const sec_prot_certs_t *certs);
113+
104114
/**
105115
* sec_prot_certs_chain_entry_create allocate memory for certificate chain entry
106116
*
@@ -146,6 +156,15 @@ int8_t sec_prot_certs_cert_set(cert_chain_entry_t *entry, uint8_t index, uint8_t
146156
*/
147157
uint8_t *sec_prot_certs_cert_get(const cert_chain_entry_t *entry, uint8_t index, uint16_t *cert_len);
148158

159+
/**
160+
* sec_prot_certs_cert_chain_entry_len_get get length of certificate chain on cert chain entry
161+
*
162+
* \param entry certificate chain entry
163+
*
164+
* \return total length of all the certificates in the entry
165+
*/
166+
uint16_t sec_prot_certs_cert_chain_entry_len_get(const cert_chain_entry_t *entry);
167+
149168
/**
150169
* sec_prot_certs_priv_key_set set certificate (chain) private key
151170
*

source/Security/protocols/tls_sec_prot/tls_sec_prot.c

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,8 @@ static bool tls_sec_prot_queue_check(sec_prot_t *prot);
104104
static bool tls_sec_prot_queue_process(sec_prot_t *prot);
105105
static void tls_sec_prot_queue_remove(sec_prot_t *prot);
106106

107+
static uint16_t tls_sec_prot_send_buffer_size_get(sec_prot_t *prot);
108+
107109
#define tls_sec_prot_get(prot) (tls_sec_prot_int_t *) &prot->data
108110

109111
static NS_LIST_DEFINE(tls_sec_prot_queue, tls_sec_prot_queue_t, link);
@@ -498,12 +500,23 @@ static int16_t tls_sec_prot_tls_send(void *handle, const void *buf, size_t len)
498500
tls_sec_prot_int_t *data = tls_sec_prot_get(prot);
499501

500502
if (!data->tls_send.data) {
501-
eap_tls_sec_prot_lib_message_allocate(&data->tls_send, prot->header_size, TLS_SEC_PROT_BUFFER_SIZE);
503+
uint16_t buffer_len = tls_sec_prot_send_buffer_size_get(prot);
504+
eap_tls_sec_prot_lib_message_allocate(&data->tls_send, prot->header_size, buffer_len);
502505
}
503506
if (!data->tls_send.data) {
504507
return -1;
505508
}
506509

510+
/* If send buffer is too small for the TLS payload, re-allocates */
511+
uint16_t new_len = prot->header_size + data->tls_send.handled_len + len;
512+
if (new_len > data->tls_send.total_len) {
513+
tr_error("TLS send buffer size too small: %i < %i, allocating new: %i", data->tls_send.total_len, new_len, data->tls_send.total_len + TLS_SEC_PROT_SEND_BUFFER_SIZE_INCREMENT);
514+
if (eap_tls_sec_prot_lib_message_realloc(&data->tls_send, prot->header_size,
515+
data->tls_send.total_len + TLS_SEC_PROT_SEND_BUFFER_SIZE_INCREMENT) < 0) {
516+
return -1;
517+
}
518+
}
519+
507520
memcpy(data->tls_send.data + prot->header_size + data->tls_send.handled_len, buf, len);
508521
data->tls_send.handled_len += len;
509522

@@ -689,4 +702,9 @@ static void tls_sec_prot_queue_remove(sec_prot_t *prot)
689702
}
690703
}
691704

705+
static uint16_t tls_sec_prot_send_buffer_size_get(sec_prot_t *prot)
706+
{
707+
return TLS_SEC_PROT_SEND_BUFFER_SIZE + sec_prot_certs_own_cert_chain_len_get(prot->sec_keys->certs);
708+
}
709+
692710
#endif /* HAVE_WS */

source/Security/protocols/tls_sec_prot/tls_sec_prot.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,13 @@
2323
*
2424
*/
2525

26-
#define TLS_SEC_PROT_BUFFER_SIZE 1200 // Send buffer size (maximum size for a TLS data for a flight)
26+
/* TLS send buffer size not including certificates. This should include e.g. on
27+
* server: server hello, server key exchange, certificate request and server
28+
* hello done. */
29+
#define TLS_SEC_PROT_SEND_BUFFER_SIZE 500
30+
31+
/* TLS send buffer size increment if it is detected that buffer is too small */
32+
#define TLS_SEC_PROT_SEND_BUFFER_SIZE_INCREMENT 1000
2733

2834
/**
2935
* client_tls_sec_prot_register register client TLS protocol to KMP service

source/Security/protocols/tls_sec_prot/tls_sec_prot_lib.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ struct tls_security_s {
7575
mbedtls_pk_context pkey; /**< Private key for own certificate */
7676
void *handle; /**< Handle provided in callbacks (defined by library user) */
7777
bool ext_cert_valid : 1; /**< Extended certificate validation enabled */
78-
tls_sec_prot_lib_crt_verify_cb *crt_verify; /**< Verify function for top certificate */
78+
tls_sec_prot_lib_crt_verify_cb *crt_verify; /**< Verify function for client/server certificate */
7979
tls_sec_prot_lib_send *send; /**< Send callback */
8080
tls_sec_prot_lib_receive *receive; /**< Receive callback */
8181
tls_sec_prot_lib_export_keys *export_keys; /**< Export keys callback */
@@ -488,7 +488,7 @@ static int tls_sec_prot_lib_x509_crt_verify(void *ctx, mbedtls_x509_crt *crt, in
488488
tr_error("Invalid signature pk algorithm");
489489
}
490490

491-
// Verify top certificate of the chain
491+
// Verify client/server certificate of the chain
492492
if (certificate_depth == 0) {
493493
return sec->crt_verify(sec, crt, flags);
494494
}

0 commit comments

Comments
 (0)