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.
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 Mon Aug 29 2022 19:53:38 by
