rubyntlm 0.5.2 → 0.6.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.gitignore +2 -0
- data/.travis.yml +10 -7
- data/CHANGELOG.md +126 -5
- data/Rakefile +4 -1
- data/lib/net/ntlm.rb +5 -2
- data/lib/net/ntlm/channel_binding.rb +65 -0
- data/lib/net/ntlm/client.rb +2 -2
- data/lib/net/ntlm/client/session.rb +21 -7
- data/lib/net/ntlm/encode_util.rb +1 -2
- data/lib/net/ntlm/exceptions.rb +14 -0
- data/lib/net/ntlm/target_info.rb +89 -0
- data/lib/net/ntlm/version.rb +2 -2
- data/rubyntlm.gemspec +1 -0
- data/spec/lib/net/ntlm/channel_binding_spec.rb +17 -0
- data/spec/lib/net/ntlm/client_spec.rb +1 -1
- data/spec/lib/net/ntlm/encode_util_spec.rb +2 -2
- data/spec/lib/net/ntlm/target_info_spec.rb +76 -0
- data/spec/support/certificates/sha_256_hash.pem +19 -0
- metadata +26 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 9ef7e8c4a2e91abd9fac8aff17da320fc011a25b0a74b14e8f121332daa33ee6
|
4
|
+
data.tar.gz: 9158fdcca0c6121fbfc27731bae0865398aee7a410e0be463872cfe764924b61
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f3150588419fc1a400aacc52cbbdd61df58212e77cead9cc7b90b71af31d9a9d0cae90285e9d555bb1a953b4085af47ddc82c350b89b2ce31475e70f6c909a49
|
7
|
+
data.tar.gz: 20f50357f7ae738617386d1504dfae5d759ecceb2f7adc501e1458be80d22ea2864dc1b216d4853cda568271e81134fcda182f520477f8fd8613386e168ceefc
|
data/.travis.yml
CHANGED
@@ -1,10 +1,13 @@
|
|
1
1
|
language: ruby
|
2
2
|
rvm:
|
3
|
-
- 1.9
|
4
|
-
-
|
5
|
-
-
|
6
|
-
-
|
7
|
-
|
8
|
-
-
|
9
|
-
- jruby-19mode
|
3
|
+
- 2.1.9
|
4
|
+
- 2.6.6
|
5
|
+
- 2.7.1
|
6
|
+
- 3.0.0
|
7
|
+
before_install:
|
8
|
+
- gem update bundler
|
10
9
|
|
10
|
+
# This prevents testing branches that are created just for PRs
|
11
|
+
branches:
|
12
|
+
only:
|
13
|
+
- master
|
data/CHANGELOG.md
CHANGED
@@ -1,6 +1,127 @@
|
|
1
|
-
|
2
|
-
- Bug - Type 1 packets do not include a domain and workstation by defauly. Packet capture software will see this type of packet as malformed. All packets now include this information
|
3
|
-
- Bug - Type 3 packets do not include the calling workstation. This should be setup by default.
|
1
|
+
# Change Log
|
4
2
|
|
5
|
-
0.
|
6
|
-
|
3
|
+
## [0.6.3](https://github.com/WinRb/rubyntlm/tree/0.6.3) (2021-01-26)
|
4
|
+
[Full Changelog](https://github.com/WinRb/rubyntlm/compare/v0.6.2...0.6.3)
|
5
|
+
|
6
|
+
**Closed issues:**
|
7
|
+
|
8
|
+
- Timeout issues with mailcatcher [\#18](https://github.com/WinRb/rubyntlm/issues/18)
|
9
|
+
|
10
|
+
**Merged pull requests:**
|
11
|
+
|
12
|
+
- Fix an error showing the key not being set on the DES cypher [\#41](https://github.com/WinRb/rubyntlm/pull/41) ([Castone22](https://github.com/Castone22))
|
13
|
+
|
14
|
+
## [v0.6.2](https://github.com/WinRb/rubyntlm/tree/v0.6.2) (2017-04-24)
|
15
|
+
[Full Changelog](https://github.com/WinRb/rubyntlm/compare/v0.6.1...v0.6.2)
|
16
|
+
|
17
|
+
**Merged pull requests:**
|
18
|
+
|
19
|
+
- preps 0.6.2 release and adds a changelog generator [\#35](https://github.com/WinRb/rubyntlm/pull/35) ([mwrock](https://github.com/mwrock))
|
20
|
+
- Support Ruby 2.4 [\#34](https://github.com/WinRb/rubyntlm/pull/34) ([fwininger](https://github.com/fwininger))
|
21
|
+
- ignore pkg directory in git [\#33](https://github.com/WinRb/rubyntlm/pull/33) ([mwrock](https://github.com/mwrock))
|
22
|
+
|
23
|
+
## [v0.6.1](https://github.com/WinRb/rubyntlm/tree/v0.6.1) (2016-09-15)
|
24
|
+
[Full Changelog](https://github.com/WinRb/rubyntlm/compare/v0.6.0...v0.6.1)
|
25
|
+
|
26
|
+
**Merged pull requests:**
|
27
|
+
|
28
|
+
- Release 0.6.1 [\#32](https://github.com/WinRb/rubyntlm/pull/32) ([mwrock](https://github.com/mwrock))
|
29
|
+
- only test supported rubies and do not test twice [\#31](https://github.com/WinRb/rubyntlm/pull/31) ([mwrock](https://github.com/mwrock))
|
30
|
+
|
31
|
+
## [v0.6.0](https://github.com/WinRb/rubyntlm/tree/v0.6.0) (2016-02-16)
|
32
|
+
[Full Changelog](https://github.com/WinRb/rubyntlm/compare/v0.5.3...v0.6.0)
|
33
|
+
|
34
|
+
**Closed issues:**
|
35
|
+
|
36
|
+
- support Extended Protection for Authentication \(Channel Binding Tokens\) [\#27](https://github.com/WinRb/rubyntlm/issues/27)
|
37
|
+
- RubyNTLM is not documented [\#20](https://github.com/WinRb/rubyntlm/issues/20)
|
38
|
+
|
39
|
+
## [v0.5.3](https://github.com/WinRb/rubyntlm/tree/v0.5.3) (2016-01-22)
|
40
|
+
[Full Changelog](https://github.com/WinRb/rubyntlm/compare/0.5.3...v0.5.3)
|
41
|
+
|
42
|
+
## [0.5.3](https://github.com/WinRb/rubyntlm/tree/0.5.3) (2016-01-22)
|
43
|
+
[Full Changelog](https://github.com/WinRb/rubyntlm/compare/0.5.2...0.5.3)
|
44
|
+
|
45
|
+
**Merged pull requests:**
|
46
|
+
|
47
|
+
- fix session.workstation when passing only domain [\#26](https://github.com/WinRb/rubyntlm/pull/26) ([mwrock](https://github.com/mwrock))
|
48
|
+
|
49
|
+
## [0.5.2](https://github.com/WinRb/rubyntlm/tree/0.5.2) (2015-07-20)
|
50
|
+
[Full Changelog](https://github.com/WinRb/rubyntlm/compare/0.5.1...0.5.2)
|
51
|
+
|
52
|
+
**Merged pull requests:**
|
53
|
+
|
54
|
+
- Add Pass the Hash capability to the NTLM client [\#24](https://github.com/WinRb/rubyntlm/pull/24) ([thelightcosine](https://github.com/thelightcosine))
|
55
|
+
|
56
|
+
## [0.5.1](https://github.com/WinRb/rubyntlm/tree/0.5.1) (2015-06-23)
|
57
|
+
[Full Changelog](https://github.com/WinRb/rubyntlm/compare/0.5.0...0.5.1)
|
58
|
+
|
59
|
+
**Merged pull requests:**
|
60
|
+
|
61
|
+
- fix NTLM1 auth - NTLM::lm\_response\(pwd, chal\) and NTLM::ntlm\_response… [\#23](https://github.com/WinRb/rubyntlm/pull/23) ([marek-veber](https://github.com/marek-veber))
|
62
|
+
- Make the session key available to clients [\#21](https://github.com/WinRb/rubyntlm/pull/21) ([jlee-r7](https://github.com/jlee-r7))
|
63
|
+
|
64
|
+
## [0.5.0](https://github.com/WinRb/rubyntlm/tree/0.5.0) (2015-02-22)
|
65
|
+
[Full Changelog](https://github.com/WinRb/rubyntlm/compare/v0.4.0...0.5.0)
|
66
|
+
|
67
|
+
**Closed issues:**
|
68
|
+
|
69
|
+
- require 'net/ntlm/version' in spec/lib/net/ntlm/version\_spec.rb [\#12](https://github.com/WinRb/rubyntlm/issues/12)
|
70
|
+
- License missing from gemspec [\#5](https://github.com/WinRb/rubyntlm/issues/5)
|
71
|
+
|
72
|
+
**Merged pull requests:**
|
73
|
+
|
74
|
+
- Protect against mutating frozen strings [\#30](https://github.com/WinRb/rubyntlm/pull/30) ([mwrock](https://github.com/mwrock))
|
75
|
+
- Support Extended Protection for Authentication \(Channel binding\) [\#28](https://github.com/WinRb/rubyntlm/pull/28) ([mwrock](https://github.com/mwrock))
|
76
|
+
- Encode client and domain in oem/unicode in `Client\#authenticate!` [\#19](https://github.com/WinRb/rubyntlm/pull/19) ([jlee-r7](https://github.com/jlee-r7))
|
77
|
+
- require version to fix specs [\#17](https://github.com/WinRb/rubyntlm/pull/17) ([sneal](https://github.com/sneal))
|
78
|
+
- Initial go at an NTLM Client that will do session signing/sealing [\#16](https://github.com/WinRb/rubyntlm/pull/16) ([zenchild](https://github.com/zenchild))
|
79
|
+
- Verify passwords in Type3 messages [\#15](https://github.com/WinRb/rubyntlm/pull/15) ([jlee-r7](https://github.com/jlee-r7))
|
80
|
+
- RSpect should =\> expect modernization [\#14](https://github.com/WinRb/rubyntlm/pull/14) ([zenchild](https://github.com/zenchild))
|
81
|
+
- update http example with EncodeUtil class [\#11](https://github.com/WinRb/rubyntlm/pull/11) ([stensonb](https://github.com/stensonb))
|
82
|
+
- update readme with how to use and the correct namespacing for using the gem [\#10](https://github.com/WinRb/rubyntlm/pull/10) ([stensonb](https://github.com/stensonb))
|
83
|
+
|
84
|
+
## [v0.4.0](https://github.com/WinRb/rubyntlm/tree/v0.4.0) (2013-09-12)
|
85
|
+
[Full Changelog](https://github.com/WinRb/rubyntlm/compare/v0.3.4...v0.4.0)
|
86
|
+
|
87
|
+
**Closed issues:**
|
88
|
+
|
89
|
+
- The domain should always be capitalized otherwise domain authentication fails [\#7](https://github.com/WinRb/rubyntlm/issues/7)
|
90
|
+
|
91
|
+
**Merged pull requests:**
|
92
|
+
|
93
|
+
- Add licensing information and clean up attributions to provide licensing... [\#9](https://github.com/WinRb/rubyntlm/pull/9) ([pmorton](https://github.com/pmorton))
|
94
|
+
- Upcase the domain [\#8](https://github.com/WinRb/rubyntlm/pull/8) ([pmorton](https://github.com/pmorton))
|
95
|
+
- Refactor/refactor classes [\#6](https://github.com/WinRb/rubyntlm/pull/6) ([thelightcosine](https://github.com/thelightcosine))
|
96
|
+
|
97
|
+
## [v0.3.4](https://github.com/WinRb/rubyntlm/tree/v0.3.4) (2013-08-08)
|
98
|
+
[Full Changelog](https://github.com/WinRb/rubyntlm/compare/v0.3.3...v0.3.4)
|
99
|
+
|
100
|
+
## [v0.3.3](https://github.com/WinRb/rubyntlm/tree/v0.3.3) (2013-07-23)
|
101
|
+
[Full Changelog](https://github.com/WinRb/rubyntlm/compare/v0.3.2...v0.3.3)
|
102
|
+
|
103
|
+
**Merged pull requests:**
|
104
|
+
|
105
|
+
- Typo in NTLM namespace calls [\#4](https://github.com/WinRb/rubyntlm/pull/4) ([thelightcosine](https://github.com/thelightcosine))
|
106
|
+
|
107
|
+
## [v0.3.2](https://github.com/WinRb/rubyntlm/tree/v0.3.2) (2013-06-24)
|
108
|
+
[Full Changelog](https://github.com/WinRb/rubyntlm/compare/v0.3.1...v0.3.2)
|
109
|
+
|
110
|
+
**Closed issues:**
|
111
|
+
|
112
|
+
- Gem is locked at 1.9.2 [\#1](https://github.com/WinRb/rubyntlm/issues/1)
|
113
|
+
|
114
|
+
## [v0.3.1](https://github.com/WinRb/rubyntlm/tree/v0.3.1) (2013-03-29)
|
115
|
+
[Full Changelog](https://github.com/WinRb/rubyntlm/compare/v0.3.0...v0.3.1)
|
116
|
+
|
117
|
+
**Merged pull requests:**
|
118
|
+
|
119
|
+
- Fix gemspec for the proper ruby version and bump the version [\#2](https://github.com/WinRb/rubyntlm/pull/2) ([pmorton](https://github.com/pmorton))
|
120
|
+
|
121
|
+
## [v0.3.0](https://github.com/WinRb/rubyntlm/tree/v0.3.0) (2013-03-25)
|
122
|
+
[Full Changelog](https://github.com/WinRb/rubyntlm/compare/v0.2.0...v0.3.0)
|
123
|
+
|
124
|
+
## [v0.2.0](https://github.com/WinRb/rubyntlm/tree/v0.2.0) (2013-03-22)
|
125
|
+
|
126
|
+
|
127
|
+
\* *This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)*
|
data/Rakefile
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
require "bundler/gem_tasks"
|
2
|
-
|
2
|
+
require 'github_changelog_generator/task'
|
3
3
|
|
4
4
|
require 'rspec/core/rake_task'
|
5
5
|
RSpec::Core::RakeTask.new(:spec)
|
@@ -20,3 +20,6 @@ task :console do
|
|
20
20
|
Pry.start
|
21
21
|
end
|
22
22
|
|
23
|
+
GitHubChangelogGenerator::RakeTask.new :changelog do |config|
|
24
|
+
config.future_release = Net::NTLM::VERSION::STRING
|
25
|
+
end
|
data/lib/net/ntlm.rb
CHANGED
@@ -42,6 +42,7 @@ require 'openssl/digest'
|
|
42
42
|
require 'socket'
|
43
43
|
|
44
44
|
# Load Order is important here
|
45
|
+
require 'net/ntlm/exceptions'
|
45
46
|
require 'net/ntlm/field'
|
46
47
|
require 'net/ntlm/int16_le'
|
47
48
|
require 'net/ntlm/int32_le'
|
@@ -60,6 +61,8 @@ require 'net/ntlm/message/type3'
|
|
60
61
|
require 'net/ntlm/encode_util'
|
61
62
|
|
62
63
|
require 'net/ntlm/client'
|
64
|
+
require 'net/ntlm/channel_binding'
|
65
|
+
require 'net/ntlm/target_info'
|
63
66
|
|
64
67
|
module Net
|
65
68
|
module NTLM
|
@@ -120,11 +123,11 @@ module Net
|
|
120
123
|
end
|
121
124
|
|
122
125
|
def apply_des(plain, keys)
|
123
|
-
dec = OpenSSL::Cipher
|
126
|
+
dec = OpenSSL::Cipher.new("des-cbc").encrypt
|
124
127
|
dec.padding = 0
|
125
128
|
keys.map {|k|
|
126
129
|
dec.key = k
|
127
|
-
dec.
|
130
|
+
dec.update(plain) + dec.final
|
128
131
|
}
|
129
132
|
end
|
130
133
|
|
@@ -0,0 +1,65 @@
|
|
1
|
+
module Net
|
2
|
+
module NTLM
|
3
|
+
class ChannelBinding
|
4
|
+
|
5
|
+
# Creates a ChannelBinding used for Extended Protection Authentication
|
6
|
+
# @see http://blogs.msdn.com/b/openspecification/archive/2013/03/26/ntlm-and-channel-binding-hash-aka-exteneded-protection-for-authentication.aspx
|
7
|
+
#
|
8
|
+
# @param outer_channel [OpenSSL::X509::Certificate] Server certificate securing
|
9
|
+
# the outer TLS channel
|
10
|
+
# @return [NTLM::ChannelBinding] A ChannelBinding holding a token that can be
|
11
|
+
# embedded in a {Type3} message
|
12
|
+
def self.create(outer_channel)
|
13
|
+
new(outer_channel)
|
14
|
+
end
|
15
|
+
|
16
|
+
# @param outer_channel [OpenSSL::X509::Certificate] Server certificate securing
|
17
|
+
# the outer TLS channel
|
18
|
+
def initialize(outer_channel)
|
19
|
+
@channel = outer_channel
|
20
|
+
@unique_prefix = 'tls-server-end-point'
|
21
|
+
@initiator_addtype = 0
|
22
|
+
@initiator_address_length = 0
|
23
|
+
@acceptor_addrtype = 0
|
24
|
+
@acceptor_address_length = 0
|
25
|
+
end
|
26
|
+
|
27
|
+
attr_reader :channel, :unique_prefix, :initiator_addtype
|
28
|
+
attr_reader :initiator_address_length, :acceptor_addrtype
|
29
|
+
attr_reader :acceptor_address_length
|
30
|
+
|
31
|
+
# Returns a channel binding hash acceptable for use as a AV_PAIR MsvAvChannelBindings
|
32
|
+
# field value as specified in the NTLM protocol
|
33
|
+
#
|
34
|
+
# @return [String] MD5 hash of gss_channel_bindings_struct
|
35
|
+
def channel_binding_token
|
36
|
+
@channel_binding_token ||= OpenSSL::Digest::MD5.new(gss_channel_bindings_struct).digest
|
37
|
+
end
|
38
|
+
|
39
|
+
def gss_channel_bindings_struct
|
40
|
+
@gss_channel_bindings_struct ||= begin
|
41
|
+
token = [initiator_addtype].pack('I')
|
42
|
+
token << [initiator_address_length].pack('I')
|
43
|
+
token << [acceptor_addrtype].pack('I')
|
44
|
+
token << [acceptor_address_length].pack('I')
|
45
|
+
token << [application_data.length].pack('I')
|
46
|
+
token << application_data
|
47
|
+
token
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def channel_hash
|
52
|
+
@channel_hash ||= OpenSSL::Digest::SHA256.new(channel.to_der)
|
53
|
+
end
|
54
|
+
|
55
|
+
def application_data
|
56
|
+
@application_data ||= begin
|
57
|
+
data = unique_prefix
|
58
|
+
data << ':'
|
59
|
+
data << channel_hash.digest
|
60
|
+
data
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
data/lib/net/ntlm/client.rb
CHANGED
@@ -27,12 +27,12 @@ module Net
|
|
27
27
|
end
|
28
28
|
|
29
29
|
# @return [NTLM::Message]
|
30
|
-
def init_context(resp = nil)
|
30
|
+
def init_context(resp = nil, channel_binding = nil)
|
31
31
|
if resp.nil?
|
32
32
|
@session = nil
|
33
33
|
type1_message
|
34
34
|
else
|
35
|
-
@session = Client::Session.new(self, Net::NTLM::Message.decode64(resp))
|
35
|
+
@session = Client::Session.new(self, Net::NTLM::Message.decode64(resp), channel_binding)
|
36
36
|
@session.authenticate!
|
37
37
|
end
|
38
38
|
end
|
@@ -10,13 +10,14 @@ module Net
|
|
10
10
|
CLIENT_TO_SERVER_SEALING = "session key to client-to-server sealing key magic constant\0"
|
11
11
|
SERVER_TO_CLIENT_SEALING = "session key to server-to-client sealing key magic constant\0"
|
12
12
|
|
13
|
-
attr_reader :client, :challenge_message
|
13
|
+
attr_reader :client, :challenge_message, :channel_binding
|
14
14
|
|
15
15
|
# @param client [Net::NTLM::Client] the client instance
|
16
16
|
# @param challenge_message [Net::NTLM::Message::Type2] server message
|
17
|
-
def initialize(client, challenge_message)
|
17
|
+
def initialize(client, challenge_message, channel_binding = nil)
|
18
18
|
@client = client
|
19
19
|
@challenge_message = challenge_message
|
20
|
+
@channel_binding = channel_binding
|
20
21
|
end
|
21
22
|
|
22
23
|
# Generate an NTLMv2 AUTHENTICATE_MESSAGE
|
@@ -35,7 +36,7 @@ module Net
|
|
35
36
|
t3 = Message::Type3.create type3_opts
|
36
37
|
if negotiate_key_exchange?
|
37
38
|
t3.enable(:session_key)
|
38
|
-
rc4 = OpenSSL::Cipher
|
39
|
+
rc4 = OpenSSL::Cipher.new("rc4")
|
39
40
|
rc4.encrypt
|
40
41
|
rc4.key = user_session_key
|
41
42
|
sk = rc4.update exported_session_key
|
@@ -124,7 +125,7 @@ module Net
|
|
124
125
|
def client_cipher
|
125
126
|
@client_cipher ||=
|
126
127
|
begin
|
127
|
-
rc4 = OpenSSL::Cipher
|
128
|
+
rc4 = OpenSSL::Cipher.new("rc4")
|
128
129
|
rc4.encrypt
|
129
130
|
rc4.key = client_seal_key
|
130
131
|
rc4
|
@@ -134,7 +135,7 @@ module Net
|
|
134
135
|
def server_cipher
|
135
136
|
@server_cipher ||=
|
136
137
|
begin
|
137
|
-
rc4 = OpenSSL::Cipher
|
138
|
+
rc4 = OpenSSL::Cipher.new("rc4")
|
138
139
|
rc4.decrypt
|
139
140
|
rc4.key = server_seal_key
|
140
141
|
rc4
|
@@ -172,7 +173,7 @@ module Net
|
|
172
173
|
end
|
173
174
|
|
174
175
|
def workstation
|
175
|
-
(client.
|
176
|
+
(client.workstation ? oem_or_unicode_str(client.workstation) : "")
|
176
177
|
end
|
177
178
|
|
178
179
|
def domain
|
@@ -213,11 +214,24 @@ module Net
|
|
213
214
|
b = Blob.new
|
214
215
|
b.timestamp = timestamp
|
215
216
|
b.challenge = client_challenge
|
216
|
-
b.target_info =
|
217
|
+
b.target_info = target_info
|
217
218
|
b.serialize
|
218
219
|
end
|
219
220
|
end
|
220
221
|
|
222
|
+
def target_info
|
223
|
+
@target_info ||= begin
|
224
|
+
if channel_binding
|
225
|
+
t = Net::NTLM::TargetInfo.new(challenge_message.target_info)
|
226
|
+
av_id = Net::NTLM::TargetInfo::MSV_AV_CHANNEL_BINDINGS
|
227
|
+
t.av_pairs[av_id] = channel_binding.channel_binding_token
|
228
|
+
t.to_s
|
229
|
+
else
|
230
|
+
challenge_message.target_info
|
231
|
+
end
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
221
235
|
end
|
222
236
|
end
|
223
237
|
end
|
data/lib/net/ntlm/encode_util.rb
CHANGED
@@ -27,7 +27,7 @@ module NTLM
|
|
27
27
|
# Decode a UTF16 string to a ASCII string
|
28
28
|
# @param [String] str The string to convert
|
29
29
|
def self.decode_utf16le(str)
|
30
|
-
str.force_encoding(Encoding::UTF_16LE)
|
30
|
+
str = str.dup.force_encoding(Encoding::UTF_16LE)
|
31
31
|
str.encode(Encoding::UTF_8, Encoding::UTF_16LE).force_encoding('UTF-8')
|
32
32
|
end
|
33
33
|
|
@@ -39,7 +39,6 @@ module NTLM
|
|
39
39
|
# the function will convert the string bytes to UTF-16LE and note the encoding as UTF-8 so that byte
|
40
40
|
# concatination works seamlessly.
|
41
41
|
def self.encode_utf16le(str)
|
42
|
-
str = str.force_encoding('UTF-8') if [::Encoding::ASCII_8BIT,::Encoding::US_ASCII].include?(str.encoding)
|
43
42
|
str.dup.force_encoding('UTF-8').encode(Encoding::UTF_16LE, Encoding::UTF_8).force_encoding('UTF-8')
|
44
43
|
end
|
45
44
|
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
module Net
|
2
|
+
module NTLM
|
3
|
+
|
4
|
+
# Represents a list of AV_PAIR structures
|
5
|
+
# @see https://msdn.microsoft.com/en-us/library/cc236646.aspx
|
6
|
+
class TargetInfo
|
7
|
+
|
8
|
+
# Allowed AvId values for an AV_PAIR
|
9
|
+
MSV_AV_EOL = "\x00\x00".freeze
|
10
|
+
MSV_AV_NB_COMPUTER_NAME = "\x01\x00".freeze
|
11
|
+
MSV_AV_NB_DOMAIN_NAME = "\x02\x00".freeze
|
12
|
+
MSV_AV_DNS_COMPUTER_NAME = "\x03\x00".freeze
|
13
|
+
MSV_AV_DNS_DOMAIN_NAME = "\x04\x00".freeze
|
14
|
+
MSV_AV_DNS_TREE_NAME = "\x05\x00".freeze
|
15
|
+
MSV_AV_FLAGS = "\x06\x00".freeze
|
16
|
+
MSV_AV_TIMESTAMP = "\x07\x00".freeze
|
17
|
+
MSV_AV_SINGLE_HOST = "\x08\x00".freeze
|
18
|
+
MSV_AV_TARGET_NAME = "\x09\x00".freeze
|
19
|
+
MSV_AV_CHANNEL_BINDINGS = "\x0A\x00".freeze
|
20
|
+
|
21
|
+
# @param av_pair_sequence [String] AV_PAIR list from challenge message
|
22
|
+
def initialize(av_pair_sequence)
|
23
|
+
@av_pairs = read_pairs(av_pair_sequence)
|
24
|
+
end
|
25
|
+
|
26
|
+
attr_reader :av_pairs
|
27
|
+
|
28
|
+
def to_s
|
29
|
+
result = ''
|
30
|
+
av_pairs.each do |k,v|
|
31
|
+
result << k
|
32
|
+
result << [v.length].pack('S')
|
33
|
+
result << v
|
34
|
+
end
|
35
|
+
result << Net::NTLM::TargetInfo::MSV_AV_EOL
|
36
|
+
result << [0].pack('S')
|
37
|
+
result.force_encoding(Encoding::ASCII_8BIT)
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
VALID_PAIR_ID = [
|
43
|
+
MSV_AV_EOL,
|
44
|
+
MSV_AV_NB_COMPUTER_NAME,
|
45
|
+
MSV_AV_NB_DOMAIN_NAME,
|
46
|
+
MSV_AV_DNS_COMPUTER_NAME,
|
47
|
+
MSV_AV_DNS_DOMAIN_NAME,
|
48
|
+
MSV_AV_DNS_TREE_NAME,
|
49
|
+
MSV_AV_FLAGS,
|
50
|
+
MSV_AV_TIMESTAMP,
|
51
|
+
MSV_AV_SINGLE_HOST,
|
52
|
+
MSV_AV_TARGET_NAME,
|
53
|
+
MSV_AV_CHANNEL_BINDINGS
|
54
|
+
].freeze
|
55
|
+
|
56
|
+
def read_pairs(av_pair_sequence)
|
57
|
+
offset = 0
|
58
|
+
result = {}
|
59
|
+
return result if av_pair_sequence.nil?
|
60
|
+
|
61
|
+
until offset >= av_pair_sequence.length
|
62
|
+
id = av_pair_sequence[offset..offset+1]
|
63
|
+
|
64
|
+
unless VALID_PAIR_ID.include?(id)
|
65
|
+
raise Net::NTLM::InvalidTargetDataError.new(
|
66
|
+
"Invalid AvId #{to_hex(id)} in AV_PAIR structure",
|
67
|
+
av_pair_sequence
|
68
|
+
)
|
69
|
+
end
|
70
|
+
|
71
|
+
length = av_pair_sequence[offset+2..offset+3].unpack('S')[0].to_i
|
72
|
+
if length > 0
|
73
|
+
value = av_pair_sequence[offset+4..offset+4+length-1]
|
74
|
+
result[id] = value
|
75
|
+
end
|
76
|
+
|
77
|
+
offset += 4 + length
|
78
|
+
end
|
79
|
+
|
80
|
+
result
|
81
|
+
end
|
82
|
+
|
83
|
+
def to_hex(str)
|
84
|
+
return nil if str.nil?
|
85
|
+
str.bytes.map {|b| '0x' + b.to_s(16).rjust(2,'0').upcase}.join('-')
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
data/lib/net/ntlm/version.rb
CHANGED
data/rubyntlm.gemspec
CHANGED
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Net::NTLM::ChannelBinding do
|
4
|
+
let(:certificates_path) { 'spec/support/certificates' }
|
5
|
+
let(:sha_256_path) { File.join(certificates_path, 'sha_256_hash.pem') }
|
6
|
+
let(:sha_256_cert) { OpenSSL::X509::Certificate.new(File.read(sha_256_path)) }
|
7
|
+
let(:cert_hash) { "\x04\x0E\x56\x28\xEC\x4A\x98\x29\x91\x70\x73\x62\x03\x7B\xB2\x3C".force_encoding(Encoding::ASCII_8BIT) }
|
8
|
+
|
9
|
+
subject { Net::NTLM::ChannelBinding.create(sha_256_cert) }
|
10
|
+
|
11
|
+
describe '#channel_binding_token' do
|
12
|
+
|
13
|
+
it 'returns the correct hash' do
|
14
|
+
expect(subject.channel_binding_token).to eq cert_hash
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -55,7 +55,7 @@ describe Net::NTLM::Client do
|
|
55
55
|
t2_challenge = "TlRMTVNTUAACAAAADAAMADgAAAA1goriAAyk1DmJUnUAAAAAAAAAAFAAUABEAAAABgLwIwAAAA9TAEUAUgBWAEUAUgACAAwAUwBFAFIAVgBFAFIAAQAMAFMARQBSAFYARQBSAAQADABzAGUAcgB2AGUAcgADAAwAcwBlAHIAdgBlAHIABwAIADd7mrNaB9ABAAAAAA=="
|
56
56
|
session = double("session")
|
57
57
|
expect(session).to receive(:authenticate!)
|
58
|
-
expect(Net::NTLM::Client::Session).to receive(:new).with(inst, instance_of(Net::NTLM::Message::Type2)).and_return(session)
|
58
|
+
expect(Net::NTLM::Client::Session).to receive(:new).with(inst, instance_of(Net::NTLM::Message::Type2), nil).and_return(session)
|
59
59
|
inst.init_context t2_challenge
|
60
60
|
end
|
61
61
|
|
@@ -4,13 +4,13 @@ describe Net::NTLM::EncodeUtil do
|
|
4
4
|
|
5
5
|
context '#encode_utf16le' do
|
6
6
|
it 'should convert an ASCII string to UTF' do
|
7
|
-
expect(Net::NTLM::EncodeUtil.encode_utf16le('Test')).to eq("T\x00e\x00s\x00t\x00")
|
7
|
+
expect(Net::NTLM::EncodeUtil.encode_utf16le('Test'.encode(::Encoding::ASCII_8BIT).freeze)).to eq("T\x00e\x00s\x00t\x00")
|
8
8
|
end
|
9
9
|
end
|
10
10
|
|
11
11
|
context '#decode_utf16le' do
|
12
12
|
it 'should convert a UTF string to ASCII' do
|
13
|
-
expect(Net::NTLM::EncodeUtil.decode_utf16le("T\x00e\x00s\x00t\x00")).to eq('Test')
|
13
|
+
expect(Net::NTLM::EncodeUtil.decode_utf16le("T\x00e\x00s\x00t\x00".freeze)).to eq('Test')
|
14
14
|
end
|
15
15
|
end
|
16
16
|
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Net::NTLM::TargetInfo do
|
4
|
+
let(:key1) { Net::NTLM::TargetInfo::MSV_AV_NB_COMPUTER_NAME }
|
5
|
+
let(:value1) { 'some data' }
|
6
|
+
let(:key2) { Net::NTLM::TargetInfo::MSV_AV_NB_DOMAIN_NAME }
|
7
|
+
let(:value2) { 'some other data' }
|
8
|
+
let(:data) do
|
9
|
+
dt = key1.dup
|
10
|
+
dt << [value1.length].pack('S')
|
11
|
+
dt << value1
|
12
|
+
dt << key2.dup
|
13
|
+
dt << [value2.length].pack('S')
|
14
|
+
dt << value2
|
15
|
+
dt << Net::NTLM::TargetInfo::MSV_AV_EOL
|
16
|
+
dt << [0].pack('S')
|
17
|
+
dt.force_encoding(Encoding::ASCII_8BIT)
|
18
|
+
end
|
19
|
+
|
20
|
+
subject { Net::NTLM::TargetInfo.new(data) }
|
21
|
+
|
22
|
+
describe 'invalid data' do
|
23
|
+
|
24
|
+
context 'invalid pair id' do
|
25
|
+
let(:data) { "\xFF\x00" }
|
26
|
+
|
27
|
+
it 'returns an error' do
|
28
|
+
expect{subject}.to raise_error Net::NTLM::InvalidTargetDataError
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
describe '#av_pairs' do
|
34
|
+
|
35
|
+
it 'returns the pair values with the given keys' do
|
36
|
+
expect(subject.av_pairs[key1]).to eq value1
|
37
|
+
expect(subject.av_pairs[key2]).to eq value2
|
38
|
+
end
|
39
|
+
|
40
|
+
context "target data is nil" do
|
41
|
+
subject { Net::NTLM::TargetInfo.new(nil) }
|
42
|
+
|
43
|
+
it 'returns the pair values with the given keys' do
|
44
|
+
expect(subject.av_pairs).to be_empty
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
describe '#to_s' do
|
50
|
+
let(:data) do
|
51
|
+
dt = key1.dup
|
52
|
+
dt << [value1.length].pack('S')
|
53
|
+
dt << value1
|
54
|
+
dt << key2.dup
|
55
|
+
dt << [value2.length].pack('S')
|
56
|
+
dt << value2
|
57
|
+
dt.force_encoding(Encoding::ASCII_8BIT)
|
58
|
+
end
|
59
|
+
let(:new_key) { Net::NTLM::TargetInfo::MSV_AV_CHANNEL_BINDINGS }
|
60
|
+
let(:new_value) { 'bindings' }
|
61
|
+
let(:new_data) do
|
62
|
+
dt = data
|
63
|
+
dt << new_key
|
64
|
+
dt << [new_value.length].pack('S')
|
65
|
+
dt << new_value
|
66
|
+
dt << Net::NTLM::TargetInfo::MSV_AV_EOL
|
67
|
+
dt << [0].pack('S')
|
68
|
+
dt.force_encoding(Encoding::ASCII_8BIT)
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'returns bytes with any new data added' do
|
72
|
+
subject.av_pairs[new_key] = new_value
|
73
|
+
expect(subject.to_s).to eq new_data
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
-----BEGIN CERTIFICATE-----
|
2
|
+
MIIDKjCCAhKgAwIBAgIQV0qwsk2MCoxI2Do7IQ6eQzANBgkqhkiG9w0BAQsFADAa
|
3
|
+
MRgwFgYDVQQDDA8xOTIuMTY4LjEzNy4xNjEwHhcNMTYwMTI3MjIyMzA5WhcNMTcw
|
4
|
+
MTI3MjI0MzA5WjAaMRgwFgYDVQQDDA8xOTIuMTY4LjEzNy4xNjEwggEiMA0GCSqG
|
5
|
+
SIb3DQEBAQUAA4IBDwAwggEKAoIBAQC+bGWZQFYjF+bV1WJ1L/MGVNmJR89aJ44Z
|
6
|
+
rKI/IXKFdbn5wjQPWng/DcaHR6xtMXQkc22boe58GK/uzl84ofbRa6qtboa5djdZ
|
7
|
+
9CGsd4Yf6CnVz4mhKSi+BnLi80ydhIRByxoX5bGcCSW6dixR5XiNMaMKzhCjQ+of
|
8
|
+
TU+PBNt7doXB7p0mO4AZz42v4rorRiPNasETj6wlKhFKCMvPLePTwphCgCQsLvgG
|
9
|
+
NQKtFD7TXvrZwplPSeCPhnzd1vHoZMisMn8ZVQ5dAfSEGGkPkOLO0htbUbdaNMoU
|
10
|
+
DPyo7Bu62Q/dqqo1MNbMYM5Ilw8mxe4drOs9UupH0eMovFhVMO0LAgMBAAGjbDBq
|
11
|
+
MA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwEw
|
12
|
+
GgYDVR0RBBMwEYIPMTkyLjE2OC4xMzcuMTYxMB0GA1UdDgQWBBSLuqyHonSmdm8m
|
13
|
+
9R+z2obO/X3/+TANBgkqhkiG9w0BAQsFAAOCAQEAH4pDGBclTHrwF+Bkbfj81ibK
|
14
|
+
E2SJSHbdhSx6YCsR28jXUOESfaik5ZPPMXscJqVc1FPpsU9clPFnGiAf0Kt48gsR
|
15
|
+
twfrRSGgJRv1ZgQyJ4dEQkXbQf2+8uY25Rv4kkFDSvPrE6E9o9Jf9bjqefUYski1
|
16
|
+
YoYdWzgrh/2qoNhnM34wizZgE1bWYbWA9MlUuWH9q/OBEx9uP/K53SXOR7DRzYcY
|
17
|
+
Kg1Z7hV86nvc0WutjEadgdtvJ7eUlg8vAWZqWo5SIdp69l0OEWUlHiaRsPImS5Hd
|
18
|
+
pX3W8n0wHCxBSntDww7U3SHg6DrYf72taBIQW7xFf63S37yLP4CNss68GqPdyQ==
|
19
|
+
-----END CERTIFICATE-----
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rubyntlm
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kohei Kajimoto
|
@@ -9,8 +9,22 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2021-01-27 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: github_changelog_generator
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
18
|
+
- - '='
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: 1.14.3
|
21
|
+
type: :development
|
22
|
+
prerelease: false
|
23
|
+
version_requirements: !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - '='
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
version: 1.14.3
|
14
28
|
- !ruby/object:Gem::Dependency
|
15
29
|
name: pry
|
16
30
|
requirement: !ruby/object:Gem::Requirement
|
@@ -88,9 +102,11 @@ files:
|
|
88
102
|
- examples/smtp.rb
|
89
103
|
- lib/net/ntlm.rb
|
90
104
|
- lib/net/ntlm/blob.rb
|
105
|
+
- lib/net/ntlm/channel_binding.rb
|
91
106
|
- lib/net/ntlm/client.rb
|
92
107
|
- lib/net/ntlm/client/session.rb
|
93
108
|
- lib/net/ntlm/encode_util.rb
|
109
|
+
- lib/net/ntlm/exceptions.rb
|
94
110
|
- lib/net/ntlm/field.rb
|
95
111
|
- lib/net/ntlm/field_set.rb
|
96
112
|
- lib/net/ntlm/int16_le.rb
|
@@ -103,10 +119,12 @@ files:
|
|
103
119
|
- lib/net/ntlm/message/type3.rb
|
104
120
|
- lib/net/ntlm/security_buffer.rb
|
105
121
|
- lib/net/ntlm/string.rb
|
122
|
+
- lib/net/ntlm/target_info.rb
|
106
123
|
- lib/net/ntlm/version.rb
|
107
124
|
- lib/rubyntlm.rb
|
108
125
|
- rubyntlm.gemspec
|
109
126
|
- spec/lib/net/ntlm/blob_spec.rb
|
127
|
+
- spec/lib/net/ntlm/channel_binding_spec.rb
|
110
128
|
- spec/lib/net/ntlm/client/session_spec.rb
|
111
129
|
- spec/lib/net/ntlm/client_spec.rb
|
112
130
|
- spec/lib/net/ntlm/encode_util_spec.rb
|
@@ -122,9 +140,11 @@ files:
|
|
122
140
|
- spec/lib/net/ntlm/message_spec.rb
|
123
141
|
- spec/lib/net/ntlm/security_buffer_spec.rb
|
124
142
|
- spec/lib/net/ntlm/string_spec.rb
|
143
|
+
- spec/lib/net/ntlm/target_info_spec.rb
|
125
144
|
- spec/lib/net/ntlm/version_spec.rb
|
126
145
|
- spec/lib/net/ntlm_spec.rb
|
127
146
|
- spec/spec_helper.rb
|
147
|
+
- spec/support/certificates/sha_256_hash.pem
|
128
148
|
- spec/support/shared/examples/net/ntlm/field_shared.rb
|
129
149
|
- spec/support/shared/examples/net/ntlm/fieldset_shared.rb
|
130
150
|
- spec/support/shared/examples/net/ntlm/int_shared.rb
|
@@ -148,13 +168,13 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
148
168
|
- !ruby/object:Gem::Version
|
149
169
|
version: '0'
|
150
170
|
requirements: []
|
151
|
-
|
152
|
-
rubygems_version: 2.4.7
|
171
|
+
rubygems_version: 3.1.4
|
153
172
|
signing_key:
|
154
173
|
specification_version: 4
|
155
174
|
summary: Ruby/NTLM library.
|
156
175
|
test_files:
|
157
176
|
- spec/lib/net/ntlm/blob_spec.rb
|
177
|
+
- spec/lib/net/ntlm/channel_binding_spec.rb
|
158
178
|
- spec/lib/net/ntlm/client/session_spec.rb
|
159
179
|
- spec/lib/net/ntlm/client_spec.rb
|
160
180
|
- spec/lib/net/ntlm/encode_util_spec.rb
|
@@ -170,9 +190,11 @@ test_files:
|
|
170
190
|
- spec/lib/net/ntlm/message_spec.rb
|
171
191
|
- spec/lib/net/ntlm/security_buffer_spec.rb
|
172
192
|
- spec/lib/net/ntlm/string_spec.rb
|
193
|
+
- spec/lib/net/ntlm/target_info_spec.rb
|
173
194
|
- spec/lib/net/ntlm/version_spec.rb
|
174
195
|
- spec/lib/net/ntlm_spec.rb
|
175
196
|
- spec/spec_helper.rb
|
197
|
+
- spec/support/certificates/sha_256_hash.pem
|
176
198
|
- spec/support/shared/examples/net/ntlm/field_shared.rb
|
177
199
|
- spec/support/shared/examples/net/ntlm/fieldset_shared.rb
|
178
200
|
- spec/support/shared/examples/net/ntlm/int_shared.rb
|