CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-python-yubico

Python library for communicating with Yubico YubiKey hardware authentication tokens

Pending
Overview
Eval results
Files

device-interface.mddocs/

YubiKey Device Interface

Core YubiKey device operations including version detection, serial number retrieval, device status queries, and basic device communication available across all YubiKey models.

Capabilities

Device Information

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")

Device Status

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())

Challenge-Response Operations

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")

Configuration Management

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}")

Device-Specific Features

Additional features available on specific YubiKey models.

YubiKey NEO Features

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)

Device Capabilities

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

docs

challenge-response.md

configuration.md

device-discovery.md

device-interface.md

exceptions.md

index.md

utilities.md

tile.json