Skip to content

Commit ef5930d

Browse files
authored
Merge pull request #12 from sysdevrun/claude/add-fips-trust-checkbox-0EzC0
Add FIPS trust checkbox to decode page for RICS 9999, key id 0
2 parents e8d3e33 + ce8fa5b commit ef5930d

5 files changed

Lines changed: 35 additions & 8 deletions

File tree

package-lock.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

website/package-lock.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

website/src/components/DecodeTab.tsx

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ export default function DecodeTab({ initialHex, onHexChange, onEditInEncoder }:
2020
const [showCamera, setShowCamera] = useState(false);
2121
const [showHexViewer, setShowHexViewer] = useState(false);
2222
const [showRawJson, setShowRawJson] = useState(false);
23-
const { ticket, signatures, signedData, error, loading } = useTicketDecode(hex);
23+
const [trustFipsKey, setTrustFipsKey] = useState(true);
24+
const { ticket, signatures, signedData, error, loading } = useTicketDecode(hex, trustFipsKey);
2425

2526
useEffect(() => {
2627
if (initialHex && initialHex !== hex) {
@@ -60,6 +61,16 @@ export default function DecodeTab({ initialHex, onHexChange, onEditInEncoder }:
6061
onOpenCamera={() => setShowCamera(true)}
6162
/>
6263

64+
<label className="flex items-center gap-2 text-xs text-gray-600">
65+
<input
66+
type="checkbox"
67+
checked={trustFipsKey}
68+
onChange={(e) => setTrustFipsKey(e.target.checked)}
69+
className="rounded border-gray-300"
70+
/>
71+
Trust FIPS public key for level 1 as RICS 9999, key id 0
72+
</label>
73+
6374
{showCamera && (
6475
<CameraScanner
6576
onScan={(h) => {

website/src/hooks/useTicketDecode.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ export interface DecodeResult {
1515
loading: boolean;
1616
}
1717

18-
export function useTicketDecode(hex: string): DecodeResult {
18+
export function useTicketDecode(hex: string, trustFipsKey = false): DecodeResult {
1919
const [ticket, setTicket] = useState<UicBarcodeTicket | null>(null);
2020
const [signatures, setSignatures] = useState<SignatureVerificationResult | null>(null);
2121
const [signedData, setSignedData] = useState<ExtractedSignedData | null>(null);
@@ -60,7 +60,7 @@ export function useTicketDecode(hex: string): DecodeResult {
6060
const bytes = new Uint8Array(
6161
clean.match(/.{1,2}/g)!.map((b) => parseInt(b, 16)),
6262
);
63-
const keyProvider = await createKeyProvider();
63+
const keyProvider = await createKeyProvider(trustFipsKey);
6464
const result = await verifySignatures(bytes, {
6565
level1KeyProvider: keyProvider,
6666
});
@@ -79,7 +79,7 @@ export function useTicketDecode(hex: string): DecodeResult {
7979
}, 200);
8080

8181
return () => clearTimeout(debounceRef.current);
82-
}, [hex]);
82+
}, [hex, trustFipsKey]);
8383

8484
return { ticket, signatures, signedData, error, loading };
8585
}

website/src/lib/keys.ts

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,22 @@
1-
import { parseKeysXml, findKeyInXml } from 'dosipas-ts';
1+
import { parseKeysXml, findKeyInXml, getPublicKey as derivePublicKey } from 'dosipas-ts';
22
import type { Level1KeyProvider, UicPublicKeyEntry } from 'dosipas-ts';
33

44
let cachedXml: string | null = null;
55
let cachedKeys: UicPublicKeyEntry[] | null = null;
66

7+
/** NIST FIPS 186-4 ECDSA P-256 test vector private key (Level 1). */
8+
const FIPS_L1_PRIV_HEX = 'c9806898a0334916c860748880a541f093b579a9b1f32934d86c363c39800357';
9+
10+
let cachedFipsL1PubKey: Uint8Array | null = null;
11+
12+
function getFipsL1PublicKey(): Uint8Array {
13+
if (!cachedFipsL1PubKey) {
14+
const privBytes = new Uint8Array(FIPS_L1_PRIV_HEX.match(/.{1,2}/g)!.map((b) => parseInt(b, 16)));
15+
cachedFipsL1PubKey = derivePublicKey(privBytes, 'P-256');
16+
}
17+
return cachedFipsL1PubKey;
18+
}
19+
720
export async function loadKeysXml(): Promise<string> {
821
if (cachedXml) return cachedXml;
922
const resp = await fetch('./uic-publickeys.xml');
@@ -19,11 +32,14 @@ export async function getKeys(): Promise<UicPublicKeyEntry[]> {
1932
return cachedKeys;
2033
}
2134

22-
export async function createKeyProvider(): Promise<Level1KeyProvider> {
35+
export async function createKeyProvider(trustFipsKey = false): Promise<Level1KeyProvider> {
2336
const xml = await loadKeysXml();
2437
return {
2538
async getPublicKey(securityProvider, keyId) {
2639
const issuerCode = securityProvider.num ?? 0;
40+
if (trustFipsKey && issuerCode === 9999 && keyId === 0) {
41+
return getFipsL1PublicKey();
42+
}
2743
const key = findKeyInXml(xml, issuerCode, keyId);
2844
if (!key) {
2945
throw new Error(`Key not found: issuer=${issuerCode}, keyId=${keyId}`);

0 commit comments

Comments
 (0)