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