/
githubmirror
/
panama-vector
Обзор
Документация
Войти
/
githubmirror
/
panama-vector
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
test/jdk/java/security/PEM/PEMEncoderTest.java
394 строки
17 KB
Anthony Scarpino
8377506: Implement JEP 538: PEM Encodings of Cryptographic Objects (Third Preview)
03 июн 2026, 20:06
03 июн 2026, 20:06
e70e691
Код
Авторство
О чём код?
/* * 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. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * 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 8298420 * @library /test/lib * @summary Testing basic PEM API encoding * @enablePreview * @modules java.base/sun.security.util * @run main PEMEncoderTest PBEWithHmacSHA256AndAES_128 * @run main/othervm -Djava.security.properties=${test.src}/java.security-anotherAlgo * PEMEncoderTest PBEWithHmacSHA512AndAES_256 * @run main/othervm -Djava.security.properties=${test.src}/java.security-emptyAlgo * PEMEncoderTest PBEWithHmacSHA256AndAES_128 */ import sun.security.util.Pem; import javax.crypto.EncryptedPrivateKeyInfo; import javax.crypto.spec.PBEParameterSpec; import java.nio.charset.StandardCharsets; import java.security.*; import java.security.spec.InvalidParameterSpecException; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; import java.util.*; import jdk.test.lib.security.SecurityUtils; import static jdk.test.lib.Asserts.assertEquals; import static jdk.test.lib.Asserts.assertThrows; public class PEMEncoderTest { static Map<String, BinaryEncodable> keymap; static String pkcs8DefaultAlgExpect; public static void main(String[] args) throws Exception { pkcs8DefaultAlgExpect = args[0]; PEMEncoder encoder = PEMEncoder.of(); PEMDecoder decoder = PEMDecoder.of(); EncryptedPrivateKeyInfo ekpi; KeyPair kp; PEM pem; // These entries are removed var newEntryList = new ArrayList<>(PEMData.entryList); newEntryList.remove(PEMData.getEntry("rsaOpenSSL")); newEntryList.remove(PEMData.getEntry("ecsecp256")); newEntryList.remove(PEMData.getEntry("ecsecp384")); keymap = generateObjKeyMap(newEntryList); System.out.println("Same instance re-encode test:"); keymap.keySet().forEach(key -> test(key, encoder)); System.out.println("New instance re-encode test:"); keymap.keySet().forEach(key -> test(key, PEMEncoder.of())); System.out.println("Same instance re-encode testToString:"); keymap.keySet().forEach(key -> testToString(key, encoder)); System.out.println("Same instance encode/encodeToString consistency test:"); keymap.keySet().forEach(key -> testEncodeConsistency(key, encoder)); System.out.println("New instance re-encode testToString:"); keymap.keySet().forEach(key -> testToString(key, PEMEncoder.of())); System.out.println("New instance encode/encodeToString consistency test:"); keymap.keySet().forEach(key -> testEncodeConsistency(key, PEMEncoder.of())); System.out.println("Same instance Encoder testEncodedKeySpec:"); testEncodedKeySpec(encoder); System.out.println("New instance Encoder testEncodedKeySpec:"); testEncodedKeySpec(PEMEncoder.of()); System.out.println("Same instance Encoder testEmptyKey:"); testEmptyAndNullKey(encoder); keymap = generateObjKeyMap(PEMData.encryptedList); System.out.println("Same instance Encoder match test:"); keymap.keySet().forEach(key -> testEncryptedMatch(key, encoder)); System.out.println("Same instance encrypted encode/encodeToString consistency test:"); keymap.keySet().forEach(key -> testEncodeConsistency(key, encoder)); System.out.println("Same instance Encoder new withEnc test:"); keymap.keySet().forEach(key -> testEncrypted(key, encoder)); System.out.println("New instance Encoder and withEnc test:"); keymap.keySet().forEach(key -> testEncrypted(key, PEMEncoder.of())); System.out.println("Same instance encrypted Encoder test:"); PEMEncoder encEncoder = encoder.withEncryption("fish".toCharArray()); keymap.keySet().forEach(key -> testSameEncryptor(key, encEncoder)); try { encoder.withEncryption(null); } catch (Exception e) { if (!(e instanceof NullPointerException)) { throw new Exception("Should have been a NullPointerException thrown"); } } pem = decoder.decode(PEMData.ed25519ep8.pem(), PEM.class); PEMData.checkResults(PEMData.ed25519ep8, pem.toString()); // test PEM is encapsulated with PEM header and footer on encoding String[] pemLines = PEMData.ed25519ep8.pem().split("\n"); String[] pemNoHeaderFooter = Arrays.copyOfRange(pemLines, 1, pemLines.length - 1); pem = new PEM("ENCRYPTED PRIVATE KEY", String.join("\n", pemNoHeaderFooter)); PEMData.checkResults(PEMData.ed25519ep8.pem(), encoder.encodeToString(pem)); // Verify the same private key bytes are returned with an ECDSA private // key PEM and an encrypted PEM. kp = decoder.decode(PEMData.ecsecp256.pem(), KeyPair.class); var origPriv = kp.getPrivate(); String s = encoder.withEncryption(PEMData.ecsecp256ekpi.password()).encodeToString(kp); kp = decoder.withDecryption(PEMData.ecsecp256ekpi.password()).decode(s, KeyPair.class); var newPriv = kp.getPrivate(); if (!Arrays.equals(origPriv.getEncoded(), newPriv.getEncoded())) { throw new AssertionError("compare fails"); } // Encoded non-encrypted Keypair kp = KeyPairGenerator.getInstance("XDH").generateKeyPair(); s = encoder.encodeToString(kp); decoder.decode(s, KeyPair.class); // EmptyKey for the PrivateKey in a KeyPair. Uses keypair from above. try { encoder.encode(new KeyPair(kp.getPublic(), new EmptyKey())); throw new AssertionError("encoder accepted a empty private key encoding"); } catch (IllegalArgumentException _) {} // NullKey for the PrivateKey in a KeyPair. Uses keypair from above. try { encoder.encode(new KeyPair(kp.getPublic(), new NullKey())); throw new AssertionError("encoder accepted a empty private key encoding"); } catch (IllegalArgumentException _) {} ekpi = decoder.decode(PEMData.ecsecp256ekpi.pem(), EncryptedPrivateKeyInfo.class); try { encoder.withEncryption("blah".toCharArray()).encode(ekpi); throw new AssertionError("encoder tried to encrypt " + "an EncryptedPrivateKeyInfo."); } catch (IllegalArgumentException _) {} // Check PEM string exact String expected = encoder.encodeToString(decoder.decode( PEMData.ecsecp256.pem())); PEMData.Entry e = PEMData.ecsecp256.makeCRLF("ecsecp256CRLF"); System.out.println("Exact PEM String check with CRLF only PEM:"); PEMData.checkResultsExact(expected, encoder.encodeToString( decoder.decode(e.pem()))); System.out.println("Exact PEM String check with CR only PEM:"); e = PEMData.ecsecp256.makeCR("ecsecp256CR"); PEMData.checkResultsExact(expected, encoder.encodeToString( decoder.decode(e.pem()))); System.out.println("Exact PEM String check with NoCRLF only PEM:"); e = PEMData.ecsecp256.makeValidNoCRLF("ecsecp256ValidNoCRLF"); System.out.println(HexFormat.of().formatHex(e.pem().getBytes(StandardCharsets.UTF_8))); System.out.println("EOL: " + HexFormat.of().formatHex(System.lineSeparator().getBytes(StandardCharsets.UTF_8))); PEMData.checkResultsExact(expected, encoder.encodeToString( decoder.decode(e.pem()))); // Independent structural check for the new byte-oriented utility path. System.out.println("Testing consistency between pemEncodedFromArray()" + "and pemEncoded():"); testPemEncodedFromArray(); // Encode an empty PEM content encoder.encode(new PEM("X", "")); } static Map generateObjKeyMap(List<PEMData.Entry> list) { Map<String, BinaryEncodable> keymap = new HashMap<>(); PEMDecoder pemd = PEMDecoder.of(); for (PEMData.Entry entry : list) { try { if (entry.password() != null) { keymap.put(entry.name(), pemd.withDecryption( entry.password()).decode(entry.pem())); } else { keymap.put(entry.name(), pemd.decode(entry.pem(), entry.clazz())); } } catch (Exception e) { System.err.println("Verify PEMDecoderTest passes before " + "debugging this test."); throw new AssertionError("Failed to initialize map on" + " entry \"" + entry.name() + "\"", e); } } return keymap; } static void test(String key, PEMEncoder encoder) { byte[] result; PEMData.Entry entry = PEMData.getEntry(key); try { result = encoder.encode(keymap.get(key)); } catch (RuntimeException e) { throw new AssertionError("Encoder use failure with " + entry.name(), e); } PEMData.checkResults(entry, new String(result, StandardCharsets.UTF_8)); System.out.println("PASS: " + entry.name()); } static void testToString(String key, PEMEncoder encoder) { String result; PEMData.Entry entry = PEMData.getEntry(key); try { result = encoder.encodeToString(keymap.get(key)); } catch (RuntimeException e) { throw new AssertionError("Encoder use failure with " + entry.name(), e); } PEMData.checkResults(entry, result); System.out.println("PASS: " + entry.name()); } static void testEncodeConsistency(String key, PEMEncoder encoder) { byte[] encoding; String pem; PEMData.Entry entry = PEMData.getEntry(key); try { encoding = encoder.encode(keymap.get(key)); pem = encoder.encodeToString(keymap.get(key)); } catch (RuntimeException e) { throw new AssertionError("Encoder consistency failure with " + entry.name(), e); } assertEquals(new String(encoding, StandardCharsets.ISO_8859_1), pem); System.out.println("PASS: " + entry.name()); } static void testPemEncodedFromArray() { byte[] data = {1, 2, 3, 4, 5}; String type = Pem.CERTIFICATE; String base64 = Base64.getMimeEncoder(64, "\r\n".getBytes( StandardCharsets.ISO_8859_1)).encodeToString(data); var expected = ("-----BEGIN " + type + "-----\r\n" + base64 + (!base64.endsWith("\n") ? "\r\n" : "") + "-----END " + type + "-----\r\n"); var result = Pem.pemEncoded(type, base64.getBytes(StandardCharsets.ISO_8859_1)); if (!Arrays.equals(result, expected.getBytes(StandardCharsets.ISO_8859_1))) { throw new AssertionError( "result =\n" + new String(result, StandardCharsets.ISO_8859_1) + "expected =\n " + expected); } // Empty data should still include a CRLF before footer. byte[] empty = new byte[0]; String emptyBase64 = Base64.getMimeEncoder(64, "\r\n".getBytes( StandardCharsets.ISO_8859_1)).encodeToString(empty); String emptyExpected = "-----BEGIN " + type + "-----\r\n" + emptyBase64 + (!emptyBase64.endsWith("\n") ? "\r\n" : "") + "-----END " + type + "-----\r\n"; assertEquals(new String(Pem.pemEncoded(type, empty), StandardCharsets.ISO_8859_1), emptyExpected); System.out.println("PASS"); } /* Test cannot verify PEM was the same as known PEM because we have no public access to the AlgoritmID.params and PBES2Parameters. */ static void testEncrypted(String key, PEMEncoder encoder) { PEMData.Entry entry = PEMData.getEntry(key); try { String pem = encoder.withEncryption( (entry.password() != null ? entry.password() : "fish".toCharArray())) .encodeToString(keymap.get(key)); verifyEncriptionAlg(pem); } catch (RuntimeException e) { throw new AssertionError("Encrypted encoder failed with " + entry.name(), e); } System.out.println("PASS: " + entry.name()); } private static void verifyEncriptionAlg(String pem) { var epki = PEMDecoder.of().decode(pem, EncryptedPrivateKeyInfo.class); assertEquals(epki.getAlgName(), pkcs8DefaultAlgExpect); } /* Test cannot verify PEM was the same as known PEM because we have no public access to the AlgoritmID.params and PBES2Parameters. */ static void testSameEncryptor(String key, PEMEncoder encoder) { PEMData.Entry entry = PEMData.getEntry(key); try { encoder.encodeToString(keymap.get(key)); } catch (RuntimeException e) { throw new AssertionError("Encrypted encoder failed with " + entry.name(), e); } System.out.println("PASS: " + entry.name()); } static void testEncryptedMatch(String key, PEMEncoder encoder) { String result; PEMData.Entry entry = PEMData.getEntry(key); try { PrivateKey pkey = (PrivateKey) keymap.get(key); EncryptedPrivateKeyInfo ekpi = PEMDecoder.of().decode(entry.pem(), EncryptedPrivateKeyInfo.class); if (entry.password() != null) { EncryptedPrivateKeyInfo.encrypt(pkey, entry.password(), Pem.DEFAULT_ALGO, ekpi.getAlgParameters(). getParameterSpec(PBEParameterSpec.class), null); } result = encoder.encodeToString(ekpi); } catch (RuntimeException | InvalidParameterSpecException e) { throw new AssertionError("Encrypted encoder failure with " + entry.name(), e); } PEMData.checkResults(entry, result); System.out.println("PASS: " + entry.name()); } static void testEncodedKeySpec(PEMEncoder encoder) throws NoSuchAlgorithmException { KeyPair kp = getKeyPair(); encoder.encodeToString(new X509EncodedKeySpec(kp.getPublic().getEncoded())); encoder.encodeToString(new PKCS8EncodedKeySpec(kp.getPrivate().getEncoded())); System.out.println("PASS: testEncodedKeySpec"); } private static void testEmptyAndNullKey(PEMEncoder encoder) throws NoSuchAlgorithmException { KeyPair kp = getKeyPair(); assertThrows(IllegalArgumentException.class, () -> encoder.encode( new KeyPair(kp.getPublic(), new EmptyKey()))); assertThrows(IllegalArgumentException.class, () -> encoder.encode( new KeyPair(kp.getPublic(), null))); assertThrows(IllegalArgumentException.class, () -> encoder.encode( new KeyPair(new EmptyKey(), kp.getPrivate()))); assertThrows(IllegalArgumentException.class, () -> encoder.encode( new KeyPair(null, kp.getPrivate()))); System.out.println("PASS: testEmptyKey"); } private static KeyPair getKeyPair() throws NoSuchAlgorithmException { Provider provider = Security.getProvider("SunRsaSign"); KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA", provider); kpg.initialize(SecurityUtils.getTestKeySize("RSA")); return kpg.generateKeyPair(); } private static class EmptyKey implements PublicKey, PrivateKey { @Override public String getAlgorithm() { return "Test"; } @Override public String getFormat() { return "Test"; } @Override public byte[] getEncoded() { return new byte[0]; } } private static class NullKey implements PrivateKey { @Override public String getAlgorithm() { return "Test"; } @Override public String getFormat() { return "Test"; } @Override public byte[] getEncoded() { return null; } } }