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