JMRTD Nedir? e-Pasaport Okuma ve NFC Tabanlı Kimlik Doğrulama İçin Teknik Bir Giriş
Elektronik pasaportlar ve ICAO 9303 uyumlu seyahat belgeleri, klasik görsel veri alanlarının ötesinde, temassız çip içinde saklanan güvenli biyografik ve biyometrik veriler taşır. Bu verilere erişmek için sadece NFC okuyucu kullanmak yetmez; aynı zamanda BAC, PACE, Chip Authentication ve Passive Authentication gibi protokollerin doğru uygulanması gerekir. İşte tam bu noktada JMRTD, yani Java Machine Readable Travel Documents kütüphanesi devreye girer. JMRTD, eMRTD belgeleriyle haberleşmek, LDS veri gruplarını okumak ve güvenlik adımlarını yürütmek için kullanılan Java tabanlı bir kütüphanedir.
Java tabanlı eMRTD projeleri için teknik bir giriş: BAC, PACE, LDS, DG1, DG2, SOD ve pratik entegrasyon yaklaşımı.
Teknik blog yazısı Java / NFC / ICAO 9303 Kod örnekliElektronik pasaportlar ve ICAO 9303 uyumlu seyahat belgeleri, temassız çip içinde güvenli biçimde saklanan biyografik ve biyometrik veriler taşır. Bu verilere erişmek için sadece NFC okuyucu kullanmak yetmez; aynı zamanda BAC, PACE, Passive Authentication ve bazen Chip Authentication gibi güvenlik adımlarını da doğru yönetmek gerekir. JMRTD, bu süreci Java ekosisteminde standartlara daha yakın şekilde ele almak için kullanılan en bilinen kütüphanelerden biridir.
1. JMRTD’nin Temel Amacı
JMRTD, ICAO uyumlu elektronik pasaportlar ve diğer machine readable travel document türleriyle haberleşmek için tasarlanmış bir Java kütüphanesidir. Kütüphane; akıllı kart bağlantısı, erişim anahtarı üretimi, güvenli kanal kurulması ve LDS veri gruplarının okunması gibi işlemleri kolaylaştırır. Kurumsal projelerde bu yapı özellikle eKYC, sınır kontrol, kiosk check-in, otel kayıt ve kimlik doğrulama senaryolarında öne çıkar.
Görsel 1 — Basit mimari görünüm: okuyucu, JMRTD servis katmanı ve e-pasaport çipi arasındaki akış.2. Genel Mimari: Smart Card Katmanı, PassportService ve LDS
Tipik bir JMRTD uygulamasında üç katman vardır: kart okuyucuya erişen javax.smartcardio katmanı, APDU haberleşmesini yöneten servis katmanı ve çip içindeki dosyaları temsil eden LDS nesneleri.
Akış genelde şu şekilde ilerler: önce terminal bulunur, sonra karta bağlanılır, ardından MRZ’den türetilen erişim bilgisi ile BAC veya PACE başlatılır. Güvenli kanal kurulduktan sonra DG1, DG2 ve SOD gibi dosyalar okunur.
import java.util.List;
import javax.smartcardio.*;
public class ReaderListExample {
public static void main(String[] args) throws Exception {
TerminalFactory factory = TerminalFactory.getDefault();
CardTerminals terminals = factory.terminals();
List<CardTerminal> terminalList = terminals.list();
for (CardTerminal terminal : terminalList) {
System.out.println("Terminal: " + terminal.getName());
}
}
}
Bu örnek yalnızca kart terminallerini listeler. Gerçek projede bunun devamında kartla oturum açılır ve JMRTD üzerinden güvenli erişim akışı başlatılır.
3. MRZ Bilgisinden BAC Anahtarı Türetme
Birçok belgede ilk erişim katmanı Basic Access Control (BAC) olur. BAC için gerekli anahtarlar, pasaportun MRZ alanındaki belge numarası, doğum tarihi ve son geçerlilik tarihi üzerinden türetilir.
Bu nedenle optik MRZ okumasının doğruluğu kritik önemdedir. Özellikle O/0, I/1 ve < gibi karakter karışıklıkları BAC hatalarının en yaygın nedenlerindendir.
import org.jmrtd.BACKey;
public class BacKeyExample {
public static void main(String[] args) {
String documentNumber = "U12345678";
String dateOfBirth = "900101"; // YYMMDD
String dateOfExpiry = "300101"; // YYMMDD
BACKey bacKey = new BACKey(documentNumber, dateOfBirth, dateOfExpiry);
System.out.println("BAC key objesi hazır: " + bacKey);
}
}
Üretim ortamında MRZ tarafında check digit doğrulaması, karakter normalizasyonu ve eksik karakter telafisi gibi ek kontroller uygulanmalıdır. Aksi halde NFC tarafı hatalı görünse bile sorun aslında optik taraftaki veri kirliliğinden kaynaklanabilir.
4. PassportService ile Güvenli Erişim ve DG1 Okuma
JMRTD’nin merkezindeki ana bileşenlerden biri PassportService sınıfıdır. Bu servis, karta APDU gönderimini ve BAC/PACE sonrası veri gruplarının okunmasını yönetir.
Güvenli oturum açıldıktan sonra ilk okunan dosya çoğu zaman DG1 olur; çünkü DG1, MRZ’den türeyen kimlik bilgisini içerir.
import javax.smartcardio.*;
import net.sf.scuba.smartcards.CardService;
import org.jmrtd.PassportService;
import org.jmrtd.BACKey;
import org.jmrtd.lds.icao.DG1File;
import java.io.InputStream;
public class ReadDG1Example {
public static void main(String[] args) throws Exception {
CardTerminal terminal = TerminalFactory.getDefault()
.terminals()
.list()
.get(0);
Card card = terminal.connect("*");
CardService cardService = CardService.getInstance(card);
cardService.open();
PassportService passportService = new PassportService(
cardService,
PassportService.NORMAL_MAX_TRANCEIVE_LENGTH,
PassportService.DEFAULT_MAX_BLOCKSIZE,
true,
false
);
passportService.open();
BACKey bacKey = new BACKey("U12345678", "900101", "300101");
passportService.doBAC(bacKey);
InputStream dg1In = passportService.getInputStream(PassportService.EF_DG1);
DG1File dg1File = new DG1File(dg1In);
System.out.println("MRZ Bilgisi: " + dg1File.getMRZInfo().toString());
dg1In.close();
passportService.close();
cardService.close();
}
}
Buradaki önemli nokta, her belgenin sadece BAC ile ilerlemeyebilmesidir. Daha yeni belgelerde PACE zorunlu olabilir. Bu yüzden üretim kodunda belge yeteneklerine göre dinamik protokol seçimi yapmak daha doğru olur.
5. DG1 ve DG2: Metinsel Veri ile Biyometrik Görüntünün Ayrımı
DG1, ad, soyad, belge numarası, vatandaşlık ve doğum tarihi gibi metinsel bilgileri taşır. DG2 ise çoğu zaman yüz biyometrisini içerir. DG2 içindeki yüz görseli, doğrulama sistemlerinde canlı yüz veya kayıtlı biyometrik veri ile karşılaştırmak için kullanılır. Bu nedenle DG1 ve DG2 çoğunlukla birlikte değerlendirilir.
Görsel 2 — DG1 çoğunlukla metinsel ve MRZ türevli kimlik bilgisini taşır. Görsel 3 — DG2 çoğunlukla yüz biyometrisini içerir.import org.jmrtd.lds.icao.DG2File;
import org.jmrtd.lds.iso19794.FaceImageInfo;
import org.jmrtd.lds.iso19794.FaceInfo;
import java.io.InputStream;
import java.util.List;
public class ReadDG2Example {
public static void main(String[] args) throws Exception {
PassportService passportService = null; // örnek amaçlı
InputStream dg2In = passportService.getInputStream(PassportService.EF_DG2);
DG2File dg2File = new DG2File(dg2In);
List<FaceInfo> faceInfos = dg2File.getFaceInfos();
for (FaceInfo faceInfo : faceInfos) {
for (FaceImageInfo imageInfo : faceInfo.getFaceImageInfos()) {
byte[] imageBytes = imageInfo.getImageBytes();
System.out.println("Yüz görüntüsü boyutu: " + imageBytes.length);
}
}
dg2In.close();
}
}
Burada dönen görüntü verisinin formatı belgeye göre değişebilir. Bazı belgelerde standart JPEG görülürken bazılarında JPEG2000 gibi ek codec ihtiyacı doğabilir.
6. Passive Authentication ve SOD Doğrulaması
Veriyi okuyabilmek tek başına yeterli değildir. Okunan verinin gerçekten belge üreticisi tarafından imzalanmış olup olmadığını ve sonradan değiştirilmediğini de doğrulamak gerekir. Bunun için Passive Authentication uygulanır. Bu süreçte SOD dosyası okunur, veri gruplarının hash değerleri kontrol edilir ve mümkünse sertifika zinciri doğrulanır.
Görsel 4 — Passive Authentication akışı: veri grupları, hash üretimi, SOD karşılaştırması ve doğrulama.Pratikte en zor alanlardan biri sertifika güven zincirinin yönetimidir. Sadece imzayı doğrulamak değil, o imzayı atan belgenin gerçekten güvenilen bir CSCA zincirinden gelip gelmediğini kontrol etmek de gerekir.
7. PACE Neden BAC’tan Daha Güçlü?
Daha yeni nesil belgelerde PACE, BAC’a göre daha modern ve daha güvenli bir erişim modeli sunar. Temel fark, oturum kurulumu sırasında kullanılan yöntemlerin brute-force ve pasif dinleme gibi saldırılara karşı daha dayanıklı olmasıdır. Bu nedenle modern uygulamalarda belge destekliyorsa önce PACE denenmesi, başarısız olursa BAC fallback uygulanması daha doğru bir tasarım yaklaşımıdır.
Sağlam bir uygulama, kartın CardAccess içeriğini okuyarak hangi protokolün desteklendiğini belirler ve erişim stratejisini buna göre seçer.
Protokolü sabit kodlamak, farklı ülke pasaportlarında veya farklı nesil belgelerde uyumsuzluğa yol açabilir.
8. Gerçek Hayatta Karşılaşılan Sorunlar
JMRTD teoride güçlüdür, ancak üretim senaryolarında çeşitli pratik zorluklar çıkar. İlk sorun okuyucu donanımı ve sürücü uyumluluğudur. Bazı PC/SC okuyucular uzun APDU bloklarında kararsız davranabilir. İkinci sorun MRZ kalitesidir; optik hata yüzünden BAC/PACE erişimi başarısız olabilir. Üçüncü olarak DG2 görüntü formatı veya SOD sertifika zinciri doğrulaması gibi ek bağımlılıklar devreye girer.
Bu yüzden iyi tasarlanmış bir sistemde MRZ okuma, NFC erişimi, biyometrik dosya parse işlemleri ve doğrulama katmanı birbirinden ayrılmalıdır. Hata log’ları da “NFC çalışmadı” gibi genel ifadeler yerine “BAC key mismatch”, “PACE unsupported”, “DG2 decode failed” veya “SOD hash mismatch” gibi net sınıflandırmalarla tutulmalıdır.
9. Sonuç
JMRTD, ICAO 9303 uyumlu elektronik seyahat belgeleriyle çalışan Java projeleri için güçlü bir temel sunar. Smart card erişimi, BAC/PACE, LDS veri okuma ve güvenlik doğrulaması gibi bileşenleri aynı ekosistemde toplayabildiği için özellikle eKYC, kiosk, sınır kontrol ve güvenli kimlik doğrulama çözümlerinde ciddi avantaj sağlar.
Ancak başarılı bir entegrasyon için sadece kütüphaneyi projeye eklemek yetmez. MRZ doğruluğu, okuyucu stabilitesi, sertifika zinciri doğrulaması, biyometrik veri işleme ve detaylı hata yönetimi birlikte düşünülmelidir. Doğru tasarımla kullanıldığında JMRTD, e-pasaport ve NFC tabanlı kimlik doğrulama projelerinde son derece sağlam bir omurga oluşturur.
Hazırlanan dosya: JMRTD teknik blog yazısı — HTML formatı, örnek kodlar ve çizim temelli görseller dahil.Bu yazı hakkında ne düşünüyorsun?
Beğendim, beğenmedim veya nötr seçeneklerinden birini işaretleyebilirsin.