red_spnego/
negotiation_token.rs

1use crate::spnego_oid;
2use crate::NegTokenInit2;
3use crate::NegTokenResp;
4use red_asn1::{
5    build_length, parse_length, Asn1Object, Oid, Tag, TagClass, TagType,
6};
7
8#[derive(Clone, Debug, PartialEq)]
9pub enum NegToken {
10    Init2(NegTokenInit2),
11    Resp(NegTokenResp),
12}
13
14impl NegToken {
15    pub fn build(&self) -> Vec<u8> {
16        match self {
17            Self::Init2(init2) => {
18                let mut raw = Vec::new();
19                raw.extend(spnego_oid().build());
20
21                raw.extend(
22                    Tag::new(0, TagType::Constructed, TagClass::Context)
23                        .build(),
24                );
25
26                let raw_init2 = init2.build();
27                raw.extend(build_length(raw_init2.len()));
28                raw.extend(raw_init2);
29
30                let mut ext_raw =
31                    Tag::new(0, TagType::Constructed, TagClass::Application)
32                        .build();
33                ext_raw.extend(build_length(raw.len()));
34                ext_raw.extend(raw);
35
36                return ext_raw;
37            }
38            Self::Resp(resp) => {
39                let mut ext_raw =
40                    Tag::new(1, TagType::Constructed, TagClass::Context)
41                        .build();
42
43                let raw_resp = resp.build();
44                ext_raw.extend(build_length(raw_resp.len()));
45                ext_raw.extend(raw_resp);
46
47                return ext_raw;
48            }
49        }
50    }
51
52    pub fn parse(raw: &[u8]) -> red_asn1::Result<Self> {
53        let (raw, initial_tag) = Tag::parse(raw)?;
54        let (raw, _) = parse_length(raw)?;
55
56        if initial_tag
57            == Tag::new(0, TagType::Constructed, TagClass::Application)
58        {
59            let (raw, _) = Oid::parse(raw)?;
60
61            let (raw, _) = Tag::parse(raw)?;
62
63            let (raw, _) = parse_length(raw)?;
64
65            let (_, token_init) = NegTokenInit2::parse(raw)?;
66            return Ok(Self::Init2(token_init));
67        }
68
69        let (_, token_resp) = NegTokenResp::parse(raw)?;
70        return Ok(Self::Resp(token_resp));
71    }
72}
73
74#[cfg(test)]
75mod tests {
76    use super::*;
77    use crate::ntlmssp_oid;
78    use crate::ACCEPT_INCOMPLETE;
79
80    const RAW_SPNEGO_INIT_MSG: &'static [u8] = &[
81        0x60, 0x40, 0x06, 0x06, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x02, 0xa0, 0x36,
82        0x30, 0x34, 0xa0, 0x0e, 0x30, 0x0c, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04,
83        0x01, 0x82, 0x37, 0x02, 0x02, 0x0a, 0xa2, 0x22, 0x04, 0x20, 0x4e, 0x54,
84        0x4c, 0x4d, 0x53, 0x53, 0x50, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x02,
85        0x88, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
86        0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
87    ];
88
89    #[test]
90    fn test_build_spnego_init_msg() {
91        let mut init = NegTokenInit2::default();
92        init.mech_types = vec![ntlmssp_oid()];
93        init.mech_token = Some(vec![
94            0x4e, 0x54, 0x4c, 0x4d, 0x53, 0x53, 0x50, 0x00, 0x01, 0x00, 0x00,
95            0x00, 0x05, 0x02, 0x88, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
96            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
97        ]);
98
99        assert_eq!(RAW_SPNEGO_INIT_MSG.to_vec(), NegToken::Init2(init).build(),);
100    }
101
102    #[test]
103    fn test_parse_spnego_init_msg() {
104        let mut init = NegTokenInit2::default();
105        init.mech_types = vec![ntlmssp_oid()];
106        init.mech_token = Some(vec![
107            0x4e, 0x54, 0x4c, 0x4d, 0x53, 0x53, 0x50, 0x00, 0x01, 0x00, 0x00,
108            0x00, 0x05, 0x02, 0x88, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
109            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
110        ]);
111
112        assert_eq!(
113            NegToken::Init2(init),
114            NegToken::parse(RAW_SPNEGO_INIT_MSG).unwrap()
115        );
116    }
117
118    const RAW_SPNEGO_RESP_MSG: &'static [u8] = &[
119        0xa1, 0x82, 0x01, 0x00, 0x30, 0x81, 0xfd, 0xa0, 0x03, 0x0a, 0x01, 0x01,
120        0xa1, 0x0c, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x02,
121        0x02, 0x0a, 0xa2, 0x81, 0xe7, 0x04, 0x81, 0xe4, 0x4e, 0x54, 0x4c, 0x4d,
122        0x53, 0x53, 0x50, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x0e, 0x00,
123        0x38, 0x00, 0x00, 0x00, 0x05, 0x02, 0x89, 0xa2, 0x29, 0x4d, 0xc3, 0x21,
124        0x91, 0x96, 0x86, 0xd1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
125        0x9e, 0x00, 0x9e, 0x00, 0x46, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x61, 0x4a,
126        0x00, 0x00, 0x00, 0x0f, 0x43, 0x00, 0x4f, 0x00, 0x4e, 0x00, 0x54, 0x00,
127        0x4f, 0x00, 0x53, 0x00, 0x4f, 0x00, 0x02, 0x00, 0x0e, 0x00, 0x43, 0x00,
128        0x4f, 0x00, 0x4e, 0x00, 0x54, 0x00, 0x4f, 0x00, 0x53, 0x00, 0x4f, 0x00,
129        0x01, 0x00, 0x0e, 0x00, 0x57, 0x00, 0x53, 0x00, 0x30, 0x00, 0x31, 0x00,
130        0x2d, 0x00, 0x31, 0x00, 0x30, 0x00, 0x04, 0x00, 0x1a, 0x00, 0x63, 0x00,
131        0x6f, 0x00, 0x6e, 0x00, 0x74, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x6f, 0x00,
132        0x2e, 0x00, 0x6c, 0x00, 0x6f, 0x00, 0x63, 0x00, 0x61, 0x00, 0x6c, 0x00,
133        0x03, 0x00, 0x2a, 0x00, 0x77, 0x00, 0x73, 0x00, 0x30, 0x00, 0x31, 0x00,
134        0x2d, 0x00, 0x31, 0x00, 0x30, 0x00, 0x2e, 0x00, 0x63, 0x00, 0x6f, 0x00,
135        0x6e, 0x00, 0x74, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x6f, 0x00, 0x2e, 0x00,
136        0x6c, 0x00, 0x6f, 0x00, 0x63, 0x00, 0x61, 0x00, 0x6c, 0x00, 0x05, 0x00,
137        0x1a, 0x00, 0x63, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x74, 0x00, 0x6f, 0x00,
138        0x73, 0x00, 0x6f, 0x00, 0x2e, 0x00, 0x6c, 0x00, 0x6f, 0x00, 0x63, 0x00,
139        0x61, 0x00, 0x6c, 0x00, 0x07, 0x00, 0x08, 0x00, 0x4d, 0x01, 0xec, 0x80,
140        0x9a, 0xf0, 0xd6, 0x01, 0x00, 0x00, 0x00, 0x00,
141    ];
142
143    #[test]
144    fn test_parse_spnego_resp_msg() {
145        let mut neg_token_resp = NegTokenResp::default();
146        *neg_token_resp.neg_state = ACCEPT_INCOMPLETE;
147        neg_token_resp.supported_mech = Some(ntlmssp_oid());
148        neg_token_resp.response_token = Some(vec![
149            0x4e, 0x54, 0x4c, 0x4d, 0x53, 0x53, 0x50, 0x00, 0x02, 0x00, 0x00,
150            0x00, 0x0e, 0x00, 0x0e, 0x00, 0x38, 0x00, 0x00, 0x00, 0x05, 0x02,
151            0x89, 0xa2, 0x29, 0x4d, 0xc3, 0x21, 0x91, 0x96, 0x86, 0xd1, 0x00,
152            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x9e, 0x00,
153            0x46, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x61, 0x4a, 0x00, 0x00, 0x00,
154            0x0f, 0x43, 0x00, 0x4f, 0x00, 0x4e, 0x00, 0x54, 0x00, 0x4f, 0x00,
155            0x53, 0x00, 0x4f, 0x00, 0x02, 0x00, 0x0e, 0x00, 0x43, 0x00, 0x4f,
156            0x00, 0x4e, 0x00, 0x54, 0x00, 0x4f, 0x00, 0x53, 0x00, 0x4f, 0x00,
157            0x01, 0x00, 0x0e, 0x00, 0x57, 0x00, 0x53, 0x00, 0x30, 0x00, 0x31,
158            0x00, 0x2d, 0x00, 0x31, 0x00, 0x30, 0x00, 0x04, 0x00, 0x1a, 0x00,
159            0x63, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x74, 0x00, 0x6f, 0x00, 0x73,
160            0x00, 0x6f, 0x00, 0x2e, 0x00, 0x6c, 0x00, 0x6f, 0x00, 0x63, 0x00,
161            0x61, 0x00, 0x6c, 0x00, 0x03, 0x00, 0x2a, 0x00, 0x77, 0x00, 0x73,
162            0x00, 0x30, 0x00, 0x31, 0x00, 0x2d, 0x00, 0x31, 0x00, 0x30, 0x00,
163            0x2e, 0x00, 0x63, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x74, 0x00, 0x6f,
164            0x00, 0x73, 0x00, 0x6f, 0x00, 0x2e, 0x00, 0x6c, 0x00, 0x6f, 0x00,
165            0x63, 0x00, 0x61, 0x00, 0x6c, 0x00, 0x05, 0x00, 0x1a, 0x00, 0x63,
166            0x00, 0x6f, 0x00, 0x6e, 0x00, 0x74, 0x00, 0x6f, 0x00, 0x73, 0x00,
167            0x6f, 0x00, 0x2e, 0x00, 0x6c, 0x00, 0x6f, 0x00, 0x63, 0x00, 0x61,
168            0x00, 0x6c, 0x00, 0x07, 0x00, 0x08, 0x00, 0x4d, 0x01, 0xec, 0x80,
169            0x9a, 0xf0, 0xd6, 0x01, 0x00, 0x00, 0x00, 0x00,
170        ]);
171
172        assert_eq!(
173            NegToken::Resp(neg_token_resp),
174            NegToken::parse(RAW_SPNEGO_RESP_MSG).unwrap()
175        );
176    }
177
178    #[test]
179    fn test_build_spnego_resp_msg() {
180        let mut neg_token_resp = NegTokenResp::default();
181        *neg_token_resp.neg_state = ACCEPT_INCOMPLETE;
182        neg_token_resp.supported_mech = Some(ntlmssp_oid());
183        neg_token_resp.response_token = Some(vec![
184            0x4e, 0x54, 0x4c, 0x4d, 0x53, 0x53, 0x50, 0x00, 0x02, 0x00, 0x00,
185            0x00, 0x0e, 0x00, 0x0e, 0x00, 0x38, 0x00, 0x00, 0x00, 0x05, 0x02,
186            0x89, 0xa2, 0x29, 0x4d, 0xc3, 0x21, 0x91, 0x96, 0x86, 0xd1, 0x00,
187            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x9e, 0x00,
188            0x46, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x61, 0x4a, 0x00, 0x00, 0x00,
189            0x0f, 0x43, 0x00, 0x4f, 0x00, 0x4e, 0x00, 0x54, 0x00, 0x4f, 0x00,
190            0x53, 0x00, 0x4f, 0x00, 0x02, 0x00, 0x0e, 0x00, 0x43, 0x00, 0x4f,
191            0x00, 0x4e, 0x00, 0x54, 0x00, 0x4f, 0x00, 0x53, 0x00, 0x4f, 0x00,
192            0x01, 0x00, 0x0e, 0x00, 0x57, 0x00, 0x53, 0x00, 0x30, 0x00, 0x31,
193            0x00, 0x2d, 0x00, 0x31, 0x00, 0x30, 0x00, 0x04, 0x00, 0x1a, 0x00,
194            0x63, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x74, 0x00, 0x6f, 0x00, 0x73,
195            0x00, 0x6f, 0x00, 0x2e, 0x00, 0x6c, 0x00, 0x6f, 0x00, 0x63, 0x00,
196            0x61, 0x00, 0x6c, 0x00, 0x03, 0x00, 0x2a, 0x00, 0x77, 0x00, 0x73,
197            0x00, 0x30, 0x00, 0x31, 0x00, 0x2d, 0x00, 0x31, 0x00, 0x30, 0x00,
198            0x2e, 0x00, 0x63, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x74, 0x00, 0x6f,
199            0x00, 0x73, 0x00, 0x6f, 0x00, 0x2e, 0x00, 0x6c, 0x00, 0x6f, 0x00,
200            0x63, 0x00, 0x61, 0x00, 0x6c, 0x00, 0x05, 0x00, 0x1a, 0x00, 0x63,
201            0x00, 0x6f, 0x00, 0x6e, 0x00, 0x74, 0x00, 0x6f, 0x00, 0x73, 0x00,
202            0x6f, 0x00, 0x2e, 0x00, 0x6c, 0x00, 0x6f, 0x00, 0x63, 0x00, 0x61,
203            0x00, 0x6c, 0x00, 0x07, 0x00, 0x08, 0x00, 0x4d, 0x01, 0xec, 0x80,
204            0x9a, 0xf0, 0xd6, 0x01, 0x00, 0x00, 0x00, 0x00,
205        ]);
206
207        assert_eq!(
208            RAW_SPNEGO_RESP_MSG.to_vec(),
209            NegToken::Resp(neg_token_resp).build(),
210        );
211    }
212}