Compare commits

...

34 Commits

Author SHA1 Message Date
Tony Arcieri (iqlusion) b571f81007 yubikey-cli v0.6.0 (#404) 2022-08-10 17:23:41 -07:00
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
Tony Arcieri (iqlusion) 86d482b38d yubikey-cli v0.5.0 (#328) 2021-11-21 08:10:17 -08:00
Tony Arcieri (iqlusion) edf74871ba yubikey v0.5.0 (#327) 2021-11-21 07:42:39 -08:00
Tony Arcieri (iqlusion) b11d5c409b Cargo.lock: bump dependencies (#326) 2021-11-21 07:06:17 -08:00
str4d 52107281df nom 7 (#322) 2021-10-19 06:38:38 -07:00
Shella Stephens bcef792f69 Update dependencies & add RUSTSEC-2020-0071 to audit.toml (#323) 2021-10-18 17:07:32 -06:00
Tony Arcieri (iqlusion) 10a7ead932 Cargo.lock: bump dependencies (#317) 2021-09-11 13:55:34 -07:00
Benno Rice 54ce90d51d Update dependencies (#315)
* Update rsa dependency to 0.5

* Update pbkdf dependency to 0.9

* Update x509-parser dependency to 0.11

* Update crypto-bigint subdepdendency to 0.2.6
2021-09-10 10:44:59 -07:00
Tony Arcieri (iqlusion) 3905104b52 Cargo.lock: bump dependencies (#308) 2021-08-20 18:09:51 -07:00
Tony Arcieri (iqlusion) 97e15abcee Cargo.lock: bump dependencies (#304) 2021-07-26 14:52:06 -07:00
Shella Stephens da7e7af109 Add deps.rs badge (#299) 2021-07-19 15:07:41 -07:00
Shella Stephens 6e96087b93 Cargo.lock: update deps (#300) 2021-07-19 15:00:16 -07:00
Tony Arcieri (iqlusion) f3bb858a2f Cargo.lock: bump dependencies (#298) 2021-07-19 09:05:32 -07:00
Tony Arcieri (iqlusion) ac72797d1f yubikey v0.4.2 (#291) 2021-07-13 06:35:53 -07:00
Tony Arcieri (iqlusion) fdd3b8730a Make yubikey::Buffer a pub type (#290) 2021-07-13 06:05:24 -07:00
Tony Arcieri (iqlusion) d51ec0a225 Have YubiKey::block_puk take &mut self as argument (#289)
This is effectively the same signature; it just uses `self` instead of a
named argument.
2021-07-13 05:55:24 -07:00
Tony Arcieri (iqlusion) d601c33ba3 yubikey v0.4.1 (#288) 2021-07-12 19:37:12 -07:00
Tony Arcieri (iqlusion) 8e52d75992 Rename Ccc to CccId (#287) 2021-07-12 19:28:46 -07:00
Tony Arcieri (iqlusion) 42ae5fb974 Rename SettingValue to Setting. (#286)
Breaking change, but the crate is fresh and there's time to yank and
republish.
2021-07-12 17:36:42 -07:00
27 changed files with 967 additions and 553 deletions
+5
View File
@@ -0,0 +1,5 @@
[advisories]
ignore = [
"RUSTSEC-2020-0071", # time
"RUSTSEC-2020-0159", # chrono
]
+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
+52 -1
View File
@@ -4,7 +4,58 @@ 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.4.0 (2021-07-12) ## 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)
### Changed
- Update `rsa` dependency to 0.5 ([#315])
- Update `pbkdf2` dependency to 0.9 ([#315])
- Update `x509-parser` dependency to 0.12 ([#315], [#322])
- Update `nom` to v7.0 ([#322])
[#315]: https://github.com/iqlusioninc/yubikey.rs/pull/315
[#322]: https://github.com/iqlusioninc/yubikey.rs/pull/322
## 0.4.2 (2021-07-13)
### Added
- Make `yubikey::Buffer` a pub type ([#290])
### Changed
- Have `YubiKey::block_puk` take `&mut self` as argument ([#289])
[#289]: https://github.com/iqlusioninc/yubikey.rs/pull/289
[#290]: https://github.com/iqlusioninc/yubikey.rs/pull/290
## 0.4.1 (2021-07-12)
### Changed
- Rename `SettingValue` to `Setting` ([#286])
- Rename `Ccc` to `CccId` ([#287])
[#286]: https://github.com/iqlusioninc/yubikey.rs/pull/286
[#287]: https://github.com/iqlusioninc/yubikey.rs/pull/287
## 0.4.0 (2021-07-12) [YANKED]
### Added ### Added
- `Result` alias ([#271]) - `Result` alias ([#271])
Generated
+695 -323
View File
File diff suppressed because it is too large Load Diff
+19 -18
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "yubikey" name = "yubikey"
version = "0.4.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
@@ -8,12 +8,13 @@ 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,33 +22,33 @@ members = [".", "cli"]
[dependencies] [dependencies]
chrono = "0.4" chrono = "0.4"
cookie-factory = "0.3" cookie-factory = "0.3"
der-parser = "5" 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 = "6" 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.8", 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.4" rsa = "0.6"
secrecy = "0.7" 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.9" x509-parser = "0.14"
zeroize = "1" zeroize = "1"
[dev-dependencies] [dev-dependencies]
env_logger = "0.8" env_logger = "0.9"
lazy_static = "1" lazy_static = "1"
[features] [features]
+9 -6
View File
@@ -5,9 +5,10 @@
[![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]
Pure Rust cross-platform host-side driver for [YubiKey] devices from [Yubico] Pure Rust cross-platform host-side driver for [YubiKey] devices from [Yubico]
with support for public-key encryption and digital signatures using the with support for public-key encryption and digital signatures using the
@@ -25,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,
@@ -35,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
@@ -122,7 +123,7 @@ Yubico's [yubico-piv-tool], a C library/CLI program. The original library
was licensed under a [2-Clause BSD License][BSDL], which this library inherits was licensed under a [2-Clause BSD License][BSDL], which this library inherits
as a derived work. as a derived work.
Copyright (c) 2014-2021 Yubico AB, Tony Arcieri Copyright (c) 2014-2022 Yubico AB, Tony Arcieri
All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
@@ -164,11 +165,13 @@ 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
[build-link]: https://github.com/iqlusioninc/yubikey.rs/actions [build-link]: https://github.com/iqlusioninc/yubikey.rs/actions
[deps-image]: https://deps.rs/repo/github/iqlusioninc/yubikey.rs/status.svg
[deps-link]: https://deps.rs/repo/github/iqlusioninc/yubikey.rs
[//]: # (general links) [//]: # (general links)
+17 -1
View File
@@ -4,6 +4,22 @@ 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; MSRV 1.57 ([#343])
- Migrate from `gumdrop` to `clap` v3 ([#379])
- Bump `yubikey` dependency to v0.6 ([#403])
[#343]: https://github.com/iqlusioninc/yubikey.rs/pull/343
[#379]: https://github.com/iqlusioninc/yubikey.rs/pull/379
[#403]: https://github.com/iqlusioninc/yubikey.rs/pull/403
## 0.5.0 (2021-11-21)
### Changed
- Bump `yubikey` dependency to v0.5 ([#327])
[#327]: https://github.com/iqlusioninc/yubikey.rs/pull/327
## 0.4.0 (2021-07-12) ## 0.4.0 (2021-07-12)
### Changed ### Changed
- Switch to renamed `yubikey` crate ([#283]) - Switch to renamed `yubikey` crate ([#283])
@@ -30,7 +46,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- `status` command ([#72], [#74]) - `status` command ([#72], [#74])
### Changed ### Changed
- Bump `yubikey-piv` to v0.1.0 ([#180]) - Bump `yubikey-piv` to v0.1 ([#180])
- Bump `x509-parser` to v0.8 ([#181]) - Bump `x509-parser` to v0.8 ([#181])
- Bump `sha2` to v0.9 ([#182]) - Bump `sha2` to v0.9 ([#182])
- Rename `list` command to `readers`; improve usage ([#71]) - Rename `list` command to `readers`; improve usage ([#71])
+7 -6
View File
@@ -1,25 +1,26 @@
[package] [package]
name = "yubikey-cli" name = "yubikey-cli"
version = "0.4.0" version = "0.6.0"
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.8" env_logger = "0.9"
lazy_static = "1" lazy_static = "1"
log = "0.4" log = "0.4"
sha2 = "0.9" sha2 = "0.9"
subtle-encoding = "0.5" subtle-encoding = "0.5"
termcolor = "1" termcolor = "1"
x509-parser = "0.9" x509-parser = "0.12"
yubikey = { version = "0.4", path = ".." } yubikey = { version = "0.6", path = ".." }
+3 -7
View File
@@ -18,7 +18,7 @@ utility with general-purpose public-key encryption and signing support.
## Minimum Supported Rust Version ## Minimum Supported Rust Version
Rust **1.51** or newer. Rust **1.57** or newer.
## Supported YubiKeys ## Supported YubiKeys
@@ -35,10 +35,6 @@ an experimental stage and may still contain high-severity issues.
USE AT YOUR OWN RISK! USE AT YOUR OWN RISK!
## Status
WIP. Check back later.
## Code of Conduct ## Code of Conduct
We abide by the [Contributor Covenant][cc-md] and ask that you do as well. We abide by the [Contributor Covenant][cc-md] and ask that you do as well.
@@ -47,7 +43,7 @@ For more information, please see [CODE_OF_CONDUCT.md][cc-md].
## License ## License
Copyright (c) 2014-2021 Yubico AB, Tony Arcieri Copyright (c) 2014-2022 Yubico AB, Tony Arcieri
All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
@@ -88,7 +84,7 @@ or conditions.
[docs-image]: https://docs.rs/yubikey-cli/badge.svg [docs-image]: https://docs.rs/yubikey-cli/badge.svg
[docs-link]: https://docs.rs/yubikey-cli/ [docs-link]: https://docs.rs/yubikey-cli/
[license-image]: https://img.shields.io/badge/license-BSD-blue.svg [license-image]: https://img.shields.io/badge/license-BSD-blue.svg
[rustc-image]: https://img.shields.io/badge/rustc-1.39+-blue.svg [rustc-image]: https://img.shields.io/badge/rustc-1.57+-blue.svg
[maintenance-image]: https://img.shields.io/badge/maintenance-experimental-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-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/
+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 {
+3 -4
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,
}; };
@@ -78,9 +77,9 @@ impl CardId {
/// Cardholder Capability Container (CCC) Identifier. /// Cardholder Capability Container (CCC) Identifier.
#[derive(Copy, Clone, Debug, Eq, PartialEq)] #[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct Ccc(pub [u8; Self::BYTE_SIZE]); pub struct CccId(pub [u8; Self::BYTE_SIZE]);
impl Ccc { impl CccId {
/// CCC size in bytes /// CCC size in bytes
pub const BYTE_SIZE: usize = 51; pub const BYTE_SIZE: usize = 51;
@@ -115,7 +114,7 @@ impl Ccc {
} }
} }
impl Display for Ccc { impl Display for CccId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(str::from_utf8(&hex::encode(&self.0[..])).unwrap()) f.write_str(str::from_utf8(&hex::encode(&self.0[..])).unwrap())
} }
+26 -30
View File
@@ -45,11 +45,9 @@ use log::error;
use num_bigint_dig::BigUint; use num_bigint_dig::BigUint;
use p256::NistP256; 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)
} }
@@ -172,7 +170,7 @@ pub enum PublicKeyInfo {
algorithm: AlgorithmId, algorithm: AlgorithmId,
/// Public key /// Public key
pubkey: RSAPublicKey, pubkey: RsaPublicKey,
}, },
/// EC P-256 keys /// EC P-256 keys
@@ -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,13 +587,13 @@ 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, DerObject}, der::{parse_der_integer, parse_der_sequence_defined_g, DerObject},
error::BerError, error::BerError,
*,
}; };
use nom::{combinator, IResult}; use nom::{combinator, sequence::pair, IResult};
use rsa::{BigUint, RSAPublicKey}; use rsa::{BigUint, RsaPublicKey};
use super::{OID_NIST_P256, OID_NIST_P384}; use super::{OID_NIST_P256, OID_NIST_P384};
use crate::{piv::AlgorithmId, Error, Result}; use crate::{piv::AlgorithmId, Error, Result};
@@ -606,21 +605,18 @@ mod read_pki {
/// publicExponent INTEGER -- e /// publicExponent INTEGER -- e
/// } /// }
/// ``` /// ```
pub(super) fn rsa_pubkey(encoded: &[u8]) -> Result<RSAPublicKey> { pub(super) fn rsa_pubkey(encoded: &[u8]) -> Result<RsaPublicKey> {
fn parse_rsa_pubkey(i: &[u8]) -> IResult<&[u8], DerObject<'_>, BerError> { fn parse_rsa_pubkey(i: &[u8]) -> IResult<&[u8], (DerObject<'_>, DerObject<'_>), BerError> {
parse_der_sequence_defined!(i, parse_der_integer >> parse_der_integer) parse_der_sequence_defined_g(|i, _| pair(parse_der_integer, parse_der_integer)(i))(i)
} }
fn rsa_pubkey_parts(i: &[u8]) -> IResult<&[u8], (BigUint, BigUint), BerError> { fn rsa_pubkey_parts(i: &[u8]) -> IResult<&[u8], (BigUint, BigUint), BerError> {
combinator::map(parse_rsa_pubkey, |object| { combinator::map(parse_rsa_pubkey, |(modulus, public_exponent)| {
let seq = object.as_sequence().expect("is DER sequence"); let n = match modulus.content {
assert_eq!(seq.len(), 2);
let n = match seq[0].content {
BerObjectContent::Integer(s) => BigUint::from_bytes_be(s), BerObjectContent::Integer(s) => BigUint::from_bytes_be(s),
_ => panic!("expected DER integer"), _ => panic!("expected DER integer"),
}; };
let e = match seq[1].content { let e = match public_exponent.content {
BerObjectContent::Integer(s) => BigUint::from_bytes_be(s), BerObjectContent::Integer(s) => BigUint::from_bytes_be(s),
_ => panic!("expected DER integer"), _ => panic!("expected DER integer"),
}; };
@@ -634,7 +630,7 @@ mod read_pki {
_ => return Err(Error::InvalidObject), _ => return Err(Error::InvalidObject),
}; };
RSAPublicKey::new(n, e).map_err(|_| Error::InvalidObject) RsaPublicKey::new(n, e).map_err(|_| Error::InvalidObject)
} }
/// From [RFC 5480](https://tools.ietf.org/html/rfc5480#section-2.1.1): /// From [RFC 5480](https://tools.ietf.org/html/rfc5480#section-2.1.1):
@@ -645,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),
@@ -658,7 +654,7 @@ mod read_pki {
mod write_pki { mod write_pki {
use cookie_factory::{SerializeFn, WriteContext}; use cookie_factory::{SerializeFn, WriteContext};
use rsa::{BigUint, PublicKeyParts, RSAPublicKey}; use rsa::{BigUint, PublicKeyParts, RsaPublicKey};
use std::io::Write; use std::io::Write;
use x509::der::write::{der_integer, der_sequence}; use x509::der::write::{der_integer, der_sequence};
@@ -675,7 +671,7 @@ mod write_pki {
/// } /// }
/// ``` /// ```
pub(super) fn rsa_pubkey<'a, W: Write + 'a>( pub(super) fn rsa_pubkey<'a, W: Write + 'a>(
pubkey: &'a RSAPublicKey, pubkey: &'a RsaPublicKey,
) -> impl SerializeFn<W> + 'a { ) -> impl SerializeFn<W> + 'a {
der_sequence(( der_sequence((
der_integer_biguint(pubkey.n()), der_integer_biguint(pubkey.n()),
-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;
+6 -7
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.4.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)]
@@ -153,12 +152,12 @@ pub mod piv;
mod policy; mod policy;
pub mod reader; pub mod reader;
mod serialization; mod serialization;
mod settings; mod setting;
mod transaction; mod transaction;
mod yubikey; mod yubikey;
pub use crate::{ pub use crate::{
cccid::{CardId, Ccc}, cccid::{CardId, CccId},
certificate::Certificate, certificate::Certificate,
chuid::ChuId, chuid::ChuId,
config::Config, config::Config,
@@ -167,7 +166,7 @@ pub use crate::{
piv::Key, piv::Key,
policy::{PinPolicy, TouchPolicy}, policy::{PinPolicy, TouchPolicy},
reader::Context, reader::Context,
settings::{SettingSource, SettingValue}, setting::{Setting, SettingSource},
yubikey::{CachedPin, Serial, Version, YubiKey}, yubikey::{CachedPin, Serial, Version, YubiKey},
}; };
@@ -180,4 +179,4 @@ pub use uuid::Uuid;
pub type ObjectId = u32; pub type ObjectId = u32;
/// Buffer type (self-zeroizing byte vector) /// Buffer type (self-zeroizing byte vector)
pub(crate) type Buffer = zeroize::Zeroizing<Vec<u8>>; pub type Buffer = zeroize::Zeroizing<Vec<u8>>;
+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);
+38 -14
View File
@@ -48,14 +48,19 @@ use crate::{
error::{Error, Result}, error::{Error, Result},
policy::{PinPolicy, TouchPolicy}, policy::{PinPolicy, TouchPolicy},
serialization::*, serialization::*,
settings, setting,
yubikey::YubiKey, yubikey::YubiKey,
Buffer, ObjectId, Buffer, ObjectId,
}; };
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 rsa::{BigUint, RSAPublicKey}; use p256::NistP256;
use std::{convert::TryFrom, str::FromStr}; use p384::NistP384;
use rsa::{BigUint, RsaPublicKey};
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 {
@@ -481,7 +501,7 @@ pub fn generate(
const SZ_ROCA_BLOCK_ADMIN: &str = "was blocked due to an administrator configuration setting."; const SZ_ROCA_BLOCK_ADMIN: &str = "was blocked due to an administrator configuration setting.";
const SZ_ROCA_DEFAULT: &str = "was permitted by default, but is not recommended. The default behavior will change in a future Yubico release."; const SZ_ROCA_DEFAULT: &str = "was permitted by default, but is not recommended. The default behavior will change in a future Yubico release.";
let setting_roca: settings::SettingValue; let setting_roca: setting::Setting;
match algorithm { match algorithm {
AlgorithmId::Rsa1024 | AlgorithmId::Rsa2048 => { AlgorithmId::Rsa1024 | AlgorithmId::Rsa2048 => {
@@ -489,17 +509,17 @@ pub fn generate(
&& (yubikey.version.minor < 3 && (yubikey.version.minor < 3
|| yubikey.version.minor == 3 && (yubikey.version.patch < 5)) || yubikey.version.minor == 3 && (yubikey.version.patch < 5))
{ {
setting_roca = settings::SettingValue::get(SZ_SETTING_ROCA, true); setting_roca = setting::Setting::get(SZ_SETTING_ROCA, true);
let psz_msg = match setting_roca.source { let psz_msg = match setting_roca.source {
settings::SettingSource::User => { setting::SettingSource::User => {
if setting_roca.value { if setting_roca.value {
SZ_ROCA_ALLOW_USER SZ_ROCA_ALLOW_USER
} else { } else {
SZ_ROCA_BLOCK_USER SZ_ROCA_BLOCK_USER
} }
} }
settings::SettingSource::Admin => { setting::SettingSource::Admin => {
if setting_roca.value { if setting_roca.value {
SZ_ROCA_ALLOW_ADMIN SZ_ROCA_ALLOW_ADMIN
} else { } else {
@@ -624,7 +644,7 @@ pub fn generate(
Ok(PublicKeyInfo::Rsa { Ok(PublicKeyInfo::Rsa {
algorithm, algorithm,
pubkey: RSAPublicKey::new( pubkey: RsaPublicKey::new(
BigUint::from_bytes_be(&modulus), BigUint::from_bytes_be(&modulus),
BigUint::from_bytes_be(&exp), BigUint::from_bytes_be(&exp),
) )
@@ -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)))
+7 -16
View File
@@ -65,8 +65,8 @@ 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 SettingValue { pub struct Setting {
/// Boolean value /// Boolean value
pub value: bool, pub value: bool,
@@ -74,8 +74,8 @@ pub struct SettingValue {
pub source: SettingSource, pub source: SettingSource,
} }
impl SettingValue { impl Setting {
/// Get a [`SettingValue`] value by name. /// Get a setting by name.
pub fn get(key: &str, default: bool) -> Self { pub fn get(key: &str, default: bool) -> Self {
Self::from_file(key) Self::from_file(key)
.or_else(|| Self::from_env(key)) .or_else(|| Self::from_env(key))
@@ -99,7 +99,7 @@ impl SettingValue {
} }
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()) {
@@ -109,7 +109,7 @@ impl SettingValue {
}; };
if name == key { if name == key {
return Some(SettingValue { return Some(Setting {
source: SettingSource::Admin, source: SettingSource::Admin,
value: value == "1" || value == "true", value: value == "1" || value == "true",
}); });
@@ -124,18 +124,9 @@ impl SettingValue {
fn from_env(key: &str) -> Option<Self> { fn from_env(key: &str) -> Option<Self> {
env::var(format!("YUBIKEY_PIV_{}", key)) env::var(format!("YUBIKEY_PIV_{}", key))
.ok() .ok()
.map(|value| SettingValue { .map(|value| Setting {
source: SettingSource::User, source: SettingSource::User,
value: value == "1" || value == "true", value: value == "1" || value == "true",
}) })
} }
} }
impl Default for SettingValue {
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")]
+5 -6
View File
@@ -32,7 +32,7 @@
use crate::{ use crate::{
apdu::{Apdu, Ins}, apdu::{Apdu, Ins},
cccid::Ccc, cccid::CccId,
chuid::ChuId, chuid::ChuId,
config::Config, config::Config,
error::{Error, Result}, error::{Error, Result},
@@ -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,
}; };
@@ -275,8 +274,8 @@ impl YubiKey {
} }
/// Get Cardholder Capability Container (CCC) Identifier. /// Get Cardholder Capability Container (CCC) Identifier.
pub fn cccid(&mut self) -> Result<Ccc> { pub fn cccid(&mut self) -> Result<CccId> {
Ccc::get(self) CccId::get(self)
} }
/// Authenticate to the card using the provided management key (MGM). /// Authenticate to the card using the provided management key (MGM).
@@ -476,12 +475,12 @@ impl YubiKey {
/// Block PUK: permanently prevent the PIN from becoming unblocked. /// Block PUK: permanently prevent the PIN from becoming unblocked.
#[cfg(feature = "untested")] #[cfg(feature = "untested")]
#[cfg_attr(docsrs, doc(cfg(feature = "untested")))] #[cfg_attr(docsrs, doc(cfg(feature = "untested")))]
pub fn block_puk(yubikey: &mut YubiKey) -> Result<()> { pub fn block_puk(&mut self) -> Result<()> {
let mut puk = [0x30, 0x42, 0x41, 0x44, 0x46, 0x30, 0x30, 0x44]; let mut puk = [0x30, 0x42, 0x41, 0x44, 0x46, 0x30, 0x30, 0x44];
let mut tries_remaining: i32 = -1; let mut tries_remaining: i32 = -1;
let mut flags = [0]; let mut flags = [0];
let txn = yubikey.begin_transaction()?; let txn = self.begin_transaction()?;
while tries_remaining != 0 { while tries_remaining != 0 {
// 2 -> change puk // 2 -> change puk
+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");
}