Last active
October 16, 2023 09:26
-
-
Save krzys-h/579c11d4c5e3b4a69843cca5ea71cb79 to your computer and use it in GitHub Desktop.
Reading ELS (Elektroniczna Legitymacja Studencka) data on Linux
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# TODO: verify signatures | |
# TODO: clean up the APDU code | |
# Some documentation on the ELS format: https://isap.sejm.gov.pl/isap.nsf/download.xsp/WDU20062241634/O/D20061634.pdf | |
from smartcard.System import readers | |
from binascii import hexlify, unhexlify | |
from pyasn1_modules import rfc2315 | |
from pyasn1.codec.der.decoder import decode as der_decoder | |
from pyasn1.type import univ | |
import sels | |
SELECT_FILE = [0x00, 0xA4, 0x04, 0x00, 0x07] | |
READ_FILE = [0x00, 0xA4, 0x00, 0x00, 0x02] | |
GET_RESPONSE = [0xA0, 0xC0, 0x00, 0x00] | |
READ_BINARY = [0x00, 0xB0] | |
DF_SELS = [0xD6, 0x16, 0x00, 0x00, 0x30, 0x01, 0x01] | |
EF_CERT = [0x00, 0x01] | |
EF_ELS = [0x00, 0x02] | |
for reader in readers(): | |
if "Virtual" in reader.name: | |
continue | |
connection = reader.createConnection() | |
connection.connect() | |
print("ATR", hexlify(bytes(connection.getATR())).decode()) | |
response, sw1, sw2 = connection.transmit(SELECT_FILE + DF_SELS + [0x00]) | |
assert sw1 == 0x61 # Command successfully executed; ‘XX’ bytes of data are available and can be requested using GET RESPONSE. | |
num_bytes = sw2 | |
response, sw1, sw2 = connection.transmit(GET_RESPONSE + [num_bytes]) | |
#print(hexlify(bytes([sw1, sw2])).decode(), hexlify(bytes(response)).decode()) | |
response, sw1, sw2 = connection.transmit(READ_FILE + EF_ELS + [0x00]) | |
assert sw1 == 0x61 # Command successfully executed; ‘XX’ bytes of data are available and can be requested using GET RESPONSE. | |
num_bytes = sw2 | |
response, sw1, sw2 = connection.transmit(GET_RESPONSE + [num_bytes]) | |
#print(hexlify(bytes([sw1, sw2])).decode(), hexlify(bytes(response)).decode()) | |
offset = 0x0000 | |
block_size = 0x80 | |
data = b"" | |
while True: | |
response, sw1, sw2 = connection.transmit(READ_BINARY + [(offset >> 8) & 0xFF, offset & 0xFF] + [block_size]) | |
#print(hexlify(bytes([sw1, sw2])).decode(), hexlify(bytes(response)).decode()) | |
data += bytes(response) | |
if sw1 == 0x90: | |
offset += block_size | |
elif sw1 == 0x6C: # Bad length value in Le; ‘xx’ is the correct exact Le | |
block_size = sw2 | |
elif sw1 == 0x6b and sw2 == 0x00: # Wrong parameter(s) P1-P2 | |
break | |
else: | |
assert False | |
print(hexlify(data).decode()) | |
contentInfo, rest_of_input = der_decoder(data, asn1Spec=rfc2315.ContentInfo()) | |
signedData, rest_of_input = der_decoder(contentInfo['content'], asn1Spec=rfc2315.contentTypeMap[contentInfo['contentType']]) | |
infoEncoded, rest_of_input = der_decoder(signedData['contentInfo']['content'], asn1Spec=univ.OctetString()) | |
info, rest_of_input = der_decoder(infoEncoded, asn1Spec=sels.SELSInfo()) | |
print(info) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
SELS DEFINITIONS ::= BEGIN | |
id-SELSInfo OBJECT IDENTIFIER ::= {iso(1) member-body(2) pl(616) organization(1) gov(101) moneas(4) pki(1) sels(1) 1} | |
SELSInfo ::= SEQUENCE { | |
wersja INTEGER {v1(1)}, | |
numerSeryjnyUkladu PrintableString (SIZE (8..16)), | |
nazwaUczelni UTF8String (SIZE (1..128)), | |
nazwiskoStudenta SEQUENCE OF | |
UTF8String (SIZE (1..28)), | |
imionaStudenta SEQUENCE OF | |
UTF8String (SIZE (1..24)), | |
numerAlbumu PrintableString (SIZE (1..16)), | |
numerEdycji PrintableString (SIZE (1)), | |
numerPesel PrintableString (SIZE (11)), | |
dataWaznosci GeneralizedTime | |
} | |
END |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Auto-generated by asn1ate v.0.6.1.dev0 from sels.asn1 | |
# (last modified on 2022-09-12 00:14:53.138777) | |
# SELS | |
from pyasn1.type import univ, char, namedtype, namedval, tag, constraint, useful | |
def _OID(*components): | |
output = [] | |
for x in tuple(components): | |
if isinstance(x, univ.ObjectIdentifier): | |
output.extend(list(x)) | |
else: | |
output.append(int(x)) | |
return univ.ObjectIdentifier(output) | |
class SELSInfo(univ.Sequence): | |
pass | |
SELSInfo.componentType = namedtype.NamedTypes( | |
namedtype.NamedType('wersja', univ.Integer(namedValues=namedval.NamedValues(('v1', 1)))), | |
namedtype.NamedType('numerSeryjnyUkladu', char.PrintableString().subtype(subtypeSpec=constraint.ValueSizeConstraint(8, 16))), | |
namedtype.NamedType('nazwaUczelni', char.UTF8String().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, 128))), | |
namedtype.NamedType('nazwiskoStudenta', univ.SequenceOf(componentType=char.UTF8String().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, 28)))), | |
namedtype.NamedType('imionaStudenta', univ.SequenceOf(componentType=char.UTF8String().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, 24)))), | |
namedtype.NamedType('numerAlbumu', char.PrintableString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, 16))), | |
namedtype.NamedType('numerEdycji', char.PrintableString().subtype(subtypeSpec=constraint.ValueSizeConstraint(1, 1))), | |
namedtype.NamedType('numerPesel', char.PrintableString().subtype(subtypeSpec=constraint.ValueSizeConstraint(11, 11))), | |
namedtype.NamedType('dataWaznosci', useful.GeneralizedTime()) | |
) | |
id_SELSInfo = _OID(1, 2, 616, 1, 101, 4, 1, 1, 1) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment