Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ jobs:
# Update this anchor value when bumping MSRV checks.
rust_version:
- stable
- &rust_oldest_version "1.88.0"
- &rust_oldest_version "1.89.0"
os:
- ubuntu-latest
- windows-latest
Expand Down
7 changes: 4 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ authors = [
"Michael Farrell <micolous+git@gmail.com>",
"James Hodgkinson <james@terminaloutcomes.com>",
]
rust-version = "1.88"
rust-version = "1.89"
edition = "2021"
repository = "https://github.com/kanidm/webauthn-rs"
homepage = "https://github.com/kanidm/webauthn-rs"
Expand Down Expand Up @@ -52,8 +52,9 @@ members = [
# Due to --cfg=web_sys_unstable_apis
exclude = ["compat_tester/webauthn-rs-demo-wasm", "tutorial/wasm"]

# [patch.crates-io]
[patch.crates-io]

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
[patch.crates-io]
# [patch.crates-io]

# crypto-glue = { path = "../crypto-glue" }

# crypto-glue = { git = "https://github.com/kanidm/crypto-glue.git", branch = "6.0-webauthn-rs" }

[workspace.dependencies]
Expand All @@ -78,7 +79,7 @@ anyhow = "1.0"
base64 = "0.21"
clap = { version = "^4.5", features = ["derive", "env"] }

crypto-glue = "^0.1.18"
crypto-glue = "^0.2.1"
compact_jwt = "0.5.6"
futures = "^0.3.25"
hex = "0.4.3"
Expand Down
2 changes: 1 addition & 1 deletion device-catalog/src/certificate_authority.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ pub struct Authority {
impl fmt::Debug for Authority {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Authority")
.field("subject", &self.ca.tbs_certificate.subject)
.field("subject", &self.ca.tbs_certificate().subject())
.finish()
}
}
14 changes: 7 additions & 7 deletions webauthn-authenticator-rs/examples/authenticate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ use std::time::{Duration, SystemTime};
use clap::Args;
use clap::{Parser, Subcommand, ValueEnum};
use crypto_glue::{
ecdsa_p256::EcdsaP256PrivateKey,
rand::{rngs::ThreadRng, Rng, RngCore},
ecdsa_p256,
rand::{rngs::ThreadRng, Rng, RngExt},
x509::Certificate,
};
#[cfg(feature = "cable")]
Expand Down Expand Up @@ -308,11 +308,11 @@ fn fake_credential(
rng: &mut ThreadRng,
verification_policy: UvPolicy,
) -> WebauthnResult<CredentialV5> {
let cred_len = rng.gen_range(16..=64);
let cred_len = rng.random_range(16..=64);
let mut cred_id: Vec<u8> = vec![0; cred_len];
rng.fill_bytes(&mut cred_id);

let key = EcdsaP256PrivateKey::random(rng);
let key = ecdsa_p256::new_key();
let cred = (&key.public_key()).try_into()?;

Ok(CredentialV5 {
Expand Down Expand Up @@ -344,9 +344,9 @@ fn fake_credential(
fn print_certs(certs: &[Certificate]) {
for (i, cert) in certs.iter().enumerate() {
println!("### Certificate {}", i + 1);
println!("Issuer: {}", cert.tbs_certificate.issuer);
println!("Subject: {}", cert.tbs_certificate.subject);
println!("Serial: {}", cert.tbs_certificate.serial_number);
println!("Issuer: {}", cert.tbs_certificate().issuer());
println!("Subject: {}", cert.tbs_certificate().subject());
println!("Serial: {}", cert.tbs_certificate().serial_number());

println!("");
}
Expand Down
6 changes: 3 additions & 3 deletions webauthn-authenticator-rs/examples/cable_tunnel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ use bluetooth_hci::{
BdAddr, BdAddrType,
};
use clap::{ArgGroup, Parser};
use crypto_glue::rand::{rngs::ThreadRng, RngCore as _};
use crypto_glue::rand::{self, Rng};
use futures::StreamExt;
use serialport::FlowControl;
use serialport_hci::{
Expand Down Expand Up @@ -227,8 +227,8 @@ impl Advertiser for SerialHciAdvertiser {
};
let mut addr = [0u8; 6];
addr[5] = 0xc0;
let mut rng = ThreadRng::default();
rng.try_fill_bytes(&mut addr[..5])?;
let mut rng = rand::rng();
rng.fill_bytes(&mut addr[..5]);

self.hci.le_set_random_address(BdAddr(addr)).unwrap();
let _ = self.read();
Expand Down
20 changes: 10 additions & 10 deletions webauthn-authenticator-rs/src/cable/discovery.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@
use crate::stubs::*;

use crypto_glue::{
block_padding::generic_array::{
sequence::Split,
block_padding::array::{
// sequence::Split,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// sequence::Split,

typenum::{U32, U64},
GenericArray,
Array,
},
ecdh_p256::{self, EcdhP256EphemeralSecret},
hmac_s256::{self, HmacSha256Key},
rand::{rngs::ThreadRng, RngCore},
rand::{self, Rng},
traits::Zeroizing,
};
use num_traits::ToPrimitive;
Expand All @@ -30,11 +30,11 @@ type QrSecret = [u8; 16];

/// Two concatenated [`Aes256Key`s][crypto_glue::aes256::Aes256Key], the encryption key and signing
/// key.
type EidKey = Zeroizing<GenericArray<u8, U64>>;
type EidKey = Zeroizing<Array<u8, U64>>;

/// Alias for a non-[`Zeroizing`][] form of [`Aes256Key`][crypto_glue::aes256::Aes256Key], used to
/// reassure Rust's type checker.
type NonZeroingAes256Key = GenericArray<u8, U32>;
type NonZeroingAes256Key = Array<u8, U32>;

type CableEid = [u8; 16];
type TunnelId = [u8; 16];
Expand Down Expand Up @@ -77,8 +77,8 @@ impl Discovery {
pub fn new(request_type: CableRequestType) -> Result<Self, WebauthnCError> {
// chrome_authenticator_request_delegate.cc ChromeAuthenticatorRequestDelegate::ConfigureCable
let mut qr_secret: QrSecret = [0; size_of::<QrSecret>()];
let mut rng = ThreadRng::default();
rng.try_fill_bytes(&mut qr_secret)?;
let mut rng = rand::rng();
rng.fill_bytes(&mut qr_secret);
Self::new_with_qr_secret(request_type, qr_secret)
}

Expand Down Expand Up @@ -214,9 +214,9 @@ pub struct Eid {
impl Eid {
/// Creates a new [Eid] using a random nonce.
pub fn new(tunnel_server_id: u16, routing_id: RoutingId) -> Result<Self, WebauthnCError> {
let mut rng = ThreadRng::default();
let mut rng = rand::rng();
let mut nonce: BleNonce = [0; size_of::<BleNonce>()];
rng.try_fill_bytes(&mut nonce)?;
rng.fill_bytes(&mut nonce);

Ok(Self {
tunnel_server_id,
Expand Down
4 changes: 2 additions & 2 deletions webauthn-authenticator-rs/src/cable/handshake.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#[cfg(doc)]
use crate::stubs::*;

use crypto_glue::{ecdh_p256::EcdhP256PublicKey, traits::ToEncodedPoint as _};
use crypto_glue::{ecdh_p256::EcdhP256PublicKey, traits::ToSec1Point as _};
use serde::Serialize;
use serde_cbor_2::Value;
use std::{
Expand Down Expand Up @@ -47,7 +47,7 @@ impl From<HandshakeV2> for BTreeMap<u32, Value> {
let mut o = BTreeMap::from([
(
0,
Value::Bytes(peer_identity.to_encoded_point(true).to_bytes().to_vec()),
Value::Bytes(peer_identity.to_sec1_point(true).to_bytes().to_vec()),
),
(1, Value::Bytes(secret.to_vec())),
(2, Value::Integer(known_domains_count.into())),
Expand Down
40 changes: 22 additions & 18 deletions webauthn-authenticator-rs/src/cable/noise.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@ use crate::stubs::*;
use crypto_glue::{
aes256::Aes256Key,
aes256gcm::{Aes256Gcm, Aes256GcmNonce},
block_padding::generic_array::{
sequence::Split,
block_padding::array::{
// sequence::Split,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// sequence::Split,

typenum::{U16, U32, U64, U96},
GenericArray,
Array,
},
ecdh_p256::{self, EcdhP256EphemeralSecret, EcdhP256PublicKey},
s256::Sha256Output,
traits::{AeadInPlace, KeyInit, ToEncodedPoint as _, Zeroizing},
traits::{AeadInOut, KeyInit, ToSec1Point as _, Zeroizing},
};
use std::mem::size_of;

Expand Down Expand Up @@ -121,8 +121,10 @@ impl CipherState {

let cipher = Aes256Gcm::new(key);
// trace!("encrypting: {:?}", hex::encode(&buf[..padded_len]));

let work = &mut buf[..padded_len];
let tag = cipher
.encrypt_in_place_detached(&nonce, aad, &mut buf[..padded_len])
.encrypt_inout_detached(&nonce, aad, work.into())
.map_err(|_| WebauthnCError::CryptographyAeadError)?;
// trace!(
// "encrypted: {:?}, tag: {:?}, nonce: {:?}, aad: {:?}, key: {:?}",
Expand Down Expand Up @@ -158,14 +160,16 @@ impl CipherState {

let msg_len = buf.len() - 16;
let (ct, tag) = buf.split_at_mut(msg_len);
let tag: &mut GenericArray<u8, U16> = tag.into();
let tag: &mut Array<u8, U16> = tag
.try_into()
.map_err(|_| WebauthnCError::CryptographyAeadError)?;

let nonce = self.construct_nonce();

let cipher = Aes256Gcm::new(key);

if cipher
.decrypt_in_place_detached(&nonce, aad, ct, tag)
.decrypt_inout_detached(&nonce, aad, ct.into(), tag)
.is_err()
{
// error!(
Expand Down Expand Up @@ -233,7 +237,7 @@ impl CipherState {
///
/// [SymmetricState]: https://noiseprotocol.org/noise.html#the-symmetricstate-object
pub struct CableNoise {
ck: Zeroizing<GenericArray<u8, U32>>,
ck: Zeroizing<Array<u8, U32>>,
h: Sha256Output,

cipher_state: CipherState,
Expand Down Expand Up @@ -269,23 +273,23 @@ impl CableNoise {
}

fn mix_hash_point(&mut self, point: &EcdhP256PublicKey) -> Result<(), WebauthnCError> {
let point = point.to_encoded_point(false);
let point = point.to_sec1_point(false);
// trace!("mix_hash_point(point={:?})", hex::encode(point.as_bytes()));
self.mix_hash(point.as_bytes());
Ok(())
}

/// `SymmetricState.MixKey(input_key_material)`
fn mix_key(&mut self, ikm: &[u8]) -> Result<(), WebauthnCError> {
let mut o: Zeroizing<GenericArray<u8, U64>> = Default::default();
let mut o: Zeroizing<Array<u8, U64>> = Default::default();
hkdf_sha_256(&self.ck, ikm, None, &mut o)?;
// trace!(
// "mix_key(ikm={:?}) => hkdf(salt={:?}, output={:?})",
// hex::encode(&ikm),
// hex::encode(&self.ck),
// hex::encode(&o),
// );
let (ck, temp_k): (GenericArray<u8, U32>, _) = o.split();
let (ck, temp_k): (Array<u8, U32>, _) = o.split();
self.ck.copy_from_slice(&ck);
self.cipher_state.init_key(temp_k.into());
Ok(())
Expand All @@ -294,16 +298,16 @@ impl CableNoise {
/// `SymmetricState.MixKeyAndHash(input_key_material)`
fn mix_key_and_hash(&mut self, ikm: &[u8]) -> Result<(), WebauthnCError> {
// https://source.chromium.org/chromium/chromium/src/+/main:device/fido/cable/noise.cc;l=90;drc=38321ee39cd73ac2d9d4400c56b90613dee5fe29
let mut o: Zeroizing<GenericArray<u8, U96>> = Default::default();
let mut o: Zeroizing<Array<u8, U96>> = Default::default();
hkdf_sha_256(&self.ck, ikm, None, &mut o)?;
// trace!(
// "mix_key_and_hash(ikm={:?}) => hkdf(salt={:?}, output={:?})",
// hex::encode(&ikm),
// hex::encode(&self.ck),
// hex::encode(&o),
// );
let (ck, temp): (GenericArray<u8, U32>, _) = o.split();
let (temp_h, temp_k): (GenericArray<u8, U32>, GenericArray<u8, U32>) = temp.split();
let (ck, temp): (Array<u8, U32>, _) = o.split();
let (temp_h, temp_k): (Array<u8, U32>, Array<u8, U32>) = temp.split();

self.ck.copy_from_slice(&ck);
self.mix_hash(&temp_h);
Expand Down Expand Up @@ -333,7 +337,7 @@ impl CableNoise {
/// further transport messages. `write_key` is for messages sent by the
/// initiator, `read_key` is for messages sent by the authenticator.
fn traffic_keys(&self) -> Result<(EncryptionKey, EncryptionKey), WebauthnCError> {
let mut o: Zeroizing<GenericArray<u8, U64>> = Default::default();
let mut o: Zeroizing<Array<u8, U64>> = Default::default();
hkdf_sha_256(&self.ck, &[], None, &mut o)?;

let (a, b) = o.split();
Expand All @@ -342,7 +346,7 @@ impl CableNoise {

fn get_ephemeral_key_public_bytes(&self) -> Result<[u8; 65], WebauthnCError> {
let mut o = [0; 65];
let point = self.ephemeral_key.public_key().to_encoded_point(false);
let point = self.ephemeral_key.public_key().to_sec1_point(false);
if point.len() != o.len() {
error!(
"unexpected public key length {} != {}",
Expand Down Expand Up @@ -641,7 +645,7 @@ mod test {
let cipher = Aes256Gcm::new(&Default::default());
let mut buf = vec![];
let tag = cipher
.encrypt_in_place_detached(&[0u8; 12].into(), &[0], &mut buf)
.encrypt_inout_detached(&[0u8; 12].into(), &[0], buf.as_mut_slice().into())
.unwrap();

warn!("our empty tag was: {}", hex::encode(tag));
Expand All @@ -650,7 +654,7 @@ mod test {
let cipher = Aes256Gcm::new(&Default::default());
let mut buf = vec![];
cipher
.decrypt_in_place_detached(&[0u8; 12].into(), &[0], &mut buf, &tag)
.decrypt_inout_detached(&[0u8; 12].into(), &[0], buf.as_mut_slice().into(), &tag)
.unwrap();
}

Expand Down
17 changes: 7 additions & 10 deletions webauthn-authenticator-rs/src/crypto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use crypto_glue::ecdh_p256::EcdhP256PublicKey;
use crypto_glue::{
aes256::Aes256Key,
aes256cbc::{
Aes256CbcDec, Aes256CbcEnc, Aes256CbcIv, BlockDecryptMut, BlockEncryptMut, KeyIvInit,
Aes256CbcDec, Aes256CbcEnc, Aes256CbcIv, BlockModeDecrypt, BlockModeEncrypt, KeyIvInit,
},
block_padding::NoPadding,
hkdf_s256::HkdfSha256,
Expand Down Expand Up @@ -42,7 +42,7 @@ pub fn encrypt(
) -> Result<Vec<u8>, WebauthnCError> {
let enc = Aes256CbcEnc::new(key, iv);

let ciphertext = enc.encrypt_padded_vec_mut::<NoPadding>(plaintext);
let ciphertext = enc.encrypt_padded_vec::<NoPadding>(plaintext);

Ok(ciphertext)
}
Expand All @@ -57,7 +57,7 @@ pub fn decrypt(
) -> Result<Vec<u8>, WebauthnCError> {
let enc = Aes256CbcDec::new(key, iv);

enc.decrypt_padded_vec_mut::<NoPadding>(ciphertext)
enc.decrypt_padded_vec::<NoPadding>(ciphertext)
.map_err(|_| WebauthnCError::CryptographyAes256CbcDecrypt)
}

Expand Down Expand Up @@ -88,7 +88,7 @@ pub fn public_key_from_bytes(buf: &[u8]) -> Result<EcdhP256PublicKey, WebauthnCE
#[allow(clippy::expect_used, clippy::unwrap_used)]
mod test {
use super::*;
use crypto_glue::ecdh_p256;
use crypto_glue::{ecdh_p256, traits::ToSec1Point};

#[test]
fn hkdf() {
Expand Down Expand Up @@ -151,10 +151,7 @@ mod test {
/// Test using ECDH with static keys.
#[test]
fn ecdh_expected() {
use crypto_glue::{
ecdh_p256::EcdhP256EphemeralSecret, ecdsa_p256::EcdsaP256NonZeroScalar,
traits::ToEncodedPoint,
};
use crypto_glue::{ecdh_p256::EcdhP256EphemeralSecret, ecdsa_p256::EcdsaP256NonZeroScalar};

let alice_secret = EcdsaP256NonZeroScalar::from_repr((*b"\x13\xeaL\xe1\xd1\xff\xb3\xc2\x88\\\x8eb 0[\xe8a\x92\x1d\xee\xdd\x17\xca:\x171\xae\xbf\x8c\xf0\xdc\xb8").into()).unwrap();
let bob_secret = EcdsaP256NonZeroScalar::from_repr((*b"\x84\x0ed:\x90\xee\xb9}\xc8\xb4\xb5\x12\x03\x8b\xc5~\xe1\x13\x04\xceZ\x9d,\xfd\xd6F\x13\xea\xb0\x96?q").into()).unwrap();
Expand All @@ -166,11 +163,11 @@ mod test {

// Check that we can get the same pubkey from either side:
let alice_pub = alice_secret.public_key();
let alice_pub_point = alice_pub.to_encoded_point(false);
let alice_pub_point = alice_pub.to_sec1_point(false);
assert_eq!(alice_pub_point.as_bytes(), b"\x04\xa5\x99\xe0\xdd{\x1a\xa3m0\x98\x80R\x1a\xc2\x8b\xbe\xc3A\x81\x91W$\x055\x16\xe5\xb0\tF\x86\xe8`\xaf\xe6.\x98\xf5:\x99\xf1\xb4\x1cai\x96\xb0e\x83\x8c&\x12*\xfd,~\x14\xb8\xf8q9-\xd1\x18\xed");

let bob_pub = bob_secret.public_key();
let bob_pub_point = bob_pub.to_encoded_point(false);
let bob_pub_point = bob_pub.to_sec1_point(false);
assert_eq!(bob_pub_point.as_bytes(), b"\x04\xe3F/\xe9\xd6\x8e\xb5L\xc9!\x14w\x0cs8z)\xcc)\r\x87]\x829fC \xf7>\xe5\x07b\x8b\xe8\xfd\xdd\0\xd66\x9d\x11\xfe\xec\xe4Z\x0c\xf4\xc3e#\x19\xc5\xa0\x81\x19\xe7\xd8}}\xd3a\xea\x9a\x12");

// Now lets do ECDH (like caBLE), and check that Alice came up with our expected secret:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -379,7 +379,7 @@ impl TryFrom<BTreeMap<u32, Value>> for CredentialManagementResponse {
.and_then(|v| value_to_vec_u8(v, "0x04"))
.and_then(|v| {
// Returns None if not exactly sized.
Sha256Output::from_exact_iter(v)
Sha256Output::try_from_iter(v).ok()
})
{
if let Some(rp) = &mut rp {
Expand Down
Loading
Loading