@@ -110,6 +110,118 @@ const std::map<byte_vector, ElectronicIDConstructor> SUPPORTED_ATRS {
110110 {{0x3b , 0x7e , 0x94 , 0x00 , 0x00 , 0x80 , 0x25 , 0xd2 , 0x03 , 0x10 , 0x01 , 0x00 , 0x56 , 0x00 , 0x00 ,
111111 0x00 , 0x02 , 0x02 , 0x00 },
112112 constructor<ElectronicID::Type::CzeEID>},
113+ // LuxtrustV2
114+ {{0x3B , 0x7D , 0x00 , 0x00 , 0x00 , 0x80 , 0x31 , 0x80 , 0x65 , 0xB0 , 0x00 , 0x00 , 0x00 , 0x00 , 0x83 ,
115+ 0x00 , 0x90 , 0x00 },
116+ constructor<ElectronicID::Type::LuxtrustV2>},
117+ // LuxEID
118+ {{0x3B , 0x7F , 0x00 , 0x00 , 0x00 , 0x80 , 0x31 , 0x80 , 0x65 , 0xB0 ,
119+ 0x00 , 0x03 , 0x00 , 0x00 , 0x12 , 0x0F , 0xFF , 0x82 , 0x90 , 0x00 },
120+ constructor<ElectronicID::Type::LuxEID>},
121+ // LuxEID
122+ {{0x3B , 0xFF , 0x00 , 0x00 , 0x00 , 0x81 , 0x31 , 0x00 , 0x43 , 0x80 , 0x31 , 0x80 , 0x65 ,
123+ 0xB0 , 0x00 , 0x03 , 0x00 , 0x00 , 0x12 , 0x0F , 0xFF , 0x82 , 0x90 , 0x00 , 0x00 },
124+ constructor<ElectronicID::Type::LuxEID>},
125+ // LuxEID
126+ {{0x3B , 0x8F , 0x00 , 0x01 , 0x80 , 0x31 , 0x80 , 0x65 , 0xB0 , 0x00 ,
127+ 0x03 , 0x00 , 0x00 , 0x12 , 0x0F , 0xFF , 0x82 , 0x90 , 0x00 , 0x00 },
128+ constructor<ElectronicID::Type::LuxEID>},
129+ // LuxEID
130+ {{0x3B , 0x88 , 0x00 , 0x01 , 0xE1 , 0xF3 , 0x5E , 0x11 , 0x00 , 0x87 , 0x95 , 0x00 , 0x00 },
131+ constructor<ElectronicID::Type::LuxEID>},
132+ // LuxEID
133+ {{0x3b , 0x7f , 0x00 , 0x00 , 0x00 , 0x80 , 0x31 , 0x80 , 0x65 , 0xb0 ,
134+ 0x00 , 0x04 , 0x00 , 0x00 , 0x12 , 0x0f , 0xff , 0x82 , 0x90 , 0x00 },
135+ constructor<ElectronicID::Type::LuxEID>},
136+ // LuxEID
137+ {{0x3b , 0xff , 0x00 , 0x00 , 0x00 , 0x81 , 0x31 , 0x00 , 0x43 , 0x80 , 0x31 , 0x80 , 0x65 ,
138+ 0xb0 , 0x00 , 0x04 , 0x00 , 0x00 , 0x12 , 0x0f , 0xff , 0x82 , 0x90 , 0x00 , 0x00 },
139+ constructor<ElectronicID::Type::LuxEID>},
140+ // LuxEID
141+ {{0x3B , 0x8F , 0x80 , 0x01 , 0x80 , 0x31 , 0x80 , 0x65 , 0xB0 , 0x00 ,
142+ 0x04 , 0x00 , 0x00 , 0x12 , 0x0F , 0xFF , 0x82 , 0x90 , 0x00 , 0x00 },
143+ constructor<ElectronicID::Type::LuxEID>},
144+ // LuxEID
145+ {{0x3b , 0x88 , 0x80 , 0x01 , 0x00 , 0x88 , 0x3c , 0x1f , 0x77 , 0x81 , 0x95 , 0x00 , 0xc1 },
146+ constructor<ElectronicID::Type::LuxEID>},
147+ // LuxEID
148+ {{0x3b , 0x7f , 0x00 , 0x00 , 0x00 , 0x80 , 0x31 , 0x80 , 0x65 , 0xb0 ,
149+ 0x00 , 0x05 , 0x00 , 0x00 , 0x12 , 0x0f , 0xff , 0x82 , 0x90 , 0x00 },
150+ constructor<ElectronicID::Type::LuxEID>},
151+ // LuxEID
152+ {{0x3b , 0xff , 0x00 , 0x00 , 0x00 , 0x81 , 0x31 , 0x00 , 0x43 , 0x80 , 0x31 , 0x80 , 0x65 ,
153+ 0xb0 , 0x00 , 0x05 , 0x00 , 0x00 , 0x12 , 0x0f , 0xff , 0x82 , 0x90 , 0x00 , 0x00 },
154+ constructor<ElectronicID::Type::LuxEID>},
155+ // LuxEID
156+ {{0x3B , 0x8F , 0x80 , 0x01 , 0x80 , 0x31 , 0x80 , 0x65 , 0xB0 , 0x00 ,
157+ 0x05 , 0x00 , 0x00 , 0x12 , 0x0F , 0xFF , 0x82 , 0x90 , 0x00 , 0x00 },
158+ constructor<ElectronicID::Type::LuxEID>},
159+ // LuxEID
160+ {{0x3b , 0x88 , 0x80 , 0x01 , 0xe1 , 0xf3 , 0x5e , 0x11 , 0x77 , 0xa1 , 0x97 , 0x00 , 0x15 },
161+ constructor<ElectronicID::Type::LuxEID>},
162+ };
163+
164+ // Masked cards.
165+ const std::map<byte_vector, byte_vector> MASKED_ATRS {
166+ // LuxtrustV2
167+ {{0x3B , 0x7D , 0x00 , 0x00 , 0x00 , 0x80 , 0x31 , 0x80 , 0x65 , 0xB0 , 0x00 , 0x00 , 0x00 , 0x00 , 0x83 ,
168+ 0x00 , 0x90 , 0x00 },
169+ {0xFF , 0xFF , 0x00 , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0x00 , 0x00 , 0x00 , 0x00 , 0xFF ,
170+ 0x00 , 0xFF , 0xFF }},
171+ // LuxEID
172+ {{0x3B , 0x7F , 0x00 , 0x00 , 0x00 , 0x80 , 0x31 , 0x80 , 0x65 , 0xB0 ,
173+ 0x00 , 0x03 , 0x00 , 0x00 , 0x12 , 0x0F , 0xFF , 0x82 , 0x90 , 0x00 },
174+ {0xFF , 0xFF , 0x00 , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF ,
175+ 0x00 , 0xFF , 0x00 , 0x00 , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF }},
176+ // LuxEID
177+ {{0x3B , 0xFF , 0x00 , 0x00 , 0x00 , 0x81 , 0x31 , 0x00 , 0x43 , 0x80 , 0x31 , 0x80 , 0x65 ,
178+ 0xB0 , 0x00 , 0x03 , 0x00 , 0x00 , 0x12 , 0x0F , 0xFF , 0x82 , 0x90 , 0x00 , 0x00 },
179+ {0xFF , 0xFF , 0x00 , 0xFF , 0xFF , 0xFF , 0xFF , 0x00 , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF ,
180+ 0xFF , 0x00 , 0xFF , 0x00 , 0x00 , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0x00 }},
181+ // LuxEID
182+ {{0x3B , 0x8F , 0x00 , 0x01 , 0x80 , 0x31 , 0x80 , 0x65 , 0xB0 , 0x00 ,
183+ 0x03 , 0x00 , 0x00 , 0x12 , 0x0F , 0xFF , 0x82 , 0x90 , 0x00 , 0x00 },
184+ {0xFF , 0xFF , 0x00 , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0x00 ,
185+ 0xFF , 0x00 , 0x00 , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0x00 }},
186+ // LuxEID
187+ {{0x3B , 0x88 , 0x00 , 0x01 , 0xE1 , 0xF3 , 0x5E , 0x11 , 0x00 , 0x87 , 0x95 , 0x00 , 0x00 },
188+ {0xFF , 0xFF , 0x00 , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0x00 , 0xFF , 0xFF , 0xFF , 0x00 }},
189+ // LuxEID
190+ {{0x3b , 0x7f , 0x00 , 0x00 , 0x00 , 0x80 , 0x31 , 0x80 , 0x65 , 0xb0 ,
191+ 0x00 , 0x04 , 0x00 , 0x00 , 0x12 , 0x0f , 0xff , 0x82 , 0x90 , 0x00 },
192+ {0xFF , 0xFF , 0x00 , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF ,
193+ 0x00 , 0xFF , 0x00 , 0x00 , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF }},
194+ // LuxEID
195+ {{0x3b , 0xff , 0x00 , 0x00 , 0x00 , 0x81 , 0x31 , 0x00 , 0x43 , 0x80 , 0x31 , 0x80 , 0x65 ,
196+ 0xb0 , 0x00 , 0x04 , 0x00 , 0x00 , 0x12 , 0x0f , 0xff , 0x82 , 0x90 , 0x00 , 0x00 },
197+ {0xFF , 0xFF , 0x00 , 0xFF , 0xFF , 0xFF , 0xFF , 0x00 , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF ,
198+ 0xFF , 0x00 , 0xFF , 0x00 , 0x00 , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0x00 }},
199+ // LuxEID
200+ {{0x3B , 0x8F , 0x80 , 0x01 , 0x80 , 0x31 , 0x80 , 0x65 , 0xB0 , 0x00 ,
201+ 0x04 , 0x00 , 0x00 , 0x12 , 0x0F , 0xFF , 0x82 , 0x90 , 0x00 , 0x00 },
202+ {0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0x00 ,
203+ 0xFF , 0x00 , 0x00 , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0x00 }},
204+ // LuxEID
205+ {{0x3b , 0x88 , 0x80 , 0x01 , 0x00 , 0x88 , 0x3c , 0x1f , 0x77 , 0x81 , 0x95 , 0x00 , 0xc1 },
206+ {0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF }},
207+ // LuxEID
208+ {{0x3b , 0x7f , 0x00 , 0x00 , 0x00 , 0x80 , 0x31 , 0x80 , 0x65 , 0xb0 ,
209+ 0x00 , 0x05 , 0x00 , 0x00 , 0x12 , 0x0f , 0xff , 0x82 , 0x90 , 0x00 },
210+ {0xFF , 0xFF , 0x00 , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF ,
211+ 0x00 , 0xFF , 0x00 , 0x00 , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF }},
212+ // LuxEID
213+ {{0x3b , 0xff , 0x00 , 0x00 , 0x00 , 0x81 , 0x31 , 0x00 , 0x43 , 0x80 , 0x31 , 0x80 , 0x65 ,
214+ 0xb0 , 0x00 , 0x05 , 0x00 , 0x00 , 0x12 , 0x0f , 0xff , 0x82 , 0x90 , 0x00 , 0x00 },
215+ {0xFF , 0xFF , 0x00 , 0xFF , 0xFF , 0xFF , 0xFF , 0x00 , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF ,
216+ 0xFF , 0x00 , 0xFF , 0x00 , 0x00 , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0x00 }},
217+ // LuxEID
218+ {{0x3B , 0x8F , 0x80 , 0x01 , 0x80 , 0x31 , 0x80 , 0x65 , 0xB0 , 0x00 ,
219+ 0x05 , 0x00 , 0x00 , 0x12 , 0x0F , 0xFF , 0x82 , 0x90 , 0x00 , 0x00 },
220+ {0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0x00 ,
221+ 0xFF , 0x00 , 0x00 , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0x00 }},
222+ // LuxEID
223+ {{0x3b , 0x88 , 0x80 , 0x01 , 0xe1 , 0xf3 , 0x5e , 0x11 , 0x77 , 0xa1 , 0x97 , 0x00 , 0x15 },
224+ {0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF }},
113225};
114226
115227inline std::string byteVectorToHexString (const byte_vector& bytes)
@@ -137,22 +249,46 @@ const auto SUPPORTED_ALGORITHMS = std::map<std::string, HashAlgorithm> {
137249namespace electronic_id
138250{
139251
252+ pcsc_cpp::byte_vector applyMask (const pcsc_cpp::byte_vector& atr, const pcsc_cpp::byte_vector& mask)
253+ {
254+ pcsc_cpp::byte_vector result (atr.size ());
255+ for (size_t i = 0 ; i < atr.size (); ++i) {
256+ result[i] = atr[i] & mask[i];
257+ }
258+ return result;
259+ }
260+
140261bool isCardSupported (const pcsc_cpp::byte_vector& atr)
141262{
142- return SUPPORTED_ATRS.count (atr);
263+ if (SUPPORTED_ATRS.count (atr)) {
264+ return true ;
265+ }
266+ for (const auto & [maskedAtr, mask] : MASKED_ATRS) {
267+ if (applyMask (atr, mask) == maskedAtr) {
268+ return SUPPORTED_ATRS.count (maskedAtr);
269+ }
270+ }
271+ return false ;
143272}
144273
145274ElectronicID::ptr getElectronicID (const pcsc_cpp::Reader& reader)
146275{
147- try {
276+ if (SUPPORTED_ATRS. count (reader. cardAtr )) {
148277 const auto & eidConstructor = SUPPORTED_ATRS.at (reader.cardAtr );
149278 return eidConstructor (reader);
150- } catch (const std::out_of_range&) {
151- // It should be verified that the card is supported with isCardSupported() before
152- // calling getElectronicID(), so it is a programming error if out_of_range occurs here.
153- THROW (ProgrammingError,
154- " Card with ATR '" + byteVectorToHexString (reader.cardAtr ) + " ' is not supported" );
155279 }
280+
281+ for (const auto & [maskedAtr, mask] : MASKED_ATRS) {
282+ if (applyMask (reader.cardAtr , mask) == maskedAtr && SUPPORTED_ATRS.count (maskedAtr)) {
283+ const auto & eidConstructor = SUPPORTED_ATRS.at (maskedAtr);
284+ return eidConstructor (reader);
285+ }
286+ }
287+
288+ // It should be verified that the card is supported with isCardSupported() before
289+ // calling getElectronicID(), so it is a programming error if out_of_range occurs here.
290+ THROW (ProgrammingError,
291+ " Card with ATR '" + byteVectorToHexString (reader.cardAtr ) + " ' is not supported" );
156292}
157293
158294bool ElectronicID::isSupportedSigningHashAlgorithm (const HashAlgorithm hashAlgo) const
0 commit comments