Skip to content

Commit b51da46

Browse files
authored
Remove bouncy castle and change the exception for invalid security token (#131)
Removed the Bouncy Castle libraries and replaced with standard Java JCE APIs Changed the exception thrown in Instance/Resource/OKE principal providers for invalid security token from IllegalArgumentException to SecurityInfoNotReadyException
1 parent fc9df98 commit b51da46

23 files changed

+2279
-284
lines changed

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/).
1313
provide local region information.
1414
- Cloud only: fixed a compatibility issue introduced in 5.4.15 regarding use of
1515
the Bouncy Castle artifacts. This would turn up when using Instance Principal
16-
authentication
16+
authentication, the bouncy castle artifacts have been removed and replaced
17+
with standard Java JCE APIs.
1718

1819
### Changed
1920
- Put and Put if-present can return the existing row when setReturnRow is

THIRD_PARTY_LICENSES.txt

Lines changed: 1 addition & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -35,26 +35,6 @@ in some artifacts (usually source distributions); but is always available
3535
from the source code management (SCM) system project uses.
3636
===============
3737

38-
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
39-
Bouncy Castle
40-
Copyright (c) 2000 - 2017 The Legion of the Bouncy Castle Inc.
41-
License: modified MIT
42-
43-
Permission is hereby granted, free of charge, to any person obtaining a copy of this
44-
software and associated documentation files (the "Software"), to deal in the Software
45-
without restriction, including without limitation the rights to use, copy, modify,
46-
merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
47-
permit persons to whom the Software is furnished to do so, subject to the following conditions:
48-
49-
The above copyright notice and this permission notice shall be included in all copies or
50-
substantial portions of the Software.
51-
52-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
53-
BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
54-
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
55-
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
56-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
57-
5838
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
5939
jQuery UI for Javadoc
6040

@@ -1511,4 +1491,4 @@ indemnify, defend, and hold each Contributor harmless for any liability incurred
15111491
by, or claims asserted against, such Contributor by reason of your accepting any
15121492
such warranty or additional liability.
15131493

1514-
END OF TERMS AND CONDITIONS
1494+
END OF TERMS AND CONDITIONS

driver/pom.xml

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,6 @@
4848
<maven.deploy.skip>false</maven.deploy.skip>
4949
<netty.version>4.1.108.Final</netty.version>
5050
<jackson.version>2.15.2</jackson.version>
51-
<bouncy.version>1.78</bouncy.version>
5251
<!-- by default, skip tests; tests require a profile -->
5352
<maven.test.skip>true</maven.test.skip>
5453
<javac>javac</javac>
@@ -249,19 +248,6 @@
249248
<version>${netty.version}</version>
250249
</dependency>
251250

252-
<!-- Bouncycastle - request signing in cloud -->
253-
<dependency>
254-
<groupId>org.bouncycastle</groupId>
255-
<artifactId>bcprov-jdk18on</artifactId>
256-
<version>${bouncy.version}</version>
257-
</dependency>
258-
259-
<dependency>
260-
<groupId>org.bouncycastle</groupId>
261-
<artifactId>bcpkix-jdk18on</artifactId>
262-
<version>${bouncy.version}</version>
263-
</dependency>
264-
265251
<!-- test -->
266252
<dependency>
267253
<groupId>junit</groupId>

driver/src/main/java/oracle/nosql/driver/iam/OkeWorkloadIdentityProvider.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232

3333
import oracle.nosql.driver.NoSQLHandleConfig;
3434
import oracle.nosql.driver.Region;
35+
import oracle.nosql.driver.SecurityInfoNotReadyException;
3536
import oracle.nosql.driver.httpclient.HttpClient;
3637
import oracle.nosql.driver.iam.SessionKeyPairSupplier.DefaultSessionKeySupplier;
3738
import oracle.nosql.driver.util.HttpRequestUtil;
@@ -222,6 +223,16 @@ private String getSecurityToken() {
222223
final byte[] payloadByte = new byte[buf.remaining()];
223224
buf.get(payloadByte);
224225

226+
try {
227+
return getSecurityTokenFromProxymux(requestId, saToken, payloadByte);
228+
} catch (Exception e) {
229+
throw new SecurityInfoNotReadyException(e.getMessage(), e);
230+
}
231+
}
232+
233+
private String getSecurityTokenFromProxymux(String requestId,
234+
String saToken,
235+
byte[] payloadByte) {
225236
HttpRequestUtil.HttpResponse response = HttpRequestUtil.doPostRequest(
226237
okeTokenClient, tokenURL.toString(), headers(saToken, requestId),
227238
payloadByte, timeoutMs, logger);

driver/src/main/java/oracle/nosql/driver/iam/PrivateKeyProvider.java

Lines changed: 25 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -7,37 +7,29 @@
77

88
package oracle.nosql.driver.iam;
99

10-
import static oracle.nosql.driver.util.CheckNull.requireNonNullIAE;
11-
1210
import java.io.IOException;
1311
import java.io.InputStream;
14-
import java.io.InputStreamReader;
15-
import java.nio.charset.StandardCharsets;
16-
import java.security.Provider;
17-
import java.security.Security;
12+
import java.nio.channels.Channels;
13+
import java.nio.channels.ReadableByteChannel;
14+
import java.security.PrivateKey;
1815
import java.security.interfaces.RSAPrivateKey;
1916
import java.util.Arrays;
2017

21-
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
22-
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
23-
import org.bouncycastle.openssl.EncryptionException;
24-
import org.bouncycastle.openssl.PEMDecryptorProvider;
25-
import org.bouncycastle.openssl.PEMEncryptedKeyPair;
26-
import org.bouncycastle.openssl.PEMException;
27-
import org.bouncycastle.openssl.PEMKeyPair;
28-
import org.bouncycastle.openssl.PEMParser;
29-
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
30-
import org.bouncycastle.openssl.jcajce.JcePEMDecryptorProviderBuilder;
18+
import oracle.nosql.driver.iam.pki.Pem;
19+
import oracle.nosql.driver.iam.pki.PemEncryptionException;
20+
import oracle.nosql.driver.iam.pki.PemException;
3121

3222
/**
3323
* @hidden
3424
* Internal use only
3525
* <p>
3626
* The RSA private key provider that loads and caches private key from input
37-
* stream using bouncy castle PEM key utilities.
27+
* stream using PEM key utilities in oci-java-sdk.
28+
*
29+
* See com.oracle.bmc.http.signing.internal.PEMStreamRSAPrivateKeySupplier
30+
* for reference.
3831
*/
3932
class PrivateKeyProvider {
40-
private final JcaPEMKeyConverter converter = new JcaPEMKeyConverter();
4133
private RSAPrivateKey key = null;
4234

4335
/**
@@ -66,79 +58,25 @@ void reload(InputStream keyInputStream, char[] passphrase) {
6658
}
6759

6860
void getKeyInternal(InputStream keyInputStream, char[] passphrase) {
69-
PEMParser keyReader = null;
70-
try {
71-
keyReader = new PEMParser(
72-
new InputStreamReader(keyInputStream, StandardCharsets.UTF_8));
73-
74-
Object object = null;
75-
try {
76-
object = keyReader.readObject();
77-
} catch (IOException ioe) {
78-
throw new IllegalArgumentException(
79-
"Error reading private key", ioe);
80-
}
81-
PrivateKeyInfo keyInfo;
82-
83-
if (object instanceof PEMEncryptedKeyPair) {
84-
requireNonNullIAE(
85-
passphrase,
86-
"The provided private key requires a passphrase");
87-
88-
JcePEMDecryptorProviderBuilder decryptBuilder =
89-
new JcePEMDecryptorProviderBuilder();
90-
91-
if (!isProviderInstalled()) {
92-
/*
93-
* If BouncyCastle is not installed, must add the provider
94-
* explicitly to enable the PEMDecrptorProvider.
95-
* https://github.com/bcgit/bc-java/issues/156
96-
*/
97-
decryptBuilder.setProvider(getBouncyCastleProvider());
98-
}
99-
100-
PEMDecryptorProvider decProv = decryptBuilder.build(passphrase);
101-
try {
102-
keyInfo = ((PEMEncryptedKeyPair) object)
103-
.decryptKeyPair(decProv)
104-
.getPrivateKeyInfo();
105-
} catch (EncryptionException ee) {
106-
throw new IllegalArgumentException(
107-
"The provided passphrase is incorrect.", ee);
108-
} catch (IOException ioe) {
109-
throw new IllegalArgumentException(
110-
"Error decrypting private key.", ioe);
111-
}
112-
} else if (object instanceof PrivateKeyInfo) {
113-
keyInfo = (PrivateKeyInfo) object;
114-
} else if (object instanceof PEMKeyPair) {
115-
keyInfo = ((PEMKeyPair) object).getPrivateKeyInfo();
116-
} else if (object instanceof SubjectPublicKeyInfo) {
117-
throw new IllegalArgumentException(
118-
"Public key provided instead of private key");
119-
} else if (object != null) {
120-
throw new IllegalArgumentException(
121-
"Private key must be in PEM format," +
122-
"was: " + object.getClass());
61+
try (ReadableByteChannel channel = Channels.newChannel(keyInputStream);
62+
Pem.Passphrase pemPassphrase = Pem.Passphrase.of(passphrase)){
63+
PrivateKey privateKey =
64+
Pem.decoder().with(pemPassphrase).decodePrivateKey(channel);
65+
if (privateKey instanceof RSAPrivateKey) {
66+
key = (RSAPrivateKey) privateKey;
12367
} else {
12468
throw new IllegalArgumentException(
125-
"Private key must be in PEM format");
126-
}
127-
128-
try {
129-
this.key = (RSAPrivateKey) converter.getPrivateKey(keyInfo);
130-
} catch (PEMException e) {
131-
throw new IllegalArgumentException(
132-
"Error converting private key");
69+
"Must be RSA private key, but " + privateKey.toString());
13370
}
71+
} catch (PemEncryptionException e) {
72+
throw new IllegalArgumentException(
73+
"The provided passphrase is incorrect.", e);
74+
} catch (PemException e) {
75+
throw new IllegalArgumentException(
76+
"Private key must be in PEM format", e);
77+
} catch (IOException e) {
78+
throw new IllegalArgumentException("Error reading private key", e);
13479
} finally {
135-
if (keyReader != null) {
136-
try {
137-
keyReader.close();
138-
} catch (IOException e) {
139-
/* ignore */
140-
}
141-
}
14280
if (keyInputStream != null) {
14381
try {
14482
keyInputStream.close();
@@ -151,25 +89,4 @@ void getKeyInternal(InputStream keyInputStream, char[] passphrase) {
15189
}
15290
}
15391
}
154-
155-
private static boolean isProviderInstalled() {
156-
return (Security.getProvider("BC") != null);
157-
}
158-
159-
private static Provider getBouncyCastleProvider() {
160-
Provider provider = null;
161-
try {
162-
Class<?> providerClass = Class.forName(
163-
"org.bouncycastle.jce.provider.BouncyCastleProvider");
164-
provider = (Provider)providerClass
165-
.getDeclaredConstructor().newInstance();
166-
} catch (ClassNotFoundException e) {
167-
throw new IllegalArgumentException(
168-
"Unable to find bouncy castle provider");
169-
} catch (Exception e) {
170-
throw new IllegalArgumentException(
171-
"Error creating bouncy castle provider");
172-
}
173-
return provider;
174-
}
17592
}

driver/src/main/java/oracle/nosql/driver/iam/ResourcePrincipalTokenSupplier.java

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import java.security.KeyPair;
1717
import java.util.logging.Logger;
1818

19+
import oracle.nosql.driver.SecurityInfoNotReadyException;
1920
import oracle.nosql.driver.iam.SecurityTokenSupplier.SecurityToken;
2021

2122
/**
@@ -91,11 +92,15 @@ private synchronized String refreshAndGetSecurityToken() {
9192
logTrace(logger, "Refreshing session keys");
9293
sessionKeyPairSupplier.refreshKeys();
9394

94-
logTrace(logger, "Getting security token from file.");
95-
SecurityToken token = getSecurityTokenFromFile();
96-
token.validate(minTokenLifetime, logger);
97-
securityToken = token;
98-
return securityToken.getSecurityToken();
95+
try {
96+
logTrace(logger, "Getting security token from file.");
97+
SecurityToken token = getSecurityTokenFromFile();
98+
token.validate(minTokenLifetime, logger);
99+
securityToken = token;
100+
return securityToken.getSecurityToken();
101+
} catch (Exception e) {
102+
throw new SecurityInfoNotReadyException(e.getMessage(), e);
103+
}
99104
}
100105

101106
SecurityToken getSecurityTokenFromFile() {

driver/src/main/java/oracle/nosql/driver/iam/SecurityTokenSupplier.java

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -164,13 +164,10 @@ private synchronized String refreshAndGetTokenInternal() {
164164
}
165165
}
166166
}
167-
SecurityToken token = getSecurityTokenFromIAM();
168-
token.validate(minTokenLifetime, logger);
169-
170-
return token.getSecurityToken();
167+
return getSecurityTokenFromIAM();
171168
}
172169

173-
private SecurityToken getSecurityTokenFromIAM() {
170+
private String getSecurityTokenFromIAM() {
174171
KeyPair keyPair = keyPairSupplier.getKeyPair();
175172
requireNonNullIAE(keyPair, "Keypair for session not provided");
176173

@@ -211,7 +208,9 @@ private SecurityToken getSecurityTokenFromIAM() {
211208
Utils.base64EncodeNoChunking(certificateAndKeyPair),
212209
intermediateStrings);
213210

214-
return new SecurityToken(securityToken, keyPairSupplier);
211+
SecurityToken st = new SecurityToken(securityToken, keyPairSupplier);
212+
st.validate(minTokenLifetime, logger);
213+
return st.getSecurityToken();
215214
} catch (Exception e) {
216215
throw new SecurityInfoNotReadyException(e.getMessage(), e);
217216
}

0 commit comments

Comments
 (0)