Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: jruby/jruby-openssl
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 993ed5f6b2e6
Choose a base ref
...
head repository: jruby/jruby-openssl
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 7d13c15d3f80
Choose a head ref
  • 2 commits
  • 6 files changed
  • 2 contributors

Commits on Nov 3, 2016

  1. Copy the full SHA
    b71026d View commit details
  2. some ~ explicit security manager checks for jruby/openssl

    ... transplanted from jruby/jruby#853
    Dmitry Ratnikov authored and kares committed Nov 3, 2016
    Copy the full SHA
    7d13c15 View commit details
83 changes: 83 additions & 0 deletions src/test/java/org/jruby/ext/openssl/security/SecurityManager.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package org.jruby.ext.openssl.security;

import org.jruby.Ruby;
import org.jruby.RubyString;
import org.jruby.runtime.builtin.IRubyObject;

import java.util.ArrayList;
import java.util.List;

public class SecurityManager extends java.lang.SecurityManager {
public static class RubyPermission {
private final IRubyObject lambda;

public RubyPermission(IRubyObject lambda) {
this.lambda = lambda;
}

public boolean matches(java.security.Permission perm) {
Ruby runtime = lambda.getRuntime();

return lambda.callMethod(runtime.getCurrentContext(),
"call",
new IRubyObject[] {
RubyString.newString(runtime, perm.getClass().getSimpleName()),
RubyString.newString(runtime, perm.getName()),
RubyString.newString(runtime, perm.getActions())
}).isTrue();
}
}

/*
public static SecurityManager install() {
SecurityManager manager = new SecurityManager();
System.setSecurityManager(manager);
return manager;
} */

private boolean verbose = false;
private boolean strict = false;
private final List<RubyPermission> temporaryPermissions = new ArrayList<RubyPermission>();

@Override
public void checkPermission(java.security.Permission perm) {
for (RubyPermission permission: temporaryPermissions) {
if (permission.matches(perm)) {
return;
}
}

if (strict) {
logTrace(perm.toString() + " denied");
super.checkPermission(perm);
}
}

public SecurityManager setStrict(boolean strict) {
this.strict = strict;
return this;
}

public SecurityManager permit(RubyPermission permission) {
temporaryPermissions.add(permission);
return this;
}

public SecurityManager revoke(RubyPermission permission) {
temporaryPermissions.remove(permission);
return this;
}

public SecurityManager setVerbosity(boolean verbose) {
this.verbose = verbose;
return this;
}

private void logTrace(String message) {
if (verbose) {
new Exception(message).printStackTrace();
}
}
}
2 changes: 1 addition & 1 deletion src/test/ruby/ec/test_ec.rb
Original file line number Diff line number Diff line change
@@ -70,7 +70,7 @@ def test_encrypt
# assert server.group.nil? # TODO MRI has a "null" group

server.private_key = OpenSSL::BN.new('107411000028178101972699773683980269641478018566010848092863514011724406285076')
'62303413620263991527470772975506242387142677576794087805856701493545918209262092657150628139966331940997693252502978347289754390001755240229834360187731879'
# '62303413620263991527470772975506242387142677576794087805856701493545918209262092657150628139966331940997693252502978347289754390001755240229834360187731879'

group = OpenSSL::PKey::EC::Group.new(group_name)
client_public_key_bn = OpenSSL::BN.new(Base64.urlsafe_decode64(p256dh), 2)
10 changes: 4 additions & 6 deletions src/test/ruby/ssl/test_context.rb
Original file line number Diff line number Diff line change
@@ -56,18 +56,16 @@ def test_verify_mode
server_cert = OpenSSL::X509::Certificate.new IO.read( File.join(File.dirname(__FILE__), 'server.crt') )
server_key = OpenSSL::PKey::RSA.new IO.read( File.join(File.dirname(__FILE__), 'server.key') )

context = OpenSSL::SSL::SSLContext.new.tap do |context|
context.cert = server_cert
context.key = server_key
context = OpenSSL::SSL::SSLContext.new.tap do |ctx|
ctx.cert = server_cert ; ctx.key = server_key
end
assert_nil context.verify_mode

client_cert = OpenSSL::X509::Certificate.new IO.read( File.join(File.dirname(__FILE__), 'client.crt') )
client_key = OpenSSL::PKey::RSA.new IO.read( File.join(File.dirname(__FILE__), 'client.key') )

context = OpenSSL::SSL::SSLContext.new.tap do |context|
context.cert = client_cert
context.key = client_key
context = OpenSSL::SSL::SSLContext.new.tap do |ctx|
ctx.cert = client_cert ; ctx.key = client_key
end
assert_nil context.verify_mode
end
170 changes: 170 additions & 0 deletions src/test/ruby/test_security.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
$CLASSPATH << File.expand_path('../../../pkg/test-classes', File.dirname(__FILE__))

class SecurityWrapper

java_import 'org.jruby.ext.openssl.security.SecurityManager'

attr_reader :java_manager

def initialize(java_manager)
@java_manager = java_manager
end

def install_security_manager
java.lang.System.setSecurityManager java_manager
end

def allow(permissions_hash = nil, &block)
if permissions_hash
permissions = parse_hash_value(permissions_hash).uniq.map { |v| v.flatten }

return allow do |expected_type, expected_name, expected_actions|
permissions.any? do |parr|
(type, name, actions) = *parr
(type == expected_type &&
(name.nil? || name == expected_name) &&
(actions.nil? || actions == expected_actions))
end
end
end

SecurityManager::RubyPermission.new(block).tap { |perm| java_manager.permit perm }
end

def with_permissions(hash)
p = allow(hash)
begin
yield
ensure
java_manager.revoke p
end
end

def permissive!
java_manager.setStrict(false)
self
end

def strict!
java_manager.setStrict(true)
self
end

def verbose!
java_manager.setVerbosity true
self
end

def silent!
java_manager.setVerbosity false
self
end

private

def parse_hash_value(value)
return [ value ].compact unless value.is_a?(Hash)
value.reduce([]) { |arr, kv| arr += [ kv.first ].product(parse_hash_value(kv.last)) }
end
end

Security = SecurityWrapper.new org.jruby.ext.openssl.security.SecurityManager.new

Security.allow do |type, name, actions|
case type
when 'FilePermission'
# Allow to read the FS (.rb, .pem, .class, ...)
actions == "read"
when 'LoggingPermission'
# NOTE invokebinder initializes JUL :
# https://github.com/headius/invokebinder/blob/master/src/main/java/com/headius/invokebinder/Binder.java#L70
name == "control" # ("java.util.logging.LoggingPermission" "control")
when 'PropertyPermission'
actions == "read" && [
"java.protocol.handler.pkgs",
"sun.misc.ProxyGenerator.saveGeneratedFiles",

# FFI needs to be able to read its properties
/^jnr\.ffi\..*/,

# Allow reading any jruby properties
/^jruby/,

# Allow knowledge about environment
/^os\..*/,
/^user\..*/,
"sun.arch.data.model",
"java.home",

# Allow proxies
/^sun.reflect.proxy.*/,

# NOTE invokebinder initializes JUL :
"sun.util.logging.disableCallerCheck"
].any? { |read_permission| read_permission === name }
when 'RuntimePermission'
# Allow loading of native libraries
name =~ /^loadLibrary\..*\.so$/ ||
name == "loadLibrary.nio" ||

# jnr.posix needs this
name == "accessDeclaredMembers" ||
name == "createClassLoader" ||

# Let Main do System.exit
name == "exitVM.1" ||

name =~ /^accessClassInPackage\.sun.*$/ ||

# Not sure what this is about
name == "getProtectionDomain" ||
name == "fileSystemProvider"
when 'ReflectPermission'
# JRuby makes heavy usage of reflection for dynamic invocation, etc
name == "suppressAccessChecks"
else
false
end
end

##

Security.install_security_manager

##

Security.strict!.with_permissions({
"SecurityPermission" => [
"getProperty.keystore.type",
"putProviderProperty.SunJGSS",
"putProviderProperty.SunEC-Internal",
"putProviderProperty.BC",
"insertProvider.BC"
],

# OpenSSL uses java.text.SimpleDateFormat that needs to load this
"RuntimePermission" => "accessClassInPackage.sun.util.resources",
"PropertyPermission" => {
"com.sun.security.preserveOldDCEncoding" => "read",
"sun.security.key.serial.interop" => "read",

# Maybe this should be global?
"java.nio.file.spi.DefaultFileSystemProvider" => "read",

# SimpleDateFormat again
"sun.timezone.ids.oldmapping" => "read",
"sun.nio.fs.chdirAllowed" => "read",

# java.util.TimeZone.getDefault memoizes the default in property
"user.timezone" => "write"
}

}) do
require 'openssl'
end

##

Security.permissive!

puts "using permissive! security with installed manager: #{java.lang.System.getSecurityManager}"
12 changes: 6 additions & 6 deletions src/test/ruby/x509/test_x509cert.rb
Original file line number Diff line number Diff line change
@@ -105,22 +105,22 @@ def test_resolve_extensions

exts = cert.extensions.dup

assert ext = exts.find { |ext| ext.oid == 'basicConstraints' }, "missing 'basicConstraints' among: #{exts.join(', ')}"
assert ext = exts.find { |e| e.oid == 'basicConstraints' }, "missing 'basicConstraints' among: #{exts.join(', ')}"
assert_equal 'CA:TRUE', ext.value
assert ext.critical?

assert ext = exts.find { |ext| ext.oid == 'authorityKeyIdentifier' }, "missing 'authorityKeyIdentifier' among: #{exts.join(', ')}"
assert ext = exts.find { |e| e.oid == 'authorityKeyIdentifier' }, "missing 'authorityKeyIdentifier' among: #{exts.join(', ')}"
assert_equal "keyid:97:39:9D:C3:FB:CD:BA:8F:54:0C:90:7B:46:3F:EA:D6:43:75:B1:CB\n", ext.value
assert ! ext.critical?

assert ext = exts.find { |ext| ext.oid == 'subjectKeyIdentifier' }, "missing 'subjectKeyIdentifier' among: #{exts.join(', ')}"
assert ext = exts.find { |e| e.oid == 'subjectKeyIdentifier' }, "missing 'subjectKeyIdentifier' among: #{exts.join(', ')}"
assert_equal "97:39:9D:C3:FB:CD:BA:8F:54:0C:90:7B:46:3F:EA:D6:43:75:B1:CB", ext.value
assert ! ext.critical?

assert ext = exts.find { |ext| ext.oid == 'subjectAltName' }, "missing 'subjectAltName' among: #{exts.join(', ')}"
assert ext = exts.find { |e| e.oid == 'subjectAltName' }, "missing 'subjectAltName' among: #{exts.join(', ')}"
assert_equal 'email:self@jruby.org', ext.value
exts.delete(ext)
assert ext = exts.find { |ext| ext.oid == 'subjectAltName' }, "missing 'subjectAltName' among: #{exts.join(', ')}"
assert ext = exts.find { |e| e.oid == 'subjectAltName' }, "missing 'subjectAltName' among: #{exts.join(', ')}"
assert_equal 'DNS:jruby.org', ext.value
end

@@ -161,7 +161,7 @@ def test_extensions
when /IP\:/
# NOTE: probably fine as "IP:174.129.31.214" on JRuby while on MRI :
# assert_equal 'IP Address:174.129.31.214', ext.value
assert_match /IP.*?:174.129.31.214/, ext.value
assert_match( /IP.*?:174.129.31.214/, ext.value )
else
assert_equal ca_exts[i][1], ext.value
end
7 changes: 2 additions & 5 deletions src/test/ruby/x509/test_x509store.rb
Original file line number Diff line number Diff line change
@@ -76,18 +76,15 @@ def test_verfy_with_wrong_argument
def test_add_cert_concurrently
store = OpenSSL::X509::Store.new
t = []
(0..25).each do |i|

(0..25).each do
t << Thread.new do
(0..2).each do
store.add_file @pem
end
end
end

t.each do |t|
t.join
end
t.each(&:join)
# just ensure there is no concurreny error
assert true
end