use picky_krb::data_types::PaData;
use picky_krb::messages::AsRep;
use crate::kerberos::client::extractors::extract_session_key_from_as_rep;
use crate::kerberos::client::generators::{
GenerateAsPaDataOptions as AuthIdentityPaDataOptions, generate_pa_datas_for_as_req as generate_password_based,
};
use crate::kerberos::encryption_params::EncryptionParams;
#[cfg(feature = "scard")]
use crate::pk_init::{
GenerateAsPaDataOptions as SmartCardPaDataOptions, generate_pa_datas_for_as_req as generate_private_key_based,
};
use crate::{Result, Secret};
pub(crate) enum AsReqPaDataOptions<'a> {
AuthIdentity(AuthIdentityPaDataOptions<'a>),
#[cfg(feature = "scard")]
SmartCard(Box<SmartCardPaDataOptions<'a>>),
}
impl AsReqPaDataOptions<'_> {
pub(crate) fn generate(&mut self) -> Result<Vec<PaData>> {
match self {
AsReqPaDataOptions::AuthIdentity(options) => generate_password_based(options),
#[cfg(feature = "scard")]
AsReqPaDataOptions::SmartCard(options) => generate_private_key_based(options),
}
}
pub(crate) fn with_pre_auth(&mut self, pre_auth: bool) {
match self {
AsReqPaDataOptions::AuthIdentity(options) => options.with_pre_auth = pre_auth,
#[cfg(feature = "scard")]
AsReqPaDataOptions::SmartCard(options) => options.with_pre_auth = pre_auth,
}
}
pub(crate) fn with_salt(&mut self, salt: Vec<u8>) {
match self {
AsReqPaDataOptions::AuthIdentity(options) => options.salt = salt,
#[cfg(feature = "scard")]
AsReqPaDataOptions::SmartCard(_) => {}
}
}
}
#[derive(Debug)]
pub(super) enum AsRepSessionKeyExtractor<'a> {
AuthIdentity {
salt: &'a str,
password: &'a str,
enc_params: &'a EncryptionParams,
},
#[cfg(feature = "scard")]
SmartCard {
dh_parameters: &'a mut crate::pk_init::DhParameters,
enc_params: &'a mut EncryptionParams,
},
}
impl AsRepSessionKeyExtractor<'_> {
#[instrument(level = "trace", ret, skip(self))]
pub(super) fn session_key(&mut self, as_rep: &AsRep) -> Result<Secret<Vec<u8>>> {
match self {
AsRepSessionKeyExtractor::AuthIdentity {
salt,
password,
enc_params,
} => extract_session_key_from_as_rep(as_rep, salt, password, enc_params),
#[cfg(feature = "scard")]
AsRepSessionKeyExtractor::SmartCard {
dh_parameters,
enc_params,
} => {
use picky_asn1_x509::signed_data::SignedData;
use picky_krb::crypto::CipherSuite;
use picky_krb::crypto::diffie_hellman::{DhNonce, generate_key};
use picky_krb::pkinit::PaPkAsRep;
use crate::pk_init::{Wrapper, extract_server_dh_public_key};
use crate::pku2u::{
extract_pa_pk_as_rep, extract_server_nonce, validate_server_p2p_certificate, validate_signed_data,
};
use crate::{Error, ErrorKind, check_if_empty, pku2u};
let dh_rep_info = match extract_pa_pk_as_rep(as_rep)? {
PaPkAsRep::DhInfo(dh) => dh.0,
PaPkAsRep::EncKeyPack(_) => {
return Err(Error::new(
ErrorKind::OperationNotSupported,
"encKeyPack is not supported for the PA-PK-AS-REP",
));
}
};
let server_nonce = extract_server_nonce(&dh_rep_info)?;
dh_parameters.server_nonce = Some(server_nonce);
let wrapped_signed_data: Wrapper<SignedData> =
picky_asn1_der::from_bytes(&dh_rep_info.dh_signed_data.0)?;
let signed_data = wrapped_signed_data.content.0;
let rsa_public_key = validate_server_p2p_certificate(&signed_data)?;
validate_signed_data(&signed_data, &rsa_public_key)?;
let public_key = extract_server_dh_public_key(&signed_data)?;
dh_parameters.other_public_key = Some(public_key);
enc_params.encryption_type = Some(CipherSuite::try_from(as_rep.0.enc_part.0.etype.0.0.as_slice())?);
let key = generate_key(
check_if_empty!(dh_parameters.other_public_key.as_ref(), "dh public key is not set"),
&dh_parameters.private_key,
&dh_parameters.modulus,
Some(DhNonce {
client_nonce: check_if_empty!(dh_parameters.client_nonce.as_ref(), "dh client none is not set"),
server_nonce: check_if_empty!(
dh_parameters.server_nonce.as_ref(),
"dh server nonce is not set"
),
}),
check_if_empty!(enc_params.encryption_type.as_ref(), "encryption type is not set")
.cipher()
.as_ref(),
)?;
let session_key = pku2u::extract_session_key_from_as_rep(as_rep, &key, enc_params)?;
Ok(session_key)
}
}
}
}