pcsc_scan (from pcsc-tools) output:
3B 7F 96 00 00 80 31 B8 65 B0 85 04 02 1B 12 00 F6 82 90 00
Finnish ID-card v5.0(?) (eID)
https://dvv.fi/en/fineid-specifications
The communication flow is as follows: mutt -> gpgme -> (gpgsm) -> gpg-agent -> gnupg-pkcs11-scd -> libcryptoki -> smartcard
- pkcs11-helper
- gnupg-pkcs11
- Version > 0.9.2 because of #17
~/.gnupg/gpg-agent.conf:
scdaemon-program /usr/bin/gnupg-pkcs11-scd
~/.gnupg/gnupg-pkcs11-scd.conf:
providers p1
provider-p1-library /usr/lib64/libcryptoki.so
muttrc:
set crypt_use_gpgme
set smime_default_key="12345678.0" <- check your ID with the commands described below in "Usage"
set nohonor_disposition
gpgsm --learn-card
Run gpgsm --list-keys and check the ID of your cert with key usage: digitalSignature keyEncipherment dataEncipherment.
You can test whether your card is identified by running gpg-agent --server gpg-connect-agent and issuing the SCD LEARN command.
Determine your private key ID with pkcs11-tool --module /usr/lib64/libcryptoki.so --list-objects --type privkey. It should look like this:
Private Key Object; RSA
label: todentamis- ja salausavain
ID: 45
Usage: decrypt, sign
Determine the IDs of your "todentamis- ja salausvarmenne" certificate and the intermediate CA "VRK Gov. CA for Citizen Certificates - G3" certificate with the following command:
pkcs11-tool --module /usr/lib64/libcryptoki.so --list-objects --type cert
Extract the "todentamis- ja salausvarmenne" and "VRK Gov. CA for Citizen Certificates - G3" certificates from the card into separate files with (repeat and save into different files):
pkcs11-tool --module /usr/lib64/libcryptoki.so --read-object --id KEY_ID --type cert --output-file cert.der
Convert them from DER to PEM (repeat for both certificates):
openssl x509 -in cert.der -inform DER -out cert.pem -outform PEM
Create the following OpenSSL configuration (see Using the engine from the command line):
openssl_conf = openssl_init
[openssl_init]
engines = engine_section
[engine_section]
pkcs11 = pkcs11_section
[pkcs11_section]
engine_id = pkcs11
dynamic_path = /usr/lib64/engines-1.1/pkcs11.so
MODULE_PATH = /usr/lib64/libcryptoki.so
init = 0
- You need to disable GPGME in Mutt, so you can use the old school
smime_*_commands cert.pemis the extracted "todentamis- ja salausvarmenne" certificateca.pemis the "VRK Gov. CA for Citizen Certificates - G3" intermediate CA certificate- The key ID is hardcoded and determined in the "Determine your private key ID" part
smime_default_keyandsmime_sign_asare just dummy values so Mutt doesn't prompt you for the key ID
Add the following to your muttrc:
unset crypt_use_gpgme
set smime_default_key="12345678.0"
set nohonor_disposition
set smime_decrypt_command="OPENSSL_CONF=/path/to/openssl.conf openssl smime -decrypt -engine pkcs11 -keyform engine -inform DER -in %f -inkey 45"
set smime_sign_as="87654321.0"
set smime_sign_command="OPENSSL_CONF=/path/to/openssl.conf openssl smime -sign -engine pkcs11 -keyform engine -signer /path/to/cert.pem -certfile /path/to/ca.pem -inkey 45 -in %f -outform DER"
Mutt will ask you for a passphrase, but as this comes from mpollux you can enter anything to the prompt.
If you have #1608 patch, you can get your SSH public key with pkcs15-tool --read-ssh-key ID where ID is the ID of your "todentamis- ja salausvarmenne" certificate. You also need to have the following in /etc/opensc.conf or otherwise pkcs15-tool will not work:
app default {
card_atr 3b:7f:96:00:00:80:31:b8:65:b0:85:04:02:1b:12:00:f6:82:90:00 {
driver = fineid;
}
}
Do note that the patch does not seem to work properly with FINEID v5, except for the pkcs15-tool part so leaving it to your opensc.conf is not recommended.
Other option to convert your certificate into SSH authorized_key is to run openssl x509 -in cert.pem -noout -pubkey | ssh-keygen -i -m PKCS8 -f /dev/stdin.
You need to have the following in your SSH client configuration (ssh_config):
Host ...
PKCS11Provider /usr/lib64/libcryptoki.so
Then just add the public key into your authorized_key and you can authenticate with your FINEID card.
mPollux stores "DigiSign WebSigner ROOT Certificate" into your ~/.pki/nssdb database. It uses a password, which you can find from ~/.digisign/Seed.txt.
See DigiSignApplication.bin:
nth paddr vaddr len size section type string
――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
2856 0x0043b520 0x0043b520 19 20 .rodata ascii /.digisign/Seed.txt
52823 0x006d4041 0x006d4041 2288 2289 .rodata ascii #!/bin/bash\n\npwdfile=$1\nnsdCreate=$2\n\nif [ -f /usr/lib/libcryptoki.so ]; then\n cryptokiPath=/usr/lib/libcryptoki.so;\nelse\n cryptokiPath=/usr/lib64/libcryptoki.so;\nfi\n\nif [ "$nsdCreate" = "true" ]; then\n certutil -d sql:$HOME/.pki/nssdb -N -f $pwdfile\nfi\n\nif [ $? -gt 0 ]; then\n echo nssdb creation failed\n exit 1\nfi\n\nhostname=$(hostname)\nif [ -z "$hostname" ]; then\n echo hostname not defined\n exit 1\nfi\n\nrootname="DigiSign WebSigner ROOT Certificate for $hostname"\n\n#Wrong password exit status: \n# local nssd: 2\n# firefox and thunderbird: 3\n\n#add root certificate to nssd db sent by parameters\naddRootCertificate()\n{\n dbPath=$1\n isPwdFile=$2\n exitStatus=$3\n\n certCheck=$(certutil -d $dbPath -L | grep "$rootname")\n if [ -n "$certCheck" ]; then\n #remove old certificate, ignore if it doesn't exist\n certutil -d $dbPath -D -n "$rootname"\n fi\n\n if [ "$isPwdFile" = "true" ]; then\n certutil -d $dbPath -A -t "TC,Tw,Tw" -n "$rootname" -i /etc/xdg/Fujitsu/SSLCA.cer -f $pwdfile\n else\n certutil -d $dbPath -A -t "TC,Tw,Tw" -n "$rootname" -i /etc/xdg/Fujitsu/SSLCA.cer\n fi\n if [ $? -gt 0 ]; then\n #if certificate inset failed for some reason, certutil added incorrect data to db. Clean incorrect data from db.\n certutil -d $dbPath -D -n "$rootname"\n exit $exitStatus\n fi\n #update pkcs11.txt\n isInFile=$(cat $dbPath/pkcs11.txt | grep -c "DigiSign PKCS#11 Module")\n\n if [ $isInFile -eq 0 ]; then\n echo "library=$cryptokiPath" >> $dbPath/pkcs11.txt\n\t echo "name=DigiSign PKCS#11 Module" >> $dbPath/pkcs11.txt\n fi\n}\n\naddRootCertificate $HOME/.pki/nssdb true 2\n\nif [ -d ~/snap/firefox ]; then\necho snap version\n for certDB in $(find ~/snap/firefox/common/ -name "cert9.db")\n do\n certDir=$(dirname ${certDB});\n\t addRootCertificate $certDir false 3\n done\nelse\n for certDB in $(find ~/.mozilla* ~/.thunderbird -name "cert9.db")\n do\n certDir=$(dirname ${certDB});\n\t addRootCertificate $certDir false 3\n done\n #we need also check cet8.db for old version of Firefox or thunderbird. More related to Ubuntu 32 version\n for certDB in $(find ~/.mozilla* ~/.thunderbird -name "cert8.db")\n do\n certDir=$(dirname ${certDB});\n\t addRootCertificate $certDir false 3\n done\nfi\n\nexit 0\n
Atostek ID is the new software that is going to replace mPollux. All these notes are about the Debian package.
https://files.fineid.fi/download/atostek/4.4.1.0/linux/AtostekID_DEB_4.4.1.0.deb
6fec3d89bf2ff95a2f12acd2d28563b9a4ce416d82de52e882401c4bce4ca647 AtostekID_DEB_4.4.1.0.deb
A mysterious private key is embedded within the binary:
nth paddr vaddr len size section type string
――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
2197 0x005735a1 0x005735a1 3500 3501 .rodata ascii -----BEGIN ENCRYPTED PRIVATE KEY-----\r\n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\r\n-----END ENCRYPTED PRIVATE KEY-----\r\n
Couldn't find any code referencing it and apparently the installCA function does generate it's own keys.
You can find a reference string:
nth paddr vaddr len size section type string
――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
471 0x0056521c 0x0056521c 27 28 .rodata ascii Entering installCA function
From there you can find the function:
address noret size nbbs edges cc cost min bound range max bound calls locals args xref frame name
================== ===== ===== ===== ===== ===== ==== ================== ===== ================== ===== ====== ==== ==== ===== ====
0x000000000013c180 0 7025 256 418 164 2394 0x000000000013c180 7279 0x000000000013ddef 288 31 1 1 520 fcn.0013c180
I dislike the idea of having random private keys stored on my computer and not knowing how to unlock them.
When you run the binary with the -installCA parameter, it creates this AID-ERASMARTCARD-EHOITO-FI-CA CA certificate for you into ~/.local/share/Atostek Oy/Atostek ID/ directory. The password for the PKCS #12 file is DyCpu4fB4y4WdsnCG6k3. The password is the same between different machines (e.g. not using any instance specific attributes to generate a unique one). You can breakpoint PKCS12_create to catch it.
You can see the password loaded into the r12 register before calling the function at 0x0013e430:
0x0013ca7a 4c8b6590 mov r12, qword [rbp - 0x70]
The -installSCSCA parameter installs another cert (AID_SCSCA) and the password for that is Le3svzKWE2OD4cgWzXan.
The deobfuscation function (for installCA) is as follows:
╭ 82: fcn.0013e1f0 (int64_t arg1);
│ `- args(rdi)
│ 0x0013e1f0 53 push rbx
│ 0x0013e1f1 31d2 xor edx, edx
│ 0x0013e1f3 4889fb mov rbx, rdi ; arg1
│ 0x0013e1f6 4c8d05a372.. lea r8, str.xYue6hgg5ImeRot68oYdAdding_certificate ; 0x5654a0 ; "xYue6hgg5ImeRot68oYdAdding certificate"
│ 0x0013e1fd 488d357c72.. lea rsi, [0x00565480]
│ 0x0013e204 4883ec20 sub rsp, 0x20
│ 0x0013e208 4889e1 mov rcx, rsp
│ ; CODE XREF from fcn.0013e1f0 @ 0x13e227(x)
│ ╭─> 0x0013e20b 66410f6e0410 movd xmm0, dword [r8 + rdx]
│ ╎ 0x0013e211 660f6e0c16 movd xmm1, dword [rsi + rdx]
│ ╎ 0x0013e216 660fefc1 pxor xmm0, xmm1
│ ╎ 0x0013e21a 660f7e0411 movd dword [rcx + rdx], xmm0
│ ╎ 0x0013e21f 4883c204 add rdx, 4
│ ╎ 0x0013e223 4883fa14 cmp rdx, 0x14
│ ╰─< 0x0013e227 75e2 jne 0x13e20b
│ 0x0013e229 4889df mov rdi, rbx
│ 0x0013e22c be14000000 mov esi, 0x14
│ 0x0013e231 4889ca mov rdx, rcx
│ 0x0013e234 e8976ef9ff call sym.imp.QString::fromLatin1_QByteArrayView_ ; QString::fromLatin1(QByteArrayView)
│ 0x0013e239 4883c420 add rsp, 0x20
│ 0x0013e23d 4889d8 mov rax, rbx
│ 0x0013e240 5b pop rbx
╰ 0x0013e241 c3 ret
The XOR key is this:
nth paddr vaddr len size section type string
――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
497 0x005654a0 0x005654a0 39 40 .rodata ascii xYue6hgg5ImeRot68oYdAdding certificate
The obfuscated password is here:
- offset - 4041 4243 4445 4647 4849 4A4B 4C4D 4E4F 0123456789ABCDEF
0x0013c240 4889 8568 feff ffe8 0491 f9ff 488b 75a0 H..h........H.u.
0x0013c250 488b 5598 H.U.
You can deobfuscate the "secret" with r2 -n -qc 'e io.cache=true; b 20; s 0x565480; wox `p8 20 @ 0x5654a0`; ps' atostekid.
For the installSCSCA the deobfuscation function is here:
address noret size nbbs edges cc cost min bound range max bound calls locals args xref frame name
================== ===== ===== ===== ===== ===== ==== ================== ===== ================== ===== ====== ==== ==== ===== ====
0x0000000000219220 0 82 3 3 2 27 0x0000000000219220 82 0x0000000000219272 1 0 1 4 40 fcn.00219220
Deobfuscate with: r2 -n -qc 'e io.cache=true; b 20; s 0x56fac0; wox `p8 20 @ 0x56fae0`; ps' atostekid.
https://files.fineid.fi/download/atostek/4.5.0.0/linux/AtostekID_DEB_4.5.0.0.deb
14d2e980e27e8bdd0a27a3bec925864018540ae3f09baf146f19c4986890b3e4 AtostekID_DEB_4.5.0.0.deb
The installation manual states the following:
Atostek ID -sovellus tukee kaikkia ylläpidettyjä Linux-käyttöjärjestelmän Debian- ja Red Hat -distribuutioita.
So it should work in supported Debian distributions, yet it doesn't work in Debian 13. The version string in the .deb package has 4.5.0.0-Debian12.
installCA function:
address noret size nbbs edges cc cost min bound range max bound calls locals args xref frame name
================== ===== ===== ===== ===== ===== ==== ================== ===== ================== ===== ====== ==== ==== ===== ====
0x0000000000146500 0 7718 264 428 168 2451 0x0000000000146500 7917 0x00000000001483ed 289 36 1 1 552 fcn.00146500
XOR key:
nth paddr vaddr len size section type string
――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
498 0x00599400 0x00599400 38 40 .rodata ascii xYue6hgg5ImeRot68oYdAdding certificate
CA-side deobfuscation helper:
// fcn.00148910
r10 = "xYue6hgg5ImeRot68oYdAdding certificate" // XOR key
r9 = 0x005993e0 // ciphertext
r8 = rsp // 20-byte scratch buffer
for (rdx = 0; rdx != 0x14; rdx += 4) {
xmm0 = *(uint32_t*)(r10 + rdx);
xmm1 = *(uint32_t*)(r9 + rdx);
xmm0 ^= xmm1;
*(uint32_t*)(r8 + rdx) = xmm0;
}
QString::fromLatin1(rsp, 0x14);So the 20 ciphertext bytes live at 0x005993e0 and the 20-byte XOR key at 0x00599400 (the leading part of the "xYue…" string).
Deobfuscate with: r2 -n -qc 'e io.cache=true; b 20; s 0x5993e0; wox p8 20 @ 0x599400; ps' /usr/bin/atostekid
The byte-wise XOR loop pattern (cmp rdx, 0x14 ; jne …) matches at exactly two places in the binary:
0x00148964 (inside fcn.00148910 — the installCA deobfuscator, above)
0x00247cd4 (inside a second function starting at 0x00247c80)
The second one uses byte-wise movzx/xor/mov byte rather than the movd/pxor SSE variant, but it is functionally identical:
0x00247c95 lea r10, [0x005a4260] ; source #1
0x00247c9c lea r9, [0x005a4240] ; source #2
0x00247cb7 mov r8, rsp ; 20-byte scratch buffer
loop:
0x00247cc0 movzx ecx, byte [r10 + rdx]
0x00247cc5 movzx esi, byte [r9 + rdx]
0x00247cca xor ecx, esi
0x00247ccc mov byte [r8 + rdx], cl
0x00247cd0 add rdx, 1
0x00247cd4 cmp rdx, 0x14
0x00247cd8 jne loop
"Ciphertext":
0x005a4240 ea 55 f2 e4 07 76 ec 2e 15 87 6e 0d f1 cb 85 9f (ciphertext, 20 bytes)
0x005a4250 a9 91 8c f7 00 00 00 00 00 00 00 00 00 00 00 00
0x005a4260 a6 30 c1 97 71 0c a7 79 50 b5 21 49 c5 a8 e2 c8 (XOR key, 20 bytes)
0x005a4270 d3 c9 ed 99 "Atostek ID Local SCS CA\x00Subject name doe…"
So the SCSCA XOR key blob at 0x005a4260 is followed immediately by
the printable string Atostek ID Local SCS CA — mirroring the way
the installCA XOR key blob at 0x00599400 is immediately followed
by Adding certificate. In both cases the 20 "key" bytes and the
adjacent human-readable string are stored as a single .rodata
literal.
Deobfuscate with: r2 -n -qc 'e io.cache=true; b 20; s 0x5a4260; wox p8 20 @ 0x5a4240; ps' /usr/bin/atostekid