Skip to content

Commit 3c73958

Browse files
committed
Add MyEID NFC functionality
MOPPIOS-1669 Fix for TLV 0x85 tag in APDU response (odd and even instructions handling). MOPPIOS-1669 Additional sw code for pin verification method exception. Encrypt can number saving NFC refactor
1 parent 6370007 commit 3c73958

31 files changed

Lines changed: 1313 additions & 361 deletions

Modules/CommonsLib/Sources/CommonsLib/Constants.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ public struct Constants {
9999

100100
public struct File {
101101
public static let LDAPCertsPem = "ldapCerts.pem"
102+
public static let nfcCANKey = "canKey.txt"
102103
}
103104

104105
public struct FileBaseName {

Modules/IdCardLib/Sources/IdCardLib/CardActions/CardCommandsInternal.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ extension CardCommandsInternal {
7474
return
7575
case 0x6A80: // New pin is invalid
7676
throw IdCardInternalError.invalidNewPin
77-
case 0x63C0, 0x6983: // Authentication method blocked
77+
case 0x63C0, 0x6983, 0x6984: // Authentication method blocked
7878
throw IdCardInternalError.pinVerificationFailed
7979
// For pin codes this means verification failed due to wrong pin
8080
case let uInt16 where (uInt16 & 0xFFF0) == 0x63C0:

Modules/IdCardLib/Sources/IdCardLib/CardActions/CardReaderNFC.swift

Lines changed: 42 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -234,19 +234,38 @@ class CardReaderNFC: @unchecked CardReader, Loggable {
234234
}
235235
return (tlvEnc, tlvRes, tlvMac)
236236
}
237-
237+
// swiftlint:disable cyclomatic_complexity
238238
func transmit(_ apduData: Bytes) async throws -> (responseData: Bytes, sw: UInt16) {
239239
CardReaderNFC.logger().debug("Plain >: \(apduData.toHex)")
240240
guard let apdu = NFCISO7816APDU(data: Data(apduData)) else {
241241
throw IdCardInternalError.invalidAPDU
242242
}
243243
_ = SSC.increment()
244-
let DO87 = try getDO87(apdu)
245-
let DO97 = try getDO97(apdu)
244+
let DO87: Data
245+
if let data = apdu.data, !data.isEmpty {
246+
let ivValue = try AES.CBC(key: ksEnc).encrypt(SSC)
247+
let encData = try AES.CBC(key: ksEnc, ivVal: ivValue).encrypt(data.addPadding())
248+
if apdu.instructionCode & 0x01 == 0 {
249+
DO87 = TLV(tag: 0x87, bytes: [0x01] + encData).data
250+
} else {
251+
DO87 = TLV(tag: 0x85, bytes: encData).data
252+
}
253+
} else {
254+
DO87 = Data()
255+
}
256+
let DO97: Data
257+
if apdu.expectedResponseLength > 0 {
258+
DO97 = TLV(
259+
tag: 0x97,
260+
bytes: [UInt8(apdu.expectedResponseLength == 256 ? 0 : apdu.expectedResponseLength)]
261+
).data
262+
} else {
263+
DO97 = Data()
264+
}
246265
let cmdHeader: Bytes = [apdu.instructionClass | 0x0C, apdu.instructionCode, apdu.p1Parameter, apdu.p2Parameter]
247-
let MValue = cmdHeader.addPadding() + DO87 + DO97
248-
let NValue = SSC + MValue
249-
let mac = try AES.CMAC(key: ksMac).authenticate(bytes: NValue.addPadding())
266+
let mVal = cmdHeader.addPadding() + DO87 + DO97
267+
let nVal = SSC + mVal
268+
let mac = try AES.CMAC(key: ksMac).authenticate(bytes: nVal.addPadding())
250269
let DO8E = TLV(tag: 0x8E, bytes: mac).data
251270
let send = DO87 + DO97 + DO8E
252271
let response = try await tag.sendCommand(
@@ -257,26 +276,39 @@ class CardReaderNFC: @unchecked CardReader, Loggable {
257276
data: send,
258277
leByte: 256
259278
)
260-
let (tlvEnc, tlvRes, tlvMac) = try getTLVs(response)
279+
var tlvEnc: TKTLVRecord?
280+
var tlvRes: TKTLVRecord?
281+
var tlvMac: TKTLVRecord?
282+
for tlv in TLV.sequenceOfRecords(from: response) ?? [] {
283+
switch tlv.tag {
284+
case 0x85, 0x87: tlvEnc = tlv
285+
case 0x99: tlvRes = tlv
286+
case 0x8E: tlvMac = tlv
287+
default: print("Unknown tag")
288+
}
289+
}
261290
guard let tlvRes else {
262291
throw IdCardInternalError.missingRESTag
263292
}
264293
guard let tlvMac else {
265294
throw IdCardInternalError.missingMACTag
266295
}
267-
let KValue = SSC.increment() + (tlvEnc?.data ?? Data()) + tlvRes.data
268-
if try Data(AES.CMAC(key: ksMac).authenticate(bytes: KValue.addPadding())) != tlvMac.value {
296+
let kVal = SSC.increment() + (tlvEnc?.data ?? Data()) + tlvRes.data
297+
if try Data(AES.CMAC(key: ksMac).authenticate(bytes: kVal.addPadding())) != tlvMac.value {
269298
throw IdCardInternalError.invalidMACValue
270299
}
271300
guard let tlvEnc else {
272301
CardReaderNFC.logger().debug("Plain <: \(tlvRes.value.toHex)")
273302
return (.init(), UInt16(tlvRes.value[0], tlvRes.value[1]))
274303
}
275304
let ivValue = try AES.CBC(key: ksEnc).encrypt(SSC)
276-
let responseData = try (try AES.CBC(key: ksEnc, ivVal: ivValue).decrypt(tlvEnc.value[1...])).removePadding()
305+
let responseData = try (try AES.CBC(key: ksEnc, ivVal: ivValue)
306+
.decrypt(tlvEnc.tag == 0x85 ? tlvEnc.value : tlvEnc.value[1...]))
307+
.removePadding()
277308
CardReaderNFC.logger().debug("Plain <: \(responseData.toHex) \(tlvRes.value.toHex)")
278309
return (Bytes(responseData), UInt16(tlvRes.value[0], tlvRes.value[1]))
279310
}
311+
// swiftlint:enable cyclomatic_complexity
280312

281313
// MARK: - Utils
282314

Modules/IdCardLib/Sources/IdCardLib/CardActions/Thales.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ final class Thales: CardCommandsInternal {
115115
guard type != .puk else {
116116
throw IdCardInternalError.notSupportedCodeType
117117
}
118+
_ = try await select(file: Thales.kAID)
118119
try await unblockCode(type.pinRef, puk: puk, newCode: newCode)
119120
}
120121

Modules/IdCardLib/Sources/IdCardLib/Operations/OperationUnblockPin.swift

Lines changed: 0 additions & 104 deletions
This file was deleted.

RIADigiDoc.xcodeproj/project.pbxproj

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@
156156
"Domain/Model/My eID/MyEidPinCodeStep.swift",
157157
Domain/Model/Notification/ContainerNotificationType.swift,
158158
Domain/Model/SettingsMenuBottomSheetPages.swift,
159+
Domain/Model/Signing/ActionType.swift,
159160
Domain/Model/Signing/MobileId/MobileIdInputData.swift,
160161
Domain/Model/Signing/NFC/NFCInputData.swift,
161162
Domain/Model/Signing/SigningMethod.swift,
@@ -165,9 +166,14 @@
165166
Domain/Model/SupportedTheme.swift,
166167
Domain/Model/ToastMessage.swift,
167168
Domain/NFC/DecryptError.swift,
169+
Domain/NFC/NFCOperationBase.swift,
168170
Domain/NFC/NFCSessionStrings.swift,
171+
Domain/NFC/NFCSessionStringsUtil.swift,
172+
Domain/NFC/OperationChangePin.swift,
169173
Domain/NFC/OperationDecrypt.swift,
174+
Domain/NFC/OperationReadCardData.swift,
170175
Domain/NFC/OperationReadCertAndSign.swift,
176+
Domain/NFC/OperationUnblockPin.swift,
171177
Domain/Preferences/DataStore.swift,
172178
Domain/Preferences/DataStoreProtocol.swift,
173179
Domain/Preferences/KeychainStore.swift,
@@ -194,6 +200,7 @@
194200
UI/Theme/Theme.swift,
195201
Util/Certificate/CertificateUtil.swift,
196202
Util/Certificate/CertificateUtilProtocol.swift,
203+
Util/EncryptedData/EncryptedDataUtil.swift,
197204
Util/File/FileInspector.swift,
198205
Util/File/FileInspectorProtocol.swift,
199206
Util/Language/LanguageSettings.swift,

RIADigiDoc/DI/AppContainer.swift

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -503,7 +503,10 @@ extension Container {
503503
self { @MainActor in
504504
NFCViewModel(
505505
dataStore: self.dataStore(),
506-
userAgentUtil: self.userAgentUtil()
506+
userAgentUtil: self.userAgentUtil(),
507+
certificateUtil: self.certificateUtil(),
508+
sharedMyEidSession: self.sharedMyEidSession(),
509+
keychainStore: self.keychainStore()
507510
)
508511
}
509512
}
@@ -517,17 +520,31 @@ extension Container {
517520
}
518521
}
519522

523+
// swiftlint:disable closure_parameter_position
524+
// swiftlint:disable large_tuple
520525
@MainActor
521-
var myEidPinChangeViewModel: ParameterFactory<(MyEidPinCodeAction, CodeType, String), MyEidPinChangeViewModel> {
522-
self { @MainActor (pinAction: MyEidPinCodeAction, codeType: CodeType, personalCode: String
526+
var myEidPinChangeViewModel: ParameterFactory<(
527+
MyEidPinCodeAction,
528+
CodeType,
529+
String,
530+
ActionMethod
531+
), MyEidPinChangeViewModel> {
532+
self { @MainActor (
533+
pinAction: MyEidPinCodeAction,
534+
codeType: CodeType,
535+
personalCode: String,
536+
actionMethod: ActionMethod
523537
) -> MyEidPinChangeViewModel in
524538
MyEidPinChangeViewModel(
525539
pinAction: pinAction,
526540
codeType: codeType,
527541
personalCode: personalCode,
542+
actionMethod: actionMethod,
528543
idCardRepository: self.idCardRepository(),
529544
sharedMyEidSession: self.sharedMyEidSession()
530545
)
531546
}
532547
}
548+
// swiftlint:enable closure_parameter_position
549+
// swiftlint:enable large_tuple
533550
}

RIADigiDoc/Domain/Model/KeychainKey.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,5 @@
1919

2020
public enum KeychainKey: String, CaseIterable, Sendable {
2121
case proxyPassword = "proxy_password"
22+
case nfcCANKey = "nfc_can_key"
2223
}

RIADigiDoc/Domain/Model/Navigation/NavigationDestination.swift

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,12 +72,14 @@ public enum NavigationDestination: Hashable {
7272

7373
case myEidRootView
7474
case myEidView(
75-
idCardData: IdCardData
75+
idCardData: IdCardData,
76+
actionMethod: ActionMethod
7677
)
7778

7879
case myEidPinView(
7980
pinAction: MyEidPinCodeAction,
8081
codeType: CodeType,
81-
personalCode: String
82+
personalCode: String,
83+
actionMethod: ActionMethod
8284
)
8385
}

0 commit comments

Comments
 (0)