|
| 1 | +/* |
| 2 | + * Copyright (c) 2025, Red Hat, Inc. |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| 4 | + * |
| 5 | + * This code is free software; you can redistribute it and/or modify it |
| 6 | + * under the terms of the GNU General Public License version 2 only, as |
| 7 | + * published by the Free Software Foundation. |
| 8 | + * |
| 9 | + * This code is distributed in the hope that it will be useful, but WITHOUT |
| 10 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| 11 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| 12 | + * version 2 for more details (a copy is included in the LICENSE file that |
| 13 | + * accompanied this code). |
| 14 | + * |
| 15 | + * You should have received a copy of the GNU General Public License version |
| 16 | + * 2 along with this work; if not, write to the Free Software Foundation, |
| 17 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| 18 | + * |
| 19 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| 20 | + * or visit www.oracle.com if you need additional information or have any |
| 21 | + * questions. |
| 22 | + */ |
| 23 | + |
| 24 | +import java.io.ByteArrayInputStream; |
| 25 | +import java.io.ByteArrayOutputStream; |
| 26 | +import java.io.FileInputStream; |
| 27 | +import java.io.FileOutputStream; |
| 28 | +import java.io.IOException; |
| 29 | +import java.io.InputStream; |
| 30 | +import java.nio.file.Path; |
| 31 | +import java.security.KeyStore; |
| 32 | +import java.security.cert.Certificate; |
| 33 | +import java.security.cert.CertificateException; |
| 34 | +import java.security.cert.CertificateFactory; |
| 35 | +import java.security.cert.X509Certificate; |
| 36 | + |
| 37 | +import jdk.test.lib.process.OutputAnalyzer; |
| 38 | +import tests.Helper; |
| 39 | + |
| 40 | +/* |
| 41 | + * @test |
| 42 | + * @summary Verify that no errors are reported for files that have been |
| 43 | + * upgraded when linking from the run-time image |
| 44 | + * @requires (vm.compMode != "Xcomp" & os.maxMemory >= 2g) |
| 45 | + * @library ../../lib /test/lib |
| 46 | + * @modules java.base/jdk.internal.jimage |
| 47 | + * jdk.jlink/jdk.tools.jlink.internal |
| 48 | + * jdk.jlink/jdk.tools.jlink.plugin |
| 49 | + * jdk.jlink/jdk.tools.jimage |
| 50 | + * @build tests.* jdk.test.lib.process.OutputAnalyzer |
| 51 | + * jdk.test.lib.process.ProcessTools |
| 52 | + * @run main/othervm -Xmx1g UpgradeableFileCacertsTest |
| 53 | + */ |
| 54 | +public class UpgradeableFileCacertsTest extends ModifiedFilesTest { |
| 55 | + |
| 56 | + /* |
| 57 | + * Generated with: |
| 58 | + * $ rm -f server.keystore && keytool -genkey -alias jlink-upgrade-test \ |
| 59 | + * -keyalg RSA -dname CN=jlink-upgrade-test \ |
| 60 | + * -storepass changeit -keysize 3072 -sigalg SHA512withRSA \ |
| 61 | + * -validity 7300 -keystore server.keystore |
| 62 | + * $ keytool -export -alias jlink-upgrade-test -storepass changeit \ |
| 63 | + * -keystore server.keystore -rfc |
| 64 | + */ |
| 65 | + private static final String CERT = """ |
| 66 | + -----BEGIN CERTIFICATE----- |
| 67 | + MIID3jCCAkagAwIBAgIJALiT/+HXBkSIMA0GCSqGSIb3DQEBDQUAMB0xGzAZBgNV |
| 68 | + BAMTEmpsaW5rLXVwZ3JhZGUtdGVzdDAeFw0yNTA0MDQxMjA3MjJaFw00NTAzMzAx |
| 69 | + MjA3MjJaMB0xGzAZBgNVBAMTEmpsaW5rLXVwZ3JhZGUtdGVzdDCCAaIwDQYJKoZI |
| 70 | + hvcNAQEBBQADggGPADCCAYoCggGBANmrnCDKqSXEJRIiSi4yHWN97ILls3RqYjED |
| 71 | + la3AZTeXnZrrEIgSjVFUMxCztYqbWoVzKa2lov42Vue2BXVYffcQ8TKc2EJDNO+2 |
| 72 | + uRKQZpsN7RI4QoVBR2Rq8emrO8CrdOQT7Hh4agxkN9AOvGKMFdt+fXeCIPIuflKP |
| 73 | + f+RfvhLfC2A70Y+Uu74C5uWgLloA/HF0SsVxf9KmqS9fZBQaiTYhKyoDghCRlWpa |
| 74 | + nPIHB1XVaRdw8aSpCuzIOQzSCTTlLcammJkBjbFwMZdQG7eglTWzIYryZwe/cyY2 |
| 75 | + xctLVW3xhUHvnMFG+MajeFny2mxNu163Rxf/rBu4e7jRC/LGSU784nJGapq5K170 |
| 76 | + WbaeceKp+YORJBviFFORrmkPIwIgE+iGCD6PD6Xwu8vcpeuTVDgsSWMlfgCL3NoI |
| 77 | + GXmdGiI2Xc/hQX7uzu3UBF6IcPDMTcYr2JKYbgu3v2/vDlJu3qO2ycUeePo5jhuG |
| 78 | + X2WgcHkb6uOU4W5qdbCA+wFPVZBuwQIDAQABoyEwHzAdBgNVHQ4EFgQUtMJM0+ct |
| 79 | + ssKqryRckk4YEWdYAZkwDQYJKoZIhvcNAQENBQADggGBAI8A6gJQ8wDx12sy2ZI4 |
| 80 | + 1q9b+WG6w3LcFEF6Fko5NBizhtfmVycQv4mBa/NJgx4DZmd+5d60gJcTp/hJXGY0 |
| 81 | + LZyFilm/AgxsLNUUQLbHAV6TWqd3ODWwswAuew9sFU6izl286a9W65tbMWL5r1EA |
| 82 | + t34ZYVWZYbCS9+czU98WomH4uarRAOlzcEUui3ZX6ZcQxWbz/R2wtKcUPUAYnsqH |
| 83 | + JPivpE25G5xW2Dp/yeQTrlffq9OLgZWVz0jtOguBUMnsUsgCcpQZtqZX08//wtpz |
| 84 | + ohLHFGvpXTPbRumRasWWtnRR/QqGRT66tYDqybXXz37UtKZ8VKW0sv2ypVbmAEs5 |
| 85 | + pLkA/3XiXlstJuCD6cW0Gfbpb5rrPPD46O3FDVlmqlTH3b/MsiQREdydqGzqY7uG |
| 86 | + AA2GFVaKFASA5ls01CfHLAcrKxSVixditXvsjeIqhddB7Pnbsx20RdzPQoeo9/hF |
| 87 | + WeIrh4zePDPZChuLR8ZyxeVJhLB71nTrTDDjwXarVez9Xw== |
| 88 | + -----END CERTIFICATE----- |
| 89 | + """; |
| 90 | + |
| 91 | + private static final String CERT_ALIAS = "jlink-upgrade-test"; |
| 92 | + |
| 93 | + public static void main(String[] args) throws Exception { |
| 94 | + UpgradeableFileCacertsTest test = new UpgradeableFileCacertsTest(); |
| 95 | + test.run(); |
| 96 | + } |
| 97 | + |
| 98 | + @Override |
| 99 | + String initialImageName() { |
| 100 | + return "java-base-jlink-upgrade-cacerts"; |
| 101 | + } |
| 102 | + |
| 103 | + @Override |
| 104 | + void testAndAssert(Path modifiedFile, Helper helper, Path initialImage) throws Exception { |
| 105 | + CapturingHandler handler = new CapturingHandler(); |
| 106 | + jlinkUsingImage(new JlinkSpecBuilder() |
| 107 | + .helper(helper) |
| 108 | + .imagePath(initialImage) |
| 109 | + .name("java-base-jlink-upgrade-cacerts-target") |
| 110 | + .addModule("java.base") |
| 111 | + .validatingModule("java.base") |
| 112 | + .build(), handler); |
| 113 | + OutputAnalyzer analyzer = handler.analyzer(); |
| 114 | + // verify we don't get any modified warning |
| 115 | + analyzer.stdoutShouldNotContain(modifiedFile.toString() + " has been modified"); |
| 116 | + analyzer.stdoutShouldNotContain("java.lang.IllegalArgumentException"); |
| 117 | + analyzer.stdoutShouldNotContain("IOException"); |
| 118 | + } |
| 119 | + |
| 120 | + // Add an extra certificate in the cacerts file so that it no longer matches |
| 121 | + // the recorded hash sum at build time. |
| 122 | + protected Path modifyFileInImage(Path jmodLessImg) |
| 123 | + throws IOException, AssertionError { |
| 124 | + Path cacerts = jmodLessImg.resolve(Path.of("lib", "security", "cacerts")); |
| 125 | + try (FileInputStream fin = new FileInputStream(cacerts.toFile())) { |
| 126 | + KeyStore certStore = KeyStore.getInstance(cacerts.toFile(), |
| 127 | + (char[])null); |
| 128 | + certStore.load(fin, (char[])null); |
| 129 | + X509Certificate cert; |
| 130 | + try (ByteArrayInputStream bin = new ByteArrayInputStream(CERT.getBytes())) { |
| 131 | + cert = (X509Certificate)generateCertificate(bin); |
| 132 | + } catch (ClassCastException | CertificateException ce) { |
| 133 | + throw new AssertionError("Test failed unexpectedly", ce); |
| 134 | + } |
| 135 | + certStore.setCertificateEntry(CERT_ALIAS, cert); |
| 136 | + ByteArrayOutputStream bout = new ByteArrayOutputStream(); |
| 137 | + certStore.store(bout, (char[])null); |
| 138 | + try (FileOutputStream fout = new FileOutputStream(cacerts.toFile())) { |
| 139 | + fout.write(bout.toByteArray()); |
| 140 | + } |
| 141 | + } catch (Exception e) { |
| 142 | + throw new AssertionError("Test failed unexpectedly: ", e); |
| 143 | + } |
| 144 | + return cacerts; |
| 145 | + } |
| 146 | + |
| 147 | + private Certificate generateCertificate(InputStream in) |
| 148 | + throws CertificateException, IOException { |
| 149 | + byte[] data = in.readAllBytes(); |
| 150 | + return CertificateFactory.getInstance("X.509") |
| 151 | + .generateCertificate(new ByteArrayInputStream(data)); |
| 152 | + } |
| 153 | +} |
0 commit comments