Skip to content

Commit

Permalink
Merge pull request #6 from eu-digital-identity-wallet/develop
Browse files Browse the repository at this point in the history
Develop
  • Loading branch information
psima authored Sep 28, 2023
2 parents 079bc6c + ac46a0c commit f3575b3
Show file tree
Hide file tree
Showing 22 changed files with 382 additions and 178 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
//
// ConnectionMethodHttp.swift
// ScytalesDigitalWallet

import Foundation
import SwiftCBOR

public struct ConnectionMethodHttp {
public let uriWebsite: String

public static let METHOD_TYPE: UInt64 = 4
static let METHOD_MAX_VERSION: UInt64 = 1
static let OPTION_KEY_URI_WEBSITE: UInt64 = 0

// Creates a new connection method for REST API. @param uriWebsite the URL for the website.
init(_ uriWebsite: String) {
self.uriWebsite = uriWebsite
}
}

extension ConnectionMethodHttp: CBORDecodable {
public init?(cbor: CBOR) {
guard case let .array(arr) = cbor, arr.count == 3 else { return nil }
guard case let .unsignedInt(type) = arr[0], case let .unsignedInt(version) = arr[1] else { return nil } // throw AppError.cbor("First two items are not numbers") }
guard case let .map(options) = arr[2] else { return nil } // throw AppError.cbor("Third item is not a map") }
guard type == Self.METHOD_TYPE else { return nil } // throw AppError.cbor("Unexpected method type \(type)") }
guard version <= Self.METHOD_MAX_VERSION else { return nil } //throw AppError.cbor("Unsupported options version \(version)") }
guard case let .utf8String(url) = options[.unsignedInt(Self.OPTION_KEY_URI_WEBSITE)] else { return nil } // throw AppError.cbor("Options does not contain uri of website") }
self.init(url)
}
}

extension ConnectionMethodHttp: CBOREncodable {
public func toCBOR(options: CBOROptions) -> CBOR {
.array([.unsignedInt(Self.METHOD_TYPE), .unsignedInt(Self.METHOD_MAX_VERSION), .map([.unsignedInt(Self.OPTION_KEY_URI_WEBSITE): .utf8String(uriWebsite)])])
}
}

7 changes: 7 additions & 0 deletions Sources/MdocDataModel18013/DeviceEngagement/CoseKey.swift
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ public struct CoseKeyPrivate {
}

extension CoseKeyPrivate {
// make new key
public init(crv: ECCurveType) {
var privateKeyx963Data: Data
switch crv {
Expand All @@ -71,6 +72,12 @@ extension CoseKeyPrivate {
key = CoseKey(crv: crv, x: xdata.bytes, y: ydata.bytes)
d = ddata.bytes
}

// decode cbor string
public init?(base64: String) {
guard let d = Data(base64Encoded: base64), let obj = try? CBOR.decode([UInt8](d)), let coseKey = CoseKey(cbor: obj), let cd = obj[-4], case let CBOR.byteString(rd) = cd else { return nil }
self.init(key: coseKey, d: rd)
}
}

extension CoseKey: CBOREncodable {
Expand Down
87 changes: 45 additions & 42 deletions Sources/MdocDataModel18013/DeviceEngagement/DeviceEngagement.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,40 +32,41 @@ import SwiftCBOR
/// let de = DeviceEngagement(data: bytes)
/// ```
public struct DeviceEngagement {
static let versionImpl: String = "1.0"
var version: String = Self.versionImpl
let security: Security
var deviceRetrievalMethods: [DeviceRetrievalMethod]? = nil
var serverRetrievalOptions: ServerRetrievalOptions? = nil
static let versionImpl: String = "1.0"
var version: String = Self.versionImpl
let security: Security
public var originInfos: [OriginInfoWebsite]? = nil
public var deviceRetrievalMethods: [DeviceRetrievalMethod]? = nil
public var serverRetrievalOptions: ServerRetrievalOptions? = nil
// private key data for holder only
var d: [UInt8]?
var d: [UInt8]?
public var qrCoded: [UInt8]?
#if DEBUG
mutating func setD(d: [UInt8]) { self.d = d }
#endif

#if DEBUG
mutating func setD(d: [UInt8]) { self.d = d }
#endif
/// Generate device engagement
/// - Parameters
/// - isBleServer: true for BLE mdoc peripheral server mode, false for BLE mdoc central client mode
/// - crv: The EC curve type used in the mdoc ephemeral private key
public init(isBleServer: Bool?, crv: ECCurveType = .p256) {
let pk = CoseKeyPrivate(crv: crv)
security = Security(deviceKey: pk.key)
d = pk.d
if let isBleServer {
deviceRetrievalMethods = [.ble(isBleServer: isBleServer, uuid: DeviceRetrievalMethod.getRandomBleUuid())]
}
}
/// initialize from cbor data
public init?(data: [UInt8]) {
guard let obj = try? CBOR.decode(data) else { return nil }
self.init(cbor: obj)
}

public var privateKey: CoseKeyPrivate? {
guard let d else { return nil }
return CoseKeyPrivate(key: security.deviceKey, d: d)
}
public init(isBleServer: Bool?, crv: ECCurveType = .p256) {
let pk = CoseKeyPrivate(crv: crv)
security = Security(deviceKey: pk.key)
d = pk.d
if let isBleServer {
deviceRetrievalMethods = [.ble(isBleServer: isBleServer, uuid: DeviceRetrievalMethod.getRandomBleUuid())]
}
}
/// initialize from cbor data
public init?(data: [UInt8]) {
guard let obj = try? CBOR.decode(data) else { return nil }
self.init(cbor: obj)
}
public var privateKey: CoseKeyPrivate? {
guard let d else { return nil }
return CoseKeyPrivate(key: security.deviceKey, d: d)
}

public var isBleServer: Bool? {
guard let deviceRetrievalMethods else { return nil}
Expand All @@ -85,24 +86,26 @@ public struct DeviceEngagement {
}

extension DeviceEngagement: CBOREncodable {
public func toCBOR(options: SwiftCBOR.CBOROptions) -> SwiftCBOR.CBOR {
var res = CBOR.map([0: .utf8String(version), 1: security.toCBOR(options: options)])
if let drms = deviceRetrievalMethods { res[2] = .array(drms.map { $0.toCBOR(options: options)}) }
if let sro = serverRetrievalOptions { res[3] = sro.toCBOR(options: options) }
return res
}
public func toCBOR(options: SwiftCBOR.CBOROptions) -> SwiftCBOR.CBOR {
var res = CBOR.map([0: .utf8String(version), 1: security.toCBOR(options: options)])
if let drms = deviceRetrievalMethods { res[2] = .array(drms.map { $0.toCBOR(options: options)}) }
if let sro = serverRetrievalOptions { res[3] = sro.toCBOR(options: options) }
if let oi = originInfos { res[5] = .array(oi.map {$0.toCBOR(options: CBOROptions()) }) }
return res
}
}


extension DeviceEngagement: CBORDecodable {
public init?(cbor: CBOR) {
guard case let .map(map) = cbor else { return nil }
guard let cv = map[0], case let .utf8String(v) = cv, v.prefix(2) == "1." else { return nil }
guard let cs = map[1], let s = Security(cbor: cs) else { return nil }
if let cdrms = map[2], case let .array(drms) = cdrms, drms.count > 0 { deviceRetrievalMethods = drms.compactMap(DeviceRetrievalMethod.init(cbor:)) }
if let csro = map[3], let sro = ServerRetrievalOptions.init(cbor: csro) { serverRetrievalOptions = sro }
version = v; security = s
}
public init?(cbor: CBOR) {
guard case let .map(map) = cbor else { return nil }
guard let cv = map[0], case let .utf8String(v) = cv, v.prefix(2) == "1." else { return nil }
guard let cs = map[1], let s = Security(cbor: cs) else { return nil }
if let cdrms = map[2], case let .array(drms) = cdrms, drms.count > 0 { deviceRetrievalMethods = drms.compactMap(DeviceRetrievalMethod.init(cbor:)) }
if let csro = map[3], let sro = ServerRetrievalOptions.init(cbor: csro) { serverRetrievalOptions = sro }
if case let .array(obj5) = map[5] { originInfos = obj5.compactMap(OriginInfoWebsite.init(cbor:)) }
version = v; security = s
}
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import SwiftCBOR

/// A `DeviceRetrievalMethod` holds two mandatory values (type and version). The first element defines the type and the second element the version for the transfer method.
/// Additionally, may contain extra info for each connection.
enum DeviceRetrievalMethod: Equatable {
public enum DeviceRetrievalMethod: Equatable {
static var version: UInt64 { 1 }

case qr
Expand All @@ -42,7 +42,7 @@ extension DeviceRetrievalMethod: CBOREncodable {
static func appendTypeAndVersion(_ cborArr: inout [CBOR], type: UInt64) {
cborArr.append(.unsignedInt(type)); cborArr.append(.unsignedInt(version))
}
func toCBOR(options: CBOROptions) -> CBOR {
public func toCBOR(options: CBOROptions) -> CBOR {
var cborArr = [CBOR]()
switch self {
case .qr:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
//
// OriginInfoWebsite.swift
// ScytalesDigitalWallet

import Foundation
import SwiftCBOR

public struct OriginInfoWebsite {
public static let ENGAGEMENT_VERSION_1_1 = "1.1"
// * The constant used to specify how the current engagement structure is delivered.
static let CAT_DELIVERY: UInt64 = 0
// * The constant used to specify how the other party engagement structure has been received.
static let CAT_RECEIVE: UInt64 = 1
static let TYPE: UInt64 = 100
private let mCat: UInt64
private let mBaseUrl: String
public init(baseUrl: String, cat: UInt64 = 1) {
mCat = cat
mBaseUrl = baseUrl
}
}

extension OriginInfoWebsite: CBOREncodable {
public func toCBOR(options: CBOROptions) -> CBOR {
.map(["cat": .unsignedInt(mCat), "type": .unsignedInt(Self.TYPE), "Details": .map(["baseUrl": .utf8String(mBaseUrl)])])
}
}

extension OriginInfoWebsite: CBORDecodable {
public init?(cbor: CBOR) {
guard case let .map(tS) = cbor else { return nil } // throw AppError.cbor("Top-level CBOR is not an map")}
guard case let .unsignedInt(nsCat) = tS["cat"] else { return nil } // throw AppError.cbor("cat not found")};
guard case let .map(nsDetails) = tS["Details"], case let .utf8String(nsUrl) = nsDetails["baseUrl"] else { return nil } //throw AppError.cbor("CBOR does not contain a url field")};
self.init(baseUrl: nsUrl, cat: nsCat)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,21 +21,21 @@ import Foundation
import SwiftCBOR

/// Server retrieval information
struct ServerRetrievalOption: Codable, Equatable {
public struct ServerRetrievalOption: Codable, Equatable {
static var versionImpl: UInt64 { 1 }
var version: UInt64 = Self.versionImpl
var url: String
var token: String
public var url: String
public var token: String
}

extension ServerRetrievalOption: CBOREncodable {
func toCBOR(options: CBOROptions) -> CBOR {
public func toCBOR(options: CBOROptions) -> CBOR {
.array([.unsignedInt(Self.versionImpl), .utf8String(url), .utf8String(token) ])
}
}

extension ServerRetrievalOption: CBORDecodable {
init?(cbor: CBOR) {
public init?(cbor: CBOR) {
guard case let .array(arr) = cbor, arr.count > 2 else { return nil }
guard case let .unsignedInt(v) = arr[0], v == Self.versionImpl else { return nil }
guard case let .utf8String(u) = arr[1], case let .utf8String(t) = arr[2] else { return nil }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@ import Foundation
import SwiftCBOR

/// Optional information on the server retrieval methods supported by the mdoc
struct ServerRetrievalOptions: Equatable {
var webAPI: ServerRetrievalOption?
var oIDC: ServerRetrievalOption?
var isEmpty:Bool { webAPI == nil && oIDC == nil }
public struct ServerRetrievalOptions: Equatable {
public var webAPI: ServerRetrievalOption?
public var oIDC: ServerRetrievalOption?
public var isEmpty:Bool { webAPI == nil && oIDC == nil }

enum Keys : String {
case webApi
Expand All @@ -34,7 +34,7 @@ struct ServerRetrievalOptions: Equatable {
}

extension ServerRetrievalOptions: CBOREncodable {
func toCBOR(options: CBOROptions) -> CBOR {
public func toCBOR(options: CBOROptions) -> CBOR {
var cborMap = [CBOR: CBOR]()
if let webAPI { cborMap[.utf8String(Keys.webApi.rawValue)] = webAPI.toCBOR(options: options) }
if let oIDC { cborMap[.utf8String(Keys.oidc.rawValue)] = oIDC.toCBOR(options: options) }
Expand All @@ -43,7 +43,7 @@ extension ServerRetrievalOptions: CBOREncodable {
}

extension ServerRetrievalOptions: CBORDecodable {
init?(cbor: CBOR) {
public init?(cbor: CBOR) {
guard case let .map(map) = cbor else { return nil }
if let cborW = map[.utf8String(Keys.webApi.rawValue)] { webAPI = ServerRetrievalOption(cbor: cborW) }
if let cborO = map[.utf8String(Keys.oidc.rawValue)] { oIDC = ServerRetrievalOption(cbor: cborO) }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,15 @@ import Foundation
import SwiftCBOR

/// The categories of vehicles/restrictions/conditions contain information describing the driving privileges of the mDL holder
struct DrivingPrivilege: Codable {
public struct DrivingPrivilege: Codable {
/// Vehicle category code as per ISO/IEC 18013-1
let vehicleCategoryCode: String
public let vehicleCategoryCode: String
/// Date of issue encoded as full-date
let issueDate: String?
public let issueDate: String?
/// Date of expiry encoded as full-date
let expiryDate: String?
public let expiryDate: String?
/// Array of code info
let codes: [DrivingPrivilegeCode]?
public let codes: [DrivingPrivilegeCode]?

enum CodingKeys: String, CodingKey, CaseIterable {
case vehicleCategoryCode = "vehicle_category_code"
Expand All @@ -39,7 +39,7 @@ struct DrivingPrivilege: Codable {
}

extension DrivingPrivilege: CBORDecodable {
init?(cbor: CBOR) {
public init?(cbor: CBOR) {
guard case let .utf8String(v) = cbor[.utf8String(CodingKeys.vehicleCategoryCode.rawValue)] else { return nil }
vehicleCategoryCode = v
if let id = cbor[.utf8String(CodingKeys.issueDate.rawValue)]?.decodeFullDate() { issueDate = id} else { issueDate = nil }
Expand All @@ -49,7 +49,7 @@ extension DrivingPrivilege: CBORDecodable {
}

extension DrivingPrivilege: CBOREncodable {
func toCBOR(options: CBOROptions) -> CBOR {
public func toCBOR(options: CBOROptions) -> CBOR {
var cborMap = [CBOR: CBOR]()
cborMap[.utf8String(CodingKeys.vehicleCategoryCode.rawValue)] = .utf8String(vehicleCategoryCode)
if let issueDate { cborMap[.utf8String(CodingKeys.issueDate.rawValue)] = issueDate.fullDateEncoded }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@ import Foundation
import SwiftCBOR

/// Driving privilege code
struct DrivingPrivilegeCode: Codable {
let code: String
let sign: String?
let value: String?
public struct DrivingPrivilegeCode: Codable {
public let code: String
public let sign: String?
public let value: String?

enum CodingKeys: String, CodingKey, CaseIterable {
case code = "code"
Expand All @@ -33,7 +33,7 @@ struct DrivingPrivilegeCode: Codable {
}

extension DrivingPrivilegeCode: CBORDecodable {
init?(cbor: CBOR) {
public init?(cbor: CBOR) {
guard case let .utf8String(c) = cbor[.utf8String(CodingKeys.code.rawValue)] else { return nil }
code = c
if case let .utf8String(s) = cbor[.utf8String(CodingKeys.sign.rawValue)] { sign = s} else { sign = nil }
Expand All @@ -42,7 +42,7 @@ extension DrivingPrivilegeCode: CBORDecodable {
}

extension DrivingPrivilegeCode: CBOREncodable {
func toCBOR(options: CBOROptions) -> CBOR {
public func toCBOR(options: CBOROptions) -> CBOR {
var cborMap = [CBOR: CBOR]()
cborMap[.utf8String(CodingKeys.code.rawValue)] = .utf8String(code)
if let sign { cborMap[.utf8String(CodingKeys.sign.rawValue)] = .utf8String(sign) }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,20 +20,20 @@ import Foundation
import SwiftCBOR

/// The DrivingPrivileges structure can be an empty array.
struct DrivingPrivileges: Codable {
let drivingPrivileges: [DrivingPrivilege]
subscript(i: Int) -> DrivingPrivilege { drivingPrivileges[i] }
public struct DrivingPrivileges: Codable {
public let drivingPrivileges: [DrivingPrivilege]
public subscript(i: Int) -> DrivingPrivilege { drivingPrivileges[i] }
}

extension DrivingPrivileges: CBORDecodable {
init?(cbor: CBOR) {
guard case let .array(dp) = cbor else { return nil }
drivingPrivileges = dp.compactMap(DrivingPrivilege.init(cbor:))
}
public init?(cbor: CBOR) {
guard case let .array(dp) = cbor else { return nil }
drivingPrivileges = dp.compactMap(DrivingPrivilege.init(cbor:))
}
}

extension DrivingPrivileges: CBOREncodable {
func toCBOR(options: CBOROptions) -> CBOR {
return .array(drivingPrivileges.map { $0.toCBOR(options: options) })
}
public func toCBOR(options: CBOROptions) -> CBOR {
return .array(drivingPrivileges.map { $0.toCBOR(options: options) })
}
}
Loading

0 comments on commit f3575b3

Please sign in to comment.