grakic / jfreesteel

A native Java library, a Swing GUI application and an applet to read the Serbian eID card, built on javax.smartcardio
http://jfreesteel.devbase.net
53 stars 24 forks source link

ERROR net.devbase.jfreesteel.EidCard - Card error #8

Open nikola-lukic opened 7 years ago

nikola-lukic commented 7 years ago

Prilikom čitanja "novih" kartica dolazilo je do sledeće greške (sama aplikacija je u GUI izbacivala null):

[Thread-1] ERROR net.devbase.jfreesteel.EidCard - Card error
java.nio.BufferUnderflowException
    at java.nio.HeapByteBuffer.get(HeapByteBuffer.java:151)
    at java.nio.ByteBuffer.get(ByteBuffer.java:715)
    at net.devbase.jfreesteel.EidCard.parseTlv(EidCard.java:143)
    at net.devbase.jfreesteel.EidCard.readEidInfo(EidCard.java:297)
    at net.devbase.jfreesteel.viewer.EidViewer.inserted(EidViewer.java:265)
    at net.devbase.jfreesteel.Reader.notifyCardListener(Reader.java:210)
    at net.devbase.jfreesteel.Reader.access$500(Reader.java:45)
    at net.devbase.jfreesteel.Reader$1.notifyListeners(Reader.java:176)
    at net.devbase.jfreesteel.Reader$1.run(Reader.java:156)
    at java.lang.Thread.run(Thread.java:748)

Problem je u okviru klase EidCard (package net.devbase.jfreesteel) u izvršavanju metode public static Map<Integer, byte[]> parseTlv(final byte[] bytes). Prilikom čitanja "novih" kartice dolazilo je do toga da pokuša da pročita više podataka nego što u bufferu postoji. Moram prizanti da ne poznajem strukturu iščitavanja, ali sam code pomenute metode malo promenio i iščitavanje je bilo uspešno i sa "novim" karticama. Ovo je izgled promenjene metode:

public static Map<Integer, byte[]> parseTlv(final byte[] bytes) {
        HashMap<Integer, byte[]> out = new HashMap<Integer, byte[]>();

        // [fld 16bit LE] [len 16bit LE] [len bytes of data] | [fld] [06] ...

        ByteBuffer buffer = ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN);

        // repeat as long as we have next tag and len...
        while (buffer.remaining() > 4) {
            char tag = buffer.getChar();
            char length = buffer.getChar();
            //pocetak izmenjenog dela u odnosu na originalni kod
            byte[] range;
            if (buffer.remaining()>(int)length){
                range = new byte[(int) length];
            } else {
                range = new byte[buffer.remaining()];
            }
            //kraj izmenjenog dela u odnosu na originalni kod
            buffer.get(range);
            out.put((int) tag, range);
        }

        return out;
    }

Možda nije najsrećnije rešenje ali je odradilo posao :)

Inače, u jednom trenutku prilikom čitanja u length se upisuje vrednost veća od 1000, a ukupna veličina bafera je reda 250 (u tom trenutku je preostalo negde oko 130 byte-ova za čitanje).

Napomena: Ovo sam probao sa jednom "starom" ličnom karticom i dve "nove".

Nisam neki guru u programiranju, poznajem osnove, te smatram da ćeš možda dati neko drugo rešenje, a nadam se da će uskoro nova verzija (*.deb bar) sa sređenim bug-om.

Svako dobro!!!

grakic commented 7 years ago

Hvala na prijavi greške.

Možeš li mi se javiti mejlom na grakic@devbase.net kako bih pribavio "data dump" sa te problematične (tih problematičnih?) kartica?

Polje length čita dva bajta tako da vrednost 1000 jeste moguća, međutim ako je tek 130b preostalo za parsiranje to bi značilo da ili nemamo tačan ceo sadržaj pročitan sa kartice (možda imamo neke bajtove viška?) ili da je parsiranje već omanulo negde ranije pa sadržaj taga čitamo kao novi tag.