Skip to content

Commit a7d7aff

Browse files
committed
allow to inject Cipher and Signature implementations
this allows to replace certain Ciphers and Signatures with different implementations other than what comes with BouncyCastle or JCE. Sponsored by Lookout Inc.
1 parent 68c7757 commit a7d7aff

File tree

4 files changed

+216
-2
lines changed

4 files changed

+216
-2
lines changed

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

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,28 @@ public abstract class SecurityHelper {
102102
private static Boolean registerProvider = null;
103103
private static final Map<String, Class> implEngines = new ConcurrentHashMap<String, Class>(16, 0.75f, 1);
104104

105+
/**
106+
* inject under a given name a cipher. also ensures that the registered
107+
* classes are getting used.
108+
*
109+
* @param name the name under which the class gets registered
110+
* @param the CipherSpi class
111+
*/
112+
public static void addCipher(String name, Class<? extends CipherSpi> clazz) {
113+
implEngines.put("Cipher:" + name, clazz);
114+
tryCipherInternal = true;
115+
}
116+
117+
/**
118+
* inject under a given name a signature
119+
*
120+
* @param name the name under which the class gets registered
121+
* @param the SignaturSpi class
122+
*/
123+
public static void addSignature(String name, Class<? extends SignatureSpi> clazz) {
124+
implEngines.put("Signature:" + name, clazz);
125+
}
126+
105127
public static Provider getSecurityProvider() {
106128
if ( setBouncyCastleProvider && securityProvider == null ) {
107129
synchronized(SecurityHelper.class) {
@@ -417,10 +439,12 @@ private static Cipher getCipherInternal(String transformation, final Provider pr
417439
catch( IllegalStateException e ) {
418440
// this can be due to trusted check in Cipher constructor
419441
if (e.getCause().getClass() == NullPointerException.class) {
420-
return newInstance(Cipher.class,
442+
Cipher cipher = newInstance(Cipher.class,
421443
new Class[] { CipherSpi.class, String.class },
422444
new Object[] { spi, transformation }
423445
);
446+
setField(cipher, Cipher.class, "provider", provider);
447+
return cipher;
424448
}
425449
throw e;
426450
}
@@ -735,5 +759,4 @@ private static void setField(Object obj, Class<?> fieldOwner, String fieldName,
735759
throw new IllegalStateException(e);
736760
}
737761
}
738-
739762
}
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
/*
2+
* The MIT License
3+
*
4+
* Copyright 2014 Karol Bucek.
5+
*
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy
7+
* of this software and associated documentation files (the "Software"), to deal
8+
* in the Software without restriction, including without limitation the rights
9+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
* copies of the Software, and to permit persons to whom the Software is
11+
* furnished to do so, subject to the following conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be included in
14+
* all copies or substantial portions of the Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22+
* THE SOFTWARE.
23+
*/
24+
package org.jruby.ext.openssl;
25+
26+
import javax.crypto.*;
27+
import java.security.*;
28+
import java.security.spec.AlgorithmParameterSpec;
29+
30+
class CipherSpiFake extends CipherSpi {
31+
32+
@Override
33+
protected void engineSetMode(String s) throws NoSuchAlgorithmException {
34+
35+
}
36+
37+
@Override
38+
protected void engineSetPadding(String s) throws NoSuchPaddingException {
39+
40+
}
41+
42+
@Override
43+
protected int engineGetBlockSize() {
44+
return 0;
45+
}
46+
47+
@Override
48+
protected int engineGetOutputSize(int i) {
49+
return 0;
50+
}
51+
52+
@Override
53+
protected byte[] engineGetIV() {
54+
return new byte[0];
55+
}
56+
57+
@Override
58+
protected AlgorithmParameters engineGetParameters() {
59+
return null;
60+
}
61+
62+
@Override
63+
protected void engineInit(int i, Key key, SecureRandom secureRandom) throws InvalidKeyException {
64+
65+
}
66+
67+
@Override
68+
protected void engineInit(int i, Key key, AlgorithmParameterSpec algorithmParameterSpec, SecureRandom secureRandom) throws InvalidKeyException, InvalidAlgorithmParameterException {
69+
70+
}
71+
72+
@Override
73+
protected void engineInit(int i, Key key, AlgorithmParameters algorithmParameters, SecureRandom secureRandom) throws InvalidKeyException, InvalidAlgorithmParameterException {
74+
75+
}
76+
77+
@Override
78+
protected byte[] engineUpdate(byte[] bytes, int i, int i1) {
79+
return new byte[0];
80+
}
81+
82+
@Override
83+
protected int engineUpdate(byte[] bytes, int i, int i1, byte[] bytes1, int i2) throws ShortBufferException {
84+
return 0;
85+
}
86+
87+
@Override
88+
protected byte[] engineDoFinal(byte[] bytes, int i, int i1) throws IllegalBlockSizeException, BadPaddingException {
89+
return new byte[0];
90+
}
91+
92+
@Override
93+
protected int engineDoFinal(byte[] bytes, int i, int i1, byte[] bytes1, int i2) throws ShortBufferException, IllegalBlockSizeException, BadPaddingException {
94+
return 0;
95+
}
96+
}

src/test/java/org/jruby/ext/openssl/SecurityHelperTest.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import java.security.KeyStoreException;
1111
import java.security.NoSuchAlgorithmException;
1212
import java.security.Provider;
13+
import java.security.Signature;
1314
import java.security.cert.CertificateException;
1415

1516
import org.junit.After;
@@ -43,6 +44,24 @@ public void disableSecurityProvider() {
4344
SecurityHelper.setBouncyCastleProvider = false;
4445
}
4546

47+
@Test
48+
public void injectCipherImpl() throws Exception {
49+
SecurityHelper.addCipher("fake", CipherSpiFake.class);
50+
javax.crypto.Cipher cipher = SecurityHelper.getCipher("fake");
51+
assertEquals(cipher.getProvider(), savedProvider);
52+
java.lang.reflect.Field spi = cipher.getClass().getDeclaredField("spi");
53+
spi.setAccessible(true);
54+
assertEquals(spi.get(cipher).getClass(), CipherSpiFake.class);
55+
}
56+
57+
@Test
58+
public void injectSignatureImpl() throws Exception {
59+
SecurityHelper.addSignature("fake", SignatureSpiFake.class);
60+
Signature signature = SecurityHelper.getSignature("fake");
61+
assertEquals(signature.getProvider(), savedProvider);
62+
assertEquals(signature.getClass(), SignatureSpiFake.class);
63+
}
64+
4665
@Test
4766
public void usesBouncyCastleSecurityProviderByDefault() {
4867
assertNotNull(SecurityHelper.getSecurityProvider());
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
/*
2+
* The MIT License
3+
*
4+
* Copyright 2014 Karol Bucek.
5+
*
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy
7+
* of this software and associated documentation files (the "Software"), to deal
8+
* in the Software without restriction, including without limitation the rights
9+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
* copies of the Software, and to permit persons to whom the Software is
11+
* furnished to do so, subject to the following conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be included in
14+
* all copies or substantial portions of the Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22+
* THE SOFTWARE.
23+
*/
24+
package org.jruby.ext.openssl;
25+
26+
import java.security.*;
27+
28+
/**
29+
* Created by cmeier on 7/29/15.
30+
*/
31+
class SignatureSpiFake extends Signature {
32+
33+
SignatureSpiFake() {
34+
super("fake");
35+
}
36+
37+
@Override
38+
protected void engineInitVerify(PublicKey publicKey) throws InvalidKeyException {
39+
40+
}
41+
42+
@Override
43+
protected void engineInitSign(PrivateKey privateKey) throws InvalidKeyException {
44+
45+
}
46+
47+
@Override
48+
protected void engineUpdate(byte b) throws SignatureException {
49+
50+
}
51+
52+
@Override
53+
protected void engineUpdate(byte[] b, int off, int len) throws SignatureException {
54+
55+
}
56+
57+
@Override
58+
protected byte[] engineSign() throws SignatureException {
59+
return new byte[0];
60+
}
61+
62+
@Override
63+
protected boolean engineVerify(byte[] sigBytes) throws SignatureException {
64+
return false;
65+
}
66+
67+
@Override
68+
protected void engineSetParameter(String param, Object value) throws InvalidParameterException {
69+
70+
}
71+
72+
@Override
73+
protected Object engineGetParameter(String param) throws InvalidParameterException {
74+
return null;
75+
}
76+
}

0 commit comments

Comments
 (0)