diff --git a/make/jdk/src/classes/build/tools/cldrconverter/CLDRConverter.java b/make/jdk/src/classes/build/tools/cldrconverter/CLDRConverter.java index 17ecb7545295..71652859ae74 100644 --- a/make/jdk/src/classes/build/tools/cldrconverter/CLDRConverter.java +++ b/make/jdk/src/classes/build/tools/cldrconverter/CLDRConverter.java @@ -87,6 +87,7 @@ public class CLDRConverter { static final String EXEMPLAR_CITY_PREFIX = "timezone.excity."; static final String ZONE_NAME_PREFIX = "timezone.displayname."; static final String METAZONE_ID_PREFIX = "metazone.id."; + static final String METAZONE_DSTOFFSET_PREFIX = "metazone.dstoffset."; static final String PARENT_LOCALE_PREFIX = "parentLocale."; static final String META_EMPTY_ZONE_NAME = "EMPTY_ZONE"; static final String[] EMPTY_ZONE = {"", "", "", "", "", ""}; @@ -122,6 +123,11 @@ public class CLDRConverter { static Map pluralRules; static Map dayPeriodRules; + // Map of explicit dst offsets for metazones + // key: time zone ID + // value: explicit dstOffset for the corresponding metazone name + static final Map explicitDstOffsets = HashMap.newHashMap(32); + static enum DraftType { UNCONFIRMED, PROVISIONAL, @@ -772,6 +778,12 @@ private static Map extractZoneNames(Map map, Str .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); names.putAll(exCities); + // Explicit metazone offsets + if (id.equals("root")) { + explicitDstOffsets.forEach((k, v) -> + names.put(METAZONE_DSTOFFSET_PREFIX + k, v)); + } + // If there's no UTC entry at this point, add an empty one if (!names.isEmpty() && !names.containsKey("UTC")) { names.putIfAbsent(METAZONE_ID_PREFIX + META_EMPTY_ZONE_NAME, EMPTY_ZONE); diff --git a/make/jdk/src/classes/build/tools/cldrconverter/MetaZonesParseHandler.java b/make/jdk/src/classes/build/tools/cldrconverter/MetaZonesParseHandler.java index 2c3757b7a47e..45de46d24769 100644 --- a/make/jdk/src/classes/build/tools/cldrconverter/MetaZonesParseHandler.java +++ b/make/jdk/src/classes/build/tools/cldrconverter/MetaZonesParseHandler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -84,7 +84,15 @@ public void startElement(String uri, String localName, String qName, Attributes if (fromLDT.isBefore(now) && toLDT.isAfter(now)) { metazone = attributes.getValue("mzone"); + + // Explicit metazone DST offsets. Only the "dst" offset is needed, + // as "std" is used by default when it doesn't match. + String dstOffset = attributes.getValue("dstOffset"); + if (dstOffset != null) { + CLDRConverter.explicitDstOffsets.put(tzid, dstOffset); + } } + pushIgnoredContainer(qName); break; diff --git a/make/jdk/src/classes/build/tools/cldrconverter/ResourceBundleGenerator.java b/make/jdk/src/classes/build/tools/cldrconverter/ResourceBundleGenerator.java index 6b2b5b4c0c03..6af06b565594 100644 --- a/make/jdk/src/classes/build/tools/cldrconverter/ResourceBundleGenerator.java +++ b/make/jdk/src/classes/build/tools/cldrconverter/ResourceBundleGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -197,7 +197,8 @@ public void generateBundle(String packageName, String baseName, String localeID, } else if (value instanceof String) { String valStr = (String)value; if (type == BundleType.TIMEZONE && - !key.startsWith(CLDRConverter.EXEMPLAR_CITY_PREFIX) || + !(key.startsWith(CLDRConverter.EXEMPLAR_CITY_PREFIX) || + key.startsWith(CLDRConverter.METAZONE_DSTOFFSET_PREFIX)) || valStr.startsWith(META_VALUE_PREFIX)) { out.printf(" { \"%s\", %s },\n", key, CLDRConverter.saveConvert(valStr, useJava)); } else { diff --git a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp index a58fa8d9dc79..180e3fda0905 100644 --- a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp @@ -11138,6 +11138,7 @@ class StubGenerator: public StubCodeGenerator { #endif // LINUX +#ifdef COMPILER2 if (UseSecondarySupersTable) { StubRoutines::_lookup_secondary_supers_table_slow_path_stub = generate_lookup_secondary_supers_table_slow_path_stub(); if (! InlineSecondarySupersTest) { @@ -11147,6 +11148,7 @@ class StubGenerator: public StubCodeGenerator { } } } +#endif StubRoutines::aarch64::set_completed(); // Inidicate that arraycopy and zero_blocks stubs are generated } diff --git a/src/java.base/share/classes/java/text/SimpleDateFormat.java b/src/java.base/share/classes/java/text/SimpleDateFormat.java index 4eb08f6f5f66..7ff1ee373024 100644 --- a/src/java.base/share/classes/java/text/SimpleDateFormat.java +++ b/src/java.base/share/classes/java/text/SimpleDateFormat.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2022, 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 @@ -41,7 +41,7 @@ import java.io.IOException; import java.io.InvalidObjectException; import java.io.ObjectInputStream; -import static java.text.DateFormatSymbols.*; +import java.time.ZoneOffset; import java.util.Calendar; import java.util.Date; import java.util.GregorianCalendar; @@ -57,6 +57,8 @@ import sun.util.locale.provider.LocaleProviderAdapter; import sun.util.locale.provider.TimeZoneNameUtility; +import static java.text.DateFormatSymbols.*; + /** * {@code SimpleDateFormat} is a concrete class for formatting and * parsing dates in a locale-sensitive manner. It allows for formatting @@ -1283,15 +1285,22 @@ private void subFormat(int patternCharIndex, int count, case PATTERN_ZONE_NAME: // 'z' if (current == null) { + TimeZone tz = calendar.getTimeZone(); + String tzid = tz.getID(); + int zoneOffset = calendar.get(Calendar.ZONE_OFFSET); + int dstOffset = calendar.get(Calendar.DST_OFFSET) + zoneOffset; + + // Check if an explicit metazone DST offset exists + String explicitDstOffset = TimeZoneNameUtility.explicitDstOffset(tzid); + boolean daylight = explicitDstOffset != null ? + dstOffset == ZoneOffset.of(explicitDstOffset).getTotalSeconds() * 1_000 : + dstOffset != zoneOffset; if (formatData.locale == null || formatData.isZoneStringsSet) { - int zoneIndex = - formatData.getZoneIndex(calendar.getTimeZone().getID()); + int zoneIndex = formatData.getZoneIndex(tzid); if (zoneIndex == -1) { - value = calendar.get(Calendar.ZONE_OFFSET) + - calendar.get(Calendar.DST_OFFSET); - buffer.append(ZoneInfoFile.toCustomID(value)); + buffer.append(ZoneInfoFile.toCustomID(dstOffset)); } else { - int index = (calendar.get(Calendar.DST_OFFSET) == 0) ? 1: 3; + int index = daylight ? 3 : 1; if (count < 4) { // Use the short name index++; @@ -1300,8 +1309,6 @@ private void subFormat(int patternCharIndex, int count, buffer.append(zoneStrings[zoneIndex][index]); } } else { - TimeZone tz = calendar.getTimeZone(); - boolean daylight = (calendar.get(Calendar.DST_OFFSET) != 0); int tzstyle = (count < 4 ? TimeZone.SHORT : TimeZone.LONG); buffer.append(tz.getDisplayName(daylight, tzstyle, formatData.locale)); } diff --git a/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java b/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java index b55d0232a18d..57c3a9316bd5 100644 --- a/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java +++ b/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -4503,7 +4503,11 @@ public boolean format(DateTimePrintContext context, StringBuilder buf) { TemporalAccessor dt = context.getTemporal(); int type = GENERIC; if (!isGeneric) { - if (dt.isSupported(ChronoField.INSTANT_SECONDS)) { + // Check if an explicit metazone DST offset exists + String dstOffset = TimeZoneNameUtility.explicitDstOffset(zname); + if (dt.isSupported(OFFSET_SECONDS) && dstOffset != null) { + type = ZoneOffset.from(dt).equals(ZoneOffset.of(dstOffset)) ? DST : STD; + } else if (dt.isSupported(ChronoField.INSTANT_SECONDS)) { type = zone.getRules().isDaylightSavings(Instant.from(dt)) ? DST : STD; } else if (dt.isSupported(ChronoField.EPOCH_DAY) && dt.isSupported(ChronoField.NANO_OF_DAY)) { diff --git a/src/java.base/share/classes/sun/util/locale/provider/LocaleResources.java b/src/java.base/share/classes/sun/util/locale/provider/LocaleResources.java index 650add2094c5..c03780fb807f 100644 --- a/src/java.base/share/classes/sun/util/locale/provider/LocaleResources.java +++ b/src/java.base/share/classes/sun/util/locale/provider/LocaleResources.java @@ -105,6 +105,9 @@ public class LocaleResources { // TimeZoneNamesBundle exemplar city prefix private static final String TZNB_EXCITY_PREFIX = "timezone.excity."; + // TimeZoneNamesBundle explicit metazone dst offset prefix + private static final String TZNB_METAZONE_DSTOFFSET_PREFIX = "metazone.dstoffset."; + // null singleton cache value private static final Object NULLOBJECT = new Object(); @@ -321,7 +324,8 @@ public Object getTimeZoneNames(String key) { if (Objects.isNull(data) || Objects.isNull(val = data.get())) { TimeZoneNamesBundle tznb = localeData.getTimeZoneNames(locale); - if (key.startsWith(TZNB_EXCITY_PREFIX)) { + if (key.startsWith(TZNB_EXCITY_PREFIX) || + key.startsWith(TZNB_METAZONE_DSTOFFSET_PREFIX)) { if (tznb.containsKey(key)) { val = tznb.getString(key); assert val instanceof String; @@ -378,7 +382,8 @@ String[][] getZoneStrings() { Set value = new LinkedHashSet<>(); Set tzIds = new HashSet<>(Arrays.asList(TimeZone.getAvailableIDs())); for (String key : keyset) { - if (!key.startsWith(TZNB_EXCITY_PREFIX)) { + if (!key.startsWith(TZNB_EXCITY_PREFIX) && + !key.startsWith(TZNB_METAZONE_DSTOFFSET_PREFIX)) { value.add(rb.getStringArray(key)); tzIds.remove(key); } diff --git a/src/java.base/share/classes/sun/util/locale/provider/TimeZoneNameUtility.java b/src/java.base/share/classes/sun/util/locale/provider/TimeZoneNameUtility.java index fd3d4965db3b..6c684e176c8e 100644 --- a/src/java.base/share/classes/sun/util/locale/provider/TimeZoneNameUtility.java +++ b/src/java.base/share/classes/sun/util/locale/provider/TimeZoneNameUtility.java @@ -37,7 +37,7 @@ import java.util.spi.TimeZoneNameProvider; import sun.util.calendar.ZoneInfo; import sun.util.cldr.CLDRLocaleProviderAdapter; -import static sun.util.locale.provider.LocaleProviderAdapter.Type; +import static sun.util.locale.provider.LocaleProviderAdapter.Type.CLDR; /** * Utility class that deals with the localized time zone names @@ -169,10 +169,22 @@ public static Optional convertLDMLShortID(String shortID) { * Returns the canonical ID for the given ID */ public static Optional canonicalTZID(String id) { - return ((CLDRLocaleProviderAdapter)LocaleProviderAdapter.forType(Type.CLDR)) + return ((CLDRLocaleProviderAdapter)LocaleProviderAdapter.forType(CLDR)) .canonicalTZID(id); } + /** + * {@return the explicit metazone DST offset for the specified time zone ID, if exists} + * @param tzid the time zone ID + */ + public static String explicitDstOffset(String tzid) { + return (String) (LocaleProviderAdapter.forType(CLDR) instanceof CLDRLocaleProviderAdapter ca ? + ca.getLocaleResources(Locale.ROOT) + .getTimeZoneNames("metazone.dstoffset." + + ca.canonicalTZID(tzid).orElse(tzid)) : + null); + } + private static String[] retrieveDisplayNamesImpl(String id, Locale locale) { LocaleServiceProviderPool pool = LocaleServiceProviderPool.getPool(TimeZoneNameProvider.class); diff --git a/src/java.base/share/classes/sun/util/resources/TimeZoneNamesBundle.java b/src/java.base/share/classes/sun/util/resources/TimeZoneNamesBundle.java index a30b84c6872b..c5e95c8a4044 100644 --- a/src/java.base/share/classes/sun/util/resources/TimeZoneNamesBundle.java +++ b/src/java.base/share/classes/sun/util/resources/TimeZoneNamesBundle.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2022, 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 @@ -43,8 +43,6 @@ import java.util.Map; import java.util.LinkedHashMap; import java.util.LinkedHashSet; -import java.util.MissingResourceException; -import java.util.Objects; import java.util.Set; /** diff --git a/src/java.base/share/data/cacerts/luxtrustglobalrootca b/src/java.base/share/data/cacerts/luxtrustglobalrootca deleted file mode 100644 index 7fb3d818f807..000000000000 --- a/src/java.base/share/data/cacerts/luxtrustglobalrootca +++ /dev/null @@ -1,28 +0,0 @@ -Owner: CN=LuxTrust Global Root, O=LuxTrust s.a., C=LU -Issuer: CN=LuxTrust Global Root, O=LuxTrust s.a., C=LU -Serial number: bb8 -Valid from: Thu Mar 17 09:51:37 GMT 2011 until: Wed Mar 17 09:51:37 GMT 2021 -Signature algorithm name: SHA256withRSA -Subject Public Key Algorithm: 2048-bit RSA key -Version: 3 ------BEGIN CERTIFICATE----- -MIIDZDCCAkygAwIBAgICC7gwDQYJKoZIhvcNAQELBQAwRDELMAkGA1UEBhMCTFUx -FjAUBgNVBAoTDUx1eFRydXN0IHMuYS4xHTAbBgNVBAMTFEx1eFRydXN0IEdsb2Jh -bCBSb290MB4XDTExMDMxNzA5NTEzN1oXDTIxMDMxNzA5NTEzN1owRDELMAkGA1UE -BhMCTFUxFjAUBgNVBAoTDUx1eFRydXN0IHMuYS4xHTAbBgNVBAMTFEx1eFRydXN0 -IEdsb2JhbCBSb290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsn+n -QPAiygz267Hxyw6VV0B1r6A/Ps7sqjJX5hmxZ0OYWmt8s7j6eJyqpoSyYBuAQc5j -zR8XCJmk9e8+EsdMsFeaXHhAePxFjdqRZ9w6Ubltc+a3OY52OrQfBfVpVfmTz3iI -Sr6qm9d7R1tGBEyCFqY19vx039a0r9jitScRdFmiwmYsaArhmIiIPIoFdRTjuK7z -CISbasE/MRivJ6VLm6T9eTHemD0OYcqHmMH4ijCc+j4z1aXEAwfh95Z0GAAnOCfR -K6qq4UFFi2/xJcLcopeVx0IUM115hCNq52XAV6DYXaljAeew5Ivo+MVjuOVsdJA9 -x3f8K7p56aTGEnin/wIDAQABo2AwXjAMBgNVHRMEBTADAQH/MA4GA1UdDwEB/wQE -AwIBBjAfBgNVHSMEGDAWgBQXFYWJCS8kh28/HRvk8pZ5g0gTzjAdBgNVHQ4EFgQU -FxWFiQkvJIdvPx0b5PKWeYNIE84wDQYJKoZIhvcNAQELBQADggEBAFrwHNDUUM9B -fua4nX3DcNBeNv9ujnov3kgR1TQuPLdFwlQlp+HBHjeDtpSutkVIA+qVvuucarQ3 -XB8u02uCgUNbCj8RVWOs+nwIAjegPDkEM/6XMshS5dklTbDG7mgfcKpzzlcD3H0K -DTPy0lrfCmw7zBFRlxqkIaKFNQLXgCLShLL4wKpov9XrqsMLq6F8K/f1O4fhVFfs -BSTveUJO84ton+Ruy4KZycwq3FPCH3CDqyEPVrRI/98HIrOM+R2mBN8tAza53W/+ -MYhm/2xtRDSvCHc+JtJy9LtHVpM8mGPhM7uZI5K1g3noHZ9nrWLWidb2/CfeMifL -hNp3hSGhEiE= ------END CERTIFICATE----- diff --git a/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipFileSystem.java b/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipFileSystem.java index 8334d47afcb0..9aa0095f2d0c 100644 --- a/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipFileSystem.java +++ b/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipFileSystem.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 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 @@ -1202,7 +1202,7 @@ private void endRead() { private volatile boolean isOpen = true; private final SeekableByteChannel ch; // channel to the zipfile - final byte[] cen; // CEN & ENDHDR + final byte[] cen; // CEN private END end; private long locpos; // position of first LOC header (usually 0) @@ -1566,15 +1566,15 @@ private byte[] initCEN() throws IOException { if (locpos < 0) throw new ZipException("invalid END header (bad central directory offset)"); - // read in the CEN and END - byte[] cen = new byte[(int)(end.cenlen + ENDHDR)]; - if (readNBytesAt(cen, 0, cen.length, cenpos) != end.cenlen + ENDHDR) { + // read in the CEN + byte[] cen = new byte[(int)(end.cenlen)]; + if (readNBytesAt(cen, 0, cen.length, cenpos) != end.cenlen) { throw new ZipException("read CEN tables failed"); } // Iterate through the entries in the central directory inodes = LinkedHashMap.newLinkedHashMap(end.centot + 1); int pos = 0; - int limit = cen.length - ENDHDR; + int limit = cen.length; while (pos < limit) { if (!cenSigAt(cen, pos)) throw new ZipException("invalid CEN header (bad signature)"); @@ -1606,7 +1606,7 @@ private byte[] initCEN() throws IOException { // skip ext and comment pos += (CENHDR + nlen + elen + clen); } - if (pos + ENDHDR != cen.length) { + if (pos != cen.length) { throw new ZipException("invalid CEN header (bad header size)"); } buildNodeTree(); diff --git a/test/jdk/java/awt/TextField/CaretPositionTest/CaretPositionTest.java b/test/jdk/java/awt/TextField/CaretPositionTest/CaretPositionTest.java index 56a39758874e..bb30cc65597a 100644 --- a/test/jdk/java/awt/TextField/CaretPositionTest/CaretPositionTest.java +++ b/test/jdk/java/awt/TextField/CaretPositionTest/CaretPositionTest.java @@ -79,13 +79,15 @@ public void setupGUI() { public void test() throws AWTException, InterruptedException, InvocationTargetException { - EventQueue.invokeAndWait(() -> { - onScreen = text_field.getLocationOnScreen(); - size = text_field.getSize(); - }); Robot robot = new Robot(); robot.setAutoDelay(50); robot.delay(1000); + + EventQueue.invokeAndWait(() -> { + onScreen = text_field.getLocationOnScreen(); + size = text_field.getSize(); + }); + int y = onScreen.y + (size.height / 2); robot.mouseMove(onScreen.x + (size.width / 2), y); robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); diff --git a/test/jdk/sun/security/lib/cacerts/VerifyCACerts.java b/test/jdk/sun/security/lib/cacerts/VerifyCACerts.java index 30947f96dba2..87c0fea985f4 100644 --- a/test/jdk/sun/security/lib/cacerts/VerifyCACerts.java +++ b/test/jdk/sun/security/lib/cacerts/VerifyCACerts.java @@ -28,7 +28,7 @@ * 8223499 8225392 8232019 8234245 8233223 8225068 8225069 8243321 8243320 * 8243559 8225072 8258630 8259312 8256421 8225081 8225082 8225083 8245654 * 8305975 8304760 8307134 8295894 8314960 8317373 8317374 8318759 8319187 - * 8321408 8316138 8341057 8303770 8350498 8359170 8361212 8372351 + * 8321408 8316138 8341057 8303770 8350498 8359170 8361212 8372351 8387123 * @summary Check root CA entries in cacerts file */ import java.io.ByteArrayInputStream; @@ -48,13 +48,13 @@ public class VerifyCACerts { // The numbers of certs now. // SapMachine 2021-09-23: Additional certificate for SAP - private static final int COUNT = 112; + private static final int COUNT = 111; // SHA-256 of cacerts, can be generated with // shasum -a 256 cacerts | sed -e 's/../&:/g' | tr '[:lower:]' '[:upper:]' | cut -c1-95 // SapMachine 2021-09-23: Additional certificate for SAP private static final String CHECKSUM - = "46:B4:9E:42:70:3A:8A:AA:28:88:21:EE:DA:1B:4A:9B:6F:0C:C6:5F:D4:58:31:F7:A5:DB:9E:1B:5E:43:A8:9D"; + = "A6:7C:8E:66:E1:30:1E:DB:A0:AF:2A:1E:63:44:EB:D3:E5:B5:4A:75:F8:AE:A2:85:3A:1F:20:09:E4:A5:D7:33"; // Hex formatter to upper case with ":" delimiter private static final HexFormat HEX = HexFormat.ofDelimiter(":").withUpperCase(); @@ -147,8 +147,6 @@ public class VerifyCACerts { "96:BC:EC:06:26:49:76:F3:74:60:77:9A:CF:28:C5:A7:CF:E8:A3:C0:AA:E1:1A:8F:FC:EE:05:C0:BD:DF:08:C6"); put("letsencryptisrgx2 [jdk]", "69:72:9B:8E:15:A8:6E:FC:17:7A:57:AF:B7:17:1D:FC:64:AD:D2:8C:2F:CA:8C:F1:50:7E:34:45:3C:CB:14:70"); - put("luxtrustglobalrootca [jdk]", - "A1:B2:DB:EB:64:E7:06:C6:16:9E:3C:41:18:B2:3B:AA:09:01:8A:84:27:66:6D:8B:F0:E2:88:91:EC:05:19:50"); put("quovadisrootca [jdk]", "A4:5E:DE:3B:BB:F0:9C:8A:E1:5C:72:EF:C0:72:68:D6:93:A2:1C:99:6F:D5:1E:67:CA:07:94:60:FD:6D:88:73"); put("quovadisrootca1g3 [jdk]", @@ -300,8 +298,6 @@ public class VerifyCACerts { add("addtrustexternalca [jdk]"); // Valid until: Sat May 30 10:44:50 GMT 2020 add("addtrustqualifiedca [jdk]"); - // Valid until: Wed Mar 17 02:51:37 PDT 2021 - add("luxtrustglobalrootca [jdk]"); // Valid until: Wed Mar 17 11:33:33 PDT 2021 add("quovadisrootca [jdk]"); // Valid until: Sat May 21 04:00:00 GMT 2022 diff --git a/test/jdk/sun/util/resources/TimeZone/Bug8139107.java b/test/jdk/sun/util/resources/TimeZone/Bug8139107.java index 4334d63dcdf5..a7bf0f7ec508 100644 --- a/test/jdk/sun/util/resources/TimeZone/Bug8139107.java +++ b/test/jdk/sun/util/resources/TimeZone/Bug8139107.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 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 @@ -27,11 +27,12 @@ * @summary Test that date parsing with DateTimeFormatter pattern * that contains timezone field doesn't trigger NPE. All supported * locales are tested. - * @run testng/othervm -Djava.locale.providers=JRE,SPI Bug8139107 + * @run junit/othervm -Djava.locale.providers=JRE,SPI Bug8139107 */ import java.time.format.DateTimeFormatter; import java.util.Locale; -import org.testng.annotations.Test; + +import org.junit.jupiter.api.Test; public class Bug8139107 { diff --git a/test/jdk/sun/util/resources/TimeZone/ChineseTimeZoneNameTest.java b/test/jdk/sun/util/resources/TimeZone/ChineseTimeZoneNameTest.java index c752ec4d63c2..ad068d114d6a 100644 --- a/test/jdk/sun/util/resources/TimeZone/ChineseTimeZoneNameTest.java +++ b/test/jdk/sun/util/resources/TimeZone/ChineseTimeZoneNameTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 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,8 +26,8 @@ * @bug 8275721 * @modules jdk.localedata * @summary Checks Chinese time zone names for `UTC` using CLDR are consistent - * @run testng/othervm -Djava.locale.providers=CLDR,COMPAT ChineseTimeZoneNameTest - * @run testng/othervm -Djava.locale.providers=CLDR ChineseTimeZoneNameTest + * @run junit/othervm -Djava.locale.providers=CLDR,COMPAT ChineseTimeZoneNameTest + * @run junit/othervm -Djava.locale.providers=CLDR ChineseTimeZoneNameTest */ import java.time.Instant; @@ -36,11 +36,10 @@ import java.time.format.DateTimeFormatter; import java.util.Locale; -import static org.testng.Assert.assertEquals; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +import static org.junit.jupiter.api.Assertions.assertEquals; -@Test public class ChineseTimeZoneNameTest { private static final Locale SIMPLIFIED_CHINESE = Locale.forLanguageTag("zh-Hans"); @@ -48,8 +47,7 @@ public class ChineseTimeZoneNameTest { private static final ZonedDateTime EPOCH_UTC = ZonedDateTime.ofInstant(Instant.ofEpochSecond (0), ZoneId.of ("UTC")); - @DataProvider(name="locales") - Object[][] data() { + private static Object[][] data() { return new Object[][] { {Locale.CHINESE, SIMPLIFIED_CHINESE}, {Locale.SIMPLIFIED_CHINESE, SIMPLIFIED_CHINESE}, @@ -62,11 +60,12 @@ Object[][] data() { }; } - @Test(dataProvider="locales") + @ParameterizedTest + @MethodSource("data") public void test_ChineseTimeZoneNames(Locale testLoc, Locale resourceLoc) { - assertEquals(DateTimeFormatter.ofPattern("z", testLoc).format(EPOCH_UTC), - DateTimeFormatter.ofPattern("z", resourceLoc).format(EPOCH_UTC)); - assertEquals(DateTimeFormatter.ofPattern("zzzz", testLoc).format(EPOCH_UTC), - DateTimeFormatter.ofPattern("zzzz", resourceLoc).format(EPOCH_UTC)); + assertEquals(DateTimeFormatter.ofPattern("z", resourceLoc).format(EPOCH_UTC), + DateTimeFormatter.ofPattern("z", testLoc).format(EPOCH_UTC)); + assertEquals(DateTimeFormatter.ofPattern("zzzz", resourceLoc).format(EPOCH_UTC), + DateTimeFormatter.ofPattern("zzzz", testLoc).format(EPOCH_UTC)); } } diff --git a/test/jdk/sun/util/resources/cldr/Bug8202764.java b/test/jdk/sun/util/resources/cldr/Bug8202764.java index 6f3e40e62012..e7fa110671af 100644 --- a/test/jdk/sun/util/resources/cldr/Bug8202764.java +++ b/test/jdk/sun/util/resources/cldr/Bug8202764.java @@ -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 @@ -28,11 +28,9 @@ * @summary Checks time zone names are consistent with aliased ids, * between DateFormatSymbols.getZoneStrings() and getDisplayName() * of TimeZone/ZoneId classes - * @run testng/othervm Bug8202764 + * @run junit/othervm Bug8202764 */ -import static org.testng.Assert.assertEquals; - import java.time.ZoneId; import java.time.format.TextStyle; import java.text.DateFormatSymbols; @@ -41,7 +39,8 @@ import java.util.Set; import java.util.TimeZone; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; public class Bug8202764 { @@ -53,15 +52,15 @@ public void testAliasedTZs() { .forEach(zone -> { System.out.println(zone[0]); TimeZone tz = TimeZone.getTimeZone(zone[0]); - assertEquals(zone[1], tz.getDisplayName(false, TimeZone.LONG, Locale.US)); - assertEquals(zone[2], tz.getDisplayName(false, TimeZone.SHORT, Locale.US)); - assertEquals(zone[3], tz.getDisplayName(true, TimeZone.LONG, Locale.US)); - assertEquals(zone[4], tz.getDisplayName(true, TimeZone.SHORT, Locale.US)); + assertEquals(tz.getDisplayName(false, TimeZone.LONG, Locale.US), zone[1]); + assertEquals(tz.getDisplayName(false, TimeZone.SHORT, Locale.US), zone[2]); + assertEquals(tz.getDisplayName(true, TimeZone.LONG, Locale.US), zone[3]); + assertEquals(tz.getDisplayName(true, TimeZone.SHORT, Locale.US), zone[4]); if (zoneIds.contains(zone[0])) { // Some of the ids, e.g. three-letter ids are not supported in ZoneId ZoneId zi = tz.toZoneId(); - assertEquals(zone[5], zi.getDisplayName(TextStyle.FULL, Locale.US)); - assertEquals(zone[6], zi.getDisplayName(TextStyle.SHORT, Locale.US)); + assertEquals(zi.getDisplayName(TextStyle.FULL, Locale.US), zone[5]); + assertEquals(zi.getDisplayName(TextStyle.SHORT, Locale.US), zone[6]); } }); } diff --git a/test/jdk/sun/util/resources/cldr/TimeZoneNamesTest.java b/test/jdk/sun/util/resources/cldr/TimeZoneNamesTest.java index eb56c087ad65..bc121979fa95 100644 --- a/test/jdk/sun/util/resources/cldr/TimeZoneNamesTest.java +++ b/test/jdk/sun/util/resources/cldr/TimeZoneNamesTest.java @@ -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,29 +24,35 @@ /* * @test * @bug 8181157 8202537 8234347 8236548 8261279 + * 8381379 * @modules jdk.localedata * @summary Checks CLDR time zone names are generated correctly at runtime - * @run testng/othervm -Djava.locale.providers=CLDR TimeZoneNamesTest + * @run junit/othervm -Djava.locale.providers=CLDR TimeZoneNamesTest */ import java.text.DateFormatSymbols; +import java.text.SimpleDateFormat; import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; import java.time.format.TextStyle; import java.util.Arrays; +import java.util.Date; import java.util.Locale; import java.util.Objects; import java.util.TimeZone; +import java.util.stream.Stream; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertFalse; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; -@Test public class TimeZoneNamesTest { - @DataProvider(name="noResourceTZs") - Object[][] data() { + private static Object[][] data() { return new Object[][] { // tzid, locale, style, expected @@ -177,20 +183,33 @@ Object[][] data() { }; } + private static Stream explicitDstOffsets() { + return Stream.of( + Arguments.of(ZonedDateTime.of(2026, 4, 5, 0, 0, 0, 0, ZoneId.of("Europe/Dublin")), "Irish Standard Time"), + Arguments.of(ZonedDateTime.of(2026, 12, 5, 0, 0, 0, 0, ZoneId.of("Europe/Dublin")), "Greenwich Mean Time"), + Arguments.of(ZonedDateTime.of(2026, 4, 5, 0, 0, 0, 0, ZoneId.of("Eire")), "Irish Standard Time"), + Arguments.of(ZonedDateTime.of(2026, 12, 5, 0, 0, 0, 0, ZoneId.of("Eire")), "Greenwich Mean Time"), + Arguments.of(ZonedDateTime.of(2026, 4, 5, 0, 0, 0, 0, ZoneId.of("America/Vancouver")), "Pacific Daylight Time"), + // This needs to change once TZDB adopts -7 offset year round, and CLDR uses explicit dst offset + // namely, "Pacific Standard Time" -> "Pacific Daylight Time" + Arguments.of(ZonedDateTime.of(2026, 12, 5, 0, 0, 0, 0, ZoneId.of("America/Vancouver")), "Pacific Standard Time") + ); + } - @Test(dataProvider="noResourceTZs") + @ParameterizedTest + @MethodSource("data") public void test_tzNames(String tzid, Locale locale, String lstd, String sstd, String ldst, String sdst, String lgen, String sgen) { // Standard time - assertEquals(TimeZone.getTimeZone(tzid).getDisplayName(false, TimeZone.LONG, locale), lstd); - assertEquals(TimeZone.getTimeZone(tzid).getDisplayName(false, TimeZone.SHORT, locale), sstd); + assertEquals(lstd, TimeZone.getTimeZone(tzid).getDisplayName(false, TimeZone.LONG, locale)); + assertEquals(sstd, TimeZone.getTimeZone(tzid).getDisplayName(false, TimeZone.SHORT, locale)); // daylight saving time - assertEquals(TimeZone.getTimeZone(tzid).getDisplayName(true, TimeZone.LONG, locale), ldst); - assertEquals(TimeZone.getTimeZone(tzid).getDisplayName(true, TimeZone.SHORT, locale), sdst); + assertEquals(ldst, TimeZone.getTimeZone(tzid).getDisplayName(true, TimeZone.LONG, locale)); + assertEquals(sdst, TimeZone.getTimeZone(tzid).getDisplayName(true, TimeZone.SHORT, locale)); // generic name - assertEquals(ZoneId.of(tzid).getDisplayName(TextStyle.FULL, locale), lgen); - assertEquals(ZoneId.of(tzid).getDisplayName(TextStyle.SHORT, locale), sgen); + assertEquals(lgen, ZoneId.of(tzid).getDisplayName(TextStyle.FULL, locale)); + assertEquals(sgen, ZoneId.of(tzid).getDisplayName(TextStyle.SHORT, locale)); } // Make sure getZoneStrings() returns non-empty string array @@ -209,4 +228,19 @@ public void test_getZoneStrings() { .isPresent(), "getZoneStrings() returned array containing non-empty string element(s)"); } + + // Explicit metazone dst offset test. As of CLDR v48, only Europe/Dublin utilizes + // this attribute, but will be used for America/Vancouver once CLDR adopts the + // explicit offset for that zone, which warrants the test data modification. + @ParameterizedTest + @MethodSource("explicitDstOffsets") + public void test_ExplicitMetazoneOffsets(ZonedDateTime zdt, String expected) { + // java.time + assertEquals(expected, DateTimeFormatter.ofPattern("zzzz").format(zdt)); + + // java.text/util + var sdf = new SimpleDateFormat("zzzz"); + sdf.setTimeZone(TimeZone.getTimeZone(zdt.getZone())); + assertEquals(expected, sdf.format(Date.from(zdt.toInstant()))); + } } diff --git a/test/lib-test/jdk/test/lib/security/CPVAlgTestWithOCSP.java b/test/lib-test/jdk/test/lib/security/CPVAlgTestWithOCSP.java new file mode 100644 index 000000000000..73659d1434d7 --- /dev/null +++ b/test/lib-test/jdk/test/lib/security/CPVAlgTestWithOCSP.java @@ -0,0 +1,229 @@ +/* + * Copyright (c) 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 + * 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 8349759 + * @summary Test the CertificateBuilder and SimpleOCSPServer test utility + * classes using a range of signature algorithms and parameters. + * The goal is to test with both no-parameter and parameterized + * signature algorithms and use the CertPathValidator to validate + * the correctness of the certificate and OCSP server-side structures. + * @modules java.base/sun.security.x509 + * java.base/sun.security.provider.certpath + * java.base/sun.security.util + * @library /test/lib + * @run main/othervm CPVAlgTestWithOCSP RSA + * @run main/othervm CPVAlgTestWithOCSP RSA:3072 + * @run main/othervm CPVAlgTestWithOCSP DSA + * @run main/othervm CPVAlgTestWithOCSP DSA:3072 + * @run main/othervm CPVAlgTestWithOCSP RSASSA-PSS + * @run main/othervm CPVAlgTestWithOCSP RSASSA-PSS:3072 + * @run main/othervm CPVAlgTestWithOCSP RSASSA-PSS:4096:SHA-512:SHA3-384:128:1 + * @run main/othervm CPVAlgTestWithOCSP EC + * @run main/othervm CPVAlgTestWithOCSP EC:secp521r1 + * @run main/othervm CPVAlgTestWithOCSP Ed25519 + */ + +import java.math.BigInteger; +import java.security.*; +import java.security.cert.*; +import java.security.cert.Certificate; +import java.security.spec.*; +import java.util.*; +import java.util.concurrent.TimeUnit; + +import jdk.test.lib.security.SimpleOCSPServer; +import jdk.test.lib.security.CertificateBuilder; + +import static java.security.cert.PKIXRevocationChecker.Option.NO_FALLBACK; + +public class CPVAlgTestWithOCSP { + + static final String passwd = "passphrase"; + static final String ROOT_ALIAS = "root"; + static final boolean[] CA_KU_FLAGS = {true, false, false, false, false, + true, true, false, false}; + static final boolean[] EE_KU_FLAGS = {true, false, false, false, false, + false, false, false, false}; + static final List EE_EKU_OIDS = List.of("1.3.6.1.5.5.7.3.1", + "1.3.6.1.5.5.7.3.2"); + + public static void main(String[] args) throws Exception { + if (args == null || args.length < 1) { + throw new RuntimeException( + "Usage: CPVAlgTestWithOCSP "); + } + String keyGenAlg = args[0]; + + // Generate Root and EE keys + KeyPairGenerator keyGen = getKpGen(keyGenAlg); + KeyPair rootCaKP = keyGen.genKeyPair(); + KeyPair eeKp = keyGen.genKeyPair(); + + // Set up the Root CA Cert + // Make a 3 year validity starting from 60 days ago + long start = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(60); + long end = start + TimeUnit.DAYS.toMillis(1085); + CertificateBuilder cbld = new CertificateBuilder(); + cbld.setSubjectName("CN=Root CA Cert, O=SomeCompany"). + setPublicKey(rootCaKP.getPublic()). + setSerialNumber(new BigInteger("1")). + setValidity(new Date(start), new Date(end)). + addSubjectKeyIdExt(rootCaKP.getPublic()). + addAuthorityKeyIdExt(rootCaKP.getPublic()). + addBasicConstraintsExt(true, true, -1). + addKeyUsageExt(CA_KU_FLAGS); + + // Make our Root CA Cert! + X509Certificate rootCert = cbld.build(null, rootCaKP.getPrivate()); + log("Root CA Created:\n%s", rootCert); + + // Now build a keystore and add the keys and cert + KeyStore.Builder keyStoreBuilder = + KeyStore.Builder.newInstance("PKCS12", null, + new KeyStore.PasswordProtection("adminadmin0".toCharArray())); + KeyStore rootKeystore = keyStoreBuilder.getKeyStore(); + Certificate[] rootChain = {rootCert}; + rootKeystore.setKeyEntry(ROOT_ALIAS, rootCaKP.getPrivate(), + passwd.toCharArray(), rootChain); + + // Now fire up the OCSP responder + SimpleOCSPServer rootOcsp = new SimpleOCSPServer(rootKeystore, + passwd, ROOT_ALIAS, null); + rootOcsp.enableLog(true); + rootOcsp.setNextUpdateInterval(3600); + rootOcsp.start(); + + // Wait 60 seconds for server ready + boolean readyStatus = rootOcsp.awaitServerReady(60, TimeUnit.SECONDS); + if (!readyStatus) { + throw new RuntimeException("Server not ready"); + } + int rootOcspPort = rootOcsp.getPort(); + String rootRespURI = "http://localhost:" + rootOcspPort; + log("Root OCSP Responder URI is %s", rootRespURI); + + // Let's make an EE cert + // Make a 1 year validity starting from 60 days ago + start = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(60); + end = start + TimeUnit.DAYS.toMillis(365); + cbld.reset().setSubjectName("CN=Brave Sir Robin, O=SomeCompany"). + setPublicKey(eeKp.getPublic()). + setValidity(new Date(start), new Date(end)). + addSubjectKeyIdExt(eeKp.getPublic()). + addAuthorityKeyIdExt(rootCaKP.getPublic()). + addKeyUsageExt(EE_KU_FLAGS). + addExtendedKeyUsageExt(EE_EKU_OIDS). + addSubjectAltNameDNSExt(Collections.singletonList("localhost")). + addAIAExt(Collections.singletonList(rootRespURI)); + X509Certificate eeCert = cbld.build(rootCert, rootCaKP.getPrivate()); + log("EE CA Created:\n%s", eeCert); + + // Provide end entity cert revocation info to the Root CA + // OCSP responder. + Map revInfo = + new HashMap<>(); + revInfo.put(eeCert.getSerialNumber(), + new SimpleOCSPServer.CertStatusInfo( + SimpleOCSPServer.CertStatus.CERT_STATUS_GOOD)); + rootOcsp.updateStatusDb(revInfo); + + // validate chain + CertPathValidator cpv = CertPathValidator.getInstance("PKIX"); + PKIXRevocationChecker prc = + (PKIXRevocationChecker) cpv.getRevocationChecker(); + prc.setOptions(EnumSet.of(NO_FALLBACK)); + PKIXParameters params = + new PKIXParameters(Set.of(new TrustAnchor(rootCert, null))); + params.addCertPathChecker(prc); + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + CertPath cp = cf.generateCertPath(List.of(eeCert)); + cpv.validate(cp, params); + } + + private static KeyPairGenerator getKpGen(String keyGenAlg) + throws GeneralSecurityException { + String[] algComps = keyGenAlg.split(":"); + KeyPairGenerator kpg = KeyPairGenerator.getInstance(algComps[0]); + int bitLen; + + // Handle any parameters in additional tokenized fields + switch (algComps[0].toUpperCase()) { + case "EC": + // The curve name will be the second token, or secp256r1 + // if not provided. + String curveName = (algComps.length >= 2) ? algComps[1] : + "secp256r1"; + kpg.initialize(new ECGenParameterSpec(curveName)); + break; + case "RSA": + case "DSA": + // Form is RSA|DSA[:] + bitLen = (algComps.length >= 2) ? + Integer.parseInt(algComps[1]) : 2048; + kpg.initialize(bitLen); + break; + case "RSASSA-PSS": + // Form is RSASSA-PSS[:[:HASH:MGFHASH:SALTLEN:TR]] + switch (algComps.length) { + case 1: // Default key length and parameters + kpg.initialize(2048); + break; + case 2: // Specified key length, default params + kpg.initialize(Integer.parseInt(algComps[1])); + break; + default: // len > 2, key length and specified parameters + bitLen = Integer.parseInt(algComps[1]); + String hashAlg = algComps[2]; + MGF1ParameterSpec mSpec = (algComps.length >= 4) ? + new MGF1ParameterSpec(algComps[3]) : + MGF1ParameterSpec.SHA256; + int saltLen = (algComps.length >= 5) ? + Integer.parseInt(algComps[4]) : 32; + int trail = (algComps.length >= 6) ? + Integer.parseInt(algComps[5]) : + PSSParameterSpec.TRAILER_FIELD_BC; + PSSParameterSpec pSpec = new PSSParameterSpec(hashAlg, + "MGF1", mSpec, saltLen, trail); + kpg.initialize(new RSAKeyGenParameterSpec(bitLen, + RSAKeyGenParameterSpec.F4, pSpec)); + break; + } + + // Default: just use the KPG as-is, no additional init needed. + } + + return kpg; + } + + /** + * Log a message on stdout + * + * @param format the format string for the log entry + * @param args zero or more arguments corresponding to the format string + */ + private static void log(String format, Object ... args) { + System.out.format(format + "\n", args); + } +} diff --git a/test/lib/jdk/test/lib/security/CertificateBuilder.java b/test/lib/jdk/test/lib/security/CertificateBuilder.java index 2cf836b0a5d7..7213ca3c6568 100644 --- a/test/lib/jdk/test/lib/security/CertificateBuilder.java +++ b/test/lib/jdk/test/lib/security/CertificateBuilder.java @@ -48,13 +48,13 @@ 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; import sun.security.x509.KeyUsageExtension; -import sun.security.x509.SerialNumber; import sun.security.x509.SubjectAlternativeNameExtension; import sun.security.x509.URIName; import sun.security.x509.KeyIdentifier; @@ -452,11 +452,8 @@ public CertificateBuilder addAIAExt(List locations) * * @param bitSettings Boolean array for all nine bit settings in the order * documented in RFC 5280 section 4.2.1.3. - * - * @throws IOException if an encoding error occurs. */ - public CertificateBuilder addKeyUsageExt(boolean[] bitSettings) - throws IOException { + public CertificateBuilder addKeyUsageExt(boolean[] bitSettings) { return addExtension(new KeyUsageExtension(bitSettings)); } @@ -469,11 +466,9 @@ public CertificateBuilder addKeyUsageExt(boolean[] bitSettings) * @param maxPathLen The maximum path length issued by this CA. Values * less than zero will omit this field from the resulting extension and * no path length constraint will be asserted. - * - * @throws IOException if an encoding error occurs. */ public CertificateBuilder addBasicConstraintsExt(boolean crit, boolean isCA, - int maxPathLen) throws IOException { + int maxPathLen) { return addExtension(new BasicConstraintsExtension(crit, isCA, maxPathLen)); } @@ -564,7 +559,27 @@ public CertificateBuilder reset() { } /** - * Build the certificate. + * Build the certificate using the default algorithm for the provided + * signing key. + * + * @param issuerCert The certificate of the issuing authority, or + * {@code null} if the resulting certificate is self-signed. + * @param issuerKey The private key of the issuing authority + * + * @return The resulting {@link X509Certificate} + * + * @throws IOException if an encoding error occurs. + * @throws CertificateException If the certificate cannot be generated + * by the underlying {@link CertificateFactory} + */ + public X509Certificate build(X509Certificate issuerCert, + PrivateKey issuerKey) throws IOException, CertificateException { + return build(issuerCert, issuerKey, + SignatureUtil.getDefaultSigAlgForKey(issuerKey)); + } + + /** + * Build the certificate using the key and specified signing algorithm. * * @param issuerCert The certificate of the issuing authority, or * {@code null} if the resulting certificate is self-signed. @@ -576,14 +591,10 @@ public CertificateBuilder reset() { * @throws IOException if an encoding error occurs. * @throws CertificateException If the certificate cannot be generated * by the underlying {@link CertificateFactory} - * @throws NoSuchAlgorithmException If an invalid signature algorithm - * is provided. */ public X509Certificate build(X509Certificate issuerCert, PrivateKey issuerKey, String algName) - throws IOException, CertificateException, NoSuchAlgorithmException { - // TODO: add some basic checks (key usage, basic constraints maybe) - + throws IOException, CertificateException { byte[] encodedCert = encodeTopLevel(issuerCert, issuerKey, algName); ByteArrayInputStream bais = new ByteArrayInputStream(encodedCert); return (X509Certificate)factory.generateCertificate(bais); @@ -612,15 +623,14 @@ public X509Certificate build(X509Certificate issuerCert, */ private byte[] encodeTopLevel(X509Certificate issuerCert, PrivateKey issuerKey, String algName) - throws CertificateException, IOException, NoSuchAlgorithmException { + throws CertificateException, IOException { - AlgorithmId signAlg = AlgorithmId.get(algName); + AlgorithmId signAlg; DerOutputStream outerSeq = new DerOutputStream(); DerOutputStream topLevelItems = new DerOutputStream(); try { - Signature sig = SignatureUtil.fromKey(signAlg.getName(), issuerKey, (Provider)null); - // Rewrite signAlg, RSASSA-PSS needs some parameters. + Signature sig = SignatureUtil.fromKey(algName, issuerKey, ""); signAlg = SignatureUtil.fromSignature(sig, issuerKey); tbsCertBytes = encodeTbsCert(issuerCert, signAlg); sig.update(tbsCertBytes); @@ -677,7 +687,9 @@ private byte[] encodeTbsCert(X509Certificate issuerCert, } // Serial Number - SerialNumber sn = new SerialNumber(serialNumber); + CertificateSerialNumber sn = (serialNumber != null) ? + new CertificateSerialNumber(serialNumber) : + CertificateSerialNumber.newRandom64bit(new SecureRandom()); sn.encode(tbsCertItems); // Algorithm ID @@ -694,8 +706,12 @@ private byte[] encodeTbsCert(X509Certificate issuerCert, // Validity period (set as UTCTime) DerOutputStream valSeq = new DerOutputStream(); - valSeq.putUTCTime(notBefore); - valSeq.putUTCTime(notAfter); + Instant now = Instant.now(); + Date startDate = (notBefore != null) ? notBefore : Date.from(now); + valSeq.putUTCTime(startDate); + Date endDate = (notAfter != null) ? notAfter : + Date.from(now.plus(90, ChronoUnit.DAYS)); + valSeq.putUTCTime(endDate); tbsCertItems.write(DerValue.tag_Sequence, valSeq); // Subject Name @@ -735,6 +751,9 @@ private byte[] encodeTbsCert(X509Certificate issuerCert, */ private void encodeExtensions(DerOutputStream tbsStream) throws IOException { + if (extensions.isEmpty()) { + return; + } DerOutputStream extSequence = new DerOutputStream(); DerOutputStream extItems = new DerOutputStream(); diff --git a/test/lib/jdk/test/lib/security/SimpleOCSPServer.java b/test/lib/jdk/test/lib/security/SimpleOCSPServer.java index e8ce021b1387..4e25467ca80b 100644 --- a/test/lib/jdk/test/lib/security/SimpleOCSPServer.java +++ b/test/lib/jdk/test/lib/security/SimpleOCSPServer.java @@ -25,6 +25,7 @@ import java.io.*; import java.net.*; +import java.nio.charset.StandardCharsets; import java.security.*; import java.security.cert.CRLReason; import java.security.cert.X509Certificate; @@ -61,7 +62,7 @@ public class SimpleOCSPServer { static final int FREE_PORT = 0; // CertStatus values - public static enum CertStatus { + public enum CertStatus { CERT_STATUS_GOOD, CERT_STATUS_REVOKED, CERT_STATUS_UNKNOWN, @@ -69,14 +70,14 @@ public static enum CertStatus { // Fields used for the networking portion of the responder private ServerSocket servSocket; - private InetAddress listenAddress; + private final InetAddress listenAddress; private int listenPort; // Keystore information (certs, keys, etc.) - private KeyStore keystore; - private X509Certificate issuerCert; - private X509Certificate signerCert; - private PrivateKey signerKey; + private final KeyStore keystore; + private final X509Certificate issuerCert; + private final X509Certificate signerCert; + private final PrivateKey signerKey; // Fields used for the operational portions of the server private boolean logEnabled = false; @@ -91,9 +92,9 @@ public static enum CertStatus { // Fields used in the generation of responses private long nextUpdateInterval = -1; private Date nextUpdate = null; - private ResponderId respId; - private AlgorithmId sigAlgId; - private Map statusDb = + private final ResponderId respId; + private String sigAlgName; + private final Map statusDb = Collections.synchronizedMap(new HashMap<>()); /** @@ -140,25 +141,24 @@ public SimpleOCSPServer(KeyStore ks, String password, String issuerAlias, public SimpleOCSPServer(InetAddress addr, int port, KeyStore ks, String password, String issuerAlias, String signerAlias) throws GeneralSecurityException, IOException { - Objects.requireNonNull(ks, "Null keystore provided"); + keystore = Objects.requireNonNull(ks, "Null keystore provided"); Objects.requireNonNull(issuerAlias, "Null issuerName provided"); utcDateFmt.setTimeZone(TimeZone.getTimeZone("GMT")); - keystore = ks; - issuerCert = (X509Certificate)ks.getCertificate(issuerAlias); + issuerCert = (X509Certificate)keystore.getCertificate(issuerAlias); if (issuerCert == null) { throw new IllegalArgumentException("Certificate for alias " + issuerAlias + " not found"); } if (signerAlias != null) { - signerCert = (X509Certificate)ks.getCertificate(signerAlias); + signerCert = (X509Certificate)keystore.getCertificate(signerAlias); if (signerCert == null) { throw new IllegalArgumentException("Certificate for alias " + signerAlias + " not found"); } - signerKey = (PrivateKey)ks.getKey(signerAlias, + signerKey = (PrivateKey)keystore.getKey(signerAlias, password.toCharArray()); if (signerKey == null) { throw new IllegalArgumentException("PrivateKey for alias " + @@ -166,14 +166,14 @@ public SimpleOCSPServer(InetAddress addr, int port, KeyStore ks, } } else { signerCert = issuerCert; - signerKey = (PrivateKey)ks.getKey(issuerAlias, + signerKey = (PrivateKey)keystore.getKey(issuerAlias, password.toCharArray()); if (signerKey == null) { throw new IllegalArgumentException("PrivateKey for alias " + issuerAlias + " not found"); } } - sigAlgId = AlgorithmId.get(SignatureUtil.getDefaultSigAlgForKey(signerKey)); + sigAlgName = SignatureUtil.getDefaultSigAlgForKey(signerKey); respId = new ResponderId(signerCert.getSubjectX500Principal()); listenAddress = addr; listenPort = port; @@ -495,8 +495,14 @@ private Map checkStatusDb( public void setSignatureAlgorithm(String algName) throws NoSuchAlgorithmException { if (!started) { - sigAlgId = AlgorithmId.get(algName); - log("Signature algorithm set to " + sigAlgId.getName()); + // We don't care about the AlgorithmId object, we're just + // using it to validate the algName parameter. + AlgorithmId.get(algName); + sigAlgName = algName; + log("Signature algorithm set to " + algName); + } else { + log("Signature algorithm cannot be set on a running server, " + + "stop the server first"); } } @@ -604,9 +610,9 @@ private static synchronized void err(Throwable exc) { * object may be used to construct OCSP responses. */ public static class CertStatusInfo { - private CertStatus certStatusType; + private final CertStatus certStatusType; private CRLReason reason; - private Date revocationTime; + private final Date revocationTime; /** * Create a Certificate status object by providing the status only. @@ -745,7 +751,7 @@ public void run() { // This will be tokenized so we know if we are dealing with // a GET or POST. String[] headerTokens = readLine(in).split(" "); - LocalOcspRequest ocspReq = null; + LocalOcspRequest ocspReq; LocalOcspResponse ocspResp = null; ResponseStatus respStat = ResponseStatus.INTERNAL_ERROR; try { @@ -794,7 +800,7 @@ public void run() { out.flush(); log("Closing " + ocspSocket); - } catch (IOException | CertificateException exc) { + } catch (IOException | GeneralSecurityException exc) { err(exc); } } @@ -826,10 +832,10 @@ public void sendResponse(OutputStream out, LocalOcspResponse resp) append("\r\n"); } sb.append("\r\n"); + log(resp.toString()); - out.write(sb.toString().getBytes("UTF-8")); + out.write(sb.toString().getBytes(StandardCharsets.UTF_8)); out.write(respBytes); - log(resp.toString()); } /** @@ -940,7 +946,7 @@ private LocalOcspRequest parseHttpOcspGet(String[] headerTokens, // "/" off before decoding. return new LocalOcspRequest(Base64.getMimeDecoder().decode( URLDecoder.decode(headerTokens[1].replaceAll("/", ""), - "UTF-8"))); + StandardCharsets.UTF_8))); } /** @@ -974,8 +980,7 @@ private String readLine(InputStream is) throws IOException { bos.write(b); } } - - return new String(bos.toByteArray(), "UTF-8"); + return bos.toString(StandardCharsets.UTF_8); } } @@ -1052,7 +1057,6 @@ private void parseSignature(DerValue sigSequence) if (sigItems[2].isContextSpecific((byte)0)) { DerValue[] certDerItems = sigItems[2].data.getSequence(4); - int i = 0; for (DerValue dv : certDerItems) { X509Certificate xc = new X509CertImpl(dv); certificates.add(xc); @@ -1131,7 +1135,7 @@ private List getRequests() { * Return the list of X.509 Certificates in this OCSP request. * * @return an unmodifiable {@code List} of zero or more - * {@cpde X509Certificate} objects. + * {@code X509Certificate} objects. */ private List getCertificates() { return Collections.unmodifiableList(certificates); @@ -1295,7 +1299,8 @@ public class LocalOcspResponse { private final Map responseExtensions; private byte[] signature; private final List certificates; - private final byte[] encodedResponse; + private final Signature signEngine; + private final AlgorithmId sigAlgId; /** * Constructor for the generation of non-successful responses @@ -1305,9 +1310,11 @@ public class LocalOcspResponse { * @throws IOException if an error happens during encoding * @throws NullPointerException if {@code respStat} is {@code null} * or {@code respStat} is successful. + * @throws GeneralSecurityException if errors occur while obtaining + * the signature object or any algorithm identifier parameters. */ public LocalOcspResponse(OCSPResponse.ResponseStatus respStat) - throws IOException { + throws IOException, GeneralSecurityException { this(respStat, null, null); } @@ -1324,10 +1331,13 @@ public LocalOcspResponse(OCSPResponse.ResponseStatus respStat) * @throws NullPointerException if {@code respStat} is {@code null} * or {@code respStat} is successful, and a {@code null} {@code itemMap} * has been provided. + * @throws GeneralSecurityException if errors occur while obtaining + * the signature object or any algorithm identifier parameters. */ public LocalOcspResponse(OCSPResponse.ResponseStatus respStat, Map itemMap, - Map reqExtensions) throws IOException { + Map reqExtensions) + throws IOException, GeneralSecurityException { responseStatus = Objects.requireNonNull(respStat, "Illegal null response status"); if (responseStatus == ResponseStatus.SUCCESSFUL) { @@ -1348,13 +1358,18 @@ public LocalOcspResponse(OCSPResponse.ResponseStatus respStat, certificates.add(signerCert); } certificates.add(issuerCert); + // Create the signature object and AlgorithmId that we'll use + // later to create the signature on this response. + signEngine = SignatureUtil.fromKey(sigAlgName, signerKey, ""); + sigAlgId = SignatureUtil.fromSignature(signEngine, signerKey); } else { respItemMap = null; producedAtDate = null; responseExtensions = null; certificates = null; + signEngine = null; + sigAlgId = null; } - encodedResponse = this.getBytes(); } /** @@ -1436,13 +1451,9 @@ private byte[] encodeBasicOcspResponse() throws IOException { basicORItemStream.write(tbsResponseBytes); try { - // Create the signature - Signature sig = SignatureUtil.fromKey( - sigAlgId.getName(), signerKey, (Provider)null); - sig.update(tbsResponseBytes); - signature = sig.sign(); - // Rewrite signAlg, RSASSA-PSS needs some parameters. - sigAlgId = SignatureUtil.fromSignature(sig, signerKey); + // Create the signature with the initialized Signature object + signEngine.update(tbsResponseBytes); + signature = signEngine.sign(); sigAlgId.encode(basicORItemStream); basicORItemStream.putBitString(signature); } catch (GeneralSecurityException exc) {