packetgen-plugin-ipsec 1.0.2 → 1.0.3

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.
@@ -5,75 +5,76 @@
5
5
 
6
6
  # frozen_string_literal: true
7
7
 
8
- module PacketGen
9
- module Plugin
10
- class IKE
11
- # PacketGen::Header::Base class for IKE payloads. This class may also be used for unknown payloads.
12
- #
13
- # This class handles generic IKE payload Plugin:
14
- # 1 2 3
15
- # 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
16
- # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
17
- # | Next Payload |C| RESERVED | Payload Length |
18
- # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
19
- # to which a {#content} field is added to handle content of unknown payload types.
20
- # @author Sylvain Daubert
21
- class Payload < PacketGen::Header::Base
22
- # Give protocol name
23
- # @return [String]
24
- def self.protocol_name
25
- return @protocol_name if defined? @protocol_name
8
+ module PacketGen::Plugin
9
+ class IKE
10
+ # PacketGen::Header::Base class for IKE payloads. This class may also be used for unknown payloads.
11
+ #
12
+ # This class handles generic IKE payload Plugin:
13
+ # 1 2 3
14
+ # 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
15
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
16
+ # | Next Payload |C| RESERVED | Payload Length |
17
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
18
+ # to which a {#content} field is added to handle content of unknown payload types.
19
+ # @author Sylvain Daubert
20
+ class Payload < PacketGen::Header::Base
21
+ # Give protocol name
22
+ # @return [String]
23
+ def self.protocol_name
24
+ return @protocol_name if defined? @protocol_name
26
25
 
27
- basename = to_s.sub(/.*::/, '')
28
- @protocol_name = "IKE::#{basename}"
29
- end
26
+ basename = to_s.sub(/.*::/, '')
27
+ @protocol_name = "IKE::#{basename}"
28
+ end
30
29
 
31
- # @!attribute next
32
- # 8-bit next payload
33
- # @return [Integer]
34
- define_field :next, PacketGen::Types::Int8
35
- # @!attribute flags
36
- # 8-bit flags
37
- # @return [Integer]
38
- define_field :flags, PacketGen::Types::Int8
39
- # @!attribute length
40
- # 16-bit payload total length, including generic payload Plugin
41
- # @return [Integer]
42
- define_field :length, PacketGen::Types::Int16
43
- # @!attribute content
44
- # Payload content. Depends on payload. Variable length.
45
- # @return [String]
46
- define_field :content, PacketGen::Types::String, builder: ->(h, t) { t.new(length_from: -> { h.length - h.offset_of(:content) }) }
30
+ # @!attribute next
31
+ # 8-bit next payload
32
+ # @return [Integer]
33
+ define_field :next, PacketGen::Types::Int8
34
+ # @!attribute flags
35
+ # 8-bit flags
36
+ # @return [Integer]
37
+ define_field :flags, PacketGen::Types::Int8
38
+ # @!attribute length
39
+ # 16-bit payload total length, including generic payload Plugin
40
+ # @return [Integer]
41
+ define_field :length, PacketGen::Types::Int16
42
+ # @!attribute content
43
+ # Payload content. Depends on payload. Variable length.
44
+ # @return [String]
45
+ define_field :content, PacketGen::Types::String, builder: ->(h, t) { t.new(length_from: -> { h.length - h.offset_of(:content) }) }
47
46
 
48
- # Defining a body permits using Packet#parse to parse next IKE payloads.
49
- define_field :body, PacketGen::Types::String
47
+ # Defining a body permits using Packet#parse to parse next IKE payloads.
48
+ define_field :body, PacketGen::Types::String
50
49
 
51
- # @!attribute critical
52
- # critical flag
53
- # @return [Boolean]
54
- # @!attribute hreserved
55
- # reserved part of {#flags} field
56
- # @return [Integer]
57
- define_bit_fields_on :flags, :critical, :hreserved, 7
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
58
57
 
59
- def initialize(options={})
60
- super
61
- self[:content].replace(options[:content]) if options[:content]
62
- calc_length unless options[:length]
58
+ def initialize(options={})
59
+ super
60
+ if options[:content]
61
+ self[:content] = PacketGen::Types::String.new
62
+ self[:content].read options[:content]
63
63
  end
64
+ calc_length unless options[:length]
65
+ end
64
66
 
65
67
  # Compute length and set {#length} field
66
68
  # @return [Integer] new length
67
- def calc_length
68
- # Here, #body is next payload, so body size should not be taken in
69
- # account (payload's real body is #content).
70
- self.length = sz - self[:body].sz
71
- end
69
+ def calc_length
70
+ # Here, #body is next payload, so body size should not be taken in
71
+ # account (payload's real body is #content).
72
+ self.length = sz - self[:body].sz
72
73
  end
73
74
  end
74
-
75
- Header.add_class IKE::Payload
76
75
  end
76
+
77
+ PacketGen::Header.add_class IKE::Payload
77
78
  end
78
79
 
79
80
  require_relative 'sa'
@@ -1,494 +1,557 @@
1
1
  # coding: utf-8
2
+ # frozen_string_literal: true
3
+
2
4
  # This file is part of IPsec packetgen plugin.
3
5
  # See https://github.com/sdaubert/packetgen-plugin-ipsec for more informations
4
6
  # Copyright (c) 2018 Sylvain Daubert <sylvain.daubert@laposte.net>
5
7
  # This program is published under MIT license.
6
8
 
7
- # frozen_string_literal: true
8
-
9
- module PacketGen
10
- module Plugin
11
- class IKE
12
- # Transform attribute.
13
- # 1 2 3
14
- # 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
15
- # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
16
- # |A| Attribute Type | AF=0 Attribute Length |
17
- # |F| | AF=1 Attribute Value |
18
- # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
19
- # | AF=0 Attribute Value |
20
- # | AF=1 Not Transmitted |
21
- # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
22
- # Such an attribute may have a TLV (Type/length/value) format if AF=0,
23
- # or a TV format (AF=1).
24
- # @author Sylvain Daubert
25
- class Attribute < PacketGen::Types::Fields
26
- TYPE_KEY_LENGTH = 14
27
-
28
- # @!attribute type
29
- # attribute type
30
- # @return [Integer]
31
- define_field :type, PacketGen::Types::Int16
32
- # @!attribute length
33
- # attribute length
34
- # @return [Integer]
35
- define_field :length, PacketGen::Types::Int16
36
- # @!attribute value
37
- # attribute value
38
- # @return [Integer]
39
- define_field :value, PacketGen::Types::Int32, optional: ->(h) { !h.tv_format? }
40
-
41
- def initialize(options={})
42
- super
43
- if tv_format?
44
- self[:length].value = (options[:value] & 0xffff)
45
- else
46
- self[:length].value = 8 unless options[:length]
47
- end
9
+ module PacketGen::Plugin
10
+ class IKE
11
+ # Transform attribute.
12
+ # 1 2 3
13
+ # 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
14
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
15
+ # |A| Attribute Type | AF=0 Attribute Length |
16
+ # |F| | AF=1 Attribute Value |
17
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
18
+ # | AF=0 Attribute Value |
19
+ # | AF=1 Not Transmitted |
20
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
21
+ # Such an attribute may have a TLV (Type/length/value) format if AF=0,
22
+ # or a TV format (AF=1).
23
+ # @author Sylvain Daubert
24
+ class Attribute < PacketGen::Types::Fields
25
+ # KeyLength attribute type
26
+ TYPE_KEY_LENGTH = 14
27
+
28
+ # @!attribute type
29
+ # attribute type
30
+ # @return [Integer]
31
+ define_field :type, PacketGen::Types::Int16
32
+ # @!attribute length
33
+ # attribute length
34
+ # @return [Integer]
35
+ define_field :length, PacketGen::Types::Int16
36
+ # @!attribute value
37
+ # attribute value
38
+ # @return [Integer]
39
+ define_field :value, PacketGen::Types::Int32, optional: ->(h) { !h.tv_format? }
40
+
41
+ def initialize(options={})
42
+ super
43
+ if tv_format?
44
+ self[:length].value = (options[:value] & 0xffff)
45
+ else
46
+ self[:length].value = 8 unless options[:length]
48
47
  end
48
+ end
49
49
 
50
- undef length, value
50
+ undef length, value
51
51
 
52
- # @return [Integer]
53
- def length
54
- tv_format? ? 4 : self[:length].to_i
55
- end
56
-
57
- # @return [Integer]
58
- def value
59
- tv_format? ? self[:length].to_i : self[:value].to_i
60
- end
52
+ # @return [Integer]
53
+ def length
54
+ tv_format? ? 4 : self[:length].to_i
55
+ end
61
56
 
62
- # Get a human readable string
63
- # @return [String]
64
- def to_human
65
- name = self.class.constants.grep(/TYPE_/)
66
- .detect { |c| self.class.const_get(c) == (type & 0x7fff) } || "attr[#{type & 0x7fff}]"
67
- name = name.to_s.sub(/TYPE_/, '')
68
- "#{name}=#{value}"
69
- end
57
+ # @return [Integer]
58
+ def value
59
+ tv_format? ? self[:length].to_i : self[:value].to_i
60
+ end
70
61
 
71
- # Say if attribute use TV format (+true+) or TLV one (+false+)
72
- # @return [Boolean]
73
- def tv_format?
74
- type & 0x8000 == 0x8000
75
- end
62
+ # Get a human readable string
63
+ # @return [String]
64
+ def to_human
65
+ name = self.class.constants.grep(/TYPE_/)
66
+ .detect { |c| self.class.const_get(c) == (type & 0x7fff) } || "attr[#{type & 0x7fff}]"
67
+ name = name.to_s.sub(/TYPE_/, '')
68
+ "#{name}=#{value}"
76
69
  end
77
70
 
78
- # Set of {Attribute} in a {Transform}
79
- # @author Sylvain Daubert
80
- class Attributes < PacketGen::Types::Array
81
- set_of Attribute
71
+ # Say if attribute use TV format (+true+) or TLV one (+false+)
72
+ # @return [Boolean]
73
+ def tv_format?
74
+ type & 0x8000 == 0x8000
82
75
  end
76
+ end
83
77
 
84
- # SA Tranform substructure, as defined in RFC 7296 §3.3.2
85
- # 1 2 3
86
- # 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
87
- # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
88
- # | Last Substruc | RESERVED | Transform Length |
89
- # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
90
- # |Transform Type | RESERVED | Transform ID |
91
- # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
92
- # | |
93
- # ~ Transform Attributes ~
94
- # | |
95
- # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
96
- #
97
- # == Create a Transform
98
- # # using type and id names
99
- # trans = PacketGen::Plugin::IKE::Transform.new(type: 'ENCR', id: 'AES_CBC')
100
- # # using integer values
101
- # trans = PacketGen::Plugin::IKE::Transform.new(type: 1, id: 12)
102
- # == Add attributes to a transform
103
- # # using an Attribute object
104
- # attr = PacketGen::Plugin::IKE::Attribute.new(type: 14, value: 128)
105
- # trans.attributes << attr
106
- # # using a hash
107
- # trans.attributes << { type: 14, value: 128 }
108
- # @author Sylvain Daubert
109
- class Transform < PacketGen::Types::Fields
110
- TYPES = {
111
- 'ENCR' => 1,
112
- 'PRF' => 2,
113
- 'INTG' => 3,
114
- 'DH' => 4,
115
- 'ESN' => 5
116
- }.freeze
117
-
118
- ENCR_DES_IV64 = 1
119
- ENCR_DES = 2
120
- ENCR_3DES = 3
121
- ENCR_RC5 = 4
122
- ENCR_IDEA = 5
123
- ENCR_CAST = 6
124
- ENCR_BLOWFISH = 7
125
- ENCR_3IDEA = 8
126
- ENCR_DES_IV32 = 9
127
- ENCR_AES_CBC = 12
128
- ENCR_AES_CTR = 13
129
- ENCR_AES_CCM8 = 14
130
- ENCR_AES_CCM12 = 15
131
- ENCR_AES_CCM16 = 16
132
- ENCR_AES_GCM8 = 18
133
- ENCR_AES_GCM12 = 19
134
- ENCR_AES_GCM16 = 20
135
- ENCR_CAMELLIA_CBC = 23
136
- ENCR_CAMELLIA_CTR = 24
137
- ENCR_CAMELLIA_CCM8 = 25
138
- ENCR_CAMELLIA_CCM12 = 26
139
- ENCR_CAMELLIA_CCM16 = 27
140
- ENCR_CHACHA20_POLY1305 = 28
141
-
142
- PRF_HMAC_MD5 = 1
143
- PRF_HMAC_SHA1 = 2
144
- PRF_AES128_XCBC = 4
145
- PRF_HMAC_SHA2_256 = 5
146
- PRF_HMAC_SHA2_384 = 6
147
- PRF_HMAC_SHA2_512 = 7
148
- PRF_AES128_CMAC = 8
149
-
150
- INTG_NONE = 0
151
- INTG_HMAC_MD5_96 = 1
152
- INTG_HMAC_SHA1_96 = 2
153
- INTG_AES_XCBC_96 = 5
154
- INTG_HMAC_MD5_128 = 6
155
- INTG_HMAC_SHA1_160 = 7
156
- INTG_AES_CMAC_96 = 8
157
- INTG_AES128_GMAC = 9
158
- INTG_AES192_GMAC = 10
159
- INTG_AES256_GMAC = 11
160
- INTG_HMAC_SHA2_256_128 = 12
161
- INTG_HMAC_SHA2_384_192 = 13
162
- INTG_HMAC_SHA2_512_256 = 14
163
-
164
- DH_NONE = 0
165
- DH_MODP768 = 1
166
- DH_MODP1024 = 2
167
- DH_MODP1536 = 5
168
- DH_MODP2048 = 14
169
- DH_MODP3072 = 15
170
- DH_MODP4096 = 16
171
- DH_MODP6144 = 17
172
- DH_MODP8192 = 18
173
- DH_ECP256 = 19
174
- DH_ECP384 = 20
175
- DH_ECP521 = 21
176
- DH_BRAINPOOLP224 = 27
177
- DH_BRAINPOOLP256 = 28
178
- DH_BRAINPOOLP384 = 29
179
- DH_BRAINPOOLP512 = 30
180
- DH_CURVE25519 = 31
181
- DH_CURVE448 = 32
182
-
183
- ESN_NO_ESN = 0
184
- ESN_ESN = 1
185
-
186
- # @!attribute last
187
- # 8-bit last substructure. Specifies whether or not this is the
188
- # last Transform Substructure in the Proposal. This field has a value of 0
189
- # if this was the last Transform Substructure, and a value of 3 if
190
- # there are more Transform Substructures.
191
- # @return [Integer]
192
- define_field :last, PacketGen::Types::Int8
193
- # @!attribute rsv1
194
- # 8-bit reserved field
195
- # @return [Integer]
196
- define_field :rsv1, PacketGen::Types::Int8
197
- # @!attribute length
198
- # 16-bit transform length
199
- # @return [Integer]
200
- define_field :length, PacketGen::Types::Int16
201
- # @!attribute [r] type
202
- # 8-bit transform type. The Transform Type is the cryptographic
203
- # algorithm type (i.e. encryption, PRF, integrity, etc.)
204
- # @return [Integer]
205
- define_field :type, PacketGen::Types::Int8Enum, enum: TYPES
206
- # @!attribute rsv2
207
- # 8-bit reserved field
208
- # @return [Integer]
209
- define_field :rsv2, PacketGen::Types::Int8
210
- # @!attribute [r] id
211
- # 16-bit transform ID. The Transform ID is the specific instance of
212
- # the proposed transform type.
213
- # @return [Integer]
214
- define_field :id, PacketGen::Types::Int16
215
- # @!attribute attributes
216
- # Set of attributes for this transform
217
- # @return [Attributes]
218
- define_field :attributes, Attributes, builder: ->(h, t) { t.new(length_from: -> { h.length - h.offset_of(:attributes) }) }
219
-
220
- def initialize(options={})
221
- super
222
- self.type = options[:type] if options[:type]
223
- self.id = options[:id] if options[:id]
224
- self[:length].value = sz unless options[:length]
225
- end
78
+ # Set of {Attribute} in a {Transform}
79
+ # @author Sylvain Daubert
80
+ class Attributes < PacketGen::Types::Array
81
+ set_of Attribute
82
+ end
226
83
 
227
- undef id=
228
-
229
- # Set transform ID
230
- # @param [Integer,String] value
231
- # @return [Integer]
232
- def id=(value)
233
- id = case value
234
- when Integer
235
- value
236
- else
237
- c = self.class.constants.grep(/#{human_type}_#{value}/).first
238
- c ? self.class.const_get(c) : nil
239
- end
240
- raise ArgumentError, "unknown ID #{value.inspect}" unless id
241
- self[:id].value = id
242
- end
84
+ # SA Tranform substructure, as defined in RFC 7296 §3.3.2
85
+ # 1 2 3
86
+ # 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
87
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
88
+ # | Last Substruc | RESERVED | Transform Length |
89
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
90
+ # |Transform Type | RESERVED | Transform ID |
91
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
92
+ # | |
93
+ # ~ Transform Attributes ~
94
+ # | |
95
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
96
+ #
97
+ # == Create a Transform
98
+ # # using type and id names
99
+ # trans = PacketGen::Plugin::IKE::Transform.new(type: 'ENCR', id: 'AES_CBC')
100
+ # # using integer values
101
+ # trans = PacketGen::Plugin::IKE::Transform.new(type: 1, id: 12)
102
+ # == Add attributes to a transform
103
+ # # using an Attribute object
104
+ # attr = PacketGen::Plugin::IKE::Attribute.new(type: 14, value: 128)
105
+ # trans.attributes << attr
106
+ # # using a hash
107
+ # trans.attributes << { type: 14, value: 128 }
108
+ # @author Sylvain Daubert
109
+ class Transform < PacketGen::Types::Fields
110
+ # Transform types
111
+ TYPES = {
112
+ 'ENCR' => 1,
113
+ 'PRF' => 2,
114
+ 'INTG' => 3,
115
+ 'DH' => 4,
116
+ 'ESN' => 5
117
+ }.freeze
118
+
119
+ # DES encryption with 64-bit IV
120
+ ENCR_DES_IV64 = 1
121
+ # DES encryption
122
+ ENCR_DES = 2
123
+ # 3DES encryption
124
+ ENCR_3DES = 3
125
+ # RC5 integrity
126
+ ENCR_RC5 = 4
127
+ # IDEA encryption
128
+ ENCR_IDEA = 5
129
+ # Cast encryption
130
+ ENCR_CAST = 6
131
+ # Blowfish encryption
132
+ ENCR_BLOWFISH = 7
133
+ # 3IDEA encryption
134
+ ENCR_3IDEA = 8
135
+ # DES encryption with 32-bit IV
136
+ ENCR_DES_IV32 = 9
137
+ # AES with CBC mode encryption
138
+ ENCR_AES_CBC = 12
139
+ # AES with CTR mode encryption
140
+ ENCR_AES_CTR = 13
141
+ # AES with CCM mode encryption/authentication, 8-bytes ICV
142
+ ENCR_AES_CCM8 = 14
143
+ # AES with CCM mode encryption/authentication, 12-bytes ICV
144
+ ENCR_AES_CCM12 = 15
145
+ # AES with CCM mode encryption/authentication, 16-bytes ICV
146
+ ENCR_AES_CCM16 = 16
147
+ # AES with GCM mode encryption/authentication, 8-bytes ICV
148
+ ENCR_AES_GCM8 = 18
149
+ # AES with GCM mode encryption/authentication, 12-bytes ICV
150
+ ENCR_AES_GCM12 = 19
151
+ # AES with GCM mode encryption/authentication, 16-bytes ICV
152
+ ENCR_AES_GCM16 = 20
153
+ # CAMELLIA with CBC mode encryption
154
+ ENCR_CAMELLIA_CBC = 23
155
+ # CAMELLIA with CTR mode encryption
156
+ ENCR_CAMELLIA_CTR = 24
157
+ # CAMELLIA with CCM mode encryption/authentication, 8-bytes ICV
158
+ ENCR_CAMELLIA_CCM8 = 25
159
+ # CAMELLIA with CCM mode encryption/authentication, 12-bytes ICV
160
+ ENCR_CAMELLIA_CCM12 = 26
161
+ # CAMELLIA with CCM mode encryption/authentication, 16-bytes ICV
162
+ ENCR_CAMELLIA_CCM16 = 27
163
+ # CHACHA20 encryption with POLY1035 authentication
164
+ ENCR_CHACHA20_POLY1305 = 28
165
+
166
+ # PRF with HMAC on MD5
167
+ PRF_HMAC_MD5 = 1
168
+ # PRF with HMAC on SHA-1
169
+ PRF_HMAC_SHA1 = 2
170
+ # PRF with AES-128 with XCBC mode
171
+ PRF_AES128_XCBC = 4
172
+ # PRF with HMAC on SHA-256
173
+ PRF_HMAC_SHA2_256 = 5
174
+ # PRF with HMAC on SHA-384
175
+ PRF_HMAC_SHA2_384 = 6
176
+ # PRF with HMAC on SHA-512
177
+ PRF_HMAC_SHA2_512 = 7
178
+ # PRF with AES-128 withg CMAC mode
179
+ PRF_AES128_CMAC = 8
180
+
181
+ # No integrity
182
+ INTG_NONE = 0
183
+ # Integrity with HMAC on MD5, 96-bit ICV
184
+ INTG_HMAC_MD5_96 = 1
185
+ # Integrity with HMAC on SHA-1, 96-bit ICV
186
+ INTG_HMAC_SHA1_96 = 2
187
+ # Integrity with AES with XCBC mode, 96-bit ICV
188
+ INTG_AES_XCBC_96 = 5
189
+ # Integrity with HMAC on MD5, 128-bit ICV
190
+ INTG_HMAC_MD5_128 = 6
191
+ # Integrity with HMAC on SHA-1, 128-bit ICV
192
+ INTG_HMAC_SHA1_160 = 7
193
+ # Integrity with AES with CMAC mode, 96-bit ICV
194
+ INTG_AES_CMAC_96 = 8
195
+ # Integrity with AES-128 with GMAC mode, 128-bit ICV
196
+ INTG_AES128_GMAC = 9
197
+ # Integrity with AES-192 with GMAC mode, 128-bit ICV
198
+ INTG_AES192_GMAC = 10
199
+ # Integrity with AES-256 with GMAC mode, 128-bit ICV
200
+ INTG_AES256_GMAC = 11
201
+ # Integrity with HMAC on SHA-256, 128-bit ICV
202
+ INTG_HMAC_SHA2_256_128 = 12
203
+ # Integrity with HMAC on SHA-384, 192-bit ICV
204
+ INTG_HMAC_SHA2_384_192 = 13
205
+ # Integrity with HMAC on SHA-512, 256-bit ICV
206
+ INTG_HMAC_SHA2_512_256 = 14
207
+
208
+ # No key-exchange
209
+ DH_NONE = 0
210
+ # Key exchange with Diffie-Hellman on modp-768 group
211
+ DH_MODP768 = 1
212
+ # Key exchange with Diffie-Hellman on modp-1024 group
213
+ DH_MODP1024 = 2
214
+ # Key exchange with Diffie-Hellman on modp-1536 group
215
+ DH_MODP1536 = 5
216
+ # Key exchange with Diffie-Hellman on modp-2048 group
217
+ DH_MODP2048 = 14
218
+ # Key exchange with Diffie-Hellman on modp-3072 group
219
+ DH_MODP3072 = 15
220
+ # Key exchange with Diffie-Hellman on modp-4096 group
221
+ DH_MODP4096 = 16
222
+ # Key exchange with Diffie-Hellman on modp-6144 group
223
+ DH_MODP6144 = 17
224
+ # Key exchange with Diffie-Hellman on modp-8192 group
225
+ DH_MODP8192 = 18
226
+ # Key exchange with Diffie-Hellman on NIST p256 Elliptic curve
227
+ DH_ECP256 = 19
228
+ # Key exchange with Diffie-Hellman on NIST p384 Elliptic curve
229
+ DH_ECP384 = 20
230
+ # Key exchange with Diffie-Hellman on NIST p521 Elliptic curve
231
+ DH_ECP521 = 21
232
+ # Key exchange with Diffie-Hellman on Brainpool P224 Elliptic curve
233
+ DH_BRAINPOOLP224 = 27
234
+ # Key exchange with Diffie-Hellman on Brainpool P256 Elliptic curve
235
+ DH_BRAINPOOLP256 = 28
236
+ # Key exchange with Diffie-Hellman on Brainpool P384 Elliptic curve
237
+ DH_BRAINPOOLP384 = 29
238
+ # Key exchange with Diffie-Hellman on Brainpool P512 Elliptic curve
239
+ DH_BRAINPOOLP512 = 30
240
+ # Key exchange with Diffie-Hellman on curve25519 Elliptic curve
241
+ DH_CURVE25519 = 31
242
+ # Key exchange with Diffie-Hellman on curve448 Elliptic curve
243
+ DH_CURVE448 = 32
244
+
245
+ # No Extended Sequence Number
246
+ ESN_NO_ESN = 0
247
+ # Use Extended Sequence Number
248
+ ESN_ESN = 1
249
+
250
+ # @!attribute last
251
+ # 8-bit last substructure. Specifies whether or not this is the
252
+ # last Transform Substructure in the Proposal. This field has a value of 0
253
+ # if this was the last Transform Substructure, and a value of 3 if
254
+ # there are more Transform Substructures.
255
+ # @return [Integer]
256
+ define_field :last, PacketGen::Types::Int8
257
+ # @!attribute rsv1
258
+ # 8-bit reserved field
259
+ # @return [Integer]
260
+ define_field :rsv1, PacketGen::Types::Int8
261
+ # @!attribute length
262
+ # 16-bit transform length
263
+ # @return [Integer]
264
+ define_field :length, PacketGen::Types::Int16
265
+ # @!attribute [r] type
266
+ # 8-bit transform type. The Transform Type is the cryptographic
267
+ # algorithm type (i.e. encryption, PRF, integrity, etc.)
268
+ # @return [Integer]
269
+ define_field :type, PacketGen::Types::Int8Enum, enum: TYPES
270
+ # @!attribute rsv2
271
+ # 8-bit reserved field
272
+ # @return [Integer]
273
+ define_field :rsv2, PacketGen::Types::Int8
274
+ # @!attribute [r] id
275
+ # 16-bit transform ID. The Transform ID is the specific instance of
276
+ # the proposed transform type.
277
+ # @return [Integer]
278
+ define_field :id, PacketGen::Types::Int16
279
+ # @!attribute attributes
280
+ # Set of attributes for this transform
281
+ # @return [Attributes]
282
+ define_field :attributes, Attributes, builder: ->(h, t) { t.new(length_from: -> { h.length - h.offset_of(:attributes) }) }
283
+
284
+ def initialize(options={})
285
+ super
286
+ self.type = options[:type] if options[:type]
287
+ self.id = options[:id] if options[:id]
288
+ self[:length].value = sz unless options[:length]
289
+ end
243
290
 
244
- # Compute length and set {#length} field
245
- # @return [Integer] new length
246
- def calc_length
247
- PacketGen::Header::Base.calculate_and_set_length self
248
- end
291
+ undef id=
292
+
293
+ # Set transform ID
294
+ # @param [Integer,String] value
295
+ # @return [Integer]
296
+ def id=(value)
297
+ id = case value
298
+ when Integer
299
+ value
300
+ else
301
+ c = self.class.constants.grep(/#{human_type}_#{value}/).first
302
+ c ? self.class.const_get(c) : nil
303
+ end
304
+ raise ArgumentError, "unknown ID #{value.inspect}" unless id
305
+
306
+ self[:id].value = id
307
+ end
249
308
 
250
- # Get a human readable string
251
- # @return [String]
252
- def to_human
253
- h = "#{human_type}(#{human_id}".dup
254
- h << ",#{attributes.to_human}" unless attributes.empty?
255
- h << ')'
256
- end
309
+ # Compute length and set {#length} field
310
+ # @return [Integer] new length
311
+ def calc_length
312
+ PacketGen::Header::Base.calculate_and_set_length self
313
+ end
257
314
 
258
- # Get human-readable type
259
- # @return [String]
260
- def human_type
261
- if self[:type].enum.value? self.type
262
- self[:type].to_human
263
- else
264
- "type[#{self.type}]"
265
- end
266
- end
315
+ # Get a human readable string
316
+ # @return [String]
317
+ def to_human
318
+ h = +"#{human_type}(#{human_id}"
319
+ h << ",#{attributes.to_human}" unless attributes.empty?
267
320
 
268
- # Get human-readable ID
269
- # @return [String]
270
- def human_id
271
- name = self.class.constants.grep(/#{human_type}_/)
272
- .detect { |c| self.class.const_get(c) == id } || "ID=#{id}"
273
- name.to_s.sub(/#{human_type}_/, '')
274
- end
321
+ h << ')'
322
+ end
275
323
 
276
- # Say if this transform is the last one (from {#last} field)
277
- # @return [Boolean,nil] returns a Boolean when {#last} has defined value (+0+ => +true+, +3+ => +false+), else +nil+ is returned.
278
- def last?
279
- case last
280
- when 0
281
- true
282
- when 3
283
- false
284
- end
324
+ # Get human-readable type
325
+ # @return [String]
326
+ def human_type
327
+ if self[:type].enum.value? self.type
328
+ self[:type].to_human
329
+ else
330
+ "type[#{self.type}]"
285
331
  end
286
332
  end
287
333
 
288
- # Set of {Transform} in a {SAProposal}
289
- # @author Sylvain Daubert
290
- class Transforms < PacketGen::Types::Array
291
- set_of Transform
292
-
293
- # Same as {PacketGen::Types::Array#push} but update previous {Transform#last} attribute
294
- # @see PacketGen::Types::Array#push
295
- def push(trans)
296
- super
297
- self[-2].last = 3 if size > 1
298
- self[-1].last = 0
299
- self
300
- end
334
+ # Get human-readable ID
335
+ # @return [String]
336
+ def human_id
337
+ name = self.class.constants.grep(/#{human_type}_/)
338
+ .detect { |c| self.class.const_get(c) == id } || "ID=#{id}"
339
+ name.to_s.sub(/#{human_type}_/, '')
301
340
  end
302
341
 
303
- # SA Proposal, as defined in RFC 7296 §3.3.1
304
- # 1 2 3
305
- # 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
306
- # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
307
- # | Last Substruc | RESERVED | Proposal Length |
308
- # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
309
- # | Proposal Num | Protocol ID | SPI Size |Num Transforms|
310
- # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
311
- # ~ SPI (variable) ~
312
- # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
313
- # | |
314
- # ~ <Transforms> ~
315
- # | |
316
- # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
317
- #
318
- # == Create a proposal
319
- # # using protocol name
320
- # proposal = PacketGen::Plugin::IKE::Proposal.new(num: 1, protocol: 'IKE')
321
- # # using integer values
322
- # proposal = PacketGen::Plugin::IKE::Proposal.new(num: 1, protocol: 1)
323
- # == Add transforms to a proposal
324
- # # using a Transform object
325
- # trans = PacketGen::Plugin::IKE::Transform.new(type: 'ENCR', id: '3DES')
326
- # proposal.transforms << trans
327
- # # using a hash
328
- # proposal.transforms << { type: 'ENCR', id: '3DES' }
329
- # @author Sylvain Daubert
330
- class SAProposal < PacketGen::Types::Fields
331
- # @!attribute last
332
- # 8-bit last substructure. Specifies whether or not this is the
333
- # last Proposal Substructure in the SA. This field has a value of 0
334
- # if this was the last Proposal Substructure, and a value of 2 if
335
- # there are more Proposal Substructures.
336
- # @return [Integer]
337
- define_field :last, PacketGen::Types::Int8
338
- # @!attribute reserved
339
- # 8-bit reserved field
340
- # @return [Integer]
341
- define_field :reserved, PacketGen::Types::Int8
342
- # @!attribute length
343
- # 16-bit proposal length
344
- # @return [Integer]
345
- define_field :length, PacketGen::Types::Int16
346
- # @!attribute num
347
- # 8-bit proposal number. When a proposal is made, the first
348
- # proposal in an SA payload MUST be 1, and subsequent proposals MUST
349
- # be one more than the previous proposal (indicating an OR of the
350
- # two proposals). When a proposal is accepted, the proposal number
351
- # in the SA payload MUST match the number on the proposal sent that
352
- # was accepted.
353
- # @return [Integer]
354
- define_field :num, PacketGen::Types::Int8, default: 1
355
- # @!attribute [r] protocol
356
- # 8-bit protocol ID. Specify IPsec protocol currently negociated.
357
- # May 1 (IKE), 2 (AH) or 3 (ESP).
358
- # @return [Integer]
359
- define_field :protocol, PacketGen::Types::Int8Enum, enum: PROTOCOLS
360
- # @!attribute spi_size
361
- # 8-bit SPI size. Give size of SPI field. Set to 0 for an initial IKE SA
362
- # negotiation, as SPI is obtained from outer Plugin.
363
- # @return [Integer]
364
- define_field :spi_size, PacketGen::Types::Int8, default: 0
365
- # @!attribute num_trans
366
- # 8-bit number of transformations
367
- # @return [Integer]
368
- define_field :num_trans, PacketGen::Types::Int8, default: 0
369
- # @!attribute spi
370
- # the sending entity's SPI. When the {#spi_size} field is zero,
371
- # this field is not present in the proposal.
372
- # @return [String]
373
- define_field :spi, PacketGen::Types::String, builder: ->(h, t) { t.new(length_from: h[:spi_size]) }
374
- # @!attribute transforms
375
- # 8-bit set of tranforms for this proposal
376
- # @return [Transforms]
377
- define_field :transforms, Transforms, builder: ->(h, t) { t.new(counter: h[:num_trans]) }
378
-
379
- def initialize(options={})
380
- if options[:spi] && options[:spi_size].nil?
381
- options[:spi_size] = options[:spi].size
382
- end
383
- super
384
- self.length = sz unless options[:length]
385
- self.protocol = options[:protocol] if options[:protocol]
342
+ # Say if this transform is the last one (from {#last} field)
343
+ # @return [Boolean,nil] returns a Boolean when {#last} has defined value (+0+ => +true+, +3+ => +false+), else +nil+ is returned.
344
+ def last?
345
+ case last
346
+ when 0
347
+ true
348
+ when 3
349
+ false
386
350
  end
351
+ end
352
+ end
387
353
 
388
- # Compute length and set {#length} field
389
- # @return [Integer] new length
390
- def calc_length
391
- transforms.each(&:calc_length)
392
- PacketGen::Header::Base.calculate_and_set_length self
393
- end
354
+ # Set of {Transform} in a {SAProposal}
355
+ # @author Sylvain Daubert
356
+ class Transforms < PacketGen::Types::Array
357
+ set_of Transform
358
+
359
+ # Same as {PacketGen::Types::Array#push} but update previous {Transform#last} attribute
360
+ # @see PacketGen::Types::Array#push
361
+ def push(trans)
362
+ super
363
+ self[-2].last = 3 if size > 1
364
+ self[-1].last = 0
365
+ self
366
+ end
367
+ end
394
368
 
395
- # Get a human readable string
396
- # @return [String]
397
- def to_human
398
- str = "##{num} #{human_protocol}".dup
399
- case spi_size
400
- when 4
401
- str << '(spi:0x%08x)' % PacketGen::Types::Int32.new.read(spi).to_i
402
- when 8
403
- str << '(spi:0x%016x)' % PacketGen::Types::Int64.new.read(spi).to_i
404
- end
405
- str << ":#{transforms.to_human}"
406
- end
369
+ # SA Proposal, as defined in RFC 7296 §3.3.1
370
+ # 1 2 3
371
+ # 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
372
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
373
+ # | Last Substruc | RESERVED | Proposal Length |
374
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
375
+ # | Proposal Num | Protocol ID | SPI Size |Num Transforms|
376
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
377
+ # ~ SPI (variable) ~
378
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
379
+ # | |
380
+ # ~ <Transforms> ~
381
+ # | |
382
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
383
+ #
384
+ # == Create a proposal
385
+ # # using protocol name
386
+ # proposal = PacketGen::Plugin::IKE::Proposal.new(num: 1, protocol: 'IKE')
387
+ # # using integer values
388
+ # proposal = PacketGen::Plugin::IKE::Proposal.new(num: 1, protocol: 1)
389
+ # == Add transforms to a proposal
390
+ # # using a Transform object
391
+ # trans = PacketGen::Plugin::IKE::Transform.new(type: 'ENCR', id: '3DES')
392
+ # proposal.transforms << trans
393
+ # # using a hash
394
+ # proposal.transforms << { type: 'ENCR', id: '3DES' }
395
+ # @author Sylvain Daubert
396
+ class SAProposal < PacketGen::Types::Fields
397
+ # @!attribute last
398
+ # 8-bit last substructure. Specifies whether or not this is the
399
+ # last Proposal Substructure in the SA. This field has a value of 0
400
+ # if this was the last Proposal Substructure, and a value of 2 if
401
+ # there are more Proposal Substructures.
402
+ # @return [Integer]
403
+ define_field :last, PacketGen::Types::Int8
404
+ # @!attribute reserved
405
+ # 8-bit reserved field
406
+ # @return [Integer]
407
+ define_field :reserved, PacketGen::Types::Int8
408
+ # @!attribute length
409
+ # 16-bit proposal length
410
+ # @return [Integer]
411
+ define_field :length, PacketGen::Types::Int16
412
+ # @!attribute num
413
+ # 8-bit proposal number. When a proposal is made, the first
414
+ # proposal in an SA payload MUST be 1, and subsequent proposals MUST
415
+ # be one more than the previous proposal (indicating an OR of the
416
+ # two proposals). When a proposal is accepted, the proposal number
417
+ # in the SA payload MUST match the number on the proposal sent that
418
+ # was accepted.
419
+ # @return [Integer]
420
+ define_field :num, PacketGen::Types::Int8, default: 1
421
+ # @!attribute [r] protocol
422
+ # 8-bit protocol ID. Specify IPsec protocol currently negociated.
423
+ # May 1 (IKE), 2 (AH) or 3 (ESP).
424
+ # @return [Integer]
425
+ define_field :protocol, PacketGen::Types::Int8Enum, enum: PROTOCOLS
426
+ # @!attribute spi_size
427
+ # 8-bit SPI size. Give size of SPI field. Set to 0 for an initial IKE SA
428
+ # negotiation, as SPI is obtained from outer Plugin.
429
+ # @return [Integer]
430
+ define_field :spi_size, PacketGen::Types::Int8, default: 0
431
+ # @!attribute num_trans
432
+ # 8-bit number of transformations
433
+ # @return [Integer]
434
+ define_field :num_trans, PacketGen::Types::Int8, default: 0
435
+ # @!attribute spi
436
+ # the sending entity's SPI. When the {#spi_size} field is zero,
437
+ # this field is not present in the proposal.
438
+ # @return [String]
439
+ define_field :spi, PacketGen::Types::String, builder: ->(h, t) { t.new(length_from: h[:spi_size]) }
440
+ # @!attribute transforms
441
+ # 8-bit set of tranforms for this proposal
442
+ # @return [Transforms]
443
+ define_field :transforms, Transforms, builder: ->(h, t) { t.new(counter: h[:num_trans]) }
444
+
445
+ def initialize(options={})
446
+ options[:spi_size] = options[:spi].size if options[:spi] && options[:spi_size].nil?
447
+ super
448
+ self.length = sz unless options[:length]
449
+ self.protocol = options[:protocol] if options[:protocol]
450
+ end
407
451
 
408
- # Get protocol name
409
- # @return [String]
410
- def human_protocol
411
- self[:protocol].to_human
412
- end
452
+ # Compute length and set {#length} field
453
+ # @return [Integer] new length
454
+ def calc_length
455
+ transforms.each(&:calc_length)
456
+ PacketGen::Header::Base.calculate_and_set_length self
457
+ end
413
458
 
414
- # Say if this proposal is the last one (from {#last} field)
415
- # @return [Boolean,nil] returns a Boolean when {#last} has defined value
416
- # (+0+ => +true+, +2+ => +false+), else +nil+ is returned.
417
- def last?
418
- case last
419
- when 0
420
- true
421
- when 2
422
- false
423
- end
459
+ # Get a human readable string
460
+ # @return [String]
461
+ def to_human
462
+ str = +"##{num} #{human_protocol}"
463
+ case spi_size
464
+ when 4
465
+ str << '(spi:0x%08x)' % PacketGen::Types::Int32.new.read(spi).to_i
466
+ when 8
467
+ str << '(spi:0x%016x)' % PacketGen::Types::Int64.new.read(spi).to_i
424
468
  end
469
+ str << ":#{transforms.to_human}"
425
470
  end
426
471
 
427
- # Set of {SAProposal}
428
- # @author Sylvain Daubert
429
- class SAProposals < PacketGen::Types::Array
430
- set_of SAProposal
431
-
432
- # Separator used between proposals in {#to_human}
433
- HUMAN_SEPARATOR = '; '
434
-
435
- # Same as {PacketGen::Types::Array#push} but update previous {SAProposal#last} attribute
436
- # @see PacketGen::Types::Array#push
437
- def push(prop)
438
- super
439
- self[-2].last = 2 if size > 1
440
- self[-1].last = 0
441
- self
442
- end
472
+ # Get protocol name
473
+ # @return [String]
474
+ def human_protocol
475
+ self[:protocol].to_human
443
476
  end
444
477
 
445
- # This class handles Security Assocation payloads, as defined in RFC 7296 §3.3.
446
- #
447
- # A SA payload contains a generic payload Plugin (see {Payload}) and a set of
448
- # {SAProposal} ({#proposals} field, which is a {SAProposals} object):
449
- # 1 2 3
450
- # 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
451
- # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
452
- # | Next Payload |C| RESERVED | Payload Length |
453
- # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
454
- # | |
455
- # ~ <Proposals> ~
456
- # | |
457
- # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
458
- #
459
- # == Create a SA payload
460
- # # Create a IKE packet with a SA payload
461
- # pkt = PacketGen.gen('IP').add('UDP').add('IKE').add('IKE::SA')
462
- # # add a proposal. Protocol name is taken from SAProposal::PROTO_* constants
463
- # pkt.ike_sa.proposals << { num: 1, protocol: 'ESP' }
464
- # # add a transform to this proposal.
465
- # # type name is taken from Transform::TYPE_* constants.
466
- # # ID is taken from Transform::<TYPE>_* constants.
467
- # pkt.ike_sa.proposals.first.transforms << { type: 'ENCR', id: 'AES_CTR' }
468
- # # and finally, add an attribute to this transform (here, KEY_SIZE = 128 bits)
469
- # pkt.ike_sa.proposals[0].transforms[0].attributes << { type: 0x800e, value: 128 }
470
- # pkt.calc_length
471
- # @author Sylvain Daubert
472
- class SA < Payload
473
- # Payload type number
474
- PAYLOAD_TYPE = 33
475
-
476
- remove_field :content
477
-
478
- # @!attribute proposals
479
- # Set of SA proposals
480
- # @return [SAProposals]
481
- define_field_before :body, :proposals, SAProposals, builder: ->(h, t) { t.new(length_from: -> { h.length - h.offset_of(:proposals) }) }
482
-
483
- # Compute length and set {#length} field
484
- # @return [Integer] new length
485
- def calc_length
486
- proposals.each(&:calc_length)
487
- super
478
+ # Say if this proposal is the last one (from {#last} field)
479
+ # @return [Boolean,nil] returns a Boolean when {#last} has defined value
480
+ # (+0+ => +true+, +2+ => +false+), else +nil+ is returned.
481
+ def last?
482
+ case last
483
+ when 0
484
+ true
485
+ when 2
486
+ false
488
487
  end
489
488
  end
490
489
  end
491
490
 
492
- Header.add_class IKE::SA
491
+ # Set of {SAProposal}
492
+ # @author Sylvain Daubert
493
+ class SAProposals < PacketGen::Types::Array
494
+ set_of SAProposal
495
+
496
+ # Separator used between proposals in {#to_human}
497
+ HUMAN_SEPARATOR = '; '
498
+
499
+ # Same as {PacketGen::Types::Array#push} but update previous {SAProposal#last} attribute
500
+ # @see PacketGen::Types::Array#push
501
+ def push(prop)
502
+ super
503
+ self[-2].last = 2 if size > 1
504
+ self[-1].last = 0
505
+ self
506
+ end
507
+ end
508
+
509
+ # This class handles Security Assocation payloads, as defined in RFC 7296 §3.3.
510
+ #
511
+ # A SA payload contains a generic payload Plugin (see {Payload}) and a set of
512
+ # {SAProposal} ({#proposals} field, which is a {SAProposals} object):
513
+ # 1 2 3
514
+ # 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
515
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
516
+ # | Next Payload |C| RESERVED | Payload Length |
517
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
518
+ # | |
519
+ # ~ <Proposals> ~
520
+ # | |
521
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
522
+ #
523
+ # == Create a SA payload
524
+ # # Create a IKE packet with a SA payload
525
+ # pkt = PacketGen.gen('IP').add('UDP').add('IKE').add('IKE::SA')
526
+ # # add a proposal. Protocol name is taken from SAProposal::PROTO_* constants
527
+ # pkt.ike_sa.proposals << { num: 1, protocol: 'ESP' }
528
+ # # add a transform to this proposal.
529
+ # # type name is taken from Transform::TYPE_* constants.
530
+ # # ID is taken from Transform::<TYPE>_* constants.
531
+ # pkt.ike_sa.proposals.first.transforms << { type: 'ENCR', id: 'AES_CTR' }
532
+ # # and finally, add an attribute to this transform (here, KEY_SIZE = 128 bits)
533
+ # pkt.ike_sa.proposals[0].transforms[0].attributes << { type: 0x800e, value: 128 }
534
+ # pkt.calc_length
535
+ # @author Sylvain Daubert
536
+ class SA < Payload
537
+ # Payload type number
538
+ PAYLOAD_TYPE = 33
539
+
540
+ remove_field :content
541
+
542
+ # @!attribute proposals
543
+ # Set of SA proposals
544
+ # @return [SAProposals]
545
+ define_field_before :body, :proposals, SAProposals, builder: ->(h, t) { t.new(length_from: -> { h.length - h.offset_of(:proposals) }) }
546
+
547
+ # Compute length and set {#length} field
548
+ # @return [Integer] new length
549
+ def calc_length
550
+ proposals.each(&:calc_length)
551
+ super
552
+ end
553
+ end
493
554
  end
555
+
556
+ PacketGen::Header.add_class IKE::SA
494
557
  end