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}