Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions WireCoreCrypto/Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,15 @@ let package = Package(
targets: [
.binaryTarget(
name: "WireCoreCrypto",
url: "https://github.com/wireapp/core-crypto/releases/download/v8.0.0/WireCoreCrypto.xcframework.zip",
checksum: "d372f1eda32f5fc4bfa0ac0ee51468fb06336072e50d6d0b254fce90853080e7"
url: "https://github.com/wireapp/core-crypto/releases/download/v9.2.1/WireCoreCrypto.xcframework.zip",
checksum: "a87a1b88626174918d107af911d54518d313ec182ca4d314b4a5271dacc46139"
),
// this is an internal dependency to WireCoreCrypto but currently needs to explictly
// added as a dependency due to limitations of Swift packages.
.binaryTarget(
name: "WireCoreCryptoUniffi",
url: "https://github.com/wireapp/core-crypto/releases/download/v8.0.0/WireCoreCryptoUniffi.xcframework.zip",
checksum: "21ccdb11ec709eec593f5fb9dd3b77df01195e81560740e7ecbc6a2d189be3a6"
url: "https://github.com/wireapp/core-crypto/releases/download/v9.2.1/WireCoreCryptoUniffi.xcframework.zip",
checksum: "db991bfd31595bc02efa7521561ec7c6c581ca072db2b71a820ff7b7a8fd0a6d"
)
]
)
Original file line number Diff line number Diff line change
Expand Up @@ -72,15 +72,23 @@ public class CoreCryptoKeyMigrationManager: CoreCryptoKeyMigrationManagerProtoco
attributes: .safePublic
)

try await migrateDatabaseKeyTypeToBytes(path: path, oldKey: oldKey, newKey: newKey)
try await migrateDatabaseKeyTypeToBytes(
path: path,
oldKey: oldKey,
newKey: DatabaseKey(key: newKey)
)
journal[.isCoreCryptoKeyMigrationToBytesRequired] = false

WireLogger.coreCrypto.info("Core crypto key is migrated to bytes successfully", attributes: .safePublic)
}

public func updateKey(path: String, oldKey: Data, newKey: Data) async throws {
do {
try await updateDatabaseKey(name: path, oldKey: oldKey, newKey: newKey)
try await updateDatabaseKey(
name: path,
oldKey: DatabaseKey(key: oldKey),
newKey: DatabaseKey(key: newKey)
)
} catch {
throw CoreCryptoKeyMigrationManagerError.failedToUpdateKey(underlyingError: error)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -321,7 +321,7 @@ public struct IncrementalSyncV2: LiveSyncProtocol {
var storedEnvelopes: [(UpdateEventEnvelope, Int64)] = []

// decrypt
try await coreCryptoProvider.coreCrypto().perform { coreCryptoContext in
try await coreCryptoProvider.coreCrypto().transaction { coreCryptoContext in
for envelope in envelopes {

if DeveloperFlag.ignoreIncomingEvents.isOn {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ public struct PullPendingUpdateEventsSync: PullPendingUpdateEventsSyncProtocol {
var lastEnvelopeID: UUID?

// We are decrypting the batch within one core crypto transaction
try await coreCryptoProvider.coreCrypto().perform { context in
try await coreCryptoProvider.coreCrypto().transaction { context in
WireLogger.sync.debug(
"decrypting batch of \(envelopes.count) envelopes",
attributes: .safePublic
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ public struct PullPendingUpdateEventsSyncV2: PullPendingUpdateEventsSyncV2Protoc
var storedEnvelopes: [(UpdateEventEnvelope, Int64)] = []

// decrypt
try await coreCryptoProvider.coreCrypto().perform { coreCryptoContext in
try await coreCryptoProvider.coreCrypto().transaction { coreCryptoContext in
for envelope in envelopes {
var envelope = envelope
envelope.events = await decryptEnvelope(envelope, in: coreCryptoContext)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ final class IncrementalSyncV2Tests: XCTestCase {
var syncStateSubject: CurrentValueSubject<SyncState, Never>!
var liveBrokenGroupSubject: PassthroughSubject<Set<String>, Never>!
var liveDelegate: MockLiveSyncDelegate!
var coreCrypto: MockSafeCoreCrypto!
var coreCryptoContext: MockCoreCryptoContextProtocol!
var coreCrypto: MockCoreCryptoProtocol!
var coreCryptoProvider: MockCoreCryptoProviderProtocol!
var pushChannelState: MockPushChannelStateProtocol!
var mlsGroupRepairAgent: MockMLSGroupRepairAgentProtocol!
Expand All @@ -55,7 +56,9 @@ final class IncrementalSyncV2Tests: XCTestCase {
databaseSaver = MockDatabaseSaverProtocol()
liveDelegate = MockLiveSyncDelegate()
syncStateSubject = .init(.idle)
coreCrypto = MockSafeCoreCrypto()
coreCryptoContext = MockCoreCryptoContextProtocol()
coreCrypto = MockCoreCryptoProtocol()
coreCrypto.mockTransaction(context: coreCryptoContext)
coreCryptoProvider = MockCoreCryptoProviderProtocol()
coreCryptoProvider.coreCrypto_MockValue = coreCrypto
journal = Journal(
Expand Down Expand Up @@ -115,6 +118,7 @@ final class IncrementalSyncV2Tests: XCTestCase {
coreCrypto = nil
coreCryptoProvider = nil
cancellables = nil
coreCryptoContext = nil
}

func testPerform_pendingEventsExist() async throws {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,7 @@ final class PullPendingUpdateEventsSyncTests: XCTestCase {
private var api: MockUpdateEventsAPI!
private var store: MockUpdateEventsLocalStoreProtocol!
private var decryptor: MockUpdateEventDecryptorProtocol!
private var coreCrypto: MockSafeCoreCrypto!
private var coreCryptoProvider: MockCoreCryptoProviderProtocol!
private var envelope: CoreCryptoMocksEnvelope!

override func setUp() async throws {
journal = Journal(
Expand All @@ -41,21 +40,20 @@ final class PullPendingUpdateEventsSyncTests: XCTestCase {
api = MockUpdateEventsAPI()
store = MockUpdateEventsLocalStoreProtocol()
decryptor = MockUpdateEventDecryptorProtocol()
coreCrypto = MockSafeCoreCrypto()
coreCryptoProvider = MockCoreCryptoProviderProtocol()
coreCryptoProvider.coreCrypto_MockValue = coreCrypto
envelope = CoreCryptoMocksEnvelope()

sut = PullPendingUpdateEventsSync(
selfClientID: Scaffolding.selfClientID,
api: api,
store: store,
journal: journal,
decryptor: decryptor,
coreCryptoProvider: coreCryptoProvider
coreCryptoProvider: envelope.coreCryptoProvider
)
}

override func tearDown() async throws {
envelope = nil
api = nil
store = nil
decryptor = nil
Expand Down Expand Up @@ -143,20 +141,22 @@ final class PullPendingUpdateEventsSyncTests: XCTestCase {
store.storeLastEventIDId_MockMethod = { _ in }
store.storeServerTimeDelta_MockMethod = { _ in }

coreCrypto.completeTransactionByDefault = false
envelope.setCompleteTransactionByDefault(false)

// When
let pullingEventsTask = Task { [sut] in
try await sut.pull()
}

// we wait until the sync tries to commit the batch of decrypted events
try await coreCrypto.waitUntilTransactionIsPending()
try await envelope.waitUntilTransactionIsPending()

// Then
try XCTAssertCount(store.storeLastEventIDId_Invocations, count: 0)

coreCrypto.completeAllTransactions()
// complete all transaction
envelope.completeAllTransactions()

_ = await pullingEventsTask.result

// after allowing the transaction to complete we should we see
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,9 @@ class PullPendingUpdateEventsSyncV2Tests: XCTestCase {
var processor: MockUpdateEventProcessorProtocol!
var databaseSaver: MockDatabaseSaverProtocol!
var journal: Journal!
var coreCryptoContext: MockCoreCryptoContextProtocol!
var coreCryptoProvider: MockCoreCryptoProviderProtocol!
var coreCrypto: MockSafeCoreCrypto!
var coreCrypto: MockCoreCryptoProtocol!

override func setUp() {
pushChannelAPI = MockPushChannelV2API()
Expand All @@ -46,7 +47,9 @@ class PullPendingUpdateEventsSyncV2Tests: XCTestCase {
messageLocalStore = MockMessageLocalStoreProtocol()
processor = MockUpdateEventProcessorProtocol()
coreCryptoProvider = MockCoreCryptoProviderProtocol()
coreCrypto = MockSafeCoreCrypto()
coreCryptoContext = MockCoreCryptoContextProtocol()
coreCrypto = MockCoreCryptoProtocol()
coreCrypto.mockTransaction(context: coreCryptoContext)

journal = Journal(
userID: UUID(),
Expand Down Expand Up @@ -82,6 +85,7 @@ class PullPendingUpdateEventsSyncV2Tests: XCTestCase {
databaseSaver = nil
coreCryptoProvider = nil
coreCrypto = nil
coreCryptoContext = nil
journal = nil
}

Expand Down
61 changes: 25 additions & 36 deletions wire-ios-data-model/Source/Core Crypto/CoreCryptoProvider.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public protocol CoreCryptoProviderProtocol {
/// Retrieve the shared core crypto instance or create one if one does not yet exist.
///
/// This function is safe to be called concurrently from multiple Tasks
func coreCrypto() async throws -> SafeCoreCryptoProtocol
func coreCrypto() async throws -> CoreCryptoProtocol

/// Initialise a new MLS client with basic credentials
///
Expand Down Expand Up @@ -66,13 +66,11 @@ public actor CoreCryptoProvider: CoreCryptoProviderProtocol {
private let featureRespository: LegacyFeatureRepositoryInterface
private let syncContext: NSManagedObjectContext
private let allowCreation: Bool
private var coreCrypto: SafeCoreCrypto?
private var coreCrypto: CoreCrypto?
private var loadingCoreCrypto = false
private var initialisatingMLS = false
private var hasInitialisedMLS = false
private var hasRegisteredMlsTransport = false
private var hasRegisteredEpochObserver = false
private var coreCryptoContinuations: [CheckedContinuation<SafeCoreCrypto, Error>] = []
private var coreCryptoContinuations: [CheckedContinuation<CoreCrypto, Error>] = []
private nonisolated(unsafe) var mlsTransport: MlsTransport?
private var epochObserver: WireCoreCryptoUniffi.EpochObserver?
private let localDomain: String?
Expand All @@ -98,7 +96,7 @@ public actor CoreCryptoProvider: CoreCryptoProviderProtocol {
self.localDomain = localDomain
}

public func coreCrypto() async throws -> SafeCoreCryptoProtocol {
public func coreCrypto() async throws -> CoreCryptoProtocol {
let coreCrypto = try await getCoreCrypto()
try await registerMlsTransportIfNecessary(with: coreCrypto)
return coreCrypto
Expand All @@ -108,7 +106,7 @@ public actor CoreCryptoProvider: CoreCryptoProviderProtocol {
WireLogger.mls.info("Initialising MLS client with basic credentials")
let defaultCiphersuite = await featureRespository.fetchMLS().config.defaultCipherSuite.coreCryptoCipherSuite
let coreCrypto = try await coreCrypto()
_ = try await coreCrypto.perform { context in
_ = try await coreCrypto.transaction { context in
try await context.mlsInit(
clientId: .init(bytes: mlsClientID.data),
ciphersuites: [defaultCiphersuite],
Expand All @@ -124,7 +122,7 @@ public actor CoreCryptoProvider: CoreCryptoProviderProtocol {
) async throws -> CRLsDistributionPoints? {
WireLogger.mls.info("Initialising MLS client from end-to-end identity enrollment")
let coreCrypto = try await coreCrypto()
return try await coreCrypto.perform { context in
return try await coreCrypto.transaction { context in
let crlsDistributionPoints = try await context.e2eiMlsInitOnly(
enrollment: enrollment,
certificateChain: certificateChain,
Expand All @@ -145,32 +143,24 @@ public actor CoreCryptoProvider: CoreCryptoProviderProtocol {
}
}

private func registerEpochObserverIfNecessary(with coreCrypto: SafeCoreCryptoProtocol) async throws {
private func registerEpochObserverIfNecessary(with coreCrypto: CoreCryptoProtocol) async throws {
guard let epochObserver, !hasRegisteredEpochObserver else {
return
}
try await coreCrypto.configure { configure in
try await configure.registerEpochObserver(epochObserver)
}
try await coreCrypto.registerEpochObserver(epochObserver)
hasRegisteredEpochObserver = true
}

public nonisolated func registerMlsTransport(_ transport: any MlsTransport) {
mlsTransport = transport
}

private func reset() {
coreCrypto = nil
}

private func registerMlsTransportIfNecessary(with coreCrypto: SafeCoreCrypto) async throws {
private func registerMlsTransportIfNecessary(with coreCrypto: CoreCryptoProtocol) async throws {
guard let mlsTransport, !hasRegisteredMlsTransport else {
return
}

try await coreCrypto.configure { coreCrypto in
try await coreCrypto.provideTransport(transport: mlsTransport)
}
try await coreCrypto.provideTransport(transport: mlsTransport)
hasRegisteredMlsTransport = true
}

Expand All @@ -179,7 +169,7 @@ public actor CoreCryptoProvider: CoreCryptoProviderProtocol {
//
// Based on the structured caching in an actor:
// https://forums.swift.org/t/structured-caching-in-an-actor/65501/13
private func getCoreCrypto() async throws -> SafeCoreCrypto {
private func getCoreCrypto() async throws -> CoreCrypto {
guard !loadingCoreCrypto else {
WireLogger.coreCrypto.debug(
"already loading CoreCrypto, waiting for continuation",
Expand All @@ -194,7 +184,7 @@ public actor CoreCryptoProvider: CoreCryptoProviderProtocol {
return coreCrypto
} else {
loadingCoreCrypto = true
let cc: SafeCoreCrypto
let cc: CoreCrypto
do {
cc = try await createCoreCrypto()
} catch {
Expand All @@ -210,7 +200,7 @@ public actor CoreCryptoProvider: CoreCryptoProviderProtocol {
}
}

private func resumeCoreCryptoContinuations(with result: Result<SafeCoreCrypto, Error>) {
private func resumeCoreCryptoContinuations(with result: Result<CoreCrypto, Error>) {
for continuation in coreCryptoContinuations {
WireLogger.coreCrypto.debug(
"resuming continuations",
Expand All @@ -221,7 +211,7 @@ public actor CoreCryptoProvider: CoreCryptoProviderProtocol {
coreCryptoContinuations = []
}

func createCoreCrypto() async throws -> SafeCoreCrypto {
func createCoreCrypto() async throws -> CoreCrypto {
let coreCryptoKeyProvider = CoreCryptoKeyProvider(
coreCryptoKeyMigrationManager: coreCryptoKeyMigrationManager,
userID: selfUserID,
Expand All @@ -245,9 +235,9 @@ public actor CoreCryptoProvider: CoreCryptoProviderProtocol {
attributes: .safePublic
)

let coreCrypto = try await SafeCoreCrypto(
path: configuration.path,
key: configuration.key
let coreCrypto = try await CoreCrypto(
keystorePath: configuration.path,
key: DatabaseKey(key: configuration.key)
)

updateKeychainItemAccess()
Expand All @@ -258,16 +248,13 @@ public actor CoreCryptoProvider: CoreCryptoProviderProtocol {
return coreCrypto
}

private func configureProteusClient(coreCrypto: SafeCoreCrypto) async throws {
// here we don't need to lock the context or restoreFromDisk()
// it fixes `Mls(WireCoreCrypto.MlsError.Other("Proteus client hasn\'t been initialized"))`
// Empty transaction was committed, this could be an indication of a programming error - [core_crypto_context:
// {}]
private func configureProteusClient(coreCrypto: CoreCrypto) async throws {
WireLogger.coreCrypto.debug(
"configuring proteus client",
attributes: .safePublic
)
try await coreCrypto.unsafePerform {

try await coreCrypto.transaction {
WireLogger.coreCrypto.debug(
"proteus init",
attributes: .safePublic
Expand All @@ -276,7 +263,7 @@ public actor CoreCryptoProvider: CoreCryptoProviderProtocol {
}
}

private func configureMLSClient(coreCrypto: SafeCoreCrypto) async throws {
private func configureMLSClient(coreCrypto: CoreCrypto) async throws {
WireLogger.coreCrypto.debug(
"configuring mls client",
attributes: .safePublic
Expand Down Expand Up @@ -305,15 +292,17 @@ public actor CoreCryptoProvider: CoreCryptoProviderProtocol {
attributes: .safePublic
)
let cipherSuite = await featureRespository.fetchMLS().config.defaultCipherSuite.coreCryptoCipherSuite

WireLogger.coreCrypto.debug(
"core crypto perform...",
"core crypto transaction...",
attributes: .safePublic
)
try await coreCrypto.perform {
try await coreCrypto.transaction {
WireLogger.coreCrypto.debug(
"mls init",
attributes: .safePublic
)

try await $0.mlsInit(
clientId: .init(bytes: mlsClientID.data),
ciphersuites: [cipherSuite],
Expand Down
Loading
Loading