Python library for communicating with Yubico YubiKey hardware authentication tokens
—
Core YubiKey device operations including version detection, serial number retrieval, device status queries, and basic device communication available across all YubiKey models.
Methods for retrieving basic device information and capabilities.
class YubiKey:
def version(self):
"""
Get YubiKey firmware version as string.
Returns:
str: Version string (e.g., "1.3.0", "2.3.1", "4.3.7")
"""
def version_num(self):
"""
Get YubiKey firmware version as tuple.
Available on USB HID implementations.
Returns:
tuple: Version tuple (major, minor, build)
"""
def serial(self, may_block=True):
"""
Get YubiKey serial number.
Available on YubiKey 2.2 and later. May block waiting for user touch
on some YubiKey models.
Parameters:
- may_block (bool): Allow blocking operations that may require user interaction
Returns:
int: Device serial number
Raises:
YubiKeyVersionError: If device doesn't support serial number reading
YubiKeyTimeout: If operation times out waiting for user interaction
"""Usage examples:
import yubico
yk = yubico.find_yubikey()
# Get version information
print("Version string:", yk.version())
if hasattr(yk, 'version_num'):
print("Version tuple:", yk.version_num())
# Get serial number (may require user touch)
try:
serial = yk.serial()
print("Serial number:", serial)
except yubico.yubikey_base.YubiKeyVersionError:
print("This YubiKey doesn't support serial number reading")
except yubico.yubikey_base.YubiKeyTimeout:
print("Timeout waiting for user interaction")Retrieve detailed device status information including configuration state and capabilities.
class YubiKeyUSBHID(YubiKey):
def status(self):
"""
Poll YubiKey for status information.
Returns:
YubiKeyUSBHIDStatus: Status object with device information
"""
class YubiKeyUSBHIDStatus:
def __init__(self, data):
"""
Initialize status object from raw device data.
Parameters:
- data (bytes): Raw status data from device
"""
def ykver(self):
"""
Get YubiKey firmware version as tuple.
Returns:
tuple: Version tuple (major, minor, build)
"""
def version(self):
"""
Get YubiKey firmware version as string.
Returns:
str: Version string
"""
def valid_configs(self):
"""
Get list of configuration slots that have valid configurations.
Returns:
list: List of slot numbers with valid configurations
"""Status usage example:
import yubico
yk = yubico.find_yubikey()
status = yk.status()
print("Firmware version:", status.version())
print("Version tuple:", status.ykver())
print("Valid config slots:", status.valid_configs())Perform challenge-response authentication using HMAC-SHA1 or Yubico protocols.
def challenge_response(challenge, mode='HMAC', slot=1, variable=True, may_block=True):
"""
Issue challenge to YubiKey and return response.
Available on YubiKey 2.2 and later for challenge-response configurations.
Parameters:
- challenge (bytes): Challenge data (up to 64 bytes for HMAC, 6 bytes for OTP)
- mode (str): Challenge mode - 'HMAC' for HMAC-SHA1 or 'OTP' for Yubico
- slot (int): Configuration slot number (1 or 2)
- variable (bool): Variable length response (HMAC mode only)
- may_block (bool): Allow operations that may require user interaction
Returns:
bytes: Response data (20 bytes for HMAC, 16 bytes for OTP)
Raises:
YubiKeyVersionError: If device doesn't support challenge-response
YubiKeyTimeout: If operation times out
InputError: If challenge data is invalid
"""Challenge-response usage example:
import yubico
import binascii
yk = yubico.find_yubikey()
# HMAC-SHA1 challenge-response
challenge = b"test challenge data"
try:
response = yk.challenge_response(challenge, mode='HMAC', slot=1)
print("HMAC response:", binascii.hexlify(response).decode())
except yubico.yubikey_base.YubiKeyVersionError:
print("Device doesn't support challenge-response")
# Yubico OTP challenge-response (6-byte challenge)
otp_challenge = b"123456"
try:
otp_response = yk.challenge_response(otp_challenge, mode='OTP', slot=2)
print("OTP response:", binascii.hexlify(otp_response).decode())
except yubico.yubikey_base.YubiKeyVersionError:
print("OTP challenge-response not configured")Write configuration objects to YubiKey slots.
def write_config(cfg, slot):
"""
Write configuration to YubiKey slot.
Parameters:
- cfg (YubiKeyConfig): Configuration object to write
- slot (int): Target configuration slot (1 or 2, or use SLOT constants)
Raises:
YubiKeyError: If configuration write fails
YubiKeyVersionError: If device doesn't support the configuration
"""
def init_config(self, **kwargs):
"""
Initialize configuration object for this YubiKey type.
Parameters:
- **kwargs: Configuration parameters passed to YubiKeyConfig constructor
Returns:
YubiKeyConfig: Configuration object compatible with this device
"""Configuration usage example:
import yubico
from yubico.yubikey_config import YubiKeyConfig
yk = yubico.find_yubikey()
# Create and write configuration
cfg = yk.init_config()
cfg.mode_challenge_response(
secret=b"0123456789abcdef0123456789abcdef",
type='HMAC',
variable=True
)
try:
yk.write_config(cfg, slot=1)
print("Configuration written successfully")
except yubico.yubikey_base.YubiKeyError as e:
print(f"Configuration failed: {e.reason}")Additional features available on specific YubiKey models.
class YubiKeyNEO_USBHID(YubiKeyUSBHID):
def write_ndef(self, ndef, slot=1):
"""
Write NDEF tag configuration to YubiKey NEO.
Parameters:
- ndef (YubiKeyNEO_NDEF): NDEF configuration object
- slot (int): Configuration slot
"""
def write_device_config(self, device_config):
"""
Write device configuration to YubiKey NEO.
Parameters:
- device_config (YubiKeyNEO_DEVICE_CONFIG): Device configuration object
"""
def write_scan_map(self, scanmap=None):
"""
Write scancode map to YubiKey NEO.
Parameters:
- scanmap (YubiKeyNEO_SCAN_MAP): Scancode map configuration
"""NEO-specific usage example:
import yubico
from yubico.yubikey_neo_usb_hid import YubiKeyNEO_NDEF, YubiKeyNEO_DEVICE_CONFIG
yk = yubico.find_yubikey()
# Check if this is a NEO device
if isinstance(yk, yubico.yubikey_neo_usb_hid.YubiKeyNEO_USBHID):
# Configure NDEF tag
ndef = YubiKeyNEO_NDEF("https://example.com/auth")
ndef.type(url=True)
yk.write_ndef(ndef)
# Configure device settings
device_config = YubiKeyNEO_DEVICE_CONFIG()
device_config.cr_timeout(60) # 60 second timeout
yk.write_device_config(device_config)Query device capabilities to determine supported features.
class YubiKeyCapabilities:
def have_yubico_OTP(self):
"""Check if device supports Yubico OTP mode."""
def have_OATH(self, mode):
"""Check if device supports OATH mode."""
def have_challenge_response(self, mode):
"""Check if device supports challenge-response mode."""
def have_serial_number(self):
"""Check if device supports serial number reading."""
def have_ticket_flag(self, flag):
"""Check if device supports specific ticket flag."""
def have_config_flag(self, flag):
"""Check if device supports specific config flag."""
def have_extended_flag(self, flag):
"""Check if device supports specific extended flag."""Capabilities usage example:
import yubico
yk = yubico.find_yubikey()
caps = yk.capabilities if hasattr(yk, 'capabilities') else None
if caps:
if caps.have_challenge_response('HMAC'):
print("Device supports HMAC challenge-response")
if caps.have_serial_number():
print("Device supports serial number reading")
if caps.have_OATH('HOTP'):
print("Device supports OATH-HOTP")Install with Tessl CLI
npx tessl i tessl/pypi-python-yubico