arrow-left

Only this pageAll pages
gitbookPowered by GitBook
1 of 48

v3.6.x

Loading...

Loading...

Loading...

Loading...

Loading...

Core

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Token

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Payment

Loading...

Loading...

Loading...

FIle

Loading...

HSM

Loading...

Other

Loading...

Loading...

Miscellaneous

Loading...

Loading...

Introduction

Trust1Connector v3 Documentation

hashtag
A Word of Introduction

The Trust1Connector Javascript SDK is a library that purely functions as a proxy towards the Trust1Connector API. This Library does not contain any business logic.

circle-exclamation

Sample code uses ES6 language features such as arrow functions and promises. For compatibility with IE11, code written with these features must be either transpiled using tools like Babel or refactored accordingly using callbacks which are also available on the Trust1Connector Javascript SDK.

Authenticated client

circle-exclamation

Sample code uses ES6 language features such as arrow functions and promises. For compatibility with IE11, code written with these features must be either transpiled using tools like Babel or refactored accordingly using callbacks.

hashtag
Introduction

The Trust1Connector API requires a valid JWT token to be provided in the Authorization header. This JWT token can be retrieved by asking the Distribution Service to generate a token for a specific API-key. It is important that this API-key is not exposed in the front-end application as this is a security violation.

When you've received a valid JWT token from the DS you can provide this into the configuration object when initialising the Trust1Connector JS client.

When using the Trust1Connector Javascript SDK the Authorization header is automatically populated with the JWT provided while initialising.

When the Token has expired there is a function which you can call to provide a new token and which will in turn return an updated client to be used.

hashtag
Retrieving a JWT token

Retrieving a valid JWT token happens via the DS. When passing a valid API-key to header of the endpoint {{ds-url}}/v3/tokens/application (GET) you wil in turn receive a valid JWT token.

Example response

hashtag
Refresh JWT token

circle-exclamation

Refreshing the JWT token can only be done after a first successfull initialisation of the Trust1Connector. This means the Trust1Connector has to be initialised with a valid configuration the first time. When the token expires after first successfull initialisation you can use the refreshJWT function described below

A JWT token is only valid for a certain period. After this period the API will return an error. At this point you need to request a new JWT token to be able to communicate with the API.

In the T1C JS SDK there is a function which you can use to re-initalise the client with a new valid JWT token. This should be done when you receive a 104026 error-code which means you do not have a valid JWT

The updateJWT function can be found in the Core service. After initialising you can retrieve the core as follows:

The function's interface is as follows;

This function returns an updated client which you can continue to use for your desired use-cases.

hashtag
Distribution services

Environment

DS url

Acceptance

https://acc-ds.t1t.io

Production

https://ds.t1t.io

// Config object definition
export class T1CConfigOptions {
  constructor(
    public t1cApiUrl?: string,
    public t1cApiPort?: string,
    public t1cProxyUrl?: string,
    public t1cProxyPort?: string,
    public jwt?: string
  ) {}
}



// example
const configoptions = new T1CSdk.T1CConfigOptions(
  environment.t1cApiUrl,
  environment.t1cApiPort,
  environment.t1cProxyUrl,
  environment.t1cProxyPort,
  environment.jwt
);
config = new T1CSdk.T1CConfig(configoptions);
curl --location --request GET 'https://acc-ds.t1t.io/v3_5/tokens/application' \
--header 'apikey: your-api-key'
{
    "success": true,
    "data": "eyJraWQiOiJ0MWNkcyIsImFsZyI6IlJTMjU2In0.eyJpc3MiOiJ0MWNkcy1hcHAiLCJzdWIiOiJkZXZlbG9wbWVudCIsImV4cCI6MTU5OTA1MTExMywiaWF0IjoxNTk5MDQ5OTEzLCJuYmYiOjE1OTkwNDk5MDh9.LE_AdYv9PWxqSRm6-lkV_3TxInCqbf_hTwHFKCFfYwkuzex6AMkeW6FaVCOxu-EBU158S2g70i4VBpeT2TAr0IoOyjK-nalvVG5aB9MwidZMtiPlidcUfsDhsyhbhwqlhI2dzB5J5KsBmvZwpoG-Pg2koUSidruixg3SxRrCMotBRlRNKItnYgfs6_wvd_OOLXs2OlufYOD876MWcJymBK48wf9ESQ50clR3zwPAQsNnXFq2Augk0gOlCgWO1--WgaFeMnBF28b7genZXIkwZCfT82nRYtiOs0zLK2WtyireTHDgjIZif4nX8pggE7t_63Hbv8wCvv8_Mg2PfdhCMQ"
}
const configoptions = new T1CSdk.T1CConfigOptions(
  environment.t1cApiUrl,
  environment.t1cApiPort,
  environment.t1cProxyUrl,
  environment.t1cProxyPort,
  environment.jwt
);
config = new T1CSdk.T1CConfig(configoptions);

T1CSdk.T1CClient.initialize(config).then(res => {
        client = res;
        console.log("Client config: ", client.localConfig)
        core = client.core();
    }, err => {});
updateJWT(jwt: string, callback?: (error: T1CLibException, data?: T1CClient) => void): Promise<T1CClient>
core.updateJWT("jwt").then(client => {}, error => {});

Generic token

circle-exclamation

Sample code uses ES6 language features such as arrow functions and promises. For compatibility with IE11, code written with these features must be either transpiled using tools like Babel or refactored accordingly using callbacks.

hashtag
Introduction

The Generic token interface is an interface used to integrate all supported tokens. This interface relies on the fact that you will need to provide a valid module. The module suggested from the reader response can be used here.

hashtag
Interface

hashtag
Models

All model information can be found in the

hashtag
Initialise the Trust1Connector JS

Initialise a Trust1Connector client with a valid configuration:

hashtag
Obtain the Reader information

In order to get all connected card-readers, with available cards:

This function call returns:

As you can see in the response we get a property suggestedModule which is returned based on the card, reader and AID information. This suggested module can be used in the generic interface.

Using the generic interface can be done as follows;

The pin and pinType are optional and are used for unlocking the pace layer (if the card is protected with a pace layer).

At this point for each use-case you will need to provide the module. This can be manually defined or be retrieved from the suggestedModule property in the reader-response. In the examples below we provide the module as a variable module

hashtag
Cardholder Information

The card holder is the person identified using the Belgian eID card. It's important to note that all data must be validated in your backend. Data validation can be done using the appropriate certificate (public key).

hashtag
Biometric data

Contains all card holder related data, excluding the card holder address and photo. The service can be called:

An example callback:

Response:

hashtag
Address

Contains the card holder's address. The service can be called:

Response:

hashtag
Picture

Contains the card holder's picture stored on the smart card. The service can be called:

Response:

hashtag
Token info

The token info contains generic information about the card and it's capabilities. This information includes the serial number, file types for object directory files, algorithms implemented on the card, etc.

Response

hashtag
Certificates

Exposes all the certificates publicly available on the smart card.

hashtag
Extended certificates

You can also fetch the extended versions of the certificates via the functions

this has the capabilities to return multiple certificates if the token has multiple of this type.

for a single certificate the response looks like:

the allCertsExtended returns the following, with the contents of the certificates as the one you can see above;

hashtag
Root Certificate

Contains the 'root certificate' stored on the smart card. The root certificate is used to sign the 'citizen CA certificate'. When additional parsing of the certificate is needed you can add a boolean to indicate if you want to parse the certificate or not. The service can be called:

Response:

You can also fetch the root certificate via the function rootCertificateExtended this has the capabilities to return multiple certificates if the token has multiple of this type.

The response looks like:

hashtag
Authentication Certificate

Contains the 'authentication certificate' stored on the smart card. The 'authentication certificate' contains the public key corresponding to the private RSA authentication key. The 'authentication certificate' is needed for pin validation and authentication. When additional parsing of the certificate is needed you can add a boolean to indicate if you want to parse the certificate or not The service can be called:

Response:

You can also fetch the root certificate via the function authenticationCertificateExtended this has the capabilities to return multiple certificates if the token has multiple of this type.

The response looks like:

hashtag
Intermediate Certificate (citizen)

Contains the citizen certificate stored on the smart card. The 'citizen certificate' is used to sign the 'authentication certificate' and the 'non-repudiation certificate'. When additional parsing of the certificate is needed you can add a boolean to indicate if you want to parse the certificate or not The service can be called:

Response:

You can also fetch the root certificate via the function intermediateCertificateExtended this has the capabilities to return multiple certificates if the token has multiple of this type.

The response looks like:

hashtag
Non-repudiation Certificate

Contains the 'non-repudiation certificate' stored on the smart card. The 'non-repudiation certificate' contains the public key corresponding the private RSA non-repudiation key. When additional parsing of the certificate is needed you can add a boolean to indicate if you want to parse the certificate or not The service can be called:

Response:

The response looks like:

You can also fetch the root certificate via the function nonRepudiationCertificateExtended this has the capabilities to return multiple certificates if the token has multiple of this type.

hashtag
Encryption Certificate (RRN)

Contains the 'encryption certificate' stored on the smart card. The 'encryption certificate' corresponds to the private key used to sign the 'biometric' and 'Address' data. When additional parsing of the certificate is needed you can add a boolean to indicate if you want to parse the certificate or not The service can be called:

Response:

You can also fetch the root certificate via the function encryptionCertificateExtended this has the capabilities to return multiple certificates if the token has multiple of this type.

The response looks like:

hashtag
All certificates

Contains the 'encryption certificate' stored on the smart card. The 'encryption certificate' corresponds to the private key used to sign the 'biometric' and 'Address' data. When additional parsing of the certificate is needed you can add a boolean to indicate if you want to parse the certificate or not The service can be called:

Response:

You can also fetch the root certificate via the function allCertsExtended this has the capabilities to return multiple certificates if the token has multiple of this type.

The response looks like:

hashtag
Data Filter

hashtag
Filter Card Holder Data

All data on the smart card can be dumped at once, or using a filter. In order to read all data at once:

Response:

The filter can be used to ask a list of custom data containers. For example, we want to read only the biometric data

Response:

hashtag
Filter Certificates

All certificates on the smart card can be dumped at once, or using a filter. In order to read all certificates at once:

Response:

The filter can be used to ask a list of custom data containers. For example, we want to read only the rootCertificate

Response:

hashtag
Sign Data

Data can be signed using the Belgian eID smart card. To do so, the T1C-GCL facilitates in:

  • Retrieving the certificate chain (citizen-certificate, root-certificate and non-repudiation certificate)

  • Perform a sign operation (private key stays on the smart card)

  • Return the signed hash

To get the certificates necessary for signature validation in your back-end:

Response:

Depending on the connected smart card reader. A sign can be executed in 2 modes:

  • Using a connected card reader with 'pin-pad' capabilities (keypad and display available)

  • Using a connected card reader without 'pin-pad' capabilities (no keypad nor display available)

Security consideration: In order to sign a hash, security considerations prefer using a 'pin-pad'.

hashtag
Sign Hash without pin-pad

When the web or native application is responsible for showing the password input, the following request is used to sign a given hash:

Response is a base64 encoded signed hash:

hashtag
Sign Hash with pin-pad

When the pin entry is done on the pin-pad, the following request is used to sign a given hash:

Response is a base64 encoded signed hash:

The core services lists connected readers, and if they have pin-pad capability. You can find more information in the Core Service documentation on how to verify card reader capabilities.

hashtag
Raw data signing

With the function signRaw you can sign unhashed document data. This means that the Trust1Connector will hash the value itself depending on the provided sign algorithm.

circle-exclamation

Trust1Connector only supports SHA2 hashing at this point.

When using SHA3, the Trust1Connector will convert to SHA2 implicitly

Below you can find an example

The function looks the same as a regular sign operation but expects a base64 data object that is unhashed.

Supported hash functions (SHA2) are;

  • SHA256

  • SHA384

  • SHA512

hashtag
Bulk Signing

It is possible to bulk sign data without having to re-enter the PIN by adding an optional bulk parameter set to true to the request. Subsequent sign requests will not require the PIN to be re-entered until a request with bulk being set to false is sent, or the method is called.

triangle-exclamation

When using bulk signing, great care must be taken to validate that the first signature request was successful prior to sending subsequent requests. Failing to do this will likely result in the card being blocked.

hashtag
Bulk PIN Reset

The PIN set for bulk signing can be reset by calling this method.

Response will look like:

hashtag
Verify PIN

hashtag
Verify PIN without pin-pad

When the web or native application is responsible for showing the password input, the following request is used to verify a card holder PIN:

Response:

hashtag
Verify PIN with pin-pad

When the pin entry is done on the pin-pad, the following request is used to verify a given PIN:

Response:

hashtag
Authentication

The T1C is able to authenticate a card holder based on a challenge. The challenge can be:

  • provided by an external service

  • provided by the smart card An authentication can be interpreted as a signature use case, the challenge is signed data, that can be validated in a back-end process.

    External Challenge

    An external challenge is provided in the data property of the following example:

Response:

Take notice that the PIN property can be omitted when using a smart card reader with pin-pad capabilities.

hashtag
Get valid algorithms to use for Sign or Authenticate

Via the Trust1Connector modules you are able to retrieve available algorithms to use for Signing or Authenticate

The response you can expect is a list of algorithms, an example can be found below (the values below are purely examplatory)

Belgian eID

circle-exclamation

Sample code uses ES6 language features such as arrow functions and promises. For compatibility with IE11, code written with these features must be either transpiled using tools like Babel or refactored accordingly using callbacks.

hashtag
Introduction

Token typings model page
Bulk Sign Reset
export interface AbstractEidGeneric {
  allData(module: string, filters?: string[] | Options, callback?: (error: T1CLibException, data: TokenAllDataResponse) => void): Promise<TokenAllDataResponse>;
  allCerts(module: string, parseCerts?: boolean,  filters?: string[] | Options, callback?: (error: T1CLibException, data: TokenAllCertsResponse) => void): Promise<TokenAllCertsResponse>;
  biometric(module: string, callback?: (error: T1CLibException, data: TokenBiometricDataResponse) => void): Promise<TokenBiometricDataResponse>;
  tokenData(module: string, callback?: (error: T1CLibException, data: TokenInfoResponse) => void): Promise<TokenInfoResponse>;
  address(module: string, callback?: (error: T1CLibException, data: TokenAddressResponse) => void): Promise<TokenAddressResponse>;
  picture(module: string, callback?: (error: T1CLibException, data: TokenPictureResponse) => void): Promise<TokenPictureResponse>;
  rootCertificate(module: string, parseCerts?: boolean,  callback?: (error: T1CLibException, data: TokenCertificateResponse) => void): Promise<TokenCertificateResponse>;
  intermediateCertificates(module: string, parseCerts?: boolean,  callback?: (error: T1CLibException, data: TokenCertificateResponse) => void): Promise<TokenCertificateResponse>;
  authenticationCertificate(module: string, parseCerts?: boolean,  callback?: (error: T1CLibException, data: TokenCertificateResponse) => void): Promise<TokenCertificateResponse>;
  nonRepudiationCertificate(module: string, parseCerts?: boolean,  callback?: (error: T1CLibException, data: TokenCertificateResponse) => void): Promise<TokenCertificateResponse>;
  encryptionCertificate(module: string, parseCerts?: boolean,  callback?: (error: T1CLibException, data: TokenCertificateResponse) => void): Promise<TokenCertificateResponse>;
  issuerCertificate(module: string, parseCerts?: boolean,  callback?: (error: T1CLibException, data: TokenCertificateResponse) => void): Promise<TokenCertificateResponse>;

  allCertsExtended(module: string, parseCerts?: boolean, filters?: string[] | Options, callback?: (error: T1CLibException, data: TokenAllCertsExtendedResponse) => void): Promise<TokenAllCertsExtendedResponse>;
  rootCertificateExtended(module: string, parseCerts?: boolean, callback?: (error: T1CLibException, data: TokenCertificateExtendedResponse) => void): Promise<TokenCertificateExtendedResponse>;
  intermediateCertificatesExtended(module: string, parseCerts?: boolean, callback?: (error: T1CLibException, data: TokenCertificateExtendedResponse) => void): Promise<TokenCertificateExtendedResponse>;
  authenticationCertificateExtended(module: string, parseCerts?: boolean, callback?: (error: T1CLibException, data: TokenCertificateExtendedResponse) => void): Promise<TokenCertificateExtendedResponse>;
  nonRepudiationCertificateExtended(module: string, parseCerts?: boolean, callback?: (error: T1CLibException, data: TokenCertificateExtendedResponse) => void): Promise<TokenCertificateExtendedResponse>;
  encryptionCertificateExtended(module: string, parseCerts?: boolean, callback?: (error: T1CLibException, data: TokenCertificateExtendedResponse) => void): Promise<TokenCertificateExtendedResponse>;
  issuerCertificateExtended(module: string, parseCerts?: boolean,  callback?: (error: T1CLibException, data: TokenCertificateExtendedResponse) => void): Promise<TokenCertificateExtendedResponse>;

  verifyPin(module: string, body: TokenVerifyPinData, callback?: (error: T1CLibException, data: TokenVerifyPinResponse) => void): Promise<TokenVerifyPinResponse>;
  authenticate(module: string, body: TokenAuthenticateOrSignData, callback?: (error: T1CLibException, data: TokenAuthenticateResponse) => void): Promise<TokenAuthenticateResponse>;
  sign(module: string, body: TokenAuthenticateOrSignData, bulk?: boolean, callback?: (error: T1CLibException, data: TokenSignResponse) => void): Promise<TokenSignResponse>;
  signRaw(module: string, body: TokenAuthenticateOrSignData, bulk?: boolean, callback?: (error: T1CLibException, data: TokenSignResponse) => void): Promise<TokenSignResponse>;
  allAlgoRefs(module: string, callback?: (error: T1CLibException, data: TokenAlgorithmReferencesResponse) => void): Promise<TokenAlgorithmReferencesResponse>
  resetBulkPin(module: string, callback?: (error: T1CLibException, data: BoolDataResponse) => void): Promise<BoolDataResponse>;
}
T1CSdk.T1CClient.initialize(config).then(res => {
    client = res;
}, err => {
    console.error(error)
});
var core = client.core();
core.readersCardAvailable(callback);
{
  "data": [
    {
      "card": {
        "atr": "3B9813400AA503010101AD1311",
        "description": ["Belgian eID Card"]
      },
      "id": "57a3e2e71c48cee9",
      "name": "Bit4id miniLector",
      "pinpad": false,
      "suggestedModule": "beid"
    }
  ],
  "success": true
}
var generic = client.generic(selected_reader.id, pin, pinType);
generic.biometric(module, options, callback);
function callback(err,data) {
    if(err){
        console.log("Error:",JSON.stringify(err, null, '  '));
    }
    else {
        console.log(JSON.stringify(data, null, '  '));
    }
}
{
 "birthDate": "15 JUL  1993",
 "birthLocation": "Roeselare",
 "cardDeliveryMunicipality": "Avelgem",
 "cardNumber": "592..8233",
 "cardValidityDateBegin": "27.05.2015",
 "cardValidityDateEnd": "27.05.2025",
 "chipNumber": "U0xHk...EstwAjEpJQQg==",
 "documentType": "01",
 "firstNames": "Gilles Frans",
 "name": "Platteeuw",
 "nationalNumber": "930...154",
 "nationality": "Belg",
 "nobleCondition": "",
 "pictureHash": "Fqva9YCp...JKyn8=",
 "rawData": "AQw1OTIxMjQwNTgy...TARFBar2vWAqTW+axEIuyskBgFySsp/",
 "sex": "M",
 "signature": "hKys9WMjUm4ipg...14xUCg/98Y9/gP/vgG7JTRZJoKgDXLLTvLZO4qlfA==",
 "specialStatus": "0",
 "thirdName": "J",
 "version": "0"
}
generic.address(module, callback);
{
 "municipality": "Hoeselt",
 "rawData": "ARJLZXJrc...AAAAAA==",
 "signature": "mhPyeRg25H...w==",
 "streetAndNumber": "Kerkstraat X",
 "version": "0",
 "zipcode": "3730"
}
generic.picture(module, callback);
{
  "data": "/9j/4AAQSkZJRgABA...59aVpcklSDzyKUTEDGK//9k=",
  "success": true
}
{
  "data": {
    "eid_compliant":48,
    "electrical_perso_interface_version":0,
    "electrical_perso_version":3,
    "graphical_perso_version":7,
    "label":"BELPIC",
    "prn_generation":4,
    "raw_data":"MCcCAQAEEFNMSU4z...JFTFBJQwMCBDCeBAcDAAA=",
    "serial_number":"534C494E..1231C",
    "version":0,
    "version_rfu":0
    },
    "success": true
}
allCertsExtended(module: string, parseCerts?: boolean, filters?: string[] | Options, callback?: (error: T1CLibException, data: TokenAllCertsExtendedResponse) => void): Promise<TokenAllCertsExtendedResponse>;
rootCertificateExtended(module: string, parseCerts?: boolean, callback?: (error: T1CLibException, data: TokenCertificateExtendedResponse) => void): Promise<TokenCertificateExtendedResponse>;
intermediateCertificatesExtended(module: string, parseCerts?: boolean, callback?: (error: T1CLibException, data: TokenCertificateExtendedResponse) => void): Promise<TokenCertificateExtendedResponse>;
authenticationCertificateExtended(module: string, parseCerts?: boolean, callback?: (error: T1CLibException, data: TokenCertificateExtendedResponse) => void): Promise<TokenCertificateExtendedResponse>;
nonRepudiationCertificateExtended(module: string, parseCerts?: boolean, callback?: (error: T1CLibException, data: TokenCertificateExtendedResponse) => void): Promise<TokenCertificateExtendedResponse>;
encryptionCertificateExtended(module: string, parseCerts?: boolean, callback?: (error: T1CLibException, data: TokenCertificateExtendedResponse) => void): Promise<TokenCertificateExtendedResponse>;
issuerCertificateExtended(module: string, parseCerts?: boolean,  callback?: (error: T1CLibException, data: TokenCertificateExtendedResponse) => void): Promise<TokenCertificateExtendedResponse>;
{
    "success" : true
    "data" : {
        "certificates": [{
            "certificate"?: string,
            "certificateType"?: string,
            "id"?: string,
            "subject"?: string,
            "issuer"?: string,
            "serialNumber"?: string,
            "url"?: string,
            "hashSubPubKey"?: string,
            "hashIssPubKey"?: string,
            "exponent"?: string,
            "remainder"?: string,
            "parsedCertificate"?: Certificate
        }]
    }
}
{
    "success" : true
    "data" : {
        "rootCertificate": {
            "certificates": [...]
        },
        "authenticationCertificate": {
            "certificates": [...]
        },
        "nonRepudiationCertificate": {
            "certificates": [...]
        },
        "intermediateCertificates": {
            "certificates": [...]
        },
        "encryptionCertificate": {
            "certificates": [...]
        }
   }
}
generic.rootCertificate(module, parseCertsBoolean, callback);
{
    success: true,
    data: {
        certificate?: string,
        certificates?: Array<string>,
        certificateType?: string,
        id?: string,
        parsedCertificate?: Certificate,
        parsedCertificates?: Array<Certificate>
    }    
}
{
    "success" : true
    "data" : {
        "certificates": [
            "certificate"?: string,
            "certificateType"?: string,
            "id"?: string,
            "subject"?: string,
            "issuer"?: string,
            "serialNumber"?: string,
            "url"?: string,
            "hashSubPubKey"?: string,
            "hashIssPubKey"?: string,
            "exponent"?: string,
            "remainder"?: string,
            "parsedCertificate"?: Certificate
        ]
    }
}
generic.authenticationCertificate(module, parseCertsBoolean, callback);
{
    success: true,
    data: {
        certificate?: string,
        certificates?: Array<string>,
        certificateType?: string,
        id?: string,
        parsedCertificate?: Certificate,
        parsedCertificates?: Array<Certificate>
    }    
}
{
    "success" : true
    "data" : {
        "certificates": [
            "certificate"?: string,
            "certificateType"?: string,
            "id"?: string,
            "subject"?: string,
            "issuer"?: string,
            "serialNumber"?: string,
            "url"?: string,
            "hashSubPubKey"?: string,
            "hashIssPubKey"?: string,
            "exponent"?: string,
            "remainder"?: string,
            "parsedCertificate"?: Certificate
        ]
    }
}
generic.intermediateCertificates(module, parseCertsBoolean, callback);
{
    success: true,
    data: {
        certificate?: string,
        certificates?: Array<string>,
        certificateType?: string,
        id?: string,
        parsedCertificate?: Certificate,
        parsedCertificates?: Array<Certificate>
    }    
}
{
    "success" : true
    "data" : {
        "certificates": [
            "certificate"?: string,
            "certificateType"?: string,
            "id"?: string,
            "subject"?: string,
            "issuer"?: string,
            "serialNumber"?: string,
            "url"?: string,
            "hashSubPubKey"?: string,
            "hashIssPubKey"?: string,
            "exponent"?: string,
            "remainder"?: string,
            "parsedCertificate"?: Certificate
        ]
    }
}
generic.nonRepudiationCertificate(module, parseCertsBoolean, callback);
{
    success: true,
    data: {
        certificate?: string,
        certificates?: Array<string>,
        certificateType?: string,
        id?: string,
        parsedCertificate?: Certificate,
        parsedCertificates?: Array<Certificate>
    }    
}
{
    "success" : true
    "data" : {
        "certificates": [
            "certificate"?: string,
            "certificateType"?: string,
            "id"?: string,
            "subject"?: string,
            "issuer"?: string,
            "serialNumber"?: string,
            "url"?: string,
            "hashSubPubKey"?: string,
            "hashIssPubKey"?: string,
            "exponent"?: string,
            "remainder"?: string,
            "parsedCertificate"?: Certificate
        ]
    }
}
generic.encryptionCertificate(module, parseCertsBoolean, callback);
{
    success: true,
    data: {
        certificate?: string,
        certificates?: Array<string>,
        certificateType?: string,
        id?: string,
        parsedCertificate?: Certificate,
        parsedCertificates?: Array<Certificate>
    }    
}
{
    "success" : true
    "data" : {
        "certificates": [
            "certificate"?: string,
            "certificateType"?: string,
            "id"?: string,
            "subject"?: string,
            "issuer"?: string,
            "serialNumber"?: string,
            "url"?: string,
            "hashSubPubKey"?: string,
            "hashIssPubKey"?: string,
            "exponent"?: string,
            "remainder"?: string,
            "parsedCertificate"?: Certificate
        ]
    }
}
generic.allCerts(module, parseCertsBoolean, callback);
{
 "rootCertificate": {
 ...
 },
 "authenticationCertificate": {
 ...
 },
 "nonRepudiationCertificate": {
 ...
 },
 "intermediateCertificates": {
 ...
 },
 "encryptionCertificate": {
 ...
 }
}
{
    "success" : true
    "data" : {
        "rootCertificate": {
            "certificates": [...]
        },
        "authenticationCertificate": {
            "certificates": [...]
        },
        "nonRepudiationCertificate": {
            "certificates": [...]
        },
        "intermediateCertificates": {
            "certificates": [...]
        },
        "encryptionCertificate": {
            "certificates": [...]
        }
   }
}
var filter = [];
generic.allData(module, { filters: filter}, callback);
{
 "picture": {
  "picture": "/9j/4AAQSkZJRgABAgEBLAEsAAD/.../wAALCADIAIwBAREA/8QA0gAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoLEAACAQMDAgQDBQUEBAAAAX0BAgMABBEFEiExQQYTUWEHInEUMoGRoQgjQrHBFVLR8CQzYnKCCQoWFxgZGiUmJygpKjQ1Njc4OTpDREVGR0hJSlNUVVZXWFlaY2RlZmdoaWpzdHV2d3h5eoOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4eLj5OXm5+jp6vHy8/T19vf4+fr/2gAIAQEAAD8A9JpKKWiikooooopaKSilooooopKr3d9bWaFriVEwM4J5Ncjq3jUxkixQADozjJNcze+L9WndWF20OOCI/lzRb+KtYjhIN67Z7vyf1qT/AIS3Wc5F2OnQgY/lWrovjC7hYLqJ86IkksPvCustPEumXbbUuAjYzh+K1UkWRA6MGU9CDkGn0UUUUUUUhOBk8CuY1zxOls/kWjbnH3pAMgewrz7VtWmu7gvJIzZ65NZk1wSBjOagWbn5lB+vagy7+2KlilUE7eRj1qS3ncSEE4X3qwzNs81Dgg9K19G8VXumTLFv8yDOWjb+len6bqMGp2qz2zZU8Ed1PpVyiiiiio5pkgiaSRgqKMkmuH8ReKXlMlpAAkHRnB5b29q4+e5HzAHjPFZkoLyhevH6014XUcjBqAow5xQEYjFPClDxkCnq20AkZ/xqyl2oUK4xu6n0qwgguZQ28K2Ofc1v6Pqs2lSRGJzsLAOv94d69MtriO6gSaFgyMMg1LS0UUlcn491FbfS/sicyzEH6AGvOCzuApPOakt7CWYk7TjNXE0iUNnyyfpVqPQ53XiNwPepYfDMhb94GAq5/wAIzbhc4IPpVK/8OYjzEMmsWbRZ0XIUnHtVRrR4/vqR9RSwQGXdt4Zav2rbFww6DI5ruvBuqIIjaSuMu2Y8/TpXYUtFFIa8r8W6h9v1d9mCqHYuO4FVdM0t7iZWb8a6y10+KNQCOlXFijQfKop6g9hUmw4pjoRzmopEyvIqrJEjDGKpXGnwzoQ68+1YNxpv2Ry8RPHrVGUqse4MN38Qq7o8o8kOh+dG3AjsRXpejapHqVsDkLMo+dM8/WtOiis/WrxrHTJp1GWAwOeme9eWqqzTln6k5rqNLhWKFcDmtJRk1aSPPWp0i21J5dRSx8VWKVXkQA1WmwvGDzWVegSRsp4zXNT2WwMASSxqa1kNimMBkOB9fWt7QLx4ddgaNCyyLtIHevR6Wiuf8ZsRobAdWcD+dcLYQZlHck/lXWQKEjUVZj69OlXI+manXnvTiADioXPJ4qBhVaQ/NVWbkZ7VlXeDmqRYY27Rn1rOmkDXOwKBgH8av6XOba9guVz8hA2+1epg5GaWiuf8ZqTom4fwyKf5iuS0uFiQcV0MYwgBqxH1FWl6VLGeKcxOOaaRmoZAcVTkBqrOcL61j3B5NVgducVXkeOOXLKMt1p9tIsyjaAMGvVI+I1+gp9FZXiOAT6LcKRnaN35Vy+lhfKJ9Kv+cifeYACpIry3A5kA+tW1uYmXKuD+NSRzDseKl3gjrTS47UhYAGqFxINxqhcSA8ZrPlQmq8kZArNujljkdBUuhAy3cUOOWdRXrY4FLRUN0iSW8iSkBGUg5riLGMrbzxq3IkI3CozpuWZmnkye+6qT6TlmPnkk9M1Smsbq3OUuOOvWtDTrq4j+V5CRn1rpIZy6ZNSbiBz1qneXphFcpqmqzyNiJiBnqKyl+33DDZJL9dxq2i6pDg7mYehNX7a/lx5d5EADwGHUVBeR/MfT2q/4It2n10vtykY3H29K9MpaSsLxKJJo4oI5Ci53NjvWbbweUGAH3sE5qG8DpnqB7CsKNru7umitUKgdXbqay3m1L7cluxlMm/DAqMYrqLfTW5DKAw7joa1LRCnDVNelYo91cXq13NcMfLDbAcA+tVbXTppyzMrNtGSq9RTP7VhgZY44HBP+1k1Zi1LzZNgbOexGCKS8kwQcc1LM4ayeT0Sl8M+IhpDzfuA4kwCe+BXqFldxXtrHcQnKOMjNWKSsfV48zI3qMVVwpIA5xxTpI1bqBVNrRQ25EwfVaja3cybtgz/eK81ahjKrz1pTwR6k1U1aQ/Zm57VhQKDGhAyBWxatHACUXbuHOO9Yt3plol01wkWSTnGazLixaW5EsSbSO4q5HZu6Ey9R0qLUQYNOcdA3FY1vGS4wK9f8NQtBolurdSC2PrWtRWfqoHlI3cHFZUXJJ9TU3U4xxTguKdsyM1FINtQNjcKpauC1uwHORWLYsAAhPStqOPKAjoaHhU8Fc1G0KDouKgmUBTisDXCTBGoxgtk1W02AysoUclgK9it4hDBHGOiKFqWiqWppvtT7EGsgKoGVJB7ip161KoWlY4qrctjGOpqCJd74JqLUlVYic8YrlI22ySSKehzXUWDCa2RxzkVaaMVUnXaDWXdzBVIzziuf1Pc80MS9x1rd8Maa39qxRucqhDtj2r0elopkiCRGRuhGKxJreaFipQlB/EBTA2Dih5tg4ySeAKlUnbufr6VBOpkBA4PassR3NtIZJJ/MB/h24xWDr+rySYihU+/NZULXMkXlrHyepFdfoYaG1RG5IFa7yZTIrNv5gqHmudnn3zgdeazrjL3+7PyggV6J4QgY28ly643YRT64610tFFJTXXcjL6jFc+/BIP8ACcUKoEm888YFI13GuVkbafehZ4uu8UOYpVwGGazp9KtmYs2AfempZQx524pyusRAyKkEuXU9jxWNrUxUsnc1k26F50U9WIFd1F4N08XCzu0rdCUJ4Jro0RY0VEUKqjAA7U+iiikrCvV2Xki9ic1BExDYPOKL6xhvIdrqM9j6VjmwNuNiu6/8CzUiW0uw73bOOCADVO7hulGRIxY9iOKy5RfgnbKB+NLZWWp3EwMtwBHnPU8106xrFGiZzt5JNcpqdyLnVWVOUU81a0GL7TrdsmMgOCfoDmvUaWiiiikrM1aHlJh0HBrNBAcZqcnH0qJ1EnBGaqvGy/dPFU51mfv+tVRaNnLc/Wp0cRLgHmqup35hs2AJ8xxgYrBijKRlm+8eSa6nwLbbryW4b+EYFd5RRRRRRVXURmxlz7fzrmDJ820noavoQ0WCcmlQZpXjBGarMijpzVedBtJNZczbSTmsW6k864BY/Kvaomk3sFB4rtfBO398F6BcV19FFFFFFVr/AJs5fpXLXEJK716imWt5tOxzir6Tqe9JLcAcbhUTTrt4Iqhc3IOQGrA1C/CcZ56VkPOzHr1p0JZ32r07mu/8ELsaYZ5K5rsKKKKSloqtfnFnL9KwkAP41Qv7I53R9ax5ri5tzhg31qm+qzdDzUb6zKBjAqlNqkrZxwTWe8jSOSSSalhiaRgO1a1tAsYA711/hA7bpx6qa7CikpaSio1njZioYZHWs/UdQtmhlgjnjeUYyinJHPes2M5HNPYDbiqr28cvyuoIqjceH7eQ5AI+lZ0vhyME4Z/zqjPoiRZ5aqBslRulXbe3woOKtLGc8itvQJxbXqseh4NdRPqaxpujjMnqAcYHrToNShlAz8h96mkvLeJQ0k8aKe7MBT0uIZF3JNGy+qsCKqajfx2gUFvmJ6ZrB1HxUkSttIGOOtcpfeK5jC8dsxDP1f0+laehxeVp8cjcyTfOxPU1uRmpm6VAchqkEmKjkcYz0rJvGDZrJMe+Tgd6vRwbU6UpTBqS1O2ZT71vRkSJtakaARITyy+3UVyXiXUTvijEqugB+6en1rJi1AqmN7D6Gut8S61a6XKipbieSRSSXPSuBv8AUZbyQlwFXP3VGAKp7q9B0OTzdLtG/wBnH5VtR1Z6ionXnIprDI6VWkjB/i5qnPCMHAqCCAeZyKutGoWqsvBqOM4cH3rcgOQKvRNxisbxB4ettQgaZcRToM7gOv1rgEvzAvl+VE+D1K1//9k="
 },
 "biometric": {
  "birthDate": "15 JUL  1993",
  "birthLocation": "Roeselare",
  "cardDeliveryMunicipality": "Avelgem",
  "cardNumber": "592124058233",
  "cardValidityDateBegin": "27.05.2015",
  "cardValidityDateEnd": "27.05.2025",
  "chipNumber": "...==",
  "documentType": "01",
  "firstNames": "Gilles Frans",
  "name": "Platteeuw",
  "nationalNumber": "...",
  "nationality": "Belg",
  "nobleCondition": "",
  "pictureHash": "...=",
  "rawData": "...+axEIuyskBgFySsp/",
  "sex": "M",
  "signature": ".../OlA44h4YCM/h+J14xUCg/98Y9/.../C/RB2dtVbHwFvDuafmr4ZEshTlZTLidHKlISFvFWOtsLAEPCbl5LjfQwcOKe0pDADtHb4IStBnr+aaE8oHsTaKq66Y+zt+AbwdmWOrMA5URKKf7dZkY7jt3h8KZDw36VjcytUgjxVIdqwHsDkmIjK6mJtakIwybS5wn3RiQj33/vgG7JTRZJoKgDXLLTvLZO4qlfA==",
  "specialStatus": "0",
  "thirdName": "J",
  "version": "0"
 },
 "address": {
  "municipality": "Hoeselt",
  "rawData": "...==",
  "signature": "...+Evety1PnTE4pqXaHgBxIpk+P8kRL5W3zDV+../../..+YoHBC9KqTmSpl5KULxdnKiyCt+2RyJdzE2wyoymjRmysIhJy1wW9PRnx99S1TFqQLuc0tyBmkBPR4aFqmOq4a7zqd0q2Q1g+BbnwJ4d3oa10ia5+0kBXf0THoXv3HYIHlnwhBMfAtWzPnFrYBuAKTwyl7yBF5IFfXFpGWuVZUTJElgNcmNvsHMnAhVwDw==",
  "streetAndNumber": "Kerkstraat X",
  "version": "0",
  "zipcode": "3730"
 }
}
var filter = ['biometric'];
generic.allData(module, { filters: filter }, callback);
{
 "biometric": {
  "birthDate": "15 JUL  1993",
  "birthLocation": "Roeselare",
  "cardDeliveryMunicipality": "Avelgem",
  "cardNumber": "592124058233",
  "cardValidityDateBegin": "27.05.2015",
  "cardValidityDateEnd": "27.05.2025",
  "chipNumber": "...==",
  "documentType": "01",
  "firstNames": "Gilles Frans",
  "name": "Platteeuw",
  "nationalNumber": "...",
  "nationality": "Belg",
  "nobleCondition": "",
  "pictureHash": "...=",
  "rawData": "...+axEIuyskBgFySsp/",
  "sex": "M",
  "signature": ".../OlA44h4YCM/h+J14xUCg/98Y9/.../C/RB2dtVbHwFvDuafmr4ZEshTlZTLidHKlISFvFWOtsLAEPCbl5LjfQwcOKe0pDADtHb4IStBnr+aaE8oHsTaKq66Y+zt+AbwdmWOrMA5URKKf7dZkY7jt3h8KZDw36VjcytUgjxVIdqwHsDkmIjK6mJtakIwybS5wn3RiQj33/vgG7JTRZJoKgDXLLTvLZO4qlfA==",
  "specialStatus": "0",
  "thirdName": "J",
  "version": "0"
 }
}
var filter = [];
generic.allCerts(module, parseCerts, { filters: filter}, callback);
{
 "rootCertificate": {
 ...
 },
 "authenticationCertificate": {
 ...
 },
 "nonRepudiationCertificate": {
 ...
 },
 "intermediateCertificates": {
 ...
 },
 "encryptionCertificate": {
 ...
 }
}
var filter = ['rootCertificate'];
generic.allCerts(module, { filters: filter}, callback);
{
 "rootCertificate": {
  ...
 }
}
var filter = null;
generic.allCerts(module, { filters: filter}, callback);
{
 "rootCertificate": {
 ...
 },
 "authenticationCertificate": {
 ...
 },
 "nonRepudiationCertificate": {
 ...
 },
 "intermediateCertificates": {
 ...
 },
 "encryptionCertificate": {
 ...
 }
}
var data = {
      "pin":"...",
      "algorithm":"sha1",
      "data":"I2e+u/sgy7fYgh+DWA0p2jzXQ7E=",
      "osDialog": true
}
generic.sign(module, data, callback);
{
  "success": true,
  "data": {
    "data" : "W7wqvWA8m9S...="
  }
}
var data = {
      "algorithm":"sha1",
      "data":"I2e+u/sgy7fYgh+DWA0p2jzXQ7E=",
      "osDialog": false
}
generic.sign(module, data, callback);
{
  "success": true,
  "data": {
    "data" : "W7wqvWA8m9S...="
  }
}
var data = {
      "algorithm":"sha256",
      "data":"vl5He0ulthjX+VWNM46QX7vJ8VvXMq2k/Tq8Xq1bwEw=",
      "osDialog": false
}
generic.signRaw(module, data, callback);
const data = {
    algorithm: "sha256",
    data: "E1uHACbPvhLew0gGmBH83lvtKIAKxU2/RezfBOsT6Vs=",
    pin: "1234"
}
const bulk = true;
generic.sign(module, data, bulk).then(res => {
}, err => {
    console.error(err)
})
generic.resetBulkPin(module).then(res => {
}, err => {
    console.error(err)
})
{
    "success": true,
    "data": true
}
var data = {
      "pin":"..."
}
generic.verifyPin(module, data, callback);
{
  "verified": true
}
var data = {}
generic.verifyPin(module, data, callback);
{
  "verified": true
}
var data = {
  "pin": "...",
  "algorithm": "sha1",
  "data":"I2e+u/sgy7fYgh+DWA0p2jzXQ7E="
}
generic.authenticate(module, data, callback);
{
  "success": true,
  "data": {
    "data" : "W7wqvWA8m9S...="
  }
}
generic.allAlgoRefs(module, callback);
{
    "success": true,
    "data": ["sha1", "sha256"]
The Belgian eID container facilitates communication with card readers with inserted Belgian eID smart card. The T1C-JS client library provides function to communicate with the smart card and facilitates integration into a web or native application. This document describes the functionality provided by the Belgian eID container on the T1C

hashtag
Interface

hashtag
Models

All model information can be found in the Token typings model page

hashtag
Get Belgian eID container object

Initialise a Trust1Connector client:

Get the Belgian eID container service:

Call a function for the Belgian eID container:

hashtag
Obtain the Reader-ID

The constructor for the Belgian eID expect as the parameter to be a valid reader-ID. A reader-ID can be obtained from the exposed core functionality, for more information see Core services responds with available card-readers, available card in a card-reader, etc. For example: In order to get all connected card-readers, with available cards:

This function call returns:

We notice that a card object is available in the response in the context of a detected reader. The reader in the example above is Bit4id miniLector, has no pin-pad capabilities, and there is a card detected with given ATR and description "Belgian eID Card". An ATR (Answer To Reset) identifies the type of a smart-card. The reader, has a unique ID, reader_id; this reader_id must be used in order to request functionalities for the Belgian eID card. This must be done upon instantiation of the Belgian eID container:

All methods for beid will use the selected reader - identified by the reader_id.

hashtag
Cardholder Information

The card holder is the person identified using the Belgian eID card. It's important to note that all data must be validated in your backend. Data validation can be done using the appropriate certificate (public key).

hashtag
Biometric data

Contains all card holder related data, excluding the card holder address and photo. The service can be called:

An example callback:

Response:

hashtag
Address

Contains the card holder's address. The service can be called:

Response:

hashtag
Picture

Contains the card holder's picture stored on the smart card. The service can be called:

Response:

hashtag
Token info

The token info contains generic information about the card and it's capabilities. This information includes the serial number, file types for object directory files, algorithms implemented on the card, etc.

Response can either be a BaseTokenInfo or a PKCS11TokenInfo object. Depending if its a pkcs11 token or not

hashtag
Certificates

Exposes all the certificates publicly available on the smart card.

hashtag
Extended certificates

You can also fetch the extended versions of the certificates via the functions

this has the capabilities to return multiple certificates if the token has multiple of this type.

for a single certificate the response looks like:

the allCertsExtended returns the following, with the contents of the certificates as the one you can see above;

hashtag
Root Certificate

Contains the 'root certificate' stored on the smart card. The root certificate is used to sign the 'citizen CA certificate'. When additional parsing of the certificate is needed you can add a boolean to indicate if you want to parse the certificate or not. The service can be called:

Response:

hashtag
Authentication Certificate

Contains the 'authentication certificate' stored on the smart card. The 'authentication certificate' contains the public key corresponding to the private RSA authentication key. The 'authentication certificate' is needed for pin validation and authentication. When additional parsing of the certificate is needed you can add a boolean to indicate if you want to parse the certificate or not The service can be called:

Response:

hashtag
Intermediate Certificate (citizen)

Contains the citizen certificate stored on the smart card. The 'citizen certificate' is used to sign the 'authentication certificate' and the 'non-repudiation certificate'. When additional parsing of the certificate is needed you can add a boolean to indicate if you want to parse the certificate or not The service can be called:

Response:

hashtag
Non-repudiation Certificate

Contains the 'non-repudiation certificate' stored on the smart card. The 'non-repudiation certificate' contains the public key corresponding the private RSA non-repudiation key. When additional parsing of the certificate is needed you can add a boolean to indicate if you want to parse the certificate or not The service can be called:

Response:

hashtag
Encryption Certificate (RRN)

Contains the 'encryption certificate' stored on the smart card. The 'encryption certificate' corresponds to the private key used to sign the 'biometric' and 'Address' data. When additional parsing of the certificate is needed you can add a boolean to indicate if you want to parse the certificate or not The service can be called:

Response:

hashtag
Data Filter

hashtag
Filter Card Holder Data

All data on the smart card can be dumped at once, or using a filter. In order to read all data at once:

circle-info

Options are; biometric, picture and address

Response:

The filter can be used to ask a list of custom data containers. For example, we want to read only the biometric data

Response:

hashtag
Filter Certificates

All certificates on the smart card can be dumped at once, or using a filter. In order to read all certificates at once:

Response:

The filter can be used to ask a list of custom data containers. For example, we want to read only the rootCertificate

Response:

hashtag
Sign Data

hashtag
Algorithm

As the Beid module incorperates Beid 1.7 and 1.8 there is a difference in the algorithms being used. In 1.7 we have the following;

  • md5

  • sha1

  • sha256

  • sha512

For beid 1.8 we have;

  • sha2_256

  • sha2_384

  • sha2_512

  • sha3_256

  • sha3_384

  • sha3_512

As we've noticed most integrators use sha256 and to make sure current integrations do not break we have made the Trust1Connector to map sha256 to sha3_256 for beid 1.8. Ofcourse if you want to use a specifc supported algorithm you can still select them.

By default the 1.7 will fall back to sha256 and 1.8 to sha3_256 if an incompatible algorithm is passed to the function.

The tables below explain which algorithm will be used when providing a certain algorithm value in the function;

hashtag
Belgian EID 1.7

Provided algorithm value

Selected algorithm by T1C

md5

md5

sha1

sha1

sha256

sha256

sha512

sha512

any other value

sha256

hashtag
Belgian EID 1.8

Provided algorithm value

Selected algorithm by T1C

sha2_256

sha2_256

sha2_384

sha2_384

sha2_512

sha2_512

sha3_256

sha3_256

sha3_384

sha3_384

hashtag
Signing

Data can be signed using the Belgian eID smart card. To do so, the T1C facilitates in:

  • Retrieving the certificate chain (citizen-certificate, root-certificate and non-repudiation certificate)

  • Perform a sign operation (private key stays on the smart card)

  • Return the signed hash

To get the certificates necessary for signature validation in your back-end:

Response:

Depending on the connected smart card reader. A sign can be executed in 2 modes:

  • Using a connected card reader with 'pin-pad' capabilities (keypad and display available)

  • Using a connected card reader without 'pin-pad' capabilities (no keypad nor display available)

Security consideration: In order to sign a hash, security considerations prefer using a 'pin-pad'.

hashtag
Signing with a Crelan card reader

When signing with a crelan card reader, it is additionally possible to optionally specify a transaction ID and the language. If the card reader is not a Crelan reader, these values will be ignored. This applies to all signing methods described below.

circle-exclamation

Crelan card readers only support nl, fr, and de as languages

hashtag
Sign Hash without pin-pad

When the web or native application is responsible for showing the password input, the following request is used to sign a given hash:

Response is a base64 encoded signed hash:

hashtag
Sign Hash with pin-pad

When the pin entry is done on the pin-pad, the following request is used to sign a given hash:

Response is a base64 encoded signed hash:

The core services lists connected readers, and if they have pin-pad capability. You can find more information in the Core Service documentation on how to verify card reader capabilities.

hashtag
Raw data signing

With the function signRaw you can sign unhashed document data. This means that the Trust1Connector will hash the value itself depending on the provided sign algorithm.

circle-exclamation

Trust1Connector only supports SHA2 hashing at this point.

SHA3 digest is used for the new Belgian eID cards (v1.8). The Trust1Connector falls back in this sitution by using implicitly a SHA2 digest.

Below you can find an example

The function looks the same as a regular sign operation but expects a base64 data object that is unhashed.

Supported hash functions (SHA2) are;

  • SHA256

  • SHA384

  • SHA512

hashtag
Bulk Signing

It is possible to bulk sign data without having to re-enter the PIN by adding an optional bulk parameter set to true to the request. Subsequent sign requests will not require the PIN to be re-entered until a request with bulk being set to false is sent, or the Bulk Sign Reset method is called.

triangle-exclamation

When using bulk signing, great care must be taken to validate that the first signature request was successful prior to sending subsequent requests. Failing to do this will likely result in the card being blocked.

hashtag
Bulk PIN Reset

The PIN set for bulk signing can be reset by calling this method.

Response will look like:

hashtag
Calculate Hash

In order to calculate a hash from the data to sign, you need to know the algorithm you will use in order to sign.

You can use the following online tool to calculate the SHA256: calculate SHA256arrow-up-right

Hexadecimal result:

Notice that the length of the SHA256 is always the same. Now we need to convert the hexadecimal string to a base64-encoded string, another online tool can be used for this example: hex to base64 converterarrow-up-right

Base64-encoded result:

Now we can sign the data:

Result:

Note: If you want to convert a binary signed hash to HEX (for development) you can use for example an online hexdump tool:

http://www.fileformat.info/tool/hexdump.htmarrow-up-right

hashtag
Verify PIN

hashtag
Verify PIN without pin-pad

When the web or native application is responsible for showing the password input, the following request is used to verify a card holder PIN:

Response:

hashtag
Verify PIN with pin-pad

When the pin entry is done on the pin-pad, the following request is used to verify a given PIN:

Response:

hashtag
Verify PIN - retries left

In order to inform a user upon the PIN retries left, the Belgian eID doesn't provide a request to retrieve this information. After an unsuccessful PIN verification, the error code indicates the number of retries left. For example, when executing:

Note that, when the user has at least one retry left, entering a correct PIN resets the PIN retry status.

For more information about the error codes you can check the Error codes page

hashtag
Authentication

hashtag
Algorithm

As the Beid module incorperates Beid 1.7 and 1.8 there is a difference in the algorithms being used. In 1.7 we have the following;

  • md5

  • sha1

  • sha256

  • sha512

For beid 1.8 we have;

  • sha2_256

  • sha2_384

  • sha2_512

  • sha3_256

  • sha3_384

  • sha3_512

As we've noticed most integrators use sha256 and to make sure current integrations do not break we have made the Trust1Connector to map sha256 to sha3_256 for beid 1.8. Ofcourse if you want to use a specifc supported algorithm you can still select them.

By default the 1.7 will fall back to sha256 and 1.8 to sha3_256 if an incompatible algorithm is passed to the function.

The tables below explain which algorithm will be used when providing a certain algorithm value in the function;

hashtag
Belgian EID 1.7

Provided algorithm value

Selected algorithm by T1C

md5

md5

sha1

sha1

sha256

sha256

sha512

sha512

any other value

sha256

hashtag
Belgian EID 1.8

Provided algorithm value

Selected algorithm by T1C

sha2_256

sha2_256

sha2_384

sha2_384

sha2_512

sha2_512

sha3_256

sha3_256

sha3_384

sha3_384

The T1C is able to authenticate a card holder based on a challenge. The challenge can be:

  • provided by an external service

  • provided by the smart card An authentication can be interpreted as a signature use case, the challenge is signed data, that can be validated in a back-end process.

    External Challenge

    An external challenge is provided in the data property of the following example:

    Response:

    Take notice that the PIN property can be omitted when using a smart card reader with pin-pad capabilities. The 'algorithm_reference' property can contain the following values: sha1, sha256, sha512, md5.

    Generated Challenge

    A server generated challenge can be provided to the JavaScript library. In order to do so, an additional contract must be provided with the 'OCV API' (Open Certificate Validation API).

hashtag
Get valid algorithms to use for Sign or Authenticate

Via the Trust1Connector modules you are able to retrieve available algorithms to use for Signing or Authenticate

The response you can expect is a list of algorithms, an example can be found below (the values below are purely examplatory)

var data = {
  "pin": "...",
  "algorithm": "sha1",
  "data":"I2e+u/sgy7fYgh+DWA0p2jzXQ7E="
}
client.beid(reader_id).authenticate(data, callback);
export interface AbstractEidBE {
  allData(filters?: string[] | Options, callback?: (error: T1CLibException, data: TokenAllDataResponse) => void): Promise<TokenAllDataResponse>;
  biometric(callback?: (error: T1CLibException, data: TokenBiometricDataResponse) => void): Promise<TokenBiometricDataResponse>;
  tokenData(callback?: (error: T1CLibException, data: TokenInfoResponse) => void): Promise<TokenInfoResponse>;
  address(callback?: (error: T1CLibException, data: TokenAddressResponse) => void): Promise<TokenAddressResponse>;
  picture(callback?: (error: T1CLibException, data: TokenPictureResponse) => void): Promise<TokenPictureResponse>;
  allCerts(parseCerts?: boolean, filters?: string[] | Options, callback?: (error: T1CLibException, data: TokenAllCertsResponse) => void): Promise<TokenAllCertsResponse>;
  rootCertificate(parseCerts?: boolean, callback?: (error: T1CLibException, data: TokenCertificateResponse) => void): Promise<TokenCertificateResponse>;
  intermediateCertificates(parseCerts?: boolean, callback?: (error: T1CLibException, data: TokenCertificateResponse) => void): Promise<TokenCertificateResponse>;
  authenticationCertificate(parseCerts?: boolean, callback?: (error: T1CLibException, data: TokenCertificateResponse) => void): Promise<TokenCertificateResponse>;
  nonRepudiationCertificate(parseCerts?: boolean, callback?: (error: T1CLibException, data: TokenCertificateResponse) => void): Promise<TokenCertificateResponse>;
  encryptionCertificate(parseCerts?: boolean, callback?: (error: T1CLibException, data: TokenCertificateResponse) => void): Promise<TokenCertificateResponse>;

  allCertsExtended(parseCerts?: boolean, filters?: string[] | Options, callback?: (error: T1CLibException, data: TokenAllCertsExtendedResponse) => void): Promise<TokenAllCertsExtendedResponse>;
  rootCertificateExtended(parseCerts?: boolean, callback?: (error: T1CLibException, data: TokenCertificateExtendedResponse) => void): Promise<TokenCertificateExtendedResponse>;
  intermediateCertificatesExtended(parseCerts?: boolean, callback?: (error: T1CLibException, data: TokenCertificateExtendedResponse) => void): Promise<TokenCertificateExtendedResponse>;
  authenticationCertificateExtended(parseCerts?: boolean, callback?: (error: T1CLibException, data: TokenCertificateExtendedResponse) => void): Promise<TokenCertificateExtendedResponse>;
  nonRepudiationCertificateExtended(parseCerts?: boolean, callback?: (error: T1CLibException, data: TokenCertificateExtendedResponse) => void): Promise<TokenCertificateExtendedResponse>;
  encryptionCertificateExtended(parseCerts?: boolean, callback?: (error: T1CLibException, data: TokenCertificateExtendedResponse) => void): Promise<TokenCertificateExtendedResponse>;

  verifyPin(body: TokenVerifyPinData, callback?: (error: T1CLibException, data: TokenVerifyPinResponse) => void): Promise<TokenVerifyPinResponse>;
  authenticate(body: TokenAuthenticateOrSignData, callback?: (error: T1CLibException, data: TokenAuthenticateResponse) => void): Promise<TokenAuthenticateResponse>;
  sign(body: TokenAuthenticateOrSignData, bulk?: boolean, callback?: (error: T1CLibException, data: TokenSignResponse) => void): Promise<TokenSignResponse>;
  signRaw(body: TokenAuthenticateOrSignData, bulk?: boolean, callback?: (error: T1CLibException, data: TokenSignResponse) => void): Promise<TokenSignResponse>;
  allAlgoRefs(callback?: (error: T1CLibException, data: TokenAlgorithmReferencesResponse) => void): Promise<TokenAlgorithmReferencesResponse>
  resetBulkPin(callback?: (error: T1CLibException, data: BoolDataResponse) => void): Promise<BoolDataResponse>;
}
T1CSdk.T1CClient.initialize(config).then(res => {
    client = res;
}, err => {
    console.error(error)
});
var beid = client.beid(reader_id);
function callback(err,data) {
    if(err){console.log("Error:",JSON.stringify(err, null, '  '));}
    else {console.log(JSON.stringify(data, null, '  '));}
}
beid.biometric(callback);
var core = client.core();
core.readersCardAvailable(callback);
{
  "data": [
    {
      "card": {
        "atr": "3B9813400AA503010101AD1311",
        "description": ["Belgian eID Card"]
      },
      "id": "57a3e2e71c48cee9",
      "name": "Bit4id miniLector",
      "pinpad": false
    }
  ],
  "success": true
}
var beid = client.beid(reader_id);
client.beid(reader_id).biometric(callback);
function callback(err,data) {
    if(err){
        console.log("Error:",JSON.stringify(err, null, '  '));
    }
    else {
        console.log(JSON.stringify(data, null, '  '));
    }
}
{
 "birthDate": "15 JUL  1993",
 "birthLocation": "Roeselare",
 "cardDeliveryMunicipality": "Avelgem",
 "cardNumber": "592..8233",
 "cardValidityDateBegin": "27.05.2015",
 "cardValidityDateEnd": "27.05.2025",
 "chipNumber": "U0xHk...EstwAjEpJQQg==",
 "documentType": "01",
 "firstNames": "Gilles Frans",
 "name": "Platteeuw",
 "nationalNumber": "930...154",
 "nationality": "Belg",
 "nobleCondition": "",
 "pictureHash": "Fqva9YCp...JKyn8=",
 "rawData": "AQw1OTIxMjQwNTgy...TARFBar2vWAqTW+axEIuyskBgFySsp/",
 "sex": "M",
 "signature": "hKys9WMjUm4ipg...14xUCg/98Y9/gP/vgG7JTRZJoKgDXLLTvLZO4qlfA==",
 "specialStatus": "0",
 "thirdName": "J",
 "version": "0"
}
client.beid(reader_id).address(callback);
{
 "municipality": "Hoeselt",
 "rawData": "ARJLZXJrc...AAAAAA==",
 "signature": "mhPyeRg25H...w==",
 "streetAndNumber": "Kerkstraat X",
 "version": "0",
 "zipcode": "3730"
}
client.beid(reader_id).picture(callback);
{
  "data": "/9j/4AAQSkZJRgABA...59aVpcklSDzyKUTEDGK//9k=",
  "success": true
}
{
    "info": {
        "rawData": "string",
        "version": "string",
        "serialNumber": "string",
        "label": "string",
        "prnGeneration": "string",
        "eidCompliant": "string",
        "graphicalPersoVersion": "string",
        "versionRfu": "string",
        "electricalPersoVersion": "string",
        "electricalPersoInterfaceVersion": "string",
        "changeCounter": "number",
        "activated": "string",
    },
    "infoType": "Token"
}
allCertsExtended(parseCerts?: boolean, filters?: string[] | Options, callback?: (error: T1CLibException, data: TokenAllCertsExtendedResponse) => void): Promise<TokenAllCertsExtendedResponse>;
rootCertificateExtended(parseCerts?: boolean, callback?: (error: T1CLibException, data: TokenCertificateExtendedResponse) => void): Promise<TokenCertificateExtendedResponse>;
intermediateCertificatesExtended(parseCerts?: boolean, callback?: (error: T1CLibException, data: TokenCertificateExtendedResponse) => void): Promise<TokenCertificateExtendedResponse>;
authenticationCertificateExtended(parseCerts?: boolean, callback?: (error: T1CLibException, data: TokenCertificateExtendedResponse) => void): Promise<TokenCertificateExtendedResponse>;
nonRepudiationCertificateExtended(parseCerts?: boolean, callback?: (error: T1CLibException, data: TokenCertificateExtendedResponse) => void): Promise<TokenCertificateExtendedResponse>;
encryptionCertificateExtended(parseCerts?: boolean, callback?: (error: T1CLibException, data: TokenCertificateExtendedResponse) => void): Promise<TokenCertificateExtendedResponse>;
{
    "success" : true
    "data" : {
        "certificates": [{
            "certificate"?: string,
            "certificateType"?: string,
            "id"?: string,
            "subject"?: string,
            "issuer"?: string,
            "serialNumber"?: string,
            "url"?: string,
            "hashSubPubKey"?: string,
            "hashIssPubKey"?: string,
            "exponent"?: string,
            "remainder"?: string,
            "parsedCertificate"?: Certificate
        }]
    }
}
{
    "success" : true
    "data" : {
        "rootCertificate": {
            "certificates": [...]
        },
        "authenticationCertificate": {
            "certificates": [...]
        },
        "nonRepudiationCertificate": {
            "certificates": [...]
        },
        "intermediateCertificates": {
            "certificates": [...]
        },
        "encryptionCertificate": {
            "certificates": [...]
        }
   }
}
client.beid(reader_id).rootCertificate(parseCertsBoolean, callback);
{
    success: true,
    data: {
        certificate?: string,
        certificates?: Array<string>,
        certificateType?: string,
        id?: string,
        parsedCertificate?: Certificate,
        parsedCertificates?: Array<Certificate>
    }    
}
client.beid(reader_id).authenticationCertificate(parseCertsBoolean, callback);
{
    success: true,
    data: {
        certificate?: string,
        certificates?: Array<string>,
        certificateType?: string,
        id?: string,
        parsedCertificate?: Certificate,
        parsedCertificates?: Array<Certificate>
    }    
}
client.beid(reader_id).intermediateCertificates(parseCertsBoolean, callback);
{
    success: true,
    data: {
        certificate?: string,
        certificates?: Array<string>,
        certificateType?: string,
        id?: string,
        parsedCertificate?: Certificate,
        parsedCertificates?: Array<Certificate>
    }    
}
client.beid(reader_id).nonRepudiationCertificate(parseCertsBoolean, callback);
{
    success: true,
    data: {
        certificate?: string,
        certificates?: Array<string>,
        certificateType?: string,
        id?: string,
        parsedCertificate?: Certificate,
        parsedCertificates?: Array<Certificate>
    }    
}
client.beid(reader_id).encryptionCertificate(parseCertsBoolean, callback);
{
    success: true,
    data: {
        certificate?: string,
        certificates?: Array<string>,
        certificateType?: string,
        id?: string,
        parsedCertificate?: Certificate,
        parsedCertificates?: Array<Certificate>
    }    
}
var filter = [];
client.beid(reader_id).allData({ filters: filter}, callback);
{
 "picture": {
  "picture": "/9j/4AAQSkZJRgABAgEBLAEsAAD/.../wAALCADIAIwBAREA/8QA0gAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoLEAACAQMDAgQDBQUEBAAAAX0BAgMABBEFEiExQQYTUWEHInEUMoGRoQgjQrHBFVLR8CQzYnKCCQoWFxgZGiUmJygpKjQ1Njc4OTpDREVGR0hJSlNUVVZXWFlaY2RlZmdoaWpzdHV2d3h5eoOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4eLj5OXm5+jp6vHy8/T19vf4+fr/2gAIAQEAAD8A9JpKKWiikooooopaKSilooooopKr3d9bWaFriVEwM4J5Ncjq3jUxkixQADozjJNcze+L9WndWF20OOCI/lzRb+KtYjhIN67Z7vyf1qT/AIS3Wc5F2OnQgY/lWrovjC7hYLqJ86IkksPvCustPEumXbbUuAjYzh+K1UkWRA6MGU9CDkGn0UUUUUUUhOBk8CuY1zxOls/kWjbnH3pAMgewrz7VtWmu7gvJIzZ65NZk1wSBjOagWbn5lB+vagy7+2KlilUE7eRj1qS3ncSEE4X3qwzNs81Dgg9K19G8VXumTLFv8yDOWjb+len6bqMGp2qz2zZU8Ed1PpVyiiiiio5pkgiaSRgqKMkmuH8ReKXlMlpAAkHRnB5b29q4+e5HzAHjPFZkoLyhevH6014XUcjBqAow5xQEYjFPClDxkCnq20AkZ/xqyl2oUK4xu6n0qwgguZQ28K2Ofc1v6Pqs2lSRGJzsLAOv94d69MtriO6gSaFgyMMg1LS0UUlcn491FbfS/sicyzEH6AGvOCzuApPOakt7CWYk7TjNXE0iUNnyyfpVqPQ53XiNwPepYfDMhb94GAq5/wAIzbhc4IPpVK/8OYjzEMmsWbRZ0XIUnHtVRrR4/vqR9RSwQGXdt4Zav2rbFww6DI5ruvBuqIIjaSuMu2Y8/TpXYUtFFIa8r8W6h9v1d9mCqHYuO4FVdM0t7iZWb8a6y10+KNQCOlXFijQfKop6g9hUmw4pjoRzmopEyvIqrJEjDGKpXGnwzoQ68+1YNxpv2Ry8RPHrVGUqse4MN38Qq7o8o8kOh+dG3AjsRXpejapHqVsDkLMo+dM8/WtOiis/WrxrHTJp1GWAwOeme9eWqqzTln6k5rqNLhWKFcDmtJRk1aSPPWp0i21J5dRSx8VWKVXkQA1WmwvGDzWVegSRsp4zXNT2WwMASSxqa1kNimMBkOB9fWt7QLx4ddgaNCyyLtIHevR6Wiuf8ZsRobAdWcD+dcLYQZlHck/lXWQKEjUVZj69OlXI+manXnvTiADioXPJ4qBhVaQ/NVWbkZ7VlXeDmqRYY27Rn1rOmkDXOwKBgH8av6XOba9guVz8hA2+1epg5GaWiuf8ZqTom4fwyKf5iuS0uFiQcV0MYwgBqxH1FWl6VLGeKcxOOaaRmoZAcVTkBqrOcL61j3B5NVgducVXkeOOXLKMt1p9tIsyjaAMGvVI+I1+gp9FZXiOAT6LcKRnaN35Vy+lhfKJ9Kv+cifeYACpIry3A5kA+tW1uYmXKuD+NSRzDseKl3gjrTS47UhYAGqFxINxqhcSA8ZrPlQmq8kZArNujljkdBUuhAy3cUOOWdRXrY4FLRUN0iSW8iSkBGUg5riLGMrbzxq3IkI3CozpuWZmnkye+6qT6TlmPnkk9M1Smsbq3OUuOOvWtDTrq4j+V5CRn1rpIZy6ZNSbiBz1qneXphFcpqmqzyNiJiBnqKyl+33DDZJL9dxq2i6pDg7mYehNX7a/lx5d5EADwGHUVBeR/MfT2q/4It2n10vtykY3H29K9MpaSsLxKJJo4oI5Ci53NjvWbbweUGAH3sE5qG8DpnqB7CsKNru7umitUKgdXbqay3m1L7cluxlMm/DAqMYrqLfTW5DKAw7joa1LRCnDVNelYo91cXq13NcMfLDbAcA+tVbXTppyzMrNtGSq9RTP7VhgZY44HBP+1k1Zi1LzZNgbOexGCKS8kwQcc1LM4ayeT0Sl8M+IhpDzfuA4kwCe+BXqFldxXtrHcQnKOMjNWKSsfV48zI3qMVVwpIA5xxTpI1bqBVNrRQ25EwfVaja3cybtgz/eK81ahjKrz1pTwR6k1U1aQ/Zm57VhQKDGhAyBWxatHACUXbuHOO9Yt3plol01wkWSTnGazLixaW5EsSbSO4q5HZu6Ey9R0qLUQYNOcdA3FY1vGS4wK9f8NQtBolurdSC2PrWtRWfqoHlI3cHFZUXJJ9TU3U4xxTguKdsyM1FINtQNjcKpauC1uwHORWLYsAAhPStqOPKAjoaHhU8Fc1G0KDouKgmUBTisDXCTBGoxgtk1W02AysoUclgK9it4hDBHGOiKFqWiqWppvtT7EGsgKoGVJB7ip161KoWlY4qrctjGOpqCJd74JqLUlVYic8YrlI22ySSKehzXUWDCa2RxzkVaaMVUnXaDWXdzBVIzziuf1Pc80MS9x1rd8Maa39qxRucqhDtj2r0elopkiCRGRuhGKxJreaFipQlB/EBTA2Dih5tg4ySeAKlUnbufr6VBOpkBA4PassR3NtIZJJ/MB/h24xWDr+rySYihU+/NZULXMkXlrHyepFdfoYaG1RG5IFa7yZTIrNv5gqHmudnn3zgdeazrjL3+7PyggV6J4QgY28ly643YRT64610tFFJTXXcjL6jFc+/BIP8ACcUKoEm888YFI13GuVkbafehZ4uu8UOYpVwGGazp9KtmYs2AfempZQx524pyusRAyKkEuXU9jxWNrUxUsnc1k26F50U9WIFd1F4N08XCzu0rdCUJ4Jro0RY0VEUKqjAA7U+iiikrCvV2Xki9ic1BExDYPOKL6xhvIdrqM9j6VjmwNuNiu6/8CzUiW0uw73bOOCADVO7hulGRIxY9iOKy5RfgnbKB+NLZWWp3EwMtwBHnPU8106xrFGiZzt5JNcpqdyLnVWVOUU81a0GL7TrdsmMgOCfoDmvUaWiiiikrM1aHlJh0HBrNBAcZqcnH0qJ1EnBGaqvGy/dPFU51mfv+tVRaNnLc/Wp0cRLgHmqup35hs2AJ8xxgYrBijKRlm+8eSa6nwLbbryW4b+EYFd5RRRRRRVXURmxlz7fzrmDJ820noavoQ0WCcmlQZpXjBGarMijpzVedBtJNZczbSTmsW6k864BY/Kvaomk3sFB4rtfBO398F6BcV19FFFFFFVr/AJs5fpXLXEJK716imWt5tOxzir6Tqe9JLcAcbhUTTrt4Iqhc3IOQGrA1C/CcZ56VkPOzHr1p0JZ32r07mu/8ELsaYZ5K5rsKKKKSloqtfnFnL9KwkAP41Qv7I53R9ax5ri5tzhg31qm+qzdDzUb6zKBjAqlNqkrZxwTWe8jSOSSSalhiaRgO1a1tAsYA711/hA7bpx6qa7CikpaSio1njZioYZHWs/UdQtmhlgjnjeUYyinJHPes2M5HNPYDbiqr28cvyuoIqjceH7eQ5AI+lZ0vhyME4Z/zqjPoiRZ5aqBslRulXbe3woOKtLGc8itvQJxbXqseh4NdRPqaxpujjMnqAcYHrToNShlAz8h96mkvLeJQ0k8aKe7MBT0uIZF3JNGy+qsCKqajfx2gUFvmJ6ZrB1HxUkSttIGOOtcpfeK5jC8dsxDP1f0+laehxeVp8cjcyTfOxPU1uRmpm6VAchqkEmKjkcYz0rJvGDZrJMe+Tgd6vRwbU6UpTBqS1O2ZT71vRkSJtakaARITyy+3UVyXiXUTvijEqugB+6en1rJi1AqmN7D6Gut8S61a6XKipbieSRSSXPSuBv8AUZbyQlwFXP3VGAKp7q9B0OTzdLtG/wBnH5VtR1Z6ionXnIprDI6VWkjB/i5qnPCMHAqCCAeZyKutGoWqsvBqOM4cH3rcgOQKvRNxisbxB4ettQgaZcRToM7gOv1rgEvzAvl+VE+D1K1//9k="
 },
 "biometric": {
  "birthDate": "15 JUL  1993",
  "birthLocation": "Roeselare",
  "cardDeliveryMunicipality": "Avelgem",
  "cardNumber": "592124058233",
  "cardValidityDateBegin": "27.05.2015",
  "cardValidityDateEnd": "27.05.2025",
  "chipNumber": "...==",
  "documentType": "01",
  "firstNames": "Gilles Frans",
  "name": "Platteeuw",
  "nationalNumber": "...",
  "nationality": "Belg",
  "nobleCondition": "",
  "pictureHash": "...=",
  "rawData": "...+axEIuyskBgFySsp/",
  "sex": "M",
  "signature": ".../OlA44h4YCM/h+J14xUCg/98Y9/.../C/RB2dtVbHwFvDuafmr4ZEshTlZTLidHKlISFvFWOtsLAEPCbl5LjfQwcOKe0pDADtHb4IStBnr+aaE8oHsTaKq66Y+zt+AbwdmWOrMA5URKKf7dZkY7jt3h8KZDw36VjcytUgjxVIdqwHsDkmIjK6mJtakIwybS5wn3RiQj33/vgG7JTRZJoKgDXLLTvLZO4qlfA==",
  "specialStatus": "0",
  "thirdName": "J",
  "version": "0"
 },
 "address": {
  "municipality": "Hoeselt",
  "rawData": "...==",
  "signature": "...+Evety1PnTE4pqXaHgBxIpk+P8kRL5W3zDV+../../..+YoHBC9KqTmSpl5KULxdnKiyCt+2RyJdzE2wyoymjRmysIhJy1wW9PRnx99S1TFqQLuc0tyBmkBPR4aFqmOq4a7zqd0q2Q1g+BbnwJ4d3oa10ia5+0kBXf0THoXv3HYIHlnwhBMfAtWzPnFrYBuAKTwyl7yBF5IFfXFpGWuVZUTJElgNcmNvsHMnAhVwDw==",
  "streetAndNumber": "Kerkstraat X",
  "version": "0",
  "zipcode": "3730"
 }
}
var filter = ['biometric'];
client.beid().allData({ filters: filter }, callback);
{
 "biometric": {
  "birthDate": "15 JUL  1993",
  "birthLocation": "Roeselare",
  "cardDeliveryMunicipality": "Avelgem",
  "cardNumber": "592124058233",
  "cardValidityDateBegin": "27.05.2015",
  "cardValidityDateEnd": "27.05.2025",
  "chipNumber": "...==",
  "documentType": "01",
  "firstNames": "Gilles Frans",
  "name": "Platteeuw",
  "nationalNumber": "...",
  "nationality": "Belg",
  "nobleCondition": "",
  "pictureHash": "...=",
  "rawData": "...+axEIuyskBgFySsp/",
  "sex": "M",
  "signature": ".../OlA44h4YCM/h+J14xUCg/98Y9/.../C/RB2dtVbHwFvDuafmr4ZEshTlZTLidHKlISFvFWOtsLAEPCbl5LjfQwcOKe0pDADtHb4IStBnr+aaE8oHsTaKq66Y+zt+AbwdmWOrMA5URKKf7dZkY7jt3h8KZDw36VjcytUgjxVIdqwHsDkmIjK6mJtakIwybS5wn3RiQj33/vgG7JTRZJoKgDXLLTvLZO4qlfA==",
  "specialStatus": "0",
  "thirdName": "J",
  "version": "0"
 }
}
var filter = [];
client.beid(reader_id).allCerts(parseCerts, { filters: filter}, callback);
{
 "rootCertificate": {
  ...
 },
 "authenticationCertificate": {
  ...
 },
 "nonRepudiationCertificate": {
  ...
 },
 "intermediateCertificates": {
  ...
 },
 "encryptionCertificate": {
  ...
 }
}
var filter = ['rootCertificate'];
client.beid(reader_id).allCerts(parseCerts, { filters: filter}, callback);
{
 "rootCertificate": {
  ...
 }
}
var filter = null;
client.beid(reader_id).allCerts(parseCerts, { filters: filter}, callback);
{
 "rootCertificate": {
  ...
 },
 "authenticationCertificate": {
  ...
 },
 "nonRepudiationCertificate": {
  ...
 },
 "intermediateCertificates": {
  ...
 },
 "encryptionCertificate": {
  ...
 }
}
var data = {
      "pin":"...",
      "algorithm":"sha1",
      "data":"I2e+u/sgy7fYgh+DWA0p2jzXQ7E=",
      "osDialog": true,
      "txId": "1234",
      "language": "fr"
}
client.beid(reader_id).sign(data, callback);
var data = {
      "pin":"...",
      "algorithm":"sha1",
      "data":"I2e+u/sgy7fYgh+DWA0p2jzXQ7E=",
      "osDialog": true
}
client.beid(reader_id).sign(data, callback);
{
  "success": true,
  "data": {
    "data" : "W7wqvWA8m9S...="
  }
}
var data = {
      "algorithm":"sha1",
      "data":"I2e+u/sgy7fYgh+DWA0p2jzXQ7E=",
      "osDialog": false
}
client.beid(reader_id).sign(data, callback);
{
  "success": true,
  "data": {
    "data" : "W7wqvWA8m9S...="
  }
}
var data = {
      "algorithm":"sha256",
      "data":"vl5He0ulthjX+VWNM46QX7vJ8VvXMq2k/Tq8Xq1bwEw=",
      "osDialog": false
}
beid.signRaw(data, callback);
const data = {
    algorithm: "sha256",
    data: "E1uHACbPvhLew0gGmBH83lvtKIAKxU2/RezfBOsT6Vs=",
    pin: "1234"
}
const bulk = true;
beid.sign(data, bulk).then(res => {
}, err => {
    console.error(err)
})
beid.resetBulkPin().then(res => {
}, err => {
    console.error(err)
})
{
    "success": true,
    "data": true
}
This is sample text to demonstrate siging with Belgian eID
135b870026cfbe12dec348069811fcde5bed28800ac54dbf45ecdf04eb13e95b
E1uHACbPvhLew0gGmBH83lvtKIAKxU2/RezfBOsT6Vs=
var data = {
      "pin":"...",
      "algorithm":"sha256",
      "data":"E1uHACbPvhLew0gGmBH83lvtKIAKxU2/RezfBOsT6Vs="
}
client.beid(reader_id).signData(data, callback);
{
  "success": true,
  "data": {
    "data" : "W7wqvWA8m9S...="
  }
}
var data = {
      "pin":"..."
}
client.beid(reader_id).verifyPin(data, callback);
{
  "verified": true
}
var data = {}
client.beid(reader_id).verifyPin(data, callback);
{
  "verified": true
}
  $("#buttonValidate").on('click', function () {
      var _body={};
      _body.pin = $("#psw").val(); //only when no pin-pad available
      var beid = client.beid(reader_id);
      beid.verifyPin(_body, validationCallback);
  });
The calculated digest of the hash is prefixed with:
DigestInfo ::= SEQUENCE {
      digestAlgorithm AlgorithmIdentifier,
      digest OCTET STRING
  }
Make sure this has been taken into consideration in order to validate the signature in a backend process.
generic.allAlgoRefs(module, callback);
{
    "success": true,
    "data": ["sha1", "sha256"]
}

sha3_512

sha3_512

sha256

sha3_256

sha384

sha3_384

sha512

sha3_512

any other value

sha3_256

sha3_512

sha3_512

sha256

sha3_256

sha384

sha3_384

sha512

sha3_512

any other value

sha3_256

{
  "success": true,
  "data": {
    "data" : "W7wqvWA8m9S...="
  }
}

Chambersign

circle-exclamation

Sample code uses ES6 language features such as arrow functions and promises. For compatibility with IE11, code written with these features must be either transpiled using tools like Babel or refactored accordingly using callbacks

hashtag
Chambersign introduction

The Chambersign token is a token that requires for the middleware of Chambersign to be installed prior to using it on the Trust1Connector.

circle-info

The middleware of Chambersign has to be installed to be able to fully use the Chambersign

The version of the middleware supported is; Mac: Windows:

hashtag
Interface

hashtag
Models

All model information can be found in the

hashtag
Initialise the Trust1Connector JS

Initialise a Trust1Connector client with a valid configuration:

hashtag
Obtain the Reader information

In order to get all connected card-readers, with available cards:

This function call returns:

Using the generic interface can be done as follows;

Because we're using the generic interface we can define the module variable upfront since we know we want to use the chambersign integration.

If you want to use the module directly you can initialise as folows (same functions are available but dont need the module to be included in the called function)

hashtag
Token info

You can fetch the token information via the function. this will give all the information of the token you need according to the PKCS11 specifications

hashtag
Certificates

Exposes all the certificates publicly available on the smart card.

hashtag
Authentication Certificate

Contains the 'authentication certificate' stored on the smart card. The 'authentication certificate' contains the public key corresponding to the private RSA authentication key. The 'authentication certificate' is needed for pin validation and authentication. When additional parsing of the certificate is needed you can add a boolean to indicate if you want to parse the certificate or not The service can be called:

Response:

hashtag
Non-repudiation Certificate

Contains the 'non-repudiation certificate' stored on the smart card. The 'non-repudiation certificate' contains the public key corresponding the private RSA non-repudiation key. When additional parsing of the certificate is needed you can add a boolean to indicate if you want to parse the certificate or not The service can be called:

Response:

hashtag
Filter Certificates

All certificates on the smart card can be dumped at once, or using a filter. In order to read all certificates at once:

Response:

The filter can be used to ask a list of custom data containers. For example, we want to read only the rootCertificate

Response:

hashtag
Sign Data

To get the certificates necessary for signature validation in your back-end:

Response:

Depending on the connected smart card reader. A sign can be executed in 2 modes:

  • Using a connected card reader with 'pin-pad' capabilities (keypad and display available)

  • Using a connected card reader without 'pin-pad' capabilities (no keypad nor display available)

Security consideration: In order to sign a hash, security considerations prefer using a 'pin-pad'.

hashtag
Sign Hash without pin-pad

When the web or native application is responsible for showing the password input, the following request is used to sign a given hash:

Response is a base64 encoded signed hash:

hashtag
Sign Hash with pin-pad

When the pin entry is done on the pin-pad, the following request is used to sign a given hash:

Response is a base64 encoded signed hash:

The core services lists connected readers, and if they have pin-pad capability. You can find more information in the Core Service documentation on how to verify card reader capabilities.

hashtag
Raw data signing

With the function signRaw you can sign unhashed document data. This means that the Trust1Connector will hash the value itself depending on the provided sign algorithm.

circle-exclamation

Trust1Connector only supports SHA2 hashing at this point.

When using SHA3, the Trust1Connector will convert to SHA2 implicitly

Below you can find an example

The function looks the same as a regular sign operation but expects a base64 data object that is unhashed.

Supported hash functions (SHA2) are;

  • SHA256

  • SHA384

  • SHA512

hashtag
Bulk Signing

It is possible to bulk sign data without having to re-enter the PIN by adding an optional bulk parameter set to true to the request. Subsequent sign requests will not require the PIN to be re-entered until a request with bulk being set to false is sent, or the method is called.

triangle-exclamation

When using bulk signing, great care must be taken to validate that the first signature request was successful prior to sending subsequent requests. Failing to do this will likely result in the card being blocked.

hashtag
Bulk PIN Reset

The PIN set for bulk signing can be reset by calling this method.

Response will look like:

hashtag
Verify PIN

hashtag
Verify PIN without pin-pad

When the web or native application is responsible for showing the password input, the following request is used to verify a card holder PIN:

Response:

hashtag
Verify PIN with pin-pad

When the pin entry is done on the pin-pad, the following request is used to verify a given PIN:

Response:

hashtag
Authentication

The T1C-GCL is able to authenticate a card holder based on a challenge. The challenge can be:

  • provided by an external service

  • provided by the smart card An authentication can be interpreted as a signature use case, the challenge is signed data, that can be validated in a back-end process.

    External Challenge

    An external challenge is provided in the data property of the following example:

Response:

Take notice that the PIN property can be omitted when using a smart card reader with pin-pad capabilities.

hashtag
Get valid algorithms to use for Sign or Authenticate

Via the Trust1Connector generic modules you are able to retrieve available algorithms to use for Signing or Authenticate

The response you can expect is a list of algorithms, an example can be found below (the values below are purely examplatory)

hashtag
Validate signature

The module allows you to call a function on the token that can validate a signature. For this we need to use the validateSignature function. You can call this one via;

The response of this function will return a valid property that is either true or false.

6.17.1arrow-up-right
6.12.0arrow-up-right
Token typings model page
Bulk Sign Reset
export interface AbstractChambersign {
    allCerts(parseCerts?: boolean, filters?: string[] | Options, callback?: (error: T1CLibException, data: TokenAllCertsResponse) => void): Promise<TokenAllCertsResponse>;
    authenticationCertificate(parseCerts?: boolean, callback?: (error: T1CLibException, data: TokenCertificateResponse) => void): Promise<TokenCertificateResponse>;
    nonRepudiationCertificate(parseCerts?: boolean, callback?: (error: T1CLibException, data: TokenCertificateResponse) => void): Promise<TokenCertificateResponse>;

    allCertsExtended(parseCerts?: boolean, filters?: string[] | Options, callback?: (error: T1CLibException, data: TokenAllCertsExtendedResponse) => void): Promise<TokenAllCertsExtendedResponse>;
    authenticationCertificateExtended(parseCerts?: boolean, callback?: (error: T1CLibException, data: TokenCertificateExtendedResponse) => void): Promise<TokenCertificateExtendedResponse>;
    nonRepudiationCertificateExtended(parseCerts?: boolean, callback?: (error: T1CLibException, data: TokenCertificateExtendedResponse) => void): Promise<TokenCertificateExtendedResponse>;

    validateSignature(body: TokenValidateSignatureRequest, callback?: (error: T1CLibException, data: TokenValidateSignatureResponse) => void): Promise<TokenValidateSignatureResponse>;

    verifyPin(body: TokenVerifyPinData, callback?: (error: T1CLibException, data: TokenVerifyPinResponse) => void): Promise<TokenVerifyPinResponse>;
    authenticate(body: TokenAuthenticateOrSignData, callback?: (error: T1CLibException, data: TokenAuthenticateResponse) => void): Promise<TokenAuthenticateResponse>;
    sign(body: TokenAuthenticateOrSignData, bulk?: boolean, callback?: (error: T1CLibException, data: TokenSignResponse) => void): Promise<TokenSignResponse>;
    signRaw(body: TokenAuthenticateOrSignData, bulk?: boolean, callback?: (error: T1CLibException, data: TokenSignResponse) => void): Promise<TokenSignResponse>;
    allAlgoRefs(callback?: (error: T1CLibException, data: TokenAlgorithmReferencesResponse) => void): Promise<TokenAlgorithmReferencesResponse>
    resetBulkPin(callback?: (error: T1CLibException, data: BoolDataResponse) => void): Promise<BoolDataResponse>;
    tokenData(callback?: (error: T1CLibException, data: TokenInfoResponse) => void): Promise<TokenInfoResponse>;
}
T1CSdk.T1CClient.initialize(config).then(res => {
    client = res;
}, err => {
    console.error(error)
});
var core = client.core();
core.readersCardAvailable(callback);
{
  "data": [
    // List of reader with cards found
  ],
  "success": true
}
const moduleName = "chambersign";
var module = client.generic(selected_reader.id);
var module = client.chambersign(selected_reader.id);
module.tokenData().then(res => {
    // see response below
})
{
    "success": true,
    "data": {
        "info": {
            "slot": "string",
            "label": "string",
            "manufacturerId": "string",
            "model": "string",
            "serialNumber": "string",
            "flags": {
                "isRandomNumberGenerator": "boolean",
                "isWriteProtected": "boolean",
                "isLoginRequired": "boolean",
                "isUserPinInitialized": "boolean",
                "isRestoreKeyNotNeeded": "boolean",
                "isClockOnToken": "boolean",
                "isProtectedAuthenticationPath": "boolean",
                "isDualCryptoOperations": "boolean",
                "isTokenInitialized": "boolean",
                "isSecondaryAuthentication": "boolean",
                "isUserPinCountLow": "boolean",
                "isUserPinFinalTry": "boolean",
                "isUserPinLocked": "boolean",
                "isUserPinToBeChanged": "boolean",
                "isSoPinCountLow": "boolean",
                "isSoPinFinalTry": "boolean",
                "isSoPinLocked": "boolean",
                "isSoPinToBeChanged": "boolean"
            },
            "mechanisms": [
                {
                    "mechanism": "string",
                    "flags": {
                        "isHardware": "boolean",
                        "isEncrypt": "boolean",
                        "isDecrypt": "boolean",
                        "isDigest": "boolean",
                        "isSign": "boolean",
                        "isSignRecover": "boolean",
                        "isVerify": "boolean",
                        "isVerifyRecover": "boolean",
                        "isGenerate": "boolean",
                        "isGenerateKeyPair": "boolean",
                        "isWrap": "boolean",
                        "isUnwrap": "boolean",
                        "isExtension": "boolean",
                        "isEcFP": "boolean",
                        "isEcNamedcurve": "boolean",
                        "isEcUncompress": "boolean",
                        "isEcCompress": "boolean"
                    },
                    "ulMinKeySize": "number",
                    "ulMaxKeySize": "number"
                }
            ],
            "ulMaxSessionCount": "number",
            "ulSessionCount": "number",
            "ulMaxRwSessionCount": "number",
            "ulMaxPinLen": "number",
            "ulMinPinLen": "number",
            "ulTotalPubLicMemory": "number",
            "ulFreePubMemory": "number",
            "ulTotalPrivateMemory": "number",
            "ulFreePrivateMemory": "number",
            "hardwareVersion": "string",
            "firmwareVersion": "string"
        },
        "infoType": "TokenInfoType"
    }
}



//ENUM
TokenInfoType {
    Token,
    PKCS11,
    File,
    Payment,
    HSM,
    Vault,
    Wallet,
}
module.authenticationCertificate(module, parseCertsBoolean, callback);
{
    success: true,
    data: {
        certificate?: string,
        certificates?: Array<string>,
        certificateType?: string,
        id?: string,
        parsedCertificate?: Certificate,
        parsedCertificates?: Array<Certificate>
    }    
}
module.nonRepudiationCertificate(module, parseCertsBoolean, callback);
{
    success: true,
    data: {
        certificate?: string,
        certificates?: Array<string>,
        certificateType?: string,
        id?: string,
        parsedCertificate?: Certificate,
        parsedCertificates?: Array<Certificate>
    }    
}
var filter = [];
module.allCerts(module, parseCerts, { filters: filter}, callback);
{
 "authenticationCertificate": {
  ...
 },
 "nonRepudiationCertificate": {
  ...
 }
}
var filter = ['authenticationCertificate'];
module.allCerts(module, { filters: filter}, callback);
{
 "authenticationCertificate": {
  ...
 }
}
var filter = null;
module.allCerts(module, { filters: filter}, callback);
{
 "authenticationCertificate": {
  ...
 },
 "nonRepudiationCertificate": {
  ...
 }
}
var data = {
      "pin":"...",
      "algorithm":"sha1",
      "data":"I2e+u/sgy7fYgh+DWA0p2jzXQ7E=",
      "osDialog": true
}
module.sign(module, data, callback);
{
  "success": true,
  "data": {
    "data" : "W7wqvWA8m9S...="
  }
}
var data = {
      "algorithm":"sha1",
      "data":"I2e+u/sgy7fYgh+DWA0p2jzXQ7E=",
      "osDialog": false
}
module.sign(module, data, callback);
{
  "success": true,
  "data": {
    "data" : "W7wqvWA8m9S...="
  }
}
var data = {
      "algorithm":"sha256",
      "data":"vl5He0ulthjX+VWNM46QX7vJ8VvXMq2k/Tq8Xq1bwEw=",
      "osDialog": false
}
chambersign.signRaw(data, callback);
const data = {
    algorithm: "sha256",
    data: "E1uHACbPvhLew0gGmBH83lvtKIAKxU2/RezfBOsT6Vs=",
    pin: "1234"
}
const bulk = true;
module.sign(module, data, bulk).then(res => {
}, err => {
    console.error(err)
})
module.resetBulkPin(module).then(res => {
}, err => {
    console.error(err)
})
{
    "success": true,
    "data": true
}
var data = {
      "pin":"..."
}
module.verifyPin(module, data, callback);
{
  "verified": true
}
var data = {}
module.verifyPin(module, data, callback);
{
  "verified": true
}
var data = {
  "pin": "...",
  "algorithm": "sha1",
  "data":"I2e+u/sgy7fYgh+DWA0p2jzXQ7E="
}
module.authenticate(module, data, callback);
{
  "success": true,
  "data": {
    "data" : "W7wqvWA8m9S...="
  }
}
module.allAlgoRefs(module, callback);
{
    "success": true,
    "data": ["sha1", "sha256"]
}
const body = {
    "algorithm": 'sha256',
    "hash": '...',
    "signedHash": '...',
    "osDialog": false,
    "id": 'cert_id',
    "pin": 'pin_code',
    "timeout": 120 //timeout in seconds
}
module.validateSignature(body).then(response => {
    response.valid
).catch(error => {
    errorHandler(error)}
)
{
    "success": true,
    "data": {
        "valid": true
    }
}

LuxTrust

hashtag
Introduction

The LuxTrust smartcard container facilitates communication with card readers with inserted LuxTrust smartcards and LuxTrust Signing Sticks. The T1C-JS client library provides function to communicate with the smart card and facilitates integration into a web or native application. This document describes the functionality provided by the LuxTrust smartcard - which is a PKI container

Interface Summary

The Abstract LuxTrust smartcard interface is summarized in the following snippet:

hashtag
Additional Remarks

The LuxTrust Signing Stick can be seen as an smartcard integrated in an USB smartcard reader. The use cases described in this wiki are valid for both LuxTrust smartcards as LuxTrust Signing Stick, as there a no technical implementation differences.

hashtag
Retrieve a connected card reader

In order to start with any use case, we need to select a card reader. The targeted reader will be passed as a parameter to the subsequent methods provided. This is part of the core Trust1Connector functionality. More information about core service functionality can be found on the following page: .

For demonstration purpose we'll add a simple console output callback, which we'll use throughout the documentation.

Just as an example, we instantiate a new gcl (local client) and ask for all connected smart card readers:

This will returns us all connected readers:

In the example you'll notice that we are using a dual interface uTrust reader and a card has been inserted.

The reader id 'c8d31f8fed44d952' can be used as parameter in the next steps in order to select a smartcard reader for the functionality we want to execute. The pinpad property can be used to decided whether to pass the pin property to the reader (e.g. when verifying the pin).

hashtag
Certificates

Exposes all the certificates publicly available on the smart card. The following certificates can be found on the card:

  • Root certificate

  • Intermediate certificate

  • Authentication certificate

T1C-JS will return the raw base64 certificate, optionally it can also return an object representing the certificate as parsed by . To enable parsing, parseCerts must be set to true.

The root and intermediate certificates are both stored as root certificates.

hashtag
Certificate Chain

hashtag
Extended certificates

You can also fetch the extended versions of the certificates via the functions

this has the capabilities to return multiple certificates if the token has multiple of this type.

for a single certificate the response looks like:

the allCertsExtended returns the following, with the contents of the certificates as the one you can see above;

hashtag
Root Certificate

Contains the 'root certificate' stored on the smart card. The root certificate is used to sign the 'intermediate certificate'. The service can be called:

Response:

There are 2 root certificates on the card, one is the issuer certificate of the intermediate

hashtag
Authentication Certificate

Contains the 'authentication certificate' stored on the smart card. The 'authentication certificate' contains the public key corresponding to the private RSA authentication key. The 'authentication certificate' is needed for pin validation, authentication and singing. The service can be called:

Response:

hashtag
Signing Certificate

Contains the 'non-repudiation certificate' stored on the smart card. The 'non-repudiation certificate' contains the public key corresponding the private RSA non-repudiation key. The service can be called:

Response:

hashtag
Data Filter

hashtag
Filter Certificates

All certificates on the smart card can be dumped at once, or using a filter. In order to read all certificates at once:

Response:

The filter can be used to ask a list of custom data containers. For example, we want to read only the 'root-certificate' and the 'authentication_certificate':

Response:

hashtag
Sign Data

Data can be signed using the LuxTrust smartcard and Signing Stick. To do so, the T1C-GCL facilitates in:

  • Retrieving the certificate chain (root, intermediate and non-repudiation certificate)

  • Perform a sign operation (private key stays on the smart card)

  • Return the signed hash

To get the certificates necessary for signature validation in your back-end:

Response:

Depending on the connected smart card reader. A sign can be executed in 2 modes:

  • Using a connected card reader with 'pin-pad' capabilities (keypad and display available)

  • Using a connected card reader without 'pin-pad' capabilities (no keypad nor display available)

Security consideration: In order to sign a hash, security considerations prefer using a 'pin-pad'.

hashtag
Sign Hash

When the web or native application is responsible for showing the password input, the following request is used to sign a given hash:

hashtag
Without a pinpad reader

hashtag
With a pinpad reader

Response is a base64 encoded signed hash:

The 'authentication_reference' property can contain the following values: sha1 and sha256.

Avoid using SHA-1: is deprecated on the interface and will not be available in the future

The LuxTrust smartcard and Signing Stick is not supporting SHA512 at the moment.

hashtag
Calculate Hash

In order to calculate a hash from the data to sign, you need to know the algorithm you will use in order to sign. You might have noticed the algorithm_reference property provided in the sign request. The algorithm_reference can be one of the values: sha1, sha256. For example, we want the following text to be signed using sha256:

You can use the following online tool to calculate the SHA256:

Hexadecimal result:

Notice that the length of the SHA256 is always the same. Now we need to convert the hexadecimal string to a base64-encoded string, another online tool can be used for this example:

Base64-encoded result:

Now we can sign the data (remove the pin property for pinpad readers):

Result:

hashtag
Raw data signing

With the function signRaw you can sign unhashed document data. This means that the Trust1Connector will hash the value itself depending on the provided sign algorithm.

circle-exclamation

Trust1Connector only supports SHA2 hashing at this point.

When using SHA3, the Trust1Connector will convert to SHA2 implicitly.

Below you can find an example

The function looks the same as a regular sign operation but expects a base64 data object that is unhashed.

Supported hash functions (SHA2) are;

  • SHA256

  • SHA384

  • SHA512

hashtag
Verify PIN

When the web or native application is responsible for showing the password input, the following request is used to verify a card holder PIN:

hashtag
Without a pinpad reader

hashtag
With a pinpad reader

Response:

hashtag
Authentication

The T1C-GCL is able to authenticate a card holder based on a challenge. The challenge can be:

  • provided by an external service

provided by the smart card An authentication can be interpreted as a signature use case, the challenge is signed data, that can be validated in a back-end process.

hashtag
External Challenge

An external challenge is provided in the data property of the following example:

hashtag
Without a pinpad reader

hashtag
With a pinpad reader

Response:

Take notice that the PIN property can be omitted when using a smart card reader with pin-pad capabilities. The 'algorithm_reference' property can contain the following values: sha1 and sha256.

hashtag
Generated Challenge

A server generated challenge can be provided to the JavaScript library. In order to do so, an additional contract must be provided with the 'OCV API' (Open Certificate Validation API).

hashtag
Error Handling

hashtag
Error Object

The functions specified are asynchronous and always need a callback function. The callback function will reply with a data object in case of success, or with an error object in case of an error. An example callback:

The error object returned:

For the error codes and description, see ..

export interface AbstractLuxTrust {
  allCerts(parseCerts?: boolean, filters?: string[] | Options, callback?: (error: T1CLibException, data: TokenAllCertsResponse) => void): Promise<TokenAllCertsResponse>;
  rootCertificate(parseCerts?: boolean, callback?: (error: T1CLibException, data: TokenCertificateResponse) => void): Promise<TokenCertificateResponse>;
  authenticationCertificate(parseCerts?: boolean, callback?: (error: T1CLibException, data: TokenCertificateResponse) => void): Promise<TokenCertificateResponse>;
  nonRepudiationCertificate(parseCerts?: boolean, callback?: (error: T1CLibException, data: TokenCertificateResponse) => void): Promise<TokenCertificateResponse>;

  allCertsExtended(parseCerts?: boolean, filters?: string[] | Options, callback?: (error: T1CLibException, data: TokenAllCertsExtendedResponse) => void): Promise<TokenAllCertsExtendedResponse>;
  rootCertificateExtended(parseCerts?: boolean, callback?: (error: T1CLibException, data: TokenCertificateExtendedResponse) => void): Promise<TokenCertificateExtendedResponse>;
  authenticationCertificateExtended(parseCerts?: boolean, callback?: (error: T1CLibException, data: TokenCertificateExtendedResponse) => void): Promise<TokenCertificateExtendedResponse>;
  nonRepudiationCertificateExtended(parseCerts?: boolean, callback?: (error: T1CLibException, data: TokenCertificateExtendedResponse) => void): Promise<TokenCertificateExtendedResponse>;

  verifyPin(body: TokenVerifyPinData, callback?: (error: T1CLibException, data: TokenVerifyPinResponse) => void): Promise<TokenVerifyPinResponse>;
  authenticate(body: TokenAuthenticateOrSignData, callback?: (error: T1CLibException, data: TokenAuthenticateResponse) => void): Promise<TokenAuthenticateResponse>;
  sign(body: TokenAuthenticateOrSignData, bulk?: boolean, callback?: (error: T1CLibException, data: TokenSignResponse) => void): Promise<TokenSignResponse>;
  signRaw(body: TokenAuthenticateOrSignData, bulk?: boolean, callback?: (error: T1CLibException, data: TokenSignResponse) => void): Promise<TokenSignResponse>;
  allAlgoRefs(callback?: (error: T1CLibException, data: TokenAlgorithmReferencesResponse) => void): Promise<TokenAlgorithmReferencesResponse>
  resetBulkPin(callback?: (error: T1CLibException, data: BoolDataResponse) => void): Promise<BoolDataResponse>;
}
Non-repudiation certificate
Core Services
PKI.jsarrow-up-right
calculate SHA256arrow-up-right
hex to base64 converterarrow-up-right
Status codes

Airbus

circle-exclamation

Sample code uses ES6 language features such as arrow functions and promises. For compatibility with IE11, code written with these features must be either transpiled using tools like Babel or refactored accordingly using callbacks.

hashtag
Introduction

The following page describes how you can integrate the Airbus module exposed on the Trust1Connector onto your web application.

hashtag
Interface

hashtag
Models

All model information can be found in the

hashtag
Initialise the Trust1Connector JS

Initialise a Trust1Connector client with a valid configuration:

hashtag
Obtain the Reader information

In order to get all connected card-readers, with available cards:

This function call returns:

Using the generic interface can be done as follows;

Because we're using the generic interface we can define the module variable upfront since we know we want to use the jcop3 integration.

If you want to use the module directly you can initialise as folows (same functions are available but dont need the module to be included in the called function)

hashtag
Token info

You can fetch the token information via the function. this will give all the information of the token you need according to the PKCS11 specifications

hashtag
Certificates

Exposes all the certificates publicly available on the smart card.

hashtag
Extended certificates

You can also fetch the extended versions of the certificates via the functions

this has the capabilities to return multiple certificates if the token has multiple of this type.

for a single certificate the response looks like:

the allCertsExtended returns the following, with the contents of the certificates as the one you can see above;

hashtag
Authentication Certificate

Contains the 'authentication certificate' stored on the smart card. The 'authentication certificate' contains the public key corresponding to the private RSA authentication key. The 'authentication certificate' is needed for pin validation and authentication. When additional parsing of the certificate is needed you can add a boolean to indicate if you want to parse the certificate or not The service can be called:

Response:

hashtag
Non-repudiation Certificate

Contains the 'non-repudiation certificate' stored on the smart card. The 'non-repudiation certificate' contains the public key corresponding the private RSA non-repudiation key. When additional parsing of the certificate is needed you can add a boolean to indicate if you want to parse the certificate or not The service can be called:

Response:

hashtag
Encryption Certificate

Contains the 'encryption certificate' stored on the smart card. The 'encryption certificate' corresponds to the private key used to sign the 'biometric' and 'Address' data. When additional parsing of the certificate is needed you can add a boolean to indicate if you want to parse the certificate or not The service can be called:

Response:

hashtag
Root Certificate/Issuer Certificate

Contains the 'root certificate' or 'Issuer certificate stored on the smart card. The service can be called:

Response:

hashtag
Filter Certificates

All certificates on the smart card can be dumped at once, or using a filter. In order to read all certificates at once:

Response:

The filter can be used to ask a list of custom data containers. For example, we want to read only the rootCertificate

Response:

hashtag
Sign Data

Data can be signed using the Jcop3 smart card. To do so, the T1C-GCL facilitates in:

To get the certificates necessary for signature validation in your back-end:

Response:

Depending on the connected smart card reader. A sign can be executed in 2 modes:

  • Using a connected card reader with 'pin-pad' capabilities (keypad and display available)

  • Using a connected card reader without 'pin-pad' capabilities (no keypad nor display available)

Security consideration: In order to sign a hash, security considerations prefer using a 'pin-pad'.

hashtag
Sign Hash without pin-pad

When the web or native application is responsible for showing the password input, the following request is used to sign a given hash:

Response is a base64 encoded signed hash:

hashtag
Sign Hash with pin-pad

When the pin entry is done on the pin-pad, the following request is used to sign a given hash:

Response is a base64 encoded signed hash:

The core services lists connected readers, and if they have pin-pad capability. You can find more information in the Core Service documentation on how to verify card reader capabilities.

hashtag
Raw data signing

With the function signRaw you can sign unhashed document data. This means that the Trust1Connector will hash the value itself depending on the provided sign algorithm.

circle-exclamation

Trust1Connector only supports SHA2 hashing at this point.

When using SHA3, the Trust1Connector will convert to SHA2 implicitly

Below you can find an example

The function looks the same as a regular sign operation but expects a base64 data object that is unhashed.

Supported hash functions (SHA2) are;

  • SHA256

  • SHA384

  • SHA512

hashtag
Bulk Signing

It is possible to bulk sign data without having to re-enter the PIN by adding an optional bulk parameter set to true to the request. Subsequent sign requests will not require the PIN to be re-entered until a request with bulk being set to false is sent, or the method is called.

triangle-exclamation

When using bulk signing, great care must be taken to validate that the first signature request was successful prior to sending subsequent requests. Failing to do this will likely result in the card being blocked.

hashtag
Bulk PIN Reset

The PIN set for bulk signing can be reset by calling this method.

Response will look like:

hashtag
Verify PIN

hashtag
Verify PIN without pin-pad

When the web or native application is responsible for showing the password input, the following request is used to verify a card holder PIN:

Response:

hashtag
Verify PIN with pin-pad

When the pin entry is done on the pin-pad, the following request is used to verify a given PIN:

Response:

hashtag
Authentication

The T1C-GCL is able to authenticate a card holder based on a challenge. The challenge can be:

  • provided by an external service

  • provided by the smart card An authentication can be interpreted as a signature use case, the challenge is signed data, that can be validated in a back-end process.

    External Challenge

    An external challenge is provided in the data property of the following example:

Response:

Take notice that the PIN property can be omitted when using a smart card reader with pin-pad capabilities.

hashtag
Get valid algorithms to use for Sign or Authenticate

Via the Trust1Connector modules you are able to retrieve available algorithms to use for Signing or Authenticate

The response you can expect is a list of algorithms, an example can be found below (the values below are purely examplatory)

hashtag
Validate signature

The module allows you to call a function on the token that can validate a signature. For this we need to use the validateSignature function. You can call this one via;

The response of this function will return a valid property that is either true or false.

function callback(err,data) {
    if(err){console.log("Error:",JSON.stringify(err, null, '  '));}
    else {console.log(JSON.stringify(data, null, '  '));}
T1CSdk.T1CClient.initialize(config).then(res => {
    client = res;
    client.core().readers(callback);
}, err => {
    console.error(error)
});
{
  "data": [
    {
      "card": {
        "atr": "3B7D94000080318065B0831100C883009000",
        "description": [
          "personal identity card (ID card)",
          "LuxTrust card"
        ]
      },
      "id": "c8d31f8fed44d952",
      "name": "Identiv uTrust 4701 F Dual Interface Reader(1)",
      "pinpad": false
    },
    {
      "id": "ec3109c84ee9eeb5",
      "name": "Identiv uTrust 4701 F Dual Interface Reader(2)",
      "pinpad": false
    }
  ],
  "success": true
}
allCertsExtended(parseCerts?: boolean, filters?: string[] | Options, callback?: (error: T1CLibException, data: TokenAllCertsExtendedResponse) => void): Promise<TokenAllCertsExtendedResponse>;
authenticationCertificateExtended(parseCerts?: boolean, callback?: (error: T1CLibException, data: TokenCertificateExtendedResponse) => void): Promise<TokenCertificateExtendedResponse>;
nonRepudiationCertificateExtended(parseCerts?: boolean, callback?: (error: T1CLibException, data: TokenCertificateExtendedResponse) => void): Promise<TokenCertificateExtendedResponse>;
rootCertificateExtended(parseCerts?: boolean, callback?: (error: T1CLibException, data: TokenCertificateExtendedResponse) => void): Promise<TokenCertificateExtendedResponse>;
{
    "success" : true
    "data" : {
        "certificates": [{
            "certificate"?: string,
            "certificateType"?: string,
            "id"?: string,
            "subject"?: string,
            "issuer"?: string,
            "serialNumber"?: string,
            "url"?: string,
            "hashSubPubKey"?: string,
            "hashIssPubKey"?: string,
            "exponent"?: string,
            "remainder"?: string,
            "parsedCertificate"?: Certificate
        }]
    }
}
{
    "success" : true
    "data" : {
        "authenticationCertificate": {
            "certificates": [...]
        },
        "nonRepudiationCertificate": {
            "certificates": [...]
        },
        "rootCertificate": {
            "certificates": [...]
        }        
   }
}
client.luxtrust(reader_id).rootCertificate({ parseCerts: true }, callback);
{
    success: true,
    data: {
        certificate?: string,
        certificates?: Array<string>,
        certificateType?: string,
        id?: string,
        parsedCertificate?: Certificate,
        parsedCertificates?: Array<Certificate>
    }    
}
client.luxtrust(reader_id).authenticationCertificate({ parseCerts: true }, callback);
{
    success: true,
    data: {
        certificate?: string,
        certificates?: Array<string>,
        certificateType?: string,
        id?: string,
        parsedCertificate?: Certificate,
        parsedCertificates?: Array<Certificate>
    }    
}
client.luxtrust(reader_id).signingCertificate({ parseCerts: true }, callback);
{
    success: true,
    data: {
        certificate?: string,
        certificates?: Array<string>,
        certificateType?: string,
        id?: string,
        parsedCertificate?: Certificate,
        parsedCertificates?: Array<Certificate>
    }    
}
var filter = [];
client.luxtrust(reader_id).allCerts({ filters: filter, parseCerts: true }, callback);
{
 "rootCertificate": {
  ...
 },
 "authenticationCertificate": {
  ...
 },
 "nonRepudiationCertificate": {
  ...
 }
}
var filter = ['authentication-certificate'];
client.luxtrust(reader_id).allCerts({ filters: filter, parseCerts: true }, callback);
{
 "rootCertificate": {
  ...
 }
}
var filter = ['root-certificates','authentication-certificate','signing-certificate'];
client.luxtrust(reader_id).allCertificates({ filters: filter, parseCerts: false }, callback);
{
 "rootCertificate": {
  ...
 },
 "authenticationCertificate": {
  ...
 },
 "nonRepudiationCertificate": {
  ...
 }
}
var data = {
      "pin":"...",
      "algorithm":"sha1",
      "data":"I2e+u/sgy7fYgh+DWA0p2jzXQ7E="
}
client.luxtrust(reader_id).sign(data, callback);
var data = {
      "algorithm":"sha1",
      "data":"I2e+u/sgy7fYgh+DWA0p2jzXQ7E="
}
client.luxtrust(reader_id).sign(data, callback);
{
  "success": true,
  "data": "W7wqvWA8m9SBALZPxN0qUCZfB1O/WLaM/silenLzSXXmeR+0nzB7hXC/Lc/fMru82m/AAqCuGTYMPKcIpQG6MtZ/SGVpZUA/71jv3D9CatmGYGZc52cpcb7cqOVT7EmhrMtwo/jyUbi/Dy5c8G05owkbgx6QxnLEuTLkfoqsW9Q="
}
This is sample text to demonstrate siging with LuxTrust smartcard or signing stick
135b870026cfbe12dec348069811fcde5bed28800ac54dbf45ecdf04eb13e95b
E1uHACbPvhLew0gGmBH83lvtKIAKxU2/RezfBOsT6Vs=
var data = {
      "pin":"...",
      "algorithm":"sha256",
      "data":"E1uHACbPvhLew0gGmBH83lvtKIAKxU2/RezfBOsT6Vs="
}
client.luxtrust(reader_id).sign(data, callback);
{
  "data": "C7SG5eix1+lzMcZXgL0bCL+rLxKhd8ngrSj6mvlgooWH7CloEU13Rj8QiQHdhHnZgAi4Q0fCMIqAc4dn9uW9OP+MRitimRpYZcaDsGrUehPi/JpOD1e+ko7xKZ67ijUU4KTmG4HXc114oJ7xxx3CGL7TNFfvuEphLbbZa+9IZSSnYDOOENJqhggqqu7paSbLJrxC2zaeMxODKb5WSexHnZH6NnLPl2OmvPTYtxiTUMrLbFRsDRAziF6/VQkgM8/xOm+1/9Expv5DSLRY8RQ+wha6/nMlJjx50JszYIj2aBQKp4AOxPVdPewVGEWF4NF9ffrPLrOA2v2d7t5M4q7yxA==",
  "success": true
}
var data = {
      "algorithm":"sha256",
      "data":"vl5He0ulthjX+VWNM46QX7vJ8VvXMq2k/Tq8Xq1bwEw=",
      "osDialog": false
}
luxtrustClient.signRaw(data, callback);
var data = {
      "pin":"..."
}
client.luxtrust(reader_id).verifyPin(data, callback);
var data = {}
client.luxtrust(reader_id).verifyPin(data, callback);
{
  "success": true
}
var data = {
  "pin": "...",
  "algorithm_reference": "sha1",
  "data":"I2e+u/sgy7fYgh+DWA0p2jzXQ7E="
}
client.luxtrust(reader_id).authenticate(data, callback);
var data = {
  "algorithm_reference": "sha1",
  "data":"I2e+u/sgy7fYgh+DWA0p2jzXQ7E="
}
client.luxtrust(reader_id).authenticate(data, callback);
{
  "success": true,
  "data": "W7wqvWA8m9SBALZPxN0qUCZfB1O/WLaM/silenLzSXXmeR+0nzB7hXC/Lc/fMru82m/AAqCuGTYMPKcIpQG6MtZ/SGVpZUA/71jv3D9CatmGYGZc52cpcb7cqOVT7EmhrMtwo/jyUbi/Dy5c8G05owkbgx6QxnLEuTLkfoqsW9Q="
}
The calculated digest of the hash is prefixed with:
DigestInfo ::= SEQUENCE {
      digestAlgorithm AlgorithmIdentifier,
      digest OCTET STRING
  }
Make sure this has been taken into consideration in order to validate the signature in a backend process.
function callback(err,data) {
    if(err){
        console.log("Error:",JSON.stringify(err, null, '  '));
    }
    else {
        console.log(JSON.stringify(data, null, '  '));
    }
}
{
  success: false,
  description: "some error description",
  code: "some error code"
}
Token typings model page
Bulk Sign Reset
export interface AbstractEidGeneric {
    allCerts(parseCerts?: boolean, filters?: string[] | Options, callback?: (error: T1CLibException, data: TokenAllCertsResponse) => void): Promise<TokenAllCertsResponse>;
    authenticationCertificate(parseCerts?: boolean, callback?: (error: T1CLibException, data: TokenCertificateResponse) => void): Promise<TokenCertificateResponse>;
    nonRepudiationCertificate(parseCerts?: boolean, callback?: (error: T1CLibException, data: TokenCertificateResponse) => void): Promise<TokenCertificateResponse>;
    rootCertificate(parseCerts?: boolean, callback?: (error: T1CLibException, data: TokenCertificateResponse) => void): Promise<TokenCertificateResponse>;
    encryptionCertificate(parseCerts?: boolean, callback?: (error: T1CLibException, data: TokenCertificateResponse) => void): Promise<TokenCertificateResponse>;
    issuerCertificate(parseCerts?: boolean, callback?: (error: T1CLibException, data: TokenCertificateResponse) => void): Promise<TokenCertificateResponse>;

    allCertsExtended(parseCerts?: boolean, filters?: string[] | Options, callback?: (error: T1CLibException, data: TokenAllCertsExtendedResponse) => void): Promise<TokenAllCertsExtendedResponse>;
    rootCertificateExtended(parseCerts?: boolean, callback?: (error: T1CLibException, data: TokenCertificateExtendedResponse) => void): Promise<TokenCertificateExtendedResponse>;
    authenticationCertificateExtended(parseCerts?: boolean, callback?: (error: T1CLibException, data: TokenCertificateExtendedResponse) => void): Promise<TokenCertificateExtendedResponse>;
    nonRepudiationCertificateExtended(parseCerts?: boolean, callback?: (error: T1CLibException, data: TokenCertificateExtendedResponse) => void): Promise<TokenCertificateExtendedResponse>;
    encryptionCertificateExtended(parseCerts?: boolean, callback?: (error: T1CLibException, data: TokenCertificateExtendedResponse) => void): Promise<TokenCertificateExtendedResponse>;
    issuerCertificateExtended(parseCerts?: boolean,  callback?: (error: T1CLibException, data: TokenCertificateExtendedResponse) => void): Promise<TokenCertificateExtendedResponse>;

    validateSignature(body: TokenValidateSignatureRequest, callback?: (error: T1CLibException, data: TokenValidateSignatureResponse) => void): Promise<TokenValidateSignatureResponse>;

    verifyPin(body: TokenVerifyPinData, callback?: (error: T1CLibException, data: TokenVerifyPinResponse) => void): Promise<TokenVerifyPinResponse>;
    authenticate(body: TokenAuthenticateOrSignData, callback?: (error: T1CLibException, data: TokenAuthenticateResponse) => void): Promise<TokenAuthenticateResponse>;
    sign(body: TokenAuthenticateOrSignData, bulk?: boolean, callback?: (error: T1CLibException, data: TokenSignResponse) => void): Promise<TokenSignResponse>;
    signRaw(body: TokenAuthenticateOrSignData, bulk?: boolean, callback?: (error: T1CLibException, data: TokenSignResponse) => void): Promise<TokenSignResponse>;
    allAlgoRefs(callback?: (error: T1CLibException, data: TokenAlgorithmReferencesResponse) => void): Promise<TokenAlgorithmReferencesResponse>
    resetBulkPin(callback?: (error: T1CLibException, data: BoolDataResponse) => void): Promise<BoolDataResponse>;
}
T1CSdk.T1CClient.initialize(config).then(res => {
    client = res;
}, err => {
    console.error(error)
});
var core = client.core();
core.readersCardAvailable(callback);
{
  "data": [
    // List of reader with cards found
  ],
  "success": true
}
const moduleName = "airbus";
var module = client.generic(selected_reader.id);
var module = client.airbus(selected_reader.id);
module.tokenData().then(res => {
    // see response below
})
{
    "success": true,
    "data": {
        "info": {
            "slot": "string",
            "label": "string",
            "manufacturerId": "string",
            "model": "string",
            "serialNumber": "string",
            "flags": {
                "isRandomNumberGenerator": "boolean",
                "isWriteProtected": "boolean",
                "isLoginRequired": "boolean",
                "isUserPinInitialized": "boolean",
                "isRestoreKeyNotNeeded": "boolean",
                "isClockOnToken": "boolean",
                "isProtectedAuthenticationPath": "boolean",
                "isDualCryptoOperations": "boolean",
                "isTokenInitialized": "boolean",
                "isSecondaryAuthentication": "boolean",
                "isUserPinCountLow": "boolean",
                "isUserPinFinalTry": "boolean",
                "isUserPinLocked": "boolean",
                "isUserPinToBeChanged": "boolean",
                "isSoPinCountLow": "boolean",
                "isSoPinFinalTry": "boolean",
                "isSoPinLocked": "boolean",
                "isSoPinToBeChanged": "boolean"
            },
            "mechanisms": [
                {
                    "mechanism": "string",
                    "flags": {
                        "isHardware": "boolean",
                        "isEncrypt": "boolean",
                        "isDecrypt": "boolean",
                        "isDigest": "boolean",
                        "isSign": "boolean",
                        "isSignRecover": "boolean",
                        "isVerify": "boolean",
                        "isVerifyRecover": "boolean",
                        "isGenerate": "boolean",
                        "isGenerateKeyPair": "boolean",
                        "isWrap": "boolean",
                        "isUnwrap": "boolean",
                        "isExtension": "boolean",
                        "isEcFP": "boolean",
                        "isEcNamedcurve": "boolean",
                        "isEcUncompress": "boolean",
                        "isEcCompress": "boolean"
                    },
                    "ulMinKeySize": "number",
                    "ulMaxKeySize": "number"
                }
            ],
            "ulMaxSessionCount": "number",
            "ulSessionCount": "number",
            "ulMaxRwSessionCount": "number",
            "ulMaxPinLen": "number",
            "ulMinPinLen": "number",
            "ulTotalPubLicMemory": "number",
            "ulFreePubMemory": "number",
            "ulTotalPrivateMemory": "number",
            "ulFreePrivateMemory": "number",
            "hardwareVersion": "string",
            "firmwareVersion": "string"
        },
        "infoType": "TokenInfoType"
    }
}



//ENUM
TokenInfoType {
    Token,
    PKCS11,
    File,
    Payment,
    HSM,
    Vault,
    Wallet,
}
allCertsExtended(parseCerts?: boolean, filters?: string[] | Options, callback?: (error: T1CLibException, data: TokenAllCertsExtendedResponse) => void): Promise<TokenAllCertsExtendedResponse>;
authenticationCertificateExtended(parseCerts?: boolean, callback?: (error: T1CLibException, data: TokenCertificateExtendedResponse) => void): Promise<TokenCertificateExtendedResponse>;
nonRepudiationCertificateExtended(parseCerts?: boolean, callback?: (error: T1CLibException, data: TokenCertificateExtendedResponse) => void): Promise<TokenCertificateExtendedResponse>;
encryptionCertificateExtended(parseCerts?: boolean, callback?: (error: T1CLibException, data: TokenCertificateExtendedResponse) => void): Promise<TokenCertificateExtendedResponse>;
rootCertificateExtended(parseCerts?: boolean, callback?: (error: T1CLibException, data: TokenCertificateExtendedResponse) => void): Promise<TokenCertificateExtendedResponse>;
{
    "success" : true
    "data" : {
        "certificates": [{
            "certificate"?: string,
            "certificateType"?: string,
            "id"?: string,
            "subject"?: string,
            "issuer"?: string,
            "serialNumber"?: string,
            "url"?: string,
            "hashSubPubKey"?: string,
            "hashIssPubKey"?: string,
            "exponent"?: string,
            "remainder"?: string,
            "parsedCertificate"?: Certificate
        }]
    }
}
{
    "success" : true
    "data" : {
        "authenticationCertificate": {
            "certificates": [...]
        },
        "nonRepudiationCertificate": {
            "certificates": [...]
        },
        "encryptionCertificate": {
            "certificates": [...]
        },
        "rootCertificate": {
            "certificates": [...]
        }        
   }
}
module.authenticationCertificate(module, parseCertsBoolean, callback);
{
    success: true,
    data: {
        certificate?: string,
        certificates?: Array<string>,
        certificateType?: string,
        id?: string,
        parsedCertificate?: Certificate,
        parsedCertificates?: Array<Certificate>
    }    
}
module.nonRepudiationCertificate(module, parseCertsBoolean, callback);
{
    success: true,
    data: {
        certificate?: string,
        certificates?: Array<string>,
        certificateType?: string,
        id?: string,
        parsedCertificate?: Certificate,
        parsedCertificates?: Array<Certificate>
    }    
}
module.nonRepudiationCertificate(module, parseCertsBoolean, callback);
{
    success: true,
    data: {
        certificate?: string,
        certificates?: Array<string>,
        certificateType?: string,
        id?: string,
        parsedCertificate?: Certificate,
        parsedCertificates?: Array<Certificate>
    }    
}
module.rootCertificate(module, parseCertsBoolean, callback);
{
    success: true,
    data: {
        certificate?: string,
        certificates?: Array<string>,
        certificateType?: string,
        id?: string,
        parsedCertificate?: Certificate,
        parsedCertificates?: Array<Certificate>
    }    
}
var filter = [];
module.allCerts(module, parseCerts, { filters: filter}, callback);
{
 "authenticationCertificate": {
  ...
 },
 "nonRepudiationCertificate": {
  ...
 },
 "encryptionCertificate": {
  ...
 }
}
var filter = ['authenticationCertificate'];
module.allCerts(module, { filters: filter}, callback);
{
 "authenticationCertificate": {
  ...
 }
}
var filter = null;
module.allCerts(module, { filters: filter}, callback);
{
 "authenticationCertificate": {
  ...
 },
 "nonRepudiationCertificate": {
  ...
 }
}
var data = {
      "pin":"...",
      "algorithm":"sha1",
      "data":"I2e+u/sgy7fYgh+DWA0p2jzXQ7E=",
      "osDialog": true,
      "id": "id.."
}
module.sign(module, data, callback);
{
  "success": true,
  "data": {
    "data" : "W7wqvWA8m9S...="
  }
}
var data = {
      "algorithm":"sha1",
      "data":"I2e+u/sgy7fYgh+DWA0p2jzXQ7E=",
      "osDialog": false,
      "id": "id.."
}
module.sign(module, data, callback);
{
  "success": true,
  "data": {
    "data" : "W7wqvWA8m9S...="
  }
}
var data = {
      "algorithm":"sha256",
      "data":"vl5He0ulthjX+VWNM46QX7vJ8VvXMq2k/Tq8Xq1bwEw=",
      "osDialog": false
}
module.signRaw(data, callback);
const data = {
    algorithm: "sha256",
    data: "E1uHACbPvhLew0gGmBH83lvtKIAKxU2/RezfBOsT6Vs=",
    pin: "1234",
    id: "id.."
}
const bulk = true;
module.sign(module, data, bulk).then(res => {
}, err => {
    console.error(err)
})
module.resetBulkPin(module).then(res => {
}, err => {
    console.error(err)
})
{
    "success": true,
    "data": true
}
var data = {
      "pin":"..."
}
module.verifyPin(module, data, callback);
{
  "verified": true
}
var data = {}
module.verifyPin(module, data, callback);
{
  "verified": true
}
var data = {
  "pin": "...",
  "algorithm": "sha1",
  "data":"I2e+u/sgy7fYgh+DWA0p2jzXQ7E=",
  "id": "id.."
}
module.authenticate(module, data, callback);
{
  "success": true,
  "data": {
    "data" : "W7wqvWA8m9S...="
  }
}
module.verifyPin(module, data, callback);
module.allAlgoRefs(module, callback);
{
    "success": true,
    "data": ["sha1", "sha256"]
}
const body = {
    "algorithm": 'sha256',
    "hash": '...',
    "signedHash": '...',
    "osDialog": false,
    "id": 'cert_id',
    "pin": 'pin_code',
    "timeout": 120 //timeout in seconds
}
module.validateSignature(body).then(response => {
    response.valid
).catch(error => {
    errorHandler(error)}
)
{
    "success": true,
    "data": {
        "valid": true
    }
}

Changelog

hashtag
Legend

Icon
Description

✅

Improvement upon the Trust1Connector

🔺

hashtag
v3.6.3

circle-info

Released 19/08/2022

chevron-rightRelease noteshashtag

hashtag
Bug

t1c-sdk-js tries to validate any present consent token when consent is disabled (optional consent)

hashtag
v3.6.1

circle-exclamation

Javascript SDK 3.6.0 has been unpublished and contains a bug in the consent flow where the error code is not returned correctly

circle-info

Released 01/04/2022

circle-exclamation

The Mac Silicon (M1) is not yet supported for this version

chevron-rightRelease noteshashtag

hashtag
Bug

hashtag
🔺 Consent error code update

The consent error code has been updated in the Trust1Connector API library, and t1c-sdk-js clients have no impact on that change

hashtag
🔺 Multi-client support and race condition fix

When using different instances of the Trust1Connector (optionally from another partner) on a Windows system, a port collision could be possible due to a race condition in port assignment upon initialization. Ports are now protected with anti-collision and are salted to make a port less guessable.

hashtag
🔺 Implicit creation of LaunchAgents folder on Mac/OSX

When no LaunchAgents folder was present on the system, the installation procedure creates this folder implicitly.

hashtag
☑️ Exposed Camerfirma interface

Camerfima is a new PKCS11 token added to the modules of the Trust1Connector. The Camerfirma token pre-requisites the installation of the Carmerfirma middleware.

hashtag
☑️ Exposed Chambersign interface

Chambersign is a new PKCS11 token added to the modules of the Trust1Connector. The Chambersign token pre-requisites the installation of the Chambersign middleware.

hashtag
☑️ Token Info endpoint will now returned detailed information when using a PKCS11 token

The token info endpoint has been implemented before only for identity tokens. We have added support for Token Info of the PKCS11 modules. As the response has a different data structure, an additional type has been added for clients to parse the response correctly.

The PKCS11 token info exposes information on the algorithms which can be used for different use cases (digital signature, validation, authentication, ...). In a future release additional functionality will be provided such as: encryption, decryption, key exchange,...

hashtag
✅ Fetch all the certificates on a token including all their information

For the different notification types, many tokens share multiple certificates for a single type. The original interface supported only a single certificate response. To be backwards compatible, those certification function have been adapted to be behave the same as in v3.5.x.

New functions are available to support multiple certificate reponses, they are called: [certificateType]Extended. For PKCS11 tokens the certificate response also returns, besides the base64 encoded certificate and the certificate id, the following properties:

  • issuer

  • subject

  • serial number

You can find an example for

hashtag
✅ Signed hash validation function exposed for PKCS11 tokens

A new function has been added for all PKCS11 modules called the 'validate' endpoint. This endpoint, when available, can be used to validate a signed hash received after calling the 'sign' function. In an next version a variant of the validation function using OpenSSL will be added for all tokens.

hashtag
✅ PKCS11 migration towards RUST

For the Trust1Connector to support more PKCS11 functionality, the intermediate PKCS11 layer has been removed in preference of a direct PKCS11 LIB integration. FFI is used in RUST to support any library which need to be loaded.

hashtag
✅ Token Algortihm input validation for signing and authentication

Additional guard has been implemented to prevent empty algorithms for the digital signature and validation endpoints. PKCS11 tokens will verify as well if the provided algortihm is exposed as an allowed mechanism for the targetted use case.

hashtag
✅ JCOP3 ATR added

The Trust1Connector can now detec Java Card Object Platform 3 typed cards

hashtag
✅ Select default PKCS11 non-repudation or authentication certificate

When requesting for a signature or an authentication, the correct certificate must be provided. For PKCS11 tokens the certificate id (or reference) can be ommitted. The PKCS11 token will be default pick the first certificate (for the type needed) and use this with the specified mechanism to sign/authenticate.

hashtag
Improvement

Remove the implicit CORS request from API info endpoint to DS, and provide/expose a public function in JS for application to force a CORS sync

hashtag
Story

As a dashboard user I want to see how many installation have the DNS rebind issue

Update consent error codes for 3.6.x so that they do not interfere with other error codes

hashtag
Improvement

  • As an SDK integrator I want to be able to fetch all the certificates on a token, including their information

  • As a user I want to validate the signed hash from a PKCS11 token, using the validation function of the PKCS11 interface

hashtag
Story

  • As a user I want ot use Camerfirma token

  • As a user I want to use Chambersign token

  • As a SDK integrator I want to be able to call the TokenInfo enpdoint on PKCS11 tokens

hash sub pub key
  • hash iss pub key

  • exponent (payment modules)

  • remainder (payment modules)

  • parsed certificate (ASN1 format of the base64 encoded certificate)

  • Bugfix

    ☑️

    Story / new feature for the Trust1Connector

    certigna here

    Setting up the SDK

    hashtag
    Include Trust1Connector JS SDK

    Include the Trust1Connector JavaScript SDK on your web application. This will provide you with access to the SDK's functions which are used to execute the Trust1Connector's functionality.

    From now on we will refer to the Trust1Connector JS SDK to the following variances;

    • T1C-js/t1cjs

    • T1C SDK

    hashtag
    Using Trust1Connector in as a library

    The Trust1Connector is a Javascript Library with TypeScript typings. This can be easily used in any web-application by loading the javacript files on the web-page.

    Loading the T1C SDK onto a web-page can be done as shown in the code example below of a html page

    In the example you can see that we load the Javascript SDK on line 8

    The defer attribute means that the script will be downloaded in parallel with the rest of the web-page but will be executed when the page has finished loading in.

    This is mostly used to make sure that when the Javascript wants to target a specific element on the page, for example a div, that this element has already been loaded and is accessable.

    hashtag
    Using Trust1Connector as a module

    We also provide an npm package that makes it easier to load and use the Trust1Connector Javascript SDK as a module.

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
        <script defer src="./T1CSdk.js"></script>
    </head>
    <body>
        ...
    </body>
    </html>
    <script defer src="./T1CSdk.js"></script>

    Concept

    Running the Trust1Connector in a shared environment, such as Citrix, XenApp and Remote Desktop, requires additional installation steps. In this section we explain the concept and approach used.

    hashtag
    Architecture Overview

    The following schematic seems rather complicated as it explains the inner workings of the Trust1Connector components, the concept is elaborate further on this page. If you are only interested in what the integration impact is for your Web Application in a Shared Environment, you can skip directly to the section: Integration in Web Applications

    Component Diagram

    hashtag
    Components

    hashtag
    Web Environment

    The Web Application can use the T1C-SDK-JS or a custom REST API client for integration purpose. As the Web Application operates in a browser context, resolving an agent, by means of a consent, will result in a browser cookie being provided.

    The T1C-SDK-JS implements the detection of a Shared Environment during the initialisation of the library. When initialisation succeeds without a controlled exception, the setup is a standalone; when the initialisation throws an 401 Error, the T1C-SDK-JS can be used to request the user for a Consent.

    When using the REST API directly form your web application, reading the browser cookie and performing the initialisation must be done by the integrating Web Application itself.

    hashtag
    Shared Environment Host

    Compared to Trust1Connector v2, the v3 release has a separate component to be be installed on a shared host. This component is called the T1C-Proxy and only exposes the following use cases:

    • Verify random available ports [in a predefined range] which can be used by an Agent (Session of T1C-API running in user space)

    • Port reservation upon installation of a new T1C-API in an active user session

    • Port registration upon initialisation of a T1C-API in an active user session

    The T1C-Proxy operates by Default on the API port defined in the T1C-DS (Distribution Server). From a Web Application perspective, this is the only information known. When a Web Application requests the information of the device, the PROXY device type will inform the Web Application that the targeted underlying API is a PROXY, which means that the Web Application must ask for the Agent specific API port to configure an URI which can be used to execute the use cases.

    When using the T1C-SDK-JS this is done implicitly during initialisation.

    hashtag
    Shared Environment Client

    A T1C-API installed for a specific users runs in [User Space]. To avoid possible attack vectors, the Trust1Connector v3 will always run in [User Space].

    Upon installation of the T1C-API, during the post install phase, the T1C-API will try to verify automatically if it is running in a shared environment. If this is the case, the T1C-API will ask the T1C-Proxy for available ports and will reserve those post, prior to initialisation and startup.

    The ports which are reserved by the T1C-Proxy are the following:

    • T1C-API Port: This is the port exposing the OpenAPI interface towards Web Applications and used by the T1C-SDK-JS

    When receiving ports during post-install, an user agent device is temporary RESERVED in the Agent Registry of the T1C-Proxy. Upon T1C-API initialisation, the port configurations will be confirmed and the Agent Registry will set the device state on REGISTERED. From this moment on, a T1C-API instance, running in an active user session, will be available for the Web Application via the .

    The T1C-gRPC instance is inherently a component from the T1C-API, and thus is managed by the T1C-API. As each user must have it's own hardened runtime for communication purpose, the port assigned for T1C-gRPC will be registered and configured by the T1C-API (and restarted when needed).

    hashtag
    Central Back-Office

    Starting from this release (v3) of the Trust1Connector, each device must have a link with an active and running T1C-DS (Trust1Connector Distribution Server). This is to guarantee security, updates, and avoid potential risk in production.

    The T1C-DS is proceeded by an API Gateway who is managing the security offloading in the application layer. For a Web Application to communicate with a T1C-Proxy or T1C-API, a JWT (Json Web Token) is needed and obliged. The T1C-DS is responsible for the key management, the certificate management and other use cases which are described in a separate wiki.

    In order to retrieve a valid JWT, the T1C-DS can be requested from your application back-end with a valid api-key. The JWT is valid for a given amount of time, and sets the context used when requesting the T1C-API on a device.

    hashtag
    Security

    hashtag
    Pin Handling

    The PIN handling logic is implemented in the Trust1Connector API. More information on the basic and/or advanced rules can be found on the following link:

    hashtag
    Share Environment Flows

    hashtag
    Communication Stack

    Management of an in-memory list of active Agents

  • Management of user consents in a shared environment by means of browser cookies with an optional configurable TTL (time to live)

  • consent flow

    Initialize Trust1Connector

    hashtag
    Introduction

    For initialisation of the T1C you need to prepare your application first by adding the SDK JS files to your project and importing them in such a way that you can call for the Javascript functions when you need them. When you've succesfully downloaded and installed the Trust1Connector you can initialize and use the Trust1Connector

    hashtag
    Mode of operations

    The Trust1Connector's architecture is created so that we can support a wide range of system setups. This means we can both support single users using the Trust1Connector but also systems where multiple users make use of the same hardware, we call this shared environments.

    Additionally to shared environments, we support remote desktops as an extension on shared environments.

    Since Trust1Connector version 3.6.1 we can provide integrators the support to initialise the Trust1Connector in different ways.

    hashtag
    Single Instance Without Consent

    circle-info

    Please contact support if you need support for this modus. As this is not the default mode and requires the Trust1Connector to be run in a specific context

    Using this operation mode, the integrator can decide to use the Trust1Connector and inforce that no consent is needed. making it very straightforward for the end-user to utilise any functionality the Trust1Connector offers.

    In this mode we cannot support multiple instances of the Trust1Connector. Meaning shared environments and multiple users logged in on the same system can create unexpected behaviour.

    hashtag
    Single Instance With Consent

    This is the default mode of operation and goes hand-in-hand with instances. A consent is required to both request the user's permission to use the Trust1Connector on his system and also to correctly determine which instance of the Trust1Connector needs to be used.

    The Consent provides support to use the Trust1Connector with multiple users on the same system ().

    Using Single Instance with consent as an operational mode, enforeces users to consent unregarded the environment - be it single device or multi user environment. Validity of the consent can be determined by the application.

    hashtag
    Multi-user Instance With Consent

    Just like the this mode requires a consent to both ask permission to the user and determine the correct instance of the Trust1Connector Agent/API.

    This mode support shared environments such as Citrix, terminal server and remote desktop.

    hashtag
    Creating the configuration object

    We will prepare the SDK's configuration Object, this object is used to pass information about which default port the Trust1Connector is running on, JWT key, API url, ... which is needed to properly contact and use the Trust1Connector.

    When the Trust1Connector is configured with a Distribution Service in mind you can provide a valid JWT token in the configuration object. .

    circle-exclamation

    Retrieving JWT tokens should be handled in your own backend to maximize security

    Now we can create a complete Configuration Options object to be passed to the Trust1Connector.

    hashtag
    T1CConfigOptions

    The T1C config options is a class that can be used to create a valid configuration object to initialize the Trust1Connector. Below you can find a class definition.

    circle-info

    t1cProxyUrl and t1cProxyPort are deprecated since 3.5.x and only used in 3.4.x versions.

    hashtag
    Parameters

    t1cApiUrl: string Optional The URL that connects to the local Trust1Connector instances. This can be either localhost or a domain that directs towards localhost. By default this will be https://t1c.t1t.io

    t1cApiPort: string Optional The port defined to be used for the Trust1Connector. By default this is 51983

    t1cProxyUrl: string Optional - Deprecated The URL that connects to the local Trust1Connector Proxy instances. This can be either localhost or a domain that directs towards localhost. By default this will be https://t1c.t1t.io

    t1cProxyPort: string Optional - Deprecated The port defined to be used for the Trust1Connector Proxy. By default this is 51983

    jwt: string Optional The JWT token that is used to authenticate towards the Trust1Connector. This should be retrieved from the DS and is only needed when the Trust1Connector is configured to work with a DS and requires JWT validation

    applicationDomain: string Optional The domain of the application that is using the Trust1Connector. This is used to make sure the consent is only available for a specific web-application. This prevents various clients to interfere with eachother. This domain also tags the Distribution service transactions being sent to the Distribution service. This makes it easy to distinguish between applications/tags for the transactions

    When a remote DS is used you can set the following field with the correct DS url, this will in turn use the DS's capabilities of acting as a Trust1Connector proxy for enchanced security.

    Now we can continue to use the config variable to and retrieve a T1CClient

    hashtag
    Authenticated client

    If you need to set up the Trust1Connector with a valid JWT token you can follow the documentation on the to from the DS.

    When you have a valid token you can provide this in the Configuration. This will make sure the Trust1Connector is usable until the token becomes unvalid. At which point you can your token to continue to use the Trust1Connector. More information on how to retrieve,use and refresh a token can be found on the .

    hashtag
    Initializing the Trust1Connector SDK

    Initialization of the Trust1Connector in many cases requires a user consent, the exception being when no registry is configured (either local or central) and if the Trust1Connector is run in a enabled. More information can be found . The registry allowed us to create a Trust1Connector that works in any environment, without the need for Administrative rights from the users, wether it be Standalone, Multi session, RDP, Citrix, ...

    To Initialize the Trust1Connector a is required(when a central or local registry is present) or when the . When no consent can be found the error codes 814500 or 814501 will be thrown. This means that either the previous consent is not valid anymore or no consent was given yet.

    More information regarding the consent can be found on the which explains it in more detail.

    If you have the enabled the consent error will not appear but will either give a valid Client to use or a 112999 error, depicting it could not find any active instance of the Trust1Connector.

    When either no consent is present or its invalid you will receive a invalid client object (line 8 in example above) that can be used to trigger the getImplicitConsent function in the Core serivce.

    The Consent requires a user action to . This data is used by the T1C registry to make sure you're targetting the correct instance of the Trust1Connector. More information about this can be found here.

    The signature of the getImplicitConsent function is as follows;

    This function expects:

    codeword: string The string value that is saved to the user's clipboard needs to be sent to the Consent function.

    durationInDays: number Optional Amount of days that the consent is valid.

    callback: (error?: T1CLibException, data?: T1CClient) Optional Callback when you're not using ES

    Below is a small javascript example of how you can trigger the getImplicitConsent function

    After this you will have a client that can be used to execute the rest of the functionality that the Trust1Connector has to offer.

    hashtag
    Full example

    hashtag
    Enforcing consent flow in a optional consent enabled Trust1Connector

    When your instance of the Trust1Connector has the optional consent mode enabled but still want to enforce the consent flow you can use the following explicit consent initialisation.

    This will ignore the enabled feature of having the consent being optional and will require a valid consent to operate the Trust1Connector.

    hashtag
    Clipboard

    To provide a consent, we suggest you use the clipboard functionality available in browsers. The most supported way is via document.exeCommand and below you can find an example of this.

    There is also a but this is not fully supported yet

    circle-info

    The code below is an example of how you can integrate a copy command in the webbrowser

    hashtag
    Retrieve JWT token

    GET https://ds.t1t.io/v3/tokens/application

    This endpoint will return a valid JWT token to use for a certain period based on the API-key you provide in the `apikey` header

    hashtag
    Headers

    Name
    Type
    Description

    hashtag
    Trust1Connector environments

    The Trust1Connector has a Develop, Acceptance and production version. The difference between them is mainly the Distirbution service connection and the port number they use.

    circle-info

    These port numbers are linked to the Trust1Connector distributed by Trust1Team. If you have a custom installation these will be different. Please contact your distributor for more information.

    The port numbers of the Trust1Connector are;

    Environment
    Port number
    Distribution service

    apikey

    string

    API-key received from Trust1Team

    Production

    51983

    https://ds.t1t.io

    Acceptance

    51883

    https://acc-ds.t1t.io

    Develop

    51783

    None

    multi user
    even at the same time
    single instance with consent mode
    You can retrieve such token via the Distribution Service based on the API key you received
    initialize
    Authenticated Client page
    retrieve a valid token
    refresh
    Authenticated Client page
    specific single modus
    here
    Consent
    modus is set to optional consent
    Consent page
    optional consent mode
    copy some data to its clipboard
    clipboard API arrow-up-right
    class T1CConfigOptions {
      constructor(
        public t1cApiUrl?: string,
        public t1cApiPort?: string,
        public t1cProxyUrl?: string, // deprecated
        public t1cProxyPort?: string, // deprecated
        public jwt?: string,
        public applicationDomain?: string, // "rmc.t1t.be"
      ) {}
    }
    // ...
    
    let environment = {
        t1cApiUrl: 'https://t1c.t1t.io',
        t1cApiPort: '51983',
        t1cProxyUrl: 'https://t1c.t1t.io',
        t1cProxyPort: '51983',
        jwt: 'eyJraWQiOiJ0MWNkcyIsImFsZyI6IlJTMjU2In0..._Mg2PfdhCMQ',
        applicationDomain: 'test-app'
    };
    
    const configoptions = new T1CSdk.T1CConfigOptions(
            environment.t1cApiUrl,
            environment.t1cApiPort,
            environment.t1cProxyUrl,
            environment.t1cProxyPort,
            environment.jwt,
            environment.applicationDomain
        );
    config = new T1CSdk.T1CConfig(configoptions);
    
    // ...
    // When remote DS is used set the following parameter
    config.dsUrl = "https://acc-ds.t1t.io";
    // ...
    
    T1CSdk.T1CClient.initialize(config).then(res => {
        client = res;
        console.log("Client config: ", client.localConfig);
        core = client.core();
        core.version().then(versionResult => console.log("T1C running on core "+ versionResult));
    }, err => {
        if (err.code == 814500 || err.code == 814501) {
            client = err.client;
            // (new) Consent is required
        }
        else if(err.code == 112999) {
            // Could not connect with the Trust1Connector
        } else {
            // an uncatched error occured
            console.error("T1C error:", err)
        }
    });
    
    // ...
    public getImplicitConsent(codeWord: string, durationInDays?: number, 
        callback?: (error?: T1CLibException, data?: T1CClient) => void
    ): Promise<T1CClient>
    client.core().getImplicitConsent(document.querySelector(".clipboard-data").innerHTML).then(res => {
        console.log("Consent Executed")
        client = res;        
        // Use the client for your use-cases
    }, err => {
        // Failed, use the error client to retry the consent
        this.client = err.client;
        console.error(err.description ? err.description : err)
    })
    // Global client to be used over the entire application
    const client = null
    
    // Prepare the configuration
    let environment = {
        t1cApiUrl: 'https://t1c.t1t.io',
        t1cApiPort: '51983',
        t1cProxyUrl: 'https://t1c.t1t.io',
        t1cProxyPort: '51983',
        jwt: 'eyJraWQiOiJ0MWNkcyIsImFsZyI6IlJTMjU2In0..._Mg2PfdhCMQ',
        applicationDomain: 'test-app'
    };
    
    const configoptions = new T1CSdk.T1CConfigOptions(
            environment.t1cApiUrl,
            environment.t1cApiPort,
            environment.t1cProxyUrl,
            environment.t1cProxyPort,
            environment.jwt,
            environment.applicationDomain
        );
    config = new T1CSdk.T1CConfig(configoptions);
    
    // Initialize the Trust1Connector with the previously created configuration object
    T1CSdk.T1CClient.initialize(config).then(res => {
        client = res;
        console.log("Client config: ", client.localConfig);
        core = client.core();
        core.version().then(versionResult => console.log("T1C running on core "+ versionResult));
    }, err => {
        if (err.code == 814500 || err.code == 814501) {
            // (new) Consent is required
        }
        else if(err.code == 112999) {
            // Could not connect with the Trust1Connector
        } else {
            // an uncatched error occured
            console.error("T1C error:", err)
        }
    });
        
        
    
    // when the user has clicked on the clipboard/consent button we execute the getImplicitConsent function
    document.querySelector(".clipboard").addEventListener("click", (ev) => {
        if (client != null) {
            client.core().getImplicitConsent(document.querySelector(".clipboard-data").innerHTML).then(res => {
                console.log("Consent Executed")
                client = res;        
                // Use the client for your use-cases
            }, err => {
                this.client = err.client;
                console.error(err.description ? err.description : err)
            })
        }
    
    })
    // ...
    
    T1CSdk.T1CClient.initializeExplicitConsent(config).then(res => {
        client = res;
        console.log("Client config: ", client.localConfig);
        core = client.core();
        core.version().then(versionResult => console.log("T1C running on core "+ versionResult));
    }, err => {
        if (err.code == 814500 || err.code == 814501) {
            client = err.client;
            // (new) Consent is required
        }
        else if(err.code == 112999) {
            // Could not connect with the Trust1Connector
        } else {
            // an uncatched error occured
            console.error("T1C error:", err)
        }
    });
    
    // ...
    const tokenNode = document.querySelector('.consent-token');
    var range = document.createRange();
    range.selectNode(tokenNode);
    window.getSelection().addRange(range);
    try {
        // Now that we've selected the anchor text, execute the copy command
        document.execCommand('copy');
    } catch(err) {
        console.log('Oops, unable to copy');
    }
    
    // Remove the selections - NOTE: Should use
    // removeRange(range) when it is supported
    window.getSelection().removeRange(range);
    const clipboardData = tokenNode.textContent;
    {
        "success": true,
        "data": "eyJraWQiOiJ0MWNkcyIsImFsZyI6IlJTMjU2In0...v8_Mg2PfdhCMQ"
    }
    {
        "message": "No API key found in request"
    }
    {
        "success": false,
        "description": "Invalid API key",
        "code": 1005,
    }

    Prerequisites

    hashtag
    Trust1Connector API DNS

    The Trust1Connector API v3 exposes a secure REST API on the client device. Trust1Team has created a t1c.t1t.io DNS entry (or customer-specific DNS entry) that points to 127.0.0.1 in order to facilitate SSL communication. This means that if the customer infrastructure uses a proxy for all network traffic, an exemption must be made for t1c.t1t.io to always point to the origin device's loopback address.

    If no exemption is made and https://t1c.t1t.io is handled by a proxy, it will redirect to 127.0.0.1 IP of the proxy server instead of the local machine, and the Trust1Connector API will be unreachable.

    The reserved domain from Trust1Team (t1c.t1t.io) has been registered with DNSSEC on the aforementioned URI. When a PARTNER uses its own DNS, we strongly recommend applying DNSSEC on the domain used in production.

    hashtag
    DNS rebind protection

    Some (corporate) networks have a policy that disables the ability to bind a domain to a local network IP. The Trust1Connector relies on this for t1c.t1t.io which resolves in to 127.0.0.1 which is a local ip for localhost

    If DNS rebind protection is enabled it is unable to use t1c.t1t.io for connection towards the Trust1Connector because the network does not allow this Domain to be a local ip-address.

    To resolve the issue either DNS rebind protection can be disabled or you can whitelist the domain t1c.t1t.io to allow this domain.

    hashtag
    Applications using the Trust1Connector

    Applications that want to make use of the Trust1Connector will be run from a specific domain. This means that the Trust1Connector needs to know that certain domains/applications want to make use of the Trust1Connector's functionality.

    For these applications to gain access to the Trust1Connectors API we need to whitelist the domain in whats called the cors list. This list contains all the accepted domains that can make use of the Trust1Connector.

    circle-info

    If you want to use the Trust1Connector on a specific domain, please contact our support team to add this domain to the cors list.

    hashtag
    Distribution Service

    In order to correctly function, the Trust1Connector API must be able to connect to its configured Distribution Service. You must allow REST traffic to the following URLs (if applicable):

    • Acceptance: https://acc-ds.t1t.io

    • Production: https://ds.t1t.io

    A partner can opt for its own Distribution server, whereas the URIs mentioned above, will be defined by the hosting party.

    The option of working without Distribution Service is also possible. You can find all the possibilities to run the Trust1Connector here

    In some cases (environments) the Domain acc-ds.t1t.io or ds.t1t.io are not accessable. If this is because the domain cannot be resolved we do recommend to either ask the network/system administrator to make sure that those domains can be resolved on the network. Or changing the DNS server to the google DNS (8.8.8.8 & 8.8.4.4), this has solved the issue for some of our customers.

    hashtag
    Disk Space

    circle-info

    Keep in mind sizes can vary a bit depending on the Operating system and the environment (develop, acceptance, production)

    These differences will never be greater than 5Mb

    hashtag
    Windows

    Trust1Connector installer is about 15-20Mb in size. The installed size comes to 35-45Mb.

    This includes the Trust1Connector API, Registry and Sandbox.

    hashtag
    MacOS

    Trust1Connector installer is about 15-20Mb in size. The installed size comes to 40-50Mb.

    This includes the Trust1Connector API, Registry and Sandbox.

    The increased size over windows mainly comes to the way MacOS handles dialogs. These are distributed with the Trust1Connector as seperate binaries.

    hashtag
    API Key

    All endpoints of the Trust1Connector API are secured and require a JWT to access. To obtain a token, an .

    This API key must be requested from TRUST1TEAM, or created by the customer if they are hosting their own Distribution Service. The API key must never be used in a front-end application (where the API key can be compromised). The API key is needed to exchange the token, using a Distribution Server, resulting in a short-lived Json Web Token.

    A PARTNER can decide to distribute a version without the use of a JWT. In those cases, the liability of the security flow resides completely in the context of the web application, thus Trust1Team can not guarantee the security context where the Trust1Connector is integrated upon.

    hashtag
    Operating System

    Right now Trust1Connector support two operating systems;

    • MacOS 12.x or higher

      • X86 architecture

      • M1/ARM architecture

    Trust1Team support Windows/Mac OSX OS families where lifecycle support is guaranteed from the Vendor of the Operating System. The moment the OS version has been marked as ‘end of life’, Trust1Team can not guarantee the functionality anymore.

    When PARTNERS are in need to support an older version or keeping the support running on the level of Trust1Team, no guarantees can be made. Trust1Team can setup a custom project, on demand of the PARTNER. Those requirements, changes or other adaptations needed, are not covered in the Trust1Connector license fee.

    hashtag
    Windows 8.1 or higher

    To run in user-space on Windows 8.1 or higher some components have to be set on the operating system

    hashtag
    Registry keys

    Below you can find a list of all registry keys that will be created for the working of the Trust1Connector, All these keys are added to HKCU

    HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Run

    HKEY_CURRENT_USER\SOFTWARE\Trust1Team\Trust1Connector

    hashtag
    Cookies

    Since 3.5.x no more cookies are used.

    hashtag
    Browsers

    The Trust1Connector is browser agnostic so it does not matter what browser is being used as long as it support HTTP communication (HTTP 1.1) (which should all of them).

    Version wise we do recommend to use the latest versions of your browser for security reasons but the versions below is was we accept as a minimum

    • Chrome >80

    • Firefox >75

    • Edge 88 or higher

    Trust1Connector JS SDK

    You can find the trust1connector JS SDK for the Trust1Connector v3 via NPM

    You can also find the source code here

    Windows 8.1 or higher

    IE 11 (End of Life is June 15 2022)
  • All other browsers. As recent as possible

  • API key must be exchanged
    https://github.com/Trust1Team/t1c-sdk-js/tagsarrow-up-right

    Core Service

    hashtag
    Introduction

    The Trust1Connector core services address communication functionality with local devices. The Trust1Connector core exposes 2 main interfaces:

    • interface for web/native applications using JavaScrip/Typescript

    • REST API as a new approach and to incorporate the Trust1Connector as a microservice in the application architecture

    In this guide, we target only the use of Trust1Connector's core interface for web/native applications. The T1C-SDK-JS exposes protected resources for administration and consumer usage.

    The JavaScript library must be in order to access the all resource.

    hashtag
    Consumer resources

    Consumer resources are typically used from an application perspective:

    • Get pub-key certificate

    • Get version

    • Get Information (operating system, runtime, user context, variable configuration)

    Executing these functionality is explained further.

    hashtag
    Core Functionalities

    The Trust1Connector functionalities are about secured communication with device hardware. The document highlights communication with smart card readers - contact and contact-less. Other hardware devices can be enabled or integrated as well in the solution. Some of the already are, for example printer drivers, signature tablet drivers, ...

    After you've you can execute the rest of the Trust1Connector's functionality, for example listing the readers and fetching information from a specific smart card.

    hashtag
    List card readers

    Returns a list of available card readers. Multiple readers can be connected. Each reader is identified by a unique reader_id.

    The response will contains a list of card readers:

    When multiple readers are attached to a device, the response will show all connected card readers:

    Important to notice:

    • The response adds a card-element when a card is inserted into the card reader.

    • The response contains card-reader pin-pad capabilities

    hashtag
    Card Inserted

    As mentioned in the List card-readers, when a smart-card is inserted/detected, the reader will contain the cart-type based on the ATR. The ATR (Anwser To Reset), is the response from any smart-card when powered, and defines the card type. The Trust1Connector recognized more than 3k smart-card types.

    hashtag
    Pin-Pad Capabilities

    As mentioned in the List card-readers, when a card-reader has pin-pad capabilities, this will be mentioned in the response (notice the pinpadproperty):

    hashtag
    List Card-Readers - Explained Example

    The following example is the response for List card-readers on a device with 4 different card-readers attached:

    In the above example you notice that 4 card-readers are connected. Each card-reader receives his temporary id which can be used for other functions where a card-reader id is needed. This method can be requested in order to list all available card-readers, and optional cards-inserted. Each card-reader has a vendor provided name, which is retrieved from the card-reader itself. An additional property pinpad, a boolean value, denotes if the card-reader has pin-pad capabilities. A pin-pad is a card-reader, most of the times with its own display and key-pad. From a security perspective, it's considered best practice to use as much as possible pin-pad capabilities of a pin-pad card-reader. When a reader has a smart-card inserted (contact interface) or detected (contactless interface), the card type will be resolved by the GCL in order to respond with a meaningful type. In the above examples you see that; one card-reader has a Belgian eID card; another card-reader has a MisterCash or VISA Card available for interaction.

    The readers returned, are the card-readers with a card available. The card-readers where no card is presented, are ignored.

    hashtag
    Get card reader with card inserted

    Returns a list of available card readers with a smart card inserted. Multiple readers can be connected with multiple smart cards inserted. Each reader is identified by a unique reader_id and contains information about a connected smart card. A smart card is of a certain type. The Trust1Connector detects the type of the smart card and returns this information in the JSON response.

    Response:

    hashtag
    Get the Javascript SDK version

    To retrieve the version of the Javascript SDK you can use the version function available in the CoreService

    You can follow the example below to retrieve the version number

    The ouput in the log of the code above should look like the following

    hashtag
    Get device public key

    via the getDevicePublicKey endpoint you're able to fetch the public key information of the device. This requires an authenticated client to be able to access this endpoint.

    This endpoint is used in the library to encrypt pin, puk and pace information so that it is not exposed in the network logs of the browser.

    Encryption of pin, puk and pace is only possible when the Trust1Connector is registered via a DS and has a valid device key-pair. The SDK will automatically switch to send the pin, puk or pace info in clear text if its not able to encrypt. The Trust1Connector API will also detect if it has no valid device key-pair it will not try to decrypt the incoming pin, puk or pace information.

    hashtag
    Core interface

    Readers

    hashtag
    Introduction

    The Trust1Connector after correct initialization has the ability to retrieve the available card readers detected on the system. With these card readers you can continue and execute functionality such as retrieving biometric information, signing data, authentication, ...

    Below you can find more information on how to retrieve the available readers. All these functions are available in the Core Service

    hashtag
    List card readers

    Returns a list of available card readers. Multiple readers can be connected. Each reader is identified by a unique reader_id.

    The response will contains a list of card readers:

    When multiple readers are attached to a device, the response will show all connected card readers:

    Important to notice:

    • The response adds a card-element when a card is inserted into the card reader.

    • The response contains card-reader pin-pad capabilities

    hashtag
    Card Inserted

    As mentioned in the List card-readers, when a smart-card is inserted/detected, the reader will contain the cart-type based on the ATR. The ATR (Anwser To Reset), is the response from any smart-card when powered, and defines the card type. The Trust1Connector recognized more than 3k smart-card types.

    In the response below you notice that this specific card also includes a module and description property. Both of these are arrays and are also optional. This means that the Trust1Connector recognizes this specific token and knows which module can be used for this token. The Trust1Connector has the possibility to detect that a card can be used by more than 1 module, in that case the module array will display multiple values depicting which modules can be used. The description is purely metadata.

    hashtag
    Pin-Pad Capabilities

    As mentioned, when a card-reader has pin-pad capabilities, this will be mentioned in the response (notice the pinpadproperty):

    hashtag
    List Card-Readers - Explained Example

    The following example is the response for List card-readers on a device with 4 different card-readers attached:

    In the above example you notice that 4 card-readers are connected. Each card-reader receives his temporary id which can be used for other functions where a card-reader id is needed. This method can be requested in order to list all available card-readers, and optional cards-inserted. Each card-reader has a vendor provided name, which is retrieved from the card-reader itself. An additional property pinpad, a boolean value, denotes if the card-reader has pin-pad capabilities. A pin-pad is a card-reader, most of the times with its own display and key-pad. From a security perspective, it's considered best practice to use as much as possible pin-pad capabilities of a pin-pad card-reader.

    When a reader has a smart-card inserted (contact interface) or detected (contactless interface), the card type will be resolved by the Trust1Connector in order to respond with a meaningful type. In the above examples you see that; one card-reader has a Belgian eID card; another card-reader has a MisterCash or VISA Card available for interaction.

    hashtag
    Get card readers with card inserted

    Returns a list of available card readers with a smart card inserted. Multiple readers can be connected with multiple smart cards inserted. Each reader is identified by a unique reader_id and contains information about a connected smart card. A smart card is of a certain type. The Trust1Connector detects the type of the smart card and returns this information in the JSON response.

    Response:

    Downloading latest Trust1Connector

    hashtag
    Downloading Trust1Connector

    The T1C JS SDK no longer has a method to download the T1C installer.

    Instead, the T1C installer can be downloaded by navigating the client browser to the /v3_5/downloads/installer endpoint of the Distribution Service (e.g. https://acc-ds.t1t.io/v3_5/downloads/installer). The Distribution Service will analyse the User-Agent header and automatically initiate the download of an OS-appropriate installer of the latest configured version. The user agent string parsing is considered "best-effort"; as they can vary wildly depending OS and browser software.

    Alternatively, you can also initiate the download of a T1C installer with the following endpoints:

    1. /v3_5/downloads/installers/{{OS}}: This endpoint allows you to specify the OS for which you wish to obtain an installer. The possible values are win32, win64, unix, macos macosarm.

    2. /v3_5/downloads/installers/{{OS}}/versions/{{version}}

    circle-exclamation

    If using the generic endpoint 3_5/downloads/installer

    The automatic user-agent detection also does not differentiate between ARM/M1 and Intel Mac devices

    hashtag
    Differentiate between MacOS architectures

    For MacOS there are currently 2 supported architectures:

    • ARM64 (M1, ...)

    • Intel x86_64

    Currently, browsers etc do not display which architecture you're running. So in order to provide download links to the users you need to provide them with the option to download any of the 2 architectures. The user needs to decide which platform he is running.

    From the DS you can get both links with the following URL's (Production DS is used in the example);

    After this, you can provide the user with the choice of which one they want to download. Below you can see an example of how Google does this with their Browser, Google Chrome.

    Here you can clearly see they provide two versions, with a recommendation on Intel because the majority of the users still run Intel Apple devices

    hashtag
    Distribution services

    Below you can find a list of Distribuction services available from Trust1Team. If you are integrating with a 3rd party that uses the Trust1Connector you can contact them for information regarding the Distribution services.

    hashtag
    Example upgrade flow

    circle-info

    Information below is an example. If the integrator pleases he can alter the flow to their business use-case

    Via the Distribution service you can fetch the latest available version. This can be done via the call

    This will return all information needed from the latest version, for example our latest version at this point returns:

    You can check the boolean values mandatory recommended and allowed to determine a pop-up for example, so that the user can download and use this Trust1Connector.

    You can also retrieve the same information for a specific version. This endpoint returns the same response type as the latest version call:

    circle-info

    In the call above, you can substitute 3.6.0 for the desired version ID

    Example screenshot below of our demo-application (rmc.t1t.io)

    Below you can find an example of how an version check can be implemented in your front-end application.

    Status codes / error handeling

    hashtag
    Introduction

    In the Trust1Connector V3 we've completely reworked the error system. The goal of this system is to have error codes which are easy to read, understand and integrate. Our first implementation was a very generic approach with as few error codes as possible.

    After some iterations of the Trust1Connector we've discovered that the old error system did not suffice the needs of integrators. So we've upgraded the system to be more consistent and extensive. This provides integrators the flexibility to have a very detailed error handeling system while keeping it easy to understand and read.

    The new system provides information about the origin, type and detailed information of the error. We maintained the same type (integers) as our previous error codes, this makes it easier to differentiate them.

    hashtag
    Status Codes

    T1C uses response codes when handling a request.

    In case of an error the response will contain a body with more detailed information about the error:

    hashtag
    Error format

    Error codes will be in the following number format XXXXXX for example 201010 is an error code that depicts an error occurred with the reader in the Transaction service.

    The first digit depicts the Origin of that error, values can be the following;

    The following 2 digits describe the type of error;

    Finally we have 3 digits that give a more detailed error. These will give you more information about the specific error-case. Currently we have the following exceptions that can be thrown.

    hashtag
    Codes to expect

    The following list are codes that you can expect.

    hashtag
    General / Controller

    hashtag
    Aventry My Id 4

    hashtag
    Oberthur 7.3

    hashtag
    Idemia cosmo 8.2

    hashtag
    BeID

    hashtag
    Diplad

    hashtag
    Luxtrust

    hashtag
    Luxeid

    hashtag
    EMV

    hashtag
    Crelan

    hashtag
    File exchange

    hashtag
    Error codes coming from v2

    hashtag
    Simple error handeling

    The most simple way you can check the error codes is by only taking into account the latest 3 digits. The first 3 digits provide information about the Context and environment

    Module/container setup

    hashtag
    Introduction

    This document will describe how you can set up your desired module or generic module for using the functionalities that each module have. This ofcourse requires you to succesfully initialized the Trust1Connector via initialize or authenticated client and have a valid reader to contact

    hashtag
    Initialize your module

    When the user has selected his desired reader to use we can continue to initialize the module to use. This requires at least the readerID to properly initialize.

    Some modules like the LuxID module require you to also add a additional pin and pinType for example, this will also need to be provided in the module initialization.

    To initialize a module we first need the client as described in the introduction, here's a quick happy flow of how to retrieve a T1CClient

    When we have the T1CClient we can use this to choose our module. We can also use the generic interface if we want.

    circle-info

    the reader_id is the identifier which can be retrieved from the

    hashtag
    Base module initialization

    Below is an example of how to iniailize the Belgian EID module. This is a specific module that has all the functionalities for the Belgian EID card. You can see we use the client to fetch an instance of the beid module which we can further use to execute any functionality exposed on the beid module.

    now we can use this to for example fetch all the available token data;

    hashtag
    Generic

    hashtag
    Generic Token

    Ofcourse we can also use the generic interface which has all the functions exposed that you can use for all the modules.

    This will require you to always provide the module when you call any of its functions. Because it still needs to know which commands it needs to send to the card/token.

    When we now want to execute a getAllData for beid we would call it like this;

    triangle-exclamation

    Generic is split up in 2 different generic modules. This is because the payment modules differ to much from the regular tokens.

    hashtag
    Generic Payment

    To initialise a generic payment module its very similar to the token version but the available functions will differ.

    When we now want to execute a readData for emv we would call it like this;

    hashtag
    Interfaces

    Below you can find an overview of the generic interfaces. This shows what functions are available on both. If you want more information about a specific token/module you need to go to their respecitve pages which will explain more in detail what you can do with them.

    hashtag
    Generic Token interface

    hashtag
    Generic Payment interface

    hashtag
    Available modules

    Below is a list of the available modules;

    • generic

    • paymentGeneric

    • fileex

    hashtag
    Functions

    these are the exposed functions available on the T1CClient to initialize a module