diff --git a/src/hotspot/cpu/aarch64/aarch64.ad b/src/hotspot/cpu/aarch64/aarch64.ad index 53fa4e3066c..185d5b72013 100644 --- a/src/hotspot/cpu/aarch64/aarch64.ad +++ b/src/hotspot/cpu/aarch64/aarch64.ad @@ -7708,10 +7708,11 @@ instruct bytes_reverse_unsigned_short(iRegINoSp dst, iRegIorL2I src) %{ match(Set dst (ReverseBytesUS src)); ins_cost(INSN_COST); - format %{ "rev16w $dst, $src" %} + format %{ "rev16w $dst, $src\t# $dst -> unsigned short" %} ins_encode %{ __ rev16w(as_Register($dst$$reg), as_Register($src$$reg)); + __ narrow_subword_type(as_Register($dst$$reg), T_CHAR); %} ins_pipe(ialu_reg); diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp index 7bec0a3c0ca..40f7251600a 100644 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp @@ -2815,6 +2815,17 @@ void MacroAssembler::store_sized_value(Address dst, Register src, size_t size_in } } +void MacroAssembler::narrow_subword_type(Register reg, BasicType bt) { + assert(is_subword_type(bt), "required"); + switch (bt) { + case T_BOOLEAN: andw(reg, reg, 1); break; + case T_BYTE: sxtbw(reg, reg); break; + case T_CHAR: uxthw(reg, reg); break; + case T_SHORT: sxthw(reg, reg); break; + default: ShouldNotReachHere(); + } +} + void MacroAssembler::decrementw(Register reg, int value) { if (value < 0) { incrementw(reg, -value); return; } diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp index a6cc862d05c..e5e36d43516 100644 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp @@ -33,6 +33,7 @@ #include "oops/compressedOops.hpp" #include "oops/compressedKlass.hpp" #include "runtime/vm_version.hpp" +#include "utilities/globalDefinitions.hpp" #include "utilities/powerOfTwo.hpp" class OopMap; @@ -719,6 +720,9 @@ public: // Support for sign-extension (hi:lo = extend_sign(lo)) void extend_sign(Register hi, Register lo); + // Clean up a subword typed value to the representation in compliance with JVMS §2.3 + void narrow_subword_type(Register reg, BasicType bt); + // Load and store values by size and signed-ness void load_sized_value(Register dst, Address src, size_t size_in_bytes, bool is_signed); void store_sized_value(Address dst, Register src, size_t size_in_bytes); diff --git a/src/hotspot/cpu/arm/arm.ad b/src/hotspot/cpu/arm/arm.ad index 60a0ef307b5..45ae283e05a 100644 --- a/src/hotspot/cpu/arm/arm.ad +++ b/src/hotspot/cpu/arm/arm.ad @@ -9214,10 +9214,12 @@ instruct bytes_reverse_long(iRegL dst, iRegL src) %{ instruct bytes_reverse_unsigned_short(iRegI dst, iRegI src) %{ match(Set dst (ReverseBytesUS src)); - size(4); - format %{ "REV16 $dst,$src" %} + size(8); + format %{ "REV32 $dst,$src\n\t" + "LSR $dst,$dst,#16" %} ins_encode %{ - __ rev16($dst$$Register, $src$$Register); + __ rev($dst$$Register, $src$$Register); + __ mov($dst$$Register, AsmOperand($dst$$Register, lsr, 16)); %} ins_pipe( iload_mem ); // FIXME %} diff --git a/src/hotspot/cpu/ppc/ppc.ad b/src/hotspot/cpu/ppc/ppc.ad index f3d33b4305d..33747538e00 100644 --- a/src/hotspot/cpu/ppc/ppc.ad +++ b/src/hotspot/cpu/ppc/ppc.ad @@ -12480,6 +12480,19 @@ instruct countTrailingZerosL_cnttzd(iRegIdst dst, iRegLsrc src) %{ ins_pipe(pipe_class_default); %} +// Expand nodes for byte_reverse_int/ushort/short. +instruct rlwinm(iRegIdst dst, iRegIsrc src, immI16 shift, immI16 mb, immI16 me) %{ + effect(DEF dst, USE src, USE shift, USE mb, USE me); + predicate(false); + + format %{ "RLWINM $dst, $src, $shift, $mb, $me" %} + size(4); + ins_encode %{ + __ rlwinm($dst$$Register, $src$$Register, $shift$$constant, $mb$$constant, $me$$constant); + %} + ins_pipe(pipe_class_default); +%} + // Expand nodes for byte_reverse_int. instruct insrwi_a(iRegIdst dst, iRegIsrc src, immI16 n, immI16 b) %{ effect(DEF dst, USE src, USE n, USE b); @@ -12636,34 +12649,22 @@ instruct bytes_reverse_long(iRegLdst dst, iRegLsrc src) %{ ins_pipe(pipe_class_default); %} +// Need zero extend. Must not use brh only. instruct bytes_reverse_ushort_Ex(iRegIdst dst, iRegIsrc src) %{ match(Set dst (ReverseBytesUS src)); - predicate(!UseByteReverseInstructions); ins_cost(2*DEFAULT_COST); expand %{ + immI16 imm31 %{ (int) 31 %} + immI16 imm24 %{ (int) 24 %} immI16 imm16 %{ (int) 16 %} immI16 imm8 %{ (int) 8 %} - urShiftI_reg_imm(dst, src, imm8); + rlwinm(dst, src, imm24, imm24, imm31); insrwi(dst, src, imm8, imm16); %} %} -instruct bytes_reverse_ushort(iRegIdst dst, iRegIsrc src) %{ - match(Set dst (ReverseBytesUS src)); - predicate(UseByteReverseInstructions); - ins_cost(DEFAULT_COST); - size(4); - - format %{ "BRH $dst, $src" %} - - ins_encode %{ - __ brh($dst$$Register, $src$$Register); - %} - ins_pipe(pipe_class_default); -%} - instruct bytes_reverse_short_Ex(iRegIdst dst, iRegIsrc src) %{ match(Set dst (ReverseBytesS src)); predicate(!UseByteReverseInstructions); diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.cpp b/src/hotspot/cpu/x86/macroAssembler_x86.cpp index 5ab3ca339aa..4c851377ce5 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86.cpp @@ -55,6 +55,7 @@ #include "runtime/sharedRuntime.hpp" #include "runtime/stubRoutines.hpp" #include "utilities/checkedCast.hpp" +#include "utilities/globalDefinitions.hpp" #include "utilities/macros.hpp" #ifdef PRODUCT @@ -2540,6 +2541,17 @@ void MacroAssembler::sign_extend_short(Register reg) { movswl(reg, reg); // movsxw } +void MacroAssembler::narrow_subword_type(Register reg, BasicType bt) { + assert(is_subword_type(bt), "required"); + switch (bt) { + case T_BOOLEAN: andl(reg, 1); break; + case T_BYTE: movsbl(reg, reg); break; + case T_CHAR: movzwl(reg, reg); break; + case T_SHORT: movswl(reg, reg); break; + default: ShouldNotReachHere(); + } +} + void MacroAssembler::testl(Address dst, int32_t imm32) { if (imm32 >= 0 && is8bit(imm32)) { testb(dst, imm32); diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.hpp b/src/hotspot/cpu/x86/macroAssembler_x86.hpp index 021d2943ee8..b73339c217f 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86.hpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86.hpp @@ -444,6 +444,9 @@ class MacroAssembler: public Assembler { void sign_extend_short(Register reg); void sign_extend_byte(Register reg); + // Clean up a subword typed value to the representation in compliance with JVMS §2.3 + void narrow_subword_type(Register reg, BasicType bt); + // Division by power of 2, rounding towards 0 void division_with_shift(Register reg, int shift_value); diff --git a/src/hotspot/cpu/x86/x86.ad b/src/hotspot/cpu/x86/x86.ad index 9b80697601c..dee5a9b7d34 100644 --- a/src/hotspot/cpu/x86/x86.ad +++ b/src/hotspot/cpu/x86/x86.ad @@ -10899,10 +10899,11 @@ instruct xaddB(memory mem, rRegI newval, rFlagsReg cr) %{ predicate(!n->as_LoadStore()->result_not_used()); match(Set newval (GetAndAddB mem newval)); effect(KILL cr); - format %{ "xaddb_lock $mem, $newval" %} + format %{ "xaddb_lock $mem, $newval\t# $newval -> byte" %} ins_encode %{ __ lock(); __ xaddb($mem$$Address, $newval$$Register); + __ narrow_subword_type($newval$$Register, T_BYTE); %} ins_pipe(pipe_cmpxchg); %} @@ -10935,10 +10936,11 @@ instruct xaddS(memory mem, rRegI newval, rFlagsReg cr) %{ predicate(!n->as_LoadStore()->result_not_used()); match(Set newval (GetAndAddS mem newval)); effect(KILL cr); - format %{ "xaddw_lock $mem, $newval" %} + format %{ "xaddw_lock $mem, $newval\t# $newval -> short" %} ins_encode %{ __ lock(); __ xaddw($mem$$Address, $newval$$Register); + __ narrow_subword_type($newval$$Register, T_SHORT); %} ins_pipe(pipe_cmpxchg); %} @@ -11017,18 +11019,20 @@ instruct xaddL(memory mem, rRegL newval, rFlagsReg cr) %{ instruct xchgB( memory mem, rRegI newval) %{ match(Set newval (GetAndSetB mem newval)); - format %{ "XCHGB $newval,[$mem]" %} + format %{ "XCHGB $newval,[$mem]\t# $newval -> byte" %} ins_encode %{ __ xchgb($newval$$Register, $mem$$Address); + __ narrow_subword_type($newval$$Register, T_BYTE); %} ins_pipe( pipe_cmpxchg ); %} instruct xchgS( memory mem, rRegI newval) %{ match(Set newval (GetAndSetS mem newval)); - format %{ "XCHGW $newval,[$mem]" %} + format %{ "XCHGW $newval,[$mem]\t# $newval -> short" %} ins_encode %{ __ xchgw($newval$$Register, $mem$$Address); + __ narrow_subword_type($newval$$Register, T_SHORT); %} ins_pipe( pipe_cmpxchg ); %} @@ -25317,6 +25321,7 @@ instruct reinterpretHF2S(rRegI dst, regF src) format %{ "evmovw $dst, $src" %} ins_encode %{ __ evmovw($dst$$Register, $src$$XMMRegister); + __ narrow_subword_type($dst$$Register, T_SHORT); %} ins_pipe(pipe_slow); %} diff --git a/src/hotspot/share/classfile/classLoader.cpp b/src/hotspot/share/classfile/classLoader.cpp index c19a1770aef..6d25e460688 100644 --- a/src/hotspot/share/classfile/classLoader.cpp +++ b/src/hotspot/share/classfile/classLoader.cpp @@ -707,6 +707,7 @@ ClassPathEntry* ClassLoader::create_class_path_entry(JavaThread* current, if (zip != nullptr && error_msg == nullptr) { new_entry = new ClassPathZipEntry(zip, path); } else { + log_info(class, path)("failed: %s, err: %s", path, error_msg); return nullptr; } log_info(class, path)("opened: %s", path); diff --git a/src/java.base/share/classes/com/sun/crypto/provider/PBES1Core.java b/src/java.base/share/classes/com/sun/crypto/provider/PBES1Core.java index e10b0b1a7cf..d614412b13b 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/PBES1Core.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/PBES1Core.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2025, 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 @@ -47,7 +47,38 @@ final class PBES1Core { private final MessageDigest md; private final String algo; private byte[] salt = null; - private int iCount = 10; + // RFC 8018 and NIST SP 800-132 sec 5.2 recommend 1000 as the minimum + private int iCount = PKCS12PBECipherCore.DEFAULT_COUNT; + + // utility method for checking weak salts of PBEWithMD5AndTripleDES cipher + private static boolean isWeak(byte[] s) { + // consider salts weak if it met both of the following conditions: + // 1) s[0...3] == s[4...7] + // 2) s[0] == s[3] && s[1] == s[2] + if (Arrays.equals(s, 0, 4, s, 4, 8)) { + return (s[0] == s[3]) && (s[1] == s[2]); + } + return false; + } + + // utility method for generating 8-byte salts + private static byte[] generateSalt(String algo, SecureRandom sr) { + byte[] salt = new byte[8]; + sr.nextBytes(salt); + // check and re-generate for DESede if necessary + if (algo.equals("DESede")) { + // prevent an infinite-loop in case of a rigged SecureRandom + int numAttempts = 50; + while (isWeak(salt)) { + sr.nextBytes(salt); + if (numAttempts-- < 0) { + throw new ProviderException( + "Unable to find salts after 50 attempts"); + } + } + } + return salt; + } /** * Creates an instance of PBE Cipher using the specified CipherSpi @@ -163,8 +194,7 @@ final class PBES1Core { AlgorithmParameters getParameters() { AlgorithmParameters params; if (salt == null) { - salt = new byte[8]; - SunJCE.getRandom().nextBytes(salt); + salt = generateSalt(algo, SunJCE.getRandom()); } PBEParameterSpec pbeSpec = new PBEParameterSpec(salt, iCount); try { @@ -227,8 +257,7 @@ final class PBES1Core { if (params == null) { // create random salt and use default iteration count - salt = new byte[8]; - random.nextBytes(salt); + salt = generateSalt(algo, random); } else { if (!(params instanceof PBEParameterSpec)) { throw new InvalidAlgorithmParameterException @@ -240,6 +269,15 @@ final class PBES1Core { throw new InvalidAlgorithmParameterException ("Salt must be 8 bytes long"); } + // for DESede, reject weak salts for encryption + if (algo.equals("DESede") && + (opmode == Cipher.ENCRYPT_MODE || + opmode == Cipher.WRAP_MODE) && + isWeak(salt)) { + throw new InvalidAlgorithmParameterException( + "Weak salts cannot be used for encryption"); + } + iCount = ((PBEParameterSpec) params).getIterationCount(); if (iCount <= 0) { throw new InvalidAlgorithmParameterException diff --git a/src/java.base/share/classes/com/sun/crypto/provider/PKCS12PBECipherCore.java b/src/java.base/share/classes/com/sun/crypto/provider/PKCS12PBECipherCore.java index 7d2ba7f9831..517d7777287 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/PKCS12PBECipherCore.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/PKCS12PBECipherCore.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, 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 @@ -53,7 +53,7 @@ final class PKCS12PBECipherCore { private int iCount = 0; private static final int DEFAULT_SALT_LENGTH = 20; - private static final int DEFAULT_COUNT = 1024; + static final int DEFAULT_COUNT = 1024; static final int CIPHER_KEY = 1; static final int CIPHER_IV = 2; diff --git a/src/java.base/share/classes/jdk/internal/foreign/SegmentFactories.java b/src/java.base/share/classes/jdk/internal/foreign/SegmentFactories.java index 728ee235547..a94800711cf 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/SegmentFactories.java +++ b/src/java.base/share/classes/jdk/internal/foreign/SegmentFactories.java @@ -190,15 +190,16 @@ public class SegmentFactories { if (VM.isDirectMemoryPageAligned()) { byteAlignment = Math.max(byteAlignment, AbstractMemorySegmentImpl.NIO_ACCESS.pageSize()); } + // Always allocate at least some memory so that zero-length segments have distinct + // non-zero addresses. + byteSize = Math.max(1, byteSize); + // Align the allocation size up to a multiple of 8 so we can init the memory with longs long alignedSize = init ? Utils.alignUp(byteSize, Long.BYTES) : byteSize; // Check for wrap around if (alignedSize < 0) { throw new OutOfMemoryError(); } - // Always allocate at least some memory so that zero-length segments have distinct - // non-zero addresses. - alignedSize = Math.max(1, alignedSize); long allocationSize; long allocationBase; @@ -226,12 +227,13 @@ public class SegmentFactories { if (init) { initNativeMemory(result, alignedSize); } + final long cleanupByteSize = byteSize; sessionImpl.addOrCleanupIfFail(new MemorySessionImpl.ResourceList.ResourceCleanup() { @Override public void cleanup() { UNSAFE.freeMemory(allocationBase); if (shouldReserve) { - AbstractMemorySegmentImpl.NIO_ACCESS.unreserveMemory(allocationSize, byteSize); + AbstractMemorySegmentImpl.NIO_ACCESS.unreserveMemory(allocationSize, cleanupByteSize); } } }); diff --git a/src/java.base/share/classes/sun/security/provider/X509Factory.java b/src/java.base/share/classes/sun/security/provider/X509Factory.java index 4be83d629bb..154d1428414 100644 --- a/src/java.base/share/classes/sun/security/provider/X509Factory.java +++ b/src/java.base/share/classes/sun/security/provider/X509Factory.java @@ -66,6 +66,7 @@ public class X509Factory extends CertificateFactorySpi { public static final String END_CERT = "-----END CERTIFICATE-----"; private static final int ENC_MAX_LENGTH = 4096 * 1024; // 4 MB MAX + public static final int BER_ITERATION_COUNT = 128; // Limit nested depth private static final Cache certCache = Cache.newSoftMemoryCache(750); @@ -570,7 +571,7 @@ public class X509Factory extends CertificateFactorySpi { if (c == DerValue.tag_Sequence) { ByteArrayOutputStream bout = new ByteArrayOutputStream(2048); bout.write(c); - readBERInternal(is, bout, c); + readBERInternal(is, bout, c, BER_ITERATION_COUNT); return bout.toByteArray(); } else { try { @@ -594,12 +595,16 @@ public class X509Factory extends CertificateFactorySpi { * @param is Read from this InputStream * @param bout Write into this OutputStream * @param tag Tag already read (-1 mean not read) + * @param depth nesting depth limit * @return The current tag, used to check EOC in indefinite-length BER * @throws IOException Any parsing error */ private static int readBERInternal(InputStream is, - ByteArrayOutputStream bout, int tag) throws IOException { + ByteArrayOutputStream bout, int tag, int depth) throws IOException { + if (depth-- == 0) { + throw new IOException("Nesting sequence depth limit reached."); + } if (tag == -1) { // Not read before the call, read now tag = is.read(); if (tag == -1) { @@ -625,7 +630,7 @@ public class X509Factory extends CertificateFactorySpi { "Non constructed encoding must have definite length"); } while (true) { - int subTag = readBERInternal(is, bout, -1); + int subTag = readBERInternal(is, bout, -1, depth); if (subTag == 0) { // EOC, end of indefinite-length section break; } diff --git a/src/java.base/share/classes/sun/security/provider/certpath/DistributionPointFetcher.java b/src/java.base/share/classes/sun/security/provider/certpath/DistributionPointFetcher.java index 31c0f4ecb9c..ed0fd0f5576 100644 --- a/src/java.base/share/classes/sun/security/provider/certpath/DistributionPointFetcher.java +++ b/src/java.base/share/classes/sun/security/provider/certpath/DistributionPointFetcher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2025, 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 @@ -43,9 +43,7 @@ import static sun.security.x509.PKIXExtensions.IssuingDistributionPoint_Id; /** * Class to obtain CRLs via the CRLDistributionPoints extension. - * Note that the functionality of this class must be explicitly enabled - * via a system property, see the USE_CRLDP variable below. - * + *

* This class uses the URICertStore class to fetch CRLs. The URICertStore * class also implements CRL caching: see the class description for more * information. diff --git a/src/java.base/share/classes/sun/security/provider/certpath/RevocationChecker.java b/src/java.base/share/classes/sun/security/provider/certpath/RevocationChecker.java index 297727310d4..7751f6a32bf 100644 --- a/src/java.base/share/classes/sun/security/provider/certpath/RevocationChecker.java +++ b/src/java.base/share/classes/sun/security/provider/certpath/RevocationChecker.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2025, 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 @@ -1007,13 +1007,17 @@ class RevocationChecker extends PKIXRevocationChecker { // any way to convey them back to the application. // That's the default, so no need to write code. builderParams.setDate(params.date()); - builderParams.setCertPathCheckers(params.certPathCheckers()); builderParams.setSigProvider(params.sigProvider()); // Skip revocation during this build to detect circular // references. But check revocation afterwards, using the // key (or any other that works). builderParams.setRevocationEnabled(false); + // Remove itself from params to avoid circular reference. + builderParams.setCertPathCheckers(params.certPathCheckers() + .stream() + .filter(checker -> checker != this) + .toList()); // check for AuthorityInformationAccess extension if (Builder.USE_AIA) { diff --git a/src/java.base/share/native/libzip/zip_util.c b/src/java.base/share/native/libzip/zip_util.c index 3ad148b0be5..96d3050f527 100644 --- a/src/java.base/share/native/libzip/zip_util.c +++ b/src/java.base/share/native/libzip/zip_util.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 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 @@ -568,7 +568,7 @@ static jlong readCEN(jzfile *zip, jint knownTotal) { /* Following are unsigned 32-bit */ - jlong endpos, end64pos, cenpos, cenlen, cenoff; + jlong endpos, end64pos, cenpos, cenlen, cenoff, total64; /* Following are unsigned 16-bit */ jint total, tablelen, i, j; unsigned char *cenbuf = NULL; @@ -604,7 +604,16 @@ readCEN(jzfile *zip, jint knownTotal) if ((end64pos = findEND64(zip, end64buf, endpos)) != -1) { cenlen = ZIP64_ENDSIZ(end64buf); cenoff = ZIP64_ENDOFF(end64buf); - total = (jint)ZIP64_ENDTOT(end64buf); + total64 = ZIP64_ENDTOT(end64buf); + /* ZIP64 size, offset and total-count fields are unsigned 64-bit + * values. Sizes and offsets that do not fit in signed jlong + * (i.e., >= 2^63), or total values that do not fit in jint, are + * not supported and indicate a corrupt or invalid zip file. + */ + if (cenlen < 0 || cenoff < 0 || total64 < 0 || total64 > INT_MAX) { + ZIP_FORMAT_ERROR("Zip64 END values exceed supported size"); + } + total = (jint)total64; endpos = end64pos; #ifdef USE_MMAP endhdrlen = ZIP64_ENDHDR; @@ -1137,20 +1146,8 @@ ZIP_FreeEntry(jzfile *jz, jzentry *ze) } } -/* - * Returns the zip entry corresponding to the specified name, or - * NULL if not found. - */ -jzentry * -ZIP_GetEntry(jzfile *zip, char *name, jint ulen) -{ - if (ulen == 0) { - return ZIP_GetEntry2(zip, name, (jint)strlen(name), JNI_FALSE); - } - return ZIP_GetEntry2(zip, name, ulen, JNI_TRUE); -} - -jboolean equals(char* name1, int len1, char* name2, int len2) { +static jboolean +equals(const char* name1, int len1, const char* name2, int len2) { if (len1 != len2) { return JNI_FALSE; } @@ -1162,16 +1159,12 @@ jboolean equals(char* name1, int len1, char* name2, int len2) { return JNI_TRUE; } -/* - * Returns the zip entry corresponding to the specified name, or - * NULL if not found. - * This method supports embedded null character in "name", use ulen - * for the length of "name". - */ jzentry * -ZIP_GetEntry2(jzfile *zip, char *name, jint ulen, jboolean addSlash) +ZIP_GetEntry(jzfile *zip, const char *name) { - unsigned int hsh = hashN(name, ulen); + // length of the entry name being searched for + const jint name_len = (jint) strlen(name); + const unsigned int hsh = hashN(name, name_len); jint idx; jzentry *ze = 0; @@ -1182,79 +1175,47 @@ ZIP_GetEntry2(jzfile *zip, char *name, jint ulen, jboolean addSlash) idx = zip->table[hsh % zip->tablelen]; - /* - * This while loop is an optimization where a double lookup - * for name and name+/ is being performed. The name char - * array has enough room at the end to try again with a - * slash appended if the first table lookup does not succeed. - */ - while(1) { - - /* Check the cached entry first */ - ze = zip->cache; - if (ze && equals(ze->name, ze->nlen, name, ulen)) { - /* Cache hit! Remove and return the cached entry. */ - zip->cache = 0; - ZIP_Unlock(zip); - return ze; - } - ze = 0; - - /* - * Search down the target hash chain for a cell whose - * 32 bit hash matches the hashed name. - */ - while (idx != ZIP_ENDCHAIN) { - jzcell *zc = &zip->entries[idx]; - - if (zc->hash == hsh) { - /* - * OK, we've found a ZIP entry whose 32 bit hashcode - * matches the name we're looking for. Try to read - * its entry information from the CEN. If the CEN - * name matches the name we're looking for, we're - * done. - * If the names don't match (which should be very rare) - * we keep searching. - */ - ze = newEntry(zip, zc, ACCESS_RANDOM); - if (ze && equals(ze->name, ze->nlen, name, ulen)) { - break; - } - if (ze != 0) { - /* We need to release the lock across the free call */ - ZIP_Unlock(zip); - ZIP_FreeEntry(zip, ze); - ZIP_Lock(zip); - } - ze = 0; - } - idx = zc->next; - } - - /* Entry found, return it */ - if (ze != 0) { - break; - } - - /* If no need to try appending slash, we are done */ - if (!addSlash) { - break; - } - - /* Slash is already there? */ - if (ulen > 0 && name[ulen - 1] == '/') { - break; - } - - /* Add slash and try once more */ - name[ulen++] = '/'; - name[ulen] = '\0'; - hsh = hash_append(hsh, '/'); - idx = zip->table[hsh % zip->tablelen]; - addSlash = JNI_FALSE; + /* Check the cached entry first */ + ze = zip->cache; + if (ze && equals(ze->name, ze->nlen, name, name_len)) { + /* Cache hit! Remove and return the cached entry. */ + zip->cache = 0; + ZIP_Unlock(zip); + return ze; } + ze = 0; + /* + * Search down the target hash chain for a cell whose + * 32 bit hash matches the hashed name. + */ + while (idx != ZIP_ENDCHAIN) { + jzcell *zc = &zip->entries[idx]; + + if (zc->hash == hsh) { + /* + * OK, we've found a ZIP entry whose 32 bit hashcode + * matches the name we're looking for. Try to read + * its entry information from the CEN. If the CEN + * name matches the name we're looking for, we're + * done. + * If the names don't match (which should be very rare) + * we keep searching. + */ + ze = newEntry(zip, zc, ACCESS_RANDOM); + if (ze && equals(ze->name, ze->nlen, name, name_len)) { + break; + } + if (ze != 0) { + /* We need to release the lock across the free call */ + ZIP_Unlock(zip); + ZIP_FreeEntry(zip, ze); + ZIP_Lock(zip); + } + ze = 0; + } + idx = zc->next; + } Finally: ZIP_Unlock(zip); return ze; @@ -1466,9 +1427,9 @@ InflateFully(jzfile *zip, jzentry *entry, void *buf, char **msg) * has the size bigger than 2**32 bytes in ONE invocation. */ JNIEXPORT jzentry * -ZIP_FindEntry(jzfile *zip, char *name, jint *sizeP, jint *nameLenP) +ZIP_FindEntry(jzfile *zip, const char *name, jint *sizeP, jint *nameLenP) { - jzentry *entry = ZIP_GetEntry(zip, name, 0); + jzentry *entry = ZIP_GetEntry(zip, name); if (entry) { *sizeP = (jint)entry->size; *nameLenP = (jint)strlen(entry->name); diff --git a/src/java.base/share/native/libzip/zip_util.h b/src/java.base/share/native/libzip/zip_util.h index 9825202fc7b..8cfe0b261f5 100644 --- a/src/java.base/share/native/libzip/zip_util.h +++ b/src/java.base/share/native/libzip/zip_util.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 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 @@ -241,8 +241,15 @@ typedef struct jzfile { /* Zip file */ */ #define ZIP_ENDCHAIN ((jint)-1) +/* + * Returns the ZIP entry corresponding to the given (NULL terminated) + * entry name. Returns NULL if no entry is found by that name. + * If the entry is found, then the value of the given sizeP will be + * updated to the ZIP entry's size and the value of nameLenP will be + * updated to the ZIP entry name's length. + */ JNIEXPORT jzentry * -ZIP_FindEntry(jzfile *zip, char *name, jint *sizeP, jint *nameLenP); +ZIP_FindEntry(jzfile *zip, const char *name, jint *sizeP, jint *nameLenP); JNIEXPORT jboolean ZIP_ReadEntry(jzfile *zip, jzentry *entry, unsigned char *buf, char *entrynm); @@ -268,8 +275,12 @@ ZIP_Put_In_Cache0(const char *name, ZFILE zfd, char **pmsg, jlong lastModified, JNIEXPORT void ZIP_Close(jzfile *zip); +/* + * Returns the ZIP entry corresponding to the given (NULL terminated) + * entry name. Returns NULL if no entry is found by that name. + */ jzentry * -ZIP_GetEntry(jzfile *zip, char *name, jint ulen); +ZIP_GetEntry(jzfile *zip, const char *name); void ZIP_Lock(jzfile *zip); void @@ -279,7 +290,6 @@ ZIP_Read(jzfile *zip, jzentry *entry, jlong pos, void *buf, jint len); JNIEXPORT void ZIP_FreeEntry(jzfile *zip, jzentry *ze); jlong ZIP_GetEntryDataOffset(jzfile *zip, jzentry *entry); -jzentry * ZIP_GetEntry2(jzfile *zip, char *name, jint ulen, jboolean addSlash); JNIEXPORT jboolean ZIP_InflateFully(void *inBuf, jlong inLen, void *outBuf, jlong outLen, char **pmsg); diff --git a/src/java.desktop/share/classes/sun/awt/geom/AreaOp.java b/src/java.desktop/share/classes/sun/awt/geom/AreaOp.java index 1d0e6df3734..65f7dbf11eb 100644 --- a/src/java.desktop/share/classes/sun/awt/geom/AreaOp.java +++ b/src/java.desktop/share/classes/sun/awt/geom/AreaOp.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2025, 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 @@ -146,6 +146,8 @@ public abstract class AreaOp { public static final int RSTAG_INSIDE = 1; public static final int RSTAG_OUTSIDE = -1; + public static final int MAX_LINK_COUNT = 1024; + public abstract void newRow(); public abstract int classify(Edge e); @@ -195,6 +197,25 @@ public abstract class AreaOp { } }; + private void consumeSubCurves(Vector subcurves, + Vector chains, + Vector curve) { + finalizeSubCurves(subcurves, chains); + Enumeration enum_ = subcurves.elements(); + while (enum_.hasMoreElements()) { + CurveLink link = enum_.nextElement(); + curve.add(link.getMoveto()); + CurveLink nextlink = link; + while ((nextlink = nextlink.getNext()) != null) { + if (!link.absorb(nextlink)) { + curve.add(link.getSubCurve()); + link = nextlink; + } + } + curve.add(link.getSubCurve()); + } + } + private Vector pruneEdges(Vector edges) { int numedges = edges.size(); if (numedges < 2) { @@ -218,6 +239,8 @@ public abstract class AreaOp { Vector subcurves = new Vector<>(); Vector chains = new Vector<>(); Vector links = new Vector<>(); + Vector ret = new Vector<>(); + int linkCount = 0; // Active edges are between left (inclusive) and right (exclusive) while (left < numedges) { double y = yrange[0]; @@ -390,27 +413,22 @@ public abstract class AreaOp { System.out.println(" "+link.getSubCurve()); } } + // If we have complex area calculation, we should consume the + // intermediate subcurves to optimize memory footprint + if (linkCount >= MAX_LINK_COUNT) { + consumeSubCurves(subcurves, chains, ret); + linkCount = 0; + chains.clear(); + subcurves.clear(); + } + linkCount += links.size(); resolveLinks(subcurves, chains, links); links.clear(); // Finally capture the bottom of the valid Y range as the top // of the next Y range. yrange[0] = yend; } - finalizeSubCurves(subcurves, chains); - Vector ret = new Vector<>(); - Enumeration enum_ = subcurves.elements(); - while (enum_.hasMoreElements()) { - CurveLink link = enum_.nextElement(); - ret.add(link.getMoveto()); - CurveLink nextlink = link; - while ((nextlink = nextlink.getNext()) != null) { - if (!link.absorb(nextlink)) { - ret.add(link.getSubCurve()); - link = nextlink; - } - } - ret.add(link.getSubCurve()); - } + consumeSubCurves(subcurves, chains, ret); return ret; } diff --git a/src/java.desktop/share/classes/sun/awt/geom/Curve.java b/src/java.desktop/share/classes/sun/awt/geom/Curve.java index 83986b88777..7cdb45e5a22 100644 --- a/src/java.desktop/share/classes/sun/awt/geom/Curve.java +++ b/src/java.desktop/share/classes/sun/awt/geom/Curve.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2025, 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 @@ -1046,6 +1046,9 @@ public abstract class Curve { double bump = ymin; double maxbump = Math.min(ymin * 1E13, (y1 - y0) * .1); double y = y0 + bump; + if (!Double.isFinite(y1)) { + return 0; + } while (y <= y1) { if (fairlyClose(this.XforY(y), that.XforY(y))) { if ((bump *= 2) > maxbump) { @@ -1319,7 +1322,7 @@ public abstract class Curve { public boolean fairlyClose(double v1, double v2) { return (Math.abs(v1 - v2) < - Math.max(Math.abs(v1), Math.abs(v2)) * 1E-10); + Math.max(Math.abs(v1), Math.abs(v2)) * 1E-8); } public abstract int getSegment(double[] coords); diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/common/SSLFlowDelegate.java b/src/java.net.http/share/classes/jdk/internal/net/http/common/SSLFlowDelegate.java index c662983d0af..e7dec5a6963 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/common/SSLFlowDelegate.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/common/SSLFlowDelegate.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 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 @@ -273,7 +273,7 @@ public class SSLFlowDelegate { final SequentialScheduler scheduler; volatile ByteBuffer readBuf; - volatile boolean completing; + boolean completing; final ReentrantLock readBufferLock = new ReentrantLock(); final Logger debugr = Utils.getDebugLogger(this::dbgString, Utils.DEBUG); @@ -301,6 +301,11 @@ public class SSLFlowDelegate { return enterReadScheduling(); } + @Override + public boolean closing() { + return closeNotifyReceived(); + } + public final String dbgString() { return "SSL Reader(" + tubeName + ")"; } @@ -505,7 +510,7 @@ public class SSLFlowDelegate { if (result.handshaking()) { handshaking = true; if (debugr.on()) debugr.log("handshaking"); - if (doHandshake(result, READER)) continue; // need unwrap + if (doHandshake(result.handshakeStatus(), READER)) continue; // need unwrap else break; // doHandshake will have triggered the write scheduler if necessary } else { if (trySetALPN()) { @@ -550,6 +555,7 @@ public class SSLFlowDelegate { private volatile Status lastUnwrapStatus; EngineResult unwrapBuffer(ByteBuffer src) throws IOException { + assert readBufferLock.isHeldByCurrentThread(); ByteBuffer dst = getAppBuffer(); int len = src.remaining(); while (true) { @@ -573,6 +579,8 @@ public class SSLFlowDelegate { break; case CLOSED: assert dst.position() == 0; + src.position(src.limit()); + completing = true; return doClosure(new EngineResult(sslResult)); case BUFFER_UNDERFLOW: // handled implicitly by compaction/reallocation of readBuf @@ -834,7 +842,7 @@ public class SSLFlowDelegate { boolean handshaking = false; if (result.handshaking()) { if (debugw.on()) debugw.log("handshaking"); - doHandshake(result, WRITER); // ok to ignore return + doHandshake(result.handshakeStatus(), WRITER); // ok to ignore return handshaking = true; } else { if (trySetALPN()) { @@ -1090,14 +1098,14 @@ public class SSLFlowDelegate { return (current & HANDSHAKING); }; - private boolean doHandshake(EngineResult r, int caller) { + private boolean doHandshake(HandshakeStatus handshakeStatus, int caller) { // unconditionally sets the HANDSHAKING bit, while preserving task bits handshakeState.getAndAccumulate(0, (current, unused) -> HANDSHAKING | (current & TASK_BITS)); if (stateList != null && debug.on()) { - stateList.add(r.handshakeStatus().toString()); + stateList.add(handshakeStatus.toString()); stateList.add(Integer.toString(caller)); } - switch (r.handshakeStatus()) { + switch (handshakeStatus) { case NEED_TASK: int s = handshakeState.accumulateAndGet(0, REQUEST_OR_DO_TASKS); if ((s & REQUESTING_TASKS) > 0) { // someone else is or will do tasks @@ -1125,7 +1133,7 @@ public class SSLFlowDelegate { break; default: throw new InternalError("Unexpected handshake status:" - + r.handshakeStatus()); + + handshakeStatus); } return true; } @@ -1182,34 +1190,20 @@ public class SSLFlowDelegate { return false; } - // FIXME: acknowledge a received CLOSE request from peer EngineResult doClosure(EngineResult r) throws IOException { if (debug.on()) debug.log("doClosure(%s): %s [isOutboundDone: %s, isInboundDone: %s]", r.result, engine.getHandshakeStatus(), engine.isOutboundDone(), engine.isInboundDone()); + if (debug.on()) debug.log("doClosure: close_notify received"); + close_notify_received = true; + engine.closeOutbound(); if (engine.getHandshakeStatus() == HandshakeStatus.NEED_WRAP) { // we have received TLS close_notify and need to send // an acknowledgement back. We're calling doHandshake // to finish the close handshake. - if (engine.isInboundDone() && !engine.isOutboundDone()) { - if (debug.on()) debug.log("doClosure: close_notify received"); - close_notify_received = true; - if (!writer.scheduler.isStopped()) { - doHandshake(r, READER); - } else { - // We have received closed notify, but we - // won't be able to send the acknowledgement. - // Nothing more will come from the socket either, - // so mark the reader as completed. - var readerLock = reader.readBufferLock; - readerLock.lock(); - try { - reader.completing = true; - } finally { - readerLock.unlock(); - } - } + if (!writer.scheduler.isStopped()) { + doHandshake(HandshakeStatus.NEED_WRAP, READER); } } return r; diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/common/SubscriberWrapper.java b/src/java.net.http/share/classes/jdk/internal/net/http/common/SubscriberWrapper.java index b9e1def58e0..013ed31c8c1 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/common/SubscriberWrapper.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/common/SubscriberWrapper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 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 @@ -459,7 +459,7 @@ public abstract class SubscriberWrapper } void checkCompletion() { - if (downstreamCompleted || !upstreamCompleted) { + if (downstreamCompleted || (!upstreamCompleted && !completionAcknowledged)) { return; } if (!outputQ.isEmpty()) { diff --git a/src/java.security.jgss/share/classes/sun/security/krb5/internal/crypto/dk/AesDkCrypto.java b/src/java.security.jgss/share/classes/sun/security/krb5/internal/crypto/dk/AesDkCrypto.java index 1f6e98e50e8..f04f28ae134 100644 --- a/src/java.security.jgss/share/classes/sun/security/krb5/internal/crypto/dk/AesDkCrypto.java +++ b/src/java.security.jgss/share/classes/sun/security/krb5/internal/crypto/dk/AesDkCrypto.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2025, 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 @@ -118,14 +118,7 @@ public class AesDkCrypto extends DkCrypto { private byte[] stringToKey(char[] secret, byte[] salt, byte[] params) throws GeneralSecurityException { - int iter_count = DEFAULT_ITERATION_COUNT; - if (params != null) { - if (params.length != 4) { - throw new RuntimeException("Invalid parameter to stringToKey"); - } - iter_count = readBigEndian(params, 0, 4); - } - + int iter_count = DkCrypto.iterationCount(params, DEFAULT_ITERATION_COUNT); byte[] tmpKey = randomToKey(PBKDF2(secret, salt, iter_count, getKeySeedLength())); byte[] result = dk(tmpKey, KERBEROS_CONSTANT); @@ -485,17 +478,4 @@ public class AesDkCrypto extends DkCrypto { return result; } - - public static final int readBigEndian(byte[] data, int pos, int size) { - int retVal = 0; - int shifter = (size-1)*8; - while (size > 0) { - retVal += (data[pos] & 0xff) << shifter; - shifter -= 8; - pos++; - size--; - } - return retVal; - } - } diff --git a/src/java.security.jgss/share/classes/sun/security/krb5/internal/crypto/dk/AesSha2DkCrypto.java b/src/java.security.jgss/share/classes/sun/security/krb5/internal/crypto/dk/AesSha2DkCrypto.java index cb9e42b2dee..5af0517f883 100644 --- a/src/java.security.jgss/share/classes/sun/security/krb5/internal/crypto/dk/AesSha2DkCrypto.java +++ b/src/java.security.jgss/share/classes/sun/security/krb5/internal/crypto/dk/AesSha2DkCrypto.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, 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 @@ -122,14 +122,7 @@ public class AesSha2DkCrypto extends DkCrypto { private byte[] stringToKey(char[] secret, byte[] salt, byte[] params) throws GeneralSecurityException { - int iter_count = DEFAULT_ITERATION_COUNT; - if (params != null) { - if (params.length != 4) { - throw new RuntimeException("Invalid parameter to stringToKey"); - } - iter_count = readBigEndian(params, 0, 4); - } - + int iter_count = DkCrypto.iterationCount(params, DEFAULT_ITERATION_COUNT); byte[] saltp = new byte[26 + 1 + salt.length]; if (keyLength == 128) { System.arraycopy(ETYPE_NAME_128, 0, saltp, 0, 26); @@ -525,17 +518,4 @@ public class AesSha2DkCrypto extends DkCrypto { return result; } - - public static final int readBigEndian(byte[] data, int pos, int size) { - int retVal = 0; - int shifter = (size-1)*8; - while (size > 0) { - retVal += (data[pos] & 0xff) << shifter; - shifter -= 8; - pos++; - size--; - } - return retVal; - } - } diff --git a/src/java.security.jgss/share/classes/sun/security/krb5/internal/crypto/dk/DkCrypto.java b/src/java.security.jgss/share/classes/sun/security/krb5/internal/crypto/dk/DkCrypto.java index da327814592..260f30bd000 100644 --- a/src/java.security.jgss/share/classes/sun/security/krb5/internal/crypto/dk/DkCrypto.java +++ b/src/java.security.jgss/share/classes/sun/security/krb5/internal/crypto/dk/DkCrypto.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2025, Oracle and/or its affiliates. All rights reserved. */ /* @@ -31,8 +31,8 @@ package sun.security.krb5.internal.crypto.dk; import javax.crypto.Cipher; -import javax.crypto.Mac; import java.security.GeneralSecurityException; +import java.security.InvalidAlgorithmParameterException; import java.util.Arrays; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -692,4 +692,41 @@ public abstract class DkCrypto { bb.get(answer, 0, len); return answer; } + + static int iterationCount(byte[] params, int defaultValue) + throws InvalidAlgorithmParameterException { + if (params == null) { + return defaultValue; + } + if (params.length != 4) { + throw new InvalidAlgorithmParameterException("Invalid params"); + } + if (params[0] != 0 || ((params[1] & 0xff) >= 80)) { + // IC should be less than 80 * 2^16. This is roughly + // the same as PKCS12KeyStore's 5_000_000 limit. + throw new InvalidAlgorithmParameterException( + "Incoming iteration count is too big"); + } + int iter_count = readBigEndian(params, 0, 4); + if (!ALLOW_WEAK_PBKDF2_ITERATION_COUNT && iter_count < defaultValue) { + throw new InvalidAlgorithmParameterException( + "Incoming iteration count is too small"); + } + return iter_count; + } + + public static final int readBigEndian(byte[] data, int pos, int size) { + int retVal = 0; + int shifter = (size-1)*8; + while (size > 0) { + retVal += (data[pos] & 0xff) << shifter; + shifter -= 8; + pos++; + size--; + } + return retVal; + } + + // Only used by test + public static boolean ALLOW_WEAK_PBKDF2_ITERATION_COUNT = false; } diff --git a/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathExpressionImpl.java b/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathExpressionImpl.java index e3f25731e6d..d6ac228b982 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathExpressionImpl.java +++ b/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathExpressionImpl.java @@ -34,6 +34,8 @@ import javax.xml.xpath.XPathVariableResolver; import jdk.xml.internal.JdkXmlConfig; import jdk.xml.internal.JdkXmlFeatures; +import jdk.xml.internal.XMLSecurityManager; +import jdk.xml.internal.XMLSecurityPropertyManager; import org.w3c.dom.Document; import org.xml.sax.InputSource; @@ -41,7 +43,7 @@ import org.xml.sax.InputSource; * The XPathExpression interface encapsulates a (compiled) XPath expression. * * @author Ramesh Mandava - * @LastModified: May 2025 + * @LastModified: Nov 2025 */ public class XPathExpressionImpl extends XPathImplUtil implements XPathExpression { @@ -51,7 +53,9 @@ public class XPathExpressionImpl extends XPathImplUtil implements XPathExpressio * from the context. */ protected XPathExpressionImpl() { - this(null, null, null, null, false, JdkXmlConfig.getInstance(false).getXMLFeatures(true)); + this(null, null, null, null, false, JdkXmlConfig.getInstance(false).getXMLFeatures(true), + JdkXmlConfig.getInstance(false).getXMLSecurityManager(false), + JdkXmlConfig.getInstance(false).getXMLSecurityPropertyManager(false)); }; protected XPathExpressionImpl(com.sun.org.apache.xpath.internal.XPath xpath, @@ -59,13 +63,16 @@ public class XPathExpressionImpl extends XPathImplUtil implements XPathExpressio XPathFunctionResolver functionResolver, XPathVariableResolver variableResolver) { this(xpath, prefixResolver, functionResolver, variableResolver, - false, JdkXmlConfig.getInstance(false).getXMLFeatures(true)); + false, JdkXmlConfig.getInstance(false).getXMLFeatures(true), + JdkXmlConfig.getInstance(false).getXMLSecurityManager(false), + JdkXmlConfig.getInstance(false).getXMLSecurityPropertyManager(false)); }; protected XPathExpressionImpl(com.sun.org.apache.xpath.internal.XPath xpath, JAXPPrefixResolver prefixResolver,XPathFunctionResolver functionResolver, XPathVariableResolver variableResolver, boolean featureSecureProcessing, - JdkXmlFeatures featureManager) { + JdkXmlFeatures featureManager, XMLSecurityManager xmlSecMgr, + XMLSecurityPropertyManager xmlSecPropMgr) { this.xpath = xpath; this.prefixResolver = prefixResolver; this.functionResolver = functionResolver; @@ -74,6 +81,8 @@ public class XPathExpressionImpl extends XPathImplUtil implements XPathExpressio this.overrideDefaultParser = featureManager.getFeature( JdkXmlFeatures.XmlFeature.JDK_OVERRIDE_PARSER); this.featureManager = featureManager; + this.xmlSecMgr = xmlSecMgr; + this.xmlSecPropMgr = xmlSecPropMgr; }; public void setXPath (com.sun.org.apache.xpath.internal.XPath xpath) { diff --git a/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathImpl.java b/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathImpl.java index c2faf90ce2e..f62a290557d 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathImpl.java +++ b/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathImpl.java @@ -51,7 +51,7 @@ import org.xml.sax.InputSource; * New methods: evaluateExpression * Refactored to share code with XPathExpressionImpl. * - * @LastModified: June 2025 + * @LastModified: Nov 2025 */ public class XPathImpl extends XPathImplUtil implements javax.xml.xpath.XPath { @@ -175,7 +175,8 @@ public class XPathImpl extends XPathImplUtil implements javax.xml.xpath.XPath { // Can have errorListener XPathExpressionImpl ximpl = new XPathExpressionImpl (xpath, prefixResolver, functionResolver, variableResolver, - featureSecureProcessing, featureManager); + featureSecureProcessing, featureManager, + xmlSecMgr, xmlSecPropMgr); return ximpl; } catch (TransformerException te) { throw new XPathExpressionException (te) ; diff --git a/test/jdk/sun/security/krb5/RFC396xTest.java b/test/jdk/sun/security/krb5/RFC396xTest.java index e8f48d7c488..fd011c7f198 100644 --- a/test/jdk/sun/security/krb5/RFC396xTest.java +++ b/test/jdk/sun/security/krb5/RFC396xTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2025, 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 @@ public class RFC396xTest { public static void main(String[] args) throws Exception { System.setProperty("sun.security.krb5.msinterop.des.s2kcharset", "utf-8"); + DkCrypto.ALLOW_WEAK_PBKDF2_ITERATION_COUNT = true; test(); } diff --git a/test/jdk/sun/security/krb5/auto/DiffSaltParams.java b/test/jdk/sun/security/krb5/auto/DiffSaltParams.java index e03b4fe5098..04ee2960daa 100644 --- a/test/jdk/sun/security/krb5/auto/DiffSaltParams.java +++ b/test/jdk/sun/security/krb5/auto/DiffSaltParams.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, 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 @@ -38,11 +38,11 @@ public class DiffSaltParams { OneKDC kdc = new OneKDC(null).writeJAASConf(); kdc.addPrincipal("user1", "user1pass".toCharArray(), - "hello", new byte[]{0, 0, 1, 0}); + "hello", new byte[]{0, 1, 0, 0}); kdc.addPrincipal("user2", "user2pass".toCharArray(), "hello", null); kdc.addPrincipal("user3", "user3pass".toCharArray(), - null, new byte[]{0, 0, 1, 0}); + null, new byte[]{0, 1, 0, 0}); kdc.addPrincipal("user4", "user4pass".toCharArray()); Context.fromUserPass("user1", "user1pass".toCharArray(), true); diff --git a/test/jdk/sun/security/krb5/auto/KDC.java b/test/jdk/sun/security/krb5/auto/KDC.java index 37a4e828469..168a84722c7 100644 --- a/test/jdk/sun/security/krb5/auto/KDC.java +++ b/test/jdk/sun/security/krb5/auto/KDC.java @@ -366,11 +366,12 @@ public class KDC { name.indexOf('/') < 0 ? PrincipalName.KRB_NT_UNKNOWN : PrincipalName.KRB_NT_SRV_HST); - ktab.addEntry(pn, - getSalt(pn), - pass, - kvno, - true); + int[] etypes = EType.getDefaults("default_tkt_enctypes"); + EncryptionKey[] keys = new EncryptionKey[etypes.length]; + for (int i = 0; i < etypes.length; i++) { + keys[i] = keyForUser(pn, etypes[i], false); + } + ktab.addEntry(pn, keys, kvno, true); } else { nativeKdc.ktadd(name, tab); } @@ -671,10 +672,7 @@ public class KDC { */ private char[] getPassword(PrincipalName p, boolean server) throws KrbException { - String pn = p.toString(); - if (p.getRealmString() == null) { - pn = pn + "@" + getRealm(); - } + String pn = nameOf(p); char[] pass = passwords.get(pn); if (pass == null) { throw new KrbException(server? @@ -690,10 +688,7 @@ public class KDC { * @return the salt */ protected String getSalt(PrincipalName p) { - String pn = p.toString(); - if (p.getRealmString() == null) { - pn = pn + "@" + getRealm(); - } + String pn = nameOf(p); if (salts.containsKey(pn)) { return salts.get(pn); } @@ -725,10 +720,7 @@ public class KDC { case EncryptedData.ETYPE_AES256_CTS_HMAC_SHA1_96: case EncryptedData.ETYPE_AES128_CTS_HMAC_SHA256_128: case EncryptedData.ETYPE_AES256_CTS_HMAC_SHA384_192: - String pn = p.toString(); - if (p.getRealmString() == null) { - pn = pn + "@" + getRealm(); - } + String pn = nameOf(p); if (s2kparamses.containsKey(pn)) { return s2kparamses.get(pn); } @@ -742,6 +734,23 @@ public class KDC { } } + /** + * Returns the name of a PrincipalName inside KDC dbs. + * @param p the principal name + * @return the name + */ + private String nameOf(PrincipalName p) { + String pn = p.toString(); + if (p.getRealmString() == null) { + pn = pn + "@" + getRealm(); + } + if (pn.startsWith("krbtgt/")) { + // We always register krbtgt using REALM + pn = "krbtgt/" + pn.substring(7).toUpperCase(Locale.ROOT); + } + return pn; + } + /** * Returns the key for a given principal of the given encryption type * @param p the principal diff --git a/test/jdk/sun/security/krb5/auto/UserIterCount.java b/test/jdk/sun/security/krb5/auto/UserIterCount.java new file mode 100644 index 00000000000..f972e20ee1e --- /dev/null +++ b/test/jdk/sun/security/krb5/auto/UserIterCount.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2025, 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. + */ + +/* + * @test + * @bug 8370615 + * @summary Improve Kerberos credentialing + * @library /test/lib + * @compile -XDignore.symbol.file UserIterCount.java + * @run main jdk.test.lib.FileInstaller TestHosts TestHosts + * @run main/othervm -Djdk.net.hosts.file=TestHosts UserIterCount + */ + +import java.util.HashMap; + +import sun.security.krb5.EncryptionKey; +import sun.security.krb5.KrbException; +import sun.security.krb5.PrincipalName; + +public class UserIterCount { + + static class MyKDC extends OneKDC { + static final HashMap CACHE + = new HashMap<>(); + + public MyKDC() throws Exception { + super(null); + } + + @Override + protected byte[] getParams(PrincipalName p, int etype) { + if (etype == 18) { + if (p.toString().startsWith(OneKDC.USER)) { + return new byte[]{0, 0, 16, 01}; + } else { + return new byte[]{0, 79, (byte)255, (byte)255}; + } + } else { + return super.getParams(p, etype); + } + } + + @Override + EncryptionKey keyForUser(PrincipalName p, int etype, boolean server) + throws KrbException { + var key = p.toString() + etype + server; + var v = CACHE.get(key); + if (v == null) { + v = super.keyForUser(p, etype, server); + CACHE.put(key, v); + } + return v; + } + } + + public static void main(String[] args) throws Exception { + new MyKDC().writeJAASConf(); + Context.fromUserPass(OneKDC.USER, OneKDC.PASS, false); + Context.fromUserPass(OneKDC.USER2, OneKDC.PASS2, false); + } +}