fluent-plugin-secure-forward-addproxy 0.3.3dev2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,24 @@
1
+ <source>
2
+ type forward
3
+ </source>
4
+
5
+ <match test.**>
6
+ type secure_forward
7
+ secure yes
8
+ self_hostname client
9
+ shared_key hogeposxxx0
10
+ keepalive 30
11
+ ca_cert_path /Users/tagomoris/github/fluent-plugin-secure-forward/test/tmp/cadir/ca_cert.pem
12
+ enable_strict_verification yes
13
+ <server>
14
+ host localhost
15
+ </server>
16
+ # <server>
17
+ # host localhost
18
+ # standby yes
19
+ # </server>
20
+ # <server>
21
+ # host localhost
22
+ # </server>
23
+ flush_interval 1s
24
+ </match>
@@ -0,0 +1,26 @@
1
+ <source>
2
+ type forward
3
+ </source>
4
+
5
+ <match test.**>
6
+ type secure_forward
7
+ secure yes
8
+ self_hostname client
9
+ shared_key hogeposxxx0
10
+ keepalive 30
11
+ ca_cert_path /Users/tagomoris/github/fluent-plugin-secure-forward/test/tmp/cadir/ca_cert.pem
12
+ enable_strict_verification yes
13
+ <server>
14
+ proxy_uri http://foo.foo.local:3128
15
+ host localhost
16
+ </server>
17
+ # <server>
18
+ # proxy_uri http://bar.bar.local:3128
19
+ # host localhost
20
+ # standby yes
21
+ # </server>
22
+ # <server>
23
+ # host localhost
24
+ # </server>
25
+ flush_interval 1s
26
+ </match>
@@ -0,0 +1,23 @@
1
+ <source>
2
+ type forward
3
+ </source>
4
+
5
+ <match test.**>
6
+ type secure_forward
7
+ secure no
8
+ self_hostname client
9
+ shared_key hogeposxxx0
10
+ keepalive 30
11
+ enable_strict_verification yes
12
+ <server>
13
+ host localhost
14
+ </server>
15
+ # <server>
16
+ # host localhost
17
+ # standby yes
18
+ # </server>
19
+ # <server>
20
+ # host localhost
21
+ # </server>
22
+ flush_interval 1s
23
+ </match>
@@ -0,0 +1,10 @@
1
+ <source>
2
+ type secure_forward
3
+ secure no
4
+ self_hostname localhost
5
+ shared_key hogeposxxx0
6
+ </source>
7
+
8
+ <match test.**>
9
+ type stdout
10
+ </match>
@@ -0,0 +1,13 @@
1
+ <source>
2
+ type secure_forward
3
+ secure yes
4
+ self_hostname localhost
5
+ shared_key hogeposxxx0
6
+ ca_cert_path /Users/tagomoris/github/fluent-plugin-secure-forward/test/tmp/cadir/ca_cert.pem
7
+ ca_private_key_path /Users/tagomoris/github/fluent-plugin-secure-forward/test/tmp/cadir/ca_key.pem
8
+ ca_private_key_passphrase testing secret phrase
9
+ </source>
10
+
11
+ <match test.**>
12
+ type stdout
13
+ </match>
@@ -0,0 +1,23 @@
1
+ # -*- encoding: utf-8 -*-
2
+ Gem::Specification.new do |gem|
3
+ gem.name = "fluent-plugin-secure-forward-addproxy"
4
+ gem.version = "0.3.3dev2"
5
+ gem.authors = ["TAGOMORI Satoshi"]
6
+ gem.email = ["tagomoris@gmail.com"]
7
+ gem.summary = %q{Fluentd input/output plugin to forward over SSL with authentications + proxy}
8
+ gem.description = %q{fork from fluent-plugin-secure-forward 0.3.3dev2 }
9
+ gem.homepage = "https://github.com/tagomoris/fluent-plugin-secure-forward"
10
+ gem.license = "APLv2"
11
+
12
+ gem.files = `git ls-files`.split($\)
13
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
14
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
15
+ gem.require_paths = ["lib"]
16
+
17
+ gem.add_runtime_dependency "fluentd", ">= 0.10.46"
18
+ gem.add_runtime_dependency "fluent-mixin-config-placeholders", ">= 0.3.0"
19
+ gem.add_runtime_dependency "resolve-hostname"
20
+ gem.add_runtime_dependency "proxifier"
21
+ gem.add_development_dependency "test-unit"
22
+ gem.add_development_dependency "rake"
23
+ end
@@ -0,0 +1,278 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ require 'fluent/mixin/config_placeholders'
4
+
5
+ module Fluent
6
+ class SecureForwardInput < Input
7
+ end
8
+ end
9
+
10
+ require_relative 'input_session'
11
+ require_relative './secure_forward/cert_util'
12
+
13
+ module Fluent
14
+ class SecureForwardInput < Input
15
+ DEFAULT_SECURE_LISTEN_PORT = 24284
16
+
17
+ Fluent::Plugin.register_input('secure_forward', self)
18
+
19
+ config_param :secure, :bool # if secure, cert_path or ca_cert_path required
20
+
21
+ config_param :self_hostname, :string
22
+ include Fluent::Mixin::ConfigPlaceholders
23
+
24
+ config_param :shared_key, :string
25
+
26
+ config_param :bind, :string, default: '0.0.0.0'
27
+ config_param :port, :integer, default: DEFAULT_SECURE_LISTEN_PORT
28
+ config_param :allow_keepalive, :bool, default: true #TODO: implement
29
+
30
+ config_param :allow_anonymous_source, :bool, default: true
31
+ config_param :authentication, :bool, default: false
32
+
33
+ config_param :ssl_version, :string, default: 'TLSv1_2'
34
+ config_param :ssl_ciphers, :string, default: nil
35
+
36
+ # Cert signed by public CA
37
+ config_param :cert_path, :string, default: nil
38
+ config_param :private_key_path, :string, default: nil
39
+ config_param :private_key_passphrase, :string, default: nil
40
+
41
+ # Cert automatically generated and signed by private CA
42
+ config_param :ca_cert_path, :string, default: nil
43
+ config_param :ca_private_key_path, :string, default: nil
44
+ config_param :ca_private_key_passphrase, :string, default: nil
45
+
46
+ # Otherwise: Cert automatically generated and signed by itself (for without any verification)
47
+
48
+ config_param :generate_private_key_length, :integer, default: 2048
49
+ config_param :generate_cert_country, :string, default: 'US'
50
+ config_param :generate_cert_state, :string, default: 'CA'
51
+ config_param :generate_cert_locality, :string, default: 'Mountain View'
52
+ config_param :generate_cert_common_name, :string, default: nil
53
+
54
+ config_param :read_length, :size, default: 8*1024*1024 # 8MB
55
+ config_param :read_interval_msec, :integer, default: 50 # 50ms
56
+ config_param :socket_interval_msec, :integer, default: 200 # 200ms
57
+
58
+ attr_reader :read_interval, :socket_interval
59
+
60
+ config_section :user, param_name: :users do
61
+ config_param :username, :string
62
+ config_param :password, :string
63
+ end
64
+
65
+ config_section :client, param_name: :clients do
66
+ config_param :host, :string, default: nil
67
+ config_param :network, :string, default: nil
68
+ config_param :shared_key, :string, default: nil
69
+ config_param :users, :string, default: nil # comma separated username list
70
+ end
71
+ attr_reader :nodes
72
+
73
+ attr_reader :sessions # node/socket/thread list which has sslsocket instance keepaliving to client
74
+
75
+ def initialize
76
+ super
77
+ require 'ipaddr'
78
+ require 'socket'
79
+ require 'openssl'
80
+ require 'digest'
81
+ require 'securerandom'
82
+ end
83
+
84
+ # Define `log` method for v0.10.42 or earlier
85
+ unless method_defined?(:log)
86
+ define_method("log") { $log }
87
+ end
88
+
89
+ def configure(conf)
90
+ super
91
+
92
+ if @secure
93
+ unless @cert_path || @ca_cert_path
94
+ raise Fluent::ConfigError, "cert_path or ca_cert_path required for secure communication"
95
+ end
96
+ if @cert_path
97
+ raise Fluent::ConfigError, "private_key_path required" unless @private_key_path
98
+ raise Fluent::ConfigError, "private_key_passphrase required" unless @private_key_passphrase
99
+ else # @ca_cert_path
100
+ raise Fluent::ConfigError, "ca_private_key_path required" unless @ca_private_key_path
101
+ raise Fluent::ConfigError, "ca_private_key_passphrase required" unless @ca_private_key_passphrase
102
+ end
103
+ else
104
+ log.warn "'insecure' mode has vulnerability for man-in-the-middle attacks for clients (output plugins)."
105
+ end
106
+
107
+ @read_interval = @read_interval_msec / 1000.0
108
+ @socket_interval = @socket_interval_msec / 1000.0
109
+
110
+ @nodes = []
111
+
112
+ @clients.each do |client|
113
+ if client.host && client.network
114
+ raise Fluent::ConfigError, "both of 'host' and 'network' are specified for client"
115
+ end
116
+ if !client.host && !client.network
117
+ raise Fluent::ConfigError, "Either of 'host' and 'network' must be specified for client"
118
+ end
119
+ source = nil
120
+ if client.host
121
+ begin
122
+ source = IPSocket.getaddress(client.host)
123
+ rescue SocketError => e
124
+ raise Fluent::ConfigError, "host '#{client.host}' cannot be resolved"
125
+ end
126
+ end
127
+ source_addr = begin
128
+ IPAddr.new(source || client.network)
129
+ rescue ArgumentError => e
130
+ raise Fluent::ConfigError, "network '#{client.network}' address format is invalid"
131
+ end
132
+ @nodes.push({
133
+ address: source_addr,
134
+ shared_key: (client.shared_key || @shared_key),
135
+ users: (client.users ? client.users.split(',') : nil)
136
+ })
137
+ end
138
+
139
+ @generate_cert_common_name ||= @self_hostname
140
+
141
+ # To check whether certificates are successfully generated/loaded at startup time
142
+ self.certificate
143
+
144
+ true
145
+ end
146
+
147
+ def start
148
+ super
149
+ OpenSSL::Random.seed(SecureRandom.random_bytes(16))
150
+ @sessions = []
151
+ @sock = nil
152
+ @listener = Thread.new(&method(:run))
153
+ @listener.abort_on_exception
154
+ end
155
+
156
+ def shutdown
157
+ @listener.kill
158
+ @listener.join
159
+ @sessions.each{ |s| s.shutdown }
160
+ @sock.close
161
+ end
162
+
163
+ def select_authenticate_users(node, username)
164
+ if node.nil? || node[:users].nil?
165
+ @users.select{|u| u.username == username}
166
+ else
167
+ @users.select{|u| node[:users].include?(u.username) && u.username == username}
168
+ end
169
+ end
170
+
171
+ def certificate
172
+ return @cert, @key if @cert && @key
173
+
174
+ if @cert_path
175
+ @key = OpenSSL::PKey::RSA.new(File.read(@private_key_path), @private_key_passphrase)
176
+ @cert = OpenSSL::X509::Certificate.new(File.read(@cert_path))
177
+ elsif @ca_cert_path
178
+ opts = {
179
+ ca_cert_path: @ca_cert_path,
180
+ ca_key_path: @ca_private_key_path,
181
+ ca_key_passphrase: @ca_private_key_passphrase,
182
+ private_key_length: @generate_private_key_length,
183
+ country: @generate_cert_country,
184
+ state: @generate_cert_state,
185
+ locality: @generate_cert_locality,
186
+ common_name: @generate_cert_common_name,
187
+ }
188
+ @cert, @key = Fluent::SecureForward::CertUtil.generate_server_pair(opts)
189
+ else
190
+ opts = {
191
+ private_key_length: @generate_private_key_length,
192
+ country: @generate_cert_country,
193
+ state: @generate_cert_state,
194
+ locality: @generate_cert_locality,
195
+ common_name: @generate_cert_common_name,
196
+ }
197
+ @cert, @key = Fluent::SecureForward::CertUtil.generate_self_signed_server_pair(opts)
198
+ end
199
+ return @cert, @key
200
+ end
201
+
202
+ def run # sslsocket server thread
203
+ log.trace "setup for ssl sessions"
204
+ cert, key = self.certificate
205
+
206
+ ctx = OpenSSL::SSL::SSLContext.new(@ssl_version)
207
+ if @secure
208
+ # inject OpenSSL::SSL::SSLContext::DEFAULT_PARAMS
209
+ # https://bugs.ruby-lang.org/issues/9424
210
+ ctx.set_params({})
211
+
212
+ if @ssl_ciphers
213
+ ctx.ciphers = @ssl_ciphers
214
+ else
215
+ ### follow httpclient configuration by nahi
216
+ # OpenSSL 0.9.8 default: "ALL:!ADH:!LOW:!EXP:!MD5:+SSLv2:@STRENGTH"
217
+ ctx.ciphers = "ALL:!aNULL:!eNULL:!SSLv2" # OpenSSL >1.0.0 default
218
+ end
219
+ end
220
+
221
+ ctx.cert = cert
222
+ ctx.key = key
223
+
224
+ log.trace "start to listen", bind: @bind, port: @port
225
+ server = TCPServer.new(@bind, @port)
226
+ log.trace "starting SSL server", bind: @bind, port: @port
227
+ @sock = OpenSSL::SSL::SSLServer.new(server, ctx)
228
+ @sock.start_immediately = false
229
+ begin
230
+ log.trace "accepting sessions"
231
+ loop do
232
+ while socket = @sock.accept
233
+ log.trace "accept tcp connection (ssl session not established yet)"
234
+ @sessions.push Session.new(self, socket)
235
+
236
+ # cleanup closed session instance
237
+ @sessions.delete_if(&:closed?)
238
+ log.trace "session instances:", all: @sessions.size, closed: @sessions.select(&:closed?).size
239
+ end
240
+ end
241
+ rescue OpenSSL::SSL::SSLError => e
242
+ raise unless e.message.start_with?('SSL_accept SYSCALL') # signal trap on accept
243
+ end
244
+ end
245
+
246
+ def on_message(msg)
247
+ # NOTE: copy&paste from Fluent::ForwardInput#on_message(msg)
248
+
249
+ # TODO: format error
250
+ tag = msg[0].to_s
251
+ entries = msg[1]
252
+
253
+ if entries.class == String
254
+ # PackedForward
255
+ es = MessagePackEventStream.new(entries, @cached_unpacker)
256
+ Fluent::Engine.emit_stream(tag, es)
257
+
258
+ elsif entries.class == Array
259
+ # Forward
260
+ es = Fluent::MultiEventStream.new
261
+ entries.each {|e|
262
+ time = e[0].to_i
263
+ time = (now ||= Fluent::Engine.now) if time == 0
264
+ record = e[1]
265
+ es.add(time, record)
266
+ }
267
+ Fluent::Engine.emit_stream(tag, es)
268
+
269
+ else
270
+ # Message
271
+ time = msg[1]
272
+ time = Fluent::Engine.now if time == 0
273
+ record = msg[2]
274
+ Fluent::Engine.emit(tag, time, record)
275
+ end
276
+ end
277
+ end
278
+ end
@@ -0,0 +1,219 @@
1
+ require 'msgpack'
2
+ require 'socket'
3
+ require 'openssl'
4
+ require 'digest'
5
+ # require 'resolv'
6
+
7
+ class Fluent::SecureForwardInput::Session
8
+ attr_accessor :receiver
9
+ attr_accessor :state, :thread, :node, :socket, :unpacker, :auth_salt
10
+
11
+ def initialize(receiver, socket)
12
+ @receiver = receiver
13
+
14
+ @state = :helo
15
+
16
+ @socket = socket
17
+ @socket.sync = true
18
+
19
+ @ipaddress = nil
20
+ @node = nil
21
+ @unpacker = MessagePack::Unpacker.new
22
+ @thread = Thread.new(&method(:start))
23
+ end
24
+
25
+ def log
26
+ @receiver.log
27
+ end
28
+
29
+ def closed?
30
+ @state == :closed
31
+ end
32
+
33
+ def established?
34
+ @state == :established
35
+ end
36
+
37
+ def generate_salt
38
+ OpenSSL::Random.random_bytes(16)
39
+ end
40
+
41
+ def check_node(ipaddress)
42
+ node = nil
43
+ @receiver.nodes.each do |n|
44
+ if n[:address].include?(ipaddress)
45
+ node = n
46
+ break
47
+ end
48
+ end
49
+ node
50
+ end
51
+
52
+ ## not implemented yet
53
+ # def check_hostname_reverse_lookup(ipaddress)
54
+ # rev_name = Resolv.getname(ipaddress)
55
+ # proto, port, host, ipaddr, family_num, socktype_num, proto_num = Socket.getaddrinfo(rev_name, DUMMY_PORT)
56
+ # unless ipaddr == ipaddress
57
+ # return false
58
+ # end
59
+ # true
60
+ # end
61
+
62
+ def generate_helo
63
+ log.debug "generating helo"
64
+ # ['HELO', options(hash)]
65
+ [ 'HELO', {'nonce' => @shared_key_nonce, 'auth' => (@receiver.authentication ? @auth_key_salt : ''), 'keepalive' => @receiver.allow_keepalive } ]
66
+ end
67
+
68
+ def check_ping(message)
69
+ log.debug "checking ping"
70
+ # ['PING', self_hostname, shared_key\_salt, sha512\_hex(shared_key\_salt + self_hostname + nonce + shared_key),
71
+ # username || '', sha512\_hex(auth\_salt + username + password) || '']
72
+ unless message.size == 6 && message[0] == 'PING'
73
+ return false, 'invalid ping message'
74
+ end
75
+ ping, hostname, shared_key_salt, shared_key_hexdigest, username, password_digest = message
76
+
77
+ shared_key = if @node && @node[:shared_key]
78
+ @node[:shared_key]
79
+ else
80
+ @receiver.shared_key
81
+ end
82
+ serverside = Digest::SHA512.new.update(shared_key_salt).update(hostname).update(@shared_key_nonce).update(shared_key).hexdigest
83
+ if shared_key_hexdigest != serverside
84
+ log.warn "Shared key mismatch from '#{hostname}'"
85
+ return false, 'shared_key mismatch'
86
+ end
87
+
88
+ if @receiver.authentication
89
+ users = @receiver.select_authenticate_users(@node, username)
90
+ success = false
91
+ users.each do |user|
92
+ passhash = Digest::SHA512.new.update(@auth_key_salt).update(username).update(user[:password]).hexdigest
93
+ success ||= (passhash == password_digest)
94
+ end
95
+ unless success
96
+ log.warn "Authentication failed from client '#{hostname}', username '#{username}'"
97
+ return false, 'username/password mismatch'
98
+ end
99
+ end
100
+
101
+ return true, shared_key_salt
102
+ end
103
+
104
+ def generate_pong(auth_result, reason_or_salt)
105
+ log.debug "generating pong"
106
+ # ['PONG', bool(authentication result), 'reason if authentication failed',
107
+ # self_hostname, sha512\_hex(salt + self_hostname + nonce + sharedkey)]
108
+ if not auth_result
109
+ return ['PONG', false, reason_or_salt, '', '']
110
+ end
111
+
112
+ shared_key = if @node && @node[:shared_key]
113
+ @node[:shared_key]
114
+ else
115
+ @receiver.shared_key
116
+ end
117
+ shared_key_hex = Digest::SHA512.new.update(reason_or_salt).update(@receiver.self_hostname).update(@shared_key_nonce).update(shared_key).hexdigest
118
+ [ 'PONG', true, '', @receiver.self_hostname, shared_key_hex ]
119
+ end
120
+
121
+ def on_read(data)
122
+ log.debug "on_read"
123
+ if self.established?
124
+ @receiver.on_message(data)
125
+ end
126
+
127
+ case @state
128
+ when :pingpong
129
+ success, reason_or_salt = self.check_ping(data)
130
+ if not success
131
+ send_data generate_pong(false, reason_or_salt)
132
+ self.shutdown
133
+ return
134
+ end
135
+ send_data generate_pong(true, reason_or_salt)
136
+
137
+ log.debug "connection established"
138
+ @state = :established
139
+ end
140
+ end
141
+
142
+ def send_data(data)
143
+ # not nonblock because write data (response) needs sequence
144
+ @socket.write data.to_msgpack
145
+ end
146
+
147
+ def start
148
+ log.debug "starting server"
149
+
150
+ log.trace "accepting ssl session"
151
+ begin
152
+ @socket.accept
153
+ rescue OpenSSL::SSL::SSLError => e
154
+ log.debug "failed to establish ssl session", error_class: e.class, error: e
155
+ self.shutdown
156
+ return
157
+ end
158
+
159
+ proto, port, host, ipaddr = @socket.io.peeraddr
160
+ @node = check_node(ipaddr)
161
+ if @node.nil? && (! @receiver.allow_anonymous_source)
162
+ log.warn "Connection required from unknown host '#{host}' (#{ipaddr}), disconnecting..."
163
+ self.shutdown
164
+ return
165
+ end
166
+
167
+ @shared_key_nonce = generate_salt
168
+ @auth_key_salt = generate_salt
169
+
170
+ buf = ''
171
+ read_length = @receiver.read_length
172
+ read_interval = @receiver.read_interval
173
+ socket_interval = @receiver.socket_interval
174
+
175
+ send_data generate_helo()
176
+ @state = :pingpong
177
+
178
+ loop do
179
+ begin
180
+ while @socket.read_nonblock(read_length, buf)
181
+ if buf == ''
182
+ sleep read_interval
183
+ next
184
+ end
185
+ @unpacker.feed_each(buf, &method(:on_read))
186
+ buf = ''
187
+ end
188
+ rescue OpenSSL::SSL::SSLError => e
189
+ # to wait i/o restart
190
+ sleep socket_interval
191
+ rescue EOFError => e
192
+ log.debug "Connection closed from '#{host}'(#{ipaddr})"
193
+ break
194
+ end
195
+ end
196
+ rescue Errno::ECONNRESET => e
197
+ # disconnected from client
198
+ rescue => e
199
+ log.warn "unexpected error in in_secure_forward", error_class: e.class, error: e
200
+ ensure
201
+ self.shutdown
202
+ end
203
+
204
+ def shutdown
205
+ @state = :closed
206
+ if @thread == Thread.current
207
+ @socket.close
208
+ @thread.kill
209
+ else
210
+ if @thread
211
+ @thread.kill
212
+ @thread.join
213
+ end
214
+ @socket.close
215
+ end
216
+ rescue => e
217
+ log.debug "#{e.class}:#{e.message}"
218
+ end
219
+ end
@@ -0,0 +1,38 @@
1
+ module Fluent::SecureForwardOutput::OpenSSLUtil
2
+ def self.verify_result_name(code)
3
+ case code
4
+ when OpenSSL::X509::V_OK then 'V_OK'
5
+ when OpenSSL::X509::V_ERR_AKID_SKID_MISMATCH then 'V_ERR_AKID_SKID_MISMATCH'
6
+ when OpenSSL::X509::V_ERR_APPLICATION_VERIFICATION then 'V_ERR_APPLICATION_VERIFICATION'
7
+ when OpenSSL::X509::V_ERR_CERT_CHAIN_TOO_LONG then 'V_ERR_CERT_CHAIN_TOO_LONG'
8
+ when OpenSSL::X509::V_ERR_CERT_HAS_EXPIRED then 'V_ERR_CERT_HAS_EXPIRED'
9
+ when OpenSSL::X509::V_ERR_CERT_NOT_YET_VALID then 'V_ERR_CERT_NOT_YET_VALID'
10
+ when OpenSSL::X509::V_ERR_CERT_REJECTED then 'V_ERR_CERT_REJECTED'
11
+ when OpenSSL::X509::V_ERR_CERT_REVOKED then 'V_ERR_CERT_REVOKED'
12
+ when OpenSSL::X509::V_ERR_CERT_SIGNATURE_FAILURE then 'V_ERR_CERT_SIGNATURE_FAILURE'
13
+ when OpenSSL::X509::V_ERR_CERT_UNTRUSTED then 'V_ERR_CERT_UNTRUSTED'
14
+ when OpenSSL::X509::V_ERR_CRL_HAS_EXPIRED then 'V_ERR_CRL_HAS_EXPIRED'
15
+ when OpenSSL::X509::V_ERR_CRL_NOT_YET_VALID then 'V_ERR_CRL_NOT_YET_VALID'
16
+ when OpenSSL::X509::V_ERR_CRL_SIGNATURE_FAILURE then 'V_ERR_CRL_SIGNATURE_FAILURE'
17
+ when OpenSSL::X509::V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT then 'V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT'
18
+ when OpenSSL::X509::V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD then 'V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD'
19
+ when OpenSSL::X509::V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD then 'V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD'
20
+ when OpenSSL::X509::V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD then 'V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD'
21
+ when OpenSSL::X509::V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD then 'V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD'
22
+ when OpenSSL::X509::V_ERR_INVALID_CA then 'V_ERR_INVALID_CA'
23
+ when OpenSSL::X509::V_ERR_INVALID_PURPOSE then 'V_ERR_INVALID_PURPOSE'
24
+ when OpenSSL::X509::V_ERR_KEYUSAGE_NO_CERTSIGN then 'V_ERR_KEYUSAGE_NO_CERTSIGN'
25
+ when OpenSSL::X509::V_ERR_OUT_OF_MEM then 'V_ERR_OUT_OF_MEM'
26
+ when OpenSSL::X509::V_ERR_PATH_LENGTH_EXCEEDED then 'V_ERR_PATH_LENGTH_EXCEEDED'
27
+ when OpenSSL::X509::V_ERR_SELF_SIGNED_CERT_IN_CHAIN then 'V_ERR_SELF_SIGNED_CERT_IN_CHAIN'
28
+ when OpenSSL::X509::V_ERR_SUBJECT_ISSUER_MISMATCH then 'V_ERR_SUBJECT_ISSUER_MISMATCH'
29
+ when OpenSSL::X509::V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY then 'V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY'
30
+ when OpenSSL::X509::V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE then 'V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY'
31
+ when OpenSSL::X509::V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE then 'V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE'
32
+ when OpenSSL::X509::V_ERR_UNABLE_TO_GET_CRL then 'V_ERR_UNABLE_TO_GET_CRL'
33
+ when OpenSSL::X509::V_ERR_UNABLE_TO_GET_ISSUER_CERT then 'V_ERR_UNABLE_TO_GET_ISSUER_CERT'
34
+ when OpenSSL::X509::V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY then 'V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY'
35
+ when OpenSSL::X509::V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE then 'V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE'
36
+ end
37
+ end
38
+ end