mirror of
https://github.com/mistergibson/gxg-web-client.git
synced 2026-10-19 07:39:44 -07:00
Initial Commit
This commit is contained in:
parent
356ad3315b
commit
81daf6f387
283 changed files with 130672 additions and 1 deletions
40
gxg/standard/openssl/bn.rb
Normal file
40
gxg/standard/openssl/bn.rb
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
# frozen_string_literal: false
|
||||
#--
|
||||
#
|
||||
# = Ruby-space definitions that completes C-space funcs for BN
|
||||
#
|
||||
# = Info
|
||||
# 'OpenSSL for Ruby 2' project
|
||||
# Copyright (C) 2002 Michal Rokos <m.rokos@sh.cvut.cz>
|
||||
# All rights reserved.
|
||||
#
|
||||
# = Licence
|
||||
# This program is licensed under the same licence as Ruby.
|
||||
# (See the file 'LICENCE'.)
|
||||
#++
|
||||
|
||||
module OpenSSL
|
||||
class BN
|
||||
include Comparable
|
||||
|
||||
def pretty_print(q)
|
||||
q.object_group(self) {
|
||||
q.text ' '
|
||||
q.text to_i.to_s
|
||||
}
|
||||
end
|
||||
end # BN
|
||||
end # OpenSSL
|
||||
|
||||
##
|
||||
#--
|
||||
# Add double dispatch to Integer
|
||||
#++
|
||||
class Integer
|
||||
# Casts an Integer as an OpenSSL::BN
|
||||
#
|
||||
# See `man bn` for more info.
|
||||
def to_bn
|
||||
OpenSSL::BN::new(self)
|
||||
end
|
||||
end # Integer
|
||||
455
gxg/standard/openssl/buffering.rb
Normal file
455
gxg/standard/openssl/buffering.rb
Normal file
|
|
@ -0,0 +1,455 @@
|
|||
# coding: binary
|
||||
# frozen_string_literal: false
|
||||
#--
|
||||
#= Info
|
||||
# 'OpenSSL for Ruby 2' project
|
||||
# Copyright (C) 2001 GOTOU YUUZOU <gotoyuzo@notwork.org>
|
||||
# All rights reserved.
|
||||
#
|
||||
#= Licence
|
||||
# This program is licensed under the same licence as Ruby.
|
||||
# (See the file 'LICENCE'.)
|
||||
#++
|
||||
|
||||
##
|
||||
# OpenSSL IO buffering mix-in module.
|
||||
#
|
||||
# This module allows an OpenSSL::SSL::SSLSocket to behave like an IO.
|
||||
#
|
||||
# You typically won't use this module directly, you can see it implemented in
|
||||
# OpenSSL::SSL::SSLSocket.
|
||||
|
||||
module OpenSSL::Buffering
|
||||
include Enumerable
|
||||
|
||||
##
|
||||
# The "sync mode" of the SSLSocket.
|
||||
#
|
||||
# See IO#sync for full details.
|
||||
|
||||
attr_accessor :sync
|
||||
|
||||
##
|
||||
# Default size to read from or write to the SSLSocket for buffer operations.
|
||||
|
||||
BLOCK_SIZE = 1024*16
|
||||
|
||||
##
|
||||
# Creates an instance of OpenSSL's buffering IO module.
|
||||
|
||||
def initialize(*)
|
||||
super
|
||||
@eof = false
|
||||
@rbuffer = ""
|
||||
@sync = @io.sync
|
||||
end
|
||||
|
||||
#
|
||||
# for reading.
|
||||
#
|
||||
private
|
||||
|
||||
##
|
||||
# Fills the buffer from the underlying SSLSocket
|
||||
|
||||
def fill_rbuff
|
||||
begin
|
||||
@rbuffer << self.sysread(BLOCK_SIZE)
|
||||
rescue Errno::EAGAIN
|
||||
retry
|
||||
rescue EOFError
|
||||
@eof = true
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# Consumes _size_ bytes from the buffer
|
||||
|
||||
def consume_rbuff(size=nil)
|
||||
if @rbuffer.empty?
|
||||
nil
|
||||
else
|
||||
size = @rbuffer.size unless size
|
||||
ret = @rbuffer[0, size]
|
||||
@rbuffer[0, size] = ""
|
||||
ret
|
||||
end
|
||||
end
|
||||
|
||||
public
|
||||
|
||||
##
|
||||
# Reads _size_ bytes from the stream. If _buf_ is provided it must
|
||||
# reference a string which will receive the data.
|
||||
#
|
||||
# See IO#read for full details.
|
||||
|
||||
def read(size=nil, buf=nil)
|
||||
if size == 0
|
||||
if buf
|
||||
buf.clear
|
||||
return buf
|
||||
else
|
||||
return ""
|
||||
end
|
||||
end
|
||||
until @eof
|
||||
break if size && size <= @rbuffer.size
|
||||
fill_rbuff
|
||||
end
|
||||
ret = consume_rbuff(size) || ""
|
||||
if buf
|
||||
buf.replace(ret)
|
||||
ret = buf
|
||||
end
|
||||
(size && ret.empty?) ? nil : ret
|
||||
end
|
||||
|
||||
##
|
||||
# Reads at most _maxlen_ bytes from the stream. If _buf_ is provided it
|
||||
# must reference a string which will receive the data.
|
||||
#
|
||||
# See IO#readpartial for full details.
|
||||
|
||||
def readpartial(maxlen, buf=nil)
|
||||
if maxlen == 0
|
||||
if buf
|
||||
buf.clear
|
||||
return buf
|
||||
else
|
||||
return ""
|
||||
end
|
||||
end
|
||||
if @rbuffer.empty?
|
||||
begin
|
||||
return sysread(maxlen, buf)
|
||||
rescue Errno::EAGAIN
|
||||
retry
|
||||
end
|
||||
end
|
||||
ret = consume_rbuff(maxlen)
|
||||
if buf
|
||||
buf.replace(ret)
|
||||
ret = buf
|
||||
end
|
||||
ret
|
||||
end
|
||||
|
||||
##
|
||||
# Reads at most _maxlen_ bytes in the non-blocking manner.
|
||||
#
|
||||
# When no data can be read without blocking it raises
|
||||
# OpenSSL::SSL::SSLError extended by IO::WaitReadable or IO::WaitWritable.
|
||||
#
|
||||
# IO::WaitReadable means SSL needs to read internally so read_nonblock
|
||||
# should be called again when the underlying IO is readable.
|
||||
#
|
||||
# IO::WaitWritable means SSL needs to write internally so read_nonblock
|
||||
# should be called again after the underlying IO is writable.
|
||||
#
|
||||
# OpenSSL::Buffering#read_nonblock needs two rescue clause as follows:
|
||||
#
|
||||
# # emulates blocking read (readpartial).
|
||||
# begin
|
||||
# result = ssl.read_nonblock(maxlen)
|
||||
# rescue IO::WaitReadable
|
||||
# IO.select([io])
|
||||
# retry
|
||||
# rescue IO::WaitWritable
|
||||
# IO.select(nil, [io])
|
||||
# retry
|
||||
# end
|
||||
#
|
||||
# Note that one reason that read_nonblock writes to the underlying IO is
|
||||
# when the peer requests a new TLS/SSL handshake. See openssl the FAQ for
|
||||
# more details. http://www.openssl.org/support/faq.html
|
||||
#
|
||||
# By specifying a keyword argument _exception_ to +false+, you can indicate
|
||||
# that read_nonblock should not raise an IO::Wait*able exception, but
|
||||
# return the symbol +:wait_writable+ or +:wait_readable+ instead. At EOF,
|
||||
# it will return +nil+ instead of raising EOFError.
|
||||
|
||||
def read_nonblock(maxlen, buf=nil, exception: true)
|
||||
if maxlen == 0
|
||||
if buf
|
||||
buf.clear
|
||||
return buf
|
||||
else
|
||||
return ""
|
||||
end
|
||||
end
|
||||
if @rbuffer.empty?
|
||||
return sysread_nonblock(maxlen, buf, exception: exception)
|
||||
end
|
||||
ret = consume_rbuff(maxlen)
|
||||
if buf
|
||||
buf.replace(ret)
|
||||
ret = buf
|
||||
end
|
||||
ret
|
||||
end
|
||||
|
||||
##
|
||||
# Reads the next "line" from the stream. Lines are separated by _eol_. If
|
||||
# _limit_ is provided the result will not be longer than the given number of
|
||||
# bytes.
|
||||
#
|
||||
# _eol_ may be a String or Regexp.
|
||||
#
|
||||
# Unlike IO#gets the line read will not be assigned to +$_+.
|
||||
#
|
||||
# Unlike IO#gets the separator must be provided if a limit is provided.
|
||||
|
||||
def gets(eol=$/, limit=nil)
|
||||
idx = @rbuffer.index(eol)
|
||||
until @eof
|
||||
break if idx
|
||||
fill_rbuff
|
||||
idx = @rbuffer.index(eol)
|
||||
end
|
||||
if eol.is_a?(Regexp)
|
||||
size = idx ? idx+$&.size : nil
|
||||
else
|
||||
size = idx ? idx+eol.size : nil
|
||||
end
|
||||
if size && limit && limit >= 0
|
||||
size = [size, limit].min
|
||||
end
|
||||
consume_rbuff(size)
|
||||
end
|
||||
|
||||
##
|
||||
# Executes the block for every line in the stream where lines are separated
|
||||
# by _eol_.
|
||||
#
|
||||
# See also #gets
|
||||
|
||||
def each(eol=$/)
|
||||
while line = self.gets(eol)
|
||||
yield line
|
||||
end
|
||||
end
|
||||
alias each_line each
|
||||
|
||||
##
|
||||
# Reads lines from the stream which are separated by _eol_.
|
||||
#
|
||||
# See also #gets
|
||||
|
||||
def readlines(eol=$/)
|
||||
ary = []
|
||||
while line = self.gets(eol)
|
||||
ary << line
|
||||
end
|
||||
ary
|
||||
end
|
||||
|
||||
##
|
||||
# Reads a line from the stream which is separated by _eol_.
|
||||
#
|
||||
# Raises EOFError if at end of file.
|
||||
|
||||
def readline(eol=$/)
|
||||
raise EOFError if eof?
|
||||
gets(eol)
|
||||
end
|
||||
|
||||
##
|
||||
# Reads one character from the stream. Returns nil if called at end of
|
||||
# file.
|
||||
|
||||
def getc
|
||||
read(1)
|
||||
end
|
||||
|
||||
##
|
||||
# Calls the given block once for each byte in the stream.
|
||||
|
||||
def each_byte # :yields: byte
|
||||
while c = getc
|
||||
yield(c.ord)
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# Reads a one-character string from the stream. Raises an EOFError at end
|
||||
# of file.
|
||||
|
||||
def readchar
|
||||
raise EOFError if eof?
|
||||
getc
|
||||
end
|
||||
|
||||
##
|
||||
# Pushes character _c_ back onto the stream such that a subsequent buffered
|
||||
# character read will return it.
|
||||
#
|
||||
# Unlike IO#getc multiple bytes may be pushed back onto the stream.
|
||||
#
|
||||
# Has no effect on unbuffered reads (such as #sysread).
|
||||
|
||||
def ungetc(c)
|
||||
@rbuffer[0,0] = c.chr
|
||||
end
|
||||
|
||||
##
|
||||
# Returns true if the stream is at file which means there is no more data to
|
||||
# be read.
|
||||
|
||||
def eof?
|
||||
fill_rbuff if !@eof && @rbuffer.empty?
|
||||
@eof && @rbuffer.empty?
|
||||
end
|
||||
alias eof eof?
|
||||
|
||||
#
|
||||
# for writing.
|
||||
#
|
||||
private
|
||||
|
||||
##
|
||||
# Writes _s_ to the buffer. When the buffer is full or #sync is true the
|
||||
# buffer is flushed to the underlying socket.
|
||||
|
||||
def do_write(s)
|
||||
@wbuffer = "" unless defined? @wbuffer
|
||||
@wbuffer << s
|
||||
@wbuffer.force_encoding(Encoding::BINARY)
|
||||
@sync ||= false
|
||||
if @sync or @wbuffer.size > BLOCK_SIZE or @wbuffer.rindex("\n")
|
||||
until @wbuffer.empty?
|
||||
begin
|
||||
nwrote = syswrite(@wbuffer)
|
||||
rescue Errno::EAGAIN
|
||||
retry
|
||||
end
|
||||
@wbuffer[0, nwrote] = ""
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
public
|
||||
|
||||
##
|
||||
# Writes _s_ to the stream. If the argument is not a String it will be
|
||||
# converted using +.to_s+ method. Returns the number of bytes written.
|
||||
|
||||
def write(*s)
|
||||
s.inject(0) do |written, str|
|
||||
do_write(str)
|
||||
written + str.bytesize
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# Writes _s_ in the non-blocking manner.
|
||||
#
|
||||
# If there is buffered data, it is flushed first. This may block.
|
||||
#
|
||||
# write_nonblock returns number of bytes written to the SSL connection.
|
||||
#
|
||||
# When no data can be written without blocking it raises
|
||||
# OpenSSL::SSL::SSLError extended by IO::WaitReadable or IO::WaitWritable.
|
||||
#
|
||||
# IO::WaitReadable means SSL needs to read internally so write_nonblock
|
||||
# should be called again after the underlying IO is readable.
|
||||
#
|
||||
# IO::WaitWritable means SSL needs to write internally so write_nonblock
|
||||
# should be called again after underlying IO is writable.
|
||||
#
|
||||
# So OpenSSL::Buffering#write_nonblock needs two rescue clause as follows.
|
||||
#
|
||||
# # emulates blocking write.
|
||||
# begin
|
||||
# result = ssl.write_nonblock(str)
|
||||
# rescue IO::WaitReadable
|
||||
# IO.select([io])
|
||||
# retry
|
||||
# rescue IO::WaitWritable
|
||||
# IO.select(nil, [io])
|
||||
# retry
|
||||
# end
|
||||
#
|
||||
# Note that one reason that write_nonblock reads from the underlying IO
|
||||
# is when the peer requests a new TLS/SSL handshake. See the openssl FAQ
|
||||
# for more details. http://www.openssl.org/support/faq.html
|
||||
#
|
||||
# By specifying a keyword argument _exception_ to +false+, you can indicate
|
||||
# that write_nonblock should not raise an IO::Wait*able exception, but
|
||||
# return the symbol +:wait_writable+ or +:wait_readable+ instead.
|
||||
|
||||
def write_nonblock(s, exception: true)
|
||||
flush
|
||||
syswrite_nonblock(s, exception: exception)
|
||||
end
|
||||
|
||||
##
|
||||
# Writes _s_ to the stream. _s_ will be converted to a String using
|
||||
# +.to_s+ method.
|
||||
|
||||
def <<(s)
|
||||
do_write(s)
|
||||
self
|
||||
end
|
||||
|
||||
##
|
||||
# Writes _args_ to the stream along with a record separator.
|
||||
#
|
||||
# See IO#puts for full details.
|
||||
|
||||
def puts(*args)
|
||||
s = ""
|
||||
if args.empty?
|
||||
s << "\n"
|
||||
end
|
||||
args.each{|arg|
|
||||
s << arg.to_s
|
||||
s.sub!(/(?<!\n)\z/, "\n")
|
||||
}
|
||||
do_write(s)
|
||||
nil
|
||||
end
|
||||
|
||||
##
|
||||
# Writes _args_ to the stream.
|
||||
#
|
||||
# See IO#print for full details.
|
||||
|
||||
def print(*args)
|
||||
s = ""
|
||||
args.each{ |arg| s << arg.to_s }
|
||||
do_write(s)
|
||||
nil
|
||||
end
|
||||
|
||||
##
|
||||
# Formats and writes to the stream converting parameters under control of
|
||||
# the format string.
|
||||
#
|
||||
# See Kernel#sprintf for format string details.
|
||||
|
||||
def printf(s, *args)
|
||||
do_write(s % args)
|
||||
nil
|
||||
end
|
||||
|
||||
##
|
||||
# Flushes buffered data to the SSLSocket.
|
||||
|
||||
def flush
|
||||
osync = @sync
|
||||
@sync = true
|
||||
do_write ""
|
||||
return self
|
||||
ensure
|
||||
@sync = osync
|
||||
end
|
||||
|
||||
##
|
||||
# Closes the SSLSocket and flushes any unwritten data.
|
||||
|
||||
def close
|
||||
flush rescue nil
|
||||
sysclose
|
||||
end
|
||||
end
|
||||
67
gxg/standard/openssl/cipher.rb
Normal file
67
gxg/standard/openssl/cipher.rb
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
# frozen_string_literal: false
|
||||
#--
|
||||
# = Ruby-space predefined Cipher subclasses
|
||||
#
|
||||
# = Info
|
||||
# 'OpenSSL for Ruby 2' project
|
||||
# Copyright (C) 2002 Michal Rokos <m.rokos@sh.cvut.cz>
|
||||
# All rights reserved.
|
||||
#
|
||||
# = Licence
|
||||
# This program is licensed under the same licence as Ruby.
|
||||
# (See the file 'LICENCE'.)
|
||||
#++
|
||||
|
||||
module OpenSSL
|
||||
class Cipher
|
||||
%w(AES CAST5 BF DES IDEA RC2 RC4 RC5).each{|name|
|
||||
klass = Class.new(Cipher){
|
||||
define_method(:initialize){|*args|
|
||||
cipher_name = args.inject(name){|n, arg| "#{n}-#{arg}" }
|
||||
super(cipher_name.downcase)
|
||||
}
|
||||
}
|
||||
const_set(name, klass)
|
||||
}
|
||||
|
||||
%w(128 192 256).each{|keylen|
|
||||
klass = Class.new(Cipher){
|
||||
define_method(:initialize){|mode = "CBC"|
|
||||
super("aes-#{keylen}-#{mode}".downcase)
|
||||
}
|
||||
}
|
||||
const_set("AES#{keylen}", klass)
|
||||
}
|
||||
|
||||
# call-seq:
|
||||
# cipher.random_key -> key
|
||||
#
|
||||
# Generate a random key with OpenSSL::Random.random_bytes and sets it to
|
||||
# the cipher, and returns it.
|
||||
#
|
||||
# You must call #encrypt or #decrypt before calling this method.
|
||||
def random_key
|
||||
str = OpenSSL::Random.random_bytes(self.key_len)
|
||||
self.key = str
|
||||
end
|
||||
|
||||
# call-seq:
|
||||
# cipher.random_iv -> iv
|
||||
#
|
||||
# Generate a random IV with OpenSSL::Random.random_bytes and sets it to the
|
||||
# cipher, and returns it.
|
||||
#
|
||||
# You must call #encrypt or #decrypt before calling this method.
|
||||
def random_iv
|
||||
str = OpenSSL::Random.random_bytes(self.iv_len)
|
||||
self.iv = str
|
||||
end
|
||||
|
||||
# Deprecated.
|
||||
#
|
||||
# This class is only provided for backwards compatibility.
|
||||
# Use OpenSSL::Cipher.
|
||||
class Cipher < Cipher; end
|
||||
deprecate_constant :Cipher
|
||||
end # Cipher
|
||||
end # OpenSSL
|
||||
474
gxg/standard/openssl/config.rb
Normal file
474
gxg/standard/openssl/config.rb
Normal file
|
|
@ -0,0 +1,474 @@
|
|||
# frozen_string_literal: false
|
||||
=begin
|
||||
= Ruby-space definitions that completes C-space funcs for Config
|
||||
|
||||
= Info
|
||||
Copyright (C) 2010 Hiroshi Nakamura <nahi@ruby-lang.org>
|
||||
|
||||
= Licence
|
||||
This program is licensed under the same licence as Ruby.
|
||||
(See the file 'LICENCE'.)
|
||||
|
||||
=end
|
||||
|
||||
require 'stringio'
|
||||
|
||||
module OpenSSL
|
||||
##
|
||||
# = OpenSSL::Config
|
||||
#
|
||||
# Configuration for the openssl library.
|
||||
#
|
||||
# Many system's installation of openssl library will depend on your system
|
||||
# configuration. See the value of OpenSSL::Config::DEFAULT_CONFIG_FILE for
|
||||
# the location of the file for your host.
|
||||
#
|
||||
# See also http://www.openssl.org/docs/apps/config.html
|
||||
class Config
|
||||
include Enumerable
|
||||
|
||||
class << self
|
||||
|
||||
##
|
||||
# Parses a given _string_ as a blob that contains configuration for
|
||||
# OpenSSL.
|
||||
#
|
||||
# If the source of the IO is a file, then consider using #parse_config.
|
||||
def parse(string)
|
||||
c = new()
|
||||
parse_config(StringIO.new(string)).each do |section, hash|
|
||||
c[section] = hash
|
||||
end
|
||||
c
|
||||
end
|
||||
|
||||
##
|
||||
# load is an alias to ::new
|
||||
alias load new
|
||||
|
||||
##
|
||||
# Parses the configuration data read from _io_, see also #parse.
|
||||
#
|
||||
# Raises a ConfigError on invalid configuration data.
|
||||
def parse_config(io)
|
||||
begin
|
||||
parse_config_lines(io)
|
||||
rescue ConfigError => e
|
||||
e.message.replace("error in line #{io.lineno}: " + e.message)
|
||||
raise
|
||||
end
|
||||
end
|
||||
|
||||
def get_key_string(data, section, key) # :nodoc:
|
||||
if v = data[section] && data[section][key]
|
||||
return v
|
||||
elsif section == 'ENV'
|
||||
if v = ENV[key]
|
||||
return v
|
||||
end
|
||||
end
|
||||
if v = data['default'] && data['default'][key]
|
||||
return v
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def parse_config_lines(io)
|
||||
section = 'default'
|
||||
data = {section => {}}
|
||||
while definition = get_definition(io)
|
||||
definition = clear_comments(definition)
|
||||
next if definition.empty?
|
||||
if definition[0] == ?[
|
||||
if /\[([^\]]*)\]/ =~ definition
|
||||
section = $1.strip
|
||||
data[section] ||= {}
|
||||
else
|
||||
raise ConfigError, "missing close square bracket"
|
||||
end
|
||||
else
|
||||
if /\A([^:\s]*)(?:::([^:\s]*))?\s*=(.*)\z/ =~ definition
|
||||
if $2
|
||||
section = $1
|
||||
key = $2
|
||||
else
|
||||
key = $1
|
||||
end
|
||||
value = unescape_value(data, section, $3)
|
||||
(data[section] ||= {})[key] = value.strip
|
||||
else
|
||||
raise ConfigError, "missing equal sign"
|
||||
end
|
||||
end
|
||||
end
|
||||
data
|
||||
end
|
||||
|
||||
# escape with backslash
|
||||
QUOTE_REGEXP_SQ = /\A([^'\\]*(?:\\.[^'\\]*)*)'/
|
||||
# escape with backslash and doubled dq
|
||||
QUOTE_REGEXP_DQ = /\A([^"\\]*(?:""[^"\\]*|\\.[^"\\]*)*)"/
|
||||
# escaped char map
|
||||
ESCAPE_MAP = {
|
||||
"r" => "\r",
|
||||
"n" => "\n",
|
||||
"b" => "\b",
|
||||
"t" => "\t",
|
||||
}
|
||||
|
||||
def unescape_value(data, section, value)
|
||||
scanned = []
|
||||
while m = value.match(/['"\\$]/)
|
||||
scanned << m.pre_match
|
||||
c = m[0]
|
||||
value = m.post_match
|
||||
case c
|
||||
when "'"
|
||||
if m = value.match(QUOTE_REGEXP_SQ)
|
||||
scanned << m[1].gsub(/\\(.)/, '\\1')
|
||||
value = m.post_match
|
||||
else
|
||||
break
|
||||
end
|
||||
when '"'
|
||||
if m = value.match(QUOTE_REGEXP_DQ)
|
||||
scanned << m[1].gsub(/""/, '').gsub(/\\(.)/, '\\1')
|
||||
value = m.post_match
|
||||
else
|
||||
break
|
||||
end
|
||||
when "\\"
|
||||
c = value.slice!(0, 1)
|
||||
scanned << (ESCAPE_MAP[c] || c)
|
||||
when "$"
|
||||
ref, value = extract_reference(value)
|
||||
refsec = section
|
||||
if ref.index('::')
|
||||
refsec, ref = ref.split('::', 2)
|
||||
end
|
||||
if v = get_key_string(data, refsec, ref)
|
||||
scanned << v
|
||||
else
|
||||
raise ConfigError, "variable has no value"
|
||||
end
|
||||
else
|
||||
raise 'must not reaced'
|
||||
end
|
||||
end
|
||||
scanned << value
|
||||
scanned.join
|
||||
end
|
||||
|
||||
def extract_reference(value)
|
||||
rest = ''
|
||||
if m = value.match(/\(([^)]*)\)|\{([^}]*)\}/)
|
||||
value = m[1] || m[2]
|
||||
rest = m.post_match
|
||||
elsif [?(, ?{].include?(value[0])
|
||||
raise ConfigError, "no close brace"
|
||||
end
|
||||
if m = value.match(/[a-zA-Z0-9_]*(?:::[a-zA-Z0-9_]*)?/)
|
||||
return m[0], m.post_match + rest
|
||||
else
|
||||
raise
|
||||
end
|
||||
end
|
||||
|
||||
def clear_comments(line)
|
||||
# FCOMMENT
|
||||
if m = line.match(/\A([\t\n\f ]*);.*\z/)
|
||||
return m[1]
|
||||
end
|
||||
# COMMENT
|
||||
scanned = []
|
||||
while m = line.match(/[#'"\\]/)
|
||||
scanned << m.pre_match
|
||||
c = m[0]
|
||||
line = m.post_match
|
||||
case c
|
||||
when '#'
|
||||
line = nil
|
||||
break
|
||||
when "'", '"'
|
||||
regexp = (c == "'") ? QUOTE_REGEXP_SQ : QUOTE_REGEXP_DQ
|
||||
scanned << c
|
||||
if m = line.match(regexp)
|
||||
scanned << m[0]
|
||||
line = m.post_match
|
||||
else
|
||||
scanned << line
|
||||
line = nil
|
||||
break
|
||||
end
|
||||
when "\\"
|
||||
scanned << c
|
||||
scanned << line.slice!(0, 1)
|
||||
else
|
||||
raise 'must not reaced'
|
||||
end
|
||||
end
|
||||
scanned << line
|
||||
scanned.join
|
||||
end
|
||||
|
||||
def get_definition(io)
|
||||
if line = get_line(io)
|
||||
while /[^\\]\\\z/ =~ line
|
||||
if extra = get_line(io)
|
||||
line += extra
|
||||
else
|
||||
break
|
||||
end
|
||||
end
|
||||
return line.strip
|
||||
end
|
||||
end
|
||||
|
||||
def get_line(io)
|
||||
if line = io.gets
|
||||
line.gsub(/[\r\n]*/, '')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# Creates an instance of OpenSSL's configuration class.
|
||||
#
|
||||
# This can be used in contexts like OpenSSL::X509::ExtensionFactory.config=
|
||||
#
|
||||
# If the optional _filename_ parameter is provided, then it is read in and
|
||||
# parsed via #parse_config.
|
||||
#
|
||||
# This can raise IO exceptions based on the access, or availability of the
|
||||
# file. A ConfigError exception may be raised depending on the validity of
|
||||
# the data being configured.
|
||||
#
|
||||
def initialize(filename = nil)
|
||||
@data = {}
|
||||
if filename
|
||||
File.open(filename.to_s) do |file|
|
||||
Config.parse_config(file).each do |section, hash|
|
||||
self[section] = hash
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# Gets the value of _key_ from the given _section_
|
||||
#
|
||||
# Given the following configurating file being loaded:
|
||||
#
|
||||
# config = OpenSSL::Config.load('foo.cnf')
|
||||
# #=> #<OpenSSL::Config sections=["default"]>
|
||||
# puts config.to_s
|
||||
# #=> [ default ]
|
||||
# # foo=bar
|
||||
#
|
||||
# You can get a specific value from the config if you know the _section_
|
||||
# and _key_ like so:
|
||||
#
|
||||
# config.get_value('default','foo')
|
||||
# #=> "bar"
|
||||
#
|
||||
def get_value(section, key)
|
||||
if section.nil?
|
||||
raise TypeError.new('nil not allowed')
|
||||
end
|
||||
section = 'default' if section.empty?
|
||||
get_key_string(section, key)
|
||||
end
|
||||
|
||||
##
|
||||
#
|
||||
# *Deprecated*
|
||||
#
|
||||
# Use #get_value instead
|
||||
def value(arg1, arg2 = nil) # :nodoc:
|
||||
warn('Config#value is deprecated; use Config#get_value')
|
||||
if arg2.nil?
|
||||
section, key = 'default', arg1
|
||||
else
|
||||
section, key = arg1, arg2
|
||||
end
|
||||
section ||= 'default'
|
||||
section = 'default' if section.empty?
|
||||
get_key_string(section, key)
|
||||
end
|
||||
|
||||
##
|
||||
# Set the target _key_ with a given _value_ under a specific _section_.
|
||||
#
|
||||
# Given the following configurating file being loaded:
|
||||
#
|
||||
# config = OpenSSL::Config.load('foo.cnf')
|
||||
# #=> #<OpenSSL::Config sections=["default"]>
|
||||
# puts config.to_s
|
||||
# #=> [ default ]
|
||||
# # foo=bar
|
||||
#
|
||||
# You can set the value of _foo_ under the _default_ section to a new
|
||||
# value:
|
||||
#
|
||||
# config.add_value('default', 'foo', 'buzz')
|
||||
# #=> "buzz"
|
||||
# puts config.to_s
|
||||
# #=> [ default ]
|
||||
# # foo=buzz
|
||||
#
|
||||
def add_value(section, key, value)
|
||||
check_modify
|
||||
(@data[section] ||= {})[key] = value
|
||||
end
|
||||
|
||||
##
|
||||
# Get a specific _section_ from the current configuration
|
||||
#
|
||||
# Given the following configurating file being loaded:
|
||||
#
|
||||
# config = OpenSSL::Config.load('foo.cnf')
|
||||
# #=> #<OpenSSL::Config sections=["default"]>
|
||||
# puts config.to_s
|
||||
# #=> [ default ]
|
||||
# # foo=bar
|
||||
#
|
||||
# You can get a hash of the specific section like so:
|
||||
#
|
||||
# config['default']
|
||||
# #=> {"foo"=>"bar"}
|
||||
#
|
||||
def [](section)
|
||||
@data[section] || {}
|
||||
end
|
||||
|
||||
##
|
||||
# Deprecated
|
||||
#
|
||||
# Use #[] instead
|
||||
def section(name) # :nodoc:
|
||||
warn('Config#section is deprecated; use Config#[]')
|
||||
@data[name] || {}
|
||||
end
|
||||
|
||||
##
|
||||
# Sets a specific _section_ name with a Hash _pairs_.
|
||||
#
|
||||
# Given the following configuration being created:
|
||||
#
|
||||
# config = OpenSSL::Config.new
|
||||
# #=> #<OpenSSL::Config sections=[]>
|
||||
# config['default'] = {"foo"=>"bar","baz"=>"buz"}
|
||||
# #=> {"foo"=>"bar", "baz"=>"buz"}
|
||||
# puts config.to_s
|
||||
# #=> [ default ]
|
||||
# # foo=bar
|
||||
# # baz=buz
|
||||
#
|
||||
# It's important to note that this will essentially merge any of the keys
|
||||
# in _pairs_ with the existing _section_. For example:
|
||||
#
|
||||
# config['default']
|
||||
# #=> {"foo"=>"bar", "baz"=>"buz"}
|
||||
# config['default'] = {"foo" => "changed"}
|
||||
# #=> {"foo"=>"changed"}
|
||||
# config['default']
|
||||
# #=> {"foo"=>"changed", "baz"=>"buz"}
|
||||
#
|
||||
def []=(section, pairs)
|
||||
check_modify
|
||||
@data[section] ||= {}
|
||||
pairs.each do |key, value|
|
||||
self.add_value(section, key, value)
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# Get the names of all sections in the current configuration
|
||||
def sections
|
||||
@data.keys
|
||||
end
|
||||
|
||||
##
|
||||
# Get the parsable form of the current configuration
|
||||
#
|
||||
# Given the following configuration being created:
|
||||
#
|
||||
# config = OpenSSL::Config.new
|
||||
# #=> #<OpenSSL::Config sections=[]>
|
||||
# config['default'] = {"foo"=>"bar","baz"=>"buz"}
|
||||
# #=> {"foo"=>"bar", "baz"=>"buz"}
|
||||
# puts config.to_s
|
||||
# #=> [ default ]
|
||||
# # foo=bar
|
||||
# # baz=buz
|
||||
#
|
||||
# You can parse get the serialized configuration using #to_s and then parse
|
||||
# it later:
|
||||
#
|
||||
# serialized_config = config.to_s
|
||||
# # much later...
|
||||
# new_config = OpenSSL::Config.parse(serialized_config)
|
||||
# #=> #<OpenSSL::Config sections=["default"]>
|
||||
# puts new_config
|
||||
# #=> [ default ]
|
||||
# foo=bar
|
||||
# baz=buz
|
||||
#
|
||||
def to_s
|
||||
ary = []
|
||||
@data.keys.sort.each do |section|
|
||||
ary << "[ #{section} ]\n"
|
||||
@data[section].keys.each do |key|
|
||||
ary << "#{key}=#{@data[section][key]}\n"
|
||||
end
|
||||
ary << "\n"
|
||||
end
|
||||
ary.join
|
||||
end
|
||||
|
||||
##
|
||||
# For a block.
|
||||
#
|
||||
# Receive the section and its pairs for the current configuration.
|
||||
#
|
||||
# config.each do |section, key, value|
|
||||
# # ...
|
||||
# end
|
||||
#
|
||||
def each
|
||||
@data.each do |section, hash|
|
||||
hash.each do |key, value|
|
||||
yield [section, key, value]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# String representation of this configuration object, including the class
|
||||
# name and its sections.
|
||||
def inspect
|
||||
"#<#{self.class.name} sections=#{sections.inspect}>"
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def data # :nodoc:
|
||||
@data
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def initialize_copy(other)
|
||||
@data = other.data.dup
|
||||
end
|
||||
|
||||
def check_modify
|
||||
raise TypeError.new("Insecure: can't modify OpenSSL config") if frozen?
|
||||
end
|
||||
|
||||
def get_key_string(section, key)
|
||||
Config.get_key_string(@data, section, key)
|
||||
end
|
||||
end
|
||||
end
|
||||
75
gxg/standard/openssl/digest.rb
Normal file
75
gxg/standard/openssl/digest.rb
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
# frozen_string_literal: false
|
||||
#--
|
||||
# = Ruby-space predefined Digest subclasses
|
||||
#
|
||||
# = Info
|
||||
# 'OpenSSL for Ruby 2' project
|
||||
# Copyright (C) 2002 Michal Rokos <m.rokos@sh.cvut.cz>
|
||||
# All rights reserved.
|
||||
#
|
||||
# = Licence
|
||||
# This program is licensed under the same licence as Ruby.
|
||||
# (See the file 'LICENCE'.)
|
||||
#++
|
||||
|
||||
module OpenSSL
|
||||
class Digest
|
||||
|
||||
alg = %w(MD2 MD4 MD5 MDC2 RIPEMD160 SHA1 SHA224 SHA256 SHA384 SHA512)
|
||||
if OPENSSL_VERSION_NUMBER < 0x10100000
|
||||
alg += %w(DSS DSS1 SHA)
|
||||
end
|
||||
|
||||
# Return the hash value computed with _name_ Digest. _name_ is either the
|
||||
# long name or short name of a supported digest algorithm.
|
||||
#
|
||||
# === Examples
|
||||
#
|
||||
# OpenSSL::Digest.digest("SHA256", "abc")
|
||||
#
|
||||
# which is equivalent to:
|
||||
#
|
||||
# OpenSSL::Digest::SHA256.digest("abc")
|
||||
|
||||
def self.digest(name, data)
|
||||
super(data, name)
|
||||
end
|
||||
|
||||
alg.each{|name|
|
||||
klass = Class.new(self) {
|
||||
define_method(:initialize, ->(data = nil) {super(name, data)})
|
||||
}
|
||||
singleton = (class << klass; self; end)
|
||||
singleton.class_eval{
|
||||
define_method(:digest){|data| new.digest(data) }
|
||||
define_method(:hexdigest){|data| new.hexdigest(data) }
|
||||
}
|
||||
const_set(name, klass)
|
||||
}
|
||||
|
||||
# Deprecated.
|
||||
#
|
||||
# This class is only provided for backwards compatibility.
|
||||
# Use OpenSSL::Digest instead.
|
||||
class Digest < Digest; end # :nodoc:
|
||||
deprecate_constant :Digest
|
||||
|
||||
end # Digest
|
||||
|
||||
# Returns a Digest subclass by _name_
|
||||
#
|
||||
# require 'openssl'
|
||||
#
|
||||
# OpenSSL::Digest("MD5")
|
||||
# # => OpenSSL::Digest::MD5
|
||||
#
|
||||
# Digest("Foo")
|
||||
# # => NameError: wrong constant name Foo
|
||||
|
||||
def Digest(name)
|
||||
OpenSSL::Digest.const_get(name)
|
||||
end
|
||||
|
||||
module_function :Digest
|
||||
|
||||
end # OpenSSL
|
||||
22
gxg/standard/openssl/pkcs5.rb
Normal file
22
gxg/standard/openssl/pkcs5.rb
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
# frozen_string_literal: false
|
||||
#--
|
||||
# Ruby/OpenSSL Project
|
||||
# Copyright (C) 2017 Ruby/OpenSSL Project Authors
|
||||
#++
|
||||
|
||||
module OpenSSL
|
||||
module PKCS5
|
||||
module_function
|
||||
|
||||
# OpenSSL::PKCS5.pbkdf2_hmac has been renamed to OpenSSL::KDF.pbkdf2_hmac.
|
||||
# This method is provided for backwards compatibility.
|
||||
def pbkdf2_hmac(pass, salt, iter, keylen, digest)
|
||||
OpenSSL::KDF.pbkdf2_hmac(pass, salt: salt, iterations: iter,
|
||||
length: keylen, hash: digest)
|
||||
end
|
||||
|
||||
def pbkdf2_hmac_sha1(pass, salt, iter, keylen)
|
||||
pbkdf2_hmac(pass, salt, iter, keylen, "sha1")
|
||||
end
|
||||
end
|
||||
end
|
||||
25
gxg/standard/openssl/pkey.rb
Normal file
25
gxg/standard/openssl/pkey.rb
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
# frozen_string_literal: false
|
||||
#--
|
||||
# Ruby/OpenSSL Project
|
||||
# Copyright (C) 2017 Ruby/OpenSSL Project Authors
|
||||
#++
|
||||
|
||||
module OpenSSL::PKey
|
||||
if defined?(EC)
|
||||
class EC::Point
|
||||
# :call-seq:
|
||||
# point.to_bn([conversion_form]) -> OpenSSL::BN
|
||||
#
|
||||
# Returns the octet string representation of the EC point as an instance of
|
||||
# OpenSSL::BN.
|
||||
#
|
||||
# If _conversion_form_ is not given, the _point_conversion_form_ attribute
|
||||
# set to the group is used.
|
||||
#
|
||||
# See #to_octet_string for more information.
|
||||
def to_bn(conversion_form = group.point_conversion_form)
|
||||
OpenSSL::BN.new(to_octet_string(conversion_form), 2)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
504
gxg/standard/openssl/ssl.rb
Normal file
504
gxg/standard/openssl/ssl.rb
Normal file
|
|
@ -0,0 +1,504 @@
|
|||
# frozen_string_literal: false
|
||||
=begin
|
||||
= Info
|
||||
'OpenSSL for Ruby 2' project
|
||||
Copyright (C) 2001 GOTOU YUUZOU <gotoyuzo@notwork.org>
|
||||
All rights reserved.
|
||||
|
||||
= Licence
|
||||
This program is licensed under the same licence as Ruby.
|
||||
(See the file 'LICENCE'.)
|
||||
=end
|
||||
|
||||
require "openssl/buffering"
|
||||
require "io/nonblock"
|
||||
require "ipaddr"
|
||||
|
||||
module OpenSSL
|
||||
module SSL
|
||||
class SSLContext
|
||||
DEFAULT_PARAMS = { # :nodoc:
|
||||
:min_version => OpenSSL::SSL::TLS1_VERSION,
|
||||
:verify_mode => OpenSSL::SSL::VERIFY_PEER,
|
||||
:verify_hostname => true,
|
||||
:options => -> {
|
||||
opts = OpenSSL::SSL::OP_ALL
|
||||
opts &= ~OpenSSL::SSL::OP_DONT_INSERT_EMPTY_FRAGMENTS
|
||||
opts |= OpenSSL::SSL::OP_NO_COMPRESSION
|
||||
opts
|
||||
}.call
|
||||
}
|
||||
|
||||
if defined?(OpenSSL::PKey::DH)
|
||||
DEFAULT_2048 = OpenSSL::PKey::DH.new <<-_end_of_pem_
|
||||
-----BEGIN DH PARAMETERS-----
|
||||
MIIBCAKCAQEA7E6kBrYiyvmKAMzQ7i8WvwVk9Y/+f8S7sCTN712KkK3cqd1jhJDY
|
||||
JbrYeNV3kUIKhPxWHhObHKpD1R84UpL+s2b55+iMd6GmL7OYmNIT/FccKhTcveab
|
||||
VBmZT86BZKYyf45hUF9FOuUM9xPzuK3Vd8oJQvfYMCd7LPC0taAEljQLR4Edf8E6
|
||||
YoaOffgTf5qxiwkjnlVZQc3whgnEt9FpVMvQ9eknyeGB5KHfayAc3+hUAvI3/Cr3
|
||||
1bNveX5wInh5GDx1FGhKBZ+s1H+aedudCm7sCgRwv8lKWYGiHzObSma8A86KG+MD
|
||||
7Lo5JquQ3DlBodj3IDyPrxIv96lvRPFtAwIBAg==
|
||||
-----END DH PARAMETERS-----
|
||||
_end_of_pem_
|
||||
private_constant :DEFAULT_2048
|
||||
|
||||
DEFAULT_TMP_DH_CALLBACK = lambda { |ctx, is_export, keylen| # :nodoc:
|
||||
warn "using default DH parameters." if $VERBOSE
|
||||
DEFAULT_2048
|
||||
}
|
||||
end
|
||||
|
||||
if !(OpenSSL::OPENSSL_VERSION.start_with?("OpenSSL") &&
|
||||
OpenSSL::OPENSSL_VERSION_NUMBER >= 0x10100000)
|
||||
DEFAULT_PARAMS.merge!(
|
||||
ciphers: %w{
|
||||
ECDHE-ECDSA-AES128-GCM-SHA256
|
||||
ECDHE-RSA-AES128-GCM-SHA256
|
||||
ECDHE-ECDSA-AES256-GCM-SHA384
|
||||
ECDHE-RSA-AES256-GCM-SHA384
|
||||
DHE-RSA-AES128-GCM-SHA256
|
||||
DHE-DSS-AES128-GCM-SHA256
|
||||
DHE-RSA-AES256-GCM-SHA384
|
||||
DHE-DSS-AES256-GCM-SHA384
|
||||
ECDHE-ECDSA-AES128-SHA256
|
||||
ECDHE-RSA-AES128-SHA256
|
||||
ECDHE-ECDSA-AES128-SHA
|
||||
ECDHE-RSA-AES128-SHA
|
||||
ECDHE-ECDSA-AES256-SHA384
|
||||
ECDHE-RSA-AES256-SHA384
|
||||
ECDHE-ECDSA-AES256-SHA
|
||||
ECDHE-RSA-AES256-SHA
|
||||
DHE-RSA-AES128-SHA256
|
||||
DHE-RSA-AES256-SHA256
|
||||
DHE-RSA-AES128-SHA
|
||||
DHE-RSA-AES256-SHA
|
||||
DHE-DSS-AES128-SHA256
|
||||
DHE-DSS-AES256-SHA256
|
||||
DHE-DSS-AES128-SHA
|
||||
DHE-DSS-AES256-SHA
|
||||
AES128-GCM-SHA256
|
||||
AES256-GCM-SHA384
|
||||
AES128-SHA256
|
||||
AES256-SHA256
|
||||
AES128-SHA
|
||||
AES256-SHA
|
||||
}.join(":"),
|
||||
)
|
||||
end
|
||||
|
||||
DEFAULT_CERT_STORE = OpenSSL::X509::Store.new # :nodoc:
|
||||
DEFAULT_CERT_STORE.set_default_paths
|
||||
DEFAULT_CERT_STORE.flags = OpenSSL::X509::V_FLAG_CRL_CHECK_ALL
|
||||
|
||||
# A callback invoked when DH parameters are required.
|
||||
#
|
||||
# The callback is invoked with the Session for the key exchange, an
|
||||
# flag indicating the use of an export cipher and the keylength
|
||||
# required.
|
||||
#
|
||||
# The callback must return an OpenSSL::PKey::DH instance of the correct
|
||||
# key length.
|
||||
|
||||
attr_accessor :tmp_dh_callback
|
||||
|
||||
# A callback invoked at connect time to distinguish between multiple
|
||||
# server names.
|
||||
#
|
||||
# The callback is invoked with an SSLSocket and a server name. The
|
||||
# callback must return an SSLContext for the server name or nil.
|
||||
attr_accessor :servername_cb
|
||||
|
||||
# call-seq:
|
||||
# SSLContext.new -> ctx
|
||||
# SSLContext.new(:TLSv1) -> ctx
|
||||
# SSLContext.new("SSLv23") -> ctx
|
||||
#
|
||||
# Creates a new SSL context.
|
||||
#
|
||||
# If an argument is given, #ssl_version= is called with the value. Note
|
||||
# that this form is deprecated. New applications should use #min_version=
|
||||
# and #max_version= as necessary.
|
||||
def initialize(version = nil)
|
||||
self.options |= OpenSSL::SSL::OP_ALL
|
||||
self.ssl_version = version if version
|
||||
end
|
||||
|
||||
##
|
||||
# call-seq:
|
||||
# ctx.set_params(params = {}) -> params
|
||||
#
|
||||
# Sets saner defaults optimized for the use with HTTP-like protocols.
|
||||
#
|
||||
# If a Hash _params_ is given, the parameters are overridden with it.
|
||||
# The keys in _params_ must be assignment methods on SSLContext.
|
||||
#
|
||||
# If the verify_mode is not VERIFY_NONE and ca_file, ca_path and
|
||||
# cert_store are not set then the system default certificate store is
|
||||
# used.
|
||||
def set_params(params={})
|
||||
params = DEFAULT_PARAMS.merge(params)
|
||||
self.options = params.delete(:options) # set before min_version/max_version
|
||||
params.each{|name, value| self.__send__("#{name}=", value) }
|
||||
if self.verify_mode != OpenSSL::SSL::VERIFY_NONE
|
||||
unless self.ca_file or self.ca_path or self.cert_store
|
||||
self.cert_store = DEFAULT_CERT_STORE
|
||||
end
|
||||
end
|
||||
return params
|
||||
end
|
||||
|
||||
# call-seq:
|
||||
# ctx.min_version = OpenSSL::SSL::TLS1_2_VERSION
|
||||
# ctx.min_version = :TLS1_2
|
||||
# ctx.min_version = nil
|
||||
#
|
||||
# Sets the lower bound on the supported SSL/TLS protocol version. The
|
||||
# version may be specified by an integer constant named
|
||||
# OpenSSL::SSL::*_VERSION, a Symbol, or +nil+ which means "any version".
|
||||
#
|
||||
# Be careful that you don't overwrite OpenSSL::SSL::OP_NO_{SSL,TLS}v*
|
||||
# options by #options= once you have called #min_version= or
|
||||
# #max_version=.
|
||||
#
|
||||
# === Example
|
||||
# ctx = OpenSSL::SSL::SSLContext.new
|
||||
# ctx.min_version = OpenSSL::SSL::TLS1_1_VERSION
|
||||
# ctx.max_version = OpenSSL::SSL::TLS1_2_VERSION
|
||||
#
|
||||
# sock = OpenSSL::SSL::SSLSocket.new(tcp_sock, ctx)
|
||||
# sock.connect # Initiates a connection using either TLS 1.1 or TLS 1.2
|
||||
def min_version=(version)
|
||||
set_minmax_proto_version(version, @max_proto_version ||= nil)
|
||||
@min_proto_version = version
|
||||
end
|
||||
|
||||
# call-seq:
|
||||
# ctx.max_version = OpenSSL::SSL::TLS1_2_VERSION
|
||||
# ctx.max_version = :TLS1_2
|
||||
# ctx.max_version = nil
|
||||
#
|
||||
# Sets the upper bound of the supported SSL/TLS protocol version. See
|
||||
# #min_version= for the possible values.
|
||||
def max_version=(version)
|
||||
set_minmax_proto_version(@min_proto_version ||= nil, version)
|
||||
@max_proto_version = version
|
||||
end
|
||||
|
||||
# call-seq:
|
||||
# ctx.ssl_version = :TLSv1
|
||||
# ctx.ssl_version = "SSLv23"
|
||||
#
|
||||
# Sets the SSL/TLS protocol version for the context. This forces
|
||||
# connections to use only the specified protocol version. This is
|
||||
# deprecated and only provided for backwards compatibility. Use
|
||||
# #min_version= and #max_version= instead.
|
||||
#
|
||||
# === History
|
||||
# As the name hints, this used to call the SSL_CTX_set_ssl_version()
|
||||
# function which sets the SSL method used for connections created from
|
||||
# the context. As of Ruby/OpenSSL 2.1, this accessor method is
|
||||
# implemented to call #min_version= and #max_version= instead.
|
||||
def ssl_version=(meth)
|
||||
meth = meth.to_s if meth.is_a?(Symbol)
|
||||
if /(?<type>_client|_server)\z/ =~ meth
|
||||
meth = $`
|
||||
if $VERBOSE
|
||||
warn "#{caller(1, 1)[0]}: method type #{type.inspect} is ignored"
|
||||
end
|
||||
end
|
||||
version = METHODS_MAP[meth.intern] or
|
||||
raise ArgumentError, "unknown SSL method `%s'" % meth
|
||||
set_minmax_proto_version(version, version)
|
||||
@min_proto_version = @max_proto_version = version
|
||||
end
|
||||
|
||||
METHODS_MAP = {
|
||||
SSLv23: 0,
|
||||
SSLv2: OpenSSL::SSL::SSL2_VERSION,
|
||||
SSLv3: OpenSSL::SSL::SSL3_VERSION,
|
||||
TLSv1: OpenSSL::SSL::TLS1_VERSION,
|
||||
TLSv1_1: OpenSSL::SSL::TLS1_1_VERSION,
|
||||
TLSv1_2: OpenSSL::SSL::TLS1_2_VERSION,
|
||||
}.freeze
|
||||
private_constant :METHODS_MAP
|
||||
|
||||
# The list of available SSL/TLS methods. This constant is only provided
|
||||
# for backwards compatibility.
|
||||
METHODS = METHODS_MAP.flat_map { |name,|
|
||||
[name, :"#{name}_client", :"#{name}_server"]
|
||||
}.freeze
|
||||
deprecate_constant :METHODS
|
||||
end
|
||||
|
||||
module SocketForwarder
|
||||
def addr
|
||||
to_io.addr
|
||||
end
|
||||
|
||||
def peeraddr
|
||||
to_io.peeraddr
|
||||
end
|
||||
|
||||
def setsockopt(level, optname, optval)
|
||||
to_io.setsockopt(level, optname, optval)
|
||||
end
|
||||
|
||||
def getsockopt(level, optname)
|
||||
to_io.getsockopt(level, optname)
|
||||
end
|
||||
|
||||
def fcntl(*args)
|
||||
to_io.fcntl(*args)
|
||||
end
|
||||
|
||||
def closed?
|
||||
to_io.closed?
|
||||
end
|
||||
|
||||
def do_not_reverse_lookup=(flag)
|
||||
to_io.do_not_reverse_lookup = flag
|
||||
end
|
||||
end
|
||||
|
||||
def verify_certificate_identity(cert, hostname)
|
||||
should_verify_common_name = true
|
||||
cert.extensions.each{|ext|
|
||||
next if ext.oid != "subjectAltName"
|
||||
ostr = OpenSSL::ASN1.decode(ext.to_der).value.last
|
||||
sequence = OpenSSL::ASN1.decode(ostr.value)
|
||||
sequence.value.each{|san|
|
||||
case san.tag
|
||||
when 2 # dNSName in GeneralName (RFC5280)
|
||||
should_verify_common_name = false
|
||||
return true if verify_hostname(hostname, san.value)
|
||||
when 7 # iPAddress in GeneralName (RFC5280)
|
||||
should_verify_common_name = false
|
||||
if san.value.size == 4 || san.value.size == 16
|
||||
begin
|
||||
return true if san.value == IPAddr.new(hostname).hton
|
||||
rescue IPAddr::InvalidAddressError
|
||||
end
|
||||
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
|
||||
module_function :verify_certificate_identity
|
||||
|
||||
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
|
||||
module_function :verify_hostname
|
||||
|
||||
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
|
||||
module_function :verify_wildcard
|
||||
|
||||
class SSLSocket
|
||||
include Buffering
|
||||
include SocketForwarder
|
||||
|
||||
attr_reader :hostname
|
||||
|
||||
# The underlying IO object.
|
||||
attr_reader :io
|
||||
alias :to_io :io
|
||||
|
||||
# The SSLContext object used in this connection.
|
||||
attr_reader :context
|
||||
|
||||
# Whether to close the underlying socket as well, when the SSL/TLS
|
||||
# connection is shut down. This defaults to +false+.
|
||||
attr_accessor :sync_close
|
||||
|
||||
# call-seq:
|
||||
# ssl.sysclose => nil
|
||||
#
|
||||
# Sends "close notify" to the peer and tries to shut down the SSL
|
||||
# connection gracefully.
|
||||
#
|
||||
# If sync_close is set to +true+, the underlying IO is also closed.
|
||||
def sysclose
|
||||
return if closed?
|
||||
stop
|
||||
io.close if sync_close
|
||||
end
|
||||
|
||||
# call-seq:
|
||||
# ssl.post_connection_check(hostname) -> true
|
||||
#
|
||||
# Perform hostname verification following RFC 6125.
|
||||
#
|
||||
# This method MUST be called after calling #connect to ensure that the
|
||||
# hostname of a remote peer has been verified.
|
||||
def post_connection_check(hostname)
|
||||
if peer_cert.nil?
|
||||
msg = "Peer verification enabled, but no certificate received."
|
||||
if using_anon_cipher?
|
||||
msg += " Anonymous cipher suite #{cipher[0]} was negotiated. " \
|
||||
"Anonymous suites must be disabled to use peer verification."
|
||||
end
|
||||
raise SSLError, msg
|
||||
end
|
||||
|
||||
unless OpenSSL::SSL.verify_certificate_identity(peer_cert, hostname)
|
||||
raise SSLError, "hostname \"#{hostname}\" does not match the server certificate"
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
# call-seq:
|
||||
# ssl.session -> aSession
|
||||
#
|
||||
# Returns the SSLSession object currently used, or nil if the session is
|
||||
# not established.
|
||||
def session
|
||||
SSL::Session.new(self)
|
||||
rescue SSL::Session::SessionError
|
||||
nil
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def using_anon_cipher?
|
||||
ctx = OpenSSL::SSL::SSLContext.new
|
||||
ctx.ciphers = "aNULL"
|
||||
ctx.ciphers.include?(cipher)
|
||||
end
|
||||
|
||||
def client_cert_cb
|
||||
@context.client_cert_cb
|
||||
end
|
||||
|
||||
def tmp_dh_callback
|
||||
@context.tmp_dh_callback || OpenSSL::SSL::SSLContext::DEFAULT_TMP_DH_CALLBACK
|
||||
end
|
||||
|
||||
def tmp_ecdh_callback
|
||||
@context.tmp_ecdh_callback
|
||||
end
|
||||
|
||||
def session_new_cb
|
||||
@context.session_new_cb
|
||||
end
|
||||
|
||||
def session_get_cb
|
||||
@context.session_get_cb
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# SSLServer represents a TCP/IP server socket with Secure Sockets Layer.
|
||||
class SSLServer
|
||||
include SocketForwarder
|
||||
# When true then #accept works exactly the same as TCPServer#accept
|
||||
attr_accessor :start_immediately
|
||||
|
||||
# Creates a new instance of SSLServer.
|
||||
# * _srv_ is an instance of TCPServer.
|
||||
# * _ctx_ is an instance of OpenSSL::SSL::SSLContext.
|
||||
def initialize(svr, ctx)
|
||||
@svr = svr
|
||||
@ctx = ctx
|
||||
unless ctx.session_id_context
|
||||
# see #6137 - session id may not exceed 32 bytes
|
||||
prng = ::Random.new($0.hash)
|
||||
session_id = prng.bytes(16).unpack('H*')[0]
|
||||
@ctx.session_id_context = session_id
|
||||
end
|
||||
@start_immediately = true
|
||||
end
|
||||
|
||||
# Returns the TCPServer passed to the SSLServer when initialized.
|
||||
def to_io
|
||||
@svr
|
||||
end
|
||||
|
||||
# See TCPServer#listen for details.
|
||||
def listen(backlog=5)
|
||||
@svr.listen(backlog)
|
||||
end
|
||||
|
||||
# See BasicSocket#shutdown for details.
|
||||
def shutdown(how=Socket::SHUT_RDWR)
|
||||
@svr.shutdown(how)
|
||||
end
|
||||
|
||||
# Works similar to TCPServer#accept.
|
||||
def accept
|
||||
# Socket#accept returns [socket, addrinfo].
|
||||
# TCPServer#accept returns a socket.
|
||||
# The following comma strips addrinfo.
|
||||
sock, = @svr.accept
|
||||
begin
|
||||
ssl = OpenSSL::SSL::SSLSocket.new(sock, @ctx)
|
||||
ssl.sync_close = true
|
||||
ssl.accept if @start_immediately
|
||||
ssl
|
||||
rescue Exception => ex
|
||||
if ssl
|
||||
ssl.close
|
||||
else
|
||||
sock.close
|
||||
end
|
||||
raise ex
|
||||
end
|
||||
end
|
||||
|
||||
# See IO#close for details.
|
||||
def close
|
||||
@svr.close
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
215
gxg/standard/openssl/x509.rb
Normal file
215
gxg/standard/openssl/x509.rb
Normal file
|
|
@ -0,0 +1,215 @@
|
|||
# frozen_string_literal: false
|
||||
#--
|
||||
# = Ruby-space definitions that completes C-space funcs for X509 and subclasses
|
||||
#
|
||||
# = Info
|
||||
# 'OpenSSL for Ruby 2' project
|
||||
# Copyright (C) 2002 Michal Rokos <m.rokos@sh.cvut.cz>
|
||||
# All rights reserved.
|
||||
#
|
||||
# = Licence
|
||||
# This program is licensed under the same licence as Ruby.
|
||||
# (See the file 'LICENCE'.)
|
||||
#++
|
||||
|
||||
module OpenSSL
|
||||
module X509
|
||||
class ExtensionFactory
|
||||
def create_extension(*arg)
|
||||
if arg.size > 1
|
||||
create_ext(*arg)
|
||||
else
|
||||
send("create_ext_from_"+arg[0].class.name.downcase, arg[0])
|
||||
end
|
||||
end
|
||||
|
||||
def create_ext_from_array(ary)
|
||||
raise ExtensionError, "unexpected array form" if ary.size > 3
|
||||
create_ext(ary[0], ary[1], ary[2])
|
||||
end
|
||||
|
||||
def create_ext_from_string(str) # "oid = critical, value"
|
||||
oid, value = str.split(/=/, 2)
|
||||
oid.strip!
|
||||
value.strip!
|
||||
create_ext(oid, value)
|
||||
end
|
||||
|
||||
def create_ext_from_hash(hash)
|
||||
create_ext(hash["oid"], hash["value"], hash["critical"])
|
||||
end
|
||||
end
|
||||
|
||||
class Extension
|
||||
def ==(other)
|
||||
return false unless Extension === other
|
||||
to_der == other.to_der
|
||||
end
|
||||
|
||||
def to_s # "oid = critical, value"
|
||||
str = self.oid
|
||||
str << " = "
|
||||
str << "critical, " if self.critical?
|
||||
str << self.value.gsub(/\n/, ", ")
|
||||
end
|
||||
|
||||
def to_h # {"oid"=>sn|ln, "value"=>value, "critical"=>true|false}
|
||||
{"oid"=>self.oid,"value"=>self.value,"critical"=>self.critical?}
|
||||
end
|
||||
|
||||
def to_a
|
||||
[ self.oid, self.value, self.critical? ]
|
||||
end
|
||||
end
|
||||
|
||||
class Name
|
||||
module RFC2253DN
|
||||
Special = ',=+<>#;'
|
||||
HexChar = /[0-9a-fA-F]/
|
||||
HexPair = /#{HexChar}#{HexChar}/
|
||||
HexString = /#{HexPair}+/
|
||||
Pair = /\\(?:[#{Special}]|\\|"|#{HexPair})/
|
||||
StringChar = /[^\\"#{Special}]/
|
||||
QuoteChar = /[^\\"]/
|
||||
AttributeType = /[a-zA-Z][0-9a-zA-Z]*|[0-9]+(?:\.[0-9]+)*/
|
||||
AttributeValue = /
|
||||
(?!["#])((?:#{StringChar}|#{Pair})*)|
|
||||
\#(#{HexString})|
|
||||
"((?:#{QuoteChar}|#{Pair})*)"
|
||||
/x
|
||||
TypeAndValue = /\A(#{AttributeType})=#{AttributeValue}/
|
||||
|
||||
module_function
|
||||
|
||||
def expand_pair(str)
|
||||
return nil unless str
|
||||
return str.gsub(Pair){
|
||||
pair = $&
|
||||
case pair.size
|
||||
when 2 then pair[1,1]
|
||||
when 3 then Integer("0x#{pair[1,2]}").chr
|
||||
else raise OpenSSL::X509::NameError, "invalid pair: #{str}"
|
||||
end
|
||||
}
|
||||
end
|
||||
|
||||
def expand_hexstring(str)
|
||||
return nil unless str
|
||||
der = str.gsub(HexPair){$&.to_i(16).chr }
|
||||
a1 = OpenSSL::ASN1.decode(der)
|
||||
return a1.value, a1.tag
|
||||
end
|
||||
|
||||
def expand_value(str1, str2, str3)
|
||||
value = expand_pair(str1)
|
||||
value, tag = expand_hexstring(str2) unless value
|
||||
value = expand_pair(str3) unless value
|
||||
return value, tag
|
||||
end
|
||||
|
||||
def scan(dn)
|
||||
str = dn
|
||||
ary = []
|
||||
while true
|
||||
if md = TypeAndValue.match(str)
|
||||
remain = md.post_match
|
||||
type = md[1]
|
||||
value, tag = expand_value(md[2], md[3], md[4]) rescue nil
|
||||
if value
|
||||
type_and_value = [type, value]
|
||||
type_and_value.push(tag) if tag
|
||||
ary.unshift(type_and_value)
|
||||
if remain.length > 2 && remain[0] == ?,
|
||||
str = remain[1..-1]
|
||||
next
|
||||
elsif remain.length > 2 && remain[0] == ?+
|
||||
raise OpenSSL::X509::NameError,
|
||||
"multi-valued RDN is not supported: #{dn}"
|
||||
elsif remain.empty?
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
msg_dn = dn[0, dn.length - str.length] + " =>" + str
|
||||
raise OpenSSL::X509::NameError, "malformed RDN: #{msg_dn}"
|
||||
end
|
||||
return ary
|
||||
end
|
||||
end
|
||||
|
||||
class << self
|
||||
def parse_rfc2253(str, template=OBJECT_TYPE_TEMPLATE)
|
||||
ary = OpenSSL::X509::Name::RFC2253DN.scan(str)
|
||||
self.new(ary, template)
|
||||
end
|
||||
|
||||
def parse_openssl(str, template=OBJECT_TYPE_TEMPLATE)
|
||||
if str.start_with?("/")
|
||||
# /A=B/C=D format
|
||||
ary = str[1..-1].split("/").map { |i| i.split("=", 2) }
|
||||
else
|
||||
# Comma-separated
|
||||
ary = str.split(",").map { |i| i.strip.split("=", 2) }
|
||||
end
|
||||
self.new(ary, template)
|
||||
end
|
||||
|
||||
alias parse parse_openssl
|
||||
end
|
||||
|
||||
def pretty_print(q)
|
||||
q.object_group(self) {
|
||||
q.text ' '
|
||||
q.text to_s(OpenSSL::X509::Name::RFC2253)
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
class Attribute
|
||||
def ==(other)
|
||||
return false unless Attribute === other
|
||||
to_der == other.to_der
|
||||
end
|
||||
end
|
||||
|
||||
class StoreContext
|
||||
def cleanup
|
||||
warn "(#{caller.first}) OpenSSL::X509::StoreContext#cleanup is deprecated with no replacement" if $VERBOSE
|
||||
end
|
||||
end
|
||||
|
||||
class Certificate
|
||||
def pretty_print(q)
|
||||
q.object_group(self) {
|
||||
q.breakable
|
||||
q.text 'subject='; q.pp self.subject; q.text ','; q.breakable
|
||||
q.text 'issuer='; q.pp self.issuer; q.text ','; q.breakable
|
||||
q.text 'serial='; q.pp self.serial; q.text ','; q.breakable
|
||||
q.text 'not_before='; q.pp self.not_before; q.text ','; q.breakable
|
||||
q.text 'not_after='; q.pp self.not_after
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
class CRL
|
||||
def ==(other)
|
||||
return false unless CRL === other
|
||||
to_der == other.to_der
|
||||
end
|
||||
end
|
||||
|
||||
class Revoked
|
||||
def ==(other)
|
||||
return false unless Revoked === other
|
||||
to_der == other.to_der
|
||||
end
|
||||
end
|
||||
|
||||
class Request
|
||||
def ==(other)
|
||||
return false unless Request === other
|
||||
to_der == other.to_der
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
Loading…
Reference in a new issue