yubikey.rs

repository·main·Indexed 42 days ago

https://github.com/iqlusioninc/yubikey.rs

A pure Rust, cross-platform host-side driver and CLI utility for YubiKey 4 and 5 series devices. It provides support for the Personal Identity Verification (PIV) standard, enabling public-key encryption and digital signatures using algorithms such as RSA (up to 4096), ECC (P-256, P-384), and 3DES. The library communicates with hardware via the PC/SC interface. Version 0.9.0-pre.0 is currently in an experimental stage and has not undergone security audits.

Tokens
12.1K
Snippets
46
Records
67
Agent score
54%

What's inside yubikey.rs

  1. Overview of yubikey-cli.rs

    main
    yubikey-cli.rs is a pure Rust host-side CLI utility designed for interacting with YubiKeys via the Personal Identity Verification (PIV) standard. It provides support for general-purpose public-key encryption and digital signing operations.
  2. Overview of yubikey.rs

    main
    yubikey.rs is a pure Rust, cross-platform host-side driver for YubiKey devices. It provides support for public-key encryption and digital signatures using the Personal Identity Verification (PIV) application. The library uses the Personal Computer/Smart Card (PC/SC) interface via the pcsc crate to communicate with hardware.
  3. Requirements and Compatibility for yubikey-cli.rs

    main

    Minimum Rust Version

    To use this tool, you must have Rust 1.60 or newer installed.

    Supported YubiKey Hardware

    • YubiKey 4 series
    • YubiKey 5 series

    Note: Nano and USB-C variants of the 4 and 5 series are supported. The NEO series is NOT supported.

    ⚠️ Security Warning

    This crate is currently in an experimental stage and has not undergone any security audits. It may contain high-severity issues. Use this tool at your own risk.

  4. How to run tests with a YubiKey

    main

    To run the full test suite, you must have a supported YubiKey device connected in its default state (default PIN/PUK). Tests that interact with live hardware are marked as #[ignore] by default to prevent CI failures. To run them locally, use the --ignored flag.

    To see detailed logging, set the RUST_LOG environment variable. To trace raw Application Protocol Data Unit (APDU) messages sent to/from the card, use the trace level.

    # Run tests that interact with the YubiKey
    cargo test -- --ignored
    
    # Run tests with info-level logging
    RUST_LOG=info cargo test -- --ignored
    
    # Run tests with trace-level logging to see raw APDU messages
    RUST_LOG=trace cargo test -- --ignored
  5. Manage Cardholder Capability Container (CCC) IDs

    main

    The CccId and CardId types allow you to interact with the Cardholder Capability Container (CCC) on a YubiKey. The CCC contains metadata about the card's capabilities, including a specific CardId.

    Key Concepts

    • CccId: Represents the full 51-byte CCC identifier.
    • CardId: Represents the 14-byte card identifier component extracted from the CCC.

    Common Tasks

    Retrieve the CCC ID from a YubiKey

    Use CccId::get(&mut yubikey) to fetch the current CCC identifier from the device. This requires an active YubiKey instance.

    Extract the Card ID from a CCC ID

    If you have a CccId instance, you can extract the underlying 14-byte CardId using the .card_id() method.

    Generate a new random Card ID

    You can generate a new, random CardId using CardId::generate() or by providing a specific random number generator via CardId::generate_from_rng(rng).

    use crate::yubikey::YubiKey;
    use crate::cccid::{CccId, CardId};
    
    // 1. Get the CCC ID from the device
    let mut yubikey = YubiKey::open()?;
    let ccc_id = CccId::get(&mut yubikey)?;
    
    // 2. Extract the Card ID component
    let card_id = ccc_id.card_id()?;
    
    // 3. Generate a new random Card ID for future use
    let new_card_id = CardId::generate();
  6. Understand YubiKey Device Configuration and Info

    main

    The DeviceInfo and DeviceConfig structures provide a snapshot of the YubiKey's current state and capabilities.

    DeviceConfig Fields

    • usb_enabled_apps: A Capability bitflag set of apps available via USB.
    • nfc_enabled_apps: An Option<Capability> set of apps available via NFC. If None, the NFC interface is disabled.
    • auto_eject_timeout: An optional u16 value for automatic smartcard ejection.
    • challenge_response_timeout: An optional u8 value for waiting for user touch during challenge-response.
    • device_flags: An optional DeviceFlags bitflag set.

    DeviceFlags

    • REMOTE_WAKEUP: Enables remote wake-up functionality.
    • Eject: Enables automatic ejection.

    FormFactor

    Identifies the physical shape of the device (e.g., UsbAKeychain, UsbCKeychain, UsbABio, UsbCBio).

  7. Configure TouchPolicy for key generation or importation

    main

    The TouchPolicy enum specifies the conditions under which a physical touch on the YubiKey's metal contact is required, in addition to the PinPolicy. Like PinPolicy, this must be set during key generation or importation and cannot be changed later.

    Available policies:

    • Default: Uses the slot's default touch policy.
    • Never: A physical touch is NOT required for private key operations.
    • Always: A physical touch is required for every single operation to ensure cardholder participation.
    • Cached: A physical touch is required, but the touch is cached for 15 seconds. Multiple operations can be performed within this window without additional interaction.
    use yubikey::TouchPolicy;
    
    // Example usage during key setup (conceptual)
    let policy = TouchPolicy::Cached;
    // This policy is applied during the generation/importation phase.
  8. Configure PinPolicy for key generation or importation

    main

    The PinPolicy enum specifies how often a PIN must be entered to access a credential in a specific slot. This policy is immutable: it must be set at the time of key generation or importation and cannot be changed later.

    Available policies:

    • Default: Uses the slot's default PIN policy.
    • Never: The end user PIN is NOT required for private key operations.
    • Once: The PIN is required for private key operations. Once provided, multiple operations can be performed without further consent.
    • Always: The PIN must be submitted immediately before every single operation to ensure active cardholder participation.
    use yubikey::PinPolicy;
    
    // Example usage during key setup (conceptual)
    let policy = PinPolicy::Always;
    // This policy is applied during the generation/importation phase.
  9. Handle APDU Status Words (SW)

    main

    Every APDU response includes 2-byte Status Words (SW) that indicate the result of the command. You can check for success using response.is_success() or inspect the specific error type using response.status_words().

    Common status words include:

    • Success (0x9000): Command executed successfully.
    • BytesRemaining { len } (0x61xx): Data was too large for the response; more data is available.
    • VerifyFailError { tries } (0x63c0): PIN verification failed; tries indicates remaining attempts.
    • SecurityStatusError (0x6982): Security status not satisfied.
    • CommandNotAllowedError (0x6986): Command not allowed.
    • NotFoundError (0x6a82): Data object or application not found.
    • NotSupportedError (0x6d00): Command not supported.
  10. Manage enterprise trust roots with MsRoots

    main

    The MsRoots struct provides a way to manage a PKCS#7-formatted certificate store for enterprise trusted roots on a YubiKey. This is useful for interoperability with Windows smart card guidelines. The msroots file is stored as a series of objects on the YubiKey, allowing a bag of certificates to be written and read as a single logical unit.

    Key operations:

    • Read: Retrieves the existing msroots certificate store from the YubiKey.
    • Write: Saves a new msroots certificate store to the YubiKey. The data is automatically chunked across multiple YubiKey objects (up to 5 objects) using TAG_MSROOTS_MID and TAG_MSROOTS_END tags.

    Note: If the data size exceeds the capacity of 5 objects, a Error::SizeError will be returned.

    use yubikey::MsRoots;
    
    // To read existing roots
    if let Ok(Some(roots)) = MsRoots::read(&mut yubikey) {
        let bytes = roots.as_ref();
        // process bytes...
    }
    
    // To write new roots
    let new_roots = MsRoots::new(pkcs7_bytes)?;
    new_roots.write(&mut yubikey)?;
  11. Understand PIV Slot Identifiers

    main

    Personal Identity Verification (PIV) uses specific slots to store cryptographic keys and certificates. Each slot has a distinct purpose and security policy requirements:

    • SlotId::Authentication: Used for system login. Requires PIN. Once provided, multiple operations can occur without further consent.
    • SlotId::Signature: Used for digital signatures (e.g., document signing). Requires PIN for every signature operation to ensure user participation.
    • SlotId::KeyManagement: Used for encryption (e.g., email/files). Requires PIN. Once provided, multiple operations can occur without further consent.
    • SlotId::CardAuthentication: Used for physical access (e.g., door locks). PIN is not required.
    • SlotId::Attestation: (YubiKey 4.3+) Used for attesting other keys generated on-device.
    • SlotId::Retired(RetiredSlotId): Slots (R1-R20) for legacy Key Management keys (YubiKey 4 & 5).
    • SlotId::Management(ManagementSlotId): Management slots for Pin, Puk, and Management keys.
  12. APDU Response Data and Security

    main

    The Response struct contains the status words and the payload returned by the YubiKey.

    Security Note: Both Apdu and Response implement Zeroize. When these objects are dropped, the sensitive data buffers are zeroed out in memory to prevent accidental exposure of secrets.