Giter Club home page Giter Club logo

Comments (21)

Jakuje avatar Jakuje commented on July 18, 2024

Hi. Thank you for the interest in the OpenSC project!

We are adding support for the IDPrime cards slowly over last couple of releases with the cards we have access to so any new input is very useful for us. Good thing is that the card is correctly detected. On the first review of the log, it sounds like there is some logical error in reading the certificate (unless that is the part you were heavily redacting, but I assume you removed just the part with the PIN). Can you confirm, there were no removed likes around the line 711 of the log? The reading failure sounds suspicious as it looks like the reading is not called at all:

P:3657753; T:0x140489810786304 10:24:55.972 [opensc-pkcs11] card-idprime.c:884:idprime_read_binary: called; 256 bytes at offset 0
P:3657753; T:0x140489810786304 10:24:55.972 [opensc-pkcs11] card-idprime.c:907:idprime_read_binary: returning with: -1305 (Invalid data)

There is a logic to parse compressed certificates, but if the certificate is not compressed, the read is kept on 0, leading to this failure. Can you try the following patch if it helps?

diff --git a/src/libopensc/card-idprime.c b/src/libopensc/card-idprime.c
index a3aedd98e..84873ce91 100644
--- a/src/libopensc/card-idprime.c
+++ b/src/libopensc/card-idprime.c
@@ -890,7 +890,7 @@ static int idprime_read_binary(sc_card_t *card, unsigned int offset,
 
 	if (!priv->cached && offset == 0) {
 		/* Read what was reported by FCI from select command */
-		int left = priv->file_size;
+		int left = priv->file_size > 0 ? priv->file_size : count;
 		size_t read = 0;
 
 		// this function is called to read and uncompress the certificate

from opensc.

Nihlus avatar Nihlus commented on July 18, 2024

Thank you for the quick reply! I did not remove any lines of the log, no - I just blacked out the value of the PIN code.

The suggested patch did not resolve the issue, but the errors appeared to change. Here's the new log.

https://gist.github.com/Nihlus/2bb99bdf6d1b04cb0a880d6dbee7a281

from opensc.

Nihlus avatar Nihlus commented on July 18, 2024

I dug into the code a little myself, and realized that there were other instances of direct use of priv->file_size in the aforementioned function - replacing those with the initial value of left appears to produce valid data from the card, but parsing of the actual certificate fails (with an error of -1401 (Invalid ASN.1 object).

I'm remiss to share those logs unless I have to since they contain live certificates, but I suspect it has to do with the size of the object being read - it's only ever reading 256 bytes, which seems incorrect to me.

from opensc.

Jakuje avatar Jakuje commented on July 18, 2024

Do you have a patch and debug log towards the error? It might be that for the uncompressed certificates, we need to skip some bytes in the beginning too, which might not be done now.
I think I had cards only with the compressed ones.

from opensc.

Nihlus avatar Nihlus commented on July 18, 2024

I went ahead and removed the certificates from the logs, though I suspect it may cause some trouble when trying to determine the cause. I'll see if I can get my hands on a test card instead of a live one so I can share unredacted logs.

https://gist.github.com/Nihlus/34662a779b86aca913ddb7f3f9edd4e8

Patch is as below; I'm not all that familiar with OpenSC so I may have made some silly mistakes.

--- a/src/libopensc/card-idprime.c
+++ b/src/libopensc/card-idprime.c
@@ -886,30 +886,31 @@
 
 	if (!priv->cached && offset == 0) {
 		/* Read what was reported by FCI from select command */
-		int left = priv->file_size;
+		int left = priv->file_size > 0 ? priv->file_size : count;
+		int file_size = left;
 		size_t read = 0;
 
 		// this function is called to read and uncompress the certificate
 		u8 buffer[SC_MAX_EXT_APDU_BUFFER_SIZE];
 		u8 *data_buffer = buffer;
-		if (sizeof(buffer) < count || sizeof(buffer) < priv->file_size) {
+		if (sizeof(buffer) < count || sizeof(buffer) < (size_t)file_size) {
 			LOG_FUNC_RETURN(card->ctx, SC_ERROR_INTERNAL);
 		}
 		while (left > 0) {
-			r = iso_ops->read_binary(card, read, buffer + read, priv->file_size - read, flags);
+			r = iso_ops->read_binary(card, read, buffer + read, file_size - read, flags);
 			if (r <= 0) {
 				LOG_FUNC_RETURN(card->ctx, r);
 			}
 			left -= r;
 			read += r;
 		}
-		if (read < 4 || read != priv->file_size) {
+		if (read < 4 || read != (size_t)file_size) {
 			LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_DATA);
 		}
 		if (buffer[0] == 1 && buffer[1] == 0) {
 			/* Data will be decompressed later */
 			data_buffer += 4;
-			r = priv->file_size - 4;
+			r = file_size - 4;
 			if (flags)
 				*flags |= SC_FILE_FLAG_COMPRESSED_AUTO;
 		}

from opensc.

Nihlus avatar Nihlus commented on July 18, 2024

Ah, now I see what's going on. It's only reading a single chunk of the file in card.c - the full file size is actually 2084 bytes, and the function doesn't indicate to sc_read_binary that it should keep reading.

from opensc.

Nihlus avatar Nihlus commented on July 18, 2024

Got it to work! If you unconditionally cache the real file size in idprime_select_file instead of only when the header starts with 0x01, 0x00 and drop the changes mentioned before, I can successfully read the certificates from the card.

On top of that, I found a likely bug with the cache allocation - r is set to the number of bytes read in the last loop iteration if the certificate is not compressed, resulting in a too-short buffer being created. I've included a minimal possible fix for that in the attached patch; though I'd argue that reusing r in this manner is fairly prone to mistakes.

Subject: [PATCH] card-idprime.c: unconditionally cache real file size
---
Index: src/libopensc/card-idprime.c
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/src/libopensc/card-idprime.c b/src/libopensc/card-idprime.c
--- a/src/libopensc/card-idprime.c	(revision d43cfd8afc59c872f13226b7076cdd2d817aca32)
+++ b/src/libopensc/card-idprime.c	(date 1702395880220)
@@ -861,13 +861,8 @@
 
 	r = iso_ops->select_file(card, in_path, file_out);
 	if (r == SC_SUCCESS && file_out != NULL) {
-		/* Try to read first bytes of the file to fix FCI in case of
-		 * compressed certififcate */
-		len = iso_ops->read_binary(card, 0, data, data_len, 0);
-		if (len == HEADER_LEN && data[0] == 0x01 && data[1] == 0x00) {
-			/* Cache the real file size for the caching read_binary() */
-			priv->file_size = (*file_out)->size;
-		}
+ 	 	/* Cache the real file size for the caching read_binary() */
+ 	 	priv->file_size = (*file_out)->size;
 	}
 	/* Return the exit code of the select command */
 	return r;
@@ -912,7 +907,9 @@
 			r = priv->file_size - 4;
 			if (flags)
 				*flags |= SC_FILE_FLAG_COMPRESSED_AUTO;
-		}
+		} else {
+ 	 	 	r = priv->file_size;
+ 	 	}
 		priv->cache_buf = malloc(r);
 		if (priv->cache_buf == NULL) {
 			return SC_ERROR_OUT_OF_MEMORY;

Unfortunately, the troubles don't seem to end there, as signing with the certificate (pkcs11-tool --login --test) fails with CKR_USER_NOT_LOGGED_IN.

$ pkcs11-tool --login --test
Using slot 0 with a present token (0x0)
Logging in to "TOKEN".
Please enter User PIN: 
C_SeedRandom() and C_GenerateRandom():
  seeding (C_SeedRandom) not supported
  seems to be OK
Digests:
  all 4 digest functions seem to work
  MD5: OK
  RIPEMD160: OK
  SHA-1: OK
  SHA256: OK
Ciphers: not implemented
Signatures (currently only for RSA)
  testing key 0 (Private key 1) 
error: PKCS11 function C_SignFinal failed: rv = CKR_USER_NOT_LOGGED_IN (0x101)
Aborting.

I've saved debug logs for this, but I need to scrub them first. Will get back to you once I either do that or get that test card.

from opensc.

Jakuje avatar Jakuje commented on July 18, 2024

Good to hear that! You can also isolate the signature operation with pkcs11-tool to get cleaner log without running the whole tests:

https://github.com/OpenSC/OpenSC/wiki/Using-pkcs11-tool-and-OpenSSL

I think not much more than the content of the certificates and the PIN values should have possible confidential content. Feel free to open (even WIP) PR.

from opensc.

Nihlus avatar Nihlus commented on July 18, 2024

PR opened! Here are the scrubbed logs for the signing operation: https://gist.github.com/Nihlus/1c78a04cc80f04857757fa8b97045407

from opensc.

Jakuje avatar Jakuje commented on July 18, 2024
P:508603; T:0x140609348577280 18:07:02.223 [opensc-pkcs11] /home/jarl/Programming/source-projects/c/OpenSC/src/pkcs11/pkcs11-object.c:809:C_SignFinal: C_SignFinal() = CKR_DATA_INVALID

this sounds the card returns some invalid data after request for the signature (its different from the previous error which was saying CKR_USER_NOT_LOGGED_IN). It can be for various reasons, but I would bet on the key reference, which is mostly guessed from the cards we had access to as I was not not able to come with better solution:

case SC_CARD_TYPE_IDPRIME_3810:
new_object.key_reference = 0x31 + cert_id;
break;
case SC_CARD_TYPE_IDPRIME_830:
new_object.key_reference = 0x41 + cert_id;
break;
case SC_CARD_TYPE_IDPRIME_930:
new_object.key_reference = 0x11 + cert_id * 2;
break;
case SC_CARD_TYPE_IDPRIME_940: {
idprime_keyref_t *keyref = (idprime_keyref_t *) list_seek(&priv->keyrefmap, &cert_id);
if (!keyref) {
sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "No corresponding key reference found for certificate with id=%d, skipping", cert_id);
continue;
}
new_object.key_reference = keyref->key_reference;
new_object.pin_index = keyref->pin_index;
break;
}
case SC_CARD_TYPE_IDPRIME_840:
new_object.key_reference = 0xf7 + cert_id;
break;
default:
new_object.key_reference = 0x56 + cert_id;
break;

This is used in the set security environment APDU before making signature. If you have the proprietary driver and you can intercept APDUs it is using to see what key reference is used for your key (and then try to adjust the guessing to work for your card, ideally without breaking it for other cards).

from opensc.

Nihlus avatar Nihlus commented on July 18, 2024

I've got the driver now (downloadable from https://service.secmaker.com/download-access.aspx) - how would I intercept APDUs in this case?

from opensc.

Jakuje avatar Jakuje commented on July 18, 2024

I've got the driver now (downloadable from https://service.secmaker.com/download-access.aspx) - how would I intercept APDUs in this case?

on linux, it will most probably use pcsc-lite as the PCSC so the simplest thing is to stop the pcscd service, run it in forerground in the debug mode (with --apdu switch to print APDUs) as described in https://pcsclite.apdu.fr/

from opensc.

Nihlus avatar Nihlus commented on July 18, 2024

That did it, thanks. It looks like the proprietary module is also having trouble with the signing operation on the card, producing a CKR_DEVICE_ERROR in C_SignFinal.

Could you test with one of the IDPrime cards with a compressed certificate that you have on hand using the linked-to module? I'd like to rule out an issue with the card itself before going too deep into any one rabbit hole. I've found several PKCS#11 modules from various sources that claim to support the IDPrime 940, but none of them have fully worked.

from opensc.

Nihlus avatar Nihlus commented on July 18, 2024

Aha, nevermind - there was a mostly-hidden patch version available too which works correctly (https://supportportal.thalesgroup.com/csm?id=kb_restricted&sysparm_article=KB0026523). I'll use this library as a reference point in future work.

from opensc.

Nihlus avatar Nihlus commented on July 18, 2024

Okay, after some fiddling I've got the key reference for my certificate sniffed out (using a modified version of https://github.com/eIDuy/apdu-parser - quite a nice program).

22 : MANAGE SECURITY ENVIRONMENT (Sets or replaces one component of the current SE.)

	00 22 41 B6 06 80 01 02 84 01 5E

90 00 : Command successfully executed (OK). [I]

	90 00

I'm quite a bit out of my depth here, I'm afraid. I can't see any selection of file 0005 in the logs from the proprietary module, which - if I'm understanding the code correctly - should be the file with the key reference map. Instead, it looks at the following files in order:

0201 (16 bytes)
0202 (6 bytes)
0028 (not found)

Whatever it finds in those files are apparently enough, as after that it can list out all the objects on the card. There are a couple of 00 A6 00 00 XX commands that return XX number of bytes whose purpose isn't entirely clear, but the data appears to be constant. There are also a lot of D0 39 00 00 00 commands with an also apparently constant return value (20 bytes).

Interestingly, the IDs used appear to be GUIDs with an extra 8 bytes on the end - the object labels are properly formatted GUIDs, and the ID is that GUID without dashes and with the extra data appended. Example output:

Using slot 0 with a present token (0x0)
Certificate Object; type = X.509 cert
  label:      93533823-f30c-9cd7-f754-08c4c951c22b
  subject:    <redacted>
  ID:         93533823f30c9cd7f75408c4c951c22b0ca43d99
Public Key Object; RSA 2048 bits
  label:      93533823-f30c-9cd7-f754-08c4c951c22b
  ID:         93533823f30c9cd7f75408c4c951c22b0ca43d99
  Usage:      encrypt, verify
  Access:     local
Private Key Object; RSA 
  label:      93533823-f30c-9cd7-f754-08c4c951c22b
  ID:         93533823f30c9cd7f75408c4c951c22b0ca43d99
  Usage:      decrypt, sign, unwrap
  Access:     sensitive, always sensitive, never extractable, local

from opensc.

Jakuje avatar Jakuje commented on July 18, 2024

00 22 41 B6 06 80 01 02 84 01 5E

The data is TLV encoded (INS=0x22, P1,P2=0x41,0xB6, data len 6B).

https://github.com/OpenSC/OpenSC/blob/master/src/libopensc/iso7816.c#L976

We are mostly up for the key references, which is the last block 84 01 5E. Here the 5E (hexa) is used for some reason

While in the debug log from previous comments, we read it as 86 (decimal):

P:508603; T:0x140609348577280 18:06:59.756 [opensc-pkcs11] .../card-idprime.c:470:idprime_process_index: Found certificate with fd=1, key_ref=86 corresponding to container "NetiD-1-k1M4I/MMnNc="

This looks like the code goes through the default branch of the switch:

default:
new_object.key_reference = 0x56 + cert_id;
break;
}

The card is detected as Gemalto IDPrime (generic) so maybe just updating the ATR mask at the beginning of the card-idprime.c file to match it as a IDPrime 940 might solve the issue (as it will try to read keyrefmap).

from opensc.

Nihlus avatar Nihlus commented on July 18, 2024

Changing the ATR mask helped! We're now past that problem, and there's seemingly just one more to go.

Proprietary:

$: pkcs11-tool --login --test
Using slot 0 with a present token (0x0)
C_SeedRandom() and C_GenerateRandom():
  seems to be OK
Digests:
  all 4 digest functions seem to work
  SHA-1: OK
Signatures (currently only for RSA)
  testing key 0 (93533823-f30c-9cd7-f754-08c4c951c22b) 
  ERR: C_SignUpdate failed: CKR_KEY_FUNCTION_NOT_PERMITTED (0x68)
  testing signature mechanisms:
    RSA-PKCS: OK
    SHA256-RSA-PKCS: OK
Verify (currently only for RSA)
  testing key 0 (93533823-f30c-9cd7-f754-08c4c951c22b)
    RSA-PKCS: OK
Decryption (currently only for RSA)
  testing key 0 (93533823-f30c-9cd7-f754-08c4c951c22b)
    RSA-PKCS: OK
    RSA-PKCS-OAEP: mgf not set, defaulting to MGF1-SHA256
This version of OpenSSL only supports SHA1 for OAEP, returning
1 errors

OpenSC:

$: pkcs11-tool --login --test
Using slot 0 with a present token (0x0)
C_SeedRandom() and C_GenerateRandom():
  seeding (C_SeedRandom) not supported
  seems to be OK
Digests:
  all 4 digest functions seem to work
  MD5: OK
  RIPEMD160: OK
  SHA-1: OK
  SHA256: OK
Ciphers: not implemented
Signatures (currently only for RSA)
  testing key 0 (Private key 1) 
  all 4 signature functions seem to work
  testing signature mechanisms:
    RSA-PKCS: OK
    SHA256-RSA-PKCS: OK
Verify (currently only for RSA)
  testing key 0 (Private key 1)
    RSA-PKCS: OK
Decryption (currently only for RSA)
  testing key 0 (Private key 1)
    RSA-PKCS: OK
    RSA-PKCS-OAEP: mgf not set, defaulting to MGF1-SHA256
OAEP parameters: hashAlg=SHA256, mgf=MGF1-SHA256, encoding parameter (Label) present, length 3
error: PKCS11 function C_Decrypt failed: rv = CKR_DATA_INVALID (0x20)
Aborting.

It should be noted that the proprietary module requires libssl1.1, so there's probably some limitation in this card regarding the available hash algorithms or how to request them.

from opensc.

Jakuje avatar Jakuje commented on July 18, 2024

Good to hear that it worked for you! I have the test cards in the office so I will be able to test your changes next week.

The PKCS-OAEP encryption is not very widely used. For most of the logging into your infrastructure, you should be good with signatures. Given the large variety of OAEP parameters, the pkcs11-tool --test runs just one test with one parameter combination. There are also some limitations of the input and output sizes, which might come into play with the 2k keys. Its possible that the card requires some specific salt length or something. If you want to dig into that deeper, there is p11test that runs larger matrix of tests against cards with different parameters to see if some will work:

int oaep_encrypt_decrypt_test(test_cert_t *o, token_info_t *info, test_mech_t *mech)

The error with the proprietary driver is probably related to the old version of openssl as you mention. And given the card does not support SHA1 digestst with signatures/mgf, it looks like it is not even tried.

from opensc.

Nihlus avatar Nihlus commented on July 18, 2024

Ah, excellent - p11test produces the following output, which looks pretty good to my untrained eyes.

https://gist.github.com/Nihlus/90a244b35a8d700430900724bfcdb06c

from opensc.

Jakuje avatar Jakuje commented on July 18, 2024

Right. There are three working OAEP combinations:

  [ RSA_PKCS_OAEP        ] [SHA256] [MGF1_SHA256] [   0] [           ] [   [./]    ]
  [ RSA_PKCS_OAEP        ] [SHA384] [MGF1_SHA384] [   0] [           ] [   [./]    ]
  [ RSA_PKCS_OAEP        ] [SHA512] [MGF1_SHA512] [   0] [           ] [   [./]    ]

I am not sure why the SHA256 did not work from the pkcs11-tool though. If you want to dig into this deeper, you can see what the pkcs11-tool does differently.

But I think you have mostly working card by now for what you need :) I will update the PR with the test results next week (please update also the ATR matching in the PR as we discussed above).

from opensc.

Nihlus avatar Nihlus commented on July 18, 2024

Yup, I've pushed those changes!

from opensc.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.