Mayank Gupta / Mbed OS pelion-example-frdm

Dependencies:   FXAS21002 FXOS8700Q

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers EstClient.cpp Source File

EstClient.cpp

00001 // ----------------------------------------------------------------------------
00002 // Copyright 2016-2017 ARM Ltd.
00003 //
00004 // SPDX-License-Identifier: Apache-2.0
00005 //
00006 // Licensed under the Apache License, Version 2.0 (the "License");
00007 // you may not use this file except in compliance with the License.
00008 // You may obtain a copy of the License at
00009 //
00010 //     http://www.apache.org/licenses/LICENSE-2.0
00011 //
00012 // Unless required by applicable law or agreed to in writing, software
00013 // distributed under the License is distributed on an "AS IS" BASIS,
00014 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00015 // See the License for the specific language governing permissions and
00016 // limitations under the License.
00017 // ----------------------------------------------------------------------------
00018 
00019 #define __STDC_FORMAT_MACROS
00020 #include <inttypes.h>
00021 
00022 #include "include/ConnectorClient.h"
00023 #include "include/EstClient.h"
00024 #include "mbed-trace/mbed_trace.h"
00025 #include "mbed-client-libservice/common_functions.h"
00026 
00027 #include <stdio.h>
00028 #include <stdlib.h>
00029 
00030 #define TRACE_GROUP "est"
00031 
00032 struct enrollment_context_s {
00033     est_enrollment_result_cb   result_cb;
00034     uint8_t                    *data;
00035     size_t                     data_size;
00036     void*                      context;
00037 };
00038 
00039 #define EST_SEN_LWM2M                "est/sen"
00040 #define EST_SEN_URI_FORMAT           "est/%.*s/sen"
00041 
00042 #define EST_CERT_CHAIN_VERSION       1
00043 
00044 EstClient::EstClient(ConnectorClient& connector_client)
00045   :_connector_client(connector_client)
00046 {
00047 
00048 }
00049 
00050 
00051 EstClient::~EstClient()
00052 {
00053 }
00054 
00055 est_status_e EstClient::est_request_enrollment(const char *cert_name,
00056                                                const size_t cert_name_length,
00057                                                uint8_t *csr,
00058                                                const size_t csr_length,
00059                                                est_enrollment_result_cb result_cb,
00060                                                void *context) const
00061 {
00062     if (csr == NULL || csr_length == 0 || result_cb == NULL) {
00063         return EST_STATUS_INVALID_PARAMETERS;
00064     }
00065 
00066     if (_connector_client.m2m_interface() == NULL) {
00067         return EST_STATUS_INVALID_PARAMETERS;
00068     }
00069 
00070     enrollment_context_s *ctx = (enrollment_context_s*)malloc(sizeof(enrollment_context_s));
00071     if (ctx == NULL) {
00072         return EST_STATUS_MEMORY_ALLOCATION_FAILURE;
00073     }
00074 
00075     char *uri = make_est_uri(cert_name, cert_name_length);
00076     if (uri == NULL) {
00077       free(ctx);
00078       return EST_STATUS_MEMORY_ALLOCATION_FAILURE;
00079     }
00080 
00081     ctx->result_cb = result_cb;
00082     ctx->context = context;
00083     ctx->data = NULL;
00084     ctx->data_size = 0;
00085 
00086     _connector_client.m2m_interface()->post_data_request(uri,
00087                                                          false,
00088                                                          csr_length,
00089                                                          csr,
00090                                                          EstClient::est_post_data_cb,
00091                                                          EstClient::est_post_data_error_cb,
00092                                                          (void*)ctx);
00093 
00094     free(uri);
00095 
00096     return EST_STATUS_SUCCESS;
00097 }
00098 
00099 char* EstClient::make_est_uri(const char *cert_name,
00100                               const size_t cert_name_length)
00101 {
00102     char *uri = NULL;
00103     size_t uri_len = 0;
00104     if (cert_name == NULL) {
00105         // LwM2M certificate
00106         uri = (char*)malloc(sizeof(EST_SEN_LWM2M));
00107         if (uri != NULL) {
00108             strcpy(uri, EST_SEN_LWM2M);
00109         }
00110     }
00111     else {
00112         // User certificate
00113         uri_len = snprintf(NULL, 0, EST_SEN_URI_FORMAT, (int)cert_name_length, cert_name);
00114         uri_len++; // For null terminator
00115         uri = (char*)calloc(uri_len, sizeof(char));
00116         if (uri != NULL) {
00117             snprintf(uri, uri_len, EST_SEN_URI_FORMAT, (int)cert_name_length, cert_name);
00118         }
00119     }
00120     return uri;
00121 }
00122 
00123 void EstClient::est_post_data_cb(const uint8_t *buffer,
00124                                  size_t buffer_size,
00125                                  size_t total_size,
00126                                  bool last_block,
00127                                  void *context)
00128 {
00129     enrollment_context_s *enrollment_context = static_cast<enrollment_context_s*>(context);
00130     (void)total_size;
00131     assert(enrollment_context);
00132 
00133     // Append new buffer to payload
00134     size_t new_size = enrollment_context->data_size + buffer_size;
00135     uint8_t *new_buffer = (uint8_t*)malloc(new_size);
00136     if (!new_buffer) {
00137         // Memory error!
00138         return;
00139     }
00140 
00141     // Copy old data to start of buffer
00142     if (enrollment_context->data) {
00143         memcpy(new_buffer, enrollment_context->data, enrollment_context->data_size);
00144         free(enrollment_context->data);
00145     }
00146 
00147     // Copy new data to buffer
00148     memcpy(new_buffer + enrollment_context->data_size, buffer, buffer_size);
00149 
00150     enrollment_context->data = new_buffer;
00151     enrollment_context->data_size = new_size;
00152 
00153     if (last_block) {
00154         cert_chain_context_s *cert_ctx = parse_cert_chain(enrollment_context->data, enrollment_context->data_size);
00155         if (cert_ctx != NULL) {
00156             enrollment_context->result_cb(EST_ENROLLMENT_SUCCESS, cert_ctx, enrollment_context->context);
00157         }
00158         else {
00159             enrollment_context->result_cb(EST_ENROLLMENT_FAILURE, NULL, enrollment_context->context);
00160         }
00161 
00162         free(enrollment_context);
00163     }
00164 
00165 }
00166 
00167 void EstClient::est_post_data_error_cb(get_data_req_error_t error_code,
00168                                        void *context)
00169 {
00170     enrollment_context_s *enrollment_context = static_cast<enrollment_context_s*>(context);
00171     assert(enrollment_context);
00172     enrollment_context->result_cb(EST_ENROLLMENT_FAILURE, NULL, enrollment_context->context);
00173     free(enrollment_context);
00174 }
00175 
00176 cert_chain_context_s* EstClient::parse_cert_chain(uint8_t *cert_chain_data,
00177                                                   uint16_t cert_chain_data_len)
00178 {
00179     assert(cert_chain_data);
00180     assert(cert_chain_data_len > 0);
00181 
00182     uint8_t *ptr = cert_chain_data;
00183     cert_chain_context_s *context = (cert_chain_context_s*)malloc(sizeof(cert_chain_context_s));
00184 
00185     if (context != NULL) {
00186         bool success = true;
00187         context->cert_data_context = ptr;
00188         uint8_t version = *ptr++;
00189         context->chain_length = *ptr++;
00190         cert_context_s **next_context_ptr = &context->certs;
00191 
00192         // Check if unknown version
00193         if (version != EST_CERT_CHAIN_VERSION) {
00194             success = false;
00195         }
00196 
00197         // Check overflow
00198         if (success && ptr - cert_chain_data > cert_chain_data_len) {
00199             success = false;
00200             context->chain_length = 0;
00201         }
00202 
00203         if (success) {
00204             for (int i = 0; i < context->chain_length; i++) {
00205                 // Parse certificate length (2 bytes)
00206                 uint16_t cert_len = common_read_16_bit(ptr);
00207                 ptr += 2;
00208                 // Check overflow
00209                 if (ptr - cert_chain_data > cert_chain_data_len) {
00210                     success = false;
00211                     break;
00212                 }
00213 
00214                 // Allocate new certificate context
00215                 *next_context_ptr = (cert_context_s*)malloc(sizeof(cert_context_s));
00216                 if (*next_context_ptr == NULL) {
00217                     // Error
00218                     success = false;
00219                     break;
00220                 }
00221 
00222                 // Set cert pointer to correct position in data
00223                 (*next_context_ptr)->cert_length = cert_len;
00224                 (*next_context_ptr)->cert = ptr;
00225 
00226                 ptr += cert_len;
00227 
00228                 // Check overflow
00229                 if (ptr - cert_chain_data > cert_chain_data_len) {
00230                     success = false;
00231                     free(*next_context_ptr);
00232                     break;
00233                 }
00234 
00235                 next_context_ptr = &((*next_context_ptr)->next);
00236             }
00237             *next_context_ptr = NULL;
00238         }
00239 
00240         if (!success) {
00241             free_cert_chain_context(context);
00242             context = NULL;
00243         }
00244     }
00245 
00246     return context;
00247 }
00248 
00249 void EstClient::free_cert_chain_context(cert_chain_context_s *context) {
00250     if (context) {
00251         cert_context_s *next_cert = context->certs;
00252         while (next_cert != NULL) {
00253             cert_context_s *temp = next_cert->next;
00254             // Free each cert context, no need to free the cert data in
00255             // next_cert->cert because it points inside context->cert_data_context
00256             // which is free'd last
00257             free(next_cert);
00258             next_cert = temp;
00259         }
00260         free(context->cert_data_context);
00261         free(context);
00262     }
00263 }