Skip to content

Commit

Permalink
Merge pull request #25 from niscy-eudiw/SecureArea
Browse files Browse the repository at this point in the history
Refactor key storage and issue request handling
  • Loading branch information
phisakel authored Nov 28, 2024
2 parents 9fe492a + 20deea3 commit 32079a4
Show file tree
Hide file tree
Showing 12 changed files with 259 additions and 170 deletions.
2 changes: 0 additions & 2 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@
"ghcr.io/devcontainers/features/common-utils:2": {
"installZsh": "false",
"username": "vscode",
"userUid": "1000",
"userGid": "1000",
"upgradePackages": "false"
},
"ghcr.io/devcontainers/features/git:1": {
Expand Down
9 changes: 6 additions & 3 deletions .github/workflows/swift.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-swift

name: Swift

on: [push]

on:
pull_request:
types: [opened, reopened]
push:
branches: ['main']
tags: [ v* ]
jobs:
build:

Expand Down
79 changes: 79 additions & 0 deletions .swiftpm/xcode/xcshareddata/xcschemes/WalletStorage.xcscheme
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 = "WalletStorage"
BuildableName = "WalletStorage"
BlueprintName = "WalletStorage"
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 = "WalletStorageTests"
BuildableName = "WalletStorageTests"
BlueprintName = "WalletStorageTests"
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 = "WalletStorage"
BuildableName = "WalletStorage"
BlueprintName = "WalletStorage"
ReferencedContainer = "container:">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
54 changes: 54 additions & 0 deletions .swiftpm/xcode/xcshareddata/xcschemes/WalletStorageTests.xcscheme
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 = "WalletStorageTests"
BuildableName = "WalletStorageTests"
BlueprintName = "WalletStorageTests"
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>
6 changes: 3 additions & 3 deletions Package.resolved
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
{
"originHash" : "5899d8de2075d7a83e61827a33fdb4419671b2313f3f6131cd2e3ed570f58a7d",
"originHash" : "fcb82ddcec78f864b92635b39a134e6c2ebc5f4f04274dc94f535c265aaae092",
"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"
}
},
{
Expand Down
2 changes: 1 addition & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ let package = Package(
],
dependencies: [
.package(url: "https://github.com/apple/swift-log.git", from: "1.5.3"),
.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-data-model.git", exact: "0.4.0"),
],
targets: [
// Targets are the basic building blocks of a package, defining a module or a test suite.
Expand Down
14 changes: 4 additions & 10 deletions Sources/WalletStorage/Document.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,12 @@ import MdocDataModel18013

/// wallet document structure
public struct Document: DocumentProtocol, Sendable {
public init(id: String = UUID().uuidString, docType: String, docDataType: DocDataType, data: Data, privateKeyType: PrivateKeyType?, privateKey: Data?, createdAt: Date?, modifiedAt: Date? = nil, displayName: String?, status: DocumentStatus) {
public init(id: String = UUID().uuidString, docType: String, docDataType: DocDataType, data: Data, secureAreaName: String?, createdAt: Date?, modifiedAt: Date? = nil, displayName: String?, status: DocumentStatus) {
self.id = id
self.docType = docType
self.docDataType = docDataType
self.data = data
self.privateKeyType = privateKeyType
self.privateKey = privateKey
self.secureAreaName = secureAreaName
self.createdAt = createdAt ?? Date()
self.modifiedAt = modifiedAt
self.displayName = displayName
Expand All @@ -36,8 +35,7 @@ public struct Document: DocumentProtocol, Sendable {
public let docType: String
public let data: Data
public let docDataType: DocDataType
public let privateKeyType: PrivateKeyType?
public let privateKey: Data?
public let secureAreaName: String?
public let createdAt: Date
public let modifiedAt: Date?
public let displayName: String?
Expand All @@ -48,12 +46,8 @@ public struct Document: DocumentProtocol, Sendable {
/// get CBOR data and private key from document
public func getCborData() -> (iss: (String, IssuerSigned), dpk: (String, CoseKeyPrivate))? {
switch docDataType {
case .signupResponseJson:
guard let sr = data.decodeJSON(type: SignUpResponse.self), let dr = sr.deviceResponse, let iss = dr.documents?.first?.issuerSigned, let dpk = sr.devicePrivateKey else { return nil }
let randomId = UUID().uuidString
return ((randomId, iss), (randomId, dpk))
case .cbor:
guard let iss = IssuerSigned(data: [UInt8](data)), let privateKeyType, let privateKey, let dpk = try? IssueRequest(id: id, privateKeyType: privateKeyType, keyData: privateKey).toCoseKeyPrivate() else { return nil }
guard let iss = IssuerSigned(data: [UInt8](data)), case let dpk = CoseKeyPrivate(privateKeyId: id, secureArea: SecureAreaRegistry.shared.get(name: secureAreaName)) else { return nil }
return ((id, iss), (id, dpk))
case .sjwt:
fatalError("Format \(docDataType) not implemented")
Expand Down
17 changes: 3 additions & 14 deletions Sources/WalletStorage/Enumerations.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,10 @@ import Foundation
/// type of data to save in storage
/// ``doc``: Document data
/// ``key``: Private-key
public enum SavedKeyChainDataType: String, Sendable {
public enum SavedKeyChainDataType: String, Sendable, CaseIterable {
case doc = "sdoc"
case key = "skey"
case keyInfo = "skei"
}

/// Format of document data
Expand All @@ -32,19 +33,7 @@ public enum SavedKeyChainDataType: String, Sendable {
public enum DocDataType: String, Sendable {
case cbor = "cbor"
case sjwt = "sjwt"
case signupResponseJson = "srjs"
}

/// Format of private key
/// ``derEncodedP256``: DER encoded
/// ``pemStringDataP256`` PEM string encoded as utf8
/// ``x963EncodedP256``: ANSI x9.63 representation (default)
/// ``secureEnclaveP256``: data representation for the secure enclave
public enum PrivateKeyType: String, Sendable {
case derEncodedP256 = "dep2"
case pemStringDataP256 = "pep2"
case x963EncodedP256 = "x9p2"
case secureEnclaveP256 = "sep2"
// case signupResponseJson = "srjs"
}


Expand Down
83 changes: 9 additions & 74 deletions Sources/WalletStorage/IssueRequest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,87 +21,22 @@ import MdocDataModel18013
/// Issue request structure
public struct IssueRequest: Sendable {
public var id: String
public var docType: String?
public var keyData: Data
public var privateKeyType: PrivateKeyType

public var keyOptions: KeyOptions?
public var secureArea: SecureArea
public var secureAreaName: String { type(of: secureArea).name }
/// Initialize issue request with id
///
/// - Parameters:
/// - id: a key identifier (uuid)
public init(id: String = UUID().uuidString, docType: String? = nil, privateKeyType: PrivateKeyType = .secureEnclaveP256, keyData: Data? = nil) throws {
self.id = id
self.docType = docType
self.privateKeyType = privateKeyType
if let keyData {
self.keyData = keyData
// key-data already created, exit
return
}
switch privateKeyType {
case .derEncodedP256:
let p256 = P256.KeyAgreement.PrivateKey()
self.keyData = p256.derRepresentation
case .pemStringDataP256:
let p256 = P256.KeyAgreement.PrivateKey()
self.keyData = p256.pemRepresentation.data(using: .utf8)!
case .x963EncodedP256:
let p256 = P256.KeyAgreement.PrivateKey()
self.keyData = p256.x963Representation
case .secureEnclaveP256:
let secureEnclaveKey = try SecureEnclave.P256.KeyAgreement.PrivateKey()
self.keyData = secureEnclaveKey.dataRepresentation
}
logger.info("Created private key of type \(privateKeyType)")
if let docType { logger.info(" and docType: \(docType)") }
}

public func saveTo(storageService: any DataStorageService, status: DocumentStatus) async throws {
// save key data to storage with id
logger.info("Saving Issue request with id: \(id) and document status: \(status)")
let docKey = Document(id: id, docType: docType ?? "P256", docDataType: .cbor, data: Data(), privateKeyType: privateKeyType, privateKey: keyData, createdAt: Date(), displayName: nil, status: status)
try await storageService.saveDocument(docKey, allowOverwrite: true)
}

public mutating func loadFrom(storageService: any DataStorageService, id: String, status: DocumentStatus) async throws {
guard let doc = try await storageService.loadDocument(id: id, status: status), let pk = doc.privateKey, let pkt = doc.privateKeyType else { return }
public init(id: String = UUID().uuidString, keyOptions: KeyOptions? = nil) throws {
self.id = id
keyData = pk
privateKeyType = pkt
}

public func toCoseKeyPrivate() throws -> CoseKeyPrivate {
switch privateKeyType {
case .derEncodedP256:
let p256 = try P256.KeyAgreement.PrivateKey(derRepresentation: keyData)
return CoseKeyPrivate(privateKeyx963Data: p256.x963Representation, crv: .p256)
case .x963EncodedP256:
let p256 = try P256.KeyAgreement.PrivateKey(x963Representation: keyData)
return CoseKeyPrivate(privateKeyx963Data: p256.x963Representation, crv: .p256)
case .pemStringDataP256:
let p256 = try P256.KeyAgreement.PrivateKey(pemRepresentation: String(data: keyData, encoding: .utf8)!)
return CoseKeyPrivate(privateKeyx963Data: p256.x963Representation, crv: .p256)
case .secureEnclaveP256:
let se256 = try SecureEnclave.P256.KeyAgreement.PrivateKey(dataRepresentation: keyData)
return CoseKeyPrivate(publicKeyx963Data: se256.publicKey.x963Representation, secureEnclaveKeyID: keyData)
}
self.keyOptions = keyOptions
secureArea = SecureAreaRegistry.shared.get(name: keyOptions?.secureAreaName)
}

public func getPublicKeyPEM() throws -> String {
switch privateKeyType {
case .derEncodedP256:
let p256 = try P256.KeyAgreement.PrivateKey(derRepresentation: keyData)
return p256.publicKey.pemRepresentation
case .pemStringDataP256:
let p256 = try P256.KeyAgreement.PrivateKey(pemRepresentation: String(data: keyData, encoding: .utf8)!)
return p256.publicKey.pemRepresentation
case .x963EncodedP256:
let p256 = try P256.KeyAgreement.PrivateKey(x963Representation: keyData)
return p256.publicKey.pemRepresentation
case .secureEnclaveP256:
let se256 = try SecureEnclave.P256.KeyAgreement.PrivateKey(dataRepresentation: keyData)
return se256.publicKey.pemRepresentation
}
public func createKey() async throws -> CoseKey {
let res = try await secureArea.createKey(id: id, keyOptions: keyOptions)
return res
}

}
Expand Down
Loading

0 comments on commit 32079a4

Please sign in to comment.