Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Private Key Objects of D-TRUST Card 4.1 Multi ECC 2 are not regcognized #3031

Closed
hamarituc opened this issue Feb 16, 2024 · 1 comment · Fixed by #3033
Closed

Private Key Objects of D-TRUST Card 4.1 Multi ECC 2 are not regcognized #3031

hamarituc opened this issue Feb 16, 2024 · 1 comment · Fixed by #3033

Comments

@hamarituc
Copy link
Contributor

Problem Description

I am trying to implement the D-Trust signatur cards using ECC algorithms (Multicard and Multicard 100). The private key objects are not recognized by pkcs15-tool.

Steps to reproduce

  1. Insert card
  2. Execute pkcs15-tool -D
$ pkcs15-tool -D --short
Using reader with a card: Alcor Micro AU9540 00 00
PKCS#15 Card [D-TRUST Card 4.1 Multi ECC 2ca]:
        Version        : 1
        Serial number  : 9276003211760004942f
        Manufacturer ID: D-TRUST GmbH (C)
        Flags          : Login required, PRN generation

Card has 3 Authentication object(s).
        PIN  ID:03  Ref:0x03  AuthID:04  Tries:3  Card-PIN
        PIN  ID:04  Ref:0x04  Tries:3  Card-PUK
        PIN  ID:07  Ref:0x87  AuthID:04  Path:3f000101  Tries:3  Signature-PIN
Card has 0 Private key(s).
Card has 0 Public key(s).
Card has 6 Certificate(s).
        Path:3f0001030204  ID:03
        Path:3f0001030201  ID:02
        Path:3f0001030205  ID:03  Authority
        Path:3f0001030206  ID:03  Authority
        Path:3f0001030202  ID:02  Authority
        Path:3f0001030203  ID:02  Authority
Card has 0 Data object(s).

Logs

The content of the private key description object is as follows.

OpenSC [3F00/0104]> asn1 5001
A0 Context 0  (62 bytes)
   30 SEQUENCE (35 bytes)
      0C UTF8String (26 bytes): Authentisierungsschluessel
      03 BIT STRING (2 bytes): 01
      04 OCTET STRING (1 byte): 03 .
   30 SEQUENCE (11 bytes)
      04 OCTET STRING (1 byte): 03 .
      03 BIT STRING (3 bytes): 100000100
      02 INTEGER (1 byte): 131
   A1 Context 1  (10 bytes)
      30 SEQUENCE (8 bytes)
         30 SEQUENCE (6 bytes)
            04 OCTET STRING (4 bytes): 3F 00 01 02 ?...
A0 Context 0  (54 bytes)
   30 SEQUENCE (27 bytes)
      0C UTF8String (18 bytes): Signaturschluessel
      03 BIT STRING (2 bytes): 01
      04 OCTET STRING (1 byte): 07 .
   30 SEQUENCE (11 bytes)
      04 OCTET STRING (1 byte): 02 .
      03 BIT STRING (3 bytes): 1000000000
      02 INTEGER (1 byte): 130
   A1 Context 1  (10 bytes)
      30 SEQUENCE (8 bytes)
         30 SEQUENCE (6 bytes)
            04 OCTET STRING (4 bytes): 3F 00 01 01 ?...

Proposed Resolution

I nailed down the problem to sc_pkcs15_decode_prkdf_entry() in src/libopensc/pkcs15-prkey.c.

                obj->type = SC_PKCS15_TYPE_PRKEY_EC;
#ifdef ENABLE_OPENSSL
                if (!info.field_length && ec_domain_len) {
                        const unsigned char *p = ec_domain;
                        ASN1_OBJECT *object = d2i_ASN1_OBJECT(NULL, &p, ec_domain_len);
                        int nid;
                        EC_GROUP *group;
                        if (!object) {
                                r = SC_ERROR_INVALID_ASN1_OBJECT;
                                goto err;
                        }
                        nid = OBJ_obj2nid(object);
                        ASN1_OBJECT_free(object);
                        if (nid == NID_undef) {
                                r = SC_ERROR_OBJECT_NOT_FOUND;
                                goto err;
                        }
                        group = EC_GROUP_new_by_curve_name(nid);
                        if (!group) {
                                r = SC_ERROR_INVALID_DATA;
                                goto err;
                        }
                        info.field_length = EC_GROUP_order_bits(group);
                        EC_GROUP_free(group);
                        if (!info.field_length) {
                                r = SC_ERROR_CORRUPTED_DATA;
                                goto err;
                        }
                }
#endif

As no field size is specified in the private key object, !info.field_length evaluates to true and ec_domain_len has still its initial value 32 (size of the buffer ec_domain) since no EC domain is specified in the private key object. Thus the if-clause is entered and bails out because d2i_ASN1_OBJECT() returns NULL.

The code was introduced in commit 4b2ef66.

I am unsure how to fix it. In my opinion ec_domain_len has to be set to 0 if no EC domain is specified. Is there a possibility to do that with sc_format_asn1_entry() as the call to sc_format_asn1_entry(asn1_ecckey_attr + 3, ec_domain, &ec_domain_len, 0); seems to leave ec_domain_len unchanged if the tag is not present?

If I comment out the if-clause above, the private keys are recognized as expected.

$ pkcs15-tool -D --short
Using reader with a card: Alcor Micro AU9540 00 00
PKCS#15 Card [D-TRUST Card 4.1 Multi ECC 2ca]:
        Version        : 1
        Serial number  : 9276003211760004942f
        Manufacturer ID: D-TRUST GmbH (C)
        Flags          : Login required, PRN generation

Card has 3 Authentication object(s).
        PIN  ID:03  Ref:0x03  AuthID:04  Tries:3  Card-PIN
        PIN  ID:04  Ref:0x04  Tries:3  Card-PUK
        PIN  ID:07  Ref:0x87  AuthID:04  Path:3f000101  Tries:3  Signature-PIN
Card has 2 Private key(s).
        EC   ID:03  Ref:0x83  AuthID:03
             Authentisierungsschluessel [0x104, sign, derive]
        EC   ID:02  Ref:0x82  AuthID:07
             Signaturschluessel [0x200, nonRepudiation]
Card has 0 Public key(s).
Card has 6 Certificate(s).
        Path:3f0001030204  ID:03
        Path:3f0001030201  ID:02
        Path:3f0001030205  ID:03  Authority
        Path:3f0001030206  ID:03  Authority
        Path:3f0001030202  ID:02  Authority
        Path:3f0001030203  ID:02  Authority
Card has 0 Data object(s).
@Jakuje
Copy link
Member

Jakuje commented Feb 16, 2024

There is a flag SC_ASN1_PRESENT that should be used for checking if the entry was present so I think the line detecting this should be rewritten to something like:

-		if (!info.field_length && ec_domain_len) {
+		if (info.field_length == 0 && asn1_prkey[3].flags & SC_ASN1_PRESENT && ec_domain_len) { 

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants