//! Kerberos 5 parsing functions use der_parser::ber::*; use der_parser::der::*; use der_parser::error::*; use nom::combinator::{complete, map, map_res, opt, verify}; use nom::error::{make_error, ErrorKind}; use nom::multi::many1; use nom::{Err, IResult}; use std::str; use crate::krb5::*; /// Parse a signed 32 bits integer /// ///
/// Int32 ::= INTEGER (-2147483648..2147483647) /// -- signed values representable in 32 bits ///pub fn parse_der_int32(i: &[u8]) -> IResult<&[u8], i32, BerError> { map_res(parse_der_integer, |x: DerObject| match x.content { BerObjectContent::Integer(i) => match i.len() { 1 => Ok(i[0] as i8 as i32), 2 => Ok((i[0] as i8 as i32) << 8 | (i[1] as i32)), 3 => Ok((i[0] as i8 as i32) << 16 | (i[1] as i32) << 8 | (i[2] as i32)), 4 => Ok((i[0] as i8 as i32) << 24 | (i[1] as i32) << 16 | (i[2] as i32) << 8 | (i[3] as i32)), _ => Err(BerError::IntegerTooLarge), }, _ => Err(BerError::BerTypeError), })(i) } // Microseconds ::= INTEGER (0..999999) // -- microseconds fn parse_der_microseconds(i: &[u8]) -> IResult<&[u8], u32, BerError> { verify(parse_der_u32, |x: &u32| *x <= 999_999)(i) } /// Parse a Kerberos string object /// ///
/// KerberosString ::= GeneralString (IA5String) ///pub fn parse_kerberos_string(i: &[u8]) -> IResult<&[u8], String, BerError> { match parse_der_generalstring(i) { Ok((rem, ref obj)) => { if let BerObjectContent::GeneralString(s) = obj.content { match str::from_utf8(s) { Ok(r) => Ok((rem, r.to_owned())), Err(_) => Err(Err::Error(make_error(i, ErrorKind::IsNot))), } } else { Err(Err::Error(make_error(i, ErrorKind::Tag))) } } Err(e) => Err(e), } } fn parse_kerberos_string_sequence(i: &[u8]) -> IResult<&[u8], Vec
/// KerberosFlags ::= BIT STRING (SIZE (32..MAX)) /// -- minimum number of bits shall be sent, /// -- but no fewer than 32 ///#[inline] pub fn parse_kerberos_flags(i: &[u8]) -> IResult<&[u8], DerObject, BerError> { parse_der_bitstring(i) } /// Parse of a Kerberos Realm /// ///
/// Realm ::= KerberosString ///#[inline] pub fn parse_krb5_realm(i: &[u8]) -> IResult<&[u8], Realm, BerError> { map(parse_kerberos_string, Realm)(i) } /// Parse Kerberos PrincipalName /// ///
/// PrincipalName ::= SEQUENCE { /// name-type [0] Int32, /// name-string [1] SEQUENCE OF KerberosString /// } ///pub fn parse_krb5_principalname(i: &[u8]) -> IResult<&[u8], PrincipalName, BerError> { parse_ber_sequence_defined_g(|i, _| { let (i, name_type) = parse_ber_tagged_explicit_g(0, |a, _| map(parse_der_int32, NameType)(a))(i)?; let (i, name_string) = parse_ber_tagged_explicit_g(1, |a, _| parse_kerberos_string_sequence(a))(i)?; Ok(( i, PrincipalName { name_type, name_string, }, )) })(i) } /// Parse of a Kerberos Time /// ///
/// KerberosTime ::= GeneralizedTime -- with no fractional seconds ///#[inline] pub fn parse_kerberos_time(i: &[u8]) -> IResult<&[u8], DerObject, BerError> { parse_der_generalizedtime(i) } /// Parse Kerberos HostAddress /// ///
/// HostAddress ::= SEQUENCE { /// addr-type [0] Int32, /// address [1] OCTET STRING /// } ///pub fn parse_krb5_hostaddress(i: &[u8]) -> IResult<&[u8], HostAddress, BerError> { parse_ber_sequence_defined_g(|i, _| { let (i, addr_type) = parse_ber_tagged_explicit_g(0, |a, _| map(parse_der_int32, AddressType)(a))(i)?; let (i, address) = parse_ber_tagged_explicit_g(1, |a, _| { map_res(parse_ber_octetstring, |o| o.as_slice())(a) })(i)?; Ok((i, HostAddress { addr_type, address })) })(i) } /// Parse Kerberos HostAddresses /// ///
/// -- NOTE: HostAddresses is always used as an OPTIONAL field and /// -- should not be empty. /// HostAddresses -- NOTE: subtly different from rfc1510, /// -- but has a value mapping and encodes the same /// ::= SEQUENCE OF HostAddress ///pub fn parse_krb5_hostaddresses(i: &[u8]) -> IResult<&[u8], Vec
/// Ticket ::= [APPLICATION 1] SEQUENCE { /// tkt-vno [0] INTEGER (5), /// realm [1] Realm, /// sname [2] PrincipalName, /// enc-part [3] EncryptedData -- EncTicketPart /// } ///pub fn parse_krb5_ticket(i: &[u8]) -> IResult<&[u8], Ticket, BerError> { parse_ber_tagged_explicit_g(BerTag(1), |i, hdr| { if !hdr.is_application() { return Err(Err::Error(BerError::InvalidTag)); } parse_ber_sequence_defined_g(|i, _| { let (i, tkt_vno) = parse_ber_tagged_explicit_g(0, |a, _| parse_der_u32(a))(i)?; if tkt_vno != 5 { return Err(Err::Error(BerError::Custom(5))); } let (i, realm) = parse_ber_tagged_explicit_g(1, |a, _| parse_krb5_realm(a))(i)?; let (i, sname) = parse_ber_tagged_explicit_g(2, |a, _| parse_krb5_principalname(a))(i)?; let (i, enc_part) = parse_ber_tagged_explicit_g(3, |a, _| parse_encrypted(a))(i)?; let tkt = Ticket { tkt_vno, realm, sname, enc_part, }; Ok((i, tkt)) })(i) })(i) } /// Parse Kerberos EncryptedData /// ///
/// EncryptedData ::= SEQUENCE { /// etype [0] Int32 -- EncryptionType --, /// kvno [1] UInt32 OPTIONAL, /// cipher [2] OCTET STRING -- ciphertext /// } ///pub fn parse_encrypted(i: &[u8]) -> IResult<&[u8], EncryptedData, BerError> { parse_ber_sequence_defined_g(|i, _| { let (i, etype) = parse_ber_tagged_explicit_g(0, |a, _| map(parse_der_int32, EncryptionType)(a))(i)?; let (i, kvno) = opt(complete(parse_ber_tagged_explicit_g(1, |a, _| { parse_der_u32(a) })))(i)?; let (i, cipher) = parse_ber_tagged_explicit_g(2, |a, _| map_res(parse_der, |o| o.as_slice())(a))(i)?; let enc = EncryptedData { etype, kvno, cipher, }; Ok((i, enc)) })(i) } /// Parse a Kerberos KDC Request /// ///
/// KDC-REQ ::= SEQUENCE { /// -- NOTE: first tag is [1], not [0] /// pvno [1] INTEGER (5) , /// msg-type [2] INTEGER (10 -- AS -- | 12 -- TGS --), /// padata [3] SEQUENCE OF PA-DATA OPTIONAL /// -- NOTE: not empty --, /// req-body [4] KDC-REQ-BODY /// } ///pub fn parse_kdc_req(i: &[u8]) -> IResult<&[u8], KdcReq, BerError> { parse_ber_sequence_defined_g(|i, _| { let (i, pvno) = parse_ber_tagged_explicit_g(1, |a, _| parse_der_u32(a))(i)?; let (i, msg_type) = parse_ber_tagged_explicit_g(2, |a, _| map(parse_der_u32, MessageType)(a))(i)?; let (i, padata) = parse_ber_tagged_explicit_g(3, |a, _| parse_krb5_padata_sequence(a))(i) .unwrap_or_else(|_| (i, Vec::new())); let (i, req_body) = parse_ber_tagged_explicit_g(4, |a, _| parse_kdc_req_body(a))(i)?; let req = KdcReq { pvno, msg_type, padata, req_body, }; Ok((i, req)) })(i) } /// Parse the body of a Kerberos KDC Request /// ///
/// KDC-REQ-BODY ::= SEQUENCE { /// kdc-options [0] KDCOptions, /// cname [1] PrincipalName OPTIONAL /// -- Used only in AS-REQ --, /// realm [2] Realm /// -- Server's realm /// -- Also client's in AS-REQ --, /// sname [3] PrincipalName OPTIONAL, /// from [4] KerberosTime OPTIONAL, /// till [5] KerberosTime, /// rtime [6] KerberosTime OPTIONAL, /// nonce [7] UInt32, /// etype [8] SEQUENCE OF Int32 -- EncryptionType /// -- in preference order --, /// addresses [9] HostAddresses OPTIONAL, /// enc-authorization-data [10] EncryptedData OPTIONAL /// -- AuthorizationData --, /// additional-tickets [11] SEQUENCE OF Ticket OPTIONAL /// -- NOTE: not empty /// } ///pub fn parse_kdc_req_body(i: &[u8]) -> IResult<&[u8], KdcReqBody, BerError> { parse_ber_sequence_defined_g(|i, _| { let (i, kdc_options) = parse_ber_tagged_explicit_g(0, |a, _| parse_kerberos_flags(a))(i)?; let (i, cname) = opt(complete(parse_ber_tagged_explicit_g(1, |a, _| { parse_krb5_principalname(a) })))(i)?; let (i, realm) = parse_ber_tagged_explicit_g(2, |a, _| parse_krb5_realm(a))(i)?; let (i, sname) = opt(complete(parse_ber_tagged_explicit_g(3, |a, _| { parse_krb5_principalname(a) })))(i)?; let (i, from) = opt(complete(parse_ber_tagged_explicit_g(4, |a, _| { parse_kerberos_time(a) })))(i)?; let (i, till) = parse_ber_tagged_explicit_g(5, |a, _| parse_kerberos_time(a))(i)?; let (i, rtime) = opt(complete(parse_ber_tagged_explicit_g(6, |a, _| { parse_kerberos_time(a) })))(i)?; let (i, nonce) = parse_ber_tagged_explicit_g(7, |a, _| parse_der_u32(a))(i)?; let (i, etype) = parse_ber_tagged_explicit_g(8, |a, _| { map(parse_ber_sequence_of_v(parse_der_int32), |v| { v.iter().map(|&x| EncryptionType(x)).collect() })(a) })(i)?; let (i, addresses) = opt(complete(parse_ber_tagged_explicit_g(9, |a, _| { parse_krb5_hostaddresses(a) })))(i)?; let addresses = addresses.unwrap_or_default(); let (i, enc_authorization_data) = opt(complete(parse_ber_tagged_explicit_g(10, |a, _| { parse_encrypted(a) })))(i)?; let (i, additional_tickets) = opt(complete(parse_ber_tagged_explicit_g(11, |a, _| { many1(complete(parse_krb5_ticket))(a) })))(i)?; let additional_tickets = additional_tickets.unwrap_or_default(); let body = KdcReqBody { kdc_options, cname, realm, sname, from, till, rtime, nonce, etype, addresses, enc_authorization_data, additional_tickets, }; Ok((i, body)) })(i) } /// Parse a Kerberos AS Request /// ///
/// AS-REQ ::= [APPLICATION 10] KDC-REQ ///pub fn parse_as_req(i: &[u8]) -> IResult<&[u8], KdcReq, BerError> { parse_ber_tagged_explicit_g(BerTag(10), |i, hdr| { if !hdr.is_application() { return Err(Err::Error(BerError::InvalidTag)); } parse_kdc_req(i) })(i) } /// Parse a Kerberos TGS Request /// ///
/// TGS-REQ ::= [APPLICATION 12] KDC-REQ ///pub fn parse_tgs_req(i: &[u8]) -> IResult<&[u8], KdcReq, BerError> { parse_ber_tagged_explicit_g(BerTag(12), |i, hdr| { if !hdr.is_application() { return Err(Err::Error(BerError::InvalidTag)); } parse_kdc_req(i) })(i) } /// Parse a Kerberos KDC Reply /// ///
/// KDC-REP ::= SEQUENCE { /// pvno [0] INTEGER (5), /// msg-type [1] INTEGER (11 -- AS -- | 13 -- TGS --), /// padata [2] SEQUENCE OF PA-DATA OPTIONAL /// -- NOTE: not empty --, /// crealm [3] Realm, /// cname [4] PrincipalName, /// ticket [5] Ticket, /// enc-part [6] EncryptedData /// -- EncASRepPart or EncTGSRepPart, /// -- as appropriate /// } ///pub fn parse_kdc_rep(i: &[u8]) -> IResult<&[u8], KdcRep, BerError> { parse_ber_sequence_defined_g(|i, _| { let (i, pvno) = parse_ber_tagged_explicit_g(0, |a, _| parse_der_u32(a))(i)?; let (i, msg_type) = parse_ber_tagged_explicit_g(1, |a, _| map(parse_der_u32, MessageType)(a))(i)?; let (i, padata) = parse_ber_tagged_explicit_g(2, |a, _| parse_krb5_padata_sequence(a))(i) .unwrap_or_else(|_| (i, Vec::new())); let (i, crealm) = parse_ber_tagged_explicit_g(3, |a, _| parse_krb5_realm(a))(i)?; let (i, cname) = parse_ber_tagged_explicit_g(4, |a, _| parse_krb5_principalname(a))(i)?; let (i, ticket) = parse_ber_tagged_explicit_g(5, |a, _| parse_krb5_ticket(a))(i)?; let (i, enc_part) = parse_ber_tagged_explicit_g(6, |a, _| parse_encrypted(a))(i)?; let rep = KdcRep { pvno, msg_type, padata, crealm, cname, ticket, enc_part, }; Ok((i, rep)) })(i) } /// Parse a Kerberos AS Reply /// ///
/// AS-REP ::= [APPLICATION 11] KDC-REP ///pub fn parse_as_rep(i: &[u8]) -> IResult<&[u8], KdcRep, BerError> { parse_ber_tagged_explicit_g(BerTag(11), |i, hdr| { if !hdr.is_application() { return Err(Err::Error(BerError::InvalidTag)); } parse_kdc_rep(i) })(i) } /// Parse a Kerberos TGS Reply /// ///
/// TGS-REP ::= [APPLICATION 13] KDC-REP ///pub fn parse_tgs_rep(i: &[u8]) -> IResult<&[u8], KdcRep, BerError> { parse_ber_tagged_explicit_g(BerTag(13), |i, hdr| { if !hdr.is_application() { return Err(Err::Error(BerError::InvalidTag)); } parse_kdc_rep(i) })(i) } /// Parse a Kerberos Error /// ///
/// KRB-ERROR ::= [APPLICATION 30] SEQUENCE { /// pvno [0] INTEGER (5), /// msg-type [1] INTEGER (30), /// ctime [2] KerberosTime OPTIONAL, /// cusec [3] Microseconds OPTIONAL, /// stime [4] KerberosTime, /// susec [5] Microseconds, /// error-code [6] Int32, /// crealm [7] Realm OPTIONAL, /// cname [8] PrincipalName OPTIONAL, /// realm [9] Realm -- service realm --, /// sname [10] PrincipalName -- service name --, /// e-text [11] KerberosString OPTIONAL, /// e-data [12] OCTET STRING OPTIONAL /// } ///pub fn parse_krb_error(i: &[u8]) -> IResult<&[u8], KrbError, BerError> { parse_ber_tagged_explicit_g(BerTag(30), |i, hdr| { if !hdr.is_application() { return Err(Err::Error(BerError::InvalidTag)); } parse_ber_sequence_defined_g(|i, _| { let (i, pvno) = parse_ber_tagged_explicit_g(0, |a, _| parse_der_u32(a))(i)?; let (i, msg_type) = parse_ber_tagged_explicit_g(1, |a, _| map(parse_der_u32, MessageType)(a))(i)?; let (i, ctime) = opt(complete(parse_ber_tagged_explicit_g(2, |a, _| { parse_kerberos_time(a) })))(i)?; let (i, cusec) = opt(complete(parse_ber_tagged_explicit_g(3, |a, _| { parse_der_microseconds(a) })))(i)?; let (i, stime) = parse_ber_tagged_explicit_g(4, |a, _| parse_kerberos_time(a))(i)?; let (i, susec) = parse_ber_tagged_explicit_g(5, |a, _| parse_der_microseconds(a))(i)?; let (i, error_code) = parse_ber_tagged_explicit_g(6, |a, _| map(parse_der_int32, ErrorCode)(a))(i)?; let (i, crealm) = opt(complete(parse_ber_tagged_explicit_g(7, |a, _| { parse_krb5_realm(a) })))(i)?; let (i, cname) = opt(complete(parse_ber_tagged_explicit_g(8, |a, _| { parse_krb5_principalname(a) })))(i)?; let (i, realm) = parse_ber_tagged_explicit_g(9, |a, _| parse_krb5_realm(a))(i)?; let (i, sname) = parse_ber_tagged_explicit_g(10, |a, _| parse_krb5_principalname(a))(i)?; let (i, etext) = opt(complete(parse_ber_tagged_explicit_g(11, |a, _| { parse_kerberos_string(a) })))(i)?; let (i, edata) = opt(complete(parse_ber_tagged_explicit_g(12, |a, _| { parse_der_octetstring(a) })))(i)?; let err = KrbError { pvno, msg_type, ctime, cusec, stime, susec, error_code, crealm, cname, realm, sname, etext, edata, }; Ok((i, err)) })(i) })(i) } /// Parse Kerberos PA-Data /// ///
/// PA-DATA ::= SEQUENCE { /// -- NOTE: first tag is [1], not [0] /// padata-type [1] Int32, /// padata-value [2] OCTET STRING -- might be encoded AP-REQ /// } ///pub fn parse_krb5_padata(i: &[u8]) -> IResult<&[u8], PAData, BerError> { parse_ber_sequence_defined_g(|i, _| { let (i, padata_type) = parse_ber_tagged_explicit_g(1, |a, _| map(parse_der_int32, PAType)(a))(i)?; let (i, padata_value) = parse_ber_tagged_explicit_g(2, |a, _| map_res(parse_der, |o| o.as_slice())(a))(i)?; let padata = PAData { padata_type, padata_value, }; Ok((i, padata)) })(i) } fn parse_krb5_padata_sequence(i: &[u8]) -> IResult<&[u8], Vec
/// AP-REQ ::= [APPLICATION 14] SEQUENCE { /// pvno [0] INTEGER (5), /// msg-type [1] INTEGER (14), /// ap-options [2] APOptions, /// ticket [3] Ticket, /// authenticator [4] EncryptedData -- Authenticator /// } /// /// APOptions ::= KerberosFlags /// -- reserved(0), /// -- use-session-key(1), /// -- mutual-required(2) ///pub fn parse_ap_req(i: &[u8]) -> IResult<&[u8], ApReq, BerError> { parse_ber_tagged_explicit_g(BerTag(14), |i, hdr| { if !hdr.is_application() { return Err(Err::Error(BerError::InvalidTag)); } parse_ber_sequence_defined_g(|i, _| { let (i, pvno) = parse_ber_tagged_explicit_g(0, |a, _| parse_der_u32(a))(i)?; let (i, msg_type) = parse_ber_tagged_explicit_g(1, |a, _| map(parse_der_u32, MessageType)(a))(i)?; let (i, ap_options) = parse_ber_tagged_explicit_g(2, |a, _| parse_kerberos_flags(a))(i)?; let (i, ticket) = parse_ber_tagged_explicit_g(3, |a, _| parse_krb5_ticket(a))(i)?; let (i, authenticator) = parse_ber_tagged_explicit_g(4, |a, _| parse_encrypted(a))(i)?; let req = ApReq { pvno, msg_type, ap_options, ticket, authenticator, }; Ok((i, req)) })(i) })(i) } /// Parse a Kerberos AP Reply /// ///
/// AP-REP ::= [APPLICATION 15] SEQUENCE { /// pvno [0] INTEGER (5), /// msg-type [1] INTEGER (15), /// enc-part [2] EncryptedData -- EncAPRepPart /// } ///pub fn parse_ap_rep(i: &[u8]) -> IResult<&[u8], ApRep, BerError> { parse_ber_tagged_explicit_g(BerTag(15), |i, hdr| { if !hdr.is_application() { return Err(Err::Error(BerError::InvalidTag)); } parse_ber_sequence_defined_g(|i, _| { let (i, pvno) = parse_ber_tagged_explicit_g(0, |a, _| parse_der_u32(a))(i)?; let (i, msg_type) = parse_ber_tagged_explicit_g(1, |a, _| map(parse_der_u32, MessageType)(a))(i)?; let (i, enc_part) = parse_ber_tagged_explicit_g(2, |a, _| parse_encrypted(a))(i)?; let rep = ApRep { pvno, msg_type, enc_part, }; Ok((i, rep)) })(i) })(i) }