资讯详情

S32K1xx 固件更新

1 介绍

随着当前技术的进步,车辆变得更加电子化,而不是机械化。车辆中的电子创新正在增加。因此,车辆中的软件也在增加,因此存在潜在的错误风险。

每次发现软件错误,都需要召回更新软件。这些召回代表了汽车制造商的成本和最终用户的耗时过程。

如今,无线更新已经开始使用 a/b 实施交换技术的新车。该技术的更新仅限于具有高密度存储器的微控制器,如网关或信息娱乐单元。边缘节点应用的小型微控制器不会更新。

除了负责边缘节点微控制器上的固件更新外,另一个问题是保持更新过程的安全这是为了保护更新免受可能的窃听和复制攻击。

本应用笔记的重点是展示 S32K1xx 如何处理微控制器的安全通信过程? a/b 交换更新。它解释了引导加载程序,a/b 交换更新和安全概念的基本概念。本文涵盖了固件更新作为整个系统的实施。 flash控制器、安全模块、CAN请参考控制器等具体模块的功能细节S32K1xx设备参考手册。

本应用笔记包含用于演示的补充软件 a/b 同时使用交换更新 S32K144 和 S32K146 微控制器的功能。

2 引导加载程序的概念

在应用程序的固件开发阶段,闪存编程工具完成了微控制器的更新,需要一定数量的微控制器 I/O 与一个特殊的头与工具互动。固件完成后,下载焊接 PCB 中微控制器。此 pcb 它可能包含或不包含编程工具所需的标头,以避免访问闪存中存储的数据或应用程序所需的数据 I/O 用于其应用程序。在某些情况下,托管微控制器的最终模块很难访问,例如,在汽车应用中,电子控制单元被放置在最终用户隐藏的区域。那么,如果由于故障或升级,设备在现场后需要更新固件怎么办?开发了引导加载程序来解决这个问题。

引导加载程序是驻留在微控制器中的非易失性存储器 (NVM) 用于处理应用程序或数据更新的中间固件。引导加载程序和应用程序可能停留在同一个非易失性存储块或不同块中。内存中不应重叠应用固件和引导加载程序;因此,引导加载程序通常放置在内存空间的开头。引导加载程序预计不会更新,因此其区域受到保护,以避免有意或无意的修改。

引导加载程序通过通信协议从主机接收新的固件数据,包括但不限于 CAN、LIN、UART、ETHERNET 和 USB。通信协议取决于开发人员的决定、应用程序和微控制器的特性。例如,主机使用已知格式发送新如 srec 或 bin 文件。引导加载程序使用新固件数据捕获数据包,然后更新旧固件的内存位置。引导加载程序在收到并验证完整的固件后跳转到新的应用程序。

在深入了解引导加载程序更新算法的细节之前,有必要了解写入 NVM 的过程。要写入 NVM 在位置上,必须先擦除数据,并根据风扇区域擦除非易失性存储器中的数据。这个扇区大小是可以擦除的数据的最小部分,它取决于每种非易失性存储器技术,它被称为存储器的粒度。风扇区域一旦被擦除,数据就可以写入风扇区域。写入过程也取决于 NVM 技术,每个 NVM 每个写入命令都有很多字节。最后,为了完成写入过程,需要一个程序检查命令来验证数据是否按预期写入闪存。

引导加载程序的固件尺寸取决于非易损存储器的粒度。粒度越大,风扇面积越小,引导加载程序的尺寸越灵活。由于引导加载程序将从主机接收新的固件数据,这些数据将被编程到 NVM 因此,有必要考虑风扇区域在写入数据之前已被擦除。

从 NVM 读取和执行指导加载程序固件将启动擦除和写入命令,以更新新的应用程序数据 NVM 因此,必须同时考虑内存操作。内存允许在每个设备上同时操作,只要发生在不同的读取分区或内存块中,就允许在写入内存的同时读取一些设备。如果边读边写功能不可用,则需要将内存命令放入引导加载程序中 ram 这些命令可以从那里启动,以避免任何冲突。

更新过程可以通过软件或硬件方法进行。通过在应用程序运行过程中按下按钮、复位后输入的低电平或高电平状态或需要更新的特定通信数据包来触发更新。一般情况下,微控制器复位后,引导加载程序固件会在一定时间内检查是否有启动更新过程的条件,如果不符合这一条件,则会跳转到应用程序固件。有些用例还可以在应用程序运行时检查触发器,允许在运行过程中更新,避免重置后的停机时间。因此,在下一次重置中,设备将立即启动到最新图像。如何触发更新过程取决于最终的应用程序、内存和设备特性。

当检测到更新过程触发时,更新算法开始将新的固件应用程序放入 NVM。更新算法包括以下步骤:从通信协议中接收数据,验证接收到的数据是否正确,擦除/编程闪存,检查完整数据是否已下载。

更新过程后,引导加载程序应将使用的外设和时钟配置恢复到默认状态。复位后需要引导加载程序启动。中断向量表除外设和时钟配置外,还应重新定位。在这种情况下,指向中断表的指针必须从其默认位置重新定位。引导加载程序一旦处理好这些注意事项,就可以跳转到应用程序固件。如下图所示。

主机和引导加载程序之间共享的应用固件很容易被捕获和读取。这是因为潜在的攻击者可以嗅程中的网络。为了避免窃听攻击,保护固件的机密性,可以加密数据。

在网络中传输数据之前,可以在主机中加密。然后,引导加载程序使用已知密钥解密数据,然后写入 NVM 内存。除加密外,还可将验证主机真实性和数据新鲜度的机制添加到引导加载程序中。

最后,在开发和引导加载程序固件时,应考虑内存的位置。引导加载程序固件和应用程序可能停留在同一个位置 NVM 在内存块中,有必要修改固件链接器文件,以避免重叠。一些设备在内存中有一个特殊的位置来放置指导加载程序。链接器文件的修改取决于使用的微控制器和编译器。

3 固件更新方法

要更新微控制器中的固件,可采用两种方法之一。这两种方法是:a/b 方法和本地方法。传统上,本地方法已被使用。在这种方法中,微控制器只存储一个固件图像,可能会占用所有可用的闪存。在这种情况下,微控制器无法更新,如果更新过程没有正确完成,旧图像可能很难恢复。这个过程显示在下图中。

a/b 交换方法是指微控制器将两个图像存储在不同的闪存区域。在这种情况下,固件可以在微控制器运行时更新。由于微控制器存储了两种不同的固件、旧固件和更新固件,因此新固件不能正常工作时可以立即恢复。主要缺点是两个应用程序的图像应该适合微控制器 NVM,因此,固件应用程序的最大尺寸减少了。这种方法的另一个挑战是固件重新映射,因为在 NVM 在不同的物理地址中有两个应用程序。 a/b 如下图所示。

因此,这两种方法各有优缺点,但汽车制造商决定哪种方法适合应用。本应用笔记重点介绍 S32K1xx 在微控制器中 a/b 交换实现。

4 安全概念

高级加密标准(AES)本标准采用对称加密/解密码。 Rijndael 算法使用密码密钥处理数据。每个密钥的大小可以是 128、192 或 256 位。算法步骤显示在下图中。

加密和解密数据有两种方法。这两种方法是:电子密码本(ECB)和链密码本(CBC)。 ECB 该方法将纯文本分为输入。每个输入都有密码粒度。加密输出仅取决于纯文本输入和密钥。每个密码输出都是独立加密的。该密码模式的缺点是,相同的输入值将解码为相同的输出值。这给了攻击者使用统计分析的机会(例如,在普通文本中,某些字母组合比其他字母组合更频繁)。 CBC 该方法在输入中划分纯文本。每个输入都有密码粒度。最后一个编码步骤的输出与当前编码步骤的输入块不同或不同。因此,第一个编码步骤的附加值是必要的,称为初始向量 (IV)。使用此方法,每个密码块都取决于该点处理的明文输入。 以企鹅图像为纯文本,以下示例说明了两种方法的结果。

基于密码的消息验证码 (CMAC) 提供了验证信息和数据的方法。 CMAC 使用 AES 算法。 CMAC 算法接受密钥和任何长度的待验证信息作为输入和输出 CMAC。 CMAC 该值通过允许验证者(也有密钥)检测对消息内容的任何变化来保护数据的完整性和真实性。图显示了 CMAC 的组件。

5 S32K1xx 概述

NXP S32K1xx 32 汽车微控制器产品系列提供高集成、低功耗、安全可靠的单芯片解决方案。 CPU 与低功耗相比,结合灵活的低功耗模式和低泄漏技术工艺不会做出任何妥协。

S32K1xx 该系列提供广泛的内存,从 128kB 到 2MB。允许开发人员共享一般外设和引脚数量 MCU 系列内或在 MCU 为了使用更多的内存或功能集成,系列之间很容易迁移。这种可扩展性允许开发人员 S32K1xx 产品系列被用作最终产品平台的标准,以最大限度地重复使用硬件和软件,缩短上市时间。

S32K1xx 支持 CAN 数据速率灵活 (CAN-FD) 以及新的 FlexIO 可配置外设,允许客户实施未发明的未来通信协议,并将通道扩展到现有的电影硬件协议控制器。

压缩安全模块,加密服务引擎 (CSEc),包含在 S32K1xx 产品中。 CSEc 实现了 SHE 功能规范中描述的一整套加密功能包括:通用密钥AES-128、CBC、ECB、CMAC、生成伪随机数 (PRNG) 随机生成和真数 (TRNG)。这允许保护 ECU 免受各种攻击场景,确保系统完整性。

下图显示了 S32K11x 和 S32K14x 产品框图。

5.1 NVM 架构

S32K1xx 有微控制器 C90TFS(膜存储)技术闪存。这些设备中有两个闪存,程序闪存 (pflash) 弹性内存。/p>

程序闪存是一种非易失性存储器,其主要用途是执行代码。程序闪存的大小因设备而异,介于 128kB 到 1.5 MB 之间。该闪存在程序闪存高于 256kB 的设备中具有 4kB 的扇区大小,而在程序闪存等于或小于 256kB 的设备中具有 2kB 的扇区大小。在所有器件中,pflash 编程命令一次写入 8B。此闪存的块大小为 512kB 或更小,具体取决于设备是否有一个或多个闪存块。每个块代表一个读取分区,这意味着可以在擦除或写入另一个块的同时读取一个块。

Flex 内存闪存的目的是与 flex ram 内存一起执行代码、存储数据或用作 EEPROM。此弹性内存的大小因每个设备而异,32kB (S32K11x)、64kB (S32K142/4/6) 或 512kB (S32K148)。对于 S32K116/8 和 S32K142/4/6 设备,此内存中的扇区大小为 2kB,而对于 S32K148 设备,扇区大小为 4kB。在所有器件中,flex memory 编程命令一次写入 8B。弹性内存是一个单独的读取分区,因此可以在擦除或写入程序闪存时从该闪存读取,反之亦然。如果将弹性存储器配置为用作 EEPROM,则可以对其进行分区,以便弹性存储器的一部分存储代码或数据,而另一部分用作 EEPROM 备份。弹性内存的大小可以分为:16kB、32kB和64kB。 每个 S32K1xx 器件的大小和闪存粒度摘要如下表所示。这些存储器在每个器件的存储器映射中的位置如图 9 所示。

 

 闪存控制器包含在用于这些存储器的微控制器中。该闪存控制器执行命令以擦除、编程和检查这些存储器。除了访问这些存储器中的内容的命令外,还包括安全命令。可以从闪存控制器执行加密、解密、cmac 计算、随机数生成等命令。

6 S321xx 固件更新实施

6.1 S32K144 用例

6.1.1 S32K144 用于 A/B 交换的内存映射,带有单个 pflash 块

在这种情况下,S32K144 设备用于实现设备中的 a/b 交换更新。记住 S32K144 有一个 512kB 的程序闪存和一个 64kB 的弹性内存,总共有两个可用的读取分区。引导加载程序从弹性存储器加载到 16kB 空间中。程序闪存定位 a/b 交换所需的两个应用程序映像,每个映像都包含一个标题。

每个应用程序函数的标头确定固件信息。诸如但不限于固件版本、最旧版本、软件开发人员详细信息、大小、作者、应用程序密钥等信息可以包含在此标题中。每次更新后,标题信息也会更新。标头大小为 4kB,一个程序闪存扇区大小。标头不仅可以存储固件运行的信息,还可以验证最新的固件以及是否可以执行固件。

在 ARM® Cortex M 内核中,复位发生后,内核从程序闪存位置读取前两个字,该位置预期中断向量表。第一个字包含堆栈指针,第二个字包含复位处理程序的地址。然后,内核将主堆栈指针地址 (SP) 和程序计数器 (PC) 设置为复位处理程序的开始。由于内核的这个初始引导过程,有必要保留而不是擦除程序闪存的第一个扇区。在 S32K144 中,向量表的大小为 1kB,因此给定程序闪存的扇区大小,不得擦除闪存的初始 4kB。

对于这种情况,引导加载程序被分配到弹性内存区域,因此 pflash 中的第二个字包含指向弹性内存地址的地址。引导加载程序放置在弹性存储器上,因为它是一个不同的读取分区,允许执行修改程序闪存内容的命令,而无需在 RAM 中分配例程。在弹性内存中分配引导加载程序的另一个好处是,在 S32K146 中有两个程序闪存的读取分区。可以在旧固件仍在运行时更新新固件。

这两个应用程序被放置在其标题之后。在每个应用程序之间,一个扇区的间隙留为空白。这是因为在考虑了默认中断表的初始扇区和固件头的两个扇区之后剩余的扇区数不均匀。然后每个应用程序固件映像将具有 248kB 或 62 个扇区的大小。下图显示了生成的闪存映射的摘要。

6.1.2 S32K144 启动和更新程序

为了确定程序闪存中最旧映像的位置,使用了头信息。在这种情况下,通过检查固件是否在最后一个标头地址处具有有效的应用程序密钥符号 0x55AA55AA 来完成标头的验证。标头的此签名是在跳转到应用程序之前更新过程中完成的最后一步。该键表示固件更新完成,并且有效。

当引导加载程序启动时,它会在应用程序头中搜索 app 键。它首先读取标题一的最后一个地址的内容,如果在那个位置没有找到任何东西,那么分配即将到来的固件的新地址就是那个位置。如果在映像 1 标头中找到应用程序密钥,则读取固件标头 2 的内容,如果未找到应用程序密钥,则分配即将到来的固件的新地址是映像 2 位置。当在两个标题中都找到应用程序密钥时,将读取固件的版本以确定最旧的版本。最旧固件的位置就是分配即将到来的固件的位置。

如果主机在复位后的定义超时(例如 4 秒)内没有请求更新,则引导加载程序会跳转到具有最新固件的闪存位置。对于两个标头都没有应用程序密钥的最终情况,这意味着没有有效的固件,然后忽略超时,并且引导加载程序继续等待来自主机的更新请求。图 11 显示了引导过程的步骤。

复位后:获取 PC 值@0x00000004。 Bootloader 启动。 Bootloader 搜索最旧和最新的图像。         - 检查 FW 标头信息。         - 在标题末尾找到应用程序密钥 (0x55AA55AA)。         - 如果在任一标头中都没有找到应用程序密钥,则留在引导加载程序中(即不要跳转到任何应用程序)。 超时后:跳转到最新的应用程序。         - 重新定位 VTOR 表。         - PC 从固件中断表中获取值。

当在复位后的超时时间内触发新的更新请求时,主机和引导加载程序(边缘节点)之间的通信开始下载新固件。主机和引导加载程序之间的通信由最终应用程序决定,在这种情况下使用 CANFD。新固件传输完成后,新固件的头部被签名并写入 NVM 内存,而旧固件头部被擦除。最后,引导加载程序跳转到新的固件位置。如果更新过程未完成(例如,由于主机和边缘节点之间的连接断开),引导加载程序会跳转到旧固件位置。图 12 显示了此更新过程的步骤。

复位后:获取 PC 值@0x00000004。 Bootloader 启动。引导加载程序搜索最旧和最新的图像。         - 检查固件标题信息。         - 在标题末尾找到应用程序密钥 (0x55AA55AA)。         - 分配要更新的固件位置(最旧的)。 收到更新触发器。         - 首先接收标题。         - 验证它是一个新版本。         - 开始在最旧的位置更新新固件。 更新完成。         - 更新新的固件标头。         - 擦除/更新旧固件标头。 跳转到新应用程序。         - 重新定位 VTOR 表。         - PC 从新的固件中断表中获取值。

6.2 S32K146 用例

6.2.1 用于 A/B 交换的 S32K146 内存映射,带有双 pflash 块

对于这个用例,S32K146 用于演示 a/b 交换更新机制。 S32K146 有 1 MB 的程序闪存,有两个每个 512 KB 的读取分区和一个 64 KB 的灵活存储空间。双 pflash 读取分区允许擦除/写入其中一个分区,同时读取另一个分区或从那里执行代码。这意味着当前固件可以在加载新固件的同时继续执行。引导加载程序放置在弹性存储器的 16 KB 空间中。

与 S32K144 用例一样,两个应用程序分别加载到两个 pflash 读取分区中。每个固件应用程序都包含一个带有固件信息(固件版本、最旧版本、软件开发人员详细信息等)的标题。

复位后,ARM Cortex M4 内核从向量表中获取前两个字来初始化堆栈指针 (SP) 并加载初始程序计数器 (PC),在这种情况下,它是位于 flex 中的引导加载程序的入口点记忆。由于这个默认的 ARM Cortex M4 引导过程,必须保留向量表所在的第一个闪存扇区。

在第二个 pflash 读取分区的开头留有一个扇区的空白,以补偿包含向量表的第一个读取分区中保留的闪存扇区,这样每个固件映像具有相同的可用空间。使用这种结构,pflash 中的每个固件映像除了 4 KB 映像头外,最多可以占用 504 KB(126 个扇区)的空间。

下图显示了 S32K146 用例的内存映射。

6.2.2 S32K146 启动和更新程序

就像在 S32K144 用例中一样,每个固件头的信息用于确定程序闪存中最旧映像的位置。这是通过验证固件标头在最后一个标头地址是否具有有效的应用程序密钥符号 (0x55AA55AA) 来执行的,这表明相应的固件是有效的。

当引导加载程序启动时,它会读取固件头文件。分配即将发布的新固件的内存块是具有没有有效应用程序密钥的标头的内存块。如果两个标头都具有有效的应用程序密钥,则比较固件版本以确定即将发布的固件的位置。最旧版本的固件将被覆盖。

引导加载程序在任何复位(例如 S32K146 用例为 2 秒)等待来自主机的更新请求命令后具有定义的超时。如果未收到请求,则引导加载程序将跳转到具有最新固件的闪存位置。如果引导加载程序在任一固件标头中都找不到有效的应用程序密钥,则会禁用超时,并且引导加载程序会继续等待更新请求。图 14 显示了 S32K146 用例的启动过程。

. 复位后:获取 PC 值@0x00000004。 Bootloader 启动。 Bootloader 搜索最旧和最新的图像。         - 检查 FW 标头信息。         - 在标题末尾找到应用程序密钥 (0x55AA55AA)。         - 如果在任一标头中都没有找到应用程序密钥,则留在引导加载程序中(即不要跳转到任何应用程序)。 超时后:跳转到最新的应用程序。         - 重新定位 VTOR 表。         - PC 从固件中断表中获取值。

对于 S32K146 用例中的更新过程,有两种可能的情况:

        1. 主机在复位后但超时到期之前请求更新,因此在引导加载程序跳转到应用程序之前。         2. 当前应用程序运时主机请求更新。

场景 (1) - 在跳转到应用程序之前复位后更新请求

对于第一种场景,主机在复位后的超时时间内向引导加载程序(边缘节点)触发更新请求。在这种情况下,更新的处理方式与 S32K144 用例中的相同,通过 CANFD 接收新固件,将其加载到最旧固件的 pflash 块中,当更新完成时,新固件头被签名并存储,而旧的固件标头被擦除。最后,引导加载程序跳转到新应用程序。图 15 显示了此场景的顺序。

复位后:获取 PC 值@0x00000004。Bootloader 启动。引导加载程序搜索最旧和最新的图像。         - 检查固件标题信息。         - 在标题末尾找到应用程序密钥 (0x55AA55AA)。         - 分配要更新的固件位置(最旧的)。收到更新触发器。         - 首先接收标题。         - 验证它是一个新版本。         - 开始在最旧的位置更新新固件。更新完成。         - 更新新的固件标头。         - 擦除/更新旧固件标头。 跳转到新应用程序。         - 重新定位 VTOR 表。         - PC 从新的固件中断表中获取值。

场景 (2) - 当前应用程序正在运行时更新请求

在第二个更新场景中,当收到来自主机的更新请求时,最新的应用程序已经在运行。为了在不完全停止当前固件的执行的情况下处理更新过程,需要一种在引导加载程序和应用程序之间共享 CPU 处理时间的机制。这种机制的实现是灵活的,最终应用程序将确定从应用程序窃取的处理时间与完成新固件更新所需的总时间之间的适当平衡。一个重要的考虑因素是应用软件需要对引导加载程序有一定程度的了解,例如通过初始化与主机的通信接口,以及包括一种控制引导加载程序的方法,以便它可以处理更新命令和数据从主机。

对于此参考实现,只要从主机接收到带有固件数据的新 CANFD 消息,执行就会从应用程序跳转到引导加载程序。数据被处理并存储在相应的 pflash 块中,然后执行跳回到应用程序停止的同一点。 loader 专用入口地址与应用程序共享,以便它在接收到主机的命令时知道跳转到哪里。应用程序-引导加载程序跳转循环一直持续到更新过程完成。此时,引导加载程序使用 SRAM 存储器中的状态变量向应用程序通知完成状态,然后应用程序触发软件复位以启动新的固件版本。图 16 显示了此更新方案的总体过程。

复位后:获取 PC 值@0x00000004。 Bootloader 启动。 Bootloader 搜索最旧和最新的图像。         - 检查 FW 标头信息。         - 在标题末尾找到应用程序密钥 (0x55AA55AA)。         - 分配要更新的固件位置(最旧的)。 超时后:跳转到最新的应用程序。         - 重新定位 VTOR 表。         - PC 从固件中断表中获取值。 运行当前应用程序。         - 继续直到收到来自主机的消息。         - 当一个新的应用程序准备好时,触发一个重置。 收到来自主机的消息。         - 停止应用程序并跳转到引导加载程序。         - 首先接收header并验证它是一个新版本。         - 对于收到的后续数据消息,o 继续更新最旧的位置。         - 跳回应用程序(步骤 5)。 更新完成。         - 更新新的固件标头。         - 擦除/更新旧固件标头。         - 通过共享变量通知当前应用程序更新已完成。

6.3 使用位置无关代码 (PIC) 进行 A/B 交换

在更新过程之后,将有两个固件映像位于程序闪存中。图像位于闪存的不同物理地址中。为了能够在特定地址执行代码,应修改每个固件链接器以指示其将被放置的位置。为现场的每个设备跟踪新固件的放置位置可能很困难。因此,无论其在程序闪存上的地址如何,都可以方便地执行代码。 与位置无关的代码意味着固件无论在内存中的绝对地址如何都可以执行,这意味着代码中不会有绝对跳转。这允许在不需要修改链接器文件的情况下开发固件,并且固件可以从放置它的任何 pflash 存储器地址运行。 有一些编译器和工具可以使代码与位置无关,但有一些限制。例如,IAR 编译器提供只读的位置独立特性 (ropi),如下图所示。在这种情况下,在固件开发过程中需要考虑以下几个方面。         • 不能使用C++ 结构。         • 不能使用对象attribute_ramfunc。         • 指针常量不能用另一个常量、字符串文字或函数的地址来初始化。但是,可写变量可以在运行时初始化为常量地址。

还需要考虑生成的位置无关固件的中断表。即使固件确实包含相对跳转,也不会考虑到中断表地址的跳转。中断表中的地址不受 ropi 影响,并且与链接器文件中声明的地址相同。为了解决这个问题,中断在链接器文件中默认位于地址 0x00000000 开始,然后在更新过程中必须在中断表的每个条目中添加一个偏移地址,除了第一个条目是堆栈指针.地址偏移值取决于新固件在程序闪存中的位置。因此,当发生中断时,内核会跳转到程序闪存中放置应用程序固件的确切位置。

6.4 通信过程

通信更新过程包括六个主要步骤: 

        1. 更新触发检测。

        2. 头信息传输

        3. 应用数据传输。

        4.更新触发检测:第一步,接收来自主机的消息以触发更新过程。

        5. 头信息传输:虽然在用例中,头是最后写入闪存的部分,但因为它包含固件版本,所以首先接收它。将此值与当前固件版本进行比较,以验证收到的固件是否比闪存中最新下载的固件更新。如果接收到的固件版本相同或更旧,则停止更新过程,并向主机发送错误消息。如果它是较新的版本,则更新过程将继续。

        6、应用数据传输:最后一步,将固件地址和数据共享给bootloader。每次引导加载程序接收到有效消息时,它都会回复一个确认消息。 下图显示了这个过程。

6.5 安全通信

在更新过程中,主机和引导加载程序之间共享的固件容易受到攻击。可能的攻击可以嗅探网络以窃取固件的知识产权。另一种可能的攻击是从未经授权的主机向引导加载程序发送未经授权的固件,以操纵最终应用程序。为避免窃听、复制攻击并确保固件来自真实来源,必须在主机和引导加载程序之间建立安全通信。对于 S32K1xx 设备,由于包含 CSEc 模块,这是可能的。

窃听攻击是攻击者嗅探网络以获取共享固件的情况。然后,攻击者可以使用该数据使用固件重新编程其他未经授权的模块或窃取知识产权。为了避免这种攻击,更新过程中共享的数据是加密的。主机使用 AES-128 CBC 算法加密固件数据,并在将其发送到引导加载程序之前使用密钥。 Bootloader 接收此数据并使用相同的已知密钥对其进行解密。更新过程中不共享密钥,之前以离线方式存储在各个设备上。使用数据加密,可以保护固件的机密性。下一步要考虑的是共享消息的完整性和身份验证。未经授权的主机可以向引导加载程序发送数据,将数据下载到引导加载程序闪存中,这将导致设备故障。为了验证消息的来源以及消息未被修改,使用 CMAC 值。

使用已知密钥和要共享的数据从主机生成每条消息的 CMAC 值。当引导加载程序接收到带有固件数据的新消息时,它会使用与主机相同的密钥为接收到的数据计算 CMAC 值。引导加载程序计算出 CMAC 后,会将其与接收到的 CMAC 进行比较。如果 CMAC 验证正确,则认为收到的消息有效。如果 CMAC 值不同,则表明它不是来自授权来源或数据已损坏。因此,该消息被认为是无效的并且数据不会被下载到闪存。

除了保密和接收消息的真实性外,还应考虑消息的新鲜度以避免回复攻击。潜在的攻击者可以将通过嗅探网络获得的相同消息多次发送到引导加载程序,从而导致设备出现不需要的功能。为了防止这种攻击,可以在引导加载程序和主机之间的每条消息中共享一个随机数。 CSEc 模块包括两个可用于此目的的随机数生成器。

CSEc 随机数生成器是真随机数生成器 (TRNG) 和伪随机数生成器 (PRNG)。 TRNG 用于生成种子,随后用于 PRNG 使用 CSEc 命令生成随机数。随机数发生器应在每次复位后初始化;因此使用了一个新的随机种子。

对于更新过程,bootloader 会生成一个随机数并与主机共享,以避免回复攻击。 Bootloader 向主机发送一个普通的随机数,然后主机接收这个数字并使用 CBC 和一个已知密钥对其进行加密。下次主机向引导加载程序发送数据时,它会将加密的随机数与固件数据和 CMAC 一起添加。然后,引导加载程序接收消息并解密随机数。如果解密的随机数与之前共享的随机数相同,则消息是新鲜且有效的,否则可以认为消息无效。

在验证消息的新鲜度后,完成消息的解密和 CMAC 验证。

总之,主机和引导加载程序之间的安全通信包括三个主要方面:

        • 数据加密以保护知识产权。

        • CMAC 生成以验证源真实性和数据完整性

        • 随机数生成以防止回复攻击并检查源真实性。 下图显示了主机和引导加载程序之间的安全通信过程。

 

6.6 用例实现

6.6.1 引导加载程序固件

引导加载程序在 S32K144 和 S32K146 中实现,使用评估板 (EVB) 和 S32 Design Studio (S32DS) IDE。每次微控制器复位时,执行的引导加载程序都会执行。复位后,引导加载程序初始化其时钟和通信配置,并检查最旧固件所在的程序闪存物理区域。

在 S32K144 的情况下,bootloader 等待 4 秒以接收触发以启动更新过程,在这种情况下,触发是特定消息。如果触发发生,更新过程通过 CANFD 通信开始。如果 4 秒后没有触发,则引导加载程序会将时钟和通信外设配置恢复为默认值,并跳转到最新固件所在的位置。为了检测到触发消息,需要重置 S32K144,因此 4 秒周期再次开始。

对于 S32K146,bootloader 只等待 2 秒接收到触发,然后恢复时钟和通信外设,最后跳转到最新的应用程序。可以从网关发送触发消息以在当前固件执行时启动更新过程。为此,应用程序应依次初始化通信外围设备,以便准备好接收来自主机的消息。

引导加载程序放置在弹性存储区的前 16kB 中。 S32K144 或 S32K146 之前已分区用作 EEPROM 备份,其中 16kB 保留用于数据闪存(引导加载程序执行),而其他 48kB 用于 EEPROM 数据备份和 CSEc 的密钥存储。

下图显示了 S32K144 引导加载程序的链接器文件中指定的存储区域。

在 S32K146 引导加载程序用例中,除了为引导加载程序保留数据闪存中的空间外,还保留了 4 个字节的空间来存储加载程序入口点,以便正在运行的应用程序在收到更新命令时知道跳转到哪里。此外,在 ram 内存中保留了 4 个字节的空间,用于在加载程序和应用程序之间共享状态变量。下图显示了 S32K146 引导加载程序的链接器文件中的存储器组织。

 引导加载程序固件分为以下几层。

:引导加载程序和低级闪存驱动程序之间的内存抽象接口,用于启动写入和擦除等操作。:S32K1xx MCU 中闪存控制器的低级驱动程序,用于擦除/写入/验证操作。:引导加载程序和 CANFD 通信外设之间的抽象接口,用于处理来自主机的数据接收和确认消息的传输。:S32K1xx 设备中 FlexCAN 通信外设的低级驱动程序,用于通过 CANFD 总线发送和传输数据。:引导加载程序使用安全接口层来请求数据的加密/解密并验证接收到的消息的真实性和完整性,利用安全外围设备。:使用 S32K1xx 中的 CSEc 外设处理加密/解密操作和 CMAC 计算的低级驱动程序。

6.6.2 CANFD 通信

bootloader 支持CANFD 通信协议,执行更新过程。 CANFD标准比特率为500kbps,快速比特率为2Mbps。传输四种类型的消息,每种类型都有一个关联的 ID。         • 更新过程的开始。         • 固件/标头数据的地址。         • 固件或标题的数据。         • 确认/错误消息。 启动消息触发更新过程,它的 ID 为 0x200,其有效负载为 4 个字节,值为 0x15151515。地址报文,传输固件的逻辑地址或报头地址,其ID为0x100,有效载荷大小为4B。数据消息的结尾表示固件或标头的所有数据都已发送,其 ID 与地址消息相同,但有效载荷包含唯一值 0x53535353。固件或标头数据消息,包含将下载到闪存的数据,其 ID 为 0x300,有效负载大小为 32B。

这些消息从主机传输到引导加载程序,但引导加载程序也传输确认或错误消息。确认消息,表示上一条消息被正确接收,它的 ID 为 0x400,有效载荷大小为 4B,值为 0x04040404。消息错误,表示收到消息时出错或收到的固件版本不是最新的,它的 ID 也是 0x400,payload 大小为 4B,值为 0x55555555。下表总结了消息 ID 和有效负载。

6.6.3 安全 CANFD 通信

对于主机和引导加载程序之间的安全通信实现,使用 CANFD,这是因为每条消息的有效负载增加高达 64B。使用 64B 的有效载荷,可以发送 16B 用于 CMAC 和 16B 用于随机数,而剩余 32B 用于发送数据。对于上表中的消息,添加了有效载荷数据以包括 CMAC 和随机数值。

当引导加载程序从主机接收到启动消息时,如果这是正确的,则会向主机回复确认消息。除了 4B 的确认值外,还增加了 16B 的随机数以避免回复攻击。确认消息总共有 20B 长。下图显示了确认消息的组织方式。

 在地址报文中,除了用于传输地址的4B外,bootloader还期望接收之前发送的随机数的16B。因此,消息大小增加到 20B。由于这20个数据是加密的,并且加密是在16B的数据包中进行的,所以需要传输32B。剩余的 12B 用 0 填充。当引导加载程序收到此消息时,它会解密数据以比较随机数并验证源的真实性。无论是在地址消息中发送数据有效载荷的结尾还是发送地址,这都适用。下图显示了此消息的组织结构。

Bootloader 期望在数据消息中接收 64B 的有效载荷。这64B的数据由32B的固件数据、16B的为固件数据的32B计算的CMAC值和16B的随机数组成。完整的有效载荷是加密的。收到消息后,将其解密以比较随机数,并验证其真实性。然后比较 CMAC 值。如果随机数和 CMAC 都有效,则将数据下载到闪存中。在不匹配的情况下,错误消息会从引导加载程序传输到主机。下图显示了此消息的组织结构。

对于此示例,使用单个密钥来计算 CMAC 并加密所有消息,但可以使用多个密钥。可以使用一个密钥来计算 CMAC,而可以使用一个或多个不同的密钥来加密消息的数据。在这种情况下使用的密钥被加载到 RAM 中,但它可以存储在弹性内存安全区域中。该键的值为 0xc13dd10dbfb5e142316c6d5c2e903ec9。

7 演示

为了验证 a/b 交换用例,使用了具有 CANFD 通信的主机/网关设备。两个用例的软件组织如下:

        • S32K144 用例:1 个 S32K144 主机/网关项目和 1 个 S32K144 引导加载程序项目。         • S32K146 用例:1 个 S32K146 主机/网关项目和 1 个 S32K146 引导加载程序项目。

主机微控制器在其程序闪存中存储两个应用程序,固件 v1 和固件 v2,它们用于使用引导加载程序对设备进行编程。用于传输固件的主机程序代码正在弹性存储器中执行。该程序发送一条启动消息并等待引导加载程序确认。收到后,发送固件头,然后发送存储在自己的程序闪存中的固件。下图显示了 S32K144 和 S32K146 网关项目在闪存中的程序是如何分配的。

 要从主机开始传输,按下 SW2 或 SW3 以发送存储在主机闪存中的两个固件版本之一。当按下任一按钮时,传输开始。固件传输完成后,主机将准备好通过按下 SW2 或 SW3 发送另一个固件。为了将这两个应用程序存储在程序闪存中,使用 S32DS 中的主机/网关项目,为每个应用程序固件生成一个 bin 文件。 S32DS 项目的链接器被修改为在相应位置为此类二进制文件分配闪存。

应用固件是使用 IAR IDE 和位置无关功能开发的。固件版本标识为 V1 和 V2。两种固件都包括从定时器中断内部切换 LED(红色或蓝色 LED,取决于固件)。该固件还使用 EVB 板载 OpenSDA 接口通过 LPUART 接口将消息打印到 PC 控制台,该接口枚举为虚拟 COM 端口。打印的消息主要指示正在运行的 LED 应用程序、应用程序版本和运行应用程序的程序闪存区域。区域 A 对应于下程序闪存区域,而区域 B 对应于上闪存区域。对于 S32K144,这两个区域 (A/B) 只是来自同一个 pflash 读取分区的两个不同的内存空间,而对于 S32K146,这两个区域映射到两个可用的 pflash 读取分区。当网关触发新的更新过程时,S32K146 用例的应用程序固件额外打印消息“Update in progress...”,最后在更新完成时打印消息“New firmware version ready,resetting device...”完全的。

下图显示了每个演示用例的设置。

 

 

7.1 设置演示

本节介绍每个引导加载程序用例演示的设置。相应的 S32 Design Studio 项目和 IAR 应用项目作为软件包与本应用笔记一起包含在内。

7.1.1 设置 S32K144 引导加载程序演示

工作区 OTA_S32K144_Use_Case_WS 包括以下项目:

        • S32K144_Memory_Partition:该项目设置 S32K144 的弹性存储器,为 48 KB 的 EEPROM 备份和 16 KB 的代码。

        • S32K144_FOTA_Bootloader:该项目是 S32K144 边缘节点微控制器的引导加载程序

        • S32K144_FOTA_Gateway:该项目适用于充当主机/网关的 S32K144 设备。该项目包括两个预编译的应用固件 (v1/v2) 的二进制文件。

需要以下硬件:

        • 2 x S32K144 EVB 板。         • 4 x 母对母跳线。         • 1 根微型 USB 电缆。         • 1 x 12 V 电源。

按照以下步骤安装和运行演示:

        1) 打开 S32DS 并选择文件夹 OTA_S32K144_Use_Case_WS 作为工作区。

        2) 将 S32K144_Memory_Partition 项目导入、构建和下载到每个 S32K144 EVB,为每个设备的 flex memory 分区,用于 48 KB 的 EEPROM 备份和 16 KB 的代码。网关和引导加载程序执行的代码将在 16 KB 的弹性内存区域上运行。

        3) 选择一个 S32K144 EVB 作为网关设备。将 S32K144_FOTA_Gateway 项目导入、构建和下载到此 EVB。

        4) 将 S32K144_FOTA_Bootloader 导入、构建并下载到另一个 S32K144 EVB。

5) 如下设置所需的板连接:

        • 使用跨接电缆连接板之间的 CAN 信号和共享 VBAT 电源。         • 在两个板上,将跳线J107 更改为1-2 的位置。这是使用外部电源为电路板供电。         • 将12 V 电源连接到其中一个板(任何板)。两块板上的 LED D3 应亮起。         • 将微型 USB 电缆连接到边缘节点 EVB(引导加载程序)中的微型 USB 连接器 (J7),并将另一端连接到 PC。 LED D2 应亮起。

6)打开串口终端,选择OpenSDA虚拟COM,设置终端波特率为9600。

7) 通过按下复位按钮 SW5 来复位边缘节点 EVB(引导加载程序板)。

8) 在 4 秒超时到期之前,按下网关板中的 SW2(蓝色 LED,v1 固件)或 SW3(红色 LED,v2 固件)。

9) 更新完成后,边缘节点固件版本对应的LED开始闪烁,终端显示新固件信息

7.1.2 设置 S32K146 引导加载程序演示

工作区 OTA_S32K146_Use_Case_WS 包括以下项目:

        • S32K146_Memory_Partition:该项目设置 S32K146 的弹性存储器,为 48 KB 的 EEPROM 备份和 16 KB 的代码。         • S32K146_FOTA_Bootloader:该项目是 S32K146 边缘节点微控制器的引导加载程序

        • S32K146_FOTA_Gateway:该项目适用于充当主机/网关的 S32K146 设备。该项目包括两个预编译的应用固件 (v1/v2) 的二进制文件。 需要以下硬件:

        • 2 x S32K146 EVB 板。         • 4 x 母对母跳线。         • 1 根微型 USB 电缆。         • 1 x 12 V 电源。 按照以下步骤安装和运行演示:

1) 打开 S32DS 并选择文件夹 OTA_S32K146_Use_Case_WS 作为工作区。

2) 将 S32K146_Memory_Partition 项目导入、构建和下载到每个 S32K146 EVB,为每个设备的 flex memory 分区,用于 48 KB 的 EEPROM 备份和 16 KB 的代码。网关和引导加载程序执行的代码将在 16 KB 的弹性内存区域上运行。

3) 选择一个 S32K146 EVB 作为网关设备。将 S32K144_FOTA_Gateway 项目导入、构建和下载到此 EVB。

4) 将 S32K146_FOTA_Bootloader 导入、构建并下载到另一个 S32K146 EVB。

 

5) 如下设置所需的板连接:

        • 使用跨接电缆连接板之间的 CAN 信号和共享 VBAT 电源。

        • 在两个板上,将跳线J107 更改为1-2 的位置。这是使用外部电源为电路板供电。

        • 将12 V 电源连接到其中一个板(任何板)。两块板上的 LED D3 应亮起。

        • 将微型 USB 电缆连接到边缘节点 EVB(引导加载程序)中的微型 USB 连接器 (J7),并将另一端连接到 PC。 LED D2 应亮起。

6)打开串口终端,选择OpenSDA虚拟COM,设置终端波特率为9600。 7) 按网关板中的 SW2(蓝色 LED,v1 固件)或 SW3(红色 LED,v2 固件)。 8) 更新完成后,边缘节点固件版本对应的LED开始闪烁,终端显示新的固件信息。

8 参考资料

• S32K 系列参考手册

• 使用 IAR 定位独立代码

• 使用链接器命令将二进制文件合并到 S32 Design Studio 项目中

标签: 90k1集成电路

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台