sspi/
lib.rs

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