854 jdk17 visibility (#855)

* Closes #854.

- Replaced `ByteArrayInputStream` reflection with new `BytesInputStream` implementation. The reflection is what required `--add-opens java.base/java.io=jjwt.api` on JDK 17+.
- Refactored `KeysBridge` to perform our own key length logic instead of delegating to `sun.security.util.KeyUtil`.  The reflection is what required `--add-opens java.base/sun.security.util=jjwt.api` on JDK 17+
- Removed `AddOpens.java` due to above refactoring (no longer needed).
- Returned a test-only `--add-opens` for `sun.security.util` for 3 test cases (added to `test.addOpens` maven property)
This commit is contained in:
lhazlewood 2023-10-05 22:13:57 -07:00 committed by GitHub
parent fad6e2737d
commit a7d3d3197c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
32 changed files with 164 additions and 255 deletions

View File

@ -64,7 +64,6 @@ import io.jsonwebtoken.security.UnsupportedKeyException;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
@ -588,18 +587,18 @@ public class DefaultJwtBuilder implements JwtBuilder {
InputStream payloadStream = null; // not needed unless b64 is enabled
if (this.encodePayload) {
encodeAndWrite("JWS Payload", payload, jws);
signingInput = new ByteArrayInputStream(jws.toByteArray());
signingInput = Streams.of(jws.toByteArray());
} else { // b64
// First, ensure we have the base64url header bytes + the SEPARATOR_CHAR byte:
ByteArrayInputStream prefixStream = new ByteArrayInputStream(jws.toByteArray());
InputStream prefixStream = Streams.of(jws.toByteArray());
// Next, b64 extension requires the raw (non-encoded) payload to be included directly in the signing input,
// so we ensure we have an input stream for that:
if (payload.isClaims() || payload.isCompressed()) {
ByteArrayOutputStream claimsOut = new ByteArrayOutputStream(8192);
writeAndClose("JWS Unencoded Payload", payload, claimsOut);
payloadStream = new ByteArrayInputStream(claimsOut.toByteArray());
payloadStream = Streams.of(claimsOut.toByteArray());
} else {
// No claims and not compressed, so just get the direct InputStream:
payloadStream = Assert.stateNotNull(payload.toInputStream(), "Payload InputStream cannot be null.");
@ -698,7 +697,7 @@ public class DefaultJwtBuilder implements JwtBuilder {
if (content.isClaims()) {
ByteArrayOutputStream out = new ByteArrayOutputStream(4096);
writeAndClose("JWE Claims", content, out);
plaintext = new ByteArrayInputStream(out.toByteArray());
plaintext = Streams.of(out.toByteArray());
} else {
plaintext = content.toInputStream();
}

View File

@ -39,6 +39,7 @@ import io.jsonwebtoken.ProtectedHeader;
import io.jsonwebtoken.SigningKeyResolver;
import io.jsonwebtoken.UnsupportedJwtException;
import io.jsonwebtoken.impl.io.AbstractParser;
import io.jsonwebtoken.impl.io.BytesInputStream;
import io.jsonwebtoken.impl.io.CharSequenceReader;
import io.jsonwebtoken.impl.io.JsonObjectDeserializer;
import io.jsonwebtoken.impl.io.Streams;
@ -56,7 +57,6 @@ import io.jsonwebtoken.io.Decoder;
import io.jsonwebtoken.io.DeserializationException;
import io.jsonwebtoken.io.Deserializer;
import io.jsonwebtoken.lang.Assert;
import io.jsonwebtoken.lang.Classes;
import io.jsonwebtoken.lang.Collections;
import io.jsonwebtoken.lang.DateFormats;
import io.jsonwebtoken.lang.Objects;
@ -74,7 +74,6 @@ import io.jsonwebtoken.security.WeakKeyException;
import javax.crypto.SecretKey;
import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.Reader;
@ -315,7 +314,7 @@ public class DefaultJwtParser extends AbstractParser<Jwt<?, ?>> implements JwtPa
bb.rewind();
byte[] data = new byte[bb.remaining()];
bb.get(data);
verificationInput = new ByteArrayInputStream(data);
verificationInput = Streams.of(data);
} else { // b64 extension
ByteBuffer headerBuf = StandardCharsets.US_ASCII.encode(Strings.wrap(tokenized.getProtected()));
headerBuf.rewind();
@ -325,7 +324,7 @@ public class DefaultJwtParser extends AbstractParser<Jwt<?, ?>> implements JwtPa
buf.rewind();
byte[] data = new byte[buf.remaining()];
buf.get(data);
InputStream prefixStream = new ByteArrayInputStream(data);
InputStream prefixStream = Streams.of(data);
payloadStream = payload.toInputStream();
// We wrap the payloadStream here in an UncloseableInputStream to prevent the SequenceInputStream from
// closing it since we'll need to rewind/reset it if decompression is enabled
@ -378,7 +377,7 @@ public class DefaultJwtParser extends AbstractParser<Jwt<?, ?>> implements JwtPa
// =============== Header =================
final byte[] headerBytes = decode(base64UrlHeader, "protected header");
Map<String, ?> m = deserialize(new ByteArrayInputStream(headerBytes), "protected header");
Map<String, ?> m = deserialize(Streams.of(headerBytes), "protected header");
Header header;
try {
header = tokenized.createHeader(m);
@ -517,7 +516,7 @@ public class DefaultJwtParser extends AbstractParser<Jwt<?, ?>> implements JwtPa
ByteBuffer buf = StandardCharsets.US_ASCII.encode(Strings.wrap(base64UrlHeader));
final byte[] aadBytes = new byte[buf.remaining()];
buf.get(aadBytes);
InputStream aad = new ByteArrayInputStream(aadBytes);
InputStream aad = Streams.of(aadBytes);
base64Url = base64UrlDigest;
//guaranteed to be non-empty via the `alg` + digest check above:
@ -834,8 +833,8 @@ public class DefaultJwtParser extends AbstractParser<Jwt<?, ?>> implements JwtPa
}
private static Payload payloadFor(InputStream in) {
if (in instanceof ByteArrayInputStream) {
byte[] data = Classes.getFieldValue(in, "buf", byte[].class);
if (in instanceof BytesInputStream) {
byte[] data = Streams.bytes(in, "Unable to obtain payload InputStream bytes.");
return new Payload(data, null);
}
//if (in.markSupported()) in.mark(0);
@ -874,7 +873,7 @@ public class DefaultJwtParser extends AbstractParser<Jwt<?, ?>> implements JwtPa
protected byte[] decode(CharSequence base64UrlEncoded, String name) {
try {
InputStream decoding = this.decoder.decode(new ByteArrayInputStream(Strings.utf8(base64UrlEncoded)));
InputStream decoding = this.decoder.decode(Streams.of(Strings.utf8(base64UrlEncoded)));
return Streams.bytes(decoding, "Unable to Base64Url-decode input.");
} catch (Throwable t) {
// Don't disclose potentially-sensitive information per https://github.com/jwtk/jjwt/issues/824:

View File

@ -18,13 +18,13 @@ package io.jsonwebtoken.impl;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.CompressionCodec;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.impl.io.Streams;
import io.jsonwebtoken.impl.lang.Bytes;
import io.jsonwebtoken.io.CompressionAlgorithm;
import io.jsonwebtoken.lang.Assert;
import io.jsonwebtoken.lang.Collections;
import io.jsonwebtoken.lang.Strings;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.OutputStream;
@ -68,10 +68,10 @@ class Payload {
}
this.bytes = data;
if (in == null && !Bytes.isEmpty(this.bytes)) {
in = new ByteArrayInputStream(data);
in = Streams.of(data);
}
this.inputStreamEmpty = in == null;
this.inputStream = this.inputStreamEmpty ? new ByteArrayInputStream(Bytes.EMPTY) : in;
this.inputStream = this.inputStreamEmpty ? Streams.of(Bytes.EMPTY) : in;
}
boolean isClaims() {

View File

@ -27,7 +27,6 @@ import io.jsonwebtoken.lang.Assert;
import io.jsonwebtoken.lang.Objects;
import io.jsonwebtoken.lang.Strings;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
@ -152,7 +151,7 @@ public abstract class AbstractCompressionAlgorithm implements CompressionAlgorit
* @throws IOException if the decompression runs into an IO problem
*/
protected byte[] doDecompress(byte[] compressed) throws IOException {
InputStream is = new ByteArrayInputStream(compressed);
InputStream is = Streams.of(compressed);
InputStream decompress = decompress(is);
byte[] buffer = new byte[512];
ByteArrayOutputStream out = new ByteArrayOutputStream(buffer.length);

View File

@ -0,0 +1,43 @@
/*
* Copyright © 2023 jsonwebtoken.io
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jsonwebtoken.impl.io;
import io.jsonwebtoken.impl.lang.Bytes;
import java.io.ByteArrayInputStream;
import java.io.IOException;
/**
* Allows read access to the internal byte array, avoiding the need copy/extract to a
* {@link java.io.ByteArrayOutputStream}.
*
* @since JJWT_RELEASE_VERSION
*/
public final class BytesInputStream extends ByteArrayInputStream {
BytesInputStream(byte[] buf) {
super(Bytes.isEmpty(buf) ? Bytes.EMPTY : buf);
}
public byte[] getBytes() {
return this.buf;
}
@Override
public void close() throws IOException {
reset();
}
}

View File

@ -20,7 +20,6 @@ import io.jsonwebtoken.io.DecodingException;
import io.jsonwebtoken.lang.Assert;
import io.jsonwebtoken.lang.Strings;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
@SuppressWarnings("DeprecatedIsStillUsed")
@ -38,7 +37,7 @@ public class DelegateStringDecoder implements Decoder<InputStream, InputStream>
try {
byte[] data = Streams.bytes(in, "Unable to Base64URL-decode input.");
data = delegate.decode(Strings.utf8(data));
return new ByteArrayInputStream(data);
return Streams.of(data);
} catch (Throwable t) {
String msg = "Unable to Base64Url-decode InputStream: " + t.getMessage();
throw new DecodingException(msg, t);

View File

@ -15,15 +15,12 @@
*/
package io.jsonwebtoken.impl.io;
import io.jsonwebtoken.impl.lang.AddOpens;
import io.jsonwebtoken.impl.lang.Bytes;
import io.jsonwebtoken.lang.Assert;
import io.jsonwebtoken.lang.Classes;
import io.jsonwebtoken.lang.Objects;
import io.jsonwebtoken.lang.Strings;
import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.Flushable;
import java.io.IOException;
@ -43,30 +40,26 @@ public class Streams {
*/
public static final int EOF = -1;
static {
// For reflective access to ByteArrayInputStream via the 'bytes' static method on >= JDK 9:
AddOpens.open("java.base", "java.io");
}
public static byte[] bytes(final InputStream in, String exmsg) {
if (in instanceof ByteArrayInputStream) {
return Classes.getFieldValue(in, "buf", byte[].class);
if (in instanceof BytesInputStream) {
return ((BytesInputStream) in).getBytes();
}
// otherwise we have to copy over:
ByteArrayOutputStream out = new ByteArrayOutputStream(8192);
copy(in, out, new byte[8192], exmsg);
return out.toByteArray();
}
public static ByteArrayInputStream of(byte[] bytes) {
return Bytes.isEmpty(bytes) ? new ByteArrayInputStream(Bytes.EMPTY) : new ByteArrayInputStream(bytes);
public static InputStream of(byte[] bytes) {
return new BytesInputStream(bytes);
}
public static ByteArrayInputStream of(CharSequence seq) {
public static InputStream of(CharSequence seq) {
return of(Strings.utf8(seq));
}
public static Reader reader(byte[] bytes) {
return reader(new ByteArrayInputStream(bytes));
return reader(Streams.of(bytes));
}
public static Reader reader(InputStream in) {

View File

@ -1,128 +0,0 @@
/*
* Copyright 2021 Stefan Zobel
* Copyright © 2023 jsonwebtoken.io
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jsonwebtoken.impl.lang;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
/**
* A utility class that allows to open arbitrary packages to the calling module
* at runtime, so it is a kind of dynamic device for "--add-opens" that could be
* used inside libraries instead of forcing the application to be run with
* command line parameters like "--add-opens java.base/java.util=ALL-UNNAMED" or
* having the "Add-Opens:" entries supplied in the application Jar manifest.
* Note that this still works in the Java 17 GA release, dated 2021-09-14 but it
* may break at any time in the future (theoretically even for a minor
* release!).
*
* @since 0.12.1, gratefully copied from <a href="https://github.com/stefan-zobel/wip/blob/b74e927edddf19a5dce7c8610835f620c0b6f557/src/main/java/misc/AddOpens.java">https://github.com/stefan-zobel/wip/blob/b74e927edddf19a5dce7c8610835f620c0b6f557/src/main/java/misc/AddOpens.java</a>
* under the terms of the Apache 2 open source license (same as the JJWT license).
*/
public final class AddOpens {
// field offset of the override field (Warning: this may change at any time!)
private static final long OVERRIDE_OFFSET = 12;
private static final sun.misc.Unsafe U = getUnsafe();
private AddOpens() {
throw new AssertionError();
}
/**
* Open one or more packages in the given module to the current module. Example
* usage:
*
* <pre>{@code
* boolean success = AddOpens.open("java.base", "java.util", "java.net");
* }</pre>
*
* @param moduleName the module you want to open
* @param packageNames packages in that module you want to be opened
* @return {@code true} if the open operation has succeeded for all packages,
* otherwise {@code false}
*/
public static boolean open(String moduleName, String... packageNames) {
// Use reflection so that this code can run on Java 8
Class<?> javaLangModule;
try {
javaLangModule = Class.forName("java.lang.Module");
} catch (Throwable t) {
// we must be < Java 9
return true;
}
try {
// the module we are currently running in (either named or unnamed)
Object thisModule = getCurrentModule();
// find the module to open
Object targetModule = findModule(moduleName);
// get the method that is also used by "--add-opens"
Method m = javaLangModule.getDeclaredMethod("implAddOpens", String.class, javaLangModule);
// override language-level access checks
setAccessible(m);
// open given packages in the target module to this module
for (String package_ : packageNames) {
m.invoke(targetModule, package_, thisModule);
}
return true;
} catch (Throwable ignore) {
return false;
}
}
private static Object findModule(String moduleName) {
// Use reflection so that this code can run on Java 8
try {
Class<?> moduleLayerClass = Class.forName("java.lang.ModuleLayer");
Method bootMethod = moduleLayerClass.getDeclaredMethod("boot");
Object bootLayer = bootMethod.invoke(null);
Method findModuleMethod = moduleLayerClass.getDeclaredMethod("findModule", String.class);
Object optionalModule = findModuleMethod.invoke(bootLayer, moduleName);
Class<?> optionalClass = Class.forName("java.util.Optional");
Method getMethod = optionalClass.getDeclaredMethod("get");
return getMethod.invoke(optionalModule);
} catch (Throwable t) {
return null;
}
}
private static Object getCurrentModule() {
// Use reflection so that this code can run on Java 8
try {
Method m = Class.class.getDeclaredMethod("getModule");
setAccessible(m);
return m.invoke(AddOpens.class);
} catch (Throwable t) {
return null;
}
}
private static void setAccessible(Method method) {
if (U != null) {
U.putBoolean(method, OVERRIDE_OFFSET, true);
}
}
private static sun.misc.Unsafe getUnsafe() {
try {
Field unsafe = sun.misc.Unsafe.class.getDeclaredField("theUnsafe");
unsafe.setAccessible(true);
return (sun.misc.Unsafe) unsafe.get(null);
} catch (Throwable ignore) {
return null;
}
}
}

View File

@ -15,6 +15,7 @@
*/
package io.jsonwebtoken.impl.security;
import io.jsonwebtoken.impl.io.Streams;
import io.jsonwebtoken.impl.lang.Nameable;
import io.jsonwebtoken.impl.lang.Parameter;
import io.jsonwebtoken.impl.lang.ParameterReadable;
@ -31,7 +32,6 @@ import io.jsonwebtoken.security.JwkThumbprint;
import io.jsonwebtoken.security.Jwks;
import io.jsonwebtoken.security.KeyOperation;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.security.Key;
@ -152,7 +152,7 @@ public abstract class AbstractJwk<K extends Key> implements Jwk<K>, ParameterRea
String json = toThumbprintJson();
Assert.hasText(json, "Canonical JWK Thumbprint JSON cannot be null or empty.");
byte[] bytes = json.getBytes(StandardCharsets.UTF_8); // https://www.rfc-editor.org/rfc/rfc7638#section-3 #2
InputStream in = new ByteArrayInputStream(bytes);
InputStream in = Streams.of(bytes);
byte[] digest = alg.digest(new DefaultRequest<>(in, this.context.getProvider(), this.context.getRandom()));
return new DefaultJwkThumbprint(digest, alg);
}

View File

@ -135,9 +135,8 @@ final class DefaultMacAlgorithm extends AbstractSecureDigestAlgorithm<SecretKey,
throw new InvalidKeyException(msg);
}
// We can ignore PKCS11 key name assertions for two reasons:
// 1. HSM module key algorithm names don't always align with JCA standard algorithm names, and
// 2. Our KeysBridge.findBitLength implementation can extract the key length so we can still validate with that
// We can ignore PKCS11 key name assertions because HSM module key algorithm names don't always align with
// JCA standard algorithm names:
boolean pkcs11Key = KeysBridge.isSunPkcs11GenericSecret(key);
//assert key's jca name is valid if it's a JWA standard algorithm:

View File

@ -26,7 +26,6 @@ import io.jsonwebtoken.security.DecryptAeadRequest;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.SequenceInputStream;
@ -93,7 +92,7 @@ public class GcmAesAeadAlgorithm extends AesAlgorithm implements AeadAlgorithm {
final AlgorithmParameterSpec ivSpec = getIvSpec(iv);
//for tagged GCM, the JCA spec requires that the tag be appended to the end of the ciphertext byte array:
final InputStream taggedCiphertext = new SequenceInputStream(ciphertext, new ByteArrayInputStream(tag));
final InputStream taggedCiphertext = new SequenceInputStream(ciphertext, Streams.of(tag));
jca(req).withCipher(new CheckedFunction<Cipher, byte[]>() {
@Override

View File

@ -31,7 +31,6 @@ import io.jsonwebtoken.security.SignatureException;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
@ -145,11 +144,11 @@ public class HmacAesAeadAlgorithm extends AesAlgorithm implements AeadAlgorithm
Collection<InputStream> streams = new ArrayList<>(4);
if (!Bytes.isEmpty(aad)) { // must come first if it exists
streams.add(new ByteArrayInputStream(aad));
streams.add(Streams.of(aad));
}
streams.add(new ByteArrayInputStream(iv));
streams.add(Streams.of(iv));
streams.add(ciphertext);
streams.add(new ByteArrayInputStream(AL));
streams.add(Streams.of(AL));
InputStream in = new SequenceInputStream(Collections.enumeration(streams));
SecretKey key = new SecretKeySpec(macKeyBytes, SIGALG.getJcaName());

View File

@ -16,6 +16,7 @@
package io.jsonwebtoken.impl.security;
import io.jsonwebtoken.Identifiable;
import io.jsonwebtoken.impl.io.Streams;
import io.jsonwebtoken.impl.lang.Bytes;
import io.jsonwebtoken.impl.lang.CheckedFunction;
import io.jsonwebtoken.impl.lang.CheckedSupplier;
@ -36,7 +37,6 @@ import javax.crypto.Mac;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.security.AlgorithmParameters;
import java.security.InvalidAlgorithmParameterException;
@ -332,7 +332,7 @@ public class JcaTemplate {
return fallback(CertificateFactory.class, new CheckedFunction<CertificateFactory, X509Certificate>() {
@Override
public X509Certificate apply(CertificateFactory cf) throws CertificateException {
InputStream is = new ByteArrayInputStream(x509DerBytes);
InputStream is = Streams.of(x509DerBytes);
return (X509Certificate) cf.generateCertificate(is);
}
});

View File

@ -15,9 +15,7 @@
*/
package io.jsonwebtoken.impl.security;
import io.jsonwebtoken.impl.lang.AddOpens;
import io.jsonwebtoken.impl.lang.Bytes;
import io.jsonwebtoken.impl.lang.OptionalMethodInvoker;
import io.jsonwebtoken.lang.Assert;
import io.jsonwebtoken.lang.Strings;
import io.jsonwebtoken.security.InvalidKeyException;
@ -30,6 +28,8 @@ import javax.crypto.SecretKey;
import java.security.Key;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.interfaces.ECKey;
import java.security.interfaces.RSAKey;
@SuppressWarnings({"unused"}) // reflection bridge class for the io.jsonwebtoken.security.Keys implementation
public final class KeysBridge {
@ -37,16 +37,6 @@ public final class KeysBridge {
private static final String SUNPKCS11_GENERIC_SECRET_CLASSNAME = "sun.security.pkcs11.P11Key$P11SecretKey";
private static final String SUNPKCS11_GENERIC_SECRET_ALGNAME = "Generic Secret"; // https://github.com/openjdk/jdk/blob/4f90abaf17716493bad740dcef76d49f16d69379/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11KeyStore.java#L1292
private static final String SUN_KEYUTIL_CLASSNAME = "sun.security.util.KeyUtil";
private static final OptionalMethodInvoker<Key, Integer> SUN_KEYSIZE =
new OptionalMethodInvoker<>(SUN_KEYUTIL_CLASSNAME, "getKeySize", Key.class, true);
private static final String SUN_KEYUTIL_ERR = "Unexpected " + SUN_KEYUTIL_CLASSNAME + " invocation error.";
static {
// For reflective access to KeyUtil on >= JDK 9:
AddOpens.open("java.base", "sun.security.util");
}
// prevent instantiation
private KeysBridge() {
}
@ -119,23 +109,29 @@ public final class KeysBridge {
*/
public static int findBitLength(Key key) {
Integer retval = SUN_KEYSIZE.apply(key);
int bitlen = Assert.stateNotNull(retval, SUN_KEYUTIL_ERR);
int bitlen = -1;
// SunPKCS11 SecretKey lengths are unfortunately reported in bytes, not bits
// per https://bugs.openjdk.org/browse/JDK-8163173
// (they should be multiplying the PKCS11 CKA_VALUE_LEN value by 8 since their own
// sun.security.util.Length#getLength() JavaDoc states that values are intended to be in bits, not bytes)
// So we account for that here:
if (bitlen > 0 && isSunPkcs11GenericSecret(key)) {
bitlen *= Byte.SIZE;
// try to parse the length from key specification
if (key instanceof SecretKey) {
SecretKey secretKey = (SecretKey) key;
if ("RAW".equals(secretKey.getFormat())) {
byte[] encoded = findEncoded(secretKey);
if (!Bytes.isEmpty(encoded)) {
bitlen = (int) Bytes.bitLength(encoded);
Bytes.clear(encoded);
}
if (bitlen > 0) return bitlen;
}
} else if (key instanceof RSAKey) {
RSAKey rsaKey = (RSAKey) key;
bitlen = rsaKey.getModulus().bitLength();
} else if (key instanceof ECKey) {
ECKey ecKey = (ECKey) key;
bitlen = ecKey.getParams().getOrder().bitLength();
} else {
// We can check additional logic for EdwardsCurve even if the current JDK version doesn't support it:
EdwardsCurve curve = EdwardsCurve.findByKey(key);
if (curve != null) bitlen = curve.getKeyBitLength();
}
return bitlen;
}

View File

@ -16,6 +16,7 @@
package io.jsonwebtoken.impl.security;
import io.jsonwebtoken.impl.ParameterMap;
import io.jsonwebtoken.impl.io.Streams;
import io.jsonwebtoken.impl.lang.CheckedFunction;
import io.jsonwebtoken.impl.lang.Function;
import io.jsonwebtoken.impl.lang.Functions;
@ -27,7 +28,6 @@ import io.jsonwebtoken.security.Jwks;
import io.jsonwebtoken.security.Request;
import io.jsonwebtoken.security.X509Builder;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.net.URI;
import java.security.cert.X509Certificate;
@ -99,7 +99,7 @@ public class X509BuilderSupport implements X509Builder<X509BuilderSupport> {
private byte[] computeThumbprint(final X509Certificate cert, HashAlgorithm alg) {
byte[] encoded = GET_X509_BYTES.apply(cert);
InputStream in = new ByteArrayInputStream(encoded);
InputStream in = Streams.of(encoded);
Request<InputStream> request = new DefaultRequest<>(in, null, null);
return alg.digest(request);
}

View File

@ -18,6 +18,7 @@ package io.jsonwebtoken
import io.jsonwebtoken.SignatureAlgorithm
import io.jsonwebtoken.impl.*
import io.jsonwebtoken.impl.compression.GzipCompressionAlgorithm
import io.jsonwebtoken.impl.io.Streams
import io.jsonwebtoken.impl.lang.Bytes
import io.jsonwebtoken.impl.lang.Services
import io.jsonwebtoken.impl.security.*
@ -141,7 +142,7 @@ class JwtsTest {
def h = base64Url('{"alg":"HS256"}')
def c = base64Url('{"sub":"joe","exp":"-42-"}')
def data = Strings.utf8(("$h.$c" as String))
def payload = new ByteArrayInputStream(data)
def payload = Streams.of(data)
def request = new DefaultSecureRequest<>(payload, null, null, key)
def result = Jwts.SIG.HS256.digest(request)
def sig = Encoders.BASE64URL.encode(result)
@ -191,7 +192,7 @@ class JwtsTest {
@Test
void testContentStreamWithContentType() {
String s = 'Hello JJWT'
InputStream content = new ByteArrayInputStream(Strings.utf8(s))
InputStream content = Streams.of(Strings.utf8(s))
String cty = 'text/plain'
String compact = Jwts.builder().content(content, cty).compact()
def jwt = Jwts.parser().unsecured().build().parseUnsecuredContent(compact)
@ -202,7 +203,7 @@ class JwtsTest {
@Test
void testContentStreamWithoutContentType() {
String s = 'Hello JJWT'
InputStream content = new ByteArrayInputStream(Strings.utf8(s))
InputStream content = Streams.of(Strings.utf8(s))
String compact = Jwts.builder().content(content).compact()
def jwt = Jwts.parser().unsecured().build().parseUnsecuredContent(compact)
assertNull jwt.header.getContentType()

View File

@ -17,6 +17,7 @@ package io.jsonwebtoken
import io.jsonwebtoken.impl.DefaultJwsHeader
import io.jsonwebtoken.impl.DefaultJwtParser
import io.jsonwebtoken.impl.io.Streams
import io.jsonwebtoken.impl.lang.Bytes
import io.jsonwebtoken.impl.lang.Services
import io.jsonwebtoken.impl.security.TestKeys
@ -69,8 +70,8 @@ class RFC7797Test {
String s = Jwts.builder().signWith(key).content(content).encodePayload(false).compact()
// But verify with 3 types of sources: string, byte array, and two different kinds of InputStreams:
InputStream asByteInputStream = new ByteArrayInputStream(content)
InputStream asBufferedInputStream = new BufferedInputStream(new ByteArrayInputStream(content))
InputStream asByteInputStream = Streams.of(content)
InputStream asBufferedInputStream = new BufferedInputStream(Streams.of(content))
for (def payload : [content, asByteInputStream, asBufferedInputStream]) {
def parser = Jwts.parser().verifyWith(key).build()
@ -107,8 +108,8 @@ class RFC7797Test {
String s = Jwts.builder().signWith(key).content(content).encodePayload(false).compact()
// But verify with 3 types of sources: string, byte array, and two different kinds of InputStreams:
InputStream asByteInputStream = new ByteArrayInputStream(content)
InputStream asBufferedInputStream = new BufferedInputStream(new ByteArrayInputStream(content))
InputStream asByteInputStream = Streams.of(content)
InputStream asBufferedInputStream = new BufferedInputStream(Streams.of(content))
for (def payload : [content, asByteInputStream, asBufferedInputStream]) {
def parser = Jwts.parser().verifyWith(key).build()
@ -128,13 +129,13 @@ class RFC7797Test {
def key = TestKeys.HS256
byte[] content = Strings.utf8('$.02') // https://datatracker.ietf.org/doc/html/rfc7797#section-4.2
InputStream contentStream = new ByteArrayInputStream(content)
InputStream contentStream = Streams.of(content)
String s = Jwts.builder().signWith(key).content(contentStream).encodePayload(false).compact()
// But verify with 3 types of sources: byte array, and two different kinds of InputStreams:
InputStream asByteInputStream = new ByteArrayInputStream(content)
InputStream asBufferedInputStream = new BufferedInputStream(new ByteArrayInputStream(content))
InputStream asByteInputStream =Streams.of(content)
InputStream asBufferedInputStream = new BufferedInputStream(Streams.of(content))
for (def payload : [content, asByteInputStream, asBufferedInputStream]) {
def parser = Jwts.parser().verifyWith(key).build()
@ -348,8 +349,8 @@ class RFC7797Test {
.compact()
// But verify with 3 types of sources: byte array, and two different kinds of InputStreams:
InputStream asByteInputStream = new ByteArrayInputStream(compressed)
InputStream asBufferedInputStream = new BufferedInputStream(new ByteArrayInputStream(compressed))
InputStream asByteInputStream = Streams.of(compressed)
InputStream asBufferedInputStream = new BufferedInputStream(Streams.of(compressed))
for (def payload : [compressed, asByteInputStream, asBufferedInputStream]) {
def parser = Jwts.parser().verifyWith(key).build()

View File

@ -16,6 +16,7 @@
package io.jsonwebtoken.impl
import io.jsonwebtoken.Jwts
import io.jsonwebtoken.impl.io.Streams
import io.jsonwebtoken.impl.lang.Bytes
import io.jsonwebtoken.impl.security.DefaultHashAlgorithm
import io.jsonwebtoken.impl.security.DefaultRequest
@ -269,7 +270,7 @@ class DefaultMutableJweHeaderTest {
*/
@Test
void testX509Sha1Thumbprint() {
def payload = new ByteArrayInputStream(TestKeys.RS256.cert.getEncoded())
def payload = Streams.of(TestKeys.RS256.cert.getEncoded())
def request = new DefaultRequest(payload, null, null)
def x5t = DefaultHashAlgorithm.SHA1.digest(request)
String encoded = Encoders.BASE64URL.encode(x5t)
@ -285,7 +286,7 @@ class DefaultMutableJweHeaderTest {
*/
@Test
void testX509Sha256Thumbprint() {
def payload = new ByteArrayInputStream(TestKeys.RS256.cert.getEncoded())
def payload = Streams.of(TestKeys.RS256.cert.getEncoded())
def request = new DefaultRequest(payload, null, null)
def x5tS256 = Jwks.HASH.@SHA256.digest(request)
String encoded = Encoders.BASE64URL.encode(x5tS256)

View File

@ -25,7 +25,7 @@ class CountingInputStreamTest {
@Test
void readEmpty() {
def stream = new CountingInputStream(new ByteArrayInputStream(Bytes.EMPTY))
def stream = new CountingInputStream(Streams.of(Bytes.EMPTY))
stream.read()
assertEquals 0, stream.getCount()
}
@ -34,7 +34,7 @@ class CountingInputStreamTest {
void readSingle() {
def single = (byte) 0x18 // any random byte is fine
def data = new byte[1]; data[0] = single
def stream = new CountingInputStream(new ByteArrayInputStream(data))
def stream = new CountingInputStream(Streams.of(data))
assertEquals single, stream.read()
assertEquals 1, stream.getCount()
}
@ -42,7 +42,7 @@ class CountingInputStreamTest {
@Test
void testSkip() {
def data = Strings.utf8('hello world')
def stream = new CountingInputStream(new ByteArrayInputStream(data))
def stream = new CountingInputStream(Streams.of(data))
stream.skip(6)
assertEquals 6, stream.getCount()
int w = ('w' as char)

View File

@ -29,7 +29,7 @@ class DelegateStringDecoderTest {
void decode() {
def value = 'test'
def bytes = Strings.utf8(value)
def ins = new ByteArrayInputStream(bytes)
def ins = Streams.of(bytes)
def test = new Decoder<CharSequence, byte[]>() {
@Override
byte[] decode(CharSequence s) throws DecodingException {

View File

@ -15,6 +15,7 @@
*/
package io.jsonwebtoken.impl.security
import io.jsonwebtoken.impl.io.Streams
import io.jsonwebtoken.io.Encoders
import io.jsonwebtoken.security.*
import org.junit.Test
@ -64,7 +65,7 @@ class AbstractAsymmetricJwkBuilderTest {
@Test
void testX509CertificateSha1Thumbprint() {
def payload = new ByteArrayInputStream(TestKeys.RS256.cert.getEncoded())
def payload = Streams.of(TestKeys.RS256.cert.getEncoded())
Request<byte[]> request = new DefaultRequest(payload, null, null)
def x5t = DefaultHashAlgorithm.SHA1.digest(request)
def encoded = Encoders.BASE64URL.encode(x5t)
@ -75,7 +76,7 @@ class AbstractAsymmetricJwkBuilderTest {
@Test
void testX509CertificateSha1ThumbprintEnabled() {
def payload = new ByteArrayInputStream(TestKeys.RS256.cert.getEncoded())
def payload = Streams.of(TestKeys.RS256.cert.getEncoded())
Request<byte[]> request = new DefaultRequest(payload, null, null)
def x5t = DefaultHashAlgorithm.SHA1.digest(request)
def encoded = Encoders.BASE64URL.encode(x5t)
@ -86,7 +87,7 @@ class AbstractAsymmetricJwkBuilderTest {
@Test
void testX509CertificateSha256Thumbprint() {
def payload = new ByteArrayInputStream(TestKeys.RS256.cert.getEncoded())
def payload = Streams.of(TestKeys.RS256.cert.getEncoded())
Request<byte[]> request = new DefaultRequest(payload, null, null)
def x5tS256 = Jwks.HASH.SHA256.digest(request)
def encoded = Encoders.BASE64URL.encode(x5tS256)
@ -97,7 +98,7 @@ class AbstractAsymmetricJwkBuilderTest {
@Test
void testX509CertificateSha256ThumbprintEnabled() {
def payload = new ByteArrayInputStream(TestKeys.RS256.cert.getEncoded())
def payload = Streams.of(TestKeys.RS256.cert.getEncoded())
Request<InputStream> request = new DefaultRequest(payload, null, null)
def x5tS256 = Jwks.HASH.SHA256.digest(request)
def encoded = Encoders.BASE64URL.encode(x5tS256)

View File

@ -16,6 +16,7 @@
package io.jsonwebtoken.impl.security
import io.jsonwebtoken.Jwts
import io.jsonwebtoken.impl.io.Streams
import io.jsonwebtoken.lang.Strings
import io.jsonwebtoken.security.SecureRequest
import io.jsonwebtoken.security.SignatureException
@ -37,7 +38,7 @@ class AbstractSecureDigestAlgorithmTest {
Provider provider = Security.getProvider('BC')
def pair = Jwts.SIG.RS256.keyPair().build()
byte[] data = Strings.utf8('foo')
def payload = new ByteArrayInputStream(data)
def payload = Streams.of(data)
byte[] signature = Jwts.SIG.RS256.digest(new DefaultSecureRequest<>(payload, provider, null, pair.getPrivate()))
payload.reset()
assertTrue Jwts.SIG.RS256.verify(new DefaultVerifySecureDigestRequest<PublicKey>(payload, provider, null, pair.getPublic(), signature))
@ -54,7 +55,7 @@ class AbstractSecureDigestAlgorithmTest {
}
}
try {
def payload = new ByteArrayInputStream(Strings.utf8('foo'))
def payload = Streams.of(Strings.utf8('foo'))
alg.digest(new DefaultSecureRequest(payload, null, null, pair.getPrivate()))
} catch (SignatureException e) {
assertTrue e.getMessage().startsWith('Unable to compute test signature with JCA algorithm \'test\' using key {')
@ -74,7 +75,7 @@ class AbstractSecureDigestAlgorithmTest {
}
}
def data = Strings.utf8('foo')
def payload = new ByteArrayInputStream(data)
def payload = Streams.of(data)
try {
byte[] signature = alg.digest(new DefaultSecureRequest(payload, null, null, pair.getPrivate()))
payload.reset()

View File

@ -15,6 +15,7 @@
*/
package io.jsonwebtoken.impl.security
import io.jsonwebtoken.impl.io.Streams
import io.jsonwebtoken.lang.Strings
import io.jsonwebtoken.security.HashAlgorithm
import io.jsonwebtoken.security.Jwks
@ -29,7 +30,7 @@ class DefaultHashAlgorithmTest {
@Test
void testDigestAndVerify() {
byte[] data = Strings.utf8('Hello World')
InputStream payload = new ByteArrayInputStream(data)
InputStream payload = Streams.of(data)
for (HashAlgorithm alg : algs) {
byte[] hash = alg.digest(new DefaultRequest<>(payload, null, null))
payload.reset()

View File

@ -17,6 +17,7 @@ package io.jsonwebtoken.impl.security
import io.jsonwebtoken.impl.io.CharSequenceReader
import io.jsonwebtoken.impl.io.ConvertingParser
import io.jsonwebtoken.impl.io.Streams
import io.jsonwebtoken.io.AbstractDeserializer
import io.jsonwebtoken.io.DeserializationException
import io.jsonwebtoken.io.Deserializer
@ -133,7 +134,7 @@ class DefaultJwkParserBuilderTest {
assertEquals jwk, parsed
// InputStream parsing:
parsed = parser.parse(new ByteArrayInputStream(Strings.utf8(json)))
parsed = parser.parse(Streams.of(json))
assertEquals jwk, parsed
}
}

View File

@ -15,6 +15,7 @@
*/
package io.jsonwebtoken.impl.security
import io.jsonwebtoken.impl.io.Streams
import io.jsonwebtoken.io.Encoders
import io.jsonwebtoken.lang.Strings
import io.jsonwebtoken.security.HashAlgorithm
@ -30,7 +31,7 @@ class DefaultJwkThumbprintTest {
private static String content = "Hello World"
private static HashAlgorithm alg = Jwks.HASH.SHA256
private static byte[] digest = alg.digest(new DefaultRequest<InputStream>(new ByteArrayInputStream(Strings.utf8(content)), null, null))
private static byte[] digest = alg.digest(new DefaultRequest<InputStream>(Streams.of(content), null, null))
private static String expectedToString = Encoders.BASE64URL.encode(digest)
private static String expectedUriString = DefaultJwkThumbprint.URI_PREFIX + alg.getId() + ":" + expectedToString
private static URI expectedUri = URI.create(expectedUriString)
@ -81,7 +82,7 @@ class DefaultJwkThumbprintTest {
assertFalse thumbprint == new DefaultJwkThumbprint(digest, DefaultHashAlgorithm.SHA1)
// same alg, different digest:
def payload = new ByteArrayInputStream(Strings.utf8('Hello World!'))
def payload = Streams.of(Strings.utf8('Hello World!'))
byte[] digest2 = alg.digest(new DefaultRequest<>(payload, null, null))
assertFalse thumbprint == new DefaultJwkThumbprint(digest2, DefaultHashAlgorithm.SHA1)
}

View File

@ -169,7 +169,7 @@ class EcSignatureAlgorithmTest {
@Test
void testVerifyWithPrivateKey() {
byte[] data = 'foo'.getBytes(StandardCharsets.UTF_8)
def payload = new ByteArrayInputStream(data)
def payload = Streams.of(data)
algs().each {
payload.reset()
def pair = it.keyPair().build()
@ -194,7 +194,7 @@ class EcSignatureAlgorithmTest {
BigInteger order = BigInteger.ONE
ECParameterSpec spec = new ECParameterSpec(new EllipticCurve(new TestECField(), BigInteger.ONE, BigInteger.ONE), new ECPoint(BigInteger.ONE, BigInteger.ONE), order, 1)
ECPublicKey pub = new TestECPublicKey(algorithm: 'EC', params: spec)
def request = new DefaultVerifySecureDigestRequest(new ByteArrayInputStream(new byte[1]), null, null, pub, new byte[1])
def request = new DefaultVerifySecureDigestRequest(Streams.of(new byte[1]), null, null, pub, new byte[1])
try {
it.verify(request)
} catch (InvalidKeyException expected) {
@ -310,7 +310,7 @@ class EcSignatureAlgorithmTest {
def signatureStart = token.lastIndexOf('.')
def withoutSignature = token.substring(0, signatureStart)
def data = Strings.ascii(withoutSignature);
def payload = new ByteArrayInputStream(data)
def payload = Streams.of(data)
def signature = Decoders.BASE64URL.decode(token.substring(signatureStart + 1))
assertTrue "Signature do not match that of other implementations", alg.verify(new DefaultVerifySecureDigestRequest(payload, null, null, pub, signature))
}
@ -329,7 +329,7 @@ class EcSignatureAlgorithmTest {
assertTrue keypair.getPublic() instanceof ECPublicKey
assertTrue keypair.getPrivate() instanceof ECPrivateKey
def data = Strings.ascii(withoutSignature)
def payload = new ByteArrayInputStream(data)
def payload = Streams.of(data)
def signature = alg.digest(new DefaultSecureRequest<>(payload, null, null, keypair.private))
payload.reset()
assertTrue alg.verify(new DefaultVerifySecureDigestRequest(payload, null, null, keypair.public, signature))
@ -473,7 +473,7 @@ class EcSignatureAlgorithmTest {
def signature = token.substring(signatureStart + 1)
def data = withoutSignature.getBytes(StandardCharsets.US_ASCII)
def payload = new ByteArrayInputStream(data)
def payload = Streams.of(data)
def sigBytes = Decoders.BASE64URL.decode(signature)
def request = new DefaultVerifySecureDigestRequest(payload, null, null, pub, sigBytes)
assert alg.verify(request), "Signature do not match that of other implementations"
@ -495,7 +495,7 @@ class EcSignatureAlgorithmTest {
signature.initSign(keypair.private)
signature.update(data)
def signed = signature.sign()
def request = new DefaultVerifySecureDigestRequest(new ByteArrayInputStream(data), null, null, keypair.public, signed)
def request = new DefaultVerifySecureDigestRequest(Streams.of(data), null, null, keypair.public, signed)
try {
alg.verify(request)
fail()
@ -519,7 +519,7 @@ class EcSignatureAlgorithmTest {
def keypair = alg.keyPair().build()
def signature = Signature.getInstance(alg.jcaName as String)
def data = Strings.ascii(withoutSignature)
def payload = new ByteArrayInputStream(data)
def payload = Streams.of(data)
signature.initSign(keypair.private)
signature.update(data)
def signed = signature.sign()
@ -538,7 +538,7 @@ class EcSignatureAlgorithmTest {
def alg = Jwts.SIG.ES256
def keypair = alg.keyPair().build()
def data = Strings.ascii(withoutSignature)
def payload = new ByteArrayInputStream(data)
def payload = Streams.of(data)
def request = new DefaultVerifySecureDigestRequest(payload, null, null, keypair.public, forgedSig)
assertFalse alg.verify(request)
}
@ -556,7 +556,7 @@ class EcSignatureAlgorithmTest {
def alg = Jwts.SIG.ES256
def keypair = alg.keyPair().build()
def data = Strings.ascii(withoutSignature)
def payload = new ByteArrayInputStream(data)
def payload = Streams.of(data)
def request = new DefaultVerifySecureDigestRequest(payload, null, null, keypair.public, sig)
assertFalse alg.verify(request)
}
@ -574,7 +574,7 @@ class EcSignatureAlgorithmTest {
def alg = Jwts.SIG.ES256
def keypair = alg.keyPair().build()
def data = Strings.ascii(withoutSignature)
def payload = new ByteArrayInputStream(data)
def payload = Streams.of(data)
def request = new DefaultVerifySecureDigestRequest(payload, null, null, keypair.public, sig)
assertFalse alg.verify(request)
}
@ -587,7 +587,7 @@ class EcSignatureAlgorithmTest {
def alg = Jwts.SIG.ES256
def keypair = alg.keyPair().build()
def data = Strings.ascii(withoutSignature)
def payload = new ByteArrayInputStream(data)
def payload = Streams.of(data)
def invalidSignature = Decoders.BASE64URL.decode(invalidEncodedSignature)
def request = new DefaultVerifySecureDigestRequest(payload, null, null, keypair.public, invalidSignature)
assertFalse("Forged signature must not be considered valid.", alg.verify(request))

View File

@ -60,7 +60,7 @@ class GcmAesAeadAlgorithmTest {
def alg = Jwts.ENC.A256GCM
def ins = new ByteArrayInputStream(P)
def ins = Streams.of(P)
def aad = Streams.of(AAD)
def out = new ByteArrayOutputStream(8192)
def res = new DefaultAeadResult(out)

View File

@ -15,6 +15,7 @@
*/
package io.jsonwebtoken.impl.security
import io.jsonwebtoken.impl.io.Streams
import io.jsonwebtoken.lang.Registry
import io.jsonwebtoken.security.HashAlgorithm
import io.jsonwebtoken.security.Jwks
@ -80,7 +81,7 @@ class HashAlgorithmsTest {
static DefaultRequest<InputStream> request(String msg) {
byte[] data = msg.getBytes(StandardCharsets.UTF_8)
InputStream payload = new ByteArrayInputStream(data)
InputStream payload = Streams.of(data)
return new DefaultRequest<InputStream>(payload, null, null)
}

View File

@ -15,6 +15,7 @@
*/
package io.jsonwebtoken.impl.security
import io.jsonwebtoken.impl.io.Streams
import io.jsonwebtoken.impl.lang.Bytes
import io.jsonwebtoken.impl.lang.CheckedFunction
import io.jsonwebtoken.lang.Classes
@ -347,7 +348,7 @@ class JcaTemplateTest {
X509Certificate cert = template.withCertificateFactory(new CheckedFunction<CertificateFactory, X509Certificate>() {
@Override
X509Certificate apply(CertificateFactory certificateFactory) throws Exception {
(X509Certificate)certificateFactory.generateCertificate(new ByteArrayInputStream(expected.getEncoded()))
(X509Certificate) certificateFactory.generateCertificate(Streams.of(expected.getEncoded()))
}
})
assertEquals expected, cert

View File

@ -16,13 +16,13 @@
package io.jsonwebtoken.impl.security
import io.jsonwebtoken.impl.RfcTests
import io.jsonwebtoken.impl.io.Streams
import io.jsonwebtoken.security.HashAlgorithm
import io.jsonwebtoken.security.JwkThumbprint
import io.jsonwebtoken.security.Jwks
import org.junit.Test
import javax.crypto.SecretKey
import java.nio.charset.StandardCharsets
import static io.jsonwebtoken.impl.security.DefaultHashAlgorithm.SHA1
import static org.junit.Assert.assertEquals
@ -32,8 +32,7 @@ class JwkThumbprintsTest {
static final HashAlgorithm SHA256 = Jwks.HASH.@SHA256
static byte[] digest(String json, HashAlgorithm alg) {
def utf8Bytes = json.getBytes(StandardCharsets.UTF_8)
def payload = new ByteArrayInputStream(utf8Bytes);
def payload = Streams.of(json)
def req = new DefaultRequest(payload, null, null)
return alg.digest(req)
}

View File

@ -121,7 +121,7 @@ class EncryptionAlgorithmsTest {
assertEquals(ciphertextBytes.length, PLAINTEXT_BYTES.length)
}
def ciphertext = new ByteArrayInputStream(ciphertextBytes)
def ciphertext = Streams.of(ciphertextBytes)
out = new ByteArrayOutputStream(8192)
def dreq = new DefaultDecryptAeadRequest(ciphertext, key, null, iv, tag)
alg.decrypt(dreq, out)
@ -155,7 +155,7 @@ class EncryptionAlgorithmsTest {
assertEquals(ciphertextBytes.length, PLAINTEXT_BYTES.length)
}
def ciphertext = new ByteArrayInputStream(ciphertextBytes)
def ciphertext = Streams.of(ciphertextBytes)
out = new ByteArrayOutputStream(8192)
def dreq = new DefaultDecryptAeadRequest(ciphertext, key, aad, iv, tag)
alg.decrypt(dreq, out)

View File

@ -133,7 +133,10 @@
<test.addOpens>
--add-opens java.base/java.lang=ALL-UNNAMED, <!-- Needed by EasyMock/cglib -->
--add-opens java.desktop/java.beans=ALL-UNNAMED, <!-- Needed by EasyMock/cglib -->
--add-opens java.base/java.lang.ref=ALL-UNNAMED <!-- Needed by PowerMock -->
--add-opens java.base/java.lang.ref=ALL-UNNAMED, <!-- Needed by PowerMock -->
<!-- needed by KeysImplTest.testKeyPairFor, KeysTest.testDeprecatedKeyPairFor, and
KeysTest.testKeyPairBuilder: -->
--add-opens java.base/sun.security.util=ALL-UNNAMED
</test.addOpens>
</properties>