I'm encountering a critical issue after migrating my legacy Java Swing smart card encoding application (which uses JMRTD and SCUBA) to a modern JavaFX/Maven-based application.
Background
My legacy app (Java 1.8, Swing, JMRTD + Scuba, JCOP card with PassportApplet) works perfectly: BAC and LDS file upload (DG1, DG2, SOD) succeed without errors.
In my new JavaFX/Maven application (Java 21, Swing, JMRTD 0.8.1 + Scuba 0.20.0, using the same card, applet, and BACKey generation), the same upload logic consistently fails during BAC with the error:
org.jmrtd.CardServiceProtocolException: BAC failed in GET CHALLENGE (SW = 0x6982: SECURITY STATUS NOT SATISFIED)
What I Have Checked
* AID SELECT always returns 9000 (success).
*
* BACKey values are identical (docNumber, dateOfBirth, dateOfExpiry — confirmed in logs).
*
* Applet and smart card are identical to those used with the legacy app.
*
* No difference in MRZ format or BACKey construction.
LDS files (DG1, DG2, SOD) are correctly generated, match the old structure.
I have tried reusing the exact same CardManager, CardService, and PassportPersoService upload code from the legacy app in the new app.
I have verified that polling is stopped and started exactly as in the old working code.
Additional Notes
If I run my original Swing-based legacy app, encoding/upload works on the same card immediately after a failed attempt in the new JavaFX app (no card reset/reformat needed).
The BAC failure (6982) occurs before any file writes — at the initial BAC authentication step.
I do not re-install or delete the applet before each encode.
**Logs **
2025-07-28 13:33:49 [JavaFX Application Thread] INFO InfoLog - ✅ Applet installation completed successfully.
2025-07-28 13:33:49 [JavaFX Application Thread] INFO org.cdac.in.services.SmartCardUploadService - ✅ Card connected: ATR = [59, -120, -128, 1, 74, 67, 79, 80, 118, 50, 52, 49, 94]
2025-07-28 13:33:49 [JavaFX Application Thread] INFO org.cdac.in.services.SmartCardUploadService - 🧪 SELECT AID SW=9000
2025-07-28 13:33:49 [JavaFX Application Thread] INFO org.cdac.in.services.SmartCardUploadService - ✅ Passport applet selected.
2025-07-28 13:33:49 [JavaFX Application Thread] INFO org.cdac.in.services.SmartCardUploadService - BAC keys: doc=M35056062, dob=060725, doe=341219
2025-07-28 13:33:49 [JavaFX Application Thread] ERROR org.cdac.in.services.SmartCardUploadService - ❌ Upload failed
org.jmrtd.CardServiceProtocolException: BAC failed in GET CHALLENGE (SW = 0x6982: SECURITY STATUS NOT SATISFIED) (step: 1)
at org.jmrtd.protocol.BACProtocol.doBACStep(BACProtocol.java:132) ~[classes/:?]
at org.jmrtd.protocol.BACProtocol.doBAC(BACProtocol.java:91) ~[classes/:?]
at org.jmrtd.PassportService.doBAC(PassportService.java:393) ~[classes/:?]
at org.cdac.in.services.SmartCardUploadService.uploadLDSData(SmartCardUploadService.java:94) ~[classes/:?]
at org.cdac.in.controllers.MainController.handleEncoding(MainController.java:350) ~[classes/:?]
at jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) ~[?:?]
at java.lang.reflect.Method.invoke(Method.java:580) ~[?:?]
at com.sun.javafx.reflect.Trampoline.invoke(MethodUtil.java:72) ~[javafx.base.jar:?]
at jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) ~[?:?]
at java.lang.reflect.Method.invoke(Method.java:580) ~[?:?]
at com.sun.javafx.reflect.MethodUtil.invoke(MethodUtil.java:270) ~[javafx.base.jar:?]
at com.sun.javafx.fxml.MethodHelper.invoke(MethodHelper.java:84) ~[javafx.fxml.jar:?]
at javafx.fxml.FXMLLoader$MethodHandler.invoke(FXMLLoader.java:1855) ~[javafx.fxml.jar:?]
at javafx.fxml.FXMLLoader$ControllerMethodEventHandler.handle(FXMLLoader.java:1726) ~[javafx.fxml.jar:?]
at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:86) ~[javafx.base.jar:?]
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:232) ~[javafx.base.jar:?]
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:189) ~[javafx.base.jar:?]
at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59) ~[javafx.base.jar:?]
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58) ~[javafx.base.jar:?]
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114) ~[javafx.base.jar:?]
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56) ~[javafx.base.jar:?]
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114) ~[javafx.base.jar:?]
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56) ~[javafx.base.jar:?]
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114) ~[javafx.base.jar:?]
at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74) ~[javafx.base.jar:?]
at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:49) ~[javafx.base.jar:?]
at javafx.event.Event.fireEvent(Event.java:198) ~[javafx.base.jar:?]
at javafx.scene.Node.fireEvent(Node.java:8875) ~[javafx.graphics.jar:?]
at javafx.scene.control.Button.fire(Button.java:203) ~[javafx.controls.jar:?]
at com.sun.javafx.scene.control.behavior.ButtonBehavior.mouseReleased(ButtonBehavior.java:207) ~[javafx.controls.jar:?]
at com.sun.javafx.scene.control.inputmap.InputMap.handle(InputMap.java:274) ~[javafx.controls.jar:?]
at com.sun.javafx.event.CompositeEventHandler$NormalEventHandlerRecord.handleBubblingEvent(CompositeEventHandler.java:247) ~[javafx.base.jar:?]
at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:80) ~[javafx.base.jar:?]
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:232) ~[javafx.base.jar:?]
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:189) ~[javafx.base.jar:?]
at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59) ~[javafx.base.jar:?]
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58) ~[javafx.base.jar:?]
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114) ~[javafx.base.jar:?]
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56) ~[javafx.base.jar:?]
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114) ~[javafx.base.jar:?]
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56) ~[javafx.base.jar:?]
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114) ~[javafx.base.jar:?]
at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74) ~[javafx.base.jar:?]
at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:54) ~[javafx.base.jar:?]
at javafx.event.Event.fireEvent(Event.java:198) ~[javafx.base.jar:?]
at javafx.scene.Scene$MouseHandler.process(Scene.java:3984) ~[javafx.graphics.jar:?]
at javafx.scene.Scene.processMouseEvent(Scene.java:1890) ~[javafx.graphics.jar:?]
at javafx.scene.Scene$ScenePeerListener.mouseEvent(Scene.java:2708) ~[javafx.graphics.jar:?]
at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:411) ~[javafx.graphics.jar:?]
at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:301) ~[javafx.graphics.jar:?]
at java.security.AccessController.doPrivileged(AccessController.java:400) ~[?:?]
at com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleMouseEvent$2(GlassViewEventHandler.java:450) ~[javafx.graphics.jar:?]
at com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:424) ~[javafx.graphics.jar:?]
at com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(GlassViewEventHandler.java:449) ~[javafx.graphics.jar:?]
at com.sun.glass.ui.View.handleMouseEvent(View.java:551) ~[javafx.graphics.jar:?]
at com.sun.glass.ui.View.notifyMouse(View.java:937) ~[javafx.graphics.jar:?]
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method) ~[javafx.graphics.jar:?]
at com.sun.glass.ui.win.WinApplication.lambda$runLoop$3(WinApplication.java:185) ~[javafx.graphics.jar:?]
at java.lang.Thread.run(Thread.java:1575) ~[?:?]
Caused by: net.sf.scuba.smartcards.CardServiceException: Get challenge failed (SW = 0x6982: SECURITY STATUS NOT SATISFIED)
at org.jmrtd.protocol.BACAPDUSender.sendGetChallenge(BACAPDUSender.java:88) ~[classes/:?]
at org.jmrtd.protocol.BACAPDUSender.sendGetChallenge(BACAPDUSender.java:71) ~[classes/:?]
at org.jmrtd.protocol.BACProtocol.doBACStep(BACProtocol.java:130) ~[classes/:?]
... 58 more
2025-07-28 13:33:49 [JavaFX Application Thread] INFO org.cdac.in.services.SmartCardUploadService - 🔌 Smart card disconnected.
My Key Question
1. What could cause JMRTD’s BAC logic to succeed in a legacy (Swing, old Java) application but always fail with 6982 SECURITY STATUS NOT SATISFIED when run in a JavaFX/Maven (new Java) environment, despite using identical code, card, and applet?
2. Is there any known session/polling/state handling difference between old and new Java environments that would affect Scuba/JMRTD's CardService or BAC flows?
Request
Any insight, known incompatibilities, or debugging suggestions for diagnosing this kind of BAC authentication difference between environments?
If you require any logs, code samples, or card ATRs, please let me know.
Thank you for maintaining JMRTD and supporting the open ePassport ecosystem!
Anonymous