Skip to content

Commit

Permalink
Merge pull request #43 from niscy-eudiw/SecureArea
Browse files Browse the repository at this point in the history
Refactor to use secure area for signing and key agreement
  • Loading branch information
phisakel authored Nov 28, 2024
2 parents 25a71be + 6504a4f commit b774365
Show file tree
Hide file tree
Showing 9 changed files with 187 additions and 57 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/swift.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
name: Swift
on:
pull_request:
types: [opened, reopened]
types: [opened, reopened, edited]
push:
branches: ['main']
tags: [ v* ]
Expand All @@ -17,7 +17,7 @@ jobs:
steps:
- uses: maxim-lobanov/setup-xcode@v1
with:
xcode-version: '16.0'
xcode-version: '16.1'
- name: Get swift version
run: swift --version
- uses: actions/checkout@v4
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1610"
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES"
buildArchitectures = "Automatic">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "MdocDataTransfer18013"
BuildableName = "MdocDataTransfer18013"
BlueprintName = "MdocDataTransfer18013"
ReferencedContainer = "container:">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
shouldAutocreateTestPlan = "YES">
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "MdocDataTransfer18013Tests"
BuildableName = "MdocDataTransfer18013Tests"
BlueprintName = "MdocDataTransfer18013Tests"
ReferencedContainer = "container:">
</BuildableReference>
</TestableReference>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "MdocDataTransfer18013"
BuildableName = "MdocDataTransfer18013"
BlueprintName = "MdocDataTransfer18013"
ReferencedContainer = "container:">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1610"
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES"
buildArchitectures = "Automatic">
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
shouldAutocreateTestPlan = "YES">
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "MdocDataTransfer18013Tests"
BuildableName = "MdocDataTransfer18013Tests"
BlueprintName = "MdocDataTransfer18013Tests"
ReferencedContainer = "container:">
</BuildableReference>
</TestableReference>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
26 changes: 13 additions & 13 deletions Package.resolved
Original file line number Diff line number Diff line change
@@ -1,40 +1,40 @@
{
"originHash" : "fc60708f41996a66ff09913bb5bc0934ff3d47779d3ec833bf24adbed0bb2ad4",
"originHash" : "aba63bdc14b9431049b57af2080cd340ba4da0baa6a3bfbb3ffb8740ed9dfed2",
"pins" : [
{
"identity" : "eudi-lib-ios-iso18013-data-model",
"kind" : "remoteSourceControl",
"location" : "https://github.com/eu-digital-identity-wallet/eudi-lib-ios-iso18013-data-model.git",
"state" : {
"revision" : "c1b4383d6fc3387a8ed4c79177548624c4e34e3a",
"version" : "0.3.3"
"revision" : "29f30a92427733db0c7b9cea9616607a1df24284",
"version" : "0.4.0"
}
},
{
"identity" : "eudi-lib-ios-iso18013-security",
"kind" : "remoteSourceControl",
"location" : "https://github.com/eu-digital-identity-wallet/eudi-lib-ios-iso18013-security.git",
"state" : {
"revision" : "13d65a1010ee9e6219f8bccbab6eb32f67405d86",
"version" : "0.2.6"
"revision" : "6d335f19cb5bdb590bf2f5557c4d91dda146555b",
"version" : "0.3.0"
}
},
{
"identity" : "swift-asn1",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-asn1.git",
"state" : {
"revision" : "c7e239b5c1492ffc3ebd7fbcc7a92548ce4e78f0",
"version" : "1.1.0"
"revision" : "7faebca1ea4f9aaf0cda1cef7c43aecd2311ddf6",
"version" : "1.3.0"
}
},
{
"identity" : "swift-certificates",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-certificates.git",
"state" : {
"revision" : "4688f242811d21a9c7a8ad669b3bc5b336759929",
"version" : "1.4.0"
"revision" : "1fbb6ef21f1525ed5faf4c95207b9c11bea27e94",
"version" : "1.6.1"
}
},
{
Expand All @@ -51,17 +51,17 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-crypto.git",
"state" : {
"revision" : "46072478ca365fe48370993833cb22de9b41567f",
"version" : "3.5.2"
"revision" : "ff0f781cf7c6a22d52957e50b104f5768b50c779",
"version" : "3.10.0"
}
},
{
"identity" : "swift-log",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-log.git",
"state" : {
"revision" : "9cb486020ebf03bfa5b5df985387a14a98744537",
"version" : "1.6.1"
"revision" : "96a2f8a0fa41e9e09af4585e2724c4e825410b91",
"version" : "1.6.2"
}
},
{
Expand Down
4 changes: 1 addition & 3 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,13 @@ let package = Package(
targets: ["MdocDataTransfer18013"]),
],
dependencies: [
.package(url: "https://github.com/eu-digital-identity-wallet/eudi-lib-ios-iso18013-data-model.git", exact: "0.3.3"),
.package(url: "https://github.com/eu-digital-identity-wallet/eudi-lib-ios-iso18013-security.git", exact: "0.2.6"),
.package(url: "https://github.com/eu-digital-identity-wallet/eudi-lib-ios-iso18013-security.git", exact: "0.3.0"),
],
targets: [
// Targets are the basic building blocks of a package, defining a module or a test suite.
// Targets can depend on other targets in this package and products from dependencies.
.target(
name: "MdocDataTransfer18013", dependencies: [
.product(name: "MdocDataModel18013", package: "eudi-lib-ios-iso18013-data-model"),
.product(name: "MdocSecurity18013", package: "eudi-lib-ios-iso18013-security")]),
.testTarget(
name: "MdocDataTransfer18013Tests",
Expand Down
44 changes: 27 additions & 17 deletions Sources/MdocDataTransfer18013/BLETransfer/MdocGATTServer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ public class MdocGattServer: @unchecked Sendable, ObservableObject {
public weak var delegate: (any MdocOfflineDelegate)?
public var advertising: Bool = false
public var error: Error? = nil { willSet { handleErrorSet(newValue) }}
public var status: TransferStatus = .initializing { willSet { handleStatusChange(newValue) } }
public var status: TransferStatus = .initializing { willSet { Task { @MainActor in await handleStatusChange(newValue) } } }
public var unlockData: [String: Data]!
var readBuffer = Data()
var sendBuffer = [Data]()
var numBlocks: Int = 0
Expand All @@ -60,8 +61,8 @@ public class MdocGattServer: @unchecked Sendable, ObservableObject {
self.iaca = iaca
self.dauthMethod = dauthMethod
status = .initialized
initPeripheralManager()
initSuccess = true
handleStatusChange(status)
}

@objc(CBPeripheralManagerDelegate)
Expand Down Expand Up @@ -135,14 +136,15 @@ public class MdocGattServer: @unchecked Sendable, ObservableObject {
// Create a new device engagement object and start the device engagement process.
///
/// ``qrCodePayload`` is set to QR code data corresponding to the device engagement.
public func performDeviceEngagement(rfus: [String]? = nil) {
guard !isPreview && !isInErrorState else {
public func performDeviceEngagement(secureArea: any SecureArea, crv: CoseEcCurve, rfus: [String]? = nil) async throws {
guard !isPreview && !isInErrorState else {
logger.info("Current status is \(status)")
return
}
// Check that the class is in the right state to start the device engagement process. It will fail if the class is in any other state.
guard status == .initialized || status == .disconnected || status == .responseSent else { error = MdocHelpers.makeError(code: .unexpected_error, str: error?.localizedDescription ?? "Not initialized!"); return }
deviceEngagement = DeviceEngagement(isBleServer: true, crv: .p256, rfus: rfus)
deviceEngagement = DeviceEngagement(isBleServer: true, rfus: rfus)
try await deviceEngagement!.makePrivateKey(crv: crv, secureArea: secureArea)
sessionEncryption = nil
#if os(iOS)
qrCodePayload = deviceEngagement!.getQrCodePayload()
Expand Down Expand Up @@ -199,35 +201,41 @@ public class MdocGattServer: @unchecked Sendable, ObservableObject {
qrCodePayload = nil
advertising = false
subscribeCount = 0
if let pk = deviceEngagement?.privateKey { Task { @MainActor in try? await pk.secureArea.deleteKey(id: pk.privateKeyId); deviceEngagement?.privateKey = nil } }
if status == .error && initSuccess { status = .initializing }
}

func handleStatusChange(_ newValue: TransferStatus) {
fileprivate func initPeripheralManager() {
guard peripheralManager == nil else { return }
bleDelegate = Delegate(server: self)
logger.info("Initializing BLE peripheral manager")
peripheralManager = CBPeripheralManager(delegate: bleDelegate, queue: nil)
subscribeCount = 0
}

func handleStatusChange(_ newValue: TransferStatus) async {
guard !isPreview && !isInErrorState else { return }
logger.log(level: .info, "Transfer status will change to \(newValue)")
delegate?.didChangeStatus(newValue)
if newValue == .requestReceived {
peripheralManager.stopAdvertising()
let decodedRes = MdocHelpers.decodeRequestAndInformUser(deviceEngagement: deviceEngagement, docs: docs, iaca: iaca, requestData: readBuffer, devicePrivateKeys: devicePrivateKeys, dauthMethod: dauthMethod, readerKeyRawData: nil, handOver: BleTransferMode.QRHandover)
let decodedRes = await MdocHelpers.decodeRequestAndInformUser(deviceEngagement: deviceEngagement, docs: docs, iaca: iaca, requestData: readBuffer, devicePrivateKeys: devicePrivateKeys, dauthMethod: dauthMethod, unlockData: unlockData, readerKeyRawData: nil, handOver: BleTransferMode.QRHandover)
switch decodedRes {
case .success(let decoded):
self.deviceRequest = decoded.deviceRequest
sessionEncryption = decoded.sessionEncryption
if decoded.isValidRequest {
delegate?.didReceiveRequest(decoded.userRequestInfo, handleSelected: userSelected)
} else {
userSelected(false, nil)
await userSelected(false, nil)
}
case .failure(let err):
error = err
return
}
}
else if newValue == .initialized {
bleDelegate = Delegate(server: self)
logger.info("Initializing BLE peripheral manager")
peripheralManager = CBPeripheralManager(delegate: bleDelegate, queue: nil)
subscribeCount = 0
initPeripheralManager()
} else if newValue == .disconnected && status != .disconnected {
stop()
}
Expand All @@ -239,9 +247,9 @@ public class MdocGattServer: @unchecked Sendable, ObservableObject {

var isInErrorState: Bool { status == .error }

public func userSelected(_ b: Bool, _ items: RequestItems?) {
public func userSelected(_ b: Bool, _ items: RequestItems?) async {
status = .userSelected
let resError = MdocHelpers.getSessionDataToSend(sessionEncryption: sessionEncryption, status: .error, docToSend: DeviceResponse(status: 0))
let resError = await MdocHelpers.getSessionDataToSend(sessionEncryption: sessionEncryption, status: .error, docToSend: DeviceResponse(status: 0))
var bytesToSend = try! resError.get()
var errorToSend: Error?
defer {
Expand All @@ -255,9 +263,11 @@ public class MdocGattServer: @unchecked Sendable, ObservableObject {
if let items {
do {
let docTypeReq = deviceRequest?.docRequests.first?.itemsRequest.docType ?? ""
guard let (drToSend, _, _) = try MdocHelpers.getDeviceResponseToSend(deviceRequest: deviceRequest!, issuerSigned: docs, selectedItems: items, sessionEncryption: sessionEncryption, eReaderKey: sessionEncryption!.sessionKeys.publicKey, devicePrivateKeys: devicePrivateKeys, dauthMethod: dauthMethod) else { errorToSend = MdocHelpers.getErrorNoDocuments(docTypeReq); return }
guard let (drToSend, _, _) = try await MdocHelpers.getDeviceResponseToSend(deviceRequest: deviceRequest!, issuerSigned: docs, selectedItems: items, sessionEncryption: sessionEncryption, eReaderKey: sessionEncryption!.sessionKeys.publicKey, devicePrivateKeys: devicePrivateKeys, dauthMethod: dauthMethod, unlockData: unlockData) else {
errorToSend = MdocHelpers.getErrorNoDocuments(docTypeReq); return
}
guard let dts = drToSend.documents, !dts.isEmpty else { errorToSend = MdocHelpers.getErrorNoDocuments(docTypeReq); return }
let dataRes = MdocHelpers.getSessionDataToSend(sessionEncryption: sessionEncryption, status: .requestReceived, docToSend: drToSend)
let dataRes = await MdocHelpers.getSessionDataToSend(sessionEncryption: sessionEncryption, status: .requestReceived, docToSend: drToSend)
switch dataRes {
case .success(let bytes):
bytesToSend = bytes
Expand All @@ -267,7 +277,7 @@ public class MdocGattServer: @unchecked Sendable, ObservableObject {
}
}
catch { errorToSend = error }
if let errorToSend { logger.error("Error preparing response: \(errorToSend.localizedDescription)") }
if let errorToSend { logger.error("Error sending data: \(errorToSend)")}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import MdocSecurity18013
public protocol MdocOfflineDelegate: AnyObject {
func didChangeStatus(_ newStatus: TransferStatus)
func didFinishedWithError(_ error: Error)
func didReceiveRequest(_ request: UserRequestInfo, handleSelected: @escaping (Bool, RequestItems?) -> Void)
func didReceiveRequest(_ request: UserRequestInfo, handleSelected: @escaping (Bool, RequestItems?) async -> Void)
}


2 changes: 0 additions & 2 deletions Sources/MdocDataTransfer18013/Enumerations.swift
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,8 @@ public enum ErrorCode: Int, CustomStringConvertible, Sendable {

/// String keys for the initialization dictionary
public enum InitializeKeys: String, Sendable {
case document_json_data
case document_signup_issuer_signed_data
case document_signup_issuer_signed_obj
case device_private_key_data
case device_private_key_obj
case trusted_certificates
case device_auth_method
Expand Down
Loading

0 comments on commit b774365

Please sign in to comment.