Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Diff: simple-mbed-cloud-client/mbed-cloud-client/source/EstClient.cpp
- Revision:
- 0:8f0bb79ddd48
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/source/EstClient.cpp Tue May 04 08:55:12 2021 +0000 @@ -0,0 +1,263 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// 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. +// ---------------------------------------------------------------------------- + +#define __STDC_FORMAT_MACROS +#include <inttypes.h> + +#include "include/ConnectorClient.h" +#include "include/EstClient.h" +#include "mbed-trace/mbed_trace.h" +#include "mbed-client-libservice/common_functions.h" + +#include <stdio.h> +#include <stdlib.h> + +#define TRACE_GROUP "est" + +struct enrollment_context_s { + est_enrollment_result_cb result_cb; + uint8_t *data; + size_t data_size; + void* context; +}; + +#define EST_SEN_LWM2M "est/sen" +#define EST_SEN_URI_FORMAT "est/%.*s/sen" + +#define EST_CERT_CHAIN_VERSION 1 + +EstClient::EstClient(ConnectorClient& connector_client) + :_connector_client(connector_client) +{ + +} + + +EstClient::~EstClient() +{ +} + +est_status_e EstClient::est_request_enrollment(const char *cert_name, + const size_t cert_name_length, + uint8_t *csr, + const size_t csr_length, + est_enrollment_result_cb result_cb, + void *context) const +{ + if (csr == NULL || csr_length == 0 || result_cb == NULL) { + return EST_STATUS_INVALID_PARAMETERS; + } + + if (_connector_client.m2m_interface() == NULL) { + return EST_STATUS_INVALID_PARAMETERS; + } + + enrollment_context_s *ctx = (enrollment_context_s*)malloc(sizeof(enrollment_context_s)); + if (ctx == NULL) { + return EST_STATUS_MEMORY_ALLOCATION_FAILURE; + } + + char *uri = make_est_uri(cert_name, cert_name_length); + if (uri == NULL) { + free(ctx); + return EST_STATUS_MEMORY_ALLOCATION_FAILURE; + } + + ctx->result_cb = result_cb; + ctx->context = context; + ctx->data = NULL; + ctx->data_size = 0; + + _connector_client.m2m_interface()->post_data_request(uri, + false, + csr_length, + csr, + EstClient::est_post_data_cb, + EstClient::est_post_data_error_cb, + (void*)ctx); + + free(uri); + + return EST_STATUS_SUCCESS; +} + +char* EstClient::make_est_uri(const char *cert_name, + const size_t cert_name_length) +{ + char *uri = NULL; + size_t uri_len = 0; + if (cert_name == NULL) { + // LwM2M certificate + uri = (char*)malloc(sizeof(EST_SEN_LWM2M)); + if (uri != NULL) { + strcpy(uri, EST_SEN_LWM2M); + } + } + else { + // User certificate + uri_len = snprintf(NULL, 0, EST_SEN_URI_FORMAT, (int)cert_name_length, cert_name); + uri_len++; // For null terminator + uri = (char*)calloc(uri_len, sizeof(char)); + if (uri != NULL) { + snprintf(uri, uri_len, EST_SEN_URI_FORMAT, (int)cert_name_length, cert_name); + } + } + return uri; +} + +void EstClient::est_post_data_cb(const uint8_t *buffer, + size_t buffer_size, + size_t total_size, + bool last_block, + void *context) +{ + enrollment_context_s *enrollment_context = static_cast<enrollment_context_s*>(context); + (void)total_size; + assert(enrollment_context); + + // Append new buffer to payload + size_t new_size = enrollment_context->data_size + buffer_size; + uint8_t *new_buffer = (uint8_t*)malloc(new_size); + if (!new_buffer) { + // Memory error! + return; + } + + // Copy old data to start of buffer + if (enrollment_context->data) { + memcpy(new_buffer, enrollment_context->data, enrollment_context->data_size); + free(enrollment_context->data); + } + + // Copy new data to buffer + memcpy(new_buffer + enrollment_context->data_size, buffer, buffer_size); + + enrollment_context->data = new_buffer; + enrollment_context->data_size = new_size; + + if (last_block) { + cert_chain_context_s *cert_ctx = parse_cert_chain(enrollment_context->data, enrollment_context->data_size); + if (cert_ctx != NULL) { + enrollment_context->result_cb(EST_ENROLLMENT_SUCCESS, cert_ctx, enrollment_context->context); + } + else { + enrollment_context->result_cb(EST_ENROLLMENT_FAILURE, NULL, enrollment_context->context); + } + + free(enrollment_context); + } + +} + +void EstClient::est_post_data_error_cb(get_data_req_error_t error_code, + void *context) +{ + enrollment_context_s *enrollment_context = static_cast<enrollment_context_s*>(context); + assert(enrollment_context); + enrollment_context->result_cb(EST_ENROLLMENT_FAILURE, NULL, enrollment_context->context); + free(enrollment_context); +} + +cert_chain_context_s* EstClient::parse_cert_chain(uint8_t *cert_chain_data, + uint16_t cert_chain_data_len) +{ + assert(cert_chain_data); + assert(cert_chain_data_len > 0); + + uint8_t *ptr = cert_chain_data; + cert_chain_context_s *context = (cert_chain_context_s*)malloc(sizeof(cert_chain_context_s)); + + if (context != NULL) { + bool success = true; + context->cert_data_context = ptr; + uint8_t version = *ptr++; + context->chain_length = *ptr++; + cert_context_s **next_context_ptr = &context->certs; + + // Check if unknown version + if (version != EST_CERT_CHAIN_VERSION) { + success = false; + } + + // Check overflow + if (success && ptr - cert_chain_data > cert_chain_data_len) { + success = false; + context->chain_length = 0; + } + + if (success) { + for (int i = 0; i < context->chain_length; i++) { + // Parse certificate length (2 bytes) + uint16_t cert_len = common_read_16_bit(ptr); + ptr += 2; + // Check overflow + if (ptr - cert_chain_data > cert_chain_data_len) { + success = false; + break; + } + + // Allocate new certificate context + *next_context_ptr = (cert_context_s*)malloc(sizeof(cert_context_s)); + if (*next_context_ptr == NULL) { + // Error + success = false; + break; + } + + // Set cert pointer to correct position in data + (*next_context_ptr)->cert_length = cert_len; + (*next_context_ptr)->cert = ptr; + + ptr += cert_len; + + // Check overflow + if (ptr - cert_chain_data > cert_chain_data_len) { + success = false; + free(*next_context_ptr); + break; + } + + next_context_ptr = &((*next_context_ptr)->next); + } + *next_context_ptr = NULL; + } + + if (!success) { + free_cert_chain_context(context); + context = NULL; + } + } + + return context; +} + +void EstClient::free_cert_chain_context(cert_chain_context_s *context) { + if (context) { + cert_context_s *next_cert = context->certs; + while (next_cert != NULL) { + cert_context_s *temp = next_cert->next; + // Free each cert context, no need to free the cert data in + // next_cert->cert because it points inside context->cert_data_context + // which is free'd last + free(next_cert); + next_cert = temp; + } + free(context->cert_data_context); + free(context); + } +}