packetgen-plugin-ipsec 1.0.2 → 1.0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -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