mirror of
https://github.com/openjdk/jdk.git
synced 2026-08-03 06:35:31 +00:00
Merge
Reviewed-by: prr, kcr
This commit is contained in:
commit
9efe2ddd38
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -68,7 +68,7 @@ class JarVerifier {
|
||||
private ArrayList<SignatureFileVerifier> pendingBlocks;
|
||||
|
||||
/* cache of CodeSigner objects */
|
||||
private ArrayList<CodeSigner[]> signerCache;
|
||||
private List<CodeSigner[]> signerCache;
|
||||
|
||||
/* Are we parsing a block? */
|
||||
private boolean parsingBlockOrSF = false;
|
||||
@ -288,7 +288,7 @@ class JarVerifier {
|
||||
String key = uname.substring(0, uname.lastIndexOf('.'));
|
||||
|
||||
if (signerCache == null)
|
||||
signerCache = new ArrayList<>();
|
||||
signerCache = new LinkedList<>();
|
||||
|
||||
if (manDig == null) {
|
||||
synchronized(manifestRawBytes) {
|
||||
|
||||
@ -571,8 +571,8 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
|
||||
throws ProtocolException {
|
||||
lock();
|
||||
try {
|
||||
if (connecting) {
|
||||
throw new IllegalStateException("connect in progress");
|
||||
if (connected || connecting) {
|
||||
throw new IllegalStateException("Already connected");
|
||||
}
|
||||
super.setRequestMethod(method);
|
||||
} finally {
|
||||
|
||||
@ -178,7 +178,7 @@ public abstract class AbstractDelegateHttpsURLConnection extends
|
||||
public void connect() throws IOException {
|
||||
if (connected)
|
||||
return;
|
||||
plainConnect();
|
||||
super.connect();
|
||||
if (cachedResponse != null) {
|
||||
// using cached response
|
||||
return;
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1996, 2026, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -341,6 +341,21 @@ public class SignerInfo implements DerEncoder {
|
||||
// if there are authenticated attributes, get the message
|
||||
// digest and compare it with the digest of data
|
||||
if (authenticatedAttributes == null) {
|
||||
// RFC 5652 Section 5.3. "[signedAttrs] MUST be present if the
|
||||
// content type of the EncapsulatedContentInfo value being
|
||||
// signed is not id-data."
|
||||
if (!content.getContentType().equals(ContentInfo.DATA_OID)) {
|
||||
throw new SignatureException("Missing authenticatedAttributes");
|
||||
} else {
|
||||
try {
|
||||
var c = new DerValue(data);
|
||||
if (c.tag == DerValue.tag_Set) {
|
||||
throw new SignatureException("Not a .SF file content");
|
||||
}
|
||||
} catch (IOException e) {
|
||||
// Expected or ignored
|
||||
}
|
||||
}
|
||||
dataSigned = data;
|
||||
} else {
|
||||
|
||||
@ -688,6 +703,12 @@ public class SignerInfo implements DerEncoder {
|
||||
return null;
|
||||
}
|
||||
|
||||
// RFC 3161 Section 2.4.2. id-ct-TSTInfo.
|
||||
if (!tsToken.getContentInfo().getContentType()
|
||||
.equals(ContentInfo.TIMESTAMP_TOKEN_INFO_OID)) {
|
||||
throw new SignatureException("Not using id-ct-TSTInfo");
|
||||
}
|
||||
|
||||
// Extract the content (an encoded timestamp token info)
|
||||
byte[] encTsTokenInfo = tsToken.getContentInfo().getData();
|
||||
// Extract the signer (the Timestamping Authority)
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2006, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2006, 2026, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -25,6 +25,7 @@
|
||||
|
||||
package sun.security.provider.certpath;
|
||||
|
||||
import java.io.FilterInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.HttpURLConnection;
|
||||
@ -188,6 +189,16 @@ class URICertStore extends CertStoreSpi {
|
||||
return timeoutVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Maximum size for a CRL downloaded through a URICertStore
|
||||
* in bytes. This can be controlled by the com.sun.security.crl.maxSize
|
||||
* Security or System property. The System property, if set, overrides
|
||||
* the Security property. The default size is 20MiB.
|
||||
*/
|
||||
private static final long MAX_CRL_DOWNLOAD_SIZE =
|
||||
SecurityProperties.getOverridableLongProp(
|
||||
"com.sun.security.crl.maxSize", 20971520, debug);
|
||||
|
||||
/**
|
||||
* Enumeration for the allowed schemes we support when following a
|
||||
* URI from an authorityInfoAccess extension on a certificate.
|
||||
@ -228,6 +239,13 @@ class URICertStore extends CertStoreSpi {
|
||||
private static final boolean CA_ISS_ALLOW_ANY;
|
||||
|
||||
static {
|
||||
// Add a debug message for the configured CRL download limit
|
||||
if (debug != null) {
|
||||
debug.println("Maximum downloadable CRL size: " +
|
||||
MAX_CRL_DOWNLOAD_SIZE +
|
||||
((MAX_CRL_DOWNLOAD_SIZE < 0) ? " (DISABLED)" : ""));
|
||||
}
|
||||
|
||||
boolean allowAny = false;
|
||||
try {
|
||||
if (Builder.USE_AIA) {
|
||||
@ -623,7 +641,19 @@ class URICertStore extends CertStoreSpi {
|
||||
if (debug != null) {
|
||||
debug.println("Downloading new CRL...");
|
||||
}
|
||||
crl = (X509CRL) factory.generateCRL(in);
|
||||
InputStream crlIn = (MAX_CRL_DOWNLOAD_SIZE > -1) ?
|
||||
new SizeLimitedInputStream(in, MAX_CRL_DOWNLOAD_SIZE) :
|
||||
in;
|
||||
try {
|
||||
crl = (X509CRL) factory.generateCRL(crlIn);
|
||||
} catch (IllegalArgumentException iae) {
|
||||
// IAE should only be thrown when the CRL exceeds a
|
||||
// configured maximum length.
|
||||
if (debug != null) {
|
||||
debug.println("Discarding CRL: " + iae.getMessage());
|
||||
crl = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
return getMatchingCRLs(crl, selector);
|
||||
} catch (IOException | CRLException e) {
|
||||
@ -816,4 +846,59 @@ class URICertStore extends CertStoreSpi {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stream wrapper used when an InputStream passed into a CertificateFactory
|
||||
* needs to be size limited. It will throw IllegalArgumentException when
|
||||
* the downloaded resource via the underlying stream exceeds the maximum
|
||||
* limit.
|
||||
*/
|
||||
private static class SizeLimitedInputStream extends FilterInputStream {
|
||||
|
||||
private final long maxBytes;
|
||||
private long bytesRead = 0;
|
||||
|
||||
private SizeLimitedInputStream(InputStream in, long maxBytes) {
|
||||
super(in);
|
||||
this.maxBytes = maxBytes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
if (bytesRead >= maxBytes) {
|
||||
// We will use IAE here to differentiate this special case
|
||||
// from other IOEs that the underlying input stream might
|
||||
// legitimately throw.
|
||||
throw new IllegalArgumentException("InputStream exceeded max " +
|
||||
"size of " + maxBytes);
|
||||
}
|
||||
|
||||
int b = super.read();
|
||||
if (b != -1) {
|
||||
bytesRead++;
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(byte[] b, int off, int len) throws IOException {
|
||||
|
||||
if (bytesRead >= maxBytes) {
|
||||
// We will use IAE here to differentiate this special case
|
||||
// from other IOEs that the underlying input stream might
|
||||
// legitimately throw.
|
||||
throw new IllegalArgumentException("InputStream exceeded max " +
|
||||
"size of " + maxBytes);
|
||||
}
|
||||
|
||||
long remaining = maxBytes - bytesRead;
|
||||
int toRead = (int) Math.min(len, remaining);
|
||||
|
||||
int n = super.read(b, off, toRead);
|
||||
if (n != -1) {
|
||||
bytesRead += n;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -181,11 +181,13 @@ public enum Alert {
|
||||
|
||||
AlertMessage(TransportContext context,
|
||||
ByteBuffer m) throws IOException {
|
||||
// From RFC 8446 "Implementations
|
||||
// MUST NOT send Handshake and Alert records that have a zero-length
|
||||
// TLSInnerPlaintext.content; if such a message is received, the
|
||||
// receiving implementation MUST terminate the connection with an
|
||||
// "unexpected_message" alert."
|
||||
|
||||
// From RFC 8446: TLSv1.3
|
||||
//
|
||||
// Implementations MUST NOT send Handshake and Alert records that
|
||||
// have a zero-length TLSInnerPlaintext.content; if such a message
|
||||
// is received, the receiving implementation MUST terminate the
|
||||
// connection with an "unexpected_message" alert.
|
||||
if (m.remaining() == 0) {
|
||||
throw context.fatal(Alert.UNEXPECTED_MESSAGE,
|
||||
"Alert fragments must not be zero length.");
|
||||
@ -264,27 +266,39 @@ public enum Alert {
|
||||
} else if ((level == Level.WARNING) && (alert != null)) {
|
||||
// Terminate the connection if an alert with a level of warning
|
||||
// is received during handshaking, except the no_certificate
|
||||
// warning.
|
||||
if (alert.handshakeOnly && (tc.handshakeContext != null)) {
|
||||
// It's OK to get a no_certificate alert from a client of
|
||||
// which we requested client authentication. However,
|
||||
// if we required it, then this is not acceptable.
|
||||
if (tc.sslConfig.isClientMode ||
|
||||
alert != Alert.NO_CERTIFICATE ||
|
||||
(tc.sslConfig.clientAuthType !=
|
||||
// warning for SSLv3.
|
||||
HandshakeContext hc = tc.handshakeContext;
|
||||
if (alert.handshakeOnly && (hc != null)) {
|
||||
// In SSLv3, it's OK to get a no_certificate alert from a
|
||||
// client where we requested (want) client authentication.
|
||||
// If we required it (need), this is not acceptable
|
||||
// and must fail.
|
||||
//
|
||||
// no_certificate alerts are not acceptable in TLSv1.*.
|
||||
//
|
||||
if (!tc.sslConfig.isClientMode &&
|
||||
(hc.negotiatedProtocol == ProtocolVersion.SSL30) &&
|
||||
(alert == Alert.NO_CERTIFICATE) &&
|
||||
(tc.sslConfig.clientAuthType ==
|
||||
ClientAuthType.CLIENT_AUTH_REQUESTED)) {
|
||||
throw tc.fatal(Alert.HANDSHAKE_FAILURE,
|
||||
"received handshake warning: " + alert.description);
|
||||
} else {
|
||||
// Otherwise, ignore the warning but remove the
|
||||
// Certificate and CertificateVerify handshake
|
||||
// consumer so the state machine doesn't expect it.
|
||||
tc.handshakeContext.handshakeConsumers.remove(
|
||||
SSLHandshake.CERTIFICATE.id);
|
||||
tc.handshakeContext.handshakeConsumers.remove(
|
||||
|
||||
// We'll ignore the warning and remove the Certificate,
|
||||
// CompressedCertificate and CertificateVerify handshake
|
||||
// consumers so the state machine isn't expecting them.
|
||||
if (hc.handshakeConsumers.remove(
|
||||
SSLHandshake.CERTIFICATE.id) != null) {
|
||||
hc.handshakeConsumers.remove(
|
||||
SSLHandshake.COMPRESSED_CERTIFICATE.id);
|
||||
tc.handshakeContext.handshakeConsumers.remove(
|
||||
hc.handshakeConsumers.remove(
|
||||
SSLHandshake.CERTIFICATE_VERIFY.id);
|
||||
} else {
|
||||
throw tc.fatal(Alert.HANDSHAKE_FAILURE,
|
||||
"NO_CERTIFICATE alert received when certs" +
|
||||
" were not expected or already received");
|
||||
}
|
||||
} else {
|
||||
throw tc.fatal(Alert.HANDSHAKE_FAILURE,
|
||||
"Received handshake warning: " + alert.description);
|
||||
}
|
||||
} // Otherwise, ignore the warning
|
||||
} else { // fatal or unknown
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -26,6 +26,7 @@
|
||||
package sun.security.ssl;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.SecureRandom;
|
||||
@ -121,6 +122,7 @@ abstract class HelloCookieManager {
|
||||
private static final
|
||||
class D10HelloCookieManager extends HelloCookieManager {
|
||||
|
||||
private static final byte[] EMPTY_BYTE_ARRAY = new byte[0];
|
||||
final SecureRandom secureRandom;
|
||||
private int cookieVersion; // allow to wrap, version + sequence
|
||||
private final byte[] cookieSecret;
|
||||
@ -170,6 +172,7 @@ abstract class HelloCookieManager {
|
||||
}
|
||||
byte[] helloBytes = clientHello.getHelloCookieBytes();
|
||||
md.update(helloBytes);
|
||||
md.update(getHostPortBytes(context));
|
||||
byte[] cookie = md.digest(secret); // 32 bytes
|
||||
cookie[0] = (byte)((version >> 24) & 0xFF);
|
||||
|
||||
@ -205,11 +208,30 @@ abstract class HelloCookieManager {
|
||||
}
|
||||
byte[] helloBytes = clientHello.getHelloCookieBytes();
|
||||
md.update(helloBytes);
|
||||
md.update(getHostPortBytes(context));
|
||||
byte[] target = md.digest(secret); // 32 bytes
|
||||
target[0] = cookie[0];
|
||||
|
||||
return MessageDigest.isEqual(target, cookie);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns host and port bytes if those are set.
|
||||
* Using ASCII unit separator character to separate host and port so we
|
||||
* can differentiate between otherwise identical host and port string
|
||||
* concatenations, for example host 172.0.0.1 with port 25 and host
|
||||
* 172.0.0.12 with port 5.
|
||||
*/
|
||||
private static byte[] getHostPortBytes(ServerHandshakeContext context) {
|
||||
final String host = context.conContext.transport.getPeerHost();
|
||||
final int port = context.conContext.transport.getPeerPort();
|
||||
final String hostStr = host != null ? host : "";
|
||||
final String portStr = port > -1 ? Integer.toString(port) : "";
|
||||
return hostStr.isEmpty() && portStr.isEmpty() ?
|
||||
EMPTY_BYTE_ARRAY :
|
||||
(hostStr + '\u001F' + portStr).getBytes(
|
||||
StandardCharsets.UTF_8);
|
||||
}
|
||||
}
|
||||
|
||||
private static final
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -26,6 +26,8 @@
|
||||
package sun.security.timestamp;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import sun.security.pkcs.ContentInfo;
|
||||
import sun.security.pkcs.PKCS7;
|
||||
import sun.security.util.Debug;
|
||||
import sun.security.util.DerValue;
|
||||
@ -357,6 +359,11 @@ public final class TSResponse {
|
||||
DerValue timestampToken = derValue.data.getDerValue();
|
||||
encodedTsToken = timestampToken.toByteArray();
|
||||
tsToken = new PKCS7(encodedTsToken);
|
||||
// RFC 3161 Section 2.4.2. id-ct-TSTInfo.
|
||||
if (!tsToken.getContentInfo().getContentType()
|
||||
.equals(ContentInfo.TIMESTAMP_TOKEN_INFO_OID)) {
|
||||
throw new TimestampException("Not using id-ct-TSTInfo");
|
||||
}
|
||||
tstInfo = new TimestampToken(tsToken.getContentInfo().getData());
|
||||
}
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1996, 2026, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -157,6 +157,9 @@ public class DerValue {
|
||||
*/
|
||||
public static final byte tag_SetOf = 0x31;
|
||||
|
||||
// Max nested depth for constructed data
|
||||
private static final int MAX_CONSTRUCTED_NEST = 30;
|
||||
|
||||
// This class is mostly immutable except that:
|
||||
//
|
||||
// 1. resetTag() modifies the tag
|
||||
@ -564,6 +567,14 @@ public class DerValue {
|
||||
* @return the octet string held in this DER value
|
||||
*/
|
||||
public byte[] getOctetString() throws IOException {
|
||||
return getOctetString(0);
|
||||
}
|
||||
|
||||
private byte[] getOctetString(int limit) throws IOException {
|
||||
if (++limit > MAX_CONSTRUCTED_NEST) {
|
||||
throw new IOException("Nested OctetString limit reached ("
|
||||
+ MAX_CONSTRUCTED_NEST + ").");
|
||||
}
|
||||
|
||||
if (tag != tag_OctetString && !isConstructed(tag_OctetString)) {
|
||||
throw new IOException(
|
||||
@ -582,7 +593,7 @@ public class DerValue {
|
||||
ByteArrayOutputStream bout = new ByteArrayOutputStream();
|
||||
DerInputStream dis = data();
|
||||
while (dis.available() > 0) {
|
||||
bout.write(dis.getDerValue().getOctetString());
|
||||
bout.write(dis.getDerValue().getOctetString(limit));
|
||||
}
|
||||
return bout.toByteArray();
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2002, 2026, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -263,7 +263,7 @@ public class HostnameChecker {
|
||||
* The <code>name</code> parameter should represent a DNS name. The
|
||||
* <code>template</code> parameter may contain the wildcard character '*'.
|
||||
*/
|
||||
private boolean isMatched(String name, String template,
|
||||
public boolean isMatched(String name, String template,
|
||||
boolean chainsToPublicCA) {
|
||||
|
||||
// Normalize to Unicode, because PSL is in Unicode.
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2018 SAP SE. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
@ -139,6 +139,36 @@ public class SecurityProperties {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A convenience routine for fetching a numeric value from a Security
|
||||
* or System property and returning it as a long. The value from the
|
||||
* property is obtained according to the logic in
|
||||
* {@link SecurityProperties#getOverridableProperty(String)}
|
||||
*
|
||||
* @param prop the property to query
|
||||
* @param defaultValue the default value
|
||||
* @param dbg a Debug object, if null no debug messages will be sent
|
||||
* @return the value of the property as a {@code long}. If a non-numeric
|
||||
* value is supplied, the default value will be returned.
|
||||
*/
|
||||
public static long getOverridableLongProp(String prop, long defaultValue,
|
||||
Debug dbg) {
|
||||
long longVal = defaultValue;
|
||||
try {
|
||||
String propVal = SecurityProperties.getOverridableProperty(prop);
|
||||
if (propVal != null) {
|
||||
longVal = Long.parseLong(propVal);
|
||||
}
|
||||
} catch (NumberFormatException nfe) {
|
||||
// We will use the default, but add a warning debug message
|
||||
if (dbg != null) {
|
||||
dbg.println("Warning: Non-numeric value found in property " +
|
||||
prop + ", using default value of " + defaultValue);
|
||||
}
|
||||
}
|
||||
return longVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method for fetching System property values that are booleans.
|
||||
*
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -46,7 +46,12 @@ public class SignatureFileVerifier {
|
||||
/* Are we debugging ? */
|
||||
private static final Debug debug = Debug.getInstance("jar");
|
||||
|
||||
private final ArrayList<CodeSigner[]> signerCache;
|
||||
private final List<CodeSigner[]> signerCache;
|
||||
|
||||
// The maximum size of the signerCache. This is for debug only
|
||||
// and not intended to be adjusted by users.
|
||||
private static int SIGNER_CACHE_SIZE
|
||||
= Integer.getInteger("sun.security.util.jar.signer.cache.size", 5);
|
||||
|
||||
private static final String ATTR_DIGEST =
|
||||
"-DIGEST-" + ManifestDigester.MF_MAIN_ATTRS.toUpperCase(Locale.ENGLISH);
|
||||
@ -97,7 +102,7 @@ public class SignatureFileVerifier {
|
||||
*
|
||||
* @param rawBytes the raw bytes of the signature block file
|
||||
*/
|
||||
public SignatureFileVerifier(ArrayList<CodeSigner[]> signerCache,
|
||||
public SignatureFileVerifier(List<CodeSigner[]> signerCache,
|
||||
ManifestDigester md,
|
||||
String name,
|
||||
byte[] rawBytes)
|
||||
@ -282,7 +287,6 @@ public class SignatureFileVerifier {
|
||||
} finally {
|
||||
Providers.stopJarVerification(obj);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void processImpl(Hashtable<String, CodeSigner[]> signers,
|
||||
@ -850,6 +854,9 @@ public class SignatureFileVerifier {
|
||||
newSigners.length);
|
||||
}
|
||||
signerCache.add(cachedSigners);
|
||||
if (signerCache.size() > SIGNER_CACHE_SIZE) {
|
||||
signerCache.remove(0);
|
||||
}
|
||||
signers.put(name, cachedSigners);
|
||||
}
|
||||
|
||||
|
||||
@ -52,6 +52,8 @@ import sun.security.util.*;
|
||||
public class DNSName implements GeneralNameInterface {
|
||||
private final String name;
|
||||
|
||||
private static final HostnameChecker HOSTNAME_CHECKER =
|
||||
HostnameChecker.getInstance(HostnameChecker.TYPE_TLS);
|
||||
private static final String DNS_ALLOWED =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-";
|
||||
|
||||
@ -218,17 +220,22 @@ public class DNSName implements GeneralNameInterface {
|
||||
* For example, www.host.example.com would satisfy the constraint but
|
||||
* host1.example.com would not.
|
||||
* <p>
|
||||
* RFC6125: Match wildcard pattern in the input name being constrained,
|
||||
* any wildcard in this name will be matched as a literal character.
|
||||
* <p>
|
||||
* RFC1034: By convention, domain names can be stored with arbitrary case, but
|
||||
* domain name comparisons for all present domain functions are done in a
|
||||
* case-insensitive manner, assuming an ASCII character set, and a high
|
||||
* order zero bit.
|
||||
*
|
||||
* @param inputName to be checked for being constrained
|
||||
* @param matchWildcard whether to match a wildcard in inputName
|
||||
* @return constraint type above
|
||||
* @throws UnsupportedOperationException if name is not exact match, but narrowing and widening are
|
||||
* not supported for this name type.
|
||||
*/
|
||||
public int constrains(GeneralNameInterface inputName) throws UnsupportedOperationException {
|
||||
public int constrains(GeneralNameInterface inputName, boolean matchWildcard)
|
||||
throws UnsupportedOperationException {
|
||||
int constraintType;
|
||||
if (inputName == null)
|
||||
constraintType = NAME_DIFF_TYPE;
|
||||
@ -238,7 +245,10 @@ public class DNSName implements GeneralNameInterface {
|
||||
String inName =
|
||||
(((DNSName)inputName).getName()).toLowerCase(Locale.ENGLISH);
|
||||
String thisName = name.toLowerCase(Locale.ENGLISH);
|
||||
if (inName.equals(thisName))
|
||||
|
||||
if (inName.equals(thisName) || (matchWildcard
|
||||
&& inName.contains("*")
|
||||
&& HOSTNAME_CHECKER.isMatched(thisName, inName, false)))
|
||||
constraintType = NAME_MATCH;
|
||||
else if (thisName.endsWith(inName)) {
|
||||
int inNdx = thisName.lastIndexOf(inName);
|
||||
@ -259,6 +269,10 @@ public class DNSName implements GeneralNameInterface {
|
||||
return constraintType;
|
||||
}
|
||||
|
||||
public int constrains(GeneralNameInterface inputName) {
|
||||
return constrains(inputName, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return subtree depth of this name for purposes of determining
|
||||
* NameConstraints minimum and maximum bounds and for calculating
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -506,9 +506,15 @@ public class NameConstraintsExtension extends Extension
|
||||
if (exName == null)
|
||||
continue;
|
||||
|
||||
// Match a wildcard in DNSName only against the excluded subtree
|
||||
int matchResult =
|
||||
exName.getType() == GeneralNameInterface.NAME_DNS
|
||||
? ((DNSName) exName).constrains(name, true)
|
||||
: exName.constrains(name);
|
||||
|
||||
// if name matches or narrows any excluded subtree,
|
||||
// return false
|
||||
switch (exName.constrains(name)) {
|
||||
switch (matchResult) {
|
||||
case GeneralNameInterface.NAME_DIFF_TYPE:
|
||||
case GeneralNameInterface.NAME_WIDENS: // name widens excluded
|
||||
case GeneralNameInterface.NAME_SAME_TYPE:
|
||||
|
||||
@ -1730,6 +1730,22 @@ jdk.epkcs8.defaultAlgorithm=PBEWithHmacSHA256AndAES_128
|
||||
# ldap://ldap.company.com/dc=company,dc=com?caCertificate;binary
|
||||
com.sun.security.allowedAIALocations=
|
||||
|
||||
#
|
||||
# Certificate Revocation List (CRL) Download Size Limitation
|
||||
#
|
||||
# This property sets a size limit for CRLs downloaded via URIs provided
|
||||
# in the CRL Distribution Points certificate extension. This property
|
||||
# must be a numeric value that is the size in bytes of the DER-encoded CRL.
|
||||
# For protocols that can return multi-value responses, such as LDAP, the
|
||||
# size threshold is the sum of all CRLs downloaded from a single search
|
||||
# query. CRLs that exceed this length will not be processed during certificate
|
||||
# path validation. This size limit does not apply to CRLs that are imported
|
||||
# through non-network-based means. A negative value will disable this size
|
||||
# limitation. A non-numeric value will be ignored and the default size will
|
||||
# be used instead. The default size limit is 20MiB.
|
||||
# This property may be overridden by a System property of the same name.
|
||||
com.sun.security.crl.maxSize = 20971520
|
||||
|
||||
#
|
||||
# PKCS #8 encoding format for newly created ML-KEM and ML-DSA private keys
|
||||
#
|
||||
|
||||
@ -31,12 +31,8 @@ package sun.awt.image;
|
||||
import java.awt.image.ImageConsumer;
|
||||
import java.awt.image.IndexColorModel;
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.io.IOException;
|
||||
|
||||
import static java.lang.Math.multiplyExact;
|
||||
|
||||
@ -62,9 +58,8 @@ public class XbmImageDecoder extends ImageDecoder {
|
||||
ImageConsumer.SINGLEPASS |
|
||||
ImageConsumer.SINGLEFRAME);
|
||||
|
||||
private static final int MAX_CHAR_LIMIT = 128000;
|
||||
private static final int MAX_XBM_SIZE = 16384;
|
||||
private static final int HEADER_SCAN_LIMIT = 100;
|
||||
|
||||
public XbmImageDecoder(InputStreamImageSource src, InputStream is) {
|
||||
super(src, is);
|
||||
if (!(input instanceof BufferedInputStream)) {
|
||||
@ -86,150 +81,229 @@ public class XbmImageDecoder extends ImageDecoder {
|
||||
* produce an image from the stream.
|
||||
*/
|
||||
public void produceImage() throws IOException, ImageFormatException {
|
||||
char[] nm = new char[80];
|
||||
int c;
|
||||
int i = 0;
|
||||
int state = 0;
|
||||
int H = 0;
|
||||
int W = 0;
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
int n = 0;
|
||||
int state = 0;
|
||||
boolean consumeWidthValue = false;
|
||||
boolean consumeHeightValue = false;
|
||||
boolean validWidthConsumed = false;
|
||||
boolean validHeightConsumed = false;
|
||||
// number of tokens seen as part of this define statement
|
||||
int defineTokenCount = 0;
|
||||
byte[] raster = null;
|
||||
IndexColorModel model = null;
|
||||
int charCount = 0;
|
||||
|
||||
String matchRegex = "\\s*(0[xX])?((?:(?!,|\\};).)+)(,|\\};)";
|
||||
String replaceRegex = "0[xX]|,|\\s+|\\};";
|
||||
|
||||
String line;
|
||||
int lineNum = 0;
|
||||
|
||||
try (BufferedReader br = new BufferedReader(new InputStreamReader(input))) {
|
||||
// loop to process XBM header - width, height and create raster
|
||||
while (!aborted && (line = br.readLine()) != null
|
||||
&& lineNum <= HEADER_SCAN_LIMIT) {
|
||||
lineNum++;
|
||||
// process #define stmts
|
||||
if (line.trim().startsWith("#define")) {
|
||||
String[] token = line.split("\\s+");
|
||||
if (token.length != 3) {
|
||||
error("Error while parsing define statement");
|
||||
}
|
||||
try {
|
||||
if (state < 2) {
|
||||
if (token[1].endsWith("h")) {
|
||||
W = Integer.parseInt(token[2]);
|
||||
} else if (token[1].endsWith("ht")) {
|
||||
H = Integer.parseInt(token[2]);
|
||||
}
|
||||
// After the 1st dimension is set, state becomes 1;
|
||||
// after the 2nd dimension is set, state becomes 2
|
||||
++state;
|
||||
}
|
||||
} catch (NumberFormatException nfe) {
|
||||
// parseInt() can throw NFE
|
||||
error("Error while parsing width or height.");
|
||||
}
|
||||
}
|
||||
|
||||
if (state == 2) {
|
||||
if (W <= 0 || H <= 0) {
|
||||
error("Invalid values for width or height.");
|
||||
}
|
||||
if (multiplyExact(W, H) > MAX_XBM_SIZE) {
|
||||
error("Large XBM file size."
|
||||
+ " Maximum allowed size: " + MAX_XBM_SIZE);
|
||||
}
|
||||
model = new IndexColorModel(8, 2, XbmColormap,
|
||||
0, false, 0);
|
||||
setDimensions(W, H);
|
||||
setColorModel(model);
|
||||
setHints(XbmHints);
|
||||
headerComplete();
|
||||
raster = new byte[W];
|
||||
state = 3;
|
||||
break;
|
||||
}
|
||||
//read header info
|
||||
while (!aborted && (c = input.read()) != -1) {
|
||||
charCount++;
|
||||
if (charCount > MAX_CHAR_LIMIT) {
|
||||
error("Incomplete image after reading "
|
||||
+ "the maximum allowed number of characters: "
|
||||
+ MAX_CHAR_LIMIT);
|
||||
}
|
||||
|
||||
if (state != 3) {
|
||||
error("Width or Height of XBM file not defined");
|
||||
}
|
||||
|
||||
boolean contFlag = false;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
// loop to process image data
|
||||
while (!aborted && (line = br.readLine()) != null) {
|
||||
lineNum++;
|
||||
|
||||
if (!contFlag) {
|
||||
if (line.contains("[]")) {
|
||||
contFlag = true;
|
||||
} else {
|
||||
if ('a' <= c && c <= 'z' ||
|
||||
'A' <= c && c <= 'Z' ||
|
||||
'0' <= c && c <= '9' || c == '#' || c == '_') {
|
||||
if (i < nm.length) {
|
||||
nm[i++] = (char) c;
|
||||
} else {
|
||||
error("XBM header contains literal greater than size 80");
|
||||
}
|
||||
} else if (i > 0) {
|
||||
int nc = i;
|
||||
i = 0;
|
||||
if (defineTokenCount >= 1) {
|
||||
// we are inside a #define line
|
||||
defineTokenCount++;
|
||||
}
|
||||
if (defineTokenCount == 0) {
|
||||
if (nc == 7 &&
|
||||
nm[0] == '#' &&
|
||||
nm[1] == 'd' &&
|
||||
nm[2] == 'e' &&
|
||||
nm[3] == 'f' &&
|
||||
nm[4] == 'i' &&
|
||||
nm[5] == 'n' &&
|
||||
nm[6] == 'e')
|
||||
{
|
||||
defineTokenCount++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
} else if (defineTokenCount == 2) {
|
||||
// consume second token in #define line
|
||||
if (state < 2) {
|
||||
if (nm[nc - 1] == 'h' &&
|
||||
!validWidthConsumed) {
|
||||
consumeWidthValue = true;
|
||||
} else if ((nm[nc - 1] == 't' && nc > 1 &&
|
||||
nm[nc - 2] == 'h') &&
|
||||
!validHeightConsumed) {
|
||||
consumeHeightValue = true;
|
||||
}
|
||||
}
|
||||
} else if (defineTokenCount == 3) {
|
||||
defineTokenCount = 0;
|
||||
// consume third token in #define line
|
||||
int n = 0;
|
||||
for (int p = 0; p < nc; p++) {
|
||||
if ('0' <= (c = nm[p]) && c <= '9') {
|
||||
n = n * 10 + c - '0';
|
||||
if (n > MAX_XBM_SIZE) {
|
||||
error("Width/Height cannot be more than: "
|
||||
+ MAX_XBM_SIZE);
|
||||
}
|
||||
} else {
|
||||
error("Invalid width/height value");
|
||||
}
|
||||
}
|
||||
|
||||
int end = line.indexOf(';');
|
||||
if (end >= 0) {
|
||||
sb.append(line, 0, end + 1);
|
||||
break;
|
||||
} else {
|
||||
sb.append(line).append(System.lineSeparator());
|
||||
if (n > 0 && (consumeWidthValue || consumeHeightValue)) {
|
||||
if (consumeWidthValue) {
|
||||
if (!validWidthConsumed) {
|
||||
W = n;
|
||||
validWidthConsumed = true;
|
||||
state++;
|
||||
}
|
||||
consumeWidthValue = false;
|
||||
} else if (consumeHeightValue) {
|
||||
if (!validHeightConsumed) {
|
||||
H = n;
|
||||
validHeightConsumed = true;
|
||||
state++;
|
||||
}
|
||||
consumeHeightValue = false;
|
||||
}
|
||||
}
|
||||
// verify the consumed width & height value and initialize
|
||||
// required constructs
|
||||
if (state == 2) {
|
||||
if (multiplyExact(W, H) > MAX_XBM_SIZE) {
|
||||
error("Large XBM file size."
|
||||
+ " Maximum allowed size: " + MAX_XBM_SIZE);
|
||||
}
|
||||
model = new IndexColorModel(8, 2, XbmColormap,
|
||||
0, false, 0);
|
||||
setDimensions(W, H);
|
||||
setColorModel(model);
|
||||
setHints(XbmHints);
|
||||
headerComplete();
|
||||
raster = new byte[W];
|
||||
state = 3;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String resultLine = sb.toString();
|
||||
int cutOffIndex = resultLine.indexOf('{');
|
||||
resultLine = resultLine.substring(cutOffIndex + 1);
|
||||
|
||||
Matcher matcher = Pattern.compile(matchRegex).matcher(resultLine);
|
||||
while (matcher.find()) {
|
||||
if (y >= H) {
|
||||
error("Scan size of XBM file exceeds"
|
||||
+ " the defined width x height");
|
||||
}
|
||||
|
||||
int startIndex = matcher.start();
|
||||
int endIndex = matcher.end();
|
||||
String hexByte = resultLine.substring(startIndex, endIndex);
|
||||
hexByte = hexByte.replaceAll("^\\s+", "");
|
||||
|
||||
if (!(hexByte.startsWith("0x")
|
||||
|| hexByte.startsWith("0X"))) {
|
||||
error("Invalid hexadecimal number at Ln#:" + lineNum
|
||||
+ " Col#:" + (startIndex + 1));
|
||||
}
|
||||
hexByte = hexByte.replaceAll(replaceRegex, "");
|
||||
if (hexByte.length() != 2) {
|
||||
error("Invalid hexadecimal number at Ln#:" + lineNum
|
||||
+ " Col#:" + (startIndex + 1));
|
||||
}
|
||||
|
||||
try {
|
||||
n = Integer.parseInt(hexByte, 16);
|
||||
} catch (NumberFormatException nfe) {
|
||||
error("Error parsing hexadecimal at Ln#:" + lineNum
|
||||
+ " Col#:" + (startIndex + 1));
|
||||
}
|
||||
for (int mask = 1; mask <= 0x80; mask <<= 1) {
|
||||
if (x < W) {
|
||||
if ((n & mask) != 0)
|
||||
raster[x] = 1;
|
||||
else
|
||||
raster[x] = 0;
|
||||
}
|
||||
x++;
|
||||
}
|
||||
|
||||
if (x >= W) {
|
||||
int result = setPixels(0, y, W, 1, model, raster, 0, W);
|
||||
if (result <= 0) {
|
||||
error("Unexpected error occurred during setPixel()");
|
||||
}
|
||||
x = 0;
|
||||
y++;
|
||||
}
|
||||
}
|
||||
imageComplete(ImageConsumer.STATICIMAGEDONE, true);
|
||||
}
|
||||
|
||||
if (state != 3) {
|
||||
error("Width or Height of XBM file not defined");
|
||||
}
|
||||
|
||||
// skip until we find '{'
|
||||
boolean imageDataStarted = false;
|
||||
while (!aborted && (c = input.read()) != -1) {
|
||||
charCount++;
|
||||
if (charCount > MAX_CHAR_LIMIT) {
|
||||
error("Incomplete image after reading "
|
||||
+ "the maximum allowed number of characters: "
|
||||
+ MAX_CHAR_LIMIT);
|
||||
}
|
||||
if (c == '{') {
|
||||
imageDataStarted = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!imageDataStarted) {
|
||||
error("Missing '{' at the start of image data");
|
||||
}
|
||||
|
||||
// used to make sure that we have the final delimiter '};',
|
||||
// while parsing the image data
|
||||
int previousChar = '{';
|
||||
// parse image data
|
||||
boolean imageDataTerminated = false;
|
||||
while (!aborted && (c = input.read()) != -1) {
|
||||
charCount++;
|
||||
if (charCount > MAX_CHAR_LIMIT) {
|
||||
error("Incomplete image after reading "
|
||||
+ "the maximum allowed number of characters: "
|
||||
+ MAX_CHAR_LIMIT);
|
||||
}
|
||||
|
||||
if (c == ';') {
|
||||
if (previousChar != '}') {
|
||||
error("Abrupt end of image data without '};' delimiter");
|
||||
}
|
||||
imageDataTerminated = true;
|
||||
break;
|
||||
}
|
||||
if (!Character.isWhitespace(c)) {
|
||||
previousChar = c;
|
||||
}
|
||||
|
||||
if (',' != c && '}' != c &&
|
||||
!Character.isWhitespace(c)) {
|
||||
nm[i++] = (char) c;
|
||||
if (i > 4) {
|
||||
error("Image hex data should be 3 or 4 characters long");
|
||||
}
|
||||
} else if (i == 3 || i == 4) {
|
||||
// consume valid hex image data
|
||||
int n = 0;
|
||||
int nc = i;
|
||||
i = 0;
|
||||
if (nm[0] == '0' &&
|
||||
(nm[1] == 'x' || nm[1] == 'X')) {
|
||||
for (int p = 2; p < nc; p++) {
|
||||
c = nm[p];
|
||||
if ('0' <= c && c <= '9')
|
||||
c = c - '0';
|
||||
else if ('A' <= c && c <= 'F')
|
||||
c = c - 'A' + 10;
|
||||
else if ('a' <= c && c <= 'f')
|
||||
c = c - 'a' + 10;
|
||||
else
|
||||
error("Corrupt hex image data");
|
||||
n = n * 16 + c;
|
||||
}
|
||||
for (int mask = 1; mask <= 0x80; mask <<= 1) {
|
||||
if (x < W) {
|
||||
if ((n & mask) != 0)
|
||||
raster[x] = 1;
|
||||
else
|
||||
raster[x] = 0;
|
||||
}
|
||||
x++;
|
||||
}
|
||||
if (x >= W) {
|
||||
if ((y + 1) > H) {
|
||||
error("Scan size of XBM file exceeds"
|
||||
+ " the defined width x height");
|
||||
}
|
||||
if (setPixels(0, y, W, 1, model, raster, 0, W) == 0) {
|
||||
error("Unexpected error occurred during setPixel()");
|
||||
}
|
||||
x = 0;
|
||||
y++;
|
||||
}
|
||||
} else {
|
||||
error("Corrupt hex image data");
|
||||
}
|
||||
} else if (i == 1 || i == 2) {
|
||||
error("Image hex data should be 3 or 4 characters long");
|
||||
}
|
||||
}
|
||||
if (!imageDataTerminated) {
|
||||
error("Missing terminator ';'");
|
||||
}
|
||||
input.close();
|
||||
imageComplete(ImageConsumer.STATICIMAGEDONE, true);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -2218,7 +2218,11 @@ allocateArray(JNIEnv *env, BufImageS_t *imageP,
|
||||
/* Means we need to fill in alpha */
|
||||
if (!cvtToDefault && addAlpha) {
|
||||
*mlibImagePP = (*sMlibSysFns.createFP)(MLIB_BYTE, 4, width, height);
|
||||
if (*mlibImagePP != NULL) {
|
||||
if (*mlibImagePP == NULL) {
|
||||
(*env)->ReleasePrimitiveArrayCritical(env, rasterP->jdata, dataP,
|
||||
JNI_ABORT);
|
||||
return -1;
|
||||
} else {
|
||||
unsigned int *dstP = (unsigned int *)
|
||||
mlib_ImageGetData(*mlibImagePP);
|
||||
int dstride = (*mlibImagePP)->stride>>2;
|
||||
@ -2234,10 +2238,10 @@ allocateArray(JNIEnv *env, BufImageS_t *imageP,
|
||||
dP[x] = sP[x] | 0xff000000;
|
||||
}
|
||||
}
|
||||
(*env)->ReleasePrimitiveArrayCritical(env, rasterP->jdata, dataP,
|
||||
JNI_ABORT);
|
||||
return 0;
|
||||
}
|
||||
(*env)->ReleasePrimitiveArrayCritical(env, rasterP->jdata, dataP,
|
||||
JNI_ABORT);
|
||||
return 0;
|
||||
}
|
||||
else if ((hintP->packing & BYTE_INTERLEAVED) == BYTE_INTERLEAVED) {
|
||||
int nChans = (cmP->isDefaultCompatCM ? 4 : hintP->numChans);
|
||||
@ -2252,6 +2256,11 @@ allocateArray(JNIEnv *env, BufImageS_t *imageP,
|
||||
hintP->sStride,
|
||||
(unsigned char *)dataP
|
||||
+ hintP->dataOffset);
|
||||
if (*mlibImagePP == NULL) {
|
||||
(*env)->ReleasePrimitiveArrayCritical(env, rasterP->jdata, dataP,
|
||||
JNI_ABORT);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else if ((hintP->packing & SHORT_INTERLEAVED) == SHORT_INTERLEAVED) {
|
||||
*mlibImagePP = (*sMlibSysFns.createStructFP)(MLIB_SHORT,
|
||||
@ -2261,6 +2270,11 @@ allocateArray(JNIEnv *env, BufImageS_t *imageP,
|
||||
imageP->raster.scanlineStride*2,
|
||||
(unsigned short *)dataP
|
||||
+ hintP->channelOffset);
|
||||
if (*mlibImagePP == NULL) {
|
||||
(*env)->ReleasePrimitiveArrayCritical(env, rasterP->jdata, dataP,
|
||||
JNI_ABORT);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Release the data array */
|
||||
@ -2360,6 +2374,11 @@ allocateRasterArray(JNIEnv *env, RasterS_t *rasterP,
|
||||
width, height,
|
||||
rasterP->scanlineStride*4,
|
||||
(unsigned char *)dataP + offset);
|
||||
if (*mlibImagePP == NULL) {
|
||||
(*env)->ReleasePrimitiveArrayCritical(env, rasterP->jdata, dataP,
|
||||
JNI_ABORT);
|
||||
return -1;
|
||||
}
|
||||
*dataPP = dataP;
|
||||
return 0;
|
||||
case sun_awt_image_IntegerComponentRaster_TYPE_BYTE_SAMPLES:
|
||||
@ -2388,6 +2407,11 @@ allocateRasterArray(JNIEnv *env, RasterS_t *rasterP,
|
||||
width, height,
|
||||
rasterP->scanlineStride,
|
||||
(unsigned char *)dataP + offset);
|
||||
if (*mlibImagePP == NULL) {
|
||||
(*env)->ReleasePrimitiveArrayCritical(env, rasterP->jdata, dataP,
|
||||
JNI_ABORT);
|
||||
return -1;
|
||||
}
|
||||
*dataPP = dataP;
|
||||
return 0;
|
||||
case sun_awt_image_IntegerComponentRaster_TYPE_USHORT_SAMPLES:
|
||||
@ -2418,6 +2442,11 @@ allocateRasterArray(JNIEnv *env, RasterS_t *rasterP,
|
||||
width, height,
|
||||
rasterP->scanlineStride*2,
|
||||
(unsigned char *)dataP + offset);
|
||||
if (*mlibImagePP == NULL) {
|
||||
(*env)->ReleasePrimitiveArrayCritical(env, rasterP->jdata, dataP,
|
||||
JNI_ABORT);
|
||||
return -1;
|
||||
}
|
||||
*dataPP = dataP;
|
||||
return 0;
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -120,6 +120,7 @@ typedef struct streamBufferStruct {
|
||||
size_t bufferLength; // Allocated, nut just used
|
||||
int suspendable; // Set to true to suspend input
|
||||
long remaining_skip; // Used only on input
|
||||
jboolean isCopy; // GetByteArrayElements copied/pinned the Java array
|
||||
} streamBuffer, *streamBufferPtr;
|
||||
|
||||
/*
|
||||
@ -200,7 +201,8 @@ static void destroyStreamBuffer(JNIEnv *env, streamBufferPtr sb) {
|
||||
// Forward reference
|
||||
static void unpinStreamBuffer(JNIEnv *env,
|
||||
streamBufferPtr sb,
|
||||
const JOCTET *next_byte);
|
||||
const JOCTET *next_byte,
|
||||
int streamReleaseMode);
|
||||
/*
|
||||
* Resets the state of a streamBuffer object that has been in use.
|
||||
* The global reference to the stream is released, but the reference
|
||||
@ -212,15 +214,16 @@ static void resetStreamBuffer(JNIEnv *env, streamBufferPtr sb) {
|
||||
(*env)->DeleteWeakGlobalRef(env, sb->ioRef);
|
||||
sb->ioRef = NULL;
|
||||
}
|
||||
unpinStreamBuffer(env, sb, NULL);
|
||||
unpinStreamBuffer(env, sb, NULL, JNI_ABORT);
|
||||
sb->bufferOffset = NO_DATA;
|
||||
sb->suspendable = FALSE;
|
||||
sb->remaining_skip = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Pins the data buffer associated with this stream. Returns OK on
|
||||
* success, NOT_OK on failure, as GetPrimitiveArrayCritical may fail.
|
||||
* Pins/copies the data buffer associated with this stream. Returns OK on
|
||||
* success, NOT_OK on failure, as GetByteArrayElements
|
||||
* may fail.
|
||||
*/
|
||||
static int pinStreamBuffer(JNIEnv *env,
|
||||
streamBufferPtr sb,
|
||||
@ -228,9 +231,9 @@ static int pinStreamBuffer(JNIEnv *env,
|
||||
if (sb->hstreamBuffer != NULL) {
|
||||
assert(sb->buf == NULL);
|
||||
sb->buf =
|
||||
(JOCTET *)(*env)->GetPrimitiveArrayCritical(env,
|
||||
sb->hstreamBuffer,
|
||||
NULL);
|
||||
(JOCTET *)(*env)->GetByteArrayElements(env,
|
||||
sb->hstreamBuffer,
|
||||
&sb->isCopy);
|
||||
if (sb->buf == NULL) {
|
||||
return NOT_OK;
|
||||
}
|
||||
@ -242,11 +245,12 @@ static int pinStreamBuffer(JNIEnv *env,
|
||||
}
|
||||
|
||||
/*
|
||||
* Unpins the data buffer associated with this stream.
|
||||
* Unpins/releases the data buffer associated with this stream.
|
||||
*/
|
||||
static void unpinStreamBuffer(JNIEnv *env,
|
||||
streamBufferPtr sb,
|
||||
const JOCTET *next_byte) {
|
||||
const JOCTET *next_byte,
|
||||
int streamReleaseMode) {
|
||||
if (sb->buf != NULL) {
|
||||
assert(sb->hstreamBuffer != NULL);
|
||||
if (next_byte == NULL) {
|
||||
@ -254,11 +258,13 @@ static void unpinStreamBuffer(JNIEnv *env,
|
||||
} else {
|
||||
sb->bufferOffset = next_byte - sb->buf;
|
||||
}
|
||||
(*env)->ReleasePrimitiveArrayCritical(env,
|
||||
sb->hstreamBuffer,
|
||||
sb->buf,
|
||||
0);
|
||||
sb->buf = NULL;
|
||||
(*env)->ReleaseByteArrayElements(env,
|
||||
sb->hstreamBuffer,
|
||||
(jbyte *)sb->buf,
|
||||
streamReleaseMode);
|
||||
if (streamReleaseMode != JNI_COMMIT) {
|
||||
sb->buf = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -276,6 +282,7 @@ static void clearStreamBuffer(streamBufferPtr sb) {
|
||||
typedef struct pixelBufferStruct {
|
||||
jobject hpixelObject; // Usually a DataBuffer bank as a byte array
|
||||
unsigned int byteBufferLength;
|
||||
jboolean isCopy; // GetByteArrayElements copied/pinned the Java array
|
||||
union pixptr {
|
||||
INT32 *ip; // Pinned buffer pointer, as 32-bit ints
|
||||
unsigned char *bp; // Pinned buffer pointer, as bytes
|
||||
@ -309,7 +316,7 @@ static int setPixelBuffer(JNIEnv *env, pixelBufferPtr pb, jobject obj) {
|
||||
}
|
||||
|
||||
// Forward reference
|
||||
static void unpinPixelBuffer(JNIEnv *env, pixelBufferPtr pb);
|
||||
static void unpinPixelBuffer(JNIEnv *env, pixelBufferPtr pb, int pixelReleaseMode);
|
||||
|
||||
/*
|
||||
* Resets a pixel buffer to its initial state. Unpins any pixel buffer,
|
||||
@ -318,7 +325,7 @@ static void unpinPixelBuffer(JNIEnv *env, pixelBufferPtr pb);
|
||||
*/
|
||||
static void resetPixelBuffer(JNIEnv *env, pixelBufferPtr pb) {
|
||||
if (pb->hpixelObject != NULL) {
|
||||
unpinPixelBuffer(env, pb);
|
||||
unpinPixelBuffer(env, pb, JNI_ABORT);
|
||||
(*env)->DeleteGlobalRef(env, pb->hpixelObject);
|
||||
pb->hpixelObject = NULL;
|
||||
pb->byteBufferLength = 0;
|
||||
@ -326,13 +333,13 @@ static void resetPixelBuffer(JNIEnv *env, pixelBufferPtr pb) {
|
||||
}
|
||||
|
||||
/*
|
||||
* Pins the data buffer. Returns OK on success, NOT_OK on failure.
|
||||
* Pins/copies the data buffer. Returns OK on success, NOT_OK on failure.
|
||||
*/
|
||||
static int pinPixelBuffer(JNIEnv *env, pixelBufferPtr pb) {
|
||||
if (pb->hpixelObject != NULL) {
|
||||
assert(pb->buf.ip == NULL);
|
||||
pb->buf.bp = (unsigned char *)(*env)->GetPrimitiveArrayCritical
|
||||
(env, pb->hpixelObject, NULL);
|
||||
pb->buf.bp = (unsigned char *)(*env)->GetByteArrayElements
|
||||
(env, pb->hpixelObject, &pb->isCopy);
|
||||
if (pb->buf.bp == NULL) {
|
||||
return NOT_OK;
|
||||
}
|
||||
@ -341,17 +348,19 @@ static int pinPixelBuffer(JNIEnv *env, pixelBufferPtr pb) {
|
||||
}
|
||||
|
||||
/*
|
||||
* Unpins the data buffer.
|
||||
* Unpins/releases the pixel buffer.
|
||||
*/
|
||||
static void unpinPixelBuffer(JNIEnv *env, pixelBufferPtr pb) {
|
||||
static void unpinPixelBuffer(JNIEnv *env, pixelBufferPtr pb, int pixelReleaseMode) {
|
||||
|
||||
if (pb->buf.ip != NULL) {
|
||||
assert(pb->hpixelObject != NULL);
|
||||
(*env)->ReleasePrimitiveArrayCritical(env,
|
||||
pb->hpixelObject,
|
||||
pb->buf.ip,
|
||||
0);
|
||||
pb->buf.ip = NULL;
|
||||
(*env)->ReleaseByteArrayElements(env,
|
||||
pb->hpixelObject,
|
||||
(jbyte *)pb->buf.ip,
|
||||
pixelReleaseMode);
|
||||
if (pixelReleaseMode != JNI_COMMIT) {
|
||||
pb->buf.ip = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -468,34 +477,28 @@ static j_common_ptr destroyImageioData(JNIEnv *env, imageIODataPtr data) {
|
||||
|
||||
/******************** Java array pinning and unpinning *****************/
|
||||
|
||||
/* We use Get/ReleasePrimitiveArrayCritical functions to avoid
|
||||
* the need to copy array elements for the above two objects.
|
||||
*
|
||||
* MAKE SURE TO:
|
||||
*
|
||||
* - carefully insert pairs of RELEASE_ARRAYS and GET_ARRAYS around
|
||||
* callbacks to Java.
|
||||
* - call RELEASE_ARRAYS before returning to Java.
|
||||
*
|
||||
* Otherwise things will go horribly wrong. There may be memory leaks,
|
||||
* excessive pinning, or even VM crashes!
|
||||
*
|
||||
* Note that GetPrimitiveArrayCritical may fail!
|
||||
/*
|
||||
* We use Get/ReleaseByteArrayElements functions for access stream
|
||||
* and pixel information from Java level arrays.
|
||||
* If we receive reference to copy of Java array make sure you update
|
||||
* Java array also when the latest information is needed at Java level.
|
||||
* Also we use specific release modes for performance optimizations.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Release (unpin) all the arrays in use during a read.
|
||||
* Release (unpin) both stream and pixel arrays.
|
||||
*/
|
||||
static void RELEASE_ARRAYS(JNIEnv *env, imageIODataPtr data, const JOCTET *next_byte)
|
||||
static void RELEASE_ARRAYS(JNIEnv *env, imageIODataPtr data, const JOCTET *next_byte,
|
||||
int streamReleaseMode, int pixelReleaseMode)
|
||||
{
|
||||
unpinStreamBuffer(env, &data->streamBuf, next_byte);
|
||||
unpinStreamBuffer(env, &data->streamBuf, next_byte, streamReleaseMode);
|
||||
|
||||
unpinPixelBuffer(env, &data->pixelBuf);
|
||||
unpinPixelBuffer(env, &data->pixelBuf, pixelReleaseMode);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Get (pin) all the arrays in use during a read.
|
||||
* Get (pin) both stream and pixel arrays.
|
||||
*/
|
||||
static int GET_ARRAYS(JNIEnv *env, imageIODataPtr data, const JOCTET **next_byte) {
|
||||
if (pinStreamBuffer(env, &data->streamBuf, next_byte) == NOT_OK) {
|
||||
@ -503,7 +506,7 @@ static int GET_ARRAYS(JNIEnv *env, imageIODataPtr data, const JOCTET **next_byte
|
||||
}
|
||||
|
||||
if (pinPixelBuffer(env, &data->pixelBuf) == NOT_OK) {
|
||||
RELEASE_ARRAYS(env, data, *next_byte);
|
||||
RELEASE_ARRAYS(env, data, *next_byte, JNI_ABORT, JNI_ABORT);
|
||||
return NOT_OK;
|
||||
}
|
||||
return OK;
|
||||
@ -570,26 +573,16 @@ sun_jpeg_output_message (j_common_ptr cinfo)
|
||||
theObject = data->imageIOobj;
|
||||
|
||||
if (cinfo->is_decompressor) {
|
||||
struct jpeg_source_mgr *src = ((j_decompress_ptr)cinfo)->src;
|
||||
RELEASE_ARRAYS(env, data, src->next_input_byte);
|
||||
(*env)->CallVoidMethod(env, theObject,
|
||||
JPEGImageReader_warningWithMessageID,
|
||||
string);
|
||||
if ((*env)->ExceptionCheck(env)
|
||||
|| !GET_ARRAYS(env, data, &(src->next_input_byte))) {
|
||||
cinfo->err->error_exit(cinfo);
|
||||
}
|
||||
} else {
|
||||
struct jpeg_destination_mgr *dest = ((j_compress_ptr)cinfo)->dest;
|
||||
RELEASE_ARRAYS(env, data, (const JOCTET *)(dest->next_output_byte));
|
||||
(*env)->CallVoidMethod(env, theObject,
|
||||
JPEGImageWriter_warningWithMessageID,
|
||||
string);
|
||||
if ((*env)->ExceptionCheck(env)
|
||||
|| !GET_ARRAYS(env, data,
|
||||
(const JOCTET **)(&dest->next_output_byte))) {
|
||||
cinfo->err->error_exit(cinfo);
|
||||
}
|
||||
}
|
||||
if ((*env)->ExceptionCheck(env)) {
|
||||
cinfo->err->error_exit(cinfo);
|
||||
}
|
||||
}
|
||||
|
||||
@ -941,7 +934,7 @@ imageio_fill_input_buffer(j_decompress_ptr cinfo)
|
||||
#ifdef DEBUG_IIO_JPEG
|
||||
printf("Filling input buffer, remaining skip is %ld, ",
|
||||
sb->remaining_skip);
|
||||
printf("Buffer length is %d\n", sb->bufferLength);
|
||||
printf("Buffer length is %zu\n", sb->bufferLength);
|
||||
#endif
|
||||
|
||||
/*
|
||||
@ -956,8 +949,15 @@ imageio_fill_input_buffer(j_decompress_ptr cinfo)
|
||||
/*
|
||||
* Now fill a complete buffer, or as much of one as the stream
|
||||
* will give us if we are near the end.
|
||||
*
|
||||
* The native copy of java array is not valid anymore so we just
|
||||
* release it and get new copy, if we don't have native copy we rely
|
||||
* on JVM to maintain the pinned handle of java array.
|
||||
*/
|
||||
RELEASE_ARRAYS(env, data, src->next_input_byte);
|
||||
jboolean isCopy = sb->isCopy;
|
||||
if (isCopy) {
|
||||
unpinStreamBuffer(env, &data->streamBuf, src->next_input_byte, JNI_ABORT);
|
||||
}
|
||||
|
||||
GET_IO_REF(input);
|
||||
|
||||
@ -969,9 +969,12 @@ imageio_fill_input_buffer(j_decompress_ptr cinfo)
|
||||
if ((ret > 0) && ((unsigned int)ret > sb->bufferLength)) {
|
||||
ret = (int)sb->bufferLength;
|
||||
}
|
||||
if ((*env)->ExceptionCheck(env)
|
||||
|| !GET_ARRAYS(env, data, &(src->next_input_byte))) {
|
||||
cinfo->err->error_exit((j_common_ptr) cinfo);
|
||||
|
||||
if ((*env)->ExceptionCheck(env) ||
|
||||
(isCopy && (pinStreamBuffer(env,
|
||||
&data->streamBuf,
|
||||
&(src->next_input_byte)) == NOT_OK))) {
|
||||
cinfo->err->error_exit((j_common_ptr) cinfo);
|
||||
}
|
||||
|
||||
#ifdef DEBUG_IIO_JPEG
|
||||
@ -988,12 +991,10 @@ imageio_fill_input_buffer(j_decompress_ptr cinfo)
|
||||
#ifdef DEBUG_IIO_JPEG
|
||||
printf("YO! Early EOI! ret = %d\n", ret);
|
||||
#endif
|
||||
RELEASE_ARRAYS(env, data, src->next_input_byte);
|
||||
(*env)->CallVoidMethod(env, reader,
|
||||
JPEGImageReader_warningOccurredID,
|
||||
READ_NO_EOI);
|
||||
if ((*env)->ExceptionCheck(env)
|
||||
|| !GET_ARRAYS(env, data, &(src->next_input_byte))) {
|
||||
if ((*env)->ExceptionCheck(env)) {
|
||||
cinfo->err->error_exit((j_common_ptr) cinfo);
|
||||
}
|
||||
|
||||
@ -1008,97 +1009,6 @@ imageio_fill_input_buffer(j_decompress_ptr cinfo)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* With I/O suspension turned on, the JPEG library requires that all
|
||||
* buffer filling be done at the top application level, using this
|
||||
* function. Due to the way that backtracking works, this procedure
|
||||
* saves all of the data that was left in the buffer when suspension
|
||||
* occurred and read new data only at the end.
|
||||
*/
|
||||
|
||||
GLOBAL(void)
|
||||
imageio_fill_suspended_buffer(j_decompress_ptr cinfo)
|
||||
{
|
||||
struct jpeg_source_mgr *src = cinfo->src;
|
||||
imageIODataPtr data = (imageIODataPtr) cinfo->client_data;
|
||||
streamBufferPtr sb = &data->streamBuf;
|
||||
JNIEnv *env = (JNIEnv *)JNU_GetEnv(the_jvm, JNI_VERSION_1_2);
|
||||
jint ret;
|
||||
size_t offset, buflen;
|
||||
jobject input = NULL;
|
||||
|
||||
/*
|
||||
* The original (jpegdecoder.c) had code here that called
|
||||
* InputStream.available and just returned if the number of bytes
|
||||
* available was less than any remaining skip. Presumably this was
|
||||
* to avoid blocking, although the benefit was unclear, as no more
|
||||
* decompression can take place until more data is available, so
|
||||
* the code would block on input a little further along anyway.
|
||||
* ImageInputStreams don't have an available method, so we'll just
|
||||
* block in the skip if we have to.
|
||||
*/
|
||||
|
||||
if (sb->remaining_skip) {
|
||||
src->skip_input_data(cinfo, 0);
|
||||
}
|
||||
|
||||
/* Save the data currently in the buffer */
|
||||
offset = src->bytes_in_buffer;
|
||||
if (src->next_input_byte > sb->buf) {
|
||||
memcpy(sb->buf, src->next_input_byte, offset);
|
||||
}
|
||||
|
||||
|
||||
RELEASE_ARRAYS(env, data, src->next_input_byte);
|
||||
|
||||
GET_IO_REF(input);
|
||||
|
||||
buflen = sb->bufferLength - offset;
|
||||
if (buflen <= 0) {
|
||||
if (!GET_ARRAYS(env, data, &(src->next_input_byte))) {
|
||||
cinfo->err->error_exit((j_common_ptr) cinfo);
|
||||
}
|
||||
RELEASE_ARRAYS(env, data, src->next_input_byte);
|
||||
return;
|
||||
}
|
||||
|
||||
ret = (*env)->CallIntMethod(env, input,
|
||||
JPEGImageReader_readInputDataID,
|
||||
sb->hstreamBuffer,
|
||||
offset, buflen);
|
||||
if ((ret > 0) && ((unsigned int)ret > buflen)) ret = (int)buflen;
|
||||
if ((*env)->ExceptionCheck(env)
|
||||
|| !GET_ARRAYS(env, data, &(src->next_input_byte))) {
|
||||
cinfo->err->error_exit((j_common_ptr) cinfo);
|
||||
}
|
||||
/*
|
||||
* If we have reached the end of the stream, then the EOI marker
|
||||
* is missing. We accept such streams but generate a warning.
|
||||
* The image is likely to be corrupted, though everything through
|
||||
* the end of the last complete MCU should be usable.
|
||||
*/
|
||||
if (ret <= 0) {
|
||||
jobject reader = data->imageIOobj;
|
||||
RELEASE_ARRAYS(env, data, src->next_input_byte);
|
||||
(*env)->CallVoidMethod(env, reader,
|
||||
JPEGImageReader_warningOccurredID,
|
||||
READ_NO_EOI);
|
||||
if ((*env)->ExceptionCheck(env)
|
||||
|| !GET_ARRAYS(env, data, &(src->next_input_byte))) {
|
||||
cinfo->err->error_exit((j_common_ptr) cinfo);
|
||||
}
|
||||
|
||||
sb->buf[offset] = (JOCTET) 0xFF;
|
||||
sb->buf[offset + 1] = (JOCTET) JPEG_EOI;
|
||||
ret = 2;
|
||||
}
|
||||
|
||||
src->next_input_byte = sb->buf;
|
||||
src->bytes_in_buffer = ret + offset;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Skip num_bytes worth of data. The buffer pointer and count are
|
||||
* advanced over num_bytes input bytes, using the input stream
|
||||
@ -1160,16 +1070,13 @@ imageio_skip_input_data(j_decompress_ptr cinfo, long num_bytes)
|
||||
return;
|
||||
}
|
||||
|
||||
RELEASE_ARRAYS(env, data, src->next_input_byte);
|
||||
|
||||
GET_IO_REF(input);
|
||||
|
||||
ret = (*env)->CallLongMethod(env,
|
||||
input,
|
||||
JPEGImageReader_skipInputBytesID,
|
||||
(jlong) num_bytes);
|
||||
if ((*env)->ExceptionCheck(env)
|
||||
|| !GET_ARRAYS(env, data, &(src->next_input_byte))) {
|
||||
if ((*env)->ExceptionCheck(env)) {
|
||||
cinfo->err->error_exit((j_common_ptr) cinfo);
|
||||
}
|
||||
|
||||
@ -1181,15 +1088,12 @@ imageio_skip_input_data(j_decompress_ptr cinfo, long num_bytes)
|
||||
*/
|
||||
if (ret <= 0) {
|
||||
reader = data->imageIOobj;
|
||||
RELEASE_ARRAYS(env, data, src->next_input_byte);
|
||||
(*env)->CallVoidMethod(env,
|
||||
reader,
|
||||
JPEGImageReader_warningOccurredID,
|
||||
READ_NO_EOI);
|
||||
|
||||
if ((*env)->ExceptionCheck(env)
|
||||
|| !GET_ARRAYS(env, data, &(src->next_input_byte))) {
|
||||
cinfo->err->error_exit((j_common_ptr) cinfo);
|
||||
if ((*env)->ExceptionCheck(env)) {
|
||||
cinfo->err->error_exit((j_common_ptr) cinfo);
|
||||
}
|
||||
sb->buf[0] = (JOCTET) 0xFF;
|
||||
sb->buf[1] = (JOCTET) JPEG_EOI;
|
||||
@ -1215,7 +1119,7 @@ imageio_term_source(j_decompress_ptr cinfo)
|
||||
JNIEnv *env = (JNIEnv *)JNU_GetEnv(the_jvm, JNI_VERSION_1_2);
|
||||
jobject reader = data->imageIOobj;
|
||||
if (src->bytes_in_buffer > 0) {
|
||||
RELEASE_ARRAYS(env, data, src->next_input_byte);
|
||||
RELEASE_ARRAYS(env, data, src->next_input_byte, JNI_ABORT, 0);
|
||||
(*env)->CallVoidMethod(env,
|
||||
reader,
|
||||
JPEGImageReader_pushBackID,
|
||||
@ -1659,7 +1563,7 @@ Java_com_sun_imageio_plugins_jpeg_JPEGImageReader_readImageHeader
|
||||
if (setjmp(jerr->setjmp_buffer)) {
|
||||
/* If we get here, the JPEG code has signaled an error
|
||||
while reading the header. */
|
||||
RELEASE_ARRAYS(env, data, src->next_input_byte);
|
||||
RELEASE_ARRAYS(env, data, src->next_input_byte, JNI_ABORT, JNI_ABORT);
|
||||
if (!(*env)->ExceptionCheck(env)) {
|
||||
char buffer[JMSG_LENGTH_MAX];
|
||||
(*cinfo->err->format_message) ((struct jpeg_common_struct *) cinfo,
|
||||
@ -1678,7 +1582,7 @@ Java_com_sun_imageio_plugins_jpeg_JPEGImageReader_readImageHeader
|
||||
(*env)->ExceptionClear(env);
|
||||
JNU_ThrowByName(env,
|
||||
"javax/imageio/IIOException",
|
||||
"Array pin failed");
|
||||
"Get array elements failed");
|
||||
return retval;
|
||||
}
|
||||
|
||||
@ -1701,7 +1605,11 @@ Java_com_sun_imageio_plugins_jpeg_JPEGImageReader_readImageHeader
|
||||
printf("just read tables-only image; q table 0 at %p\n",
|
||||
cinfo->quant_tbl_ptrs[0]);
|
||||
#endif
|
||||
RELEASE_ARRAYS(env, data, src->next_input_byte);
|
||||
/*
|
||||
* readImageHeader can be called independently, so
|
||||
* we release the arrays when we return back.
|
||||
*/
|
||||
RELEASE_ARRAYS(env, data, src->next_input_byte, JNI_ABORT, 0);
|
||||
} else {
|
||||
/*
|
||||
* Now adjust the jpeg_color_space variable, which was set in
|
||||
@ -1802,7 +1710,6 @@ Java_com_sun_imageio_plugins_jpeg_JPEGImageReader_readImageHeader
|
||||
/* Leave the output space as CMYK */
|
||||
}
|
||||
}
|
||||
RELEASE_ARRAYS(env, data, src->next_input_byte);
|
||||
|
||||
/* read icc profile data */
|
||||
profileData = read_icc_profile(env, cinfo);
|
||||
@ -1819,14 +1726,17 @@ Java_com_sun_imageio_plugins_jpeg_JPEGImageReader_readImageHeader
|
||||
cinfo->out_color_space,
|
||||
cinfo->num_components,
|
||||
profileData);
|
||||
if ((*env)->ExceptionCheck(env)
|
||||
|| !GET_ARRAYS(env, data, &(src->next_input_byte))) {
|
||||
if ((*env)->ExceptionCheck(env)) {
|
||||
cinfo->err->error_exit((j_common_ptr) cinfo);
|
||||
}
|
||||
if (reset) {
|
||||
jpeg_abort_decompress(cinfo);
|
||||
}
|
||||
RELEASE_ARRAYS(env, data, src->next_input_byte);
|
||||
/*
|
||||
* readImageHeader can be called independently, so
|
||||
* we release the arrays when we return back.
|
||||
*/
|
||||
RELEASE_ARRAYS(env, data, src->next_input_byte, JNI_ABORT, 0);
|
||||
}
|
||||
|
||||
return retval;
|
||||
@ -1987,7 +1897,7 @@ Java_com_sun_imageio_plugins_jpeg_JPEGImageReader_readImage
|
||||
if (setjmp(jerr->setjmp_buffer)) {
|
||||
/* If we get here, the JPEG code has signaled an error
|
||||
while reading. */
|
||||
RELEASE_ARRAYS(env, data, src->next_input_byte);
|
||||
RELEASE_ARRAYS(env, data, src->next_input_byte, JNI_ABORT, JNI_ABORT);
|
||||
if (!(*env)->ExceptionCheck(env)) {
|
||||
char buffer[JMSG_LENGTH_MAX];
|
||||
(*cinfo->err->format_message) ((struct jpeg_common_struct *) cinfo,
|
||||
@ -2005,7 +1915,7 @@ Java_com_sun_imageio_plugins_jpeg_JPEGImageReader_readImage
|
||||
(*env)->ExceptionClear(env);
|
||||
JNU_ThrowByName(env,
|
||||
"javax/imageio/IIOException",
|
||||
"Array pin failed");
|
||||
"Get array elements failed");
|
||||
return data->abortFlag;
|
||||
}
|
||||
|
||||
@ -2037,7 +1947,7 @@ Java_com_sun_imageio_plugins_jpeg_JPEGImageReader_readImage
|
||||
jpeg_start_decompress(cinfo);
|
||||
|
||||
if (numBands != cinfo->output_components) {
|
||||
RELEASE_ARRAYS(env, data, src->next_input_byte);
|
||||
RELEASE_ARRAYS(env, data, src->next_input_byte, JNI_ABORT, JNI_ABORT);
|
||||
JNU_ThrowByName(env, "javax/imageio/IIOException",
|
||||
"Invalid argument to native readImage");
|
||||
return data->abortFlag;
|
||||
@ -2046,7 +1956,7 @@ Java_com_sun_imageio_plugins_jpeg_JPEGImageReader_readImage
|
||||
if (cinfo->output_components <= 0 ||
|
||||
cinfo->image_width > (0xffffffffu / (unsigned int)cinfo->output_components))
|
||||
{
|
||||
RELEASE_ARRAYS(env, data, src->next_input_byte);
|
||||
RELEASE_ARRAYS(env, data, src->next_input_byte, JNI_ABORT, JNI_ABORT);
|
||||
JNU_ThrowByName(env, "javax/imageio/IIOException",
|
||||
"Invalid number of output components");
|
||||
return data->abortFlag;
|
||||
@ -2055,7 +1965,7 @@ Java_com_sun_imageio_plugins_jpeg_JPEGImageReader_readImage
|
||||
// Allocate a 1-scanline buffer
|
||||
scanLinePtr = (JSAMPROW)malloc(cinfo->image_width*cinfo->output_components);
|
||||
if (scanLinePtr == NULL) {
|
||||
RELEASE_ARRAYS(env, data, src->next_input_byte);
|
||||
RELEASE_ARRAYS(env, data, src->next_input_byte, JNI_ABORT, JNI_ABORT);
|
||||
JNU_ThrowByName( env,
|
||||
"java/lang/OutOfMemoryError",
|
||||
"Reading JPEG Stream");
|
||||
@ -2070,22 +1980,18 @@ Java_com_sun_imageio_plugins_jpeg_JPEGImageReader_readImage
|
||||
// the first interesting pass.
|
||||
jpeg_start_output(cinfo, cinfo->input_scan_number);
|
||||
if (wantUpdates) {
|
||||
RELEASE_ARRAYS(env, data, src->next_input_byte);
|
||||
(*env)->CallVoidMethod(env, this,
|
||||
JPEGImageReader_passStartedID,
|
||||
cinfo->input_scan_number-1);
|
||||
if ((*env)->ExceptionCheck(env)
|
||||
|| !GET_ARRAYS(env, data, &(src->next_input_byte))) {
|
||||
if ((*env)->ExceptionCheck(env)) {
|
||||
cinfo->err->error_exit((j_common_ptr) cinfo);
|
||||
}
|
||||
}
|
||||
} else if (wantUpdates) {
|
||||
RELEASE_ARRAYS(env, data, src->next_input_byte);
|
||||
(*env)->CallVoidMethod(env, this,
|
||||
JPEGImageReader_passStartedID,
|
||||
0);
|
||||
if ((*env)->ExceptionCheck(env)
|
||||
|| !GET_ARRAYS(env, data, &(src->next_input_byte))) {
|
||||
if ((*env)->ExceptionCheck(env)) {
|
||||
cinfo->err->error_exit((j_common_ptr) cinfo);
|
||||
}
|
||||
}
|
||||
@ -2136,16 +2042,20 @@ Java_com_sun_imageio_plugins_jpeg_JPEGImageReader_readImage
|
||||
}
|
||||
}
|
||||
|
||||
// And call it back to Java
|
||||
RELEASE_ARRAYS(env, data, src->next_input_byte);
|
||||
/*
|
||||
* Optimisation to just commit the native pixel buffer
|
||||
* content back to java array without releasing the
|
||||
* native buffer.
|
||||
*/
|
||||
if (pb->isCopy) {
|
||||
unpinPixelBuffer(env, pb, JNI_COMMIT);
|
||||
}
|
||||
(*env)->CallVoidMethod(env,
|
||||
this,
|
||||
JPEGImageReader_acceptPixelsID,
|
||||
targetLine++,
|
||||
progressive);
|
||||
|
||||
if ((*env)->ExceptionCheck(env)
|
||||
|| !GET_ARRAYS(env, data, &(src->next_input_byte))) {
|
||||
if ((*env)->ExceptionCheck(env)) {
|
||||
cinfo->err->error_exit((j_common_ptr) cinfo);
|
||||
}
|
||||
|
||||
@ -2175,11 +2085,9 @@ Java_com_sun_imageio_plugins_jpeg_JPEGImageReader_readImage
|
||||
done = TRUE;
|
||||
}
|
||||
if (wantUpdates) {
|
||||
RELEASE_ARRAYS(env, data, src->next_input_byte);
|
||||
(*env)->CallVoidMethod(env, this,
|
||||
JPEGImageReader_passCompleteID);
|
||||
if ((*env)->ExceptionCheck(env)
|
||||
|| !GET_ARRAYS(env, data, &(src->next_input_byte))) {
|
||||
if ((*env)->ExceptionCheck(env)) {
|
||||
cinfo->err->error_exit((j_common_ptr) cinfo);
|
||||
}
|
||||
}
|
||||
@ -2204,13 +2112,16 @@ Java_com_sun_imageio_plugins_jpeg_JPEGImageReader_readImage
|
||||
this,
|
||||
JPEGImageReader_skipPastImageID,
|
||||
imageIndex);
|
||||
if ((*env)->ExceptionCheck(env)) {
|
||||
cinfo->err->error_exit((j_common_ptr) cinfo);
|
||||
}
|
||||
} else {
|
||||
jpeg_finish_decompress(cinfo);
|
||||
}
|
||||
|
||||
free(scanLinePtr);
|
||||
|
||||
RELEASE_ARRAYS(env, data, src->next_input_byte);
|
||||
RELEASE_ARRAYS(env, data, src->next_input_byte, JNI_ABORT, 0);
|
||||
|
||||
return data->abortFlag;
|
||||
}
|
||||
@ -2405,8 +2316,16 @@ imageio_empty_output_buffer (j_compress_ptr cinfo)
|
||||
JNIEnv *env = (JNIEnv *)JNU_GetEnv(the_jvm, JNI_VERSION_1_2);
|
||||
jobject output = NULL;
|
||||
|
||||
RELEASE_ARRAYS(env, data, (const JOCTET *)(dest->next_output_byte));
|
||||
|
||||
/*
|
||||
* Optimization to not delete the native copy of stream buffer,
|
||||
* but just commit the content back to the Java array.
|
||||
* In case where we don't have a copy, we rely on JVM to maintain
|
||||
* the native reference of Java array.
|
||||
*/
|
||||
jboolean isCopy = sb->isCopy;
|
||||
if (isCopy) {
|
||||
unpinStreamBuffer(env, sb, dest->next_output_byte, JNI_COMMIT);
|
||||
}
|
||||
GET_IO_REF(output);
|
||||
|
||||
(*env)->CallVoidMethod(env,
|
||||
@ -2415,10 +2334,8 @@ imageio_empty_output_buffer (j_compress_ptr cinfo)
|
||||
sb->hstreamBuffer,
|
||||
0,
|
||||
sb->bufferLength);
|
||||
if ((*env)->ExceptionCheck(env)
|
||||
|| !GET_ARRAYS(env, data,
|
||||
(const JOCTET **)(&dest->next_output_byte))) {
|
||||
cinfo->err->error_exit((j_common_ptr) cinfo);
|
||||
if ((*env)->ExceptionCheck(env)) {
|
||||
cinfo->err->error_exit((j_common_ptr) cinfo);
|
||||
}
|
||||
|
||||
dest->next_output_byte = sb->buf;
|
||||
@ -2447,7 +2364,16 @@ imageio_term_destination (j_compress_ptr cinfo)
|
||||
if (datacount != 0) {
|
||||
jobject output = NULL;
|
||||
|
||||
RELEASE_ARRAYS(env, data, (const JOCTET *)(dest->next_output_byte));
|
||||
/*
|
||||
* Optimization to not delete the native copy of stream buffer,
|
||||
* but just commit the content back to the Java array.
|
||||
* In case where we don't have a copy, we rely on JVM to maintain
|
||||
* the native reference of Java array.
|
||||
*/
|
||||
jboolean isCopy = sb->isCopy;
|
||||
if (isCopy) {
|
||||
unpinStreamBuffer(env, sb, dest->next_output_byte, JNI_COMMIT);
|
||||
}
|
||||
|
||||
GET_IO_REF(output);
|
||||
|
||||
@ -2457,17 +2383,13 @@ imageio_term_destination (j_compress_ptr cinfo)
|
||||
sb->hstreamBuffer,
|
||||
0,
|
||||
datacount);
|
||||
|
||||
if ((*env)->ExceptionCheck(env)
|
||||
|| !GET_ARRAYS(env, data,
|
||||
(const JOCTET **)(&dest->next_output_byte))) {
|
||||
if ((*env)->ExceptionCheck(env)) {
|
||||
cinfo->err->error_exit((j_common_ptr) cinfo);
|
||||
}
|
||||
}
|
||||
|
||||
dest->next_output_byte = NULL;
|
||||
dest->free_in_buffer = 0;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2668,7 +2590,7 @@ Java_com_sun_imageio_plugins_jpeg_JPEGImageWriter_writeTables
|
||||
if (setjmp(jerr->setjmp_buffer)) {
|
||||
/* If we get here, the JPEG code has signaled an error
|
||||
while writing. */
|
||||
RELEASE_ARRAYS(env, data, (const JOCTET *)(dest->next_output_byte));
|
||||
RELEASE_ARRAYS(env, data, (const JOCTET *)(dest->next_output_byte), JNI_ABORT, JNI_ABORT);
|
||||
if (!(*env)->ExceptionCheck(env)) {
|
||||
char buffer[JMSG_LENGTH_MAX];
|
||||
(*cinfo->err->format_message) ((j_common_ptr) cinfo,
|
||||
@ -2683,7 +2605,7 @@ Java_com_sun_imageio_plugins_jpeg_JPEGImageWriter_writeTables
|
||||
(*env)->ExceptionClear(env);
|
||||
JNU_ThrowByName(env,
|
||||
"javax/imageio/IIOException",
|
||||
"Array pin failed");
|
||||
"Get array elements failed");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -2703,7 +2625,15 @@ Java_com_sun_imageio_plugins_jpeg_JPEGImageWriter_writeTables
|
||||
}
|
||||
|
||||
jpeg_write_tables(cinfo); // Flushes the buffer for you
|
||||
RELEASE_ARRAYS(env, data, NULL);
|
||||
/*
|
||||
* writeTables can be called independently, so
|
||||
* we release the arrays when we return back.
|
||||
* Also the table content in output_buffer is
|
||||
* already flushed, so no need to commit the
|
||||
* native copy of stream content back to the
|
||||
* Java array.
|
||||
*/
|
||||
RELEASE_ARRAYS(env, data, NULL, JNI_ABORT, 0);
|
||||
}
|
||||
|
||||
static void freeArray(UINT8** arr, jint size) {
|
||||
@ -2766,7 +2696,6 @@ Java_com_sun_imageio_plugins_jpeg_JPEGImageWriter_writeImage
|
||||
UINT8** scale = NULL;
|
||||
boolean success = TRUE;
|
||||
|
||||
|
||||
/* verify the inputs */
|
||||
|
||||
if (data == NULL) {
|
||||
@ -2891,7 +2820,7 @@ Java_com_sun_imageio_plugins_jpeg_JPEGImageWriter_writeImage
|
||||
if (setjmp(jerr->setjmp_buffer)) {
|
||||
/* If we get here, the JPEG code has signaled an error
|
||||
while writing. */
|
||||
RELEASE_ARRAYS(env, data, (const JOCTET *)(dest->next_output_byte));
|
||||
RELEASE_ARRAYS(env, data, (const JOCTET *)(dest->next_output_byte), JNI_ABORT, JNI_ABORT);
|
||||
if (!(*env)->ExceptionCheck(env)) {
|
||||
char buffer[JMSG_LENGTH_MAX];
|
||||
(*cinfo->err->format_message) ((j_common_ptr) cinfo,
|
||||
@ -2973,7 +2902,7 @@ Java_com_sun_imageio_plugins_jpeg_JPEGImageWriter_writeImage
|
||||
free(scanLinePtr);
|
||||
JNU_ThrowByName(env,
|
||||
"javax/imageio/IIOException",
|
||||
"Array pin failed");
|
||||
"Get array elements failed");
|
||||
return data->abortFlag;
|
||||
}
|
||||
|
||||
@ -3006,7 +2935,7 @@ Java_com_sun_imageio_plugins_jpeg_JPEGImageWriter_writeImage
|
||||
scanptr = (int *) cinfo->script_space;
|
||||
scanData = (*env)->GetIntArrayElements(env, scanInfo, NULL);
|
||||
if (scanData == NULL) {
|
||||
RELEASE_ARRAYS(env, data, (const JOCTET *)(dest->next_output_byte));
|
||||
RELEASE_ARRAYS(env, data, (const JOCTET *)(dest->next_output_byte), JNI_ABORT, JNI_ABORT);
|
||||
freeArray(scale, numBands);
|
||||
free(scanLinePtr);
|
||||
return data->abortFlag;
|
||||
@ -3034,16 +2963,13 @@ Java_com_sun_imageio_plugins_jpeg_JPEGImageWriter_writeImage
|
||||
if (haveMetadata) {
|
||||
// Flush the buffer
|
||||
imageio_flush_destination(cinfo);
|
||||
// Call Java to write the metadata
|
||||
RELEASE_ARRAYS(env, data, (const JOCTET *)(dest->next_output_byte));
|
||||
// Call Java to write the metadata.
|
||||
(*env)->CallVoidMethod(env,
|
||||
this,
|
||||
JPEGImageWriter_writeMetadataID);
|
||||
if ((*env)->ExceptionCheck(env)
|
||||
|| !GET_ARRAYS(env, data,
|
||||
(const JOCTET **)(&dest->next_output_byte))) {
|
||||
cinfo->err->error_exit((j_common_ptr) cinfo);
|
||||
}
|
||||
if ((*env)->ExceptionCheck(env)) {
|
||||
cinfo->err->error_exit((j_common_ptr) cinfo);
|
||||
}
|
||||
}
|
||||
|
||||
targetLine = 0;
|
||||
@ -3053,20 +2979,29 @@ Java_com_sun_imageio_plugins_jpeg_JPEGImageWriter_writeImage
|
||||
// for each line in destHeight
|
||||
while ((data->abortFlag == JNI_FALSE)
|
||||
&& (cinfo->next_scanline < cinfo->image_height)) {
|
||||
// get the line from Java
|
||||
RELEASE_ARRAYS(env, data, (const JOCTET *)(dest->next_output_byte));
|
||||
/*
|
||||
* Get a line of pixel data from Java.
|
||||
* In case where we have native copy of Java pixel array,
|
||||
* we need to just use JNI_ABORT to exclude any copy operation
|
||||
* and then get new copy for next scanline.
|
||||
*
|
||||
* If we have direct reference to Java array, we rely on
|
||||
* JVM to maintain the reference appropriately.
|
||||
*/
|
||||
jboolean isCopy = pb->isCopy;
|
||||
if (isCopy) {
|
||||
unpinPixelBuffer(env, pb, JNI_ABORT);
|
||||
}
|
||||
(*env)->CallVoidMethod(env,
|
||||
this,
|
||||
JPEGImageWriter_grabPixelsID,
|
||||
targetLine);
|
||||
if ((*env)->ExceptionCheck(env)
|
||||
|| !GET_ARRAYS(env, data,
|
||||
(const JOCTET **)(&dest->next_output_byte))) {
|
||||
cinfo->err->error_exit((j_common_ptr) cinfo);
|
||||
}
|
||||
if ((*env)->ExceptionCheck(env) ||
|
||||
(isCopy && (pinPixelBuffer(env, pb) == NOT_OK))) {
|
||||
cinfo->err->error_exit((j_common_ptr) cinfo);
|
||||
}
|
||||
|
||||
// subsample it into our buffer
|
||||
|
||||
in = data->pixelBuf.buf.bp;
|
||||
out = scanLinePtr;
|
||||
pixelLimit = in + ((pixelBufferSize > data->pixelBuf.byteBufferLength) ?
|
||||
@ -3108,7 +3043,7 @@ Java_com_sun_imageio_plugins_jpeg_JPEGImageWriter_writeImage
|
||||
|
||||
freeArray(scale, numBands);
|
||||
free(scanLinePtr);
|
||||
RELEASE_ARRAYS(env, data, NULL);
|
||||
RELEASE_ARRAYS(env, data, NULL, 0, JNI_ABORT);
|
||||
return data->abortFlag;
|
||||
}
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -52,6 +52,7 @@ import sun.security.util.HexDumpEncoder;
|
||||
import sun.security.provider.certpath.X509CertificatePair;
|
||||
import sun.security.util.Cache;
|
||||
import sun.security.util.Debug;
|
||||
import sun.security.util.SecurityProperties;
|
||||
|
||||
/**
|
||||
* Core implementation of a LDAP Cert Store.
|
||||
@ -96,6 +97,16 @@ final class LDAPCertStoreImpl {
|
||||
private static final String PROP_DISABLE_APP_RESOURCE_FILES =
|
||||
"sun.security.certpath.ldap.disable.app.resource.files";
|
||||
|
||||
/**
|
||||
* Maximum size for a CRL downloaded through an LDAPCertStoreImpl
|
||||
* in bytes. This can be controlled by the com.sun.security.crl.maxSize
|
||||
* Security or System property. The System property, if set, overrides
|
||||
* the Security property. The default size is 20MiB.
|
||||
*/
|
||||
private static final long MAX_CRL_DOWNLOAD_SIZE =
|
||||
SecurityProperties.getOverridableLongProp(
|
||||
"com.sun.security.crl.maxSize", 20971520, debug);
|
||||
|
||||
static {
|
||||
String s = System.getProperty(PROP_LIFETIME);
|
||||
if (s != null) {
|
||||
@ -103,6 +114,13 @@ final class LDAPCertStoreImpl {
|
||||
} else {
|
||||
LIFETIME = DEFAULT_CACHE_LIFETIME;
|
||||
}
|
||||
|
||||
// Add a debug message for the configured CRL download limit
|
||||
if (debug != null) {
|
||||
debug.println("Maximum downloadable CRL size: " +
|
||||
MAX_CRL_DOWNLOAD_SIZE +
|
||||
((MAX_CRL_DOWNLOAD_SIZE < 0) ? " (DISABLED)" : ""));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -672,12 +690,12 @@ final class LDAPCertStoreImpl {
|
||||
return certs;
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* Gets CRLs from an attribute id and location in the LDAP directory.
|
||||
* Returns a Collection containing only the CRLs that match the
|
||||
* specified X509CRLSelector.
|
||||
*
|
||||
* @param name the location holding the attribute
|
||||
* @param request the LDAP request used for this CRL fetch operation
|
||||
* @param id the attribute identifier
|
||||
* @param sel a X509CRLSelector that the CRLs must match
|
||||
* @return a Collection of CRLs found
|
||||
@ -689,7 +707,26 @@ final class LDAPCertStoreImpl {
|
||||
/* fetch the encoded crls from storage */
|
||||
byte[][] encodedCRL;
|
||||
try {
|
||||
encodedCRL = request.getValues(id);
|
||||
byte[][] tmpCrls = request.getValues(id);
|
||||
if (MAX_CRL_DOWNLOAD_SIZE > -1) {
|
||||
int totalSize = 0;
|
||||
for (byte[] tCrl : tmpCrls) {
|
||||
totalSize += tCrl.length;
|
||||
}
|
||||
if (totalSize <= MAX_CRL_DOWNLOAD_SIZE) {
|
||||
encodedCRL = tmpCrls;
|
||||
} else {
|
||||
if (debug != null) {
|
||||
debug.println("Received " + tmpCrls.length +
|
||||
" CRL(s). Combined length of " + totalSize +
|
||||
" exceeds configured maximum. Discarding.");
|
||||
}
|
||||
encodedCRL = new byte[0][];
|
||||
}
|
||||
} else {
|
||||
// Download limits disabled
|
||||
encodedCRL = tmpCrls;
|
||||
}
|
||||
} catch (NamingException namingEx) {
|
||||
throw new CertStoreException(namingEx);
|
||||
}
|
||||
|
||||
@ -770,15 +770,24 @@ class ServerImpl {
|
||||
requestLine, "Bad request line");
|
||||
return;
|
||||
}
|
||||
|
||||
// Read the request URI
|
||||
String uriStr = requestLine.substring(start, space);
|
||||
// Reject ambiguous URIs
|
||||
if (uriStr.startsWith("//")) {
|
||||
reject(Code.HTTP_BAD_REQUEST,
|
||||
requestLine, "Bad request URI");
|
||||
return;
|
||||
}
|
||||
URI uri;
|
||||
try {
|
||||
uri = new URI(uriStr);
|
||||
} catch (URISyntaxException e3) {
|
||||
reject(Code.HTTP_BAD_REQUEST,
|
||||
requestLine, "URISyntaxException thrown");
|
||||
requestLine, "Bad request URI");
|
||||
return;
|
||||
}
|
||||
|
||||
start = space+1;
|
||||
String version = requestLine.substring(start);
|
||||
Headers headers = req.headers();
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2005, 2026, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -106,16 +106,22 @@ public final class FileServerHandler implements HttpHandler {
|
||||
|
||||
private void handleSupportedMethod(HttpExchange exchange, Path path, boolean writeBody)
|
||||
throws IOException {
|
||||
boolean requestURIEndsWithSlash = pathEndsWithSlash(exchange);
|
||||
if (Files.isDirectory(path)) {
|
||||
if (missingSlash(exchange)) {
|
||||
if (!requestURIEndsWithSlash) {
|
||||
handleMovedPermanently(exchange);
|
||||
return;
|
||||
}
|
||||
if (indexFile(path) != null) {
|
||||
serveFile(exchange, indexFile(path), writeBody);
|
||||
Path indexFile = indexFile(path);
|
||||
if (indexFile != null) {
|
||||
serveFile(exchange, indexFile, writeBody);
|
||||
} else {
|
||||
listFiles(exchange, path, writeBody);
|
||||
}
|
||||
}
|
||||
// Disallow non-directory paths ending with slash
|
||||
else if (requestURIEndsWithSlash) {
|
||||
handleNotFound(exchange);
|
||||
} else {
|
||||
serveFile(exchange, path, writeBody);
|
||||
}
|
||||
@ -126,10 +132,6 @@ public final class FileServerHandler implements HttpHandler {
|
||||
exchange.sendResponseHeaders(301, RSPBODY_EMPTY);
|
||||
}
|
||||
|
||||
private void handleForbidden(HttpExchange exchange) throws IOException {
|
||||
exchange.sendResponseHeaders(403, RSPBODY_EMPTY);
|
||||
}
|
||||
|
||||
private void handleNotFound(HttpExchange exchange) throws IOException {
|
||||
String fileNotFound = ResourceBundleHelper.getMessage("html.not.found");
|
||||
var bytes = (openHTML
|
||||
@ -161,8 +163,8 @@ public final class FileServerHandler implements HttpHandler {
|
||||
return query == null ? redirectPath : redirectPath + "?" + query;
|
||||
}
|
||||
|
||||
private static boolean missingSlash(HttpExchange exchange) {
|
||||
return !exchange.getRequestURI().getPath().endsWith("/");
|
||||
private static boolean pathEndsWithSlash(HttpExchange exchange) {
|
||||
return exchange.getRequestURI().getPath().endsWith("/");
|
||||
}
|
||||
|
||||
private static String contextPath(HttpExchange exchange) {
|
||||
|
||||
116
test/lib-test/jdk/test/lib/security/DerUtilsTest.java
Normal file
116
test/lib-test/jdk/test/lib/security/DerUtilsTest.java
Normal file
@ -0,0 +1,116 @@
|
||||
/*
|
||||
* Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HexFormat;
|
||||
|
||||
import jdk.test.lib.Asserts;
|
||||
import jdk.test.lib.Utils;
|
||||
import jdk.test.lib.security.DerUtils;
|
||||
import sun.security.util.DerOutputStream;
|
||||
import sun.security.util.DerValue;
|
||||
import sun.security.util.KnownOIDs;
|
||||
import sun.security.util.ObjectIdentifier;
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8381049
|
||||
* @library /test/lib
|
||||
* @modules java.base/sun.security.util
|
||||
* @summary Tests DerUtils navigation, assertions, and editing helpers
|
||||
*/
|
||||
public class DerUtilsTest {
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
//0000:0015 [] SEQUENCE
|
||||
//0002:0004 [0] OID 1.2.3
|
||||
//0006:0003 [1] INTEGER 1
|
||||
//0009:000C [2] OCTET STRING
|
||||
// >>> into 10 octets
|
||||
//000B:000A [2c] SEQUENCE
|
||||
//000D:0005 [2c0] OID 2.5.4.3 (CommonName)
|
||||
//0012:0003 [2c1] INTEGER 2
|
||||
byte[] der = bytes("30 13 06022a03 020101 04 0a 30 08 0603550403 020102");
|
||||
|
||||
// Test innerDerValue
|
||||
Asserts.assertEQ(DerUtils.innerDerValue(der, "0").getOID(),
|
||||
ObjectIdentifier.of("1.2.3"));
|
||||
Asserts.assertEQ(DerUtils.innerDerValue(der, "1").getInteger(), 1);
|
||||
Asserts.assertEQ(DerUtils.innerDerValue(der, "2c0").getOID(),
|
||||
ObjectIdentifier.of(KnownOIDs.CommonName));
|
||||
Asserts.assertEQ(DerUtils.innerDerValue(der, "2c1").getInteger(), 2);
|
||||
Asserts.assertTrue(DerUtils.innerDerValue(der, "3") == null);
|
||||
|
||||
// Test checks
|
||||
DerUtils.checkAlg(der, "0", ObjectIdentifier.of("1.2.3"));
|
||||
DerUtils.checkInt(der, "1", 1);
|
||||
DerUtils.checkAlg(der, "2c0", ObjectIdentifier.of(KnownOIDs.CommonName));
|
||||
DerUtils.checkInt(der, "2c1", 2);
|
||||
DerUtils.shouldNotExist(der, "3");
|
||||
|
||||
// Test edit
|
||||
der = DerUtils.edit(der, "0", oidValue("1.2.3.4"));
|
||||
Asserts.assertEqualsByteArray(
|
||||
bytes("30 14 06032a0304 020101 04 0a 30 08 0603550403 020102"), der);
|
||||
|
||||
der = DerUtils.edit(der, "2c1", intValue(8));
|
||||
Asserts.assertEqualsByteArray(
|
||||
bytes("30 14 06032a0304 020101 04 0a 30 08 0603550403 020108"), der);
|
||||
|
||||
der = DerUtils.edit(der, "1", null);
|
||||
Asserts.assertEqualsByteArray(
|
||||
bytes("30 11 06032a0304 04 0a 30 08 0603550403 020108"), der);
|
||||
|
||||
// Test insert
|
||||
der = DerUtils.insert(der, "0", oidValue("1.2.5"));
|
||||
Asserts.assertEqualsByteArray(
|
||||
bytes("30 15 06022a05 06032a0304 04 0a 30 08 0603550403 020108"), der);
|
||||
|
||||
der = DerUtils.insert(der, "2c1", intValue(9));
|
||||
Asserts.assertEqualsByteArray(
|
||||
bytes("30 18 06022a05 06032a0304 04 0d 30 0b 0603550403 020109 020108"), der);
|
||||
|
||||
der = DerUtils.insert(der, "2c1", oidValue("1.2.6"));
|
||||
Asserts.assertEqualsByteArray(
|
||||
bytes("30 1c 06022a05 06032a0304 04 11 30 0f 0603550403 06022a06 020109 020108"), der);
|
||||
|
||||
// Cannot insert into a position ends with "c"
|
||||
var derClone = der.clone(); // non-final reference cannot be used in lambda
|
||||
Utils.runAndCheckException(() -> DerUtils.insert(derClone, "2c",
|
||||
oidValue("1.2.7")), IOException.class);
|
||||
}
|
||||
|
||||
static DerValue oidValue(String oid) throws IOException {
|
||||
return DerValue.wrap(new DerOutputStream()
|
||||
.putOID(ObjectIdentifier.of(oid)).toByteArray());
|
||||
}
|
||||
|
||||
static DerValue intValue(int value) throws IOException {
|
||||
return DerValue.wrap(new DerOutputStream()
|
||||
.putInteger(value).toByteArray());
|
||||
}
|
||||
|
||||
public static byte[] bytes(String hex) {
|
||||
return HexFormat.of().parseHex(hex.replace(" ", ""));
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -24,6 +24,7 @@
|
||||
package jdk.test.lib.security;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.IDN;
|
||||
import java.security.cert.*;
|
||||
import java.security.cert.Extension;
|
||||
import java.util.*;
|
||||
@ -41,11 +42,15 @@ import sun.security.x509.AccessDescription;
|
||||
import sun.security.x509.AlgorithmId;
|
||||
import sun.security.x509.AuthorityInfoAccessExtension;
|
||||
import sun.security.x509.AuthorityKeyIdentifierExtension;
|
||||
import sun.security.x509.CRLDistributionPointsExtension;
|
||||
import sun.security.x509.GeneralSubtrees;
|
||||
import sun.security.x509.IPAddressName;
|
||||
import sun.security.x509.NameConstraintsExtension;
|
||||
import sun.security.x509.SubjectKeyIdentifierExtension;
|
||||
import sun.security.x509.BasicConstraintsExtension;
|
||||
import sun.security.x509.CertificateSerialNumber;
|
||||
import sun.security.x509.ExtendedKeyUsageExtension;
|
||||
import sun.security.x509.DistributionPoint;
|
||||
import sun.security.x509.DNSName;
|
||||
import sun.security.x509.GeneralName;
|
||||
import sun.security.x509.GeneralNames;
|
||||
@ -58,13 +63,13 @@ import sun.security.x509.X500Name;
|
||||
|
||||
/**
|
||||
* Helper class that builds and signs X.509 certificates.
|
||||
*
|
||||
* <p>
|
||||
* A CertificateBuilder is created with a default constructor, and then
|
||||
* uses additional public methods to set the public key, desired validity
|
||||
* dates, serial number and extensions. It is expected that the caller will
|
||||
* have generated the necessary key pairs prior to using a CertificateBuilder
|
||||
* to generate certificates.
|
||||
*
|
||||
* <p>
|
||||
* The following methods are mandatory before calling build():
|
||||
* <UL>
|
||||
* <LI>{@link #setSubjectName(java.lang.String)}
|
||||
@ -78,12 +83,12 @@ import sun.security.x509.X500Name;
|
||||
* Additionally, the caller can either provide a {@link List} of
|
||||
* {@link Extension} objects, or use the helper classes to add specific
|
||||
* extension types.
|
||||
*
|
||||
* <p>
|
||||
* When all required and desired parameters are set, the
|
||||
* {@link #build(java.security.cert.X509Certificate, java.security.PrivateKey,
|
||||
* java.lang.String)} method can be used to create the {@link X509Certificate}
|
||||
* object.
|
||||
*
|
||||
* <p>
|
||||
* Multiple certificates may be cut from the same settings using subsequent
|
||||
* calls to the build method. Settings may be cleared using the
|
||||
* {@link #reset()} method.
|
||||
@ -109,20 +114,23 @@ public class CertificateBuilder {
|
||||
KEY_CERT_SIGN,
|
||||
CRL_SIGN,
|
||||
ENCIPHER_ONLY,
|
||||
DECIPHER_ONLY;
|
||||
DECIPHER_ONLY
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new CertificateBuilder instance. This method sets the subject name,
|
||||
* public key, authority key id, and serial number.
|
||||
* Create a new {@code CertificateBuilder} instance. This method sets the
|
||||
* subject name, public key, authority key id, and serial number.
|
||||
*
|
||||
* @param subjectName entity associated with the public key
|
||||
* @param publicKey the entity's public key
|
||||
* @param caKey public key of certificate signer
|
||||
* @param keyUsages list of key uses
|
||||
* @return
|
||||
* @throws CertificateException
|
||||
* @throws IOException
|
||||
* @return a {@code CertificateBuilder} configured with the provided
|
||||
* parameters
|
||||
*
|
||||
* @throws CertificateException if an error occurs when obtaining the
|
||||
* underlying {@link CertificateFactory}
|
||||
* @throws IOException if any extension encoding errors occur
|
||||
*/
|
||||
public static CertificateBuilder newCertificateBuilder(String subjectName,
|
||||
PublicKey publicKey, PublicKey caKey, KeyUsage... keyUsages)
|
||||
@ -148,9 +156,13 @@ public class CertificateBuilder {
|
||||
|
||||
/**
|
||||
* Create a Subject Alternative Name extension for the given DNS name
|
||||
*
|
||||
* @param critical Sets the extension to critical or non-critical
|
||||
* @param dnsName DNS name to use in the extension
|
||||
* @throws IOException
|
||||
* @param dnsNames one or more DNS names to use in the extension
|
||||
* @return a {@code SubjectAlternativeNameExtension} configured with
|
||||
* the {@code dnsNames} as individual DNSName entries.
|
||||
*
|
||||
* @throws IOException if any encoding errors occur
|
||||
*/
|
||||
public static SubjectAlternativeNameExtension createDNSSubjectAltNameExt(
|
||||
boolean critical, String... dnsNames) throws IOException {
|
||||
@ -163,9 +175,13 @@ public class CertificateBuilder {
|
||||
|
||||
/**
|
||||
* Create a Subject Alternative Name extension for the given IP address
|
||||
*
|
||||
* @param critical Sets the extension to critical or non-critical
|
||||
* @param ipAddresses IP addresses to use in the extension
|
||||
* @throws IOException
|
||||
* @param ipAddresses one or more IP addresses to use in the extension
|
||||
* @return a {@code SubjectAlternativeNameExtension} configured with
|
||||
* the {@code ipAddresses} as individual IPAddressName entries.
|
||||
*
|
||||
* @throws IOException if any encoding errors occur
|
||||
*/
|
||||
public static SubjectAlternativeNameExtension createIPSubjectAltNameExt(
|
||||
boolean critical, String... ipAddresses) throws IOException {
|
||||
@ -212,6 +228,9 @@ public class CertificateBuilder {
|
||||
* Set the subject name for the certificate.
|
||||
*
|
||||
* @param name The subject name in RFC 2253 format
|
||||
*
|
||||
* @throws IllegalArgumentException if any parsing errors on the
|
||||
* {@code name} parameter occur.
|
||||
*/
|
||||
public CertificateBuilder setSubjectName(String name) {
|
||||
try {
|
||||
@ -238,6 +257,9 @@ public class CertificateBuilder {
|
||||
* Set the public key for this certificate.
|
||||
*
|
||||
* @param pubKey The {@link PublicKey} to be used on this certificate.
|
||||
*
|
||||
* @throws NullPointerException if the {@code pubKey} parameter
|
||||
* is {@code null}
|
||||
*/
|
||||
public CertificateBuilder setPublicKey(PublicKey pubKey) {
|
||||
publicKey = Objects.requireNonNull(pubKey, "Caught null public key");
|
||||
@ -249,6 +271,9 @@ public class CertificateBuilder {
|
||||
*
|
||||
* @param nbDate A {@link Date} object specifying the start of the
|
||||
* certificate validity period.
|
||||
*
|
||||
* @throws NullPointerException if the {@code nbDate} parameter
|
||||
* is {@code null}
|
||||
*/
|
||||
public CertificateBuilder setNotBefore(Date nbDate) {
|
||||
Objects.requireNonNull(nbDate, "Caught null notBefore date");
|
||||
@ -261,6 +286,9 @@ public class CertificateBuilder {
|
||||
*
|
||||
* @param naDate A {@link Date} object specifying the end of the
|
||||
* certificate validity period.
|
||||
*
|
||||
* @throws NullPointerException if the {@code naDate} parameter
|
||||
* is {@code null}
|
||||
*/
|
||||
public CertificateBuilder setNotAfter(Date naDate) {
|
||||
Objects.requireNonNull(naDate, "Caught null notAfter date");
|
||||
@ -275,6 +303,9 @@ public class CertificateBuilder {
|
||||
* certificate validity period.
|
||||
* @param naDate A {@link Date} object specifying the end of the
|
||||
* certificate validity period.
|
||||
*
|
||||
* @throws NullPointerException if either the {@code nbDate} or
|
||||
* {@code naDate} parameters are {@code null}
|
||||
*/
|
||||
public CertificateBuilder setValidity(Date nbDate, Date naDate) {
|
||||
return setNotBefore(nbDate).setNotAfter(naDate);
|
||||
@ -289,6 +320,8 @@ public class CertificateBuilder {
|
||||
* Set the serial number on the certificate.
|
||||
*
|
||||
* @param serial A serial number in {@link BigInteger} form.
|
||||
*
|
||||
* @throws NullPointerException if {@code serial} is {@code null}
|
||||
*/
|
||||
public CertificateBuilder setSerialNumber(BigInteger serial) {
|
||||
Objects.requireNonNull(serial, "Caught null serial number");
|
||||
@ -313,6 +346,8 @@ public class CertificateBuilder {
|
||||
*
|
||||
* @param extList The {@link List} of extensions to be added to
|
||||
* the certificate.
|
||||
*
|
||||
* @throws NullPointerException if {@code extList} is {@code null}
|
||||
*/
|
||||
public CertificateBuilder addExtensions(List<Extension> extList) {
|
||||
Objects.requireNonNull(extList, "Caught null extension list");
|
||||
@ -334,7 +369,8 @@ public class CertificateBuilder {
|
||||
if (!dnsNames.isEmpty()) {
|
||||
GeneralNames gNames = new GeneralNames();
|
||||
for (String name : dnsNames) {
|
||||
gNames.add(new GeneralName(new DNSName(name)));
|
||||
gNames.add(new GeneralName(new DNSName(new DerValue(
|
||||
DerValue.tag_IA5String, IDN.toASCII(name)))));
|
||||
}
|
||||
addExtension(new SubjectAlternativeNameExtension(false,
|
||||
gNames));
|
||||
@ -347,6 +383,7 @@ public class CertificateBuilder {
|
||||
*
|
||||
* @param ipAddresses A {@code List} of names to add as IPAddress
|
||||
* types
|
||||
*
|
||||
* @throws IOException if an encoding error occurs.
|
||||
*/
|
||||
public CertificateBuilder addSubjectAltNameIPExt(List<String> ipAddresses)
|
||||
@ -362,13 +399,41 @@ public class CertificateBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to add one or more distribution points to the CRL
|
||||
* Distribution Points extension. This form of the method only supports
|
||||
* URI name types, but can be extended in the future to support other types.
|
||||
*
|
||||
* @param uriNames a list of URIs in String form
|
||||
* @return the {@code CertificateBuilder} configured to add this
|
||||
* CRL Distribution Points extension.
|
||||
*
|
||||
* @throws IOException if any of the URIs in {@code uriNames} are
|
||||
* malformed
|
||||
*/
|
||||
public CertificateBuilder addCrlDistributionPointsExt(List<String> uriNames)
|
||||
throws IOException {
|
||||
if (uriNames != null && !uriNames.isEmpty()) {
|
||||
GeneralNames gNames = new GeneralNames();
|
||||
for (String name : uriNames) {
|
||||
gNames.add(new GeneralName(new URIName(name)));
|
||||
}
|
||||
addExtension(new CRLDistributionPointsExtension(List.of(
|
||||
new DistributionPoint(gNames, null, null))));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to add one or more OCSP URIs to the Authority Info Access
|
||||
* certificate extension. Location strings can be in two forms:
|
||||
* 1) Just a URI by itself: This will be treated as using the OCSP
|
||||
* <ol>
|
||||
* <li>Just a URI by itself: This will be treated as using the OCSP
|
||||
* access description (legacy behavior).
|
||||
* 2) An access description name (case-insensitive) followed by a
|
||||
* pipe (|) and the URI (e.g. OCSP|http://ocsp.company.com/revcheck).
|
||||
* <li>An access description name (case-insensitive) followed by a
|
||||
* pipe (|) and the URI (e.g.
|
||||
* {@code OCSP|http://ocsp.company.com/revcheck}).
|
||||
* </ol>
|
||||
* Current description names are OCSP and CAISSUER. Others may be
|
||||
* added later.
|
||||
*
|
||||
@ -389,16 +454,12 @@ public class CertificateBuilder {
|
||||
adObj = AccessDescription.Ad_OCSP_Id;
|
||||
uriLoc = tokens[0];
|
||||
} else {
|
||||
switch (tokens[0].toUpperCase()) {
|
||||
case "OCSP":
|
||||
adObj = AccessDescription.Ad_OCSP_Id;
|
||||
break;
|
||||
case "CAISSUER":
|
||||
adObj = AccessDescription.Ad_CAISSUERS_Id;
|
||||
break;
|
||||
default:
|
||||
throw new IOException("Unknown AD: " + tokens[0]);
|
||||
}
|
||||
adObj = switch (tokens[0].toUpperCase()) {
|
||||
case "OCSP" -> AccessDescription.Ad_OCSP_Id;
|
||||
case "CAISSUER" -> AccessDescription.Ad_CAISSUERS_Id;
|
||||
default -> throw new IOException("Unknown AD: " +
|
||||
tokens[0]);
|
||||
};
|
||||
uriLoc = tokens[1];
|
||||
}
|
||||
acDescList.add(new AccessDescription(adObj,
|
||||
@ -437,6 +498,17 @@ public class CertificateBuilder {
|
||||
maxPathLen));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Name Constraints Extension for a certificate.
|
||||
*
|
||||
* @param permitted permitted names
|
||||
* @param excluded excluded names
|
||||
*/
|
||||
public CertificateBuilder addNameConstraintsExt(
|
||||
GeneralSubtrees permitted, GeneralSubtrees excluded) {
|
||||
return addExtension(new NameConstraintsExtension(permitted, excluded));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the Authority Key Identifier extension.
|
||||
*
|
||||
@ -554,7 +626,7 @@ public class CertificateBuilder {
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode the contents of the outer-most ASN.1 SEQUENCE:
|
||||
* Encode the contents of the outermost ASN.1 SEQUENCE:
|
||||
*
|
||||
* <PRE>
|
||||
* Certificate ::= SEQUENCE {
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -24,6 +24,7 @@ package jdk.test.lib.security;
|
||||
|
||||
import jdk.test.lib.Asserts;
|
||||
import sun.security.util.DerInputStream;
|
||||
import sun.security.util.DerOutputStream;
|
||||
import sun.security.util.DerValue;
|
||||
import sun.security.util.KnownOIDs;
|
||||
import sun.security.util.ObjectIdentifier;
|
||||
@ -124,4 +125,84 @@ public class DerUtils {
|
||||
throws Exception {
|
||||
Asserts.assertTrue(innerDerValue(der, location) == null);
|
||||
}
|
||||
|
||||
/// Replaces a `DerValue` (deep) inside with another one.
|
||||
///
|
||||
/// @param data the `DerValue`
|
||||
/// @param target the location to edit. Cannot be empty.
|
||||
/// @param replacement replace the value at `target` with this. Can be a `DerValue`
|
||||
/// or a `DerOutputStream`. Remove if `null`.
|
||||
/// @return the new value
|
||||
public static byte[] edit(byte[] data, String target, Object replacement)
|
||||
throws IOException {
|
||||
if (target.isEmpty()) throw new IOException("Must be a sub-location");
|
||||
return modify0(data, "", target, replacement, false).toByteArray();
|
||||
}
|
||||
|
||||
/// Inserts a `DerValue` (deep) into another one.
|
||||
///
|
||||
/// @param data the `DerValue`
|
||||
/// @param target the location to insert at. Cannot be empty. The new value
|
||||
/// is inserted before the existing value at `target`, and following
|
||||
/// values are shifted. After insertion, the value at `target`
|
||||
/// is the inserted value. A target ending exactly with `c` is not
|
||||
/// a valid insertion position because the content of an OCTET
|
||||
/// STRING must be only one `DerValue`.
|
||||
/// @param addition the value to insert. Can be a `DerValue` or a
|
||||
/// `DerOutputStream`
|
||||
/// @return the new value
|
||||
public static byte[] insert(byte[] data, String target, Object addition)
|
||||
throws IOException {
|
||||
if (target.isEmpty()) throw new IOException("Must be a sub-location");
|
||||
return modify0(data, "", target, addition, true).toByteArray();
|
||||
}
|
||||
|
||||
/// Implementation of [#edit] and [#insert], recursively.
|
||||
///
|
||||
/// @param data the `DerValue`
|
||||
/// @param now the current location
|
||||
/// @param target the location to edit or insert at
|
||||
/// @param replacement the replacement or inserted value
|
||||
/// @param insert true to insert before the target, false to replace it
|
||||
/// @return the new value at this location
|
||||
private static DerOutputStream modify0(byte[] data, String now, String target,
|
||||
Object replacement, boolean insert) throws IOException {
|
||||
var out = new DerOutputStream();
|
||||
var parent = DerUtils.innerDerValue(data, now);
|
||||
if (target.equals(now + "c")) {
|
||||
if (insert) {
|
||||
throw new IOException("Action cannot be performed at position " + target);
|
||||
}
|
||||
if (replacement instanceof DerValue v) {
|
||||
out.putDerValue(v);
|
||||
} else if (replacement instanceof DerOutputStream s) {
|
||||
out.write(s);
|
||||
}
|
||||
} else if (target.startsWith(now + "c")) { // not there yet, go inside
|
||||
return out.write(parent.tag, modify0(data, now + "c", target, replacement, insert));
|
||||
} else {
|
||||
for (int i = 0; ; i++) {
|
||||
// We only support locations of one digit now
|
||||
if (i > 9) throw new IllegalStateException("Too big " + i);
|
||||
String pos = now + i;
|
||||
var sub = DerUtils.innerDerValue(data, pos); // current value
|
||||
if (sub == null) break; // at the end
|
||||
if (target.equals(pos)) { // the one we want to change
|
||||
if (replacement instanceof DerValue v) {
|
||||
out.putDerValue(v);
|
||||
} else if (replacement instanceof DerOutputStream s) {
|
||||
out.write(s);
|
||||
}
|
||||
if (insert) {
|
||||
out.putDerValue(sub);
|
||||
}
|
||||
} else if (target.startsWith(pos)) { // not there yet, go inside
|
||||
out.write(modify0(data, pos, target, replacement, insert));
|
||||
} else { // the untouched values
|
||||
out.putDerValue(sub);
|
||||
}
|
||||
}
|
||||
}
|
||||
return new DerOutputStream().write(parent.tag, out);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -148,7 +148,6 @@ public class TsaHandler implements HttpHandler {
|
||||
*/
|
||||
protected TsaParam getParam(URI uri) {
|
||||
String query = uri.getQuery();
|
||||
|
||||
TsaParam param = TsaParam.newInstance();
|
||||
if (query != null) {
|
||||
for (String bufParam : query.split("&")) {
|
||||
@ -186,6 +185,12 @@ public class TsaHandler implements HttpHandler {
|
||||
} else if ("certReq".equalsIgnoreCase(pair[0])) {
|
||||
param.certReq(Boolean.valueOf(pair[1]));
|
||||
System.out.println("certReq: " + param.certReq());
|
||||
} else if ("noSignedAttrs".equalsIgnoreCase(pair[0])) {
|
||||
param.noSignedAttrs(Boolean.valueOf(pair[1]));
|
||||
System.out.println("noSignedAttrs: " + param.noSignedAttrs());
|
||||
} else if ("notTimestampOID".equalsIgnoreCase(pair[0])) {
|
||||
param.notTimestampOID(Boolean.valueOf(pair[1]));
|
||||
System.out.println("notTimestampOID: " + param.notTimestampOID());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -71,6 +71,12 @@ public class TsaParam {
|
||||
// Indicate if request TSA server certificate
|
||||
private Boolean certReq;
|
||||
|
||||
// Do not create signedAttrs
|
||||
private Boolean noSignedAttrs;
|
||||
|
||||
// Do not use TIMESTAMP_TOKEN_INFO_OID
|
||||
private Boolean notTimestampOID;
|
||||
|
||||
public static TsaParam newInstance() {
|
||||
return new TsaParam();
|
||||
}
|
||||
@ -177,4 +183,22 @@ public class TsaParam {
|
||||
this.certReq = certReq;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Boolean noSignedAttrs() {
|
||||
return noSignedAttrs;
|
||||
}
|
||||
|
||||
public TsaParam noSignedAttrs(Boolean noSignedAttrs) {
|
||||
this.noSignedAttrs = noSignedAttrs;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Boolean notTimestampOID() {
|
||||
return notTimestampOID;
|
||||
}
|
||||
|
||||
public TsaParam notTimestampOID(Boolean notTimestampOID) {
|
||||
this.notTimestampOID = notTimestampOID;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -23,8 +23,8 @@
|
||||
|
||||
package jdk.test.lib.security.timestamp;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.math.BigInteger;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.Signature;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.Date;
|
||||
@ -33,6 +33,8 @@ import java.util.Objects;
|
||||
import jdk.test.lib.hexdump.HexPrinter;
|
||||
import sun.security.pkcs.ContentInfo;
|
||||
import sun.security.pkcs.PKCS7;
|
||||
import sun.security.pkcs.PKCS9Attribute;
|
||||
import sun.security.pkcs.PKCS9Attributes;
|
||||
import sun.security.pkcs.SignerInfo;
|
||||
import sun.security.util.*;
|
||||
import sun.security.x509.AlgorithmId;
|
||||
@ -202,8 +204,11 @@ public class TsaSigner {
|
||||
DerOutputStream eContentOut = new DerOutputStream();
|
||||
eContentOut.putOctetString(tstInfoSeqData);
|
||||
|
||||
ObjectIdentifier infoOid = respParam.notTimestampOID() == Boolean.TRUE
|
||||
? ContentInfo.DATA_OID
|
||||
: ContentInfo.TIMESTAMP_TOKEN_INFO_OID;
|
||||
ContentInfo eContentInfo = new ContentInfo(
|
||||
ObjectIdentifier.of(KnownOIDs.TimeStampTokenInfo),
|
||||
infoOid,
|
||||
new DerValue(eContentOut.toByteArray()));
|
||||
|
||||
String defaultSigAlgo = SignatureUtil.getDefaultSigAlgForKey(
|
||||
@ -213,16 +218,36 @@ public class TsaSigner {
|
||||
System.out.println(
|
||||
"Signature algorithm: " + signature.getAlgorithm());
|
||||
signature.initSign(signerEntry.privateKey);
|
||||
signature.update(tstInfoSeqData);
|
||||
|
||||
AlgorithmId digestAlg = SignatureUtil.getDigestAlgInPkcs7SignerInfo(
|
||||
signature, sigAlgo, signerEntry.privateKey,
|
||||
signerEntry.cert.getPublicKey(), false);
|
||||
|
||||
PKCS9Attributes authAttrs = null;
|
||||
|
||||
if (respParam.noSignedAttrs() == Boolean.TRUE) {
|
||||
signature.update(tstInfoSeqData);
|
||||
} else {
|
||||
authAttrs = new PKCS9Attributes(new PKCS9Attribute[]{
|
||||
new PKCS9Attribute(PKCS9Attribute.CONTENT_TYPE_OID,
|
||||
infoOid),
|
||||
new PKCS9Attribute(PKCS9Attribute.SIGNING_TIME_OID,
|
||||
new Date()),
|
||||
new PKCS9Attribute(PKCS9Attribute.MESSAGE_DIGEST_OID,
|
||||
MessageDigest.getInstance(digestAlg.getName())
|
||||
.digest(tstInfoSeqData))
|
||||
});
|
||||
signature.update(authAttrs.getDerEncoding());
|
||||
}
|
||||
|
||||
SignerInfo signerInfo = new SignerInfo(
|
||||
new X500Name(issuerName),
|
||||
signerEntry.cert.getSerialNumber(),
|
||||
SignatureUtil.getDigestAlgInPkcs7SignerInfo(
|
||||
signature, sigAlgo, signerEntry.privateKey,
|
||||
signerEntry.cert.getPublicKey(), false),
|
||||
digestAlg,
|
||||
authAttrs,
|
||||
AlgorithmId.get(sigAlgo),
|
||||
signature.sign());
|
||||
signature.sign(),
|
||||
null);
|
||||
|
||||
X509Certificate[] signerCertChain = interceptor.getSignerCertChain(
|
||||
signerEntry.certChain, requestParam.certReq());
|
||||
|
||||
@ -0,0 +1,166 @@
|
||||
/*
|
||||
* Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package org.openjdk.bench.javax.imageio.plugins.jpeg;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Iterator;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.openjdk.jmh.annotations.Benchmark;
|
||||
import org.openjdk.jmh.annotations.BenchmarkMode;
|
||||
import org.openjdk.jmh.annotations.Fork;
|
||||
import org.openjdk.jmh.annotations.Measurement;
|
||||
import org.openjdk.jmh.annotations.Mode;
|
||||
import org.openjdk.jmh.annotations.OutputTimeUnit;
|
||||
import org.openjdk.jmh.annotations.Scope;
|
||||
import org.openjdk.jmh.annotations.Setup;
|
||||
import org.openjdk.jmh.annotations.State;
|
||||
import org.openjdk.jmh.annotations.Warmup;
|
||||
import org.openjdk.jmh.infra.Blackhole;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.imageio.ImageReader;
|
||||
import javax.imageio.event.IIOReadProgressListener;
|
||||
import javax.imageio.stream.ImageInputStream;
|
||||
|
||||
/**
|
||||
* Measure time taken to read large jpeg image
|
||||
* make test TEST="micro:javax.imageio.plugins.jpeg.LargeJpegReadWithProgressBench"
|
||||
*/
|
||||
@BenchmarkMode(Mode.AverageTime)
|
||||
@OutputTimeUnit(TimeUnit.MILLISECONDS)
|
||||
@Warmup(iterations = 5, time = 1)
|
||||
@Measurement(iterations = 5, time = 1)
|
||||
@Fork(3)
|
||||
@State(Scope.Benchmark)
|
||||
public class LargeJpegReadWithProgressBench {
|
||||
|
||||
private static final File pwd = new File(".");
|
||||
private static ImageReader reader;
|
||||
|
||||
@Setup
|
||||
public void setup() throws IOException {
|
||||
BufferedImage src = createSource();
|
||||
ImageInputStream iis = prepareInput(src);
|
||||
reader = null;
|
||||
Iterator<ImageReader> it = ImageIO.getImageReadersByFormatName("jpeg");
|
||||
if (it.hasNext()) {
|
||||
reader = (ImageReader)it.next();
|
||||
} else {
|
||||
throw new RuntimeException("Could not find JPEG reader");
|
||||
}
|
||||
reader.setInput(iis);
|
||||
ImageReadProgressListener listener = new ImageReadProgressListener();
|
||||
reader.addIIOReadProgressListener(listener);
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public void readLargeJpegImage(Blackhole bh) throws IOException {
|
||||
reader.read(0);
|
||||
}
|
||||
|
||||
private static BufferedImage createSource() {
|
||||
int width = 2000;
|
||||
int height = 2000;
|
||||
int squareSize = 20;
|
||||
|
||||
Color red = Color.RED;
|
||||
Color green = Color.GREEN;
|
||||
BufferedImage image = new BufferedImage(width, height,
|
||||
BufferedImage.TYPE_INT_RGB);
|
||||
for (int y = 0; y < height; y++) {
|
||||
for (int x = 0; x < width; x++) {
|
||||
if (((x / squareSize) + (y / squareSize)) % 2 == 0) {
|
||||
image.setRGB(x, y, red.getRGB());
|
||||
} else {
|
||||
image.setRGB(x, y, green.getRGB());
|
||||
}
|
||||
}
|
||||
}
|
||||
return image;
|
||||
}
|
||||
|
||||
private static ImageInputStream prepareInput(BufferedImage src)
|
||||
throws IOException {
|
||||
File f = File.createTempFile("src_", ".jpeg", pwd);
|
||||
if (ImageIO.write(src, "jpeg", f)) {
|
||||
ImageInputStream iis = ImageIO.createImageInputStream(f);
|
||||
f.deleteOnExit();
|
||||
return iis;
|
||||
} else {
|
||||
throw new RuntimeException("Unable to write jpeg image");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ImageReadProgressListener implements IIOReadProgressListener {
|
||||
// This class is a no-op, it is added just to have a progress listener
|
||||
@Override
|
||||
public void sequenceStarted(ImageReader source, int minIndex) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sequenceComplete(ImageReader source) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void imageStarted(ImageReader source, int imageIndex) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void imageProgress(ImageReader source, float percentageDone) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void imageComplete(ImageReader source) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void thumbnailStarted(ImageReader source, int imageIndex, int thumbnailIndex) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void thumbnailProgress(ImageReader source, float percentageDone) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void thumbnailComplete(ImageReader source) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readAborted(ImageReader source) {
|
||||
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,141 @@
|
||||
/*
|
||||
* Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package org.openjdk.bench.javax.imageio.plugins.jpeg;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Iterator;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.openjdk.jmh.annotations.Benchmark;
|
||||
import org.openjdk.jmh.annotations.BenchmarkMode;
|
||||
import org.openjdk.jmh.annotations.Fork;
|
||||
import org.openjdk.jmh.annotations.Measurement;
|
||||
import org.openjdk.jmh.annotations.Mode;
|
||||
import org.openjdk.jmh.annotations.OutputTimeUnit;
|
||||
import org.openjdk.jmh.annotations.Scope;
|
||||
import org.openjdk.jmh.annotations.Setup;
|
||||
import org.openjdk.jmh.annotations.State;
|
||||
import org.openjdk.jmh.annotations.Warmup;
|
||||
import org.openjdk.jmh.infra.Blackhole;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.imageio.ImageReader;
|
||||
import javax.imageio.ImageWriter;
|
||||
import javax.imageio.stream.ImageInputStream;
|
||||
import javax.imageio.stream.ImageOutputStream;
|
||||
|
||||
/**
|
||||
* Measure time taken to read large jpeg image
|
||||
* make test TEST="micro:javax.imageio.plugins.jpeg.LargeJpegReadWriteBench"
|
||||
*/
|
||||
@BenchmarkMode(Mode.AverageTime)
|
||||
@OutputTimeUnit(TimeUnit.MILLISECONDS)
|
||||
@Warmup(iterations = 5, time = 1)
|
||||
@Measurement(iterations = 5, time = 1)
|
||||
@Fork(3)
|
||||
@State(Scope.Benchmark)
|
||||
public class LargeJpegReadWriteBench {
|
||||
|
||||
private static final File pwd = new File(".");
|
||||
private static ImageReader reader;
|
||||
private static ImageWriter writer;
|
||||
private static BufferedImage src;
|
||||
|
||||
@Setup
|
||||
public void setup() throws IOException {
|
||||
src = createSource();
|
||||
ImageInputStream iis = prepareInput(src);
|
||||
reader = null;
|
||||
Iterator<ImageReader> readerIterator = ImageIO.getImageReadersByFormatName("jpeg");
|
||||
if (readerIterator.hasNext()) {
|
||||
reader = readerIterator.next();
|
||||
} else {
|
||||
throw new RuntimeException("Could not find JPEG reader");
|
||||
}
|
||||
reader.setInput(iis);
|
||||
|
||||
ImageOutputStream ios = prepareOutput(src);
|
||||
writer = null;
|
||||
Iterator<ImageWriter> writerIterator = ImageIO.getImageWritersByFormatName("jpeg");
|
||||
if (writerIterator.hasNext()) {
|
||||
writer = writerIterator.next();
|
||||
} else {
|
||||
throw new RuntimeException("Could not find JPEG writer");
|
||||
}
|
||||
writer.setOutput(ios);
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public void readLargeJpegImage(Blackhole bh) throws IOException {
|
||||
reader.read(0);
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public void writeLargeJpegImage(Blackhole bh) throws IOException {
|
||||
writer.write(src);
|
||||
}
|
||||
|
||||
private static BufferedImage createSource() {
|
||||
int width = 2000;
|
||||
int height = 2000;
|
||||
int squareSize = 20;
|
||||
|
||||
Color red = Color.RED;
|
||||
Color green = Color.GREEN;
|
||||
BufferedImage image = new BufferedImage(width, height,
|
||||
BufferedImage.TYPE_INT_RGB);
|
||||
for (int y = 0; y < height; y++) {
|
||||
for (int x = 0; x < width; x++) {
|
||||
if (((x / squareSize) + (y / squareSize)) % 2 == 0) {
|
||||
image.setRGB(x, y, red.getRGB());
|
||||
} else {
|
||||
image.setRGB(x, y, green.getRGB());
|
||||
}
|
||||
}
|
||||
}
|
||||
return image;
|
||||
}
|
||||
|
||||
private static ImageInputStream prepareInput(BufferedImage src)
|
||||
throws IOException {
|
||||
File f = File.createTempFile("src_", ".jpeg", pwd);
|
||||
if (ImageIO.write(src, "jpeg", f)) {
|
||||
ImageInputStream iis = ImageIO.createImageInputStream(f);
|
||||
f.deleteOnExit();
|
||||
return iis;
|
||||
} else {
|
||||
throw new RuntimeException("Unable to write jpeg image");
|
||||
}
|
||||
}
|
||||
|
||||
private static ImageOutputStream prepareOutput(BufferedImage src) throws IOException {
|
||||
File f = File.createTempFile("dest_", ".jpeg", pwd);
|
||||
ImageOutputStream ios = ImageIO.createImageOutputStream(f);
|
||||
f.deleteOnExit();
|
||||
return ios;
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user