gss_api/
lib.rs

1#![no_std]
2#![cfg_attr(docsrs, feature(doc_auto_cfg))]
3#![doc = include_str!("../README.md")]
4#![doc(
5    html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg",
6    html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg"
7)]
8#![forbid(unsafe_code)]
9#![warn(
10    clippy::mod_module_files,
11    clippy::unwrap_used,
12    missing_docs,
13    rust_2018_idioms,
14    unused_qualifications
15)]
16
17extern crate alloc;
18
19use der::{
20    AnyRef, DecodeValue, Encode, EncodeValue, FixedTag, Length, Reader, Tag, TagNumber, Writer,
21};
22use spki::ObjectIdentifier;
23
24pub mod negotiation;
25
26/// The `MechType` type is defined in [RFC 1508 Appendix B].
27///
28/// ```text
29///   MechType ::= OBJECT IDENTIFIER
30/// ```
31///
32/// [RFC 1508 Appendix B]: https://datatracker.ietf.org/doc/html/rfc1508#appendix-B
33pub type MechType = ObjectIdentifier;
34
35/// InitialContextToken as defined in [RFC 1508 Appendix B].
36///
37/// ```text
38/// InitialContextToken ::=
39/// -- option indication (delegation, etc.) indicated within
40/// -- mechanism-specific token
41/// [APPLICATION 0] IMPLICIT SEQUENCE {
42///     thisMech MechType,
43///     innerContextToken ANY DEFINED BY thisMec
44///          -- contents mechanism-specific
45///     }
46/// ```
47///
48/// [RFC 1508 Appendix B]: https://datatracker.ietf.org/doc/html/rfc1508#appendix-B
49#[derive(Clone, Debug, Eq, PartialEq)]
50pub struct InitialContextToken<'a> {
51    /// mechanism type OID
52    pub this_mech: MechType,
53    /// mechanism-specific content
54    pub inner_context_token: AnyRef<'a>,
55}
56
57impl<'a> FixedTag for InitialContextToken<'a> {
58    const TAG: Tag = Tag::Application {
59        constructed: true,
60        number: TagNumber::new(0),
61    };
62}
63
64impl<'a> DecodeValue<'a> for InitialContextToken<'a> {
65    fn decode_value<R: Reader<'a>>(reader: &mut R, _header: der::Header) -> der::Result<Self> {
66        Ok(Self {
67            this_mech: reader.decode()?,
68            inner_context_token: reader.decode()?,
69        })
70    }
71}
72
73impl<'a> EncodeValue for InitialContextToken<'a> {
74    fn value_len(&self) -> der::Result<Length> {
75        self.this_mech.encoded_len()? + self.inner_context_token.encoded_len()?
76    }
77
78    fn encode_value(&self, writer: &mut impl Writer) -> der::Result<()> {
79        self.this_mech.encode(writer)?;
80        self.inner_context_token.encode(writer)?;
81
82        Ok(())
83    }
84}
85
86/// The `SubsequentContextToken` type is defined in [RFC 1508 Appendix B].
87///
88/// ```text
89/// subsequentContextToken ::= innerContextToken ANY
90/// -- interpretation based on predecessor InitialContextToken
91/// ```
92///
93/// [RFC 1508 Appendix B]: https://datatracker.ietf.org/doc/html/rfc1508#appendix-B
94pub type SubsequentContextToken<'a> = AnyRef<'a>;
95
96/// The `PerMsgToken` type is defined in [RFC 1508 Appendix B].
97///
98/// ```text
99/// -- as emitted by GSS_Sign and processed by GSS_Verify
100///         innerMsgToken ANY
101/// ```
102///
103/// [RFC 1508 Appendix B]: https://datatracker.ietf.org/doc/html/rfc1508#appendix-B
104pub type PerMsgToken<'a> = AnyRef<'a>;
105
106/// The `SealedMessage` type is defined in [RFC 1508 Appendix B].
107///
108/// ```text
109/// SealedMessage ::=
110/// -- as emitted by GSS_Seal and processed by GSS_Unseal
111/// -- includes internal, mechanism-defined indicator
112/// -- of whether or not encrypted
113///         sealedUserData ANY
114/// ```
115///
116/// [RFC 1508 Appendix B]: https://datatracker.ietf.org/doc/html/rfc1508#appendix-B
117pub type SealedMessage<'a> = AnyRef<'a>;
118
119#[cfg(test)]
120mod tests {
121    use hex_literal::hex;
122    use spki::ObjectIdentifier;
123
124    use super::*;
125
126    use der::Decode;
127
128    #[test]
129    fn initial_context_token() {
130        let gss_bytes = hex!("604806062b0601050502a03e303ca00e300c060a2b06010401823702020aa22a04284e544c4d535350000100000005028862000000000000000000000000000000000601b01d0000000f");
131        let inner_bytes = hex!("303ca00e300c060a2b06010401823702020aa22a04284e544c4d535350000100000005028862000000000000000000000000000000000601b01d0000000f");
132
133        let gss = InitialContextToken::from_der(&gss_bytes).unwrap();
134
135        assert_eq!(ObjectIdentifier::new_unwrap("1.3.6.1.5.5.2"), gss.this_mech);
136        assert_eq!(
137            AnyRef::new(
138                Tag::ContextSpecific {
139                    constructed: true,
140                    number: TagNumber::N0
141                },
142                &inner_bytes
143            )
144            .unwrap(),
145            gss.inner_context_token
146        );
147
148        let output = InitialContextToken {
149            this_mech: MechType::new_unwrap("1.3.6.1.5.5.2"),
150            inner_context_token: AnyRef::new(
151                Tag::ContextSpecific {
152                    constructed: true,
153                    number: TagNumber::N0,
154                },
155                &inner_bytes,
156            )
157            .unwrap(),
158        };
159
160        let output_bytes = output.to_der().unwrap();
161
162        assert_eq!(&gss_bytes[..], &output_bytes);
163    }
164}