OpenSC / engine_pkcs11

OpenSSL engine for PKCS#11 modules
35 stars 37 forks source link

engine_pkcs11 fails to access public keys directly on token without a PIN #31

Closed mouse07410 closed 8 years ago

mouse07410 commented 8 years ago

File src/engine_pkcs11.c, around line 989:

    /* Make sure there is at least one private key on the token */
    if (PKCS11_enumerate_keys(tok, &keys, &key_count)) {
        fail("unable to enumerate keys\n");
    }
    if (key_count == 0) {
        fail("No keys found.\n");
    }

    if (verbose) {
        fprintf(stderr, "Found %u key%s:\n", key_count,
            (key_count <= 1) ? "" : "s");
    }

Call to PKCS11_enumerate_keys() returns only the private keys. I think it should include public keys as well.

If this function/method is unable to do so, what are the alternatives?

dengert commented 8 years ago

PKCS11_enumerate_keys calls both: pkcs11_find_keys(token, CKO_PRIVATE_KEY) pkcs11_find_keys(token, CKO_PUBLIC_KEY)

Best I can tell without a debugger, it returns an array of all the keys, but the count is just the private keys. It also looks like it expects at least one private key, and one public key, but that should be debugged too.

looks for both private and public keys. and save the list in the token

mouse07410 commented 8 years ago

looks for both private and public keys. and save the list in the token

Thank you! I think this is the problem, as it breaks PIN-less usage of public key by OpenSSL. Instead of performing signature verification, it replies with "key not found".

  1. Where is PKCS11_enumerate_keys() defined? I seemed unable to locate it in the source of either engine_pkcs11 or OpenSC. (?!) Update _I found a strange library /Library/OpenSC/lib/engines/engine_pkcs11.so dated a few months back. That library contains the entry points in question. I also found those entry points defined in /opt/local/lib/libp11.dylib, which is probably what should be used._
  2. What would you recommend? Should engine_pckcs11 call pkcs11_find_keys(token, CKO_PUBLIC_KEY) itself, when the request is for a public key???

Update 2 I've turned on verbose in engine_pkcs11, and observe that the list received by it from PKCS11_enumerate_keys() only contains private keys. There is no mention of the corresponding public keys in the verbose printout. More so, I got to the source of libp11 (Github mirror), and found this:

/*
 * Enumerate all keys on the card
 * For now, we enumerate just the private keys.
 */
int
PKCS11_enumerate_keys(PKCS11_TOKEN * token, PKCS11_KEY ** keyp, unsigned int *countp)
{
    PKCS11_TOKEN_private *priv = PRIVTOKEN(token);

    if (priv->nkeys < 0) {
        priv->nkeys = 0;
        if (pkcs11_find_keys(token, CKO_PRIVATE_KEY)) {
            pkcs11_destroy_keys(token);
            return -1;
        }
        priv->nprkeys = priv->nkeys;
        if (pkcs11_find_keys(token, CKO_PUBLIC_KEY)) {
            pkcs11_destroy_keys(token);
            return -1;
        }
    }
    *keyp = priv->keys;
    *countp = priv->nprkeys;
    return 0;
}

That means I need to (a) modify the key retrieval in engine_pkcs11.c, and (b) add something like PKCS11_enumerate_public_keys() to libp11. Nice...

dengert commented 8 years ago

Some of the changes may have been made recently to fix memory leaks. Anyone know if this is true?

The way I read the code is PKCS11_enumerate_keys calls pkcs11_find_keys(token, CKO_PRIVATE_KEY) pkcs11_find_keys(token, CKO_PUBLIC_KEY)

They both call pkcs11_next_key that calls pkcs11_init_key. pkcs11_init_key uses OpenSSL_realloc to for each key,

so when all done priv = PRIVTOKEN(token); priv->keys is

dengert commented 8 years ago

a pointer to an arrry of the pprivate and public keys of size priv->nkeys.

mouse07410 commented 8 years ago

There seems to be a ton of memory leaks still around that code.

mouse07410 commented 8 years ago

Also, when I tried to modify PKCS11_enumerate_keys() to return both private and public keys, it magically stopped working...

mouse07410 commented 8 years ago

Here's an example of what happens when I change in libp11 in PKCS11_enumerate_keys() the number of keys it reports it found:

$ pkcs11-ecdsa-demo winconfig.h
openssl dgst -engine pkcs11 -keyform engine -sha384 -sign id_02 -out /tmp/winconfig.h.sig winconfig.h
initializing engine
engine "pkcs11" set.
Looking in slot -1 for key: 02
Found 2 slots
[18446744073709551615] Virtual hotplug slot       no tok
[1] Yubico Yubikey 4 OTP+U2F+  login             (PIV_II (PIV Card Holder pin))
Found slot:  Yubico Yubikey 4 OTP+U2F+CCID
Found token: PIV_II (PIV Card Holder pin)
Found 4 certificates:
   1    Certificate for PIV Authentication (/CN=Uri the Great)
   2    Certificate for Digital Signature (/CN=Uri the Great)
   3    Certificate for Key Management (/CN=Uri the Great)
   4    Certificate for Card Authentication (/CN=Uri the Great)
PKCS#11 token PIN:
Found 4 keys:
   1 P  PIV AUTH key
   2 P  SIGN key
   3 P  KEY MAN key
   4 P  CARD AUTH key
Signature for winconfig.h is stored in /tmp/winconfig.h.sig

pkcs11-tool -r -y pubkey -d 02 -o /tmp/derive.39901.02
Using slot 1 with a present token (0x1)
openssl dgst -verify /tmp/derive.39901.02 -keyform DER -sha384 -signature /tmp/winconfig.h.sig < winconfig.h
Verified OK

openssl dgst -engine pkcs11 -keyform engine -sha384 -verify id_02 -signature /tmp/winconfig.h.sig < winconfig.h
initializing engine
engine "pkcs11" set.
Looking in slot -1 for key: 02
Found 2 slots
[18446744073709551615] Virtual hotplug slot       no tok
[1] Yubico Yubikey 4 OTP+U2F+  login             (PIV_II (PIV Card Holder pin))
Found slot:  Yubico Yubikey 4 OTP+U2F+CCID
Found token: PIV_II (PIV Card Holder pin)
Found 4 certificates:
   1    Certificate for PIV Authentication (/CN=Uri the Great)
   2    Certificate for Digital Signature (/CN=Uri the Great)
   3    Certificate for Key Management (/CN=Uri the Great)
   4    Certificate for Card Authentication (/CN=Uri the Great)
PKCS#11 token PIN:
Found 4 keys:
   1 P  PIV AUTH key
   2 P  SIGN key
   3 P  KEY MAN key
   4 P  CARD AUTH key
Verified OK

$ pkcs11-ecdsa-demo winconfig.h
openssl dgst -engine pkcs11 -keyform engine -sha384 -sign id_02 -out /tmp/winconfig.h.sig winconfig.h
initializing engine
engine "pkcs11" set.
Looking in slot -1 for key: 02
Found 2 slots
[18446744073709551615] Virtual hotplug slot       no tok
[1] Yubico Yubikey 4 OTP+U2F+  login             (PIV_II (PIV Card Holder pin))
Found slot:  Yubico Yubikey 4 OTP+U2F+CCID
Found token: PIV_II (PIV Card Holder pin)
Found 4 certificates:
   1    Certificate for PIV Authentication (/CN=Uri the Great)
   2    Certificate for Digital Signature (/CN=Uri the Great)
   3    Certificate for Key Management (/CN=Uri the Great)
   4    Certificate for Card Authentication (/CN=Uri the Great)
PKCS#11 token PIN:
Found 8 keys:
   1 P  PIV AUTH key
   2 P  SIGN key
   3 P  KEY MAN key
   4 P  CARD AUTH key
   5    PIV AUTH pubkey
   6    SIGN pubkey
   7    KEY MAN pubkey
   8    CARD AUTH pubkey
Error Signing Data
140735231131728:error:80029063:PKCS11 library:func(41):bad key parameters format:p11_ops.c:62:
Signature for winconfig.h is stored in /tmp/winconfig.h.sig

pkcs11-tool -r -y pubkey -d 02 -o /tmp/derive.40409.02
Using slot 1 with a present token (0x1)
openssl dgst -verify /tmp/derive.40409.02 -keyform DER -sha384 -signature /tmp/winconfig.h.sig < winconfig.h
Error reading signature file /tmp/winconfig.h.sig

openssl dgst -engine pkcs11 -keyform engine -sha384 -verify id_02 -signature /tmp/winconfig.h.sig < winconfig.h
initializing engine
engine "pkcs11" set.
Looking in slot -1 for key: 02
Found 2 slots
[18446744073709551615] Virtual hotplug slot       no tok
[1] Yubico Yubikey 4 OTP+U2F+  login             (PIV_II (PIV Card Holder pin))
Found slot:  Yubico Yubikey 4 OTP+U2F+CCID
Found token: PIV_II (PIV Card Holder pin)
Found 4 certificates:
   1    Certificate for PIV Authentication (/CN=Uri the Great)
   2    Certificate for Digital Signature (/CN=Uri the Great)
   3    Certificate for Key Management (/CN=Uri the Great)
   4    Certificate for Card Authentication (/CN=Uri the Great)
PKCS#11 token PIN:
Found 8 keys:
   1 P  PIV AUTH key
   2 P  SIGN key
   3 P  KEY MAN key
   4 P  CARD AUTH key
   5    PIV AUTH pubkey
   6    SIGN pubkey
   7    KEY MAN pubkey
   8    CARD AUTH pubkey
Error reading signature file /tmp/winconfig.h.sig
mouse07410 commented 8 years ago

Hmm... I think I fixed engine_pkcs11 and libp11, at least with respect to not prompting for PIN when only public key operation is required (such as by OpenSSL). Still a lot more work is necessary, but it is promising (debugging output):

$ pkcs11-rsa-pss-sign-demo winconfig.h
openssl dgst -engine pkcs11 -keyform engine -sign "pkcs11:object=SIGN%20key;object-type=private;pin-value=123456" -sha384 -sigopt rsa_padding_mode:pss -sigopt rsa_pss_saltlen:-1 -out winconfig.h.sig winconfig.h
initializing engine
engine "pkcs11" set.
Looking in slot -1 for key: label: SIGN key
Found 2 slots
[18446744073709551615] Virtual hotplug slot       no tok
[1] Yubico Yubikey NEO OTP+U2  login             (PIV_II (PIV Card Holder pin))
Found slot:  Yubico Yubikey NEO OTP+U2F+CCID
Found token: PIV_II (PIV Card Holder pin)
Found 4 certificates:
   1    Certificate for PIV Authentication (/CN=Mouse Mousevich)
   2    Certificate for Digital Signature (/emailAddress=mouse07410@outlook.com/CN=Mouse Mousevich)
   3    Certificate for Key Management (/emailAddress=mouse07410@outlook.com/CN=Mouse Mousevich)
   4    Certificate for Card Authentication (/CN=Mouse Mousevich)
PKCS#11 token PIN:
Found 8 keys:
   1 P  PIV AUTH key
   2 P  SIGN key
   3 P  KEY MAN key
   4 P  CARD AUTH key
   5    PIV AUTH pubkey
   6    SIGN pubkey
   7    KEY MAN pubkey
   8    CARD AUTH pubkey
Signature for winconfig.h is stored in winconfig.h.sig

pkcs11-tool -r -y pubkey -d 02 -o /tmp/derive.43856.pubkey.02
Using slot 1 with a present token (0x1)
openssl dgst -verify /tmp/derive.43856.pubkey.02 -keyform DER -sha384 -sigopt rsa_padding_mode:pss -sigopt rsa_pss_saltlen:-1 -signature winconfig.h.sig < winconfig.h
Verified OK

openssl dgst -engine pkcs11 -keyform engine -sha384 -verify id_02 -sigopt rsa_padding_mode:pss -sigopt rsa_pss_saltlen:-1 -signature winconfig.h.sig  winconfig.h
initializing engine
engine "pkcs11" set.
Looking in slot -1 for key: 02
Found 2 slots
[18446744073709551615] Virtual hotplug slot       no tok
[1] Yubico Yubikey NEO OTP+U2  login             (PIV_II (PIV Card Holder pin))
Found slot:  Yubico Yubikey NEO OTP+U2F+CCID
Found token: PIV_II (PIV Card Holder pin)
Found 4 certificates:
   1    Certificate for PIV Authentication (/CN=Mouse Mousevich)
   2    Certificate for Digital Signature (/emailAddress=mouse07410@outlook.com/CN=Mouse Mousevich)
   3    Certificate for Key Management (/emailAddress=mouse07410@outlook.com/CN=Mouse Mousevich)
   4    Certificate for Card Authentication (/CN=Mouse Mousevich)
Found 4 public keys:
   1    PIV AUTH pubkey
   2    SIGN pubkey
   3    KEY MAN pubkey
   4    CARD AUTH pubkey
Verified OK

The above works for RSA. So far so good. Now, trying ECDSA, the same code fails miserably:

pkcs11-ecdsa-demo winconfig.h
openssl dgst -engine pkcs11 -keyform engine -sha384 -sign pkcs11:object=SIGN%20key
/Users/uri/bin/pkcs11-ecdsa-demo: line 52: object-type=private -out /tmp/winconfig.h.sig winconfig.h: No such file or directory
initializing engine
engine "pkcs11" set.
Looking in slot -1 for key: label: SIGN key
Found 2 slots
[18446744073709551615] Virtual hotplug slot       no tok
[1] Yubico Yubikey 4 OTP+U2F+  login             (PIV_II (PIV Card Holder pin))
Found slot:  Yubico Yubikey 4 OTP+U2F+CCID
Found token: PIV_II (PIV Card Holder pin)
Found 4 certificates:
   1    Certificate for PIV Authentication (/CN=Uri the Great)
   2    Certificate for Digital Signature (/CN=Uri the Great)
   3    Certificate for Key Management (/CN=Uri the Great)
   4    Certificate for Card Authentication (/CN=Uri the Great)
PKCS#11 token PIN:
Found 8 keys:
   1 P  PIV AUTH key
   2 P  SIGN key
   3 P  KEY MAN key
   4 P  CARD AUTH key
   5    PIV AUTH pubkey
   6    SIGN pubkey
   7    KEY MAN pubkey
   8    CARD AUTH pubkey
Signature for winconfig.h is stored in /tmp/winconfig.h.sig

pkcs11-tool -r -y pubkey -d 02 -o /tmp/derive.45235.02
Using slot 1 with a present token (0x1)
openssl dgst -verify /tmp/derive.45235.02 -keyform DER -sha384 -signature /tmp/winconfig.h.sig < winconfig.h
Verified OK

openssl dgst -engine pkcs11 -keyform engine -sha384 -verify pkcs11:object=SIGN%20pubkey
/Users/uri/bin/pkcs11-ecdsa-demo: line 70: object-type=public -signature /tmp/winconfig.h.sig < winconfig.h: No such file or directory
initializing engine
engine "pkcs11" set.
Looking in slot -1 for key: label: SIGN pubkey
Found 2 slots
[18446744073709551615] Virtual hotplug slot       no tok
[1] Yubico Yubikey 4 OTP+U2F+  login             (PIV_II (PIV Card Holder pin))
Found slot:  Yubico Yubikey 4 OTP+U2F+CCID
Found token: PIV_II (PIV Card Holder pin)
Found 4 certificates:
   1    Certificate for PIV Authentication (/CN=Uri the Great)
   2    Certificate for Digital Signature (/CN=Uri the Great)
   3    Certificate for Key Management (/CN=Uri the Great)
   4    Certificate for Card Authentication (/CN=Uri the Great)
Found 4 public keys:
   1    PIV AUTH pubkey
   2    SIGN pubkey
   3    KEY MAN pubkey
   4    CARD AUTH pubkey
Out of memory
140735231131728:error:10098043:elliptic curve routines:o2i_ECPublicKey:passed a null parameter:ec_asn1.c:1271:

Returning to having engine_pkcs11 always unlock the token and enumerate all the keys (including private) all the time, it works for ECDSA as well:

pkcs11-ecdsa-demo winconfig.h
openssl dgst -engine pkcs11 -keyform engine -sha384 -sign pkcs11:object=SIGN%20key
/Users/uri/bin/pkcs11-ecdsa-demo: line 52: object-type=private -out /tmp/winconfig.h.sig winconfig.h: No such file or directory
initializing engine
engine "pkcs11" set.
Looking in slot -1 for key: label: SIGN key
Found 2 slots
[18446744073709551615] Virtual hotplug slot       no tok
[1] Yubico Yubikey 4 OTP+U2F+  login             (PIV_II (PIV Card Holder pin))
Found slot:  Yubico Yubikey 4 OTP+U2F+CCID
Found token: PIV_II (PIV Card Holder pin)
Found 4 certificates:
   1    Certificate for PIV Authentication (/CN=Uri the Great)
   2    Certificate for Digital Signature (/CN=Uri the Great)
   3    Certificate for Key Management (/CN=Uri the Great)
   4    Certificate for Card Authentication (/CN=Uri the Great)
PKCS#11 token PIN:
Found 8 keys:
   1 P  PIV AUTH key
   2 P  SIGN key
   3 P  KEY MAN key
   4 P  CARD AUTH key
   5    PIV AUTH pubkey
   6    SIGN pubkey
   7    KEY MAN pubkey
   8    CARD AUTH pubkey
Signature for winconfig.h is stored in /tmp/winconfig.h.sig

pkcs11-tool -r -y pubkey -d 02 -o /tmp/derive.45411.02
Using slot 1 with a present token (0x1)
openssl dgst -verify /tmp/derive.45411.02 -keyform DER -sha384 -signature /tmp/winconfig.h.sig < winconfig.h
Verified OK

openssl dgst -engine pkcs11 -keyform engine -sha384 -verify pkcs11:object=SIGN%20pubkey
/Users/uri/bin/pkcs11-ecdsa-demo: line 70: object-type=public -signature /tmp/winconfig.h.sig < winconfig.h: No such file or directory
initializing engine
engine "pkcs11" set.
Looking in slot -1 for key: label: SIGN pubkey
Found 2 slots
[18446744073709551615] Virtual hotplug slot       no tok
[1] Yubico Yubikey 4 OTP+U2F+  login             (PIV_II (PIV Card Holder pin))
Found slot:  Yubico Yubikey 4 OTP+U2F+CCID
Found token: PIV_II (PIV Card Holder pin)
Found 4 certificates:
   1    Certificate for PIV Authentication (/CN=Uri the Great)
   2    Certificate for Digital Signature (/CN=Uri the Great)
   3    Certificate for Key Management (/CN=Uri the Great)
   4    Certificate for Card Authentication (/CN=Uri the Great)
PKCS#11 token PIN:
Found 8 keys:
   1 P  PIV AUTH key
   2 P  SIGN key
   3 P  KEY MAN key
   4 P  CARD AUTH key
   5    PIV AUTH pubkey
   6    SIGN pubkey
   7    KEY MAN pubkey
   8    CARD AUTH pubkey
Verified OK

Needless to say, I'd appreciate some guidance here. Looks like we're close. After all, it work properly for RSA...

dengert commented 8 years ago

openssl dgst -engine pkcs11 -keyform engine -sha384 -verify pkcs11:object=SIGN%20pubkey /Users/uri/bin/pkcs11-ecdsa-demo: line 70: object-type=public -signature /tmp/winconfig.h.sig < winconfig.h: No such file or directory

Looks like an error in your script. The parameter is not quoted so ";" in parameter is taken as end of comand.

mouse07410 commented 8 years ago

You're correct. Fixing the script brings this:

$ openssl dgst -engine pkcs11 -keyform engine -sha384 -sign "pkcs11:object=SIGN%20key;object-type=private" -out t.sig winconfig.h
initializing engine
engine "pkcs11" set.
Looking in slot -1 for key: label: SIGN key
Found 2 slots
[18446744073709551615] Virtual hotplug slot       no tok
[1] Yubico Yubikey 4 OTP+U2F+  login             (PIV_II (PIV Card Holder pin))
Found slot:  Yubico Yubikey 4 OTP+U2F+CCID
Found token: PIV_II (PIV Card Holder pin)
Found 4 certificates:
   1    Certificate for PIV Authentication (/CN=Uri the Great)
   2    Certificate for Digital Signature (/CN=Uri the Great)
   3    Certificate for Key Management (/CN=Uri the Great)
   4    Certificate for Card Authentication (/CN=Uri the Great)
PKCS#11 token PIN:
Found 8 keys:
   1 P  PIV AUTH key
   2 P  SIGN key
   3 P  KEY MAN key
   4 P  CARD AUTH key
   5    PIV AUTH pubkey
   6    SIGN pubkey
   7    KEY MAN pubkey
   8    CARD AUTH pubkey
     Private-Key: (384 bit)
     pub:
         04:32:3d:ac:5d:34:44:9a:c1:70:73:d5:ee:de:c1:
         53:26:48:da:7e:19:04:c7:70:3a:a4:38:4b:fd:60:
         d4:ca:ab:4d:f5:0b:cf:d3:d4:2d:d4:d0:da:15:97:
         32:c1:2b:d6:01:64:70:05:da:35:f5:cf:16:c4:a3:
         67:4a:59:15:4c:a2:e6:6d:8e:e8:1e:11:5c:4a:9b:
         e8:9c:21:fc:19:b2:9f:0f:99:1b:f0:82:39:d0:08:
         15:63:44:35:09:08:f9
     ASN1 OID: secp384r1
     NIST CURVE: P-384
Illegal instruction: 4
dengert commented 8 years ago

How about a dump, showing were the Illegal instruction is at?

Can your run gdb in the command?

Do you build the packages with debugging? i.e. CFLAGS=-g LDFLAGS=-g

mouse07410 commented 8 years ago

How about a dump, showing were the Illegal instruction is at?

It looks to me like the crash occurs in the call to key_getattr_var():

$ openssl dgst -engine pkcs11 -keyform engine -sha384 -sign "pkcs11:object=SIGN%20key;object-type=private" -out t.sig stamp-h1
initializing engine
engine "pkcs11" set.
Looking in slot -1 for key: label: SIGN key
Found 2 slots
[18446744073709551615] Virtual hotplug slot       no tok
[1] Yubico Yubikey 4 OTP+U2F+  login             (PIV_II (PIV Card Holder pin))
Found slot:  Yubico Yubikey 4 OTP+U2F+CCID
Found token: PIV_II (PIV Card Holder pin)
Found 4 certificates:
   1    Certificate for PIV Authentication (/CN=Uri the Great)
   2    Certificate for Digital Signature (/CN=Uri the Great)
   3    Certificate for Key Management (/CN=Uri the Great)
   4    Certificate for Card Authentication (/CN=Uri the Great)
PKCS#11 token PIN:
Found 8 keys:
   1 P  PIV AUTH key
   2 P  SIGN key
   3 P  KEY MAN key
   4 P  CARD AUTH key
   5    PIV AUTH pubkey
   6    SIGN pubkey
   7    KEY MAN pubkey
   8    CARD AUTH pubkey
     Private-Key: (384 bit)
     pub:
         04:32:3d:ac:5d:34:44:9a:c1:70:73:d5:ee:de:c1:
         53:26:48:da:7e:19:04:c7:70:3a:a4:38:4b:fd:60:
         d4:ca:ab:4d:f5:0b:cf:d3:d4:2d:d4:d0:da:15:97:
         32:c1:2b:d6:01:64:70:05:da:35:f5:cf:16:c4:a3:
         67:4a:59:15:4c:a2:e6:6d:8e:e8:1e:11:5c:4a:9b:
         e8:9c:21:fc:19:b2:9f:0f:99:1b:f0:82:39:d0:08:
         15:63:44:35:09:08:f9
     ASN1 OID: secp384r1
     NIST CURVE: P-384
pkcs11_get_ec_public(): pk->type == EVP_PKEY_EC
   about to call key_getattr_var(pubkey, CKA_EC_POINT, NULL, &ec_pointlen)
Illegal instruction: 4

Does this help (please feel free to edit what's irrelevant, or tell me what parts of this long log to prune):

Process:               openssl [53738]
Path:                  /opt/local/bin/openssl
Identifier:            openssl
Version:               0
Code Type:             X86-64 (Native)
Parent Process:        bash [798]
Responsible:           iTerm [745]
User ID:               501

Date/Time:             2015-12-29 17:21:51.885 -0500
OS Version:            Mac OS X 10.11.2 (15C50)
Report Version:        11
Anonymous UUID:        B3544DF6-AE65-3AD0-0E52-DD6C16797F5A

Sleep/Wake UUID:       CCA9BD97-1EF4-4132-B51C-13F38644F395

Time Awake Since Boot: 71000 seconds
Time Since Wake:       15000 seconds

System Integrity Protection: enabled

Crashed Thread:        0  Dispatch queue: com.apple.main-thread

Exception Type:        EXC_BAD_INSTRUCTION (SIGILL)
Exception Codes:       0x0000000000000001, 0x0000000000000000

Thread 0 Crashed:: Dispatch queue: com.apple.main-thread
0   libp11.2.dylib                  0x000000010e0e9541 pkcs11_get_ec_public + 129
1   libp11.2.dylib                  0x000000010e0e7ebd PKCS11_get_private_key + 77
2   libpkcs11.dylib                 0x000000010e0e05ed pkcs11_load_key + 3485
3   libpkcs11.dylib                 0x000000010e0e077a pkcs11_load_private_key + 26
4   libcrypto.1.0.0.dylib           0x000000010dd421ed ENGINE_load_private_key + 125
5   openssl                         0x000000010dbe00de load_key + 110
6   openssl                         0x000000010dbb2191 dgst_main + 3217
7   openssl                         0x000000010dbabb0d do_cmd + 141
8   openssl                         0x000000010dbab980 main + 1280
9   libdyld.dylib                   0x00007fff8e35c5ad start + 1

Thread 1:
0   libsystem_kernel.dylib          0x00007fff9e32b6de __workq_kernreturn + 10
1   libsystem_pthread.dylib         0x00007fff8f8ef729 _pthread_wqthread + 1283
2   libsystem_pthread.dylib         0x00007fff8f8ed365 start_wqthread + 13

Thread 2:: Dispatch queue: com.apple.libdispatch-manager
0   libsystem_kernel.dylib          0x00007fff9e32bff6 kevent_qos + 10
1   libdispatch.dylib               0x00007fff90a0e099 _dispatch_mgr_invoke + 216
2   libdispatch.dylib               0x00007fff90a0dd01 _dispatch_mgr_thread + 52

Thread 3:
0   libsystem_kernel.dylib          0x00007fff9e32b6de __workq_kernreturn + 10
1   libsystem_pthread.dylib         0x00007fff8f8ef729 _pthread_wqthread + 1283
2   libsystem_pthread.dylib         0x00007fff8f8ed365 start_wqthread + 13

Thread 0 crashed with X86 Thread State (64-bit):
  rax: 0x0000000000000001  rbx: 0x00007f9f7bf01cc0  rcx: 0x0000e4000000e503  rdx: 0x0000e5000000e500
  rdi: 0x00007fff78c311e8  rsi: 0x0000000000012068  rbp: 0x00007fff52054860  rsp: 0x00007fff52054850
   r8: 0x0000000000000040   r9: 0x00007fff78c311e0  r10: 0xffffffffffffffff  r11: 0x0000000000000246
  r12: 0x0000000000000180  r13: 0x00007f9f7bf02810  r14: 0x00007f9f7bf01cc0  r15: 0x00007f9f7bf01d00
  rip: 0x000000010e0e9541  rfl: 0x0000000000010206  cr2: 0x000000010dd20000

Logical CPU:     0
Error Code:      0x00000000
Trap Number:     6

Binary Images:
       0x10dbaa000 -        0x10dc15ff7 +openssl (0) <051F2A34-1FFB-3E51-9141-9111A7959B3D> /opt/local/bin/openssl
       0x10dc3a000 -        0x10dc83fff +libssl.1.0.0.dylib (0) <180A5699-8713-3E3F-82D1-64862243EA61> /opt/local/lib/libssl.1.0.0.dylib
       0x10dca2000 -        0x10de20e67 +libcrypto.1.0.0.dylib (0) <F612E758-7FD4-3ECD-BE33-A00BCE0DAA0A> /opt/local/lib/libcrypto.1.0.0.dylib
       0x10de9c000 -        0x10deacfff +libz.1.dylib (0) <5FCFF38B-5983-3590-B5E9-074CF0950676> /opt/local/lib/libz.1.dylib
       0x10e0de000 -        0x10e0e1fff +libpkcs11.dylib (0) <ECD88537-61E6-3EBB-B0C5-822C0D76B129> /opt/local/lib/*/libpkcs11.dylib
       0x10e0e5000 -        0x10e0ebfff +libp11.2.dylib (0) <5105E0C6-EA1F-393E-B616-ACB814772E81> /opt/local/lib/libp11.2.dylib
       0x10e0f0000 -        0x10e11cfff +opensc-pkcs11.so (0) <5C1386C2-771A-3545-BCA4-F795B82EF72F> /Library/OpenSC/*/opensc-pkcs11.so
       0x10e129000 -        0x10e338fff +libopensc.4.dylib (0) <FFAE6B40-0725-3467-B426-DA7185DE871F> /Library/OpenSC/*/libopensc.4.dylib
       0x10e374000 -        0x10e383fff +libgost.dylib (0) <F4F0C018-1BF1-3086-80BF-E429BD54A131> /opt/local/lib/*/libgost.dylib
    0x7fff6a5bb000 -     0x7fff6a5f1fa7  dyld (360.18) <1A7F8274-FC32-3B86-9979-66B8F2B7B5E2> /usr/lib/dyld
    0x7fff87e1c000 -     0x7fff87e1dfff  libsystem_secinit.dylib (20) <FD6ECF2C-1489-32CA-981B-9045B5EB1FAA> /usr/lib/system/libsystem_secinit.dylib
    0x7fff88935000 -     0x7fff88988ff7  libc++.1.dylib (120.1) <8FC3D139-8055-3498-9AC5-6467CB7F4D14> /usr/lib/libc++.1.dylib
    0x7fff89b87000 -     0x7fff89b88ffb  libremovefile.dylib (41) <B8D1A5FC-CFD5-3AAB-8A10-14DDC129710A> /usr/lib/system/libremovefile.dylib
    0x7fff89c6e000 -     0x7fff89c76fff  libcopyfile.dylib (127) <F5133269-0B22-388C-A57C-079667B6291E> /usr/lib/system/libcopyfile.dylib
    0x7fff8a343000 -     0x7fff8a346ff7  libsystem_sandbox.dylib (460.20.9) <1C891336-1B25-365D-B43E-96D5B3BE66B0> /usr/lib/system/libsystem_sandbox.dylib
    0x7fff8a36a000 -     0x7fff8a3f7fff  libsystem_c.dylib (1082.20.4) <EAB38A6C-8671-3B13-B500-90EC1B912063> /usr/lib/system/libsystem_c.dylib
    0x7fff8a47f000 -     0x7fff8a47fff7  libkeymgr.dylib (28) <09397E01-6066-3179-A50C-2CE666FDA929> /usr/lib/system/libkeymgr.dylib
    0x7fff8ada6000 -     0x7fff8adb0fff  com.apple.pcsc (8.0 - 1) <A6974721-8A6A-361B-8CC5-C57809E1B985> /System/Library/Frameworks/PCSC.framework/Versions/A/PCSC
    0x7fff8adbe000 -     0x7fff8adc3ff3  libunwind.dylib (35.3) <124E0F05-2350-3774-A32C-7F5BF38EDE73> /usr/lib/system/libunwind.dylib
    0x7fff8ba0b000 -     0x7fff8ba14ff3  libsystem_notify.dylib (150.20.3) <243FADE1-255A-3B78-8033-F336CD64B817> /usr/lib/system/libsystem_notify.dylib
    0x7fff8e299000 -     0x7fff8e2a4ff7  libcommonCrypto.dylib (60075.20.1) <766BC3F5-41F3-3315-BABC-72718A98EA92> /usr/lib/system/libcommonCrypto.dylib
    0x7fff8e359000 -     0x7fff8e35cffb  libdyld.dylib (360.18) <5F3777A7-F07E-3D5F-BFA3-A920FF4170ED> /usr/lib/system/libdyld.dylib
    0x7fff8f8ec000 -     0x7fff8f8f5ff7  libsystem_pthread.dylib (138.10.4) <327CECD0-B881-3153-8FCC-4FD4818B7F16> /usr/lib/system/libsystem_pthread.dylib
    0x7fff8fab2000 -     0x7fff8fab4ff7  libquarantine.dylib (80) <163CF63A-7455-3D1F-AE57-8C4475A9204C> /usr/lib/system/libquarantine.dylib
    0x7fff8fee4000 -     0x7fff9035afff  com.apple.CoreFoundation (6.9 - 1256.14) <068D1BA9-3859-34C7-986A-97EDF739C5C8> /System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation
    0x7fff90a06000 -     0x7fff90a33fff  libdispatch.dylib (501.20.1) <324C9189-2AF3-3356-847F-6F4CE1C6E901> /usr/lib/system/libdispatch.dylib
    0x7fff90a95000 -     0x7fff90abefff  libsystem_info.dylib (477.20.1) <6513635B-4ADE-3B45-BF63-ED7AC565B0C9> /usr/lib/system/libsystem_info.dylib
    0x7fff92b8a000 -     0x7fff92b8bfff  libDiagnosticMessagesClient.dylib (100) <4243B6B4-21E9-355B-9C5A-95A216233B96> /usr/lib/libDiagnosticMessagesClient.dylib
    0x7fff92ec6000 -     0x7fff92eeffff  libxpc.dylib (756.20.4) <61AB4610-9304-354C-9E9B-D57198AE9866> /usr/lib/system/libxpc.dylib
    0x7fff92ef0000 -     0x7fff92f36ff7  libauto.dylib (186) <999E610F-41FC-32A3-ADCA-5EC049B65DFB> /usr/lib/libauto.dylib
    0x7fff934a3000 -     0x7fff934b4ff7  libz.1.dylib (61.20.1) <B3EBB42F-48E3-3287-9F0D-308E04D407AC> /usr/lib/libz.1.dylib
    0x7fff93c09000 -     0x7fff93e16ffb  libicucore.A.dylib (551.41) <CFFD7342-A7D6-323A-AC14-B9EECF6EFFED> /usr/lib/libicucore.A.dylib
    0x7fff94ac9000 -     0x7fff94ae5ff7  libsystem_malloc.dylib (67) <9EECAB18-F025-34C4-8E32-7EFFA6720EFC> /usr/lib/system/libsystem_malloc.dylib
    0x7fff94ae6000 -     0x7fff94ae7ffb  libSystem.B.dylib (1226.10.1) <54388DF0-3813-33E4-BE8D-7743A81ACF4D> /usr/lib/libSystem.B.dylib
    0x7fff958ae000 -     0x7fff958b0fff  libsystem_coreservices.dylib (19.2) <1B3F5AFC-FFCD-3ECB-8B9A-5538366FB20D> /usr/lib/system/libsystem_coreservices.dylib
    0x7fff960db000 -     0x7fff960e2ff7  libcompiler_rt.dylib (62) <D3C4AB40-23B4-3BC6-8C38-5B8758D14E80> /usr/lib/system/libcompiler_rt.dylib
    0x7fff96148000 -     0x7fff96149fff  libsystem_blocks.dylib (65) <49D42329-7DE9-3413-92C3-A473A7E9CF35> /usr/lib/system/libsystem_blocks.dylib
    0x7fff96b42000 -     0x7fff96b42ff7  liblaunch.dylib (756.20.4) <EDF719D6-D2BB-38DD-8C94-4272BEFDA2CD> /usr/lib/system/liblaunch.dylib
    0x7fff96f5b000 -     0x7fff96f84fff  libc++abi.dylib (125) <DCCC8177-3D09-35BC-9784-2A04FEC4C71B> /usr/lib/libc++abi.dylib
    0x7fff978ea000 -     0x7fff9794bff7  libsystem_network.dylib (583.20.10) <1C0410F3-F66E-3B0D-B8AD-0D49AB15A529> /usr/lib/system/libsystem_network.dylib
    0x7fff97e0a000 -     0x7fff97e0efff  libcache.dylib (75) <6B245C0A-F3EA-383B-A542-5B0D0456A41B> /usr/lib/system/libcache.dylib
    0x7fff98852000 -     0x7fff98869fff  libsystem_asl.dylib (322) <3C2D3ACD-0DD1-337A-8247-44A910D67A65> /usr/lib/system/libsystem_asl.dylib
    0x7fff99eac000 -     0x7fff99ec2ff7  libsystem_coretls.dylib (83.20.8) <30AF7134-6CA7-3582-B9D3-507D6ED19A88> /usr/lib/system/libsystem_coretls.dylib
    0x7fff99f55000 -     0x7fff9a2b7f3f  libobjc.A.dylib (680) <9F45830D-F1D5-3CDF-9461-1A5477ED7D1E> /usr/lib/libobjc.A.dylib
    0x7fff9a2e2000 -     0x7fff9a2eafe7  libsystem_platform.dylib (74.10.3) <D3A27E10-7F08-3603-ACC8-7A92B2C04BAB> /usr/lib/system/libsystem_platform.dylib
    0x7fff9a338000 -     0x7fff9a33dff7  libmacho.dylib (875.1) <CB745E1F-4885-3F96-B38B-2093DF488FD5> /usr/lib/system/libmacho.dylib
    0x7fff9a5f2000 -     0x7fff9a5faffb  libsystem_dnssd.dylib (625.20.4) <945B5FB1-DA91-3D45-A961-A8FAD53C1E7E> /usr/lib/system/libsystem_dnssd.dylib
    0x7fff9aeb4000 -     0x7fff9aebcfff  libsystem_networkextension.dylib (385.20.6) <DC8A102A-BF02-31A4-8914-65C34DF6B592> /usr/lib/system/libsystem_networkextension.dylib
    0x7fff9c799000 -     0x7fff9c799ff7  libunc.dylib (29) <1D0F8265-F026-3CBD-93D3-F8DF14FFCE68> /usr/lib/system/libunc.dylib
    0x7fff9c79a000 -     0x7fff9c7abff7  libsystem_trace.dylib (201.10.3) <F0B7622B-FB6B-31E1-8703-38F57BE84553> /usr/lib/system/libsystem_trace.dylib
    0x7fff9ca64000 -     0x7fff9ca66ff7  libsystem_configuration.dylib (802.20.7) <5FD79070-36CC-3D02-BEA7-BB5D2AE97D5D> /usr/lib/system/libsystem_configuration.dylib
    0x7fff9ce8a000 -     0x7fff9cf01fe7  libcorecrypto.dylib (335.20.1) <C6BD205F-4ECE-37EE-BCAB-A76F39CDCFFA> /usr/lib/system/libcorecrypto.dylib
    0x7fff9e1b2000 -     0x7fff9e1e1ffb  libsystem_m.dylib (3105) <26655445-CA97-321E-B221-801CB378D1AA> /usr/lib/system/libsystem_m.dylib
    0x7fff9e314000 -     0x7fff9e332fff  libsystem_kernel.dylib (3248.20.55) <0E688457-4915-36DD-8798-5C2EDEE3F1A3> /usr/lib/system/libsystem_kernel.dylib

External Modification Summary:
  Calls made by other processes targeting this process:
    task_for_pid: 1
    thread_create: 0
    thread_set_state: 0
  Calls made by this process:
    task_for_pid: 0
    thread_create: 0
    thread_set_state: 0
  Calls made by all processes on this machine:
    task_for_pid: 4085549
    thread_create: 0
    thread_set_state: 0

VM Region Summary:
ReadOnly portion of Libraries: Total=110.4M resident=0K(0%) swapped_out_or_unallocated=110.4M(100%)
Writable regions: Total=55.5M written=0K(0%) resident=0K(0%) swapped_out=0K(0%) unallocated=55.5M(100%)

                                VIRTUAL   REGION 
REGION TYPE                        SIZE    COUNT (non-coalesced) 
===========                     =======  ======= 
Activity Tracing                  2048K        2 
Dispatch continuations            8192K        2 
Kernel Alloc Once                    4K        2 
MALLOC                            36.2M        8 
MALLOC guard page                   16K        4 
STACK GUARD                       56.0M        5 
Stack                             9304K        5 
VM_ALLOCATE                         20K        3 
__DATA                            3244K       58 
__LINKEDIT                        91.7M       12 
__TEXT                            18.7M       55 
__UNICODE                          552K        2 
shared memory                       12K        4 
===========                     =======  ======= 
TOTAL                            225.4M      149 

Can your run gdb in the command?

I wish. :-(

No working gdb, and Xcode debugger (lldb) refuses to run openssl with the arguments I'm providing. :-(

Do you build the packages with debugging?

Well, now I did. Stand by for new reports.

One good thing - RSA fixes seem to really work:

$ pkcs11-rsa-pss-sign-demo winconfig.h
openssl dgst -engine pkcs11 -keyform engine -sign "pkcs11:object=SIGN%20key;object-type=private;pin-value=123456" -sha384 -sigopt rsa_padding_mode:pss -sigopt rsa_pss_saltlen:-1 -out winconfig.h.sig winconfig.h
initializing engine
engine "pkcs11" set.
Looking in slot -1 for key: label: SIGN key
Found 2 slots
[18446744073709551615] Virtual hotplug slot       no tok
[1] Yubico Yubikey NEO OTP+U2  login             (PIV_II (PIV Card Holder pin))
Found slot:  Yubico Yubikey NEO OTP+U2F+CCID
Found token: PIV_II (PIV Card Holder pin)
Found 4 certificates:
   1    Certificate for PIV Authentication (/CN=Mouse Mousevich)
   2    Certificate for Digital Signature (/emailAddress=mouse07410@outlook.com/CN=Mouse Mousevich)
   3    Certificate for Key Management (/emailAddress=mouse07410@outlook.com/CN=Mouse Mousevich)
   4    Certificate for Card Authentication (/CN=Mouse Mousevich)
PKCS#11 token PIN:
Found 8 keys:
   1 P  PIV AUTH key
   2 P  SIGN key
   3 P  KEY MAN key
   4 P  CARD AUTH key
   5    PIV AUTH pubkey
   6    SIGN pubkey
   7    KEY MAN pubkey
   8    CARD AUTH pubkey
Signature for winconfig.h is stored in winconfig.h.sig

pkcs11-tool -r -y pubkey -d 02 -o /tmp/derive.52770.pubkey.02
Using slot 1 with a present token (0x1)
openssl dgst -verify /tmp/derive.52770.pubkey.02 -keyform DER -sha384 -sigopt rsa_padding_mode:pss -sigopt rsa_pss_saltlen:-1 -signature winconfig.h.sig < winconfig.h
Verified OK

openssl dgst -engine pkcs11 -keyform engine -sha384 -verify id_02 -sigopt rsa_padding_mode:pss -sigopt rsa_pss_saltlen:-1 -signature winconfig.h.sig  winconfig.h
initializing engine
engine "pkcs11" set.
Looking in slot -1 for key: 02
Found 2 slots
[18446744073709551615] Virtual hotplug slot       no tok
[1] Yubico Yubikey NEO OTP+U2  login             (PIV_II (PIV Card Holder pin))
Found slot:  Yubico Yubikey NEO OTP+U2F+CCID
Found token: PIV_II (PIV Card Holder pin)
Found 4 certificates:
   1    Certificate for PIV Authentication (/CN=Mouse Mousevich)
   2    Certificate for Digital Signature (/emailAddress=mouse07410@outlook.com/CN=Mouse Mousevich)
   3    Certificate for Key Management (/emailAddress=mouse07410@outlook.com/CN=Mouse Mousevich)
   4    Certificate for Card Authentication (/CN=Mouse Mousevich)
Found 4 public keys:
   1    PIV AUTH pubkey
   2    SIGN pubkey
   3    KEY MAN pubkey
   4    CARD AUTH pubkey
Verified OK
mtrojnar commented 8 years ago

I confirm that engine_pkcs11 is currently unable to properly handle public keys. The proper fix requires fixing libp11 first, which also has an open issue for it. I have already started a major rewrite of libp11/src/p11_key.c.

@mouse07410: The ECDSA crash is a completely separate libp11 bug. Please open a new issue for libp11 and move the related comments into the newly opened issue.

mouse07410 commented 8 years ago

Update I think I've fixed ECDSA. So now RSA (signature/verification and encryption/decryption) work fine with OpenSSL 1.0.2e, without unnecessary prompting for PIN to access public key. ECDH still needs testing.

Patches for libp11:

diff --git a/src/libp11.exports b/src/libp11.exports
index dc7b5d9..d2c19a7 100644
--- a/src/libp11.exports
+++ b/src/libp11.exports
@@ -11,6 +11,7 @@ PKCS11_is_logged_in
 PKCS11_login
 PKCS11_logout
 PKCS11_enumerate_keys
+PKCS11_enumerate_pubkeys
 PKCS11_get_key_type
 PKCS11_get_key_size
 PKCS11_get_key_modulus
diff --git a/src/p11_attr.c b/src/p11_attr.c
index 3f5cfcb..c618c23 100644
--- a/src/p11_attr.c
+++ b/src/p11_attr.c
@@ -31,6 +31,8 @@

 #include "libp11-int.h"

+static int verbose = 0; /* print debugging output */
+
 /*
  * Query pkcs11 attributes
  */
diff --git a/src/p11_ec.c b/src/p11_ec.c
index e01795c..8252a0b 100644
--- a/src/p11_ec.c
+++ b/src/p11_ec.c
@@ -37,6 +37,8 @@
 #include <openssl/ec.h>
 #include <openssl/ecdsa.h>

+static int verbose = 0;  /* printing debugging information */
+
 /* To build this mode,
  * OpenSSL has ECDSA_METHOD defined in internal header file ecs_locl.h
  * Until this is resolved use something like:
@@ -95,7 +97,7 @@ static ECDSA_METHOD *ops = NULL;
  * We need to get the EC_PARAMS and EC_POINT into both,
  * as lib11 dates from RSA only where all the pub key components
  * were also part of the privite key.  With EC the point
- * is not in the privite key, and the params may or may not be.
+ * is not in the private key, and the params may or may not be.
  *
  */
 static int pkcs11_get_ec_private(PKCS11_KEY * key, EVP_PKEY * pk)
@@ -174,7 +176,7 @@ static int pkcs11_get_ec_private(PKCS11_KEY * key, EVP_PKEY * pk)
                    a = os->data;
                    o2i_ECPublicKey(&ec, &a, os->length);
                }
-/* EC_KEY_print_fp(stderr, ec, 5); */
+               if (verbose) EC_KEY_print_fp(stderr, ec, 5);
                }
            }
        }
@@ -203,8 +205,123 @@ static int pkcs11_get_ec_private(PKCS11_KEY * key, EVP_PKEY * pk)

 static int pkcs11_get_ec_public(PKCS11_KEY * key, EVP_PKEY * pk)
 {
+        CK_BBOOL sensitive, extractable;
+        EC_KEY * ec = NULL;
+        CK_RV ckrv;
+        int rv;
+        size_t ec_paramslen = 0;
+        CK_BYTE * ec_params = NULL;
+        size_t ec_pointlen = 0;
+        CK_BYTE * ec_point = NULL;
+        PKCS11_KEY * prkey;
+        PKCS11_KEY * pubkey;
+        ASN1_OCTET_STRING *os=NULL;
    /* TBD */
-   return pkcs11_get_ec_private(key, pk);
+
+   if (key->isPrivate)
+       return pkcs11_get_ec_private(key, pk);
+
+   pubkey = key;
+
+   if (pk->type == EVP_PKEY_EC) {
+       ec = EVP_PKEY_get1_EC_KEY(pk);
+       if (verbose)
+         fprintf(stderr, "pkcs11_get_ec_public(): pk->type == EVP_PKEY_EC\n");
+   } else {
+       ec = EC_KEY_new();
+       EVP_PKEY_set1_EC_KEY(pk, ec);
+       if (verbose)
+         fprintf(stderr, "pkcs11_get_ec_public(): pk->type is not EVP_PKEY_EC, called EVP_PKEY_set1_EC_KEY()\n");
+   }
+
+        if (key_getattr(pubkey, CKA_SENSITIVE, &sensitive, sizeof(sensitive))
+            || key_getattr(pubkey, CKA_EXTRACTABLE, &extractable, sizeof(extractable))) {
+                if (verbose)
+                        fprintf(stderr, "   ERROR! checking SENSITIVE and EXTRACTABLE attrs failed!\n");
+                EC_KEY_free(ec);
+                return -1;
+        }
+
+        if (key_getattr_var(pubkey, CKA_EC_PARAMS, NULL, &ec_paramslen) == CKR_OK &&
+            ec_paramslen > 0) {
+                ec_params = OPENSSL_malloc(ec_paramslen);
+                if (ec_params) {
+                        ckrv = key_getattr_var(pubkey, CKA_EC_PARAMS, ec_params, &ec_paramslen);
+                        if (ckrv == CKR_OK) {
+                                const unsigned char * a = ec_params;
+                                /* convert to OpenSSL parmas */
+                                d2i_ECParameters(&ec, &a, ec_paramslen);
+                        } else {
+                                if (verbose)
+                                        fprintf(stderr, "   key_getattr_var(...CKA_EC_PARAMS...) returned %d\n", ckrv);
+                        }
+                } else {
+                        if (verbose)
+                                fprintf(stderr, "   OPENSSL_malloc(%1d) failed!\n", ec_paramslen);
+                }
+        } else {
+                if (verbose)
+                        fprintf(stderr, "   ERROR! Could not retrieve ec_paramslen\n");
+        }
+
+   if (verbose)
+     fprintf(stderr, "   about to call key_getattr_var(pubkey, CKA_EC_POINT, NULL, &ec_pointlen)\n");
+
+   ckrv = key_getattr_var(pubkey, CKA_EC_POINT, NULL, &ec_pointlen);
+   if (ckrv == CKR_OK && ec_pointlen > 0) {
+     if (verbose)
+       fprintf(stderr, "  ckrv=%d  ec_pointlen=%d\n", ckrv, ec_pointlen);
+     ec_point = OPENSSL_malloc(ec_pointlen);
+     if (ec_point) {
+       ckrv = key_getattr_var(pubkey, CKA_EC_POINT, ec_point, &ec_pointlen);
+       if (verbose)
+         fprintf(stderr, "key_getattr_var(pubkey,CKA_EC_POINT, ec_point,...) == %d\n", ckrv);
+
+       if (ckrv == CKR_OK) {
+         if (verbose)
+       fprintf(stderr, "key_getattr_var() returned CKR_OK\n");
+
+         /* PKCS#11 returns ASN1 octstring*/
+         const unsigned char * a;
+         /*  we have asn1 octet string, need to strip off 04 len */
+
+         a = ec_point;
+         os = d2i_ASN1_OCTET_STRING(NULL, &a, ec_pointlen);
+         if (os) {
+       a = os->data;
+       o2i_ECPublicKey(&ec, &a, os->length);
+         }
+         if (verbose)
+       EC_KEY_print_fp(stderr, ec, 5);
+       }
+     }
+   } else {
+     if (verbose)
+       fprintf("  ERROR: ckrv=%d  ec_pointlen=%d\n", ckrv, ec_pointlen);
+   }
+
+        if (os)
+                M_ASN1_OCTET_STRING_free(os);
+        if (ec_point)
+                OPENSSL_free(ec_point);
+        if (ec_params)
+                OPENSSL_free(ec_params);
+
+   if (verbose)
+     fprintf(stderr, "pkcs11_get_ec_public(): freed os, ec_point, ec_params\n");
+
+   if (sensitive || !extractable) {
+       ECDSA_set_ex_data(ec, 0, key);
+       EC_KEY_free(ec); /* drops our reference to it. */
+       return 0;
+   }
+
+   if (ec)
+       EC_KEY_free(ec);
+   if (verbose)
+     fprintf(stderr, "pkcs11_get_ec_public(): about to return -1\n");
+   return -1;
+
 }

 /* TODO Looks like this is never called */
diff --git a/src/p11_key.c b/src/p11_key.c
index dba1480..facf16d 100644
--- a/src/p11_key.c
+++ b/src/p11_key.c
@@ -24,6 +24,8 @@
 #define strncasecmp strnicmp
 #endif

+static int verbose = 0;
+
 static int pkcs11_find_keys(PKCS11_TOKEN *, unsigned int);
 static int pkcs11_next_key(PKCS11_CTX * ctx, PKCS11_TOKEN * token,
               CK_SESSION_HANDLE session, CK_OBJECT_CLASS type);
@@ -63,10 +65,30 @@ PKCS11_enumerate_keys(PKCS11_TOKEN * token, PKCS11_KEY ** keyp, unsigned int *co
        }
    }
    *keyp = priv->keys;
-   *countp = priv->nprkeys;
+   //        *countp = priv->nprkeys;
+   *countp = priv->nkeys;
    return 0;
 }

+int
+PKCS11_enumerate_pubkeys(PKCS11_TOKEN * token, PKCS11_KEY ** keyp, unsigned int *countp)
+{
+        PKCS11_TOKEN_private *priv = PRIVTOKEN(token);
+
+   priv->nkeys = 0;
+
+   if (pkcs11_find_keys(token, CKO_PUBLIC_KEY)) {
+     pkcs11_destroy_keys(token);
+     if (verbose) {
+       fprintf(stderr, "pkcs11_find_keys(CKO_PUBLIC_KEYS) returned error\n");
+     }
+     return -1;
+   }
+   *keyp = priv->keys;
+        *countp = priv->nkeys;
+        return 0;
+}
+
 /*
  * Find key matching a certificate
  */

Patches for engine_pkcs11:

diff --git a/src/engine_pkcs11.c b/src/engine_pkcs11.c
index 5f5e9c6..b517364 100644
--- a/src/engine_pkcs11.c
+++ b/src/engine_pkcs11.c
@@ -811,6 +811,11 @@ static EVP_PKEY *pkcs11_load_key(ENGINE * e, const char *s_slot_key_id,
    size_t tmp_pin_len = sizeof(tmp_pin);
    char flags[64];

+   if (verbose)
+       fprintf(stderr, "pkcs11_load_key(...,\"%s\",...,...,%s)\n",
+           s_slot_key_id,
+           (char *)(isPrivate?"Private":"Public")
+       );
    if (s_slot_key_id && *s_slot_key_id) {
        if (!strncmp(s_slot_key_id, "pkcs11:", 7)) {
            n = parse_pkcs11_uri(s_slot_key_id, &match_tok,
@@ -941,10 +946,10 @@ static EVP_PKEY *pkcs11_load_key(ENGINE * e, const char *s_slot_key_id,
        return NULL;
    }
 /* Removed for interop with some other pkcs11 libs. */
-#if 0
+#if 1
    if (!tok->initialized) {
        fprintf(stderr, "Found uninitialized token; \n");
-       return NULL;
+       //return NULL;
    }
 #endif
    if (isPrivate && !tok->userPinSet && !tok->readOnly) {
@@ -980,23 +985,43 @@ static EVP_PKEY *pkcs11_load_key(ENGINE * e, const char *s_slot_key_id,
        }
    }

-   /* Perform login to the token if required */
-   if (!pkcs11_login(slot, tok, ui_method, callback_data)) {
-       return NULL;
-   }
-
-   /* Make sure there is at least one private key on the token */
-   if (PKCS11_enumerate_keys(tok, &keys, &key_count)) {
-       fail("unable to enumerate keys\n");
-   }
-   if (key_count == 0) {
-       fail("No keys found.\n");
-   }

-   if (verbose) {
-       fprintf(stderr, "Found %u key%s:\n", key_count,
-           (key_count <= 1) ? "" : "s");
+   if (isPrivate) {
+
+     /* Perform login to the token if required */
+     if (!pkcs11_login(slot, tok, ui_method, callback_data)) {
+       fprintf(stderr, "login to token failed, returning NULL...\n");
+       return NULL;
+     }
+
+     /* Make sure there is at least one private key on the token */
+     if (PKCS11_enumerate_keys(tok, &keys, &key_count)) {
+       fail("unable to enumerate keys\n");
+     }
+     if (key_count == 0) {
+       fail("No keys found.\n");
+     }
+
+     if (verbose) {
+       fprintf(stderr, "Found %u key%s:\n", key_count,
+           (key_count <= 1) ? "" : "s");
+     }
+   } else {
+
+     /* Make sure there is at least one public key on the token */
+     if (PKCS11_enumerate_pubkeys(tok, &keys, &key_count)) {
+       fail("unable to enumerate public keys\n");
+     }
+     if (key_count == 0) {
+       fail("No public keys found.\n");
+     }
+
+     if (verbose) {
+       fprintf(stderr, "Found %u public key%s:\n", key_count,
+           (key_count <= 1) ? "" : "s");
+     }
    }
+
    if (s_slot_key_id && *s_slot_key_id && (key_id_len != 0 || key_label != NULL)) {
        for (n = 0; n < key_count; n++) {
            PKCS11_KEY *k = keys + n;
@@ -1031,7 +1056,7 @@ static EVP_PKEY *pkcs11_load_key(ENGINE * e, const char *s_slot_key_id,
    } else {
        /*pk = PKCS11_get_public_key(&keys[0]);
           need a get_public_key? */
-       pk = PKCS11_get_private_key(selected_key);
+       pk = PKCS11_get_public_key(selected_key);
    }
    if (key_label != NULL)
        free(key_label);

Also, in order for engine_pkcs11 to work correctly (at least on my Mac) it is necessary to edit config.h (I did it manually, would be nice if configuration could do it for me) and change the default PKCS11 module to OpenSC opensc-pkcs11.so. Here's what it should look like on Mac:

/* p11-kit proxy */
#define DEFAULT_PKCS11_MODULE "/Library/OpenSC/lib/opensc-pkcs11.so"

The above works, and despite having GnuTLS and libp11 installed, my system does not have p11-kit-proxy anywhere.

Demo of the results:

$ pkcs11-ecdsa-demo xxtea.py.enc
Using reader with a card: Yubico Yubikey 4 OTP+U2F+CCID
read EC key
openssl dgst -sha384 -binary -out /tmp/derive.60527.sha384 xxtea.py.enc
pkcs11-tool --sign -f 'openssl' -m ECDSA -d 02 -i /tmp/derive.60527.sha384 -o /tmp/xxtea.py.enc.sig
Using slot 1 with a present token (0x1)
Logging in to "PIV_II (PIV Card Holder pin)".
Please enter User PIN:
Using signature algorithm ECDSA
Signature for xxtea.py.enc is stored in /tmp/xxtea.py.enc.sig

pkcs11-tool -r -y pubkey -d 02 -o /tmp/derive.60527.02
Using slot 1 with a present token (0x1)
openssl dgst -verify /tmp/derive.60527.02 -keyform DER -sha384 -signature /tmp/xxtea.py.enc.sig < xxtea.py.enc
Verified OK

openssl dgst -engine pkcs11 -keyform engine -sha384 -verify "pkcs11:object=SIGN%20pubkey;object-type=public" -signature /tmp/xxtea.py.enc.sig xxtea.py.enc
engine "pkcs11" set.
Verified OK

$ pkcs11-rsa-pss-sign-demo xxtea.py.enc
openssl dgst -engine pkcs11 -keyform engine -sign "pkcs11:object=SIGN%20key;object-type=private;pin-value=123456" -sha384 -sigopt rsa_padding_mode:pss -sigopt rsa_pss_saltlen:-1 -out xxtea.py.enc.sig xxtea.py.enc
engine "pkcs11" set.
PKCS#11 token PIN:
Signature for xxtea.py.enc is stored in xxtea.py.enc.sig

pkcs11-tool -r -y pubkey -d 02 -o /tmp/derive.60552.pubkey.02
Using slot 1 with a present token (0x1)
openssl dgst -verify /tmp/derive.60552.pubkey.02 -keyform DER -sha384 -sigopt rsa_padding_mode:pss -sigopt rsa_pss_saltlen:-1 -signature xxtea.py.enc.sig < xxtea.py.enc
Verified OK

openssl dgst -engine pkcs11 -keyform engine -sha384 -verify id_02 -sigopt rsa_padding_mode:pss -sigopt rsa_pss_saltlen:-1 -signature xxtea.py.enc.sig  xxtea.py.enc
engine "pkcs11" set.
Verified OK

@mtrojnar I concur that a rewrite wouldn't hurt, but in the meanwhile the patches I offered seem to do the job sufficiently well to use them. As I said, they work fine for RSA (all modes) and EC (tested ECDSA signature, and partially ECDH). Since it's unclear how long it would take to rewrite this fairly large piece of code (and whether any new problems would be introduced in the process that could delay deployment), please consider incorporating these patches, at least for the time being.

dengert commented 8 years ago
I suspect that ec was null.

It was never a dummy routine. 
The private key may not have the namedCurve. The code was meant to
find the namedCurve  from the public key.
There are terminology differences between OPenSSL and PKCS#11 as to
what is in the private key, or in the public key. With RSA with no
parameters it was easy. With EC the namedCurve 
(or ecParameters) are needed to determine properties of the private
key. 

On 12/29/2015 4:08 PM, Mouse wrote:

  Here's the code of pkcs11_get_ec_public(), as it
    was a dummy routine calling pkcs11_get_ec_private()
    before:
            if (verbose)
    EC_KEY_print_fp(stderr, ec, 5);
    }
  }
}

if (os)
    M_ASN1_OCTET_STRING_free(os);
if (ec_point)
    OPENSSL_free(ec_point);
if (ec_params)
    OPENSSL_free(ec_params);

if (sensitive || !extractable) {
    ECDSA_set_ex_data(ec, 0, key);
    EC_KEY_free(ec); /* drops our reference to it. */
    return 0;
}

if (ec)
    EC_KEY_free(ec);
return -1;

}

  —
    Reply to this email directly or view
      it on GitHub.

-- 

Douglas E. Engert DEEngert@gmail.com

dengert commented 8 years ago
pkcs11_get_ec_private should have been renamed  pkcs11_get_ec_key
  log ago as it is called with the PKCS11_KEY which has 
  a flag to say if it is for the public or private. the
  key->isPrivate

   92 /*
   93  * Get EC key material and stach pointer in ex_data
   94  * Note we get called twice, once for private key, and once
  for public
   95  * We need to get the EC_PARAMS and EC_POINT into both,
   96  * as lib11 dates from RSA only where all the pub key
  components
   97  * were also part of the privite key.  With EC the point
   98  * is not in the privite key, and the params may or may not
  be.
   99  *
  100  */

On 12/29/2015 4:39 PM, Mouse wrote:

  Changing pkcs11_get_ec_public() to call pkcs11_get_ec_private()
    like before, gets signature creation working:
  $ openssl dgst -engine pkcs11 -keyform engine -sha384 -sign "pkcs11:object=SIGN%20key;object-type=private" -out t.sig stamp-h1

initializing engine engine "pkcs11" set. Looking in slot -1 for key: label: SIGN key Found 2 slots [18446744073709551615] Virtual hotplug slot no tok [1] Yubico Yubikey 4 OTP+U2F+ login (PIV_II (PIV Card Holder pin)) Found slot: Yubico Yubikey 4 OTP+U2F+CCID Found token: PIV_II (PIV Card Holder pin) Found 4 certificates: 1 Certificate for PIV Authentication (/CN=Uri the Great) 2 Certificate for Digital Signature (/CN=Uri the Great) 3 Certificate for Key Management (/CN=Uri the Great) 4 Certificate for Card Authentication (/CN=Uri the Great) PKCS#11 token PIN: Found 8 keys: 1 P PIV AUTH key 2 P SIGN key 3 P KEY MAN key 4 P CARD AUTH key 5 PIV AUTH pubkey 6 SIGN pubkey 7 KEY MAN pubkey 8 CARD AUTH pubkey Private-Key: (384 bit) pub: 04:32:3d:ac:5d:34:44:9a:c1:70:73:d5:ee:de:c1: 53:26:48:da:7e:19:04:c7:70:3a:a4:38:4b:fd:60: d4:ca:ab:4d:f5:0b:cf:d3:d4:2d:d4:d0:da:15:97: 32:c1:2b:d6:01:64:70:05:da:35:f5:cf:16:c4:a3: 67:4a:59:15:4c:a2:e6:6d:8e:e8:1e:11:5c:4a:9b: e8:9c:21:fc:19:b2:9f:0f:99:1b:f0:82:39:d0:08: 15:63:44:35:09:08:f9 ASN1 OID: secp384r1 NIST CURVE: P-384 Private-Key: (384 bit) pub: 04:32:3d:ac:5d:34:44:9a:c1:70:73:d5:ee:de:c1: 53:26:48:da:7e:19:04:c7:70:3a:a4:38:4b:fd:60: d4:ca:ab:4d:f5:0b:cf:d3:d4:2d:d4:d0:da:15:97: 32:c1:2b:d6:01:64:70:05:da:35:f5:cf:16:c4:a3: 67:4a:59:15:4c:a2:e6:6d:8e:e8:1e:11:5c:4a:9b: e8:9c:21:fc:19:b2:9f:0f:99:1b:f0:82:39:d0:08: 15:63:44:35:09:08:f9 ASN1 OID: secp384r1 NIST CURVE: P-384 $ ll t.sig -rw-r--r-- 1 uri staff 102 Dec 29 17:38 t.sig $ dumpasn1 t.sig 0 100: SEQUENCE { 2 48: INTEGER : 09 33 31 99 B7 C6 C6 9D AE 69 94 0A 35 CB 38 7F : 69 00 4D 21 39 7C 7B 40 07 5F DC 45 DF AC EA 80 : AA F3 7E 02 C4 80 7B 67 16 81 5A CF C1 C1 C1 DC 52 48: INTEGER : 36 92 EE 2B 08 E5 0F EB CE 90 6B 01 AE 45 47 70 : C5 9B 25 B3 37 97 BE 6A F7 1F F0 F9 9B F1 65 DF : 7D E7 48 8E D0 11 47 3F E5 05 6F 22 AE 4B 8D 87 : }

0 warnings, 0 errors. $

  But attempts to verify an ECDSA signature result in:
  $ openssl dgst -d -engine pkcs11 -keyform engine -sha384 -verify "pkcs11:object=SIGN%20pubkey;object-type=public" -signature t.sig winconfig.h

initializing engine engine "pkcs11" set. Looking in slot -1 for key: label: SIGN pubkey Found 2 slots [18446744073709551615] Virtual hotplug slot no tok [1] Yubico Yubikey 4 OTP+U2F+ login (PIV_II (PIV Card Holder pin)) Found slot: Yubico Yubikey 4 OTP+U2F+CCID Found token: PIV_II (PIV Card Holder pin) Found 4 certificates: 1 Certificate for PIV Authentication (/CN=Uri the Great) 2 Certificate for Digital Signature (/CN=Uri the Great) 3 Certificate for Key Management (/CN=Uri the Great) 4 Certificate for Card Authentication (/CN=Uri the Great) Found 4 public keys: 1 PIV AUTH pubkey 2 SIGN pubkey 3 KEY MAN pubkey 4 CARD AUTH pubkey Out of memory 140735231131728:error:10098043:elliptic curve routines:o2i_ECPublicKey:passed a null parameter:ec_asn1.c:1271: 140735231131728:error:100DD043:elliptic curve routines:DO_EC_KEY_PRINT:passed a null parameter:ec_ameth.c:489: BIO[0x7ff393c01d80]: Free - FILE pointer

  —
    Reply to this email directly or view
      it on GitHub.

-- 

Douglas E. Engert DEEngert@gmail.com

mouse07410 commented 8 years ago

Submitted a PR that fixes all of the above: https://github.com/OpenSC/engine_pkcs11/pull/34

Hope it would be merged.

mtrojnar commented 8 years ago

https://github.com/OpenSC/engine_pkcs11/pull/34 merged.