refactor: own CredentialStore from PersonalizationApplet instance
Prepares for AMD-H by moving the singleton's anchor off a static field onto the PersonalizationApplet instance. The static INSTANCE remains solely as an in-package publish-point so AliroApplet/StepUpApplet keep working unchanged. Adds CredentialStore.bootstrap() (called from PersonalizationApplet's constructor) and CredentialStore.republish() (reserved for the upcoming onRestore hook). Drops the lazy-init path in get() — every install path now goes through PersonalizationApplet first, so INSTANCE is always set by the time AliroApplet looks it up. Test setUps that previously called CredentialStore.get().resetForTesting() before the applet was installed are reordered or dropped: each test now gets a fresh store via the constructor's bootstrap() call. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -30,7 +30,9 @@ class AliroAppletAuth1Test {
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
CredentialStore.get().resetForTesting();
|
||||
// reader.provision() below installs PersonalizationApplet, whose
|
||||
// constructor calls CredentialStore.bootstrap() and gives us a fresh
|
||||
// store for every test — no explicit reset needed any more.
|
||||
sim = new CardSimulator();
|
||||
AID expeditedAid = new AID(AliroAids.EXPEDITED, (short) 0, (byte) AliroAids.EXPEDITED.length);
|
||||
sim.installApplet(expeditedAid, AliroApplet.class);
|
||||
|
||||
@@ -2,12 +2,15 @@ package com.dangerousthings.aliro;
|
||||
|
||||
import com.licel.jcardsim.smartcardio.CardSimulator;
|
||||
import javacard.framework.AID;
|
||||
import javacard.framework.Applet;
|
||||
import javax.smartcardio.CommandAPDU;
|
||||
import javax.smartcardio.ResponseAPDU;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertSame;
|
||||
|
||||
/**
|
||||
* Tests for the PersonalizationApplet — our proprietary provisioning
|
||||
@@ -28,8 +31,8 @@ class PersonalizationAppletTest {
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
CredentialStore.get().resetForTesting();
|
||||
|
||||
// installApplet → PersonalizationApplet.<init> → CredentialStore.bootstrap()
|
||||
// gives us a fresh store for every test — no explicit reset needed any more.
|
||||
sim = new CardSimulator();
|
||||
AID aid = new AID(AliroAids.PROVISIONING, (short) 0, (byte) AliroAids.PROVISIONING.length);
|
||||
sim.installApplet(aid, PersonalizationApplet.class);
|
||||
@@ -162,4 +165,39 @@ class PersonalizationAppletTest {
|
||||
assertEquals(0x6985, send(INS_COMMIT, null).getSW(),
|
||||
"a second COMMIT must also be refused");
|
||||
}
|
||||
|
||||
@Test
|
||||
void personalizationAppletOwnsCredentialStoreInstance() throws Exception {
|
||||
// setUp() has already installed PersonalizationApplet via jcardsim.
|
||||
// Reach into the runtime and pull out the installed applet instance,
|
||||
// then assert it owns a non-null `store` instance field and that the
|
||||
// static publish-point in CredentialStore aliases the same object.
|
||||
Applet applet = getInstalledApplet(sim, AliroAids.PROVISIONING);
|
||||
org.junit.jupiter.api.Assertions.assertTrue(applet instanceof PersonalizationApplet,
|
||||
"installed applet at PROVISIONING AID must be a PersonalizationApplet");
|
||||
|
||||
java.lang.reflect.Field storeField = PersonalizationApplet.class.getDeclaredField("store");
|
||||
storeField.setAccessible(true);
|
||||
Object instanceStore = storeField.get(applet);
|
||||
assertNotNull(instanceStore,
|
||||
"PersonalizationApplet must own a CredentialStore instance field");
|
||||
assertSame(instanceStore, CredentialStore.get(),
|
||||
"Static publish-point must alias the instance-owned store");
|
||||
}
|
||||
|
||||
/** Reaches through jcardsim's protected runtime/applet APIs to fetch the
|
||||
* installed Applet instance for a given AID. Reflection-only — this is
|
||||
* test infrastructure, not production code. */
|
||||
private static Applet getInstalledApplet(CardSimulator sim, byte[] aidBytes) throws Exception {
|
||||
java.lang.reflect.Field runtimeField = null;
|
||||
for (Class<?> c = sim.getClass(); c != null && runtimeField == null; c = c.getSuperclass()) {
|
||||
try { runtimeField = c.getDeclaredField("runtime"); } catch (NoSuchFieldException ignore) {}
|
||||
}
|
||||
runtimeField.setAccessible(true);
|
||||
Object runtime = runtimeField.get(sim);
|
||||
java.lang.reflect.Method getApplet = runtime.getClass().getDeclaredMethod("getApplet", AID.class);
|
||||
getApplet.setAccessible(true);
|
||||
AID aid = new AID(aidBytes, (short) 0, (byte) aidBytes.length);
|
||||
return (Applet) getApplet.invoke(runtime, aid);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,9 @@ class StepUpAppletTest {
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
CredentialStore.get().resetForTesting();
|
||||
// StepUpApplet doesn't touch CredentialStore yet; no need to reset
|
||||
// it here. Once StepUpApplet starts reading credentials, this test
|
||||
// will need to install PersonalizationApplet first.
|
||||
sim = new CardSimulator();
|
||||
AID aid = new AID(AliroAids.STEP_UP, (short) 0, (byte) AliroAids.STEP_UP.length);
|
||||
sim.installApplet(aid, StepUpApplet.class);
|
||||
|
||||
Reference in New Issue
Block a user