diff --git a/scripts/base/init-bare.bro b/scripts/base/init-bare.bro index 35eb43f2f9..018378661e 100644 --- a/scripts/base/init-bare.bro +++ b/scripts/base/init-bare.bro @@ -2975,31 +2975,6 @@ export { module KRB; export { - ## The data from the ERROR_MSG message. See :rfc:`4120`. - type KRB::Error_Msg: record { - ## Protocol version number (5 for KRB5) - pvno: count; - ## The message type (30 for ERROR_MSG) - msg_type: count; - ## Current time on the client - client_time: time &optional; - ## Current time on the server - server_time: time; - ## The specific error code - error_code: count; - ## Realm of the ticket - client_realm: string &optional; - ## Name on the ticket - client_name: string &optional; - ## Realm of the service - service_realm: string; - ## Name of the service - service_name: string; - ## Additional text to explain the error - error_text: string &optional; - }; - - ## KDC Options. See :rfc:`4120` type KRB::KDC_Options: record { ## The ticket to be issued should have its forwardable flag set. @@ -3030,7 +3005,7 @@ export { enc_tkt_in_skey : bool; ## The request is for a renewal renew : bool; - ## The request ist to validate a postdated ticket. + ## The request is to validate a postdated ticket. validate : bool; }; @@ -3045,6 +3020,33 @@ export { type KRB::Type_Value_Vector: vector of KRB::Type_Value; + ## The data from the ERROR_MSG message. See :rfc:`4120`. + type KRB::Error_Msg: record { + ## Protocol version number (5 for KRB5) + pvno : count; + ## The message type (30 for ERROR_MSG) + msg_type : count; + ## Current time on the client + client_time : time &optional; + ## Current time on the server + server_time : time; + ## The specific error code + error_code : count; + ## Realm of the ticket + client_realm : string &optional; + ## Name on the ticket + client_name : string &optional; + ## Realm of the service + service_realm : string; + ## Name of the service + service_name : string; + ## Additional text to explain the error + error_text : string &optional; + ## Optional pre-authentication data + pa_data : vector of KRB::Type_Value &optional; + }; + + ## A Kerberos ticket. See :rfc:`4120`. type KRB::Ticket: record { ## Protocol version number (5 for KRB5) @@ -3062,9 +3064,9 @@ export { ## A Kerberos host address See :rfc:`4120`. type KRB::Host_Address: record { ## IPv4 or IPv6 address - ip : addr &optional; + ip : addr &log &optional; ## NetBIOS address - netbios : string &optional; + netbios : string &log &optional; ## Some other type that we don't support yet unknown : KRB::Type_Value &optional; }; diff --git a/scripts/base/protocols/krb/dpd.sig b/scripts/base/protocols/krb/dpd.sig index d928f38b81..89c07309f6 100644 --- a/scripts/base/protocols/krb/dpd.sig +++ b/scripts/base/protocols/krb/dpd.sig @@ -1,5 +1,7 @@ -signature dpd_krb { +signature dpd_krb_udp { ip-proto == udp payload /\x6c...\x30...\xa1\x03\x02\x05/ enable "krb" } + + diff --git a/scripts/base/protocols/krb/main.bro b/scripts/base/protocols/krb/main.bro index 97c324e758..cc133e36d6 100644 --- a/scripts/base/protocols/krb/main.bro +++ b/scripts/base/protocols/krb/main.bro @@ -9,19 +9,36 @@ export { type Info: record { ## Timestamp for when the event happened. - ts: time &log; + ts: time &log; ## Unique ID for the connection. - uid: string &log; + uid: string &log; ## The connection's 4-tuple of endpoint addresses/ports. - id: conn_id &log; + id: conn_id &log; ## Client - client: string &log &optional; + client: string &log &optional; ## Service - service:string &log; + service: string &log; ## Ticket valid from - from: time &log &optional; + from: time &log &optional; ## Ticket valid till - till: time &log &optional; + till: time &log &optional; + ## Forwardable ticket requested + forwardable: bool &log &optional; + ## Proxiable ticket requested + proxiable: bool &log &optional; + ## Postdated ticket requested + postdated: bool &log &optional; + ## Renewable ticket requested + renewable: bool &log &optional; + ## The request is for a renewal + renew_request: bool &log &optional; + # The request is to validate a postdated ticket + validate_request: bool &log &optional; + # Network addresses supplied by the client + network_addrs: vector of addr &log &optional; + # NetBIOS addresses supplied by the client + netbios_addrs: vector of string &log &optional; + ## Result result: string &log &default="unknown"; ## Error code @@ -32,6 +49,19 @@ export { logged: bool &default=F; }; + ## The server response error texts which are *not* logged. + const ignored_errors: set[string] = { + # This will significantly increase the noisiness of the log. + # However, one attack is to iterate over principals, looking + # for ones that don't require preauth, and then performn + # an offline attack on that ticket. To detect that attack, + # log NEEDED_PREAUTH. + "NEEDED_PREAUTH", + # This is a more specific version of NEEDED_PREAUTH that's used + # by Winodws AD Kerberos. + "Need to use PA-ENC-TIMESTAMP/PA-PK-AS-REQ", + } &redef; + ## Event that can be handled to access the KRB record as it is sent on ## to the loggin framework. global log_krb: event(rec: Info); @@ -53,9 +83,16 @@ event krb_error(c: connection, msg: Error_Msg) { local info: Info; + if ( msg?$error_text && msg$error_text in ignored_errors ) + { + if ( c?$krb ) + delete c$krb; + return; + } + if ( c?$krb && c$krb$logged ) return; - + if ( c?$krb ) info = c$krb; @@ -94,16 +131,43 @@ event krb_as_req(c: connection, msg: KDC_Request) { if ( c?$krb && c$krb$logged ) return; - + local info: Info; info$ts = network_time(); info$uid = c$uid; info$id = c$id; + info$client = fmt("%s/%s", msg$client_name, msg$service_realm); info$service = msg$service_name; + if ( msg?$from ) info$from = msg$from; + + if ( msg?$host_addrs ) + { + for ( i in msg$host_addrs ) + { + if ( msg$host_addrs[i]?$ip ) + { + if ( ! info?$network_addrs ) + info$network_addrs = vector(); + info$network_addrs[|info$network_addrs|] = msg$host_addrs[i]$ip; + } + + if ( msg$host_addrs[i]?$netbios ) + { + if ( ! info?$netbios_addrs ) + info$netbios_addrs = vector(); + info$netbios_addrs[|info$netbios_addrs|] = msg$host_addrs[i]$netbios; + } + } + } + info$till = msg$till; + info$forwardable = msg$kdc_options$forwardable; + info$proxiable = msg$kdc_options$proxiable; + info$postdated = msg$kdc_options$postdated; + info$renewable = msg$kdc_options$renewable; c$krb = info; } diff --git a/src/analyzer/protocol/krb/KRB.cc b/src/analyzer/protocol/krb/KRB.cc index 9dad0bc6ab..dfd6353cfd 100644 --- a/src/analyzer/protocol/krb/KRB.cc +++ b/src/analyzer/protocol/krb/KRB.cc @@ -33,6 +33,7 @@ void KRB_Analyzer::DeliverPacket(int len, const u_char* data, bool orig, } catch ( const binpac::Exception& e ) { + printf("BinPAC Exception: %s\n", e.c_msg()); ProtocolViolation(e.c_msg()); } } diff --git a/src/analyzer/protocol/krb/krb-analyzer.pac b/src/analyzer/protocol/krb/krb-analyzer.pac index 9a6804abba..14cbcbe710 100644 --- a/src/analyzer/protocol/krb/krb-analyzer.pac +++ b/src/analyzer/protocol/krb/krb-analyzer.pac @@ -5,11 +5,12 @@ connection KRB_Conn(bro_analyzer: BroAnalyzer) { flow KRB_Flow(is_orig: bool) { datagram = KRB_PDU withcontext(connection, this); - }; %header{ Val* GetTimeFromAsn1(const KRB_Time* atime); +Val* GetTimeFromAsn1(StringVal* atime); + Val* GetStringFromPrincipalName(const KRB_Principal_Name* pname); Val* asn1_integer_to_val(const ASN1Encoding* i, TypeTag t); @@ -20,18 +21,26 @@ RecordVal* proc_krb_kdc_options(const KRB_KDC_Options* opts); %code{ Val* GetTimeFromAsn1(const KRB_Time* atime) + { + return GetTimeFromAsn1(bytestring_to_val(atime->time())); + } + +Val* GetTimeFromAsn1(StringVal* atime) { time_t lResult = 0; - char lBuffer[16]; + char lBuffer[17]; char* pBuffer = lBuffer; - size_t lTimeLength = atime->time().length(); - char * pString = (char *) atime->time().data(); - - if ( lTimeLength != 15 ) + size_t lTimeLength = atime->Len(); + char * pString = (char *) atime->Bytes(); + + if ( lTimeLength != 15 && lTimeLength != 17 ) return 0; + if (lTimeLength == 17 ) + pString = pString + 2; + memcpy(pBuffer, pString, 15); *(pBuffer+15) = '\0'; @@ -53,7 +62,7 @@ Val* GetTimeFromAsn1(const KRB_Time* atime) lResult = 0; return new Val(double(lResult), TYPE_TIME); -} + } Val* GetStringFromPrincipalName(const KRB_Principal_Name* pname) { @@ -102,7 +111,6 @@ refine connection KRB_Conn += { function proc_krb_kdc_req(msg: KRB_KDC_REQ): bool %{ - if ( ( binary_to_int64(${msg.msg_type.data.content}) == 10 ) && ! krb_as_req ) return false; @@ -126,9 +134,6 @@ refine connection KRB_Conn += { case 1: // will be generated as separate event break; - case 2: - // encrypted timestamp is unreadable - break; case 3: { RecordVal * type_val = new RecordVal(BifType::Record::KRB::Type_Value); @@ -139,17 +144,20 @@ refine connection KRB_Conn += { } default: { - RecordVal * type_val = new RecordVal(BifType::Record::KRB::Type_Value); - type_val->Assign(0, new Val(${msg.padata.padata_elems[i].data_type}, TYPE_COUNT)); - type_val->Assign(1, bytestring_to_val(${msg.padata.padata_elems[i].pa_data_element.unknown})); - padata->Assign(padata->Size(), type_val); + if ( ${msg.padata.padata_elems[i].pa_data_element.unknown}.length() ) + { + RecordVal * type_val = new RecordVal(BifType::Record::KRB::Type_Value); + type_val->Assign(0, new Val(${msg.padata.padata_elems[i].data_type}, TYPE_COUNT)); + type_val->Assign(1, bytestring_to_val(${msg.padata.padata_elems[i].pa_data_element.unknown})); + padata->Assign(padata->Size(), type_val); + } break; } } } rv->Assign(2, padata); } - + for ( uint i = 0; i < ${msg.body.args}->size(); ++i ) { switch ( ${msg.body.args[i].seq_meta.index} ) @@ -197,7 +205,7 @@ refine connection KRB_Conn += { for ( uint j = 0; j < ${msg.body.args[i].data.addrs.addresses}->size(); ++j ) { RecordVal* addr = new RecordVal(BifType::Record::KRB::Host_Address); - switch ( binary_to_int64(${msg.body.args[i].data.addrs.addresses[j].addr_type.data.content}) ) + switch ( binary_to_int64(${msg.body.args[i].data.addrs.addresses[j].addr_type.encoding.content}) ) { case 2: addr->Assign(0, new AddrVal(IPAddr(IPv4, (const uint32_t*) c_str(${msg.body.args[i].data.addrs.addresses[j].address.data.content}), IPAddr::Network))); @@ -210,7 +218,7 @@ refine connection KRB_Conn += { break; default: RecordVal* unk = new RecordVal(BifType::Record::KRB::Type_Value); - unk->Assign(0, asn1_integer_to_val(${msg.body.args[i].data.addrs.addresses[j].addr_type.data}, TYPE_COUNT)); + unk->Assign(0, asn1_integer_to_val(${msg.body.args[i].data.addrs.addresses[j].addr_type}, TYPE_COUNT)); unk->Assign(1, bytestring_to_val(${msg.body.args[i].data.addrs.addresses[j].address.data.content})); addr->Assign(2, unk); break; @@ -344,31 +352,23 @@ refine connection KRB_Conn += { if ( krb_error ) { RecordVal* rv = new RecordVal(BifType::Record::KRB::Error_Msg); + rv->Assign(0, asn1_integer_to_val(${msg.pvno.data}, TYPE_COUNT)); + rv->Assign(1, asn1_integer_to_val(${msg.msg_type.data}, TYPE_COUNT)); + if ( ${msg.has_ctime} ) + rv->Assign(2, GetTimeFromAsn1(bytestring_to_val(${msg.ctime}))); + + // TODO: if ( ${msg.has_cusec} ) + + rv->Assign(3, GetTimeFromAsn1(bytestring_to_val(${msg.stime}))); + // TODO: ${msg.susec} + + + rv->Assign(4, asn1_integer_to_val(${msg.error_code.data}, TYPE_COUNT)); + for ( uint i = 0; i < ${msg.args}->size(); i++ ) { switch ( ${msg.args[i].seq_meta.index} ) { - case 0: - rv->Assign(0, asn1_integer_to_val(${msg.args[i].args.pvno}, TYPE_COUNT)); - break; - case 1: - rv->Assign(1, asn1_integer_to_val(${msg.args[i].args.msg_type}, TYPE_COUNT)); - break; - case 2: - rv->Assign(2, GetTimeFromAsn1(${msg.args[i].args.ctime})); - break; - case 3: -// TODO - break; - case 4: - rv->Assign(3, GetTimeFromAsn1(${msg.args[i].args.stime})); - break; - case 5: -// TODO - break; - case 6: - rv->Assign(4, asn1_integer_to_val(${msg.args[i].args.error_code}, TYPE_COUNT)); - break; case 7: rv->Assign(5, bytestring_to_val(${msg.args[i].args.crealm.encoding.content})); break; @@ -384,6 +384,42 @@ refine connection KRB_Conn += { case 11: rv->Assign(9, bytestring_to_val(${msg.args[i].args.e_text.encoding.content})); break; + case 12: + if ( ${msg.error_code.data.content}[0] == 25 ) + { + VectorVal* padata = new VectorVal(internal_type("KRB::Type_Value_Vector")->AsVectorType()); + + for ( uint j = 0; j < ${msg.args[i].args.e_data.padata.padata_elems}->size(); ++j) + { + switch( ${msg.args[i].args.e_data.padata.padata_elems[j].data_type} ) + { + case 1: + // will be generated as separate event + break; + case 3: + { + RecordVal * type_val = new RecordVal(BifType::Record::KRB::Type_Value); + type_val->Assign(0, new Val(${msg.args[i].args.e_data.padata.padata_elems[j].data_type}, TYPE_COUNT)); + type_val->Assign(1, bytestring_to_val(${msg.args[i].args.e_data.padata.padata_elems[j].pa_data_element.pa_pw_salt.encoding.content})); + padata->Assign(padata->Size(), type_val); + break; + } + default: + { + if ( ${msg.args[i].args.e_data.padata.padata_elems[j].pa_data_element.unknown}.length() ) + { + RecordVal * type_val = new RecordVal(BifType::Record::KRB::Type_Value); + type_val->Assign(0, new Val(${msg.args[i].args.e_data.padata.padata_elems[j].data_type}, TYPE_COUNT)); + type_val->Assign(1, bytestring_to_val(${msg.args[i].args.e_data.padata.padata_elems[j].pa_data_element.unknown})); + padata->Assign(padata->Size(), type_val); + } + break; + } + } + } + rv->Assign(10, padata); + } + break; default: break; } @@ -410,13 +446,24 @@ refine connection KRB_Conn += { // Not implemented return true; %} - + + function debug_req_arg(msg: KRB_REQ_Arg_Data): bool + %{ + printf("KRB_REQ_Arg index=%d\n", ${msg.index}); + return true; + %} + + function debug_asn1_encoding_meta(msg: ASN1EncodingMeta): bool + %{ + printf("ASN1 Element tag=%x, length=%d\n", ${msg.tag}, ${msg.length}); + return true; + %} } refine typeattr KRB_AS_REQ += &let { proc: bool = $context.connection.proc_krb_kdc_req(data); - }; +}; refine typeattr KRB_TGS_REQ += &let { proc: bool = $context.connection.proc_krb_kdc_req(data); @@ -454,3 +501,10 @@ refine typeattr KRB_CRED_MSG += &let { proc: bool = $context.connection.proc_krb_cred_msg(this); }; +#refine typeattr KRB_REQ_Arg_Data += &let { +# proc: bool = $context.connection.debug_req_arg(this); +#}; + +#refine typeattr ASN1EncodingMeta += &let { +# proc: bool = $context.connection.debug_asn1_encoding_meta(this); +#}; \ No newline at end of file diff --git a/src/analyzer/protocol/krb/krb-asn1.pac b/src/analyzer/protocol/krb/krb-asn1.pac index e5e2cd3ece..38e69dd4f7 100644 --- a/src/analyzer/protocol/krb/krb-asn1.pac +++ b/src/analyzer/protocol/krb/krb-asn1.pac @@ -4,13 +4,14 @@ type ASN1Encoding = record { }; type ASN1EncodingMeta = record { - tag: uint8; - len: uint8; - more_len: bytestring &length = long_len ? len & 0x7f : 0; + tag: uint8; + len: uint8; + more_len: bytestring &length = long_len ? (len & 0x7f) : 0; } &let { - long_len: bool = len & 0x80; - length: uint64 = long_len ? binary_to_int64(more_len) : len & 0x7f; - index: uint8 = tag - 160; + long_len: bool = (len & 0x80) > 0; + length: uint64 = long_len ? binary_to_int64(more_len) : len; + has_index: bool = (tag >= 160); + index: uint8 = tag - 160; }; type ASN1Integer = record { diff --git a/src/analyzer/protocol/krb/krb-protocol.pac b/src/analyzer/protocol/krb/krb-protocol.pac index 1741443b50..2ba591168b 100644 --- a/src/analyzer/protocol/krb/krb-protocol.pac +++ b/src/analyzer/protocol/krb/krb-protocol.pac @@ -55,7 +55,7 @@ type KRB_KDC_REQ = record { padata_meta: ASN1EncodingMeta; tmp1 : case has_padata of { true -> padata : KRB_PA_Data_Sequence &length=padata_meta.length; - false -> n1 : empty; + false -> n1 : empty; }; tmp2 : case has_padata of { true -> meta2 : ASN1EncodingMeta; @@ -64,7 +64,7 @@ type KRB_KDC_REQ = record { body : KRB_REQ_Body &length=body_length; } &let { has_padata : bool = padata_meta.index == 3; - body_length: uint8 = has_padata ? meta2.length : padata_meta.length; + body_length: uint64 = has_padata ? meta2.length : padata_meta.length; }; type KRB_PA_Data_Sequence = record { @@ -73,19 +73,18 @@ type KRB_PA_Data_Sequence = record { }; type KRB_PA_Data = record { - seq_meta : ASN1EncodingMeta; + seq_meta : ASN1EncodingMeta; pa_data_type : SequenceElement(true); pa_data_elem_meta : ASN1EncodingMeta; - pa_data_element : KRB_PA_Data_Element(data_type); + pa_data_element : KRB_PA_Data_Element(data_type, pa_data_elem_meta.length); } &let { data_type: int64 = binary_to_int64(pa_data_type.data.content); }; -type KRB_PA_Data_Element(type: int64) = case type of { +type KRB_PA_Data_Element(type: int64, length: uint64) = case type of { 1 -> pa_tgs_req : KRB_AP_REQ; - 2 -> pa_enc_timestamp : KRB_Encrypted_Data; 3 -> pa_pw_salt : ASN1OctetString; - default -> unknown : bytestring &restofdata; + default -> unknown : bytestring &length=length; }; type KRB_REQ_Body = record { @@ -99,47 +98,48 @@ type KRB_REQ_Arg = record { }; type KRB_REQ_Arg_Data(index: uint8) = case index of { - 0 -> options : KRB_KDC_Options; - 1 -> principal : KRB_Principal_Name; - 2 -> realm : ASN1OctetString; - 3 -> sname : KRB_Principal_Name; - 4 -> from : KRB_Time; - 5 -> till : KRB_Time; - 6 -> rtime : KRB_Time; - 7 -> nonce : ASN1Integer; - 8 -> etype : Array; - 9 -> addrs : KRB_Host_Addresses; - 10 -> auth_data : ASN1OctetString; # TODO - 11 -> addl_tkts : KRB_Ticket_Sequence; + 0 -> options : KRB_KDC_Options; + 1 -> principal : KRB_Principal_Name; + 2 -> realm : ASN1OctetString; + 3 -> sname : KRB_Principal_Name; + 4 -> from : KRB_Time; + 5 -> till : KRB_Time; + 6 -> rtime : KRB_Time; + 7 -> nonce : ASN1Integer; + 8 -> etype : Array; + 9 -> addrs : KRB_Host_Addresses; + 10 -> auth_data : ASN1OctetString; # TODO + 11 -> addl_tkts : KRB_Ticket_Sequence; default -> unknown : bytestring &restofdata; }; type KRB_KDC_Options = record { meta : ASN1EncodingMeta; + pad: uint8; flags: uint32; } &let { - reserved : bool = flags & 0x80000000; - forwardable : bool = flags & 0x40000000; - forwarded : bool = flags & 0x20000000; - proxiable : bool = flags & 0x10000000; - proxy : bool = flags & 0x8000000; - allow_postdate : bool = flags & 0x4000000; - postdated : bool = flags & 0x2000000; - unused7 : bool = flags & 0x1000000; - renewable : bool = flags & 0x800000; - unused9 : bool = flags & 0x400000; - unused10 : bool = flags & 0x200000; - opt_hardware_auth : bool = flags & 0x100000; - unused12 : bool = flags & 0x80000; - unused13 : bool = flags & 0x40000; + reserved : bool = (flags & 0x80000000) > 0; + forwardable : bool = (flags & 0x40000000) > 0; + forwarded : bool = (flags & 0x20000000) > 0; + proxiable : bool = (flags & 0x10000000) > 0; + proxy : bool = (flags & 0x8000000) > 0; + allow_postdate : bool = (flags & 0x4000000) > 0; + postdated : bool = (flags & 0x2000000) > 0; + unused7 : bool = (flags & 0x1000000) > 0; + renewable : bool = (flags & 0x800000) > 0; + unused9 : bool = (flags & 0x400000) > 0; + unused10 : bool = (flags & 0x200000) > 0; + opt_hardware_auth : bool = (flags & 0x100000) > 0; + unused12 : bool = (flags & 0x80000) > 0; + unused13 : bool = (flags & 0x40000) > 0; # ... - unused15 : bool = flags & 0x10000; + unused15 : bool = (flags & 0x10000) > 0; # ... - disable_transited_check : bool = flags & 0x10; - renewable_ok : bool = flags & 0x8; - enc_tkt_in_skey : bool = flags & 0x4; - renew : bool = flags & 0x2; - validate : bool = flags & 0x1; + disable_transited_check : bool = (flags & 0x10) > 0; + renewable_ok : bool = (flags & 0x8) > 0; + enc_tkt_in_skey : bool = (flags & 0x4) > 0; + renew : bool = (flags & 0x2) > 0; + validate : bool = (flags & 0x1) > 0; }; type KRB_Principal_Name = record { @@ -148,7 +148,7 @@ type KRB_Principal_Name = record { name_type : ASN1Integer; seq_meta_1: ASN1EncodingMeta; seq_meta_2: ASN1EncodingMeta; - data : ASN1OctetString[] &length=seq_meta_2.length; + data : ASN1OctetString[]; }; type KRB_Time = record { @@ -162,12 +162,13 @@ type KRB_Host_Addresses = record { }; type KRB_Host_Address = record { - addr_type: SequenceElement(true); - address : SequenceElement(true); + addr_type_meta : SequenceElement(false); + addr_type : ASN1Integer; + address : SequenceElement(true); }; type KRB_Ticket(in_sequence: bool) = record { - have_seq : case in_sequence of { + have_seq : case in_sequence of { true -> meta: ASN1EncodingMeta; false -> none: empty; }; @@ -176,7 +177,7 @@ type KRB_Ticket(in_sequence: bool) = record { tkt_vno : SequenceElement(true); realm : SequenceElement(true); sname_meta: ASN1EncodingMeta; - sname : KRB_Principal_Name; + sname : KRB_Principal_Name &length=sname_meta.length; enc_part : KRB_Encrypted_Data; }; @@ -187,7 +188,7 @@ type KRB_Ticket_Sequence = record { type KRB_Encrypted_Data_in_Seq = record { index_meta : ASN1EncodingMeta; - data : KRB_Encrypted_Data; + data : KRB_Encrypted_Data &length=index_meta.length; }; type KRB_Encrypted_Data = record { @@ -223,12 +224,13 @@ type KRB_KDC_REP = record { false -> n2 : empty; }; client_realm: ASN1OctetString &length=realm_length; - client_name : KRB_Principal_Name; + cname_meta : ASN1EncodingMeta; + client_name : KRB_Principal_Name &length=cname_meta.length; ticket : KRB_Ticket(true); enc_part : KRB_Encrypted_Data_in_Seq; } &let { has_padata : bool = padata_meta.index == 2; - realm_length: uint8 = has_padata ? meta2.length : padata_meta.length; + realm_length: uint64 = has_padata ? meta2.length : padata_meta.length; }; ### AP_REQ @@ -249,9 +251,9 @@ type KRB_AP_Options = record { flags : uint32; : padding[1]; } &let { - reserved : bool = flags & 0x80000000; - use_session_key : bool = flags & 0x40000000; - mutual_required : bool = flags & 0x20000000; + reserved : bool = (flags & 0x80000000) > 0; + use_session_key : bool = (flags & 0x40000000) > 0; + mutual_required : bool = (flags & 0x20000000) > 0; }; @@ -265,30 +267,73 @@ type KRB_AP_REP = record { ### KRB_ERROR +# 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, + type KRB_ERROR_MSG = record { - seq_meta: ASN1EncodingMeta; - args : KRB_ERROR_Arg[]; + seq_meta : ASN1EncodingMeta; + pvno : SequenceElement(true); + msg_type : SequenceElement(true); + ctime_meta : ASN1EncodingMeta; + tmp1 : case has_ctime of { + true -> ctime : bytestring &length=ctime_meta.length; + false -> n1 : empty; + }; + tmp2 : case has_ctime of { + true -> cusec_meta : ASN1EncodingMeta; + false -> n2 : empty; + }; + tmp3 : case has_cusec of { + true -> cusec : ASN1Integer; + false -> n3 : empty; + }; + tmp4 : case has_cusec of { + true -> stime_meta : ASN1EncodingMeta; + false -> n4 : empty; + }; + stime : bytestring &length=stime_length; + susec : SequenceElement(true); + error_code : SequenceElement(true); + args : KRB_ERROR_Arg(binary_to_int64(error_code.data.content))[]; +} &let { + has_ctime: bool = ctime_meta.index == 2; + has_cusec: bool = has_ctime ? cusec_meta.index == 3 : ctime_meta.index == 3; + stime_length: uint64 = has_ctime ? (has_cusec ? stime_meta.length : cusec_meta.length) : (has_cusec ? stime_meta.length : ctime_meta.length); }; -type KRB_ERROR_Arg = record { +type KRB_ERROR_Arg(error_code: uint64) = record { seq_meta: ASN1EncodingMeta; - args : KRB_ERROR_Arg_Data(seq_meta.index) &length=seq_meta.length; + args : KRB_ERROR_Arg_Data(seq_meta.index, error_code) &length=seq_meta.length; }; -type KRB_ERROR_Arg_Data(index: uint8) = case index of { - 0 -> pvno : ASN1Integer; - 1 -> msg_type : ASN1Integer; - 2 -> ctime : KRB_Time; - 3 -> cusec : ASN1Integer; - 4 -> stime : KRB_Time; - 5 -> susec : ASN1Integer; - 6 -> error_code : ASN1Integer; +type KRB_ERROR_Arg_Data(index: uint8, error_code: uint64) = case index of { 7 -> crealm : ASN1OctetString; - 8 -> cname : KRB_Principal_Name; - 9 -> realm : ASN1OctetString; - 10 -> sname : KRB_Principal_Name; + 8 -> cname : KRB_Principal_Name; + 9 -> realm : ASN1OctetString; + 10 -> sname : KRB_Principal_Name; 11 -> e_text : ASN1OctetString; - 12 -> e_data : ASN1OctetString; + 12 -> e_data : KRB_ERROR_PA_Data(error_code); +}; + +type KRB_ERROR_PA_Data(error_code: uint64) = record { + have_padata1: case ( error_code == 25 ) of { + true -> meta1 : ASN1EncodingMeta; + false -> data : ASN1OctetString; + }; + have_padata2: case ( error_code == 25 ) of { + true -> padata : KRB_PA_Data_Sequence; + false -> n1 : empty; + }; }; ### KRB_SAFE @@ -313,7 +358,7 @@ type KRB_SAFE_Arg = record { type KRB_SAFE_Arg_Data(index: uint8) = case index of { 0 -> user_data : ASN1OctetString; 1 -> timestamp : KRB_Time; - 2 -> usec : ASN1Integer; + 2 -> usec : ASN1Integer; 3 -> seq_number : ASN1Integer; 4 -> sender_addr: KRB_Host_Address; 5 -> recp_addr : KRB_Host_Address;