Skip to content

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
phisakel committed Nov 30, 2023
2 parents 6c7d06b + 6e36193 commit 296bd90
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 24 deletions.
24 changes: 15 additions & 9 deletions Sources/MdocDataTransfer18013/BLETransfer/MdocGATTServer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,14 @@ public class MdocGattServer: ObservableObject {
var sendBuffer = [Data]()
var numBlocks: Int = 0
var subscribeCount: Int = 0
var initSuccess:Bool = false

public init(parameters: [String: Any]) throws {
guard let (docs, devicePrivateKey, iaca) = MdocHelpers.initializeData(parameters: parameters) else {
throw Self.makeError(code: .documents_not_provided)
}
self.docs = docs; self.devicePrivateKey = devicePrivateKey; self.iaca = iaca
status = .initialized; handleStatusChange(status)
status = .initialized; initSuccess = true; handleStatusChange(status)
}

@objc(CBPeripheralManagerDelegate)
Expand Down Expand Up @@ -129,11 +130,11 @@ public class MdocGattServer: ObservableObject {
// Create a new device engagement object and start the device engagement process.
///
/// ``qrCodeImageData`` is set to QR code image data corresponding to the device engagement.
public func performDeviceEngagement() {
public func performDeviceEngagement(rfus: [String]? = nil) {
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 = Self.makeError(code: .unexpected_error, str: error?.localizedDescription ?? "Not initialized!"); return }
deviceEngagement = DeviceEngagement(isBleServer: true, crv: .p256)
deviceEngagement = DeviceEngagement(isBleServer: true, crv: .p256, rfus: rfus)
sessionEncryption = nil
#if os(iOS)
/// get qrCode image data corresponding to the device engagement
Expand Down Expand Up @@ -185,7 +186,7 @@ public class MdocGattServer: ObservableObject {
qrCodeImageData = nil
advertising = false
subscribeCount = 0
if status == .error { status = .initializing }
if status == .error && initSuccess { status = .initializing }
}

func handleStatusChange(_ newValue: TransferStatus) {
Expand All @@ -195,7 +196,7 @@ public class MdocGattServer: ObservableObject {
if newValue == .requestReceived {
peripheralManager.stopAdvertising()
deviceRequest = decodeRequestAndInformUser(requestData: readBuffer, devicePrivateKey: devicePrivateKey, readerKeyRawData: nil, handOver: BleTransferMode.QRHandover, handler: userSelected)
if deviceRequest == nil { error = Self.makeError(code: .requestDecodeError) }
if deviceRequest == nil && error == nil { error = Self.makeError(code: .requestDecodeError) }
}
else if newValue == .initialized {
bleDelegate = Delegate(server: self)
Expand All @@ -212,14 +213,18 @@ public class MdocGattServer: ObservableObject {
}

var isInErrorState: Bool { status == .error }
static var errorNoDocumentsDescriptionKey: String { "doctype_not_found" }
static func getErrorNoDocuments(_ docType: String) -> Error { NSError(domain: "\(MdocGattServer.self)", code: 0, userInfo: ["key": Self.errorNoDocumentsDescriptionKey, "%s": docType]) }

public func userSelected(_ b: Bool, _ items: RequestItems?) {
status = .userSelected
if !b { error = Self.makeError(code: .userRejected) }
if let items {
do {
guard let (docToSend, _, _) = try MdocHelpers.getDeviceResponseToSend(deviceRequest: deviceRequest!, deviceResponses: docs, selectedItems: items, sessionEncryption: sessionEncryption, eReaderKey: sessionEncryption!.sessionKeys.publicKey, devicePrivateKey: devicePrivateKey) else { error = Self.makeError(code: .noDocumentToReturn); return }
guard let bytes = getSessionDataToSend(docToSend: docToSend) else { error = Self.makeError(code: .noDocumentToReturn); return }
let docTypeReq = deviceRequest?.docRequests.first?.itemsRequest.docType ?? ""
guard let (drToSend, _, _) = try MdocHelpers.getDeviceResponseToSend(deviceRequest: deviceRequest!, deviceResponses: docs, selectedItems: items, sessionEncryption: sessionEncryption, eReaderKey: sessionEncryption!.sessionKeys.publicKey, devicePrivateKey: devicePrivateKey) else { error = Self.getErrorNoDocuments(docTypeReq); return }
guard let dts = drToSend.documents, !dts.isEmpty else { error = Self.getErrorNoDocuments(docTypeReq); return}
guard let bytes = getSessionDataToSend(docToSend: drToSend) else { error = Self.getErrorNoDocuments(docTypeReq); return }
prepareDataToSend(bytes)
DispatchQueue.main.asyncAfter(deadline: .now()+0.2) { self.sendDataWithUpdates() }
} catch { self.error = error }
Expand Down Expand Up @@ -294,7 +299,8 @@ public class MdocGattServer: ObservableObject {
guard var sessionEncryption else { logger.error("Session Encryption not initialized"); return nil }
guard let requestData = try sessionEncryption.decrypt(requestCipherData) else { logger.error("Request data cannot be decrypted"); return nil }
guard let deviceRequest = DeviceRequest(data: requestData) else { logger.error("Decrypted data cannot be decoded"); return nil }
guard let (_, validRequestItems, errorRequestItems) = try MdocHelpers.getDeviceResponseToSend(deviceRequest: deviceRequest, deviceResponses: docs, selectedItems: nil, sessionEncryption: sessionEncryption, eReaderKey: sessionEncryption.sessionKeys.publicKey, devicePrivateKey: devicePrivateKey) else { logger.error("Valid request items nil"); return nil }
guard let (drTest, validRequestItems, errorRequestItems) = try MdocHelpers.getDeviceResponseToSend(deviceRequest: deviceRequest, deviceResponses: docs, selectedItems: nil, sessionEncryption: sessionEncryption, eReaderKey: sessionEncryption.sessionKeys.publicKey, devicePrivateKey: devicePrivateKey) else { logger.error("Valid request items nil"); return nil }
if drTest.documents == nil { self.error = Self.getErrorNoDocuments(deviceRequest.docRequests.first?.itemsRequest.docType ?? ""); return nil }
var params: [String: Any] = [UserRequestKeys.valid_items_requested.rawValue: validRequestItems, UserRequestKeys.error_items_requested.rawValue: errorRequestItems]
if let docR = deviceRequest.docRequests.first {
let mdocAuth = MdocReaderAuthentication(transcript: sessionEncryption.transcript)
Expand All @@ -314,7 +320,7 @@ public class MdocGattServer: ObservableObject {
public static func makeError(code: ErrorCode, str: String? = nil) -> NSError {
let errorMessage = str ?? NSLocalizedString(code.description, comment: code.description)
logger.error(Logger.Message(unicodeScalarLiteral: errorMessage))
return NSError(domain: "\(MdocGattServer.self)", code: code.rawValue, userInfo: [NSLocalizedDescriptionKey: errorMessage])
return NSError(domain: "\(MdocGattServer.self)", code: code.rawValue, userInfo: [NSLocalizedDescriptionKey: errorMessage, "key": code.description])
}
}

4 changes: 3 additions & 1 deletion Sources/MdocDataTransfer18013/Enumerations.swift
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,9 @@ public enum ErrorCode: Int, CustomStringConvertible {
public enum InitializeKeys: String {
case document_json_data
case document_signup_response_data
case device_private_key
case document_signup_response_obj
case device_private_key_data
case device_private_key_obj
case trusted_certificates
}

Expand Down
36 changes: 22 additions & 14 deletions Sources/MdocDataTransfer18013/MdocHelpers.swift
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,12 @@ public class MdocHelpers {
let sampleData = d.compactMap { $0.decodeJSON(type: SignUpResponse.self) }
docs = sampleData.compactMap { $0.deviceResponse }
devicePrivateKey = sampleData.compactMap { $0.devicePrivateKey }.first
} else if let drs = parameters[InitializeKeys.document_signup_response_data.rawValue] as? [DeviceResponse], let dpk = parameters[InitializeKeys.device_private_key.rawValue] as? CoseKeyPrivate {
} else if let drs = parameters[InitializeKeys.document_signup_response_obj.rawValue] as? [DeviceResponse], let dpk = parameters[InitializeKeys.device_private_key_obj.rawValue] as? CoseKeyPrivate {
docs = drs
devicePrivateKey = dpk
} else if let drsData = parameters[InitializeKeys.document_signup_response_data.rawValue] as? [Data], let dpk = parameters[InitializeKeys.device_private_key_data.rawValue] as? Data {
docs = drsData.compactMap({ DeviceResponse(data: [UInt8]($0))})
devicePrivateKey = CoseKeyPrivate(privateKeyx963Data: dpk, crv: .p256)
}
if let i = parameters[InitializeKeys.trusted_certificates.rawValue] as? [Data] {
iaca = i.compactMap { SecCertificateCreateWithData(nil, $0 as CFData) }
Expand Down Expand Up @@ -92,23 +95,28 @@ public class MdocHelpers {
nsErrorsToAdd[reqNamespace] = Dictionary(grouping: errorItemsSet, by: { $0 }).mapValues { _ in 0 }
}
} // end ns for
let issuerAuthToAdd = doc.issuerSigned.issuerAuth
let issToAdd = IssuerSigned(issuerNameSpaces: IssuerNameSpaces(nameSpaces: nsItemsToAdd), issuerAuth: issuerAuthToAdd)
var devSignedToAdd: DeviceSigned? = nil
if let eReaderKey, let sessionEncryption, let devicePrivateKey {
let authKeys = CoseKeyExchange(publicKey: eReaderKey, privateKey: devicePrivateKey)
let mdocAuth = MdocAuthentication(transcript: sessionEncryption.transcript, authKeys: authKeys)
guard let devAuth = try mdocAuth.getDeviceAuthForTransfer(docType: reqDocType) else {logger.error("Cannot create device auth"); return nil }
devSignedToAdd = DeviceSigned(deviceAuth: devAuth)
}
let errors: Errors? = nsErrorsToAdd.count == 0 ? nil : Errors(errors: nsErrorsToAdd)
let docToAdd = Document(docType: reqDocType, issuerSigned: issToAdd, deviceSigned: devSignedToAdd, errors: errors)
docFiltered.append(docToAdd)
validReqItemsDocDict[reqDocType] = validReqItemsNsDict
if nsItemsToAdd.count > 0 {
let issuerAuthToAdd = doc.issuerSigned.issuerAuth
let issToAdd = IssuerSigned(issuerNameSpaces: IssuerNameSpaces(nameSpaces: nsItemsToAdd), issuerAuth: issuerAuthToAdd)
var devSignedToAdd: DeviceSigned? = nil
if let eReaderKey, let sessionEncryption, let devicePrivateKey {
let authKeys = CoseKeyExchange(publicKey: eReaderKey, privateKey: devicePrivateKey)
let mdocAuth = MdocAuthentication(transcript: sessionEncryption.transcript, authKeys: authKeys)
guard let devAuth = try mdocAuth.getDeviceAuthForTransfer(docType: reqDocType) else {logger.error("Cannot create device auth"); return nil }
devSignedToAdd = DeviceSigned(deviceAuth: devAuth)
}
let docToAdd = Document(docType: reqDocType, issuerSigned: issToAdd, deviceSigned: devSignedToAdd, errors: errors)
docFiltered.append(docToAdd)
validReqItemsDocDict[reqDocType] = validReqItemsNsDict
} else {
docErrors.append([reqDocType: UInt64(0)])
}
errorReqItemsDocDict[reqDocType] = nsErrorsToAdd.mapValues { Array($0.keys) }
} // end doc for
let documentErrors: [DocumentError]? = docErrors.count == 0 ? nil : docErrors.map(DocumentError.init(docErrors:))
let deviceResponseToSend = DeviceResponse(version: deviceResponses.first!.version, documents: docFiltered, documentErrors: documentErrors, status: 0)
let documentsToAdd = docFiltered.count == 0 ? nil : docFiltered
let deviceResponseToSend = DeviceResponse(version: deviceResponses.first!.version, documents: documentsToAdd, documentErrors: documentErrors, status: 0)
return (deviceResponseToSend, validReqItemsDocDict, errorReqItemsDocDict)
}

Expand Down

0 comments on commit 296bd90

Please sign in to comment.