Skip to content

mbedtls: allow storing certificates in filesystem #13863

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions connectivity/mbedtls/source/x509_crt.c
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,11 @@
#if !defined(_WIN32) || defined(EFIX64) || defined(EFI32)
#include <sys/types.h>
#include <sys/stat.h>
#if defined(__MBED__)
#include <platform/mbed_retarget.h>
#else
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we want to carry our own modification to mbedtls files, as it prevents us from upgrading mbedtls easily. We have precedent for modifying some files though, usually config files. See the mbedtls importer makefile: https://github.com/ARMmbed/mbed-os/blob/master/connectivity/mbedtls/tools/importer/Makefile

If the importer makefile isn't updated to apply this patch, we run the risk of losing these changes on an upgrade.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Totally understandable... Do you envision any way to import the patch? Or should it be filed to https://github.com/ARMmbed/mbedtls directly?

Copy link
Contributor

@0xc0170 0xc0170 May 4, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

apply this to the upstream, mbedtls repository

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@0xc0170 PR submitted here Mbed-TLS/mbedtls#4453

#include <dirent.h>
#endif /* __MBED__ */
#endif /* !_WIN32 || EFIX64 || EFI32 */
#endif

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,12 @@ int mbedtls_x509_crt_parse(mbedtls_x509_crt *a, const unsigned char *b, size_t c
return mbedtls_stub.expected_int;
}

int mbedtls_x509_crt_parse_path(mbedtls_x509_crt *a, const char *b)
{
// means 5 valid certificates found
return 5;
}

int mbedtls_x509_crt_info(char *buf, size_t size, const char *prefix,
const mbedtls_x509_crt *crt)
{
Expand Down
12 changes: 12 additions & 0 deletions connectivity/netsocket/include/netsocket/TLSSocketWrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,18 @@ class TLSSocketWrapper : public Socket {
*/
nsapi_error_t set_root_ca_cert(const char *root_ca_pem);

/** Sets the certification of Root CA.
*
* @note Must be called before calling connect()
*
* @param root_ca Path containing Root CA Certificate files in any Mbed TLS-supported format.
* @retval NSAPI_ERROR_OK on success.
* @retval NSAPI_ERROR_NO_MEMORY in case there is not enough memory to allocate certificate.
* @retval NSAPI_ERROR_PARAMETER in case the provided root_ca parameter failed parsing.
*
*/
nsapi_error_t set_root_ca_cert_path(const char *root_ca);

/** Sets client certificate, and client private key.
*
* @param client_cert Client certification in PEM or DER format.
Expand Down
29 changes: 29 additions & 0 deletions connectivity/netsocket/source/TLSSocketWrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,35 @@ nsapi_error_t TLSSocketWrapper::set_root_ca_cert(const char *root_ca_pem)
return set_root_ca_cert(root_ca_pem, strlen(root_ca_pem) + 1);
}

nsapi_error_t TLSSocketWrapper::set_root_ca_cert_path(const char *root_ca)
{
#if !defined(MBEDTLS_X509_CRT_PARSE_C) || !defined(MBEDTLS_FS_IO)
return NSAPI_ERROR_UNSUPPORTED;
#else
mbedtls_x509_crt *crt;

crt = new (std::nothrow) mbedtls_x509_crt;
if (!crt) {
return NSAPI_ERROR_NO_MEMORY;
}

mbedtls_x509_crt_init(crt);

/* Parse CA certification */
int ret = mbedtls_x509_crt_parse_path(crt, root_ca);
if (ret < 0) {
print_mbedtls_error("mbedtls_x509_crt_parse", ret);
mbedtls_x509_crt_free(crt);
delete crt;
return NSAPI_ERROR_PARAMETER;
}
set_ca_chain(crt);
_cacert_allocated = true;
return NSAPI_ERROR_OK;
#endif
}


nsapi_error_t TLSSocketWrapper::set_client_cert_key(const char *client_cert_pem, const char *client_private_key_pem)
{
return set_client_cert_key(client_cert_pem, strlen(client_cert_pem) + 1, client_private_key_pem, strlen(client_private_key_pem) + 1);
Expand Down
3 changes: 3 additions & 0 deletions connectivity/netsocket/tests/TESTS/netsocket/tls/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,9 @@ Case cases[] = {
Case("TLSSOCKET_SEND_REPEAT", TLSSOCKET_SEND_REPEAT),
Case("TLSSOCKET_SEND_TIMEOUT", TLSSOCKET_SEND_TIMEOUT),
Case("TLSSOCKET_NO_CERT", TLSSOCKET_NO_CERT),
#if defined(MBEDTLS_SSL_CLI_C) && defined(MBEDTLS_FS_IO)
Case("TLSSOCKET_CERT_IN_FILESYSTEM", TLSSOCKET_CERT_IN_FILESYSTEM),
#endif
// Temporarily removing this test, as TLS library consumes too much memory
// and we see frequent memory allocation failures on architectures with less
// RAM such as DISCO_L475VG_IOT1A and NUCLEO_F207ZG (both have 128 kB RAM)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ void TLSSOCKET_SEND_UNCONNECTED();
void TLSSOCKET_SEND_CLOSED();
void TLSSOCKET_SEND_REPEAT();
void TLSSOCKET_NO_CERT();
void TLSSOCKET_CERT_IN_FILESYSTEM();
void TLSSOCKET_SIMULTANEOUS();
void TLSSOCKET_SEND_TIMEOUT();

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* Copyright (c) 2020, Arduino SA, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#include "mbed.h"
#include "TLSSocket.h"
#include "greentea-client/test_env.h"
#include "unity/unity.h"
#include "utest.h"
#include "tls_tests.h"
#include "HeapBlockDevice.h"
#include "LittleFileSystem.h"

using namespace utest::v1;

void TLSSOCKET_CERT_IN_FILESYSTEM()
{
SKIP_IF_TCP_UNSUPPORTED();

HeapBlockDevice bd(1024 * 10);
LittleFileSystem fs("fs");
TEST_ASSERT_EQUAL(0, fs.format(&bd));
TEST_ASSERT_EQUAL(0, fs.mount(&bd));

FILE *fp = fopen("/fs/certs.pem", "wb");
int ret = fwrite(tls_global::cert, strlen(tls_global::cert), 1, fp);
fclose(fp);

TLSSocket sock;
TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, sock.open(NetworkInterface::get_default_instance()));
TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, sock.set_root_ca_cert_path("/fs"));

SocketAddress a;
TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, NetworkInterface::get_default_instance()->gethostbyname(ECHO_SERVER_ADDR, &a));
a.set_port(ECHO_SERVER_PORT_TLS);
TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, sock.connect(a));
}

Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,12 @@ TEST_F(TestTLSSocketWrapper, set_root_ca_cert_invalid)
EXPECT_EQ(wrapper->set_root_ca_cert(cert, strlen(cert)), NSAPI_ERROR_PARAMETER);
}

TEST_F(TestTLSSocketWrapper, set_root_ca_cert_path)
{
EXPECT_EQ(transport->open(&stack), NSAPI_ERROR_OK);
EXPECT_EQ(wrapper->set_root_ca_cert_path("/"), NSAPI_ERROR_OK);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is this test testing? How can we test the side effects are what we want?

Is there a mock block device we can use? or a higher level mock?

@pan- Do you know what mocks Mbed OS has available for the filesystem?

}

TEST_F(TestTLSSocketWrapper, set_client_cert_key)
{
EXPECT_EQ(wrapper->get_own_cert(), static_cast<mbedtls_x509_crt *>(NULL));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,6 @@
#define UNITTESTS_FEATURES_NETSOCKET_TLSSOCKET_TLS_TEST_CONFIG_H_

#define MBEDTLS_SSL_CLI_C

#define MBEDTLS_FS_IO

#endif /* UNITTESTS_FEATURES_NETSOCKET_TLSSOCKET_TLS_TEST_CONFIG_H_ */