diff --git a/src/java.base/share/classes/java/security/PEMDecoder.java b/src/java.base/share/classes/java/security/PEMDecoder.java index eeb6decdf40..7279e75cc98 100644 --- a/src/java.base/share/classes/java/security/PEMDecoder.java +++ b/src/java.base/share/classes/java/security/PEMDecoder.java @@ -81,24 +81,24 @@ import java.util.Objects; * {@link PEMRecord}. * *
The {@linkplain #decode(String, Class)} and - * {@linkplain #decode(InputStream, Class)} methods take a Class parameter + * {@linkplain #decode(InputStream, Class)} methods take a class parameter * which determines the type of {@code DEREncodable} that is returned. These * methods are useful when extracting or changing the return class. * For example, if the PEM contains both public and private keys, the - * Class parameter can specify which to return. Use + * class parameter can specify which to return. Use * {@code PrivateKey.class} to return only the private key. - * If the Class parameter is set to {@code X509EncodedKeySpec.class}, the + * If the class parameter is set to {@code X509EncodedKeySpec.class}, the * public key will be returned in that format. Any type of PEM data can be * decoded into a {@code PEMRecord} by specifying {@code PEMRecord.class}. - * If the Class parameter doesn't match the PEM content, an - * {@code IllegalArgumentException} will be thrown. + * If the class parameter doesn't match the PEM content, a + * {@linkplain ClassCastException} will be thrown. * *
A new {@code PEMDecoder} instance is created when configured * with {@linkplain #withFactory(Provider)} and/or * {@linkplain #withDecryption(char[])}. {@linkplain #withFactory(Provider)} * configures the decoder to use only {@linkplain KeyFactory} and * {@linkplain CertificateFactory} instances from the given {@code Provider}. - * {@link#withDecryption(char[])} configures the decoder to decrypt all + * {@linkplain #withDecryption(char[])} configures the decoder to decrypt all * encrypted private key PEM data using the given password. * Configuring an instance for decryption does not prevent decoding with * unencrypted PEM. Any encrypted PEM that fails decryption @@ -117,15 +117,15 @@ import java.util.Objects; *
Here is an example of a {@code PEMDecoder} configured with decryption * and a factory provider: * {@snippet lang = java: - * PEMDecoder pe = PEMDecoder.of().withDecryption(password). + * PEMDecoder pd = PEMDecoder.of().withDecryption(password). * withFactory(provider); - * byte[] pemData = pe.decode(privKey); + * byte[] pemData = pd.decode(privKey); * } * * @implNote An implementation may support other PEM types and - * {@code DEREncodables}. This implementation additionally supports PEM types: - * {@code X509 CERTIFICATE}, {@code X.509 CERTIFICATE}, {@code CRL}, - * and {@code RSA PRIVATE KEY}. + * {@code DEREncodable} objects. This implementation additionally supports + * the following PEM types: {@code X509 CERTIFICATE}, + * {@code X.509 CERTIFICATE}, {@code CRL}, and {@code RSA PRIVATE KEY}. * * @see PEMEncoder * @see PEMRecord @@ -179,13 +179,13 @@ public final class PEMDecoder { return switch (pem.type()) { case Pem.PUBLIC_KEY -> { X509EncodedKeySpec spec = - new X509EncodedKeySpec(decoder.decode(pem.pem())); + new X509EncodedKeySpec(decoder.decode(pem.content())); yield getKeyFactory( KeyUtil.getAlgorithm(spec.getEncoded())). generatePublic(spec); } case Pem.PRIVATE_KEY -> { - PKCS8Key p8key = new PKCS8Key(decoder.decode(pem.pem())); + PKCS8Key p8key = new PKCS8Key(decoder.decode(pem.content())); String algo = p8key.getAlgorithm(); KeyFactory kf = getKeyFactory(algo); DEREncodable d = kf.generatePrivate( @@ -216,27 +216,27 @@ public final class PEMDecoder { case Pem.ENCRYPTED_PRIVATE_KEY -> { if (password == null) { yield new EncryptedPrivateKeyInfo(decoder.decode( - pem.pem())); + pem.content())); } - yield new EncryptedPrivateKeyInfo(decoder.decode(pem.pem())). + yield new EncryptedPrivateKeyInfo(decoder.decode(pem.content())). getKey(password.getPassword()); } case Pem.CERTIFICATE, Pem.X509_CERTIFICATE, Pem.X_509_CERTIFICATE -> { CertificateFactory cf = getCertFactory("X509"); yield (X509Certificate) cf.generateCertificate( - new ByteArrayInputStream(decoder.decode(pem.pem()))); + new ByteArrayInputStream(decoder.decode(pem.content()))); } case Pem.X509_CRL, Pem.CRL -> { CertificateFactory cf = getCertFactory("X509"); yield (X509CRL) cf.generateCRL( - new ByteArrayInputStream(decoder.decode(pem.pem()))); + new ByteArrayInputStream(decoder.decode(pem.content()))); } case Pem.RSA_PRIVATE_KEY -> { KeyFactory kf = getKeyFactory("RSA"); yield kf.generatePrivate( RSAPrivateCrtKeyImpl.getKeySpec(decoder.decode( - pem.pem()))); + pem.content()))); } default -> pem; }; @@ -271,7 +271,6 @@ public final class PEMDecoder { */ public DEREncodable decode(String str) { Objects.requireNonNull(str); - DEREncodable de; try { return decode(new ByteArrayInputStream( str.getBytes(StandardCharsets.UTF_8))); @@ -483,9 +482,6 @@ public final class PEMDecoder { * from the specified {@link Provider} to produce cryptographic objects. * Any errors using the {@code Provider} will occur during decoding. * - *
If {@code provider} is {@code null}, a new instance is returned with - * the default provider configuration. - * * @param provider the factory provider * @return a new PEMEncoder instance configured to the {@code Provider}. * @throws NullPointerException if {@code provider} is null diff --git a/src/java.base/share/classes/java/security/PEMEncoder.java b/src/java.base/share/classes/java/security/PEMEncoder.java index d5465083330..95fcffe967b 100644 --- a/src/java.base/share/classes/java/security/PEMEncoder.java +++ b/src/java.base/share/classes/java/security/PEMEncoder.java @@ -71,7 +71,7 @@ import java.util.concurrent.locks.ReentrantLock; * OneAsymmetricKey structure using the "PRIVATE KEY" type. * *
When encoding a {@link PEMRecord}, the API surrounds the - * {@linkplain PEMRecord#pem()} with the PEM header and footer + * {@linkplain PEMRecord#content()} with the PEM header and footer * from {@linkplain PEMRecord#type()}. {@linkplain PEMRecord#leadingData()} is * not included in the encoding. {@code PEMRecord} will not perform * validity checks on the data. @@ -108,7 +108,8 @@ import java.util.concurrent.locks.ReentrantLock; * byte[] pemData = pe.encode(privKey); * } * - * @implNote An implementation may support other PEM types and DEREncodables. + * @implNote An implementation may support other PEM types and + * {@code DEREncodable} objects. * * * @see PEMDecoder @@ -287,7 +288,7 @@ public final class PEMEncoder { } // If `keySpec` is non-null, then `key` hasn't been established. - // Setting a `key' prevents repeated key generations operations. + // Setting a `key` prevents repeated key generation operations. // withEncryption() is a configuration method and cannot throw an // exception; therefore generation is delayed. if (keySpec != null) { diff --git a/src/java.base/share/classes/java/security/PEMRecord.java b/src/java.base/share/classes/java/security/PEMRecord.java index dfe951a0963..2ce567f9fde 100644 --- a/src/java.base/share/classes/java/security/PEMRecord.java +++ b/src/java.base/share/classes/java/security/PEMRecord.java @@ -29,7 +29,6 @@ import jdk.internal.javac.PreviewFeature; import sun.security.util.Pem; -import java.util.Base64; import java.util.Objects; /** @@ -39,20 +38,20 @@ import java.util.Objects; * cryptographic object is not desired or the type has no * {@code DEREncodable}. * - *
{@code type} and {@code pem} may not be {@code null}. + *
{@code type} and {@code content} may not be {@code null}. * {@code leadingData} may be null if no non-PEM data preceded PEM header * during decoding. {@code leadingData} may be useful for reading metadata * that accompanies PEM data. * *
No validation is performed during instantiation to ensure that - * {@code type} conforms to {@code RFC 7468}, that {@code pem} is valid Base64, - * or that {@code pem} matches the {@code type}. {@code leadingData} is not - * defensively copied and does not return a clone when - * {@linkplain #leadingData()} is called. + * {@code type} conforms to {@code RFC 7468}, that {@code content} is valid + * Base64, or that {@code content} matches the {@code type}. + * {@code leadingData} is not defensively copied and does not return a + * clone when {@linkplain #leadingData()} is called. * * @param type the type identifier in the PEM header without PEM syntax labels. * For a public key, {@code type} would be "PUBLIC KEY". - * @param pem any data between the PEM header and footer. + * @param content the Base64-encoded data, excluding the PEM header and footer * @param leadingData any non-PEM data preceding the PEM header when decoding. * * @spec https://www.rfc-editor.org/info/rfc7468 @@ -64,25 +63,25 @@ import java.util.Objects; * @since 25 */ @PreviewFeature(feature = PreviewFeature.Feature.PEM_API) -public record PEMRecord(String type, String pem, byte[] leadingData) +public record PEMRecord(String type, String content, byte[] leadingData) implements DEREncodable { /** * Creates a {@code PEMRecord} instance with the given parameters. * * @param type the type identifier - * @param pem the Base64-encoded data encapsulated by the PEM header and - * footer. + * @param content the Base64-encoded data, excluding the PEM header and + * footer * @param leadingData any non-PEM data read during the decoding process * before the PEM header. This value maybe {@code null}. - * @throws IllegalArgumentException if the {@code type} is incorrectly + * @throws IllegalArgumentException if {@code type} is incorrectly * formatted. - * @throws NullPointerException if {@code type} and/or {@code pem} are + * @throws NullPointerException if {@code type} and/or {@code content} are * {@code null}. */ - public PEMRecord(String type, String pem, byte[] leadingData) { + public PEMRecord { Objects.requireNonNull(type, "\"type\" cannot be null."); - Objects.requireNonNull(pem, "\"pem\" cannot be null."); + Objects.requireNonNull(content, "\"content\" cannot be null."); // With no validity checking on `type`, the constructor accept anything // including lowercase. The onus is on the caller. @@ -92,37 +91,22 @@ public record PEMRecord(String type, String pem, byte[] leadingData) "Only the PEM type identifier is allowed"); } - this.type = type; - this.pem = pem; - this.leadingData = leadingData; } /** * Creates a {@code PEMRecord} instance with a given {@code type} and - * {@code pem} data in String form. {@code leadingData} is set to null. + * {@code content} data in String form. {@code leadingData} is set to null. * * @param type the PEM type identifier - * @param pem the Base64-encoded data encapsulated by the PEM header and - * footer. - * @throws IllegalArgumentException if the {@code type} is incorrectly + * @param content the Base64-encoded data, excluding the PEM header and + * footer + * @throws IllegalArgumentException if {@code type} is incorrectly * formatted. - * @throws NullPointerException if {@code type} and/or {@code pem} are + * @throws NullPointerException if {@code type} and/or {@code content} are * {@code null}. */ - public PEMRecord(String type, String pem) { - this(type, pem, null); - } - - /** - * Returns the binary encoding from the Base64 data contained in - * {@code pem}. - * - * @throws IllegalArgumentException if {@code pem} cannot be decoded. - * @return a new array of the binary encoding each time this - * method is called. - */ - public byte[] getEncoded() { - return Base64.getMimeDecoder().decode(pem); + public PEMRecord(String type, String content) { + this(type, content, null); } /** 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 ec7a1ac998a..1a8ace55fc8 100644 --- a/src/java.base/share/classes/sun/security/provider/X509Factory.java +++ b/src/java.base/share/classes/sun/security/provider/X509Factory.java @@ -565,7 +565,7 @@ public class X509Factory extends CertificateFactorySpi { } catch (EOFException e) { return null; } - return Base64.getDecoder().decode(rec.pem()); + return Base64.getDecoder().decode(rec.content()); } catch (IllegalArgumentException e) { throw new IOException(e); } diff --git a/src/java.base/share/classes/sun/security/util/Pem.java b/src/java.base/share/classes/sun/security/util/Pem.java index c6e56381771..492017eca29 100644 --- a/src/java.base/share/classes/sun/security/util/Pem.java +++ b/src/java.base/share/classes/sun/security/util/Pem.java @@ -343,7 +343,7 @@ public class Pem { * @return PEM in a string */ public static String pemEncoded(PEMRecord pem) { - String p = pem.pem().replaceAll("(.{64})", "$1\r\n"); + String p = pem.content().replaceAll("(.{64})", "$1\r\n"); return pemEncoded(pem.type(), p); } } diff --git a/test/jdk/java/security/PEM/PEMDecoderTest.java b/test/jdk/java/security/PEM/PEMDecoderTest.java index 6486bfc83c7..2ee9d1a69b3 100644 --- a/test/jdk/java/security/PEM/PEMDecoderTest.java +++ b/test/jdk/java/security/PEM/PEMDecoderTest.java @@ -107,8 +107,8 @@ public class PEMDecoderTest { System.err.println("received: " + new String(rec.leadingData())); throw new AssertionError("ecCSRWithData preData wrong"); } - if (rec.pem().lastIndexOf("F") > rec.pem().length() - 5) { - System.err.println("received: " + rec.pem()); + if (rec.content().lastIndexOf("F") > rec.content().length() - 5) { + System.err.println("received: " + rec.content()); throw new AssertionError("ecCSRWithData: " + "End of PEM data has an unexpected character"); } @@ -235,10 +235,10 @@ public class PEMDecoderTest { PEMRecord r = PEMDecoder.of().decode(entry.pem(), PEMRecord.class); String expected = entry.pem().split("-----")[2].replace(System.lineSeparator(), ""); try { - PEMData.checkResults(expected, r.pem()); + PEMData.checkResults(expected, r.content()); } catch (AssertionError e) { System.err.println("expected:\n" + expected); - System.err.println("received:\n" + r.pem()); + System.err.println("received:\n" + r.content()); throw e; }