blob: 63a5baf32b64d57b763f597251ad25354165a652 [file] [log] [blame]
//
// MTRControllerTests.m
// MTRControllerTests
/**
*
* Copyright (c) 2021 Project CHIP Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#import <Matter/Matter.h>
// system dependencies
#import <XCTest/XCTest.h>
#import "MTRTestKeys.h"
#import "MTRTestOTAProvider.h"
#import "MTRTestStorage.h"
static uint16_t kTestVendorId = 0xFFF1u;
static void CheckStoredOpcertCats(id<MTRStorage> storage, uint8_t fabricIndex, NSSet<NSNumber *> * cats)
{
__auto_type * certData = [storage storageDataForKey:[NSString stringWithFormat:@"f/%x/n", fabricIndex]];
XCTAssertNotNil(certData);
__auto_type * info = [[MTRCertificateInfo alloc] initWithTLVBytes:certData];
XCTAssertNotNil(info);
__auto_type * storedCATs = info.subject.caseAuthenticatedTags;
if (cats == nil) {
XCTAssertTrue(storedCATs.count == 0);
} else {
XCTAssertEqualObjects(storedCATs, cats);
}
}
@interface MTRControllerTests : XCTestCase
@end
@implementation MTRControllerTests
- (void)testFactoryLifecycle
{
__auto_type * factory = [MTRDeviceControllerFactory sharedInstance];
XCTAssertNotNil(factory);
XCTAssertFalse([factory isRunning]);
__auto_type * storage = [[MTRTestStorage alloc] init];
__auto_type * factoryParams = [[MTRDeviceControllerFactoryParams alloc] initWithStorage:storage];
XCTAssertTrue([factory startControllerFactory:factoryParams error:nil]);
XCTAssertTrue([factory isRunning]);
[factory stopControllerFactory];
XCTAssertFalse([factory isRunning]);
// Now try to restart the factory.
XCTAssertTrue([factory startControllerFactory:factoryParams error:nil]);
XCTAssertTrue([factory isRunning]);
[factory stopControllerFactory];
XCTAssertFalse([factory isRunning]);
}
- (void)testControllerLifecycle
{
__auto_type * factory = [MTRDeviceControllerFactory sharedInstance];
XCTAssertNotNil(factory);
__auto_type * storage = [[MTRTestStorage alloc] init];
__auto_type * factoryParams = [[MTRDeviceControllerFactoryParams alloc] initWithStorage:storage];
XCTAssertTrue([factory startControllerFactory:factoryParams error:nil]);
XCTAssertTrue([factory isRunning]);
__auto_type * testKeys = [[MTRTestKeys alloc] init];
XCTAssertNotNil(testKeys);
__auto_type * params = [[MTRDeviceControllerStartupParams alloc] initWithIPK:testKeys.ipk fabricID:@(1) nocSigner:testKeys];
XCTAssertNotNil(params);
params.vendorID = @(kTestVendorId);
MTRDeviceController * controller = [factory createControllerOnNewFabric:params error:nil];
XCTAssertNotNil(controller);
XCTAssertTrue([controller isRunning]);
[controller shutdown];
XCTAssertFalse([controller isRunning]);
// now try to restart the controller
controller = [factory createControllerOnExistingFabric:params error:nil];
XCTAssertNotNil(controller);
XCTAssertTrue([controller isRunning]);
[controller shutdown];
XCTAssertFalse([controller isRunning]);
// now try to restart the controller without providing a vendor id.
params.vendorID = nil;
controller = [factory createControllerOnExistingFabric:params error:nil];
XCTAssertNotNil(controller);
XCTAssertTrue([controller isRunning]);
[controller shutdown];
XCTAssertFalse([controller isRunning]);
[factory stopControllerFactory];
XCTAssertFalse([factory isRunning]);
}
- (void)testDeprecatedControllerLifecycle
{
__auto_type * factory = [MTRControllerFactory sharedInstance];
XCTAssertNotNil(factory);
__auto_type * storage = [[MTRTestStorage alloc] init];
__auto_type * factoryParams = [[MTRControllerFactoryParams alloc] initWithStorage:storage];
XCTAssertTrue([factory startup:factoryParams]);
XCTAssertTrue([factory isRunning]);
__auto_type * testKeys = [[MTRTestKeys alloc] init];
XCTAssertNotNil(testKeys);
__auto_type * params = [[MTRDeviceControllerStartupParams alloc] initWithIPK:testKeys.ipk fabricID:@(1) nocSigner:testKeys];
XCTAssertNotNil(params);
params.vendorID = @(kTestVendorId);
MTRDeviceController * controller = [factory startControllerOnNewFabric:params];
XCTAssertNotNil(controller);
XCTAssertTrue([controller isRunning]);
[controller shutdown];
XCTAssertFalse([controller isRunning]);
// now try to restart the controller
controller = [factory startControllerOnExistingFabric:params];
XCTAssertNotNil(controller);
XCTAssertTrue([controller isRunning]);
[controller shutdown];
XCTAssertFalse([controller isRunning]);
// now try to restart the controller without providing a vendor id.
params.vendorID = nil;
controller = [factory startControllerOnExistingFabric:params];
XCTAssertNotNil(controller);
XCTAssertTrue([controller isRunning]);
[controller shutdown];
XCTAssertFalse([controller isRunning]);
[factory shutdown];
XCTAssertFalse([factory isRunning]);
}
- (void)testFactoryShutdownShutsDownController
{
__auto_type * factory = [MTRDeviceControllerFactory sharedInstance];
XCTAssertNotNil(factory);
__auto_type * storage = [[MTRTestStorage alloc] init];
__auto_type * factoryParams = [[MTRDeviceControllerFactoryParams alloc] initWithStorage:storage];
XCTAssertTrue([factory startControllerFactory:factoryParams error:nil]);
XCTAssertTrue([factory isRunning]);
__auto_type * testKeys = [[MTRTestKeys alloc] init];
XCTAssertNotNil(testKeys);
__auto_type * params = [[MTRDeviceControllerStartupParams alloc] initWithIPK:testKeys.ipk fabricID:@(1) nocSigner:testKeys];
XCTAssertNotNil(params);
params.vendorID = @(kTestVendorId);
MTRDeviceController * controller = [factory createControllerOnNewFabric:params error:nil];
XCTAssertNotNil(controller);
XCTAssertTrue([controller isRunning]);
[factory stopControllerFactory];
XCTAssertFalse([factory isRunning]);
XCTAssertFalse([controller isRunning]);
}
- (void)testControllerMultipleShutdown
{
__auto_type * factory = [MTRDeviceControllerFactory sharedInstance];
XCTAssertNotNil(factory);
__auto_type * storage = [[MTRTestStorage alloc] init];
__auto_type * factoryParams = [[MTRDeviceControllerFactoryParams alloc] initWithStorage:storage];
XCTAssertTrue([factory startControllerFactory:factoryParams error:nil]);
XCTAssertTrue([factory isRunning]);
__auto_type * testKeys = [[MTRTestKeys alloc] init];
XCTAssertNotNil(testKeys);
__auto_type * params = [[MTRDeviceControllerStartupParams alloc] initWithIPK:testKeys.ipk fabricID:@(1) nocSigner:testKeys];
XCTAssertNotNil(params);
params.vendorID = @(kTestVendorId);
MTRDeviceController * controller = [factory createControllerOnNewFabric:params error:nil];
XCTAssertTrue([controller isRunning]);
for (int i = 0; i < 5; i++) {
[controller shutdown];
XCTAssertFalse([controller isRunning]);
}
[factory stopControllerFactory];
XCTAssertFalse([factory isRunning]);
}
- (void)testControllerWithOTAProviderDelegate
{
__auto_type * factory = [MTRDeviceControllerFactory sharedInstance];
XCTAssertNotNil(factory);
__auto_type * otaProvider = [[MTRTestOTAProvider alloc] init];
__auto_type * storage = [[MTRTestStorage alloc] init];
__auto_type * factoryParams = [[MTRDeviceControllerFactoryParams alloc] initWithStorage:storage];
factoryParams.otaProviderDelegate = otaProvider;
XCTAssertTrue([factory startControllerFactory:factoryParams error:nil]);
XCTAssertTrue([factory isRunning]);
__auto_type * testKeys = [[MTRTestKeys alloc] init];
XCTAssertNotNil(testKeys);
__auto_type * params = [[MTRDeviceControllerStartupParams alloc] initWithIPK:testKeys.ipk fabricID:@(1) nocSigner:testKeys];
XCTAssertNotNil(params);
params.vendorID = @(kTestVendorId);
MTRDeviceController * controller = [factory createControllerOnNewFabric:params error:nil];
XCTAssertTrue([controller isRunning]);
[controller shutdown];
// OTA Provider depends on the system state maintained by CHIPDeviceControllerFactory that is destroyed when
// the controller count goes down to 0. Make sure that a new controller can still be started successfully onto the
// same fabric.
MTRDeviceController * controller2 = [factory createControllerOnExistingFabric:params error:nil];
XCTAssertTrue([controller2 isRunning]);
[controller2 shutdown];
// Check that a new controller can be started on a different fabric too.
__auto_type * params2 = [[MTRDeviceControllerStartupParams alloc] initWithIPK:testKeys.ipk fabricID:@(2) nocSigner:testKeys];
XCTAssertNotNil(params2);
params2.vendorID = @(kTestVendorId);
MTRDeviceController * controller3 = [factory createControllerOnNewFabric:params2 error:nil];
XCTAssertTrue([controller3 isRunning]);
[controller3 shutdown];
// Stop the factory, start it up again and create a controller to ensure that no dead state from the previous
// ota provider delegate is staying around.
[factory stopControllerFactory];
XCTAssertFalse([factory isRunning]);
XCTAssertTrue([factory startControllerFactory:factoryParams error:nil]);
XCTAssertTrue([factory isRunning]);
MTRDeviceController * controller4 = [factory createControllerOnExistingFabric:params2 error:nil];
XCTAssertTrue([controller4 isRunning]);
[controller4 shutdown];
[factory stopControllerFactory];
XCTAssertFalse([factory isRunning]);
}
- (void)testControllerInvalidAccess
{
__auto_type * factory = [MTRDeviceControllerFactory sharedInstance];
XCTAssertNotNil(factory);
__auto_type * storage = [[MTRTestStorage alloc] init];
__auto_type * factoryParams = [[MTRDeviceControllerFactoryParams alloc] initWithStorage:storage];
XCTAssertTrue([factory startControllerFactory:factoryParams error:nil]);
XCTAssertTrue([factory isRunning]);
__auto_type * testKeys = [[MTRTestKeys alloc] init];
XCTAssertNotNil(testKeys);
__auto_type * params = [[MTRDeviceControllerStartupParams alloc] initWithIPK:testKeys.ipk fabricID:@(1) nocSigner:testKeys];
XCTAssertNotNil(params);
params.vendorID = @(kTestVendorId);
MTRDeviceController * controller = [factory createControllerOnNewFabric:params error:nil];
XCTAssertTrue([controller isRunning]);
[controller shutdown];
XCTAssertFalse([controller isRunning]);
[factory stopControllerFactory];
XCTAssertFalse([factory isRunning]);
}
- (void)testControllerNewFabricMatchesOldFabric
{
__auto_type * factory = [MTRDeviceControllerFactory sharedInstance];
XCTAssertNotNil(factory);
__auto_type * storage = [[MTRTestStorage alloc] init];
__auto_type * factoryParams = [[MTRDeviceControllerFactoryParams alloc] initWithStorage:storage];
XCTAssertTrue([factory startControllerFactory:factoryParams error:nil]);
XCTAssertTrue([factory isRunning]);
__auto_type * testKeys = [[MTRTestKeys alloc] init];
XCTAssertNotNil(testKeys);
__auto_type * params = [[MTRDeviceControllerStartupParams alloc] initWithIPK:testKeys.ipk fabricID:@(1) nocSigner:testKeys];
XCTAssertNotNil(params);
params.vendorID = @(kTestVendorId);
MTRDeviceController * controller = [factory createControllerOnNewFabric:params error:nil];
XCTAssertNotNil(controller);
XCTAssertTrue([controller isRunning]);
[controller shutdown];
XCTAssertFalse([controller isRunning]);
// now try to start a new controller on a new fabric but using the
// same params; this should fail.
XCTAssertNil([factory createControllerOnNewFabric:params error:nil]);
XCTAssertFalse([controller isRunning]);
[factory stopControllerFactory];
XCTAssertFalse([factory isRunning]);
}
- (void)testControllerExistingFabricMatchesRunningController
{
__auto_type * factory = [MTRDeviceControllerFactory sharedInstance];
XCTAssertNotNil(factory);
__auto_type * storage = [[MTRTestStorage alloc] init];
__auto_type * factoryParams = [[MTRDeviceControllerFactoryParams alloc] initWithStorage:storage];
XCTAssertTrue([factory startControllerFactory:factoryParams error:nil]);
XCTAssertTrue([factory isRunning]);
__auto_type * testKeys = [[MTRTestKeys alloc] init];
XCTAssertNotNil(testKeys);
__auto_type * params = [[MTRDeviceControllerStartupParams alloc] initWithIPK:testKeys.ipk fabricID:@(1) nocSigner:testKeys];
XCTAssertNotNil(params);
params.vendorID = @(kTestVendorId);
MTRDeviceController * controller = [factory createControllerOnNewFabric:params error:nil];
XCTAssertNotNil(controller);
XCTAssertTrue([controller isRunning]);
// Now try to start a new controller on the same fabric. This should fail.
XCTAssertNil([factory createControllerOnExistingFabric:params error:nil]);
XCTAssertTrue([controller isRunning]);
[controller shutdown];
XCTAssertFalse([controller isRunning]);
[factory stopControllerFactory];
XCTAssertFalse([factory isRunning]);
}
- (void)testControllerStartControllersOnTwoFabricIds
{
__auto_type * factory = [MTRDeviceControllerFactory sharedInstance];
XCTAssertNotNil(factory);
__auto_type * storage = [[MTRTestStorage alloc] init];
__auto_type * factoryParams = [[MTRDeviceControllerFactoryParams alloc] initWithStorage:storage];
XCTAssertTrue([factory startControllerFactory:factoryParams error:nil]);
XCTAssertTrue([factory isRunning]);
__auto_type * testKeys = [[MTRTestKeys alloc] init];
XCTAssertNotNil(testKeys);
__auto_type * params1 = [[MTRDeviceControllerStartupParams alloc] initWithIPK:testKeys.ipk fabricID:@(1) nocSigner:testKeys];
XCTAssertNotNil(params1);
params1.vendorID = @(kTestVendorId);
MTRDeviceController * controller1 = [factory createControllerOnNewFabric:params1 error:nil];
XCTAssertNotNil(controller1);
XCTAssertTrue([controller1 isRunning]);
// Now try to start a new controller with the same root but a
// different fabric id.
__auto_type * params2 = [[MTRDeviceControllerStartupParams alloc] initWithIPK:testKeys.ipk fabricID:@(2) nocSigner:testKeys];
XCTAssertNotNil(params2);
params2.vendorID = @(kTestVendorId);
MTRDeviceController * controller2 = [factory createControllerOnNewFabric:params2 error:nil];
XCTAssertNotNil(controller2);
XCTAssertTrue([controller2 isRunning]);
// Verify that we can't start on an existing fabric while we have a
// controller on that fabric already.
XCTAssertNil([factory createControllerOnExistingFabric:params2 error:nil]);
// Now test restarting the controller on the first fabric while the
// controller on the second fabric is still running.
[controller1 shutdown];
XCTAssertFalse([controller1 isRunning]);
controller1 = [factory createControllerOnExistingFabric:params1 error:nil];
XCTAssertNotNil(controller1);
XCTAssertTrue([controller1 isRunning]);
// Now test restarting the controller on the second fabric while the
// controller on the first fabric is still running.
[controller2 shutdown];
XCTAssertFalse([controller2 isRunning]);
controller2 = [factory createControllerOnExistingFabric:params2 error:nil];
XCTAssertNotNil(controller2);
XCTAssertTrue([controller2 isRunning]);
// Shut down everything.
[controller1 shutdown];
XCTAssertFalse([controller1 isRunning]);
[controller2 shutdown];
XCTAssertFalse([controller2 isRunning]);
[factory stopControllerFactory];
XCTAssertFalse([factory isRunning]);
}
- (void)testControllerStartControllerSameFabricWrongSubject
{
__auto_type * factory = [MTRDeviceControllerFactory sharedInstance];
XCTAssertNotNil(factory);
__auto_type * storage = [[MTRTestStorage alloc] init];
__auto_type * factoryParams = [[MTRDeviceControllerFactoryParams alloc] initWithStorage:storage];
XCTAssertTrue([factory startControllerFactory:factoryParams error:nil]);
XCTAssertTrue([factory isRunning]);
__auto_type * testKeys = [[MTRTestKeys alloc] init];
XCTAssertNotNil(testKeys);
__auto_type * root1 = [MTRCertificates createRootCertificate:testKeys issuerID:@1 fabricID:@1 error:nil];
XCTAssertNotNil(root1);
__auto_type * root2 = [MTRCertificates createRootCertificate:testKeys issuerID:@1 fabricID:@1 error:nil];
XCTAssertNotNil(root2);
__auto_type * root3 = [MTRCertificates createRootCertificate:testKeys issuerID:@2 fabricID:@1 error:nil];
XCTAssertNotNil(root3);
__auto_type * params = [[MTRDeviceControllerStartupParams alloc] initWithIPK:testKeys.ipk fabricID:@(1) nocSigner:testKeys];
XCTAssertNotNil(params);
params.vendorID = @(kTestVendorId);
params.rootCertificate = root1;
MTRDeviceController * controller = [factory createControllerOnNewFabric:params error:nil];
XCTAssertNotNil(controller);
XCTAssertTrue([controller isRunning]);
[controller shutdown];
XCTAssertFalse([controller isRunning]);
// Now try to start a new controller on the same fabric with what should be
// a compatible root certificate.
params.rootCertificate = root2;
controller = [factory createControllerOnExistingFabric:params error:nil];
XCTAssertNotNil(controller);
XCTAssertTrue([controller isRunning]);
NSNumber * nodeId = [controller controllerNodeID];
[controller shutdown];
XCTAssertFalse([controller isRunning]);
// Now try to start a new controller on the same fabric but with a root
// certificate that has a different subject. This should fail for multipler
// reasons, including our existing operational certificate not matching this
// root.
params.rootCertificate = root3;
controller = [factory createControllerOnExistingFabric:params error:nil];
XCTAssertNil(controller);
// Now try to start a new controller on the same fabric but with a root
// certificate that has a different subject while also rotating the
// operational certificate. This should fail because our root of trust for
// the fabric would change if we allowed this.
params.rootCertificate = root3;
params.nodeID = nodeId;
controller = [factory createControllerOnExistingFabric:params error:nil];
XCTAssertNil(controller);
[factory stopControllerFactory];
XCTAssertFalse([factory isRunning]);
}
- (void)testControllerFabricIdRootCertMismatch
{
__auto_type * factory = [MTRDeviceControllerFactory sharedInstance];
XCTAssertNotNil(factory);
__auto_type * storage = [[MTRTestStorage alloc] init];
__auto_type * factoryParams = [[MTRDeviceControllerFactoryParams alloc] initWithStorage:storage];
XCTAssertTrue([factory startControllerFactory:factoryParams error:nil]);
XCTAssertTrue([factory isRunning]);
__auto_type * testKeys = [[MTRTestKeys alloc] init];
XCTAssertNotNil(testKeys);
__auto_type * root1 = [MTRCertificates createRootCertificate:testKeys issuerID:@1 fabricID:@1 error:nil];
XCTAssertNotNil(root1);
__auto_type * root2 = [MTRCertificates createRootCertificate:testKeys issuerID:@1 fabricID:@2 error:nil];
XCTAssertNotNil(root2);
__auto_type * params = [[MTRDeviceControllerStartupParams alloc] initWithIPK:testKeys.ipk fabricID:@(1) nocSigner:testKeys];
XCTAssertNotNil(params);
params.vendorID = @(kTestVendorId);
// Try to start controller when fabric id in root cert subject does not match provided fabric id.
params.rootCertificate = root2;
MTRDeviceController * controller = [factory createControllerOnNewFabric:params error:nil];
XCTAssertNil(controller);
// Start controller when the fabric ids do match.
params.rootCertificate = root1;
controller = [factory createControllerOnNewFabric:params error:nil];
XCTAssertNotNil(controller);
XCTAssertTrue([controller isRunning]);
[controller shutdown];
XCTAssertFalse([controller isRunning]);
// Re-start controller on the new fabric.
controller = [factory createControllerOnExistingFabric:params error:nil];
XCTAssertNotNil(controller);
XCTAssertTrue([controller isRunning]);
[controller shutdown];
XCTAssertFalse([controller isRunning]);
// Now try to restart controller on the fabric, but with the wrong fabric id
// in the root cert.
params.rootCertificate = root2;
controller = [factory createControllerOnExistingFabric:params error:nil];
XCTAssertNil(controller);
[factory stopControllerFactory];
XCTAssertFalse([factory isRunning]);
}
- (void)testControllerSignerDoesNotMatchRoot
{
__auto_type * factory = [MTRDeviceControllerFactory sharedInstance];
XCTAssertNotNil(factory);
__auto_type * storage = [[MTRTestStorage alloc] init];
__auto_type * factoryParams = [[MTRDeviceControllerFactoryParams alloc] initWithStorage:storage];
XCTAssertTrue([factory startControllerFactory:factoryParams error:nil]);
XCTAssertTrue([factory isRunning]);
__auto_type * rootKeys = [[MTRTestKeys alloc] init];
XCTAssertNotNil(rootKeys);
__auto_type * signerKeys = [[MTRTestKeys alloc] init];
XCTAssertNotNil(signerKeys);
__auto_type * root = [MTRCertificates createRootCertificate:rootKeys issuerID:nil fabricID:nil error:nil];
XCTAssertNotNil(root);
__auto_type * params = [[MTRDeviceControllerStartupParams alloc] initWithIPK:rootKeys.ipk fabricID:@(1) nocSigner:signerKeys];
XCTAssertNotNil(params);
params.vendorID = @(kTestVendorId);
params.rootCertificate = root;
// Try to start controller when there is no ICA and root cert does not match signing key.
params.rootCertificate = root;
MTRDeviceController * controller = [factory createControllerOnNewFabric:params error:nil];
XCTAssertNil(controller);
[factory stopControllerFactory];
XCTAssertFalse([factory isRunning]);
}
- (void)testControllerSignerKeyWithIntermediate
{
__auto_type * factory = [MTRDeviceControllerFactory sharedInstance];
XCTAssertNotNil(factory);
__auto_type * storage = [[MTRTestStorage alloc] init];
__auto_type * factoryParams = [[MTRDeviceControllerFactoryParams alloc] initWithStorage:storage];
XCTAssertTrue([factory startControllerFactory:factoryParams error:nil]);
XCTAssertTrue([factory isRunning]);
__auto_type * rootKeys = [[MTRTestKeys alloc] init];
XCTAssertNotNil(rootKeys);
__auto_type * root = [MTRCertificates createRootCertificate:rootKeys issuerID:nil fabricID:nil error:nil];
XCTAssertNotNil(root);
__auto_type * intermediateKeys = [[MTRTestKeys alloc] init];
XCTAssertNotNil(intermediateKeys);
__auto_type * intermediate = [MTRCertificates createIntermediateCertificate:rootKeys
rootCertificate:root
intermediatePublicKey:intermediateKeys.publicKey
issuerID:nil
fabricID:nil
error:nil];
XCTAssertNotNil(intermediate);
__auto_type * params = [[MTRDeviceControllerStartupParams alloc] initWithIPK:rootKeys.ipk fabricID:@(1) nocSigner:rootKeys];
XCTAssertNotNil(params);
params.vendorID = @(kTestVendorId);
// Try to start controller when there is an ICA and the ICA cert does not match signing key.
params.rootCertificate = root;
params.intermediateCertificate = intermediate;
MTRDeviceController * controller = [factory createControllerOnNewFabric:params error:nil];
XCTAssertNil(controller);
// Now start controller with the signing key matching the intermediate cert.
params = [[MTRDeviceControllerStartupParams alloc] initWithIPK:rootKeys.ipk fabricID:@(1) nocSigner:intermediateKeys];
params.vendorID = @(kTestVendorId);
params.rootCertificate = root;
params.intermediateCertificate = intermediate;
controller = [factory createControllerOnNewFabric:params error:nil];
XCTAssertNotNil(controller);
XCTAssertTrue([controller isRunning]);
[controller shutdown];
XCTAssertFalse([controller isRunning]);
[factory stopControllerFactory];
XCTAssertFalse([factory isRunning]);
}
- (void)testControllerStartupParamsInvalidFabric
{
__auto_type * factory = [MTRDeviceControllerFactory sharedInstance];
XCTAssertNotNil(factory);
__auto_type * storage = [[MTRTestStorage alloc] init];
__auto_type * factoryParams = [[MTRDeviceControllerFactoryParams alloc] initWithStorage:storage];
XCTAssertTrue([factory startControllerFactory:factoryParams error:nil]);
XCTAssertTrue([factory isRunning]);
__auto_type * rootKeys = [[MTRTestKeys alloc] init];
XCTAssertNotNil(rootKeys);
// Invalid fabric ID.
__auto_type * params = [[MTRDeviceControllerStartupParams alloc] initWithIPK:rootKeys.ipk fabricID:@(0) nocSigner:rootKeys];
XCTAssertNil(params);
[factory stopControllerFactory];
XCTAssertFalse([factory isRunning]);
}
- (void)testControllerStartupParamsInvalidVendor
{
__auto_type * factory = [MTRDeviceControllerFactory sharedInstance];
XCTAssertNotNil(factory);
__auto_type * storage = [[MTRTestStorage alloc] init];
__auto_type * factoryParams = [[MTRDeviceControllerFactoryParams alloc] initWithStorage:storage];
XCTAssertTrue([factory startControllerFactory:factoryParams error:nil]);
XCTAssertTrue([factory isRunning]);
__auto_type * rootKeys = [[MTRTestKeys alloc] init];
XCTAssertNotNil(rootKeys);
__auto_type * params = [[MTRDeviceControllerStartupParams alloc] initWithIPK:rootKeys.ipk fabricID:@(1) nocSigner:rootKeys];
XCTAssertNotNil(params);
// Invalid vendor ID ("standard").
params.vendorID = @(0);
MTRDeviceController * controller = [factory createControllerOnNewFabric:params error:nil];
XCTAssertNil(controller);
[factory stopControllerFactory];
XCTAssertFalse([factory isRunning]);
}
- (void)testControllerStartupNodeIdPreserved
{
__auto_type * factory = [MTRDeviceControllerFactory sharedInstance];
XCTAssertNotNil(factory);
__auto_type * storage = [[MTRTestStorage alloc] init];
__auto_type * factoryParams = [[MTRDeviceControllerFactoryParams alloc] initWithStorage:storage];
XCTAssertTrue([factory startControllerFactory:factoryParams error:nil]);
XCTAssertTrue([factory isRunning]);
__auto_type * rootKeys = [[MTRTestKeys alloc] init];
XCTAssertNotNil(rootKeys);
__auto_type * params = [[MTRDeviceControllerStartupParams alloc] initWithIPK:rootKeys.ipk fabricID:@(1) nocSigner:rootKeys];
XCTAssertNotNil(params);
params.vendorID = @(kTestVendorId);
MTRDeviceController * controller = [factory createControllerOnNewFabric:params error:nil];
XCTAssertNotNil(controller);
XCTAssertTrue([controller isRunning]);
NSNumber * nodeId = [controller controllerNodeID];
[controller shutdown];
XCTAssertFalse([controller isRunning]);
controller = [factory createControllerOnExistingFabric:params error:nil];
XCTAssertNotNil(controller);
XCTAssertTrue([controller isRunning]);
XCTAssertEqualObjects([controller controllerNodeID], nodeId);
[controller shutdown];
XCTAssertFalse([controller isRunning]);
[factory stopControllerFactory];
XCTAssertFalse([factory isRunning]);
}
- (void)testControllerStartupNodeIdUsed
{
__auto_type * factory = [MTRDeviceControllerFactory sharedInstance];
XCTAssertNotNil(factory);
__auto_type * storage = [[MTRTestStorage alloc] init];
__auto_type * factoryParams = [[MTRDeviceControllerFactoryParams alloc] initWithStorage:storage];
XCTAssertTrue([factory startControllerFactory:factoryParams error:nil]);
XCTAssertTrue([factory isRunning]);
__auto_type * rootKeys = [[MTRTestKeys alloc] init];
XCTAssertNotNil(rootKeys);
__auto_type * params = [[MTRDeviceControllerStartupParams alloc] initWithIPK:rootKeys.ipk fabricID:@(1) nocSigner:rootKeys];
XCTAssertNotNil(params);
params.vendorID = @(kTestVendorId);
// Bring up with node id 17.
params.nodeID = @17;
MTRDeviceController * controller = [factory createControllerOnNewFabric:params error:nil];
XCTAssertNotNil(controller);
XCTAssertTrue([controller isRunning]);
XCTAssertEqualObjects([controller controllerNodeID], @17);
[controller shutdown];
XCTAssertFalse([controller isRunning]);
// Bring up with a different node id (18).
params.nodeID = @18;
controller = [factory createControllerOnExistingFabric:params error:nil];
XCTAssertNotNil(controller);
XCTAssertTrue([controller isRunning]);
XCTAssertEqualObjects([controller controllerNodeID], @18);
[controller shutdown];
XCTAssertFalse([controller isRunning]);
// Verify the new node id has been stored.
params.nodeID = nil;
controller = [factory createControllerOnExistingFabric:params error:nil];
XCTAssertNotNil(controller);
XCTAssertTrue([controller isRunning]);
XCTAssertEqualObjects([controller controllerNodeID], @18);
[controller shutdown];
XCTAssertFalse([controller isRunning]);
[factory stopControllerFactory];
XCTAssertFalse([factory isRunning]);
}
- (void)testControllerStartupNodeIdValidation
{
__auto_type * factory = [MTRDeviceControllerFactory sharedInstance];
XCTAssertNotNil(factory);
__auto_type * storage = [[MTRTestStorage alloc] init];
__auto_type * factoryParams = [[MTRDeviceControllerFactoryParams alloc] initWithStorage:storage];
XCTAssertTrue([factory startControllerFactory:factoryParams error:nil]);
XCTAssertTrue([factory isRunning]);
__auto_type * rootKeys = [[MTRTestKeys alloc] init];
XCTAssertNotNil(rootKeys);
__auto_type * params = [[MTRDeviceControllerStartupParams alloc] initWithIPK:rootKeys.ipk fabricID:@(1) nocSigner:rootKeys];
XCTAssertNotNil(params);
params.vendorID = @(kTestVendorId);
// Try to bring up with node id 0.
params.nodeID = @0;
MTRDeviceController * controller = [factory createControllerOnNewFabric:params error:nil];
XCTAssertNil(controller);
// Try to bring up with node id that is outside of the operational range.
params.nodeID = @(0xFFFFFFFF00000000ULL);
controller = [factory createControllerOnNewFabric:params error:nil];
XCTAssertNil(controller);
// Verify that we can indeed bring up a controller for this fabric, with a valid node id.
params.nodeID = @17;
controller = [factory createControllerOnNewFabric:params error:nil];
XCTAssertNotNil(controller);
XCTAssertTrue([controller isRunning]);
XCTAssertEqualObjects([controller controllerNodeID], @17);
[controller shutdown];
XCTAssertFalse([controller isRunning]);
[factory stopControllerFactory];
XCTAssertFalse([factory isRunning]);
}
- (void)testControllerRotateToICA
{
// Tests that we can switch a fabric from not using an ICA to using an ICA.
__auto_type * factory = [MTRDeviceControllerFactory sharedInstance];
XCTAssertNotNil(factory);
__auto_type * storage = [[MTRTestStorage alloc] init];
__auto_type * factoryParams = [[MTRDeviceControllerFactoryParams alloc] initWithStorage:storage];
XCTAssertTrue([factory startControllerFactory:factoryParams error:nil]);
XCTAssertTrue([factory isRunning]);
__auto_type * rootKeys = [[MTRTestKeys alloc] init];
XCTAssertNotNil(rootKeys);
__auto_type * root = [MTRCertificates createRootCertificate:rootKeys issuerID:nil fabricID:nil error:nil];
XCTAssertNotNil(root);
__auto_type * intermediateKeys = [[MTRTestKeys alloc] init];
XCTAssertNotNil(intermediateKeys);
__auto_type * intermediate = [MTRCertificates createIntermediateCertificate:rootKeys
rootCertificate:root
intermediatePublicKey:intermediateKeys.publicKey
issuerID:nil
fabricID:nil
error:nil];
XCTAssertNotNil(intermediate);
__auto_type * params = [[MTRDeviceControllerStartupParams alloc] initWithIPK:rootKeys.ipk fabricID:@(1) nocSigner:rootKeys];
XCTAssertNotNil(params);
params.vendorID = @(kTestVendorId);
// Create a new fabric without the ICA.
params.rootCertificate = root;
MTRDeviceController * controller = [factory createControllerOnNewFabric:params error:nil];
XCTAssertNotNil(controller);
XCTAssertTrue([controller isRunning]);
NSNumber * nodeId = [controller controllerNodeID];
[controller shutdown];
XCTAssertFalse([controller isRunning]);
// Now start controller on the same fabric but using the ICA.
params = [[MTRDeviceControllerStartupParams alloc] initWithIPK:rootKeys.ipk fabricID:@(1) nocSigner:intermediateKeys];
params.vendorID = @(kTestVendorId);
params.rootCertificate = root;
params.intermediateCertificate = intermediate;
controller = [factory createControllerOnExistingFabric:params error:nil];
XCTAssertNotNil(controller);
XCTAssertTrue([controller isRunning]);
XCTAssertEqualObjects([controller controllerNodeID], nodeId);
[controller shutdown];
XCTAssertFalse([controller isRunning]);
[factory stopControllerFactory];
XCTAssertFalse([factory isRunning]);
}
- (void)testControllerRotateFromICA
{
// Tests that we can switch a fabric from using an ICA to not using an ICA.
__auto_type * factory = [MTRDeviceControllerFactory sharedInstance];
XCTAssertNotNil(factory);
__auto_type * storage = [[MTRTestStorage alloc] init];
__auto_type * factoryParams = [[MTRDeviceControllerFactoryParams alloc] initWithStorage:storage];
XCTAssertTrue([factory startControllerFactory:factoryParams error:nil]);
XCTAssertTrue([factory isRunning]);
__auto_type * rootKeys = [[MTRTestKeys alloc] init];
XCTAssertNotNil(rootKeys);
__auto_type * root = [MTRCertificates createRootCertificate:rootKeys issuerID:nil fabricID:nil error:nil];
XCTAssertNotNil(root);
__auto_type * intermediateKeys = [[MTRTestKeys alloc] init];
XCTAssertNotNil(intermediateKeys);
__auto_type * intermediate = [MTRCertificates createIntermediateCertificate:rootKeys
rootCertificate:root
intermediatePublicKey:intermediateKeys.publicKey
issuerID:nil
fabricID:nil
error:nil];
XCTAssertNotNil(intermediate);
__auto_type * params = [[MTRDeviceControllerStartupParams alloc] initWithIPK:rootKeys.ipk
fabricID:@(1)
nocSigner:intermediateKeys];
XCTAssertNotNil(params);
params.vendorID = @(kTestVendorId);
// Create a new fabric without the ICA.
params.rootCertificate = root;
params.intermediateCertificate = intermediate;
MTRDeviceController * controller = [factory createControllerOnNewFabric:params error:nil];
XCTAssertNotNil(controller);
XCTAssertTrue([controller isRunning]);
NSNumber * nodeId = [controller controllerNodeID];
[controller shutdown];
XCTAssertFalse([controller isRunning]);
// Now start controller on the same fabric but without using the ICA.
params = [[MTRDeviceControllerStartupParams alloc] initWithIPK:rootKeys.ipk fabricID:@(1) nocSigner:rootKeys];
params.vendorID = @(kTestVendorId);
params.rootCertificate = root;
controller = [factory createControllerOnExistingFabric:params error:nil];
XCTAssertNotNil(controller);
XCTAssertTrue([controller isRunning]);
XCTAssertEqualObjects([controller controllerNodeID], nodeId);
[controller shutdown];
XCTAssertFalse([controller isRunning]);
[factory stopControllerFactory];
XCTAssertFalse([factory isRunning]);
}
- (void)testControllerRotateICA
{
// Tests that we can change the ICA being used for a fabric.
__auto_type * factory = [MTRDeviceControllerFactory sharedInstance];
XCTAssertNotNil(factory);
__auto_type * storage = [[MTRTestStorage alloc] init];
__auto_type * factoryParams = [[MTRDeviceControllerFactoryParams alloc] initWithStorage:storage];
XCTAssertTrue([factory startControllerFactory:factoryParams error:nil]);
XCTAssertTrue([factory isRunning]);
__auto_type * rootKeys = [[MTRTestKeys alloc] init];
XCTAssertNotNil(rootKeys);
__auto_type * root = [MTRCertificates createRootCertificate:rootKeys issuerID:nil fabricID:nil error:nil];
XCTAssertNotNil(root);
__auto_type * intermediateKeys1 = [[MTRTestKeys alloc] init];
XCTAssertNotNil(intermediateKeys1);
__auto_type * intermediate1 = [MTRCertificates createIntermediateCertificate:rootKeys
rootCertificate:root
intermediatePublicKey:intermediateKeys1.publicKey
issuerID:nil
fabricID:nil
error:nil];
XCTAssertNotNil(intermediate1);
__auto_type * intermediateKeys2 = [[MTRTestKeys alloc] init];
XCTAssertNotNil(intermediateKeys2);
__auto_type * intermediate2 = [MTRCertificates createIntermediateCertificate:rootKeys
rootCertificate:root
intermediatePublicKey:intermediateKeys2.publicKey
issuerID:nil
fabricID:nil
error:nil];
XCTAssertNotNil(intermediate2);
__auto_type * params = [[MTRDeviceControllerStartupParams alloc] initWithIPK:rootKeys.ipk
fabricID:@(1)
nocSigner:intermediateKeys1];
XCTAssertNotNil(params);
params.vendorID = @(kTestVendorId);
// Create a new fabric without the first ICA.
params.rootCertificate = root;
params.intermediateCertificate = intermediate1;
MTRDeviceController * controller = [factory createControllerOnNewFabric:params error:nil];
XCTAssertNotNil(controller);
XCTAssertTrue([controller isRunning]);
NSNumber * nodeId = [controller controllerNodeID];
[controller shutdown];
XCTAssertFalse([controller isRunning]);
// Now start controller on the same fabric but using the second ICA.
params = [[MTRDeviceControllerStartupParams alloc] initWithIPK:rootKeys.ipk fabricID:@(1) nocSigner:intermediateKeys2];
params.vendorID = @(kTestVendorId);
params.rootCertificate = root;
params.intermediateCertificate = intermediate2;
controller = [factory createControllerOnExistingFabric:params error:nil];
XCTAssertNotNil(controller);
XCTAssertTrue([controller isRunning]);
XCTAssertEqualObjects([controller controllerNodeID], nodeId);
[controller shutdown];
XCTAssertFalse([controller isRunning]);
[factory stopControllerFactory];
XCTAssertFalse([factory isRunning]);
}
- (void)testControllerICAWithoutRoot
{
__auto_type * factory = [MTRDeviceControllerFactory sharedInstance];
XCTAssertNotNil(factory);
__auto_type * storage = [[MTRTestStorage alloc] init];
__auto_type * factoryParams = [[MTRDeviceControllerFactoryParams alloc] initWithStorage:storage];
XCTAssertTrue([factory startControllerFactory:factoryParams error:nil]);
XCTAssertTrue([factory isRunning]);
__auto_type * rootKeys = [[MTRTestKeys alloc] init];
XCTAssertNotNil(rootKeys);
__auto_type * root = [MTRCertificates createRootCertificate:rootKeys issuerID:nil fabricID:nil error:nil];
XCTAssertNotNil(root);
__auto_type * intermediateKeys = [[MTRTestKeys alloc] init];
XCTAssertNotNil(intermediateKeys);
__auto_type * intermediate = [MTRCertificates createIntermediateCertificate:rootKeys
rootCertificate:root
intermediatePublicKey:intermediateKeys.publicKey
issuerID:nil
fabricID:nil
error:nil];
XCTAssertNotNil(intermediate);
__auto_type * params = [[MTRDeviceControllerStartupParams alloc] initWithIPK:rootKeys.ipk
fabricID:@(1)
nocSigner:intermediateKeys];
XCTAssertNotNil(params);
params.vendorID = @(kTestVendorId);
// Pass in an intermediate but no root. Should fail.
params.intermediateCertificate = intermediate;
MTRDeviceController * controller = [factory createControllerOnNewFabric:params error:nil];
XCTAssertNil(controller);
[factory stopControllerFactory];
XCTAssertFalse([factory isRunning]);
}
- (void)testControllerProvideFullCertChain
{
__auto_type * factory = [MTRDeviceControllerFactory sharedInstance];
XCTAssertNotNil(factory);
__auto_type * storage = [[MTRTestStorage alloc] init];
__auto_type * factoryParams = [[MTRDeviceControllerFactoryParams alloc] initWithStorage:storage];
XCTAssertTrue([factory startControllerFactory:factoryParams error:nil]);
XCTAssertTrue([factory isRunning]);
__auto_type * rootKeys = [[MTRTestKeys alloc] init];
XCTAssertNotNil(rootKeys);
__auto_type * root = [MTRCertificates createRootCertificate:rootKeys issuerID:nil fabricID:nil error:nil];
XCTAssertNotNil(root);
__auto_type * intermediateKeys = [[MTRTestKeys alloc] init];
XCTAssertNotNil(intermediateKeys);
__auto_type * intermediate = [MTRCertificates createIntermediateCertificate:rootKeys
rootCertificate:root
intermediatePublicKey:intermediateKeys.publicKey
issuerID:nil
fabricID:nil
error:nil];
XCTAssertNotNil(intermediate);
__auto_type * operationalKeys = [[MTRTestKeys alloc] init];
XCTAssertNotNil(operationalKeys);
__auto_type * operational = [MTRCertificates createOperationalCertificate:intermediateKeys
signingCertificate:intermediate
operationalPublicKey:operationalKeys.publicKey
fabricID:@123
nodeID:@456
caseAuthenticatedTags:nil
error:nil];
XCTAssertNotNil(operational);
__auto_type * params = [[MTRDeviceControllerStartupParams alloc] initWithIPK:rootKeys.ipk
operationalKeypair:operationalKeys
operationalCertificate:operational
intermediateCertificate:intermediate
rootCertificate:root];
XCTAssertNotNil(params);
params.vendorID = @(kTestVendorId);
MTRDeviceController * controller = [factory createControllerOnNewFabric:params error:nil];
XCTAssertNotNil(controller);
XCTAssertTrue([controller isRunning]);
XCTAssertEqualObjects([controller controllerNodeID], @456);
[controller shutdown];
XCTAssertFalse([controller isRunning]);
// Trying to bring up another new fabric with the same root and NOC should fail.
controller = [factory createControllerOnNewFabric:params error:nil];
XCTAssertNil(controller);
// Trying to bring up the same fabric should succeed.
controller = [factory createControllerOnExistingFabric:params error:nil];
XCTAssertNotNil(controller);
XCTAssertTrue([controller isRunning]);
XCTAssertEqualObjects([controller controllerNodeID], @456);
[controller shutdown];
XCTAssertFalse([controller isRunning]);
[factory stopControllerFactory];
XCTAssertFalse([factory isRunning]);
}
- (void)testControllerProvideCertChainNoICA
{
__auto_type * factory = [MTRDeviceControllerFactory sharedInstance];
XCTAssertNotNil(factory);
__auto_type * storage = [[MTRTestStorage alloc] init];
__auto_type * factoryParams = [[MTRDeviceControllerFactoryParams alloc] initWithStorage:storage];
XCTAssertTrue([factory startControllerFactory:factoryParams error:nil]);
XCTAssertTrue([factory isRunning]);
__auto_type * rootKeys = [[MTRTestKeys alloc] init];
XCTAssertNotNil(rootKeys);
__auto_type * root = [MTRCertificates createRootCertificate:rootKeys issuerID:nil fabricID:nil error:nil];
XCTAssertNotNil(root);
__auto_type * operationalKeys = [[MTRTestKeys alloc] init];
XCTAssertNotNil(operationalKeys);
__auto_type * operational = [MTRCertificates createOperationalCertificate:rootKeys
signingCertificate:root
operationalPublicKey:operationalKeys.publicKey
fabricID:@123
nodeID:@456
caseAuthenticatedTags:nil
error:nil];
XCTAssertNotNil(operational);
__auto_type * params = [[MTRDeviceControllerStartupParams alloc] initWithIPK:rootKeys.ipk
operationalKeypair:operationalKeys
operationalCertificate:operational
intermediateCertificate:nil
rootCertificate:root];
XCTAssertNotNil(params);
params.vendorID = @(kTestVendorId);
MTRDeviceController * controller = [factory createControllerOnNewFabric:params error:nil];
XCTAssertNotNil(controller);
XCTAssertTrue([controller isRunning]);
XCTAssertEqualObjects([controller controllerNodeID], @456);
[controller shutdown];
XCTAssertFalse([controller isRunning]);
[factory stopControllerFactory];
XCTAssertFalse([factory isRunning]);
}
- (void)testControllerCertChainFabricMismatchRoot
{
__auto_type * factory = [MTRDeviceControllerFactory sharedInstance];
XCTAssertNotNil(factory);
__auto_type * storage = [[MTRTestStorage alloc] init];
__auto_type * factoryParams = [[MTRDeviceControllerFactoryParams alloc] initWithStorage:storage];
XCTAssertTrue([factory startControllerFactory:factoryParams error:nil]);
XCTAssertTrue([factory isRunning]);
__auto_type * rootKeys = [[MTRTestKeys alloc] init];
XCTAssertNotNil(rootKeys);
__auto_type * root = [MTRCertificates createRootCertificate:rootKeys issuerID:nil fabricID:@111 error:nil];
XCTAssertNotNil(root);
__auto_type * operationalKeys = [[MTRTestKeys alloc] init];
XCTAssertNotNil(operationalKeys);
__auto_type * operational = [MTRCertificates createOperationalCertificate:rootKeys
signingCertificate:root
operationalPublicKey:operationalKeys.publicKey
fabricID:@123
nodeID:@456
caseAuthenticatedTags:nil
error:nil];
XCTAssertNotNil(operational);
__auto_type * params = [[MTRDeviceControllerStartupParams alloc] initWithIPK:rootKeys.ipk
operationalKeypair:operationalKeys
operationalCertificate:operational
intermediateCertificate:nil
rootCertificate:root];
XCTAssertNotNil(params);
params.vendorID = @(kTestVendorId);
MTRDeviceController * controller = [factory createControllerOnNewFabric:params error:nil];
XCTAssertNil(controller);
[factory stopControllerFactory];
XCTAssertFalse([factory isRunning]);
}
- (void)testControllerCertChainFabricMismatchIntermediate
{
__auto_type * factory = [MTRDeviceControllerFactory sharedInstance];
XCTAssertNotNil(factory);
__auto_type * storage = [[MTRTestStorage alloc] init];
__auto_type * factoryParams = [[MTRDeviceControllerFactoryParams alloc] initWithStorage:storage];
XCTAssertTrue([factory startControllerFactory:factoryParams error:nil]);
XCTAssertTrue([factory isRunning]);
__auto_type * rootKeys = [[MTRTestKeys alloc] init];
XCTAssertNotNil(rootKeys);
__auto_type * root = [MTRCertificates createRootCertificate:rootKeys issuerID:nil fabricID:@123 error:nil];
XCTAssertNotNil(root);
__auto_type * intermediateKeys = [[MTRTestKeys alloc] init];
XCTAssertNotNil(intermediateKeys);
__auto_type * intermediate = [MTRCertificates createIntermediateCertificate:rootKeys
rootCertificate:root
intermediatePublicKey:intermediateKeys.publicKey
issuerID:nil
fabricID:@111
error:nil];
XCTAssertNotNil(intermediate);
__auto_type * operationalKeys = [[MTRTestKeys alloc] init];
XCTAssertNotNil(operationalKeys);
__auto_type * operational = [MTRCertificates createOperationalCertificate:intermediateKeys
signingCertificate:intermediate
operationalPublicKey:operationalKeys.publicKey
fabricID:@123
nodeID:@456
caseAuthenticatedTags:nil
error:nil];
XCTAssertNotNil(operational);
__auto_type * params = [[MTRDeviceControllerStartupParams alloc] initWithIPK:rootKeys.ipk
operationalKeypair:operationalKeys
operationalCertificate:operational
intermediateCertificate:intermediate
rootCertificate:root];
XCTAssertNotNil(params);
params.vendorID = @(kTestVendorId);
MTRDeviceController * controller = [factory createControllerOnNewFabric:params error:nil];
XCTAssertNil(controller);
[factory stopControllerFactory];
XCTAssertFalse([factory isRunning]);
}
- (void)testControllerExternallyProvidedOperationalKey
{
__auto_type * factory = [MTRDeviceControllerFactory sharedInstance];
XCTAssertNotNil(factory);
__auto_type * storage = [[MTRTestStorage alloc] init];
__auto_type * factoryParams = [[MTRDeviceControllerFactoryParams alloc] initWithStorage:storage];
XCTAssertTrue([factory startControllerFactory:factoryParams error:nil]);
XCTAssertTrue([factory isRunning]);
__auto_type * rootKeys = [[MTRTestKeys alloc] init];
XCTAssertNotNil(rootKeys);
__auto_type * operationalKeys = [[MTRTestKeys alloc] init];
XCTAssertNotNil(operationalKeys);
__auto_type * params = [[MTRDeviceControllerStartupParams alloc] initWithIPK:rootKeys.ipk fabricID:@(1) nocSigner:rootKeys];
XCTAssertNotNil(params);
params.vendorID = @(kTestVendorId);
params.operationalKeypair = operationalKeys;
MTRDeviceController * controller = [factory createControllerOnNewFabric:params error:nil];
XCTAssertNotNil(controller);
XCTAssertTrue([controller isRunning]);
__auto_type nodeId = [controller controllerNodeID];
[controller shutdown];
XCTAssertFalse([controller isRunning]);
// Trying to bring up the same fabric without specifying the operational
// keypair should now fail, because we won't know what operational keys to
// use.
params.operationalKeypair = nil;
controller = [factory createControllerOnExistingFabric:params error:nil];
XCTAssertNil(controller);
// But bringing up the controller with provided operational keys should
// work, and have the same node id.
params.operationalKeypair = operationalKeys;
controller = [factory createControllerOnExistingFabric:params error:nil];
XCTAssertNotNil(controller);
XCTAssertTrue([controller isRunning]);
XCTAssertEqualObjects([controller controllerNodeID], nodeId);
[controller shutdown];
XCTAssertFalse([controller isRunning]);
// And bringing up the controller with a different provided operational key
// should work too.
__auto_type * newOperationalKeys = [[MTRTestKeys alloc] init];
XCTAssertNotNil(newOperationalKeys);
params.operationalKeypair = newOperationalKeys;
controller = [factory createControllerOnExistingFabric:params error:nil];
XCTAssertNotNil(controller);
XCTAssertTrue([controller isRunning]);
XCTAssertEqualObjects([controller controllerNodeID], nodeId);
[controller shutdown];
XCTAssertFalse([controller isRunning]);
[factory stopControllerFactory];
XCTAssertFalse([factory isRunning]);
}
- (void)testControllerCATs
{
__auto_type * factory = [MTRDeviceControllerFactory sharedInstance];
XCTAssertNotNil(factory);
__auto_type * storage = [[MTRTestStorage alloc] init];
__auto_type * factoryParams = [[MTRDeviceControllerFactoryParams alloc] initWithStorage:storage];
XCTAssertTrue([factory startControllerFactory:factoryParams error:nil]);
XCTAssertTrue([factory isRunning]);
__auto_type * rootKeys = [[MTRTestKeys alloc] init];
XCTAssertNotNil(rootKeys);
__auto_type * params = [[MTRDeviceControllerStartupParams alloc] initWithIPK:rootKeys.ipk fabricID:@(1) nocSigner:rootKeys];
XCTAssertNotNil(params);
params.vendorID = @(kTestVendorId);
//
// Trying to bring up a controller with too-long CATs should fail.
//
__auto_type * tooLongCATs = [NSSet setWithObjects:@(0x10001), @(0x20001), @(0x30001), @(0x40001), nil];
params.caseAuthenticatedTags = tooLongCATs;
MTRDeviceController * controller = [factory createControllerOnExistingFabric:params error:nil];
XCTAssertNil(controller);
//
// Trying to bring up a controller that has an invalid CAT value should
// fail.
//
__auto_type * invalidCATs = [NSSet setWithObjects:@(0x10001), @(0x20001), @(0x0), nil];
params.caseAuthenticatedTags = invalidCATs;
controller = [factory createControllerOnExistingFabric:params error:nil];
XCTAssertNil(controller);
//
// Bring up a controller with valid CATs
//
__auto_type * validCATs = [NSSet setWithObjects:@(0x10001), @(0x20007), @(0x30005), nil];
params.nodeID = @(17);
params.caseAuthenticatedTags = validCATs;
controller = [factory createControllerOnNewFabric:params error:nil];
XCTAssertNotNil(controller);
XCTAssertTrue([controller isRunning]);
// Check that the resulting certificate has the right CATs and node ID
CheckStoredOpcertCats(storage, 1, validCATs);
XCTAssertEqualObjects([controller controllerNodeID], @(17));
[controller shutdown];
XCTAssertFalse([controller isRunning]);
//
// Trying to bring up the same fabric without specifying any node id
// should not allow trying to specify the same CATs.
//
params.nodeID = nil;
params.caseAuthenticatedTags = validCATs;
controller = [factory createControllerOnExistingFabric:params error:nil];
XCTAssertNil(controller);
//
// Trying to bring up the same fabric without specifying any node id
// should not allow trying to specify different CATs.
//
__auto_type * newCATs = [NSSet setWithObjects:@(0x20005), @(0x70009), @(0x80004), nil];
XCTAssertNotEqualObjects(validCATs, newCATs);
params.nodeID = nil;
params.caseAuthenticatedTags = newCATs;
controller = [factory createControllerOnExistingFabric:params error:nil];
XCTAssertNil(controller);
//
// Trying to bring up the same fabric without specifying any node id
// should end up using the existing CATs.
//
params.nodeID = nil;
params.caseAuthenticatedTags = nil;
controller = [factory createControllerOnExistingFabric:params error:nil];
XCTAssertNotNil(controller);
XCTAssertTrue([controller isRunning]);
// Check that the resulting certificate has the right CATs and node ID
CheckStoredOpcertCats(storage, 1, validCATs);
XCTAssertEqualObjects([controller controllerNodeID], @(17));
[controller shutdown];
XCTAssertFalse([controller isRunning]);
//
// Trying to bring up the same fabric without specifying any node id
// should end up using the existing CATs, even if a new
// operational key is specified.
//
__auto_type * operationalKeys = [[MTRTestKeys alloc] init];
XCTAssertNotNil(operationalKeys);
params.nodeID = nil;
params.operationalKeypair = operationalKeys;
params.caseAuthenticatedTags = nil;
controller = [factory createControllerOnExistingFabric:params error:nil];
XCTAssertNotNil(controller);
XCTAssertTrue([controller isRunning]);
// Check that the resulting certificate has the right CATs and node ID
CheckStoredOpcertCats(storage, 1, validCATs);
XCTAssertEqualObjects([controller controllerNodeID], @(17));
[controller shutdown];
XCTAssertFalse([controller isRunning]);
//
// Trying to bring up the same fabric while specifying the node ID, even if
// it's the same one, should pick up the new CATs.
//
params.nodeID = @(17);
params.operationalKeypair = operationalKeys;
params.caseAuthenticatedTags = newCATs;
controller = [factory createControllerOnExistingFabric:params error:nil];
XCTAssertNotNil(controller);
XCTAssertTrue([controller isRunning]);
// Check that the resulting certificate has the right CATs and node ID
CheckStoredOpcertCats(storage, 1, newCATs);
XCTAssertEqualObjects([controller controllerNodeID], @(17));
[controller shutdown];
XCTAssertFalse([controller isRunning]);
//
// Trying to bring up the same fabric while specifying the node ID should
// let us remove CATs altogether.
//
params.nodeID = @(17);
params.operationalKeypair = operationalKeys;
params.caseAuthenticatedTags = nil;
controller = [factory createControllerOnExistingFabric:params error:nil];
XCTAssertNotNil(controller);
XCTAssertTrue([controller isRunning]);
// Check that the resulting certificate has the right CATs and node ID
CheckStoredOpcertCats(storage, 1, nil);
XCTAssertEqualObjects([controller controllerNodeID], @(17));
[controller shutdown];
XCTAssertFalse([controller isRunning]);
//
// Trying to bring up the same fabric with too-long CATs should fail, if we
// are taking the provided CATs into account.
//
params.nodeID = @(17);
params.operationalKeypair = operationalKeys;
params.caseAuthenticatedTags = tooLongCATs;
controller = [factory createControllerOnExistingFabric:params error:nil];
XCTAssertNil(controller);
//
// Trying to bring up the same fabric with invalid CATs should fail, if we
// are taking the provided CATs into account.
//
params.nodeID = @(17);
params.operationalKeypair = operationalKeys;
params.caseAuthenticatedTags = invalidCATs;
controller = [factory createControllerOnExistingFabric:params error:nil];
XCTAssertNil(controller);
[factory stopControllerFactory];
XCTAssertFalse([factory isRunning]);
}
@end