dfu_init_template.c 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. /* Copyright (c) 2014 Nordic Semiconductor. All Rights Reserved.
  2. *
  3. * The information contained herein is property of Nordic Semiconductor ASA.
  4. * Terms and conditions of usage are described in detail in NORDIC
  5. * SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT.
  6. *
  7. * Licensees are granted free, non-transferable use of the information. NO
  8. * WARRANTY of ANY KIND is provided. This heading must NOT be removed from
  9. * the file.
  10. *
  11. */
  12. /**@file
  13. *
  14. * @defgroup nrf_dfu_init_template Template file with an DFU init packet handling example.
  15. * @{
  16. *
  17. * @ingroup nrf_dfu
  18. *
  19. * @brief This file contains a template on how to implement DFU init packet handling.
  20. *
  21. * @details The template shows how device type and revision can be used for a safety check of the
  22. * received image. It shows how validation can be performed in two stages:
  23. * - Stage 1: Pre-check of firmware image before transfer to ensure the firmware matches:
  24. * - Device Type.
  25. * - Device Revision.
  26. * Installed SoftDevice.
  27. * This template can be extended with additional checks according to needs.
  28. * For example, such a check could be the origin of the image (trusted source)
  29. * based on a signature scheme.
  30. * - Stage 2: Post-check of the image after image transfer but before installing firmware.
  31. * For example, such a check could be an integrity check in form of hashing or
  32. * verification of a signature.
  33. * In this template, a simple CRC check is carried out.
  34. * The CRC check can be replaced with other mechanisms, like signing.
  35. *
  36. * @note This module does not support security features such as image signing, but the
  37. * implementation allows for such extension.
  38. * If the init packet is signed by a trusted source, it must be decrypted before it can be
  39. * processed.
  40. */
  41. #include "dfu_init.h"
  42. #include <stdint.h>
  43. #include <string.h>
  44. #include <dfu_types.h>
  45. #include "nrf_error.h"
  46. #include "crc16.h"
  47. #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. */
  48. #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. */
  49. 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. */
  50. static uint8_t m_extended_packet_length; //< Length of the extended data received with init packet. */
  51. uint32_t dfu_init_prevalidate(uint8_t * p_init_data, uint32_t init_data_len)
  52. {
  53. uint32_t i = 0;
  54. // In order to support signing or encryption then any init packet decryption function / library
  55. // should be called from here or implemented at this location.
  56. // Length check to ensure valid data are parsed.
  57. if (init_data_len < sizeof(dfu_init_packet_t))
  58. {
  59. return NRF_ERROR_INVALID_LENGTH;
  60. }
  61. // Current template uses clear text data so they can be casted for pre-check.
  62. dfu_init_packet_t * p_init_packet = (dfu_init_packet_t *)p_init_data;
  63. m_extended_packet_length = ((uint32_t)p_init_data + init_data_len) -
  64. (uint32_t)&p_init_packet->softdevice[p_init_packet->softdevice_len];
  65. if (m_extended_packet_length < DFU_INIT_PACKET_EXT_LENGTH_MIN)
  66. {
  67. return NRF_ERROR_INVALID_LENGTH;
  68. }
  69. if (((uint32_t)p_init_data + init_data_len) <
  70. (uint32_t)&p_init_packet->softdevice[p_init_packet->softdevice_len])
  71. {
  72. return NRF_ERROR_INVALID_LENGTH;
  73. }
  74. memcpy(m_extended_packet,
  75. &p_init_packet->softdevice[p_init_packet->softdevice_len],
  76. m_extended_packet_length);
  77. /** [DFU init application version] */
  78. // To support application versioning, this check should be updated.
  79. // This template allows for any application to be installed. However,
  80. // customers can place a revision number at the bottom of the application
  81. // to be verified by the bootloader. This can be done at a location
  82. // relative to the application, for example the application start
  83. // address + 0x0100.
  84. /** [DFU init application version] */
  85. // First check to verify the image to be transfered matches the device type.
  86. // If no Device type is present in DFU_DEVICE_INFO then any image will be accepted.
  87. if ((DFU_DEVICE_INFO->device_type != DFU_DEVICE_TYPE_EMPTY) &&
  88. (p_init_packet->device_type != DFU_DEVICE_INFO->device_type))
  89. {
  90. return NRF_ERROR_INVALID_DATA;
  91. }
  92. // Second check to verify the image to be transfered matches the device revision.
  93. // If no Device revision is present in DFU_DEVICE_INFO then any image will be accepted.
  94. if ((DFU_DEVICE_INFO->device_rev != DFU_DEVICE_REVISION_EMPTY) &&
  95. (p_init_packet->device_rev != DFU_DEVICE_INFO->device_rev))
  96. {
  97. return NRF_ERROR_INVALID_DATA;
  98. }
  99. // Third check: Check the array of supported SoftDevices by this application.
  100. // If the installed SoftDevice does not match any SoftDevice in the list then an
  101. // error is returned.
  102. while (i < p_init_packet->softdevice_len)
  103. {
  104. if (p_init_packet->softdevice[i] == DFU_SOFTDEVICE_ANY ||
  105. p_init_packet->softdevice[i++] == SD_FWID_GET(MBR_SIZE))
  106. {
  107. return NRF_SUCCESS;
  108. }
  109. }
  110. // No matching SoftDevice found - Return NRF_ERROR_INVALID_DATA.
  111. return NRF_ERROR_INVALID_DATA;
  112. }
  113. uint32_t dfu_init_postvalidate(uint8_t * p_image, uint32_t image_len)
  114. {
  115. uint16_t image_crc;
  116. uint16_t received_crc;
  117. // In order to support hashing (and signing) then the (decrypted) hash should be fetched and
  118. // the corresponding hash should be calculated over the image at this location.
  119. // If hashing (or signing) is added to the system then the CRC validation should be removed.
  120. // calculate CRC from active block.
  121. image_crc = crc16_compute(p_image, image_len, NULL);
  122. // Decode the received CRC from extended data.
  123. received_crc = uint16_decode((uint8_t *)&m_extended_packet[0]);
  124. // Compare the received and calculated CRC.
  125. if (image_crc != received_crc)
  126. {
  127. return NRF_ERROR_INVALID_DATA;
  128. }
  129. return NRF_SUCCESS;
  130. }