simple_nts_client 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +16 -0
  3. data/.rubocop.yml +24 -0
  4. data/.travis.yml +17 -0
  5. data/Gemfile +14 -0
  6. data/LICENSE.txt +21 -0
  7. data/README.md +57 -0
  8. data/Rakefile +10 -0
  9. data/exe/simple_nts_client +8 -0
  10. data/lib/nts/cli.rb +83 -0
  11. data/lib/nts/ntske/client.rb +100 -0
  12. data/lib/nts/ntske/message/aead_algorithm_negotiation.rb +47 -0
  13. data/lib/nts/ntske/message/cookie.rb +33 -0
  14. data/lib/nts/ntske/message/end_of_message.rb +30 -0
  15. data/lib/nts/ntske/message/error_record.rb +39 -0
  16. data/lib/nts/ntske/message/nts_next_protocol_negotiation.rb +35 -0
  17. data/lib/nts/ntske/message/ntsv4_port_negotiation.rb +36 -0
  18. data/lib/nts/ntske/message/ntsv4_server_negotiation.rb +36 -0
  19. data/lib/nts/ntske/message/warning_record.rb +34 -0
  20. data/lib/nts/ntske/message.rb +107 -0
  21. data/lib/nts/ntske.rb +4 -0
  22. data/lib/nts/sntp/client.rb +160 -0
  23. data/lib/nts/sntp/extension/nts_authenticator.rb +53 -0
  24. data/lib/nts/sntp/extension/nts_cookie.rb +34 -0
  25. data/lib/nts/sntp/extension/unique_identifier.rb +36 -0
  26. data/lib/nts/sntp/extension/unknown_extension.rb +36 -0
  27. data/lib/nts/sntp/extension.rb +38 -0
  28. data/lib/nts/sntp/message.rb +119 -0
  29. data/lib/nts/sntp.rb +4 -0
  30. data/lib/nts/version.rb +5 -0
  31. data/lib/nts.rb +12 -0
  32. data/simple_nts_client.gemspec +27 -0
  33. data/spec/aead_algorithm_negotiation_spec.rb +28 -0
  34. data/spec/cookie_spec.rb +36 -0
  35. data/spec/end_of_message_spec.rb +26 -0
  36. data/spec/error_record_spec.rb +28 -0
  37. data/spec/extension_spec.rb +28 -0
  38. data/spec/nts_authenticator_spec.rb +64 -0
  39. data/spec/nts_cookie_spec.rb +36 -0
  40. data/spec/nts_next_protocol_negotiation_spec.rb +28 -0
  41. data/spec/ntsv4_port_negotiation_spec.rb +28 -0
  42. data/spec/ntsv4_server_negotiation_spec.rb +28 -0
  43. data/spec/spec_helper.rb +11 -0
  44. data/spec/unique_identifier_spec.rb +36 -0
  45. data/spec/unknown_extension_spec.rb +46 -0
  46. data/spec/warning_record_spec.rb +28 -0
  47. metadata +145 -0
@@ -0,0 +1,36 @@
1
+ # encoding: ascii-8bit
2
+ # frozen_string_literal: true
3
+
4
+ require_relative 'spec_helper'
5
+
6
+ RSpec.describe Cookie do
7
+ context 'initialized with random binary' do
8
+ let(:rb) do
9
+ OpenSSL::Random.random_bytes(32)
10
+ end
11
+
12
+ let(:message) do
13
+ Cookie.new(rb)
14
+ end
15
+
16
+ it 'should be serialized' do
17
+ expect(message.cookie).to eq rb
18
+ expect(message.serialize).to eq "\x00\x05\x00\x20" + rb
19
+ end
20
+ end
21
+
22
+ context 'received random binary' do
23
+ let(:rb) do
24
+ OpenSSL::Random.random_bytes(32)
25
+ end
26
+
27
+ let(:message) do
28
+ Cookie.deserialize(rb, false)
29
+ end
30
+
31
+ it 'should be deserialized' do
32
+ expect(message.cookie).to eq rb
33
+ expect(message.serialize).to eq "\x00\x05\x00\x20" + rb
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,26 @@
1
+ # encoding: ascii-8bit
2
+ # frozen_string_literal: true
3
+
4
+ require_relative 'spec_helper'
5
+
6
+ RSpec.describe EndOfMessage do
7
+ context 'initialized' do
8
+ let(:message) do
9
+ EndOfMessage.new
10
+ end
11
+
12
+ it 'should be serialized' do
13
+ expect(message.serialize).to eq "\x80\x00\x00\x00"
14
+ end
15
+ end
16
+
17
+ context 'received empty string' do
18
+ let(:message) do
19
+ EndOfMessage.deserialize('')
20
+ end
21
+
22
+ it 'should be deserialized' do
23
+ expect(message.serialize).to eq "\x80\x00\x00\x00"
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,28 @@
1
+ # encoding: ascii-8bit
2
+ # frozen_string_literal: true
3
+
4
+ require_relative 'spec_helper'
5
+
6
+ RSpec.describe ErrorRecord do
7
+ context 'initialized with BAD_REQUEST' do
8
+ let(:message) do
9
+ ErrorRecord.new(ErrorCode::BAD_REQUEST)
10
+ end
11
+
12
+ it 'should be serialized' do
13
+ expect(message.error_code).to eq ErrorCode::BAD_REQUEST
14
+ expect(message.serialize).to eq "\x80\x02\x00\x02\x00\x01"
15
+ end
16
+ end
17
+
18
+ context 'received "\x00\x01" that means "Bad Request"' do
19
+ let(:message) do
20
+ ErrorRecord.deserialize("\x00\x01")
21
+ end
22
+
23
+ it 'should be deserialized' do
24
+ expect(message.error_code).to eq ErrorCode::BAD_REQUEST
25
+ expect(message.serialize).to eq "\x80\x02\x00\x02\x00\x01"
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,28 @@
1
+ # encoding: ascii-8bit
2
+ # frozen_string_literal: true
3
+
4
+ require_relative 'spec_helper'
5
+
6
+ RSpec.describe Nts::Sntp::Extension do
7
+ context 'module_function :pad_zero' do
8
+ it 'should pad "\x00" to a word boundary' do
9
+ expect(Extension.pad_zero("\xFF")).to eq "\xFF\x00\x00\x00"
10
+ expect(Extension.pad_zero("\xFF\xFF")).to eq "\xFF\xFF\x00\x00"
11
+ expect(Extension.pad_zero("\xFF\xFF\xFF")).to eq "\xFF\xFF\xFF\x00"
12
+ expect(Extension.pad_zero("\xFF\xFF\xFF\xFF")).to eq "\xFF\xFF\xFF\xFF"
13
+ end
14
+ end
15
+
16
+ context 'module_function :truncate_zero_padding' do
17
+ it 'should truncate "\x00"' do
18
+ expect(Extension.truncate_zero_padding("\xFF\x00\x00\x00"))
19
+ .to eq "\xFF"
20
+ expect(Extension.truncate_zero_padding("\xFF\xFF\x00\x00"))
21
+ .to eq "\xFF\xFF"
22
+ expect(Extension.truncate_zero_padding("\xFF\xFF\xFF\x00"))
23
+ .to eq "\xFF\xFF\xFF"
24
+ expect(Extension.truncate_zero_padding("\xFF\xFF\xFF\xFF"))
25
+ .to eq "\xFF\xFF\xFF\xFF"
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,64 @@
1
+ # encoding: ascii-8bit
2
+ # frozen_string_literal: true
3
+
4
+ require_relative 'spec_helper'
5
+
6
+ RSpec.describe NtsAuthenticator do
7
+ context 'initialized with nonce and ciphertext' do
8
+ let(:nonce) do
9
+ OpenSSL::Random.random_bytes(16)
10
+ end
11
+
12
+ let(:ciphertext) do
13
+ OpenSSL::Random.random_bytes(12345)
14
+ end
15
+
16
+ let(:ex) do
17
+ NtsAuthenticator.new(nonce, ciphertext)
18
+ end
19
+
20
+ it 'should be serialized' do
21
+ expect(ex.nonce).to eq nonce
22
+ expect(ex.ciphertext).to eq ciphertext
23
+ expect(ex.padding_length).to eq 0
24
+
25
+ expected = String.new
26
+ expected << "\x04\x04\x30\x54" # Field Type | Length
27
+ expected << "\x00\x10\x30\x3C" # Nonce Length | Ciphertext Length
28
+ expected << nonce
29
+ expected << ciphertext + "\x00\x00\x00" # padded to a word boundary
30
+ expect(ex.serialize).to eq expected
31
+ end
32
+ end
33
+
34
+ context 'received string' do
35
+ let(:nonce) do
36
+ OpenSSL::Random.random_bytes(16)
37
+ end
38
+
39
+ let(:ciphertext) do
40
+ OpenSSL::Random.random_bytes(12345)
41
+ end
42
+
43
+ let(:ex) do
44
+ NtsAuthenticator.deserialize(
45
+ "\x00\x10\x30\x3C" \
46
+ + nonce \
47
+ + ciphertext + "\x00\x00\x00"
48
+ )
49
+ end
50
+
51
+ it 'should be deserialized' do
52
+ expect(ex.nonce).to eq nonce
53
+ expect(ex.ciphertext).to eq ciphertext
54
+ expect(ex.padding_length).to eq 0
55
+
56
+ expected = String.new
57
+ expected << "\x04\x04\x30\x54" # Field Type | Length
58
+ expected << "\x00\x10\x30\x3C" # Nonce Length | Ciphertext Length
59
+ expected << nonce
60
+ expected << ciphertext + "\x00\x00\x00" # padded to a word boundary
61
+ expect(ex.serialize).to eq expected
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,36 @@
1
+ # encoding: ascii-8bit
2
+ # frozen_string_literal: true
3
+
4
+ require_relative 'spec_helper'
5
+
6
+ RSpec.describe NtsCookie do
7
+ context 'initialized with random binary' do
8
+ let(:rb) do
9
+ OpenSSL::Random.random_bytes(32)
10
+ end
11
+
12
+ let(:ex) do
13
+ NtsCookie.new(rb)
14
+ end
15
+
16
+ it 'should be serialized' do
17
+ expect(ex.cookie).to eq rb
18
+ expect(ex.serialize).to eq "\x02\x04\x00\x24" + rb
19
+ end
20
+ end
21
+
22
+ context 'received random binary' do
23
+ let(:rb) do
24
+ OpenSSL::Random.random_bytes(32)
25
+ end
26
+
27
+ let(:ex) do
28
+ NtsCookie.deserialize(rb)
29
+ end
30
+
31
+ it 'should be deserialized' do
32
+ expect(ex.cookie).to eq rb
33
+ expect(ex.serialize).to eq "\x02\x04\x00\x24" + rb
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,28 @@
1
+ # encoding: ascii-8bit
2
+ # frozen_string_literal: true
3
+
4
+ require_relative 'spec_helper'
5
+
6
+ RSpec.describe NtsNextProtocolNegotiation do
7
+ context 'initialized' do
8
+ let(:message) do
9
+ NtsNextProtocolNegotiation.new
10
+ end
11
+
12
+ it 'should be serialized' do
13
+ expect(message.next_protocol).to eq "\x00\x00"
14
+ expect(message.serialize).to eq "\x00\x01\x00\x02\x00\x00"
15
+ end
16
+ end
17
+
18
+ context 'received "\x00\x00" that means NTPv4' do
19
+ let(:message) do
20
+ NtsNextProtocolNegotiation.deserialize("\x00\x00")
21
+ end
22
+
23
+ it 'should be deserialized' do
24
+ expect(message.next_protocol).to eq "\x00\x00"
25
+ expect(message.serialize).to eq "\x00\x01\x00\x02\x00\x00"
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,28 @@
1
+ # encoding: ascii-8bit
2
+ # frozen_string_literal: true
3
+
4
+ require_relative 'spec_helper'
5
+
6
+ RSpec.describe Ntsv4PortNegotiation do
7
+ context 'initialized with 123' do
8
+ let(:message) do
9
+ Ntsv4PortNegotiation.new(123)
10
+ end
11
+
12
+ it 'should be serialized' do
13
+ expect(message.port).to eq 123
14
+ expect(message.serialize).to eq "\x00\x07\x00\x02\x00\x7B"
15
+ end
16
+ end
17
+
18
+ context 'received "\x00\x7B"(=123)' do
19
+ let(:message) do
20
+ Ntsv4PortNegotiation.deserialize("\x00\x7B", false)
21
+ end
22
+
23
+ it 'should be deserialized' do
24
+ expect(message.port).to eq 123
25
+ expect(message.serialize).to eq "\x00\x07\x00\x02\x00\x7B"
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,28 @@
1
+ # encoding: ascii-8bit
2
+ # frozen_string_literal: true
3
+
4
+ require_relative 'spec_helper'
5
+
6
+ RSpec.describe Ntsv4ServerNegotiation do
7
+ context 'initialized with "localhost"' do
8
+ let(:message) do
9
+ Ntsv4ServerNegotiation.new('localhost')
10
+ end
11
+
12
+ it 'should be serialized' do
13
+ expect(message.server).to eq 'localhost'
14
+ expect(message.serialize).to eq "\x00\x06\x00\x09" + 'localhost'
15
+ end
16
+ end
17
+
18
+ context 'received "localhost"' do
19
+ let(:message) do
20
+ Ntsv4ServerNegotiation.deserialize('localhost', false)
21
+ end
22
+
23
+ it 'should be deserialized' do
24
+ expect(message.server).to eq 'localhost'
25
+ expect(message.serialize).to eq "\x00\x06\x00\x09" + 'localhost'
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,11 @@
1
+ # encoding: ascii-8bit
2
+ # frozen_string_literal: true
3
+
4
+ RSpec.configure(&:disable_monkey_patching!)
5
+
6
+ # rubocop: disable Style/MixinUsage
7
+ require 'nts'
8
+ include Nts::Ntske
9
+ include Nts::Sntp
10
+ include Nts::Sntp::Extension
11
+ # rubocop: enable Style/MixinUsage
@@ -0,0 +1,36 @@
1
+ # encoding: ascii-8bit
2
+ # frozen_string_literal: true
3
+
4
+ require_relative 'spec_helper'
5
+
6
+ RSpec.describe UniqueIdentifier do
7
+ context 'initialized with random binary' do
8
+ let(:rb) do
9
+ OpenSSL::Random.random_bytes(32)
10
+ end
11
+
12
+ let(:ex) do
13
+ UniqueIdentifier.new(rb)
14
+ end
15
+
16
+ it 'should be serialized' do
17
+ expect(ex.id).to eq rb
18
+ expect(ex.serialize).to eq "\x01\x04\x00\x24" + rb
19
+ end
20
+ end
21
+
22
+ context 'received random binary' do
23
+ let(:rb) do
24
+ OpenSSL::Random.random_bytes(32)
25
+ end
26
+
27
+ let(:ex) do
28
+ UniqueIdentifier.deserialize(rb)
29
+ end
30
+
31
+ it 'should be deserialized' do
32
+ expect(ex.id).to eq rb
33
+ expect(ex.serialize).to eq "\x01\x04\x00\x24" + rb
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,46 @@
1
+ # encoding: ascii-8bit
2
+ # frozen_string_literal: true
3
+
4
+ require_relative 'spec_helper'
5
+
6
+ RSpec.describe UnknownExtension do
7
+ context 'initialized with random binary' do
8
+ let(:rb) do
9
+ OpenSSL::Random.random_bytes(32)
10
+ end
11
+
12
+ let(:field_type) do
13
+ 12345
14
+ end
15
+
16
+ let(:ex) do
17
+ UnknownExtension.new(rb, field_type)
18
+ end
19
+
20
+ it 'should be serialized' do
21
+ expect(ex.field_type).to eq field_type
22
+ expect(ex.value).to eq rb
23
+ expect(ex.serialize).to eq "\x30\x39\x00\x24" + rb
24
+ end
25
+ end
26
+
27
+ context 'received random binary' do
28
+ let(:rb) do
29
+ OpenSSL::Random.random_bytes(32)
30
+ end
31
+
32
+ let(:field_type) do
33
+ 12345
34
+ end
35
+
36
+ let(:ex) do
37
+ UnknownExtension.deserialize(rb, field_type)
38
+ end
39
+
40
+ it 'should be deserialized' do
41
+ expect(ex.field_type).to eq field_type
42
+ expect(ex.value).to eq rb
43
+ expect(ex.serialize).to eq "\x30\x39\x00\x24" + rb
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,28 @@
1
+ # encoding: ascii-8bit
2
+ # frozen_string_literal: true
3
+
4
+ require_relative 'spec_helper'
5
+
6
+ RSpec.describe WarningRecord do
7
+ context 'initialized with 1111' do
8
+ let(:message) do
9
+ WarningRecord.new(1111)
10
+ end
11
+
12
+ it 'should be serialized' do
13
+ expect(message.warning_code).to eq 1111
14
+ expect(message.serialize).to eq "\x80\x03\x00\x02\x04\x57"
15
+ end
16
+ end
17
+
18
+ context 'received "\x04\x57"(=1111)' do
19
+ let(:message) do
20
+ WarningRecord.deserialize("\x04\x57")
21
+ end
22
+
23
+ it 'should be deserialized' do
24
+ expect(message.warning_code).to eq 1111
25
+ expect(message.serialize).to eq "\x80\x03\x00\x02\x04\x57"
26
+ end
27
+ end
28
+ end
metadata ADDED
@@ -0,0 +1,145 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: simple_nts_client
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - thekuwayama
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2019-09-26 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: miscreant
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: tttls1.3
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: 0.2.7
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: 0.2.7
55
+ description: Simple NTS(Network Time Security) Client
56
+ email:
57
+ - thekuwayama@gmail.com
58
+ executables:
59
+ - simple_nts_client
60
+ extensions: []
61
+ extra_rdoc_files: []
62
+ files:
63
+ - ".gitignore"
64
+ - ".rubocop.yml"
65
+ - ".travis.yml"
66
+ - Gemfile
67
+ - LICENSE.txt
68
+ - README.md
69
+ - Rakefile
70
+ - exe/simple_nts_client
71
+ - lib/nts.rb
72
+ - lib/nts/cli.rb
73
+ - lib/nts/ntske.rb
74
+ - lib/nts/ntske/client.rb
75
+ - lib/nts/ntske/message.rb
76
+ - lib/nts/ntske/message/aead_algorithm_negotiation.rb
77
+ - lib/nts/ntske/message/cookie.rb
78
+ - lib/nts/ntske/message/end_of_message.rb
79
+ - lib/nts/ntske/message/error_record.rb
80
+ - lib/nts/ntske/message/nts_next_protocol_negotiation.rb
81
+ - lib/nts/ntske/message/ntsv4_port_negotiation.rb
82
+ - lib/nts/ntske/message/ntsv4_server_negotiation.rb
83
+ - lib/nts/ntske/message/warning_record.rb
84
+ - lib/nts/sntp.rb
85
+ - lib/nts/sntp/client.rb
86
+ - lib/nts/sntp/extension.rb
87
+ - lib/nts/sntp/extension/nts_authenticator.rb
88
+ - lib/nts/sntp/extension/nts_cookie.rb
89
+ - lib/nts/sntp/extension/unique_identifier.rb
90
+ - lib/nts/sntp/extension/unknown_extension.rb
91
+ - lib/nts/sntp/message.rb
92
+ - lib/nts/version.rb
93
+ - simple_nts_client.gemspec
94
+ - spec/aead_algorithm_negotiation_spec.rb
95
+ - spec/cookie_spec.rb
96
+ - spec/end_of_message_spec.rb
97
+ - spec/error_record_spec.rb
98
+ - spec/extension_spec.rb
99
+ - spec/nts_authenticator_spec.rb
100
+ - spec/nts_cookie_spec.rb
101
+ - spec/nts_next_protocol_negotiation_spec.rb
102
+ - spec/ntsv4_port_negotiation_spec.rb
103
+ - spec/ntsv4_server_negotiation_spec.rb
104
+ - spec/spec_helper.rb
105
+ - spec/unique_identifier_spec.rb
106
+ - spec/unknown_extension_spec.rb
107
+ - spec/warning_record_spec.rb
108
+ homepage: https://github.com/thekuwayama/simple_nts_client
109
+ licenses:
110
+ - MIT
111
+ metadata: {}
112
+ post_install_message:
113
+ rdoc_options: []
114
+ require_paths:
115
+ - lib
116
+ required_ruby_version: !ruby/object:Gem::Requirement
117
+ requirements:
118
+ - - ">="
119
+ - !ruby/object:Gem::Version
120
+ version: 2.6.1
121
+ required_rubygems_version: !ruby/object:Gem::Requirement
122
+ requirements:
123
+ - - ">="
124
+ - !ruby/object:Gem::Version
125
+ version: '0'
126
+ requirements: []
127
+ rubygems_version: 3.0.3
128
+ signing_key:
129
+ specification_version: 4
130
+ summary: Simple NTS(Network Time Security) Client
131
+ test_files:
132
+ - spec/aead_algorithm_negotiation_spec.rb
133
+ - spec/cookie_spec.rb
134
+ - spec/end_of_message_spec.rb
135
+ - spec/error_record_spec.rb
136
+ - spec/extension_spec.rb
137
+ - spec/nts_authenticator_spec.rb
138
+ - spec/nts_cookie_spec.rb
139
+ - spec/nts_next_protocol_negotiation_spec.rb
140
+ - spec/ntsv4_port_negotiation_spec.rb
141
+ - spec/ntsv4_server_negotiation_spec.rb
142
+ - spec/spec_helper.rb
143
+ - spec/unique_identifier_spec.rb
144
+ - spec/unknown_extension_spec.rb
145
+ - spec/warning_record_spec.rb