packetgen-plugin-ipsec 1.0.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.
@@ -0,0 +1,66 @@
1
+ # coding: utf-8
2
+ # This file is part of IPsec packetgen plugin.
3
+ # See https://github.com/sdaubert/packetgen-plugin-ipsec for more informations
4
+ # Copyright (c) 2018 Sylvain Daubert <sylvain.daubert@laposte.net>
5
+ # This program is published under MIT license.
6
+
7
+ # frozen_string_literal: true
8
+
9
+ module PacketGen
10
+ module Plugin
11
+ class IKE
12
+ # This class handles Certificate Request payloads.
13
+ #
14
+ # A CertReq payload consists of the IKE generic payload Plugin (see {Payload})
15
+ # and some specific fields:
16
+ # 1 2 3
17
+ # 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
18
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
19
+ # | Next Payload |C| RESERVED | Payload Length |
20
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
21
+ # | Cert Encoding | |
22
+ # +-+-+-+-+-+-+-+-+ +
23
+ # | |
24
+ # ~ Certification Authority ~
25
+ # | |
26
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
27
+ # These specific fields are:
28
+ # * {#encoding},
29
+ # * and {#content} (Certification Authority).
30
+ #
31
+ # == Create a CertReq payload
32
+ # # Create a IKE packet with a CertReq payload
33
+ # pkt = PacketGen.gen('IP').add('UDP').add('IKE').add('IKE::CertReq', encoding: 'X509_CERT_SIG')
34
+ # pkt.ike_certreq.content.read OpenSSL::Digest::SHA1.digest(ca_cert.to_der)
35
+ # pkt.calc_length
36
+ # @author Sylvain Daubert
37
+ class CertReq < Cert
38
+ # Payload type number
39
+ PAYLOAD_TYPE = 38
40
+
41
+ # Get list of 20-byte string (SHA-1 hashes)
42
+ # @return [String]
43
+ def human_content
44
+ strs = []
45
+ idx = 0
46
+ while idx < content.size
47
+ strs << content[idx, 20]
48
+ idx += 20
49
+ end
50
+ strs.map(&:inspect).join(',')
51
+ end
52
+
53
+ # @return [String]
54
+ def inspect
55
+ super do |attr|
56
+ next unless attr == :content
57
+ str = Inspect.shift_level
58
+ str << Inspect::FMT_ATTR % ['hashes', :content, human_content]
59
+ end
60
+ end
61
+ end
62
+ end
63
+
64
+ Header.add_class IKE::CertReq
65
+ end
66
+ end
@@ -0,0 +1,99 @@
1
+ # coding: utf-8
2
+ # This file is part of IPsec packetgen plugin.
3
+ # See https://github.com/sdaubert/packetgen-plugin-ipsec for more informations
4
+ # Copyright (c) 2018 Sylvain Daubert <sylvain.daubert@laposte.net>
5
+ # This program is published under MIT license.
6
+
7
+ # frozen_string_literal: true
8
+
9
+ module PacketGen
10
+ module Plugin
11
+ class IKE
12
+ # This class handles Identification - Initiator payloads, denoted IDi
13
+ # (see RFC 7296, §3.5).
14
+ #
15
+ # A ID payload consists of the IKE generic payload Plugin (see {Payload})
16
+ # and some specific fields:
17
+ # 1 2 3
18
+ # 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
19
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
20
+ # | Next Payload |C| RESERVED | Payload Length |
21
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
22
+ # | ID Type | RESERVED |
23
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
24
+ # | |
25
+ # ~ Identification Data ~
26
+ # | |
27
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
28
+ # These specific fields are:
29
+ # * {#type} (ID type),
30
+ # * {#reserved},
31
+ # * and {#content} (Identification Data).
32
+ #
33
+ # == Create a IDi payload
34
+ # # Create a IKE packet with a IDi payload
35
+ # pkt = PacketGen.gen('IP').add('UDP').add('IKE').add('IKE::IDi', type: 'FQDN')
36
+ # pkt.ike_idi.content.read 'fqdn.example.org'
37
+ # pkt.calc_length
38
+ # @author Sylvain Daubert
39
+ class IDi < Payload
40
+ # Payload type number
41
+ PAYLOAD_TYPE = 35
42
+
43
+ TYPES = {
44
+ 'IPV4_ADDR' => 1,
45
+ 'FQDN' => 2,
46
+ 'RFC822_ADDR' => 3,
47
+ 'IPV6_ADDR' => 5,
48
+ 'DER_ASN1_DN' => 9,
49
+ 'DER_ASN1_GN' => 10,
50
+ 'KEY_ID' => 11
51
+ }.freeze
52
+
53
+ # @attribute [r] type
54
+ # 8-bit ID type
55
+ # @return [Integer]
56
+ define_field_before :content, :type, PacketGen::Types::Int8Enum, enum: TYPES
57
+ # @attribute reserved
58
+ # 24-bit reserved field
59
+ # @return [Integer]
60
+ define_field_before :content, :reserved, PacketGen::Types::Int24
61
+
62
+ # Get ID type name
63
+ # @return [String]
64
+ def human_type
65
+ self[:type].to_human
66
+ end
67
+
68
+ # Get human readable content, from {#type}
69
+ # @return [String]
70
+ def human_content
71
+ case type
72
+ when TYPES['IPV4_ADDR'], TYPES['IPV4_ADDR']
73
+ IPAddr.ntop(content)
74
+ when TYPES['DER_ASN1_DN'], TYPES['DER_ASN1_GN']
75
+ OpenSSL::X509::Name.new(content).to_s
76
+ else
77
+ content.inspect
78
+ end
79
+ end
80
+ end
81
+
82
+ # This class handles Identification - Responder payloads, denoted IDr.
83
+ # See {IDi}.
84
+ #
85
+ # == Create a IDr payload
86
+ # # Create a IKE packet with a IDr payload
87
+ # pkt = PacketGen.gen('IP').add('UDP').add('IKE').add('IKE::IDr', type: 'FQDN')
88
+ # pkt.ike_idr.content.read 'fqdn.example.org'
89
+ # @author Sylvain Daubert
90
+ class IDr < IDi
91
+ # Payload type number
92
+ PAYLOAD_TYPE = 36
93
+ end
94
+ end
95
+
96
+ Header.add_class IKE::IDi
97
+ Header.add_class IKE::IDr
98
+ end
99
+ end
@@ -0,0 +1,79 @@
1
+ # coding: utf-8
2
+ # This file is part of IPsec packetgen plugin.
3
+ # See https://github.com/sdaubert/packetgen-plugin-ipsec for more informations
4
+ # Copyright (c) 2018 Sylvain Daubert <sylvain.daubert@laposte.net>
5
+ # This program is published under MIT license.
6
+
7
+ # frozen_string_literal: true
8
+
9
+ module PacketGen
10
+ module Plugin
11
+ class IKE
12
+ # This class handles Key Exchange payloads, as defined in RFC 7296 §3.4
13
+ #
14
+ # A KE payload contains a generic payload Plugin (see {Payload}) and some
15
+ # specific fields:
16
+ # 1 2 3
17
+ # 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
18
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
19
+ # | Next Payload |C| RESERVED | Payload Length |
20
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
21
+ # | Diffie-Hellman Group Num | RESERVED |
22
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
23
+ # | |
24
+ # ~ Key Exchange Data ~
25
+ # | |
26
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
27
+ # These specific fields are:
28
+ # * {#group_num} (type {PacketGen::Types::Int16}),
29
+ # * {#reserved} (type {PacketGen::Types::Int16}),
30
+ # * and {#content} (type {PacketGen::Types::String}).
31
+ #
32
+ # == Create a KE payload
33
+ # # Create a IKE packet with a KE payload
34
+ # pkt = PacketGen.gen('IP').add('UDP').add('IKE')
35
+ # # group name is taken from Transform::DH_* constants
36
+ # pkt.add('IKE::KE', group: 'MODP4096')
37
+ # # group number may also be used
38
+ # pkt.ike_ke.group = 1
39
+ # pkt.calc_length
40
+ # @author Sylvain Daubert
41
+ class KE < Payload
42
+ # Payload type number
43
+ PAYLOAD_TYPE = 34
44
+
45
+ # @!attribute group_num
46
+ # 16-bit DH group number
47
+ # @return [Integer]
48
+ define_field_before :content, :group_num, PacketGen::Types::Int16
49
+ # @!attribute reserved
50
+ # 16-bit reserved field
51
+ # @return [Integer]
52
+ define_field_before :content, :reserved, PacketGen::Types::Int16, default: 0
53
+
54
+ def initialize(options={})
55
+ super
56
+ self.group = options[:group] if options[:group]
57
+ end
58
+
59
+ # Set group
60
+ # @param [Integer,String] value may be a String taken from
61
+ # {Transform}+::DH_*+ constant names.
62
+ # @return [Integer]
63
+ def group=(value)
64
+ group = case value
65
+ when Integer
66
+ value
67
+ else
68
+ cname = "DH_#{value}"
69
+ Transform.const_defined?(cname) ? Transform.const_get(cname) : nil
70
+ end
71
+ raise ArgumentError, "unknown group #{value.inspect}" unless group
72
+ self[:group_num].value = group
73
+ end
74
+ end
75
+ end
76
+
77
+ Header.add_class IKE::KE
78
+ end
79
+ end
@@ -0,0 +1,40 @@
1
+ # coding: utf-8
2
+ # This file is part of IPsec packetgen plugin.
3
+ # See https://github.com/sdaubert/packetgen-plugin-ipsec for more informations
4
+ # Copyright (c) 2018 Sylvain Daubert <sylvain.daubert@laposte.net>
5
+ # This program is published under MIT license.
6
+
7
+ # frozen_string_literal: true
8
+
9
+ module PacketGen
10
+ module Plugin
11
+ class IKE
12
+ # This class handles Nonce payloads, as defined in RFC 7296 §3.9.
13
+ #
14
+ # A Nonce payload contains a generic payload Plugin (see {Payload}) and
15
+ # data field (type {PacketGen::Types::String}):
16
+ # 1 2 3
17
+ # 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
18
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
19
+ # | Next Payload |C| RESERVED | Payload Length |
20
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
21
+ # | |
22
+ # ~ Nonce Data ~
23
+ # | |
24
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
25
+ #
26
+ # == Create a Nonce payload
27
+ # # Create a IKE packet with a Nonce payload
28
+ # pkt = PacketGen.gen('IP').add('UDP').add('IKE')
29
+ # pkt.add('IKE::Nonce', data: "abcdefgh")
30
+ # pkt.calc_length
31
+ # @author Sylvain Daubert
32
+ class Nonce < Payload
33
+ # Payload type number
34
+ PAYLOAD_TYPE = 40
35
+ end
36
+ end
37
+
38
+ Header.add_class IKE::Nonce
39
+ end
40
+ end
@@ -0,0 +1,159 @@
1
+ # coding: utf-8
2
+ # This file is part of IPsec packetgen plugin.
3
+ # See https://github.com/sdaubert/packetgen-plugin-ipsec for more informations
4
+ # Copyright (c) 2018 Sylvain Daubert <sylvain.daubert@laposte.net>
5
+ # This program is published under MIT license.
6
+
7
+ # frozen_string_literal: true
8
+
9
+ module PacketGen
10
+ module Plugin
11
+ class IKE
12
+ # This class handles Notify payloads, as defined in RFC 7296 §3.10.
13
+ #
14
+ # A Notify payload contains a generic payload Plugin (see {Payload}) and
15
+ # some specific fields:
16
+ # 1 2 3
17
+ # 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
18
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
19
+ # | Next Payload |C| RESERVED | Payload Length |
20
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
21
+ # | Protocol ID | SPI Size | Notify Message Type |
22
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
23
+ # | |
24
+ # ~ Security Parameter Index (SPI) ~
25
+ # | |
26
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
27
+ # | |
28
+ # ~ Notification Data ~
29
+ # | |
30
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
31
+ # These specific fields are:
32
+ # * {#protocol} (type {PacketGen::Types::Int8}),
33
+ # * {#spi_size} (type {PacketGen::Types::Int8}),
34
+ # * {#message_type} (type {PacketGen::Types::Int16}),
35
+ # * {#spi} (type {PacketGen::Types::String}),
36
+ # * {#content} (type {PacketGen::Types::String}).
37
+ #
38
+ # == Create a Notify payload
39
+ # # Create a IKE packet with a Notify payload
40
+ # pkt = PacketGen.gen('IP').add('UDP').add('IKE').add('IKE::Notify', protocol: 'IKE', type: 'INVALID_SYNTAX')
41
+ # pkt.ike_notify.spi # => ""
42
+ # pkt.ike_notify.content # => ""
43
+ # pkt.calc_length
44
+ # == Create a Notify payload with a SPI
45
+ # # Create a IKE packet with a Notify payload
46
+ # pkt = PacketGen.gen('IP').add('UDP').add('IKE').add('IKE::Notify', protocol: 'ESP', spi_size: 4, type: 'INVALID_SYNTAX')
47
+ # pkt.ike_notify.spi.read PacketGen::Types::Int32.new(0x12345678).to_s
48
+ # pkt.calc_length
49
+ # @author Sylvain Daubert
50
+ class Notify < Payload
51
+ # Payload type number
52
+ PAYLOAD_TYPE = 41
53
+
54
+ # Message types
55
+ TYPES = {
56
+ 'UNSUPPORTED_CRITICAL_PAYLOAD' => 1,
57
+ 'INVALID_IKE_SPI' => 4,
58
+ 'INVALID_MAJOR_VERSION' => 5,
59
+ 'INVALID_SYNTAX' => 7,
60
+ 'INVALID_MESSAGE_ID' => 9,
61
+ 'INVALID_SPI' => 11,
62
+ 'NO_PROPOSAL_CHOSEN' => 14,
63
+ 'INVALID_KE_PAYLOAD' => 17,
64
+ 'AUTHENTICATION_FAILED' => 24,
65
+ 'SINGLE_PAIR_REQUIRED' => 34,
66
+ 'NO_ADDITIONAL_SAS' => 35,
67
+ 'INTERNAL_ADDRESS_FAILURE' => 36,
68
+ 'FAILED_CP_REQUIRED' => 37,
69
+ 'TS_UNACCEPTABLE' => 38,
70
+ 'INVALID_SELECTORS' => 39,
71
+ 'TEMPORARY_FAILURE' => 43,
72
+ 'CHILD_SA_NOT_FOUND' => 44,
73
+ 'INITIAL_CONTACT' => 16_384,
74
+ 'SET_WINDOW_SIZE' => 16_385,
75
+ 'ADDITIONAL_TS_POSSIBLE' => 16_386,
76
+ 'IPCOMP_SUPPORTED' => 16_387,
77
+ 'NAT_DETECTION_SOURCE_IP' => 16_388,
78
+ 'NAT_DETECTION_DESTINATION_IP' => 16_389,
79
+ 'COOKIE' => 16_390,
80
+ 'USE_TRANSPORT_MODE' => 16_391,
81
+ 'HTTP_CERT_LOOKUP_SUPPORTED' => 16_392,
82
+ 'REKEY_SA' => 16_393,
83
+ 'ESP_TFC_PADDING_NOT_SUPPORTED' => 16_394,
84
+ 'NON_FIRST_FRAGMENTS_ALSO' => 16_395,
85
+ }.freeze
86
+
87
+ # @!attribute [r] protocol
88
+ # 8-bit protocol ID. If this notification concerns an existing
89
+ # SA whose SPI is given in the SPI field, this field indicates the
90
+ # type of that SA. For notifications concerning Child SAs, this
91
+ # field MUST contain either (2) to indicate AH or (3) to indicate
92
+ # ESP. Of the notifications defined in this document, the SPI is
93
+ # included only with INVALID_SELECTORS, REKEY_SA, and
94
+ # CHILD_SA_NOT_FOUND. If the SPI field is empty, this field MUST be
95
+ # sent as zero and MUST be ignored on receipt.
96
+ # @return [Integer]
97
+ define_field_before :content, :protocol, PacketGen::Types::Int8Enum, enum: PROTOCOLS
98
+ # @!attribute spi_size
99
+ # 8-bit SPI size. Give size of SPI field. Length in octets of the SPI as
100
+ # defined by the IPsec protocol ID or zero if no SPI is applicable. For a
101
+ # notification concerning the IKE SA, the SPI Size MUST be zero and
102
+ # the field must be empty.Set to 0 for an initial IKE SA
103
+ # negotiation, as SPI is obtained from outer Plugin.
104
+ # @return [Integer]
105
+ define_field_before :content, :spi_size, PacketGen::Types::Int8, default: 0
106
+ # @!attribute message_type
107
+ # 16-bit notify message type. Specifies the type of notification message.
108
+ # @return [Integer]
109
+ define_field_before :content, :message_type, PacketGen::Types::Int16Enum, enum: TYPES, default: 0
110
+ # @!attribute spi
111
+ # the sending entity's SPI. When the {#spi_size} field is zero,
112
+ # this field is not present in the proposal.
113
+ # @return [String]
114
+ define_field_before :content, :spi, PacketGen::Types::String,
115
+ builder: ->(h, t) { t.new(length_from: h[:spi_size]) }
116
+
117
+ alias type message_type
118
+
119
+ def initialize(options={})
120
+ if options[:spi] && options[:spi_size].nil?
121
+ options[:spi_size] = options[:spi].size
122
+ end
123
+ super
124
+ self.protocol = options[:protocol] if options[:protocol]
125
+ self.message_type = options[:message_type] if options[:message_type]
126
+ self.message_type = options[:type] if options[:type]
127
+ end
128
+
129
+ alias type= message_type=
130
+
131
+ # Get protocol name
132
+ # @return [String]
133
+ def human_protocol
134
+ self[:protocol].to_human
135
+ end
136
+
137
+ # Get message type name
138
+ # @return [String]
139
+ def human_message_type
140
+ self[:message_type].to_human
141
+ end
142
+ alias human_type human_message_type
143
+
144
+ # @return [String]
145
+ def inspect
146
+ super do |attr|
147
+ next unless attr == :protocol
148
+
149
+ str = Inspect.shift_level
150
+ str << Inspect::FMT_ATTR % [self[attr].class.to_s.sub(/.*::/, ''), attr,
151
+ human_protocol]
152
+ end
153
+ end
154
+ end
155
+ end
156
+
157
+ Header.add_class IKE::Notify
158
+ end
159
+ end