in HAP/HAPPairingPairings.c [43:281]
static HAPError HAPPairingPairingsAddPairingProcessM1(
HAPAccessoryServerRef* server_,
HAPSessionRef* session_,
const HAPPairingPairingsAddPairingM1TLVs* tlvs) {
HAPPrecondition(server_);
HAPAccessoryServer* server = (HAPAccessoryServer*) server_;
HAPPrecondition(session_);
HAPSession* session = (HAPSession*) session_;
HAPPrecondition(session->state.pairings.state == 1);
HAPPrecondition(session->state.pairings.method == kHAPPairingMethod_AddPairing);
HAPPrecondition(!session->state.pairings.error);
HAPPrecondition(session->hap.active);
HAPPrecondition(tlvs);
HAPPrecondition(tlvs->stateTLV);
HAPPrecondition(tlvs->stateTLV->type == kHAPPairingTLVType_State);
HAPPrecondition(tlvs->methodTLV);
HAPPrecondition(tlvs->methodTLV->type == kHAPPairingTLVType_Method);
HAPPrecondition(tlvs->identifierTLV);
HAPPrecondition(tlvs->identifierTLV->type == kHAPPairingTLVType_Identifier);
HAPPrecondition(tlvs->publicKeyTLV);
HAPPrecondition(tlvs->publicKeyTLV->type == kHAPPairingTLVType_PublicKey);
HAPPrecondition(tlvs->permissionsTLV);
HAPPrecondition(tlvs->permissionsTLV->type == kHAPPairingTLVType_Permissions);
HAPError err;
// See HomeKit Accessory Protocol Specification R14
// Section 5.10.1 M1: iOS Device -> Accessory -- `Add Pairing Request'
HAPLogDebug(&logObject, "Add Pairing M1: Add Pairing Request.");
// Validate kTLVType_State.
if (!tlvs->stateTLV->value.bytes) {
HAPLog(&logObject, "Add Pairing M1: kTLVType_State missing.");
return kHAPError_InvalidData;
}
if (tlvs->stateTLV->value.numBytes != 1) {
HAPLog(&logObject,
"Add Pairing M1: kTLVType_State has invalid length (%lu).",
(unsigned long) tlvs->stateTLV->value.numBytes);
return kHAPError_InvalidData;
}
uint8_t state = ((const uint8_t*) tlvs->stateTLV->value.bytes)[0];
if (state != 1) {
HAPLog(&logObject, "Add Pairing M1: kTLVType_State invalid: %u.", state);
return kHAPError_InvalidData;
}
// Validate kTLVType_Method.
if (!tlvs->methodTLV->value.bytes) {
HAPLog(&logObject, "Add Pairing M1: kTLVType_Method missing.");
return kHAPError_InvalidData;
}
if (tlvs->methodTLV->value.numBytes != 1) {
HAPLog(&logObject,
"Add Pairing M1: kTLVType_Method has invalid length (%lu).",
(unsigned long) tlvs->methodTLV->value.numBytes);
return kHAPError_InvalidData;
}
uint8_t method = ((const uint8_t*) tlvs->methodTLV->value.bytes)[0];
if (method != kHAPPairingMethod_AddPairing) {
HAPLog(&logObject, "Add Pairing M1: kTLVType_Method invalid: %u.", method);
return kHAPError_InvalidData;
}
// Validate kTLVType_Identifier.
if (!tlvs->identifierTLV->value.bytes) {
HAPLog(&logObject, "Add Pairing M1: kTLVType_Identifier missing.");
return kHAPError_InvalidData;
}
if (tlvs->identifierTLV->value.numBytes > sizeof(HAPPairingID)) {
HAPLog(&logObject,
"Add Pairing M1: kTLVType_Identifier has invalid length (%lu).",
(unsigned long) tlvs->identifierTLV->value.numBytes);
return kHAPError_InvalidData;
}
// Validate kTLVType_PublicKey.
if (!tlvs->publicKeyTLV->value.bytes) {
HAPLog(&logObject, "Add Pairing M1: kTLVType_Identifier missing.");
return kHAPError_InvalidData;
}
if (tlvs->publicKeyTLV->value.numBytes != sizeof(HAPPairingPublicKey)) {
HAPLog(&logObject,
"Add Pairing M1: kTLVType_Identifier has invalid length (%lu).",
(unsigned long) tlvs->publicKeyTLV->value.numBytes);
return kHAPError_InvalidData;
}
// Validate kTLVType_Permissions.
if (!tlvs->permissionsTLV->value.bytes) {
HAPLog(&logObject, "Add Pairing M1: kTLVType_Permissions missing.");
return kHAPError_InvalidData;
}
if (tlvs->permissionsTLV->value.numBytes != 1) {
HAPLog(&logObject,
"Add Pairing M1: kTLVType_Permissions has invalid length (%lu).",
(unsigned long) tlvs->permissionsTLV->value.numBytes);
return kHAPError_InvalidData;
}
uint8_t permissions = ((const uint8_t*) tlvs->permissionsTLV->value.bytes)[0];
if (permissions & ~1) {
HAPLog(&logObject, "Add Pairing M1: kTLVType_Permissions invalid: %u.", permissions);
return kHAPError_InvalidData;
}
// Check if a pairing for the additional controller's pairing identifier exists.
HAPPairing pairing;
HAPRawBufferZero(&pairing, sizeof pairing);
HAPRawBufferCopyBytes(
&pairing.identifier.bytes,
HAPNonnullVoid(tlvs->identifierTLV->value.bytes),
tlvs->identifierTLV->value.numBytes);
HAPAssert(tlvs->identifierTLV->value.numBytes <= UINT8_MAX);
pairing.numIdentifierBytes = (uint8_t) tlvs->identifierTLV->value.numBytes;
HAPPlatformKeyValueStoreKey key;
bool found;
err = HAPPairingFind(server->platform.keyValueStore, &pairing, &key, &found);
if (err) {
HAPAssert(err == kHAPError_Unknown);
return err;
}
if (found) {
// Check if the additional controller's long-term public key matches the
// stored public key for the additional controller's pairing identifier.
if (!HAPRawBufferAreEqual(
pairing.publicKey.value,
HAPNonnullVoid(tlvs->publicKeyTLV->value.bytes),
sizeof pairing.publicKey.value)) {
HAPLog(&logObject,
"Add Pairing M1: Additional controller's long-term public key does not match "
"the stored public key for the additional controller's pairing identifier.");
session->state.pairings.error = kHAPPairingError_Unknown;
return kHAPError_None;
}
// Update the permissions of the controller.
pairing.permissions = permissions;
uint8_t pairingBytes[sizeof(HAPPairingID) + sizeof(uint8_t) + sizeof(HAPPairingPublicKey) + sizeof(uint8_t)];
HAPRawBufferZero(pairingBytes, sizeof pairingBytes);
HAPAssert(sizeof pairing.identifier.bytes == 36);
HAPAssert(pairing.numIdentifierBytes <= sizeof pairing.identifier.bytes);
HAPRawBufferCopyBytes(&pairingBytes[0], pairing.identifier.bytes, pairing.numIdentifierBytes);
pairingBytes[36] = (uint8_t) pairing.numIdentifierBytes;
HAPAssert(sizeof pairing.publicKey.value == 32);
HAPRawBufferCopyBytes(&pairingBytes[37], pairing.publicKey.value, 32);
pairingBytes[69] = pairing.permissions;
err = HAPPlatformKeyValueStoreSet(
server->platform.keyValueStore,
kHAPKeyValueStoreDomain_Pairings,
key,
pairingBytes,
sizeof pairingBytes);
if (err) {
HAPAssert(err == kHAPError_Unknown);
return err;
}
// If the admin controller pairing is removed, all pairings on the accessory must be removed.
err = HAPAccessoryServerCleanupPairings(server_);
if (err) {
HAPAssert(err == kHAPError_Unknown);
HAPLog(&logObject, "Add Pairing M1: Failed to cleanup pairings.");
session->state.pairings.error = kHAPPairingError_Unknown;
return kHAPError_None;
}
} else {
// Look for free pairing slot.
for (key = 0; key < server->maxPairings; key++) {
size_t numBytes;
uint8_t pairingBytes
[sizeof(HAPPairingID) + sizeof(uint8_t) + sizeof(HAPPairingPublicKey) + sizeof(uint8_t)];
err = HAPPlatformKeyValueStoreGet(
server->platform.keyValueStore,
kHAPKeyValueStoreDomain_Pairings,
key,
pairingBytes,
sizeof pairingBytes,
&numBytes,
&found);
if (err) {
HAPAssert(err == kHAPError_Unknown);
return err;
}
if (!found) {
// Pairing found.
break;
}
if (numBytes != sizeof pairingBytes) {
HAPLog(&logObject, "Invalid pairing 0x%02X size %lu.", key, (unsigned long) numBytes);
return kHAPError_Unknown;
}
}
if (key == server->maxPairings) {
HAPLog(&logObject, "Add Pairing M1: No space for additional pairings.");
session->state.pairings.error = kHAPPairingError_MaxPeers;
return kHAPError_None;
}
// Add pairing.
HAPRawBufferZero(&pairing, sizeof pairing);
HAPRawBufferCopyBytes(
pairing.identifier.bytes,
HAPNonnullVoid(tlvs->identifierTLV->value.bytes),
tlvs->identifierTLV->value.numBytes);
HAPAssert(tlvs->identifierTLV->value.numBytes <= UINT8_MAX);
pairing.numIdentifierBytes = (uint8_t) tlvs->identifierTLV->value.numBytes;
HAPRawBufferCopyBytes(
pairing.publicKey.value,
HAPNonnullVoid(tlvs->publicKeyTLV->value.bytes),
tlvs->publicKeyTLV->value.numBytes);
pairing.permissions = permissions;
uint8_t pairingBytes[sizeof(HAPPairingID) + sizeof(uint8_t) + sizeof(HAPPairingPublicKey) + sizeof(uint8_t)];
HAPRawBufferZero(pairingBytes, sizeof pairingBytes);
HAPAssert(sizeof pairing.identifier.bytes == 36);
HAPAssert(pairing.numIdentifierBytes <= sizeof pairing.identifier.bytes);
HAPRawBufferCopyBytes(&pairingBytes[0], pairing.identifier.bytes, pairing.numIdentifierBytes);
pairingBytes[36] = (uint8_t) pairing.numIdentifierBytes;
HAPAssert(sizeof pairing.publicKey.value == 32);
HAPRawBufferCopyBytes(&pairingBytes[37], pairing.publicKey.value, 32);
pairingBytes[69] = pairing.permissions;
err = HAPPlatformKeyValueStoreSet(
server->platform.keyValueStore,
kHAPKeyValueStoreDomain_Pairings,
key,
pairingBytes,
sizeof pairingBytes);
if (err) {
HAPAssert(err == kHAPError_Unknown);
HAPLog(&logObject, "Add Pairing M1: Failed to add pairing.");
session->state.pairings.error = kHAPPairingError_Unknown;
return kHAPError_None;
}
}
return kHAPError_None;
}