Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 16 additions & 22 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,21 +77,23 @@ The demo application (`demoapp/app`) provides a complete reference implementatio
* `libs/id-card-lib/build/outputs/aar`
* `libs/smart-card-reader-lib/build/outputs/aar`
* Move the resulting `.aar` files to your project's `/libs` directory.
* Add the corresponding dependencies to your application's `build.gradle` file:
* `implementation files('app/libs/aar')`
* Add the dependencies to your application's `build.gradle` file:
* `implementation files('app/libs/id-card-lib.aar')`
* `implementation files('app/libs/smart-card-reader-lib.aar')`

## Overview

ID card support for Android applications is based on two libraries: `id-card-lib` and `smart-card-reader-lib`.

* `smart-card-reader-lib` enables the use of the ID card over USB or NFC. It provides the low-level smart card reader interfaces and communication layer.
* `smart-card-reader-lib` enables the use of the ID card over NFC. It provides the NFC smart card reader interface and communication layer.
* `id-card-lib` implements the APDU-based communication protocols required to use the core functionality across different types of ID cards (IDEMIA and Thales).

Integrating ID card support into an Android application proceeds as follows:

* The developer declares the permissions required for the chosen integration method in the application manifest.
* The developer creates a manager specific to the selected integration method.
* Using the manager, the developer detects the ID card and creates a card instance via the appropriate `factory` method.
* The developer establishes a secure communication channel between the card and the device using the card’s corresponding CAN code.
* The developer declares the NFC permission in the application manifest.
* The developer creates an `NfcSmartCardReaderManager` instance.
* Using the manager, the developer detects the ID card and creates a card instance via `TokenWithPace.create()`.
* The developer establishes a secure communication channel between the card and the device using the card’s CAN code.
* The developer communicates with the card instance to use the desired functionalities—authentication, digital signing, etc.

An example of using the NFC interface can be found in the demo application: `CardReaderFragment.kt`. The example is written in Kotlin, but the library can also be used in Java applications. The sample app additionally depends on the `libdigidocpp` library, which enables the creation of signed ASiC-E containers; however, this dependency is not required for using the ID card via NFC.
Expand Down Expand Up @@ -149,7 +151,7 @@ public interface TokenWithPace extends Token {

The `TokenWithPace` interface enables NFC communication with the ID card. An instance is obtained via
its `create` factory method, which selects the correct implementation based on the card's ATS (*Answer To Select*).
Currently, two NFC-enabled ID card types are supported: IDEMIA (ID1) and Thales, implemented as `ID1WithPace` and `ThalesWithPace`.
Currently, two NFC-enabled ID card types are supported: IDEMIA and Thales, implemented as `IdemiaWithPace` and `ThalesWithPace`.

After creating the instance, establish the communication channel using the card’s `CAN` code and the `tunnel` method.

Expand Down Expand Up @@ -263,27 +265,19 @@ private fun exceptionHandler(ex: SmartCardReaderException) {

### Specifics of the NFC Interface

In general, using the ID card over **USB** and **NFC** interfaces is quite similar —
the main functions are the same, and the APDU protocol is largely identical.
However, the NFC interface has certain characteristics that may require adjustments in the application UI or communication flow.

1. When the ID card is connected to a smart card reader via the device’s USB port,
it becomes immediately visible to the system, and certain functionalities — such as reading personal data or checking PIN retry counters — are available right away.
The card can remain inserted for long periods and does not require the user to hold it in place.
The user has time to interact with the device and enter any necessary information.
The NFC interface has certain characteristics that require attention in the application UI and communication flow.

When using the ID card via NFC, the user must know the NFC antenna’s location on the device and physically hold the card against it.
1. The user must know the NFC antenna’s location on the device and physically hold the card against it.
This is often inconvenient and unstable.
Additionally, the card cannot be accessed before a secure channel is established using the correct CAN code —
for example, it is not possible to read PIN retry counters or display warnings to the user beforehand.
While the user is holding the card near the NFC interface, it can be difficult to operate the device otherwise (e.g., to enter PIN or CAN codes).

2. When using the ID card via a USB smart card reader, the APDU protocol operates in plaintext.
Over the NFC interface, the APDU protocol is **encrypted and authenticated**.
Furthermore, the card may enforce additional restrictions — not all functionalities are available over NFC.
2. Over NFC, the APDU protocol is **encrypted and authenticated** using Secure Messaging.
The card may also enforce additional restrictions — not all functionalities are available over NFC.

3. The **CAN** is a six-digit, card-specific number required for communication with the card over NFC.
3. The **CAN** is a six-digit, card-specific number required to establish the PACE tunnel over NFC.
Unlike PIN codes, the CAN cannot be changed or locked.
As a protection mechanism against brute-force attempts, IDEMIA cards introduce a delay:
after 10 consecutive incorrect CAN entries, the card enforces a **30-second delay** before the next CAN validation.
Once the correct CAN is entered, normal operation resumes immediately.
Once the correct CAN is entered, normal operation resumes immediately.
12 changes: 6 additions & 6 deletions doc/arhitektuur.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ Tuleb pidada silmas, et 100% ühilduvuse saavutamine ei osutunud võimalikuks. L

`smart-card-reader-lib` on RIA MOPP-Android päritolu. Algselt oli tegu teegiga, mis pakkus abstraktset `SmartCardReader` liidest ning `SmartCardReaderManager` klassi, mis Android API vahendusel USB ühendusi monitooris ning ID-kaardi ühendumise tuvastas. Teek sisaldas tuge ACS ja Identiv kaardilugejatele.

NFC liidese loomise käigus refaktoreeriti USB liidese spetsiifiline kood eraldi alamteeki ning selle kõrvale loodi NFC spetsiifiline alamteek, mis realiseerib klassid `NfcSmartCardReaderManager` ja `NfcSmartCardReader`. Mõlemad alamteegid - USB ja NFC - jagavad `SmartCardReader` abstraktsiooni ja erindeid. Tulenevalt tehnoloogilistest eripäradest ei osutunud otstarbekaks haldurklasside - `UsbSmartCardReaderManager` ja `NfcSmartCardReaderManager` vaheline abstraktsioonide jagamine. Ilmselt on ka teegi kasutajal oluline teha vahet USB ja NFC liidese vahel, kuna need tingivad ka erinevad kasutajakogemused - USB kaardilugejas võib kaart olla pikalt ning rakendus saab sellega suhelda. NFC ühenduse hoidmine eeldab kasutajalt füüsilist pingutust ning kaardiga suhelda saab alles peale PACE tunneli loomist.
USB liidese spetsiifiline kood ning ACS ja Identiv kaardilugejate tugi on teegist eemaldatud. Teek realiseerib ainult NFC-spetsiifilised klassid `NfcSmartCardReaderManager` ja `NfcSmartCardReader`, mis jagavad `SmartCardReader` abstraktsiooni ja erindeid. NFC ühenduse hoidmine eeldab kasutajalt füüsilist pingutust ning kaardiga suhelda saab alles peale PACE tunneli loomist.

Klass `NfcSmartCardReaderManager` on liidestumise alguspunkt integreerijale - selle klassi instantsi abil tuvastatakse seadme NFC toe olemasolu ning olek ja reageeritakse NFC võimelise ID-kaardi ilmumisele seadme kuuldeulatusse. Viimaseks otstarbeks on realiseeritud Android NFC liidese spetsiifilised *callbackid* ning integraator peab enda koodis keskenduma ennekõike ID-kaardi funktsionaalsuse kasutamisele, mitte Androidi ja ID-kaardi septsiifikale.

Expand All @@ -147,19 +147,19 @@ Klass `NfcSmartCardReader` realiseerib `SmartCardReader` liidese. Siin luuakse I

`id-card-lib` on RIA MOPP-Android päritolu. Kui rakendus on `smart-card-reader-lib` abil saanud `SmartCardReader` instantsi, siis antud teegi *factory* meetodeid kasutades luuakse juba konkreetset tüüpi ID-kaardi suhtlusprotokolli realiseerivad klassid, mis muuhulgas implementeerivad `Token` liidest.

USB ühenduse korral kasutab liidese `Token` *factory* meetod kaardi ATR väärtust konkreetse instantseeritava alamklassi tuvastamiseks. NFC ühenduse korral tuleb tuvastada kaardi ATS väärtus ning edasise suhtlemise jätkamiseks luua PACE protokolli kasutades autenditud ja krüpteeritud suhtluskanal kaardi ja seadme vahele. Selleks on `Token` liidesest päritud `TokenWithPace` liides, mille *factory* meetod tuvastab vaid NFC võimelisi kaarte ning mis kirjeldab meetodi `tunnel`, mida liidest implementeeriv klass peab realiseerima.
NFC ühenduse korral tuleb tuvastada kaardi ATS väärtus ning edasise suhtlemise jätkamiseks luua PACE protokolli kasutades autenditud ja krüpteeritud suhtluskanal kaardi ja seadme vahele. Selleks on `Token` liidesest päritud `TokenWithPace` liides, mille *factory* meetod tuvastab NFC võimelisi kaarte ATS väärtuse põhjal ning kirjeldab meetodi `tunnel`, mida liidest implementeeriv klass peab realiseerima.

`Token` liidest realiseerivad klassid `EstEIDv3d4` ja `EstEIDv3d5` ning `ID1`. Neist viimane kirjeldab IDEMIA ID1 kaardi APDU protokolli.
`Token` liidest realiseerivad klassid `Thales` ja `Idemia`. Neist viimane kirjeldab IDEMIA kaardi APDU protokolli.

`TokenWithPace` liidest realiseerib klass `ID1WithPace`, mis on klassi `ID1` alamklass ning täiendavalt realiseerib `ApduEncryptor` liidese, olles valmis `smart-card-reader-lib'i` klassile `NfcSmartCardReader` *Secure Messaging* sõnumite krüpteerimis-/dekrüpteerimisteenust pakkuma.
`TokenWithPace` liidest realiseerivad klassid `ThalesWithPace` ja `IdemiaWithPace`, mis on vastavate baasklasside alamklassid ning täiendavalt realiseerivad `ApduEncryptor` liidese, olles valmis `smart-card-reader-lib'i` klassile `NfcSmartCardReader` *Secure Messaging* sõnumite krüpteerimis-/dekrüpteerimisteenust pakkuma.

Klass `ID1WithPace` realiseerib ID-kaardi aspektid, mis on vajalikud NFC ühenduse vahendusel kasutamiseks:
Klassid `ThalesWithPace` ja `IdemiaWithPace` realiseerivad ID-kaardi aspektid, mis on vajalikud NFC ühenduse vahendusel kasutamiseks:

* PACE protokolli abil kaardi ja seadme vahele turvalise suhtluskanali loomine
* C-APDU sõnumite krüpteerimine ja MACimine - DO85, DO87, DO97 ning DO8E andmeobjektide loomine
* R-APDU sõnumite dekrüpteerimine ja verifitseerimine - DO85, DO87, DO99 ning DO8E andmeobjektide töötlemine

Väärib märkimist, et vaid üks `ID1` klassi meetod on vajanud ülelaadimist APDU protokolli täpsustamiseks, kuna kaardi käitumine NFC ühenduse korral erineb käitumisest kaardilugejaga ühenduse korral, siiski tuleb öelda, et kuigi kõik klassi `ID1` poolt pakutavad funktsioonid on `ID1WithPace` poolt SM sõnumiteks teisendatavad, ei pruugi kogu kaardi funktsionaalsus olla üle NFC toetatud - nt. PUK koodide muutmine vms.
Kuigi kõik baasklasside poolt pakutavad funktsioonid on `WithPace` klasside poolt SM sõnumiteks teisendatavad, ei pruugi kogu kaardi funktsionaalsus olla üle NFC toetatud - nt. PUK koodide muutmine vms.



Expand Down
43 changes: 22 additions & 21 deletions doc/model/id-card.puml
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,17 @@

left to right direction

abstract class ee.ria.DigiDoc.idcard.EstEIDToken
abstract class ee.ria.DigiDoc.idcard.PersonalData
abstract class ee.ria.DigiDoc.smartcardreader.SmartCardReader
class ee.ria.DigiDoc.idcard.AlgorithmUtils
class ee.ria.DigiDoc.idcard.CodeVerificationException
class ee.ria.DigiDoc.idcard.EstEIDv3d4
class ee.ria.DigiDoc.idcard.EstEIDv3d5
class ee.ria.DigiDoc.idcard.ID1
class ee.ria.DigiDoc.idcard.ID1PersonalDataParser
class ee.ria.DigiDoc.idcard.ID1WithPace
class ee.ria.DigiDoc.idcard.IdCardException
class ee.ria.DigiDoc.idcard.Idemia
class ee.ria.DigiDoc.idcard.IdemiaPersonalDataParser
class ee.ria.DigiDoc.idcard.IdemiaWithPace
class ee.ria.DigiDoc.idcard.PaceTunnelException
class ee.ria.DigiDoc.idcard.Thales
class ee.ria.DigiDoc.idcard.ThalesPersonalDataParser
class ee.ria.DigiDoc.idcard.ThalesWithPace
class ee.ria.DigiDoc.smartcardreader.ApduResponseException
class ee.ria.DigiDoc.smartcardreader.SmartCardReaderException
class ee.ria.DigiDoc.smartcardreader.nfc.NfcSmartCardReader
Expand All @@ -39,28 +38,30 @@ package org.bouncycastle <<External>> {
package util {}
}

enum ee.ria.DigiDoc.idcard.CardType
enum ee.ria.DigiDoc.idcard.CertificateType
enum ee.ria.DigiDoc.idcard.CodeType
interface ee.ria.DigiDoc.idcard.Token
interface ee.ria.DigiDoc.idcard.TokenWithPace
interface ee.ria.DigiDoc.smartcardreader.SmartCardReaderManager
interface ee.ria.DigiDoc.smartcardreader.nfc.ApduEncryptor


ee.ria.DigiDoc.idcard.EstEIDToken ..> ee.ria.DigiDoc.smartcardreader.SmartCardReader
ee.ria.DigiDoc.idcard.EstEIDToken ..> ee.ria.DigiDoc.idcard.AlgorithmUtils
ee.ria.DigiDoc.idcard.EstEIDToken -up-|> ee.ria.DigiDoc.idcard.Token
ee.ria.DigiDoc.idcard.EstEIDv3d4 -up-|> ee.ria.DigiDoc.idcard.EstEIDToken
ee.ria.DigiDoc.idcard.EstEIDv3d4 ..> ee.ria.DigiDoc.smartcardreader.SmartCardReader
ee.ria.DigiDoc.idcard.EstEIDv3d5 -up-|> ee.ria.DigiDoc.idcard.EstEIDToken
ee.ria.DigiDoc.idcard.EstEIDv3d5 ..> ee.ria.DigiDoc.smartcardreader.SmartCardReader
ee.ria.DigiDoc.idcard.ID1 ..> ee.ria.DigiDoc.smartcardreader.SmartCardReader
ee.ria.DigiDoc.idcard.ID1 -up-|> ee.ria.DigiDoc.idcard.Token
ee.ria.DigiDoc.idcard.ID1WithPace -up-|> ee.ria.DigiDoc.idcard.ID1
ee.ria.DigiDoc.idcard.ID1WithPace ..> ee.ria.DigiDoc.smartcardreader.nfc.NfcSmartCardReader
ee.ria.DigiDoc.idcard.ID1WithPace -up-|> ee.ria.DigiDoc.idcard.TokenWithPace
ee.ria.DigiDoc.idcard.ID1WithPace -up-|> ee.ria.DigiDoc.smartcardreader.nfc.ApduEncryptor
ee.ria.DigiDoc.idcard.Thales -up-|> ee.ria.DigiDoc.idcard.Token
ee.ria.DigiDoc.idcard.Thales ..> ee.ria.DigiDoc.smartcardreader.SmartCardReader
ee.ria.DigiDoc.idcard.Thales ..> ee.ria.DigiDoc.idcard.ThalesPersonalDataParser
ee.ria.DigiDoc.idcard.ThalesWithPace -up-|> ee.ria.DigiDoc.idcard.Thales
ee.ria.DigiDoc.idcard.ThalesWithPace -up-|> ee.ria.DigiDoc.idcard.TokenWithPace
ee.ria.DigiDoc.idcard.ThalesWithPace -up-|> ee.ria.DigiDoc.smartcardreader.nfc.ApduEncryptor
ee.ria.DigiDoc.idcard.ThalesWithPace ..> ee.ria.DigiDoc.smartcardreader.nfc.NfcSmartCardReader
ee.ria.DigiDoc.idcard.Idemia -up-|> ee.ria.DigiDoc.idcard.Token
ee.ria.DigiDoc.idcard.Idemia ..> ee.ria.DigiDoc.smartcardreader.SmartCardReader
ee.ria.DigiDoc.idcard.Idemia ..> ee.ria.DigiDoc.idcard.IdemiaPersonalDataParser
ee.ria.DigiDoc.idcard.IdemiaWithPace -up-|> ee.ria.DigiDoc.idcard.Idemia
ee.ria.DigiDoc.idcard.IdemiaWithPace -up-|> ee.ria.DigiDoc.idcard.TokenWithPace
ee.ria.DigiDoc.idcard.IdemiaWithPace -up-|> ee.ria.DigiDoc.smartcardreader.nfc.ApduEncryptor
ee.ria.DigiDoc.idcard.IdemiaWithPace ..> ee.ria.DigiDoc.smartcardreader.nfc.NfcSmartCardReader
ee.ria.DigiDoc.idcard.Token ..> ee.ria.DigiDoc.smartcardreader.SmartCardReader
ee.ria.DigiDoc.idcard.TokenWithPace ..> ee.ria.DigiDoc.smartcardreader.nfc.NfcSmartCardReader
ee.ria.DigiDoc.idcard.TokenWithPace -up-|> ee.ria.DigiDoc.idcard.Token
ee.ria.DigiDoc.idcard.PersonalData ..> ee.ria.DigiDoc.idcard.CardType
@enduml
Binary file removed doc/model/smart-card-reader.png
Binary file not shown.
Loading