OctagonTests+CoreFollowUp.swift [plain text]
#if OCTAGON
class OctagonCoreFollowUpTests: OctagonTestsBase {
func testAttemptedJoinStateAttempted() throws {
self.startCKAccountStatusMock()
// Prepare an identity, then pretend like securityd thought it was in the right account
let containerName = OTCKContainerName
let contextName = OTDefaultContext
var selfPeerID: String?
let prepareExpectation = self.expectation(description: "prepare callback occurs")
tphClient.prepare(withContainer: containerName,
context: contextName,
epoch: 0,
machineID: "asdf",
bottleSalt: "123456789",
bottleID: UUID().uuidString,
modelID: "asdf",
deviceName: "asdf",
serialNumber: "1234",
osVersion: "asdf",
policyVersion: nil,
policySecrets: nil,
signingPrivKeyPersistentRef: nil,
encPrivKeyPersistentRef: nil) { peerID, permanentInfo, permanentInfoSig, stableInfo, stableInfoSig, error in
XCTAssertNil(error, "Should be no error preparing identity")
XCTAssertNotNil(peerID, "Should be a peer ID")
XCTAssertNotNil(permanentInfo, "Should have a permenent info")
XCTAssertNotNil(permanentInfoSig, "Should have a permanent info signature")
XCTAssertNotNil(stableInfo, "Should have a stable info")
XCTAssertNotNil(stableInfoSig, "Should have a stable info signature")
selfPeerID = peerID
prepareExpectation.fulfill()
}
self.wait(for: [prepareExpectation], timeout: 10)
let account = OTAccountMetadataClassC()!
account.peerID = selfPeerID
account.icloudAccountState = .ACCOUNT_AVAILABLE
account.trustState = .TRUSTED
account.attemptedJoin = .ATTEMPTED
XCTAssertNoThrow(try account.saveToKeychain(forContainer: containerName, contextID: contextName), "Should be no error saving fake account metadata")
OctagonInitialize()
self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC)
self.assertConsidersSelfUntrusted(context: self.cuttlefishContext)
// CKKS should be waiting for assistance
assertAllCKKSViews(enter: SecCKKSZoneKeyStateWaitForTLKCreation, within: 10 * NSEC_PER_SEC)
#if !os(tvOS)
XCTAssertTrue(self.cuttlefishContext.postedRepairCFU, "should have posted an repair CFU");
#else
// Apple TV should not post a CFU, as there's no peers to join
XCTAssertFalse(self.cuttlefishContext.postedRepairCFU, "appleTV should not have posted a repair CFU");
#endif
}
func testAttemptedJoinNotAttemptedStateSOSEnabled() throws {
self.startCKAccountStatusMock()
// Prepare an identity, then pretend like securityd thought it was in the right account
let containerName = OTCKContainerName
let contextName = OTDefaultContext
var selfPeerID: String?
let prepareExpectation = self.expectation(description: "prepare callback occurs")
tphClient.prepare(withContainer: containerName,
context: contextName,
epoch: 0,
machineID: "asdf",
bottleSalt: "123456789",
bottleID: UUID().uuidString,
modelID: "asdf",
deviceName: "asdf",
serialNumber: "1234",
osVersion: "asdf",
policyVersion: nil,
policySecrets: nil,
signingPrivKeyPersistentRef: nil,
encPrivKeyPersistentRef: nil) { peerID, permanentInfo, permanentInfoSig, stableInfo, stableInfoSig, error in
XCTAssertNil(error, "Should be no error preparing identity")
XCTAssertNotNil(peerID, "Should be a peer ID")
XCTAssertNotNil(permanentInfo, "Should have a permenent info")
XCTAssertNotNil(permanentInfoSig, "Should have a permanent info signature")
XCTAssertNotNil(stableInfo, "Should have a stable info")
XCTAssertNotNil(stableInfoSig, "Should have a stable info signature")
selfPeerID = peerID
prepareExpectation.fulfill()
}
self.wait(for: [prepareExpectation], timeout: 10)
let account = OTAccountMetadataClassC()!
account.peerID = selfPeerID
account.icloudAccountState = .ACCOUNT_AVAILABLE
account.trustState = .TRUSTED
account.attemptedJoin = .NOTATTEMPTED
XCTAssertNoThrow(try account.saveToKeychain(forContainer: containerName, contextID: contextName), "Should be no error saving fake account metadata")
OctagonInitialize()
self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC)
self.assertConsidersSelfUntrusted(context: self.cuttlefishContext)
// CKKS should be waiting for assistance
assertAllCKKSViews(enter: SecCKKSZoneKeyStateWaitForTLKCreation, within: 10 * NSEC_PER_SEC)
XCTAssertFalse(self.cuttlefishContext.postedRepairCFU, "should NOT have posted an repair CFU");
}
func testAttemptedJoinNotAttemptedStateSOSDisabled() throws {
self.startCKAccountStatusMock()
// Octagon only examines the JoinState if SOS is enabled
self.mockSOSAdapter.sosEnabled = false
// No need to mock not joining; Octagon won't have attempted a join if we just start it
self.cuttlefishContext.startOctagonStateMachine()
self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC)
self.assertConsidersSelfUntrusted(context: self.cuttlefishContext)
// CKKS should be waiting for assistance
assertAllCKKSViews(enter: SecCKKSZoneKeyStateWaitForTLKCreation, within: 10 * NSEC_PER_SEC)
#if !os(tvOS)
XCTAssertTrue(self.cuttlefishContext.postedRepairCFU, "should have posted an repair CFU, as SOS is disabled");
#else
// Apple TV should not post a CFU, as there's no peers to join
XCTAssertFalse(self.cuttlefishContext.postedRepairCFU, "appleTV should not have posted a repair CFU");
#endif
}
func testAttemptedJoinStateUnknown() throws {
self.startCKAccountStatusMock()
// Prepare an identity, then pretend like securityd thought it was in the right account
let containerName = OTCKContainerName
let contextName = OTDefaultContext
var selfPeerID: String?
let prepareExpectation = self.expectation(description: "prepare callback occurs")
tphClient.prepare(withContainer: containerName,
context: contextName,
epoch: 0,
machineID: "asdf",
bottleSalt: "123456789",
bottleID: UUID().uuidString,
modelID: "asdf",
deviceName: "asdf",
serialNumber: "1234",
osVersion: "asdf",
policyVersion: nil,
policySecrets: nil,
signingPrivKeyPersistentRef: nil,
encPrivKeyPersistentRef: nil) { peerID, permanentInfo, permanentInfoSig, stableInfo, stableInfoSig, error in
XCTAssertNil(error, "Should be no error preparing identity")
XCTAssertNotNil(peerID, "Should be a peer ID")
XCTAssertNotNil(permanentInfo, "Should have a permenent info")
XCTAssertNotNil(permanentInfoSig, "Should have a permanent info signature")
XCTAssertNotNil(stableInfo, "Should have a stable info")
XCTAssertNotNil(stableInfoSig, "Should have a stable info signature")
selfPeerID = peerID
prepareExpectation.fulfill()
}
self.wait(for: [prepareExpectation], timeout: 10)
let account = OTAccountMetadataClassC()!
account.peerID = selfPeerID
account.icloudAccountState = .ACCOUNT_AVAILABLE
account.trustState = .TRUSTED
account.attemptedJoin = .UNKNOWN
XCTAssertNoThrow(try account.saveToKeychain(forContainer: containerName, contextID: contextName), "Should be no error saving fake account metadata")
OctagonInitialize()
self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC)
self.assertConsidersSelfUntrusted(context: self.cuttlefishContext)
// CKKS should be waiting for assistance
assertAllCKKSViews(enter: SecCKKSZoneKeyStateWaitForTLKCreation, within: 10 * NSEC_PER_SEC)
#if !os(tvOS)
XCTAssertTrue(self.cuttlefishContext.postedRepairCFU, "should have posted an repair CFU");
#else
// Apple TV should not post a CFU, as there's no peers to join
XCTAssertFalse(self.cuttlefishContext.postedRepairCFU, "appleTV should not have posted a repair CFU");
#endif
}
#if os(tvOS)
func testPostCFUWhenApprovalCapablePeerJoins() throws {
self.startCKAccountStatusMock()
// Octagon only examines the JoinState if SOS is enabled
self.mockSOSAdapter.sosEnabled = false
self.cuttlefishContext.startOctagonStateMachine()
self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC)
self.assertConsidersSelfUntrusted(context: self.cuttlefishContext)
self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateWaitForTLKCreation, within: 10 * NSEC_PER_SEC)
// Apple TV should not post a CFU, as there's no peers to join
XCTAssertFalse(self.cuttlefishContext.postedRepairCFU, "appleTV should not have posted a repair CFU");
// Now, an iphone appears!
let iphone = self.manager.context(forContainerName: OTCKContainerName,
contextID: "asdf",
sosAdapter: self.mockSOSAdapter,
authKitAdapter: self.mockAuthKit2,
lockStateTracker: self.lockStateTracker,
accountStateTracker: self.accountStateTracker,
deviceInformationAdapter: OTMockDeviceInfoAdapter(modelID: "iPhone9,1", deviceName: "test-iphone", serialNumber: "456", osVersion: "iOS (fake version)"))
iphone.startOctagonStateMachine()
let resetAndEstablishExpectation = self.expectation(description: "resetAndEstablishExpectation returns")
iphone.rpcResetAndEstablish() { resetError in
XCTAssertNil(resetError, "should be no error resetting and establishing")
resetAndEstablishExpectation.fulfill()
}
self.wait(for: [resetAndEstablishExpectation], timeout: 10)
self.sendContainerChangeWaitForUntrustedFetch(context: self.cuttlefishContext)
// The TV should now post a CFU, as there's an iphone that can repair it
self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC)
XCTAssertTrue(self.cuttlefishContext.postedRepairCFU, "appleTV should have posted a repair CFU");
}
func testDontPostCFUWhenApprovalIncapablePeerJoins() throws {
self.startCKAccountStatusMock()
// Octagon only examines the JoinState if SOS is enabled
self.mockSOSAdapter.sosEnabled = false
self.cuttlefishContext.startOctagonStateMachine()
self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC)
self.assertConsidersSelfUntrusted(context: self.cuttlefishContext)
self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateWaitForTLKCreation, within: 10 * NSEC_PER_SEC)
// Apple TV should not post a CFU, as there's no peers to join
XCTAssertFalse(self.cuttlefishContext.postedRepairCFU, "appleTV should not have posted a repair CFU");
// Now, a mac appears! macs cannot fix apple TVs.
let mac = self.manager.context(forContainerName: OTCKContainerName,
contextID: "asdf",
sosAdapter: self.mockSOSAdapter,
authKitAdapter: self.mockAuthKit2,
lockStateTracker: self.lockStateTracker,
accountStateTracker: self.accountStateTracker,
deviceInformationAdapter: OTMockDeviceInfoAdapter(modelID: "iMac7,1", deviceName: "test-mac", serialNumber: "456", osVersion: "macOS (fake version)"))
mac.startOctagonStateMachine()
let resetAndEstablishExpectation = self.expectation(description: "resetAndEstablishExpectation returns")
mac.rpcResetAndEstablish() { resetError in
XCTAssertNil(resetError, "should be no error resetting and establishing")
resetAndEstablishExpectation.fulfill()
}
self.wait(for: [resetAndEstablishExpectation], timeout: 10)
self.sendContainerChangeWaitForUntrustedFetch(context: self.cuttlefishContext)
// The TV should not post a CFU, as there's still no iPhone to repair it
self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC)
XCTAssertFalse(self.cuttlefishContext.postedRepairCFU, "appleTV should not have posted a repair CFU; no devices present can repair it");
}
#endif
}
#endif // OCTAGON