配网(Provisioning)流程属于蓝牙Mesh网络中的重要一环,正是通过配网流程,才使得蓝牙Mesh设备(Device)变成网络中的一个节点(Node),因此,本文将着重讲解配网流程及其相关概念,希望能够给读者以清晰的理解。
如果设备支持PB-ADV配网,也就是如果设备支持通过广播方式配网的话,其必须发送Unprovisioned Device Beacon,在笔者书写时,远程配网还未在正式规范中,因此配置者必须处在设备的广播范围内(Single Hop)。设备发送的Unprovisoned Device Beacon 包含该设备的UUID用于唯一标识该设备,包含设备的OOB信息用于描述公钥传输方式,例如:NFC、二维码等,包括可选的URI信息(用于标识设备,例设备的类型、图像等),这些信息将在后续步骤中使用。
如果设备支持PB-GATT配网,也就是说设备支持通过连接方式配网的话,其必须发送可连接的广播报文,其发送的广播信息同样包括了设备UUID以及设备的OOB信息。注意:如果设备同时支持两种配网方式,必须交叉发送这两种广播报文。
首先需要说清的时,只有收到的配网广播类型与配置者支持PB-ADV或者PB-GATT方式配网能力一致才能进行,也就是说,只支持PB-GATT(大部分的智能手机就是这种)方式的配置者不能通过PB-ADV方式配网设备,即使配置者能够收到PB-ADV的广播,反之亦然。
配置者在收到相对应的未配置广播后,会发送配置邀请(Provision Invite)让设备进入配网状态。但是由于PB-ADV与PB-GATT的数据传输方式不一致,因此通过PB-ADV方式的配网流程整体复杂度要高与通过连接方式的,限于篇幅,本文将不再详述,感兴趣的读者自行看规范(Mesh Profile 1.0.1 Section 5 Provisioning)。
设备端在收到来自配置者发送的配置邀请后,会将自身的输入输出能力通过配置能力(Provision Capability)发送给配置者作为响应。这种描述设备的输入输出能力将会直接影响后续的配置流程。值得一提的是,配置能力包括设备端是否具备公钥信息带外传输能力(Public Key OOB Information),这种信息与设备在步骤1、步骤2中发送的OOB相呼应,还包括设备是否支持静态认证信息(Static OOB Information),也就是固定的认证值(双方都必须对应一致的存放才能使用),还包括输入输出能力(Input Output OOB Information),最后包括一个描述设备中元素(Element)多少的信息,综上,这些信息都将传给配置者。
配置者在收到来自设备发送的配置能力后,需要根据自身与设备的输入输出能力决定合适的配置算法来进行安全的认证。例如:配置者会检查设备与其自身是否都支持公钥带外传输能力,如果都支持,配置者可以选择这种方式(OOB Public Key)进行公钥传输,例如:通过二维码扫描或者NFC读取等,否则公钥将通过配网流程(No OOB Public Key)传输(这种方式的安全级别当然低于上面的方式)。接着配置者会检查双方输入输出能力,如果设备支持输入,配置者有能力输出的话,可以使用方式(Input OOB authentication)进行安全认证,如果设备支持输出,配置者有能力输入的话,可以使用方式(Output OOB authentication)进行安全认证,如果设备支持静态认证,配置者同样支持静态认证,可以使用方式(Static OOB authentication)进行安全认证。最后如果设备与配置者都没有合适的输入输出相呼应,只能通过非安全认证(No OOB authentication)。
根据公钥带外传输能力,后续公钥传输可以分为
根据输入输出能力,后续认证算法可以分为:
后续配置流程将根据配置者的选择进行,可能存在的路线有: A 1 B 1 、 A 1 B 2 、 A 1 B 3 、 A 1 B 4 、 A 2 B 1 、 A 2 B 2 、 A 2 B 3 、 A 2 B 4 A1B1、A1B2、A1B3、A1B4、A2B1、A2B2、A2B3、A2B4 A1B1、A1B2、A1B3、A1B4、A2B1、A2B2、A2B3、A2B4
如果配置者在步骤5选择公钥非带外传输的话,那么在配置者发送完配置开始后,紧跟着发送配置者公钥(Provisoner Public Key)。注意:公钥与私钥应当在每次配网流程中都必须重新生成。
如果配置者在步骤5选择公钥带外传输的话,其在发送配置开始后,必须通过步骤1或步骤2中OOB信息所描述的方式(NFC、二维码等)来获取设备端公钥(Device Public Key)。
如果设备端在步骤5收到来自配置者选择的公钥非带外传输后将执行此步骤,其必须等待步骤6配置者发送配置者公钥后,发送设备公钥(Provisioning Device Public Key)。
当配置者在步骤6后,应该等待步骤8设备端公钥,或者当配置者在步骤7后,开始执行生成随机数(RandomProvisioner )并根据收到的来自设备端公钥生成ECDHSecret:
E C D H S e c r e t = P − 256 ( p r i v a t e k e y , p e e r p u b l i c k e y ) ECDHSecret = P-256(private key, peer public key) ECDHSecret=P−256(privatekey,peerpublickey)
确认值(Confirm)的生成应根据:
如果配置者选择的算法是非安全认证B1
A E S − C M A C C o n f i r m a t i o n K e y ( R a n d o m P r o v i s i o n e r ∣ ∣ 0 x 00 ) AES-CMACConfirmationKey (RandomProvisioner || 0x00) AES−CMACConfirmationKey(RandomProvisioner∣∣0x00)
如果配置者选择的算法是静态安全认证B2
A E S − C M A C C o n f i r m a t i o n K e y ( R a n d o m P r o v i s i o n e r ∣ ∣ S t a t i c K e y ) AES-CMACConfirmationKey (RandomProvisioner || Static Key) AES−CMACConfirmationKey(RandomProvisioner∣∣StaticKey)
如果配置者选择的算法是输出安全认证B4,配置者应当根据设备显示的Auth Value
A E S − C M A C C o n f i r m a t i o n K e y ( R a n d o m P r o v i s i o n e r ∣ ∣ A u t h V a l u e ) AES-CMACConfirmationKey (RandomProvisioner || Auth Value) AES−CMACConfirmationKey(RandomProvisioner∣∣AuthValue)
在步骤6后,应该等待步骤8设备端公钥,或者当配置者在步骤7后,开始执行生成随机数(RandomProvisioner )以及随机化(Auth Value)并通过步骤5协商的输出方式输出出来,并根据收到的来自设备端公钥生成ECDHSecret:
E C D H S e c r e t = P − 256 ( p r i v a t e k e y , p e e r p u b l i c k e y ) ECDHSecret = P-256(private key, peer public key) ECDHSecret=P−256(privatekey,peerpublickey)
确认值(Confirm)的生成应根据:
A E S − C M A C C o n f i r m a t i o n K e y ( R a n d o m P r o v i s i o n e r ∣ ∣ A u t h V a l u e ) AES-CMACConfirmationKey (RandomProvisioner || Auth Value) AES−CMACConfirmationKey(RandomProvisioner∣∣AuthValue)
配置者应当等待来自步骤11的输入完成(Provision Input Complete)后,发送确认值(Confirm)。
在步骤6或步骤7后,开始执行生成随机数(RandomDevice)并根据收到的来自设备端公钥生成ECDHSecret:
E C D H S e c r e t = P − 256 ( p r i v a t e k e y , p e e r p u b l i c k e y ) ECDHSecret = P-256(private key, peer public key) ECDHSecret=P−256(privatekey,peerpublickey)
设备端应当根据配置者显示的Auth Value ,应当在设备端确认值生成后发送输入完成,其中确认值(Confirm)的生成应根据:
A E S − C M A C C o n f i r m a t i o n K e y ( R a n d o m D e v i c e ∣ ∣ A u t h V a l u e ) AES-CMACConfirmationKey (RandomDevice || Auth Value) AES−CMACConfirmationKey(RandomDevice∣∣AuthValue)
设备端收到来自配置者的确认值后,应当发送设备端确认值。
配置者收到来自设备端的确认值后,应当发送配置者随机数(RandomProvisioner)。
设备端收到来自配置者的随机数后,应当与之前收到的来自配置者确认值进行校验,如果匹配,应当发送设备端随机数(RandomDevice),并根据随机数生成Device Key:
D e v K e y = k 1 ( E C D H S e c r e t , P r o v i s i o n i n g S a l t , “ p r d k ” ) DevKey = k1(ECDHSecret, ProvisioningSalt, “prdk”) DevKey=k1(ECDHSecret,ProvisioningSalt,“prdk”)
其中 ProvisioningSalt应当:
P r o v i s i o n i n g S a l t = s 1 ( C o n f i r m a t i o n S a l t ∣ ∣ R a n d o m P r o v i s i o n e r ∣ ∣ R a n d o m D e v i c e ) ProvisioningSalt = s1(ConfirmationSalt || RandomProvisioner || RandomDevice) ProvisioningSalt=s1(ConfirmationSalt∣∣RandomProvisioner∣∣RandomDevice)
配置者收到来自设备端的随机数后,应当与之前收到的来自设备端确认值进行校验,如果匹配,应当发送配置数据(Provision Data)。
其中配置数据包括:
注意此数据包通过之前协商的数据进行加密:
P r o v i s i o n i n g S a l t = s 1 ( C o n f i r m a t i o n S a l t ∣ ∣ R a n d o m P r o v i s i o n e r ∣ ∣ R a n d o m D e v i c e ) ProvisioningSalt = s1(ConfirmationSalt || RandomProvisioner || RandomDevice) ProvisioningSalt=s1(ConfirmationSalt∣∣RandomProvisioner∣∣RandomDevice)
S e s s i o n K e y = k 1 ( E C D H S e c r e t , P r o v i s i o n i n g S a l t , “ p r s k ” ) SessionKey = k1(ECDHSecret, ProvisioningSalt, “prsk”) SessionKey=k1(ECDHSecret,ProvisioningSalt,“prsk”)
S e s s i o n N o n c e = k 1 ( E C D H S e c r e t , P r o v i s i o n i n g S a l t , “ p r s n ” ) SessionNonce = k1(ECDHSecret, ProvisioningSalt, “prsn”) SessionNonce=k1(ECDHSecret,ProvisioningSalt,“prsn”)
配置数据原始报文为:
P r o v i s i o n i n g D a t a = N e t w o r k K e y ∣ ∣ K e y I n d e x ∣ ∣ F l a g s ∣ ∣ I V I n d e x ∣ ∣ U n i c a s t A d d r e s s Provisioning Data = Network Key || Key Index || Flags || IV Index || Unicast Address ProvisioningData=NetworkKey∣∣KeyIndex∣∣Flags∣∣IVIndex∣∣UnicastAddress
加密后的数据应当为:
A E S − C C M ( S e s s i o n K e y , S e s s i o n N o n c e , P r o v i s i o n i n g D a t a ) AES-CCM (SessionKey, SessionNonce,Provisioning Data) AES−CCM(SessionKey,SessionNonce,ProvisioningData)
设备在收到来自配置者发送配置数据并成功解密后,应当发送配置完成(Provision Complete),至此,当前设备已经变成网络中的一个节点。