Module: OpenSSL::SSL

Defined in:
lib/jopenssl24.rb,
lib/jopenssl22/openssl/ssl.rb,
lib/jopenssl23/openssl/ssl.rb,
lib/jopenssl18/openssl/ssl-internal.rb,
lib/jopenssl19/openssl/ssl-internal.rb

Defined Under Namespace

Modules: Nonblock, SocketForwarder Classes: SSLContext, SSLServer, SSLSocket

Class Method Summary collapse

Class Method Details

.verify_certificate_identity(cert, hostname) ⇒ Object



138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
# File 'lib/jopenssl22/openssl/ssl.rb', line 138

def verify_certificate_identity(cert, hostname)
  should_verify_common_name = true
  cert.extensions.each { |ext|
    next if ext.oid != "subjectAltName"
    ext.value.split(/,\s+/).each { |general_name|
      #case san.tag
      # MRI 2.2.3 (JRuby parses ASN.1 differently)
      #when 2 # dNSName in GeneralName (RFC5280)
      if /\ADNS:(.*)/ =~ general_name
        should_verify_common_name = false
        return true if verify_hostname(hostname, $1)
      # MRI 2.2.3 (JRuby parses ASN.1 differently)
      #when 7 # iPAddress in GeneralName (RFC5280)
      elsif /\AIP(?: Address)?:(.*)/ =~ general_name
        should_verify_common_name = false
        return true if $1 == hostname
        # NOTE: bellow logic makes little sense JRuby reads exts differently
        # follows GENERAL_NAME_print() in x509v3/v3_alt.c
        #if san.value.size == 4
        #  return true if san.value.unpack('C*').join('.') == hostname
        #elsif san.value.size == 16
        #  return true if san.value.unpack('n*').map { |e| sprintf("%X", e) }.join(':') == hostname
        #end
      end
    }
  }
  if should_verify_common_name
    cert.subject.to_a.each{|oid, value|
      if oid == "CN"
        return true if verify_hostname(hostname, value)
      end
    }
  end
  return false
end

.verify_hostname(hostname, san) ⇒ Object

:nodoc:



175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
# File 'lib/jopenssl22/openssl/ssl.rb', line 175

def verify_hostname(hostname, san) # :nodoc:
  # RFC 5280, IA5String is limited to the set of ASCII characters
  return false unless san.ascii_only?
  return false unless hostname.ascii_only?

  # See RFC 6125, section 6.4.1
  # Matching is case-insensitive.
  san_parts = san.downcase.split(".")

  # TODO: this behavior should probably be more strict
  return san == hostname if san_parts.size < 2

  # Matching is case-insensitive.
  host_parts = hostname.downcase.split(".")

  # RFC 6125, section 6.4.3, subitem 2.
  # If the wildcard character is the only character of the left-most
  # label in the presented identifier, the client SHOULD NOT compare
  # against anything but the left-most label of the reference
  # identifier (e.g., *.example.com would match foo.example.com but
  # not bar.foo.example.com or example.com).
  return false unless san_parts.size == host_parts.size

  # RFC 6125, section 6.4.3, subitem 1.
  # The client SHOULD NOT attempt to match a presented identifier in
  # which the wildcard character comprises a label other than the
  # left-most label (e.g., do not match bar.*.example.net).
  return false unless verify_wildcard(host_parts.shift, san_parts.shift)

  san_parts.join(".") == host_parts.join(".")
end

.verify_wildcard(domain_component, san_component) ⇒ Object

:nodoc:



208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
# File 'lib/jopenssl22/openssl/ssl.rb', line 208

def verify_wildcard(domain_component, san_component) # :nodoc:
  parts = san_component.split("*", -1)

  return false if parts.size > 2
  return san_component == domain_component if parts.size == 1

  # RFC 6125, section 6.4.3, subitem 3.
  # The client SHOULD NOT attempt to match a presented identifier
  # where the wildcard character is embedded within an A-label or
  # U-label of an internationalized domain name.
  return false if domain_component.start_with?("xn--") && san_component != "*"

  parts[0].length + parts[1].length < domain_component.length &&
  domain_component.start_with?(parts[0]) &&
  domain_component.end_with?(parts[1])
end