Skip to content
This repository was archived by the owner on Oct 27, 2025. It is now read-only.

Commit f7aec28

Browse files
committed
MOPPAND-1569: Add new CosmoX ID-card chip support.
1 parent c57438b commit f7aec28

File tree

2 files changed

+29
-34
lines changed

2 files changed

+29
-34
lines changed

id-card-lib/src/main/java/ee/ria/DigiDoc/idcard/ID1.java

Lines changed: 18 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -2,28 +2,27 @@
22

33
import static com.google.common.primitives.Bytes.concat;
44

5-
import android.util.Pair;
65
import android.util.SparseArray;
76

8-
import com.google.common.base.Charsets;
97
import com.google.common.primitives.Bytes;
108

119
import java.io.ByteArrayOutputStream;
1210
import java.io.IOException;
11+
import java.nio.charset.StandardCharsets;
1312
import java.util.Arrays;
1413
import java.util.HashMap;
1514
import java.util.Map;
15+
import java.util.Objects;
1616

1717
import ee.ria.DigiDoc.smartcardreader.ApduResponseException;
1818
import ee.ria.DigiDoc.smartcardreader.SmartCardReader;
1919
import ee.ria.DigiDoc.smartcardreader.SmartCardReaderException;
2020

2121
class ID1 implements Token {
22-
23-
private static final Map<CertificateType, Pair<Byte, Byte>> CERT_MAP = new HashMap<>();
22+
private static final Map<CertificateType, byte[]> CERT_MAP = new HashMap<>();
2423
static {
25-
CERT_MAP.put(CertificateType.AUTHENTICATION, new Pair<>((byte) 0xF1, (byte) 0x01));
26-
CERT_MAP.put(CertificateType.SIGNING, new Pair<>((byte) 0xF2, (byte) 0x1F));
24+
CERT_MAP.put(CertificateType.AUTHENTICATION, new byte[] {(byte) 0xAD, (byte) 0xF1, 0x34, 0x01});
25+
CERT_MAP.put(CertificateType.SIGNING, new byte[] {(byte) 0xAD, (byte) 0xF2, 0x34, (byte) 0x1F});
2726
}
2827

2928
private static final Map<CodeType, Byte> PIN_MAP = new HashMap<>();
@@ -52,19 +51,18 @@ public PersonalData personalData() throws SmartCardReaderException {
5251
reader.transmit(0x00, 0xA4, 0x01, 0x0C, new byte[] {0x50, 0x00}, null);
5352
SparseArray<String> data = new SparseArray<>();
5453
for (int i = 1; i <= 8; i++) {
55-
reader.transmit(0x00, 0xA4, 0x01, 0x0C, new byte[] {0x50, (byte) i}, null);
54+
reader.transmit(0x00, 0xA4, 0x02, 0x0C, new byte[] {0x50, (byte) i}, null);
5655
byte[] record = reader.transmit(0x00, 0xB0, 0x00, 0x00, null, 0x00);
57-
data.put(i, new String(record, Charsets.UTF_8).trim());
56+
data.put(i, new String(record, StandardCharsets.UTF_8).trim());
5857
}
5958
return ID1PersonalDataParser.parse(data);
6059
}
6160

6261
@Override
6362
public byte[] certificate(CertificateType type) throws SmartCardReaderException {
6463
selectMainAid();
65-
reader.transmit(0x00, 0xA4, 0x00, 0x0C, null, null);
66-
reader.transmit(0x00, 0xA4, 0x01, 0x0C, new byte[] {(byte) 0xAD, CERT_MAP.get(type).first}, null);
67-
reader.transmit(0x00, 0xA4, 0x01, 0x0C, new byte[] {0x34, CERT_MAP.get(type).second}, null);
64+
reader.transmit(0x00, 0xA4, 0x09, 0x0C, CERT_MAP.get(type), null);
65+
6866
ByteArrayOutputStream stream = new ByteArrayOutputStream();
6967
while (true) {
7068
try {
@@ -89,65 +87,54 @@ public int codeRetryCounter(CodeType type) throws SmartCardReaderException {
8987
} else {
9088
selectMainAid();
9189
}
92-
return reader.transmit(0x00, 0xCB, 0x3F, 0xFF, new byte[] {0x4D, 0x08, 0x70, 0x06, (byte) 0xBF, (byte) 0x81, PIN_MAP.get(type), 0x02, (byte) 0xA0, (byte) 0x80}, 0x00)[13];
90+
return reader.transmit(0x00, 0xCB, 0x3F, 0xFF, new byte[] {0x4D, 0x08, 0x70, 0x06, (byte) 0xBF, (byte) 0x81, Objects.requireNonNull(PIN_MAP.get(type)), 0x02, (byte) 0xA0, (byte) 0x80}, 0x00)[13];
9391
}
9492

9593
@Override
9694
public void changeCode(CodeType type, byte[] currentCode, byte[] newCode) throws SmartCardReaderException {
97-
verifyCode(type, currentCode);
9895
if (type.equals(CodeType.PIN2)) {
9996
selectQSCDAid();
10097
} else {
10198
selectMainAid();
10299
}
103-
reader.transmit(0x00, 0x24, 0x00, VERIFY_PIN_MAP.get(type), Bytes.concat(code(currentCode), code(newCode)), null);
100+
verifyCode(type, currentCode);
101+
reader.transmit(0x00, 0x24, 0x00, Objects.requireNonNull(VERIFY_PIN_MAP.get(type)), Bytes.concat(code(currentCode), code(newCode)), null);
104102
}
105103

106104
@Override
107105
public void unblockAndChangeCode(byte[] pukCode, CodeType type, byte[] newCode) throws SmartCardReaderException {
108106
verifyCode(CodeType.PUK, pukCode);
109-
// block code if not yet blocked
110-
while (codeRetryCounter(type) != 0) {
111-
try {
112-
verifyCode(type, new byte[] {(byte) 0xFF});
113-
} catch (CodeVerificationException ignored) {}
114-
}
115107
if (type.equals(CodeType.PIN2)) {
116108
selectQSCDAid();
117109
}
118-
reader.transmit(0x00, 0x2C, 0x02, VERIFY_PIN_MAP.get(type), code(newCode), null);
110+
reader.transmit(0x00, 0x2C, 0x02, Objects.requireNonNull(VERIFY_PIN_MAP.get(type)), code(newCode), null);
119111
}
120112

121113
@Override
122-
public byte[] calculateSignature(byte[] pin2, byte[] hash, boolean ecc) throws SmartCardReaderException, IllegalStateException {
114+
public byte[] calculateSignature(byte[] pin2, byte[] hash, boolean ecc) throws SmartCardReaderException {
115+
selectQSCDAid();
123116
if (null != pin2 && pin2.length > 0) {
124-
verifyCode(CodeType.PIN2, pin2);
117+
verifyCode(CodeType.PIN2, pin2);
125118
Arrays.fill(pin2, (byte) 0);
126119
} else {
127120
throw new IllegalStateException("PIN2 is null or empty");
128121
}
129-
selectQSCDAid();
130122
reader.transmit(0x00, 0x22, 0x41, 0xB6, new byte[] {(byte) 0x80, 0x04, (byte) 0xFF, 0x15, 0x08, 0x00, (byte) 0x84, 0x01, (byte) 0x9F}, null);
131123
return reader.transmit(0x00, 0x2A, 0x9E, 0x9A, padWithZeroes(hash), 0x00);
132124
}
133125

134126
@Override
135127
public byte[] decrypt(byte[] pin1, byte[] data, boolean ecc) throws SmartCardReaderException {
128+
selectOberthurAid();
136129
byte[] prefix = new byte[] {0x00};
137130
verifyCode(CodeType.PIN1, pin1);
138-
selectOberthurAid();
139131
reader.transmit(0x00, 0x22, 0x41, 0xB8, new byte[] {(byte) 0x80, 0x04, (byte) 0xFF, 0x30, 0x04, 0x00, (byte) 0x84, 0x01, (byte) 0x81}, null);
140132
return reader.transmit(0x00, 0x2A, 0x80, 0x86, concat(prefix, data), 0x00);
141133
}
142134

143135
private void verifyCode(CodeType type, byte[] code) throws SmartCardReaderException {
144-
if (type.equals(CodeType.PIN2)) {
145-
selectQSCDAid();
146-
} else {
147-
selectMainAid();
148-
}
149136
try {
150-
reader.transmit(0x00, 0x20, 0x00, VERIFY_PIN_MAP.get(type), code(code), null);
137+
reader.transmit(0x00, 0x20, 0x00, Objects.requireNonNull(VERIFY_PIN_MAP.get(type)), code(code), null);
151138
} catch (ApduResponseException e) {
152139
if (e.sw1 == 0x63 || (e.sw1 == 0x69 && e.sw2 == (byte) 0x83)) {
153140
throw new CodeVerificationException(type);

id-card-lib/src/main/java/ee/ria/DigiDoc/idcard/Token.java

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,16 @@
1919

2020
package ee.ria.DigiDoc.idcard;
2121

22+
import android.util.Log;
23+
2224
import org.bouncycastle.util.encoders.Hex;
2325

2426
import java.nio.charset.StandardCharsets;
2527
import java.util.Arrays;
2628

2729
import ee.ria.DigiDoc.smartcardreader.SmartCardReader;
2830
import ee.ria.DigiDoc.smartcardreader.SmartCardReaderException;
29-
31+
import timber.log.Timber;
3032
/**
3133
* EstEID token interface.
3234
*/
@@ -54,7 +56,6 @@ void changeCode(CodeType type, byte[] currentCode, byte[] newCode)
5456

5557
/**
5658
* Unblock PIN1/PIN2 via PUK code and change it to a new value.
57-
*
5859
* When PIN1/PIN2 is not blocked yet it will be blocked before unblocking.
5960
*
6061
* @param pukCode PUK code.
@@ -121,7 +122,10 @@ static Token create(SmartCardReader reader) throws SmartCardReaderException {
121122
if (atr == null) {
122123
throw new SmartCardReaderException("ATR cannot be null");
123124
}
124-
if (Arrays.equals(Hex.decode("3bdb960080b1fe451f830012233f536549440f9000f1"), atr)) {
125+
Timber.log(Log.DEBUG, "ATR: " + Hex.toHexString(atr));
126+
127+
if (Arrays.equals(Hex.decode("3bdb960080b1fe451f830012233f536549440f9000f1"), atr) ||
128+
Arrays.equals(Hex.decode("3bdc960080b1fe451f830012233f54654944320f9000c3"), atr)) {
125129
return new ID1(reader);
126130
} else if (Arrays.equals(Hex.decode("3bfa1800008031fe45fe654944202f20504b4903"), atr) ||
127131
Arrays.equals(Hex.decode("3bfe1800008031fe45803180664090a4162a00830f9000ef"), atr)
@@ -132,6 +136,10 @@ static Token create(SmartCardReader reader) throws SmartCardReaderException {
132136
// TODO check for 3.0 card
133137
) {
134138
return new EstEIDv3d4(reader);
139+
/* TODO: Add Thales card
140+
} else if (Arrays.equals(Hex.decode("3bff9600008031fe438031b85365494464b085051012233f1d"), atr)) {
141+
return new Thales(reader);
142+
*/
135143
}
136144

137145
throw new SmartCardReaderException("Unsupported card ATR: " + new String(Hex.encode(atr), StandardCharsets.UTF_8));

0 commit comments

Comments
 (0)