Upgrade dependencies; bump version to v0.9.0-pre (#665)

Note: this is not a release, but bumping the version to reflect breaking
changes that have not yet been released.

The following dependencies have been upgraded to new stable releases:
- `cipher` v0.5
- `der` v0.8
- `sha1` v0.11
- `sha2` v0.11
- `rand(_core)` v0.10

The following dependencies are prereleases which have been upgraded from
older prerelease versions:
- `aes` v0.9.0-rc.4
- `curve25519-dalek` 5.0.0-pre.6
- `des` v0.9.0-rc.3
- `ecdsa` v0.17.0-rc.16
- `ed25519-dalek` v3.0.0-pre.6
- `elliptic-curve` v0.14.0-rc.29
- `p256` v0.14.0-rc.8
- `p384` v0.14.0-rc.8
- `pbkdf2` v0.13.0-rc.10
- `rsa` v0.10.0-rc.17
- `signature` v3.0.0-rc.10
- `x25519-dalek` v3.0.0-pre.6
This commit is contained in:
Tony Arcieri (iqlusion)
2026-04-02 13:35:37 -06:00
committed by GitHub
parent 872ba35f54
commit 95babac2d4
11 changed files with 466 additions and 246 deletions
Generated
+404 -169
View File
File diff suppressed because it is too large Load Diff
+20 -21
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "yubikey" name = "yubikey"
version = "0.8.0" version = "0.9.0-pre"
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
@@ -20,36 +20,35 @@ rust-version = "1.85"
members = [".", "cli"] members = [".", "cli"]
[workspace.dependencies] [workspace.dependencies]
sha2 = "0.11.0-rc.2" sha2 = "0.11"
x509-cert = { version = "0.3.0-rc.2", features = ["builder", "hazmat"] } x509-cert = { version = "0.3.0-rc.4", features = ["builder", "hazmat"] }
[dependencies] [dependencies]
aes = { version = "0.9.0-rc.1", features = ["zeroize"] } aes = { version = "0.9.0-rc.4", features = ["zeroize"] }
bitflags = "2.5.0" bitflags = "2.5.0"
cipher = { version = "0.5.0-rc.1", features = ["rand_core"] } cipher = { version = "0.5", features = ["getrandom", "rand_core"] }
der = "0.8.0-rc.9" curve25519-dalek = "5.0.0-pre.6"
des = "0.9.0-rc.1" der = "0.8"
elliptic-curve = "0.14.0-rc.13" des = "0.9.0-rc.3"
ecdsa = { version = "0.17.0-rc.16", features = ["digest", "pem"] }
ed25519-dalek = { version = "3.0.0-pre.6", features = ["alloc", "pkcs8"] }
elliptic-curve = "0.14.0-rc.29"
hex = { package = "base16ct", version = "0.2", features = ["alloc"] } hex = { package = "base16ct", version = "0.2", features = ["alloc"] }
log = "0.4" log = "0.4"
nom = "8" nom = "8"
ecdsa = { version = "0.17.0-rc.6", features = ["digest", "pem"] } p256 = "0.14.0-rc.8"
p256 = "=0.14.0-pre.11" p384 = "0.14.0-rc.8"
p384 = "=0.14.0-pre.11" pbkdf2 = { version = "0.13.0-rc.10", default-features = false, features = ["hmac"] }
pbkdf2 = { version = "0.13.0-rc.1", default-features = false, features = ["hmac"] }
curve25519-dalek = "5.0.0-pre.0"
x25519-dalek = "3.0.0-pre.0"
ed25519-dalek = { version = "3.0.0-pre.0", features = ["alloc", "pkcs8"] }
pcsc = "2.3.1" pcsc = "2.3.1"
rand = "0.9" rand = "0.10"
rand_core = { version = "0.9", features = ["os_rng"] } rand_core = "0.10"
rsa = { version = "0.10.0-rc.8", features = ["sha2"] } rsa = { version = "0.10.0-rc.17", features = ["sha2"] }
secrecy = "0.8" sha1 = { version = "0.11", features = ["oid"] }
sha1 = { version = "0.11.0-rc.2", features = ["oid"] }
sha2 = { workspace = true, features = ["oid"] } sha2 = { workspace = true, features = ["oid"] }
signature = "3.0.0-rc.4" signature = "3.0.0-rc.10"
subtle = "2" subtle = "2"
uuid = { version = "1.2", features = ["v4"] } uuid = { version = "1.2", features = ["v4"] }
x25519-dalek = "3.0.0-pre.6"
x509-cert.workspace = true x509-cert.workspace = true
zeroize = "1" zeroize = "1"
+5 -6
View File
@@ -54,6 +54,7 @@ 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.
### Supported Algorithms ### Supported Algorithms
- **Authentication**: `3DES` - **Authentication**: `3DES`
- **Encryption**: - **Encryption**:
- RSA: `RSA1024`, `RSA2048`, `RSA3072`, `RSA4096` - RSA: `RSA1024`, `RSA2048`, `RSA3072`, `RSA4096`
@@ -76,8 +77,7 @@ Rust **1.60** or newer.
- [YubiKey 4] series - [YubiKey 4] series
- [YubiKey 5] series - [YubiKey 5] series
NOTE: Nano and USB-C variants of the above are also supported. NOTE: Nano and USB-C variants of the above are also supported. NEO series is NOT supported.
Pre-YK4 [YubiKey NEO] series is **NOT** supported (see [#18]).
## Supported Operating Systems ## Supported Operating Systems
@@ -105,8 +105,8 @@ We would appreciate any help testing this functionality and removing the
## Testing ## Testing
To run the full test suite, you'll need a connected YubiKey NEO/4/5 device in To run the full test suite, you'll need a supported YubiKey device connected
the default state (i.e. default PIN/PUK). which is in the default state (i.e. default PIN/PUK).
Tests which run live against a YubiKey device are marked as `#[ignore]` by Tests which run live against a YubiKey device are marked as `#[ignore]` by
default in order to pass when running in a CI environment. To run these default in order to pass when running in a CI environment. To run these
@@ -217,7 +217,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
[msrv-image]: https://img.shields.io/badge/rustc-1.81+-blue.svg [msrv-image]: https://img.shields.io/badge/rustc-1.85+-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/actions/workflows/ci.yml/badge.svg [build-image]: https://github.com/iqlusioninc/yubikey.rs/actions/workflows/ci.yml/badge.svg
@@ -234,7 +234,6 @@ or conditions.
[PC/SC]: https://en.wikipedia.org/wiki/PC/SC [PC/SC]: https://en.wikipedia.org/wiki/PC/SC
[`pcsc` crate]: https://github.com/bluetech/pcsc-rust [`pcsc` crate]: https://github.com/bluetech/pcsc-rust
[yk-guide]: https://developers.yubico.com/PIV/Introduction/YubiKey_and_PIV.html [yk-guide]: https://developers.yubico.com/PIV/Introduction/YubiKey_and_PIV.html
[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 4]: https://support.yubico.com/support/solutions/articles/15000006486-yubikey-4
[YubiKey 5]: https://www.yubico.com/products/yubikey-5-overview/ [YubiKey 5]: https://www.yubico.com/products/yubikey-5-overview/
[yubico-piv-tool]: https://github.com/Yubico/yubico-piv-tool/ [yubico-piv-tool]: https://github.com/Yubico/yubico-piv-tool/
+3 -3
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "yubikey-cli" name = "yubikey-cli"
version = "0.8.0-pre" version = "0.9.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.
@@ -12,7 +12,7 @@ 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" edition = "2021"
rust-version = "1.81" rust-version = "1.85"
[dependencies] [dependencies]
clap = { version = "4", features = ["derive"] } clap = { version = "4", features = ["derive"] }
@@ -23,4 +23,4 @@ once_cell = "1"
sha2.workspace = true sha2.workspace = true
termcolor = "1" termcolor = "1"
x509-cert.workspace = true x509-cert.workspace = true
yubikey = { version = "0.8", path = ".." } yubikey = { version = "=0.9.0-pre", path = ".." }
+2 -4
View File
@@ -25,8 +25,7 @@ Rust **1.60** or newer.
- [YubiKey 4] series - [YubiKey 4] series
- [YubiKey 5] series - [YubiKey 5] series
NOTE: Nano and USB-C variants of the above are also supported. NOTE: Nano and USB-C variants of the above are also supported. NEO series is NOT supported.
Pre-YK4 [YubiKey NEO] series is **NOT** supported (see [#18]).
## Security Warning ## Security Warning
@@ -84,7 +83,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.60+-blue.svg [rustc-image]: https://img.shields.io/badge/rustc-1.85+-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/
@@ -98,7 +97,6 @@ or conditions.
[PIV]: https://piv.idmanagement.gov/ [PIV]: https://piv.idmanagement.gov/
[yk-guide]: https://developers.yubico.com/PIV/Introduction/YubiKey_and_PIV.html [yk-guide]: https://developers.yubico.com/PIV/Introduction/YubiKey_and_PIV.html
[Yubico]: https://www.yubico.com/ [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 4]: https://support.yubico.com/support/solutions/articles/15000006486-yubikey-4
[YubiKey 5]: https://www.yubico.com/products/yubikey-5-overview/ [YubiKey 5]: https://www.yubico.com/products/yubikey-5-overview/
[yubico-piv-tool]: https://github.com/Yubico/yubico-piv-tool/ [yubico-piv-tool]: https://github.com/Yubico/yubico-piv-tool/
+6 -8
View File
@@ -31,7 +31,8 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
use crate::{Result, YubiKey}; use crate::{Result, YubiKey};
use rand_core::{OsRng, RngCore, TryRngCore}; use cipher::common::Generate;
use rand_core::CryptoRng;
use std::fmt::{self, Debug, Display}; use std::fmt::{self, Debug, Display};
/// CCCID offset /// CCCID offset
@@ -66,15 +67,12 @@ impl CardId {
/// Generate a random CCC Card ID /// Generate a random CCC Card ID
pub fn generate() -> Self { pub fn generate() -> Self {
let mut rng = OsRng.unwrap_err(); Self(Generate::generate())
Self::generate_from_rng(&mut rng)
} }
/// Generate a random CCC Card ID from an [`RngCore`] /// Generate a random CCC Card ID from an [`Rng`]
pub fn generate_from_rng<R: RngCore + ?Sized>(rng: &mut R) -> Self { pub fn generate_from_rng<R: CryptoRng + ?Sized>(rng: &mut R) -> Self {
let mut id = [0u8; Self::BYTE_SIZE]; Self(Generate::generate_from_rng(rng))
rng.fill_bytes(&mut id);
Self(id)
} }
} }
+6 -7
View File
@@ -39,7 +39,8 @@ use crate::{
}; };
use bitflags::bitflags; use bitflags::bitflags;
use cipher::{ use cipher::{
typenum::Unsigned, BlockCipherDecrypt, BlockCipherEncrypt, Key, KeyInit, KeySizeUser, common::Generate, typenum::Unsigned, BlockCipherDecrypt, BlockCipherEncrypt, Key, KeyInit,
KeySizeUser,
}; };
use log::error; use log::error;
use rand::TryCryptoRng; use rand::TryCryptoRng;
@@ -202,16 +203,16 @@ impl MgmKey {
pub fn generate(alg: MgmAlgorithmId, rng: &mut impl TryCryptoRng) -> Result<Self> { pub fn generate(alg: MgmAlgorithmId, rng: &mut impl TryCryptoRng) -> Result<Self> {
match alg { match alg {
MgmAlgorithmId::ThreeDes => { MgmAlgorithmId::ThreeDes => {
des::TdesEde3::try_generate_key_with_rng(rng).map(MgmKeyKind::Tdes) Key::<des::TdesEde3>::try_generate_from_rng(rng).map(MgmKeyKind::Tdes)
} }
MgmAlgorithmId::Aes128 => { MgmAlgorithmId::Aes128 => {
aes::Aes128::try_generate_key_with_rng(rng).map(MgmKeyKind::Aes128) Key::<aes::Aes128>::try_generate_from_rng(rng).map(MgmKeyKind::Aes128)
} }
MgmAlgorithmId::Aes192 => { MgmAlgorithmId::Aes192 => {
aes::Aes192::try_generate_key_with_rng(rng).map(MgmKeyKind::Aes192) Key::<aes::Aes192>::try_generate_from_rng(rng).map(MgmKeyKind::Aes192)
} }
MgmAlgorithmId::Aes256 => { MgmAlgorithmId::Aes256 => {
aes::Aes256::try_generate_key_with_rng(rng).map(MgmKeyKind::Aes256) Key::<aes::Aes256>::try_generate_from_rng(rng).map(MgmKeyKind::Aes256)
} }
} }
.map_err(|e| { .map_err(|e| {
@@ -295,7 +296,6 @@ impl MgmKey {
let mut mgm = Key::<des::TdesEde3>::default(); let mut mgm = Key::<des::TdesEde3>::default();
pbkdf2_hmac::<Sha1>(pin, salt, ITER_MGM_PBKDF2, &mut mgm); pbkdf2_hmac::<Sha1>(pin, salt, ITER_MGM_PBKDF2, &mut mgm);
des::TdesEde3::weak_key_test(&mgm).map_err(|_| Error::KeyError)?;
Ok(Self(MgmKeyKind::Tdes(mgm))) Ok(Self(MgmKeyKind::Tdes(mgm)))
} }
@@ -480,7 +480,6 @@ impl MgmKey {
MgmAlgorithmId::ThreeDes => { MgmAlgorithmId::ThreeDes => {
let key = let key =
Key::<des::TdesEde3>::try_from(bytes.as_ref()).map_err(|_| Error::SizeError)?; Key::<des::TdesEde3>::try_from(bytes.as_ref()).map_err(|_| Error::SizeError)?;
des::TdesEde3::weak_key_test(&key).map_err(|_| Error::KeyError)?;
Ok(MgmKeyKind::Tdes(key)) Ok(MgmKeyKind::Tdes(key))
} }
MgmAlgorithmId::Aes128 => Key::<aes::Aes128>::try_from(bytes.as_ref()) MgmAlgorithmId::Aes128 => Key::<aes::Aes128>::try_from(bytes.as_ref())
+1 -1
View File
@@ -53,7 +53,7 @@ use crate::{
yubikey::YubiKey, yubikey::YubiKey,
Buffer, ObjectId, Buffer, ObjectId,
}; };
use elliptic_curve::{sec1::EncodedPoint as EcPublicKey, PublicKey}; use elliptic_curve::{sec1::Sec1Point as EcPublicKey, PublicKey};
use log::{debug, error, warn}; use log::{debug, error, warn};
use p256::NistP256; use p256::NistP256;
use p384::NistP384; use p384::NistP384;
+2 -7
View File
@@ -41,7 +41,7 @@ use std::{
}; };
/// Source of how a setting was configured. /// Source of how a setting was configured.
#[derive(Clone, Copy, Debug, Eq, PartialEq)] #[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
pub enum SettingSource { pub enum SettingSource {
/// User-specified setting: sourced via `YUBIKEY_PIV_*` environment vars. /// User-specified setting: sourced via `YUBIKEY_PIV_*` environment vars.
User, User,
@@ -51,15 +51,10 @@ pub enum SettingSource {
Admin, Admin,
/// Default setting. /// Default setting.
#[default]
Default, Default,
} }
impl Default for SettingSource {
fn default() -> Self {
Self::Default
}
}
/// Setting booleans: configuration values sourced from a file or the environment. /// Setting booleans: configuration values sourced from a file or the environment.
/// ///
/// These can be configured globally in `/etc/yubico/yubikeypiv.conf` by a /// These can be configured globally in `/etc/yubico/yubikeypiv.conf` by a
+10 -11
View File
@@ -41,9 +41,10 @@ use crate::{
reader::{Context, Reader}, reader::{Context, Reader},
transaction::Transaction, transaction::Transaction,
}; };
use cipher::common::getrandom::SysRng;
use log::{error, info}; use log::{error, info};
use pcsc::Card; use pcsc::Card;
use rand_core::{OsRng, RngCore, TryRngCore}; use rand_core::TryRng;
use std::{ use std::{
cmp::{Ord, Ordering}, cmp::{Ord, Ordering},
fmt::{self, Display}, fmt::{self, Display},
@@ -60,7 +61,6 @@ use {
transaction::ChangeRefAction, transaction::ChangeRefAction,
Buffer, ObjectId, Buffer, ObjectId,
}, },
secrecy::ExposeSecret,
std::time::{SystemTime, UNIX_EPOCH}, std::time::{SystemTime, UNIX_EPOCH},
}; };
@@ -77,7 +77,8 @@ pub(crate) const KEY_CARDMGM: u8 = 0x9b;
const TAG_DYN_AUTH: u8 = 0x7c; const TAG_DYN_AUTH: u8 = 0x7c;
/// Cached YubiKey PIN. /// Cached YubiKey PIN.
pub type CachedPin = secrecy::SecretVec<u8>; // TODO(tarcieri): add a newtype for this with a zeroize impl
pub type CachedPin = Vec<u8>;
/// YubiKey serial number. /// YubiKey serial number.
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, PartialOrd, Ord)] #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, PartialOrd, Ord)]
@@ -320,10 +321,7 @@ impl YubiKey {
pcsc::Disposition::ResetCard, pcsc::Disposition::ResetCard,
)?; )?;
let pin = self let pin = self.pin.as_ref().map(|p| Buffer::new(p.clone()));
.pin
.as_ref()
.map(|p| Buffer::new(p.expose_secret().clone()));
let txn = Transaction::new(&mut self.card)?; let txn = Transaction::new(&mut self.card)?;
txn.select_piv_application()?; txn.select_piv_application()?;
@@ -443,8 +441,9 @@ impl YubiKey {
data.push(challenge_len as u8); data.push(challenge_len as u8);
let mut host_challenge = vec![0u8; challenge_len]; let mut host_challenge = vec![0u8; challenge_len];
let mut rng = OsRng.unwrap_err(); SysRng
rng.fill_bytes(&mut host_challenge); .try_fill_bytes(&mut host_challenge)
.map_err(|_| Error::GenericError)?;
data.extend_from_slice(&host_challenge); data.extend_from_slice(&host_challenge);
@@ -501,7 +500,7 @@ impl YubiKey {
} }
if !pin.is_empty() { if !pin.is_empty() {
self.pin = Some(CachedPin::new(pin.into())) self.pin = Some(pin.into())
} }
Ok(()) Ok(())
@@ -557,7 +556,7 @@ impl YubiKey {
} }
if !new_pin.is_empty() { if !new_pin.is_empty() {
self.pin = Some(CachedPin::new(new_pin.into())); self.pin = Some(new_pin.into());
} }
Ok(()) Ok(())
+3 -5
View File
@@ -3,9 +3,9 @@
#![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)]
use cipher::common::{getrandom::SysRng, Generate};
use log::trace; use log::trace;
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use rand_core::{OsRng, RngCore, TryRngCore};
use rsa::{pkcs1v15, RsaPublicKey}; use rsa::{pkcs1v15, RsaPublicKey};
use sha2::{Digest, Sha256}; use sha2::{Digest, Sha256};
use signature::hazmat::PrehashVerifier; use signature::hazmat::PrehashVerifier;
@@ -129,7 +129,7 @@ fn test_verify_pin() {
#[test] #[test]
#[ignore] #[ignore]
fn test_set_mgmkey() { fn test_set_mgmkey() {
let mut rng = OsRng; let mut rng = SysRng;
let mut yubikey = match YUBIKEY.lock() { let mut yubikey = match YUBIKEY.lock() {
Ok(yubikey) => yubikey, Ok(yubikey) => yubikey,
Err(poison) => poison.into_inner(), Err(poison) => poison.into_inner(),
@@ -190,9 +190,7 @@ fn generate_self_signed_cert<KT: yubikey_signer::KeyType>() -> Certificate {
// 0x80 0x00 ... (20bytes) is invalid because of high MSB (serial will keep the sign) // 0x80 0x00 ... (20bytes) is invalid because of high MSB (serial will keep the sign)
// we'll limit ourselves to 19 bytes serial. // we'll limit ourselves to 19 bytes serial.
let mut serial = [0u8; 19]; let serial = <[u8; 19]>::generate();
let mut rng = OsRng.unwrap_err();
rng.fill_bytes(&mut serial);
let serial = SerialNumber::new(&serial[..]).expect("serial can't be more than 20 bytes long"); let serial = SerialNumber::new(&serial[..]).expect("serial can't be more than 20 bytes long");
let validity = Validity::from_now(Duration::new(500000, 0)).unwrap(); let validity = Validity::from_now(Duration::new(500000, 0)).unwrap();