ronf / asyncssh

AsyncSSH is a Python package which provides an asynchronous client and server implementation of the SSHv2 protocol on top of the Python asyncio framework.
Eclipse Public License 2.0
1.51k stars 148 forks source link

pkcs11 bad arguments exception #550

Closed Narsimha96 closed 1 week ago

Narsimha96 commented 1 year ago

I was trying to connect to a server with the following code.. `import asyncio, asyncssh, sys

async def run_client() -> None: asyncssh.read_certificate('path_to_public_key-cert.pub') async with asyncssh.connect('10.72.69.108',pkcs11_provider='path_to_libykcs11.dylib',pkcs11_pin='####',username='root') as conn: result = await conn.run('ls', check=True) print(result.stdout, end='')

try: asyncio.get_event_loop().run_until_complete(run_client()) except (OSError, asyncssh.Error) as exc: sys.exit('SSH connection failed: ' + str(exc))`

And I get the following response: `Traceback (most recent call last): File "/Users/narreddy/venv/lib/python3.9/site-packages/asyncssh/pkcs11.py", line 132, in open session = cls._sessions[token_id] KeyError: ('Yubico (www.yubico.com)', b'20439728')

During handling of the above exception, another exception occurred:

Traceback (most recent call last): File "/Users/narreddy/Desktop/connect.py", line 10, in asyncio.get_event_loop().run_until_complete(run_client()) File "/Applications/Xcode.app/Contents/Developer/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/asyncio/base_events.py", line 642, in run_until_complete return future.result() File "/Users/narreddy/Desktop/connect.py", line 5, in run_client async with asyncssh.connect('10.72.69.108',pkcs11_provider='/usr/local/lib/libykcs11.dylib',pkcs11_pin='1430',username='root') as conn: File "/Users/narreddy/venv/lib/python3.9/site-packages/asyncssh/misc.py", line 274, in aenter self._coro_result = await self._coro File "/Users/narreddy/venv/lib/python3.9/site-packages/asyncssh/connection.py", line 8042, in connect return await asyncio.wait_for( File "/Applications/Xcode.app/Contents/Developer/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/asyncio/tasks.py", line 442, in wait_for return await fut File "/Users/narreddy/venv/lib/python3.9/site-packages/asyncssh/connection.py", line 440, in _connect await options.waiter File "/Users/narreddy/venv/lib/python3.9/site-packages/asyncssh/connection.py", line 1039, in _reap_task task.result() File "/Users/narreddy/venv/lib/python3.9/site-packages/asyncssh/auth.py", line 322, in _start self._keypair = await self._conn.public_key_auth_requested() File "/Users/narreddy/venv/lib/python3.9/site-packages/asyncssh/connection.py", line 3360, in public_key_auth_requested pkcs11_keys = await self._loop.run_in_executor( File "/Applications/Xcode.app/Contents/Developer/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/concurrent/futures/thread.py", line 52, in run result = self.fn(*self.args, **self.kwargs) File "/Users/narreddy/venv/lib/python3.9/site-packages/asyncssh/pkcs11.py", line 276, in load_pkcs11_keys with SSHPKCS11Session.open(token, pin) as session: File "/Users/narreddy/venv/lib/python3.9/site-packages/asyncssh/pkcs11.py", line 134, in open session = cls(token_id, token, pin) File "/Users/narreddy/venv/lib/python3.9/site-packages/asyncssh/pkcs11.py", line 110, in init self._session = token.open(user_pin=pin) File "pkcs11/_pkcs11.pyx", line 282, in pkcs11._pkcs11.Token.open File "pkcs11/_errors.pyx", line 88, in pkcs11._pkcs11.assertRV pkcs11.exceptions.ArgumentsBad`

Am i using it correct or missing anything?

ronf commented 1 year ago

Do you have PIV functionality configured on your YubiKey? In particular do you have certificates loaded onto it? You'll need that if you want to use PKCS11 with it. AsyncSSH also supports FIDO2 if you wanted to use that instead, but in that case you'd need to leave out the PKCS11 provider argument.

You can run YubiKey Manager to see if you have any certs loaded. Go to Applications and then PIV. You can also run "yubico-piv-tool -a status" if you have that installed. These tools are available from yubico.com under Support and then Downloads.

Narsimha96 commented 1 year ago

Hey ronf, thanks for responding. Here is the output for "yubico-piv-tool -a status":

Version: 5.4.3 Serial Number: 20439728 CHUID: No data available CCC: No data available PIN tries left: 15

PIV functionality is configured but no certificates are loaded into it.

Screenshot 2023-03-24 at 3 26 35 PM

The way I use yubikey to log in to remote machine is: ssh -I path_to_libykcs11.dylib -i path_to_public_key_cert.pub root@ip-address

this command propmts for yubikey pin.. and once it is verified.. Im logged in to remote machine.

Is the certificate that i'm using here is same as the one that should be loaded in to yubikey??

I wanted to automate this for a requirement(to develop a tool, if possible interactive one, to collect or watch logs on the remote machine ) in our company.

Im using macos monterey and the remote machine is on linux distro. I hope this clears out the details regarding the functionality configured on Yubikey.

ronf commented 1 year ago

In my experience, you need to import certificates into the key for it to work with PKCS11. See more info at https://developers.yubico.com/PIV/Guides/SSH_with_PIV_and_PKCS11.html, which says:

Step 2: Create a self-signed certificate for that key. The only use for the X.509 certificate is to satisfy PIV/PKCS #11 lib. It needs to be able to extract the public-key from the smartcard, and to do that through the X.509 certificate.

In my case, I have an RSA2048 key in slot 9a and an ECCP384 key in slot 9e, each with a self-signed cert. Note that these are X.509 certificates, not OpenSSH certificates, but all that really matters is that the cert contain the right public key to match the private key in that slot.

I wonder if OpenSSH attempts to use PKCS11 but perhaps gets an error and falls back to using FIDO2, which doesn't have a requirement for this. I can try removing my certs to see if I can reproduce the issue you saw, but if you follow the steps in the link above, I think you should be able to get it to work with both OpenSSH and AsyncSSH.

You can also look at following the instructions at https://developers.yubico.com/SSH/Securing_SSH_with_FIDO2.html if you want to experiment with FIDO2. To use that with AsyncSSH, you just need to install the Python fido2 module from https://pypi.org/project/fido2. If you want to use resident keys, you can load them using the load_resident_keys() function described at https://asyncssh.readthedocs.io/en/latest/api.html#load-resident-keys. Alternately, you can keep the public key info in the filesystem as explained in the link above. By default, AsyncSSH will look for files .ssh/id_ed25519_sk and .ssh/id_ecdsa_sk containing this key information if you choose not to use resident keys, or you can specify your own list via the client_keys option.

ronf commented 1 year ago

Just tried removing the certificates here, and it looks like the PKCS11 library still worked for me even without them, so perhaps that is no longer a required step. However, that doesn't explain why you're seeing the ArgumentsBad error and I'm not.

The error suggests that somehow the set of tokens returned by calling get_tokens() in the PKCS11 library is not matching up with the set of tokens available when you call token.get_keys() later on, which shouldn't be happening.

ronf commented 1 week ago

Closing due to inactivity. Feel free to reopen this or open a new issue if you need anything else.