static HAPError HAPPairingPairingsAddPairingProcessM1()

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;
}