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...
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 following page describes how you can integrate the Certigna module exposed on the Trust1Connector onto your web application.
export interface AbstractEidGeneric {
// getModuleDescription(module: string, callback?: (error: T1CLibException, data: DataObjectResponse) => void): Promise<DataObjectResponse>;
// 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: TokenDataResponse) => void): Promise<TokenDataResponse>;
// 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>;
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>;
allAlgoRefs(module: string, callback?: (error: T1CLibException, data: TokenAlgorithmReferencesResponse) => void): Promise<TokenAlgorithmReferencesResponse>
resetBulkPin(module: string, callback?: (error: T1CLibException, data: BoolDataResponse) => void): Promise<BoolDataResponse>;
}
All model information can be found in the Token typings model page
Initialise a Trust1Connector client with a valid configuration:
T1CSdk.T1CClient.initialize(config).then(res => {
client = res;
}, err => {
console.error(error)
});
In order to get all connected card-readers, with available cards:
var core = client.core();
core.readersCardAvailable(callback);
This function call returns:
{
"data": [
// List of reader with cards found
],
"success": true
}
Using the generic interface can be done as follows;
const module = "certigna";
var generic = client.generic(selected_reader.id);
Because we're using the generic interface we can define the module variable upfront since we know we want to use the certigna integration.
Exposes all the certificates publicly available on the smart card.
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:
generic.authenticationCertificate(module, parseCertsBoolean, callback);
Response:
{
"certificate": {
"certificate": "MIIFjjCCA3agAwIBAgIIO...xg==",
"parsedCertificate": {...}
},
// OR if multiple certificates
"certificates" [
{
"certificate": {
"certificate": "MIIFjjCCA3agAwIBAgIIO...xg==",
"parsedCertificate": {...}
}
}
]
}
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:
generic.nonRepudiationCertificate(module, parseCertsBoolean, callback);
Response:
{
"certificate": {
"certificate": "MIIFjjCCA3agAwIBAgIIO...xg==",
"parsedCertificate": {...}
},
// OR if multiple certificates
"certificates" [
{
"certificate": {
"certificate": "MIIFjjCCA3agAwIBAgIIO...xg==",
"parsedCertificate": {...}
}
}
]
}
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 = [];
generic.allCerts(module, parseCerts, { filters: filter}, callback);
Response:
{
"certificate": {
"certificate": "MIIFjjCCA3agAwIBAgIIO...xg==",
"parsedCertificate": {...}
},
// OR if multiple certificates
"certificates" [
{
"certificate": {
"certificate": "MIIFjjCCA3agAwIBAgIIO...xg==",
"parsedCertificate": {...}
}
}
]
}
The filter can be used to ask a list of custom data containers. For example, we want to read only the rootCertificate
var filter = ['authenticationCertificate'];
generic.allCerts(module, { filters: filter}, callback);
Response:
{
"certificate": {
"certificate": "MIIFjjCCA3agAwIBAgIIO...xg==",
"parsedCertificate": {...}
},
// OR if multiple certificates
"certificates" [
{
"certificate": {
"certificate": "MIIFjjCCA3agAwIBAgIIO...xg==",
"parsedCertificate": {...}
}
}
]
}
To get the certificates necessary for signature validation in your back-end:
var filter = null;
generic.allCerts(module, { filters: filter}, callback);
Response:
{
"authenticationCertificate": {
...
},
"nonRepudiationCertificate": {
...
}
}
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:
var data = {
"pin":"...",
"algorithmReference":"sha1",
"data":"I2e+u/sgy7fYgh+DWA0p2jzXQ7E=",
"osDialog": true
}
generic.sign(module, data, callback);
Response is a base64 encoded signed hash:
{
"success": true,
"data": "W7wqvWA8m9SBALZPxN0qUCZfB1...0nzB7hXC/Lc/fMru82m/AAqCuGTYMPKcIpQG6MtZ/SGVpZUA/71jv3D9CatmGYGZc52cpcb7cqOVT7EmhrMtwo/jyUbi/Dy5c8G05owkbgx6QxnLEuTLkfoqsW9Q="
}
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 = {
"algorithmReference":"sha1",
"data":"I2e+u/sgy7fYgh+DWA0p2jzXQ7E=",
"osDialog": false
}
generic.sign(module, data, callback);
Response is a base64 encoded signed hash:
{
"success": true,
"data": "W7wqvWA8m...hXC/Lc/fMru82m/AAqCuGTYMPKcIpQG6MtZ/SGVpZUA/71jv3D9CatmGYGZc52cpcb7cqOVT7EmhrMtwo/jyUbi/Dy5c8G05owkbgx6QxnLEuTLkfoqsW9Q="
}
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;
generic.sign(module, data, bulk).then(res => {
}, err => {
console.error(err)
})
The PIN set for bulk signing can be reset by calling this method.
generic.resetBulkPin(module).then(res => {
}, err => {
console.error(err)
})
Response will look like:
{
"success": true,
"data": true
}
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":"..."
}
generic.verifyPin(module, 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 = {}
generic.verifyPin(module, data, callback);
Response:
{
"verified": true
}
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_reference": "sha1",
"data":"I2e+u/sgy7fYgh+DWA0p2jzXQ7E="
}
generic.authenticate(module, data, callback);
Response:
{
"success": true,
"data": "W7wqvWA8m9SBALZPxN0qUCZfB1O/WLaM/silenLzSXXmeR+0nzB7hXC/Lc/fMru82m/AAqCuGTYMPKcIpQG6MtZ/SGVpZUA/71jv3D9CatmGYGZc52cpcb7cqOVT7EmhrMtwo/jyUbi/Dy5c8G05owkbgx6QxnLEuTLkfoqsW9Q="
}
Take notice that the PIN property can be omitted when using a smart card reader with pin-pad capabilities.
Via the Trust1Connector generic 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"]
}
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.
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
config = new T1CSdk.T1CConfig(configoptions);
T1CSdk.T1CClient.initialize(config).then(res => {
client = res;
console.log("Client config: ", client.localConfig)
core = client.core();
}, err => {
errorHandler(error);
});
Returns a list of available card readers. Multiple readers can be connected. Each reader is identified by a unique reader_id
.
T1CClient.initialize(config).then(res => {
var coreService = res.core();
core.readers(callback);
})
The response will contains a list of card readers:
{
"success": true,
"data": [
{
"id": "57a3e2e71c48cee9",
"name": "Bit4id miniLector",
"pinpad": false,
"card": {
"atr": "3B9813400AA503010101AD1311",
"description": [
"Belgium Electronic ID card (eID)"
],
"module": "beid"
}
}
]
}
When multiple readers are attached to a device, the response will show all connected card readers:
{
"data": [
{
"id": "ec3109c84ee9eeb5",
"name": "Identiv uTrust 4701 F Dual Interface Reader(2)",
"pinpad": false
},
{
"card": {
"atr": "3B9813400AA503010101AD1311",
"description": [
"Belgium Electronic ID card"
]
},
"id": "57a3e2e71c48cee9",
"name": "Bit4id miniLector",
"pinpad": false
},
{
"id": "c8d31f8fed44d952",
"name": "Identiv uTrust 4701 F Dual Interface Reader(1)",
"pinpad": false
}
],
"success": true
}
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.
{
"data": [
{
"card": {
"atr": "3B9813400AA503010101AD1311",
"description": [
"Belgium Electronic ID card"
]
},
"id": "57a3e2e71c48cee9",
"name": "Bit4id miniLector",
"pinpad": false
}
],
"success": true
}
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):
{
"data": [
{
"card": {
"atr": "3B9813400AA503010101AD1311",
"description": [
"Belgium Electronic ID card"
]
},
"id": "57a3e2e71c48cee9",
"name": "Bit4id miniLector",
"pinpad": false
}
],
"success": true
}
The following example is the response for List card-readers
on a device with 4 different card-readers attached:
{
"data": [
{
"id": "ec3109c84ee9eeb5",
"name": "Identiv uTrust 4701 F Dual Interface Reader(2)",
"pinpad": false
},
{
"card": {
"atr": "3B67000000000000009000",
"description": [
"MisterCash & Proton card",
"VISA Card (emitted by Bank Card Company - Belgium)"
]
},
"id": "e5863fcc71478871",
"name": "Gemalto Ezio Shield Secure Channel",
"pinpad": true
},
{
"card": {
"atr": "3B9813400AA503010101AD1311",
"description": [
"Belgium Electronic ID card"
]
},
"id": "57a3e2e71c48cee9",
"name": "Bit4id miniLector",
"pinpad": false
},
{
"id": "c8d31f8fed44d952",
"name": "Identiv uTrust 4701 F Dual Interface Reader(1)",
"pinpad": false
}
],
"success": true
}
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.
GCLClient.initialize(config, function(err, client) {
var coreService = client.core();
core.readersCardAvailable(callback);
});
Response:
{
"data": [
{
"card": {
"atr": "3B9813400AA503010101AD1311",
"description": []
},
"id": "57a3e2e71c48cee9",
"name": "Bit4id miniLector",
"pinpad": false
}
],
"success": true
}
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.
export interface AbstractCore {
getImplicitConsent(codeWord: string, durationInDays?: number, callback?: (error: T1CLibException, data?: T1CClient) => void): Promise<T1CClient>;
updateJWT(jwt: string, callback?: (error: T1CLibException, data?: T1CClient) => void): Promise<T1CClient>
info(callback?: (error: T1CLibException, data: InfoResponse) => void): void | Promise<InfoResponse>;
reader(reader_id: string, callback?: (error: T1CLibException, data: SingleReaderResponse) => void): Promise<SingleReaderResponse>;
readers(callback?: (error: T1CLibException, data: CardReadersResponse) => void): Promise<CardReadersResponse>;
readersCardAvailable(callback?: (error: T1CLibException, data: CardReadersResponse) => void): Promise<CardReadersResponse>;
readersCardsUnavailable(callback?: (error: T1CLibException, data: CardReadersResponse) => void): Promise<CardReadersResponse>;
getUrl(): string;
version(): Promise<string>;
getDevicePublicKey(): Promise<string>;
}