summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakub Jelen <jjelen@redhat.com>2022-06-16 22:23:03 +0200
committerJakub Jelen <jjelen@redhat.com>2022-06-17 17:56:00 +0200
commit961eca798d0ce3998987d6512742c6049fc6738d (patch)
tree53ce563a0bf6e12f2b9971357c9955c603b8657b
parent8458e1b1b35e69ecdc57c5c92c5780c38695f3f0 (diff)
Sort certificates by ID
This is needed to avoid non-deterministic order of the certificates in case the underlying pkcs11 module does not guarantee that (such as softhsm). Without this change, the signing and encryption certificate might get mixed up and application might try to use wrong one for verification or decryption. Signed-off-by: Jakub Jelen <jjelen@redhat.com>
-rw-r--r--src/vcard_emul_nss.c40
1 files changed, 34 insertions, 6 deletions
diff --git a/src/vcard_emul_nss.c b/src/vcard_emul_nss.c
index b63105d..e346769 100644
--- a/src/vcard_emul_nss.c
+++ b/src/vcard_emul_nss.c
@@ -706,8 +706,9 @@ vcard_emul_mirror_card(VReader *vreader)
* us the real certs until we log in.
*/
PK11GenericObject *firstObj, *thisObj;
- int cert_count;
+ int cert_count, i;
unsigned char **certs;
+ SECItem **ids;
int *cert_len;
VCardKey **keys;
PK11SlotInfo *slot;
@@ -734,12 +735,13 @@ vcard_emul_mirror_card(VReader *vreader)
/* allocate the arrays */
vcard_emul_alloc_arrays(&certs, &cert_len, &keys, cert_count);
+ ids = g_new(SECItem *, cert_count);
/* fill in the arrays */
- cert_count = 0;
+ cert_count = i = 0;
for (thisObj = firstObj; thisObj;
thisObj = PK11_GetNextGenericObject(thisObj)) {
- SECItem derCert;
+ SECItem derCert, *id;
CERTCertificate *cert;
SECStatus rv;
@@ -749,22 +751,48 @@ vcard_emul_mirror_card(VReader *vreader)
if (rv != SECSuccess) {
continue;
}
+ /* Read ID and try to sort by this to get reproducible results
+ * in case of underlying pkcs11 module does not provide it */
+ id = SECITEM_AllocItem(NULL, NULL, 0);
+ rv = PK11_ReadRawAttribute(PK11_TypeGeneric, thisObj, CKA_ID, id);
+ if (rv != SECSuccess) {
+ SECITEM_FreeItem(&derCert, PR_FALSE);
+ SECITEM_FreeItem(id, PR_TRUE);
+ continue;
+ }
/* create floating temp cert. This gives us a cert structure even if
* the token isn't logged in */
cert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(), &derCert,
NULL, PR_FALSE, PR_TRUE);
SECITEM_FreeItem(&derCert, PR_FALSE);
if (cert == NULL) {
+ SECITEM_FreeItem(id, PR_TRUE);
continue;
}
- certs[cert_count] = cert->derCert.data;
- cert_len[cert_count] = cert->derCert.len;
- keys[cert_count] = vcard_emul_make_key(slot, cert);
+ for (i = 0; i < cert_count; i++) {
+ if (SECITEM_CompareItem(id, ids[i]) < SECEqual) {
+ /* Make space for the item here, move the rest of the items */
+ memmove(&certs[i + 1], &certs[i], (cert_count - i) * sizeof(certs[0]));
+ memmove(&cert_len[i + 1], &cert_len[i], (cert_count - i) * sizeof(cert_len[0]));
+ memmove(&keys[i + 1], &keys[i], (cert_count - i) * sizeof(keys[0]));
+ memmove(&ids[i + 1], &ids[i], (cert_count - i) * sizeof(ids[0]));
+ break;
+ }
+ }
+ certs[i] = cert->derCert.data;
+ cert_len[i] = cert->derCert.len;
+ keys[i] = vcard_emul_make_key(slot, cert);
+ ids[i] = id;
cert_count++;
CERT_DestroyCertificate(cert); /* key obj still has a reference */
}
PK11_DestroyGenericObjects(firstObj);
+ /* No longer needed */
+ for (i = 0; i < cert_count; i++) {
+ SECITEM_FreeItem(ids[i], PR_TRUE);
+ }
+ g_free(ids);
/* now create the card */
card = vcard_emul_make_card(vreader, certs, cert_len, keys, cert_count);