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
fcc_bundle_csr_utils.c
00001 // ---------------------------------------------------------------------------- 00002 // Copyright 2016-2017 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 #include "fcc_bundle_utils.h" 00017 #include "fcc_bundle_handler.h" 00018 #include "fcc_malloc.h" 00019 #include "pv_error_handling.h" 00020 #include "fcc_utils.h" 00021 #include "storage.h" 00022 #include "fcc_bundle_fields.h" 00023 #include "fcc_time_profiling.h" 00024 00025 00026 // For convenience when migrating to tinycbor 00027 #define CN_CBOR_NEXT_GET(cn) cn->next 00028 00029 // Initial attempt to allocate buffer for generated CSR will be <size (in bytes) of the encoded CSR request map (part of the CBOR)> + CSR_INITIAL_EXTRA_ALLOCATION_BYTES. 00030 // If the allocation is not enough we keep allocating an extra CSR_ALLOCATION_STEP until the buffer is sufficiently large, or, the allocation fails. 00031 #define CSR_INITIAL_EXTRA_ALLOCATION_BYTES 100 00032 #define CSR_ALLOCATION_STEP 100 00033 00034 00035 // FIXME: Temporary. This is a workaround so that the memory is still allocated when calling cn_cbor_encoder_write(). 00036 // When we migrate to tinycbor we could either write the CSR directly into the preallocated encoder buffer, or write to a separate buffer, then write to the encoder, then immediately free the separate buffer. 00037 uint8_t *g_csr_buf[CSR_MAX_NUMBER_OF_CSRS] = { 0 }; 00038 00039 void g_csr_buf_free() 00040 { 00041 int i; 00042 00043 for (i = 0; i < CSR_MAX_NUMBER_OF_CSRS; i++) { 00044 fcc_free(g_csr_buf[i]); 00045 g_csr_buf[i] = NULL; 00046 } 00047 } 00048 00049 static uint8_t **g_csr_next_available() 00050 { 00051 int i; 00052 00053 for (i = 0; i < CSR_MAX_NUMBER_OF_CSRS; i++) { 00054 if (!g_csr_buf[i]) { 00055 return &g_csr_buf[i]; 00056 } 00057 } 00058 00059 return NULL; 00060 } 00061 00062 00063 static fcc_status_e csr_extensions_parse(const cn_cbor *parser, kcm_csr_params_s *csr_params_out) 00064 { 00065 cn_cbor *cbor_iterator, *cbor_extension_map; 00066 00067 // Get the extensions from the map - a map (optional, return success if does not exist) 00068 cbor_extension_map = cn_cbor_mapget_string(parser, FCC_CSRREQ_INBOUND_EXTENSIONS_NAME); 00069 if (!cbor_extension_map) { 00070 return FCC_STATUS_SUCCESS; 00071 } 00072 00073 SA_PV_ERR_RECOVERABLE_RETURN_IF((cbor_extension_map->type != CN_CBOR_MAP), FCC_STATUS_BUNDLE_ERROR, "Extensions wrong format"); 00074 00075 // FIXME: Should parse the trust level from the extensions. Currently not in use 00076 00077 // Parse key usage (optional) 00078 cbor_iterator = cn_cbor_mapget_string(cbor_extension_map, FCC_CSRREQ_INBOUND_EXTENSION_KEYUSAGE_NAME); 00079 if (cbor_iterator) { 00080 SA_PV_ERR_RECOVERABLE_RETURN_IF((cbor_iterator->type != CN_CBOR_UINT), FCC_STATUS_BUNDLE_ERROR, "Key usage wrong format"); 00081 csr_params_out->key_usage = (uint32_t)cbor_iterator->v.uint; 00082 } 00083 00084 // Parse extended key usage (optional) 00085 cbor_iterator = cn_cbor_mapget_string(cbor_extension_map, FCC_CSRREQ_INBOUND_EXTENSION_EXTENDEDKEYUSAGE_NAME); 00086 if (cbor_iterator) { 00087 SA_PV_ERR_RECOVERABLE_RETURN_IF((cbor_iterator->type != CN_CBOR_UINT), FCC_STATUS_BUNDLE_ERROR, "Extended Key usage wrong format"); 00088 csr_params_out->ext_key_usage = (uint32_t)cbor_iterator->v.uint; 00089 } 00090 00091 return FCC_STATUS_SUCCESS; 00092 } 00093 /* 00094 * parser - points to a CSR request map 00095 */ 00096 static fcc_status_e csr_params_parse(const cn_cbor *parser, kcm_csr_params_s *csr_params_out) 00097 { 00098 cn_cbor *cbor_iterator; 00099 fcc_status_e fcc_status; 00100 00101 // Parse the extension (optional - will return success if extensions do not exist) 00102 fcc_status = csr_extensions_parse(parser, csr_params_out); 00103 SA_PV_ERR_RECOVERABLE_RETURN_IF((fcc_status != FCC_STATUS_SUCCESS), fcc_status, "Error parsing CSR extensions"); 00104 00105 // Retrieve the MD type 00106 cbor_iterator = cn_cbor_mapget_string(parser, FCC_CSRREQ_INBOUND_MESSAGEDIGEST_NAME); 00107 SA_PV_ERR_RECOVERABLE_RETURN_IF((cbor_iterator == NULL), FCC_STATUS_BUNDLE_ERROR, "No MD type"); 00108 SA_PV_ERR_RECOVERABLE_RETURN_IF((cbor_iterator->type != CN_CBOR_UINT), FCC_STATUS_BUNDLE_ERROR, "MD type wrong format"); 00109 00110 csr_params_out->md_type = (kcm_md_type_e)cbor_iterator->v.uint; 00111 00112 // Retrieve the subject 00113 cbor_iterator = cn_cbor_mapget_string(parser, FCC_CSRREQ_INBOUND_SUBJECT_NAME); 00114 SA_PV_ERR_RECOVERABLE_RETURN_IF((cbor_iterator == NULL), FCC_STATUS_BUNDLE_ERROR, "No subject"); 00115 SA_PV_ERR_RECOVERABLE_RETURN_IF((cbor_iterator->type != CN_CBOR_BYTES && cbor_iterator->type != CN_CBOR_TEXT), FCC_STATUS_BUNDLE_ERROR, "Subject wrong format"); 00116 00117 // Allocate memory for the subject, it may be large and must be terminated with a '\0' terminator 00118 csr_params_out->subject = fcc_malloc((size_t)cbor_iterator->length + 1); 00119 SA_PV_ERR_RECOVERABLE_RETURN_IF((csr_params_out->subject == NULL), FCC_STATUS_MEMORY_OUT, "Error allocating subject"); 00120 00121 memcpy(csr_params_out->subject, cbor_iterator->v.bytes, (size_t)cbor_iterator->length); 00122 00123 // Append the NULL terminator 00124 csr_params_out->subject[cbor_iterator->length] = '\0'; 00125 00126 return FCC_STATUS_SUCCESS; 00127 } 00128 00129 /** Parse, create, and encode the next CSR map into the CSR cbor array in the response CBOR 00130 * The outcome of this function is that the following map will be appended to the encoder: {"PrKN: "<name>", "Data": <CSR byte array>} 00131 * @param parser CSRrequest map: 00132 * INBOUND MESSAGE: 00133 * { 00134 * ... 00135 * 00136 * "CsrReqs" : [ { ... }, { ... }, ... , <YOU ARE HERE> ] 00137 * 00138 * ... 00139 * } 00140 * 00141 * @param encoder - points to the next place in the CSR CBOR array: 00142 * OUTBOUND MESSAGE: 00143 * { 00144 * ... 00145 * 00146 * "Csrs" : [ { ... }, { ... }, ... , <YOU ARE HERE> ] 00147 * 00148 * ... 00149 * } 00150 * 00151 * 00152 */ 00153 static fcc_status_e encode_next_csr(const cn_cbor *parser, cn_cbor *encoder) 00154 { 00155 kcm_csr_params_s csr_params; 00156 fcc_status_e fcc_status = FCC_STATUS_SUCCESS; 00157 fcc_status_e output_info_fcc_status = FCC_STATUS_SUCCESS; 00158 kcm_status_e kcm_status = KCM_STATUS_SUCCESS; 00159 bool status; 00160 size_t csr_extra_bytes = CSR_INITIAL_EXTRA_ALLOCATION_BYTES; 00161 size_t csr_buf_len; 00162 const uint8_t *private_key_name, *public_key_name; 00163 size_t private_key_name_len, public_key_name_len; 00164 int approximated_csr_size = 0; 00165 uint8_t **csr_buf; 00166 size_t csr_len = 0; 00167 00168 char *key; 00169 cn_cbor *val, *cbor, *encoder_iterator; 00170 00171 memset(&csr_params, 0, sizeof(kcm_csr_params_s)); 00172 00173 // First, Create and open a new map for the encoder, that will eventually look like that {"PrKN: "<name>", "Data": <CSR byte array>} 00174 encoder_iterator = cn_cbor_map_create(CBOR_CONTEXT_PARAM_COMMA NULL); 00175 SA_PV_ERR_RECOVERABLE_RETURN_IF((encoder_iterator == NULL), FCC_STATUS_MEMORY_OUT, "Error creating CBOR"); 00176 00177 // Push the empty map into the encoder (open the container part 2) 00178 status = cn_cbor_array_append(encoder, encoder_iterator, NULL); 00179 SA_PV_ERR_RECOVERABLE_RETURN_IF((status == false), FCC_STATUS_BUNDLE_ERROR, "CBOR error"); 00180 00181 // Get private key name 00182 cbor = cn_cbor_mapget_string(parser, FCC_CSRREQ_INBOUND_PRIVATE_KEY_NAME); 00183 SA_PV_ERR_RECOVERABLE_RETURN_IF((cbor == NULL), FCC_STATUS_BUNDLE_ERROR, "No private key in message"); 00184 SA_PV_ERR_RECOVERABLE_RETURN_IF((cbor->type != CN_CBOR_TEXT), FCC_STATUS_BUNDLE_ERROR, "No private key in message"); 00185 00186 private_key_name = cbor->v.bytes; 00187 private_key_name_len = (size_t)cbor->length; 00188 00189 // Append Name key-value into the encoder 00190 val = cn_cbor_text_create(private_key_name, (int)private_key_name_len, CBOR_CONTEXT_PARAM_COMMA NULL); 00191 SA_PV_ERR_RECOVERABLE_RETURN_IF((val == NULL), FCC_STATUS_MEMORY_OUT, "Error creating CBOR"); 00192 status = cn_cbor_mapput_string(encoder_iterator, FCC_CSR_OUTBOUND_MAP_PRIVATE_KEY_NAME, val, CBOR_CONTEXT_PARAM_COMMA NULL); 00193 SA_PV_ERR_RECOVERABLE_RETURN_IF((status == false), FCC_STATUS_BUNDLE_ERROR, "CBOR error"); 00194 00195 // Get public key name. Field is optional, if does not exist - set to NULL 00196 cbor = cn_cbor_mapget_string(parser, FCC_CSRREQ_INBOUND_PUBLIC_KEY_NAME); 00197 if (cbor == NULL) { 00198 public_key_name = NULL; 00199 public_key_name_len = 0; 00200 } else { 00201 public_key_name = cbor->v.bytes; 00202 public_key_name_len = (size_t)cbor->length; 00203 } 00204 00205 // Extract CSR params 00206 fcc_status = csr_params_parse(parser, &csr_params); 00207 SA_PV_ERR_RECOVERABLE_GOTO_IF((fcc_status != FCC_STATUS_SUCCESS), fcc_status = fcc_status, Exit, "Error parsing CSR params"); 00208 00209 // Gets the size in bytes of the encoded CSR request map 00210 approximated_csr_size = cn_cbor_get_encoded_container_size(parser); 00211 SA_PV_ERR_RECOVERABLE_GOTO_IF((approximated_csr_size < 0), fcc_status = FCC_STATUS_BUNDLE_ERROR, Exit, "Error getting encoded CBOR size"); 00212 00213 approximated_csr_size += KCM_EC_SECP256R1_MAX_PUB_KEY_DER_SIZE + KCM_ECDSA_SECP256R1_MAX_SIGNATURE_SIZE_IN_BYTES; 00214 00215 csr_buf = g_csr_next_available(); 00216 00217 // Start with an approximate allocation and keep trying to increase the allocation until it is sufficiently large, or some error occurres. 00218 while (true) { 00219 csr_buf_len = (size_t)approximated_csr_size + csr_extra_bytes; 00220 *csr_buf = fcc_malloc(csr_buf_len); 00221 SA_PV_ERR_RECOVERABLE_GOTO_IF((*csr_buf == NULL), fcc_status = FCC_STATUS_MEMORY_OUT, Exit, "Error generating CSR"); 00222 00223 FCC_SET_START_TIMER(fcc_generate_csr_timer); 00224 00225 // Generate the CSR into the encoder 00226 // FIXME: when migrating to tinycbor we might want to try to encode it directly into the encoder buffer. This may require manually creating the cbor byte-array prefix (major type 3) 00227 // Requires understanding the CBOR mechanism but could save significant space since this way the CSR will not be duplicated. 00228 kcm_status = kcm_generate_keys_and_csr(KCM_SCHEME_EC_SECP256R1, private_key_name, private_key_name_len, 00229 public_key_name, public_key_name_len, true, &csr_params, 00230 *csr_buf, csr_buf_len, &csr_len, 00231 NULL); 00232 00233 FCC_END_TIMER(private_key_name, private_key_name_len, fcc_generate_csr_timer); 00234 00235 if (kcm_status == KCM_STATUS_SUCCESS) { 00236 break; 00237 } else if (kcm_status == KCM_STATUS_INSUFFICIENT_BUFFER) { // If buffer insufficient - attempt with larger buffer 00238 csr_extra_bytes += CSR_ALLOCATION_STEP; 00239 } else { 00240 fcc_status = fcc_convert_kcm_to_fcc_status(kcm_status); 00241 goto Exit; 00242 } 00243 } 00244 00245 // Append the encoded CSR data key-value to the CSR response map 00246 key = FCC_CSR_OUTBOUND_MAP_DATA; 00247 val = cn_cbor_data_create(*csr_buf, (int)csr_len, CBOR_CONTEXT_PARAM_COMMA NULL); 00248 SA_PV_ERR_RECOVERABLE_GOTO_IF((val == NULL), fcc_status = FCC_STATUS_MEMORY_OUT, Exit, "Error creating CBOR"); 00249 00250 status = cn_cbor_mapput_string(encoder_iterator, key, val, CBOR_CONTEXT_PARAM_COMMA NULL); 00251 SA_PV_ERR_RECOVERABLE_GOTO_IF((status == false), fcc_status = FCC_STATUS_BUNDLE_ERROR, Exit, "CBOR error"); 00252 00253 // FIXME: For tinycbor - this would be the time to close the map opened in the beginning - {"Name: "<name>", "Format": "der", "Data": <CSR byte array>} 00254 00255 Exit: 00256 fcc_free(csr_params.subject); 00257 // If KCM error - store the KCM error, If FCC error, store the FCC error 00258 if (kcm_status != KCM_STATUS_SUCCESS) { 00259 output_info_fcc_status = fcc_bundle_store_error_info(private_key_name, private_key_name_len, kcm_status); 00260 SA_PV_ERR_RECOVERABLE_RETURN_IF((output_info_fcc_status != FCC_STATUS_SUCCESS), 00261 fcc_status = FCC_STATUS_OUTPUT_INFO_ERROR, 00262 "Failed to create output kcm_status error %d", kcm_status); 00263 } 00264 00265 00266 return fcc_status; 00267 } 00268 00269 /** Parse a CBOR array of CSR requests, for each CSR request - generate the keys and the CSR, save the keys in the persistent storage, and encode the CSR in the response encoder. 00270 * @param csrs_list_cb CSR Requests array: 00271 * INBOUND MESSAGE: 00272 * { 00273 * ... 00274 * 00275 * "CsrReqs" : <YOU ARE HERE> 00276 * 00277 * ... 00278 * } 00279 * 00280 * @param response_encoder - points to the next place in the CSR CBOR array: 00281 * OUTBOUND MESSAGE: 00282 * { 00283 * "SchemeVersion": "0.0.1", 00284 * ... 00285 * 00286 * <YOU ARE HERE> 00287 * 00288 * ... 00289 * } 00290 * 00291 * 00292 */ 00293 fcc_status_e fcc_bundle_process_csrs(const cn_cbor *csrs_list_cb, cn_cbor *response_encoder) 00294 { 00295 fcc_status_e fcc_status = FCC_STATUS_SUCCESS; 00296 fcc_status_e output_info_fcc_status = FCC_STATUS_SUCCESS; 00297 cn_cbor *cbor, *encoder_iterator; 00298 const cn_cbor *parser_iterator; 00299 bool status; 00300 int i = 0; 00301 00302 SA_PV_ERR_RECOVERABLE_GOTO_IF((csrs_list_cb == NULL || response_encoder == NULL), fcc_status = FCC_STATUS_BUNDLE_ERROR, SetError, "Invalid cbor_blob"); 00303 00304 // Make sure we get a array of CSR requests 00305 SA_PV_ERR_RECOVERABLE_GOTO_IF((csrs_list_cb->type != CN_CBOR_ARRAY), fcc_status = FCC_STATUS_BUNDLE_ERROR, SetError, "CSR requests must be array"); 00306 SA_PV_ERR_RECOVERABLE_GOTO_IF((csrs_list_cb->length > CSR_MAX_NUMBER_OF_CSRS), fcc_status = FCC_STATUS_TOO_MANY_CSR_REQUESTS, SetError, "More CSR requests than the maximum allowed"); 00307 00308 parser_iterator = csrs_list_cb; 00309 00310 // Open a new map for the encoder (open the container part 1) 00311 cbor = cn_cbor_array_create(CBOR_CONTEXT_PARAM_COMMA NULL); 00312 SA_PV_ERR_RECOVERABLE_GOTO_IF((cbor == NULL), fcc_status = FCC_STATUS_MEMORY_OUT, SetError, "Error creating CBOR"); 00313 00314 // Push the empty array into the encoder (open the container part 2) 00315 status = cn_cbor_mapput_string(response_encoder, FCC_CSR_OUTBOUND_GROUP_NAME, cbor, CBOR_CONTEXT_PARAM_COMMA NULL); 00316 SA_PV_ERR_RECOVERABLE_GOTO_IF((status == false), fcc_status = FCC_STATUS_BUNDLE_ERROR, SetError, "Error appending"); 00317 00318 // Step into the encoder array (the last child is the value of the last appended KV pair which is the empty array) 00319 encoder_iterator = response_encoder->last_child; 00320 00321 // Go to the first value of the array 00322 parser_iterator = parser_iterator->first_child; 00323 00324 for (i = 0; i < csrs_list_cb->length; i++) { 00325 00326 SA_PV_ERR_RECOVERABLE_GOTO_IF((parser_iterator == NULL), fcc_status = FCC_STATUS_BUNDLE_ERROR, SetError, "Error getting CBOR"); 00327 00328 fcc_status = encode_next_csr(parser_iterator, encoder_iterator); 00329 SA_PV_ERR_RECOVERABLE_GOTO_IF((fcc_status != FCC_STATUS_SUCCESS), fcc_status = fcc_status, SetError, "Error encoding CSR"); 00330 00331 // step into next value in the CBOR array 00332 parser_iterator = CN_CBOR_NEXT_GET(parser_iterator); 00333 } 00334 00335 SetError: 00336 if (fcc_status != FCC_STATUS_SUCCESS) { 00337 output_info_fcc_status = fcc_store_error_info(NULL, 0, fcc_status); 00338 SA_PV_ERR_RECOVERABLE_RETURN_IF((output_info_fcc_status != FCC_STATUS_SUCCESS), 00339 fcc_status = FCC_STATUS_OUTPUT_INFO_ERROR, 00340 "Failed to create output fcc_status error %d", fcc_status); 00341 } 00342 00343 return fcc_status; 00344 }
Generated on Tue Jul 12 2022 20:20:59 by
