from ykman.device import list_all_devices
for device, info in list_all_devices():
if info.version >= (5, 0, 0): # The info object provides details about the YubiKey
print(f"Found YubiKey with serial number: {info.serial}")
In addition to using ykman as a standalone command line application, you can also use this project as a Python library for scripting purposes.
You will need to have Python >= 3.10, and have yubikey-manager installed and
added to your PYTHON_PATH. You can verify that this is set up correctly by
running the following command from a Terminal:
python -c "import ykman"
If the above runs without error (no output at all), then you should be all set.
The first step you’ll likely want to do is to list currently connected
YubiKeys, and get some information about them. This is what the
list_all_devices function is for. It detects and connects to each attached
YubiKey, reading some information about it. It returns a list of tuples
consisting of a YubiKeyDevice and a corresponding DeviceInfo. The DeviceInfo
can tell you what kind of YubiKey it is, what capabilities it has, its serial
number, etc. The YubiKeyDevice will let you open a Connection to it, which will
let you interact with one of the available Applications.
|
Note
|
|
from ykman.device import list_all_devices
for device, info in list_all_devices():
if info.version >= (5, 0, 0): # The info object provides details about the YubiKey
print(f"Found YubiKey with serial number: {info.serial}")
To actually do anything with a YubiKey you’ll need to create a Connection and
establish a session with a YubiKey Application. Depending on which Application
you intend to access, you’ll need to establish a specific type of Connection.
Once you have a reference to a YubiKeyDevice you can call the open_connection
method on it to open a Connection of a specific type. There are three different
types of Connections, used for different Applications. These are
SmartCardConnection, OtpConnection and FidoConnection. Once you are done
using a Connection, you should close it. This can be done explicitly by calling
connection.close(), or by using a with block.
from ykman.device import list_all_devices
from yubikit.core.smartcard import SmartCardConnection
from yubikit.piv import PivSession
# Select a connected YubiKeyDevice
dev, info = list_all_devices()[0]
# Connect to a YubiKey over a SmartCardConnection, which is needed for PIV.
with dev.open_connection(SmartCardConnection) as connection:
# The connection will be automatically closed after this block
piv = PivSession(connection)
attempts = piv.get_pin_attempts()
print(f"You have {attempts} PIN attempts left.")
Sometimes you’ll want to do something when a YubiKey is inserted. You can use
the scan_devices function to poll for changes to the connected YubiKeys,
without interrupting any ongoing connections. It returns a dict of PIDs
(Product Identifiers) mapped to the number of connected devices for each PID,
as well as a state parameter which will change if the configuration of
connected YubiKeys changes.
from ykman.device import list_all_devices, scan_devices
from time import sleep
handled_serials = set() # Keep track of YubiKeys we've already handled.
state = None
while True: # Run this until we stop the script with Ctrl+C
pids, new_state = scan_devices()
if new_state != state:
state = new_state # State has changed
for device, info in list_all_devices():
if info.serial not in handled_serials: # Unhandled YubiKey
print(f"Programming YubiKey with serial: {info.serial}")
... # Do something with the device here.
handled_serials.add(info.serial)
else:
sleep(1.0) # No change, sleep for 1 second.