Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
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.
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
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.
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
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)
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.
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 consent flow.
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).
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.
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:
Check correct versions for backwards compatibility
Pin Obfuscation not working for all modules
base64 encode the PIN before sending it to the API
Pin Obfuscation not working for all modules
base64 encode the PIN before sending it to the API
I want to enable module for Certinomis
Migrate certigna integration with the latest token
Return interface to previous state to prevent breaking applications
Pkcs11 module and os dialog return decryption error
Update certificate model to correctly handle multiple certificates
Device-key endpoint gets called in error handler instead of successhandler
File-exchange ArrayBuffer should be Blob
Initialising with invalid JWT does not throw an error
Entity and type response object inconsistency
Remoteloading split TX, RX and SW value based on APDU response
Use Device certificate to encrypt the pin value sent in clear text
I want to enable the module for eHerkenning
I want to enable module for Print Writer
Aventra, Idemia, Oberthur callback functions not being triggered
FileExchange typing inconsistency
Add LuxeID to the token generic interface in JS SDK
Fix imports for Pkijs
Disbable implicit any typing
Fix for bulk sign reset in JS SDK causes the reader ID not to be included in certificate retrieval
Provide separate implementation for Belgian eID with Crelan reader
A Web Application interacts with the Trust1Connector on standalone devices or within a shared environment. The Web Application is not aware, but must take this into consideration upon integration.
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.
Integrating the Trust1Connector can be done via the Javascript SDK. This SDK is compiled in regular javascript and in Typescript. Each release of the Javascript SDK will have the following files;
dist
T1CSdk.js (complete SDK)
T1CSdk.js.map
lib (typings, default Typescript compilation)
lib-esm (typings, Compilation with ES6 module support)
In V3 of the Trust1Connector the javascript SDK is meant as a comparable manner of integrating like the V2. The SDK includes most of the API featureset but not all.
We strongly encourage to integrate via the API, since this will be the most feature-complete and the de-facto way of integration in the future.
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.
Next up 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, ...
let environment = {
t1cApiUrl: 'https://t1c.t1t.io',
t1cApiPort: '51983',
t1cProxyUrl: 'https://t1c.t1t.io',
t1cProxyPort: '51983',
jwt: '' // retrieve via Back-end
};
const configoptions = new T1CSdk.T1CConfigOptions(
environment.t1cApiUrl,
environment.t1cApiPort,
environment.t1cProxyUrl,
environment.t1cProxyPort,
environment.jwt
);
config = new T1CSdk.T1CConfig(configoptions);
When the configuration is set you can initialise the Trust1Connector with that Config and an optional property for clipboardData. This clipboard data is used for initialisation of the Trust1Connector in a shared environment. This will be handled later.
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 => {
else if (err.code == 814501) {
$('#consentModal').modal('show', {
keyboard: false
});
$('.consent-token').text(makeid(20));
}
else if (err.code == 812020) {
$('.consent-token').text(makeid(20));
}
else if(err.code == 112999) {
document.querySelector("#initAlert").classList.remove("d-none")
document.querySelector("#initAlert").innerHTML = err.description;
} else {
console.error("T1C error:", err)
}
});
You can see in the code above we catch 3 errors;
814501: Consent error, this means the user is running in a shared environment and needs to provide his consent
812020: Initialisation error: The Trust1Connector is not able to initialise because it could not find any users with a Trust1Connector installed.
112999: T1C exception, this will be thrown when the T1C is not available, where you can display an URL where the user can download the T1C
To retrieve the reader after initialisation you can do the following;
core.readersCardAvailable().then(res => {
//Reader response
}, err => {
console.log("Cards available error:", err)
})
After initialisation of the T1C you can start using it. For example the BEID module needs to be initialised with a readerId, That is why fetching the readers and providing the user-selected reader to the client is a necessity.
function getBeid() {
if(selected_reader === null || selected_reader === undefined) return undefined
else return client.beid(selected_reader.id);
}
The code above will return a BEID client which can be used to execute the BEID functionality.
Initialisation of the Trust1Connector for shared environments is similar to the regular initialisation with the difference being a required consent. More information can be found in the Consent page.
For initialising the Trust1Connector in a shared environment you need to setup the config so that it contacts the Proxy. When initialising you need to provide a token that is residing on the user's clipboard, via this clipboard token the Proxy can determine which which user is trying to communicate and will return an updated configuration value for the API and the sandbox service.
This configuration update is handled by the SDK itself.
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;
The code above is an example of how you can integrate a copy command in the webbrowser
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.
Migration from the v2 to the v3 of the Trust1Connector can be done in 2 ways;
Integration of the API
Integration via the deprecated Javascript SDK
Both are viable integrations but we strongly suggest to integrate via the API since the JS SDK does not include all features, only the ones which were available in the v2. When integrating via the API you have more control over the Javascript packages used.
The Javascript SDK has the following packages as dependencies;
"@types/lodash": "^4.14.150",
"Base64": "^1.1.0",
"axios": "^0.19.2",
"jsencrypt": "^3.0.0-rc.1",
"lodash": "^4.17.15",
"logger-bootstrap": "^2.0.0-alpha2",
"semver": "^7.3.2",
"sha256": "^0.2.0",
"store2": "^2.11.1",
"uuid": "^8.0.0"
For updating your web application first of all you need to use the new Javascript SDK. After this there are some differences in using the SDK from the v2.
The configuration from the v2 has changed, we simplified this.
The v2 had the following configuration options;
export class GCLConfigOptions {
constructor(public gclUrl?: string,
public gwOrProxyUrl?: string,
public apiKey?: string,
public gwJwt?: string,
public tokenExchangeContextPath?: string,
public ocvContextPath?: string,
public dsContextPath?: string,
public dsFileContextPath?: string,
public pkcs11Config?: Pkcs11ModuleConfig,
public agentPort?: number,
public implicitDownload?: boolean,
public forceHardwarePinpad?: boolean,
public sessionTimeout?: number,
public consentDuration?: number,
public consentTimeout?: number,
public syncManaged?: boolean,
public osPinDialog?: boolean,
public containerDownloadTimeout?: number,
public localTestMode?: boolean,
public lang?: string,
public providedContainers?: T1CContainerid[]) {
}
}
With the v3 this is significantly simplified to the following;
export class T1CConfigOptions {
constructor(
public t1cApiUrl?: string,
public t1cApiPort?: string,
public t1cProxyUrl?: string,
public t1cProxyPort?: string,
public jwt?: string
) {}
}
Some of the config options of the v3 are still in review and can be removed up until the final release of the v3, in the table below you will find more information
V2 config option
V3 config option
Description
gclUrl
t1cApiUrl
in the V2 this was https://localhost:10443 while in the V3 this will be https://t1c.t1t.io (for T1T)
t1cApiPort
is the port where the webserver is listening on, in the v2 this is 10443 but in the v3 by default(T1T) this is 51983
t1cProxyPort
This value represents the port where the Proxy webserver is listening on. By default this is 51983
gwOrProxyUrl
t1cProxyUrl
Similar to the api url this is the URL where the proxy used in shared environment is running on. This is by default the same as the API url
apiKey
/
gwJwt
jwt
JWT token used for authentication of the web application towards the Trust1Connector. This must be retrieved from the web applications backend
tokenExchangeContextPath
/
ocvContextPath
/
dsContextPath
/
in v2 this was the context path for the DS based on the gwOrProxyUrl
dsFileContextPath
/
pkcs11Config
/
agentPort
/
implicitDownload
/
forceHardwarePinpad
/
sessionTimeout
/
consentDuration
/
syncManaged
/
osPinDialog
/
boolean which depicts the default os pin dialog value
containerDownloadTimeout
/
localTestMode
/
lang
/
providedContainers
/
After you've created your configuration object you can do the initialisation of the Trust1Connector SDK. This has largely remained the same except for the error codes.
V2 example:
config = new GCLLib.GCLConfig(configoptions);
GCLLib.GCLClient.initialize(config).then(res => {
client = res;
core = client.core();
console.log("GCLClient: ", res)
}, err => {
console.log("GCL error:", err)
})
V3 example;
config = new T1CSdk.T1CConfig(configoptions);
T1CSdk.T1CClient.initialize(config).then(res => {
client = res;
console.log("Client config: ", client.localConfig)
core = client.core();
}, err => {
errorHandler(err);
});
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.
The Trust1Connector supports user consent mechanism for applications:
implicit user consent: the user will be provided with a consent token which can be pasted into his clipboard. The T1C-GCL will implicitly retrieve the consent token form the clipboard and perform a verification (the token pasted in the clipboard - form the application context - should match with the token available on the clipboard for the T1C-GCL)
The consent can be configured to have an expiration date, when this expiration date has been exceeded, a new consent will be asked towards the user.
If the consent has been enabled upon installation of the Trust1Connector, a user will not be able to retrieve any data from the connector without first giving its consent, agreeing to give access to his/her card reader of filestorage. Without this consent, all requests will return a 401 Unauthorized response with error code 500 No valid consent found or at initialisation of the Trust1Connector SDK an error code 500 No valid consent found. The application should detect these error codes and use it to trigger the consent dialog.
The application shows this code word on screen and provide a button for 'copy-to-clipboard'. When the user has copied the code word to the clipboard (on user click button event), an implicit consent request can be executed towards the T1C. The T1C will grab the pasted code word from the user system clipboard and if both match, an implicit user consent has been granted for the calling application. The relation between the application and the local T1C instance is 'approved'. At this point the Trust1Connector returns a cookie that should be stored in the browser. This cookie will be re-used the next time the user wants to use the Trust1Connector until the cookie expires.
Initially the concept was based on copying programmatically the code word, from the application context, to the user system clipboard. Although, through CAB forum, this not allowed; A user interaction is mandatory. The application should provide a 'copy-to-clipboard' button or alike in order to 'trigger' a user action. Once this action has been done, the T1C executes the flow automatically, this is retrieval and verification of the code word.
Currently, the need for a user interaction is a known limitation (aka. clipboard.js). As this is the case, the W3C has a project ' Clipboard APIs' to propose a solution for a new clipboard API in browsers. The use case for 'Remote clipboard synchronisation' as a use case included in this draft proposal. As this is a draft, and not yet supported by the browsers, we can not perform an automatic 'paste' ('copy' in terms of the browser) to the clipboard.
Sending an implicit consent request can be done as follows:
T1CSdk.T1CClient.initialize(config).then(res => {
client = res;
console.log("Client config: ", client.localConfig)
core = client.core();
}, err => {
if (err.code == 814501) {
console.log(err)
client = err.client
$('#consentModal').modal('show', {
keyboard: false
});
$('.consent-token').text(makeid(20));
} else if (err.code == 815500) {
$('.consent-token').text(makeid(20));
} else if (err.code == 112999) {
// General
} else {
console.error("T1C error:", err)
}
});
$('#consentModal .btn-primary').on('click', (ev) => {
const tokenNode = document.querySelector('.consent-token');
var range = document.createRange();
range.selectNode(tokenNode);
window.getSelection().addRange(range);
try {
document.execCommand('copy');
} catch (err) {
console.log('Oops, unable to copy');
}
window.getSelection().removeRange(range);
const clipboardData = tokenNode.textContent;
client.core().getImplicitConsent(clipboardData).then(consentRes => {
client = consentRes // replace the client and other set variables of the T1C
core = client.core();
core.version().then(versionResult => console.log("T1C running on core " + versionResult));
$('#consentModal').modal('hide');
}, err => {
console.error(err)
})
});
This call has 1 required and 2 optional parameters:
Code Word (required): a code word in string format that will be shown in the consent dialog.
Consent duration in days (optional): Allows the application the specify how long this consent is to be valid if granted. If not provided, the default value is 365 days.
Callback function (optional): function to be called with the result of the consent request.
The response of the consent will be an updated T1C Client which you after this point can use to continue your use-case(s).
The response can also be a 400 Bad Request with status code 814501 or 814500 "No agents registered to the proxy service" which means that the request has been sent with the unique code but the Proxy cannot not find the user associated with it by checking the clipboards of all connected users.
This could mean that there is no T1C API client present or it is not running correctly.
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.
In order to use the JS-SDK, the library must be initialised with an api-key. The api-key is a key received upon subscription. The JS-SDK is a client library for web based consumers. As a reminder, the T1C can be used from a native applications context using a native client, or addressing directly the T1C interface. In order to work with an api-key in a browser context, 2 type of consumers can be distinguished:
SPA (Single Page Application) integration: this is a web application without any back-end
Web Application integration: this is a web application with a back-end implementation
For an SPA, an api-key (thus the access token to the Distribution Service) is considered unsafe in a browser context. For SPA's, Trust1Team configures extra security measures on infrastructure level. A mutual authentication is required and additional policies are applied (IP restriction policy, ...).
The api-key must be translated into an JWT token in order to enable communication with the T1C.
To initialise the JavaScript client library, the library must be loaded into your HTML page:
Once loaded, the script will expose a GCLLib global. This global will allow you to create a GCLConfig
:
The GCLConfigOptions
object will allow you to specify and/or override the configuration to be used. Configuration options can be found in the Configuration Options
below. You can create a GCLConfigOptions
as follows:
Now that we have a configuration, we can initialise the client library. The following example creates a Promise that will resolve with an instance of a T1CClient
:
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.
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.
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
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.
You can find the trust1connector JS SDK for the Trust1Connector v3 via NPM
You can also find the source code here
<script src="../T1CSdk.js" charset="utf-8"></script>
var configoptions = new T1CSdk.T1CConfigOptions(
environment.t1cApiUrl,
environment.t1cApiPort,
environment.t1cApiUrl,
environment.t1cApiPort,
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 => {});
// 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/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 => {});
Environment
DS url
Acceptance
https://acc-ds.t1t.io
Production
https://ds.t1t.io
export class ModuleDescriptionResponse extends DataObjectResponse {
constructor(public data: TokenModuleDescription, public success: boolean) {
super(data, success);
}
}
export class TokenCertificateResponse extends T1CResponse {
constructor(public data: TokenCertificate, public success: boolean) {
super(success, data);
}
}
export class TokenCertificate {
constructor(
public certificate?: string,
public certificates?: Array<string>,
public certificateType?: string,
public id?: string,
public parsedCertificate?: Certificate,
public parsedCertificates?: Array<Certificate>
) {}
}
export class TokenAddressResponse extends DataObjectResponse {
constructor(public data: TokenAddressData, public success: boolean) {
super(data, success);
}
}
export class TokenPictureResponse extends DataObjectResponse {
constructor(public data: TokenPictureData, public success: boolean) {
super(data, success);
}
}
export class TokenVerifyPinResponse extends DataObjectResponse {
constructor(public data: TokenVerifyPinResponseData, public success: boolean) {
super(data, success);
}
}
export class TokenVerifyPinResponseData {
constructor(
public verified: boolean
) {}
}
export class TokenSignResponse extends DataObjectResponse {
constructor(public data: TokenSignResponseData, public success: boolean) {
super(data, success);
}
}
export class TokenSignResponseData {
constructor(
public data?: string
) {}
}
export class TokenAuthenticateResponse extends DataObjectResponse {
constructor(public data: TokenAuthenticateResponseData, public success: boolean) {
super(data, success);
}
}
export class TokenAuthenticateResponseData {
constructor(
public data?: string
) {}
}
export class TokenModuleDescription {
constructor(
public desc: string
) {}
}
export class TokenAddressData {
constructor(
public municipality?: string,
public rawData?: string,
public signature?: string,
public streetAndNumber?: string,
public version?: number,
public zipcode?: string
) {}
}
export class TokenAllDataResponse extends DataObjectResponse {
constructor(public data: TokenAllData, public success: boolean) {
super(data, success);
}
}
export class TokenAllData {
constructor(
public picture?: TokenPictureData,
public biometric?: TokenBiometricData,
public address?: TokenAddressData,
) {}
}
export class TokenPictureData {
constructor(
public picture?: string,
public signature?: string,
public width?: number,
public height?: number,
) {}
}
export class TokenData {
constructor(
public rawData?: string,
public version?: string,
public serialNumber?: string,
public label?: string,
public prnGeneration?: string,
public eidCompliant?: string,
public graphicalPersoVersion?: string,
public versionRfu?: string,
public electricalPersoVersion?: string,
public electricalPersoInterfaceVersion?: string,
public changeCounter?: number,
public activated?: string,
) {}
}
export class TokenDataResponse extends DataObjectResponse {
constructor(public data: TokenData, public success: boolean) {
super(data, success);
}
}
export class TokenBiometricData {
constructor(
public birthDate?: string,
public birthLocation?: string,
public cardDeliveryMunicipality?: string,
public cardNumber?: string,
public cardValidityDateBegin?: string,
public cardValidityDateEnd?: string,
public chipNumber?: string,
public documentType?: string,
public firstNames?: string,
public name?: string,
public nationalNumber?: string,
public nationality?: string,
public nobleCondition?: string,
public pictureHash?: string,
public rawData?: string,
public sex?: string,
public signature?: string,
public specialStatus?: string,
public thirdName?: string,
public version?: number,
public issuer?: string
) {}
}
export class TokenBiometricDataResponse extends DataObjectResponse {
constructor(public data: TokenBiometricData, public success: boolean) {
super(data, success);
}
}
export class TokenAlgorithmReferencesResponse {
constructor(public data: TokenAlgorithmReferences, public success: boolean) {
}
}
export class TokenAlgorithmReferences {
constructor(public ref: Array<string>) {
}
}
export class TokenResetPinResponse {
constructor(public data: TokenResetPin, public success: boolean) {
}
}
export class TokenResetPin {
constructor(public verified: boolean) {
}
}
export class PinType {
static PIN = 'Pin';
static CAN = 'Can';
}
The Trust1Connector API will be located in %localappdata%/Trust1Connector/
The Trust1Connector Proxy will be located in the %programfiles%/Trust1Connector-Proxy/
The API will be located in
~/Library/Application Support/Trust1Team/Trust1Connector/
For the Trust1Connector API you do not need any administrator rights. The Trust1Connector Proxy requires administrator rights.
You can execute/double click on the following script which will automatically stop and restart the Trust1Connector
%localappdata%/Trust1Connector/t1c-api-sh-env-init.vbs
First unload and stop the services. The first is the API and the second is for card communication;
launchctl unload ~/Library/LaunchAgents/com.t1t.t1c.api.plist
launchctl unload ~/Library/LaunchAgents/com.t1t.t1c.grpc.plist
Now load the service again which will make it restart
launchctl load ~/Library/LaunchAgents/com.t1t.t1c.api.plist
launchctl load ~/Library/LaunchAgents/com.t1t.t1c.grpc.plist
%localappdata%/Trust1Connector/Logs
~/Library/Application Support/Trust1Team/Trust1Connector/resources/logs
And
~/Library/Application Support/Trust1Team/Trust1Connector/resources/t1c-api/logs
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.
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-GCL (Generic Connector Library).
export interface AbstractEidBE {
allData(filters?: string[] | Options, callback?: (error: T1CLibException, data: TokenAllDataResponse) => void): Promise<TokenAllDataResponse>;
allCerts(parseCerts?: boolean, filters?: string[] | Options, callback?: (error: T1CLibException, data: TokenAllCertsResponse) => void): Promise<TokenAllCertsResponse>;
biometric(callback?: (error: T1CLibException, data: TokenBiometricDataResponse) => void): Promise<TokenBiometricDataResponse>;
tokenData(callback?: (error: T1CLibException, data: TokenDataResponse) => void): Promise<TokenDataResponse>;
address(callback?: (error: T1CLibException, data: TokenAddressResponse) => void): Promise<TokenAddressResponse>;
picture(callback?: (error: T1CLibException, data: TokenPictureResponse) => void): Promise<TokenPictureResponse>;
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>;
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>;
allAlgoRefs(callback?: (error: T1CLibException, data: TokenAlgorithmReferencesResponse) => void): Promise<TokenAlgorithmReferencesResponse>
resetBulkPin(callback?: (error: T1CLibException, data: BoolDataResponse) => void): Promise<BoolDataResponse>;
}
All model information can be found in the Token typings model page
Initialise a Trust1Connector client:
T1CSdk.T1CClient.initialize(config).then(res => {
client = res;
}, err => {
console.error(error)
});
Get the Belgian eID container service:
var beid = client.beid(reader_id);
Call a function for the Belgian eID container:
function callback(err,data) {
if(err){console.log("Error:",JSON.stringify(err, null, ' '));}
else {console.log(JSON.stringify(data, null, ' '));}
}
beid.biometric(callback);
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:
var core = client.core();
core.readersCardAvailable(callback);
This function call returns:
{
"data": [
{
"card": {
"atr": "3B9813400AA503010101AD1311",
"description": ["Belgian eID Card"]
},
"id": "57a3e2e71c48cee9",
"name": "Bit4id miniLector",
"pinpad": false
}
],
"success": true
}
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:
var beid = client.beid(reader_id);
All methods for beid
will use the selected reader - identified by the reader_id
.
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).
Contains all card holder related data, excluding the card holder address and photo. The service can be called:
client.beid(reader_id).biometric(callback);
An example callback:
function callback(err,data) {
if(err){
console.log("Error:",JSON.stringify(err, null, ' '));
}
else {
console.log(JSON.stringify(data, null, ' '));
}
}
Response:
{
"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"
}
Contains the card holder's address. The service can be called:
client.beid(reader_id).address(callback);
Response:
{
"municipality": "Hoeselt",
"rawData": "ARJLZXJrc...AAAAAA==",
"signature": "mhPyeRg25H...w==",
"streetAndNumber": "Kerkstraat X",
"version": "0",
"zipcode": "3730"
}
Contains the card holder's picture stored on the smart card. The service can be called:
client.beid(reader_id).picture(callback);
Response:
{
"data": "/9j/4AAQSkZJRgABA...59aVpcklSDzyKUTEDGK//9k=",
"success": true
}
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
{
"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
}
Exposes all the certificates publicly available on the smart card.
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:
client.beid(reader_id).rootCertificate(parseCertsBoolean, callback);
Response:
{
success: true,
data: {
certificate?: string,
certificates?: Array<string>,
certificateType?: string,
id?: string,
parsedCertificate?: Certificate,
parsedCertificates?: Array<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:
client.beid(reader_id).authenticationCertificate(parseCertsBoolean, callback);
Response:
{
success: true,
data: {
certificate?: string,
certificates?: Array<string>,
certificateType?: string,
id?: string,
parsedCertificate?: Certificate,
parsedCertificates?: Array<Certificate>
}
}
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:
client.beid(reader_id).intermediateCertificates(parseCertsBoolean, callback);
Response:
{
success: true,
data: {
certificate?: string,
certificates?: Array<string>,
certificateType?: string,
id?: string,
parsedCertificate?: Certificate,
parsedCertificates?: Array<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:
client.beid(reader_id).nonRepudiationCertificate(parseCertsBoolean, callback);
Response:
{
success: true,
data: {
certificate?: string,
certificates?: Array<string>,
certificateType?: string,
id?: string,
parsedCertificate?: Certificate,
parsedCertificates?: Array<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:
client.beid(reader_id).encryptionCertificate(parseCertsBoolean, callback);
Response:
{
success: true,
data: {
certificate?: string,
certificates?: Array<string>,
certificateType?: string,
id?: string,
parsedCertificate?: Certificate,
parsedCertificates?: Array<Certificate>
}
}
All data on the smart card can be dumped at once, or using a filter. In order to read all data at once:
var filter = [];
client.beid(reader_id).allData({ filters: filter}, callback);
Response:
{
"picture": {
"picture": "/9j/4AAQSkZJRgABAgEBLAEsAAD/...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"
},
"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"
}
}
The filter can be used to ask a list of custom data containers. For example, we want to read only the biometric data
var filter = ['biometric'];
client.beid().allData({ filters: filter }, callback);
Response:
{
"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"
}
}
All certificates on the smart card can be dumped at once, or using a filter. In order to read all certificates at once:
var filter = [];
client.beid(reader_id).allCerts(parseCerts, { filters: filter}, callback);
Response:
{
"rootCertificate": {
...
},
"authenticationCertificate": {
...
},
"nonRepudiationCertificate": {
...
},
"intermediateCertificates": {
...
},
"encryptionCertificate": {
...
}
}
The filter can be used to ask a list of custom data containers. For example, we want to read only the rootCertificate
var filter = ['rootCertificate'];
client.beid(reader_id).allCerts(parseCerts, { filters: filter}, callback);
Response:
{
"rootCertificate": {
...
}
}
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;
Provided algorithm value
Selected algorithm by T1C
md5
md5
sha1
sha1
sha256
sha256
sha512
sha512
any other value
sha256
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
sha3_512
sha3_512
sha256
sha3_256
sha384
sha3_384
sha512
sha3_512
any other value
sha3_256
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:
var filter = null;
client.beid(reader_id).allCerts(parseCerts, { filters: filter}, callback);
Response:
{
"rootCertificate": {
...
},
"authenticationCertificate": {
...
},
"nonRepudiationCertificate": {
...
},
"intermediateCertificates": {
...
},
"encryptionCertificate": {
...
}
}
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'.
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.
var data = {
"pin":"...",
"algorithm":"sha1",
"data":"I2e+u/sgy7fYgh+DWA0p2jzXQ7E=",
"osDialog": true,
"txId": "1234",
"language": "fr"
}
client.beid(reader_id).sign(data, callback);
Crelan card readers only support nl
, fr
, and de
as languages
When the web or native application is responsible for showing the password input, the following request is used to sign a given hash:
var data = {
"pin":"...",
"algorithm":"sha1",
"data":"I2e+u/sgy7fYgh+DWA0p2jzXQ7E=",
"osDialog": true
}
client.beid(reader_id).sign(data, callback);
Response is a base64 encoded signed hash:
{
"success": true,
"data": {
"data" : "W7wqvWA8m9S...="
}
}
The 'authenticationreference' property can contain the following values: sha1, sha256, sha512, md5.
When the pin entry is done on the pin-pad, the following request is used to sign a given hash:
var data = {
"algorithm":"sha1",
"data":"I2e+u/sgy7fYgh+DWA0p2jzXQ7E=",
"osDialog": false
}
client.beid(reader_id).sign(data, callback);
Response is a base64 encoded signed hash:
{
"success": true,
"data": {
"data" : "W7wqvWA8m9S...="
}
}
The 'algorithm_reference' property can contain the following values: sha1, sha256, sha512, md5.
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.
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.
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.
const data = {
algorithm: "sha256",
data: "E1uHACbPvhLew0gGmBH83lvtKIAKxU2/RezfBOsT6Vs=",
pin: "1234"
}
const bulk = true;
beid.sign(data, bulk).then(res => {
}, err => {
console.error(err)
})
The PIN set for bulk signing can be reset by calling this method.
beid.resetBulkPin().then(res => {
}, err => {
console.error(err)
})
Response will look like:
{
"success": true,
"data": true
}
In order to calculate a hash from the data to sign, you need to know the algorithm you will use in order to sign.
This is sample text to demonstrate siging with Belgian eID
You can use the following online tool to calculate the SHA256: calculate SHA256
Hexadecimal result:
135b870026cfbe12dec348069811fcde5bed28800ac54dbf45ecdf04eb13e95b
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 converter
Base64-encoded result:
E1uHACbPvhLew0gGmBH83lvtKIAKxU2/RezfBOsT6Vs=
Now we can sign the data:
var data = {
"pin":"...",
"algorithm":"sha256",
"data":"E1uHACbPvhLew0gGmBH83lvtKIAKxU2/RezfBOsT6Vs="
}
client.beid(reader_id).signData(data, callback);
Result:
{
"success": true,
"data": {
"data" : "W7wqvWA8m9S...="
}
}
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.htm
When the web or native application is responsible for showing the password input, the following request is used to verify a card holder PIN:
var data = {
"pin":"..."
}
client.beid(reader_id).verifyPin(data, callback);
Response:
{
"verified": true
}
When the pin entry is done on the pin-pad, the following request is used to verify a given PIN:
var data = {}
client.beid(reader_id).verifyPin(data, callback);
Response:
{
"verified": true
}
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:
$("#buttonValidate").on('click', function () {
var _body={};
_body.pin = $("#psw").val(); //only when no pin-pad available
var beid = connector.beid(reader_id);
beid.verifyPin(_body, validationCallback);
});
Note that, when the user has at least one retry left, entering a correct PIN resets the PIN retry status
.
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;
Provided algorithm value
Selected algorithm by T1C
md5
md5
sha1
sha1
sha256
sha256
sha512
sha512
any other value
sha256
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
sha3_512
sha3_512
sha256
sha3_256
sha384
sha3_384
sha512
sha3_512
any other value
sha3_256
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:
var data = {
"pin": "...",
"algorithm": "sha1",
"data":"I2e+u/sgy7fYgh+DWA0p2jzXQ7E="
}
client.beid(reader_id).authenticate(data, callback);
Response:
{
"success": true,
"data": {
"data" : "W7wqvWA8m9S...="
}
}
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).
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.
Via the Trust1Connector modules you are able to retrieve available algorithms to use for Signing or Authenticate
generic.allAlgoRefs(module, callback);
The response you can expect is a list of algorithms, an example can be found below (the values below are purely examplatory)
{
"success": true,
"data": ["sha1", "sha256"]
}
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/downloads/installer
endpoint of the Distribution Service (e.g. https://acc-ds.t1t.io/v3/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:
/v3/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
.
/v3/downloads/installers/{{OS}}/versions/{{version}}
: This endpoint allows you to download a specific version of a T1C installer for a specific OS.
The automatic user-agent detection does not differentiate between ARM/M1 and Intel Mac devices
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);
# Intel x86_64
https://ds.t1t.io/v3/downloads/installers/macos
# ARM64
https://ds.t1t.io/v3/downloads/installers/macosarm
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
Environment
DS url
Acceptance
https://acc-ds.t1t.io
Production
https://ds.t1t.io
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.
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.
All model information can be found in the
Initialise a Trust1Connector client with a valid configuration:
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
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).
Contains all card holder related data, excluding the card holder address and photo. The service can be called:
An example callback:
Response:
Contains the card holder's address. The service can be called:
Response:
Contains the card holder's picture stored on the smart card. The service can be called:
Response:
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
Exposes all the certificates publicly available on the smart card.
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:
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:
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:
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:
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:
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:
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:
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'.
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:
The 'authenticationreference' property can contain the following values: sha1, sha256, sha512, md5.
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 'algorithm_reference' property can contain the following values: sha1, sha256, sha512, md5.
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.
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.
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.
The PIN set for bulk signing can be reset by calling this method.
Response will look like:
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:
When the pin entry is done on the pin-pad, the following request is used to verify a given PIN:
Response:
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.
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)
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.
The ID-One Cosmo V7-n is part of the Oberthur family of cryptographic modules called ID-One Cosmo V7. Modules within
this family share the same functionalities and the description of the ID-One Cosmo V7 applies to all versions including the “-n” subject to this validation.
This document describes the functionality provided by the Oberthur ID-One smartcard - which is a PKI container:
ID-One Cosmo V7-n; FIPS 140-2 Security Policy
All model information can be found in the
When initialisation is finished you can continue using the aventra object to execute the functions below.
The expected response for this call should be;
The expected response for this call should be;
Exposes all the certificates publicly available on the smart card. The following certificates can be found on the card:
Root certificate
Signing certificate
Authentication certificate
Issuer certificate
Encryption 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 expected response for this call should be;
This will return information of the Aventra card.
The expected response for this call should be;
When additional parsing of the certificate is needed you can add a boolean to indicate if you want to parse the certificate or not.
Contains the 'root certificate' stored on the smart card. The service can be called:
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:
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:
The expected response for these calls should be in the following format;
The expected response for these calls should be in the following format;
Data can be signed using the smartcard. To do so, the SDK 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 has
To sign data, an algorithm must be specified in the algorithm
property (see ), and a Base64-encoded string representation of the digest bytes of the same algorithm in the data
property.
Additionally, 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.
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.
The expected response for this call should be;
The PIN set for bulk signing can be reset by calling this method.
Response will look like:
The SDK 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.
The expected response for this call should be;
The expected response for this call should be;
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.
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.
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 initialized with a correct token in order to access the all resource. The security policy for Trust1Connector
v3 secured ALL endpoints.
Protected resources are administration resources. The JavaScript library must be initialized with a correct token in order to access the resource.
Download Trust1Connector
installer
Get Information of the device and user context
Register T1C for device
Update T1C on device (install new version)
Update DS (distribution server) metadata
Increment use case counter
Executing these functionality is explained further.
Consumer resources are typically used from an application perspective:
Get pub-key certificate
Get version
Get Information (operating system, runtime, user context, variable configuration)
List card-readers
List modules
Get module
Get card-reader
Get card-reader with cards inserted
Get card-readers without card
Get consent (needed for shared environments)
Detect card for card-reader (polling utility resource)
Detect any card (polling utility resource)
Detect card-readers (polling utility resource)
Browser Information (utility resource)
Executing these functionality is explained further.
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, ...
The client can be initialized by passing a T1CConfig
object in the constructor
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
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.
As mentioned in the List card-readers
, when a card-reader has pin-pad capabilities, this will be mentioned in the response (notice the pinpad
property):
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.
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:
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.