Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ntlm fixes for disabled sealing and signing #182

Merged
merged 7 commits into from
Oct 27, 2023
Merged

Conversation

pauldumais
Copy link
Contributor

  1. NTLM flags now allow to disable signing and sealing
  2. MIC is now properly generated if key exchange is disabled (such as the case of disabled sealing)
  3. NTLM DecryptMessage now supports STREAM decoding

Copy link
Member

@CBenoit CBenoit left a comment

Choose a reason for hiding this comment

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

I don’t understand most of it, but I left a few comments FYI. Feel free to ignore the nits.

Comment on lines 121 to 130
let session_key = OsRng.gen::<[u8; SESSION_KEY_SIZE]>();
let mut session_key = OsRng.gen::<[u8; SESSION_KEY_SIZE]>();
let encrypted_session_key_vec = Rc4::new(&key_exchange_key).process(session_key.as_ref());
let mut encrypted_session_key = [0x00; ENCRYPTED_RANDOM_SESSION_KEY_SIZE];
encrypted_session_key.clone_from_slice(encrypted_session_key_vec.as_ref());

context.flags = get_flags(context.flags, credentials);
context.flags = get_flags(context, credentials);

if !context.flags.contains(NegotiateFlags::NTLM_SSP_NEGOTIATE_KEY_EXCH) {
session_key = key_exchange_key;
}
Copy link
Member

Choose a reason for hiding this comment

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

Nit: I understand that we re-use key_exchange_key unless the NTLM_SSP_NEGOTIATE_KEY_EXCH flag is set, in which case we generate a different session key. Instead of generating a session key that we never use and use a mutable binding, you could do that:

    let session_key = if context.flags.contains(NegotiateFlags::NTLM_SSP_NEGOTIATE_KEY_EXCH) {
        OsRng.gen::<[u8; SESSION_KEY_SIZE]>()
    } else {
        key_exchange_key
    };

(if blocks are expressions, and this is more idiomatic)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ok

src/ntlm/mod.rs Outdated
Comment on lines 429 to 430
let signature = encrypted[0..16].to_vec();
let enc = encrypted[16..].to_vec();
Copy link
Member

@CBenoit CBenoit Oct 27, 2023

Choose a reason for hiding this comment

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

Question: do you know if the "invariant" buffer.len() > 16 is checked somewhere? Inside SecurityBuffer perhaps? Just being cautious, because in Rust, when the index is out of bounds, such indexing, instead of corrupting the memory, will stop the program by panicking (similar to C++ stack unwinding when an exception is raised). However, panicking (or unwinding) across an FFI boundary is undefined behavior. (There is a working group on that matter, but as of today it’s undefined.)

One avenue is to use the get method for a checked access which returns Option<&[u8]>:

let signature = encrypted.get(0..16).ok_or_else(|| /* construct error value */)?;
let enc = &encrypted[16..]; // the second one is fine, because of the above

Another avenue is to perform an upfront check like so:

// Upfront check
if encrypted.len() < 16 {
    return Err(/* error value */);
}

// Split the slice in two using `split_at`
let (signature, enc) = encrypted.split_at(16);

Mostly a matter of preference.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Perfect!

src/ntlm/mod.rs Outdated
Comment on lines 429 to 430
let signature = encrypted[0..16].to_vec();
let enc = encrypted[16..].to_vec();
Copy link
Member

Choose a reason for hiding this comment

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

Nit: as far as I can see in the rest of the code, there is no need to use .to_vec():

Suggested change
let signature = encrypted[0..16].to_vec();
let enc = encrypted[16..].to_vec();
let signature = &encrypted[0..16];
let enc = &encrypted[16..];

(and remove the .as_slice() below)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

Comment on lines +419 to +425
let mut encrypted = if let Ok(buffer) = SecurityBuffer::find_buffer_mut(message, SecurityBufferType::Token) {
buffer
} else {
SecurityBuffer::find_buffer_mut(message, SecurityBufferType::Stream)?
}
.buffer
.clone();
Copy link
Member

@CBenoit CBenoit Oct 27, 2023

Choose a reason for hiding this comment

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

Nit: as far as I know, it’s more idiomatic to write this:

Suggested change
let mut encrypted = if let Ok(buffer) = SecurityBuffer::find_buffer_mut(message, SecurityBufferType::Token) {
buffer
} else {
SecurityBuffer::find_buffer_mut(message, SecurityBufferType::Stream)?
}
.buffer
.clone();
let security_buffer = let Ok(buffer) = SecurityBuffer::find_buffer_mut(message, SecurityBufferType::Token) {
buffer
} else {
SecurityBuffer::find_buffer_mut(message, SecurityBufferType::Stream)?
};
let encrypted = &security_buffer.buffer;

Or even better:

let security_buffer = SecurityBuffer::find_buffer_mut(message, SecurityBufferType::Token)
    .or_else(|| SecurityBuffer::find_buffer_mut(message, SecurityBufferType::Stream))?;
let encrypted = &security_buffer.buffer;

If I understand correctly, it’s also not necessary to .clone() the buffer at all.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This code was copied from the kerberos code, and the changes proposed do not compile, I will leave it as is since it's only a nit.

Copy link
Collaborator

@RRRadicalEdward RRRadicalEdward left a comment

Choose a reason for hiding this comment

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

Benoît has written all the comments. I have nothing to add

@awakecoding
Copy link
Contributor

the changes don't look like they'd break other ways to call the same APIs, so I'm good with them. I'll leave the rest for @CBenoit to review in terms of Rust code style :)

@pauldumais pauldumais merged commit 7779af5 into master Oct 27, 2023
40 checks passed
@pauldumais pauldumais deleted the ntlm-flags-fix branch October 27, 2023 13:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
4 participants