Compare commits

...

15 Commits

Author SHA1 Message Date
Tony Arcieri (iqlusion) 0a36a37ae3 yubikey v0.6.0 (#403) 2022-08-10 16:41:26 -07:00
Tony Arcieri (iqlusion) 3463d109b2 Bump der-parser to v8; x509-parser to v0.14 (#402) 2022-08-10 15:19:21 -07:00
dependabot[bot] 014b7ee6fd Bump p384 from 0.10.0 to 0.11.2 (#401)
Bumps [p384](https://github.com/RustCrypto/elliptic-curves) from 0.10.0 to 0.11.2.
- [Release notes](https://github.com/RustCrypto/elliptic-curves/releases)
- [Commits](https://github.com/RustCrypto/elliptic-curves/compare/p384/v0.10.0...p384/v0.11.2)

---
updated-dependencies:
- dependency-name: p384
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-08-10 14:57:39 -07:00
vdods 498de4c10d Adding some common traits for certain enum types to support maps. (#372) 2022-08-10 14:34:58 -07:00
Tony Arcieri (iqlusion) 98b038c873 Cargo.lock: bump dependencies (#400) 2022-08-10 14:26:33 -07:00
Tony Arcieri (iqlusion) fab9d25b0a cli: migrate from gumdrop to clap v3 (#379)
`gumdrop` was originally chosen for its minimalist set of dependencies,
but `clap` v3 has a slimmed down set of dependencies and better UX.
2022-05-24 21:45:26 -06:00
dependabot[bot] bb80551324 Bump uuid from 0.8.2 to 1.0.0 (#376)
Bumps [uuid](https://github.com/uuid-rs/uuid) from 0.8.2 to 1.0.0.
- [Release notes](https://github.com/uuid-rs/uuid/releases)
- [Commits](https://github.com/uuid-rs/uuid/compare/0.8.2...1.0.0)

---
updated-dependencies:
- dependency-name: uuid
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-05-23 20:18:58 -07:00
Tony Arcieri (iqlusion) 9e20ecfe55 RustCrypto crate upgrades; MSRV 1.57 (#378)
Updates all of the RustCrypto dependencies to the latest versions:

- `des` v0.8
- `elliptic-curve` v0.12
- `hmac` v0.12
- `num-bigint-dig` v0.8
- `pbkdf2` v0.11
- `p256` v0.11
- `p384` v0.10
- `rsa` v0.6
- `sha1` v0.10 (replacing `sha-1`)
- `sha2` v0.10
2022-05-23 20:04:12 -07:00
Tony Arcieri (iqlusion) fac83c60fb Cargo.lock: bump dependencies (#375) 2022-05-23 17:52:53 -07:00
Shella Stephens 914f9bee0d Cargo.lock: update dependencies & fix cargo audit (#365) 2022-03-07 16:29:35 -07:00
Ferdinand Linnenberg 83de59983f Add Display formatter to SlotId (#353) 2022-02-11 13:10:53 -08:00
Shella Stephens e21395c934 Cargo.lock: update dependencies (#347) 2022-01-31 08:00:16 -07:00
Tony Arcieri (iqlusion) 935fea0868 Bump p256 => v0.10; p384 => v0.9 (#344) 2022-01-17 15:08:48 -08:00
Tony Arcieri (iqlusion) dd4b1c60a4 2021 edition upgrade; MSRV 1.56 (#343)
Changes the `edition` to 2021 in both the `yubikey` and `yubikey-cli`
crates.

Removes `TryFrom`/`TryInto` imports, now that they're in the prelude.
2022-01-17 14:54:01 -08:00
Shella Stephens 74a50f0f0c Bump dependencies & fix security audit (#340)
* Bump dependencies & fix security audit

* allow dead code for issuer field #[allow(dead_code)] in Certificates struct
2022-01-10 08:40:58 -07:00
24 changed files with 839 additions and 399 deletions
+4 -4
View File
@@ -36,13 +36,13 @@ jobs:
toolchain: stable toolchain: stable
deps: true deps: true
- platform: ubuntu-latest - platform: ubuntu-latest
toolchain: 1.51.0 # MSRV toolchain: 1.57.0 # MSRV
deps: sudo apt-get install libpcsclite-dev deps: sudo apt-get install libpcsclite-dev
- platform: windows-latest - platform: windows-latest
toolchain: 1.51.0 # MSRV toolchain: 1.57.0 # MSRV
deps: true deps: true
- platform: macos-latest - platform: macos-latest
toolchain: 1.51.0 # MSRV toolchain: 1.57.0 # MSRV
deps: true deps: true
runs-on: ${{ matrix.platform }} runs-on: ${{ matrix.platform }}
steps: steps:
@@ -82,7 +82,7 @@ jobs:
- uses: actions-rs/toolchain@v1 - uses: actions-rs/toolchain@v1
with: with:
profile: minimal profile: minimal
toolchain: 1.51.0 # MSRV toolchain: 1.57.0 # MSRV
components: clippy components: clippy
override: true override: true
- run: sudo apt-get install libpcsclite-dev - run: sudo apt-get install libpcsclite-dev
+23
View File
@@ -4,6 +4,29 @@ 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/), 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). and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## 0.6.0 (2022-08-10)
### Changed
- 2021 edition upgrade ([#343])
- RustCrypto crate upgrades; MSRV 1.57 ([#378])
- `des` v0.8
- `elliptic-curve` v0.12
- `hmac` v0.12
- `num-bigint-dig` v0.8
- `pbkdf2` v0.11
- `p256` v0.11
- `p384` v0.11
- `rsa` v0.6
- `sha1` v0.10 (replacing `sha-1`)
- `sha2` v0.10
- Bump `uuid` to v1.0 ([#376])
- Bump `der-parser` to v8.0 ([#402])
- Bump `x509-parser` to v0.14 ([#402])
[#343]: https://github.com/iqlusioninc/yubikey.rs/pull/343
[#376]: https://github.com/iqlusioninc/yubikey.rs/pull/376
[#378]: https://github.com/iqlusioninc/yubikey.rs/pull/378
[#402]: https://github.com/iqlusioninc/yubikey.rs/pull/402
## 0.5.0 (2021-11-21) ## 0.5.0 (2021-11-21)
### Changed ### Changed
- Update `rsa` dependency to 0.5 ([#315]) - Update `rsa` dependency to 0.5 ([#315])
Generated
+668 -226
View File
File diff suppressed because it is too large Load Diff
+21 -20
View File
@@ -1,19 +1,20 @@
[package] [package]
name = "yubikey" name = "yubikey"
version = "0.5.0" # Also update html_root_url in lib.rs when bumping this version = "0.6.0"
description = """ description = """
Pure Rust cross-platform host-side driver for YubiKey devices from Yubico with Pure Rust cross-platform host-side driver for YubiKey devices from Yubico with
support for hardware-backed public-key decryption and digital signatures using support for hardware-backed public-key decryption and digital signatures using
the Personal Identity Verification (PIV) application. Supports RSA (1024/2048) the Personal Identity Verification (PIV) application. Supports RSA (1024/2048)
or ECC (NIST P-256/P-384) algorithms e.g, PKCS#1v1.5, ECDSA or ECC (NIST P-256/P-384) algorithms e.g, PKCS#1v1.5, ECDSA
""" """
authors = ["Tony Arcieri <tony@iqlusion.io>", "Yubico AB"] authors = ["Tony Arcieri <tony@iqlusion.io>", "Yubico AB"]
edition = "2018" license = "BSD-2-Clause"
license = "BSD-2-Clause"
repository = "https://github.com/iqlusioninc/yubikey.rs" repository = "https://github.com/iqlusioninc/yubikey.rs"
readme = "README.md" readme = "README.md"
categories = ["api-bindings", "cryptography", "hardware-support"] categories = ["api-bindings", "cryptography", "hardware-support"]
keywords = ["ecdsa", "encryption", "rsa", "piv", "signature"] keywords = ["ecdsa", "encryption", "rsa", "piv", "signature"]
edition = "2021"
rust-version = "1.57"
[workspace] [workspace]
members = [".", "cli"] members = [".", "cli"]
@@ -21,29 +22,29 @@ members = [".", "cli"]
[dependencies] [dependencies]
chrono = "0.4" chrono = "0.4"
cookie-factory = "0.3" cookie-factory = "0.3"
der-parser = "6" der-parser = "8"
des = "0.7" des = "0.8"
elliptic-curve = "0.10" elliptic-curve = "0.12"
hmac = "0.11" hmac = "0.12"
log = "0.4" log = "0.4"
nom = "7" nom = "7"
num-bigint-dig = { version = "0.7", features = ["rand"] } num-bigint-dig = { version = "0.8", features = ["rand"] }
num-traits = "0.2" num-traits = "0.2"
num-integer = "0.1" num-integer = "0.1"
pbkdf2 = { version = "0.9", default-features = false } pbkdf2 = { version = "0.11", default-features = false }
p256 = "0.9" p256 = "0.11"
p384 = "0.8" p384 = "0.11"
pcsc = "2" pcsc = "2"
rand_core = { version = "0.6", features = ["std"] } rand_core = { version = "0.6", features = ["std"] }
rsa = "0.5" rsa = "0.6"
secrecy = "0.8" secrecy = "0.8"
sha-1 = "0.9" sha1 = "0.10"
sha2 = "0.9" sha2 = "0.10"
subtle = "2" subtle = "2"
subtle-encoding = "0.5" subtle-encoding = "0.5"
uuid = { version = "0.8", features = ["v4"] } uuid = { version = "1.0", features = ["v4"] }
x509 = "0.2" x509 = "0.2"
x509-parser = "0.12" x509-parser = "0.14"
zeroize = "1" zeroize = "1"
[dev-dependencies] [dev-dependencies]
+5 -5
View File
@@ -5,7 +5,7 @@
[![crate][crate-image]][crate-link] [![crate][crate-image]][crate-link]
[![Docs][docs-image]][docs-link] [![Docs][docs-image]][docs-link]
[![2-Clause BSD Licensed][license-image]][license-link] [![2-Clause BSD Licensed][license-image]][license-link]
![Rust Version][rustc-image] ![MSRV][msrv-image]
[![Safety Dance][safety-image]][safety-link] [![Safety Dance][safety-image]][safety-link]
[![Build Status][build-image]][build-link] [![Build Status][build-image]][build-link]
[![dependency status][deps-image]][deps-link] [![dependency status][deps-image]][deps-link]
@@ -26,8 +26,8 @@ encryption (PKCS#1v1.5/ECIES) use cases are supported for either key type.
See [Yubico's guide to PIV-enabled YubiKeys][yk-guide] for more information See [Yubico's guide to PIV-enabled YubiKeys][yk-guide] for more information
on which devices support PIV and the available functionality. on which devices support PIV and the available functionality.
If you've been wanting to use Rust to sign and/or encrypt stuff using a If you've been wanting to use Rust to sign and/or encrypt data using a
private key generated and stored on a Yubikey (with option PIN-based access), private key generated and stored on a YubiKey (with option PIN-based access),
this is the crate you've been after! this is the crate you've been after!
Note that while this project started as a fork of a [Yubico] project, Note that while this project started as a fork of a [Yubico] project,
@@ -36,7 +36,7 @@ endorsed by Yubico.
## Minimum Supported Rust Version ## Minimum Supported Rust Version
Rust **1.51** or newer. Rust **1.57** or newer.
## Supported YubiKeys ## Supported YubiKeys
@@ -165,7 +165,7 @@ or conditions.
[docs-link]: https://docs.rs/yubikey/ [docs-link]: https://docs.rs/yubikey/
[license-image]: https://img.shields.io/badge/license-BSD-blue.svg [license-image]: https://img.shields.io/badge/license-BSD-blue.svg
[license-link]: https://github.com/iqlusioninc/yubikey.rs/blob/main/COPYING [license-link]: https://github.com/iqlusioninc/yubikey.rs/blob/main/COPYING
[rustc-image]: https://img.shields.io/badge/rustc-1.51+-blue.svg [msrv-image]: https://img.shields.io/badge/rustc-1.57+-blue.svg
[safety-image]: https://img.shields.io/badge/unsafe-forbidden-success.svg [safety-image]: https://img.shields.io/badge/unsafe-forbidden-success.svg
[safety-link]: https://github.com/rust-secure-code/safety-dance/ [safety-link]: https://github.com/rust-secure-code/safety-dance/
[build-image]: https://github.com/iqlusioninc/yubikey.rs/workflows/CI/badge.svg?branch=main&event=push [build-image]: https://github.com/iqlusioninc/yubikey.rs/workflows/CI/badge.svg?branch=main&event=push
+9 -8
View File
@@ -1,20 +1,21 @@
[package] [package]
name = "yubikey-cli" name = "yubikey-cli"
version = "0.5.0" version = "0.6.0-pre"
description = """ description = """
Command-line interface for performing encryption and signing using RSA/ECC keys Command-line interface for performing encryption and signing using RSA/ECC keys
stored on YubiKey devices. stored on YubiKey devices.
""" """
authors = ["Tony Arcieri <tony@iqlusion.io>"] authors = ["Tony Arcieri <tony@iqlusion.io>"]
edition = "2018" license = "BSD-2-Clause"
license = "BSD-2-Clause"
repository = "https://github.com/iqlusioninc/yubikey.rs" repository = "https://github.com/iqlusioninc/yubikey.rs"
readme = "README.md" readme = "README.md"
categories = ["command-line-utilities", "cryptography", "hardware-support"] categories = ["command-line-utilities", "cryptography", "hardware-support"]
keywords = ["ecdsa", "rsa", "piv", "pcsc", "yubikey"] keywords = ["ecdsa", "rsa", "piv", "pcsc", "yubikey"]
edition = "2021"
rust-version = "1.56"
[dependencies] [dependencies]
gumdrop = "0.8" clap = { version = "3", features = ["derive"] }
env_logger = "0.9" env_logger = "0.9"
lazy_static = "1" lazy_static = "1"
log = "0.4" log = "0.4"
@@ -22,4 +23,4 @@ sha2 = "0.9"
subtle-encoding = "0.5" subtle-encoding = "0.5"
termcolor = "1" termcolor = "1"
x509-parser = "0.12" x509-parser = "0.12"
yubikey = { version = "0.5", path = ".." } yubikey = { version = "0.6", path = ".." }
+2 -2
View File
@@ -8,9 +8,9 @@
unused_qualifications unused_qualifications
)] )]
use gumdrop::Options; use clap::Parser;
use yubikey_cli::commands::YubiKeyCli; use yubikey_cli::commands::YubiKeyCli;
fn main() { fn main() {
YubiKeyCli::parse_args_default_or_exit().run(); YubiKeyCli::parse().run()
} }
+15 -80
View File
@@ -4,62 +4,25 @@ pub mod readers;
pub mod status; pub mod status;
use self::{readers::ReadersCmd, status::StatusCmd}; use self::{readers::ReadersCmd, status::StatusCmd};
use crate::terminal::{self, STDOUT}; use crate::terminal;
use gumdrop::Options; use clap::Parser;
use std::{ use std::{env, process::exit};
env, use termcolor::ColorChoice;
io::{self, Write},
process::exit,
};
use termcolor::{ColorChoice, ColorSpec, WriteColor};
use yubikey::{Serial, YubiKey}; use yubikey::{Serial, YubiKey};
/// The `yubikey` CLI utility /// The `yubikey` CLI utility
#[derive(Debug, Options)] #[derive(Debug, Parser)]
pub struct YubiKeyCli { pub struct YubiKeyCli {
/// Obtain help about the current command /// Serial number of the YubiKey to connect to
#[options(short = "h", help = "print help message")] #[clap(short = 's', long = "serial")]
pub help: bool,
/// Specify the serial number of the YubiKey to connect to
#[options(
short = "s",
long = "serial",
help = "serial number of the YubiKey to connect to"
)]
pub serial: Option<Serial>, pub serial: Option<Serial>,
/// Subcommand to execute. /// Subcommand to execute.
#[options(command)] #[clap(subcommand)]
pub command: Option<Commands>, pub command: Commands,
} }
impl YubiKeyCli { impl YubiKeyCli {
/// Print usage information
pub fn print_usage() -> io::Result<()> {
let mut stdout = STDOUT.lock();
stdout.reset()?;
let mut bold = ColorSpec::new();
bold.set_bold(true);
stdout.set_color(&bold)?;
writeln!(
stdout,
"{} {}",
env!("CARGO_PKG_NAME"),
env!("CARGO_PKG_VERSION")
)?;
stdout.reset()?;
writeln!(stdout, "{}", env!("CARGO_PKG_AUTHORS"))?;
writeln!(stdout, "{}", env!("CARGO_PKG_DESCRIPTION").trim())?;
writeln!(stdout)?;
writeln!(stdout, "{}", Commands::usage())?;
Ok(())
}
/// Run the underlying command type or print usage info and exit /// Run the underlying command type or print usage info and exit
pub fn run(&self) { pub fn run(&self) {
// TODO(tarcieri): make this more configurable // TODO(tarcieri): make this more configurable
@@ -70,10 +33,7 @@ impl YubiKeyCli {
env_logger::builder().format_timestamp(None).init(); env_logger::builder().format_timestamp(None).init();
} }
match &self.command { self.command.run(self.yubikey_init())
Some(cmd) => cmd.run(self.yubikey_init()),
None => Self::print_usage().unwrap(),
}
} }
/// Initialize the YubiKey client driver /// Initialize the YubiKey client driver
@@ -92,22 +52,18 @@ impl YubiKeyCli {
} }
/// Subcommands of this application /// Subcommands of this application
#[derive(Debug, Options)] #[derive(Debug, Parser)]
pub enum Commands { pub enum Commands {
/// `help` subcommand
#[options(help = "show help for a command")]
Help(HelpOpts),
/// `version` subcommand /// `version` subcommand
#[options(help = "display version information")] #[clap(about = "display version information")]
Version(VersionOpts), Version(VersionOpts),
/// `readers` subcommand /// `readers` subcommand
#[options(help = "list detected readers")] #[clap(about = "list detected readers")]
Readers(ReadersCmd), Readers(ReadersCmd),
/// `status` subcommand /// `status` subcommand
#[options(help = "show yubikey status")] #[clap(about = "show yubikey status")]
Status(StatusCmd), Status(StatusCmd),
} }
@@ -115,7 +71,6 @@ impl Commands {
/// Run the given command /// Run the given command
pub fn run(&self, yubikey: YubiKey) { pub fn run(&self, yubikey: YubiKey) {
match self { match self {
Commands::Help(help) => help.run(),
Commands::Version(version) => version.run(), Commands::Version(version) => version.run(),
Commands::Readers(list) => list.run(), Commands::Readers(list) => list.run(),
Commands::Status(status) => status.run(yubikey), Commands::Status(status) => status.run(yubikey),
@@ -123,28 +78,8 @@ impl Commands {
} }
} }
/// Help options
#[derive(Debug, Options)]
pub struct HelpOpts {
#[options(free, help = "subcommand to get help for")]
free: Vec<String>,
}
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 /// Version options
#[derive(Debug, Options)] #[derive(Debug, Parser)]
pub struct VersionOpts {} pub struct VersionOpts {}
impl VersionOpts { impl VersionOpts {
+2 -2
View File
@@ -1,7 +1,7 @@
//! List detected readers //! List detected readers
use crate::terminal::STDOUT; use crate::terminal::STDOUT;
use gumdrop::Options; use clap::Parser;
use std::{ use std::{
io::{self, Write}, io::{self, Write},
process::exit, process::exit,
@@ -10,7 +10,7 @@ use termcolor::{ColorSpec, StandardStreamLock, WriteColor};
use yubikey::{Context, Serial}; use yubikey::{Context, Serial};
/// The `readers` subcommand /// The `readers` subcommand
#[derive(Debug, Options)] #[derive(Debug, Parser)]
pub struct ReadersCmd {} pub struct ReadersCmd {}
impl ReadersCmd { impl ReadersCmd {
+2 -2
View File
@@ -1,7 +1,7 @@
//! Print device status //! Print device status
use crate::terminal::{print_cert_info, STDOUT}; use crate::terminal::{print_cert_info, STDOUT};
use gumdrop::Options; use clap::Parser;
use std::io::{self, Write}; use std::io::{self, Write};
use termcolor::{ColorSpec, StandardStreamLock, WriteColor}; use termcolor::{ColorSpec, StandardStreamLock, WriteColor};
use yubikey::{piv::*, YubiKey}; use yubikey::{piv::*, YubiKey};
@@ -10,7 +10,7 @@ use yubikey::{piv::*, YubiKey};
const NONE_STR: &str = "<none>"; const NONE_STR: &str = "<none>";
/// The `status` subcommand /// The `status` subcommand
#[derive(Debug, Options)] #[derive(Debug, Parser)]
pub struct StatusCmd {} pub struct StatusCmd {}
impl StatusCmd { impl StatusCmd {
-1
View File
@@ -33,7 +33,6 @@
use crate::{Error, Result, YubiKey}; use crate::{Error, Result, YubiKey};
use rand_core::{OsRng, RngCore}; use rand_core::{OsRng, RngCore};
use std::{ use std::{
convert::TryInto,
fmt::{self, Debug, Display}, fmt::{self, Debug, Display},
str, str,
}; };
+12 -12
View File
@@ -47,9 +47,7 @@ use p256::NistP256;
use p384::NistP384; use p384::NistP384;
use rsa::{PublicKeyParts, RsaPublicKey}; use rsa::{PublicKeyParts, RsaPublicKey};
use sha2::{Digest, Sha256}; use sha2::{Digest, Sha256};
use std::convert::TryFrom; use std::{fmt, ops::DerefMut};
use std::fmt;
use std::ops::DerefMut;
use x509::{der::Oid, RelativeDistinguishedName}; use x509::{der::Oid, RelativeDistinguishedName};
use x509_parser::{parse_x509_certificate, x509::SubjectPublicKeyInfo}; use x509_parser::{parse_x509_certificate, x509::SubjectPublicKeyInfo};
use zeroize::Zeroizing; use zeroize::Zeroizing;
@@ -85,7 +83,7 @@ impl TryFrom<&[u8]> for Serial {
fn try_from(bytes: &[u8]) -> Result<Serial> { fn try_from(bytes: &[u8]) -> Result<Serial> {
if bytes.len() <= 20 { if bytes.len() <= 20 {
Ok(Serial(BigUint::from_bytes_be(&bytes))) Ok(Serial(BigUint::from_bytes_be(bytes)))
} else { } else {
Err(Error::ParseError) Err(Error::ParseError)
} }
@@ -192,7 +190,7 @@ impl PublicKeyInfo {
fn parse(subject_pki: &SubjectPublicKeyInfo<'_>) -> Result<Self> { fn parse(subject_pki: &SubjectPublicKeyInfo<'_>) -> Result<Self> {
match subject_pki.algorithm.algorithm.to_string().as_str() { match subject_pki.algorithm.algorithm.to_string().as_str() {
OID_RSA_ENCRYPTION => { OID_RSA_ENCRYPTION => {
let pubkey = read_pki::rsa_pubkey(subject_pki.subject_public_key.data)?; let pubkey = read_pki::rsa_pubkey(&subject_pki.subject_public_key.data)?;
Ok(PublicKeyInfo::Rsa { Ok(PublicKeyInfo::Rsa {
algorithm: match pubkey.n().bits() { algorithm: match pubkey.n().bits() {
@@ -212,10 +210,10 @@ impl PublicKeyInfo {
.ok_or(Error::InvalidObject)?; .ok_or(Error::InvalidObject)?;
match read_pki::ec_parameters(algorithm_parameters)? { match read_pki::ec_parameters(algorithm_parameters)? {
AlgorithmId::EccP256 => EcPublicKey::from_bytes(key_bytes) AlgorithmId::EccP256 => EcPublicKey::<NistP256>::from_bytes(key_bytes)
.map(PublicKeyInfo::EcP256) .map(PublicKeyInfo::EcP256)
.map_err(|_| Error::InvalidObject), .map_err(|_| Error::InvalidObject),
AlgorithmId::EccP384 => EcPublicKey::from_bytes(key_bytes) AlgorithmId::EccP384 => EcPublicKey::<NistP384>::from_bytes(key_bytes)
.map(PublicKeyInfo::EcP384) .map(PublicKeyInfo::EcP384)
.map_err(|_| Error::InvalidObject), .map_err(|_| Error::InvalidObject),
_ => Err(Error::AlgorithmError), _ => Err(Error::AlgorithmError),
@@ -320,6 +318,7 @@ impl x509::AlgorithmIdentifier for SignatureId {
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct Certificate { pub struct Certificate {
serial: Serial, serial: Serial,
#[allow(dead_code)]
issuer: String, issuer: String,
subject: String, subject: String,
subject_pki: PublicKeyInfo, subject_pki: PublicKeyInfo,
@@ -364,12 +363,12 @@ impl Certificate {
&serial.to_bytes(), &serial.to_bytes(),
&signature_algorithm, &signature_algorithm,
// Issuer and subject are the same in self-signed certificates. // Issuer and subject are the same in self-signed certificates.
&subject, subject,
Utc::now(), Utc::now(),
not_after, not_after,
&subject, subject,
&subject_pki, &subject_pki,
&extensions, extensions,
), ),
tbs_cert.deref_mut(), tbs_cert.deref_mut(),
) )
@@ -588,6 +587,7 @@ pub(crate) fn write_certificate(
mod read_pki { mod read_pki {
use der_parser::{ use der_parser::{
asn1_rs::Any,
ber::BerObjectContent, ber::BerObjectContent,
der::{parse_der_integer, parse_der_sequence_defined_g, DerObject}, der::{parse_der_integer, parse_der_sequence_defined_g, DerObject},
error::BerError, error::BerError,
@@ -641,8 +641,8 @@ mod read_pki {
/// -- specifiedCurve SpecifiedECDomain /// -- specifiedCurve SpecifiedECDomain
/// } /// }
/// ``` /// ```
pub(super) fn ec_parameters(parameters: &DerObject<'_>) -> Result<AlgorithmId> { pub(super) fn ec_parameters(parameters: &Any<'_>) -> Result<AlgorithmId> {
let curve_oid = parameters.as_oid_val().map_err(|_| Error::InvalidObject)?; let curve_oid = parameters.as_oid().map_err(|_| Error::InvalidObject)?;
match curve_oid.to_string().as_str() { match curve_oid.to_string().as_str() {
OID_NIST_P256 => Ok(AlgorithmId::EccP256), OID_NIST_P256 => Ok(AlgorithmId::EccP256),
-1
View File
@@ -32,7 +32,6 @@
use crate::{Error, Result, YubiKey}; use crate::{Error, Result, YubiKey};
use std::{ use std::{
convert::TryInto,
fmt::{self, Debug, Display}, fmt::{self, Debug, Display},
str, str,
}; };
+1 -4
View File
@@ -41,10 +41,7 @@ use crate::{
Result, Result,
}; };
use log::error; use log::error;
use std::{ use std::time::{Duration, SystemTime, UNIX_EPOCH};
convert::TryInto,
time::{Duration, SystemTime, UNIX_EPOCH},
};
const CB_ADMIN_TIMESTAMP: usize = 0x04; const CB_ADMIN_TIMESTAMP: usize = 0x04;
const PROTECTED_FLAGS_1_PUK_NOBLOCK: u8 = 0x01; const PROTECTED_FLAGS_1_PUK_NOBLOCK: u8 = 0x01;
+2 -3
View File
@@ -17,7 +17,7 @@
//! on which devices support PIV and the available functionality. //! on which devices support PIV and the available functionality.
//! //!
//! # Minimum Supported Rust Version //! # Minimum Supported Rust Version
//! Rust **1.51** or newer. //! Rust **1.57** or newer.
//! //!
//! # Supported YubiKeys //! # Supported YubiKeys
//! - [YubiKey 4] series //! - [YubiKey 4] series
@@ -130,8 +130,7 @@
#![cfg_attr(docsrs, feature(doc_cfg))] #![cfg_attr(docsrs, feature(doc_cfg))]
#![doc( #![doc(
html_logo_url = "https://raw.githubusercontent.com/iqlusioninc/yubikey.rs/main/img/logo.png", html_logo_url = "https://raw.githubusercontent.com/iqlusioninc/yubikey.rs/main/img/logo.png"
html_root_url = "https://docs.rs/yubikey/0.5.0"
)] )]
#![forbid(unsafe_code)] #![forbid(unsafe_code)]
#![warn(missing_docs, rust_2018_idioms, trivial_casts, unused_qualifications)] #![warn(missing_docs, rust_2018_idioms, trivial_casts, unused_qualifications)]
+3 -4
View File
@@ -33,7 +33,6 @@
use crate::{Error, Result}; use crate::{Error, Result};
use log::error; use log::error;
use rand_core::{OsRng, RngCore}; use rand_core::{OsRng, RngCore};
use std::convert::{TryFrom, TryInto};
use zeroize::{Zeroize, Zeroizing}; use zeroize::{Zeroize, Zeroizing};
#[cfg(feature = "untested")] #[cfg(feature = "untested")]
@@ -43,7 +42,7 @@ use crate::{
yubikey::YubiKey, yubikey::YubiKey,
}; };
use des::{ use des::{
cipher::{generic_array::GenericArray, BlockDecrypt, BlockEncrypt, NewBlockCipher}, cipher::{generic_array::GenericArray, BlockDecrypt, BlockEncrypt, KeyInit},
TdesEde3, TdesEde3,
}; };
#[cfg(feature = "untested")] #[cfg(feature = "untested")]
@@ -138,7 +137,7 @@ impl MgmKey {
} }
let mut mgm = [0u8; DES_LEN_3DES]; let mut mgm = [0u8; DES_LEN_3DES];
pbkdf2::<Hmac<Sha1>>(pin, &salt, ITER_MGM_PBKDF2, &mut mgm); pbkdf2::<Hmac<Sha1>>(pin, salt, ITER_MGM_PBKDF2, &mut mgm);
MgmKey::from_bytes(mgm) MgmKey::from_bytes(mgm)
} }
@@ -191,7 +190,7 @@ impl MgmKey {
pub fn set_manual(&self, yubikey: &mut YubiKey, require_touch: bool) -> Result<()> { pub fn set_manual(&self, yubikey: &mut YubiKey, require_touch: bool) -> Result<()> {
let txn = yubikey.begin_transaction()?; let txn = yubikey.begin_transaction()?;
txn.set_mgm_key(&self, require_touch).map_err(|e| { txn.set_mgm_key(self, require_touch).map_err(|e| {
// Log a warning, since the device mgm key is corrupt or we're in a state // Log a warning, since the device mgm key is corrupt or we're in a state
// where we can't set the mgm key. // where we can't set the mgm key.
error!("could not set new derived mgm key, err = {}", e); error!("could not set new derived mgm key, err = {}", e);
-1
View File
@@ -32,7 +32,6 @@
use crate::{consts::CB_OBJ_MAX, piv::SlotId, serialization::*, Error, Result, YubiKey}; use crate::{consts::CB_OBJ_MAX, piv::SlotId, serialization::*, Error, Result, YubiKey};
use log::error; use log::error;
use std::convert::{TryFrom, TryInto};
const OBJ_MSCMAP: u32 = 0x005f_ff10; const OBJ_MSCMAP: u32 = 0x005f_ff10;
+2 -2
View File
@@ -111,7 +111,7 @@ impl MsRoots {
let mut data_chunk: usize; let mut data_chunk: usize;
let data = &self.0; let data = &self.0;
let data_len = data.len(); let data_len = data.len();
let n_objs: usize;
let txn = yubikey.begin_transaction()?; let txn = yubikey.begin_transaction()?;
if data_len == 0 { if data_len == 0 {
@@ -119,7 +119,7 @@ impl MsRoots {
} }
// Calculate number of objects required to store blob // Calculate number of objects required to store blob
n_objs = (data_len / (CB_OBJ_MAX - CB_OBJ_TAG_MAX)) + 1; let n_objs: usize = (data_len / (CB_OBJ_MAX - CB_OBJ_TAG_MAX)) + 1;
if n_objs > 5 { if n_objs > 5 {
return Err(Error::SizeError); return Err(Error::SizeError);
+31 -7
View File
@@ -54,8 +54,13 @@ use crate::{
}; };
use elliptic_curve::sec1::EncodedPoint as EcPublicKey; use elliptic_curve::sec1::EncodedPoint as EcPublicKey;
use log::{debug, error, warn}; use log::{debug, error, warn};
use p256::NistP256;
use p384::NistP384;
use rsa::{BigUint, RsaPublicKey}; use rsa::{BigUint, RsaPublicKey};
use std::{convert::TryFrom, str::FromStr}; use std::{
fmt::{Display, Formatter},
str::FromStr,
};
#[cfg(feature = "untested")] #[cfg(feature = "untested")]
use { use {
@@ -83,7 +88,7 @@ const KEYDATA_RSA_EXP: u64 = 65537;
/// Slot identifiers. /// Slot identifiers.
/// <https://developers.yubico.com/PIV/Introduction/Certificate_slots.html> /// <https://developers.yubico.com/PIV/Introduction/Certificate_slots.html>
#[derive(Clone, Copy, Debug, PartialEq)] #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Ord, PartialOrd)]
pub enum SlotId { pub enum SlotId {
/// This certificate and its associated private key is used to authenticate the card /// This certificate and its associated private key is used to authenticate the card
/// and the cardholder. This slot is used for things like system login. The end user /// and the cardholder. This slot is used for things like system login. The end user
@@ -151,6 +156,15 @@ impl From<SlotId> for u8 {
} }
} }
impl Display for SlotId {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
SlotId::Retired(r) => write!(f, "{:?}", r),
_ => write!(f, "{:?}", self),
}
}
}
impl FromStr for SlotId { impl FromStr for SlotId {
type Err = Error; type Err = Error;
@@ -182,7 +196,7 @@ impl SlotId {
/// Retired slot IDs. /// Retired slot IDs.
#[allow(missing_docs)] #[allow(missing_docs)]
#[derive(Clone, Copy, Debug, PartialEq)] #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub enum RetiredSlotId { pub enum RetiredSlotId {
R1, R1,
R2, R2,
@@ -293,6 +307,12 @@ impl From<RetiredSlotId> for u8 {
} }
} }
impl Display for RetiredSlotId {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{:?}", self)
}
}
impl RetiredSlotId { impl RetiredSlotId {
/// Returns the [`ObjectId`] that corresponds to a given [`RetiredSlotId`]. /// Returns the [`ObjectId`] that corresponds to a given [`RetiredSlotId`].
pub(crate) fn object_id(self) -> ObjectId { pub(crate) fn object_id(self) -> ObjectId {
@@ -657,10 +677,14 @@ pub fn generate(
let point = tlv.value.to_vec(); let point = tlv.value.to_vec();
if let AlgorithmId::EccP256 = algorithm { match algorithm {
EcPublicKey::from_bytes(point).map(PublicKeyInfo::EcP256) AlgorithmId::EccP256 => {
} else { EcPublicKey::<NistP256>::from_bytes(point).map(PublicKeyInfo::EcP256)
EcPublicKey::from_bytes(point).map(PublicKeyInfo::EcP384) }
AlgorithmId::EccP384 => {
EcPublicKey::<NistP384>::from_bytes(point).map(PublicKeyInfo::EcP384)
}
_ => return Err(Error::AlgorithmError),
} }
.map_err(|_| Error::InvalidObject) .map_err(|_| Error::InvalidObject)
} }
+1 -1
View File
@@ -3,7 +3,6 @@
use crate::{Result, YubiKey}; use crate::{Result, YubiKey};
use std::{ use std::{
borrow::Cow, borrow::Cow,
convert::TryInto,
ffi::CStr, ffi::CStr,
sync::{Arc, Mutex}, sync::{Arc, Mutex},
}; };
@@ -45,6 +44,7 @@ impl Context {
c.list_readers(reader_names)?.collect() c.list_readers(reader_names)?.collect()
}; };
#[allow(clippy::needless_collect)]
let readers: Vec<_> = reader_cstrs let readers: Vec<_> = reader_cstrs
.iter() .iter()
.map(|name| Reader::new(name, Arc::clone(ctx))) .map(|name| Reader::new(name, Arc::clone(ctx)))
+2 -11
View File
@@ -65,7 +65,7 @@ impl Default for SettingSource {
/// These can be configured globally in `/etc/yubico/yubikeypiv.conf` by a /// These can be configured globally in `/etc/yubico/yubikeypiv.conf` by a
/// system administrator, or by the local user via `YUBIKEY_PIV_*` environment /// system administrator, or by the local user via `YUBIKEY_PIV_*` environment
/// variables. /// variables.
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug, Default)]
pub struct Setting { pub struct Setting {
/// Boolean value /// Boolean value
pub value: bool, pub value: bool,
@@ -99,7 +99,7 @@ impl Setting {
} }
let (name, value) = { let (name, value) = {
let mut parts = line.splitn(1, '='); let mut parts = line.splitn(2, '=');
let name = parts.next(); let name = parts.next();
let value = parts.next(); let value = parts.next();
match (name, value, parts.next()) { match (name, value, parts.next()) {
@@ -130,12 +130,3 @@ impl Setting {
}) })
} }
} }
impl Default for Setting {
fn default() -> Self {
Self {
value: false,
source: SettingSource::default(),
}
}
}
-1
View File
@@ -11,7 +11,6 @@ use crate::{
Buffer, ObjectId, Buffer, ObjectId,
}; };
use log::{error, trace}; use log::{error, trace};
use std::convert::TryInto;
use zeroize::Zeroizing; use zeroize::Zeroizing;
#[cfg(feature = "untested")] #[cfg(feature = "untested")]
-1
View File
@@ -45,7 +45,6 @@ use log::{error, info};
use pcsc::Card; use pcsc::Card;
use rand_core::{OsRng, RngCore}; use rand_core::{OsRng, RngCore};
use std::{ use std::{
convert::{TryFrom, TryInto},
fmt::{self, Display}, fmt::{self, Display},
str::FromStr, str::FromStr,
}; };
+34 -1
View File
@@ -8,7 +8,7 @@ use log::trace;
use rand_core::{OsRng, RngCore}; use rand_core::{OsRng, RngCore};
use rsa::{hash::Hash::SHA2_256, PaddingScheme, PublicKey}; use rsa::{hash::Hash::SHA2_256, PaddingScheme, PublicKey};
use sha2::{Digest, Sha256}; use sha2::{Digest, Sha256};
use std::{convert::TryInto, env, sync::Mutex}; use std::{env, sync::Mutex};
use x509::RelativeDistinguishedName; use x509::RelativeDistinguishedName;
use yubikey::{ use yubikey::{
certificate::{Certificate, PublicKeyInfo}, certificate::{Certificate, PublicKeyInfo},
@@ -241,3 +241,36 @@ fn generate_self_signed_ec_cert() {
use p256::ecdsa::signature::Verifier; use p256::ecdsa::signature::Verifier;
assert!(vk.verify(msg, &sig).is_ok()); assert!(vk.verify(msg, &sig).is_ok());
} }
#[test]
#[ignore]
fn test_slot_id_display() {
assert_eq!(format!("{}", SlotId::Authentication), "Authentication");
assert_eq!(format!("{}", SlotId::Signature), "Signature");
assert_eq!(format!("{}", SlotId::KeyManagement), "KeyManagement");
assert_eq!(
format!("{}", SlotId::CardAuthentication),
"CardAuthentication"
);
assert_eq!(format!("{}", SlotId::Attestation), "Attestation");
assert_eq!(format!("{}", SlotId::Retired(RetiredSlotId::R1)), "R1");
assert_eq!(format!("{}", SlotId::Retired(RetiredSlotId::R2)), "R2");
assert_eq!(format!("{}", SlotId::Retired(RetiredSlotId::R3)), "R3");
assert_eq!(format!("{}", SlotId::Retired(RetiredSlotId::R4)), "R4");
assert_eq!(format!("{}", SlotId::Retired(RetiredSlotId::R5)), "R5");
assert_eq!(format!("{}", SlotId::Retired(RetiredSlotId::R6)), "R6");
assert_eq!(format!("{}", SlotId::Retired(RetiredSlotId::R7)), "R7");
assert_eq!(format!("{}", SlotId::Retired(RetiredSlotId::R8)), "R8");
assert_eq!(format!("{}", SlotId::Retired(RetiredSlotId::R9)), "R9");
assert_eq!(format!("{}", SlotId::Retired(RetiredSlotId::R10)), "R10");
assert_eq!(format!("{}", SlotId::Retired(RetiredSlotId::R11)), "R11");
assert_eq!(format!("{}", SlotId::Retired(RetiredSlotId::R12)), "R12");
assert_eq!(format!("{}", SlotId::Retired(RetiredSlotId::R13)), "R13");
assert_eq!(format!("{}", SlotId::Retired(RetiredSlotId::R14)), "R14");
assert_eq!(format!("{}", SlotId::Retired(RetiredSlotId::R15)), "R15");
assert_eq!(format!("{}", SlotId::Retired(RetiredSlotId::R16)), "R16");
assert_eq!(format!("{}", SlotId::Retired(RetiredSlotId::R17)), "R17");
assert_eq!(format!("{}", SlotId::Retired(RetiredSlotId::R18)), "R18");
assert_eq!(format!("{}", SlotId::Retired(RetiredSlotId::R19)), "R19");
assert_eq!(format!("{}", SlotId::Retired(RetiredSlotId::R20)), "R20");
}