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.
certificate_enrollment.c
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 #include <stdio.h> 00018 #include <stdbool.h> 00019 #include "pv_error_handling.h" 00020 #include "certificate_enrollment.h" 00021 #include "key_config_manager.h" 00022 #include "pv_macros.h" 00023 #include "fcc_defs.h" 00024 #include "ce_internal.h" 00025 #include "storage.h" 00026 00027 extern const char g_renewal_status_file[]; 00028 00029 ce_status_e ce_init(void) 00030 { 00031 return kcm_init() == KCM_STATUS_SUCCESS ? CE_STATUS_SUCCESS : CE_STATUS_ERROR; 00032 } 00033 00034 00035 ce_status_e ce_error_handler(kcm_status_e kcm_status) 00036 { 00037 switch (kcm_status) { 00038 case KCM_STATUS_SUCCESS: 00039 return CE_STATUS_SUCCESS; 00040 case KCM_STATUS_INVALID_PARAMETER: 00041 return CE_STATUS_INVALID_PARAMETER; 00042 case KCM_STATUS_OUT_OF_MEMORY: 00043 return CE_STATUS_OUT_OF_MEMORY; 00044 case KCM_STATUS_INSUFFICIENT_BUFFER: 00045 return CE_STATUS_INSUFFICIENT_BUFFER; 00046 case KCM_STATUS_ITEM_NOT_FOUND: 00047 return CE_STATUS_ITEM_NOT_FOUND; 00048 case KCM_STATUS_ITEM_IS_EMPTY: 00049 return CE_STATUS_ITEM_IS_EMPTY; 00050 default: 00051 return CE_STATUS_ERROR; 00052 } 00053 } 00054 00055 ce_status_e ce_generate_keys_and_create_csr_from_certificate( 00056 const char *certificate_name, const cs_key_handle_t key_h, 00057 uint8_t **csr_out, size_t *csr_size_out) 00058 { 00059 bool success; 00060 ce_status_e ce_status = CE_STATUS_SUCCESS; 00061 kcm_status_e kcm_status = KCM_STATUS_SUCCESS; 00062 uint8_t *certificate_buff = NULL; 00063 size_t certificate_buff_max_size = 0, certificate_buff_size = 0, certificate_private_key_size = 0; 00064 uint8_t *csr_buff = NULL; 00065 size_t csr_buff_size = 0, csr_buff_max_size; 00066 char *kcm_crt_name = NULL, *kcm_priv_key_name = NULL; 00067 uint32_t kcm_crt_name_size = (uint32_t)strlen(certificate_name) + 1; // append null termination 00068 00069 00070 SA_PV_ERR_RECOVERABLE_RETURN_IF((certificate_name == NULL), CE_STATUS_INVALID_PARAMETER, "Invalid certificate_name"); 00071 SA_PV_ERR_RECOVERABLE_RETURN_IF((key_h == 0), CE_STATUS_INVALID_PARAMETER, "Invalid key_h"); 00072 SA_PV_LOG_INFO_FUNC_ENTER("certificate_name = %s key_h = %" PRIuPTR "", certificate_name, key_h); 00073 SA_PV_ERR_RECOVERABLE_RETURN_IF((csr_out == NULL), CE_STATUS_INVALID_PARAMETER, "Invalid csr_out"); 00074 SA_PV_ERR_RECOVERABLE_RETURN_IF((csr_size_out == NULL), CE_STATUS_INVALID_PARAMETER, "Invalid csr_size_out"); 00075 00076 // assert NOT a bootstrap device certificate 00077 success = pv_str_equals(g_fcc_bootstrap_device_certificate_name, certificate_name, kcm_crt_name_size); 00078 SA_PV_ERR_RECOVERABLE_RETURN_IF((success), CE_STATUS_FORBIDDEN_REQUEST, "device bootstrap certificate renewal is not allowed"); 00079 00080 // assert NOT a bootstrap device key 00081 success = pv_str_equals(g_fcc_bootstrap_device_private_key_name, certificate_name, kcm_crt_name_size); 00082 SA_PV_ERR_RECOVERABLE_RETURN_IF((success), CE_STATUS_FORBIDDEN_REQUEST, "device bootstrap certificate renewal is not allowed"); 00083 00084 success = ce_set_item_names(certificate_name, &kcm_priv_key_name, NULL, &kcm_crt_name); 00085 SA_PV_ERR_RECOVERABLE_RETURN_IF((!success), CE_STATUS_ITEM_NOT_FOUND, "failed for ce_set_item_names()"); 00086 00087 // getting the private key size successfully signifies that the certificate's private key exist and we're okay to continue 00088 kcm_status = kcm_item_get_data_size((const uint8_t *)kcm_priv_key_name, strlen(kcm_priv_key_name), KCM_PRIVATE_KEY_ITEM, &certificate_private_key_size); 00089 SA_PV_ERR_RECOVERABLE_RETURN_IF((kcm_status != KCM_STATUS_SUCCESS), ce_error_handler(kcm_status), "failed to get the certificate private key length"); 00090 SA_PV_ERR_RECOVERABLE_RETURN_IF((certificate_private_key_size == 0), CE_STATUS_ITEM_IS_EMPTY, "got empty private key for certificate %s", kcm_crt_name); 00091 00092 // get the certificate octet length 00093 kcm_status = kcm_item_get_data_size((const uint8_t *)kcm_crt_name, strlen(kcm_crt_name), KCM_CERTIFICATE_ITEM, &certificate_buff_max_size); 00094 SA_PV_ERR_RECOVERABLE_RETURN_IF((kcm_status != KCM_STATUS_SUCCESS), CE_STATUS_ERROR, "failed to get certificate octet length"); 00095 SA_PV_ERR_RECOVERABLE_RETURN_IF((certificate_buff_max_size == 0), CE_STATUS_ITEM_IS_EMPTY, "got 0 length for certificate"); 00096 00097 certificate_buff = (uint8_t *)malloc(certificate_buff_max_size); 00098 SA_PV_ERR_RECOVERABLE_RETURN_IF((certificate_buff == NULL), CE_STATUS_OUT_OF_MEMORY, "failed allocating certificate buffer"); 00099 00100 // get the certificate bytes 00101 kcm_status = kcm_item_get_data((const uint8_t *)kcm_crt_name, strlen(kcm_crt_name), KCM_CERTIFICATE_ITEM, certificate_buff, certificate_buff_max_size, &certificate_buff_size); 00102 SA_PV_ERR_RECOVERABLE_GOTO_IF((kcm_status != KCM_STATUS_SUCCESS), (ce_status = ce_error_handler(kcm_status)), exit, "failed to get certificate buffer"); 00103 SA_PV_ERR_RECOVERABLE_GOTO_IF((certificate_buff_size == 0), (ce_status = CE_STATUS_ITEM_IS_EMPTY), exit, "got 0 length for certificate"); 00104 00105 // we assume that the CSR size would not exceed the certificate size 00106 csr_buff_max_size = certificate_buff_size; 00107 00108 csr_buff = (uint8_t *)malloc(csr_buff_max_size); 00109 SA_PV_ERR_RECOVERABLE_GOTO_IF((csr_buff == NULL), (ce_status = CE_STATUS_OUT_OF_MEMORY), exit, "Failed allocating CSR buffer"); 00110 00111 kcm_status = cs_generate_keys_and_create_csr_from_certificate(certificate_buff, certificate_buff_size, key_h, csr_buff, csr_buff_max_size, &csr_buff_size); 00112 SA_PV_ERR_RECOVERABLE_GOTO_IF((kcm_status != KCM_STATUS_SUCCESS), (ce_status = ce_error_handler(kcm_status)), exit, "failed to generate keys and create CSR"); 00113 SA_PV_ERR_RECOVERABLE_GOTO_IF((csr_buff == NULL), (ce_status = CE_STATUS_ERROR), exit, "failed creating CSR or generating keys for certificate (%s)", kcm_crt_name); 00114 00115 00116 // the calling user is responsible to free csr_out buffer 00117 *csr_out = csr_buff; 00118 *csr_size_out = csr_buff_size; 00119 00120 SA_PV_LOG_INFO_FUNC_EXIT("csr_size_out = %" PRIu32 "", (uint32_t)(*csr_size_out)); 00121 00122 exit: 00123 if (certificate_buff != NULL) { 00124 free(certificate_buff); 00125 } 00126 if (ce_status != CE_STATUS_SUCCESS) { 00127 free(csr_buff); 00128 } 00129 00130 return ce_status; 00131 } 00132 ce_status_e ce_safe_renewal(const char *item_name, ce_renewal_params_s *renewal_data) 00133 { 00134 bool success; 00135 ce_status_e ce_status = CE_STATUS_SUCCESS; 00136 kcm_status_e kcm_status = KCM_STATUS_SUCCESS; 00137 char *priv_key_name = NULL, *pub_key_name = NULL, *certificate_name = NULL; 00138 size_t data_size_out; 00139 bool is_public_key = false; 00140 cs_ec_key_context_s *ec_key_ctx = NULL; 00141 struct cert_chain_context_s *certificate_chain_data = NULL; 00142 00143 //Check parameters 00144 SA_PV_ERR_RECOVERABLE_RETURN_IF((item_name == NULL), CE_STATUS_INVALID_PARAMETER, "Invalid item_name"); 00145 SA_PV_ERR_RECOVERABLE_RETURN_IF((renewal_data == NULL), CE_STATUS_INVALID_PARAMETER, "Invalid renewal_data"); 00146 SA_PV_ERR_RECOVERABLE_RETURN_IF((renewal_data->crypto_handle ==(cs_key_handle_t) NULL), CE_STATUS_INVALID_PARAMETER, "Invalid crypto handle"); 00147 SA_PV_ERR_RECOVERABLE_RETURN_IF((renewal_data->cert_data == NULL), CE_STATUS_INVALID_PARAMETER, "Invalid cert_data"); 00148 certificate_chain_data = (struct cert_chain_context_s*)renewal_data->cert_data; 00149 SA_PV_ERR_RECOVERABLE_RETURN_IF((certificate_chain_data->certs == NULL || certificate_chain_data->chain_length == 0), CE_STATUS_INVALID_PARAMETER, "Invalid certificate data"); 00150 SA_PV_LOG_INFO_FUNC_ENTER("item_name = %s ", item_name); 00151 00152 //Set item names 00153 success = ce_set_item_names(item_name, &priv_key_name, &pub_key_name, &certificate_name); 00154 SA_PV_ERR_RECOVERABLE_RETURN_IF((!success), CE_STATUS_ITEM_NOT_FOUND, "failed for ce_set_item_names()"); 00155 00156 if (pub_key_name != NULL) { //If not lwm2m items 00157 //Check if public key is present 00158 kcm_status = kcm_item_get_data_size((const uint8_t *)pub_key_name, strlen(pub_key_name), KCM_PUBLIC_KEY_ITEM, &data_size_out); 00159 SA_PV_ERR_RECOVERABLE_RETURN_IF((kcm_status != KCM_STATUS_SUCCESS && kcm_status != KCM_STATUS_ITEM_NOT_FOUND), CE_STATUS_STORAGE_ERROR, "failed to get public key size"); 00160 00161 //Set public key flag 00162 if (kcm_status == KCM_STATUS_SUCCESS) { 00163 is_public_key = true; 00164 } 00165 } 00166 00167 //Verify items correlation 00168 kcm_status = cs_verify_items_correlation(renewal_data->crypto_handle, renewal_data->cert_data->certs->cert, renewal_data->cert_data->certs->cert_length); 00169 SA_PV_ERR_RECOVERABLE_RETURN_IF((kcm_status != KCM_STATUS_SUCCESS), CE_STATUS_RENEWAL_ITEM_VALIDATION_ERROR, "failed to validate renewal items"); 00170 00171 //Create backup items 00172 kcm_status = ce_create_backup_items(item_name, is_public_key); 00173 if (kcm_status == KCM_STATUS_ITEM_NOT_FOUND) { 00174 ce_status = CE_STATUS_ORIGINAL_ITEM_ERROR; 00175 } 00176 if (kcm_status != KCM_STATUS_SUCCESS && kcm_status != KCM_STATUS_ITEM_NOT_FOUND) { 00177 ce_status = CE_STATUS_BACKUP_ITEM_ERROR; 00178 } 00179 SA_PV_ERR_RECOVERABLE_GOTO_IF((ce_status != CE_STATUS_SUCCESS), ce_status = ce_status, exit_and_delete_renewal_data,"failed to create backup items"); 00180 00181 //Create renewal status file and write item_name to the file 00182 kcm_status = ce_create_renewal_status(item_name); 00183 if (kcm_status == KCM_STATUS_FILE_EXIST) { 00184 //Assumption : in case of existing active renewal process ->ce_safe_renewal api blocked by event loop. 00185 // So we assume that it is ok to delete renewal status file, as it is impossible that it used by another active renewal process. 00186 //try to delete existing renewal status file and create new one 00187 ce_delete_renewal_status(); 00188 kcm_status = ce_create_renewal_status(item_name); 00189 } 00190 SA_PV_ERR_RECOVERABLE_GOTO_IF((kcm_status != KCM_STATUS_SUCCESS), ce_status = CE_STATUS_RENEWAL_STATUS_ERROR, exit_and_delete_renewal_data, "failed to create renewal status file"); 00191 00192 //Clean original items 00193 kcm_status = ce_clean_items(item_name, KCM_ORIGINAL_ITEM, is_public_key ); 00194 SA_PV_ERR_RECOVERABLE_GOTO_IF((kcm_status != KCM_STATUS_SUCCESS), ce_status = CE_STATUS_STORAGE_ERROR, restore_backup_data, "Falid to clean original items"); 00195 00196 ec_key_ctx = (cs_ec_key_context_s*)renewal_data->crypto_handle; 00197 00198 //Save new items 00199 kcm_status = kcm_item_store((const uint8_t*)priv_key_name, strlen(priv_key_name), KCM_PRIVATE_KEY_ITEM, false, ec_key_ctx->priv_key, ec_key_ctx->priv_key_size, NULL); 00200 SA_PV_ERR_RECOVERABLE_GOTO_IF((kcm_status != KCM_STATUS_SUCCESS), ce_status = CE_STATUS_STORAGE_ERROR, restore_backup_data, "Falid to store new private key"); 00201 00202 if (is_public_key == true) { 00203 kcm_status = kcm_item_store((const uint8_t*)pub_key_name, strlen(pub_key_name), KCM_PUBLIC_KEY_ITEM, false, ec_key_ctx->pub_key, ec_key_ctx->pub_key_size, NULL); 00204 SA_PV_ERR_RECOVERABLE_GOTO_IF((kcm_status != KCM_STATUS_SUCCESS), ce_status = CE_STATUS_STORAGE_ERROR, restore_backup_data, "Falid to store new public key"); 00205 } 00206 00207 //Save new certificate/certificate chain 00208 kcm_status = ce_store_new_certificate((const char*)certificate_name, certificate_chain_data); 00209 SA_PV_ERR_RECOVERABLE_GOTO_IF((kcm_status != KCM_STATUS_SUCCESS), ce_status = CE_STATUS_STORAGE_ERROR, restore_backup_data, "Falid to store new certificate/certificate chain"); 00210 00211 00212 restore_backup_data: 00213 if (ce_status != CE_STATUS_SUCCESS) { 00214 //the restore here done only in case of some error, and at this stage we are not still want to return an original error 00215 //this is the reason why we don't read the returned error of ce_restore_backup_items api 00216 ce_restore_backup_items(item_name); 00217 } 00218 00219 exit_and_delete_renewal_data: 00220 00221 //Delete renewal status file 00222 ce_delete_renewal_status(); 00223 00224 //Clean backup items 00225 ce_clean_items(item_name, KCM_BACKUP_ITEM, is_public_key); 00226 00227 return ce_status; 00228 } 00229 00230 /*! The API called during kcm_init() in case of error during renewal_certificate API. 00231 * The functions checks status of the renewal process, restores original data and deletes redundant files. 00232 * The APIs checks the status based on renewal file and its data. 00233 * @void 00234 */ 00235 void ce_check_and_restore_backup_status(void) 00236 { 00237 kcm_status_e kcm_status = KCM_STATUS_SUCCESS; 00238 size_t renewal_item_data_len = 0; 00239 size_t act_renewal_item_data_len = 0; 00240 uint8_t renewal_item_name[CE_MAX_SIZE_OF_KCM_ITEM_NAME] = { 0 }; 00241 00242 00243 //Get renewal status file size 00244 kcm_status = storage_data_size_read((const uint8_t *)g_renewal_status_file, strlen(g_renewal_status_file), KCM_CONFIG_ITEM, KCM_BACKUP_ITEM, &renewal_item_data_len); 00245 00246 //If renewal status file is not found or failed to get data size -> exit , no data to restore 00247 if (kcm_status != KCM_STATUS_SUCCESS) { 00248 if (kcm_status != KCM_STATUS_ITEM_NOT_FOUND) { 00249 SA_PV_LOG_ERR("Failed to read renewal status");//Add error print, as this case is exceptional 00250 } 00251 return; 00252 } 00253 if (renewal_item_data_len + 1 > sizeof(renewal_item_name)) { 00254 SA_PV_LOG_ERR("Renewal item name is too big");//Add error print, as this case is exceptional 00255 return; 00256 } 00257 00258 //Read renewal status data 00259 kcm_status = storage_data_read((const uint8_t *)g_renewal_status_file, strlen(g_renewal_status_file), KCM_CONFIG_ITEM, KCM_BACKUP_ITEM, renewal_item_name, renewal_item_data_len, &act_renewal_item_data_len); 00260 SA_PV_ERR_RECOVERABLE_GOTO_IF((kcm_status != KCM_STATUS_SUCCESS || act_renewal_item_data_len != renewal_item_data_len), kcm_status = kcm_status, exit, "Failed to read renewal status data"); 00261 00262 //Set null terminator 00263 // renewal_item_data[renewal_item_data_len] ='\0'; 00264 renewal_item_name[renewal_item_data_len] = '\0'; 00265 00266 //Restore backup items - this will clean all unnecessary data 00267 kcm_status = ce_restore_backup_items((const char *)renewal_item_name); 00268 SA_PV_ERR_RECOVERABLE_GOTO_IF((kcm_status != KCM_STATUS_SUCCESS && kcm_status!= KCM_STATUS_ITEM_NOT_FOUND), kcm_status = kcm_status, exit, "Failed to restore backup items"); 00269 00270 00271 exit: 00272 //Delete renewal status file 00273 kcm_status = storage_data_delete((const uint8_t *)g_renewal_status_file, (size_t)strlen(g_renewal_status_file), KCM_CONFIG_ITEM, KCM_BACKUP_ITEM); 00274 if (kcm_status != KCM_STATUS_SUCCESS) { 00275 SA_PV_LOG_ERR("Failed to delete renewal status");//Add error print, as this case is exceptional 00276 } 00277 00278 SA_PV_LOG_INFO_FUNC_EXIT_NO_ARGS(); 00279 return; 00280 } 00281
Generated on Mon Aug 29 2022 19:53:38 by
