Skip to content
Merged
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
4 changes: 2 additions & 2 deletions smb/src/connection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,7 @@ impl ConnectionMessageHandler {
#[maybe_async]
async fn process_sequence_outgoing(&self, msg: &mut OutgoingMessage) -> crate::Result<()> {
if let Some(neg) = self.conn_info.get() {
if neg.negotiation.dialect_rev > Dialect::Smb0202 && neg.negotiation.caps.large_mtu() {
if neg.negotiation.caps.large_mtu() {
// Calculate the cost of the message (charge).
let cost = if Self::SET_CREDIT_CHARGE_CMDS
.iter()
Expand Down Expand Up @@ -393,7 +393,7 @@ impl ConnectionMessageHandler {
#[maybe_async]
async fn process_sequence_incoming(&self, msg: &IncomingMessage) -> crate::Result<()> {
if let Some(neg) = self.conn_info.get() {
if neg.negotiation.dialect_rev > Dialect::Smb0202 && neg.negotiation.caps.large_mtu() {
if neg.negotiation.caps.large_mtu() {
let granted_credits = msg.message.header.credit_request;
let charged_credits = msg.message.header.credit_charge;
// Update the pool size - return how many EXTRA credits were granted.
Expand Down
58 changes: 43 additions & 15 deletions smb/src/dialects.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,17 @@ impl DialectImpl {
}

pub fn get_negotiate_caps_mask(&self) -> GlobalCapabilities {
let mut mask = GlobalCapabilities::new()
.with_dfs(true)
.with_leasing(true)
.with_large_mtu(true)
.with_multi_channel(true)
.with_persistent_handles(true)
.with_directory_leasing(true);
let mut mask = GlobalCapabilities::new().with_dfs(true);

mask.set_leasing(self.dialect > Dialect::Smb0202);
mask.set_large_mtu(self.dialect > Dialect::Smb0202);

mask.set_multi_channel(self.dialect > Dialect::Smb021);
mask.set_persistent_handles(self.dialect > Dialect::Smb021);
mask.set_directory_leasing(self.dialect > Dialect::Smb021);

mask.set_encryption(Dialect::Smb030 <= self.dialect && self.dialect <= Dialect::Smb0302);

mask.set_notifications(self.dialect == Dialect::Smb0311);

mask
Expand Down Expand Up @@ -97,22 +99,26 @@ impl DialectImpl {
match self.dialect {
Dialect::Smb0311 => Smb311.process_negotiate_request(response, state, config),
Dialect::Smb0302 | Dialect::Smb030 => {
Smb300_302.process_negotiate_request(response, state, config)
Smb30X.process_negotiate_request(response, state, config)
}
Dialect::Smb021 | Dialect::Smb0202 => {
Smb201.process_negotiate_request(response, state, config)
}
_ => unimplemented!(),
}
}

pub fn get_signing_derive_label(&self) -> &[u8] {
match self.dialect {
Dialect::Smb0311 => Smb311::SIGNING_KEY_LABEL,
Dialect::Smb0302 | Dialect::Smb030 => Smb300_302::SIGNING_KEY_LABEL,
Dialect::Smb0302 | Dialect::Smb030 => Smb30X::SIGNING_KEY_LABEL,
_ => unimplemented!(),
}
}

pub fn preauth_hash_supported(&self) -> bool {
self.dialect == Dialect::Smb0311
}

pub fn default_signing_algo(&self) -> SigningAlgorithmId {
match self.dialect {
Dialect::Smb0311 | Dialect::Smb0302 | Dialect::Smb030 => SigningAlgorithmId::AesCmac,
Expand All @@ -131,14 +137,14 @@ impl DialectImpl {
pub fn s2c_encrypt_key_derive_label(&self) -> &[u8] {
match self.dialect {
Dialect::Smb0311 => Smb311::ENCRYPTION_S2C_KEY_LABEL,
Dialect::Smb0302 | Dialect::Smb030 => Smb300_302::ENCRYPTION_KEY_LABEL,
Dialect::Smb0302 | Dialect::Smb030 => Smb30X::ENCRYPTION_KEY_LABEL,
_ => panic!("Encryption is not supported for this dialect!"),
}
}
pub fn c2s_encrypt_key_derive_label(&self) -> &[u8] {
match self.dialect {
Dialect::Smb0311 => Smb311::ENCRYPTION_C2S_KEY_LABEL,
Dialect::Smb0302 | Dialect::Smb030 => Smb300_302::ENCRYPTION_KEY_LABEL,
Dialect::Smb0302 | Dialect::Smb030 => Smb30X::ENCRYPTION_KEY_LABEL,
_ => panic!("Encryption is not supported for this dialect!"),
}
}
Expand Down Expand Up @@ -221,12 +227,13 @@ impl DialectMethods for Smb311 {
}
}

struct Smb300_302;
impl Smb300_302 {
/// SMB 3.0 and 3.0.2
struct Smb30X;
impl Smb30X {
pub const ENCRYPTION_KEY_LABEL: &[u8] = b"SMB2AESCCM\x00";
}

impl DialectMethods for Smb300_302 {
impl DialectMethods for Smb30X {
const SIGNING_KEY_LABEL: &[u8] = b"SMB2AESCMAC\x00";
fn process_negotiate_request(
&self,
Expand All @@ -249,3 +256,24 @@ impl DialectMethods for Smb300_302 {
Ok(())
}
}

struct Smb201;

impl DialectMethods for Smb201 {
const SIGNING_KEY_LABEL: &[u8] = b"";

fn process_negotiate_request(
&self,
response: &NegotiateResponse,
_state: &mut NegotiatedProperties,
_config: &ConnectionConfig,
) -> crate::Result<()> {
if response.negotiate_context_list.is_some() {
return Err(Error::InvalidMessage(
"Negotiate context list not expected".to_string(),
));
}

Ok(())
}
}
11 changes: 1 addition & 10 deletions smb/src/resource.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use time::PrimitiveDateTime;
use crate::{
connection::connection_info::ConnectionInfo,
msg_handler::{HandlerReference, MessageHandler},
packets::{fscc::*, guid::Guid, smb2::*},
packets::{fscc::*, smb2::*},
tree::TreeMessageHandler,
Error,
};
Expand Down Expand Up @@ -48,15 +48,6 @@ impl Resource {
create_options: CreateOptions::new(),
name: name.into(),
contexts: vec![
DurableHandleRequestV2 {
timeout: 0,
flags: DurableHandleV2Flags::new(),
create_guid: Guid::try_from(&[
180, 122, 182, 194, 188, 248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
])
.unwrap(),
}
.into(),
QueryMaximalAccessRequest::default().into(),
QueryOnDiskIdReq.into(),
],
Expand Down
45 changes: 37 additions & 8 deletions smb/src/session/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,32 @@ impl SessionState {
));
}

let (signer, enc, dec) = if info.negotiation.dialect_rev.is_smb3() {
Self::smb3xx_make_ciphers(session_key, preauth_hash, info)?
} else {
(Self::make_smb2_signer(session_key, info)?, None, None)
};

{
let mut state = state.lock().await?;
state.signer = Some(signer);
state.decryptor = dec;
state.encryptor = enc;
log::trace!("Session state set up: {:?}", state);
}

Ok(())
}

fn smb3xx_make_ciphers(
session_key: &KeyToDerive,
preauth_hash: &Option<PreauthHashValue>,
info: &ConnectionInfo,
) -> crate::Result<(
MessageSigner,
Option<MessageEncryptor>,
Option<MessageDecryptor>,
)> {
let deriver = KeyDeriver::new(session_key);

let signer = Self::make_signer(
Expand All @@ -69,15 +95,18 @@ impl SessionState {
(None, None)
};

{
let mut state = state.lock().await?;
state.signer = Some(signer);
state.decryptor = dec;
state.encryptor = enc;
log::trace!("Session state set up: {:?}", state);
}
Ok((signer, enc, dec))
}

Ok(())
fn make_smb2_signer(
session_key: &KeyToDerive,
info: &ConnectionInfo,
) -> Result<MessageSigner, CryptoError> {
debug_assert!(info.negotiation.dialect_rev < Dialect::Smb030);
Ok(MessageSigner::new(make_signing_algo(
SigningAlgorithmId::HmacSha256,
session_key,
)?))
}

fn make_signer(
Expand Down
7 changes: 4 additions & 3 deletions smb/tests/integration_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use smb::{
};
use std::env::var;

macro_rules! parametrize_dialect {
macro_rules! basic_test {
([$dialect:ident], [$($encrypt_mode:ident),*]) => {
$(
paste::paste! {
Expand All @@ -28,13 +28,14 @@ macro_rules! parametrize_dialect {

([$($dialect:ident),*], $encrypt_modes:tt) => {
$(
parametrize_dialect!([$dialect], $encrypt_modes);
basic_test!([$dialect], $encrypt_modes);
)*
};

}

parametrize_dialect!([Smb030, Smb0302, Smb0311], [Disabled, Required]);
basic_test!([Smb030, Smb0302, Smb0311], [Disabled, Required]);
basic_test!([Smb0202, Smb021], [Disabled]);

#[maybe_async::maybe_async]
async fn test_smb_integration_basic(
Expand Down