packetgen-plugin-ipsec 1.0.3 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/specs.yml +7 -3
- data/.rubocop.yml +24 -6
- data/Gemfile +13 -6
- data/README.md +12 -6
- data/lib/packetgen/plugin/crypto.rb +32 -0
- data/lib/packetgen/plugin/esp.rb +162 -133
- data/lib/packetgen/plugin/ike/auth.rb +52 -39
- data/lib/packetgen/plugin/ike/cert.rb +1 -1
- data/lib/packetgen/plugin/ike/certreq.rb +1 -1
- data/lib/packetgen/plugin/ike/id.rb +7 -8
- data/lib/packetgen/plugin/ike/ke.rb +6 -5
- data/lib/packetgen/plugin/ike/nonce.rb +1 -1
- data/lib/packetgen/plugin/ike/notify.rb +12 -13
- data/lib/packetgen/plugin/ike/payload.rb +30 -32
- data/lib/packetgen/plugin/ike/sa.rb +41 -41
- data/lib/packetgen/plugin/ike/sk.rb +76 -74
- data/lib/packetgen/plugin/ike/ts.rb +20 -17
- data/lib/packetgen/plugin/ike/vendor_id.rb +1 -1
- data/lib/packetgen/plugin/ike.rb +37 -42
- data/lib/packetgen/plugin/ipsec_version.rb +1 -1
- data/lib/packetgen-plugin-ipsec.rb +2 -0
- data/packetgen-plugin-ipsec.gemspec +5 -4
- metadata +10 -18
- data/.travis.yml +0 -14
@@ -53,11 +53,11 @@ module PacketGen::Plugin
|
|
53
53
|
# @attribute [r] auth_method
|
54
54
|
# 8-bit Auth Method
|
55
55
|
# @return [Integer]
|
56
|
-
|
56
|
+
define_attr_before :content, :auth_method, BinStruct::Int8Enum, enum: METHODS
|
57
57
|
# @attribute reserved
|
58
58
|
# 24-bit reserved field
|
59
59
|
# @return [Integer]
|
60
|
-
|
60
|
+
define_attr_before :content, :reserved, BinStruct::Int24
|
61
61
|
|
62
62
|
# Check authentication (see RFC 7296 §2.15)
|
63
63
|
# @param [Packet] init_msg first IKE message sent by peer
|
@@ -73,49 +73,17 @@ module PacketGen::Plugin
|
|
73
73
|
# supported.
|
74
74
|
# @note For certificates, only check AUTH authenticity with given (or guessed
|
75
75
|
# from packet) certificate, but certificate chain is not verified.
|
76
|
-
def check?(init_msg: nil, nonce: '', sk_p: '', prf: 1, shared_secret: '',
|
76
|
+
def check?(init_msg: nil, nonce: '', sk_p: '', prf: 1, shared_secret: '', # rubocop:disable Metrics/ParameterLists
|
77
77
|
cert: nil)
|
78
78
|
raise TypeError, 'init_msg should be a Packet' unless init_msg.is_a?(PacketGen::Packet)
|
79
79
|
|
80
|
-
signed_octets = init_msg
|
81
|
-
signed_octets << nonce
|
82
|
-
id = packet.ike.flag_i? ? packet.ike_idi : packet.ike_idr
|
83
|
-
signed_octets << prf(prf, sk_p, id.to_s[4, id.length - 4])
|
84
|
-
|
80
|
+
signed_octets = build_signed_octets(init_msg, nonce, sk_p, prf)
|
85
81
|
case auth_method
|
86
82
|
when METHODS['SHARED_KEY']
|
87
|
-
|
88
|
-
auth == content
|
83
|
+
check_shared_key?(shared_secret, signed_octets)
|
89
84
|
when METHODS['RSA_SIGNATURE'], METHODS['ECDSA256'], METHODS['ECDSA384'],
|
90
85
|
METHODS['ECDSA512']
|
91
|
-
|
92
|
-
# FIXME: Expect a ENCODING_X509_CERT_SIG
|
93
|
-
# Others types not supported for now...
|
94
|
-
cert = OpenSSL::X509::Certificate.new(packet.ike_cert.content)
|
95
|
-
elsif cert.nil?
|
96
|
-
raise CryptoError, 'a certificate should be provided'
|
97
|
-
end
|
98
|
-
|
99
|
-
text = cert.to_text
|
100
|
-
m = text.match(/Public Key Algorithm: ([a-zA-Z0-9-]+)/)
|
101
|
-
digest = case m[1]
|
102
|
-
when 'id-ecPublicKey'
|
103
|
-
m2 = text.match(/Public-Key: \((\d+) bit\)/)
|
104
|
-
case m2[1]
|
105
|
-
when '256'
|
106
|
-
OpenSSL::Digest::SHA256.new
|
107
|
-
when '384'
|
108
|
-
OpenSSL::Digest::SHA384.new
|
109
|
-
when '521'
|
110
|
-
OpenSSL::Digest::SHA512.new
|
111
|
-
end
|
112
|
-
when /sha([235]\d+)/
|
113
|
-
OpenSSL::Digest.const_get("SHA#{$1}").new
|
114
|
-
when /sha1/, 'rsaEncryption'
|
115
|
-
OpenSSL::Digest::SHA1.new
|
116
|
-
end
|
117
|
-
signature = format_signature(cert.public_key, content.to_s)
|
118
|
-
cert.public_key.verify(digest, signature, signed_octets)
|
86
|
+
check_signature?(cert, signed_octets)
|
119
87
|
when METHOD_NULL
|
120
88
|
true
|
121
89
|
else
|
@@ -131,6 +99,13 @@ module PacketGen::Plugin
|
|
131
99
|
|
132
100
|
private
|
133
101
|
|
102
|
+
def build_signed_octets(init_msg, nonce, sk_p, prf)
|
103
|
+
signed_octets = init_msg.ike.to_s
|
104
|
+
signed_octets << nonce
|
105
|
+
id = packet.ike.flag_i? ? packet.ike_idi : packet.ike_idr
|
106
|
+
signed_octets << prf(prf, sk_p, id.to_s[4, id.length - 4])
|
107
|
+
end
|
108
|
+
|
134
109
|
def prf(type, key, msg)
|
135
110
|
case type
|
136
111
|
when Transform::PRF_HMAC_MD5, Transform::PRF_HMAC_SHA1,
|
@@ -138,7 +113,7 @@ module PacketGen::Plugin
|
|
138
113
|
Transform::PRF_HMAC_SHA2_512
|
139
114
|
digestname = Transform.constants.grep(/PRF_/)
|
140
115
|
.detect { |c| Transform.const_get(c) == type }
|
141
|
-
.to_s.sub(/^PRF_HMAC_/, '').sub(
|
116
|
+
.to_s.sub(/^PRF_HMAC_/, '').sub('2_', '')
|
142
117
|
digest = OpenSSL::Digest.const_get(digestname).new
|
143
118
|
else
|
144
119
|
raise NotImplementedError, 'for now, only HMAC-based PRF are supported'
|
@@ -148,6 +123,44 @@ module PacketGen::Plugin
|
|
148
123
|
hmac.digest
|
149
124
|
end
|
150
125
|
|
126
|
+
def check_shared_key?(shared_secret, signed_octets)
|
127
|
+
auth = prf(prf(shared_secret, 'Key Pad for IKEv2'), signed_octets)
|
128
|
+
auth == content
|
129
|
+
end
|
130
|
+
|
131
|
+
def check_signature?(cert, signed_octets)
|
132
|
+
if packet.ike_cert
|
133
|
+
# FIXME: Expect a ENCODING_X509_CERT_SIG
|
134
|
+
# Others types not supported for now...
|
135
|
+
cert = OpenSSL::X509::Certificate.new(packet.ike_cert.content)
|
136
|
+
elsif cert.nil?
|
137
|
+
raise CryptoError, 'a certificate should be provided'
|
138
|
+
end
|
139
|
+
|
140
|
+
text = cert.to_text
|
141
|
+
digest = build_digest_object(text)
|
142
|
+
signature = format_signature(cert.public_key, content.to_s)
|
143
|
+
cert.public_key.verify(digest, signature, signed_octets)
|
144
|
+
end
|
145
|
+
|
146
|
+
def build_digest_object(text)
|
147
|
+
m = text.match(/Public Key Algorithm: ([a-zA-Z0-9-]+)/)
|
148
|
+
case m[1]
|
149
|
+
when 'id-ecPublicKey'
|
150
|
+
m2 = text.match(/Public-Key: \((\d+) bit\)/)
|
151
|
+
case m2[1]
|
152
|
+
when '256', '384'
|
153
|
+
OpenSSL::Digest.new("SHA#{m2[1]}")
|
154
|
+
when '521'
|
155
|
+
OpenSSL::Digest.new(SHA512)
|
156
|
+
end
|
157
|
+
when /sha([235]\d+)/
|
158
|
+
OpenSSL::Digest.new("SHA#{$1}")
|
159
|
+
when /sha1/, 'rsaEncryption'
|
160
|
+
OpenSSL::Digest.new('SHA1')
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
151
164
|
def format_signature(pkey, sig)
|
152
165
|
if pkey.is_a?(OpenSSL::PKey::EC)
|
153
166
|
# PKey::EC need a signature as a DER string representing a sequence of
|
@@ -56,7 +56,7 @@ module PacketGen::Plugin
|
|
56
56
|
# @attribute encoding
|
57
57
|
# 8-bit certificate encoding
|
58
58
|
# @return [Integer]
|
59
|
-
|
59
|
+
define_attr_before :content, :encoding, BinStruct::Int8Enum, enum: ENCODINGS
|
60
60
|
|
61
61
|
def initialize(options={})
|
62
62
|
super
|
@@ -55,7 +55,7 @@ module PacketGen::Plugin
|
|
55
55
|
next unless attr == :content
|
56
56
|
|
57
57
|
str = PacketGen::Inspect.shift_level
|
58
|
-
str << PacketGen::Inspect::FMT_ATTR % ['hashes', :content, human_content]
|
58
|
+
str << (PacketGen::Inspect::FMT_ATTR % ['hashes', :content, human_content])
|
59
59
|
end
|
60
60
|
end
|
61
61
|
end
|
@@ -41,23 +41,23 @@ module PacketGen::Plugin
|
|
41
41
|
|
42
42
|
# ID types
|
43
43
|
TYPES = {
|
44
|
-
'IPV4_ADDR'
|
45
|
-
'FQDN'
|
44
|
+
'IPV4_ADDR' => 1,
|
45
|
+
'FQDN' => 2,
|
46
46
|
'RFC822_ADDR' => 3,
|
47
|
-
'IPV6_ADDR'
|
47
|
+
'IPV6_ADDR' => 5,
|
48
48
|
'DER_ASN1_DN' => 9,
|
49
49
|
'DER_ASN1_GN' => 10,
|
50
|
-
'KEY_ID'
|
50
|
+
'KEY_ID' => 11
|
51
51
|
}.freeze
|
52
52
|
|
53
53
|
# @attribute [r] type
|
54
54
|
# 8-bit ID type
|
55
55
|
# @return [Integer]
|
56
|
-
|
56
|
+
define_attr_before :content, :type, BinStruct::Int8Enum, enum: TYPES
|
57
57
|
# @attribute reserved
|
58
58
|
# 24-bit reserved field
|
59
59
|
# @return [Integer]
|
60
|
-
|
60
|
+
define_attr_before :content, :reserved, BinStruct::Int24
|
61
61
|
|
62
62
|
# Get ID type name
|
63
63
|
# @return [String]
|
@@ -69,7 +69,7 @@ module PacketGen::Plugin
|
|
69
69
|
# @return [String]
|
70
70
|
def human_content
|
71
71
|
case type
|
72
|
-
when TYPES['IPV4_ADDR'], TYPES['
|
72
|
+
when TYPES['IPV4_ADDR'], TYPES['IPV6_ADDR']
|
73
73
|
IPAddr.ntop(content)
|
74
74
|
when TYPES['DER_ASN1_DN'], TYPES['DER_ASN1_GN']
|
75
75
|
OpenSSL::X509::Name.new(content).to_s
|
@@ -77,7 +77,6 @@ module PacketGen::Plugin
|
|
77
77
|
content.inspect
|
78
78
|
end
|
79
79
|
end
|
80
|
-
|
81
80
|
end
|
82
81
|
|
83
82
|
# This class handles Identification - Responder payloads, denoted IDr.
|
@@ -24,9 +24,9 @@ module PacketGen::Plugin
|
|
24
24
|
# | |
|
25
25
|
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
26
26
|
# These specific fields are:
|
27
|
-
# * {#group_num} (type {
|
28
|
-
# * {#reserved} (type {
|
29
|
-
# * and {#content} (type {
|
27
|
+
# * {#group_num} (type {BinStruct::Int16}),
|
28
|
+
# * {#reserved} (type {BinStruct::Int16}),
|
29
|
+
# * and {#content} (type {BinStruct::String}).
|
30
30
|
#
|
31
31
|
# == Create a KE payload
|
32
32
|
# # Create a IKE packet with a KE payload
|
@@ -44,11 +44,11 @@ module PacketGen::Plugin
|
|
44
44
|
# @!attribute group_num
|
45
45
|
# 16-bit DH group number
|
46
46
|
# @return [Integer]
|
47
|
-
|
47
|
+
define_attr_before :content, :group_num, BinStruct::Int16
|
48
48
|
# @!attribute reserved
|
49
49
|
# 16-bit reserved field
|
50
50
|
# @return [Integer]
|
51
|
-
|
51
|
+
define_attr_before :content, :reserved, BinStruct::Int16, default: 0
|
52
52
|
|
53
53
|
def initialize(options={})
|
54
54
|
super
|
@@ -68,6 +68,7 @@ module PacketGen::Plugin
|
|
68
68
|
Transform.const_defined?(cname) ? Transform.const_get(cname) : nil
|
69
69
|
end
|
70
70
|
raise ArgumentError, "unknown group #{value.inspect}" unless group
|
71
|
+
|
71
72
|
self[:group_num].value = group
|
72
73
|
end
|
73
74
|
end
|
@@ -11,7 +11,7 @@ module PacketGen::Plugin
|
|
11
11
|
# This class handles Nonce payloads, as defined in RFC 7296 §3.9.
|
12
12
|
#
|
13
13
|
# A Nonce payload contains a generic payload Plugin (see {Payload}) and
|
14
|
-
# data field (type {
|
14
|
+
# data field (type {BinStruct::String}):
|
15
15
|
# 1 2 3
|
16
16
|
# 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
17
17
|
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
@@ -28,11 +28,11 @@ module PacketGen::Plugin
|
|
28
28
|
# | |
|
29
29
|
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
30
30
|
# These specific fields are:
|
31
|
-
# * {#protocol} (type {
|
32
|
-
# * {#spi_size} (type {
|
33
|
-
# * {#message_type} (type {
|
34
|
-
# * {#spi} (type {
|
35
|
-
# * {#content} (type {
|
31
|
+
# * {#protocol} (type {BinStruct::Int8}),
|
32
|
+
# * {#spi_size} (type {BinStruct::Int8}),
|
33
|
+
# * {#message_type} (type {BinStruct::Int16}),
|
34
|
+
# * {#spi} (type {BinStruct::String}),
|
35
|
+
# * {#content} (type {BinStruct::String}).
|
36
36
|
#
|
37
37
|
# == Create a Notify payload
|
38
38
|
# # Create a IKE packet with a Notify payload
|
@@ -43,7 +43,7 @@ module PacketGen::Plugin
|
|
43
43
|
# == Create a Notify payload with a SPI
|
44
44
|
# # Create a IKE packet with a Notify payload
|
45
45
|
# pkt = PacketGen.gen('IP').add('UDP').add('IKE').add('IKE::Notify', protocol: 'ESP', spi_size: 4, type: 'INVALID_SYNTAX')
|
46
|
-
# pkt.ike_notify.spi.read
|
46
|
+
# pkt.ike_notify.spi.read BinStruct::Int32.new(0x12345678).to_s
|
47
47
|
# pkt.calc_length
|
48
48
|
# @author Sylvain Daubert
|
49
49
|
class Notify < Payload
|
@@ -93,7 +93,7 @@ module PacketGen::Plugin
|
|
93
93
|
# CHILD_SA_NOT_FOUND. If the SPI field is empty, this field MUST be
|
94
94
|
# sent as zero and MUST be ignored on receipt.
|
95
95
|
# @return [Integer]
|
96
|
-
|
96
|
+
define_attr_before :content, :protocol, BinStruct::Int8Enum, enum: PROTOCOLS
|
97
97
|
# @!attribute spi_size
|
98
98
|
# 8-bit SPI size. Give size of SPI field. Length in octets of the SPI as
|
99
99
|
# defined by the IPsec protocol ID or zero if no SPI is applicable. For a
|
@@ -101,17 +101,17 @@ module PacketGen::Plugin
|
|
101
101
|
# the field must be empty.Set to 0 for an initial IKE SA
|
102
102
|
# negotiation, as SPI is obtained from outer Plugin.
|
103
103
|
# @return [Integer]
|
104
|
-
|
104
|
+
define_attr_before :content, :spi_size, BinStruct::Int8, default: 0
|
105
105
|
# @!attribute message_type
|
106
106
|
# 16-bit notify message type. Specifies the type of notification message.
|
107
107
|
# @return [Integer]
|
108
|
-
|
108
|
+
define_attr_before :content, :message_type, BinStruct::Int16Enum, enum: TYPES, default: 0
|
109
109
|
# @!attribute spi
|
110
110
|
# the sending entity's SPI. When the {#spi_size} field is zero,
|
111
111
|
# this field is not present in the proposal.
|
112
112
|
# @return [String]
|
113
|
-
|
114
|
-
|
113
|
+
define_attr_before :content, :spi, BinStruct::String,
|
114
|
+
builder: ->(h, t) { t.new(length_from: h[:spi_size]) }
|
115
115
|
|
116
116
|
alias type message_type
|
117
117
|
|
@@ -144,8 +144,7 @@ module PacketGen::Plugin
|
|
144
144
|
next unless attr == :protocol
|
145
145
|
|
146
146
|
str = PacketGen::Inspect.shift_level
|
147
|
-
str << PacketGen::Inspect::FMT_ATTR % [self[attr].class.to_s.sub(/.*::/, ''), attr,
|
148
|
-
human_protocol]
|
147
|
+
str << (PacketGen::Inspect::FMT_ATTR % [self[attr].class.to_s.sub(/.*::/, ''), attr, human_protocol])
|
149
148
|
end
|
150
149
|
end
|
151
150
|
end
|
@@ -30,42 +30,40 @@ module PacketGen::Plugin
|
|
30
30
|
# @!attribute next
|
31
31
|
# 8-bit next payload
|
32
32
|
# @return [Integer]
|
33
|
-
|
33
|
+
define_attr :next, BinStruct::Int8
|
34
34
|
# @!attribute flags
|
35
35
|
# 8-bit flags
|
36
36
|
# @return [Integer]
|
37
|
-
|
37
|
+
# @!attribute critical
|
38
|
+
# critical flag
|
39
|
+
# @return [Boolean]
|
40
|
+
# @!attribute hreserved
|
41
|
+
# reserved part of {#flags} field
|
42
|
+
# @return [Integer]
|
43
|
+
define_bit_attr :flags, critical: 1, hreserved: 7
|
38
44
|
# @!attribute length
|
39
45
|
# 16-bit payload total length, including generic payload Plugin
|
40
46
|
# @return [Integer]
|
41
|
-
|
47
|
+
define_attr :length, BinStruct::Int16
|
42
48
|
# @!attribute content
|
43
49
|
# Payload content. Depends on payload. Variable length.
|
44
50
|
# @return [String]
|
45
|
-
|
51
|
+
define_attr :content, BinStruct::String, builder: ->(h, t) { t.new(length_from: -> { h.length - h.offset_of(:content) }) }
|
46
52
|
|
47
53
|
# Defining a body permits using Packet#parse to parse next IKE payloads.
|
48
|
-
|
49
|
-
|
50
|
-
# @!attribute critical
|
51
|
-
# critical flag
|
52
|
-
# @return [Boolean]
|
53
|
-
# @!attribute hreserved
|
54
|
-
# reserved part of {#flags} field
|
55
|
-
# @return [Integer]
|
56
|
-
define_bit_fields_on :flags, :critical, :hreserved, 7
|
54
|
+
define_attr :body, BinStruct::String
|
57
55
|
|
58
56
|
def initialize(options={})
|
59
57
|
super
|
60
58
|
if options[:content]
|
61
|
-
self[:content] =
|
59
|
+
self[:content] = BinStruct::String.new
|
62
60
|
self[:content].read options[:content]
|
63
61
|
end
|
64
62
|
calc_length unless options[:length]
|
65
63
|
end
|
66
64
|
|
67
|
-
|
68
|
-
|
65
|
+
# Compute length and set {#length} field
|
66
|
+
# @return [Integer] new length
|
69
67
|
def calc_length
|
70
68
|
# Here, #body is next payload, so body size should not be taken in
|
71
69
|
# account (payload's real body is #content).
|
@@ -89,7 +87,7 @@ require_relative 'auth'
|
|
89
87
|
require_relative 'ts'
|
90
88
|
require_relative 'vendor_id'
|
91
89
|
|
92
|
-
module PacketGen::Plugin
|
90
|
+
module PacketGen::Plugin # rubocop:disable Metrics/ModuleLength
|
93
91
|
IKE.bind IKE::SA, next: IKE::SA::PAYLOAD_TYPE
|
94
92
|
IKE::Payload.bind IKE::SA, next: IKE::SA::PAYLOAD_TYPE
|
95
93
|
IKE::KE.bind IKE::SA, next: IKE::SA::PAYLOAD_TYPE
|
@@ -287,19 +285,19 @@ module PacketGen::Plugin
|
|
287
285
|
IKE::TSr.bind IKE::VendorID, next: IKE::VendorID::PAYLOAD_TYPE
|
288
286
|
|
289
287
|
# Last defined. To be used as default if no other may be parsed.
|
290
|
-
IKE::SA.bind IKE::Payload, next:
|
291
|
-
IKE::KE.bind IKE::Payload, next:
|
292
|
-
IKE::Nonce.bind IKE::Payload, next:
|
293
|
-
IKE::Notify.bind IKE::Payload, next:
|
294
|
-
IKE::SK.bind IKE::Payload, next:
|
295
|
-
IKE::IDi.bind IKE::Payload, next:
|
296
|
-
IKE::IDr.bind IKE::Payload, next:
|
297
|
-
IKE::Cert.bind IKE::Payload, next:
|
298
|
-
IKE::CertReq.bind IKE::Payload, next:
|
299
|
-
IKE::Auth.bind IKE::Payload, next:
|
300
|
-
IKE::TSi.bind IKE::Payload, next:
|
301
|
-
IKE::TSr.bind IKE::Payload, next:
|
302
|
-
IKE::VendorID.bind IKE::Payload, next:
|
303
|
-
IKE.bind IKE::Payload, next:
|
304
|
-
IKE::Payload.bind IKE::Payload, next:
|
288
|
+
IKE::SA.bind IKE::Payload, next: lambda(&:positive?)
|
289
|
+
IKE::KE.bind IKE::Payload, next: lambda(&:positive?)
|
290
|
+
IKE::Nonce.bind IKE::Payload, next: lambda(&:positive?)
|
291
|
+
IKE::Notify.bind IKE::Payload, next: lambda(&:positive?)
|
292
|
+
IKE::SK.bind IKE::Payload, next: lambda(&:positive?)
|
293
|
+
IKE::IDi.bind IKE::Payload, next: lambda(&:positive?)
|
294
|
+
IKE::IDr.bind IKE::Payload, next: lambda(&:positive?)
|
295
|
+
IKE::Cert.bind IKE::Payload, next: lambda(&:positive?)
|
296
|
+
IKE::CertReq.bind IKE::Payload, next: lambda(&:positive?)
|
297
|
+
IKE::Auth.bind IKE::Payload, next: lambda(&:positive?)
|
298
|
+
IKE::TSi.bind IKE::Payload, next: lambda(&:positive?)
|
299
|
+
IKE::TSr.bind IKE::Payload, next: lambda(&:positive?)
|
300
|
+
IKE::VendorID.bind IKE::Payload, next: lambda(&:positive?)
|
301
|
+
IKE.bind IKE::Payload, next: lambda(&:positive?)
|
302
|
+
IKE::Payload.bind IKE::Payload, next: lambda(&:positive?)
|
305
303
|
end
|
@@ -21,22 +21,22 @@ module PacketGen::Plugin
|
|
21
21
|
# Such an attribute may have a TLV (Type/length/value) format if AF=0,
|
22
22
|
# or a TV format (AF=1).
|
23
23
|
# @author Sylvain Daubert
|
24
|
-
class Attribute <
|
24
|
+
class Attribute < BinStruct::Struct
|
25
25
|
# KeyLength attribute type
|
26
26
|
TYPE_KEY_LENGTH = 14
|
27
27
|
|
28
28
|
# @!attribute type
|
29
29
|
# attribute type
|
30
30
|
# @return [Integer]
|
31
|
-
|
31
|
+
define_attr :type, BinStruct::Int16
|
32
32
|
# @!attribute length
|
33
33
|
# attribute length
|
34
34
|
# @return [Integer]
|
35
|
-
|
35
|
+
define_attr :length, BinStruct::Int16
|
36
36
|
# @!attribute value
|
37
37
|
# attribute value
|
38
38
|
# @return [Integer]
|
39
|
-
|
39
|
+
define_attr :value, BinStruct::Int32, optional: ->(h) { !h.tv_format? }
|
40
40
|
|
41
41
|
def initialize(options={})
|
42
42
|
super
|
@@ -64,7 +64,7 @@ module PacketGen::Plugin
|
|
64
64
|
def to_human
|
65
65
|
name = self.class.constants.grep(/TYPE_/)
|
66
66
|
.detect { |c| self.class.const_get(c) == (type & 0x7fff) } || "attr[#{type & 0x7fff}]"
|
67
|
-
name = name.to_s.sub(
|
67
|
+
name = name.to_s.sub('TYPE_', '')
|
68
68
|
"#{name}=#{value}"
|
69
69
|
end
|
70
70
|
|
@@ -77,7 +77,7 @@ module PacketGen::Plugin
|
|
77
77
|
|
78
78
|
# Set of {Attribute} in a {Transform}
|
79
79
|
# @author Sylvain Daubert
|
80
|
-
class Attributes <
|
80
|
+
class Attributes < BinStruct::Array
|
81
81
|
set_of Attribute
|
82
82
|
end
|
83
83
|
|
@@ -102,11 +102,11 @@ module PacketGen::Plugin
|
|
102
102
|
# == Add attributes to a transform
|
103
103
|
# # using an Attribute object
|
104
104
|
# attr = PacketGen::Plugin::IKE::Attribute.new(type: 14, value: 128)
|
105
|
-
# trans.
|
105
|
+
# trans.tattributes << attr
|
106
106
|
# # using a hash
|
107
|
-
# trans.
|
107
|
+
# trans.tattributes << { type: 14, value: 128 }
|
108
108
|
# @author Sylvain Daubert
|
109
|
-
class Transform <
|
109
|
+
class Transform < BinStruct::Struct
|
110
110
|
# Transform types
|
111
111
|
TYPES = {
|
112
112
|
'ENCR' => 1,
|
@@ -253,33 +253,33 @@ module PacketGen::Plugin
|
|
253
253
|
# if this was the last Transform Substructure, and a value of 3 if
|
254
254
|
# there are more Transform Substructures.
|
255
255
|
# @return [Integer]
|
256
|
-
|
256
|
+
define_attr :last, BinStruct::Int8
|
257
257
|
# @!attribute rsv1
|
258
258
|
# 8-bit reserved field
|
259
259
|
# @return [Integer]
|
260
|
-
|
260
|
+
define_attr :rsv1, BinStruct::Int8
|
261
261
|
# @!attribute length
|
262
262
|
# 16-bit transform length
|
263
263
|
# @return [Integer]
|
264
|
-
|
264
|
+
define_attr :length, BinStruct::Int16
|
265
265
|
# @!attribute [r] type
|
266
266
|
# 8-bit transform type. The Transform Type is the cryptographic
|
267
267
|
# algorithm type (i.e. encryption, PRF, integrity, etc.)
|
268
268
|
# @return [Integer]
|
269
|
-
|
269
|
+
define_attr :type, BinStruct::Int8Enum, enum: TYPES
|
270
270
|
# @!attribute rsv2
|
271
271
|
# 8-bit reserved field
|
272
272
|
# @return [Integer]
|
273
|
-
|
273
|
+
define_attr :rsv2, BinStruct::Int8
|
274
274
|
# @!attribute [r] id
|
275
275
|
# 16-bit transform ID. The Transform ID is the specific instance of
|
276
276
|
# the proposed transform type.
|
277
277
|
# @return [Integer]
|
278
|
-
|
279
|
-
# @!attribute
|
278
|
+
define_attr :id, BinStruct::Int16
|
279
|
+
# @!attribute tattributes
|
280
280
|
# Set of attributes for this transform
|
281
281
|
# @return [Attributes]
|
282
|
-
|
282
|
+
define_attr :tattributes, Attributes, builder: ->(h, t) { t.new(length_from: -> { h.length - h.offset_of(:tattributes) }) }
|
283
283
|
|
284
284
|
def initialize(options={})
|
285
285
|
super
|
@@ -315,8 +315,8 @@ module PacketGen::Plugin
|
|
315
315
|
# Get a human readable string
|
316
316
|
# @return [String]
|
317
317
|
def to_human
|
318
|
-
h =
|
319
|
-
h << ",#{
|
318
|
+
h = "#{human_type}(#{human_id}"
|
319
|
+
h << ",#{tattributes.to_human}" unless tattributes.empty?
|
320
320
|
|
321
321
|
h << ')'
|
322
322
|
end
|
@@ -353,11 +353,11 @@ module PacketGen::Plugin
|
|
353
353
|
|
354
354
|
# Set of {Transform} in a {SAProposal}
|
355
355
|
# @author Sylvain Daubert
|
356
|
-
class Transforms <
|
356
|
+
class Transforms < BinStruct::Array
|
357
357
|
set_of Transform
|
358
358
|
|
359
|
-
# Same as {
|
360
|
-
# @see
|
359
|
+
# Same as {BinStruct::Array#push} but update previous {Transform#last} attribute
|
360
|
+
# @see BinStruct::Array#push
|
361
361
|
def push(trans)
|
362
362
|
super
|
363
363
|
self[-2].last = 3 if size > 1
|
@@ -393,22 +393,22 @@ module PacketGen::Plugin
|
|
393
393
|
# # using a hash
|
394
394
|
# proposal.transforms << { type: 'ENCR', id: '3DES' }
|
395
395
|
# @author Sylvain Daubert
|
396
|
-
class SAProposal <
|
396
|
+
class SAProposal < BinStruct::Struct
|
397
397
|
# @!attribute last
|
398
398
|
# 8-bit last substructure. Specifies whether or not this is the
|
399
399
|
# last Proposal Substructure in the SA. This field has a value of 0
|
400
400
|
# if this was the last Proposal Substructure, and a value of 2 if
|
401
401
|
# there are more Proposal Substructures.
|
402
402
|
# @return [Integer]
|
403
|
-
|
403
|
+
define_attr :last, BinStruct::Int8
|
404
404
|
# @!attribute reserved
|
405
405
|
# 8-bit reserved field
|
406
406
|
# @return [Integer]
|
407
|
-
|
407
|
+
define_attr :reserved, BinStruct::Int8
|
408
408
|
# @!attribute length
|
409
409
|
# 16-bit proposal length
|
410
410
|
# @return [Integer]
|
411
|
-
|
411
|
+
define_attr :length, BinStruct::Int16
|
412
412
|
# @!attribute num
|
413
413
|
# 8-bit proposal number. When a proposal is made, the first
|
414
414
|
# proposal in an SA payload MUST be 1, and subsequent proposals MUST
|
@@ -417,30 +417,30 @@ module PacketGen::Plugin
|
|
417
417
|
# in the SA payload MUST match the number on the proposal sent that
|
418
418
|
# was accepted.
|
419
419
|
# @return [Integer]
|
420
|
-
|
420
|
+
define_attr :num, BinStruct::Int8, default: 1
|
421
421
|
# @!attribute [r] protocol
|
422
422
|
# 8-bit protocol ID. Specify IPsec protocol currently negociated.
|
423
423
|
# May 1 (IKE), 2 (AH) or 3 (ESP).
|
424
424
|
# @return [Integer]
|
425
|
-
|
425
|
+
define_attr :protocol, BinStruct::Int8Enum, enum: PROTOCOLS
|
426
426
|
# @!attribute spi_size
|
427
427
|
# 8-bit SPI size. Give size of SPI field. Set to 0 for an initial IKE SA
|
428
428
|
# negotiation, as SPI is obtained from outer Plugin.
|
429
429
|
# @return [Integer]
|
430
|
-
|
430
|
+
define_attr :spi_size, BinStruct::Int8, default: 0
|
431
431
|
# @!attribute num_trans
|
432
432
|
# 8-bit number of transformations
|
433
433
|
# @return [Integer]
|
434
|
-
|
434
|
+
define_attr :num_trans, BinStruct::Int8, default: 0
|
435
435
|
# @!attribute spi
|
436
436
|
# the sending entity's SPI. When the {#spi_size} field is zero,
|
437
437
|
# this field is not present in the proposal.
|
438
438
|
# @return [String]
|
439
|
-
|
439
|
+
define_attr :spi, BinStruct::String, builder: ->(h, t) { t.new(length_from: h[:spi_size]) }
|
440
440
|
# @!attribute transforms
|
441
441
|
# 8-bit set of tranforms for this proposal
|
442
442
|
# @return [Transforms]
|
443
|
-
|
443
|
+
define_attr :transforms, Transforms, builder: ->(h, t) { t.new(counter: h[:num_trans]) }
|
444
444
|
|
445
445
|
def initialize(options={})
|
446
446
|
options[:spi_size] = options[:spi].size if options[:spi] && options[:spi_size].nil?
|
@@ -459,12 +459,12 @@ module PacketGen::Plugin
|
|
459
459
|
# Get a human readable string
|
460
460
|
# @return [String]
|
461
461
|
def to_human
|
462
|
-
str =
|
462
|
+
str = "##{num} #{human_protocol}"
|
463
463
|
case spi_size
|
464
464
|
when 4
|
465
|
-
str << '(spi:0x%08x)' %
|
465
|
+
str << ('(spi:0x%08x)' % BinStruct::Int32.new.read(spi).to_i)
|
466
466
|
when 8
|
467
|
-
str << '(spi:0x%016x)' %
|
467
|
+
str << ('(spi:0x%016x)' % BinStruct::Int64.new.read(spi).to_i)
|
468
468
|
end
|
469
469
|
str << ":#{transforms.to_human}"
|
470
470
|
end
|
@@ -490,14 +490,14 @@ module PacketGen::Plugin
|
|
490
490
|
|
491
491
|
# Set of {SAProposal}
|
492
492
|
# @author Sylvain Daubert
|
493
|
-
class SAProposals <
|
493
|
+
class SAProposals < BinStruct::Array
|
494
494
|
set_of SAProposal
|
495
495
|
|
496
496
|
# Separator used between proposals in {#to_human}
|
497
497
|
HUMAN_SEPARATOR = '; '
|
498
498
|
|
499
|
-
# Same as {
|
500
|
-
# @see
|
499
|
+
# Same as {BinStruct::Array#push} but update previous {SAProposal#last} attribute
|
500
|
+
# @see BinStruct::Array#push
|
501
501
|
def push(prop)
|
502
502
|
super
|
503
503
|
self[-2].last = 2 if size > 1
|
@@ -530,19 +530,19 @@ module PacketGen::Plugin
|
|
530
530
|
# # ID is taken from Transform::<TYPE>_* constants.
|
531
531
|
# pkt.ike_sa.proposals.first.transforms << { type: 'ENCR', id: 'AES_CTR' }
|
532
532
|
# # and finally, add an attribute to this transform (here, KEY_SIZE = 128 bits)
|
533
|
-
# pkt.ike_sa.proposals[0].transforms[0].
|
533
|
+
# pkt.ike_sa.proposals[0].transforms[0].tattributes << { type: 0x800e, value: 128 }
|
534
534
|
# pkt.calc_length
|
535
535
|
# @author Sylvain Daubert
|
536
536
|
class SA < Payload
|
537
537
|
# Payload type number
|
538
538
|
PAYLOAD_TYPE = 33
|
539
539
|
|
540
|
-
|
540
|
+
remove_attr :content
|
541
541
|
|
542
542
|
# @!attribute proposals
|
543
543
|
# Set of SA proposals
|
544
544
|
# @return [SAProposals]
|
545
|
-
|
545
|
+
define_attr_before :body, :proposals, SAProposals, builder: ->(h, t) { t.new(length_from: -> { h.length - h.offset_of(:proposals) }) }
|
546
546
|
|
547
547
|
# Compute length and set {#length} field
|
548
548
|
# @return [Integer] new length
|