213 lines
9.5 KiB
C
213 lines
9.5 KiB
C
/**
|
|
* Copyright (c) 2017 - 2017, Nordic Semiconductor ASA
|
|
*
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without modification,
|
|
* are permitted provided that the following conditions are met:
|
|
*
|
|
* 1. Redistributions of source code must retain the above copyright notice, this
|
|
* list of conditions and the following disclaimer.
|
|
*
|
|
* 2. Redistributions in binary form, except as embedded into a Nordic
|
|
* Semiconductor ASA integrated circuit in a product or a software update for
|
|
* such product, must reproduce the above copyright notice, this list of
|
|
* conditions and the following disclaimer in the documentation and/or other
|
|
* materials provided with the distribution.
|
|
*
|
|
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
|
|
* contributors may be used to endorse or promote products derived from this
|
|
* software without specific prior written permission.
|
|
*
|
|
* 4. This software, with or without modification, must only be used with a
|
|
* Nordic Semiconductor ASA integrated circuit.
|
|
*
|
|
* 5. Any software provided in binary form under this license must not be reverse
|
|
* engineered, decompiled, modified and/or disassembled.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
|
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
|
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
|
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
|
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*
|
|
*/
|
|
/**@file
|
|
*
|
|
* @defgroup nrf_dfu_init_template Template file with an DFU init packet handling example.
|
|
* @{
|
|
*
|
|
* @ingroup nrf_dfu
|
|
*
|
|
* @brief This file contains a template on how to implement DFU init packet handling.
|
|
*
|
|
* @details The template shows how device type and revision can be used for a safety check of the
|
|
* received image. It shows how validation can be performed in two stages:
|
|
* - Stage 1: Pre-check of firmware image before transfer to ensure the firmware matches:
|
|
* - Device Type.
|
|
* - Device Revision.
|
|
* Installed SoftDevice.
|
|
* This template can be extended with additional checks according to needs.
|
|
* For example, such a check could be the origin of the image (trusted source)
|
|
* based on a signature scheme.
|
|
* - Stage 2: Post-check of the image after image transfer but before installing firmware.
|
|
* For example, such a check could be an integrity check in form of hashing or
|
|
* verification of a signature.
|
|
* In this template, a simple CRC check is carried out.
|
|
* The CRC check can be replaced with other mechanisms, like signing.
|
|
*
|
|
* @note This module does not support security features such as image signing, but the
|
|
* implementation allows for such extension.
|
|
* If the init packet is signed by a trusted source, it must be decrypted before it can be
|
|
* processed.
|
|
*/
|
|
|
|
#include "dfu_init.h"
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
#include <dfu_types.h>
|
|
#include "nrf_error.h"
|
|
#include "crc16.h"
|
|
|
|
/* ADAFRUIT
|
|
* - All firmware init data must has Device Type ADAFRUIT_DEVICE_TYPE (nrf52832 and nrf52840)
|
|
* - SD + Bootloader upgrade must have correct Device Revision to make sure bootloader is not flashed
|
|
* on the wrong device (e.g flah nRF52832's bootloader on nRF52840 board and vice versa)
|
|
* - nrf52832 dev-rev is 0xADAF
|
|
* - nrf52840 dev-rev is 52840
|
|
*/
|
|
#define ADAFRUIT_DEVICE_TYPE 0x0052
|
|
|
|
#ifdef NRF52840_XXAA
|
|
#define ADAFRUIT_DEV_REV 52840
|
|
#elif defined NRF52832_XXAA
|
|
#define ADAFRUIT_DEV_REV 0xADAF
|
|
#else
|
|
#error Unknown MCU
|
|
#endif
|
|
|
|
|
|
|
|
#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. */
|
|
#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. */
|
|
|
|
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. */
|
|
static uint8_t m_extended_packet_length; //< Length of the extended data received with init packet. */
|
|
|
|
|
|
uint32_t dfu_init_prevalidate(uint8_t * p_init_data, uint32_t init_data_len, uint8_t image_type)
|
|
{
|
|
uint32_t i = 0;
|
|
|
|
// In order to support signing or encryption then any init packet decryption function / library
|
|
// should be called from here or implemented at this location.
|
|
|
|
// Length check to ensure valid data are parsed.
|
|
if (init_data_len < sizeof(dfu_init_packet_t))
|
|
{
|
|
return NRF_ERROR_INVALID_LENGTH;
|
|
}
|
|
|
|
// Current template uses clear text data so they can be casted for pre-check.
|
|
dfu_init_packet_t * p_init_packet = (dfu_init_packet_t *)p_init_data;
|
|
|
|
m_extended_packet_length = ((uint32_t)p_init_data + init_data_len) -
|
|
(uint32_t)&p_init_packet->softdevice[p_init_packet->softdevice_len];
|
|
if (m_extended_packet_length < DFU_INIT_PACKET_EXT_LENGTH_MIN)
|
|
{
|
|
return NRF_ERROR_INVALID_LENGTH;
|
|
}
|
|
|
|
if (((uint32_t)p_init_data + init_data_len) <
|
|
(uint32_t)&p_init_packet->softdevice[p_init_packet->softdevice_len])
|
|
{
|
|
return NRF_ERROR_INVALID_LENGTH;
|
|
}
|
|
|
|
memcpy(m_extended_packet,
|
|
&p_init_packet->softdevice[p_init_packet->softdevice_len],
|
|
m_extended_packet_length);
|
|
|
|
/** [DFU init application version] */
|
|
// To support application versioning, this check should be updated.
|
|
// This template allows for any application to be installed. However,
|
|
// customers can place a revision number at the bottom of the application
|
|
// to be verified by the bootloader. This can be done at a location
|
|
// relative to the application, for example the application start
|
|
// address + 0x0100.
|
|
/** [DFU init application version] */
|
|
|
|
// First check to verify the image to be transfered matches the device type.
|
|
// If no Device type is present in DFU_DEVICE_INFO then any image will be accepted.
|
|
// if ((DFU_DEVICE_INFO->device_type != DFU_DEVICE_TYPE_EMPTY) &&
|
|
// (p_init_packet->device_type != DFU_DEVICE_INFO->device_type))
|
|
// {
|
|
// return NRF_ERROR_INVALID_DATA;
|
|
// }
|
|
|
|
// Second check to verify the image to be transfered matches the device revision.
|
|
// If no Device revision is present in DFU_DEVICE_INFO then any image will be accepted.
|
|
// if ((DFU_DEVICE_INFO->device_rev != DFU_DEVICE_REVISION_EMPTY) &&
|
|
// (p_init_packet->device_rev != DFU_DEVICE_INFO->device_rev))
|
|
|
|
if ( p_init_packet->device_type != ADAFRUIT_DEVICE_TYPE )
|
|
{
|
|
return NRF_ERROR_FORBIDDEN;
|
|
}
|
|
|
|
// Adafruit unlock code must match to upgrade SoftDevice and/or Bootloader
|
|
if ( image_type & (DFU_UPDATE_SD | DFU_UPDATE_BL) )
|
|
{
|
|
if (p_init_packet->device_rev != ADAFRUIT_DEV_REV)
|
|
{
|
|
return NRF_ERROR_FORBIDDEN;
|
|
}
|
|
}
|
|
|
|
// Third check: Check the array of supported SoftDevices by this application.
|
|
// If the installed SoftDevice does not match any SoftDevice in the list then an
|
|
// error is returned.
|
|
while (i < p_init_packet->softdevice_len)
|
|
{
|
|
if (p_init_packet->softdevice[i] == DFU_SOFTDEVICE_ANY ||
|
|
p_init_packet->softdevice[i++] == SD_FWID_GET(MBR_SIZE))
|
|
{
|
|
return NRF_SUCCESS;
|
|
}
|
|
}
|
|
|
|
// No matching SoftDevice found - Return NRF_ERROR_INVALID_DATA.
|
|
return NRF_ERROR_INVALID_DATA;
|
|
}
|
|
|
|
|
|
uint32_t dfu_init_postvalidate(uint8_t * p_image, uint32_t image_len)
|
|
{
|
|
uint16_t image_crc;
|
|
uint16_t received_crc;
|
|
|
|
// In order to support hashing (and signing) then the (decrypted) hash should be fetched and
|
|
// the corresponding hash should be calculated over the image at this location.
|
|
// If hashing (or signing) is added to the system then the CRC validation should be removed.
|
|
|
|
// calculate CRC from active block.
|
|
image_crc = crc16_compute(p_image, image_len, NULL);
|
|
|
|
// Decode the received CRC from extended data.
|
|
received_crc = uint16_decode((uint8_t *)&m_extended_packet[0]);
|
|
|
|
// Compare the received and calculated CRC.
|
|
if (image_crc != received_crc)
|
|
{
|
|
return NRF_ERROR_INVALID_DATA;
|
|
}
|
|
|
|
return NRF_SUCCESS;
|
|
}
|
|
|