fn der_len(n: usize) -> Vec<u8> {
if n < 0x80 {
vec![n as u8]
} else {
let mut b = Vec::new();
let mut v = n;
while v > 0 {
b.insert(0, (v & 0xff) as u8);
v >>= 8;
}
let mut out = vec![0x80 | b.len() as u8];
out.extend_from_slice(&b);
out
}
}
fn tlv(tag: u8, content: &[u8]) -> Vec<u8> {
let mut out = vec![tag];
out.extend_from_slice(&der_len(content.len()));
out.extend_from_slice(content);
out
}
const SPNEGO_OID: &[u8] = &[0x2b, 0x06, 0x01, 0x05, 0x05, 0x02];
const KRB5_OID: &[u8] = &[0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12, 0x01, 0x02, 0x02];
pub fn gss_krb5_aprep(ap_req_der: &[u8]) -> Vec<u8> {
let mut inner = Vec::new();
inner.extend_from_slice(&tlv(0x06, KRB5_OID)); inner.extend_from_slice(&[0x01, 0x00]); inner.extend_from_slice(ap_req_der);
tlv(0x60, &inner) }
pub fn spnego_krb5_init(ap_req_der: &[u8]) -> Vec<u8> {
let mech_token = gss_krb5_aprep(ap_req_der);
let mech_types = tlv(0x30, &tlv(0x06, KRB5_OID));
let mut neg_init = Vec::new();
neg_init.extend_from_slice(&tlv(0xa0, &mech_types)); neg_init.extend_from_slice(&tlv(0xa2, &tlv(0x04, &mech_token)));
let neg_token = tlv(0xa0, &tlv(0x30, &neg_init));
let mut inner = Vec::new();
inner.extend_from_slice(&tlv(0x06, SPNEGO_OID));
inner.extend_from_slice(&neg_token);
tlv(0x60, &inner)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn der_len_forms() {
assert_eq!(der_len(5), vec![5]);
assert_eq!(der_len(200), vec![0x81, 200]);
assert_eq!(der_len(300), vec![0x82, 0x01, 0x2c]);
}
#[test]
fn spnego_wraps_krb5() {
let blob = spnego_krb5_init(&[0x6e, 0x02, 0x00, 0x00]); assert_eq!(blob[0], 0x60); assert!(blob.windows(SPNEGO_OID.len()).any(|w| w == SPNEGO_OID));
assert!(
blob.windows(KRB5_OID.len())
.filter(|w| *w == KRB5_OID)
.count()
>= 2
);
}
}