3030import org .bouncycastle .asn1 .ASN1ObjectIdentifier ;
3131import org .slf4j .Logger ;
3232import org .slf4j .LoggerFactory ;
33+ import pro .javacard .gp .data .BitField ;
3334
3435import java .io .IOException ;
3536import java .math .BigInteger ;
36- import java .time .DateTimeException ;
37- import java .time .LocalDate ;
38- import java .time .format .DateTimeFormatter ;
3937import java .util .*;
4038import java .util .stream .Collectors ;
4139
4240import static pro .javacard .gp .GPSession .CLA_GP ;
41+ import static pro .javacard .gp .data .BitField .byte_mask ;
4342
4443// Various constants from GP specification and other sources
4544// Methods to pretty-print those structures and constants.
@@ -49,13 +48,6 @@ public final class GPData {
4948 private GPData () {
5049 }
5150
52- // SD states
53- public static final byte readyStatus = 0x1 ;
54- public static final byte initializedStatus = 0x7 ;
55- public static final byte securedStatus = 0xF ;
56- public static final byte lockedStatus = 0x7F ;
57- public static final byte terminatedStatus = (byte ) 0xFF ;
58-
5951 // Default ISD AID-s
6052 static final byte [] defaultISDBytes = HexUtils .hex2bin ("A000000151000000" );
6153 static final Map <Integer , String > sw = new HashMap <>();
@@ -190,38 +182,34 @@ public String toString() {
190182 }
191183
192184 // GPC 2.3.1 Table H-9 and Table H-10
193- enum SIGNATURE {
185+ public enum SIGNATURE implements BitField < SIGNATURE > {
194186 // First byte
195- RSA1024_SHA1 (0x01 , 0 ),
196- RSAPSS_SHA256 (0x02 , 0 ),
197- DES_MAC (0x04 , 0 ),
198- CMAC_AES128 (0x08 , 0 ),
199- CMAC_AES192 (0x10 , 0 ),
200- CMAC_AES256 (0x20 , 0 ),
201- ECCP256_SHA256 (0x40 , 0 ),
202- ECCP384_SHA384 (0x80 , 0 ),
187+ RSA1024_SHA1 (byte_mask ( 0 , 0x01 ) ),
188+ RSAPSS_SHA256 (byte_mask ( 0 , 0x02 ) ),
189+ DES_MAC (byte_mask ( 0 , 0x04 ) ),
190+ CMAC_AES128 (byte_mask ( 0 , 0x08 ) ),
191+ CMAC_AES192 (byte_mask ( 0 , 0x10 ) ),
192+ CMAC_AES256 (byte_mask ( 0 , 0x20 ) ),
193+ ECCP256_SHA256 (byte_mask ( 0 , 0x40 ) ),
194+ ECCP384_SHA384 (byte_mask ( 0 , 0x80 ) ),
203195 // Second byte
204- ECCP512_SHA512 (0x01 , 1 ),
205- ECCP521_SHA512 (0x02 , 1 );
196+ ECCP512_SHA512 (byte_mask (1 , 0x01 )),
197+ ECCP521_SHA512 (byte_mask (1 , 0x02 )),
198+ RFU (new Def .RFU (byte_mask (1 , 0xFC )));
206199
207- int value ;
208- int pos ;
200+ private final BitField .Def def ;
209201
210- SIGNATURE (int byteValue , int pos ) {
211- this .value = byteValue ;
212- this .pos = pos ;
202+ SIGNATURE (BitField .Def def ) {
203+ this .def = def ;
204+ }
205+
206+ @ Override
207+ public Def def () {
208+ return def ;
213209 }
214210
215211 public static Set <SIGNATURE > byValue (byte [] v ) {
216- LinkedHashSet <SIGNATURE > r = new LinkedHashSet <>();
217- for (int i = 0 ; i < v .length ; i ++) {
218- final int p = i ;
219- Arrays .stream (values ()).filter (e -> e .pos == p ).forEach (e -> {
220- if (e .value == (e .value & v [p ]))
221- r .add (e );
222- });
223- }
224- return r ;
212+ return BitField .parse (SIGNATURE .class , v );
225213 }
226214 }
227215
@@ -427,98 +415,4 @@ public static byte[] getData(APDUBIBO channel, int p1, int p2, String name, bool
427415 }
428416 }
429417
430- public static final class CPLC {
431-
432- private final LinkedHashMap <Field , byte []> values = new LinkedHashMap <>();
433-
434- private CPLC (byte [] data ) {
435- int offset = 0 ;
436- for (Field f : Field .values ()) {
437- values .put (f , Arrays .copyOfRange (data , offset , offset + f .len ));
438- offset += f .len ;
439- }
440- }
441-
442- public static CPLC fromBytes (byte [] data ) throws GPDataException {
443- if (data == null )
444- throw new IllegalArgumentException ("data is null" );
445- if (data .length < 0x2A )
446- throw new GPDataException (String .format ("Input can't be valid CPLC if length is only %02X!" , data .length ), data );
447- // Remove tag, if present
448- if (data [0 ] == (byte ) 0x9f && data [1 ] == (byte ) 0x7f && data [2 ] == (byte ) 0x2A )
449- data = Arrays .copyOfRange (data , 3 , data .length );
450- return new CPLC (data );
451- }
452-
453- public byte [] get (Field f ) {
454- return values .get (f );
455- }
456-
457- public String toString () {
458- return Arrays .stream (Field .values ()).map (i -> i .toString () + "=" + HexUtils .bin2hex (values .get (i ))).collect (Collectors .joining (", " , "[CPLC: " , "]" ));
459- }
460-
461- public String toPrettyString () {
462- return Arrays .stream (Field .values ()).map (i -> i .toString () + "=" + HexUtils .bin2hex (values .get (i )) + (i .toString ().endsWith ("Date" ) ? " (" + toDateFailsafe (values .get (i )) + ")" : "" )).collect (Collectors .joining ("\n " , "CPLC: " , "\n " ));
463- }
464-
465- public enum Field {
466- ICFabricator (2 ),
467- ICType (2 ),
468- OperatingSystemID (2 ),
469- OperatingSystemReleaseDate (2 ),
470- OperatingSystemReleaseLevel (2 ),
471- ICFabricationDate (2 ),
472- ICSerialNumber (4 ),
473- ICBatchIdentifier (2 ),
474- ICModuleFabricator (2 ),
475- ICModulePackagingDate (2 ),
476- ICCManufacturer (2 ),
477- ICEmbeddingDate (2 ),
478- ICPrePersonalizer (2 ),
479- ICPrePersonalizationEquipmentDate (2 ),
480- ICPrePersonalizationEquipmentID (4 ),
481- ICPersonalizer (2 ),
482- ICPersonalizationDate (2 ),
483- ICPersonalizationEquipmentID (4 );
484-
485- private final int len ;
486-
487- Field (int len ) {
488- this .len = len ;
489- }
490- }
491-
492- public static Optional <LocalDate > toRelativeDate (byte [] v , LocalDate now ) throws GPDataException {
493- if ((v [0 ] == 0 && v [1 ] == 0 ) || (v [0 ] == (byte ) 0xFF && v [1 ] == (byte ) 0xFF )) {
494- logger .debug ("0x0000/0xFFFF does not represent a valid date" );
495- return Optional .empty ();
496- }
497- String sv = HexUtils .bin2hex (v );
498- try {
499- int y = Integer .parseInt (sv .substring (0 , 1 ));
500- int d = Integer .parseInt (sv .substring (1 , 4 ));
501- int base = 2020 ;
502- if (y >= now .getYear () % 10 && d > now .getDayOfYear ())
503- base = 2010 ;
504- LocalDate ld = LocalDate .ofYearDay (base + y , d );
505- return Optional .of (ld );
506- } catch (NumberFormatException | DateTimeException e ) {
507- logger .warn ("Invalid CPLC date: " + sv );
508- return Optional .empty ();
509- }
510- }
511-
512- public static String toDateFailsafe (byte [] v ) {
513- return toRelativeDate (v , LocalDate .now ()).map (e -> e .format (DateTimeFormatter .ISO_LOCAL_DATE )).orElse ("invalid date format" );
514- }
515-
516- public static byte [] today () {
517- return dateToBytes (LocalDate .now ());
518- }
519-
520- public static byte [] dateToBytes (LocalDate d ) {
521- return HexUtils .hex2bin (String .format ("%d%03d" , d .getYear () - 2020 , d .getDayOfYear ()));
522- }
523- }
524418}
0 commit comments