Module: RubySMB::Gss

Defined in:
lib/ruby_smb/gss.rb,
lib/ruby_smb/gss/provider.rb,
lib/ruby_smb/gss/provider/ntlm.rb,
lib/ruby_smb/gss/provider/authenticator.rb

Overview

module containing methods required for using the GSS-API for Secure Protected Negotiation(SPNEGO) in SMB Authentication.

Defined Under Namespace

Modules: Provider

Constant Summary collapse

OID_SPNEGO =
OpenSSL::ASN1::ObjectId.new('1.3.6.1.5.5.2')
OID_NEGOEX =
OpenSSL::ASN1::ObjectId.new('1.3.6.1.4.1.311.2.2.30')
OID_NTLMSSP =
OpenSSL::ASN1::ObjectId.new('1.3.6.1.4.1.311.2.2.10')

Class Method Summary collapse

Class Method Details

.asn1dig(asn, *path) ⇒ OpenSSL::ASN1::Sequence?

Allow safe navigation of a decoded ASN.1 data structure. Similar to Ruby's builtin Hash#dig method but using the #value attribute of each ASN object.

Parameters:

  • asn

    The ASN object to apply the traversal path on.

  • path (Array)

    The path to traverse, each element is passed to the ASN object's #value's #[] operator.

Returns:

  • (OpenSSL::ASN1::Sequence, nil)


18
19
20
21
22
23
24
25
# File 'lib/ruby_smb/gss.rb', line 18

def self.asn1dig(asn, *path)
  path.each do |part|
    return nil unless asn&.value
    asn = asn.value[part]
  end

  asn
end

.asn1encode(str = '') ⇒ Object

TODO:

Document these magic numbers

Cargo culted from Rex. Hacked Together ASN1 encoding that works for our GSS purposes



29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# File 'lib/ruby_smb/gss.rb', line 29

def self.asn1encode(str = '')
  # If the high bit of the first byte is 1, it contains the number of
  # length bytes that follow
  case str.length
  when 0..0x7F
    encoded_string = [str.length].pack('C') + str
  when 0x80..0xFF
    encoded_string = [0x81, str.length].pack('CC') + str
  when 0x100..0xFFFF
    encoded_string = [0x82, str.length].pack('Cn') + str
  when  0x10000..0xffffff
    encoded_string = [0x83, str.length >> 16, str.length & 0xFFFF].pack('CCn') + str
  when  0x1000000..0xffffffff
    encoded_string = [0x84, str.length].pack('CN') + str
  else
    raise RubySMB::Error::ASN1Encoding, "Source string is too long. Size is #{str.length}"
  end
  encoded_string
end

.gss_type1(type1) ⇒ Object

Create a GSS Security Blob of an NTLM Type 1 Message.



50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/ruby_smb/gss.rb', line 50

def self.gss_type1(type1)
  OpenSSL::ASN1::ASN1Data.new([
    OID_SPNEGO,
    OpenSSL::ASN1::ASN1Data.new([
      OpenSSL::ASN1::Sequence.new([
        OpenSSL::ASN1::ASN1Data.new([
          OpenSSL::ASN1::Sequence.new([
            OID_NTLMSSP
          ])
        ], 0, :CONTEXT_SPECIFIC),
        OpenSSL::ASN1::ASN1Data.new([
          OpenSSL::ASN1::OctetString.new(type1)
        ], 2, :CONTEXT_SPECIFIC)
      ])
    ], 0, :CONTEXT_SPECIFIC)
  ], 0, :APPLICATION).to_der
end

.gss_type2(type2) ⇒ Object

Create a GSS Security Blob of an NTLM Type 2 Message.



69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
# File 'lib/ruby_smb/gss.rb', line 69

def self.gss_type2(type2)
  OpenSSL::ASN1::ASN1Data.new([
   OpenSSL::ASN1::Sequence.new([
     OpenSSL::ASN1::ASN1Data.new([
       OpenSSL::ASN1::Enumerated.new(OpenSSL::BN.new(1))
     ], 0, :CONTEXT_SPECIFIC),
     OpenSSL::ASN1::ASN1Data.new([
       OID_NTLMSSP
     ], 1, :CONTEXT_SPECIFIC),
     OpenSSL::ASN1::ASN1Data.new([
       OpenSSL::ASN1::OctetString.new(type2)
     ], 2, :CONTEXT_SPECIFIC)
   ])
  ], 1, :CONTEXT_SPECIFIC).to_der
end

.gss_type3(type3) ⇒ Object

Create a GSS Security Blob of an NTLM Type 3 Message.



86
87
88
89
90
91
92
93
94
# File 'lib/ruby_smb/gss.rb', line 86

def self.gss_type3(type3)
  OpenSSL::ASN1::ASN1Data.new([
    OpenSSL::ASN1::Sequence.new([
      OpenSSL::ASN1::ASN1Data.new([
        OpenSSL::ASN1::OctetString.new(type3)
      ], 2, :CONTEXT_SPECIFIC)
    ])
  ], 1, :CONTEXT_SPECIFIC).to_der
end