Преглед архитектуре
LibreSCRS се састоји од два главна пројекта који заједно читају, обрађују и приказују податке са смарт картица.
Компоненте #
LibreMiddleware (LGPL-2.1) #
Колекција статичких C++23 библиотека за комуникацију са смарт картицама, без зависности од Qt-а. Обрађује све од APDU команди ниског нивоа до екстракције података са картице. Сва PC/SC комуникација живи искључиво у LibreMiddleware-у — LibreCelik нема директну зависност од PC/SC-а.
Јавни CMake циљеви #
Спољни корисници линкују против LibreSCRS::* алијас површине — стабилног
јавног API-ја који скрива интерне библиотеке иза PascalCase именских простора:
| Циљ | Именски простор | Намена |
|---|---|---|
LibreSCRS::SmartCard | LibreSCRS::SmartCard | CardSession, MonitorService — PC/SC + монитор |
LibreSCRS::Plugin | LibreSCRS::Plugin | CardPlugin, CardPluginService, CardData, ReadResult |
LibreSCRS::Auth | LibreSCRS::Auth | CredentialProvider, AuthRequirement, CredentialResult |
LibreSCRS::Certificate | LibreSCRS::Certificate | Парсирање и метаподаци X.509 сертификата |
LibreSCRS::Trust | LibreSCRS::Trust | TrustStoreService, TrustStore, TrustConfig |
LibreSCRS::Signing | LibreSCRS::Signing | SigningService, SigningRequest, SigningResult, VisualSignatureLayout |
LibreSCRS::Secure | LibreSCRS::Secure | Secure::Buffer, Secure::String (нулирање при уништавању) |
Табела испод приказује интерне bucket-B библиотеке које имплементирају ове јавне циљеве. Интерне библиотеке могу да се мењају између издања и спољни код не треба директно да линкује против њих.
| Библиотека | Намена |
|---|---|
smartcard | PCSCConnection, Monitor (детекција картица), APDU команда/одговор, TLV и BER-TLV парсирање (ISO 7816-4), TransmitFilter (транспарентни Secure Messaging слој) |
plugin | CardPlugin интерфејс (са подршком за streaming), CardData модел, CardPluginRegistry (dlopen), AutoReader (мост између Monitor-а и откривања додатака) |
pkcs15 | Генерички PKCS#15/ISO 7816-15 парсер и библиотека — EF.ODF/EF.DIR откривање, енумерација сертификата и кључева. Ради са било којом PKCS#15-компатибилном картицом |
rs-eid | API за српску eID картицу са имплементацијама читача (Apollo 2008, Gemalto 2014+, Foreigner IF2020) |
eu-vrc | ЕУ саобраћајна дозвола (Директива 2003/127/EC) |
rs-health | Картица српског здравственог осигурања (РФЗО) |
cardedge | CardEdge PKI аплет за српске смарт картице — сертификати, управљање PIN-ом, дигитално потписивање |
emrtd | eMRTD комуникација са е-пасошем — читање група података, парсирање MRZ-а |
emrtd-crypto | eMRTD криптографија — BAC, PACE (ECDH-GM), Secure Messaging |
piv | PIV комуникација са картицом (NIST SP 800-73) |
pkcs11 | PKCS#11 дељена библиотека (librescrs-pkcs11) — подржава све типове картица |
*-plugin | Додаци за картице (.so): rs-eid, rs-health, eu-vrc, emrtd, piv, pkcs15, cardedge, opensc |
LibreCelik (GPL-3.0) #
Qt6 десктоп GUI апликација за приказ података са картица. Чист презентацијски слој — без PC/SC-а, без APDU-а, без знања о протоколима картица. Прима CardData од middleware додатака и приказује га кроз GUI додатке.
| Модул | Намена |
|---|---|
smartcard | SmartCardReaderListener — Qt адаптер који обавија middleware smartcard::Monitor |
plugin | CardWidgetPlugin интерфејс и CardWidgetPluginRegistry (QPluginLoader) |
asynccardreader | Генерички асинхрони читач картица кроз middleware CardPlugin ланац |
document | Дељени PKI кориснички интерфејс (TokenSection), дијалог за промену PIN-а, штампање |
certificate | Прегледач X.509 сертификата (модел стабла + дијалог) |
plugins/ | GUI додаци (rs-eid, rs-health, eu-vrc, emrtd, piv, token) као Qt MODULE .so датотеке |
LibreCelik преузима LibreMiddleware преко CMake FetchContent. За локални развој можете усмерити на локалну копију.
Архитектура додатака #
Цео систем је изграђен око додатака. Постоје два независна слоја — middleware додаци за комуникацију са картицом, GUI додаци за приказ. Повезани су кроз CardData, универзални модел података који сваки middleware додатак производи, а сваки GUI додатак конзумира.
┌─────────────────────────────────────────────────────────┐
│ LibreCelik (GUI) │
│ │
│ ┌──────────────────────┐ ┌────────────────────────┐ │
│ │SmartCardReaderListener│ │ CardWidgetPluginRegistry│ │
│ │(Qt адаптер за Monitor)│ │ (QPluginLoader) │ │
│ └──────────────────────┘ └──────────┬─────────────┘ │
│ ▲ │ учитава │
│ │ обавија ┌──────▼──────────────┐ │
│ │ │ GUI додаци (.so) │ │
│ │ │ ┌──────┐ ┌────────┐ │ │
│ │ │ │rs-eid│ │eu-vrc │ │ │
│ │ │ ├──────┤ ├────────┤ │ │
│ │ │ │rs- │ │ emrtd │ │ │
│ │ │ │health│ ├────────┤ │ │
│ │ │ ├──────┤ │ piv │ │ │
│ │ │ │token │ └────────┘ │ │
│ │ │ └──────┘ │ │
│ │ └─────────────────────┘ │
│ │ ▲ │
│ │ │ CardData │
├───────────┼──────────────────────────┼──────────────────┤
│ │ LibreMiddleware│ │
│ │ │ │
│ ┌────────┴─────────┐ ┌─────────────┴──────────┐ │
│ │ smartcard::Monitor│ │ CardPluginRegistry │ │
│ │ (PC/SC polling) │ │ (dlopen) │ │
│ └──────────────────┘ └──────────┬─────────────┘ │
│ │ учитава │
│ ┌───────────────────────────────▼─────────────────┐ │
│ │ Middleware додаци (.so) │ │
│ │ ┌─────────┐ ┌──────────┐ ┌───────────────────┐ │ │
│ │ │ rs-eid │ │ emrtd │ │ opensc │ │ │
│ │ ├─────────┤ ├──────────┤ │ (PKI резервна) │ │ │
│ │ │ eu-vrc │ │ cardedge │ └───────────────────┘ │ │
│ │ ├─────────┤ ├──────────┤ ┌───────────────────┐ │ │
│ │ │rs-health│ │ piv │ │ pkcs15 │ │ │
│ │ └─────────┘ └──────────┘ └───────────────────┘ │ │
│ └─────────────────────────────────────────────────┘ │
│ │ │
│ │ APDU (ISO 7816-4) │
│ ▼ │
│ ┌──────────────┐ │
│ │PCSCConnection│ │
│ │ (PC/SC) │ │
│ └──────┬──────┘ │
└──────────────────────────┼─────────────────────────────┘
│
┌──────▼──────┐
│ Смарт картица│
└─────────────┘
Детекција картице: smartcard::Monitor #
Детекција картице живи у LibreMiddleware-у као smartcard::Monitor — чиста C++23 класа без зависности од Qt-а. На позадинској нити прозива PC/SC за догађаје убацивања/вађења картице и обавештава претплатнике кроз повратне позиве:
subscribe(MonitorCallback)— регистрација заMonitorEventобавештења (картица убачена/извађена, име читача, ATR)unsubscribe(id)— престанак примања догађаја
Монитор лењо покреће нит за прозивање при првој претплати и зауставља је када се последњи претплатник одјави. У LibreCelik-у, SmartCardReaderListener обавија монитор и маршалира догађаје на Qt главну нит кроз сигнале.
Middleware додаци (CardPlugin) #
Middleware додатак је дељена библиотека (.so / .dylib) коју CardPluginRegistry учитава преко dlopen у време извршавања. Сваки додатак имплементира:
canHandle(const std::vector<uint8_t>& atr)— брза провера само по ATR-у. Враћаbool— да ли овај додатак препознаје ATR? Без комуникације са картицом. Додаци такође излажуprobePriority()(int) тако да регистар може рангирати кандидате.canHandleConnection(PCSCConnection& conn)— провера на живој конекцији. Шаље SELECT команде за познате AID-ове ради потврде подршке. Позива се само на додацима који нису прошлиcanHandle()— даје им другу шансу да преузму картицу кроз живу комуникацију.readCard(PCSCConnection& conn)— екстрахује све податке са картице. Шаље APDU команде, парсира TLV/BER-TLV одговоре и враћаCardDataобјекат са типизираним групама поља (лични подаци, подаци документа, фотографије, сертификати).
Двофазна провера: Регистар прво позива canHandle(atr) на свим додацима — они који врате true иду одмах у листу кандидата, рангирани по probePriority(). Затим се canHandleConnection(conn) позива само на додацима који су вратили false у Фази 1, дајући генеричким додацима (попут OpenSC-а) шансу да преузму картицу провером живе конекције. Ово избегава непотребну комуникацију за додатке који су већ препознали картицу по ATR-у.
Streaming подршка: Додаци могу имплементирати readCardStreaming() поред readCard(). Streaming испоручује CardData инкрементално — поља се појављују у GUI-ју док се читају са картице, уместо чекања да се цело читање заврши. Ово је посебно корисно за eMRTD где се групе података читају секвенцијално кроз шифроване канале.
Ланац резервних опција: Ако readCard() најбоље рангираног додатка не успе, аутоматски се покушава следећи кандидат. OpenSC додатак служи као генеричка резервна опција за сваку картицу коју нема нативно подржану.
PKI резервна опција: Додаци за податке (еИД, саобраћајна, здравствена) читају демографске податке, али не обрађују PKI операције. Након што додатак за податке заврши, систем може покренути засебан PKI додатак (CardEdge, PKCS#15 или OpenSC) за откривање сертификата, потписивање и управљање PIN-ом. Ово раздвајање значи да додаци за податке не морају знати за PKI.
Додавање новог типа картице: Напишите класу која наслеђује CardPlugin, имплементирајте canHandle(), canHandleConnection() и readCard() (опционо readCardStreaming()), компајлирајте као дељену библиотеку и поставите је у директоријум за додатке. Регистар је аутоматски открива при следећем покретању.
GUI додаци (CardWidgetPlugin) #
GUI додатак је Qt дељена библиотека коју CardWidgetPluginRegistry учитава преко QPluginLoader. Сваки додатак имплементира:
cardType()— враћа тип картице који овај додатак може да прикаже (мора да одговара ономе што middleware додатак поставља уCardData).createWidget(const CardData&, QWidget* parent)— гради и враћа Qt виџет који приказује податке са картице. Пуна контрола над распоредом — текстуална поља, фотографије, сертификати, шта год картица садржи.
Додавање новог приказа картице: Напишите класу која наслеђује CardWidgetPlugin и Q_PLUGIN_METADATA, имплементирајте cardType() и createWidget(), компајлирајте као Qt MODULE библиотеку.
Како се повезују #
Додавање подршке за потпуно нови тип картице захтева два додатка:
- Middleware додатак — зна како да комуницира са картицом (SELECT, READ BINARY, парсирање одговора)
- GUI додатак — зна како да прикаже податке (распоред, ознаке, форматирање)
Мост између њих је CardData — мапа група поља, где свака група садржи парове кључ-вредност. Middleware додатак га попуњава, GUI додатак га чита. Ниједан не мора да зна за други. Поновна компилација основне апликације није потребна — само поставите .so датотеке.
eMRTD: Криптографски приступ картици #
eMRTD додатак демонстрира најсложенију комуникацију са картицом у систему. Е-пасоши захтевају криптографско договарање кључева пре него што се било који податак може прочитати:
- BAC (Basic Access Control) — изводи сесијске кључеве из машински читљиве зоне (MRZ) штампане на пасошу
- PACE (Password Authenticated Connection Establishment) — Diffie-Hellman договарање кључева на елиптичним кривама, модерна замена за BAC. Може захтевати од корисника унос CAN броја (Card Access Number) штампаног на пасошу.
- Secure Messaging — све наредне APDU команде и одговори су шифровани и МАЦ-овани сесијским кључевима. Имплементирано као
TransmitFilterнаPCSCConnection— једном инсталиран, шифровање је транспарентно за сав код вишег нивоа.
Библиотека emrtd-crypto имплементира ове протоколе из ICAO 9303 спецификације, док библиотека emrtd обрађује читање група података и парсирање MRZ-а. emrtd-plugin их повезује као стандардни CardPlugin са streaming подршком — групе података се читају прогресивно и испоручују GUI-ју како постану доступне. Из перспективе остатка система, то је само још један додатак који враћа CardData.
Ток података #
Комплетан ток када се смарт картица убаци:
1. Картица убачена у читач
2. smartcard::Monitor (LibreMiddleware, PC/SC нит за прозивање)
└─ SCardGetStatusChange детектује присуство картице
└─ креира MonitorEvent { CardInserted, readerName, atr }
└─ обавештава претплатнике кроз повратни позив
3. SmartCardReaderListener (LibreCelik, Qt адаптер)
└─ прима MonitorEvent на нити монитора
└─ маршалира на Qt главну нит преко QMetaObject::invokeMethod
└─ емитује сигнал са MonitorEvent
4. Главни прозор прима сигнал, покреће двофазно откривање додатака:
Фаза 1 — ATR филтрирање (без комуникације са картицом):
└─ CardPluginRegistry::findAllCandidates(atr, connection)
├─ rs-eid-plugin::canHandle(atr) → true (препознат ATR српске еИД)
├─ eu-vrc-plugin::canHandle(atr) → false
├─ emrtd-plugin::canHandle(atr) → false
└─ opensc-plugin::canHandle(atr) → false
Кандидати до сад: [rs-eid-plugin (приоритет 100)]
Фаза 2 — провера на конекцији (само додаци који су вратили false):
├─ eu-vrc-plugin::canHandleConnection(conn) → false
├─ emrtd-plugin::canHandleConnection(conn) → false
└─ opensc-plugin::canHandleConnection(conn) → true (нађен PKCS#15)
Коначни кандидати: [rs-eid-plugin (100), opensc-plugin (50)]
5. AsyncCardReader::requestData(topCandidate)
└─ std::async → позадинска нит
└─ rs-eid-plugin::readCard(connection)
├─ SELECT AID, READ BINARY лични подаци
├─ парсирање BER-TLV одговора
└─ враћа CardData { type: "rs.eid", fields: {...} }
6. Резултат маршалиран назад на Qt главну нит (QMetaObject::invokeMethod)
7. CardWidgetPluginRegistry::findByCardType("rs.eid")
└─ rseid-gui-plugin одговара
8. rseid-gui-plugin::createWidget(cardData, parent)
└─ гради виџет: фотографија, име, адреса, број документа, сертификати
9. Виџет приказан у главном прозору
Пројектни обрасци #
Strategy #
CardReaderBase дефинише интерфејс за комуникацију са одређеним чипом читача. Конкретне имплементације — CardReaderApollo (Apollo 2008 чипови) и CardReaderGemalto (Gemalto 2014+ чипови) — енкапсулирају разлике у APDU секвенцама и структурама датотека.
Async #
AsyncCardReader обавија позиве middleware додатака са std::async да би GUI остао одзиван. Резултати се маршалирају назад на Qt главну нит преко QMetaObject::invokeMethod и Qt сигнала. Подржава и batch (readCard) и streaming (readCardStreaming) режиме. У middleware слоју, AutoReader пружа удобан омотач који повезује smartcard::Monitor догађаје директно са CardPluginRegistry откривањем и читањем картице — корисно за апликације које желе аутоматско руковање картицама без ручног повезивања.
Observer #
smartcard::Monitor користи модел претплате заснован на повратним позивима у middleware слоју. У GUI слоју, SmartCardReaderListener обавија монитор и поново емитује догађаје као Qt сигнале, пропагирајући догађаје убацивања/вађења картице до главног прозора и свих регистрованих слушалаца.
Singleton #
SmartCardReaderListener::instance() пружа јединствену тачку за диспечовање догађаја картице кроз GUI апликацију.
Простори имена #
Јавни API (LibreSCRS::*) #
Јавна корисничка површина 4.0 живи испод LibreSCRS:: корена у
PascalCase именским просторима. Свако заглавље испод include/LibreSCRS/
припада овој површини; сви други простори су интерни.
| Простор имена | Опсег |
|---|---|
LibreSCRS::SmartCard | CardSession, MonitorService — PC/SC + монитор догађаја картице |
LibreSCRS::Plugin | CardPlugin, CardPluginService, CardData, ReadResult, AutoReaderService |
LibreSCRS::Auth | CredentialProvider, AuthRequirement, CredentialResult, FieldDescriptor |
LibreSCRS::Certificate | Парсирање и метаподаци X.509 сертификата |
LibreSCRS::Trust | TrustStoreService, TrustStore, TrustConfig |
LibreSCRS::Signing | SigningService, SigningRequest, SigningResult, VisualSignatureLayout |
LibreSCRS::Secure | Secure::Buffer, Secure::String (нулирање при уништавању) |
LibreSCRS (корен) | CancelToken, LocalizedText, SyncProvider |
Интерни простори имена (подложни промени) #
Простори имена малим словима испод живе у lib/<библиотека>/ и подржавају
јавни API. Нису део подржане корисничке површине — имена и потписи могу
да се мењају између издања.
| Простор имена | Опсег |
|---|---|
smartcard:: | Интерни APDU / TLV / BER-TLV / PCSCConnection помоћници |
plugin:: | Интерни помоћници за учитавање додатака и регистар |
eidcard:: | Интерни типови за српску еИД картицу |
euvrc:: | Интерни типови за ЕУ саобраћајну дозволу |
healthcard:: | Интерни типови за здравствену картицу |
cardedge:: | Интерни типови CardEdge PKI аплета |
emrtd:: | eMRTD интерне структуре података и парсирање MRZ-а |
emrtd::crypto | eMRTD криптографија — BAC, PACE, Secure Messaging |
piv:: | PIV интерни типови |
pkcs15:: | PKCS#15 интерни типови парсера |
libresign:: | Унутрашњи engine за потписивање (PAdES / XAdES / JAdES / CAdES / ASiC-E) |
Стандарди #
Следећи стандарди су релевантни за базу кода:
| Стандард | Примена |
|---|---|
| ISO 7816-4 | Комуникација са смарт картицом — структура APDU команде/одговора, TLV и BER-TLV кодирање |
| PC/SC | Слој за приступ читачу — детекција картице, управљање конекцијом, контрола трансакција |
| PKCS#11 | Интерфејс криптографског токена — аутентификација у прегледачу, дигитални потписи |
| PKCS#15 | Апликација криптографских информација — откривање сертификата и кључева на смарт картицама |
| ICAO 9303 | eMRTD (е-пасоши) — BAC и PACE договарање кључева, Secure Messaging, структура група података |
| NIST SP 800-73 | PIV интерфејс картице — откривање сертификата, аутентификација, дигитално потписивање |
| BSI TR-03110 | PACE протокол — договарање кључева аутентификованих лозинком за eMRTD |