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