use crate::ast::*;
use crate::builders::WireContext;
use alloc::vec::Vec;
fn push_der_length(out: &mut Vec<u8>, len: usize) {
if len < 128 {
out.push(len as u8);
} else if len <= 0xFF {
out.push(0x81);
out.push(len as u8);
} else if len <= 0xFFFF {
out.push(0x82);
out.extend_from_slice(&(len as u16).to_be_bytes());
} else {
out.push(0x83);
out.push((len >> 16) as u8);
out.extend_from_slice(&(len as u16).to_be_bytes());
}
}
fn encode_der_tlv(tag: u8, content: &[u8]) -> Vec<u8> {
let mut out = Vec::with_capacity(2 + content.len());
out.push(tag);
push_der_length(&mut out, content.len());
out.extend_from_slice(content);
out
}
fn encode_der_int(val: i64) -> Vec<u8> {
let bytes = val.to_be_bytes();
let mut start = 0;
while start < 7 {
if (bytes[start] == 0x00 && (bytes[start + 1] & 0x80) == 0)
|| (bytes[start] == 0xFF && (bytes[start + 1] & 0x80) != 0)
{
start += 1;
} else {
break;
}
}
encode_der_tlv(0x02, &bytes[start..])
}
fn encode_explicit_ctx(ctx_num: u8, inner: &[u8]) -> Vec<u8> {
encode_der_tlv(0xA0 | (ctx_num & 0x1F), inner)
}
fn encode_general_string(s: &str) -> Vec<u8> {
encode_der_tlv(0x1B, s.as_bytes())
}
fn encode_principal_name(name_type: i64, principal: &str) -> Vec<u8> {
let mut seq_of_strings = Vec::new();
for part in principal.split('/') {
let part_str = if part.is_empty() { principal } else { part };
seq_of_strings.extend_from_slice(&encode_general_string(part_str));
}
let name_type_field = encode_explicit_ctx(0, &encode_der_int(name_type));
let name_string_seq = encode_der_tlv(0x30, &seq_of_strings);
let name_string_field = encode_explicit_ctx(1, &name_string_seq);
let mut body = Vec::with_capacity(name_type_field.len() + name_string_field.len());
body.extend_from_slice(&name_type_field);
body.extend_from_slice(&name_string_field);
encode_der_tlv(0x30, &body)
}
fn encode_encrypted_data(etype: i64, cipher: &[u8]) -> Vec<u8> {
let mut seq = Vec::new();
seq.extend_from_slice(&encode_explicit_ctx(0, &encode_der_int(etype)));
seq.extend_from_slice(&encode_explicit_ctx(2, &encode_der_tlv(0x04, cipher)));
encode_der_tlv(0x30, &seq)
}
fn encode_ticket(realm: &str, sname: &str, etype: i64) -> Vec<u8> {
let mut seq = Vec::new();
seq.extend_from_slice(&encode_explicit_ctx(0, &encode_der_int(5)));
seq.extend_from_slice(&encode_explicit_ctx(1, &encode_general_string(realm)));
seq.extend_from_slice(&encode_explicit_ctx(2, &encode_principal_name(2, sname)));
seq.extend_from_slice(&encode_explicit_ctx(
3,
&encode_encrypted_data(etype, &[0xde, 0xad, 0xbe, 0xef]),
));
let ticket_seq = encode_der_tlv(0x30, &seq);
encode_der_tlv(0x61, &ticket_seq) }
#[doc(alias = "KERBEROS")]
#[doc(alias = "RFC4120")]
#[doc(alias = "AS_REQ")]
#[doc(alias = "AS_REP")]
#[doc(alias = "TGS_REQ")]
#[doc(alias = "TGS_REP")]
#[doc(alias = "KRB_ERROR")]
pub fn build_kerberos_payload(
_ctx: &WireContext,
spec: &KerberosSpec,
payload_bytes: &[u8],
) -> Vec<u8> {
let msg_type: u8 = if spec.is_as_req {
10 } else if spec.is_as_rep {
11 } else if spec.is_tgs_req {
12 } else if spec.is_tgs_rep {
13 } else if spec.is_krb_error {
30 } else {
10 };
let realm = spec.realm.unwrap_or("CORP.LOCAL");
let cname = spec.cname.unwrap_or("user");
let sname = spec.sname.unwrap_or("krbtgt");
let etype = i64::from(spec.etype.unwrap_or(18));
let mut pkt = match msg_type {
11 | 13 => {
let mut kdc_rep = Vec::new();
kdc_rep.extend_from_slice(&encode_explicit_ctx(0, &encode_der_int(5))); kdc_rep.extend_from_slice(&encode_explicit_ctx(
1,
&encode_der_int(i64::from(msg_type)),
)); kdc_rep.extend_from_slice(&encode_explicit_ctx(3, &encode_general_string(realm))); kdc_rep.extend_from_slice(&encode_explicit_ctx(4, &encode_principal_name(1, cname))); kdc_rep.extend_from_slice(&encode_explicit_ctx(5, &encode_ticket(realm, sname, etype))); kdc_rep.extend_from_slice(&encode_explicit_ctx(
6,
&encode_encrypted_data(etype, &[0xca, 0xfe, 0xba, 0xbe]),
)); let seq = encode_der_tlv(0x30, &kdc_rep);
encode_der_tlv(0x60 | msg_type, &seq)
}
30 => {
let mut err_seq = Vec::new();
err_seq.extend_from_slice(&encode_explicit_ctx(0, &encode_der_int(5))); err_seq.extend_from_slice(&encode_explicit_ctx(1, &encode_der_int(30))); err_seq.extend_from_slice(&encode_explicit_ctx(
4,
&encode_der_tlv(0x18, b"20261023000000Z"),
)); err_seq.extend_from_slice(&encode_explicit_ctx(5, &encode_der_int(0))); err_seq.extend_from_slice(&encode_explicit_ctx(6, &encode_der_int(24))); err_seq.extend_from_slice(&encode_explicit_ctx(7, &encode_general_string(realm))); err_seq.extend_from_slice(&encode_explicit_ctx(8, &encode_principal_name(1, cname))); err_seq.extend_from_slice(&encode_explicit_ctx(9, &encode_general_string(realm))); err_seq.extend_from_slice(&encode_explicit_ctx(10, &encode_principal_name(2, sname))); let seq = encode_der_tlv(0x30, &err_seq);
encode_der_tlv(0x7E, &seq)
}
_ => {
let mut req_body = Vec::new();
req_body.extend_from_slice(&encode_explicit_ctx(
0,
&encode_der_tlv(0x03, &[0x00, 0x40, 0x81, 0x00, 0x10]),
));
req_body.extend_from_slice(&encode_explicit_ctx(1, &encode_principal_name(1, cname)));
req_body.extend_from_slice(&encode_explicit_ctx(2, &encode_general_string(realm)));
req_body.extend_from_slice(&encode_explicit_ctx(3, &encode_principal_name(2, sname)));
req_body.extend_from_slice(&encode_explicit_ctx(
7,
&encode_der_tlv(0x18, b"20370913024805Z"),
));
req_body.extend_from_slice(&encode_explicit_ctx(8, &encode_der_int(0x1234_5678)));
let etype_seq = encode_der_tlv(0x30, &encode_der_int(etype));
req_body.extend_from_slice(&encode_explicit_ctx(9, &etype_seq));
let req_body_seq = encode_der_tlv(0x30, &req_body);
let mut kdc_req = Vec::new();
kdc_req.extend_from_slice(&encode_explicit_ctx(1, &encode_der_int(5))); kdc_req.extend_from_slice(&encode_explicit_ctx(
2,
&encode_der_int(i64::from(msg_type)),
)); kdc_req.extend_from_slice(&encode_explicit_ctx(4, &req_body_seq));
let seq = encode_der_tlv(0x30, &kdc_req);
encode_der_tlv(0x60 | msg_type, &seq)
}
};
if !payload_bytes.is_empty() {
pkt.extend_from_slice(payload_bytes);
}
pkt
}