Yubico / yubico-piv-tool

Command line tool for the YubiKey PIV application
https://developers.yubico.com/yubico-piv-tool
BSD 2-Clause "Simplified" License
290 stars 97 forks source link

ykcs11 with ed25519 (using firmware 5.7.1) #507

Open phiekl opened 3 weeks ago

phiekl commented 3 weeks ago

Since #308 was merged yesterday, I figured YKCS11 would support ed25519 keys, but I can't get it to work.

$ cat /etc/debian_version 
trixie/sid
$ dpkg -l cmake libtool libssl-dev openssh-client pkg-config check libpcsclite-dev gengetopt help2man zlib1g-dev
ii  check:amd64           0.15.2-2+b1              amd64        unit test framework for C
ii  cmake                 3.30.2-2                 amd64        cross-platform, open-source make system
ii  gengetopt             2.23+dfsg1-1             amd64        skeleton main.c generator
ii  help2man              1.49.3                   amd64        Automatic manpage generator
ii  libpcsclite-dev:amd64 2.3.0-1                  amd64        Middleware to access a smart card using PC/SC (development files)
ii  libssl-dev:amd64      3.2.2-1                  amd64        Secure Sockets Layer toolkit - development files
ii  libtool               2.4.7-7                  all          Generic library support script
ii  openssh-client        1:9.7p1-7                amd64        secure shell (SSH) client, for secure access to remote machines
ii  pkg-config:amd64      1.8.1-3                  amd64        manage compile and link flags for libraries (transitional package)
ii  zlib1g-dev:amd64      1:1.3.dfsg+really1.3.1-1 amd64        compression library - development
$ git show --oneline
06ccdfa (HEAD -> master, tag: yubico-piv-tool-2.6.0, origin/master, origin/HEAD) Merge pull request #506 from Yubico/edx_openssl_version
$ git clean -dfx
$ mkdir build; cd build
$ cmake ..
-- The C compiler identification is GNU 13.3.0
-- The CXX compiler identification is GNU 13.3.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /usr/bin/cc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Found PkgConfig: /usr/bin/pkg-config (found version "1.8.1")
-- Performing Test HAVE_SHORTEN_64_TO_32
-- Performing Test HAVE_SHORTEN_64_TO_32 - Failed
-- Checking for module 'libcrypto'
--   Found libcrypto, version 3.2.2
        OpenSSL version:   3.2.2
-- Looking for explicit_bzero
-- Looking for explicit_bzero - found
lib/CMakeList.txt
Detected neither Mac nor Windows: selecting pcsc backend
-- Checking for module 'libpcsclite'
--   Found libpcsclite, version 2.3.0
PCSC_LIBRARIES: -L/usr/lib/x86_64-linux-gnu;-lpcsclite
PCSC_CFLAGS: -I/usr/include/PCSC
BACKEND_PCSC: ON
HAVE_PCSC_WINSCARD_H: 
-- Found ZLIB: /usr/lib/x86_64-linux-gnu/libz.so (found version "1.3.1")
lib/tests/CMakeList.txt
-- Checking for module 'check'
--   Found check, version 0.15.2
ykcs11/CMakeList.txt
ykcs11/tests/CMakeList.txt
tool/CMakeList.txt
lib/tool/CMakeList.txt
Running on Windows. Skipping basic tests...
Build summary:

        Project name:     yubico-piv-tool
        Version:          2.6.0
        Host type:        Linux
        Install prefix:   
        Compiler:         /usr/bin/cc
        Compiler ID:      GNU
        CFLAGS:            -Wall -Werror -Wno-missing-braces -Wformat -Wformat-security -Wshadow -Wpointer-arith -Wmissing-prototypes -Wbad-function-cast -fstack-protector-all -Wno-pointer-sign -Wno-unused-result -I/usr/include
        CFLAGS_DEBUG:     -g -g2 -fno-omit-frame-pointer
        CPPFLAGS:          -I/usr/include
        Warnings:         
        Build type:       Debug
        Backend:          check
        PCSC
                CFLAGS:   -I/usr/include/PCSC
                LIBS:     pcsclite
        Winscard
                LIBS:     
        Mac PCSC
                LIBS:     
        Custom PCSC
                LIBS:     

        Install prefix:    /usr/local
        Install targets
                Libraries  /usr/local/lib
                Includes   /usr/local/include
                Binaries   /usr/local/bin
                Manuals    /usr/local/share/man
                Pkg-config /usr/local/lib/pkgconfig

        YKCS11 debug:     
        Hardware tests:   Disabled
-- Configuring done (0.7s)
-- Generating done (0.0s)
-- Build files have been written to: /home/user/yubico-piv-tool/build
$ make -j
[  1%] Building C object lib/CMakeFiles/ykpiv_shared.dir/ykpiv.c.o
[  3%] Building C object lib/CMakeFiles/ykpiv_shared.dir/util.c.o
[  5%] Building C object lib/CMakeFiles/ykpiv.dir/ykpiv.c.o
[  6%] Building C object lib/CMakeFiles/ykpiv.dir/util.c.o
[  8%] Building C object lib/CMakeFiles/ykpiv_shared.dir/error.c.o
[ 10%] Building C object lib/CMakeFiles/ykpiv_shared.dir/version.c.o
[ 12%] Building C object lib/CMakeFiles/ykpiv_shared.dir/internal.c.o
[ 13%] Building C object lib/CMakeFiles/ykpiv.dir/error.c.o
[ 15%] Building C object lib/CMakeFiles/ykpiv.dir/version.c.o
[ 17%] Building C object ykcs11/CMakeFiles/ykcs11.dir/ykcs11.c.o
[ 18%] Building C object lib/CMakeFiles/ykpiv.dir/internal.c.o
[ 24%] Building C object lib/CMakeFiles/ykpiv.dir/__/common/openssl-compat.c.o
[ 25%] Building C object ykcs11/CMakeFiles/ykcs11.dir/token.c.o
[ 20%] Building C object lib/CMakeFiles/ykpiv_shared.dir/__/common/util.c.o
[ 22%] Building C object lib/CMakeFiles/ykpiv_shared.dir/__/common/openssl-compat.c.o
[ 27%] Building C object lib/CMakeFiles/ykpiv.dir/__/common/util.c.o
[ 29%] Building C object ykcs11/CMakeFiles/ykcs11.dir/mechanisms.c.o
[ 31%] Building C object ykcs11/CMakeFiles/ykcs11.dir/utils.c.o
[ 32%] Building C object ykcs11/CMakeFiles/ykcs11.dir/openssl_utils.c.o
[ 34%] Building C object ykcs11/CMakeFiles/ykcs11.dir/objects.c.o
[ 36%] Building C object ykcs11/CMakeFiles/ykcs11.dir/__/common/openssl-compat.c.o
[ 37%] Building C object ykcs11/CMakeFiles/ykcs11.dir/__/common/util.c.o
[ 39%] Linking C shared library libykpiv.so
[ 41%] Linking C static library libykpiv.a
[ 41%] Built target ykpiv
[ 43%] Linking C static library libykcs11.a
[ 43%] Built target ykcs11
[ 43%] Built target ykpiv_shared
[ 44%] Building C object lib/tests/CMakeFiles/test_parse_key.dir/parse_key.c.o
[ 46%] Building C object lib/tests/CMakeFiles/test_api.dir/api.c.o
[ 48%] Building C object lib/tests/CMakeFiles/test_basic.dir/basic.c.o
[ 50%] Building C object tool/CMakeFiles/yubico-piv-tool.dir/yubico-piv-tool.c.o
[ 53%] Building C object ykcs11/CMakeFiles/ykcs11_shared.dir/ykcs11.c.o
[ 51%] Building C object tool/tests/CMakeFiles/test_parse_name.dir/parse_name.c.o
[ 55%] Building C object tool/CMakeFiles/yubico-piv-tool.dir/__/common/openssl-compat.c.o
[ 56%] Building C object tool/tests/CMakeFiles/test_inout.dir/test_inout.c.o
[ 58%] Building C object ykcs11/CMakeFiles/ykcs11_shared.dir/token.c.o
[ 60%] Building C object tool/CMakeFiles/yubico-piv-tool.dir/__/common/util.c.o
[ 62%] Building C object ykcs11/CMakeFiles/ykcs11_shared.dir/utils.c.o
[ 63%] Building C object ykcs11/CMakeFiles/ykcs11_shared.dir/mechanisms.c.o
[ 65%] Building C object tool/CMakeFiles/yubico-piv-tool.dir/cmdline.c.o
[ 67%] Building C object ykcs11/CMakeFiles/ykcs11_shared.dir/__/common/openssl-compat.c.o
[ 68%] Building C object ykcs11/CMakeFiles/ykcs11_shared.dir/objects.c.o
[ 70%] Building C object ykcs11/CMakeFiles/ykcs11_shared.dir/__/common/util.c.o
[ 72%] Building C object ykcs11/CMakeFiles/ykcs11_shared.dir/openssl_utils.c.o
[ 74%] Linking C executable test_parse_key
[ 75%] Linking C executable test_basic
[ 77%] Linking C executable test_parse_name
[ 79%] Linking C executable test_api
[ 81%] Linking C executable test_inout
[ 81%] Built target test_basic
[ 81%] Built target test_parse_key
[ 81%] Built target test_api
[ 81%] Built target test_parse_name
[ 82%] Linking C executable yubico-piv-tool
[ 82%] Built target test_inout
[ 84%] Linking C shared library libykcs11.so
[ 84%] Built target yubico-piv-tool
[ 86%] Building manpage for yubico-piv-tool
[ 86%] Built target yubico-piv-tool-man
[ 86%] Built target ykcs11_shared
[ 87%] Building C object ykcs11/tests/CMakeFiles/test_ykcs11.dir/ykcs11_tests.c.o
[ 89%] Building C object ykcs11/tests/CMakeFiles/test_ykcs11_edx.dir/ykcs11_edx_test.c.o
[ 91%] Building C object ykcs11/tests/CMakeFiles/test_ykcs11_interfaces.dir/ykcs11_interfaces_tests.c.o
[ 93%] Building C object ykcs11/tests/CMakeFiles/test_ykcs11.dir/ykcs11_tests_util.c.o
[ 94%] Building C object ykcs11/tests/CMakeFiles/test_ykcs11_edx.dir/ykcs11_tests_util.c.o
[ 96%] Linking C executable test_ykcs11_interfaces
[ 96%] Built target test_ykcs11_interfaces
[ 98%] Linking C executable test_ykcs11_edx
[100%] Linking C executable test_ykcs11
[100%] Built target test_ykcs11_edx
[100%] Built target test_ykcs11

And then semi-according to https://developers.yubico.com/PIV/Guides/SSH_with_PIV_and_PKCS11.html

$ ykman piv reset
$ tool/yubico-piv-tool -s 9a -A ED25519 -a generate -o public.pem
Successfully generated a new private key.
$ tool/yubico-piv-tool -a verify-pin -a selfsign-certificate -s 9a -S "/CN=SSH key/" -i public.pem -o cert.pem
Enter PIN: 
Successfully verified PIN.
Successfully generated a new self signed certificate.
$ tool/yubico-piv-tool -a import-certificate -s 9a -i cert.pem 
Successfully imported a new certificate.
$ tool/yubico-piv-tool -a status
Version:    5.7.1
Serial Number:  29173624
CHUID:  No data available
CCC:    No data available
Slot 9a:    
    Algorithm:  ED25519
    Subject DN: CN=SSH key
    Issuer DN:  CN=SSH key
    Fingerprint:    652debe6a63cc764ac191d494b0b6617de728d85ab96b8e841922f861861e589
    Not Before: Aug 21 16:02:19 2024 GMT
    Not After:  Aug 21 16:02:19 2025 GMT
PIN tries left: 3
user@priv-yubi571:~/yubico-piv-tool/build$ ssh-keygen -D ykcs11/libykcs11.so -e
skipping unsupported key type
failed to fetch key
unknown certificate key type
failed to fetch key
unknown certificate key type
failed to fetch key
ssh-rsa **snip** Public key for PIV Attestation

At this point I expected an ed25519 public key to show up.

The same procedure works fine using ecdsa:

$ ykman piv reset
$ tool/yubico-piv-tool -s 9a -A ECCP384 -a generate -o public.pem
Successfully generated a new private key.
$ tool/yubico-piv-tool -a verify-pin -a selfsign-certificate -s 9a -S "/CN=SSH key/" -i public.pem -o cert.pem
Enter PIN: 
Successfully verified PIN.
Successfully generated a new self signed certificate.
$ tool/yubico-piv-tool -a import-certificate -s 9a -i cert.pem
Successfully imported a new certificate.
$ tool/yubico-piv-tool -a status
Version:    5.7.1
Serial Number:  29173624
CHUID:  No data available
CCC:    No data available
Slot 9a:    
    Algorithm:  ECCP384
    Subject DN: CN=SSH key
    Issuer DN:  CN=SSH key
    Fingerprint:    537be13477e9b1fbd3b41ad7e80f362357c8d0e40b4fbffdeeb6ff8bdf6f87d4
    Not Before: Aug 21 16:11:44 2024 GMT
    Not After:  Aug 21 16:11:44 2025 GMT
PIN tries left: 3
$ ssh-keygen -D ykcs11/libykcs11.so -e
ecdsa-sha2-nistp384 **snip** Public key for PIV Authentication
ssh-rsa **snip** Public key for PIV Attestation

Are ed25519 keys simply not supported yet or did I do something wrong?

aveenismail commented 3 weeks ago

ED25519 should now be supported by YKCS11.

Can you please set the YKCS11_DBG environment variable to any value higher than 0, then run the ssh-keygen command and post the output here?

phiekl commented 3 weeks ago

Sure, this is after I generated an ed25519 key once more:

user@priv-yubi571:~/yubico-piv-tool/build$ tool/yubico-piv-tool -a status
Version:    5.7.1
Serial Number:  29173624
CHUID:  No data available
CCC:    No data available
Slot 9a:    
    Algorithm:  ED25519
    Subject DN: CN=SSH key
    Issuer DN:  CN=SSH key
    Fingerprint:    105210594355ed93a62dcaff32b38a38d4fc2b904468cde4cecb51b4bfe8dc5d
    Not Before: Aug 21 19:21:02 2024 GMT
    Not After:  Aug 21 19:21:02 2025 GMT
PIN tries left: 3

The output of YKCS11_DBG=9 ssh-keygen -D ykcs11/libykcs11.so -e is found in ssh-keygen.1724268294.log

aveenismail commented 3 weeks ago

OK, I can re-produce the error.

As far as I can see, YKCS11 does return the correct key type, and the error message "skipping unsupported key type" seems to be produced by the ssh-key command, not YKCS11.

I did some googling and found, among others, this ticket that seems to indicate that OpenSSH does not support ED25519 via PKCS11: https://github.com/OpenSC/OpenSC/issues/2824. It's from last year but it references a PR with a patch that looks to be still open

phiekl commented 3 weeks ago

Ohhh :unamused:

Well, I compiled that old referenced version and branch of openssh. I had to do that on debian 12 since it didn't really work with the openssl version in debian testing. Also recompiled yubico-piv-tool on that same system. No luck, but it outputs "C_GetAttributeValue failed: 18" instead of "skipping unsupported key type".

Here's the complete debug output: ssh-keygen.1724273754.log

diff to previous log file is basically:

-skipping unsupported key type
+DBG ykcs11.c:1834 (C_GetAttributeValue): In
+DBG objects.c:842 (get_puoa): For public key object 111, get 
+DBG objects.c:931 (get_puoa): ID
+DBG objects.c:842 (get_puoa): For public key object 111, get 
+DBG objects.c:1022 (get_puoa): EC_POINT
+DBG ykcs11.c:1871 (C_GetAttributeValue): Unable to get attribute 0x181 of object 111
+DBG objects.c:842 (get_puoa): For public key object 111, get 
+DBG objects.c:1039 (get_puoa): EC_PARAMS
+DBG ykcs11.c:1871 (C_GetAttributeValue): Unable to get attribute 0x180 of object 111
+DBG ykcs11.c:1880 (C_GetAttributeValue): Out
+C_GetAttributeValue failed: 18

So, although YKCS11 supports ed25519 now, is there some way you could actually use with SSH?

aveenismail commented 3 weeks ago

I've done some tweaks. Can you try to build yubico-piv-tool from this branch and see if it works better with your patched OpenSSH? https://github.com/Yubico/yubico-piv-tool/tree/ed_ykcs11

phiekl commented 3 weeks ago

I rebuilt it using

$ git log -1 --oneline
b0084c3 (HEAD -> ed_ykcs11, origin/ed_ykcs11) YKCS11: Return CKA_EC_PARAMS for ED keys

It seems to behave the same as before, unfortunately. ssh-keygen.1724325580.log

phiekl commented 3 weeks ago

I guess we'll simply have to wait for the official support in openssh then.

Unrelated to this repo, but I forked and patched piv-go and yubikey-agent, and now I've got a working ssh setup using ed25519 keys in PIV mode. :grinning:

aveenismail commented 3 weeks ago

Thanks you for the tip. I'm glad you got it to work 😀

I have made another tweek to add support for another missing attribute. Also on this branch https://github.com/Yubico/yubico-piv-tool/tree/ed_ykcs11. Feel free to try it out and please let me know the result if you do.

phiekl commented 3 weeks ago

Looks better!

$ ~/x/opt/bin/ssh-keygen -D ~/yubico-piv-tool/build/ykcs11/libykcs11.so -e
unknown certificate key type
failed to fetch key
unknown certificate key type
failed to fetch key
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICe0fEqZ23Qf5n95WIoSrDf4kfj4NHig+8JiCvKYwgwa Public key for PIV Authentication
ssh-rsa **snip** Public key for PIV Attestation

ssh-keygen.1724405423.log

phiekl commented 3 weeks ago
$ ~/x/opt/bin/ssh-keygen -D ~/yubico-piv-tool/build/ykcs11/libykcs11.so -e | grep ^ssh-ed25519 | sudo tee /root/.ssh/authorized_keys > /dev/null
$ ~/x/opt/bin/ssh -I ~/yubico-piv-tool/build/ykcs11/libykcs11.so root@localhost
unknown certificate key type
failed to fetch key
unknown certificate key type
failed to fetch key
sign_and_send_pubkey: signing failed for ED25519 "Public key for PIV Authentication": invalid argument
root@localhost: Permission denied (publickey).

with -vv you can see that it indeed tries to use the ed25519 key:

debug1: Next authentication method: publickey
debug1: Offering public key: Public key for PIV Authentication ED25519 SHA256:oAr/OaaY3YG21ztDVUEb05zAomYr+ETaNEJtiqkmgGo token
debug2: we sent a publickey packet, wait for reply
debug1: Server accepts key: Public key for PIV Authentication ED25519 SHA256:oAr/OaaY3YG21ztDVUEb05zAomYr+ETaNEJtiqkmgGo token
debug1: identity_sign: sshkey_sign: invalid argument
sign_and_send_pubkey: signing failed for ED25519 "Public key for PIV Authentication": invalid argument

And with YKCS11_DBG=9: ssh.1724407670.log

aveenismail commented 3 weeks ago

Thank you for trying it out.

I'm afraid I'm not sure what the debug output after the PKCS11 session has ended mean. Does this mean that YKCS11 side of things now works with the patched version of OpenSSH? I am currently unable to test this setup here.

phiekl commented 3 weeks ago

Yeah, it might mean that the YKCS11 part does work, and then it's simply the openssh patch that doesn't work all the way. While running pcscd in debug mode I'm noticing that it returns SW: 6A 80 during the signing operation, which is, AFAIK, an error code for "invalid parameter". I got the same code while using yubikey-agent prior to patching it properly.

aveenismail commented 3 weeks ago

What part returns SW: 6A 80?

phiekl commented 3 weeks ago

I combined the logs with timestamps and it seems like 6A 80 isn't related to "sign_and_send_pubkey: signing failed for ED25519 "Public key for PIV Authentication": invalid argument". I believe that error is related to the openssh patches. ssh_pcscd_combined.1724420566.log

aveenismail commented 3 weeks ago

OK. Thank you for looking into it.

In this case, we'll make sure to come out with a patch release soon. I'm sorry it won't help much with your issue but hopefully it'll work better in other settings

Pythoner6 commented 2 weeks ago

@aveenismail I tried your branch https://github.com/Yubico/yubico-piv-tool/tree/ed_ykcs11 in a different context - using https://github.com/latchset/pkcs11-provider - as I was running into the same Unable to get attribute 0x180 / Unable to get attribute 0x181. While the branch did get me past that, I ran into another issue:

[../src/objects.c:1071] p11prov_obj_find(): Error: 0x00000067; Failed to store object
[../src/objects.c:1077] p11prov_obj_find(): Find objects: found 1 objects; Returning 67
[../src/store.c:143] store_fetch(): Error: 0x00000067; Failed to load keys from slot (0)

After digging into it a bit more this appears to be because you're returning the raw public key here https://github.com/Yubico/yubico-piv-tool/blob/ed_ykcs11/ykcs11/openssl_utils.c#L699, while pkcs11-provider is expecting it to be a DER octet string with the tag and length, like what's done for EVP_PKEY_EC here: https://github.com/Yubico/yubico-piv-tool/blob/ed_ykcs11/ykcs11/openssl_utils.c#L686-L687. I tried a quick patch and it seemed to clear up that error, though I'm still running into other issues. I suspect they may not be ykcs11 issues, though I don't really understand what's going on yet.

aveenismail commented 2 weeks ago

@Pythoner6 Thank you for the report.

Can you please try the https://github.com/Yubico/yubico-piv-tool/tree/ed_ykcs11 branch again now? The encoding should be fixed now

Pythoner6 commented 2 weeks ago

Yep, that solves the failed to store issue!