CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/lib/rex/proto/kerberos/model/kdc_request_body.rb
Views: 11766
1
# -*- coding: binary -*-
2
3
module Rex
4
module Proto
5
module Kerberos
6
module Model
7
# This class provides a representation of a Kerberos KDC-REQ-BODY (request body) data
8
# definition
9
# https://datatracker.ietf.org/doc/html/rfc4120#section-5.4.1
10
# KDC-REQ-BODY ::= SEQUENCE {
11
# kdc-options [0] KDCOptions,
12
# cname [1] PrincipalName OPTIONAL
13
# -- Used only in AS-REQ --,
14
# realm [2] Realm
15
# -- Server's realm
16
# -- Also client's in AS-REQ --,
17
# sname [3] PrincipalName OPTIONAL,
18
# from [4] KerberosTime OPTIONAL,
19
# till [5] KerberosTime,
20
# rtime [6] KerberosTime OPTIONAL,
21
# nonce [7] UInt32,
22
# etype [8] SEQUENCE OF Int32 -- EncryptionType
23
# -- in preference order --,
24
# addresses [9] HostAddresses OPTIONAL,
25
# enc-authorization-data [10] EncryptedData OPTIONAL
26
# -- AuthorizationData --,
27
# additional-tickets [11] SEQUENCE OF Ticket OPTIONAL
28
# -- NOTE: not empty
29
# }
30
class KdcRequestBody < Element
31
# @!attribute options
32
# @return [Integer] The ticket flags
33
attr_accessor :options
34
# @!attribute cname
35
# @return [Rex::Proto::Kerberos::Model::PrincipalName] The name part of the client's principal identifier
36
attr_accessor :cname
37
# @!attribute realm
38
# @return [String] The realm part of the server's principal identifier
39
attr_accessor :realm
40
# @!attribute sname
41
# @return [Rex::Proto::Kerberos::Model::PrincipalName] The name part of the server's identity
42
attr_accessor :sname
43
# @!attribute from
44
# @return [Time] Start time when the ticket is to be postdated
45
attr_accessor :from
46
# @!attribute till
47
# @return [Time] Expiration date requested by the client
48
attr_accessor :till
49
# @!attribute rtime
50
# @return [Time] Optional requested renew-till time
51
attr_accessor :rtime
52
# @!attribute nonce
53
# @return [Integer] random number
54
attr_accessor :nonce
55
# @!attribute addresses
56
# @return [Array<Rex::Proto::Kerberos::Model::HostAddress>,nil] A list of addresses from which the requested ticket is valid
57
attr_accessor :addresses
58
# @!attribute etype
59
# @return [Array<Integer>] The desired encryption algorithm to be used in the response
60
attr_accessor :etype
61
# @!attribute enc_auth_data
62
# @return [Rex::Proto::Kerberos::Model::EncryptedData] An encoding of the desired authorization-data encrypted
63
attr_accessor :enc_auth_data
64
# @!attribute additional_tickets
65
# @return [Array<Rex::Proto::Kerberos::Model::EncryptedData>] Additional tickets
66
attr_accessor :additional_tickets
67
68
# Decodes the Rex::Proto::Kerberos::Model::KdcRequestBody attributes from input
69
#
70
# @param input [String, OpenSSL::ASN1::Sequence] the input to decode from
71
# @return [self] if decoding succeeds
72
# @raise [Rex::Proto::Kerberos::Model::Error::KerberosDecodingError] if decoding doesn't succeed
73
def decode(input)
74
case input
75
when String
76
decode_string(input)
77
when OpenSSL::ASN1::Sequence
78
decode_asn1(input)
79
else
80
raise ::Rex::Proto::Kerberos::Model::Error::KerberosDecodingError, 'Failed to decode KdcRequestBody, invalid input'
81
end
82
83
self
84
end
85
86
# Encodes the Rex::Proto::Kerberos::Model::KdcRequestBody into an ASN.1 String
87
#
88
# @return [String]
89
def encode
90
elems = []
91
92
elems << OpenSSL::ASN1::ASN1Data.new([encode_options], 0, :CONTEXT_SPECIFIC) if options
93
elems << OpenSSL::ASN1::ASN1Data.new([encode_cname], 1, :CONTEXT_SPECIFIC) if cname
94
elems << OpenSSL::ASN1::ASN1Data.new([encode_realm], 2, :CONTEXT_SPECIFIC) if realm
95
elems << OpenSSL::ASN1::ASN1Data.new([encode_sname], 3, :CONTEXT_SPECIFIC) if sname
96
elems << OpenSSL::ASN1::ASN1Data.new([encode_from], 4, :CONTEXT_SPECIFIC) if from
97
elems << OpenSSL::ASN1::ASN1Data.new([encode_till], 5, :CONTEXT_SPECIFIC) if till
98
elems << OpenSSL::ASN1::ASN1Data.new([encode_rtime], 6, :CONTEXT_SPECIFIC) if rtime
99
elems << OpenSSL::ASN1::ASN1Data.new([encode_nonce], 7, :CONTEXT_SPECIFIC) if nonce
100
elems << OpenSSL::ASN1::ASN1Data.new([encode_etype], 8, :CONTEXT_SPECIFIC) if etype
101
elems << OpenSSL::ASN1::ASN1Data.new([encode_addresses], 9, :CONTEXT_SPECIFIC) if addresses&.any?
102
elems << OpenSSL::ASN1::ASN1Data.new([encode_enc_auth_data], 10, :CONTEXT_SPECIFIC) if enc_auth_data
103
elems << OpenSSL::ASN1::ASN1Data.new([encode_additional_tickets], 11, :CONTEXT_SPECIFIC) if additional_tickets
104
105
seq = OpenSSL::ASN1::Sequence.new(elems)
106
107
seq.to_der
108
end
109
110
# Makes a checksum from the Rex::Proto::Kerberos::Model::KdcRequestBody
111
#
112
# @param etype [Integer] the crypto schema to checksum
113
# @param key [String] the key used as the HMAC secret (applicable to most but not all checksum algorithms)
114
# @return [String] the checksum
115
# @raise [NotImplementedError] if the encryption schema isn't supported
116
def checksum(etype, key, key_usage)
117
data = self.encode
118
checksummer = Rex::Proto::Kerberos::Crypto::Checksum::from_checksum_type(etype)
119
checksummer.checksum(key, key_usage, data)
120
end
121
122
private
123
124
# Encodes the options
125
#
126
# @return [OpenSSL::ASN1::BitString]
127
def encode_options
128
OpenSSL::ASN1::BitString.new([options.to_i].pack('N'))
129
end
130
131
# Encodes the cname
132
#
133
# @return [String]
134
def encode_cname
135
cname.encode
136
end
137
138
# Encodes the realm
139
#
140
# @return [OpenSSL::ASN1::GeneralString]
141
def encode_realm
142
OpenSSL::ASN1::GeneralString.new(realm)
143
end
144
145
# Encodes the sname
146
#
147
# @return [String]
148
def encode_sname
149
sname.encode
150
end
151
152
# Encodes the from
153
#
154
# @return [OpenSSL::ASN1::GeneralizedTime]
155
def encode_from
156
OpenSSL::ASN1::GeneralizedTime.new(from)
157
end
158
159
# Encodes the till
160
#
161
# @return [OpenSSL::ASN1::GeneralizedTime]
162
def encode_till
163
OpenSSL::ASN1::GeneralizedTime.new(till)
164
end
165
166
# Encodes the rtime
167
#
168
# @return [OpenSSL::ASN1::GeneralizedTime]
169
def encode_rtime
170
OpenSSL::ASN1::GeneralizedTime.new(rtime)
171
end
172
173
# Encodes the nonce
174
#
175
# @return [OpenSSL::ASN1::Integer]
176
def encode_nonce
177
bn = OpenSSL::BN.new(nonce.to_s)
178
int = OpenSSL::ASN1::Integer.new(bn)
179
180
int
181
end
182
183
# Encodes the etype
184
#
185
# @return [OpenSSL::ASN1::Sequence]
186
def encode_etype
187
encoded_types = []
188
etype.each do |member|
189
bn = OpenSSL::BN.new(member.to_s)
190
int = OpenSSL::ASN1::Integer.new(bn)
191
encoded_types << int
192
end
193
194
OpenSSL::ASN1::Sequence.new(encoded_types)
195
end
196
197
# Encodes the list of addresses from which the requested ticket is valid
198
#
199
# @return [OpenSSL::ASN1::Sequence]
200
def encode_addresses
201
encoded_addresses = []
202
203
addresses.each do |address|
204
encoded_addresses << address.to_asn1
205
end
206
207
OpenSSL::ASN1::Sequence.new(encoded_addresses)
208
end
209
210
# Encodes the enc_auth_data
211
#
212
# @return [String]
213
def encode_enc_auth_data
214
enc_auth_data.encode
215
end
216
217
# Encodes the additional_tickets
218
#
219
# @return [OpenSSL::ASN1::Sequence]
220
def encode_additional_tickets
221
encoded_tickets = []
222
additional_tickets.each do |ticket|
223
encoded_tickets << ticket.encode
224
end
225
226
OpenSSL::ASN1::Sequence.new(encoded_tickets)
227
end
228
229
# Decodes a Rex::Proto::Kerberos::Model::KdcRequestBody from an String
230
#
231
# @param input [String] the input to decode from
232
# @raise [Rex::Proto::Kerberos::Model::Error::KerberosDecodingError] if decoding doesn't succeed
233
def decode_string(input)
234
asn1 = OpenSSL::ASN1.decode(input)
235
236
decode_asn1(asn1)
237
rescue OpenSSL::ASN1::ASN1Error
238
raise Rex::Proto::Kerberos::Model::Error::KerberosDecodingError
239
end
240
241
# Decodes a Rex::Proto::Kerberos::Model::KdcRequestBody from an
242
# OpenSSL::ASN1::Sequence
243
#
244
# @param input [OpenSSL::ASN1::Sequence] the input to decode from
245
# @raise [Rex::Proto::Kerberos::Model::Error::KerberosDecodingError] if decoding doesn't succeed
246
def decode_asn1(input)
247
seq_values = input.value
248
249
seq_values.each do |val|
250
case val.tag
251
when 0
252
self.options = decode_options(val)
253
when 1
254
self.cname = decode_cname(val)
255
when 2
256
self.realm = decode_realm(val)
257
when 3
258
self.sname = decode_sname(val)
259
when 4
260
self.from = decode_from(val)
261
when 5
262
self.till = decode_till(val)
263
when 6
264
self.rtime = decode_rtime(val)
265
when 7
266
self.nonce = decode_nonce(val)
267
when 8
268
self.etype = decode_etype(val)
269
when 9
270
self.addresses = decode_addresses(val)
271
when 10
272
self.enc_auth_data = decode_enc_auth_data(val)
273
when 11
274
self.additional_tickets = decode_additional_tickets(val)
275
else
276
raise ::Rex::Proto::Kerberos::Model::Error::KerberosDecodingError, 'Failed to decode KdcRequestBody SEQUENCE'
277
end
278
end
279
end
280
281
# Decodes the options field
282
#
283
# @param input [OpenSSL::ASN1::ASN1Data] the input to decode from
284
# @return [Integer]
285
def decode_options(input)
286
input.value[0].value.unpack('N')[0]
287
end
288
289
# Decodes the cname field
290
#
291
# @param input [OpenSSL::ASN1::ASN1Data] the input to decode from
292
# @return [Rex::Proto::Kerberos::Model::PrincipalName]
293
def decode_cname(input)
294
Rex::Proto::Kerberos::Model::PrincipalName.decode(input.value[0])
295
end
296
297
# Decodes the realm field
298
#
299
# @param input [OpenSSL::ASN1::ASN1Data] the input to decode from
300
# @return [String]
301
def decode_realm(input)
302
input.value[0].value
303
end
304
305
# Decodes the sname field
306
#
307
# @param input [OpenSSL::ASN1::ASN1Data] the input to decode from
308
# @return [Rex::Proto::Kerberos::Model::PrincipalName]
309
def decode_sname(input)
310
Rex::Proto::Kerberos::Model::PrincipalName.decode(input.value[0])
311
end
312
313
# Decodes the from field
314
#
315
# @param input [OpenSSL::ASN1::ASN1Data] the input to decode from
316
# @return [Time]
317
def decode_from(input)
318
input.value[0].value
319
end
320
321
# Decodes the till field
322
#
323
# @param input [OpenSSL::ASN1::ASN1Data] the input to decode from
324
# @return [Time]
325
def decode_till(input)
326
input.value[0].value
327
end
328
329
# Decodes the rtime field
330
#
331
# @param input [OpenSSL::ASN1::ASN1Data] the input to decode from
332
# @return [Time]
333
def decode_rtime(input)
334
input.value[0].value
335
end
336
337
# Decodes the nonce field
338
#
339
# @param input [OpenSSL::ASN1::ASN1Data] the input to decode from
340
# @return [Integer]
341
def decode_nonce(input)
342
input.value[0].value.to_i
343
end
344
345
# Decodes the etype field
346
#
347
# @param input [OpenSSL::ASN1::ASN1Data] the input to decode from
348
# @return [Array<Integer>]
349
def decode_etype(input)
350
encs = []
351
input.value[0].value.each do |enc|
352
encs << enc.value.to_i
353
end
354
encs
355
end
356
357
# Decodes the hostaddresses field
358
#
359
# @param input [OpenSSL::ASN1::ASN1Data] the input to decode from
360
# @return [Array<Rex::Proto::Model::HostAddress>]
361
def decode_addresses(input)
362
caddr = []
363
input.value[0].value.each do |host_address_data|
364
caddr << Rex::Proto::Kerberos::Model::HostAddress.decode(host_address_data)
365
end
366
caddr
367
end
368
369
# Decodes the enc_auth_data field
370
#
371
# @param input [OpenSSL::ASN1::ASN1Data] the input to decode from
372
# @return [Rex::Proto::Kerberos::Model::EncryptedData]
373
def decode_enc_auth_data(input)
374
Rex::Proto::Kerberos::Model::EncryptedData.decode(input.value[0])
375
end
376
377
# Decodes the additional_tickets field
378
#
379
# @param input [OpenSSL::ASN1::ASN1Data] the input to decode from
380
# @return [Array<Rex::Proto::Kerberos::Model::EncryptedData>]
381
def decode_additional_tickets(input)
382
encs = []
383
input.value[0].value.each do |enc_ticket|
384
encs << enc_ticket.decode
385
end
386
encs
387
end
388
389
end
390
end
391
end
392
end
393
end
394
395