Skip to main content

eid_belgium 0.1.2 copy "eid_belgium: ^0.1.2" to clipboard
eid_belgium: ^0.1.2 copied to clipboard

Reads the Belgian eID, Kids ID and residence cards: identity, address, photo and certificates, with PIN, signature and chip checks.

eid_belgium #

Video tour Live demo Pub Version Build Maintainer Licence Platforms Donate with PayPal

Reads the Belgian eID, the Kids ID and the residence cards (EU, EU+, A to N) through their contact chip: identity, address, photo and certificates. None of it needs the PIN.

Reading a card takes a USB card reader, through eid_ccid on Android, iOS, macOS, Windows and Linux. No browser lets a page reach a card reader: on the web, the package checks cards read elsewhere (BelgianEid.fromJson, BelgianSignatureVerifier) and runs the simulator, as the live demo does.

Which packages for which document: a Belgian card in a USB reader takes eid_belgium and eid_ccid and needs no key; a passport or an EU identity card takes eid_icao, with eid_nfc on a phone or eid_ccid on a contactless USB reader, and needs the CAN or the MRZ

Install #

dependencies:
  eid_belgium: ^0.1.0
  eid_ccid: ^0.1.0 # a USB card reader, in a Flutter application

Read a card #

import 'package:eid_belgium/eid_belgium.dart';
import 'package:eid_ccid/eid_ccid.dart';

final readers = await CcidTransport.listReaders();
final transport = await CcidTransport.connect(readers.first);

final eid = await BelgianEidReader(transport).read();
eid.identity.lastName;        // Dupont
eid.identity.birthDate;       // 1985-07-30
eid.address?.municipality;    // Bruxelles
eid.photo;                    // a JPEG

await transport.disconnect();

Read on insertion #

final watcher = BelgianEidWatcher(
  CcidTerminal.any(),        // every reader, those plugged in later included
  autoRead: true,            // read as soon as the card is in
  parts: BelgianEidPart.all, // address, photo, signatures, nationalNumber
  acceptExpired: false,      // turn down expired cards
  acceptedTypes: null,       // every document type
  pinPrompt: null,           // ask for the PIN before reading
  rememberPhotos: true,      // skip the photo of a card read again
  verifySignatures: true,    // check the national register's signatures
  verifyCard: true,          // have the chip prove it is genuine
  trustedRoots: null,        // the Belgian roots
  showPrivateData: false,    // the national register number, see Personal data
  onProgress: null,          // 0 to 1, for a progress bar
  onApdu: null,              // every command and answer, never the PIN
)..start();

watcher.events.listen((event) {
  switch (event) {
    case BelgianCardRead read:
      show(read.eid);
    case BelgianCardReadFailed failed:
      showError(failed.error);
    case BelgianCardRemoved _:
      clear();
    case BelgianCardInserted _ || BelgianPinVerified _:
      break;
  }
});

Every option can be changed at any time. parts, acceptExpired, acceptedTypes, verifySignatures, verifyCard, trustedRoots and onProgress also exist on BelgianEidReader.read.

Read less #

final eid = await reader.read(parts: {BelgianEidPart.address});
eid.photo;                    // null
eid.identity.nationalNumber;  // null, and removed from the raw fields too

Turn cards down #

Three checks are on by default: an expired card, a card whose signatures do not hold and a cloned chip are turned down. acceptedTypes adds a fourth:

await reader.read(acceptedTypes: {BelgianDocumentType.eid});

A card turned down throws a BelgianCardRejectedException whose reason is expired, documentType, signature or notGenuine.

  • verifySignatures checks the national register's signatures of the identity, address and photo, and its certificate against the Belgian roots the package holds (belgianRootCertificates).
  • verifyCard has the chip sign a random challenge with its own key, which a copy of the files cannot do. It needs verifySignatures. Cards older than applet 1.8 cannot prove it: eid.authenticity is then notSupported. Each proof spends one of the 5000 the chip allows before it wants the PIN once.

On the web, the signatures are checked by the browser's WebCrypto. BelgianSignatureVerifier makes the same checks away from the card, on a server for instance, from eid.toJson().

PIN #

final watcher = BelgianEidWatcher(
  terminal,
  // triesLeft is null the first time. Return null if the holder gives up.
  pinPrompt: (triesLeft) => showMyPinDialog(triesLeft),
)..start();

await reader.verifyPin('1234');   // PinException: e.triesLeft, e.isBlocked
await reader.pinTriesLeft();      // without spending a try
await reader.changePin('1234', '5678');

Three wrong PINs in a row block the card. A PIN that is not 4 to 12 digits never reaches the card.

Certificates #

final certificates = await reader.readCertificates();
certificates.authentication?.subject.commonName; // Alice Specimen (Authentication)
await certificates.verify(BelgianSignatureVerifier()); // {} when all chain up

Revocation is not checked.

Helpers #

identity.age;                       // null when the birth date is partial
identity.isAdult;                   // certainly 18 or older
identity.isExpired;
formatBelgianNationalNumber(number, masked: true); // 85.07.30-***.**
formatBelgianCardNumber(identity.cardNumber);      // 592-1234567-89
BelgianDocumentType.eid.label(BelgianLanguage.nl); // Identiteitskaart
identity.fullName;                                 // Alice Marie Specimen
address.lines;                     // [Rue de la Loi 16, 1000 Bruxelles]
formatBelgianDate(identity.validUntil, BelgianLanguage.de); // 13. März 2034
identity.sex.label(BelgianLanguage.fr);            // Féminin
belgianErrorMessage(failed.error, BelgianLanguage.fr); // Carte expirée le ...

belgianErrorMessage turns any error of a read into a sentence for the holder, in French, Dutch, German or English.

Text is as the card holds it, in the language of the issuing municipality.

Without a reader #

import 'package:eid_belgium/testing.dart';

final card = SimulatedBelgianCard(lastName: 'Peeters', pin: '4321');
final eid = await BelgianEidReader(card).read();
card.remove();
card.insert();

A made-up national register signs it, whose root is trusted for the simulator alone. tamperedLastName and cloned give cards the checks turn down.

Personal data #

The holder must consent to their card being read, and only those authorised may use the national register number.

The number is therefore read only when asked for twice: BelgianEidPart.nationalNumber in parts, which BelgianEidPart.all includes, and showPrivateData, off by default. Most uses do not need it.

await reader.read();                        // identity.nationalNumber is null
await reader.read(showPrivateData: true);   // and here it is
await reader.read(
  parts: {BelgianEidPart.address},          // no nationalNumber part:
  showPrivateData: true,                    // still null
);

Without it, the number is removed from the identity file once read, and the signatures are checked but not returned: they would give it away. onApdu gets the answers that hold it with their data zeroed.

Sources #

The documents published with the Belgian middleware, Fedict/eid-mw: card content v5.4, ID and address file contents v5.0, Belpic V1.8 reference manual.

License #

Released under the MIT licence.

More from COMAPPS #

Electronic identity cards in Dart:

Package What it does
eid APDUs, ISO 7816-4 file reading and the values national cards share.
eid_icao Passports and identity cards with an ICAO 9303 chip.
eid_ccid The transport for a USB or PC/SC card reader.
eid_nfc The transport for the NFC of an Android phone or an iPhone.

Every package COMAPPS publishes is listed at packages.comapps.be.

0
likes
160
points
603
downloads
screenshot

Documentation

API reference

Publisher

verified publishercomapps.be

Weekly Downloads

Reads the Belgian eID, Kids ID and residence cards: identity, address, photo and certificates, with PIN, signature and chip checks.

Homepage
Repository (GitHub)
View/report issues

Topics

#eid #belgium #smartcard #identity #belpic

Funding

Consider supporting this project:

www.paypal.com

License

MIT (license)

Dependencies

crypto, eid, pointycastle

More

Packages that depend on eid_belgium