-
Notifications
You must be signed in to change notification settings - Fork 803
Description
I'm writing a daemon-like application that runs for a long time and make calls to OpenSC via both PKCS11 API and the internal one (sc_*). I know that I shouldn't really use sc_* stuff, but the bug I'm going to explain here can also be reproduced with pure C_* functions.
The core of the problem is OpenSC seems to cache quite a lot of stuff and there is no way to tell it to "reload". This can be illustrated with the following example:
$ opensc-explorer
OpenSC [3F00]> cat 005e
00000000: 61 73 64 61 73 64 00 asdasd.
OpenSC [3F00]> erase
OpenSC [3F00]> cat 005e
00000000: 61 73 64 61 73 64 00 asdasd.
OpenSC [3F00]> ^D
$ opensc-explorer
OpenSC Explorer version 0.24.0
Using reader with a card: Nitrokey Nitrokey 3 [CCID/ICCD Interface] 00 00
OpenSC [3F00]> cat 005e
As you can see, the erase command actually cleared out the 3F00/005e EF, but this change can't be seen by the library until I restart the program (read: reinitialize the library).
A related example with PKCS11 API is following:
- Generate a key pair
CK_MECHANISM mechanism = {CKM_RSA_PKCS_KEY_PAIR_GEN, NULL_PTR, 0};
CK_ULONG modulusBits = 2048;
CK_BBOOL _true = TRUE;
CK_BBOOL _false = FALSE;
CK_OBJECT_CLASS pubkey_class = CKO_PUBLIC_KEY;
CK_OBJECT_CLASS privkey_class = CKO_PRIVATE_KEY;
CK_ATTRIBUTE publicKeyTemplate[20] = {
{CKA_CLASS, &pubkey_class, sizeof(pubkey_class)},
{CKA_TOKEN, &_true, sizeof(_true)},
{CKA_PRIVATE, &_false, sizeof(_false)},
{CKA_MODULUS_BITS, &modulusBits, sizeof(modulusBits)},
};
int n_pubkey_attr = 4;
CK_ATTRIBUTE privateKeyTemplate[20] = {
{CKA_CLASS, &privkey_class, sizeof(privkey_class)},
{CKA_TOKEN, &_true, sizeof(_true)},
{CKA_PRIVATE, &_true, sizeof(_true)},
{CKA_SENSITIVE, &_true, sizeof(_true)},
};
int n_privkey_attr = 4;
rv = m_p11->C_GenerateKeyPair(m_sessionHandle, &mechanism,
publicKeyTemplate, n_pubkey_attr,
privateKeyTemplate, n_privkey_attr,
&hPublicKey, &hPrivateKey);
- Output a modulus:
CK_BBOOL _true = TRUE;
CK_ATTRIBUTE attrs[] =
{
{ CKA_ENCRYPT, &_true, sizeof(_true)},
};
auto rv = m_p11->C_FindObjectsInit(m_sessionHandle, attrs, sizeof(attrs) / sizeof(CK_ATTRIBUTE));
if (rv != CKR_OK) {
...
}
CK_OBJECT_HANDLE key;
CK_ULONG outSize;
rv = m_p11->C_FindObjects(m_sessionHandle, &key, 1, &outSize);
m_p11->C_FindObjectsFinal(m_sessionHandle);
CK_ATTRIBUTE attr = { CK_MODULUS, NULL, 0 };
rv = m_p11->C_GetAttributeValue(m_sessionHandle, object, &attr, 1);
if (rv != CKR_OK) {
...
}
if (attr.ulValueLen == -1u)
...
QByteArray ret(attr.ulValueLen + 1, 0);
attr.pValue = ret.data();
if (!attr.pValue)
...
rv = m_p11->C_GetAttributeValue(m_sessionHandle, object, &attr, 1);
if (attr.ulValueLen == -1u)
...
- Generate a key pair again using the same code as in step 1.
- Output a modulus again with the code from step 2. It outputs the same byte array, despite the fact that key pair is changed.
- Restart the program
- Output a modulus third time and now it is different from the previous two calls.
Running pkcs11-tool or openpgp-tool between steps 4 and 5 confirms that keys are actually changed on-card, it is just the application doesn't see the change.
To sum this up, I need to trigger the same reloading/recaching process inside the library as when the token is physically reattached to the host. Or am I fundametally missing something?