forked from adafruit/Adafruit_nRF52_Bootloader
-
Notifications
You must be signed in to change notification settings - Fork 0
/
dfu_init.c
214 lines (184 loc) · 9.62 KB
/
dfu_init.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
/**
* 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
#if defined(NRF52840_XXAA)
#define ADAFRUIT_DEV_REV 52840
#elif defined(NRF52833_XXAA)
#define ADAFRUIT_DEV_REV 52833
#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;
}