Encodings using Personal Desktop Client middleware in Identity Manager
This article includes updates for Smart ID 23.10.3.
An encoding description contains the information for the electronic personalization of a card. You import the encoding description from a file. This can be used in Smart ID Identity Manager.
This article describes how you create descriptions for Nexus Personal Desktop Client.
Mandatory middleware configuration
After installing and updating Nexus Personal Desktop Client, make the following configuration changes for proper operation of the Nexus Personal Desktop Client middleware with Identity Manager:
Edit C:\Program Files (x86)\Personal\config\iD2ppa.cfg and set the following (with the appropriate path instead of the example given here):
Example: Set path to PIN encryption certificate
CODE[PIN Encryption] File=C:\path\to\the\certificate.crt
The certificate you reference here can be an arbitrary dummy certificate, unless you need a specific certificate for non-Identity Manager use-cases.
Caching can cause problems during encoding due to outdated data, so you have to disable it.
Set the following in C:\Program Files (x86)\Personal\config\Personal.cfg (system-wide base config) and/or in %APPDATA%\Personal\config\Personal.cfg (per-user override config - this takes precedence, if set in both):
Disable caching of card content
CODE[Cache] CacheValidity=0
Encodings
As the 64 bit version of the Nexus Personal Desktop Client middleware DLL cannot initialize cards, it is necessary to set only the path to the 32 bit DLL in the encoding description.
Set the following in the encoding description (note the explicit use of PKCS11LibraryWindows32 and the absence of PKCS11Library and PKCS11LibraryWindows64 definitions):
Configure DLL
CODE[Description] PKCS11LibraryWindows32=C:/Program Files (x86)/Personal/bin/personal.dll
For encodings that use JPKIEncoder (usually via Nexus Card SDK), you also need to set the JAVA_HOME environment variable to the root folder of a 32 bit JRE, as a 64 bit JRE cannot load 32 bit DLLs.
This does not apply for encodings using Smart ID Desktop app, as it does not use Java.
To initialize a token with the Nexus Personal Desktop Client middleware, in addition to the topics covered in Card initialization and credentials in Identity Manager, the encoding must also contain a Card Profile (.cpf file). The profile must be referenced in the encoding description. If the Card Profile contains variables, you can assign arbitrary values to them.
Do the following:
- Create a profile. In the encoding description, click +Add and enter a name to the file you want to create. The convention is to use the .cpf file extension for card profiles. For clarity purposes, let the filename end with .cpf.
- Edit the profile. You can copy and paste the contents of an existing .cpf file.
In the encoding description, reference the created .cpf file using the keyword ChipProfile.
Optional: If you want to assign values to any variables in the profile, do the following:
Add the variable names in the [Fields] section. Each field name must be followed by an equals sign ("=").
In the [Description] section, reference these variables using the keyword ProfileParameters. Multiple variables can be referenced, use comma as the separator.
Switch to the Encoding Fields tab and map values to the variables. The values must be Base64 encoded.
During token initialization, the values will be Base64-decoded and assigned to the profile variables.
Do not use the keywords SEC_PIN1, SEC_PIN2, SEC_PUK, and SEC_OP as variable names.
The keywords SEC_PIN1, SEC_PIN2, SEC_PUK, and SEC_OP are used to pass parameters to the Card Profiles to set PINs. Setting a PIN may involve further logic than simply passing parameters to the profile, therefore you should not set these variables yourself but use the appropriate keywords (for example, PIN, InitialPUK, etc) instead.
variable1
and variable2
will be passed to the profile upon token initialization.Initialize token
[Fields]
variable1=
variable2=
[Description]
InitToken=true
ChipProfile=profilename.cpf
ProfileParameters=variable1, variable2
(...)
Nexus Personal Desktop Client can create cards which use different credentials to log in as administrative user (user type CKU_SO as defined in the PKCS#11 standard).
Depending on the settings in the card profile (CPF) used to initialize the card, either the PUK or the operator PIN will be used.
In case of the latter, the PUK is only used for the Personal-specific PIN unblocking method, but not as administrative login.
Define like this in the encoding description:
CODE[Description] Operator_Pin=... OperatorPinIsSOCredential=#true
Description of the elements:
Element Description OperatorPinIsSOCredential= The default value is false, which works for the standard Identity Manager PCM encodings, that use the PUK as SO credential. Instead of setting the value to true or false directly in the the encoding description file (the DSC file), you can also use a mapped field, like this:
CODE[Fields] UseOpPin= [Description] Operator_Pin=... OperatorPinIsSOCredential=UseOpPin
Nexus Personal Desktop Client 5.7.1 or lower does not support changing the PUK.
Nexus Personal Desktop Client 5.7.2 or higher does support changing the PUK, but only for specific cards:
- Cosmo 7
- Cosmo 8.2
For all other cards there is no way to change the PUK with this middleware.
This feature requires Identity Manager 21.04.3 or higher - changing the PUK with Nexus Personal Desktop client is blocked in previous Identity Manager versions.
The serial number is created with a number range in Identity Manager and then set on the card, the certificates and in the CM token. The handling of the card secrets is done on the server by CardProductionPostProcessor. This ensures that both possible certificate request processes (P12 requests, P10 requests) together with token creation on Nexus Certificate Manager can be handled.
Define like this in the encoding description:
CODE[Encoding] Type=1024,Chip Devices=8710 [Fields] AppList= ICCSN= PIN_FIELD= PUK_FIELD= OP_PIN_FIELD= P12CERTIFICATE_B= P12PASSWORD_B= PRIME_FIELD_WITH_CARD_SERIAL= [Description] PKCS11LibraryWindows32=C:/Program Files (x86)/Personal/bin/personal.dll iccsnfield=ICCSN UseSelectCriteriaIccsn=false InitToken=true InitialPUK=PUK_FIELD Operator_Pin=OP_PIN_FIELD InitialLabel=#01234567890123456789012345678901 ChipProfile=PRIME_CardOS5_personal.cpf PIN=PIN_FIELD CMSCardSerialNumber=PRIME_FIELD_WITH_CARD_SERIAL ApplicationListField=AppList [Application_A] CardSerialNumberField=PRIME_FIELD_WITH_CARD_SERIAL CertTempl=EncHardCodedValuesP10 ObjectCriteria=CKO_PUBLIC_KEY,CKA_LABEL,string,"Digital Signature" [Application_B] CardSerialNumberField=PRIME_FIELD_WITH_CARD_SERIAL CertTempl=EncHardCodedValues KeyArchivalRequest=true WriteP12Data=true Certificate=P12CERTIFICATE_B P12PASSWORD=P12PASSWORD_B
Description of the elements:
Element Description InitToken=true This is the trigger to run the CardProductionPostProcessor which actually sets the card secrets for the token on the Nexus CM. CMSCardSerialNumber=PRIME_FIELD_WITH_CARD_SERIAL Maps the card serial number to be written on the physical smart card and the token on the Nexus CM for setting the card secrets. These two mappings are used to ensure that a generated (either by Identity Manager or by Certificate Manager) card serial number can be used over several applications.
Usually you need an administrative login to write the card serial number. This mechanism is described in Certificates and keys in Identity Manager (heading "Create external card serial number and reuse value (CM)".)
See also "Use operator PIN vs. PUK to log in" above.
By setting the "CMSCardSerialNumber", you override the chip serial number, which acts as a default value of the ICCSN. Most applications identify the card with this overridden number. However, in some cases the original chip serial number is needed. There are three use cases working on the ICCSN:
- Read ICCSN from the active card
- Select a card based on the ICCSN (optionally combined with the ATR)
- Read the ICCSNs of all available cards (optionally combined with the ATR)
The three use cases above are fully supported by the "useChipSerialAslccsn" flag, which allows to ignore the overridden value provided via "CMSCardSerialNumber".
If the value has not been overridden, the flag has no effect.
Define like this in the encoding description:
CODE[Fields] iccsnField= ... [Description] useChipSerialAsIccsn=true ICCSN=iccsnField
There is a flag that allows to delete the entire token profile, and return the card to the uninitialized state. This is done by using a virtual object called "Card Eraser" available on certain cards (for example, CardOS 4.4, 5.x, certain Gemalto cards...).
Define like this in the encoding description:
CODE[Description] DeleteProfile=true
This flag is currently not supported on other middlewares and its use will result in an error.
If a PIN or PUK is also passed with the encoding description, the highest of those is used to log in, otherwise, an attempt to delete anonymously is done.
Neither PIN nor PUK provides a benefit over anonymous deletion - there is a third credential (operator PIN), which Personal Desktop Client requires to delete the card, but Identity Manager does not yet support to log in with that.
Whether or not you will be able to anonymously erase the card depends on the CPF file that was used to initialize the card.
Examples
- MakeCardEraseable() at the start and BurnFuse() at the end => anonymous erase should work
- Neither MakeCardEraseable() at the start nor BurnFuse() => anonymous erase should work
- BurnFuse() at the end, MakeCardEraseable() missing => anonymous erase will fail
An exception will be thrown if the "Card Eraser" object is not found.
This feature requires the use of Smart ID Desktop App as encoding application. Encoding via JPKIEncoder through Nexus Card SDK is not supported.
When pre-personalizing a card via Key Generation System (KGS) (see Produce smart cards in Certificate Manager), you can store a set of PINs on the card, which are encrypted with the public key of a so-called PIN Encryption Certificate.
Identity Manager can then read and decrypt those PINs, for example, to create a PIN letter for the user.
An example card profile (CPF) for pre-personalization could look like this:
Example: pinblob_demo_sketch.cpf
MakeCardEraseable()
CardModel 'SIEMENS50'
PROFILENAME = 'P15_Siemens'
PERSINFO_PUT_PROFILENAME(PROFILENAME)
; prepare credentials to put into the "Encrypted PINs" blob... (you can skip those you don't need)
SEC_PIN1 = ... ; TODO: define PIN1 (e.g. via SECRANDOM(...))
PERSINFO_PUT_SEC(SEC_PIN1)
SEC_PIN2 = ... ; TODO: define PIN2 (e.g. via SECRANDOM(...))
PERSINFO_PUT_SEC(SEC_PIN2)
SEC_PIN3 = ... ; TODO: define PIN3 (e.g. via SECRANDOM(...))
PERSINFO_PUT_SEC(SEC_PIN3)
SEC_PUK = ... ; TODO: define PUK (e.g. via SECRANDOM(...))
PERSINFO_PUT_SEC(SEC_PUK)
SEC_PUK1 = ... ; TODO: define PUK1 (e.g. via SECRANDOM(...))
PERSINFO_PUT_SEC(SEC_PUK1)
SEC_PUK2 = ... ; TODO: define PUK2 (e.g. via SECRANDOM(...))
PERSINFO_PUT_SEC(SEC_PUK2)
SEC_OP = ... ; TODO: define OP PIN (e.g. via SECRANDOM(...))
PERSINFO_PUT_SEC(SEC_OP)
SEC_MAN = ... ; TODO: define MAN PIN (e.g. via SECRANDOM(...))
PERSINFO_PUT_SEC(SEC_MAN)
; ...now create the PIN blob...
PERSINFO_ENCRYPT_SEC()
; start files setup...
MasterFile
;..Directory DFPKCS15
;
;(RID = 0x{A0 00 00 63}, App='PKCS 15')
CreateDf DFPKCS15 id=0x5015 maxsize=22000 update=always create=always \
aid=0x{A0 00 00 00 63 50 4B 43 53 2D 31 35}
CreateEf EFODF id=0x5031 maxsize=auto read=always update=always
CreateEf EFCDF1 id=0x4441 maxsize=1700 read=always update=always
CreateEf EFCERT1 id=0x4541 maxsize=6000 read=always update=always
EndDF ;DFPKCS15
Endfile
File Static EFODF
data= 0x{
A4 0A ; PKCS15Certificates (read only)
30 08 ; path alternative
04 06 ;
3F 00 50 15 44 41
}
Endfile
File Static EFCDF1
data= 0x{
30 2F ; Cert 1
30 1A ; Common object attributes
0C 11 ; Label: Digital Signature
44 69 67 69 74 61 6C 20 53 69 67 6E 61 74 75 72 65
03 02 06 40 ; Flags: not private, modifiable
04 01 01 ; authentication id
30 03 ; Common certificate attributes
04 01 11 ; id
A1 0C ; X.509 certificate attributes
30 0A
30 08 ; certificate value indirect
04 06
3F 00 50 15 45 41
}
Endfile
File Dynamic EFCERT1
; here the blob is written to the EFCERT1 file, it will containing a data object called "Encrypted PINs"
data = PERSINFO_SEC() ; there are also variants like PERSINFO_PUT_PUBRSA_AND_SEC() which add extra data to the same file
Endfile
; and now the files are created
CreateFiles()
See the PPA Scripting Language documentation PDF for more details (available in the doc.zip file for every Personal Desktop Client release in the support portal.)
Prerequisites
Configure private keys
You must configure the private keys matching any PIN encryption certificate you want to decrypt PINs for.
- Edit the following config files in Identity Manager Operator:
Open the <tomcat>/webapps/<application>/WEB-INF/classes/engineSignEncrypt.xml file (see Sign and encrypt engine in Identity Manager for more information) and define key entries and corresponding descriptors. For PIN decryption, always use descriptor types with algorithm="RSA" and no further parameters aside from the key name. See the example below:
Example: extract of engineSignEncrypt.xml
XML<?xml version="1.0" encoding="UTF-8"?> <engineSignEncrypt> <descriptors> ... <descriptor name="PinKeyDescA" version="1"> <type algorithm="RSA" key="pinKeyA" /> </descriptor> <descriptor name="PinKeyDescB" version="1"> <type algorithm="RSA" key="pinKeyB" /> </descriptor> ... </descriptors> <keys> ... <!-- this key is loaded from a file --> <key name="pinKeyA"> <type name="pkcs12" locationValue="classpath:pinKeyA.p12" pin="432809864240763"/> </key> <!-- this key resides in a HSM for improved security --> <key name="pinKeyB"> <type name="HSM" locationValue="C:\Program Files\Utimaco\CryptoServer\Lib\cs_pkcs11_R2" pin="10297385314563206" alias="myOtherPinKey" slot="3" /> </key> ... </keys> </engineSignEncrypt>
Open the <tomcat>/webapps/<application>/WEB-INF/classes/system.properties file and specify the parameter
pinBlobDecryptor.keyDescriptorNames
: add a comma-separated list to the parameter, of key descriptor names for all those keys you want to decrypt PINs with. See the example below:Example: extract of engineSignEncrypt.xml
CODE<?xml version="1.0" encoding="UTF-8"?> <engineSignEncrypt> <descriptors> ... <descriptor name="PinKeyDescA" version="1"> <type algorithm="RSA" key="pinKeyA" /> </descriptor> <descriptor name="PinKeyDescB" version="1"> <type algorithm="RSA" key="pinKeyB" /> </descriptor> ... </descriptors> <keys> ... <!-- this key is loaded from a file --> <key name="pinKeyA"> <type name="pkcs12" locationValue="classpath:pinKeyA.p12" pin="432809864240763"/> </key> <!-- this key resides in a HSM for improved security --> <key name="pinKeyB"> <type name="HSM" locationValue="C:\Program Files\Utimaco\CryptoServer\Lib\cs_pkcs11_R2" pin="10297385314563206" alias="myOtherPinKey" slot="3" /> </key> ... </keys> </engineSignEncrypt>
When using Docker, make sure you mount any necessary P12 files into appropriate locations inside the container (see docker-compose.yml volume mappings), in addition to editing the config/signencrypt.xml file. See the example below:
Example: extract of docker-compose.yml
YML... environment: ... - 'SYSTEM_PROPERTIES={ "pinBlobDecryptor.keyDescriptorNames": "PinKeyA,PinKeyB", ... }' ... volumes: - "/path/to/pinKeyA.p12:/usr/local/tomcat/webapps/ROOT/WEB-INF/classes/pinKeyA.p12:ro" ...
Support for multi-tenancy is limited: The PIN blob decryptor configuration is global across all tenants, that is, every tenant has access to all of the keys.
Configure encoding description
To read any of the possible PINs (PIN1, PIN2, PIN3, PUK, PUK1, PUK2, OP pin, MAN pin), configure your encoding description according to the example below:
Example: readAllEncryptedPins.dsc
CODE[Encoding] Type=1024,Chip Devices=8711 [Fields] DecryptedCardPin_PIN1= DecryptedCardPin_PIN2= DecryptedCardPin_PIN3= DecryptedCardPin_PUK= DecryptedCardPin_PUK1= DecryptedCardPin_PUK2= DecryptedCardPin_OP= DecryptedCardPin_MAN= [Description] PKCS11LibraryWindows32=C:/Program Files (x86)/Personal/bin/personal.dll # you can use any subset of the CardPinDecryption_Output_* parameters below, the others not specified will be ignored CardPinDecryption_Output_PIN1=DecryptedCardPin_PIN1 CardPinDecryption_Output_PIN2=DecryptedCardPin_PIN2 CardPinDecryption_Output_PIN3=DecryptedCardPin_PIN3 CardPinDecryption_Output_PUK=DecryptedCardPin_PUK CardPinDecryption_Output_PUK1=DecryptedCardPin_PUK1 CardPinDecryption_Output_PUK2=DecryptedCardPin_PUK2 CardPinDecryption_Output_OP=DecryptedCardPin_OP CardPinDecryption_Output_MAN=DecryptedCardPin_MAN # you MUST NOT specify any encoding application if you use this feature - it can be safely used together with reading the ICCSN
- When you configure the mapping of the encoding fields, you have to map every DSC field that is connected to a
CardPinDecryption_Output_
parameter into an encrypted field from a data pool, and the "Read" flag has to be checked. For example, if you have a field called "PukRef" of type Encrypted Field in the datapool "Card", you can map the DSC field to "${Card_PukRef}".
Any attempt to read an encrypted PIN into a plain-text field or process variable will trigger an error message and prevent the encoding from being executed, in order to prevent exposure of sensitive credentials.
Reading the encrypted PINs is executed in the finalization command block, like reading ICCSN and ATR. Its output cannot be used to log into the card during the same encoding.
Therefore use a dedicated encoding description for reading and storing the encrypted PINs combined only with other steps that do not require logging into the card.
Error messages
Matching Private Key For PIN Blob Not Found
The encoding task will return an error in the process map, for example like this:
Example: Return error in the process map
CODEProductionResultErrorMsg=Error Accessing Smartcard ( (PkiUtilsException): java.lang.IllegalArgumentException: No decryption key found matching #HEX_KEY_ID_GOES_HERE) Meta_ProductionResult=error
The process can react to these variables.
If that error happens, you are most likely either dealing with an unknown card or have some misconfiguration (for example incomplete or missing descriptor list in system.properties).
No PIN Values Returned From Encoding
- This can happen if you read from a card which does not contain encrypted PINs, for example, a blank card.
- Check the DSC to make sure you specified the correct output fields, and that the "Read" flag is checked in the field mapping.
Incorrect Field Mapping In Encoding Description
- Only encrypted datapool fields are allowed as output for encrypted PINs. Make sure that is the case and that you use the correct expression syntax: ${DataPoolName_FieldName}
- For security reasons you cannot read into plain-text datapool fields or process variables.
Support for cards with signature slot
A signature slot is generally supported. The exact configuration and possible operations depend on the profile that is used.
In the examples below, the signature slot PIN is set using the SignPIN keyword. PIN2 is an alias to SignPIN and can be used instead.
For general information on the signature slot support see also Use Signature slot in Identity Manager.
The signature slot is initialized together with the main slot, using the InitToken keyword. In addition to the usual PINs, the signature slot PIN can be set using the SignPIN keyword.
The initial signature slot PUK can't be explicitly set using SignPUK. Usually the profile creates a value.
Edit the encoding description according to the profile used. The following is an example:
Token initialization
CODE[Encoding] Type=1024,Chip Devices=8711 [Fields] PUK= OP_PIN= PIN= SIGN_PIN= [Description] PKCS11LibraryWindows32=C:/Program Files (x86)/Personal/bin/personal.dll ChipProfile=yourProfile.cpf InitToken=true InitialPUK=PUK Operator_PIN=OP_PIN PIN=PIN SignPIN=SIGN_PIN
Troubleshooting
If a virtual smartcards are present on Windows, this can cause failures when using the Personal Desktop Client middleware (for example, GENERAL_ERROR on C_GetProperty). To avoid this, you can exclude the respective reader names.
Set the following in C:\Program Files (x86)\Personal\config\Personal.cfg (system-wide base config) and/or in %APPDATA%\Personal\config\Personal.cfg (per-user override config - this takes precedence, if set in both):
Example: Exclude reader names
CODE[Reader] SkipReader=Microsoft Virtual Smart Card .*
If this error shows up in the jpki_encoder log, when trying to initialize a card, this is usually caused by one of the following:
- PIN encryption certificate is not correctly configured in the middleware
→ follow the instructions under section "Configure PIN encryption certificate" above. - Card profile configuration file (CPF) used in the Identity Manager encoding description does not match the card type to be initialized
→ use a CPF file that is properly configured for the given card type. - JPKIEncoder runs on a 64 bit JRE or the DLL path is incorrect
→ follow the instructions under section "Middleware DLL configuration" above.
Other errors can be caused by the following:
- Caching is erroneously enabled
→ follow the instructions under section "Disable caching of card content" above - The wrong middleware DLL is set in the encoding description
→ follow the instructions under section "Middleware DLL configuration" above. - JAVA_HOME is not set or points to the wrong path
→ follow the instructions under section "Middleware DLL configuration" above.
By default log files are written to %APPDATA%\Personal\log\ .
Failure to find the private key or having certain operations fail with CKR_USER_NOT_LOGGED_IN after C_Sign is usually caused by automatic logout after signing configured in C:\Program Files (x86)\Personal\config\Personal.cfg
.
Disable automatic logout after signing globally
You can explicitly disable automatic logout after signing globally and only enable automatic logout after signing for applications that need it. Do the following:
for C:\Program Files (x86)\Personal\config\Personal.cfg
[CSP_PKCS11]
P11_LogoutAfterSign=0
Sections=...other stuff..;myAppThatNeedsLogoutAfterSigning.exe
...other stuff...
[myAppThatNeedsLogoutAfterSigning.exe]
P11_LogoutAfterSign=1
Add overrides with P11_LogoutAfterSign=0
You can add overrides just for Smart ID Identity Manager encoding processes (java.exe, javaw.exe, personalx.exe, outside.exe and outside64.exe) with P11_LogoutAfterSign=0. Do the following:
for C:\Program Files (x86)\Personal\config\Personal.cfg
[CSP_PKCS11]
P11_LogoutAfterSign=1
Sections=...other stuff...;java.exe;javaw.exe;personalx.exe;outside.exe;outside64.exe
...other stuff...
[java.exe]
P11_LogoutAfterSign=0
[javaw.exe]
P11_LogoutAfterSign=0
[personalx.exe]
P11_LogoutAfterSign=0
[outside.exe]
P11_LogoutAfterSign=0
[outside64.exe]
P11_LogoutAfterSign=0
Limitations
Run CardJob in Self-service
There is a limitation when having multiple successive CardJobs without an intermediate form in chromium based browsers. Smart ID Desktop App cannot open on the second CardJob due to an "anti flooding prevention of popups" built into chromium based browsers. Read more here.
Smart ID Desktop App will close after the first cardjob when using Firefox.
You can create a workaround and add a form in between CardJobs or add more than one button in the CardJob form.
Related information
- Smart ID Identity Manager
- Encoding description in Identity Manager
- Set up an encoding description file in Identity Manager
- Structure of an encoding description in Identity Manager
- Nexus Personal Desktop Client