Skip to main content

sspi/
lib.rs

1//! sspi-rs is a Rust implementation of [Security Support Provider Interface (SSPI)](https://docs.microsoft.com/en-us/windows/win32/rpc/security-support-provider-interface-sspi-).
2//! It ships with platform-independent implementations of [Security Support Providers (SSP)](https://docs.microsoft.com/en-us/windows/win32/rpc/security-support-providers-ssps-),
3//! and is able to utilize native Microsoft libraries when ran under Windows.
4//!
5//! The purpose of sspi-rs is to clean the original interface from cluttering and provide users with Rust-friendly SSPs for execution under Linux or any other platform that is
6//! able to compile Rust.
7//!
8//! # Getting started
9//!
10//! Here is a quick example how to start working with the crate. This is the first stage of the client-server authentication performed on the client side.
11//!
12//! ```rust
13//! use sspi::Sspi;
14//! use sspi::Username;
15//! use sspi::Ntlm;
16//! use sspi::builders::EmptyInitializeSecurityContext;
17//! use sspi::SspiImpl;
18//!
19//! let mut ntlm = Ntlm::new();
20//!
21//! let identity = sspi::AuthIdentity {
22//!     username: Username::parse("user").unwrap(),
23//!     password: "password".to_string().into(),
24//! };
25//!
26//! let mut acq_creds_handle_result = ntlm
27//!     .acquire_credentials_handle()
28//!     .with_credential_use(sspi::CredentialUse::Outbound)
29//!     .with_auth_data(&identity)
30//!     .execute(&mut ntlm)
31//!     .expect("AcquireCredentialsHandle resulted in error");
32//!
33//! let mut output = vec![sspi::SecurityBuffer::new(
34//!     Vec::new(),
35//!     sspi::BufferType::Token,
36//! )];
37//!
38//! let mut builder = ntlm.initialize_security_context()
39//!     .with_credentials_handle(&mut acq_creds_handle_result.credentials_handle)
40//!     .with_context_requirements(
41//!         sspi::ClientRequestFlags::CONFIDENTIALITY | sspi::ClientRequestFlags::ALLOCATE_MEMORY
42//!     )
43//!     .with_target_data_representation(sspi::DataRepresentation::Native)
44//!     .with_output(&mut output);
45//!
46//! let result = ntlm.initialize_security_context_impl(&mut builder)
47//!     .expect("InitializeSecurityContext resulted in error")
48//!     .resolve_to_result()
49//!     .expect("InitializeSecurityContext resulted in error");
50//!
51//! println!("Initialized security context with result status: {:?}", result.status);
52//! ```
53
54#[macro_use]
55extern crate tracing;
56
57pub mod builders;
58pub mod channel_bindings;
59pub mod credssp;
60pub mod generator;
61pub mod kerberos;
62pub mod negotiate;
63pub mod network_client;
64pub mod ntlm;
65mod pk_init;
66pub mod pku2u;
67
68mod auth_identity;
69mod ber;
70mod crypto;
71mod dns;
72mod kdc;
73mod krb;
74mod rustls;
75mod secret;
76mod security_buffer;
77mod smartcard;
78mod utils;
79
80#[cfg(all(feature = "tsssp", not(target_os = "windows")))]
81compile_error!("tsssp feature should be used only on Windows");
82
83use std::{error, fmt, io, result, str, string};
84
85use bitflags::bitflags;
86#[cfg(feature = "tsssp")]
87use credssp::sspi_cred_ssp;
88pub use generator::NetworkRequest;
89use generator::{GeneratorAcceptSecurityContext, GeneratorChangePassword, GeneratorInitSecurityContext};
90pub use network_client::NetworkProtocol;
91use num_derive::{FromPrimitive, ToPrimitive};
92use picky_asn1::restricted_string::CharSetError;
93use picky_asn1_der::Asn1DerError;
94use picky_asn1_x509::Certificate;
95use picky_krb::gss_api::GssApiMessageError;
96use picky_krb::messages::KrbError;
97#[cfg(feature = "__rustls-used")]
98pub use rustls::install_default_crypto_provider_if_necessary;
99pub use security_buffer::SecurityBufferRef;
100use utils::map_keb_error_code_to_sspi_error;
101pub use utils::{modpow, str_to_w_buff, string_to_utf16, utf16_bytes_to_utf8_string};
102
103pub use self::auth_identity::{
104    AuthIdentity, AuthIdentityBuffers, Credentials, CredentialsBuffers, UserNameFormat, Username,
105};
106#[cfg(feature = "scard")]
107pub use self::auth_identity::{SmartCardIdentity, SmartCardIdentityBuffers, SmartCardType};
108pub use self::builders::{
109    AcceptSecurityContextResult, AcquireCredentialsHandleResult, InitializeSecurityContextResult,
110};
111use self::builders::{
112    ChangePassword, FilledAcceptSecurityContext, FilledAcquireCredentialsHandle, FilledInitializeSecurityContext,
113};
114pub use self::kdc::{detect_kdc_host, detect_kdc_url};
115pub use self::kerberos::config::{KerberosConfig, KerberosServerConfig};
116pub use self::kerberos::{KERBEROS_VERSION, Kerberos, KerberosState};
117pub use self::negotiate::{Negotiate, NegotiateConfig, NegotiatedProtocol};
118pub use self::ntlm::Ntlm;
119pub use self::ntlm::hash::{NTLM_HASH_PREFIX, NtlmHash, NtlmHashError};
120pub use self::pku2u::{Pku2u, Pku2uConfig, Pku2uState};
121pub use self::secret::Secret;
122use crate::builders::{
123    EmptyAcceptSecurityContext, EmptyAcquireCredentialsHandle, EmptyInitializeSecurityContext,
124    InitializeSecurityContext,
125};
126
127/// Representation of SSPI-related result operation. Makes it easier to return a `Result` with SSPI-related `Error`.
128pub type Result<T> = result::Result<T, Error>;
129pub type Luid = u64;
130
131const PACKAGE_ID_NONE: u16 = 0xFFFF;
132
133/// Retrieves information about a specified security package. This information includes credentials and contexts.
134///
135/// # Returns
136///
137/// * `PackageInfo` containing the information about the security principal upon success
138/// * `Error` on error
139///
140/// # Example
141///
142/// ```
143/// let package_info = sspi::query_security_package_info(sspi::SecurityPackageType::Ntlm)
144///     .unwrap();
145/// println!("Package info:");
146/// println!("Name: {:?}", package_info.name);
147/// println!("Comment: {}", package_info.comment);
148/// ```
149///
150/// # MSDN
151///
152/// * [QuerySecurityPackageInfoW function](https://docs.microsoft.com/en-us/windows/win32/api/sspi/nf-sspi-querysecuritypackageinfow)
153pub fn query_security_package_info(package_type: SecurityPackageType) -> Result<PackageInfo> {
154    match package_type {
155        SecurityPackageType::Ntlm => Ok(ntlm::PACKAGE_INFO.clone()),
156        SecurityPackageType::Kerberos => Ok(kerberos::PACKAGE_INFO.clone()),
157        SecurityPackageType::Negotiate => Ok(negotiate::PACKAGE_INFO.clone()),
158        SecurityPackageType::Pku2u => Ok(pku2u::PACKAGE_INFO.clone()),
159        #[cfg(feature = "tsssp")]
160        SecurityPackageType::CredSsp => Ok(sspi_cred_ssp::PACKAGE_INFO.clone()),
161        SecurityPackageType::Other(s) => Err(Error::new(
162            ErrorKind::Unknown,
163            format!("queried info about unknown package: {s:?}"),
164        )),
165    }
166}
167
168/// Returns an array of `PackageInfo` structures that provide information about the security packages available to the client.
169///
170/// # Returns
171///
172/// * `Vec` of `PackageInfo` structures upon success
173/// * `Error` on error
174///
175/// # Example
176///
177/// ```
178/// let packages = sspi::enumerate_security_packages().unwrap();
179///
180/// println!("Available packages:");
181/// for ssp in packages {
182///     println!("{:?}", ssp.name);
183/// }
184/// ```
185///
186/// # MSDN
187///
188/// * [EnumerateSecurityPackagesW function](https://docs.microsoft.com/en-us/windows/win32/api/sspi/nf-sspi-enumeratesecuritypackagesw)
189pub fn enumerate_security_packages() -> Result<Vec<PackageInfo>> {
190    Ok(vec![
191        negotiate::PACKAGE_INFO.clone(),
192        kerberos::PACKAGE_INFO.clone(),
193        pku2u::PACKAGE_INFO.clone(),
194        ntlm::PACKAGE_INFO.clone(),
195        #[cfg(feature = "tsssp")]
196        sspi_cred_ssp::PACKAGE_INFO.clone(),
197    ])
198}
199
200/// This trait provides interface for all available SSPI functions. The `acquire_credentials_handle`,
201/// `initialize_security_context`, and `accept_security_context` methods return Builders that make it
202/// easier to assemble the list of arguments for the function and then execute it.
203///
204/// # MSDN
205///
206/// * [SSPI.h](https://docs.microsoft.com/en-us/windows/win32/api/sspi/)
207pub trait Sspi
208where
209    Self: Sized + SspiImpl,
210{
211    /// Acquires a handle to preexisting credentials of a security principal. The preexisting credentials are
212    /// available only for `sspi::winapi` module. This handle is required by the `initialize_security_context`
213    /// and `accept_security_context` functions. These can be either preexisting credentials, which are
214    /// established through a system logon, or the caller can provide alternative credentials. Alternative
215    /// credentials are always required to specify when using platform independent SSPs.
216    ///
217    /// # Returns
218    ///
219    /// * `AcquireCredentialsHandle` builder
220    ///
221    /// # Requirements for execution
222    ///
223    /// These methods are required to be called before calling the `execute` method of the `AcquireCredentialsHandle` builder:
224    /// * [`with_credential_use`](builders/struct.AcquireCredentialsHandle.html#method.with_credential_use)
225    ///
226    /// # Example
227    ///
228    /// ```
229    /// use sspi::Sspi;
230    /// use sspi::Username;
231    ///
232    /// let mut ntlm = sspi::Ntlm::new();
233    ///
234    /// let identity = sspi::AuthIdentity {
235    ///     username: Username::parse("user").unwrap(),
236    ///     password: "password".to_string().into(),
237    /// };
238    ///
239    /// #[allow(unused_variables)]
240    /// let result = ntlm
241    ///     .acquire_credentials_handle()
242    ///     .with_credential_use(sspi::CredentialUse::Outbound)
243    ///     .with_auth_data(&identity)
244    ///     .execute(&mut ntlm)
245    ///     .unwrap();
246    /// ```
247    ///
248    /// # MSDN
249    ///
250    /// * [AcquireCredentialshandleW function](https://docs.microsoft.com/en-us/windows/win32/api/sspi/nf-sspi-acquirecredentialshandlew)
251    fn acquire_credentials_handle<'a>(
252        &mut self,
253    ) -> EmptyAcquireCredentialsHandle<'a, Self::CredentialsHandle, Self::AuthenticationData> {
254        EmptyAcquireCredentialsHandle::new()
255    }
256
257    /// Initiates the client side, outbound security context from a credential handle.
258    /// The function is used to build a security context between the client application and a remote peer. The function returns a token
259    /// that the client must pass to the remote peer, which the peer in turn submits to the local security implementation through the
260    /// `accept_security_context` call.
261    ///
262    /// # Returns
263    ///
264    /// * `InitializeSecurityContext` builder
265    ///
266    /// # Requirements for execution
267    ///
268    /// These methods are required to be called before calling the `execute` method
269    /// * [`with_credentials_handle`](builders/struct.InitializeSecurityContext.html#method.with_credentials_handle)
270    /// * [`with_context_requirements`](builders/struct.InitializeSecurityContext.html#method.with_context_requirements)
271    /// * [`with_target_data_representation`](builders/struct.InitializeSecurityContext.html#method.with_target_data_representation)
272    /// * [`with_output`](builders/struct.InitializeSecurityContext.html#method.with_output)
273    ///
274    /// # Example
275    ///
276    /// ```
277    /// use sspi::Sspi;
278    /// use sspi::Username;
279    /// use sspi::builders::EmptyInitializeSecurityContext;
280    /// use sspi::SspiImpl;
281    ///
282    /// let mut ntlm = sspi::Ntlm::new();
283    ///
284    /// let identity = sspi::AuthIdentity {
285    ///     username: Username::new(&whoami::username().unwrap(), Some(&whoami::hostname().unwrap())).unwrap(),
286    ///     password: String::from("password").into(),
287    /// };
288    ///
289    /// let mut acq_cred_result = ntlm
290    ///     .acquire_credentials_handle()
291    ///     .with_credential_use(sspi::CredentialUse::Outbound)
292    ///     .with_auth_data(&identity)
293    ///     .execute(&mut ntlm)
294    ///     .unwrap();
295    ///
296    /// let mut credentials_handle = acq_cred_result.credentials_handle;
297    ///
298    /// let mut output_buffer = vec![sspi::SecurityBuffer::new(Vec::new(), sspi::BufferType::Token)];
299    ///
300    /// #[allow(unused_variables)]
301    /// let mut builder = ntlm.initialize_security_context()
302    ///     .with_credentials_handle(&mut credentials_handle)
303    ///     .with_context_requirements(
304    ///         sspi::ClientRequestFlags::CONFIDENTIALITY | sspi::ClientRequestFlags::ALLOCATE_MEMORY,
305    ///     )
306    ///     .with_target_data_representation(sspi::DataRepresentation::Native)
307    ///     .with_output(&mut output_buffer);
308    ///
309    /// let result = ntlm.initialize_security_context_impl(&mut builder)
310    ///         .unwrap()
311    ///         .resolve_to_result()
312    ///         .unwrap();
313    /// ```
314    ///
315    /// # MSDN
316    ///
317    /// * [InitializeSecurityContextW function](https://docs.microsoft.com/en-us/windows/win32/api/sspi/nf-sspi-initializesecuritycontextw)
318    fn initialize_security_context<'a, 'output>(
319        &mut self,
320    ) -> EmptyInitializeSecurityContext<'a, 'output, Self::CredentialsHandle> {
321        InitializeSecurityContext::new()
322    }
323
324    /// Lets the server component of a transport application establish a security context between the server and a remote client.
325    /// The remote client calls the `initialize_security_context` function to start the process of establishing a security context.
326    /// The server can require one or more reply tokens from the remote client to complete establishing the security context.
327    ///
328    /// # Returns
329    ///
330    /// * `AcceptSecurityContext` builder
331    ///
332    /// # Requirements for execution
333    ///
334    /// These methods are required to be called before calling the `execute` method of the `AcceptSecurityContext` builder:
335    /// * [`with_credentials_handle`](builders/struct.AcceptSecurityContext.html#method.with_credentials_handle)
336    /// * [`with_context_requirements`](builders/struct.AcceptSecurityContext.html#method.with_context_requirements)
337    /// * [`with_target_data_representation`](builders/struct.AcceptSecurityContext.html#method.with_target_data_representation)
338    /// * [`with_output`](builders/struct.AcceptSecurityContext.html#method.with_output)
339    ///
340    /// # Example
341    ///
342    /// ```
343    /// use sspi::Sspi;
344    /// use sspi::Username;
345    /// use sspi::builders::EmptyInitializeSecurityContext;
346    /// use sspi::SspiImpl;
347    ///
348    /// let mut client_ntlm = sspi::Ntlm::new();
349    ///
350    /// let identity = sspi::AuthIdentity {
351    ///     username: Username::parse("user").unwrap(),
352    ///     password: "password".to_string().into(),
353    /// };
354    ///
355    /// let mut client_acq_cred_result = client_ntlm
356    ///     .acquire_credentials_handle()
357    ///     .with_credential_use(sspi::CredentialUse::Outbound)
358    ///     .with_auth_data(&identity)
359    ///     .execute(&mut client_ntlm)
360    ///     .unwrap();
361    ///
362    /// let mut client_output_buffer = vec![sspi::SecurityBuffer::new(Vec::new(), sspi::BufferType::Token)];
363    ///
364    /// let mut builder = client_ntlm.initialize_security_context()
365    ///     .with_credentials_handle(&mut client_acq_cred_result.credentials_handle)
366    ///     .with_context_requirements(
367    ///         sspi::ClientRequestFlags::CONFIDENTIALITY | sspi::ClientRequestFlags::ALLOCATE_MEMORY,
368    ///     )
369    ///     .with_target_data_representation(sspi::DataRepresentation::Native)
370    ///     .with_target_name("user")
371    ///     .with_output(&mut client_output_buffer);
372    ///
373    /// let _result = client_ntlm.initialize_security_context_impl(&mut builder)
374    ///         .unwrap()
375    ///         .resolve_to_result()
376    ///         .unwrap();
377    ///
378    /// let mut ntlm = sspi::Ntlm::new();
379    /// let mut output_buffer = vec![sspi::SecurityBuffer::new(Vec::new(), sspi::BufferType::Token)];
380    ///
381    /// let mut server_acq_cred_result = ntlm
382    ///     .acquire_credentials_handle()
383    ///     .with_credential_use(sspi::CredentialUse::Inbound)
384    ///     .with_auth_data(&identity)
385    ///     .execute(&mut ntlm)
386    ///     .unwrap();
387    ///
388    /// let mut credentials_handle = server_acq_cred_result.credentials_handle;
389    ///
390    /// #[allow(unused_variables)]
391    /// let result = ntlm
392    ///     .accept_security_context()
393    ///     .with_credentials_handle(&mut credentials_handle)
394    ///     .with_context_requirements(sspi::ServerRequestFlags::ALLOCATE_MEMORY)
395    ///     .with_target_data_representation(sspi::DataRepresentation::Native)
396    ///     .with_input(&mut client_output_buffer)
397    ///     .with_output(&mut output_buffer)
398    ///     .execute(&mut ntlm)
399    ///     .unwrap();
400    /// ```
401    ///
402    /// # MSDN
403    ///
404    /// * [AcceptSecurityContext function](https://docs.microsoft.com/en-us/windows/win32/api/sspi/nf-sspi-acceptsecuritycontext)
405    fn accept_security_context<'a>(&mut self) -> EmptyAcceptSecurityContext<'a, Self::CredentialsHandle> {
406        EmptyAcceptSecurityContext::new()
407    }
408
409    /// Completes an authentication token. This function is used by protocols, such as DCE,
410    /// that need to revise the security information after the transport application has updated some message parameters.
411    ///
412    /// # Parameters
413    ///
414    /// * `token`: `SecurityBufferRef` that contains the buffer descriptor for the entire message
415    ///
416    /// # Returns
417    ///
418    /// * `SspiOk` on success
419    /// * `Error` on error
420    ///
421    /// # Example
422    ///
423    /// ```
424    /// use sspi::Sspi;
425    /// use sspi::Username;
426    /// use sspi::builders::EmptyInitializeSecurityContext;
427    /// use sspi::SspiImpl;
428    ///
429    /// let mut client_ntlm = sspi::Ntlm::new();
430    /// let mut ntlm = sspi::Ntlm::new();
431    ///
432    /// let mut client_output_buffer = vec![sspi::SecurityBuffer::new(Vec::new(), sspi::BufferType::Token)];
433    /// let mut output_buffer = vec![sspi::SecurityBuffer::new(Vec::new(), sspi::BufferType::Token)];
434    ///
435    /// let identity = sspi::AuthIdentity {
436    ///     username: Username::parse("user").unwrap(),
437    ///     password: "password".to_string().into(),
438    /// };
439    ///
440    /// let mut client_acq_cred_result = client_ntlm
441    ///     .acquire_credentials_handle()
442    ///     .with_credential_use(sspi::CredentialUse::Outbound)
443    ///     .with_auth_data(&identity)
444    ///     .execute(&mut ntlm)
445    ///     .unwrap();
446    ///
447    /// let mut server_acq_cred_result = ntlm
448    ///     .acquire_credentials_handle()
449    ///     .with_credential_use(sspi::CredentialUse::Inbound)
450    ///     .with_auth_data(&identity)
451    ///     .execute(&mut ntlm)
452    ///     .unwrap();
453    ///
454    /// loop {
455    ///     client_output_buffer[0].buffer.clear();
456    ///
457    ///     let mut builder = client_ntlm.initialize_security_context()
458    ///         .with_credentials_handle(&mut client_acq_cred_result.credentials_handle)
459    ///         .with_context_requirements(
460    ///             sspi::ClientRequestFlags::CONFIDENTIALITY | sspi::ClientRequestFlags::ALLOCATE_MEMORY,
461    ///         )
462    ///         .with_target_data_representation(sspi::DataRepresentation::Native)
463    ///         .with_target_name("user")
464    ///         .with_input(&mut output_buffer)
465    ///         .with_output(&mut client_output_buffer);
466    ///
467    ///     let _client_result = client_ntlm.initialize_security_context_impl(&mut builder)
468    ///         .unwrap()
469    ///         .resolve_to_result()
470    ///         .unwrap();
471    ///
472    ///     let builder = ntlm
473    ///         .accept_security_context()
474    ///         .with_credentials_handle(&mut server_acq_cred_result.credentials_handle)
475    ///         .with_context_requirements(sspi::ServerRequestFlags::ALLOCATE_MEMORY)
476    ///         .with_target_data_representation(sspi::DataRepresentation::Native)
477    ///         .with_input(&mut client_output_buffer)
478    ///         .with_output(&mut output_buffer);
479    ///     let server_result = ntlm.accept_security_context_impl(builder)
480    ///         .unwrap()
481    ///         .resolve_to_result()
482    ///         .unwrap();
483    ///
484    ///     if server_result.status == sspi::SecurityStatus::CompleteAndContinue
485    ///         || server_result.status == sspi::SecurityStatus::CompleteNeeded
486    ///     {
487    ///         break;
488    ///     }
489    /// }
490    ///
491    /// #[allow(unused_variables)]
492    /// let result = ntlm
493    ///     .complete_auth_token(&mut output_buffer)
494    ///     .unwrap();
495    /// ```
496    ///
497    /// # MSDN
498    ///
499    /// * [CompleteAuthToken function](https://docs.microsoft.com/en-us/windows/win32/api/sspi/nf-sspi-completeauthtoken)
500    fn complete_auth_token(&mut self, token: &mut [SecurityBuffer]) -> Result<SecurityStatus>;
501
502    /// Encrypts a message to provide privacy. The function allows the application to choose among cryptographic algorithms supported by the chosen mechanism.
503    /// Some packages do not have messages to be encrypted or decrypted but rather provide an integrity hash that can be checked.
504    ///
505    /// # Parameters
506    ///
507    /// * `flags`: package-specific flags that indicate the quality of protection. A security package can use this parameter to enable the selection of cryptographic algorithms
508    /// * `message`: on input, the structure accepts one or more `SecurityBufferRef` structures that can be of type `BufferType::Data`.
509    ///   That buffer contains the message to be encrypted. The message is encrypted in place, overwriting the original contents of the structure.
510    /// * `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
511    ///
512    /// # Example
513    ///
514    /// ```
515    /// use sspi::Sspi;
516    /// use sspi::Username;
517    /// use sspi::builders::EmptyInitializeSecurityContext;
518    /// use sspi::SspiImpl;
519    ///
520    /// let mut client_ntlm = sspi::Ntlm::new();
521    /// let mut ntlm = sspi::Ntlm::new();
522    ///
523    /// let mut client_output_buffer = vec![sspi::SecurityBuffer::new(Vec::new(), sspi::BufferType::Token)];
524    /// let mut server_output_buffer = vec![sspi::SecurityBuffer::new(Vec::new(), sspi::BufferType::Token)];
525    ///
526    /// let identity = sspi::AuthIdentity {
527    ///     username: Username::parse("user").unwrap(),
528    ///     password: "password".to_string().into(),
529    /// };
530    ///
531    /// let mut client_acq_cred_result = client_ntlm
532    ///     .acquire_credentials_handle()
533    ///     .with_credential_use(sspi::CredentialUse::Outbound)
534    ///     .with_auth_data(&identity)
535    ///     .execute(&mut client_ntlm)
536    ///     .unwrap();
537    ///
538    /// let mut server_acq_cred_result = ntlm
539    ///     .acquire_credentials_handle()
540    ///     .with_credential_use(sspi::CredentialUse::Inbound)
541    ///     .with_auth_data(&identity)
542    ///     .execute(&mut ntlm)
543    ///     .unwrap();
544    ///
545    /// loop {
546    ///     client_output_buffer[0].buffer.clear();
547    ///
548    ///     let mut builder = client_ntlm.initialize_security_context()
549    ///         .with_credentials_handle(&mut client_acq_cred_result.credentials_handle)
550    ///         .with_context_requirements(
551    ///             sspi::ClientRequestFlags::CONFIDENTIALITY | sspi::ClientRequestFlags::ALLOCATE_MEMORY,
552    ///         )
553    ///         .with_target_data_representation(sspi::DataRepresentation::Native)
554    ///         .with_target_name("user")
555    ///         .with_input(&mut server_output_buffer)
556    ///         .with_output(&mut client_output_buffer);
557    ///
558    ///     let _client_result = client_ntlm.initialize_security_context_impl(&mut builder)
559    ///         .unwrap()
560    ///         .resolve_to_result()
561    ///         .unwrap();
562    ///
563    ///     let builder = ntlm
564    ///         .accept_security_context()
565    ///         .with_credentials_handle(&mut server_acq_cred_result.credentials_handle)
566    ///         .with_context_requirements(sspi::ServerRequestFlags::ALLOCATE_MEMORY)
567    ///         .with_target_data_representation(sspi::DataRepresentation::Native)
568    ///         .with_input(&mut client_output_buffer)
569    ///         .with_output(&mut server_output_buffer);
570    ///     let server_result = ntlm.accept_security_context_impl(builder)
571    ///         .unwrap()
572    ///         .resolve_to_result()
573    ///         .unwrap();
574    ///
575    ///     if server_result.status == sspi::SecurityStatus::CompleteAndContinue
576    ///         || server_result.status == sspi::SecurityStatus::CompleteNeeded
577    ///     {
578    ///         break;
579    ///     }
580    /// }
581    ///
582    /// let _result = ntlm
583    ///     .complete_auth_token(&mut server_output_buffer)
584    ///     .unwrap();
585    ///
586    /// let mut token = [0; 128];
587    /// let mut data = "This is a message".as_bytes().to_vec();
588    /// let mut msg_buffer = vec![
589    ///     sspi::SecurityBufferRef::token_buf(token.as_mut_slice()),
590    ///     sspi::SecurityBufferRef::data_buf(data.as_mut_slice()),
591    /// ];
592    ///
593    /// println!("Unencrypted: {:?}", msg_buffer[1].data());
594    ///
595    /// # #[allow(unused_variables)]
596    /// let result = ntlm
597    ///     .encrypt_message(sspi::EncryptionFlags::empty(), &mut msg_buffer).unwrap();
598    ///
599    /// println!("Encrypted: {:?}", msg_buffer[1].data());
600    /// ```
601    ///
602    /// # Returns
603    ///
604    /// * `SspiOk` on success
605    /// * `Error` on error
606    ///
607    /// # MSDN
608    ///
609    /// * [EncryptMessage function](https://docs.microsoft.com/en-us/windows/win32/api/sspi/nf-sspi-encryptmessage)
610    fn encrypt_message(
611        &mut self,
612        flags: EncryptionFlags,
613        message: &mut [SecurityBufferRef<'_>],
614    ) -> Result<SecurityStatus>;
615
616    /// Generates a cryptographic checksum of the message, and also includes sequencing information to prevent message loss or insertion.
617    /// The function allows the application to choose between several cryptographic algorithms, if supported by the chosen mechanism.
618    ///
619    /// # Parameters
620    /// * `flags`: package-specific flags that indicate the quality of protection. A security package can use this parameter to enable the selection of cryptographic algorithms
621    /// * `message`: On input, the structure references one or more `SecurityBufferRef` structures of type `BufferType::Data` that contain the message to be signed,
622    ///   and a `SecurityBufferRef` of type `BufferType::Token` that receives the signature.
623    /// * `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
624    ///
625    /// # Returns
626    /// * `SspiOk` on success
627    /// * `Error` on error
628    ///
629    /// # Example
630    ///
631    /// ```
632    /// use sspi::Sspi;
633    /// use sspi::Username;
634    /// use sspi::builders::EmptyInitializeSecurityContext;
635    /// use sspi::SspiImpl;
636    ///
637    /// let mut client_ntlm = sspi::Ntlm::new();
638    /// let mut ntlm = sspi::Ntlm::new();
639    ///
640    /// let mut client_output_buffer = vec![sspi::SecurityBuffer::new(Vec::new(), sspi::BufferType::Token)];
641    /// let mut server_output_buffer = vec![sspi::SecurityBuffer::new(Vec::new(), sspi::BufferType::Token)];
642    ///
643    /// let identity = sspi::AuthIdentity {
644    ///     username: Username::parse("user").unwrap(),
645    ///     password: "password".to_string().into(),
646    /// };
647    ///
648    /// let mut client_acq_cred_result = client_ntlm
649    ///     .acquire_credentials_handle()
650    ///     .with_credential_use(sspi::CredentialUse::Outbound)
651    ///     .with_auth_data(&identity)
652    ///     .execute(&mut client_ntlm)
653    ///     .unwrap();
654    ///
655    /// let mut server_acq_cred_result = ntlm
656    ///     .acquire_credentials_handle()
657    ///     .with_credential_use(sspi::CredentialUse::Inbound)
658    ///     .with_auth_data(&identity)
659    ///     .execute(&mut ntlm)
660    ///     .unwrap();
661    ///
662    /// loop {
663    ///     client_output_buffer[0].buffer.clear();
664    ///
665    ///     let mut builder = client_ntlm.initialize_security_context()
666    ///         .with_credentials_handle(&mut client_acq_cred_result.credentials_handle)
667    ///         .with_context_requirements(
668    ///             sspi::ClientRequestFlags::CONFIDENTIALITY | sspi::ClientRequestFlags::ALLOCATE_MEMORY,
669    ///         )
670    ///         .with_target_data_representation(sspi::DataRepresentation::Native)
671    ///         .with_target_name("user")
672    ///         .with_input(&mut server_output_buffer)
673    ///         .with_output(&mut client_output_buffer);
674    ///
675    ///     let _client_result = client_ntlm.initialize_security_context_impl(&mut builder)
676    ///         .unwrap()
677    ///         .resolve_to_result()
678    ///         .unwrap();
679    ///
680    ///     let builder = ntlm
681    ///         .accept_security_context()
682    ///         .with_credentials_handle(&mut server_acq_cred_result.credentials_handle)
683    ///         .with_context_requirements(sspi::ServerRequestFlags::ALLOCATE_MEMORY)
684    ///         .with_target_data_representation(sspi::DataRepresentation::Native)
685    ///         .with_input(&mut client_output_buffer)
686    ///         .with_output(&mut server_output_buffer);
687    ///     let server_result = ntlm.accept_security_context_impl(builder)
688    ///         .unwrap()
689    ///         .resolve_to_result()
690    ///         .unwrap();
691    ///
692    ///     if server_result.status == sspi::SecurityStatus::CompleteAndContinue
693    ///         || server_result.status == sspi::SecurityStatus::CompleteNeeded
694    ///     {
695    ///         break;
696    ///     }
697    /// }
698    ///
699    /// let _result = ntlm
700    ///     .complete_auth_token(&mut server_output_buffer)
701    ///     .unwrap();
702    ///
703    /// let mut token = [0; 128];
704    /// let mut data = "This is a message to be signed".as_bytes().to_vec();
705    /// let mut msg_buffer = vec![
706    ///     sspi::SecurityBufferRef::token_buf(token.as_mut_slice()),
707    ///     sspi::SecurityBufferRef::data_buf(data.as_mut_slice()),
708    /// ];
709    ///
710    /// println!("Input data: {:?}", msg_buffer[1].data());
711    ///
712    /// #[allow(unused_variables)]
713    /// let result = ntlm
714    ///     .make_signature(0, &mut msg_buffer, 0).unwrap();
715    ///
716    /// println!("Data signature: {:?}", msg_buffer[0].data());
717    /// ```
718    ///
719    /// # MSDN
720    /// * [MakeSignature function](https://learn.microsoft.com/en-us/windows/win32/api/sspi/nf-sspi-makesignature)
721    fn make_signature(&mut self, flags: u32, message: &mut [SecurityBufferRef<'_>], sequence_number: u32)
722    -> Result<()>;
723
724    /// Verifies that a message signed by using the `make_signature` function was received in the correct sequence and has not been modified.
725    ///
726    /// # Parameters
727    /// * `message`: On input, the structure references one or more `SecurityBufferRef` structures of type `BufferType::Data` that contain the message to be verified,
728    ///   and a `SecurityBufferRef` of type `BufferType::Token` that contains the signature.
729    /// * `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
730    ///
731    /// # Returns
732    /// * `u32` package-specific flags that indicate the quality of protection.
733    /// * `Error` on error
734    ///
735    /// # Example
736    ///
737    /// ```
738    /// use sspi::Sspi;
739    /// use sspi::Username;
740    /// use sspi::builders::EmptyInitializeSecurityContext;
741    /// use sspi::SspiImpl;
742    ///
743    /// let mut ntlm = sspi::Ntlm::new();
744    /// let mut server_ntlm = sspi::Ntlm::new();
745    ///
746    /// let mut client_output_buffer = vec![sspi::SecurityBuffer::new(Vec::new(), sspi::BufferType::Token)];
747    /// let mut server_output_buffer = vec![sspi::SecurityBuffer::new(Vec::new(), sspi::BufferType::Token)];
748    ///
749    /// let identity = sspi::AuthIdentity {
750    ///     username: Username::parse("user").unwrap(),
751    ///     password: "password".to_string().into(),
752    /// };
753    ///
754    /// let mut client_acq_cred_result = ntlm
755    ///     .acquire_credentials_handle()
756    ///     .with_credential_use(sspi::CredentialUse::Outbound)
757    ///     .with_auth_data(&identity)
758    ///     .execute(&mut ntlm)
759    ///     .unwrap();
760    ///
761    /// let mut server_acq_cred_result = server_ntlm
762    ///     .acquire_credentials_handle()
763    ///     .with_credential_use(sspi::CredentialUse::Inbound)
764    ///     .with_auth_data(&identity)
765    ///     .execute(&mut server_ntlm)
766    ///     .unwrap();
767    ///
768    /// loop {
769    ///     client_output_buffer[0].buffer.clear();
770    ///
771    ///     let mut builder = ntlm.initialize_security_context()
772    ///         .with_credentials_handle(&mut client_acq_cred_result.credentials_handle)
773    ///         .with_context_requirements(
774    ///             sspi::ClientRequestFlags::CONFIDENTIALITY | sspi::ClientRequestFlags::ALLOCATE_MEMORY,
775    ///         )
776    ///         .with_target_data_representation(sspi::DataRepresentation::Native)
777    ///         .with_target_name("user")
778    ///         .with_input(&mut server_output_buffer)
779    ///         .with_output(&mut client_output_buffer);
780    ///
781    ///     let _client_result = ntlm.initialize_security_context_impl(&mut builder)
782    ///         .unwrap()
783    ///         .resolve_to_result()
784    ///         .unwrap();
785    ///
786    ///     let builder = server_ntlm
787    ///         .accept_security_context()
788    ///         .with_credentials_handle(&mut server_acq_cred_result.credentials_handle)
789    ///         .with_context_requirements(sspi::ServerRequestFlags::ALLOCATE_MEMORY)
790    ///         .with_target_data_representation(sspi::DataRepresentation::Native)
791    ///         .with_input(&mut client_output_buffer)
792    ///         .with_output(&mut server_output_buffer);
793    ///     let server_result = server_ntlm.accept_security_context_impl(builder)
794    ///         .unwrap()
795    ///         .resolve_to_result()
796    ///         .unwrap();
797    ///
798    ///     if server_result.status == sspi::SecurityStatus::CompleteAndContinue
799    ///         || server_result.status == sspi::SecurityStatus::CompleteNeeded
800    ///     {
801    ///         break;
802    ///     }
803    /// }
804    ///
805    /// let _result = server_ntlm
806    ///     .complete_auth_token(&mut server_output_buffer)
807    ///     .unwrap();
808    ///
809    /// let mut token = [0; 128];
810    /// let mut data = "This is a message".as_bytes().to_vec();
811    /// let mut msg = [
812    ///     sspi::SecurityBufferRef::token_buf(token.as_mut_slice()),
813    ///     sspi::SecurityBufferRef::data_buf(data.as_mut_slice()),
814    /// ];
815    ///
816    /// let _result = server_ntlm
817    ///     .make_signature(0, &mut msg, 0).unwrap();
818    ///
819    /// let [mut token, mut data] = msg;
820    ///
821    /// let mut msg_buffer = vec![
822    ///     sspi::SecurityBufferRef::token_buf(token.take_data()),
823    ///     sspi::SecurityBufferRef::data_buf(data.take_data()),
824    /// ];
825    ///
826    /// #[allow(unused_variables)]
827    /// let signature_flags = ntlm
828    ///     .verify_signature(&mut msg_buffer, 0)
829    ///     .unwrap();
830    ///
831    /// println!("Signature calculated and verified.");
832    /// ```
833    ///
834    /// # MSDN
835    /// * [VerifySignature function](https://learn.microsoft.com/en-us/windows/win32/api/sspi/nf-sspi-verifysignature)
836    fn verify_signature(&mut self, message: &mut [SecurityBufferRef<'_>], sequence_number: u32) -> Result<u32>;
837
838    /// Decrypts a message. Some packages do not encrypt and decrypt messages but rather perform and check an integrity hash.
839    ///
840    /// # Parameters
841    ///
842    /// * `message`: on input, the structure references one or more `SecurityBufferRef` structures.
843    ///   At least one of these must be of type `BufferType::Data`.
844    ///   That buffer contains the encrypted message. The encrypted message is decrypted in place, overwriting the original contents of its buffer
845    /// * `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
846    ///
847    /// # Returns
848    ///
849    /// * `DecryptionFlags` upon success
850    /// * `Error` on error
851    ///
852    /// # Example
853    ///
854    /// ```
855    /// use sspi::Sspi;
856    /// use sspi::Username;
857    /// use sspi::builders::EmptyInitializeSecurityContext;
858    /// use sspi::SspiImpl;
859    ///
860    /// let mut ntlm = sspi::Ntlm::new();
861    /// let mut server_ntlm = sspi::Ntlm::new();
862    ///
863    /// let mut client_output_buffer = vec![sspi::SecurityBuffer::new(Vec::new(), sspi::BufferType::Token)];
864    /// let mut server_output_buffer = vec![sspi::SecurityBuffer::new(Vec::new(), sspi::BufferType::Token)];
865    ///
866    /// let identity = sspi::AuthIdentity {
867    ///     username: Username::parse("user").unwrap(),
868    ///     password: "password".to_string().into(),
869    /// };
870    ///
871    /// let mut client_acq_cred_result = ntlm
872    ///     .acquire_credentials_handle()
873    ///     .with_credential_use(sspi::CredentialUse::Outbound)
874    ///     .with_auth_data(&identity)
875    ///     .execute(&mut ntlm)
876    ///     .unwrap();
877    ///
878    /// let mut server_acq_cred_result = server_ntlm
879    ///     .acquire_credentials_handle()
880    ///     .with_credential_use(sspi::CredentialUse::Inbound)
881    ///     .with_auth_data(&identity)
882    ///     .execute(&mut server_ntlm)
883    ///     .unwrap();
884    ///
885    /// loop {
886    ///     client_output_buffer[0].buffer.clear();
887    ///
888    ///     let mut builder = ntlm.initialize_security_context()
889    ///         .with_credentials_handle(&mut client_acq_cred_result.credentials_handle)
890    ///         .with_context_requirements(
891    ///             sspi::ClientRequestFlags::CONFIDENTIALITY | sspi::ClientRequestFlags::ALLOCATE_MEMORY,
892    ///         )
893    ///         .with_target_data_representation(sspi::DataRepresentation::Native)
894    ///         .with_target_name("user")
895    ///         .with_input(&mut server_output_buffer)
896    ///         .with_output(&mut client_output_buffer);
897    ///
898    ///     let _client_result = ntlm.initialize_security_context_impl(&mut builder)
899    ///         .unwrap()
900    ///         .resolve_to_result()
901    ///         .unwrap();
902    ///
903    ///     let builder = server_ntlm
904    ///         .accept_security_context()
905    ///         .with_credentials_handle(&mut server_acq_cred_result.credentials_handle)
906    ///         .with_context_requirements(sspi::ServerRequestFlags::ALLOCATE_MEMORY)
907    ///         .with_target_data_representation(sspi::DataRepresentation::Native)
908    ///         .with_input(&mut client_output_buffer)
909    ///         .with_output(&mut server_output_buffer);
910    ///     let server_result = server_ntlm.accept_security_context_impl(builder)
911    ///         .unwrap()
912    ///         .resolve_to_result()
913    ///         .unwrap();
914    ///
915    ///     if server_result.status == sspi::SecurityStatus::CompleteAndContinue
916    ///         || server_result.status == sspi::SecurityStatus::CompleteNeeded
917    ///     {
918    ///         break;
919    ///     }
920    /// }
921    ///
922    /// let _result = server_ntlm
923    ///     .complete_auth_token(&mut server_output_buffer)
924    ///     .unwrap();
925    ///
926    /// let mut token = [0; 128];
927    /// let mut data = "This is a message".as_bytes().to_vec();
928    /// let mut msg = [
929    ///     sspi::SecurityBufferRef::token_buf(token.as_mut_slice()),
930    ///     sspi::SecurityBufferRef::data_buf(data.as_mut_slice()),
931    /// ];
932    ///
933    /// let _result = server_ntlm
934    ///     .encrypt_message(sspi::EncryptionFlags::empty(), &mut msg).unwrap();
935    ///
936    /// let [mut token, mut data] = msg;
937    ///
938    /// let mut msg_buffer = vec![
939    ///     sspi::SecurityBufferRef::token_buf(token.take_data()),
940    ///     sspi::SecurityBufferRef::data_buf(data.take_data()),
941    /// ];
942    ///
943    /// #[allow(unused_variables)]
944    /// let encryption_flags = ntlm
945    ///     .decrypt_message(&mut msg_buffer)
946    ///     .unwrap();
947    ///
948    /// println!("Decrypted message: {:?}", msg_buffer[1].data());
949    /// ```
950    ///
951    /// # MSDN
952    ///
953    /// * [DecryptMessage function](https://docs.microsoft.com/en-us/windows/win32/api/sspi/nf-sspi-decryptmessage)
954    fn decrypt_message(&mut self, message: &mut [SecurityBufferRef<'_>]) -> Result<DecryptionFlags>;
955
956    /// Retrieves information about the bounds of sizes of authentication information of the current security principal.
957    ///
958    /// # Returns
959    ///
960    /// * `ContextSizes` upon success
961    /// * `Error` on error
962    ///
963    /// # Example
964    ///
965    /// ```
966    /// use sspi::Sspi;
967    /// let mut ntlm = sspi::Ntlm::new();
968    /// let sizes = ntlm.query_context_sizes().unwrap();
969    /// println!("Max token: {}", sizes.max_token);
970    /// println!("Max signature: {}", sizes.max_signature);
971    /// println!("Block: {}", sizes.block);
972    /// println!("Security trailer: {}", sizes.security_trailer);
973    /// ```
974    ///
975    /// # MSDN
976    ///
977    /// * [QueryCredentialsAttributesW function](https://docs.microsoft.com/en-us/windows/win32/api/sspi/nf-sspi-querycredentialsattributesw)
978    fn query_context_sizes(&mut self) -> Result<ContextSizes>;
979
980    /// Retrieves the username of the credential associated to the context.
981    ///
982    /// # Returns
983    ///
984    /// * `ContextNames` upon success
985    /// * `Error` on error
986    ///
987    /// # Example
988    ///
989    /// ```
990    /// use sspi::Sspi;
991    /// use sspi::Username;
992    ///
993    /// let mut ntlm = sspi::Ntlm::new();
994    /// let identity = sspi::AuthIdentity {
995    ///     username: Username::parse("user").unwrap(),
996    ///     password: "password".to_string().into(),
997    /// };
998    ///
999    /// let _acq_cred_result = ntlm
1000    ///     .acquire_credentials_handle()
1001    ///     .with_credential_use(sspi::CredentialUse::Inbound)
1002    ///     .with_auth_data(&identity)
1003    ///     .execute(&mut ntlm).unwrap();
1004    ///
1005    /// let names = ntlm.query_context_names().unwrap();
1006    /// println!("Username: {:?}", names.username.account_name());
1007    /// println!("Domain: {:?}", names.username.domain_name());
1008    /// ```
1009    ///
1010    /// # MSDN
1011    ///
1012    /// * [QuerySecurityPackageInfoW function](https://docs.microsoft.com/en-us/windows/win32/api/sspi/nf-sspi-querysecuritypackageinfow)
1013    fn query_context_names(&mut self) -> Result<ContextNames>;
1014
1015    /// Queries the sizes of the various parts of a stream used in the per-message functions. This function is implemented only for CredSSP security package.
1016    ///
1017    /// # MSDN
1018    ///
1019    /// * [QuerySecurityPackageInfoW function (`ulAttribute` parameter)](https://learn.microsoft.com/en-us/windows/win32/secauthn/querycontextattributes--schannel)
1020    fn query_context_stream_sizes(&mut self) -> Result<StreamSizes> {
1021        Err(Error::new(
1022            ErrorKind::UnsupportedFunction,
1023            "query_context_stream_sizes is not supported",
1024        ))
1025    }
1026
1027    /// Retrieves information about the specified security package. This information includes the bounds of sizes of authentication information, credentials, and contexts.
1028    ///
1029    /// # Returns
1030    ///
1031    /// * `PackageInfo` containing the information about the package
1032    /// * `Error` on error
1033    ///
1034    /// # Example
1035    ///
1036    /// ```
1037    /// use sspi::Sspi;
1038    /// let mut ntlm = sspi::Ntlm::new();
1039    /// let info = ntlm.query_context_package_info().unwrap();
1040    /// println!("Package name: {:?}", info.name);
1041    /// ```
1042    ///
1043    /// # MSDN
1044    ///
1045    /// * [QuerySecurityPackageInfoW function](https://docs.microsoft.com/en-us/windows/win32/api/sspi/nf-sspi-querysecuritypackageinfow)
1046    fn query_context_package_info(&mut self) -> Result<PackageInfo>;
1047
1048    /// Retrieves the trust information of the certificate.
1049    ///
1050    /// # Returns
1051    ///
1052    /// * `CertTrustStatus` on success
1053    ///
1054    /// # Example
1055    ///
1056    /// ```
1057    /// use sspi::Sspi;
1058    /// let mut ntlm = sspi::Ntlm::new();
1059    /// let cert_info = ntlm.query_context_package_info().unwrap();
1060    /// ```
1061    ///
1062    /// # MSDN
1063    ///
1064    /// * [QueryContextAttributes (CredSSP) function (`ulAttribute` parameter)](https://docs.microsoft.com/en-us/windows/win32/secauthn/querycontextattributes--credssp)
1065    fn query_context_cert_trust_status(&mut self) -> Result<CertTrustStatus>;
1066
1067    /// Retrieves the information about the end certificate supplied by the server. This function is implemented only for CredSSP security package.
1068    ///
1069    /// # Returns
1070    ///
1071    /// * `CertContext` on success
1072    ///
1073    /// # MSDN
1074    ///
1075    /// * [QueryContextAttributes (CredSSP) function (`ulAttribute` parameter)](https://docs.microsoft.com/en-us/windows/win32/secauthn/querycontextattributes--credssp)
1076    fn query_context_remote_cert(&mut self) -> Result<CertContext> {
1077        Err(Error::new(
1078            ErrorKind::UnsupportedFunction,
1079            "query_remote_cert_context is not supported",
1080        ))
1081    }
1082
1083    /// Retrieves the information about the negotiated security package. This function is implemented only for CredSSP security package.
1084    ///
1085    /// # Returns
1086    ///
1087    /// * `PackageInfo` on success
1088    ///
1089    /// # MSDN
1090    ///
1091    /// * [QueryContextAttributes (CredSSP) function (`ulAttribute` parameter)](https://learn.microsoft.com/en-us/windows/win32/api/sspi/nf-sspi-querycontextattributesw)
1092    fn query_context_negotiation_package(&mut self) -> Result<PackageInfo> {
1093        Err(Error::new(
1094            ErrorKind::UnsupportedFunction,
1095            "query_context_negotiation_package is not supported",
1096        ))
1097    }
1098
1099    /// Returns detailed information on the established connection. This function is implemented only for CredSSP security package.
1100    ///
1101    /// # Returns
1102    ///
1103    /// * `ConnectionInfo` on success
1104    ///
1105    /// # MSDN
1106    ///
1107    /// * [QueryContextAttributes (CredSSP) function (`ulAttribute` parameter)](https://docs.microsoft.com/en-us/windows/win32/secauthn/querycontextattributes--credssp)
1108    fn query_context_connection_info(&mut self) -> Result<ConnectionInfo> {
1109        Err(Error::new(
1110            ErrorKind::UnsupportedFunction,
1111            "query_context_connection_info is not supported",
1112        ))
1113    }
1114
1115    /// Returns information about the session key used for the security context.
1116    ///
1117    /// # Returns
1118    ///
1119    /// * `SessionKeys` on success
1120    ///
1121    /// # MSDN
1122    ///
1123    /// * [QueryContextAttributes function (`ulAttribute` parameter)](https://docs.microsoft.com/en-us/windows/win32/secauthn/querycontextattributes--general)
1124    fn query_context_session_key(&self) -> Result<SessionKeys> {
1125        Err(Error::new(
1126            ErrorKind::UnsupportedFunction,
1127            "query_context_session_key is not supported",
1128        ))
1129    }
1130
1131    /// Changes the password for a Windows domain account.
1132    ///
1133    /// # Returns
1134    ///
1135    /// * `()` on success
1136    ///
1137    /// # Example
1138    ///
1139    /// ```ignore
1140    /// use sspi::{Sspi, ChangePasswordBuilder};
1141    /// let mut ntlm = sspi::Ntlm::new();
1142    /// let mut output = [];
1143    /// let cert_info = ntlm.query_context_package_info().unwrap();
1144    /// let change_password = ChangePasswordBuilder::new()
1145    ///     .with_domain_name("domain".into())
1146    ///     .with_account_name("username".into())
1147    ///     .with_old_password("old_password".into())
1148    ///     .with_old_password("new_password".into())
1149    ///     .with_output(&mut output)
1150    ///     .build()
1151    ///     .unwrap();
1152    /// ntlm.change_password(change_password).unwrap();
1153    /// ```
1154    ///
1155    /// # MSDN
1156    ///
1157    /// * [ChangeAccountPasswordW function](https://docs.microsoft.com/en-us/windows/win32/api/sspi/nf-sspi-changeaccountpasswordw)
1158    fn change_password<'a>(&'a mut self, change_password: ChangePassword<'a>) -> Result<GeneratorChangePassword<'a>>;
1159}
1160
1161/// Protocol used to establish connection.
1162///
1163/// # MSDN
1164///
1165/// [SecPkgContext_ConnectionInfo (`dwProtocol` field)](https://learn.microsoft.com/en-us/windows/win32/api/schannel/ns-schannel-secpkgcontext_connectioninfo)
1166#[derive(Debug, Clone, Eq, PartialEq, FromPrimitive, ToPrimitive)]
1167pub enum ConnectionProtocol {
1168    SpProtTls1Client = 0x80,
1169    SpProtTls1Server = 0x40,
1170    SpProtSsl3Client = 0x20,
1171    SpProtSsl3Server = 0x10,
1172    SpProtTls1_1Client = 0x200,
1173    SpProtTls1_1Server = 0x100,
1174    SpProtTls1_2Client = 0x800,
1175    SpProtTls1_2Server = 0x400,
1176    SpProtTls1_3Client = 0x00002000,
1177    SpProtTls1_3Server = 0x00001000,
1178    SpProtPct1Client = 0x2,
1179    SpProtPct1Server = 0x1,
1180    SpProtSsl2Client = 0x8,
1181    SpProtSsl2Server = 0x4,
1182}
1183
1184/// Algorithm identifier for the bulk encryption cipher used by the connection.
1185///
1186/// # MSDN
1187///
1188/// [SecPkgContext_ConnectionInfo (`aiCipher` field)](https://learn.microsoft.com/en-us/windows/win32/api/schannel/ns-schannel-secpkgcontext_connectioninfo)
1189#[derive(Debug, Clone, Eq, PartialEq, FromPrimitive, ToPrimitive)]
1190pub enum ConnectionCipher {
1191    Calg3des = 26115,
1192    CalgAes128 = 26126,
1193    CalgAes256 = 26128,
1194    CalgDes = 26113,
1195    CalgRc2 = 26114,
1196    CalgRc4 = 26625,
1197    NoEncryption = 0,
1198}
1199
1200/// ALG_ID indicating the hash used for generating Message Authentication Codes (MACs).
1201///
1202/// # MSDN
1203///
1204/// [SecPkgContext_ConnectionInfo (`aiHash` field)](https://learn.microsoft.com/en-us/windows/win32/api/schannel/ns-schannel-secpkgcontext_connectioninfo)
1205#[derive(Debug, Clone, Eq, PartialEq, FromPrimitive, ToPrimitive)]
1206pub enum ConnectionHash {
1207    CalgMd5 = 32771,
1208    CalgSha = 32772,
1209}
1210
1211/// ALG_ID indicating the key exchange algorithm used to generate the shared master secret.
1212///
1213/// # MSDN
1214///
1215/// [SecPkgContext_ConnectionInfo (`aiExch` field)](https://learn.microsoft.com/en-us/windows/win32/api/schannel/ns-schannel-secpkgcontext_connectioninfo)
1216#[derive(Debug, Clone, Eq, PartialEq, FromPrimitive, ToPrimitive)]
1217pub enum ConnectionKeyExchange {
1218    CalgRsaKeyx = 41984,
1219    CalgDhEphem = 43522,
1220}
1221
1222/// Type of certificate encoding used.
1223///
1224/// # MSDN
1225///
1226/// [CERT_CONTEXT (`dwCertEncodingType` field)](https://learn.microsoft.com/en-us/windows/win32/api/wincrypt/ns-wincrypt-cert_context)
1227#[derive(Debug, Clone, Eq, PartialEq, FromPrimitive, ToPrimitive)]
1228pub enum CertEncodingType {
1229    Pkcs7AsnEncoding = 65536,
1230    X509AsnEncoding = 1,
1231}
1232
1233/// The CERT_CONTEXT structure contains both the encoded and decoded representations of a certificate.
1234///
1235/// # MSDN
1236///
1237/// [CERT_CONTEXT](https://learn.microsoft.com/en-us/windows/win32/api/wincrypt/ns-wincrypt-cert_context)
1238#[derive(Debug, Clone, PartialEq)]
1239pub struct CertContext {
1240    pub encoding_type: CertEncodingType,
1241    pub raw_cert: Vec<u8>,
1242    pub cert: Certificate,
1243}
1244
1245/// This structure contains protocol and cipher information.
1246///
1247/// # MSDN
1248///
1249/// [SecPkgContext_ConnectionInfo](https://learn.microsoft.com/en-us/windows/win32/api/schannel/ns-schannel-secpkgcontext_connectioninfo)
1250#[derive(Debug, Clone, Eq, PartialEq)]
1251pub struct ConnectionInfo {
1252    pub protocol: ConnectionProtocol,
1253    pub cipher: ConnectionCipher,
1254    pub cipher_strength: u32,
1255    pub hash: ConnectionHash,
1256    pub hash_strength: u32,
1257    pub key_exchange: ConnectionKeyExchange,
1258    pub exchange_strength: u32,
1259}
1260
1261/// Trait for performing authentication on the client or server side
1262pub trait SspiImpl {
1263    /// Represents raw data for authentication
1264    type CredentialsHandle;
1265    /// Represents authentication data prepared for the authentication process
1266    type AuthenticationData;
1267
1268    fn acquire_credentials_handle_impl(
1269        &mut self,
1270        builder: FilledAcquireCredentialsHandle<'_, Self::CredentialsHandle, Self::AuthenticationData>,
1271    ) -> Result<AcquireCredentialsHandleResult<Self::CredentialsHandle>>;
1272
1273    fn initialize_security_context_impl<'ctx, 'b, 'g>(
1274        &'ctx mut self,
1275        builder: &'b mut FilledInitializeSecurityContext<'ctx, 'ctx, Self::CredentialsHandle>,
1276    ) -> Result<GeneratorInitSecurityContext<'g>>
1277    where
1278        'ctx: 'g,
1279        'b: 'g;
1280
1281    fn accept_security_context_impl<'a>(
1282        &'a mut self,
1283        builder: FilledAcceptSecurityContext<'a, Self::CredentialsHandle>,
1284    ) -> Result<GeneratorAcceptSecurityContext<'a>>;
1285}
1286
1287mod private {
1288    pub struct Sealed;
1289}
1290
1291pub trait SspiEx
1292where
1293    Self: Sized + SspiImpl,
1294{
1295    fn custom_set_auth_identity(&mut self, identity: Self::AuthenticationData) -> Result<()>;
1296
1297    /// Set multiple candidate credentials for server-side verification.
1298    ///
1299    /// During NTLM authentication, the server will try each candidate to find
1300    /// one whose password matches the client's challenge-response.
1301    ///
1302    /// # Security considerations
1303    ///
1304    /// Candidates should represent a bounded set of currently-valid credentials
1305    /// (e.g., TTL-bound tokens, or "current + previous" within a defined grace
1306    /// period), not an unbounded history. Implementations should cap the number
1307    /// of candidates and ensure existing rate-limiting / lockout behavior remains
1308    /// effective, so that multi-credential verification does not multiply online
1309    /// guessing attempts. This mechanism is for selection among multiple valid
1310    /// credentials, not for weakening a policy that intends immediate
1311    /// invalidation.
1312    ///
1313    /// The default implementation uses only the first credential.
1314    fn custom_set_auth_identities(&mut self, identities: Vec<Self::AuthenticationData>) -> Result<()> {
1315        match identities.into_iter().next() {
1316            Some(identity) => self.custom_set_auth_identity(identity),
1317            None => Err(Error::new(ErrorKind::NoCredentials, "no credentials provided")),
1318        }
1319    }
1320
1321    /// Verifies a MIC (Message Integrity Code) token for the specified message data.
1322    ///
1323    /// This method is used only by the Negotiate security package (SPNEGO protocol implementation)
1324    /// to verify the `mechListMIC` token during the authentication process.
1325    fn verify_mic_token(&mut self, _token: &[u8], _data: &[u8], _: private::Sealed) -> Result<()> {
1326        Err(Error::new(
1327            ErrorKind::UnsupportedFunction,
1328            "verify_mic_token is not supported",
1329        ))
1330    }
1331
1332    /// Generates a MIC (Message Integrity Code) token for the specified message data.
1333    ///
1334    /// This method is used only by the Negotiate security package (SPNEGO protocol implementation)
1335    /// to generate `mechListMIC` token during the authentication process.
1336    fn generate_mic_token(&mut self, _token: &[u8], _: private::Sealed) -> Result<Vec<u8>> {
1337        Err(Error::new(
1338            ErrorKind::UnsupportedFunction,
1339            "generate_mic_token is not supported",
1340        ))
1341    }
1342}
1343
1344pub type SspiPackage<'a, CredsHandle, AuthData> =
1345    &'a mut dyn SspiImpl<CredentialsHandle = CredsHandle, AuthenticationData = AuthData>;
1346
1347bitflags! {
1348    /// Indicate the quality of protection. Used in the `encrypt_message` method.
1349    ///
1350    /// # MSDN
1351    ///
1352    /// * [EncryptMessage function (`fQOP` parameter)](https://docs.microsoft.com/en-us/windows/win32/api/sspi/nf-sspi-encryptmessage)
1353    #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
1354    pub struct EncryptionFlags: u32 {
1355        const WRAP_OOB_DATA = 0x4000_0000;
1356        const WRAP_NO_ENCRYPT = 0x8000_0001;
1357    }
1358}
1359
1360bitflags! {
1361    /// Indicate the quality of protection. Returned by the `decrypt_message` method.
1362    ///
1363    /// # MSDN
1364    ///
1365    /// * [DecryptMessage function (`pfQOP` parameter)](https://docs.microsoft.com/en-us/windows/win32/api/sspi/nf-sspi-decryptmessage)
1366    #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
1367    pub struct DecryptionFlags: u32 {
1368        const SIGN_ONLY = 0x8000_0000;
1369        const WRAP_NO_ENCRYPT = 0x8000_0001;
1370    }
1371}
1372
1373bitflags! {
1374    /// Indicate requests for the context. Not all packages can support all requirements. Bit flags can be combined by using bitwise-OR operations.
1375    ///
1376    /// # MSDN
1377    ///
1378    /// * [Context Requirements](https://docs.microsoft.com/en-us/windows/win32/secauthn/context-requirements)
1379    /// * [InitializeSecurityContextW function (fContextReq parameter)](https://docs.microsoft.com/en-us/windows/win32/api/sspi/nf-sspi-initializesecuritycontextw)
1380    #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
1381    pub struct ClientRequestFlags: u32 {
1382        /// The server can use the context to authenticate to other servers as the client.
1383        /// The `MUTUAL_AUTH` flag must be set for this flag to work. Valid for Kerberos. Ignore this flag for constrained delegation.
1384        const DELEGATE = 0x1;
1385        /// The mutual authentication policy of the service will be satisfied.
1386        const MUTUAL_AUTH = 0x2;
1387        /// Detect replayed messages that have been encoded by using the `encrypt_message` or `make_signature` (TBI) functions.
1388        const REPLAY_DETECT = 0x4;
1389        /// Detect messages received out of sequence.
1390        const SEQUENCE_DETECT = 0x8;
1391        /// Encrypt messages by using the `encrypt_message` function.
1392        const CONFIDENTIALITY = 0x10;
1393        /// A new session key must be negotiated. This value is supported only by the Kerberos security package.
1394        const USE_SESSION_KEY = 0x20;
1395        const PROMPT_FOR_CREDS = 0x40;
1396        /// Schannel must not attempt to supply credentials for the client automatically.
1397        const USE_SUPPLIED_CREDS = 0x80;
1398        /// The security package allocates output buffers for you.
1399        const ALLOCATE_MEMORY = 0x100;
1400        const USE_DCE_STYLE = 0x200;
1401        const DATAGRAM = 0x400;
1402        /// The security context will not handle formatting messages. This value is the default for the Kerberos, Negotiate, and NTLM security packages.
1403        const CONNECTION = 0x800;
1404        const CALL_LEVEL = 0x1000;
1405        const FRAGMENT_SUPPLIED = 0x2000;
1406        /// When errors occur, the remote party will be notified.
1407        const EXTENDED_ERROR = 0x4000;
1408        /// Support a stream-oriented connection.
1409        const STREAM = 0x8000;
1410        /// Sign messages and verify signatures by using the `encrypt_message` and `make_signature` (TBI) functions.
1411        const INTEGRITY = 0x0001_0000;
1412        const IDENTIFY = 0x0002_0000;
1413        const NULL_SESSION = 0x0004_0000;
1414        /// Schannel must not authenticate the server automatically.
1415        const MANUAL_CRED_VALIDATION = 0x0008_0000;
1416        const RESERVED1 = 0x0010_0000;
1417        const FRAGMENT_TO_FIT = 0x0020_0000;
1418        const FORWARD_CREDENTIALS = 0x0040_0000;
1419        /// If this flag is set, the `Integrity` flag is ignored. This value is supported only by the Negotiate and Kerberos security packages.
1420        const NO_INTEGRITY = 0x0080_0000;
1421        const USE_HTTP_STYLE = 0x100_0000;
1422        const UNVERIFIED_TARGET_NAME = 0x2000_0000;
1423        const CONFIDENTIALITY_ONLY = 0x4000_0000;
1424    }
1425}
1426
1427bitflags! {
1428    /// Specify the attributes required by the server to establish the context. Bit flags can be combined by using bitwise-OR operations.
1429    ///
1430    /// # MSDN
1431    ///
1432    /// * [Context Requirements](https://docs.microsoft.com/en-us/windows/win32/secauthn/context-requirements)
1433    /// * [AcceptSecurityContext function function (fContextReq parameter)](https://docs.microsoft.com/en-us/windows/win32/api/sspi/nf-sspi-acceptsecuritycontext?redirectedfrom=MSDN)
1434    #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
1435    pub struct ServerRequestFlags: u32 {
1436        /// The server is allowed to impersonate the client. Ignore this flag for [constrained delegation](https://docs.microsoft.com/windows/desktop/SecGloss/c-gly).
1437        const DELEGATE = 0x1;
1438        const MUTUAL_AUTH = 0x2;
1439        /// Detect replayed packets.
1440        const REPLAY_DETECT = 0x4;
1441        /// Detect messages received out of sequence.
1442        const SEQUENCE_DETECT = 0x8;
1443        const CONFIDENTIALITY = 0x10;
1444        const USE_SESSION_KEY = 0x20;
1445        const SESSION_TICKET = 0x40;
1446        /// Credential Security Support Provider (CredSSP) will allocate output buffers.
1447        const ALLOCATE_MEMORY = 0x100;
1448        const USE_DCE_STYLE = 0x200;
1449        const DATAGRAM = 0x400;
1450        /// The security context will not handle formatting messages.
1451        const CONNECTION = 0x800;
1452        const CALL_LEVEL = 0x1000;
1453        const FRAGMENT_SUPPLIED = 0x2000;
1454        /// When errors occur, the remote party will be notified.
1455        const EXTENDED_ERROR = 0x8000;
1456        /// Support a stream-oriented connection.
1457        const STREAM = 0x0001_0000;
1458        const INTEGRITY = 0x0002_0000;
1459        const LICENSING = 0x0004_0000;
1460        const IDENTIFY = 0x0008_0000;
1461        const ALLOW_NULL_SESSION = 0x0010_0000;
1462        const ALLOW_NON_USER_LOGONS = 0x0020_0000;
1463        const ALLOW_CONTEXT_REPLAY = 0x0040_0000;
1464        const FRAGMENT_TO_FIT = 0x80_0000;
1465        const NO_TOKEN = 0x100_0000;
1466        const PROXY_BINDINGS = 0x400_0000;
1467        const ALLOW_MISSING_BINDINGS = 0x1000_0000;
1468    }
1469}
1470
1471bitflags! {
1472    /// Indicate the attributes of the established context.
1473    ///
1474    /// # MSDN
1475    ///
1476    /// * [Context Requirements](https://docs.microsoft.com/en-us/windows/win32/secauthn/context-requirements)
1477    /// * [InitializeSecurityContextW function (pfContextAttr parameter)](https://docs.microsoft.com/en-us/windows/win32/api/sspi/nf-sspi-initializesecuritycontextw)
1478    #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
1479    pub struct ClientResponseFlags: u32 {
1480        /// The server can use the context to authenticate to other servers as the client.
1481        /// The `MUTUAL_AUTH` flag must be set for this flag to work. Valid for Kerberos. Ignore this flag for constrained delegation.
1482        const DELEGATE = 0x1;
1483        /// The mutual authentication policy of the service will be satisfied.
1484        const MUTUAL_AUTH = 0x2;
1485        /// Detect replayed messages that have been encoded by using the `encrypt_message` or `make_signature` (TBI) functions.
1486        const REPLAY_DETECT = 0x4;
1487        /// Detect messages received out of sequence.
1488        const SEQUENCE_DETECT = 0x8;
1489        /// Encrypt messages by using the `encrypt_message` function.
1490        const CONFIDENTIALITY = 0x10;
1491        /// A new session key must be negotiated. This value is supported only by the Kerberos security package.
1492        const USE_SESSION_KEY = 0x20;
1493        const USED_COLLECTED_CREDS = 0x40;
1494        /// Schannel must not attempt to supply credentials for the client automatically.
1495        const USED_SUPPLIED_CREDS = 0x80;
1496        /// The security package allocates output buffers for you.
1497        const ALLOCATED_MEMORY = 0x100;
1498        const USED_DCE_STYLE = 0x200;
1499        const DATAGRAM = 0x400;
1500        /// The security context will not handle formatting messages. This value is the default for the Kerberos, Negotiate, and NTLM security packages.
1501        const CONNECTION = 0x800;
1502        const INTERMEDIATE_RETURN = 0x1000;
1503        const CALL_LEVEL = 0x2000;
1504        /// When errors occur, the remote party will be notified.
1505        const EXTENDED_ERROR = 0x4000;
1506        /// Support a stream-oriented connection.
1507        const STREAM = 0x8000;
1508        /// Sign messages and verify signatures by using the `encrypt_message` and `make_signature` (TBI) functions.
1509        const INTEGRITY = 0x0001_0000;
1510        const IDENTIFY = 0x0002_0000;
1511        const NULL_SESSION = 0x0004_0000;
1512        /// Schannel must not authenticate the server automatically.
1513        const MANUAL_CRED_VALIDATION = 0x0008_0000;
1514        const RESERVED1 = 0x10_0000;
1515        const FRAGMENT_ONLY = 0x0020_0000;
1516        const FORWARD_CREDENTIALS = 0x0040_0000;
1517        const USED_HTTP_STYLE = 0x100_0000;
1518        const NO_ADDITIONAL_TOKEN = 0x200_0000;
1519        const REAUTHENTICATION = 0x800_0000;
1520        const CONFIDENTIALITY_ONLY = 0x4000_0000;
1521    }
1522}
1523
1524bitflags! {
1525    /// Indicate the attributes of the established context.
1526    ///
1527    /// # MSDN
1528    ///
1529    /// * [Context Requirements](https://docs.microsoft.com/en-us/windows/win32/secauthn/context-requirements)
1530    /// * [AcceptSecurityContext function function (pfContextAttr parameter)](https://docs.microsoft.com/en-us/windows/win32/api/sspi/nf-sspi-acceptsecuritycontext?redirectedfrom=MSDN)
1531    #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
1532    pub struct ServerResponseFlags: u32 {
1533        /// The server is allowed to impersonate the client. Ignore this flag for [constrained delegation](https://docs.microsoft.com/windows/desktop/SecGloss/c-gly).
1534        const DELEGATE = 0x1;
1535        const MUTUAL_AUTH = 0x2;
1536        /// Detect replayed packets.
1537        const REPLAY_DETECT = 0x4;
1538        /// Detect messages received out of sequence.
1539        const SEQUENCE_DETECT = 0x8;
1540        const CONFIDENTIALITY = 0x10;
1541        const USE_SESSION_KEY = 0x20;
1542        const SESSION_TICKET = 0x40;
1543        /// Credential Security Support Provider (CredSSP) will allocate output buffers.
1544        const ALLOCATED_MEMORY = 0x100;
1545        const USED_DCE_STYLE = 0x200;
1546        const DATAGRAM = 0x400;
1547        /// The security context will not handle formatting messages.
1548        const CONNECTION = 0x800;
1549        const CALL_LEVEL = 0x2000;
1550        const THIRD_LEG_FAILED = 0x4000;
1551        /// When errors occur, the remote party will be notified.
1552        const EXTENDED_ERROR = 0x8000;
1553        /// Support a stream-oriented connection.
1554        const STREAM = 0x0001_0000;
1555        const INTEGRITY = 0x0002_0000;
1556        const LICENSING = 0x0004_0000;
1557        const IDENTIFY = 0x0008_0000;
1558        const NULL_SESSION = 0x0010_0000;
1559        const ALLOW_NON_USER_LOGONS = 0x0020_0000;
1560        const ALLOW_CONTEXT_REPLAY = 0x0040_0000;
1561        const FRAGMENT_ONLY = 0x0080_0000;
1562        const NO_TOKEN = 0x100_0000;
1563        const NO_ADDITIONAL_TOKEN = 0x200_0000;
1564    }
1565}
1566
1567/// The data representation, such as byte ordering, on the target.
1568///
1569/// # MSDN
1570///
1571/// * [AcceptSecurityContext function (TargetDataRep parameter)](https://docs.microsoft.com/en-us/windows/win32/api/sspi/nf-sspi-acceptsecuritycontext)
1572#[derive(Debug, Copy, Clone, Eq, PartialEq, FromPrimitive, ToPrimitive)]
1573pub enum DataRepresentation {
1574    Network = 0,
1575    Native = 0x10,
1576}
1577
1578/// Describes a buffer allocated by a transport application to pass to a security package.
1579///
1580/// # MSDN
1581///
1582/// * [SecBuffer structure](https://docs.microsoft.com/en-us/windows/win32/api/sspi/ns-sspi-secbuffer)
1583#[derive(Clone)]
1584pub struct SecurityBuffer {
1585    pub buffer: Vec<u8>,
1586    pub buffer_type: SecurityBufferType,
1587}
1588
1589impl fmt::Debug for SecurityBuffer {
1590    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1591        write!(
1592            f,
1593            "SecurityBufferRef {{ buffer_type: {:?}, buffer: 0x",
1594            self.buffer_type
1595        )?;
1596        self.buffer.iter().try_for_each(|byte| write!(f, "{byte:02X}"))?;
1597        write!(f, " }}")?;
1598
1599        Ok(())
1600    }
1601}
1602
1603impl SecurityBuffer {
1604    pub fn new(buffer: Vec<u8>, buffer_type: BufferType) -> Self {
1605        Self {
1606            buffer,
1607            buffer_type: SecurityBufferType {
1608                buffer_type,
1609                buffer_flags: SecurityBufferFlags::NONE,
1610            },
1611        }
1612    }
1613
1614    pub fn find_buffer(buffers: &[SecurityBuffer], buffer_type: BufferType) -> Result<&SecurityBuffer> {
1615        buffers
1616            .iter()
1617            .find(|b| b.buffer_type.buffer_type == buffer_type)
1618            .ok_or_else(|| {
1619                Error::new(
1620                    ErrorKind::InvalidToken,
1621                    format!("no buffer was provided with type {buffer_type:?}"),
1622                )
1623            })
1624    }
1625
1626    pub fn find_buffer_mut(buffers: &mut [SecurityBuffer], buffer_type: BufferType) -> Result<&mut SecurityBuffer> {
1627        buffers
1628            .iter_mut()
1629            .find(|b| b.buffer_type.buffer_type == buffer_type)
1630            .ok_or_else(|| {
1631                Error::new(
1632                    ErrorKind::InvalidToken,
1633                    format!("no buffer was provided with type {buffer_type:?}"),
1634                )
1635            })
1636    }
1637}
1638
1639/// Bit flags that indicate the type of buffer.
1640///
1641/// # MSDN
1642///
1643/// * [SecBuffer structure (BufferType parameter)](https://docs.microsoft.com/en-us/windows/win32/api/sspi/ns-sspi-secbuffer)
1644#[repr(u32)]
1645#[derive(Debug, Copy, Clone, Eq, PartialEq, Default, FromPrimitive, ToPrimitive)]
1646pub enum BufferType {
1647    #[default]
1648    Empty = 0,
1649    /// The buffer contains common data. The security package can read and write this data, for example, to encrypt some or all of it.
1650    Data = 1,
1651    /// The buffer contains the security token portion of the message. This is read-only for input parameters or read/write for output parameters.
1652    Token = 2,
1653    TransportToPackageParameters = 3,
1654    /// The security package uses this value to indicate the number of missing bytes in a particular message.
1655    Missing = 4,
1656    /// The security package uses this value to indicate the number of extra or unprocessed bytes in a message.
1657    Extra = 5,
1658    /// The buffer contains a protocol-specific trailer for a particular record. It is not usually of interest to callers.
1659    StreamTrailer = 6,
1660    /// The buffer contains a protocol-specific header for a particular record. It is not usually of interest to callers.
1661    StreamHeader = 7,
1662    NegotiationInfo = 8,
1663    Padding = 9,
1664    Stream = 10,
1665    ObjectIdsList = 11,
1666    ObjectIdsListSignature = 12,
1667    /// This flag is reserved. Do not use it.
1668    Target = 13,
1669    /// The buffer contains channel binding information.
1670    ChannelBindings = 14,
1671    /// The buffer contains a [DOMAIN_PASSWORD_INFORMATION](https://docs.microsoft.com/en-us/windows/win32/api/ntsecapi/ns-ntsecapi-domain_password_information) structure.
1672    ChangePasswordResponse = 15,
1673    /// The buffer specifies the [service principal name (SPN)](https://docs.microsoft.com/en-us/windows/win32/secgloss/s-gly) of the target.
1674    TargetHost = 16,
1675    /// The buffer contains an alert message.
1676    Alert = 17,
1677    /// The buffer contains a list of application protocol IDs, one list per application protocol negotiation extension type to be enabled.
1678    ApplicationProtocol = 18,
1679    /// The buffer contains a bitmask for a `ReadOnly` buffer.
1680    AttributeMark = 0xF000_0000,
1681    /// The buffer is read-only with no checksum. This flag is intended for sending header information to the security package for computing the checksum.
1682    /// The package can read this buffer, but cannot modify it.
1683    ReadOnly = 0x8000_0000,
1684    /// The buffer is read-only with a checksum.
1685    ReadOnlyWithChecksum = 0x1000_0000,
1686}
1687
1688bitflags! {
1689    #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
1690    /// Security buffer flags.
1691    ///
1692    /// [`SecBuffer` structure (sspi.h)](https://learn.microsoft.com/en-us/windows/win32/api/sspi/ns-sspi-secbuffer).
1693    pub struct SecurityBufferFlags: u32 {
1694        /// There is no flags for the buffer.
1695        const NONE = 0x0;
1696        /// The buffer is read-only with no checksum. This flag is intended for sending header information to the security package for
1697        /// computing the checksum. The package can read this buffer, but cannot modify it.
1698        const SECBUFFER_READONLY = 0x80000000;
1699        /// The buffer is read-only with a checksum.
1700        const SECBUFFER_READONLY_WITH_CHECKSUM = 0x10000000;
1701    }
1702}
1703
1704/// Security buffer type.
1705///
1706/// Contains the actual security buffer type and its flags.
1707#[derive(Clone, Copy, Eq, PartialEq, Default)]
1708pub struct SecurityBufferType {
1709    /// Security buffer type.
1710    pub buffer_type: BufferType,
1711    /// Security buffer flags.
1712    pub buffer_flags: SecurityBufferFlags,
1713}
1714
1715impl SecurityBufferType {
1716    /// The buffer contains a bitmask for a `SECBUFFER_READONLY_WITH_CHECKSUM` buffer.
1717    ///
1718    /// [`SecBuffer` structure (sspi.h)](https://learn.microsoft.com/en-us/windows/win32/api/sspi/ns-sspi-secbuffer)
1719    pub const SECBUFFER_ATTRMASK: u32 = 0xf0000000;
1720}
1721
1722impl TryFrom<u32> for SecurityBufferType {
1723    type Error = Error;
1724
1725    fn try_from(value: u32) -> Result<Self> {
1726        use num_traits::cast::FromPrimitive;
1727
1728        let buffer_type = value & !Self::SECBUFFER_ATTRMASK;
1729        let buffer_type = BufferType::from_u32(buffer_type).ok_or_else(|| {
1730            Error::new(
1731                ErrorKind::InternalError,
1732                format!("u32({buffer_type}) to UnflaggedSecurityBuffer conversion error"),
1733            )
1734        })?;
1735
1736        let buffer_flags = value & Self::SECBUFFER_ATTRMASK;
1737        let buffer_flags = SecurityBufferFlags::from_bits(buffer_flags).ok_or_else(|| {
1738            Error::new(
1739                ErrorKind::InternalError,
1740                format!("invalid SecurityBufferFlags: {buffer_flags}"),
1741            )
1742        })?;
1743
1744        Ok(Self {
1745            buffer_type,
1746            buffer_flags,
1747        })
1748    }
1749}
1750
1751impl From<SecurityBufferType> for u32 {
1752    fn from(value: SecurityBufferType) -> u32 {
1753        use num_traits::cast::ToPrimitive;
1754
1755        value.buffer_type.to_u32().unwrap() | value.buffer_flags.bits()
1756    }
1757}
1758
1759impl fmt::Debug for SecurityBufferType {
1760    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1761        f.write_fmt(format_args!("({:?}, {:?})", self.buffer_type, self.buffer_flags))
1762    }
1763}
1764
1765/// A flag that indicates how the credentials are used.
1766///
1767/// # MSDN
1768///
1769/// * [AcquireCredentialsHandleW function (fCredentialUse parameter)](https://docs.microsoft.com/en-us/windows/win32/api/sspi/nf-sspi-acquirecredentialshandlew)
1770#[derive(Debug, Copy, Clone, Eq, PartialEq, FromPrimitive, ToPrimitive)]
1771pub enum CredentialUse {
1772    Inbound = 1,
1773    Outbound = 2,
1774    Both = 3,
1775    Default = 4,
1776}
1777
1778/// Represents the security principal in use.
1779#[derive(Debug, Clone)]
1780pub enum SecurityPackageType {
1781    Ntlm,
1782    Kerberos,
1783    Negotiate,
1784    Pku2u,
1785    #[cfg(feature = "tsssp")]
1786    CredSsp,
1787    Other(String),
1788}
1789
1790impl AsRef<str> for SecurityPackageType {
1791    fn as_ref(&self) -> &str {
1792        match self {
1793            SecurityPackageType::Ntlm => ntlm::PKG_NAME,
1794            SecurityPackageType::Kerberos => kerberos::PKG_NAME,
1795            SecurityPackageType::Negotiate => negotiate::PKG_NAME,
1796            SecurityPackageType::Pku2u => pku2u::PKG_NAME,
1797            #[cfg(feature = "tsssp")]
1798            SecurityPackageType::CredSsp => sspi_cred_ssp::PKG_NAME,
1799            SecurityPackageType::Other(name) => name.as_str(),
1800        }
1801    }
1802}
1803
1804impl fmt::Display for SecurityPackageType {
1805    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1806        match self {
1807            SecurityPackageType::Ntlm => write!(f, "{}", ntlm::PKG_NAME),
1808            SecurityPackageType::Kerberos => write!(f, "{}", kerberos::PKG_NAME),
1809            SecurityPackageType::Negotiate => write!(f, "{}", negotiate::PKG_NAME),
1810            SecurityPackageType::Pku2u => write!(f, "{}", pku2u::PKG_NAME),
1811            #[cfg(feature = "tsssp")]
1812            SecurityPackageType::CredSsp => write!(f, "{}", sspi_cred_ssp::PKG_NAME),
1813            SecurityPackageType::Other(name) => write!(f, "{name}"),
1814        }
1815    }
1816}
1817
1818impl str::FromStr for SecurityPackageType {
1819    type Err = Error;
1820
1821    fn from_str(s: &str) -> Result<Self> {
1822        match s {
1823            ntlm::PKG_NAME => Ok(SecurityPackageType::Ntlm),
1824            kerberos::PKG_NAME => Ok(SecurityPackageType::Kerberos),
1825            negotiate::PKG_NAME => Ok(SecurityPackageType::Negotiate),
1826            pku2u::PKG_NAME => Ok(SecurityPackageType::Pku2u),
1827            #[cfg(feature = "tsssp")]
1828            sspi_cred_ssp::PKG_NAME => Ok(SecurityPackageType::CredSsp),
1829            s => Ok(SecurityPackageType::Other(s.to_string())),
1830        }
1831    }
1832}
1833
1834/// General security principal information
1835///
1836/// Provides general information about a security package, such as its name and capabilities. Returned by `query_security_package_info`.
1837///
1838/// # MSDN
1839///
1840/// * [SecPkgInfoW structure](https://docs.microsoft.com/en-us/windows/win32/api/sspi/ns-sspi-secpkginfow)
1841#[derive(Debug, Clone)]
1842pub struct PackageInfo {
1843    pub capabilities: PackageCapabilities,
1844    pub rpc_id: u16,
1845    pub max_token_len: u32,
1846    pub name: SecurityPackageType,
1847    pub comment: String,
1848}
1849
1850bitflags! {
1851    /// Set of bit flags that describes the capabilities of the security package. It is possible to combine them.
1852    ///
1853    /// # MSDN
1854    ///
1855    /// * [SecPkgInfoW structure (`fCapabilities` parameter)](https://docs.microsoft.com/en-us/windows/win32/api/sspi/ns-sspi-secpkginfow)
1856    #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
1857    pub struct PackageCapabilities: u32 {
1858        /// The security package supports the `make_signature` (TBI) and `verify_signature` (TBI) functions.
1859        const INTEGRITY = 0x1;
1860        /// The security package supports the `encrypt_message` and `decrypt_message` functions.
1861        const PRIVACY = 0x2;
1862        /// The package is interested only in the security-token portion of messages, and will ignore any other buffers. This is a performance-related issue.
1863        const TOKEN_ONLY = 0x4;
1864        /// Supports [datagram](https://docs.microsoft.com/en-us/windows/win32/secgloss/d-gly)-style authentication.
1865        /// For more information, see [SSPI Context Semantics](https://docs.microsoft.com/en-us/windows/win32/secauthn/sspi-context-semantics).
1866        const DATAGRAM = 0x8;
1867        /// Supports connection-oriented style authentication. For more information, see [SSPI Context Semantics](https://docs.microsoft.com/en-us/windows/win32/secauthn/sspi-context-semantics).
1868        const CONNECTION = 0x10;
1869        /// Multiple legs are required for authentication.
1870        const MULTI_REQUIRED = 0x20;
1871        /// Server authentication support is not provided.
1872        const CLIENT_ONLY = 0x40;
1873        /// Supports extended error handling. For more information, see [Extended Error Information](https://docs.microsoft.com/en-us/windows/win32/secauthn/extended-error-information).
1874        const EXTENDED_ERROR = 0x80;
1875        /// Supports Windows impersonation in server contexts.
1876        const IMPERSONATION = 0x100;
1877        /// Understands Windows principal and target names.
1878        const ACCEPT_WIN32_NAME = 0x200;
1879        /// Supports stream semantics. For more information, see [SSPI Context Semantics](https://docs.microsoft.com/en-us/windows/win32/secauthn/sspi-context-semantics).
1880        const STREAM = 0x400;
1881        /// Can be used by the [Microsoft Negotiate](https://docs.microsoft.com/windows/desktop/SecAuthN/microsoft-negotiate) security package.
1882        const NEGOTIABLE = 0x800;
1883        /// Supports GSS compatibility.
1884        const GSS_COMPATIBLE = 0x1000;
1885        /// Supports [LsaLogonUser](https://docs.microsoft.com/windows/desktop/api/ntsecapi/nf-ntsecapi-lsalogonuser).
1886        const LOGON = 0x2000;
1887        /// Token buffers are in ASCII characters format.
1888        const ASCII_BUFFERS = 0x4000;
1889        /// Supports separating large tokens into smaller buffers so that applications can make repeated calls to
1890        /// `initialize_security_context` and `accept_security_context` with the smaller buffers to complete authentication.
1891        const FRAGMENT = 0x8000;
1892        /// Supports mutual authentication.
1893        const MUTUAL_AUTH = 0x1_0000;
1894        /// Supports delegation.
1895        const DELEGATION = 0x2_0000;
1896        /// The security package supports using a checksum instead of in-place encryption when calling the `encrypt_message` function.
1897        const READONLY_WITH_CHECKSUM = 0x4_0000;
1898        /// Supports callers with restricted tokens.
1899        const RESTRICTED_TOKENS = 0x8_0000;
1900        /// The security package extends the [Microsoft Negotiate](https://docs.microsoft.com/windows/desktop/SecAuthN/microsoft-negotiate) security package.
1901        /// There can be at most one package of this type.
1902        const NEGO_EXTENDER = 0x10_0000;
1903        /// This package is negotiated by the package of type `NEGO_EXTENDER`.
1904        const NEGOTIABLE2 = 0x20_0000;
1905        /// This package receives all calls from app container apps.
1906        const APP_CONTAINER_PASSTHROUGH = 0x40_0000;
1907        /// This package receives calls from app container apps if one of the following checks succeeds:
1908        /// * Caller has default credentials capability
1909        /// * The target is a proxy server
1910        /// * The caller has supplied credentials
1911        const APP_CONTAINER_CHECKS = 0x80_0000;
1912    }
1913}
1914
1915/// Indicates the sizes of the various parts of a stream for use with the message support functions.
1916/// `query_context_stream_sizes` function returns this structure.
1917///
1918/// # MSDN
1919///
1920/// * [SecPkgContext_StreamSizes](https://learn.microsoft.com/en-us/windows/win32/api/sspi/ns-sspi-secpkgcontext_streamsizes)
1921#[derive(Debug, Clone, Eq, PartialEq)]
1922pub struct StreamSizes {
1923    pub header: u32,
1924    pub trailer: u32,
1925    pub max_message: u32,
1926    pub buffers: u32,
1927    pub block_size: u32,
1928}
1929
1930/// Indicates the sizes of important structures used in the message support functions.
1931/// `query_context_sizes` function returns this structure.
1932///
1933/// # MSDN
1934///
1935/// * [SecPkgContext_Sizes structure](https://docs.microsoft.com/en-us/windows/win32/api/sspi/ns-sspi-secpkgcontext_sizes)
1936#[derive(Debug, Clone, Eq, PartialEq)]
1937pub struct ContextSizes {
1938    pub max_token: u32,
1939    pub max_signature: u32,
1940    pub block: u32,
1941    pub security_trailer: u32,
1942}
1943
1944/// Contains trust information about a certificate in a certificate chain,
1945/// summary trust information about a simple chain of certificates, or summary information about an array of simple chains.
1946/// `query_context_cert_trust_status` function returns this structure.
1947///
1948/// # MSDN
1949///
1950/// * [CERT_TRUST_STATUS structure](https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/ns-wincrypt-cert_trust_status)
1951#[derive(Debug, Clone)]
1952pub struct CertTrustStatus {
1953    pub error_status: CertTrustErrorStatus,
1954    pub info_status: CertTrustInfoStatus,
1955}
1956
1957bitflags! {
1958    /// Flags representing the error status codes used in `CertTrustStatus`.
1959    ///
1960    /// # MSDN
1961    ///
1962    /// * [CERT_TRUST_STATUS structure](https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/ns-wincrypt-cert_trust_status)
1963    #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
1964    pub struct CertTrustErrorStatus: u32 {
1965        /// No error found for this certificate or chain.
1966        const NO_ERROR = 0x0;
1967        /// This certificate or one of the certificates in the certificate chain is not time valid.
1968        const IS_NOT_TIME_VALID = 0x1;
1969        const IS_NOT_TIME_NESTED = 0x2;
1970        /// Trust for this certificate or one of the certificates in the certificate chain has been revoked.
1971        const IS_REVOKED = 0x4;
1972        /// The certificate or one of the certificates in the certificate chain does not have a valid signature.
1973        const IS_NOT_SIGNATURE_VALID = 0x8;
1974        /// The certificate or certificate chain is not valid for its proposed usage.
1975        const IS_NOT_VALID_FOR_USAGE = 0x10;
1976        /// The certificate or certificate chain is based on an untrusted root.
1977        const IS_UNTRUSTED_ROOT = 0x20;
1978        /// The revocation status of the certificate or one of the certificates in the certificate chain is unknown.
1979        const REVOCATION_STATUS_UNKNOWN = 0x40;
1980        /// One of the certificates in the chain was issued by a
1981        /// [`certification authority`](https://docs.microsoft.com/windows/desktop/SecGloss/c-gly)
1982        /// that the original certificate had certified.
1983        const IS_CYCLIC = 0x80;
1984        /// One of the certificates has an extension that is not valid.
1985        const INVALID_EXTENSION = 0x100;
1986        /// The certificate or one of the certificates in the certificate chain has a policy constraints extension,
1987        /// and one of the issued certificates has a disallowed policy mapping extension or does not have a
1988        /// required issuance policies extension.
1989        const INVALID_POLICY_CONSTRAINTS = 0x200;
1990        /// The certificate or one of the certificates in the certificate chain has a basic constraints extension,
1991        /// and either the certificate cannot be used to issue other certificates, or the chain path length has been exceeded.
1992        const INVALID_BASIC_CONSTRAINTS = 0x400;
1993        /// The certificate or one of the certificates in the certificate chain has a name constraints extension that is not valid.
1994        const INVALID_NAME_CONSTRAINTS = 0x800;
1995        /// The certificate or one of the certificates in the certificate chain has a name constraints extension that contains
1996        /// unsupported fields. The minimum and maximum fields are not supported.
1997        /// Thus minimum must always be zero and maximum must always be absent. Only UPN is supported for an Other Name.
1998        /// The following alternative name choices are not supported:
1999        /// * X400 Address
2000        /// * EDI Party Name
2001        /// * Registered Id
2002        const HAS_NOT_SUPPORTED_NAME_CONSTRAINT = 0x1000;
2003        /// The certificate or one of the certificates in the certificate chain has a name constraints extension and a name
2004        /// constraint is missing for one of the name choices in the end certificate.
2005        const HAS_NOT_DEFINED_NAME_CONSTRAINT = 0x2000;
2006        /// The certificate or one of the certificates in the certificate chain has a name constraints extension,
2007        /// and there is not a permitted name constraint for one of the name choices in the end certificate.
2008        const HAS_NOT_PERMITTED_NAME_CONSTRAINT = 0x4000;
2009        /// The certificate or one of the certificates in the certificate chain has a name constraints extension,
2010        /// and one of the name choices in the end certificate is explicitly excluded.
2011        const HAS_EXCLUDED_NAME_CONSTRAINT = 0x8000;
2012        /// The certificate chain is not complete.
2013        const IS_PARTIAL_CHAIN = 0x0001_0000;
2014        /// A [certificate trust list](https://docs.microsoft.com/windows/desktop/SecGloss/c-gly)
2015        /// (CTL) used to create this chain was not time valid.
2016        const CTL_IS_NOT_TIME_VALID = 0x0002_0000;
2017        /// A CTL used to create this chain did not have a valid signature.
2018        const CTL_IS_NOT_SIGNATURE_VALID = 0x0004_0000;
2019        /// A CTL used to create this chain is not valid for this usage.
2020        const CTL_IS_NOT_VALID_FOR_USAGE = 0x0008_0000;
2021        /// The revocation status of the certificate or one of the certificates in the certificate chain is either offline or stale.
2022        const IS_OFFLINE_REVOCATION = 0x100_0000;
2023        /// The end certificate does not have any resultant issuance policies, and one of the issuing
2024        /// [certification authority](https://docs.microsoft.com/windows/desktop/SecGloss/c-gly)
2025        /// certificates has a policy constraints extension requiring it.
2026        const NO_ISSUANCE_CHAIN_POLICY = 0x200_0000;
2027    }
2028}
2029
2030bitflags! {
2031    /// Flags representing the info status codes used in `CertTrustStatus`.
2032    ///
2033    /// # MSDN
2034    ///
2035    /// * [CERT_TRUST_STATUS structure](https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/ns-wincrypt-cert_trust_status)
2036    #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
2037    pub struct CertTrustInfoStatus: u32 {
2038        /// An exact match issuer certificate has been found for this certificate. This status code applies to certificates only.
2039        const HAS_EXACT_MATCH_ISSUER = 0x1;
2040        /// A key match issuer certificate has been found for this certificate. This status code applies to certificates only.
2041        const HAS_KEY_MATCH_ISSUER = 0x2;
2042        /// A name match issuer certificate has been found for this certificate. This status code applies to certificates only.
2043        const HAS_NAME_MATCH_ISSUER = 0x4;
2044        /// This certificate is self-signed. This status code applies to certificates only.
2045        const IS_SELF_SIGNED = 0x8;
2046        const AUTO_UPDATE_CA_REVOCATION = 0x10;
2047        const AUTO_UPDATE_END_REVOCATION = 0x20;
2048        const NO_OCSP_FAILOVER_TO_CRL = 0x40;
2049        const IS_KEY_ROLLOVER = 0x80;
2050        /// The certificate or chain has a preferred issuer. This status code applies to certificates and chains.
2051        const HAS_PREFERRED_ISSUER = 0x100;
2052        /// An issuance chain policy exists. This status code applies to certificates and chains.
2053        const HAS_ISSUANCE_CHAIN_POLICY = 0x200;
2054        /// A valid name constraints for all namespaces, including UPN. This status code applies to certificates and chains.
2055        const HAS_VALID_NAME_CONSTRAINTS = 0x400;
2056        /// This certificate is peer trusted. This status code applies to certificates only.
2057        const IS_PEER_TRUSTED = 0x800;
2058        /// This certificate's [certificate revocation list](https://docs.microsoft.com/windows/desktop/SecGloss/c-gly)
2059        /// (CRL) validity has been extended. This status code applies to certificates only.
2060        const HAS_CRL_VALIDITY_EXTENDED = 0x1000;
2061        const IS_FROM_EXCLUSIVE_TRUST_STORE = 0x2000;
2062        const IS_CA_TRUSTED = 0x4000;
2063        const HAS_AUTO_UPDATE_WEAK_SIGNATURE = 0x8000;
2064        const SSL_HANDSHAKE_OCSP = 0x0004_0000;
2065        const SSL_TIME_VALID_OCSP = 0x0008_0000;
2066        const SSL_RECONNECT_OCSP = 0x0010_0000;
2067        const IS_COMPLEX_CHAIN = 0x0001_0000;
2068        const HAS_ALLOW_WEAK_SIGNATURE = 0x0002_0000;
2069        const SSL_TIME_VALID = 0x100_0000;
2070        const NO_TIME_CHECK = 0x200_0000;
2071    }
2072}
2073
2074/// Indicates the name of the user associated with a security context.
2075/// `query_context_names` function returns this structure.
2076///
2077/// # MSDN
2078///
2079/// * [SecPkgContext_NamesW structure](https://docs.microsoft.com/en-us/windows/win32/api/sspi/ns-sspi-secpkgcontext_namesw)
2080#[derive(Debug, Clone)]
2081pub struct ContextNames {
2082    pub username: Username,
2083}
2084
2085/// Contains information about the session key used for the security context.
2086/// `query_context_session_key` function returns this structure.
2087///
2088/// # MSDN
2089///
2090/// * [SecPkgContext_SessionKey structure](https://learn.microsoft.com/en-us/windows/win32/api/sspi/ns-sspi-secpkgcontext_sessionkey)
2091#[derive(Debug, Clone)]
2092pub struct SessionKeys {
2093    pub session_key: Secret<Vec<u8>>,
2094}
2095
2096/// The kind of an SSPI related error. Enables to specify an error based on its type.
2097///
2098/// [SSPI Status Codes](https://learn.microsoft.com/en-us/windows/win32/secauthn/sspi-status-codes).
2099#[repr(u32)]
2100#[derive(Debug, Copy, Clone, Eq, PartialEq, FromPrimitive, ToPrimitive)]
2101pub enum ErrorKind {
2102    Unknown = 0,
2103    InsufficientMemory = 0x8009_0300,
2104    InvalidHandle = 0x8009_0301,
2105    UnsupportedFunction = 0x8009_0302,
2106    TargetUnknown = 0x8009_0303,
2107    /// May correspond to any internal error (I/O error, server error, etc.).
2108    InternalError = 0x8009_0304,
2109    SecurityPackageNotFound = 0x8009_0305,
2110    NotOwned = 0x8009_0306,
2111    CannotInstall = 0x8009_0307,
2112    /// Used in cases when supplied data is missing or invalid.
2113    InvalidToken = 0x8009_0308,
2114    CannotPack = 0x8009_0309,
2115    OperationNotSupported = 0x8009_030A,
2116    NoImpersonation = 0x8009_030B,
2117    LogonDenied = 0x8009_030C,
2118    UnknownCredentials = 0x8009_030D,
2119    NoCredentials = 0x8009_030E,
2120    /// Used in contexts of supplying invalid credentials.
2121    MessageAltered = 0x8009_030F,
2122    /// Used when a required NTLM state does not correspond to the current.
2123    OutOfSequence = 0x8009_0310,
2124    NoAuthenticatingAuthority = 0x8009_0311,
2125    BadPackageId = 0x8009_0316,
2126    ContextExpired = 0x8009_0317,
2127    IncompleteMessage = 0x8009_0318,
2128    IncompleteCredentials = 0x8009_0320,
2129    BufferTooSmall = 0x8009_0321,
2130    WrongPrincipalName = 0x8009_0322,
2131    TimeSkew = 0x8009_0324,
2132    UntrustedRoot = 0x8009_0325,
2133    IllegalMessage = 0x8009_0326,
2134    CertificateUnknown = 0x8009_0327,
2135    CertificateExpired = 0x8009_0328,
2136    EncryptFailure = 0x8009_0329,
2137    DecryptFailure = 0x8009_0330,
2138    AlgorithmMismatch = 0x8009_0331,
2139    SecurityQosFailed = 0x8009_0332,
2140    UnfinishedContextDeleted = 0x8009_0333,
2141    NoTgtReply = 0x8009_0334,
2142    NoIpAddress = 0x8009_0335,
2143    WrongCredentialHandle = 0x8009_0336,
2144    CryptoSystemInvalid = 0x8009_0337,
2145    MaxReferralsExceeded = 0x8009_0338,
2146    MustBeKdc = 0x8009_0339,
2147    StrongCryptoNotSupported = 0x8009_033A,
2148    TooManyPrincipals = 0x8009_033B,
2149    NoPaData = 0x8009_033C,
2150    PkInitNameMismatch = 0x8009_033D,
2151    SmartCardLogonRequired = 0x8009_033E,
2152    ShutdownInProgress = 0x8009_033F,
2153    KdcInvalidRequest = 0x8009_0340,
2154    KdcUnknownEType = 0x8009_0341,
2155    KdcUnknownEType2 = 0x8009_0342,
2156    UnsupportedPreAuth = 0x8009_0343,
2157    DelegationRequired = 0x8009_0345,
2158    BadBindings = 0x8009_0346,
2159    MultipleAccounts = 0x8009_0347,
2160    NoKerbKey = 0x8009_0348,
2161    CertWrongUsage = 0x8009_0349,
2162    DowngradeDetected = 0x8009_0350,
2163    SmartCardCertificateRevoked = 0x8009_0351,
2164    IssuingCAUntrusted = 0x8009_0352,
2165    RevocationOffline = 0x8009_0353,
2166    PkInitClientFailure = 0x8009_0354,
2167    SmartCardCertExpired = 0x8009_0355,
2168    NoS4uProtSupport = 0x8009_0356,
2169    CrossRealmDelegationFailure = 0x8009_0357,
2170    RevocationOfflineKdc = 0x8009_0358,
2171    IssuingCaUntrustedKdc = 0x8009_0359,
2172    KdcCertExpired = 0x8009_035A,
2173    KdcCertRevoked = 0x8009_035B,
2174    InvalidParameter = 0x8009_035D,
2175    DelegationPolicy = 0x8009_035E,
2176    PolicyNtlmOnly = 0x8009_035F,
2177    NoContext = 0x8009_0361,
2178    Pku2uCertFailure = 0x8009_0362,
2179    MutualAuthFailed = 0x8009_0363,
2180    OnlyHttpsAllowed = 0x8009_0365,
2181    ApplicationProtocolMismatch = 0x8009_0367,
2182}
2183
2184/// Holds the `ErrorKind` and the description of the SSPI-related error.
2185#[derive(Debug, Clone)]
2186pub struct Error {
2187    pub error_type: ErrorKind,
2188    pub description: String,
2189    pub nstatus: Option<credssp::NStatusCode>,
2190}
2191
2192/// The success status of SSPI-related operation.
2193#[derive(Debug, Copy, Clone, Eq, PartialEq, FromPrimitive, ToPrimitive)]
2194pub enum SecurityStatus {
2195    Ok = 0,
2196    ContinueNeeded = 0x0009_0312,
2197    CompleteNeeded = 0x0009_0313,
2198    CompleteAndContinue = 0x0009_0314,
2199    LocalLogon = 0x0009_0315,
2200    ContextExpired = 0x0009_0317,
2201    IncompleteCredentials = 0x0009_0320,
2202    Renegotiate = 0x0009_0321,
2203    NoLsaContext = 0x0009_0323,
2204}
2205
2206impl Error {
2207    /// Allows to fill a new error easily, supplying it with a coherent description.
2208    pub fn new(error_type: ErrorKind, description: impl ToString) -> Self {
2209        Self {
2210            error_type,
2211            description: description.to_string(),
2212            nstatus: None,
2213        }
2214    }
2215
2216    pub fn new_with_nstatus(
2217        error_type: ErrorKind,
2218        description: impl Into<String>,
2219        status_code: credssp::NStatusCode,
2220    ) -> Self {
2221        Self {
2222            error_type,
2223            description: description.into(),
2224            nstatus: Some(status_code),
2225        }
2226    }
2227}
2228
2229impl error::Error for Error {}
2230
2231impl fmt::Display for Error {
2232    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2233        write!(f, "{:?}: {}", self.error_type, self.description)?;
2234
2235        if let Some(nstatus) = self.nstatus {
2236            write!(f, "; status is {nstatus}")?;
2237        }
2238
2239        Ok(())
2240    }
2241}
2242
2243impl From<auth_identity::UsernameError> for Error {
2244    fn from(value: auth_identity::UsernameError) -> Self {
2245        Error::new(ErrorKind::UnknownCredentials, value)
2246    }
2247}
2248
2249impl From<rsa::Error> for Error {
2250    fn from(value: rsa::Error) -> Self {
2251        Error::new(
2252            ErrorKind::InternalError,
2253            format!("an unexpected RsaError happened: {value}"),
2254        )
2255    }
2256}
2257
2258impl From<Asn1DerError> for Error {
2259    fn from(err: Asn1DerError) -> Self {
2260        Self::new(ErrorKind::InvalidToken, format!("ASN1 DER error: {err:?}"))
2261    }
2262}
2263
2264impl From<KrbError> for Error {
2265    fn from(krb_error: KrbError) -> Self {
2266        let (error_kind, mut description) = map_keb_error_code_to_sspi_error(krb_error.0.error_code.0);
2267
2268        // https://www.rfc-editor.org/rfc/rfc4120#section-5.9.1
2269
2270        // This field contains additional text to help explain the error code
2271        // associated with the failed request
2272        if let Some(e_text) = krb_error.0.e_text.0 {
2273            description.push_str(&format!(". Additional error text: {:?}", e_text.0));
2274        }
2275
2276        // This field contains additional data about the error for use by the
2277        // application to help it recover from or handle the error.
2278        if let Some(e_data) = krb_error.0.e_data.0 {
2279            description.push_str(&format!(". Additional error data: {:?}", e_data.0));
2280        }
2281
2282        Error::new(error_kind, description)
2283    }
2284}
2285
2286impl From<picky_krb::crypto::KerberosCryptoError> for Error {
2287    fn from(err: picky_krb::crypto::KerberosCryptoError) -> Self {
2288        use picky_krb::crypto::KerberosCryptoError;
2289
2290        match err {
2291            KerberosCryptoError::KeyLength(actual, expected) => Self::new(
2292                ErrorKind::InvalidParameter,
2293                format!("invalid key length. actual: {actual}. expected: {expected}"),
2294            ),
2295            KerberosCryptoError::CipherLength(actual, expected) => Self::new(
2296                ErrorKind::InvalidParameter,
2297                format!("invalid cipher length. actual: {actual}. expected: {expected}"),
2298            ),
2299            KerberosCryptoError::AlgorithmIdentifier(identifier) => Self::new(
2300                ErrorKind::InvalidParameter,
2301                format!("unknown algorithm identifier: {identifier}"),
2302            ),
2303            KerberosCryptoError::IntegrityCheck => Self::new(ErrorKind::MessageAltered, err.to_string()),
2304            KerberosCryptoError::CipherError(description) => Self::new(ErrorKind::InvalidParameter, description),
2305            KerberosCryptoError::CipherPad(description) => {
2306                Self::new(ErrorKind::InvalidParameter, description.to_string())
2307            }
2308            KerberosCryptoError::CipherUnpad(description) => {
2309                Self::new(ErrorKind::InvalidParameter, description.to_string())
2310            }
2311            KerberosCryptoError::SeedBitLen(description) => Self::new(ErrorKind::InvalidParameter, description),
2312            KerberosCryptoError::AlgorithmIdentifierData(identifier) => Self::new(
2313                ErrorKind::InvalidParameter,
2314                format!("unknown algorithm identifier: {identifier:?}"),
2315            ),
2316            KerberosCryptoError::RandError(rand) => {
2317                Self::new(ErrorKind::InvalidParameter, format!("random error: {rand:?}"))
2318            }
2319            KerberosCryptoError::TooSmallBuffer(inout) => {
2320                Self::new(ErrorKind::InvalidParameter, format!("too small buffer: {inout:?}"))
2321            }
2322            KerberosCryptoError::ArrayTryFromSliceError(array) => Self::new(
2323                ErrorKind::InvalidParameter,
2324                format!("array try from slice error: {array:?}"),
2325            ),
2326        }
2327    }
2328}
2329
2330impl From<picky_krb::crypto::diffie_hellman::DiffieHellmanError> for Error {
2331    fn from(error: picky_krb::crypto::diffie_hellman::DiffieHellmanError) -> Self {
2332        use picky_krb::crypto::diffie_hellman::DiffieHellmanError;
2333
2334        match error {
2335            DiffieHellmanError::BitLen(description) => Self::new(ErrorKind::InternalError, description),
2336            error => Self::new(ErrorKind::InternalError, error.to_string()),
2337        }
2338    }
2339}
2340
2341impl From<CharSetError> for Error {
2342    fn from(err: CharSetError) -> Self {
2343        Self::new(ErrorKind::InternalError, err.to_string())
2344    }
2345}
2346
2347impl From<GssApiMessageError> for Error {
2348    fn from(err: GssApiMessageError) -> Self {
2349        match err {
2350            GssApiMessageError::IoError(err) => Self::from(err),
2351            GssApiMessageError::InvalidId(_, _) => Self::new(ErrorKind::InvalidToken, err.to_string()),
2352            GssApiMessageError::InvalidMicFiller(_) => Self::new(ErrorKind::InvalidToken, err.to_string()),
2353            GssApiMessageError::InvalidWrapFiller(_) => Self::new(ErrorKind::InvalidToken, err.to_string()),
2354            GssApiMessageError::Asn1Error(_) => Self::new(ErrorKind::InvalidToken, err.to_string()),
2355        }
2356    }
2357}
2358
2359impl From<io::Error> for Error {
2360    fn from(err: io::Error) -> Self {
2361        Self::new(ErrorKind::InternalError, format!("IO error: {err:?}"))
2362    }
2363}
2364
2365impl From<getrandom::Error> for Error {
2366    fn from(err: getrandom::Error) -> Self {
2367        Self::new(ErrorKind::InternalError, format!("rand error: {err:?}"))
2368    }
2369}
2370
2371impl From<rand::rngs::SysError> for Error {
2372    fn from(err: rand::rngs::SysError) -> Self {
2373        Self::new(ErrorKind::InternalError, format!("rand error: {:?}", err))
2374    }
2375}
2376
2377impl From<str::Utf8Error> for Error {
2378    fn from(err: str::Utf8Error) -> Self {
2379        Self::new(ErrorKind::InternalError, err)
2380    }
2381}
2382
2383impl From<string::FromUtf8Error> for Error {
2384    fn from(err: string::FromUtf8Error) -> Self {
2385        Self::new(ErrorKind::InternalError, format!("UTF-8 error: {err:?}"))
2386    }
2387}
2388
2389impl From<string::FromUtf16Error> for Error {
2390    fn from(err: string::FromUtf16Error) -> Self {
2391        Self::new(ErrorKind::InternalError, format!("UTF-16 error: {err:?}"))
2392    }
2393}
2394
2395impl From<Error> for io::Error {
2396    fn from(err: Error) -> io::Error {
2397        io::Error::other(format!("{:?}: {}", err.error_type, err.description))
2398    }
2399}
2400
2401impl From<std::num::TryFromIntError> for Error {
2402    fn from(_: std::num::TryFromIntError) -> Self {
2403        Self::new(ErrorKind::InternalError, "integer conversion error")
2404    }
2405}
2406
2407impl<T> From<std::sync::PoisonError<T>> for Error {
2408    fn from(_: std::sync::PoisonError<T>) -> Self {
2409        Self::new(ErrorKind::InternalError, "can not lock SspiHandle mutex")
2410    }
2411}
2412
2413impl From<picky::key::KeyError> for Error {
2414    fn from(err: picky::key::KeyError) -> Self {
2415        Self::new(ErrorKind::InternalError, format!("RSA key error: {err:?}"))
2416    }
2417}
2418
2419#[cfg(feature = "scard")]
2420impl From<winscard::Error> for Error {
2421    fn from(value: winscard::Error) -> Self {
2422        Self::new(
2423            ErrorKind::InternalError,
2424            format!("Error while using a smart card: {value}"),
2425        )
2426    }
2427}
2428
2429#[cfg(all(feature = "scard", not(target_arch = "wasm32")))]
2430impl From<cryptoki::error::Error> for Error {
2431    fn from(value: cryptoki::error::Error) -> Self {
2432        Self::new(
2433            ErrorKind::NoCredentials,
2434            format!("Error while using a smart card: {value}"),
2435        )
2436    }
2437}