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