Adds CoseVerifier.verifyCoseSign1 — single-purpose RFC 9052 COSE_Sign1
verifier for the Aliro IssuerAuth signature, used once at personalization
(M2A.3) to set CredentialStore.accessDocumentVerified.
Wire walk uses hardcoded offsets that assume the
aliro_harness.issuer.cose shape (matches RFC 9052 §3 but is not a generic
CBOR parser). TODO marker for M2B.3 to swap in StructuralCbor.elementSpan.
Extracts SECP256R1_{P,A,B,G,R} into Secp256r1Params so AliroApplet and
CoseVerifier share one copy. seed(KeyPair) handles full keypair seeding;
seedPublic(ECPublicKey) covers the verify-only case for the new verifier.
Test vector: deterministic-seeded P-256 key + literal payload, signed
once via the harness cose helpers and self-verified, hex-pasted into
CoseVerifierTest. Two cases (good signature; flipped payload byte).
Regression: 80 tests green; the 3 pre-existing GCM errors from the
jcardsim m2-volume swap (AliroCryptoTest#jcardsimSupportsAesGcm,
AliroGcmTest#{partialFinalBlock,roundTripAgainstJcardsimAEADCipher})
still error, unrelated to this change.
85 lines
4.2 KiB
Java
85 lines
4.2 KiB
Java
package com.dangerousthings.aliro;
|
|
|
|
/**
|
|
* secp256r1 / NIST P-256 curve parameters per FIPS 186-4 / SEC2 §2.7.2.
|
|
*
|
|
* <p>Shared across {@link AliroApplet} and {@link CoseVerifier} (and any
|
|
* future Aliro applet that needs to seed an EC key). J3R180 ships ECC keys
|
|
* with no default domain parameters; without explicitly seeding the curve,
|
|
* calls into {@code genKeyPair} / {@code setS} / {@code setW} /
|
|
* {@code Signature.init} throw {@code CryptoException.ILLEGAL_VALUE}.
|
|
*
|
|
* <p>Package-private — only intra-package callers should depend on these.
|
|
*/
|
|
final class Secp256r1Params {
|
|
|
|
private Secp256r1Params() { }
|
|
|
|
static final byte[] SECP256R1_P = {
|
|
(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,0x00,0x00,0x00,0x01,
|
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
|
0x00,0x00,0x00,0x00,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,
|
|
(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF
|
|
};
|
|
static final byte[] SECP256R1_A = {
|
|
(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,0x00,0x00,0x00,0x01,
|
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
|
0x00,0x00,0x00,0x00,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,
|
|
(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFC
|
|
};
|
|
static final byte[] SECP256R1_B = {
|
|
0x5A,(byte)0xC6,0x35,(byte)0xD8,(byte)0xAA,0x3A,(byte)0x93,(byte)0xE7,
|
|
(byte)0xB3,(byte)0xEB,(byte)0xBD,0x55,0x76,(byte)0x98,(byte)0x86,(byte)0xBC,
|
|
0x65,0x1D,0x06,(byte)0xB0,(byte)0xCC,0x53,(byte)0xB0,(byte)0xF6,
|
|
0x3B,(byte)0xCE,0x3C,0x3E,0x27,(byte)0xD2,0x60,0x4B
|
|
};
|
|
static final byte[] SECP256R1_G = {
|
|
0x04,
|
|
0x6B,0x17,(byte)0xD1,(byte)0xF2,(byte)0xE1,0x2C,0x42,0x47,
|
|
(byte)0xF8,(byte)0xBC,(byte)0xE6,(byte)0xE5,0x63,(byte)0xA4,0x40,(byte)0xF2,
|
|
0x77,0x03,0x7D,(byte)0x81,0x2D,(byte)0xEB,0x33,(byte)0xA0,
|
|
(byte)0xF4,(byte)0xA1,0x39,0x45,(byte)0xD8,(byte)0x98,(byte)0xC2,(byte)0x96,
|
|
0x4F,(byte)0xE3,0x42,(byte)0xE2,(byte)0xFE,0x1A,0x7F,(byte)0x9B,
|
|
(byte)0x8E,(byte)0xE7,(byte)0xEB,0x4A,0x7C,0x0F,(byte)0x9E,0x16,
|
|
0x2B,(byte)0xCE,0x33,0x57,0x6B,0x31,0x5E,(byte)0xCE,
|
|
(byte)0xCB,(byte)0xB6,0x40,0x68,0x37,(byte)0xBF,0x51,(byte)0xF5
|
|
};
|
|
static final byte[] SECP256R1_R = {
|
|
(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,0x00,0x00,0x00,0x00,
|
|
(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,
|
|
(byte)0xBC,(byte)0xE6,(byte)0xFA,(byte)0xAD,(byte)0xA7,0x17,(byte)0x9E,(byte)0x84,
|
|
(byte)0xF3,(byte)0xB9,(byte)0xCA,(byte)0xC2,(byte)0xFC,0x63,0x25,0x51
|
|
};
|
|
|
|
/**
|
|
* Loads the secp256r1 / NIST P-256 curve parameters into both halves of
|
|
* {@code kp}. Must run before any {@code genKeyPair}, {@code setS},
|
|
* {@code setW}, or {@code Signature.init} on cards (like J3R180) that
|
|
* don't preset domain parameters on freshly-allocated EC keys.
|
|
*/
|
|
static void seed(javacard.security.KeyPair kp) {
|
|
javacard.security.ECPublicKey pub = (javacard.security.ECPublicKey) kp.getPublic();
|
|
javacard.security.ECPrivateKey priv = (javacard.security.ECPrivateKey) kp.getPrivate();
|
|
seedPublic(pub);
|
|
priv.setFieldFP(SECP256R1_P, (short) 0, (short) SECP256R1_P.length);
|
|
priv.setA(SECP256R1_A, (short) 0, (short) SECP256R1_A.length);
|
|
priv.setB(SECP256R1_B, (short) 0, (short) SECP256R1_B.length);
|
|
priv.setG(SECP256R1_G, (short) 0, (short) SECP256R1_G.length);
|
|
priv.setR(SECP256R1_R, (short) 0, (short) SECP256R1_R.length);
|
|
priv.setK((short) 1);
|
|
}
|
|
|
|
/**
|
|
* Seeds curve params on a standalone public key (for verify-only flows
|
|
* like {@link CoseVerifier} that never need a matching private key).
|
|
*/
|
|
static void seedPublic(javacard.security.ECPublicKey pub) {
|
|
pub.setFieldFP(SECP256R1_P, (short) 0, (short) SECP256R1_P.length);
|
|
pub.setA(SECP256R1_A, (short) 0, (short) SECP256R1_A.length);
|
|
pub.setB(SECP256R1_B, (short) 0, (short) SECP256R1_B.length);
|
|
pub.setG(SECP256R1_G, (short) 0, (short) SECP256R1_G.length);
|
|
pub.setR(SECP256R1_R, (short) 0, (short) SECP256R1_R.length);
|
|
pub.setK((short) 1);
|
|
}
|
|
}
|