目录
1.2、Generic Provisioning layer
1.2.1、Generic Provisioning PDU types
2、Link Establishment procedure
3、Generic Provisioning behavior
4.1.2、Provisioning capabilities
4.1.5、Provisioning Input Complete
4.1.6、Provisioning Confirmation
Provisioning 是将未配网设备加入到 mesh 网中的过程,该过程是通过 provisioner 来实现的。Provisioner向未配网设备提供provisioning 数据,其中包括 network-key、当前网络的 IV_Index,还有设备每一个 element 对应的 unicast 地址。
provisioner可以是手机或者其他智能设备,一个mesh网中只需要一个provisioner角色,但是亦可以允许多个provisioner实现,多个provisioner共存时的数据共享可以被特定实现。
provisioning过程,首先需要在未配网设备和provisioner节点间建立一个provisioning-bearer。未配网设备向provisioner广播自己的 UUID 以及其他必要信息(Mesh beacon)。provisioner连续扫描消息,收到未配网设备的消息时,选择与某一个对应的设备建立 provisioning-bearer。
Provisioning-bearer 建立后,provisioner与为配网设备间使用Elliptic Curve Diffie-Hellman (ECDH)协议加密。
框架图如图:
Provision协议使用分层的结构,如上图所示。设备的provision过程是通过发送provisioning-PDU实现的。provisioning-PDU通过generic provision layer层发往未配网设备。该层定义了provisioning-PDU是如何传输、分段重组的,传输包通过provisioning-bearer发送。provisioning-bearer定义了连接对话是如何建立的,即generic provision layer的传输包是怎样被传送到设备的。最后,在provision结构的最下层就是 bearers。
1、Provisioning bearer layer
provisioning bearer layer 实现了在 provision 过程中 provisioning PDUs 的传输。mesh协议中定义了两种 provisioning bearers
- PB-ADV
- PB-GATT
未配网设备可以支持 PB_ADV 或是 PB_GATT,建议在未配网设备同时实现两种 bearer。provisioner至少支持一种,强烈建议provisioner支持 PB-ADV。
1.1、PB_ADV
PB-ADV是一个provisioning bearer,是用来在advertising channel上使用Generic Provision PDUs来进行provision的。provision机制是基于对话(session)的。一个未配网设备一次只能支持一个对话(session),而对于provisioner则无此限制。
PB-ADV用来传输Generic Provisioning PDUs,PB-ADV bearer最大的传输单元(Maximum Transmission Unit, MTU)是24个字节。
针对 PB-ADV 这种承载层类型,根据 ADV 数据的承载规则,定义了数据:
这里的 AD Type 被 mesh spec 指定为 《PB-ADV》,通过查阅 Spec
https://www.bluetooth.com/specifications/assigned-numbers/generic-access-profile/
发现 《PB-ADV》 为 0x29;
注意:支持 PB-ADV 的设备应该以占空比100%的频率扫描消息,以免丢失Generic Provision PDUs
可以看到,这个 Contents 的类型是 PB-ADV PDU 包,它的组成是:
LinkID:用来表示两个设备之间的一个连接。
Transaction Number:包含一个1-byte的值,用来表示每个Generic Provisioning PDU, 如果Generic Provisioning PDU经过了分段,则每个分片的Transaction Number 都是相同的。而且当Generic Provisioning PDU重发时,该值也是不变的。
在实现时还需要遵循以下几条规则:
- 当PB-ADV PDU包含Provisioning Bearer Control PDU时, Transaction Number应该设置为0.
- 当一个Provisioner通过一个打开的provision link,首次发送Provisioning PDU时,Transaction Number 的值应该从0x00开始,每发送一个Provisioning PDU该值累加。当到达0x7F时,返回的0.
- 当未配网设备通过一个打开的provisin link首次发送PDU时,Transaction Number的值应该从0x80开始,每发送一个provisioning PDU累加1.当到达0xFF时,返回到0x80.
- 当一个设备收到provisioning PDU时,将会根据收到包的Transaction Number值来设置该值。
- 当一个设备发送Transaction响应PDU时, Transaction Number 值应该设置为其响应的那条消息的 Transaction Number 值。
1.2、Generic Provisioning layer
Generic Provisioning PDU 包含两部分,一部是Generic Provisioning Control(GPC)field, 紧接着是Generic Provisioning Payload。
其中的两个位域的字节数和含义为:
Generic ProvisionIng Control field 的最低两位包含一个 Generic Provisioning Control Format (GPCF)field,该值决定了PDU 的类型。
GPCF 的含义定义如下:
1.2.1、Generic Provisioning PDU types
1.2.1.1、Transaction Start PDU
Transaction Start PDU (Generic Provisioning Control)用来开始一段分段消息传输,其格式如下:
SegN:代表了分段的最后一个分段的 number;可以理解为有多少个分段;
GPCF:2’b00 代表是 Transaction Start PDU
TotalLength: Provisioning PDU 的字节数
FCS:Provisioning PDU 的 Frame Check Sequence
1.2.1.2、Transaction Acknowledgment PDU
Transaction Acknowledgment PDU 用来应答一个 Provisioning PDU
GPCF 固定为 0'b01;
1.2.1.3、Transaction Continuation PDU
Transaction Continuation PDU用来传输后续的 provisioning PDU,其结构如下所示:
SegmentIndex:指明分段的 Index
GPCF 固定为 0'b10;
1.2.1.4、Provisioning Bearer Control
Provisioning Bearer Control PDU 用来管理 bearer 上的对话(session),其格式如下:
因为它含有 Opcode 和 Parameters,所以根据不同的 Opcode,Provisioning Bearer Control 在细分为:
A、Link Open
该消息用于打开一个连接,该消息需要使用Link-ACK-message来响应。
一个设备一次只能处理一个连接,当一个连接处于活动状态时,会忽略其他的Link-Open-message.
Link_Open_message消息的参数是需要建立连接的设备的UUID,如下所示:
B、Link ACK
该消息用来响应Link-Open-message,没有参数,只有一个字节,如下所示:
C、Link Close
该消息同来关闭一个连接,由于该消息是没有响应的,因此发送端需要重复发送该消息至少三次,连接两端都可以发送该消息,并处理该消息。该消息的参数域描述关闭连接的原因,其结构如下:
1.3、Provisioning 包组成小结
2、Link Establishment procedure
Link Establishment procedure 用于建立一个对话(session), 一个对话用 Link ID 标识,在连接过程中该值不会变化。Link ID需要随机生成,以避免多个对话间冲突。
连接建立时,未配网设备使用 UUID 标识,Provisioner 扫描未配网设备的广播(Mesh beacon),然后provisioner发起 Link-Open-message 来建立连接。Link-Open-message 中包含了未配网设备的UUID。在PB-ADV上的PB-ADV PDU包含了连接的Link ID.
对于一个没有配网并且已经收到了Provisioning Invite PDU的设备,当其收到 Link Open messsage 时,会响应该消息返回一个带有相同 LinkID 的Link ACK message.
连接可以在任何时候通过发送 Link Close message 来关闭,连接的两端都可以发送该消息。
连接建立的流程可以用下图表示:(一个通用流程)
解读如下:
1、空中有 3 个未入 mesh 网的设备,#1、#2、#3,他们通过 Mesh Beacon 来告知别人希望入网(包含UUID和OOB)
2、有一个 Provisioner 听到了有三个希望入网的设备,选择了 UUID #2 的设备入网;
3、Provisioner 给 #2 设备发送 Link Open 消息(UUID 为 #2);
4、#2收到了 Link Open 消息,并回复 Link ACK;
5、开始入网流程 Provisioning Process;
6、#2 发送 Link Close,携带 Reason(是否入网成功);
Provisioning Process 是一个稍微复杂一些的过程,在后面罗列;
3、Generic Provisioning behavior
每个Generic Provisioning PDU发送时,要与上一个PDU有一个20~50毫秒的随机延时。
每个Provisioning PDU都应该作为一个独立的消息包,每个消息包由一个或多个分段组成。
Provisioning PDU被分段的数量,取决于该PDU的大小,segment Index可以是0~63之间的数。segment 0 应该使用Transaction Start PDU来发送。其他的分段应该使用Transaction Continue PDU来发送。每个分段都被放入Generic Provisioning Payload中。
每个bearer都有一个MTU最大值限制,每个Generic ProvisionIng PDU都应该是最长的MTU长度,最后一个分段除外。
发送端需要顺序发送每个分段,如果发送端没有收到回应,那么发送端会重发整个PDU的所有消息。
若果发送端收到了 Transaction Acknowledgement message,则表示传输成功。
如果发送端在发送第一条消息后30秒内,没有收到Transaction Acknowledgement message,则发送端会取消传输,终止provision过程,关闭link。
接收端会根据Transaction Start PDU中的内容,判断分段的个数。
在PB-ADV bearer中,当接收端收到了所有的分段,它会计算收到Provisioning PDU的FCS,如果该值符合Transaction Start PDU中的FCS值,那么接收端就会在一个20~50毫秒的人随机延时之后,发送一个Transaction Acknowledgement PDU。
4、Provisioning protocol
4.1、Provisioning PDUs
Provisioning PDUs 用来在 Provisioner 和 device 之间交互,Provisioning PDUs用 Generic Provisioning layer 层来进行传输。
他在整个包中的位置是:
Provisioning PDUs 的格式如下:
第一个字节的 Type 决定了 Provisioning PDUs Parameters的格式:
Type | Name | Description |
0x00 | Provisioning Invite | 邀请一个设备加入mesh网络 |
0x01 | Provisioning Capabilities | 指示设备的能力 |
0x02 | Provisioning Start | 指示provisioner基于设备的能力所选择的provisioning方式 |
0x03 | Provisioning Public Key | 包含设备的或者prvisioner的Public Key |
0x04 | Provisioning Input Complete | 指示用户已经完成值输入 |
0x05 | Provisioning Confirmation | 包含provisioner的或者设备的provisioning确认值 |
0x06 | Provisioning Random | 包含设备的或者provisioner的provisioning随机值 |
0x07 | Provisioning Data | 包括分配给主元素的unicast地址,一个网络密钥(network key),NetKey索引,标志(Flags)和IV索引 |
0x08 | Provisioning Complete | 指示provisioning完成 |
0x09 | Provisioning Failed | 指示provisioning失败 |
0x0A-0xFF | RFU | 为将来使用保留 |
4.1.1、Provisioning Invite
Provisioner 发送Provisioning Invite 来指示device provisioning 流程开始,Provisioning Invite PDU的 Parameters 部分定义如下:
4.1.2、Provisioning capabilities
device 发送这个消息给 Provisioner 用来指示自己支持的 provisioning capabilities,parameters 格式如下
配网能力PDU包含:
- The number of elements the device supports. 设备有的元素数量
- The set of security algorithms supported. 支持的安全机制
- The availability of its public key using an Out-of-Band (OOB) technology. 公钥的使用OOB的方法
- The ability for this device to output a value to the user. 输出一个值给用户的能力
- The ability for this device to allow a value to be inputted by the user. 用户输入值的能力
每个字段还有子字段,详见 Spec,内容较多,不在过细的分析;
4.1.3、Provisioning Start
Provisioner 根据 Provisioning Capabilities PDU 的选择来指示启动配置的 method,就是再 Provisioning Start 这个PDU中发送的,Parameters 的格式如下:
4.1.4、Provisioning Public Key
Provisioner 发送这个PDU来颁发 public key(通过ECDH 加密计算),
有两种加密信息的技术:对称加密(密钥加密)对称加密(公钥加密)。
Symmetric encryption 对称加密 使用同样的密钥来加密和解密。因为发送端和接收端都知道密钥,他们可以加密和解密所有的报文。但是,这种方法使得交换密钥会非常困难,很难保证这个密钥不落入他手。
Asymmetric encryption 非对称加密,使用两个相关密钥,一对密钥--公钥和私钥,来解决刚才对称加密遇到的问题。公钥可以给任何需要发信息给你的设备,而私钥是保密的,只有你自己知道。任何使用公钥来加密的信息(文字,二进制文件或者对称密钥)只能使用相同的算法和对应的私钥才能解密。这意味着你不用担心传输公钥,因为他只能加密而不能解密。但是非对话加密会要求更多的处理能力和时间来完成加密和解密。
在蓝牙Mesh的使用场合,大部分的设备是基于嵌入式芯片或者模块的,所以如果每次通信都用非对称加密的话代价太大。所以蓝牙选择的是两种方式的结合。
Asymmetric cryptography不对称密码:椭圆曲线Diffie–Hellman
(ECDH)是一种匿名密钥协议协议,允许双方各有一个椭圆曲线公私密钥对,在不安全的通道上建立一个共享的秘密。在蓝牙网格配置中,ECDH的目的是允许创建配网者和未配网设备之间的安全链接。它使用公钥和私钥分发一个对称密钥,这两个设备可以用来加密和解密后续消息。
- Symmetric cryptography:对称密码:在蓝牙Mesh网络中传输的每条消息都使用AES - 128加密技术进行加密。AES - 128算法是一种通用的对称加密/解密引擎,常用于嵌入式平台。
在交换公钥阶段,有两种方法可以交换ECDH公共密钥。它们可以通过蓝牙连接或通过OOB隧道进行交换。在配网邀请阶段,未配网设备已经报告是否支持通过OOB隧道发送其公钥。如果支持,配网者人可以继续使用它,并通过发送一个配网启动PDU通知未配网设备。
如果没有未配网设备支持通过OOB隧道的公钥交换,那么一个临时的公钥就从配网者传输到设备,未配网设备可以使用适当的OOB技术来读取一个静态公共密钥 (比如二维码),见图。如果不支持OOB隧道,那就通过一个BLE的连接通道交换;
详见 :https://www.bluetooth.com/blog/provisioning-a-bluetooth-mesh-network-part-1/
Parameters 格式如下:
4.1.5、Provisioning Input Complete
当用户完成输入操作的时候,device 发送这个PDU,这个PDU没有 parameters
4.1.6、Provisioning Confirmation
Provisioner 或者 device 发送这个 PDU 给配对方,以此来证实数据已经交互了,交换的数据包括 OOB Authentication value 和random number,Parameters格式如下:
4.1.7、Provisioning Random
Provisioner或者Device发送这个PDU来验证Confirmation值的有效性,格式定义如下:
4.1.8、Provisioning Data
Provisioner发送这个PDU来将provisioning数据给Device。Parameters格式如下:
4.1.9、Provisioning Complete
Devices 发送这个PDU来指示自己成功的接收到和处理了provisioning data。没有Parameters。
4.1.10、Provisioning Failed
device发送这个PDU来通知自己没有成功的接受到启动配置协议 PDU ,parameters的格式如下:
Error Code 定义如下:
4.2、Provisioning behavior
Provisioning 流程分为了 5 个步骤:
beaconing
invitation
exchanging public keys
authentication
distribution of the provisioning data
整个逻辑如下所示:
主要根据 OOB 信息来进行不同分支;
首先是邀请流程:
Provisioner 发出邀请,对方回复能力;
接着是交换 public key,这里分为了 OOB 还是没有 OOB 的形式,不使用 OOB 的情况:
使用 OOB 的情况下:
双方交换后,计算 ECDH;
接着双方进行认证过程,分为三种,Use Output OOB:
Use Input OOB:
以及不使用 OOB:
完成认证后,向希望加入的那个 node 提供 mesh 网络的 Network Key,KeyIndex,等信息: