leo hendrickson / Mbed OS example-Ethernet-mbed-Cloud-connect
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers arm_uc_certificate_kcm_api.c Source File

arm_uc_certificate_kcm_api.c

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 #include "update-client-common/arm_uc_crypto.h"
00020 #if defined(ARM_UC_FEATURE_CERT_STORE_KCM) && (ARM_UC_FEATURE_CERT_STORE_KCM == 1)
00021 
00022 #include "update-client-control-center/arm_uc_certificate.h"
00023 #include "update-client-common/arm_uc_config.h"
00024 #include "update-client-metadata-header/arm_uc_buffer_utilities.h"
00025 #include "key-config-manager/key_config_manager.h"
00026 
00027 static arm_uc_error_t kerr2ucerr(int kerr)
00028 {
00029     arm_uc_error_t err;
00030     switch (kerr) {
00031         case KCM_STATUS_SUCCESS:
00032             err.code = ERR_NONE;
00033             break;
00034         case KCM_STATUS_INVALID_PARAMETER:
00035             err.code = ARM_UC_CM_ERR_INVALID_PARAMETER;
00036             break;
00037         case KCM_STATUS_ITEM_NOT_FOUND:
00038         case KCM_STATUS_ESFS_ERROR:
00039             err.code = ARM_UC_CM_ERR_NOT_FOUND;
00040             break;
00041         case KCM_CRYPTO_STATUS_PARSING_DER_CERT:
00042             err.code = ARM_UC_CM_ERR_INVALID_CERT;
00043             break;
00044         case KCM_STATUS_OUT_OF_MEMORY:
00045         case KCM_STATUS_INSUFFICIENT_BUFFER:
00046         default:
00047             err.modulecc[0] = 'K';
00048             err.modulecc[1] = 'C';
00049             err.error       = kerr;
00050             break;
00051     }
00052     return err;
00053 }
00054 
00055 static arm_uc_error_t arm_uc_kcm_cert_fetcher(arm_uc_buffer_t *certificate,
00056                                               const arm_uc_buffer_t *fingerprint,
00057                                               const arm_uc_buffer_t *DERCertificateList,
00058                                               void (*callback)(arm_uc_error_t, const arm_uc_buffer_t *, const arm_uc_buffer_t *))
00059 {
00060     uint8_t certName[MBED_CLOUD_CLIENT_UPDATE_CERTIFICATE_NAME_SIZE] = MBED_CLOUD_CLIENT_UPDATE_CERTIFICATE_DEFAULT;
00061     // uint8_t certName[MBED_CLOUD_CLIENT_UPDATE_CERTIFICATE_NAME_SIZE] = MBED_CLOUD_CLIENT_UPDATE_CERTIFICATE_PREFIX;
00062     // uint8_t* b64hash = &certName[sizeof(MBED_CLOUD_CLIENT_UPDATE_CERTIFICATE_PREFIX)-1];
00063     // uint8_t defaultInUse = 0;
00064 
00065     UC_CONT_TRACE("Attempting to fetch certificate from: %s", certName);
00066     // Format the certificate name into the certName buffer
00067     // ARM_UC_Base64Enc(b64hash, sizeof(b64hash), fingerprint);
00068 
00069     // The arm_uc_buffer_t's size variable is 32bit, but kcm_item_get_data() needs
00070     // a pointer to size_t, so we need to use a temp variable for it or we would get
00071     // a corrupted arm_uc_buffer_t structure.
00072     size_t cert_data_size = 0;
00073 
00074     // Look up the certificate by fingerprint
00075     kcm_status_e  kerr = kcm_item_get_data(certName,
00076                                           strlen((char *)certName),
00077                                           KCM_CERTIFICATE_ITEM,
00078                                           certificate->ptr,
00079                                           certificate->size_max,
00080                                           &cert_data_size);
00081 
00082     // Check if the certificate was found.
00083     // if (kerr == KCM_STATUS_ITEM_NOT_FOUND || kerr == KCM_STATUS_ESFS_ERROR)
00084     // {
00085     //     printf("fingerprinted certificate not found. Checking for default...\n");
00086     //     // If not, try the default location.
00087     //     kerr = kcm_item_get_data(MBED_CLOUD_CLIENT_UPDATE_CERTIFICATE_DEFAULT,
00088     //                              sizeof(MBED_CLOUD_CLIENT_UPDATE_CERTIFICATE_DEFAULT) - 1,
00089     //                              KCM_CERTIFICATE_ITEM,
00090     //                              certificate->ptr,
00091     //                              certificate->size_max,
00092     //                              &cert_data_size);
00093     //     defaultInUse = 1;
00094     // }
00095     // Translate the KCM error to an update client error
00096     arm_uc_error_t err = kerr2ucerr(kerr);
00097     arm_uc_error_t errFinish = {ARM_UC_CM_ERR_INVALID_PARAMETER};
00098 
00099     // Prepare to calculate the fingerprint of the certificate.
00100     arm_uc_mdHandle_t h = { 0 };
00101     uint8_t fingerprintLocal[MBED_CLOUD_SHA256_BYTES];
00102     arm_uc_buffer_t fingerprintLocalBuffer = {
00103         .size_max = sizeof(fingerprintLocal),
00104         .size = 0,
00105         .ptr = fingerprintLocal
00106     };
00107 
00108     // Check for overflow before continuing. This is actually unnecessary
00109     // belts and suspenders type of code, as the max value given to kcm_item_get_data()
00110     // is at most UINT32_MAX, but the Coverity might point this as a error.
00111     if (cert_data_size <= UINT32_MAX) {
00112         certificate->size = (uint32_t)cert_data_size;
00113     } else {
00114         err.code = ARM_UC_CM_ERR_INVALID_CERT;
00115     }
00116 
00117     // Calculate the fingerprint of the certificate
00118     if (err.error == ERR_NONE) {
00119         err = ARM_UC_cryptoHashSetup(&h, ARM_UC_CU_SHA256);
00120     }
00121     if (err.error == ERR_NONE) {
00122         err = ARM_UC_cryptoHashUpdate(&h, certificate);
00123 
00124         // The cryptoHashFinish needs to be called no matter if the update succeeded or not as
00125         // it will do memory freeing. But in order to have valid result, the update & finish
00126         // must both have succeeded.
00127         errFinish = ARM_UC_cryptoHashFinish(&h, &fingerprintLocalBuffer);
00128 
00129         // Compare the calculated fingerprint to the requested fingerprint.
00130         if ((err.error == ERR_NONE) && (errFinish.error == ERR_NONE)) {
00131             uint32_t rc = ARM_UC_BinCompareCT(fingerprint, &fingerprintLocalBuffer);
00132             if (rc) {
00133                 err.code = ARM_UC_CM_ERR_NOT_FOUND;
00134             } else {
00135                 UC_CONT_TRACE("Certificate lookup fingerprint matched.");
00136                 err.code = ERR_NONE;
00137             }
00138 
00139             if (callback && (err.error == ERR_NONE)) {
00140                 callback(err, certificate, fingerprint);
00141             }
00142         }
00143     }
00144 
00145     return err;
00146 }
00147 
00148 static arm_uc_error_t arm_uc_kcm_cert_storer(
00149     const arm_uc_buffer_t *cert,
00150     const arm_uc_buffer_t *fingerprint,
00151     void(*callback)(arm_uc_error_t, const arm_uc_buffer_t *))
00152 {
00153     // uint8_t certName[MBED_CLOUD_CLIENT_UPDATE_CERTIFICATE_NAME_SIZE] = MBED_CLOUD_CLIENT_UPDATE_CERTIFICATE_PREFIX;
00154     // uint8_t* b64hash = &certName[sizeof(MBED_CLOUD_CLIENT_UPDATE_CERTIFICATE_PREFIX)-1];
00155     uint8_t certName[MBED_CLOUD_CLIENT_UPDATE_CERTIFICATE_NAME_SIZE] = MBED_CLOUD_CLIENT_UPDATE_CERTIFICATE_DEFAULT;
00156 
00157     UC_CONT_TRACE("Storing certificate to: %s\n", certName);
00158     // ARM_UC_Base64Enc(b64hash, sizeof(b64hash), fingerprint);
00159 
00160     kcm_status_e  kerr = kcm_item_store(certName,
00161                                        strlen((char *) certName),
00162                                        KCM_CERTIFICATE_ITEM,
00163                                        true,
00164                                        cert->ptr,
00165                                        cert->size,
00166                                        NULL);
00167 
00168     arm_uc_error_t err = kerr2ucerr(kerr);
00169 
00170     if (callback && (err.code == ERR_NONE)) {
00171         callback(err, fingerprint);
00172     }
00173 
00174     return err;
00175 }
00176 
00177 const struct arm_uc_certificate_api arm_uc_certificate_kcm_api = {
00178     .fetch = arm_uc_kcm_cert_fetcher,
00179     .store = arm_uc_kcm_cert_storer
00180 };
00181 
00182 #endif /* ARM_UC_FEATURE_CERT_STORE_KCM */