feat(applet): accessDocumentVerified flag in CredentialStore (M2A.1)
Persistent boolean flag for the cached IssuerAuth verify result. Field sits beside accessDocumentFinalized in writeTo/readFrom (FIELD_VERSION bumped 1->2 -- schema change requires re-personalize). reset() clears. Test pins the serialize/deserialize round-trip via the existing RecordingSink/ReplaySource helpers. Foundation for M2A.2 (CoseVerifier) and M2A.3 (verify-at-finalize wiring).
This commit is contained in:
@@ -36,7 +36,7 @@ final class CredentialStore {
|
|||||||
/** Stable field order for AMD-H Element serialization. Append-only —
|
/** Stable field order for AMD-H Element serialization. Append-only —
|
||||||
* never reorder or remove without bumping the package version and
|
* never reorder or remove without bumping the package version and
|
||||||
* writing an explicit migration step in the new ELF's onRestore. */
|
* writing an explicit migration step in the new ELF's onRestore. */
|
||||||
static final byte FIELD_VERSION = 1;
|
static final byte FIELD_VERSION = 2;
|
||||||
|
|
||||||
/** Publish-point read by AliroApplet/StepUpApplet via {@link #get()}.
|
/** Publish-point read by AliroApplet/StepUpApplet via {@link #get()}.
|
||||||
* PersonalizationApplet owns the actual instance; this is just an alias
|
* PersonalizationApplet owns the actual instance; this is just an alias
|
||||||
@@ -57,6 +57,7 @@ final class CredentialStore {
|
|||||||
private final byte[] accessDocument;
|
private final byte[] accessDocument;
|
||||||
private short accessDocumentLen;
|
private short accessDocumentLen;
|
||||||
private boolean accessDocumentFinalized;
|
private boolean accessDocumentFinalized;
|
||||||
|
private boolean accessDocumentVerified;
|
||||||
|
|
||||||
private boolean committed;
|
private boolean committed;
|
||||||
|
|
||||||
@@ -202,6 +203,14 @@ final class CredentialStore {
|
|||||||
return accessDocumentFinalized;
|
return accessDocumentFinalized;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void markAccessDocumentVerified() {
|
||||||
|
accessDocumentVerified = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isAccessDocumentVerified() {
|
||||||
|
return accessDocumentVerified;
|
||||||
|
}
|
||||||
|
|
||||||
short getAccessDocumentLen() {
|
short getAccessDocumentLen() {
|
||||||
return accessDocumentLen;
|
return accessDocumentLen;
|
||||||
}
|
}
|
||||||
@@ -223,6 +232,7 @@ final class CredentialStore {
|
|||||||
sink.write(credentialPubKeySet);
|
sink.write(credentialPubKeySet);
|
||||||
sink.write(readerPubKeySet);
|
sink.write(readerPubKeySet);
|
||||||
sink.write(accessDocumentFinalized);
|
sink.write(accessDocumentFinalized);
|
||||||
|
sink.write(accessDocumentVerified);
|
||||||
sink.write(accessDocumentLen);
|
sink.write(accessDocumentLen);
|
||||||
sink.write(credentialPrivKey);
|
sink.write(credentialPrivKey);
|
||||||
sink.write(credentialPubKey);
|
sink.write(credentialPubKey);
|
||||||
@@ -246,6 +256,7 @@ final class CredentialStore {
|
|||||||
s.credentialPubKeySet = src.readBoolean();
|
s.credentialPubKeySet = src.readBoolean();
|
||||||
s.readerPubKeySet = src.readBoolean();
|
s.readerPubKeySet = src.readBoolean();
|
||||||
s.accessDocumentFinalized = src.readBoolean();
|
s.accessDocumentFinalized = src.readBoolean();
|
||||||
|
s.accessDocumentVerified = src.readBoolean();
|
||||||
s.accessDocumentLen = src.readShort();
|
s.accessDocumentLen = src.readShort();
|
||||||
byte[] a;
|
byte[] a;
|
||||||
a = src.readByteArray();
|
a = src.readByteArray();
|
||||||
@@ -307,6 +318,7 @@ final class CredentialStore {
|
|||||||
readerPubKeySet = false;
|
readerPubKeySet = false;
|
||||||
accessDocumentLen = 0;
|
accessDocumentLen = 0;
|
||||||
accessDocumentFinalized = false;
|
accessDocumentFinalized = false;
|
||||||
|
accessDocumentVerified = false;
|
||||||
committed = false;
|
committed = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -81,6 +81,20 @@ class CredentialStoreSerializationTest {
|
|||||||
assertFalse(restored.hasAccessDocument());
|
assertFalse(restored.hasAccessDocument());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void accessDocumentVerifiedRoundTripsThroughSerialize() {
|
||||||
|
CredentialStore s1 = CredentialStore.bootstrap();
|
||||||
|
s1.resetForTesting();
|
||||||
|
s1.markAccessDocumentVerified();
|
||||||
|
|
||||||
|
RecordingSink buf = new RecordingSink();
|
||||||
|
s1.writeTo(buf);
|
||||||
|
CredentialStore s2 = CredentialStore.readFrom(buf.toSource());
|
||||||
|
|
||||||
|
assertTrue(s2.isAccessDocumentVerified(),
|
||||||
|
"verified flag must survive serialize/deserialize round-trip");
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Forges a payload with a bogus FIELD_VERSION byte and asserts that
|
* Forges a payload with a bogus FIELD_VERSION byte and asserts that
|
||||||
* {@link CredentialStore#readFrom} rejects it with
|
* {@link CredentialStore#readFrom} rejects it with
|
||||||
@@ -91,7 +105,7 @@ class CredentialStoreSerializationTest {
|
|||||||
@Test
|
@Test
|
||||||
void readFromRejectsWrongFieldVersion() {
|
void readFromRejectsWrongFieldVersion() {
|
||||||
RecordingSink buf = new RecordingSink();
|
RecordingSink buf = new RecordingSink();
|
||||||
buf.write((byte) 0x7F); // != FIELD_VERSION (== 1)
|
buf.write((byte) 0x7F); // != FIELD_VERSION
|
||||||
|
|
||||||
ISOException ex = assertThrows(ISOException.class,
|
ISOException ex = assertThrows(ISOException.class,
|
||||||
() -> CredentialStore.readFrom(buf.toSource()));
|
() -> CredentialStore.readFrom(buf.toSource()));
|
||||||
|
|||||||
Reference in New Issue
Block a user