use der::{
asn1::{BitString, OctetStringRef},
AnyRef, Choice, Enumerated, Sequence,
};
use crate::MechType;
pub type MechTypeList = alloc::vec::Vec<MechType>;
#[derive(Clone, Debug, PartialEq, Eq, Choice)]
pub enum NegotiationToken<'a> {
#[cfg(feature = "rfc2478")]
#[asn1(context_specific = "0", constructed = "true", tag_mode = "EXPLICIT")]
NegTokenInit(NegTokenInit<'a>),
#[cfg(not(feature = "rfc2478"))]
#[asn1(context_specific = "0", constructed = "true", tag_mode = "EXPLICIT")]
NegTokenInit2(NegTokenInit2<'a>),
#[cfg(feature = "rfc2478")]
#[asn1(context_specific = "1", constructed = "true", tag_mode = "EXPLICIT")]
NegTokenTarg(NegTokenTarg<'a>),
#[cfg(not(feature = "rfc2478"))]
#[asn1(context_specific = "1", constructed = "true", tag_mode = "EXPLICIT")]
NegTokenResp(NegTokenResp<'a>),
}
#[cfg(feature = "rfc2478")]
#[derive(Clone, Debug, Eq, PartialEq, Sequence)]
pub struct NegTokenInit<'a> {
#[asn1(context_specific = "0", optional = "true", tag_mode = "IMPLICIT")]
pub mech_types: Option<MechTypeList>,
#[asn1(context_specific = "1", optional = "true", tag_mode = "IMPLICIT")]
pub req_flags: Option<ContextFlags>,
#[asn1(context_specific = "2", optional = "true", tag_mode = "IMPLICIT")]
pub mech_token: Option<OctetStringRef<'a>>,
#[asn1(context_specific = "3", optional = "true", tag_mode = "IMPLICIT")]
pub mech_list_mic: Option<OctetStringRef<'a>>,
}
pub type ContextFlags = BitString;
#[cfg(feature = "rfc2478")]
#[derive(Clone, Copy, Debug, Eq, PartialEq, Sequence)]
pub struct NegTokenTarg<'a> {
#[asn1(context_specific = "0", optional = "true", tag_mode = "EXPLICIT")]
pub neg_result: Option<NegResult>,
#[asn1(context_specific = "1", optional = "true", tag_mode = "EXPLICIT")]
pub supported_mech: Option<MechType>,
#[asn1(context_specific = "2", optional = "true", tag_mode = "EXPLICIT")]
pub response_token: Option<OctetStringRef<'a>>,
#[asn1(context_specific = "3", optional = "true", tag_mode = "EXPLICIT")]
pub mech_list_mic: Option<OctetStringRef<'a>>,
}
#[cfg(feature = "rfc2478")]
#[derive(Clone, Debug, Copy, PartialEq, Eq, PartialOrd, Ord, Enumerated)]
#[asn1(type = "ENUMERATED")]
#[repr(u8)]
#[allow(missing_docs)]
pub enum NegResult {
AcceptCompleted = 0,
AcceptIncomplete = 1,
Reject = 2,
}
#[derive(Clone, Debug, Eq, PartialEq, Sequence)]
pub struct NegTokenResp<'a> {
#[asn1(context_specific = "0", optional = "true", tag_mode = "EXPLICIT")]
pub neg_state: Option<NegState>,
#[asn1(context_specific = "1", optional = "true", tag_mode = "EXPLICIT")]
pub supported_mech: Option<MechType>,
#[asn1(context_specific = "2", optional = "true", tag_mode = "EXPLICIT")]
pub response_token: Option<OctetStringRef<'a>>,
#[asn1(context_specific = "3", optional = "true", tag_mode = "EXPLICIT")]
pub mech_list_mic: Option<OctetStringRef<'a>>,
}
#[derive(Clone, Debug, Copy, PartialEq, Eq, PartialOrd, Ord, Enumerated)]
#[asn1(type = "ENUMERATED")]
#[repr(u8)]
#[allow(missing_docs)]
pub enum NegState {
AcceptCompleted = 0,
AcceptIncomplete = 1,
Reject = 2,
RequestMic = 3,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq, Sequence)]
pub struct NegHints<'a> {
#[asn1(
context_specific = "0",
optional = "true",
tag_mode = "IMPLICIT",
constructed = "true"
)]
pub hint_name: Option<AnyRef<'a>>,
#[asn1(context_specific = "1", optional = "true", tag_mode = "IMPLICIT")]
pub hint_address: Option<OctetStringRef<'a>>,
}
#[derive(Clone, Debug, Eq, PartialEq, Sequence)]
pub struct NegTokenInit2<'a> {
#[asn1(context_specific = "0", optional = "true", tag_mode = "EXPLICIT")]
pub mech_types: Option<MechTypeList>,
#[asn1(context_specific = "1", optional = "true", tag_mode = "EXPLICIT")]
pub req_flags: Option<ContextFlags>,
#[asn1(context_specific = "2", optional = "true", tag_mode = "EXPLICIT")]
pub mech_token: Option<OctetStringRef<'a>>,
#[asn1(context_specific = "3", optional = "true", tag_mode = "EXPLICIT")]
pub neg_hints: Option<NegHints<'a>>,
#[asn1(context_specific = "4", optional = "true", tag_mode = "EXPLICIT")]
pub mech_list_mic: Option<OctetStringRef<'a>>,
}
#[cfg(test)]
mod tests {
use hex_literal::hex;
use spki::ObjectIdentifier;
use super::*;
use der::Decode;
#[test]
fn mech_type() {
let mech_type_bytes = hex!("060a2b06010401823702020a");
let mech_type1 = MechType::from_der(&mech_type_bytes).unwrap();
assert_eq!(
ObjectIdentifier::new_unwrap("1.3.6.1.4.1.311.2.2.10"),
mech_type1
);
}
#[test]
fn token_init() {
let neg_token_init_bytes = hex!("303ca00e300c060a2b06010401823702020aa32a3028a0261b246e6f745f646566696e65645f696e5f5246433431373840706c656173655f69676e6f7265");
let neg_token = NegTokenInit2::from_der(&neg_token_init_bytes).unwrap();
assert_eq!(
1,
neg_token.mech_types.unwrap().len(),
"NegTokenInit2 mech_types len correct"
);
assert_eq!(
b"not_defined_in_RFC4178@please_ignore",
&neg_token.neg_hints.unwrap().hint_name.unwrap().value()[2..]
);
}
#[test]
fn token_response() {
let neg_token_resp_bytes = hex!("308199a0030a0101a10c060a2b06010401823702020aa281830481804e544c4d53535000020000000a000a003800000005028a6234805409a0e0e1f900000000000000003e003e0042000000060100000000000f530041004d004200410002000a00530041004d004200410001000a00530041004d00420041000400000003000a00730061006d00620061000700080036739dbd327fd90100000000");
let neg_token_resp = NegTokenResp::from_der(&neg_token_resp_bytes).unwrap();
assert_eq!(
ObjectIdentifier::new_unwrap("1.3.6.1.4.1.311.2.2.10"),
neg_token_resp.supported_mech.unwrap()
);
}
#[cfg(feature = "rfc2478")]
#[test]
fn decode_rfc2478() {
let neg_token_targ_bytes = hex!("308199a0030a0101a10c060a2b06010401823702020aa281830481804e544c4d53535000020000000a000a003800000005028a6234805409a0e0e1f900000000000000003e003e0042000000060100000000000f530041004d004200410002000a00530041004d004200410001000a00530041004d00420041000400000003000a00730061006d00620061000700080036739dbd327fd90100000000");
let neg_token_targ = NegTokenTarg::from_der(&neg_token_targ_bytes).unwrap();
assert_eq!(
NegResult::AcceptIncomplete,
neg_token_targ.neg_result.unwrap()
);
assert_eq!(
ObjectIdentifier::new_unwrap("1.3.6.1.4.1.311.2.2.10"),
neg_token_targ.supported_mech.unwrap()
);
}
}