1# -*- coding: utf-8 -*- 2# Copyright 2019 Oticon A/S 3# SPDX-License-Identifier: Apache-2.0 4 5import string; 6from enum import IntEnum; 7from components.utils import *; 8 9SMP_CID = 6; 10 11class SMPCapability(IntEnum): 12 SMP_CAP_DISPLAY_ONLY = 0 # Display Only 13 SMP_CAP_DISPLAY_YES_NO = 1 # Display Yes or No 14 SMP_CAP_KEYBOARD_ONLY = 2 # Keyboard Only 15 SMP_CAP_NO_INPUT_NO_OUTPUT = 3 # No Input and No Output 16 SMP_CAP_KEYBOARD_DISPLAY = 4 # Keyboard and Display 17 18class SMPOOBFlag(IntEnum): 19 SMP_OOB_NO_AUTH_DATA = 0 # OOB Authentication data not present 20 SMP_OOB_AUTH_DATA_PRESENT = 1 # OOB Authentication data from remote device present 21 22class SMPBondingFlag(IntEnum): 23 SMP_BOND_NONE = 0 # No Bondig requested 24 SMP_BOND_REQUESTED = 1 # Bonding requested 25 26class SMPMITMFlag(IntEnum): # MITM - 'Man In The Middle' attacks protection 27 SMP_MITM_NONE = 0 # No MITM protection requested 28 SMP_MITM_REQUESTED = 4 # MITM protection requested 29 30class SMPSecureConnections(IntEnum): 31 SMP_SC_NOT_SUPPORTED = 0 # Secure Connections Pairing not supported 32 SMP_SC_SUPPORTED = 8 # Secure Connections Pairing supported 33 34class SMPKeyPressNotifications(IntEnum): 35 SMP_KPN_NONE = 0 # Do not exchange Keypress Notifications 36 SMP_KPN_REQUESTED = 16 # Do exchange Keypress Notifications 37 38class SMPSupportH7(IntEnum): 39 SMP_CT2_NO_SUPPORT = 0 # No support for the h7 security function 40 SMP_CT2_SUPPORTED = 32 # Support for the h7 security function present 41 42class SMPPasskey(IntEnum): 43 SMP_PASSKEY_ENTRY_STARTED = 0 # Passkey entry started 44 SMP_PASSKEY_DIGIT_ENTERED = 1 # Passkey digit entered 45 SMP_PASSKEY_DIGIT_ERASED = 2 # Passkey digit erased 46 SMP_PASSKEY_CLEARED = 3 # Passkey entry cleared 47 SMP_PASSKEY_ENTRY_COMPLETE = 4 # Passkey entry completed 48 49class SMPKeyGeneration(IntEnum): 50 SMP_KEY_GEN_JUST_WORKS = 0 # Just Works 51 SMP_KEY_GEN_NUM_COMPARE = 1 # Numeric Comparison (Only for LE Secure Connections) 52 SMP_KEY_GEN_PASSKEY = 2 # PassKey Entry 53 SMP_KEY_GEN_OOB = 3 # Out of Band 54 55class SMPDistribution(IntEnum): 56 SMP_DST_ENCKEY = 1 # Distribute LTK, EDIV and Rand (LE legacy pairing); ignored (Secure Connections) 57 SMP_DST_IDKEY = 2 # Distribute IRK and BD_ADDR 58 SMP_DST_SIGNKEY = 4 # Distribute CSRK 59 SMP_DST_LINKKEY = 8 # Derive Link Key from LTK (Secure Connections); ignored (no Secure Connections) 60 61class SMPOpcode(IntEnum): 62 SMP_PAIRING_REQUEST = 1 # Pairing Request - Pairing Feature Exchange - IO Capability, OOB data flag, AuthReq, Max. Encryption Key Size, Initiator Key Distribution, Responder Key Distribution 63 SMP_PAIRING_RESPONSE = 2 # Pairing Response - Pairing Feature Exchange - IO Capability, OOB data flag, AuthReq, Max. Encryption Key Size, Initiator Key Distribution, Responder Key Distribution 64 SMP_PAIRING_CONFIRM = 3 # Pairing Confirm - Pairing Confirmation value 65 SMP_PAIRING_RANDOM = 4 # Pairing Random - Pairing Random value 66 SMP_PAIRING_FAILED = 5 # Pairing Failed - Pairing Failed reason 67 SMP_ENCRYPTION_INFORMATION = 6 # Encryption Information - Long Term Key 68 SMP_CENTRAL_IDENTIFICATION = 7 # Central Identification - Dsitribute EDIV and Rand for encrypting future connections 69 SMP_IDENTITY_INFORMATION = 8 # Identity Information - Distribute the IRK 70 SMP_IDENTITY_ADDRESS_INFORMATION = 9 # Identity Address Information - Distribute Public or Static Random device address 71 SMP_SIGNING_INFORMATION = 10 # Signing Information - Distribute the CSRK 72 SMP_SECURITY_REQUEST = 11 # Security Request - Initiate security with the requested properties 73 SMP_PAIRING_PUBLIC_KEY = 12 # Pairing Public Key - Distribute Public Keys X and Y 74 SMP_PAIRING_DHKEY_CHECK = 13 # Pairing DHKey Check - Distribute DHKey Check 75 SMP_PAIRING_KEYPRESS_NOTIFICATION = 14 # Keypress Notification - Inform about keys entered or erased 76 77class SMPError(IntEnum): 78 SMP_ERROR_PASSKEY = 1 # The user input of passkey failed, for example, the user cancelled the operation 79 SMP_ERROR_OOB = 2 # The OOB data is not available 80 SMP_ERROR_AUTHENTICATION = 3 # The pairing procedure cannot be performed as authentication requirements cannot be met due to IO capabilities of one or both devices 81 SMP_ERROR_CONFIRM = 4 # The confirm value does not match the calculated compare value 82 SMP_ERROR_PAIRING = 5 # Pairing is not supported by the device 83 SMP_ERROR_ENCRYPTION = 6 # The resultant encryption key size is insufficient for the security requirements of this device 84 SMP_ERROR_COMMAND = 7 # The SMP command received is not supported on this device 85 SMP_ERROR_REASON = 8 # Pairing failed due to an unspecified reason 86 SMP_ERROR_REPEATED_ATTEMPTS = 9 # Pairing or authentication procedure is disallowed because too little time has elapsed since last pairing request or security request 87 SMP_ERROR_INVALID_PARAMETERS = 10 # The invalid parameters error code indicates that the command length is invalid or that a parameter is outside the specified range 88 SMP_ERROR_DHKEY_CHECK = 11 # Indicates to the remote device that the DHKey Check value received doesn't match the one calculated by the local device 89 SMP_ERROR_NUMERIC_COMPARISON = 12 # Indicates that the confirm values in the numeric comparison protocol do not match 90 SMP_ERROR_PAIRING_IN_PROGRESS = 13 # Indicates that the pairing over the LE transport failed due to a Pairing Request sent over the BR/EDR transport 91 SMP_ERROR_CROSS_KEY_GENERATION = 14 # Indicates that the BR/EDR Link Key generated on the BR/EDR transport cannot be used to derive and distribute keys for the LE transport 92 93class SMPData: 94 95 def __init__(self): 96 self.data = []; 97 98 def encode(self, opcode, *args): 99 # 100 # encode ( SMPOpcode.SMP_PAIRING_REQUEST, <io_capability>, <oob_flag>, <auth_req>, <max_enq_key_size>, <init_key_dist>, <resp_key_dist> ) 101 # where <io_capability> 1 octet, <oob_flag> 1 octet, <auth_req> 1 octet, <max_enq_key_size> 1 octet, <init_key_dist> 1 octet, <resp_key_dist> 1 octet 102 # 103 if ( opcode == SMPOpcode.SMP_PAIRING_REQUEST ): 104 self.data = [ opcode ] + list( args[:6] ); 105 # 106 # encode ( SMPOpcode.SMP_PAIRING_RESPONSE, <io_capability>, <oob_flag>, <auth_req>, <max_enq_key_size>, <init_key_dist>, <resp_key_dist> ) 107 # where <io_capability> 1 octet, <oob_flag> 1 octet, <auth_req> 1 octet, <max_enq_key_size> 1 octet, <init_key_dist> 1 octet, <resp_key_dist> 1 octet 108 # 109 elif ( opcode == SMPOpcode.SMP_PAIRING_RESPONSE ): 110 self.data = [ opcode ] + list( args[:6] ); 111 # 112 # encode ( SMPOpcode.SMP_PAIRING_CONFIRM, <confirm_value> ) 113 # where <confirm_value> 16 octets 114 # 115 elif ( opcode == SMPOpcode.SMP_PAIRING_CONFIRM ): 116 self.data = [ opcode ] + toArray( args[0], 16 ); 117 # 118 # encode ( SMPOpcode.SMP_PAIRING_RANDOM, <random_value> ) 119 # where <random_value> 16 octets 120 # 121 elif ( opcode == SMPOpcode.SMP_PAIRING_RANDOM ): 122 self.data = [ opcode ] + toArray( args[0], 16 ); 123 # 124 # encode ( SMPOpcode.SMP_PAIRING_FAILED, <reason> ) 125 # where <reason> 1 octet 126 # 127 elif ( opcode == SMPOpcode.SMP_PAIRING_FAILED ): 128 self.data = [ opcode ] + [ args[0] ]; 129 # 130 # encode ( SMPOpcode.SMP_ENCRYPTION_INFORMATION, <ltk> ) 131 # where <ltk> 16 octets 132 # 133 elif ( opcode == SMPOpcode.SMP_ENCRYPTION_INFORMATION ): 134 self.data = [ opcode ] + toArray( args[0], 16 ); 135 # 136 # encode ( SMPOpcode.SMP_CENTRAL_IDENTIFICATION, <ediv>, <rand> ) 137 # where <ediv> 2 octets; <rand> 8 octets 138 # 139 elif ( opcode == SMPOpcode.SMP_CENTRAL_IDENTIFICATION ): 140 self.data = [ opcode ] + toArray( args[0], 2 ) + toArray( args[1], 8 ); 141 # 142 # encode ( SMPOpcode.SMP_IDENTITY_INFORMATION, <irk> ) 143 # where <irk> 16 octets 144 # 145 elif ( opcode == SMPOpcode.SMP_IDENTITY_INFORMATION ): 146 self.data = [ opcode ] + toArray( args[0], 16 ); 147 # 148 # encode ( SMPOpcode.SMP_IDENTITY_ADDRESS_INFORMATION, <address_type>, <address> ) 149 # where <address_type> 1 octet; <address> 6 octets 150 # 151 elif ( opcode == SMPOpcode.SMP_IDENTITY_ADDRESS_INFORMATION ): 152 self.data = [ opcode ] + [ args[0] ] + toArray( args[1], 6 ); 153 # 154 # encode ( SMPOpcode.SMP_SIGNING_INFORMATION, <csrk> ) 155 # where <csrk> 16 octets 156 # 157 elif ( opcode == SMPOpcode.SMP_SIGNING_INFORMATION ): 158 self.data = [ opcode ] + toArray( args[0], 16 ); 159 # 160 # encode ( SMPOpcode.SMP_SECURITY_REQUEST, <properties> ) 161 # where <properties> 1 octet 162 # 163 elif ( opcode == SMPOpcode.SMP_SECURITY_REQUEST ): 164 self.data = [ opcode ] + [ args[0] ]; 165 # 166 # encode ( SMPOpcode.SMP_PAIRING_PUBLIC_KEY, <key_X>, <key_Y> ) 167 # where <key_X> 32 octets; <key_Y> 32 octets 168 # 169 elif ( opcode == SMPOpcode.SMP_PAIRING_PUBLIC_KEY ): 170 self.data = [ opcode ] + toArray( args[0], 32 ) + toArray( args[1], 32 ); 171 # 172 # encode ( SMPOpcode.SMP_PAIRING_DHKEY_CHECK, <check_value> ) 173 # where <check_value> 16 octets 174 # 175 elif ( opcode == SMPOpcode.SMP_PAIRING_DHKEY_CHECK ): 176 self.data = [ opcode ] + toArray( args[0], 16 ); 177 # 178 # encode ( SMPOpcode.SMP_PAIRING_KEYPRESS_NOTIFICATION, <type> ) 179 # where <type> 1 octet 180 # 181 elif ( opcode == SMPOpcode.SMP_PAIRING_KEYPRESS_NOTIFICATION ): 182 self.data = [ opcode ] + [ args[0] ]; 183 # 184 # The first two octets in the L2CAP PDU contains the length of the entire L2CAP PDU in octets, excluding the Length and CID fields. 185 # 186 if len(self.data) > 0: 187 self.data = toArray( len(self.data), 2 ) + toArray( SMP_CID, 2 ) + self.data; 188 return self.data; 189 190 def decode(self, data): 191 self.data = data[:]; 192 size = toNumber( data[:2] ); 193 cid = toNumber( data[2:4] ); 194 opcode = SMPOpcode(data[4]); 195 196 result = { "opcode": opcode }; 197 # 198 # decode ( SMPOpcode.SMP_PAIRING_REQUEST, <io_capability>, <oob_flag>, <auth_req>, <max_enq_key_size>, <init_key_dist>, <resp_key_dist> ) 199 # where <io_capability> 1 octet, <oob_flag> 1 octet, <auth_req> 1 octet, <max_enq_key_size> 1 octet, <init_key_dist> 1 octet, <resp_key_dist> 1 octet 200 # 201 if ( opcode == SMPOpcode.SMP_PAIRING_REQUEST ): 202 result["capability"] = data[5]; 203 result["oob"] = data[6]; 204 result["auth"] = data[7]; 205 result["max_key_size"] = data[8]; 206 result["init_key_dist"] = data[9]; 207 result["resp_key_dist"] = data[10]; 208 # 209 # decode ( SMPOpcode.SMP_PAIRING_RESPONSE, <io_capability>, <oob_flag>, <auth_req>, <max_enq_key_size>, <init_key_dist>, <resp_key_dist> ) 210 # where <io_capability> 1 octet, <oob_flag> 1 octet, <auth_req> 1 octet, <max_enq_key_size> 1 octet, <init_key_dist> 1 octet, <resp_key_dist> 1 octet 211 # 212 elif ( opcode == SMPOpcode.SMP_PAIRING_RESPONSE ): 213 result["capability"] = data[5]; 214 result["oob"] = data[6]; 215 result["auth"] = data[7]; 216 result["max_key_size"] = data[8]; 217 result["init_key_dist"] = data[9]; 218 result["resp_key_dist"] = data[10]; 219 # 220 # decode ( SMPOpcode.SMP_PAIRING_CONFIRM, <confirm_value> ) 221 # where <confirm_value> 16 octets 222 # 223 elif ( opcode == SMPOpcode.SMP_PAIRING_CONFIRM ): 224 result["value"] = toNumber( data[5:21] ); 225 # 226 # decode ( SMPOpcode.SMP_PAIRING_RANDOM, <random_value> ) 227 # where <random_value> 16 octets 228 # 229 elif ( opcode == SMPOpcode.SMP_PAIRING_RANDOM ): 230 result["value"] = toNumber( data[5:21] ); 231 # 232 # decode ( SMPOpcode.SMP_PAIRING_FAILED, <reason> ) 233 # where <reason> 1 octet 234 # 235 elif ( opcode == SMPOpcode.SMP_PAIRING_FAILED ): 236 result["reason"] = (SMPError)(data[5]); 237 # 238 # decode ( SMPOpcode.SMP_ENCRYPTION_INFORMATION, <ltk> ) 239 # where <ltk> 16 octets 240 # 241 elif ( opcode == SMPOpcode.SMP_ENCRYPTION_INFORMATION ): 242 result["ltk"] = toNumber( data[5:21] ); 243 # 244 # decode ( SMPOpcode.SMP_CENTRAL_IDENTIFICATION, <ediv>, <rand> ) 245 # where <ediv> 2 octets; <rand> 8 octets 246 # 247 elif ( opcode == SMPOpcode.SMP_CENTRAL_IDENTIFICATION ): 248 result["ediv"] = toNumber( data[5:7] ); 249 result["rand"] = toNumber( data[7:15] ); 250 # 251 # decode ( SMPOpcode.SMP_IDENTITY_INFORMATION, <irk> ) 252 # where <irk> 16 octets 253 # 254 elif ( opcode == SMPOpcode.SMP_IDENTITY_INFORMATION ): 255 result["irk"] = toNumber( data[5:21] ); 256 # 257 # decode ( SMPOpcode.SMP_IDENTITY_ADDRESS_INFORMATION, <address_type>, <address> ) 258 # where <address_type> 1 octet; <address> 6 octets 259 # 260 elif ( opcode == SMPOpcode.SMP_IDENTITY_ADDRESS_INFORMATION ): 261 result["type"] = data[5]; 262 result["address"] = toNumber( data[6:12] ); 263 # 264 # decode ( SMPOpcode.SMP_SIGNING_INFORMATION, <csrk> ) 265 # where <csrk> 16 octets 266 # 267 elif ( opcode == SMPOpcode.SMP_SIGNING_INFORMATION ): 268 result["csrk"] = toNumber( data[5:21] ); 269 # 270 # decode ( SMPOpcode.SMP_PAIRING_PUBLIC_KEY, <key_X>, <key_Y> ) 271 # where <key_X> 32 octets; <key_Y> 32 octets 272 # 273 elif ( opcode == SMPOpcode.SMP_PAIRING_PUBLIC_KEY ): 274 result["key_X"] = toNumber( data[5:37] ); 275 result["key_Y"] = toNumber( data[37:69] ); 276 # 277 # decode ( SMPOpcode.SMP_PAIRING_DHKEY_CHECK, <check_value> ) 278 # where <check_value> 16 octets 279 # 280 elif ( opcode == SMPOpcode.SMP_PAIRING_DHKEY_CHECK ): 281 result["value"] = toNumber( data[5:21] ); 282 # 283 # decode ( SMPOpcode.SMP_PAIRING_KEYPRESS_NOTIFICATION, <type> ) 284 # where <type> 1 octet 285 # 286 elif ( opcode == SMPOpcode.SMP_PAIRING_KEYPRESS_NOTIFICATION ): 287 result["change"] = (SMPPasskey)(data[5]); 288 289 return result; 290 291 def error(self, code): 292 errorTexts = { 293 SMPError.SMP_ERROR_PASSKEY: 294 "The user input of passkey failed.", 295 SMPError.SMP_ERROR_OOB: 296 "The OOB data is not available.", 297 SMPError.SMP_ERROR_AUTHENTICATION: 298 "The pairing procedure cannot be performed as authentication requirements cannot be met.", 299 SMPError.SMP_ERROR_CONFIRM: 300 "The confirm value does not match the calculated compare value.", 301 SMPError.SMP_ERROR_PAIRING: 302 "Pairing is not supported by the device.", 303 SMPError.SMP_ERROR_ENCRYPTION: 304 "The resultant encryption key size is insufficient for the security requirements.", 305 SMPError.SMP_ERROR_COMMAND: 306 "The SMP command received is not supported.", 307 SMPError.SMP_ERROR_REASON: 308 "Pairing failed due to an unspecified reason.", 309 SMPError.SMP_ERROR_REPEATED_ATTEMPTS: 310 "Pairing or authentication procedure is disallowed because too little time has elapsed since last pairing- or security-request.", 311 SMPError.SMP_ERROR_INVALID_PARAMETERS: 312 "The command length is invalid or a parameter is outside the specified range.", 313 SMPError.SMP_ERROR_DHKEY_CHECK: 314 "The DHKey Check value received doesn't match the one calculated.", 315 SMPError.SMP_ERROR_NUMERIC_COMPARISON: 316 "The confirm values in the numeric comparison protocol do not match.", 317 SMPError.SMP_ERROR_PAIRING_IN_PROGRESS: 318 "The pairing over LE transport failed due to a Pairing Request sent over the BR/EDR transport.", 319 SMPError.SMP_ERROR_CROSS_KEY_GENERATION: 320 "The BR/EDR Link Key generated on the BR/EDR transport cannot be used to derive and distribute keys for the LE transport." 321 }; 322 if code in errorTexts: 323 return errorTexts[code]; 324 else: 325 return "Unknown error code (%d)" % code; 326