/ext/openssl/lib/openssl/ssl.rb

https://github.com/jlamberg/ruby · Ruby · 185 lines · 139 code · 24 blank · 22 comment · 15 complexity · 973415ea217657718eb13a26f2bed3ec MD5 · raw file

  1. =begin
  2. = $RCSfile$ -- Ruby-space definitions that completes C-space funcs for SSL
  3. = Info
  4. 'OpenSSL for Ruby 2' project
  5. Copyright (C) 2001 GOTOU YUUZOU <gotoyuzo@notwork.org>
  6. All rights reserved.
  7. = Licence
  8. This program is licenced under the same licence as Ruby.
  9. (See the file 'LICENCE'.)
  10. = Version
  11. $Id$
  12. =end
  13. require "openssl/buffering"
  14. require "fcntl"
  15. module OpenSSL
  16. module SSL
  17. class SSLContext
  18. DEFAULT_PARAMS = {
  19. :ssl_version => "SSLv23",
  20. :verify_mode => OpenSSL::SSL::VERIFY_PEER,
  21. :ciphers => "ALL:!ADH:!EXPORT:!SSLv2:RC4+RSA:+HIGH:+MEDIUM:+LOW",
  22. :options => OpenSSL::SSL::OP_ALL,
  23. }
  24. DEFAULT_CERT_STORE = OpenSSL::X509::Store.new
  25. DEFAULT_CERT_STORE.set_default_paths
  26. if defined?(OpenSSL::X509::V_FLAG_CRL_CHECK_ALL)
  27. DEFAULT_CERT_STORE.flags = OpenSSL::X509::V_FLAG_CRL_CHECK_ALL
  28. end
  29. ##
  30. # Sets the parameters for this SSL context to the values in +params+.
  31. # The keys in +params+ must be assignment methods on SSLContext.
  32. #
  33. # If the verify_mode is not VERIFY_NONE and ca_file, ca_path and
  34. # cert_store are not set then the system default certificate store is
  35. # used.
  36. def set_params(params={})
  37. params = DEFAULT_PARAMS.merge(params)
  38. params.each{|name, value| self.__send__("#{name}=", value) }
  39. if self.verify_mode != OpenSSL::SSL::VERIFY_NONE
  40. unless self.ca_file or self.ca_path or self.cert_store
  41. self.cert_store = DEFAULT_CERT_STORE
  42. end
  43. end
  44. return params
  45. end
  46. end
  47. module SocketForwarder
  48. def addr
  49. to_io.addr
  50. end
  51. def peeraddr
  52. to_io.peeraddr
  53. end
  54. def setsockopt(level, optname, optval)
  55. to_io.setsockopt(level, optname, optval)
  56. end
  57. def getsockopt(level, optname)
  58. to_io.getsockopt(level, optname)
  59. end
  60. def fcntl(*args)
  61. to_io.fcntl(*args)
  62. end
  63. def closed?
  64. to_io.closed?
  65. end
  66. def do_not_reverse_lookup=(flag)
  67. to_io.do_not_reverse_lookup = flag
  68. end
  69. end
  70. module Nonblock
  71. def initialize(*args)
  72. flag = File::NONBLOCK
  73. flag |= @io.fcntl(Fcntl::F_GETFL) if defined?(Fcntl::F_GETFL)
  74. @io.fcntl(Fcntl::F_SETFL, flag)
  75. super
  76. end
  77. end
  78. def verify_certificate_identity(cert, hostname)
  79. should_verify_common_name = true
  80. cert.extensions.each{|ext|
  81. next if ext.oid != "subjectAltName"
  82. ext.value.split(/,\s+/).each{|general_name|
  83. if /\ADNS:(.*)/ =~ general_name
  84. should_verify_common_name = false
  85. reg = Regexp.escape($1).gsub(/\\\*/, "[^.]+")
  86. return true if /\A#{reg}\z/i =~ hostname
  87. elsif /\AIP Address:(.*)/ =~ general_name
  88. should_verify_common_name = false
  89. return true if $1 == hostname
  90. end
  91. }
  92. }
  93. if should_verify_common_name
  94. cert.subject.to_a.each{|oid, value|
  95. if oid == "CN"
  96. reg = Regexp.escape(value).gsub(/\\\*/, "[^.]+")
  97. return true if /\A#{reg}\z/i =~ hostname
  98. end
  99. }
  100. end
  101. return false
  102. end
  103. module_function :verify_certificate_identity
  104. class SSLSocket
  105. include Buffering
  106. include SocketForwarder
  107. include Nonblock
  108. def post_connection_check(hostname)
  109. unless OpenSSL::SSL.verify_certificate_identity(peer_cert, hostname)
  110. raise SSLError, "hostname does not match the server certificate"
  111. end
  112. return true
  113. end
  114. def session
  115. SSL::Session.new(self)
  116. rescue SSL::Session::SessionError
  117. nil
  118. end
  119. end
  120. class SSLServer
  121. include SocketForwarder
  122. attr_accessor :start_immediately
  123. def initialize(svr, ctx)
  124. @svr = svr
  125. @ctx = ctx
  126. unless ctx.session_id_context
  127. session_id = OpenSSL::Digest::MD5.hexdigest($0)
  128. @ctx.session_id_context = session_id
  129. end
  130. @start_immediately = true
  131. end
  132. def to_io
  133. @svr
  134. end
  135. def listen(backlog=5)
  136. @svr.listen(backlog)
  137. end
  138. def shutdown(how=Socket::SHUT_RDWR)
  139. @svr.shutdown(how)
  140. end
  141. def accept
  142. sock = @svr.accept
  143. begin
  144. ssl = OpenSSL::SSL::SSLSocket.new(sock, @ctx)
  145. ssl.sync_close = true
  146. ssl.accept if @start_immediately
  147. ssl
  148. rescue SSLError => ex
  149. sock.close
  150. raise ex
  151. end
  152. end
  153. def close
  154. @svr.close
  155. end
  156. end
  157. end
  158. end