配网流程
- 概述
- 配网协议
- 配网承载层(Provisioning Bearer)
- 配网协议(Provisioning Protocol)
- 流程详解
- 发送Beacon信号
- 邀请
- 交换公共密钥
- 认证
- 输出带外(Output OOB)
- 输入带外(Input OOB)
- 静态带外(Static OOB) 或无带外(No OOB)
- 检查确认值(Check Confirmation Value)
- 确认值检查(Confirmation Value Check)
- 配置数据分发
- 参考资料
概述
配网流程(Provisioning)是向蓝牙 Mesh 网络(如灯泡)添加新的未经配置设备的过程。该过程由配网器(Provisioner) 进行管理。配网器和未经配置设备遵循蓝牙 Mesh 规格中定义的固定过程。配网器向未经配置设备提供使其成为蓝牙 Mesh 节点的配置数据(provisioning data)。
配网器通常是运行配网器应用程序的智能手机或其它移动计算设备。尽管每个网络只需要一台配网器来执行配网,但可用的配网器可以有多台。
完整的配网过程必须在更高的层面完成两项重要任务:
- 验证未经配置的设备。在蓝牙 Mesh 网络中,一个小空间中可能存在几台、几十台或数百台设备。执行认证是为了确保与配网器进行交互的设备就是用户想要配置的设备。
- 与未经配置的设备建立安全链接,并与之共享相应的信息。在流程的最后,原本未经配置的设备将成为蓝牙 Mesh 网络中的节点。
配网协议
蓝牙 Mesh 规格中定义了配网协议,该协议定义了配网流程中用于在配网器和新的未经配置设备之间进行通信的标准流程以及 PDU。下图描绘了完整蓝牙 Mesh 协议栈之外的配网协议栈。
从下到上的组件如下:
配网承载层(Provisioning Bearer)
配网承载层实现了配网 PDU 在配网器和未经配置设备之间的传输。定义的两个配网承载层包括:
-
PB-ADV:指通过蓝牙广播信道进行设备配置的配网承载层。PB-ADV 承载层用于发送通用配网 (Generic Provisioning) PDU。支持 PB-ADV 的设备应尽可能执行占空比接近 100% 的被动扫描,以避免遗漏任何发送来的通用配网 PDU。
-
PB-GATT:指使用来自代理协议的蓝牙 Mesh 代理(proxy)PDU 来进行设备配置的配网承载层。代理协议能使节点通过面向连接的低功耗蓝牙(Bluetooth Low Energy)承载层来收发网络 PDU、mesh Beacon、代理配置消息和配网 PDU。PB-GATT 在 GATT 操作中包含了配网 PDU,涉及 GATT 配网服务,同时能在配网器不支持 PB-ADV 时供其使用。
配网协议(Provisioning Protocol)
定义对于配网 PDU、行为和安全性的要求。了解配网协议将有助于您根据应用需求选择合适的验证方法。
配网协议定义了 10 种配网PDU:
- 配置邀请 (Provisioning Invite)
- 配置能力 (Provisioning Capabilities)
- 配置状态 (Provisioning State)
- 配置公钥 (Provisioning Public Key)
- 配置输入完成 (Provisioning Input Complete)
- 配置确认 (Provisioning Confirmation)
- 配置随机 (Provisioning Random)
- 配置数据 (Provisioning Data)
- 配置完成 (Provisioning Complete)
- 配置失败 (Provisioning Failed)
流程详解
配网流程包括五个阶段:
- 发送 Beacon 信号:如果未经配置的设备支持 PB-ADV承载层,则其作为未经配置设备 Beacon 进行广播;如果使用的是 PB-GATT 承载层,则发送可连接的广播数据包。这就向配网器(Provisioner)表明未经配置的设备已做好准备,可进入配网流程。
- 邀请:配网器(Provisioner)邀请未经配置的设备发送自身配置功能信息。
- 交换公共密钥:在此阶段,根据未经配置设备的功能,配网器(Provisioner)选择合适的验证方法,并通知未经配置设备将要采取的方式。之后,配网器和未经配置设备会创建一个椭圆曲线公私密钥对并交换公钥。然后,每台设备使用自己的私钥和对等设备的公钥来计算对称密钥,即 ECDHSecret。该密钥用于验证对端设备的身份。
- 认证:在此步骤中,配网器使用所选的验证方法,对未经配置设备进行验证。
- 配置数据分发:认证步骤完成之后,就可以确保在配网器(Provisioner)和未经配置设备之间建立的承载层的安全,然后就进入配网(Provisioning)过程中最重要的一步:导出并分发配置数据(provisioning data)。
发送Beacon信号
Beacon 是低功耗蓝牙的传统应用场景。想象一下,一个GAP外设(如智能手表或活动跟踪器)希望与GAP中央设备(如智能手机或平板电脑)连接。 GAP外设切换到广播状态并开始发送其广播数据包。GAP中央设备扫描广播数据包以发现其它设备并接收相关基本信息。蓝牙 Mesh 配置使用的也是相同的广播机制。
如果未经配置的设备支持 PB-ADV 承载层,则其作为未经配置设备 Beacon 进行广播。这涉及指定的数据包格式,且未经配置设备通过此方式来使自身被配网器 (Provisioner) 发现。
当未经配置设备使用 PB-GATT 承载层时,一项称为“Mesh 配置服务”的 GATT 服务会支持整个配网流程,同时支持与配网器的交互。在发送 Beacon 信号阶段,未经配置设备会发送包括 mesh 配置服务 UUID 的广播数据包,它会被配网器通过标准的低功耗蓝牙扫描程序发现。
邀请
在发送 Beacon 信号之后,配网器和未经配置设备会建立 PB-ADV 或 PB-GATT 配网承载层(provisioning bearer)。然后,配网器发送一个配置邀请 PDU,设备通过配置功能 PDU 对其作出响应。
配置邀请 PDU 包括 Attention Duration 字段,其指示了未经配置设备的主要元素应采用某种视觉指示方式,并在多长的时间内吸引用户的注意力。
配置功能 PDU 包括:
- 设备支持的元素数量;
- 支持的一组安全算法;
- 使用带外(OOB)技术实现的公共密钥可用性;
- 该设备向用户输出值的能力。
- 该设备允许用户输入值的能力。
上图中的流程图让人联想到低功耗蓝牙中的配对过程。 低功耗蓝牙配对采用的配对特性交换类似于蓝牙Mesh 配置程序中的配置邀请阶段。在配置邀请阶段,目的是向配网器(Provisioner) 提供有关未经配置设备功能的信息。有了这些信息,配网器就能决定下一步该如何进行。
交换公共密钥
信息加密涉及两项基本技术:对称加密(也称为密钥加密)和非对称加密(也称为公钥加密)。
- 对称加密采用相同的密钥进行加密和解密。只要发送设备和接收设备都知道密钥,就能够解密所有使用此密钥加密的信息。然而,很难安全地通过链路交换密钥并防止其落入坏人之手。
- 非对称加密使用两个相关的密钥(即一个密钥对)来解决上述问题:公钥和私钥。公钥免费提供给任何可能想向您发送消息的人。私钥则为保密,只有你自己知道。使用公钥加密的任何消息(文本、二进制文件或对称密钥)只能通过应用相同的算法、且仅能使用与之匹配的私钥进行解密。这意味着您不必对通过链接传递公钥的过程有任何担忧,因为它们仅用于加密而非解密。然而,非对称加密比对称加密慢一些,且需要更高的处理能力来进行消息内容的加密和解密。
在蓝牙 Mesh 用例中,大多数设备基于嵌入式芯片组或模块,因此无法使用计算成本昂贵的非对称加密技术来对每个消息进行加密/解密。对称加密更适合于不具备非对称加密所需处理能力的设备,但如何安全地交换并使用密钥仍然是一大问题。蓝牙mesh采用了非对称和对称加密结合的方式来解决这一问题。
- 非对称加密:椭圆曲线 Diffie-Hellman(ECDH)是一种匿名密钥协商协议,允许具有椭圆曲线公私密钥对的双方在非安全信道上建立共享保密信息。ECDH 在蓝牙 Mesh 配置中的目的是在配网器和未经配置设备之间创建安全链路。它使用公钥和私钥来分发对称性密钥,两台设备随后可将其用于后续消息的加密和解密。
- 对称加密:在蓝牙 Mesh 网络中传输的每个消息都使用 AES-128 密码加密。 AES-128 算法是常用的对称加密/解密引擎,常用于嵌入式平台。
在交换公钥阶段,有两种交换 ECDH 公钥的可能方式。它们可以通过蓝牙链路、或 OOB 隧道进行交换。在配置邀请阶段,未经配置的设备已经报告了是否支持通过 OOB 隧道发送自身公钥。如果是,则配置设备可继续使用它,并通过发送配置开始 PDU 来通知未经配置的设备。
如果未经配置设备的公钥可通过 OOB 隧道获得,则临时公钥从配网器发送到设备,并采用合适的 OOB 技术(例如二维码),从未经配置的设备中读取静态公钥,如图所示。
否则,双方的公钥都会经由下图中所示的蓝牙链路进行交换。
ECDHSecret = P-256 (私钥,对等公钥)
在该等式中,P-256即FIPS 186-3中定义的FIPS-P256曲线。
认证
在此步骤中,配网器使用所选的验证方法,对未经配置设备进行验证。有三种可用的验证方法(OOB, Out-Of-Band):输出 OOB(Output OOB)、输入OOB(Input OOB)、以及静态OOB(Static OOB)或无OOB(No OOB)。
输出带外(Output OOB)
若选择的是输出带外(Output OOB)验证方法,则未经配置设备会选择一个随机数,并通过与其功能兼容的方式输出该数字。例如,如果未经配置设备是一个灯泡,则它能够闪烁指定的次数。如果设备具有 LCD 屏幕,则可以将随机数显示为多位数值。配网器(Provisioner)的用户需要输入观察到的数字,来验证未经配置的设备。输出带外验证方法的工作流程如下图所示。
输入随机数后,配网器(Provisioner)生成并检查确认值。无论采用哪种验证方式,整个验证步骤中的检查确认值(check confirmation value)计算方式都是相同的。
输入带外(Input OOB)
输入带外(Input OOB)验证方法与输出带外(Output OOB)方法类似,但设备的角色相反。配网器(Provisioner)生成并显示随机数,然后提示用户采取适当的操作,将随机数输入未经配置的设备。以照明开关为例,用户可以在一定时间内数次按下按钮,以这种形式输入随机数。
与输出带外验证(Output OOB)相比,输入带外(Input OOB)方法需要发送一个附加的配置协议PDU。在完成认证操作之后,未经配置的设备向配网器发送一个配置输入完成 PDU(Provisioning Input Complete PDU),通知其随机数已输入完成。随后进入到执行检查确认值操作的步骤。
静态带外(Static OOB) 或无带外(No OOB)
在输入带外或输出带外都不可用的情况下,配网器(Provisioner)和未经配置的设备可采用静态带外(Static OOB)验证或无带外(No OOB)验证:采用静态OOB信息;或静态OOB信息不可用,直接以数值 0 代替。在此情况下,配网器和未经配置的设备各自生成一个随机数,然后进行检查确认值操作。
检查确认值(Check Confirmation Value)
无论采用何种验证方法,都会进行确认值生成和检查。根据蓝牙 Mesh 规格,配网器(Provisioner) 和未经配置设备应分别计算确认值。这两个值被称为 ConfirmationProvisioner 和 ConfirmationDevice。这两个值的计算都使用一系列相同的函数,不同之处仅在于所使用的随机数输入。
让我们来看看用于确认值生成的算法。下图是一个流程图,其中包括了几轮AES-CMAC和SALT生成[1]。该流程图对于 ConfirmationProvisioner 和 ConfirmationDevice 值均适用。
- 如果由配网器(Provisioner)执行输入,则从一个名为 RandomProvisioner 的值开始(下图中以蓝色表示),并生成ConfirmationProvisioner值。
- 如果由未经配置设备执行输入,则从一个名为 RandomDevice 的值开始(下图中以绿色表示),并生成 ConfirmationDevice 值。
确认值检查(Confirmation Value Check)
当确认值生成之后,两台设备就会进行交换,并且都会检查接收值的完整性。图4表示确认值检查的过程。
确认过程的开始就是配网器(Provisioner)将其随机数 RandomProvisioner 发送到未经配置的设备。未经配置设备使用它来重新计算确认值,并与之前接收的确认值进行比较,进行验证。
- 如果由未经配置设备计算所得的确认值与接收到的 ConfirmationProvisioner 不匹配,则配网(Provisioning)过程将被中止。
- 如果由未经配置设备计算所得的确认值与接收到的 ConfirmationProvisioner 匹配,则未经配置设备将其 RandomDevice 值发送给配网器。
然后,配网器(Provisioner) 使用相同的过程来重新计算确认值,并通过比较计算所得值与先前接收值来进行验证。
- 如果由配网器(Provisioner) 计算所得的确认值与接收到的 ConfirmationDevice 不匹配,则配网(Provisioning)流程将被中止。
- 如果由配网器(Provisioner) 计算所得的确认值与接收到的 ConfirmationDevice 匹配,则表示验证成功。后续只要配网器(Provisioner)和未经配置设备完成配网流程的第五步:配置数据分发,则未经配置设备就能成为蓝牙 Mesh 网络中的节点(node)。
配置数据分发
认证步骤完成之后,就可以确保在配网器(Provisioner)和未经配置设备之间建立的承载层的安全,然后就进入配网(Provisioning)过程中最重要的一步:导出并分发配置数据(provisioning data)。配网器(Provisioner) 负责生成配置数据,配置数据由多个数据项组成,包括一个称为网络密钥 (NetKey) 的安全密钥。下表列出了配置数据字段。
字段 | 大小(字节) | 注释 |
---|---|---|
网络密钥 | 16 | 简称 NetKey。NetKey 确保网络层(network layer)通信的安全,并在网络中所有节点(node)之间共享。是否拥有给定的 NetKey 定义了给定蓝牙 Mesh 网络或子网的成员资格。为设备赋予网络的 NetKey 是配网(Provisioning)流程的主要结果之一。 配网器(Provisioner) 在对要添加到网络中的首台设备进行配置时创建 NetKey。 |
设备密钥 | 16 | 简称 DevKey,只有配网器(Provisioner)和被配置的设备拥有的唯一安全密钥 。 |
密钥索引 | 2 | 由于 NetKey 太长,无法在单段消息中传输。为使消息传递尽可能高效,会向密钥分配一个全球唯一的12位索引值,称为密钥索引,用作密钥的短标识符。消息中包括密钥索引值,它可能以配置客户端(Configuration Clients)维护的密钥列表为参考。 |
标志 | 1 | 标志位掩码 - 指示关联密钥的状态。 |
IV 索引 | 4 | IV(初始化向量)索引是一个32位的值,被网络中的所有节点 (node)共享。其目的是在计算消息随机值时提供熵(随机性)。 |
单播地址 | 2 | 新节点中主要元素的单播地址(Unicast Address)。 |
为安全地进行配置数据分发,配网器(Provisioner)采用AES-CCM [2],借助共享的会话密钥(SessionKey)对配置数据(provisioning data)进行加密,配网器和未经配置设备都会进行计算。 AES-CCM需要三个输入参数:会话密钥、会话随机数和纯文本。纯文本参数值包含需要被加密的配置数据。设备密钥(DevKey)、会话密钥(SessionKey)和会话随机数(SessionNonce)的值通过图所示的过程导出。
从图中可以看出:
- 如果将 prsk(绿色)的输入值代入k1函数中,则会生成 SessionKey。这是用于配置数据加密的关键。
- 如果将 prsn(黄色)的输入值代入k1函数中,将生成 SessionNonce。这是用于配置数据加密的随机值。
- 如果将 prdk(蓝色)的输入值代入k1函数,则将生成 DevKey。
配网器(Provisioner)和未经配置设备都需要生成会话密钥(SessionKey)和会话随机数(SessionNonce)。当 SessionKey 和 SessionNonce 值准备就绪时,配网器将对包含导出配置数据的配置数据 PDU (Provisioning Date PDU) 进行加密,并将其发送至未经配置的设备。此处,相同的 SessionKey 和 SessionNonce 值也可用来对接收到的数据进行解密。
至此,配网流程完成。两台对等设备都已知晓新的设备密钥(DevKey)和全网的网络密钥(NetKey),这就意味着我们的新设备已成为蓝牙 Mesh 网络中的节点(node)和成员。
参考资料
- 解密蓝牙mesh系列 | 第十篇
- 解密蓝牙mesh系列 | 第九篇
- [1] 有关AES-CMAC和SALT的更多信息,请参阅《蓝牙mesh - 安全概述》。
- [2] 有关这些术语的更多信息,请参阅《蓝牙mesh - 安全概述》。