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

feat: add make_signature and verify_signature to Sspi trait #343

Merged
merged 4 commits into from
Jan 20, 2025
Merged
Changes from 1 commit
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
Prev Previous commit
Next Next commit
Documentation, UnsupportedFunction erros, and some default implementa…
…tions.

Error message formatting.
Use a generic u32 flags parameter for *_signature functions.
AvivNaaman committed Jan 11, 2025
commit 9ac42d3ecdc1beb2e4c6ef420019d4afa6120597
27 changes: 12 additions & 15 deletions src/credssp/mod.rs
Original file line number Diff line number Diff line change
@@ -953,12 +953,13 @@ impl Sspi for SspiContext {
self.change_password_impl(&mut yield_point, change_password).await
}))
}

fn make_signature(&mut self,
flags: crate::SignatureFlags,

fn make_signature(
&mut self,
flags: u32,
message: &mut [SecurityBuffer],
sequence_number: u32,
) -> crate::Result<SecurityStatus> {
) -> crate::Result<()> {
match self {
SspiContext::Ntlm(ntlm) => ntlm.make_signature(flags, message, sequence_number),
SspiContext::Kerberos(kerberos) => kerberos.make_signature(flags, message, sequence_number),
@@ -968,19 +969,15 @@ impl Sspi for SspiContext {
SspiContext::CredSsp(credssp) => credssp.make_signature(flags, message, sequence_number),
}
}

fn verify_signature(&mut self,
flags: crate::SignatureFlags,
message: &mut [SecurityBuffer],
sequence_number: u32,
) -> crate::Result<crate::SignatureFlags> {

fn verify_signature(&mut self, message: &mut [SecurityBuffer], sequence_number: u32) -> crate::Result<u32> {
match self {
SspiContext::Ntlm(ntlm) => ntlm.verify_signature(flags, message, sequence_number),
SspiContext::Kerberos(kerberos) => kerberos.verify_signature(flags, message, sequence_number),
SspiContext::Negotiate(negotiate) => negotiate.verify_signature(flags, message, sequence_number),
SspiContext::Pku2u(pku2u) => pku2u.verify_signature(flags, message, sequence_number),
SspiContext::Ntlm(ntlm) => ntlm.verify_signature(message, sequence_number),
SspiContext::Kerberos(kerberos) => kerberos.verify_signature(message, sequence_number),
SspiContext::Negotiate(negotiate) => negotiate.verify_signature(message, sequence_number),
SspiContext::Pku2u(pku2u) => pku2u.verify_signature(message, sequence_number),
#[cfg(feature = "tsssp")]
SspiContext::CredSsp(credssp) => credssp.verify_signature(flags, message, sequence_number),
SspiContext::CredSsp(credssp) => credssp.verify_signature(message, sequence_number),
}
}
}
31 changes: 17 additions & 14 deletions src/kerberos/mod.rs
Original file line number Diff line number Diff line change
@@ -441,21 +441,24 @@ impl Sspi for Kerberos {
self.change_password(&mut yield_point, change_password).await
}))
}

fn make_signature(&mut self,
flags: crate::SignatureFlags,
message: &mut [SecurityBuffer],
sequence_number: u32,
) -> crate::Result<SecurityStatus> {
todo!()

fn make_signature(
&mut self,
_flags: u32,
_message: &mut [SecurityBuffer],
_sequence_number: u32,
) -> crate::Result<()> {
Err(Error::new(
ErrorKind::UnsupportedFunction,
"make_signature is not supported. use encrypt_message to sign messages instead",
))
}

fn verify_signature(&mut self,
flags: crate::SignatureFlags,
message: &mut [SecurityBuffer],
sequence_number: u32,
) -> crate::Result<crate::SignatureFlags> {
todo!()

fn verify_signature(&mut self, _message: &mut [SecurityBuffer], _sequence_number: u32) -> crate::Result<u32> {
Err(Error::new(
ErrorKind::UnsupportedFunction,
"verify_signature is not supported. use decrypt_message to verify signatures instead",
))
}
}

234 changes: 216 additions & 18 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -602,18 +602,223 @@ where
sequence_number: u32,
) -> Result<SecurityStatus>;

/// TODO
fn make_signature(&mut self,
flags: SignatureFlags,
message: &mut [SecurityBuffer],
sequence_number: u32,
) -> crate::Result<SecurityStatus>;
/// Generates a cryptographic checksum of the message, and also includes sequencing information to prevent message loss or insertion.
/// The function allows the application to choose between several cryptographic algorithms, if supported by the chosen mechanism.
///
/// # Parameters
/// * `flags`: package-specific flags that indicate the quality of protection. A security package can use this parameter to enable the selection of cryptographic algorithms
/// * `message`: On input, the structure references one or more `SecurityBuffer` structures of `type SecurityBufferType::Data` that contain the message to be signed,
/// and a `SecurityBuffer` of type `SecurityBufferType::Token` that receives the signature.
/// * `sequence_number`: the sequence number that the transport application assigned to the message. If the transport application does not maintain sequence numbers, this parameter must be zero
///
/// # Returns
/// * `SspiOk` on success
/// * `Error` on error
///
/// # Example
///
/// ```
/// use sspi::Sspi;
/// use sspi::Username;
/// use sspi::builders::EmptyInitializeSecurityContext;
/// use sspi::SspiImpl;
///
/// let mut client_ntlm = sspi::Ntlm::new();
/// let mut ntlm = sspi::Ntlm::new();
///
/// let mut client_output_buffer = vec![sspi::OwnedSecurityBuffer::new(Vec::new(), sspi::SecurityBufferType::Token)];
/// let mut server_output_buffer = vec![sspi::OwnedSecurityBuffer::new(Vec::new(), sspi::SecurityBufferType::Token)];
///
/// let identity = sspi::AuthIdentity {
/// username: Username::parse("user").unwrap(),
/// password: "password".to_string().into(),
/// };
///
/// let mut client_acq_cred_result = client_ntlm
/// .acquire_credentials_handle()
/// .with_credential_use(sspi::CredentialUse::Outbound)
/// .with_auth_data(&identity)
/// .execute(&mut client_ntlm)
/// .unwrap();
///
/// let mut server_acq_cred_result = ntlm
/// .acquire_credentials_handle()
/// .with_credential_use(sspi::CredentialUse::Inbound)
/// .with_auth_data(&identity)
/// .execute(&mut ntlm)
/// .unwrap();
///
/// loop {
/// client_output_buffer[0].buffer.clear();
///
/// let mut builder = client_ntlm.initialize_security_context()
/// .with_credentials_handle(&mut client_acq_cred_result.credentials_handle)
/// .with_context_requirements(
/// sspi::ClientRequestFlags::CONFIDENTIALITY | sspi::ClientRequestFlags::ALLOCATE_MEMORY,
/// )
/// .with_target_data_representation(sspi::DataRepresentation::Native)
/// .with_target_name("user")
/// .with_input(&mut server_output_buffer)
/// .with_output(&mut client_output_buffer);
///
/// let _client_result = client_ntlm.initialize_security_context_impl(&mut builder)
/// .unwrap()
/// .resolve_to_result()
/// .unwrap();
///
/// let server_result = ntlm
/// .accept_security_context()
/// .with_credentials_handle(&mut server_acq_cred_result.credentials_handle)
/// .with_context_requirements(sspi::ServerRequestFlags::ALLOCATE_MEMORY)
/// .with_target_data_representation(sspi::DataRepresentation::Native)
/// .with_input(&mut client_output_buffer)
/// .with_output(&mut server_output_buffer)
/// .execute(&mut ntlm)
/// .unwrap();
///
/// if server_result.status == sspi::SecurityStatus::CompleteAndContinue
/// || server_result.status == sspi::SecurityStatus::CompleteNeeded
/// {
/// break;
/// }
/// }
///
/// let _result = ntlm
/// .complete_auth_token(&mut server_output_buffer)
/// .unwrap();
///
/// let mut token = [0; 128];
/// let mut data = "This is a message to be signed".as_bytes().to_vec();
/// let mut msg_buffer = vec![
/// sspi::SecurityBuffer::Token(token.as_mut_slice()),
/// sspi::SecurityBuffer::Data(data.as_mut_slice()),
/// ];
///
/// println!("Input data: {:?}", msg_buffer[1].data());
///
/// #[allow(unused_variables)]
/// let result = ntlm
/// .make_signature(0, &mut msg_buffer, 0).unwrap();
///
/// println!("Data signature: {:?}", msg_buffer[0].data());
/// ```
///
/// # MSDN
/// * [MakeSignature function](https://learn.microsoft.com/en-us/windows/win32/api/sspi/nf-sspi-makesignature)
fn make_signature(&mut self, flags: u32, message: &mut [SecurityBuffer], sequence_number: u32)
-> crate::Result<()>;

fn verify_signature(&mut self,
flags: SignatureFlags,
message: &mut [SecurityBuffer],
sequence_number: u32,
) -> crate::Result<SignatureFlags>;
/// Verifies that a message signed by using the `make_signature` function was received in the correct sequence and has not been modified.
///
/// # Parameters
/// * `message`: On input, the structure references one or more `SecurityBuffer` structures of `type SecurityBufferType::Data` that contain the message to be verified,
/// and a `SecurityBuffer` of type `SecurityBufferType::Token` that contains the signature.
/// * `sequence_number`: the sequence number that the transport application assigned to the message. If the transport application does not maintain sequence numbers, this parameter must be zero
///
/// # Returns
/// * `u32` package-specific flags that indicate the quality of protection.
/// * `Error` on error
///
/// # Example
///
/// ```
/// use sspi::Sspi;
/// use sspi::Username;
/// use sspi::builders::EmptyInitializeSecurityContext;
/// use sspi::SspiImpl;
///
/// let mut ntlm = sspi::Ntlm::new();
/// let mut server_ntlm = sspi::Ntlm::new();
///
/// let mut client_output_buffer = vec![sspi::OwnedSecurityBuffer::new(Vec::new(), sspi::SecurityBufferType::Token)];
/// let mut server_output_buffer = vec![sspi::OwnedSecurityBuffer::new(Vec::new(), sspi::SecurityBufferType::Token)];
///
/// let identity = sspi::AuthIdentity {
/// username: Username::parse("user").unwrap(),
/// password: "password".to_string().into(),
/// };
///
/// let mut client_acq_cred_result = ntlm
/// .acquire_credentials_handle()
/// .with_credential_use(sspi::CredentialUse::Outbound)
/// .with_auth_data(&identity)
/// .execute(&mut ntlm)
/// .unwrap();
///
/// let mut server_acq_cred_result = server_ntlm
/// .acquire_credentials_handle()
/// .with_credential_use(sspi::CredentialUse::Inbound)
/// .with_auth_data(&identity)
/// .execute(&mut server_ntlm)
/// .unwrap();
///
/// loop {
/// client_output_buffer[0].buffer.clear();
///
/// let mut builder = ntlm.initialize_security_context()
/// .with_credentials_handle(&mut client_acq_cred_result.credentials_handle)
/// .with_context_requirements(
/// sspi::ClientRequestFlags::CONFIDENTIALITY | sspi::ClientRequestFlags::ALLOCATE_MEMORY,
/// )
/// .with_target_data_representation(sspi::DataRepresentation::Native)
/// .with_target_name("user")
/// .with_input(&mut server_output_buffer)
/// .with_output(&mut client_output_buffer);
///
/// let _client_result = ntlm.initialize_security_context_impl(&mut builder)
/// .unwrap()
/// .resolve_to_result()
/// .unwrap();
///
/// let server_result = server_ntlm
/// .accept_security_context()
/// .with_credentials_handle(&mut server_acq_cred_result.credentials_handle)
/// .with_context_requirements(sspi::ServerRequestFlags::ALLOCATE_MEMORY)
/// .with_target_data_representation(sspi::DataRepresentation::Native)
/// .with_input(&mut client_output_buffer)
/// .with_output(&mut server_output_buffer)
/// .execute(&mut server_ntlm)
/// .unwrap();
///
/// if server_result.status == sspi::SecurityStatus::CompleteAndContinue
/// || server_result.status == sspi::SecurityStatus::CompleteNeeded
/// {
/// break;
/// }
/// }
///
/// let _result = server_ntlm
/// .complete_auth_token(&mut server_output_buffer)
/// .unwrap();
///
/// let mut token = [0; 128];
/// let mut data = "This is a message".as_bytes().to_vec();
/// let mut msg = [
/// sspi::SecurityBuffer::Token(token.as_mut_slice()),
/// sspi::SecurityBuffer::Data(data.as_mut_slice()),
/// ];
///
/// let _result = server_ntlm
/// .make_signature(0, &mut msg, 0).unwrap();
///
/// let [mut token, mut data] = msg;
///
/// let mut msg_buffer = vec![
/// sspi::SecurityBuffer::Token(token.take_data()),
/// sspi::SecurityBuffer::Data(data.take_data()),
/// ];
///
/// #[allow(unused_variables)]
/// let signature_flags = ntlm
/// .verify_signature(&mut msg_buffer, 0)
/// .unwrap();
///
/// println!("Signature calculated and verified.");
/// ```
///
/// # MSDN
/// * [VerifySignature function](https://learn.microsoft.com/en-us/windows/win32/api/sspi/nf-sspi-verifysignature)
fn verify_signature(&mut self, message: &mut [SecurityBuffer], sequence_number: u32) -> crate::Result<u32>;

/// Decrypts a message. Some packages do not encrypt and decrypt messages but rather perform and check an integrity hash.
///
@@ -1079,13 +1284,6 @@ bitflags! {
}
}

bitflags! {
/// TODO
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct SignatureFlags: u32 {
}
}

bitflags! {
/// Indicate requests for the context. Not all packages can support all requirements. Bit flags can be combined by using bitwise-OR operations.
///
29 changes: 17 additions & 12 deletions src/negotiate.rs
Original file line number Diff line number Diff line change
@@ -374,21 +374,26 @@ impl Sspi for Negotiate {
self.change_password(&mut yield_point, change_password).await
}))
}

fn make_signature(&mut self,
flags: crate::SignatureFlags,

fn make_signature(
&mut self,
flags: u32,
message: &mut [SecurityBuffer],
sequence_number: u32,
) -> crate::Result<SecurityStatus> {
todo!()
) -> crate::Result<()> {
match &mut self.protocol {
NegotiatedProtocol::Pku2u(pku2u) => pku2u.make_signature(flags, message, sequence_number),
NegotiatedProtocol::Kerberos(kerberos) => kerberos.make_signature(flags, message, sequence_number),
NegotiatedProtocol::Ntlm(ntlm) => ntlm.make_signature(flags, message, sequence_number),
}
}
fn verify_signature(&mut self,
flags: crate::SignatureFlags,
message: &mut [SecurityBuffer],
sequence_number: u32,
) -> crate::Result<crate::SignatureFlags> {
todo!()

fn verify_signature(&mut self, message: &mut [SecurityBuffer], sequence_number: u32) -> crate::Result<u32> {
match &mut self.protocol {
NegotiatedProtocol::Pku2u(pku2u) => pku2u.verify_signature(message, sequence_number),
NegotiatedProtocol::Kerberos(kerberos) => kerberos.verify_signature(message, sequence_number),
NegotiatedProtocol::Ntlm(ntlm) => ntlm.verify_signature(message, sequence_number),
}
}
}

Loading
Loading