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.
Dependencies: FXAS21002 FXOS8700Q
CertificateEnrollmentClient.cpp
00001 // ---------------------------------------------------------------------------- 00002 // Copyright 2018 ARM Ltd. 00003 // 00004 // Licensed under the Apache License, Version 2.0 (the "License"); 00005 // you may not use this file except in compliance with the License. 00006 // You may obtain a copy of the License at 00007 // 00008 // http://www.apache.org/licenses/LICENSE-2.0 00009 // 00010 // Unless required by applicable law or agreed to in writing, software 00011 // distributed under the License is distributed on an "AS IS" BASIS, 00012 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00013 // See the License for the specific language governing permissions and 00014 // limitations under the License. 00015 // ---------------------------------------------------------------------------- 00016 00017 00018 #include "CertificateEnrollmentClient.h" 00019 #include "mbed-client/m2mresource.h" 00020 #include "mbed-client/m2minterfacefactory.h" 00021 #include "mbed-client/m2minterface.h" 00022 #include "pal.h" 00023 #include "eventOS_scheduler.h" 00024 #include "eventOS_event.h" 00025 #include "ce_defs.h" 00026 #include "ce_tlv.h" 00027 #include "certificate_enrollment.h" 00028 #include <stdio.h> 00029 #include <string.h> 00030 #include "CertificateEnrollmentClient.h" 00031 #include "CertificateEnrollmentClientCommon.h" 00032 #include "CertificateRenewalData.h" 00033 #include "pv_error_handling.h" 00034 #include "pv_macros.h" 00035 00036 #define RESOURCE_ID_CERTIFICATE_NAME "27002" 00037 #define OBJECT_LWM2M_CERTIFICATE "35011" 00038 00039 #define NUMBER_OF_CONCURRENT_RENEWALS 1 00040 00041 00042 /************************************************************************/ 00043 /* Different calls to update */ 00044 /************************************************************************/ 00045 00046 extern const char g_lwm2m_name[]; 00047 00048 namespace CertificateEnrollmentClient { 00049 00050 // Event type that is part of the arm_event_s structure. 00051 enum event_type_e { 00052 EVENT_TYPE_INIT, // Some initializer - nothing done currently, initialization called by mbed cloud client 00053 EVENT_TYPE_RENEWAL_REQUEST, // Certificate renewal request. We can tell if it is initiated by the server or the device with the derived type of CertificateRenewalDataBase of the certificate descriptor / global variable 00054 EVENT_TYPE_EST_RESPONDED, // Certificate arrived from EST service, or EST failure 00055 EVENT_TYPE_MAX = 0xff // Must fit in a uint8_t (field in the arm_event_s struct) 00056 }; 00057 00058 // Pointer to the EST client object for dealing with the EST service. 00059 extern const CERT_ENROLLMENT_EST_CLIENT *g_est_client; 00060 00061 // Data for certificate that is currently being renewed. Will change to list if we need to support multiple renewals 00062 static CertificateRenewalDataBase *current_cert = NULL; 00063 00064 // ID of the handler we register to the MbedCloudClient event loop 00065 static int8_t handler_id = -1; 00066 00067 // Flag that indicates whether the module is initialized 00068 static bool is_initialized = false; 00069 00070 // Semaphore for enforcing that only NUMBER_OF_CONCURRENT_RENEWALS (currently 1) request at a time may update current_cert. Hold lock until process finished. 00071 // Important: When pal_osSemaphoreWait called from within event loop - do not block, must set timeout to 0, and fail if failed to acquire lock 00072 // Future: For supporting renewals of NUMBER_OF_CONCURRENT_RENEWALS certificates simultaneously - change to semaphore that counts to NUMBER_OF_CONCURRENT_RENEWALS 00073 // and maintain a list of certificates of size NUMBER_OF_CONCURRENT_RENEWALS inside the event loop. 00074 static palSemaphoreID_t g_renewal_sem = 0; 00075 00076 00077 /** 00078 * \brief Finish the renewal process. 00079 * Zero current_cert pointer, then release the semaphore. Note that when the semaphore is released - new device renewals may be made. 00080 * Then call renewal_data->finish() and delete renewal_data. 00081 * 00082 * \param renewal_data the data of the certificate to be renewed. 00083 * It is important that this is passed to the function because after releasing the semaphore - the global pointer may be replaced. 00084 * \param exit_status the status of the renewal process 00085 */ 00086 static void certificate_renewal_finish(CertificateRenewalDataBase *renewal_data, ce_status_e exit_status); 00087 00088 /** 00089 * \brief The function that handles all the CertificateEnrollmentClient events 00090 * Create an arm_event_s object and call eventOS_event_send() 00091 * The event will have an application level priority, and will be executed when in the head of the event queue. 00092 * In the future: an extra arg should be passed - some descriptor for the specific CertificateRenewalDataBase object. 00093 * 00094 * \param event_type An event identifier 00095 */ 00096 static void event_handler(arm_event_s* event); 00097 00098 /** 00099 * \brief Send a new event to the event loop queue. 00100 * Create an arm_event_s object and call eventOS_event_send() 00101 * The event will have an application level priority 00102 * 00103 * \param renewal_data A pointer to an object derived from CertificateRenewalDataBase 00104 * \param event_type An event identifier 00105 */ 00106 static ce_status_e schedule_event(event_type_e event_type); 00107 00108 /** 00109 * \brief Callback that will be executed when an EST service response is available 00110 * Event Context is probably network so this function will check if response is success, if so, allocate the data if needed in renewal_data->est_data. schedule a new event with type EVENT_TYPE_EST_RESPONDED. 00111 * 00112 * \param result Whether the EST client successfully received a certificate from the EST service 00113 * \param cert_chain structure containing the certificate/chain received from the EST service 00114 * \param Context passed when requesting a certificate via the EST client. Currently unused. In the future will be used to identify the relevant CertificateRenewalDataBase object. 00115 */ 00116 static void est_cb(est_enrollment_result_e result, 00117 cert_chain_context_s *cert_chain, 00118 void *context); 00119 00120 /** 00121 * \brief The function that handles the EST response. 00122 * 00123 * Called by event_handler(). renewal_data->est_data already exists and is valid. 00124 * Will perform a safe replacement of the certificate with the new certificate received from EST 00125 * Then it will free the EST chain and finish the renewal operation. 00126 * \param renewal_data A pointer to an object derived from CertificateRenewalDataBase 00127 */ 00128 static void est_response_process(CertificateRenewalDataBase *renewal_data); 00129 00130 /** 00131 * \brief Create g_cert_enroll_lwm2m_obj, from the object create an object resource, and create the resources. Then push the object to the MCC object list 00132 * 00133 * Note that the pointers to the objects created by this function is owned by the CertificateEnrollmentClient Module and must be released in by CertificateEnrollmentClient::finalize() 00134 * \param list A reference to the MbedCloudClient object list. MbedCloudClient will later set the resource 00135 */ 00136 static ce_status_e init_objects(M2MBaseList& list); 00137 00138 /** 00139 * \brief Release the objects created by init_objects() 00140 * 00141 */ 00142 static void release_objects(); 00143 00144 // Callback is called when we get a POST message to g_cert_enroll_lwm2m_resource (runs in high priority context!) 00145 /** 00146 * \brief Callback is called when we get a POST message to g_cert_enroll_lwm2m_resource 00147 * Runs in network context of the event loop. 00148 * This function extracts the input data, creates a CertificateEnrollmentClient::CertificateRenewalDataFromServer object sets the global variable 00149 * 00150 * \param arg a M2MResource::M2MExecuteParameter argument. 00151 */ 00152 static void certificate_renewal_post(void *arg); 00153 00154 /** 00155 * \brief Start the renewal process. 00156 * Parse the certificate name, generate keys and CSR. Then call the EST client so the new certificate may be retrieved 00157 * 00158 * \param renewal_data the data of the certificate to be renewed 00159 */ 00160 static void certificate_renewal_start(CertificateRenewalDataBase *renewal_data); 00161 00162 /** 00163 * \brief Call the user callback and send a response to the server, when a CertificateRenewalDataFromServer object does not exist. 00164 * Use only for server initiated renewal, since this sends a response to the server. 00165 * 00166 * \param tlv the raw data from the server - should be in the form of TLV 00167 * \param tlv_size size of the TLV buffer 00168 * \param ret_status The return status to return to the user callback and the server 00169 */ 00170 static void call_user_cb_send_response(const uint8_t *tlv, uint16_t tlv_size, ce_status_e ret_status); 00171 00172 #ifdef CERT_RENEWAL_TEST 00173 void testonly_certificate_renewal_post(void *arg); 00174 #endif // CERT_RENEWAL_TEST 00175 00176 } 00177 00178 // FIXME: print error 00179 void CertificateEnrollmentClient::call_user_cb_send_response(const uint8_t *tlv, uint16_t tlv_size, ce_status_e ret_status) 00180 { 00181 CertificateEnrollmentClient::CertificateRenewalDataFromServer temp_obj(tlv, tlv_size); 00182 (void)temp_obj.parse(); 00183 00184 // Call user callback with appropriate error 00185 // In case of parsing error (malformed TLV), the provided ret_status will be returned and not 00186 call_user_cert_renewal_cb(temp_obj.cert_name, ret_status, CE_INITIATOR_SERVER); 00187 00188 // Send response to the server 00189 SA_PV_LOG_INFO("sending delayed response\n"); 00190 g_cert_enroll_lwm2m_resource->set_value(ret_status); 00191 g_cert_enroll_lwm2m_resource->send_delayed_post_response(); 00192 } 00193 00194 void CertificateEnrollmentClient::certificate_renewal_post(void *arg) 00195 { 00196 palStatus_t pal_status; 00197 ce_status_e status; 00198 SA_PV_LOG_INFO_FUNC_ENTER_NO_ARGS(); 00199 00200 M2MResource::M2MExecuteParameter *args = (M2MResource::M2MExecuteParameter *)arg; 00201 const uint8_t *data = args->get_argument_value(); 00202 const uint16_t data_size = args->get_argument_value_length(); 00203 00204 // If CEC module is not initialized - do not even take semaphore - exit with proper response 00205 SA_PV_ERR_RECOVERABLE_RETURN_IF((!is_initialized), call_user_cb_send_response(data, data_size, CE_STATUS_NOT_INITIALIZED), "Certificate Renewal module not initialized"); 00206 00207 pal_status = pal_osSemaphoreWait(g_renewal_sem, 0, NULL); 00208 00209 if (pal_status == PAL_SUCCESS) { 00210 CertificateEnrollmentClient::current_cert = new CertificateEnrollmentClient::CertificateRenewalDataFromServer(data, data_size); 00211 if (!CertificateEnrollmentClient::current_cert) { 00212 status = CE_STATUS_OUT_OF_MEMORY; 00213 pal_status = pal_osSemaphoreRelease(g_renewal_sem); 00214 if (PAL_SUCCESS != pal_status) { // Should never happen 00215 status = CE_STATUS_ERROR; 00216 } 00217 00218 call_user_cb_send_response(data, data_size, status); 00219 return; 00220 } 00221 00222 // Enqueue the event 00223 status = schedule_event(CertificateEnrollmentClient::EVENT_TYPE_RENEWAL_REQUEST); 00224 SA_PV_ERR_RECOVERABLE_RETURN_IF((status != CE_STATUS_SUCCESS), certificate_renewal_finish(CertificateEnrollmentClient::current_cert, status), "Error scheduling event"); 00225 00226 } else { 00227 SA_PV_LOG_ERR("Failed to take semaphore- device busy\n"); 00228 00229 if (pal_status == PAL_ERR_RTOS_TIMEOUT ) { 00230 status = CE_STATUS_DEVICE_BUSY; 00231 } else { 00232 status = CE_STATUS_ERROR; 00233 } 00234 00235 call_user_cb_send_response(data, data_size, status); 00236 return; 00237 } 00238 00239 SA_PV_LOG_INFO_FUNC_EXIT_NO_ARGS(); 00240 } 00241 00242 ce_status_e CertificateEnrollmentClient::certificate_renew(const char *cert_name) 00243 { 00244 palStatus_t pal_status = PAL_SUCCESS; 00245 ce_status_e status = CE_STATUS_SUCCESS; 00246 00247 SA_PV_ERR_RECOVERABLE_RETURN_IF((!cert_name), CE_STATUS_INVALID_PARAMETER, "Provided NULL certificate name"); 00248 SA_PV_ERR_RECOVERABLE_RETURN_IF((!is_initialized), CE_STATUS_NOT_INITIALIZED, "Certificate Renewal module not initialized"); 00249 00250 SA_PV_LOG_INFO_FUNC_ENTER("cert_name = %s\n", cert_name); 00251 00252 pal_status = pal_osSemaphoreWait(g_renewal_sem, 0, NULL); 00253 00254 if (pal_status == PAL_SUCCESS) { 00255 CertificateEnrollmentClient::current_cert = new CertificateEnrollmentClient::CertificateRenewalDataFromDevice(cert_name); 00256 SA_PV_ERR_RECOVERABLE_GOTO_IF((!CertificateEnrollmentClient::current_cert), status = CE_STATUS_OUT_OF_MEMORY, ReleseSemReturn, "Allocation error"); 00257 00258 // Enqueue the event 00259 status = schedule_event(CertificateEnrollmentClient::EVENT_TYPE_RENEWAL_REQUEST); 00260 SA_PV_ERR_RECOVERABLE_GOTO_IF((status != CE_STATUS_SUCCESS), status = status, ReleseSemReturn, "Error scheduling event"); 00261 00262 // If some error synchronous error has occurred before scheduling the event - release the semaphore we had just taken, 00263 // and then return the error without calling the user callback 00264 ReleseSemReturn: 00265 if (status != CE_STATUS_SUCCESS) { 00266 pal_status = pal_osSemaphoreRelease(g_renewal_sem); 00267 if (PAL_SUCCESS != pal_status) { // Should never happen 00268 status = CE_STATUS_ERROR; 00269 } 00270 } 00271 00272 } else { 00273 // return with appropriate error 00274 if (pal_status == PAL_ERR_RTOS_TIMEOUT ) { 00275 status = CE_STATUS_DEVICE_BUSY; 00276 } else { 00277 status = CE_STATUS_ERROR; 00278 } 00279 00280 } 00281 00282 SA_PV_LOG_INFO_FUNC_EXIT_NO_ARGS(); 00283 return status; 00284 } 00285 00286 00287 void CertificateEnrollmentClient::on_certificate_renewal(cert_renewal_cb_f user_cb) 00288 { 00289 SA_PV_LOG_INFO_FUNC_ENTER_NO_ARGS(); 00290 CertificateEnrollmentClient::set_user_cert_renewal_cb(user_cb); 00291 SA_PV_LOG_INFO_FUNC_EXIT_NO_ARGS(); 00292 } 00293 00294 00295 ce_status_e CertificateEnrollmentClient::init_objects(M2MBaseList& list) 00296 { 00297 M2MObjectInstance *cert_enroll_lwm2m_obj_instance; 00298 00299 ce_status_e ce_status = CE_STATUS_SUCCESS; 00300 SA_PV_LOG_INFO_FUNC_ENTER_NO_ARGS(); 00301 00302 // Create the certificate enrollment resource 00303 g_cert_enroll_lwm2m_obj = M2MInterfaceFactory::create_object(OBJECT_LWM2M_CERTIFICATE); 00304 SA_PV_ERR_RECOVERABLE_RETURN_IF((!g_cert_enroll_lwm2m_obj), CE_STATUS_ERROR, "Error creating LWM2M object"); 00305 00306 // Create the instance 00307 cert_enroll_lwm2m_obj_instance = g_cert_enroll_lwm2m_obj->create_object_instance(); 00308 SA_PV_ERR_RECOVERABLE_GOTO_IF((!cert_enroll_lwm2m_obj_instance), ce_status = CE_STATUS_ERROR, Cleanup, "Error creating LWM2M object instance"); 00309 00310 // Create the resource 00311 g_cert_enroll_lwm2m_resource = cert_enroll_lwm2m_obj_instance->create_dynamic_resource(RESOURCE_ID_CERTIFICATE_NAME, "Enroll", M2MResourceInstance::INTEGER, false); 00312 SA_PV_ERR_RECOVERABLE_GOTO_IF((!g_cert_enroll_lwm2m_resource), ce_status = CE_STATUS_ERROR, Cleanup, "Error creating LWM2M resource"); 00313 00314 // Allow POST operations 00315 g_cert_enroll_lwm2m_resource->set_operation(M2MBase::POST_ALLOWED); 00316 00317 // Set the resource callback 00318 SA_PV_ERR_RECOVERABLE_GOTO_IF((!g_cert_enroll_lwm2m_resource->set_execute_function(CertificateEnrollmentClient::certificate_renewal_post)), 00319 ce_status = CE_STATUS_ERROR, Cleanup, "Error resource callback"); 00320 00321 // Enable sending of delayed responses 00322 g_cert_enroll_lwm2m_resource->set_delayed_response(true); 00323 00324 // Push the object to the list 00325 list.push_back(g_cert_enroll_lwm2m_obj); 00326 00327 Cleanup: 00328 if (ce_status != CE_STATUS_SUCCESS) { 00329 // Destroying the object will destroy all instances and resources associated with it 00330 delete g_cert_enroll_lwm2m_obj; 00331 g_cert_enroll_lwm2m_resource = NULL; 00332 } 00333 00334 SA_PV_LOG_INFO_FUNC_EXIT_NO_ARGS(); 00335 return ce_status; 00336 } 00337 00338 void CertificateEnrollmentClient::release_objects() 00339 { 00340 delete g_cert_enroll_lwm2m_obj; 00341 g_cert_enroll_lwm2m_obj = NULL; 00342 } 00343 00344 00345 ce_status_e CertificateEnrollmentClient::init(M2MBaseList& list, const EstClient *est_client) 00346 { 00347 ce_status_e ce_status = CE_STATUS_SUCCESS; 00348 palStatus_t pal_status = PAL_SUCCESS; 00349 00350 SA_PV_LOG_INFO_FUNC_ENTER_NO_ARGS(); 00351 00352 if (!is_initialized) { 00353 00354 // Init the LWM2M object and resource and push the object 00355 ce_status = init_objects(list); 00356 SA_PV_ERR_RECOVERABLE_RETURN_IF((ce_status != CE_STATUS_SUCCESS), ce_status, "Error initializing LWM2M object and resource"); 00357 00358 // Put the handler creation in a critical code block for the case that this function is called after the start of the event loop 00359 eventOS_scheduler_mutex_wait(); 00360 if (handler_id == -1) { // Register the handler only if it hadn't been registered before 00361 handler_id = eventOS_event_handler_create(CertificateEnrollmentClient::event_handler, EVENT_TYPE_INIT); 00362 SA_PV_ERR_RECOVERABLE_RETURN_IF((handler_id == -1), ce_status, "Error creating event handler"); 00363 } 00364 eventOS_scheduler_mutex_release(); 00365 00366 // Initialize the CE module 00367 ce_status = ce_init(); 00368 SA_PV_ERR_RECOVERABLE_RETURN_IF((ce_status != CE_STATUS_SUCCESS), ce_status, "Error initializing CE module"); 00369 00370 // Create the certificate renewal mutex 00371 pal_status = pal_osSemaphoreCreate(NUMBER_OF_CONCURRENT_RENEWALS, &g_renewal_sem); 00372 SA_PV_ERR_RECOVERABLE_RETURN_IF((pal_status != PAL_SUCCESS), CE_STATUS_ERROR, "Error creating semaphore"); 00373 00374 #ifdef CERT_ENROLLMENT_EST_MOCK 00375 PV_UNUSED_PARAM(est_client); 00376 g_est_client = new EstClientMock(); 00377 SA_PV_ERR_RECOVERABLE_RETURN_IF((!g_est_client), CE_STATUS_ERROR, "Error creating mock EST"); 00378 #else 00379 g_est_client = est_client; 00380 #endif 00381 00382 is_initialized = true; 00383 } 00384 00385 SA_PV_LOG_INFO_FUNC_EXIT_NO_ARGS(); 00386 return CE_STATUS_SUCCESS; 00387 } 00388 00389 void CertificateEnrollmentClient::finalize() 00390 { 00391 palStatus_t pal_status; 00392 // If module not initialized - do nothing 00393 if (is_initialized) { 00394 pal_status = pal_osSemaphoreDelete(&g_renewal_sem); 00395 if (pal_status != PAL_SUCCESS) { 00396 SA_PV_LOG_ERR("Error deleting semaphore"); 00397 } 00398 00399 #ifdef CERT_ENROLLMENT_EST_MOCK 00400 delete g_est_client; 00401 #endif 00402 is_initialized = false; 00403 00404 // LWM2M objects, instances, and resources are deleted when MbedCloudClient is unregistered and ServiceClient::state_unregister() is called 00405 // Currently nothing to finalize for CE core module except for KCM. However we do not wish to finalize it it may be used by other resources 00406 00407 // Release our resources 00408 release_objects(); 00409 } 00410 } 00411 00412 void CertificateEnrollmentClient::event_handler(arm_event_s* event) 00413 { 00414 SA_PV_LOG_INFO_FUNC_ENTER_NO_ARGS(); 00415 00416 switch (event->event_type) { 00417 case EVENT_TYPE_INIT: 00418 // Nothing to do - ce module already initialized 00419 break; 00420 case EVENT_TYPE_RENEWAL_REQUEST: 00421 certificate_renewal_start(current_cert); 00422 break; 00423 case EVENT_TYPE_EST_RESPONDED: 00424 est_response_process(current_cert); 00425 break; 00426 default: 00427 // Should never happen 00428 SA_PV_LOG_ERR("Unsuupported event\n"); 00429 } 00430 00431 SA_PV_LOG_INFO_FUNC_EXIT_NO_ARGS(); 00432 } 00433 00434 // This is the entry point of the renewal request, inside the event loop 00435 void CertificateEnrollmentClient::certificate_renewal_start(CertificateRenewalDataBase *renewal_data) 00436 { 00437 ce_status_e ce_status; 00438 est_status_e est_status; 00439 const char *cert_name; 00440 size_t cert_name_size; 00441 kcm_status_e kcm_status; 00442 SA_PV_LOG_INFO_FUNC_ENTER_NO_ARGS(); 00443 00444 // Parse the certificate name 00445 ce_status = renewal_data->parse(); 00446 SA_PV_ERR_RECOVERABLE_RETURN_IF((ce_status != CE_STATUS_SUCCESS), certificate_renewal_finish(renewal_data, ce_status), "Parse error"); 00447 00448 // Create CSR's key handle 00449 kcm_status = cs_ec_key_new(&renewal_data->key_handle); 00450 00451 // translate error to some CE native error 00452 ce_status = ce_error_handler(kcm_status); 00453 SA_PV_ERR_RECOVERABLE_RETURN_IF((ce_status != CE_STATUS_SUCCESS), certificate_renewal_finish(renewal_data, ce_status), "Failed creating new key handle"); 00454 00455 // key handle is initialized in the base constructor 00456 ce_status = ce_generate_keys_and_create_csr_from_certificate(renewal_data->cert_name, renewal_data->key_handle, &renewal_data->csr, &renewal_data->csr_size); 00457 SA_PV_ERR_RECOVERABLE_RETURN_IF((ce_status != CE_STATUS_SUCCESS), certificate_renewal_finish(renewal_data, ce_status), "Keys/CSR generation error"); 00458 00459 // Call the EST client 00460 00461 // If lwm2m device certificate - set cert name to NULL and request EST enrollment 00462 if (pv_str_equals(g_lwm2m_name, renewal_data->cert_name,(uint32_t)(strlen(g_lwm2m_name) + 1))) { 00463 SA_PV_LOG_INFO("Attempting to renew LwM2M device certificate\n"); 00464 cert_name = NULL; 00465 cert_name_size = 0; 00466 } else { 00467 SA_PV_LOG_INFO("Attempting to renew a custom certificate\n"); 00468 cert_name = renewal_data->cert_name; 00469 cert_name_size = strlen(renewal_data->cert_name); 00470 } 00471 00472 // Request a certificate from a CSR via the EST service 00473 est_status = g_est_client->est_request_enrollment(cert_name, cert_name_size, renewal_data->csr, renewal_data->csr_size, est_cb, NULL); 00474 // FIXME: Currently commented out. If we find that the CSR must be persistent only during est_request_enrollment call - uncomment, and this should be the only place we free the CSR 00475 //free(renewal_data->csr); 00476 SA_PV_ERR_RECOVERABLE_RETURN_IF((est_status != EST_STATUS_SUCCESS), certificate_renewal_finish(renewal_data, CE_STATUS_EST_ERROR), "EST request failed"); 00477 00478 SA_PV_LOG_INFO_FUNC_EXIT_NO_ARGS(); 00479 } 00480 00481 ce_status_e CertificateEnrollmentClient::schedule_event(event_type_e event_type) 00482 { 00483 int8_t event_status; 00484 00485 arm_event_s event = { 00486 .receiver = handler_id, // ID we got when creating our handler 00487 .sender = 0, // Which tasklet sent us the event is irrelevant to us 00488 .event_type = event_type, // Indicate event type 00489 .event_id = 0, // We currently do not need an ID for a specific event - event type is enough 00490 .data_ptr = 0, // Not needed, data handled in internal structure 00491 .priority = ARM_LIB_LOW_PRIORITY_EVENT, // Application level priority 00492 .event_data = 0, // With one certificate this is irrelevant. If allow multiple certificates, This will be a certificate descriptor (index in a CertificateRenewalDataBase list) 00493 }; 00494 00495 SA_PV_LOG_INFO_FUNC_ENTER_NO_ARGS(); 00496 00497 event_status = eventOS_event_send(&event); 00498 SA_PV_ERR_RECOVERABLE_RETURN_IF((event_status < 0), CE_STATUS_OUT_OF_MEMORY, "Error scheduling event"); 00499 00500 SA_PV_LOG_INFO_FUNC_EXIT_NO_ARGS(); 00501 return CE_STATUS_SUCCESS; 00502 } 00503 00504 void CertificateEnrollmentClient::est_cb(est_enrollment_result_e result, 00505 cert_chain_context_s *cert_chain, 00506 void *context) 00507 { 00508 ce_status_e status; 00509 SA_PV_LOG_INFO_FUNC_ENTER("result = %d", result); 00510 00511 PV_UNUSED_PARAM(context); 00512 if (result != EST_ENROLLMENT_SUCCESS || cert_chain == NULL) { 00513 return certificate_renewal_finish(current_cert, CE_STATUS_EST_ERROR); 00514 } 00515 00516 // Cert chain remains persistent until g_est_client->free_cert_chain_context is called 00517 current_cert->est_data = cert_chain; 00518 00519 status = schedule_event(CertificateEnrollmentClient::EVENT_TYPE_EST_RESPONDED); 00520 if (status != CE_STATUS_SUCCESS) { // If event scheduling fails - free the chain context and finish the process 00521 SA_PV_LOG_INFO("Error scheduling event"); 00522 g_est_client->free_cert_chain_context(current_cert->est_data); 00523 00524 // Make sure we do not keep an invalid pointer 00525 current_cert->est_data = NULL; 00526 certificate_renewal_finish(current_cert, status); 00527 } 00528 00529 SA_PV_LOG_INFO_FUNC_EXIT_NO_ARGS(); 00530 } 00531 00532 void CertificateEnrollmentClient::est_response_process(CertificateRenewalDataBase *renewal_data) 00533 { 00534 ce_status_e ce_status; 00535 ce_renewal_params_s params; 00536 SA_PV_LOG_INFO_FUNC_ENTER_NO_ARGS(); 00537 00538 // Fill params 00539 params.cert_data = renewal_data->est_data; 00540 params.crypto_handle = renewal_data->key_handle; 00541 00542 // Perform a safe renewal 00543 ce_status = ce_safe_renewal(renewal_data->cert_name, ¶ms); 00544 00545 // Free the est chain. Do not free in the destructor, we'd rather free it as soon as possible 00546 g_est_client->free_cert_chain_context(renewal_data->est_data); 00547 renewal_data->est_data = NULL; 00548 00549 // Done! 00550 certificate_renewal_finish(renewal_data, ce_status); 00551 SA_PV_LOG_INFO_FUNC_EXIT_NO_ARGS(); 00552 } 00553 00554 void CertificateEnrollmentClient::certificate_renewal_finish(CertificateRenewalDataBase *renewal_data, ce_status_e exit_status) 00555 { 00556 palStatus_t pal_status; 00557 SA_PV_LOG_INFO_FUNC_ENTER("exit_status = %d", exit_status); 00558 00559 // Don't leave an invalid global pointer 00560 current_cert = NULL; 00561 00562 // Note: release of the mutex is before the deletion of the object (which holds the allocated cert_name) 00563 // and before the user callback is invoked (so that the user may call the renewal API successfully from within his callback) 00564 pal_status = pal_osSemaphoreRelease(g_renewal_sem); 00565 if (PAL_SUCCESS != pal_status) { // 00566 exit_status = CE_STATUS_ERROR; 00567 } 00568 00569 // At this point, new device requests may be made and the global pointer CertificateEnrollmentClient::current_cert may be changed. 00570 // Therefore, we use the renewal_data pointer that was past as a parameter to this function 00571 // New server requests will not be made until after this function returns since the response to the server is enqueued into the event loop by renewal_data->finish() 00572 // and it is guaranteed that the server will not send another request until it receives a response. 00573 renewal_data->finish(exit_status); 00574 00575 delete renewal_data; 00576 00577 SA_PV_LOG_INFO_FUNC_EXIT_NO_ARGS(); 00578 } 00579 00580 #ifdef CERT_RENEWAL_TEST 00581 void CertificateEnrollmentClient::testonly_certificate_renewal_post(void *arg) 00582 { 00583 return certificate_renewal_post(arg); 00584 } 00585 00586 00587 #endif // CERT_RENEWAL_TEST
Generated on Tue Jul 12 2022 20:20:58 by
