Skip to content

Commit 12fbd70

Browse files
TheBestTvarynkaCBenoit
authored andcommitted
fix(sspi): Kerberos server MIC token generation and validation (#464)
1 parent 27ce28d commit 12fbd70

File tree

4 files changed

+63
-9
lines changed

4 files changed

+63
-9
lines changed

src/kerberos/client/mod.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ use self::extractors::{
2727
use self::generators::{
2828
generate_ap_rep, generate_ap_req, generate_as_req_kdc_body, generate_authenticator, generate_neg_ap_req,
2929
generate_neg_token_init, generate_tgs_req, get_client_principal_name_type, get_client_principal_realm,
30-
ChecksumOptions, ChecksumValues, EncKey, GenerateAsPaDataOptions, GenerateAsReqOptions,
30+
get_mech_list, ChecksumOptions, ChecksumValues, EncKey, GenerateAsPaDataOptions, GenerateAsReqOptions,
3131
GenerateAuthenticatorOptions, GenerateTgsReqOptions, GssFlags,
3232
};
3333
use crate::channel_bindings::ChannelBindings;
@@ -42,6 +42,9 @@ use crate::{
4242
InitializeSecurityContextResult, Kerberos, KerberosState, Result, SecurityBuffer, SecurityStatus, SspiImpl,
4343
};
4444

45+
/// Indicated that the MIC token `SentByAcceptor` flag must be enabled in the incoming MIC token.
46+
const SENT_BY_ACCEPTOR: u8 = 1;
47+
4548
/// Performs one authentication step.
4649
///
4750
/// The user should call this function until it returns `SecurityStatus::Ok`.
@@ -401,7 +404,12 @@ pub async fn initialize_security_context<'a>(
401404
client.encryption_params.sub_session_key = Some(sub_session_key);
402405

403406
if let Some(ref token) = neg_token_targ.0.mech_list_mic.0 {
404-
validate_mic_token(&token.0 .0, ACCEPTOR_SIGN, &client.encryption_params)?;
407+
validate_mic_token::<SENT_BY_ACCEPTOR>(
408+
&token.0 .0,
409+
ACCEPTOR_SIGN,
410+
&client.encryption_params,
411+
&get_mech_list(),
412+
)?;
405413
}
406414

407415
client.next_seq_number();

src/kerberos/server/generators.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ pub fn generate_final_neg_token_targ(mech_id: ObjectIdentifier, ap_rep: ApRep, m
9191
}
9292

9393
pub fn generate_mic_token(seq_number: u64, mut payload: Vec<u8>, session_key: &[u8]) -> Result<Vec<u8>> {
94-
let mut mic_token = MicToken::with_initiator_flags().with_seq_number(seq_number);
94+
let mut mic_token = MicToken::with_acceptor_flags().with_seq_number(seq_number);
9595

9696
payload.extend_from_slice(&mic_token.header());
9797

src/kerberos/server/mod.rs

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ use crate::{
3636
SecurityBuffer, SecurityStatus, ServerRequestFlags, ServerResponseFlags, SspiImpl, Username,
3737
};
3838

39+
/// Indicated that the MIC token `SentByAcceptor` flag must not be enabled in the incoming MIC token.
40+
const SENT_BY_INITIATOR: u8 = 0;
41+
3942
/// Additional properties that are needed only for server-side Kerberos.
4043
#[derive(Debug, Clone)]
4144
pub struct ServerProperties {
@@ -350,7 +353,7 @@ pub async fn accept_security_context(
350353
.mech_types,
351354
)?;
352355
let mic = generate_mic_token(
353-
u64::from(server.seq_number + 1),
356+
u64::from(server.next_seq_number()),
354357
mic_payload,
355358
server
356359
.encryption_params
@@ -377,8 +380,20 @@ pub async fn accept_security_context(
377380
SecurityStatus::ContinueNeeded
378381
}
379382
KerberosState::ApExchange => {
383+
let server_props = server.server.as_mut().ok_or_else(|| {
384+
Error::new(
385+
ErrorKind::InvalidHandle,
386+
"Kerberos server properties are not initialized",
387+
)
388+
})?;
389+
380390
let client_mic = extract_client_mic_token(&input_token.buffer)?;
381-
validate_mic_token(&client_mic, INITIATOR_SIGN, &server.encryption_params)?;
391+
validate_mic_token::<SENT_BY_INITIATOR>(
392+
&client_mic,
393+
INITIATOR_SIGN,
394+
&server.encryption_params,
395+
&server_props.mech_types,
396+
)?;
382397

383398
server.state = KerberosState::PubKeyAuth;
384399

src/kerberos/utils.rs

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,9 @@ use std::io::Write;
22

33
use picky_krb::constants::key_usages::INITIATOR_SIGN;
44
use picky_krb::crypto::aes::{checksum_sha_aes, AesSize};
5-
use picky_krb::gss_api::MicToken;
5+
use picky_krb::gss_api::{MechTypeList, MicToken};
66
use serde::Serialize;
77

8-
use crate::kerberos::client::generators::get_mech_list;
98
use crate::kerberos::encryption_params::EncryptionParams;
109
use crate::{Error, ErrorKind, Result};
1110

@@ -22,10 +21,42 @@ pub fn serialize_message<T: ?Sized + Serialize>(v: &T) -> Result<Vec<u8>> {
2221
Ok(data)
2322
}
2423

25-
pub fn validate_mic_token(raw_token: &[u8], key_usage: i32, params: &EncryptionParams) -> Result<()> {
24+
pub fn validate_mic_token<const IS_SENT_BY_ACCEPTOR: u8>(
25+
raw_token: &[u8],
26+
key_usage: i32,
27+
params: &EncryptionParams,
28+
mech_types: &MechTypeList,
29+
) -> Result<()> {
2630
let token = MicToken::decode(raw_token)?;
31+
let token_flags = token.flags;
32+
33+
// [Flags Field](https://datatracker.ietf.org/doc/html/rfc4121#section-4.2.2):
34+
//
35+
// The meanings of bits in this field (the least significant bit is bit
36+
// 0) are as follows:
37+
// Bit Name Description
38+
// --------------------------------------------------------------
39+
// 0 SentByAcceptor When set, this flag indicates the sender
40+
// is the context acceptor. When not set,
41+
// it indicates the sender is the context
42+
// initiator.
43+
if token_flags & 0b01 != IS_SENT_BY_ACCEPTOR {
44+
return Err(Error::new(
45+
ErrorKind::InvalidToken,
46+
"invalid MIC token SentByAcceptor flag",
47+
));
48+
}
49+
// 1 Sealed When set in Wrap tokens, this flag
50+
// indicates confidentiality is provided
51+
// for. It SHALL NOT be set in MIC tokens.
52+
if token_flags & 0b10 == 0b10 {
53+
return Err(Error::new(
54+
ErrorKind::InvalidToken,
55+
"the Sealed flag has not to be set in the MIC token",
56+
));
57+
}
2758

28-
let mut payload = picky_asn1_der::to_vec(&get_mech_list())?;
59+
let mut payload = picky_asn1_der::to_vec(mech_types)?;
2960
payload.extend_from_slice(&token.header());
3061

3162
// The sub-session key is always preferred over the session key.

0 commit comments

Comments
 (0)