Skip to content

Commit 2816b73

Browse files
committed
invent a JCE crypto security hack to disable restrictions
... NOT meant for production use!
1 parent b802212 commit 2816b73

File tree

2 files changed

+176
-6
lines changed

2 files changed

+176
-6
lines changed

src/main/java/org/jruby/ext/openssl/OpenSSL.java

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
import org.jruby.anno.JRubyMethod;
3737
import org.jruby.anno.JRubyModule;
3838
import org.jruby.runtime.ThreadContext;
39+
import org.jruby.runtime.Visibility;
3940
import org.jruby.runtime.builtin.IRubyObject;
4041
import org.jruby.util.ByteList;
4142
import org.jruby.util.SafePropertyAccessor;
@@ -188,22 +189,35 @@ public static IRubyObject set_fips_mode(ThreadContext context, IRubyObject self,
188189

189190
// internal (package-level) helpers :
190191

192+
/**
193+
* PRIMARILY MEANT FOR TESTING ONLY, USAGE IS DISCOURAGED!
194+
* @see org.jruby.ext.openssl.util.CryptoSecurity
195+
*/
196+
@JRubyMethod(name = "_disable_security_restrictions!", visibility = Visibility.PRIVATE, meta = true)
197+
public static IRubyObject _disable_security_restrictions(ThreadContext context, IRubyObject self) {
198+
Boolean unrestrict = org.jruby.ext.openssl.util.CryptoSecurity.unrestrictSecurity();
199+
Boolean allPerm = org.jruby.ext.openssl.util.CryptoSecurity.setAllPermissionPolicy();
200+
if ( unrestrict == null || allPerm == null ) return context.nil;
201+
return context.runtime.newBoolean( unrestrict && allPerm );
202+
}
203+
204+
191205
private static boolean debug;
192206

193207
// on by default, warnings can be disabled using -Djruby.openssl.warn=false
194208
private static boolean warn = true;
195209

196210
static boolean isDebug() { return debug; }
197211

198-
static void debugStackTrace(final Throwable e) {
212+
public static void debugStackTrace(final Throwable e) {
199213
if ( isDebug() ) e.printStackTrace(System.out);
200214
}
201215

202-
static void debug(final String msg) {
216+
public static void debug(final String msg) {
203217
if ( isDebug() ) System.out.println(msg);
204218
}
205219

206-
static void debug(final String msg, final Throwable e) {
220+
public static void debug(final String msg, final Throwable e) {
207221
if ( isDebug() ) System.out.println(msg + ' ' + e);
208222
}
209223

@@ -237,7 +251,7 @@ static void warn(final ThreadContext context, final IRubyObject msg) {
237251
if ( warn ) context.runtime.getModule("OpenSSL").callMethod(context, "warn", msg);
238252
}
239253

240-
private static String javaVersion(final String def) {
254+
public static String javaVersion(final String def) {
241255
final String javaVersionProperty =
242256
SafePropertyAccessor.getProperty("java.version", def);
243257
if ( javaVersionProperty == "0" ) return "1.7.0"; // Android
@@ -262,11 +276,11 @@ private static String javaName(final String def) {
262276
return SafePropertyAccessor.getProperty("java.vm.name", def);
263277
}
264278

265-
static boolean javaHotSpot() {
279+
public static boolean javaHotSpot() {
266280
return javaName("").contains("HotSpot(TM)");
267281
}
268282

269-
static boolean javaOpenJDK() {
283+
public static boolean javaOpenJDK() {
270284
return javaName("").contains("OpenJDK");
271285
}
272286

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
/***** BEGIN LICENSE BLOCK *****
2+
* Version: EPL 1.0/GPL 2.0/LGPL 2.1
3+
*
4+
* The contents of this file are subject to the Eclipse Public
5+
* License Version 1.0 (the "License"); you may not use this file
6+
* except in compliance with the License. You may obtain a copy of
7+
* the License at http://www.eclipse.org/legal/epl-v10.html
8+
*
9+
* Software distributed under the License is distributed on an "AS
10+
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
11+
* implied. See the License for the specific language governing
12+
* rights and limitations under the License.
13+
*
14+
* Copyright (C) 2017 Karol Bucek <[email protected]>
15+
*
16+
* Alternatively, the contents of this file may be used under the terms of
17+
* either of the GNU General Public License Version 2 or later (the "GPL"),
18+
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
19+
* in which case the provisions of the GPL or the LGPL are applicable instead
20+
* of those above. If you wish to allow use of your version of this file only
21+
* under the terms of either the GPL or the LGPL, and not to allow others to
22+
* use your version of this file under the terms of the EPL, indicate your
23+
* decision by deleting the provisions above and replace them with the notice
24+
* and other provisions required by the GPL or the LGPL. If you do not delete
25+
* the provisions above, a recipient may use your version of this file under
26+
* the terms of any one of the EPL, the GPL or the LGPL.
27+
***** END LICENSE BLOCK *****/
28+
package org.jruby.ext.openssl.util;
29+
30+
import org.jruby.ext.openssl.OpenSSL;
31+
32+
import java.lang.reflect.Field;
33+
import java.lang.reflect.Modifier;
34+
import java.security.Permission;
35+
import java.security.PermissionCollection;
36+
import java.security.Security;
37+
38+
/**
39+
* JCE security helper for disabling (default) imposed cryptographic restrictions.
40+
*
41+
* Using this class might be in **contrast with the license agreement** that came with your JRE.
42+
*
43+
* It's preferable to install:
44+
*
45+
* "Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files"
46+
*
47+
* specific to your Java version!
48+
*
49+
* @see http://www.oracle.com/technetwork/java/javase/downloads/index.html
50+
*/
51+
public final class CryptoSecurity {
52+
53+
private CryptoSecurity() { /* no instances */ }
54+
55+
public static void disableJceRestrictions() {
56+
unrestrictSecurity();
57+
setAllPermissionPolicy();
58+
}
59+
60+
public static Boolean setAllPermissionPolicy() {
61+
if ( ! OpenSSL.javaHotSpot() ) return false;
62+
try {
63+
final Class JceSecurity = Class.forName("javax.crypto.JceSecurity");
64+
65+
final Class CryptoPermissions = Class.forName("javax.crypto.CryptoPermissions");
66+
final Class CryptoAllPermission = Class.forName("javax.crypto.CryptoAllPermission");
67+
68+
Field defaultPolicy = JceSecurity.getDeclaredField("defaultPolicy");
69+
defaultPolicy.setAccessible(true);
70+
71+
Field perms = CryptoPermissions.getDeclaredField("perms");
72+
perms.setAccessible(true);
73+
74+
Field INSTANCE = CryptoAllPermission.getDeclaredField("INSTANCE");
75+
INSTANCE.setAccessible(true);
76+
77+
synchronized (Security.class) {
78+
final PermissionCollection defPolicy = (PermissionCollection) defaultPolicy.get(null);
79+
final java.util.Map permsMap = (java.util.Map) perms.get(defPolicy);
80+
if ( ! permsMap.isEmpty() ) {
81+
permsMap.clear();
82+
defPolicy.add((Permission) INSTANCE.get(null));
83+
return true;
84+
}
85+
return false;
86+
}
87+
}
88+
catch (ClassNotFoundException e) {
89+
OpenSSL.debug("unable un-restrict jce security: ", e);
90+
return null;
91+
}
92+
catch (Exception e) {
93+
OpenSSL.debug("unable un-restrict jce security: ");
94+
OpenSSL.debugStackTrace(e);
95+
return null;
96+
}
97+
}
98+
99+
public static Boolean unrestrictSecurity() {
100+
if ( ! OpenSSL.javaHotSpot() ) return false;
101+
if ( javaVersion9() ) {
102+
return unrestrictJceSecurity9();
103+
}
104+
return unrestrictJceSecurity8();
105+
}
106+
107+
static Boolean unrestrictJceSecurity9() {
108+
try {
109+
if (Security.getProperty("crypto.policy") == null) {
110+
Security.setProperty("crypto.policy", "unlimited");
111+
return true;
112+
}
113+
return false;
114+
}
115+
catch (Exception e) {
116+
OpenSSL.debug("unable un-restrict jce security: ", e);
117+
return null;
118+
}
119+
}
120+
121+
static Boolean unrestrictJceSecurity8() {
122+
try {
123+
final Class JceSecurity = Class.forName("javax.crypto.JceSecurity");
124+
125+
Field isRestricted = JceSecurity.getDeclaredField("isRestricted");
126+
127+
if ( Modifier.isFinal(isRestricted.getModifiers()) ) {
128+
Field modifiers = Field.class.getDeclaredField("modifiers");
129+
modifiers.setAccessible(true);
130+
modifiers.setInt(isRestricted, isRestricted.getModifiers() & ~Modifier.FINAL);
131+
}
132+
133+
isRestricted.setAccessible(true);
134+
if (isRestricted.getBoolean(null) == false) {
135+
isRestricted.setBoolean(null, false); // isRestricted = false;
136+
return true;
137+
}
138+
return false;
139+
}
140+
catch (ClassNotFoundException e) {
141+
OpenSSL.debug("unable un-restrict jce security: ", e);
142+
return null;
143+
}
144+
catch (Exception e) {
145+
OpenSSL.debug("unable un-restrict jce security: ");
146+
OpenSSL.debugStackTrace(e);
147+
return null;
148+
}
149+
}
150+
151+
private static boolean javaVersion9() {
152+
final int gt = "1.8".compareTo( OpenSSL.javaVersion("0.0").substring(0, 3) );
153+
return gt <= 0;
154+
}
155+
156+
}

0 commit comments

Comments
 (0)