David Kester / nRF51822

Dependents:   GonioTrainer

Fork of nRF51822 by Nordic Semiconductor

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers dfu_init_template.c Source File

dfu_init_template.c

Go to the documentation of this file.
00001 /* Copyright (c) 2014 Nordic Semiconductor. All Rights Reserved.
00002  *
00003  * The information contained herein is property of Nordic Semiconductor ASA.
00004  * Terms and conditions of usage are described in detail in NORDIC
00005  * SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT.
00006  *
00007  * Licensees are granted free, non-transferable use of the information. NO
00008  * WARRANTY of ANY KIND is provided. This heading must NOT be removed from
00009  * the file.
00010  *
00011  */
00012 
00013 /**@file
00014  *
00015  * @defgroup nrf_dfu_init_template Template file with an DFU init packet handling example.
00016  * @{
00017  *
00018  * @ingroup nrf_dfu
00019  *
00020  * @brief This file contains a template on how to implement DFU init packet handling.
00021  *
00022  * @details The template shows how device type and revision can be used for a safety check of the 
00023  *          received image. It shows how validation can be performed in two stages:
00024  *          - Stage 1: Pre-check of firmware image before transfer to ensure the firmware matches:
00025  *                     - Device Type.
00026  *                     - Device Revision.
00027  *                     Installed SoftDevice.
00028  *                     This template can be extended with additional checks according to needs.
00029  *                     For example, such a check could be the origin of the image (trusted source) 
00030  *                     based on a signature scheme.
00031  *          - Stage 2: Post-check of the image after image transfer but before installing firmware.
00032  *                     For example, such a check could be an integrity check in form of hashing or 
00033  *                     verification of a signature.
00034  *                     In this template, a simple CRC check is carried out.
00035  *                     The CRC check can be replaced with other mechanisms, like signing.
00036  *
00037  * @note This module does not support security features such as image signing, but the 
00038  *       implementation allows for such extension.
00039  *       If the init packet is signed by a trusted source, it must be decrypted before it can be
00040  *       processed.
00041  */
00042 
00043 #include "dfu_init.h "
00044 #include <stdint.h>
00045 #include <string.h>
00046 #include "dfu_types.h "
00047 #include "nrf_error.h"
00048 #include "crc16.h"
00049 
00050 #define DFU_INIT_PACKET_EXT_LENGTH_MIN      2                       //< Minimum length of the extended init packet. The extended init packet may contain a CRC, a HASH, or other data. This value must be changed according to the requirements of the system. The template uses a minimum value of two in order to hold a CRC. */
00051 #define DFU_INIT_PACKET_EXT_LENGTH_MAX      10                      //< Maximum length of the extended init packet. The extended init packet may contain a CRC, a HASH, or other data. This value must be changed according to the requirements of the system. The template uses a maximum value of 10 in order to hold a CRC and any padded data on transport layer without overflow. */
00052 
00053 static uint8_t m_extended_packet[DFU_INIT_PACKET_EXT_LENGTH_MAX];   //< Data array for storage of the extended data received. The extended data follows the normal init data of type \ref dfu_init_packet_t. Extended data can be used for a CRC, hash, signature, or other data. */
00054 static uint8_t m_extended_packet_length;                            //< Length of the extended data received with init packet. */
00055 
00056 
00057 uint32_t dfu_init_prevalidate(uint8_t * p_init_data, uint32_t init_data_len)
00058 {
00059     uint32_t i = 0;
00060     
00061     // In order to support signing or encryption then any init packet decryption function / library
00062     // should be called from here or implemented at this location.
00063 
00064     // Length check to ensure valid data are parsed.
00065     if (init_data_len < sizeof(dfu_init_packet_t))
00066     {
00067         return NRF_ERROR_INVALID_LENGTH;
00068     }
00069 
00070     // Current template uses clear text data so they can be casted for pre-check.
00071     dfu_init_packet_t * p_init_packet = (dfu_init_packet_t *)p_init_data;
00072 
00073     m_extended_packet_length = ((uint32_t)p_init_data + init_data_len) -
00074                                (uint32_t)&p_init_packet->softdevice[p_init_packet->softdevice_len];
00075     if (m_extended_packet_length < DFU_INIT_PACKET_EXT_LENGTH_MIN)
00076     {
00077         return NRF_ERROR_INVALID_LENGTH;
00078     }
00079 
00080     if (((uint32_t)p_init_data + init_data_len) < 
00081         (uint32_t)&p_init_packet->softdevice[p_init_packet->softdevice_len])
00082     {
00083         return NRF_ERROR_INVALID_LENGTH;
00084     }
00085 
00086     memcpy(m_extended_packet,
00087            &p_init_packet->softdevice[p_init_packet->softdevice_len],
00088            m_extended_packet_length);
00089 
00090 /** [DFU init application version] */
00091     // To support application versioning, this check should be updated.
00092     // This template allows for any application to be installed. However, 
00093     // customers can place a revision number at the bottom of the application 
00094     // to be verified by the bootloader. This can be done at a location 
00095     // relative to the application, for example the application start 
00096     // address + 0x0100.
00097 /** [DFU init application version] */
00098     
00099     // First check to verify the image to be transfered matches the device type.
00100     // If no Device type is present in DFU_DEVICE_INFO then any image will be accepted.
00101     if ((DFU_DEVICE_INFO->device_type != DFU_DEVICE_TYPE_EMPTY) &&
00102         (p_init_packet->device_type != DFU_DEVICE_INFO->device_type))
00103     {
00104         return NRF_ERROR_INVALID_DATA;
00105     }
00106     
00107     // Second check to verify the image to be transfered matches the device revision.
00108     // If no Device revision is present in DFU_DEVICE_INFO then any image will be accepted.
00109     if ((DFU_DEVICE_INFO->device_rev != DFU_DEVICE_REVISION_EMPTY) &&
00110         (p_init_packet->device_rev != DFU_DEVICE_INFO->device_rev))
00111     {
00112         return NRF_ERROR_INVALID_DATA;
00113     }
00114 
00115     // Third check: Check the array of supported SoftDevices by this application.
00116     //              If the installed SoftDevice does not match any SoftDevice in the list then an
00117     //              error is returned.
00118     while (i < p_init_packet->softdevice_len)
00119     {
00120         if (p_init_packet->softdevice[i] == DFU_SOFTDEVICE_ANY ||
00121             p_init_packet->softdevice[i++] == SOFTDEVICE_INFORMATION->firmware_id)
00122         {
00123             return NRF_SUCCESS;
00124         }
00125     }
00126     
00127     // No matching SoftDevice found - Return NRF_ERROR_INVALID_DATA.
00128     return NRF_ERROR_INVALID_DATA;
00129 }
00130 
00131 
00132 uint32_t dfu_init_postvalidate(uint8_t * p_image, uint32_t image_len)
00133 {
00134     uint16_t image_crc;
00135     uint16_t received_crc;
00136     
00137     // In order to support hashing (and signing) then the (decrypted) hash should be fetched and
00138     // the corresponding hash should be calculated over the image at this location.
00139     // If hashing (or signing) is added to the system then the CRC validation should be removed.
00140 
00141     // calculate CRC from active block.
00142     image_crc = crc16_compute(p_image, image_len, NULL);
00143 
00144     // Decode the received CRC from extended data.    
00145     received_crc = uint16_decode((uint8_t *)&m_extended_packet[0]);
00146 
00147     // Compare the received and calculated CRC.
00148     if (image_crc != received_crc)
00149     {
00150         return NRF_ERROR_INVALID_DATA;
00151     }
00152 
00153     return NRF_SUCCESS;
00154 }
00155