From 589ca3de1255edfb57bed0fa2d0ae5b051b243b6 Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Mon, 2 Dec 2019 09:32:42 -0800 Subject: [PATCH 1/8] readers: Initial `Readers` enumerator for detecting YubiKeys Adds a `yubikey_piv::Readers` type which opens a PC/SC context and can enumerate detected PC/SC readers with a slightly more ergonomic API than what's provided in the upstream crate. Does not support actually instantiating a `YubiKey` from a `Reader<'_>` yet, but ideally all connections to YubiKeys should go through this API. --- src/lib.rs | 3 +- src/readers.rs | 83 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 85 insertions(+), 1 deletion(-) create mode 100644 src/readers.rs diff --git a/src/lib.rs b/src/lib.rs index 37fd0c2..35f2a22 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -156,6 +156,7 @@ mod metadata; pub mod mgm; #[cfg(feature = "untested")] pub mod msroots; +pub mod readers; #[cfg(feature = "untested")] mod serialization; #[cfg(feature = "untested")] @@ -164,7 +165,7 @@ mod transaction; pub mod yubikey; #[cfg(feature = "untested")] -pub use self::{key::Key, mgm::MgmKey}; +pub use self::{key::Key, mgm::MgmKey, readers::Readers}; pub use yubikey::YubiKey; /// Object identifiers diff --git a/src/readers.rs b/src/readers.rs new file mode 100644 index 0000000..b3391d3 --- /dev/null +++ b/src/readers.rs @@ -0,0 +1,83 @@ +//! Support for enumerating available readers + +use crate::error::Error; +use std::{ + borrow::Cow, + ffi::CStr, + sync::{Arc, Mutex}, +}; + +/// Iterator over connected readers +pub type Iter<'ctx> = std::vec::IntoIter>; + +/// Enumeration support for available readers +pub struct Readers { + /// PC/SC context + ctx: Arc>, + + /// Buffer for storing reader names + reader_names: Vec, +} + +impl Readers { + /// Open a PC/SC context + pub fn open() -> Result { + let ctx = pcsc::Context::establish(pcsc::Scope::System)?; + let reader_names = vec![0u8; ctx.list_readers_len()?]; + Ok(Self { + ctx: Arc::new(Mutex::new(ctx)), + reader_names, + }) + } + + /// Iterate over the available readers + pub fn iter(&mut self) -> Result, Error> { + let Self { ctx, reader_names } = self; + + let reader_cstrs: Vec<_> = { + let c = ctx.lock().unwrap(); + + // ensure PC/SC context is valid + c.is_valid()?; + + c.list_readers(reader_names)?.collect() + }; + + let readers: Vec<_> = reader_cstrs + .iter() + .map(|name| Reader::new(name, Arc::clone(ctx))) + .collect(); + + Ok(readers.into_iter()) + } +} + +/// An individual connected reader +pub struct Reader<'ctx> { + /// Name of this reader + name: &'ctx CStr, + + /// PC/SC context + ctx: Arc>, +} + +impl<'ctx> Reader<'ctx> { + /// Create a new reader from its name and context + fn new(name: &'ctx CStr, ctx: Arc>) -> Self { + // TODO(tarcieri): open devices, determine they're YubiKeys, get serial? + Self { name, ctx } + } + + /// Get this reader's name + pub fn name(&self) -> Cow<'_, str> { + // TODO(tarcieri): is lossy ok here? try to avoid lossiness? + self.name.to_string_lossy() + } + + /// Open the given reader + // TODO(tarcieri): return a `YubiKey` here rather than a `pcsc::Card` + pub fn open(&self) -> Result { + let ctx = self.ctx.lock().unwrap(); + Ok(ctx.connect(self.name, pcsc::ShareMode::Shared, pcsc::Protocols::T1)?) + } +} From 9ce2ffe9385a65c75e354344f993cd9d5636393d Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Mon, 2 Dec 2019 10:05:17 -0800 Subject: [PATCH 2/8] readers: Use `Reader` to connect to `YubiKey` Removes the legacy API inherited from `yubico-piv-tool` and uses the `reader` module exclusively for selecting and opening the PC/SC reader. --- src/readers.rs | 16 ++-- src/yubikey.rs | 172 +++++++++++++++++++++---------------------- tests/integration.rs | 2 +- 3 files changed, 96 insertions(+), 94 deletions(-) diff --git a/src/readers.rs b/src/readers.rs index b3391d3..b505187 100644 --- a/src/readers.rs +++ b/src/readers.rs @@ -1,8 +1,9 @@ //! Support for enumerating available readers -use crate::error::Error; +use crate::{error::Error, yubikey::YubiKey}; use std::{ borrow::Cow, + convert::TryInto, ffi::CStr, sync::{Arc, Mutex}, }; @@ -20,7 +21,8 @@ pub struct Readers { } impl Readers { - /// Open a PC/SC context + /// Open a PC/SC context, which can be used to enumerate available PC/SC + /// readers (which can be used to connect to YubiKeys). pub fn open() -> Result { let ctx = pcsc::Context::establish(pcsc::Scope::System)?; let reader_names = vec![0u8; ctx.list_readers_len()?]; @@ -74,9 +76,13 @@ impl<'ctx> Reader<'ctx> { self.name.to_string_lossy() } - /// Open the given reader - // TODO(tarcieri): return a `YubiKey` here rather than a `pcsc::Card` - pub fn open(&self) -> Result { + /// Open a connection to this reader, returning a `YubiKey` if successful + pub fn open(&self) -> Result { + self.try_into() + } + + /// Connect to this reader, returning its `pcsc::Card` + pub(crate) fn connect(&self) -> Result { let ctx = self.ctx.lock().unwrap(); Ok(ctx.connect(self.name, pcsc::ShareMode::Shared, pcsc::Protocols::T1)?) } diff --git a/src/yubikey.rs b/src/yubikey.rs index 707e9ca..7bb8db4 100644 --- a/src/yubikey.rs +++ b/src/yubikey.rs @@ -42,14 +42,22 @@ use crate::{ serialization::*, Buffer, ObjectId, }; -use crate::{consts::*, error::Error, transaction::Transaction}; +use crate::{ + consts::*, + error::Error, + readers::{Reader, Readers}, + transaction::Transaction, +}; #[cfg(feature = "untested")] use getrandom::getrandom; use log::{error, info, warn}; -use pcsc::{Card, Context}; +use pcsc::Card; #[cfg(feature = "untested")] use secrecy::ExposeSecret; -use std::fmt::{self, Display}; +use std::{ + convert::TryFrom, + fmt::{self, Display}, +}; #[cfg(feature = "untested")] use std::{ convert::TryInto, @@ -130,96 +138,28 @@ pub struct YubiKey { } impl YubiKey { - /// Open a connection to a YubiKey, optionally giving the name - /// (needed if e.g. there are multiple YubiKeys connected). - pub fn open(name: Option<&[u8]>) -> Result { - let context = Context::establish(pcsc::Scope::System)?; - let mut card = Self::connect(&context, name)?; + /// Open a connection to a YubiKey. + /// + /// Returns an error if there is more than one YubiKey detected. + /// + /// If you need to operate in environments with more than one YubiKey + /// attached to the same system, use [`yubikey_piv::Readers`] to select + /// from the available PC/SC readers connected. + pub fn open() -> Result { + let mut readers = Readers::open()?; + let mut reader_iter = readers.iter()?; - let mut is_neo = false; - let version: Version; - let serial: Serial; - - { - let txn = Transaction::new(&mut card)?; - let mut atr_buf = [0; CB_ATR_MAX]; - let atr = txn.get_attribute(pcsc::Attribute::AtrString, &mut atr_buf)?; - if atr == YKPIV_ATR_NEO_R3 { - is_neo = true; + if let Some(reader) = reader_iter.next() { + if reader_iter.next().is_some() { + error!("multiple YubiKeys detected!"); + return Err(Error::PcscError { inner: None }); } - txn.select_application()?; - - // now that the PIV application is selected, retrieve the version - // and serial number. Previously the NEO/YK4 required switching - // to the yk applet to retrieve the serial, YK5 implements this - // as a PIV applet command. Unfortunately, this change requires - // that we retrieve the version number first, so that get_serial - // can determine how to get the serial number, which for the NEO/Yk4 - // will result in another selection of the PIV applet. - - version = txn.get_version().map_err(|e| { - warn!("failed to retrieve version: '{}'", e); - e - })?; - - serial = txn.get_serial(version).map_err(|e| { - warn!("failed to retrieve serial number: '{}'", e); - e - })?; + return reader.open(); } - let yubikey = YubiKey { - card, - pin: None, - is_neo, - version, - serial, - }; - - Ok(yubikey) - } - - /// Connect to a YubiKey PC/SC card. - fn connect(context: &Context, name: Option<&[u8]>) -> Result { - // ensure PC/SC context is valid - context.is_valid()?; - - let buffer_len = context.list_readers_len()?; - let mut buffer = vec![0u8; buffer_len]; - - for reader in context.list_readers(&mut buffer)? { - if let Some(wanted) = name { - if reader.to_bytes() != wanted { - warn!( - "skipping reader '{}' since it doesn't match '{}'", - reader.to_string_lossy(), - String::from_utf8_lossy(wanted) - ); - - continue; - } - } - - info!("trying to connect to reader '{}'", reader.to_string_lossy()); - - match context.connect(reader, pcsc::ShareMode::Shared, pcsc::Protocols::T1) { - Ok(card) => { - info!("connected to '{}' successfully", reader.to_string_lossy()); - return Ok(card); - } - Err(err) => { - error!( - "skipping '{}' due to connection error: {}", - reader.to_string_lossy(), - err - ); - } - } - } - - error!("error: no usable reader found"); - Err(Error::PcscError { inner: None }) + error!("no YubiKey detected!"); + Err(Error::GenericError) } /// Reconnect to a YubiKey @@ -818,3 +758,59 @@ impl YubiKey { } } } + +impl<'a> TryFrom<&'a Reader<'_>> for YubiKey { + type Error = Error; + + fn try_from(reader: &'a Reader<'_>) -> Result { + let mut card = reader.connect().map_err(|e| { + error!("error connecting to reader '{}': {}", reader.name(), e); + e + })?; + + info!("connected to reader: {}", reader.name()); + + let mut is_neo = false; + let version: Version; + let serial: Serial; + + { + let txn = Transaction::new(&mut card)?; + let mut atr_buf = [0; CB_ATR_MAX]; + let atr = txn.get_attribute(pcsc::Attribute::AtrString, &mut atr_buf)?; + if atr == YKPIV_ATR_NEO_R3 { + is_neo = true; + } + + txn.select_application()?; + + // now that the PIV application is selected, retrieve the version + // and serial number. Previously the NEO/YK4 required switching + // to the yk applet to retrieve the serial, YK5 implements this + // as a PIV applet command. Unfortunately, this change requires + // that we retrieve the version number first, so that get_serial + // can determine how to get the serial number, which for the NEO/Yk4 + // will result in another selection of the PIV applet. + + version = txn.get_version().map_err(|e| { + warn!("failed to retrieve version: '{}'", e); + e + })?; + + serial = txn.get_serial(version).map_err(|e| { + warn!("failed to retrieve serial number: '{}'", e); + e + })?; + } + + let yubikey = YubiKey { + card, + pin: None, + is_neo, + version, + serial, + }; + + Ok(yubikey) + } +} diff --git a/tests/integration.rs b/tests/integration.rs index b3ef4c5..968b5f8 100644 --- a/tests/integration.rs +++ b/tests/integration.rs @@ -14,7 +14,7 @@ fn connect() { env_logger::builder().format_timestamp(None).init(); } - let mut yubikey = YubiKey::open(None).unwrap(); + let mut yubikey = YubiKey::open().unwrap(); dbg!(&yubikey.version()); dbg!(&yubikey.serial()); } From 07f70bccb58ec7f8bd892fa058df8bf1dc5a8eef Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Mon, 2 Dec 2019 10:42:17 -0800 Subject: [PATCH 3/8] cli: Initial `yubikey-cli` utility with `list` command Adds a `yubikey-cli` crate to the workspace, with a `yubikey` binary, which presently provides a `list` command for listing detected readers. Dependencies: - `env_logger`: logging - `gumdrop`: argument parsing - `termcolor`: colored terminal output As this repo now contains a binary, it also checks in `Cargo.lock`. --- .github/workflows/rust.yml | 10 +- .gitignore | 1 - Cargo.lock | 1000 +++++++++++++++++++++++++++++++++++ Cargo.toml | 5 +- cli/Cargo.toml | 21 + cli/README.md | 112 ++++ cli/src/bin/yubikey/main.rs | 16 + cli/src/commands.rs | 98 ++++ cli/src/commands/list.rs | 40 ++ cli/src/lib.rs | 14 + cli/src/status.rs | 165 ++++++ src/lib.rs | 5 +- 12 files changed, 1478 insertions(+), 9 deletions(-) create mode 100644 Cargo.lock create mode 100644 cli/Cargo.toml create mode 100644 cli/README.md create mode 100644 cli/src/bin/yubikey/main.rs create mode 100644 cli/src/commands.rs create mode 100644 cli/src/commands/list.rs create mode 100644 cli/src/lib.rs create mode 100644 cli/src/status.rs diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 7e76767..e48b8c8 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -57,7 +57,7 @@ jobs: RUSTFLAGS: -D warnings with: command: test - args: --release + args: --all --release - name: Run cargo build --all-features uses: actions-rs/cargo@v1 @@ -65,7 +65,7 @@ jobs: RUSTFLAGS: -D warnings with: command: build - args: --all-features + args: --all --all-features test: name: Test Suite @@ -94,7 +94,7 @@ jobs: RUSTFLAGS: -D warnings with: command: test - args: --release + args: --all --release - name: Run cargo build --all-features uses: actions-rs/cargo@v1 @@ -102,7 +102,7 @@ jobs: RUSTFLAGS: -D warnings with: command: build - args: --all-features + args: --all --all-features fmt: name: Rustfmt @@ -149,7 +149,7 @@ jobs: uses: actions-rs/cargo@v1 with: command: clippy - args: --all-features -- -D warnings + args: --all --all-features -- -D warnings # TODO: use actions-rs/audit-check security_audit: diff --git a/.gitignore b/.gitignore index 6936990..53eaa21 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,2 @@ /target **/*.rs.bk -Cargo.lock diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..fec476c --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,1000 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "aho-corasick" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "arrayvec" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "nodrop 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "atty" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "autocfg" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "backtrace" +version = "0.3.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "backtrace-sys 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "backtrace-sys" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cc 1.0.47 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "base64" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "safemem 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "base64" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "bitflags" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "block-buffer" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "block-padding 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "block-cipher-trait" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "block-padding" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "byte-tools" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "byteorder" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "cc" +version = "1.0.47" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "cloudabi" +version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "crypto-mac" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", + "subtle 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "der-parser" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "nom 5.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "num-bigint 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "rusticata-macros 2.0.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "des" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "block-cipher-trait 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "digest" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "ecdsa" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", + "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "signature 1.0.0-pre.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "env_logger" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", + "humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "failure" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "backtrace 0.3.40 (registry+https://github.com/rust-lang/crates.io-index)", + "failure_derive 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "failure_derive" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)", + "synstructure 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "fake-simd" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "fuchsia-cprng" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "generic-array" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "typenum 1.11.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "getrandom" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "wasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "gumdrop" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "gumdrop_derive 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "gumdrop_derive" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "hmac" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crypto-mac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "humantime" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "spin 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "lexical-core" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "arrayvec 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "static_assertions 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "libc" +version = "0.2.66" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "libm" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "log" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "maybe-uninit" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "memchr" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "nodrop" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "nom" +version = "5.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "lexical-core 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "num-bigint" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "num-bigint-dig" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libm 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", + "num-iter 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", + "zeroize 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "num-integer" +version = "0.1.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "num-iter" +version = "0.1.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "num-traits" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "opaque-debug" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "pbkdf2" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "crypto-mac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "hmac 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", + "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "subtle 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "pcsc" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "pcsc-sys 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "pcsc-sys" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "pkg-config 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "pkg-config" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "proc-macro2" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "quick-error" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "quote" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_jitter 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_chacha" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_core" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_core" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "rand_hc" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_isaac" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_jitter" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_os" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_pcg" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_xorshift" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rdrand" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "redox_syscall" +version = "0.1.56" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "regex" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", + "thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "regex-syntax" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "rsa" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "num-bigint-dig 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", + "num-iter 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "subtle 2.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "zeroize 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "rustc_version" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rusticata-macros" +version = "2.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "nom 5.0.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "ryu" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "safemem" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "secrecy" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "zeroize 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "semver" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "semver-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "serde" +version = "1.0.103" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "sha-1" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", + "digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", + "fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "sha2" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", + "digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", + "fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "signature" +version = "1.0.0-pre.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "smallvec" +version = "0.6.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "static_assertions" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "subtle" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "subtle" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "syn" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "synstructure" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "termcolor" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "wincolor 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "thread_local" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "time" +version = "0.1.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "typenum" +version = "1.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "unicode-xid" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "version_check" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "wasi" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi-util" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "wincolor" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "x509-parser" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", + "der-parser 3.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "nom 5.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "num-bigint 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "rusticata-macros 2.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "yubikey-cli" +version = "0.0.0" +dependencies = [ + "env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "gumdrop 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "yubikey-piv 0.0.2", +] + +[[package]] +name = "yubikey-piv" +version = "0.0.2" +dependencies = [ + "der-parser 3.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "des 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ecdsa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", + "hmac 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "nom 5.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "pbkdf2 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "pcsc 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rsa 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "secrecy 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "sha-1 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", + "subtle 2.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "x509-parser 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "zeroize 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "zeroize" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "zeroize_derive 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "zeroize" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "zeroize_derive" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)", + "synstructure 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[metadata] +"checksum aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "58fb5e95d83b38284460a5fda7d6470aa0b8844d283a0b614b8535e880800d2d" +"checksum arrayvec 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "cd9fd44efafa8690358b7408d253adf110036b88f55672a933f01d616ad9b1b9" +"checksum atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "1803c647a3ec87095e7ae7acfca019e98de5ec9a7d01343f611cf3152ed71a90" +"checksum autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2" +"checksum backtrace 0.3.40 (registry+https://github.com/rust-lang/crates.io-index)" = "924c76597f0d9ca25d762c25a4d369d51267536465dc5064bdf0eb073ed477ea" +"checksum backtrace-sys 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)" = "5d6575f128516de27e3ce99689419835fce9643a9b215a14d2b5b685be018491" +"checksum base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e" +"checksum base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "489d6c0ed21b11d038c31b6ceccca973e65d73ba3bd8ecb9a2babf5546164643" +"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" +"checksum block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" +"checksum block-cipher-trait 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1c924d49bd09e7c06003acda26cd9742e796e34282ec6c1189404dee0c1f4774" +"checksum block-padding 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5" +"checksum byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" +"checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" +"checksum cc 1.0.47 (registry+https://github.com/rust-lang/crates.io-index)" = "aa87058dce70a3ff5621797f1506cb837edd02ac4c0ae642b4542dce802908b8" +"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" +"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" +"checksum crypto-mac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4434400df11d95d556bac068ddfedd482915eb18fe8bea89bc80b6e4b1c179e5" +"checksum der-parser 3.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "537a7d6becb8c3cae3bab31439c248a12d43267ccc0b1a0333362b7cefb61c3e" +"checksum des 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "74ba5f1b5aee9772379c2670ba81306e65a93c0ee3caade7a1d22b188d88a3af" +"checksum digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" +"checksum ecdsa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e1dd187cba85a8c826912572f4f76045d2e613b42e08a4c2896eefe1adf3f347" +"checksum env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" +"checksum failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "f8273f13c977665c5db7eb2b99ae520952fe5ac831ae4cd09d80c4c7042b5ed9" +"checksum failure_derive 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0bc225b78e0391e4b8683440bf2e63c2deeeb2ce5189eab46e2b68c6d3725d08" +"checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" +"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" +"checksum generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec" +"checksum getrandom 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "e7db7ca94ed4cd01190ceee0d8a8052f08a247aa1b469a7f68c6a3b71afcf407" +"checksum gumdrop 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee50908bc1beeac1f2902e0b4e0cd0d844e716f5ebdc6f0cfc1163fe5e10bcde" +"checksum gumdrop_derive 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "90454ce4de40b7ca6a8968b5ef367bdab48413962588d0d2b1638d60090c35d7" +"checksum hmac 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5dcb5e64cda4c23119ab41ba960d1e170a774c8e4b9d9e6a9bc18aabf5e59695" +"checksum humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" +"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +"checksum lexical-core 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2304bccb228c4b020f3a4835d247df0a02a7c4686098d4167762cfbbe4c5cb14" +"checksum libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)" = "d515b1f41455adea1313a4a2ac8a8a477634fbae63cc6100e3aebb207ce61558" +"checksum libm 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7fc7aa29613bd6a620df431842069224d8bc9011086b1db4c0e0cd47fa03ec9a" +"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" +"checksum maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" +"checksum memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88579771288728879b57485cc7d6b07d648c9f0141eb955f8ab7f9d45394468e" +"checksum nodrop 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" +"checksum nom 5.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c618b63422da4401283884e6668d39f819a106ef51f5f59b81add00075da35ca" +"checksum num-bigint 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f9c3f34cdd24f334cb265d9bf8bfa8a241920d026916785747a92f0e55541a1a" +"checksum num-bigint-dig 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7e8552a8edd6289764deab155204f86ccf3b0027e10f960a55d5a53deaf6688c" +"checksum num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "b85e541ef8255f6cf42bbfe4ef361305c6c135d10919ecc26126c4e5ae94bc09" +"checksum num-iter 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "76bd5272412d173d6bf9afdf98db8612bbabc9a7a830b7bfc9c188911716132e" +"checksum num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c81ffc11c212fa327657cb19dd85eb7419e163b5b076bede2bdb5c974c07e4" +"checksum opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" +"checksum pbkdf2 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "006c038a43a45995a9670da19e67600114740e8511d4333bf97a56e66a7542d9" +"checksum pcsc 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c952b5541ee39565ab528ca468650af33aaa0cae6d4809e8e86220a926b4cad9" +"checksum pcsc-sys 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e1b7bfecba2c0f1b5efb0e7caf7533ab1c295024165bcbb066231f60d33e23ea" +"checksum pkg-config 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)" = "05da548ad6865900e60eaba7f589cc0783590a92e940c26953ff81ddbab2d677" +"checksum proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9c9e470a8dc4aeae2dee2f335e8f533e2d4b347e1434e5671afc49b054592f27" +"checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0" +"checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" +"checksum rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c618c47cd3ebd209790115ab837de41425723956ad3ce2e6a7f09890947cacb9" +"checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" +"checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" +"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" +"checksum rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" +"checksum rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" +"checksum rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" +"checksum rand_jitter 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b" +"checksum rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" +"checksum rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" +"checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" +"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" +"checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" +"checksum regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dc220bd33bdce8f093101afe22a037b8eb0e5af33592e6a9caafff0d4cb81cbd" +"checksum regex-syntax 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "11a7e20d1cce64ef2fed88b66d347f88bd9babb82845b2b858f3edbf59a4f716" +"checksum rsa 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "5108a8bbfb84fe77d829d77d5a89255dcd189dfe5c4de5a33d0a47f12808bb15" +"checksum rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783" +"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +"checksum rusticata-macros 2.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1a2fec406dbe9a6def54a66dadbfa387c7f60e903691b208160d5e9c4586dff9" +"checksum ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bfa8506c1de11c9c4e4c38863ccbe02a305c8188e85a05a784c9e11e1c3910c8" +"checksum safemem 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072" +"checksum secrecy 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "30e17355cc3cbc217e0bad1a71b38c60ed9ee34bbc3ede7ffb1c4af20f0a14c9" +"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" +"checksum serde 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)" = "1217f97ab8e8904b57dd22eb61cde455fa7446a9c1cf43966066da047c1f3702" +"checksum sha-1 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "23962131a91661d643c98940b20fcaffe62d776a823247be80a48fcb8b6fce68" +"checksum sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b4d8bfd0e469f417657573d8451fb33d16cfe0989359b93baf3a1ffc639543d" +"checksum signature 1.0.0-pre.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a0cfcdc45066661979294e965c21b60355da35eb5d638af8143e5aa83fdfce53" +"checksum smallvec 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "f7b0758c52e15a8b5e3691eae6cc559f08eee9406e548a4477ba4e67770a82b6" +"checksum spin 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" +"checksum static_assertions 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7f3eb36b47e512f8f1c9e3d10c2c1965bc992bd9cdb024fa581e2194501c83d3" +"checksum subtle 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2d67a5a62ba6e01cb2192ff309324cb4875d0c451d55fe2319433abe7a05a8ee" +"checksum subtle 2.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7c65d530b10ccaeac294f349038a597e435b18fb456aadd0840a623f83b9e941" +"checksum syn 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)" = "dff0acdb207ae2fe6d5976617f887eb1e35a2ba52c13c7234c790960cdad9238" +"checksum synstructure 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "67656ea1dc1b41b1451851562ea232ec2e5a80242139f7e679ceccfb5d61f545" +"checksum termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "96d6098003bde162e4277c70665bd87c326f5a0c3f3fbfb285787fa482d54e6e" +"checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" +"checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" +"checksum typenum 1.11.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6d2783fe2d6b8c1101136184eb41be8b1ad379e4657050b8aaff0c79ee7575f9" +"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" +"checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" +"checksum wasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b89c3ce4ce14bdc6fb6beaf9ec7928ca331de5df7e5ea278375642a2f478570d" +"checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" +"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +"checksum winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7168bab6e1daee33b4557efd0e95d5ca70a03706d39fa5f3fe7a236f584b03c9" +"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +"checksum wincolor 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "96f5016b18804d24db43cebf3c77269e7569b8954a8464501c216cc5e070eaa9" +"checksum x509-parser 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9b86b92815858495482b74dab17c0b2b2399f7582b6e7ca621b87aebf8fd00e9" +"checksum zeroize 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4090487fa66630f7b166fba2bbb525e247a5449f41c468cc1d98f8ae6ac03120" +"checksum zeroize 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cdc979d9b5ead18184c357c4d8a3f81b579aae264e32507223032e64715462d3" +"checksum zeroize_derive 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc9ce59c69fc43078c6f4250b0c866bb06b9ff7ac955c7ddb82a8c189281dcae" diff --git a/Cargo.toml b/Cargo.toml index b4ded39..67e6dc6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,7 +13,10 @@ license = "BSD-2-Clause" repository = "https://github.com/iqlusioninc/yubikey-piv.rs" readme = "README.md" categories = ["api-bindings", "cryptography", "hardware-support"] -keywords = ["ccid", "ecdsa", "rsa", "piv", "yubikey"] +keywords = ["ecdsa", "rsa", "piv", "pcsc", "yubikey"] + +[workspace] +members = [".", "cli"] [badges] maintenance = { status = "experimental" } diff --git a/cli/Cargo.toml b/cli/Cargo.toml new file mode 100644 index 0000000..612a85f --- /dev/null +++ b/cli/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "yubikey-cli" +version = "0.0.0" +description = """ +Command-line interface for performing encryption and signing using RSA and/or +ECC keys stored on YubiKey devices. +""" +authors = ["Tony Arcieri "] +edition = "2018" +license = "BSD-2-Clause" +repository = "https://github.com/iqlusioninc/yubikey-piv.rs" +readme = "README.md" +categories = ["command-line-utilities", "cryptography", "hardware-support"] +keywords = ["ecdsa", "rsa", "piv", "pcsc", "yubikey"] + +[dependencies] +gumdrop = "0.7" +env_logger = "0.7" +lazy_static = "1" +termcolor = "1" +yubikey-piv = { version = "0.0.2", path = ".." } diff --git a/cli/README.md b/cli/README.md new file mode 100644 index 0000000..b359d92 --- /dev/null +++ b/cli/README.md @@ -0,0 +1,112 @@ + + +# yubikey-cli.rs + +[![crate][crate-image]][crate-link] +[![Docs][docs-image]][docs-link] +![Apache2/MIT licensed][license-image] +![Rust Version][rustc-image] +![Maintenance Status: Experimental][maintenance-image] +[![Safety Dance][safety-image]][safety-link] +[![Build Status][build-image]][build-link] +[![Gitter Chat][gitter-image]][gitter-link] + +Pure Rust host-side YubiKey [Personal Identity Verification (PIV)][PIV] CLI +utility with general-purpose public-key encryption and signing support. + +[Documentation][docs-link] + +## Minimum Supported Rust Version + +- Rust **1.39+** + +## Supported YubiKeys + +- [YubiKey NEO] series (may be dropped in the future, see [#18]) +- [YubiKey 4] series +- [YubiKey 5] series + +NOTE: Nano and USB-C variants of the above are also supported + +## Security Warning + +No security audits of this crate have ever been performed. Presently it is in +an experimental stage and may still contain high-severity issues. + +USE AT YOUR OWN RISK! + +## Status + +WIP. Check back later. + +## Code of Conduct + +We abide by the [Contributor Covenant][cc-md] and ask that you do as well. + +For more information, please see [CODE_OF_CONDUCT.md][cc-md]. + +## License + +Copyright (c) 2014-2019 Yubico AB, Tony Arcieri +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +* Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally +submitted for inclusion in the work by you shall be licensed under the +[2-Clause BSD License][BSDL] as shown above, without any additional terms +or conditions. + +[//]: # (badges) + +[crate-image]: https://img.shields.io/crates/v/yubikey-cli.svg +[crate-link]: https://crates.io/crates/yubikey-cli +[docs-image]: https://docs.rs/yubikey-cli/badge.svg +[docs-link]: https://docs.rs/yubikey-cli/ +[license-image]: https://img.shields.io/badge/license-BSD-blue.svg +[rustc-image]: https://img.shields.io/badge/rustc-1.39+-blue.svg +[maintenance-image]: https://img.shields.io/badge/maintenance-experimental-blue.svg +[safety-image]: https://img.shields.io/badge/unsafe-forbidden-success.svg +[safety-link]: https://github.com/rust-secure-code/safety-dance/ +[build-image]: https://github.com/iqlusioninc/yubikey-cli.rs/workflows/Rust/badge.svg?branch=develop&event=push +[build-link]: https://github.com/iqlusioninc/yubikey-cli.rs/actions +[gitter-image]: https://badges.gitter.im/badge.svg +[gitter-link]: https://gitter.im/iqlusioninc/community + +[//]: # (general links) + +[PIV]: https://piv.idmanagement.gov/ +[yk-guide]: https://developers.yubico.com/PIV/Introduction/YubiKey_and_PIV.html +[Yubico]: https://www.yubico.com/ +[YubiKey NEO]: https://support.yubico.com/support/solutions/articles/15000006494-yubikey-neo +[YubiKey 4]: https://support.yubico.com/support/solutions/articles/15000006486-yubikey-4 +[YubiKey 5]: https://www.yubico.com/products/yubikey-5-overview/ +[yubico-piv-tool]: https://github.com/Yubico/yubico-piv-tool/ +[Corrode]: https://github.com/jameysharp/corrode +[cc-web]: https://contributor-covenant.org/ +[cc-md]: https://github.com/iqlusioninc/yubikey-cli.rs/blob/develop/CODE_OF_CONDUCT.md +[BSDL]: https://opensource.org/licenses/BSD-2-Clause diff --git a/cli/src/bin/yubikey/main.rs b/cli/src/bin/yubikey/main.rs new file mode 100644 index 0000000..80db9c8 --- /dev/null +++ b/cli/src/bin/yubikey/main.rs @@ -0,0 +1,16 @@ +//! `yubikey` command-line utility + +#![forbid(unsafe_code)] +#![warn( + missing_docs, + rust_2018_idioms, + unused_lifetimes, + unused_qualifications +)] + +use gumdrop::Options; +use yubikey_cli::commands::YubikeyCli; + +fn main() { + YubikeyCli::parse_args_default_or_exit().run(); +} diff --git a/cli/src/commands.rs b/cli/src/commands.rs new file mode 100644 index 0000000..02124df --- /dev/null +++ b/cli/src/commands.rs @@ -0,0 +1,98 @@ +//! Commands of the CLI application + +pub mod list; + +use self::list::ListCmd; +use crate::status; +use gumdrop::Options; +use std::env; +use std::process::exit; +use termcolor::ColorChoice; + +/// The `yubikey` CLI utility +#[derive(Debug, Options)] +pub struct YubikeyCli { + /// Obtain help about the current command + #[options(short = "h", help = "print help message")] + pub help: bool, + + /// Subcommand to execute. + #[options(command)] + pub command: Option, +} + +impl YubikeyCli { + /// Run the underlying command type or print usage info and exit + pub fn run(&self) { + // TODO(tarcieri): make this more configurable + status::set_color_choice(ColorChoice::Auto); + + // Only show logs if `RUST_LOG` is set + if env::var("RUST_LOG").is_ok() { + env_logger::builder().format_timestamp(None).init(); + } + + match &self.command { + Some(cmd) => cmd.run(), + None => println!("{}", Commands::usage()), + } + } +} + +/// Subcommands of this application +#[derive(Debug, Options)] +pub enum Commands { + /// `help` subcommand + #[options(help = "show help for a command")] + Help(HelpOpts), + + /// `version` subcommand + #[options(help = "display version information")] + Version(VersionOpts), + + /// `list` subcommand + #[options(help = "list detected readers")] + List(ListCmd), +} + +impl Commands { + /// Run the given command + pub fn run(&self) { + match self { + Commands::Help(help) => help.run(), + Commands::Version(version) => version.run(), + Commands::List(list) => list.run(), + } + } +} + +/// Help options +#[derive(Debug, Options)] +pub struct HelpOpts { + #[options(free, help = "subcommand to get help for")] + free: Vec, +} + +impl HelpOpts { + fn run(&self) { + if let Some(command) = self.free.first() { + if let Some(usage) = Commands::command_usage(command) { + println!("{}", usage); + exit(1); + } + } + + println!("{}", Commands::usage()); + } +} + +/// Version options +#[derive(Debug, Options)] +pub struct VersionOpts {} + +impl VersionOpts { + /// Display version information + pub fn run(&self) { + println!("{} {}", env!("CARGO_PKG_NAME"), env!("CARGO_PKG_VERSION")); + } +} diff --git a/cli/src/commands/list.rs b/cli/src/commands/list.rs new file mode 100644 index 0000000..a30059f --- /dev/null +++ b/cli/src/commands/list.rs @@ -0,0 +1,40 @@ +//! List detected readers + +use gumdrop::Options; +use std::process::exit; +use yubikey_piv::readers::Readers; + +/// The `list` subcommand +#[derive(Debug, Options)] +pub struct ListCmd {} + +impl ListCmd { + /// Run the `list` subcommand + pub fn run(&self) { + let mut readers = Readers::open().unwrap_or_else(|e| { + status_err!("couldn't open PC/SC context: {}", e); + exit(1); + }); + + let readers_iter = readers.iter().unwrap_or_else(|e| { + status_err!("couldn't enumerate PC/SC readers: {}", e); + exit(1); + }); + + if readers_iter.len() == 0 { + status_err!("no YubiKeys detected!"); + exit(1); + } + + for (i, reader) in readers_iter.enumerate() { + let name = reader.name(); + let mut yubikey = match reader.open() { + Ok(yk) => yk, + Err(_) => continue, + }; + + let serial = yubikey.serial(); + println!("{}: {} (serial: {})", i + 1, name, serial); + } + } +} diff --git a/cli/src/lib.rs b/cli/src/lib.rs new file mode 100644 index 0000000..7e9024e --- /dev/null +++ b/cli/src/lib.rs @@ -0,0 +1,14 @@ +//! `yubikey` command-line utility + +#![forbid(unsafe_code)] +#![warn( + missing_docs, + rust_2018_idioms, + unused_lifetimes, + unused_qualifications +)] + +#[macro_use] +pub mod status; + +pub mod commands; diff --git a/cli/src/status.rs b/cli/src/status.rs new file mode 100644 index 0000000..6c8bbc5 --- /dev/null +++ b/cli/src/status.rs @@ -0,0 +1,165 @@ +//! Status messages + +use lazy_static::lazy_static; +use std::io::{self, Write}; +use std::sync::Mutex; +use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor}; + +/// Print a success status message (in green if colors are enabled) +#[macro_export] +macro_rules! status_ok { + ($status:expr, $msg:expr) => { + $crate::status::Status::new() + .justified() + .bold() + .color(termcolor::Color::Green) + .status($status) + .print_stdout($msg); + }; + ($status:expr, $fmt:expr, $($arg:tt)+) => { + $crate::status_ok!($status, format!($fmt, $($arg)+)); + }; +} + +/// Print a warning status message (in yellow if colors are enabled) +#[macro_export] +macro_rules! status_warn { + ($msg:expr) => { + $crate::status::Status::new() + .bold() + .color(termcolor::Color::Yellow) + .status("warning:") + .print_stdout($msg); + }; + ($fmt:expr, $($arg:tt)+) => { + $crate::status_warn!(format!($fmt, $($arg)+)); + }; +} + +/// Print an error message (in red if colors are enabled) +#[macro_export] +macro_rules! status_err { + ($msg:expr) => { + $crate::status::Status::new() + .bold() + .color(termcolor::Color::Red) + .status("error:") + .print_stderr($msg); + }; + ($fmt:expr, $($arg:tt)+) => { + $crate::status_err!(format!($fmt, $($arg)+)); + }; +} + +lazy_static! { + /// Color configuration + static ref COLOR_CHOICE: Mutex> = Mutex::new(None); + + /// Standard output + pub static ref STDOUT: StandardStream = StandardStream::stdout(get_color_choice()); + + /// Standard error + pub static ref STDERR: StandardStream = StandardStream::stderr(get_color_choice()); +} + +/// Obtain the color configuration. +/// +/// Panics if no configuration has been provided. +fn get_color_choice() -> ColorChoice { + let choice = COLOR_CHOICE.lock().unwrap(); + *choice + .as_ref() + .expect("terminal stream accessed before initialized!") +} + +/// Set the color configuration. +/// +/// Panics if the terminal has already been configured. +pub(super) fn set_color_choice(color_choice: ColorChoice) { + let mut choice = COLOR_CHOICE.lock().unwrap(); + assert!(choice.is_none(), "terminal colors already configured!"); + *choice = Some(color_choice); +} + +/// Status message builder +#[derive(Clone, Debug, Default)] +pub struct Status { + /// Should the status be justified? + justified: bool, + + /// Should colors be bold? + bold: bool, + + /// Color in which status should be displayed + color: Option, + + /// Prefix of the status message (e.g. `Success`) + status: Option, +} + +impl Status { + /// Create a new status message with default settings + pub fn new() -> Self { + Self::default() + } + + /// Justify status on display + pub fn justified(mut self) -> Self { + self.justified = true; + self + } + + /// Make colors bold + pub fn bold(mut self) -> Self { + self.bold = true; + self + } + + /// Set the colors used to display this message + pub fn color(mut self, c: Color) -> Self { + self.color = Some(c); + self + } + + /// Set a status message to display + pub fn status(mut self, msg: S) -> Self + where + S: ToString, + { + self.status = Some(msg.to_string()); + self + } + + /// Print the given message to stdout + pub fn print_stdout(self, msg: impl AsRef) { + self.print(&*STDOUT, msg) + .expect("error printing to stdout!") + } + + /// Print the given message to stderr + pub fn print_stderr(self, msg: impl AsRef) { + self.print(&*STDERR, msg) + .expect("error printing to stderr!") + } + + /// Print the given message + fn print(self, stream: &StandardStream, msg: impl AsRef) -> Result<(), io::Error> { + let mut s = stream.lock(); + s.reset()?; + s.set_color(ColorSpec::new().set_fg(self.color).set_bold(self.bold))?; + + if let Some(status) = self.status { + if self.justified { + write!(s, "{:>12}", status)?; + } else { + write!(s, "{}", status)?; + } + } + + s.reset()?; + writeln!(s, " {}", msg.as_ref())?; + s.flush()?; + + Ok(()) + } +} diff --git a/src/lib.rs b/src/lib.rs index 35f2a22..13ae7b9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -164,9 +164,10 @@ pub mod settings; mod transaction; pub mod yubikey; +pub use self::{readers::Readers, yubikey::YubiKey}; + #[cfg(feature = "untested")] -pub use self::{key::Key, mgm::MgmKey, readers::Readers}; -pub use yubikey::YubiKey; +pub use self::{key::Key, mgm::MgmKey}; /// Object identifiers pub type ObjectId = u32; From da897b99bb0552a35d4065ee8f568c4655a3fcb7 Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Mon, 2 Dec 2019 11:17:10 -0800 Subject: [PATCH 4/8] yubikey-piv v0.0.3 --- CHANGELOG.md | 29 +++++++++++++++++++++++++++++ Cargo.lock | 4 ++-- Cargo.toml | 2 +- cli/Cargo.toml | 2 +- src/lib.rs | 2 +- 5 files changed, 34 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9ee790a..46ef882 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,35 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.0.3] (2019-12-02) +### Added +- Initial `Readers` enumerator for detecting YubiKeys ([#51]) +- Certificate parsing ([#45]) + +### Changed +- Use `Reader` to connect to `YubiKey` ([#51]) +- Convert `SlotId` and `AlgorithmId` into enums ([#44]) +- Use `secrecy` crate for storing `CachedPin` ([#43]) +- Change `CHUID` struct to hold complete CHUID value ([#42]) +- Eliminate all usages of `unsafe` ([#37], [#39]) +- Make anonymous CHUID struct public ([#36]) +- Have `sign_data` and `decrypt_data` return a `Buffer` ([#34]) +- `Ins` (APDU instruction codes) enum ([#33]) +- Factor `Response` into `apdu` module; improved debugging ([#32]) + +[0.0.3]: https://github.com/iqlusioninc/yubikey-piv.rs/pull/53 +[#51]: https://github.com/iqlusioninc/yubikey-piv.rs/pull/51 +[#45]: https://github.com/iqlusioninc/yubikey-piv.rs/pull/45 +[#44]: https://github.com/iqlusioninc/yubikey-piv.rs/pull/44 +[#43]: https://github.com/iqlusioninc/yubikey-piv.rs/pull/43 +[#42]: https://github.com/iqlusioninc/yubikey-piv.rs/pull/42 +[#39]: https://github.com/iqlusioninc/yubikey-piv.rs/pull/39 +[#37]: https://github.com/iqlusioninc/yubikey-piv.rs/pull/37 +[#36]: https://github.com/iqlusioninc/yubikey-piv.rs/pull/36 +[#34]: https://github.com/iqlusioninc/yubikey-piv.rs/pull/34 +[#33]: https://github.com/iqlusioninc/yubikey-piv.rs/pull/33 +[#32]: https://github.com/iqlusioninc/yubikey-piv.rs/pull/32 + ## [0.0.2] (2019-11-25) ### Added - `untested` Cargo feature to mark untested functionality ([#30]) diff --git a/Cargo.lock b/Cargo.lock index fec476c..e3e249d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -842,12 +842,12 @@ dependencies = [ "gumdrop 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", - "yubikey-piv 0.0.2", + "yubikey-piv 0.0.3", ] [[package]] name = "yubikey-piv" -version = "0.0.2" +version = "0.0.3" dependencies = [ "der-parser 3.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "des 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/Cargo.toml b/Cargo.toml index 67e6dc6..149466b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "yubikey-piv" -version = "0.0.2" # Also update html_root_url in lib.rs when bumping this +version = "0.0.3" # Also update html_root_url in lib.rs when bumping this description = """ Pure Rust host-side driver for the YubiKey Personal Identity Verification (PIV) application providing general-purpose public-key signing and encryption diff --git a/cli/Cargo.toml b/cli/Cargo.toml index 612a85f..e67d904 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -18,4 +18,4 @@ gumdrop = "0.7" env_logger = "0.7" lazy_static = "1" termcolor = "1" -yubikey-piv = { version = "0.0.2", path = ".." } +yubikey-piv = { version = "0.0.3", path = ".." } diff --git a/src/lib.rs b/src/lib.rs index 13ae7b9..580ca93 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -123,7 +123,7 @@ #![doc( html_logo_url = "https://raw.githubusercontent.com/tarcieri/yubikey-piv.rs/develop/img/logo.png", - html_root_url = "https://docs.rs/yubikey-piv/0.0.2" + html_root_url = "https://docs.rs/yubikey-piv/0.0.3" )] #![forbid(unsafe_code)] #![warn( From 3a41fdc3bcabbb7259dc64bc0b3406af59d07b26 Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Mon, 2 Dec 2019 11:54:41 -0800 Subject: [PATCH 5/8] yubikey-cli v0.0.1 --- Cargo.lock | 2 +- cli/CHANGELOG.md | 8 ++++++++ cli/Cargo.toml | 2 +- 3 files changed, 10 insertions(+), 2 deletions(-) create mode 100644 cli/CHANGELOG.md diff --git a/Cargo.lock b/Cargo.lock index e3e249d..ebbdf6f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -836,7 +836,7 @@ dependencies = [ [[package]] name = "yubikey-cli" -version = "0.0.0" +version = "0.0.1" dependencies = [ "env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "gumdrop 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/cli/CHANGELOG.md b/cli/CHANGELOG.md new file mode 100644 index 0000000..9321649 --- /dev/null +++ b/cli/CHANGELOG.md @@ -0,0 +1,8 @@ +# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## 0.0.1 (2019-12-02) +- Initial release diff --git a/cli/Cargo.toml b/cli/Cargo.toml index e67d904..e1f3a30 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "yubikey-cli" -version = "0.0.0" +version = "0.0.1" description = """ Command-line interface for performing encryption and signing using RSA and/or ECC keys stored on YubiKey devices. From 9bc28f4f75c035927fe6bf071a26049eb16a4d05 Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Mon, 2 Dec 2019 12:18:44 -0800 Subject: [PATCH 6/8] cli: fix build badge --- cli/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cli/README.md b/cli/README.md index b359d92..19f9903 100644 --- a/cli/README.md +++ b/cli/README.md @@ -92,8 +92,8 @@ or conditions. [maintenance-image]: https://img.shields.io/badge/maintenance-experimental-blue.svg [safety-image]: https://img.shields.io/badge/unsafe-forbidden-success.svg [safety-link]: https://github.com/rust-secure-code/safety-dance/ -[build-image]: https://github.com/iqlusioninc/yubikey-cli.rs/workflows/Rust/badge.svg?branch=develop&event=push -[build-link]: https://github.com/iqlusioninc/yubikey-cli.rs/actions +[build-image]: https://github.com/iqlusioninc/yubikey-piv.rs/workflows/Rust/badge.svg?branch=develop&event=push +[build-link]: https://github.com/iqlusioninc/yubikey-piv.rs/actions [gitter-image]: https://badges.gitter.im/badge.svg [gitter-link]: https://gitter.im/iqlusioninc/community From d6ad70f7d132ef70c5df8bdba62f97f53edcedef Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Tue, 3 Dec 2019 13:51:52 +0000 Subject: [PATCH 7/8] Bump zeroize from 1.0.0 to 1.1.0 Bumps [zeroize](https://github.com/iqlusioninc/crates) from 1.0.0 to 1.1.0. - [Release notes](https://github.com/iqlusioninc/crates/releases) - [Commits](https://github.com/iqlusioninc/crates/compare/zeroize/v1.0.0...zeroize/v1.1.0) Signed-off-by: dependabot-preview[bot] --- Cargo.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ebbdf6f..f0eb0e1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -639,7 +639,7 @@ name = "secrecy" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "zeroize 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "zeroize 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -864,7 +864,7 @@ dependencies = [ "sha-1 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "subtle 2.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "x509-parser 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "zeroize 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "zeroize 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -877,7 +877,7 @@ dependencies = [ [[package]] name = "zeroize" -version = "1.0.0" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -996,5 +996,5 @@ dependencies = [ "checksum wincolor 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "96f5016b18804d24db43cebf3c77269e7569b8954a8464501c216cc5e070eaa9" "checksum x509-parser 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9b86b92815858495482b74dab17c0b2b2399f7582b6e7ca621b87aebf8fd00e9" "checksum zeroize 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4090487fa66630f7b166fba2bbb525e247a5449f41c468cc1d98f8ae6ac03120" -"checksum zeroize 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cdc979d9b5ead18184c357c4d8a3f81b579aae264e32507223032e64715462d3" +"checksum zeroize 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3cbac2ed2ba24cc90f5e06485ac8c7c1e5449fe8911aef4d8877218af021a5b8" "checksum zeroize_derive 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc9ce59c69fc43078c6f4250b0c866bb06b9ff7ac955c7ddb82a8c189281dcae" From b1e87020599b9396731c3a8c56c647218162fe4b Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Tue, 3 Dec 2019 11:11:54 -0800 Subject: [PATCH 8/8] README.md: Fix license image --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 73e60f9..b493cea 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ [![crate][crate-image]][crate-link] [![Docs][docs-image]][docs-link] -![Apache2/MIT licensed][license-image] +[![2-Clause BSD Licensed][license-image]][license-link] ![Rust Version][rustc-image] ![Maintenance Status: Experimental][maintenance-image] [![Safety Dance][safety-image]][safety-link] @@ -192,6 +192,7 @@ or conditions. [docs-image]: https://docs.rs/yubikey-piv/badge.svg [docs-link]: https://docs.rs/yubikey-piv/ [license-image]: https://img.shields.io/badge/license-BSD-blue.svg +[license-link]: https://github.com/iqlusioninc/yubikey-piv.rs/blob/develop/COPYING [rustc-image]: https://img.shields.io/badge/rustc-1.39+-blue.svg [maintenance-image]: https://img.shields.io/badge/maintenance-experimental-blue.svg [safety-image]: https://img.shields.io/badge/unsafe-forbidden-success.svg