diff --git a/src/java.base/macosx/classes/apple/security/KeychainStore.java b/src/java.base/macosx/classes/apple/security/KeychainStore.java index 6f70fccbb24..63dfc39afe1 100644 --- a/src/java.base/macosx/classes/apple/security/KeychainStore.java +++ b/src/java.base/macosx/classes/apple/security/KeychainStore.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 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 @@ -30,6 +30,8 @@ import java.security.*; import java.security.cert.*; import java.security.cert.Certificate; import java.security.spec.*; +import java.time.Instant; +import java.time.temporal.ChronoUnit; import java.util.*; import javax.crypto.*; @@ -114,7 +116,7 @@ abstract sealed class KeychainStore extends KeyStoreSpi { // SecCertificateRef. When we delete the key we have to delete all of the corresponding // native objects. static class KeyEntry { - Date date; // the creation date of this entry + Instant date; // the creation instant of this entry byte[] protectedPrivKey; char[] password; long keyRef; // SecKeyRef for this key @@ -124,7 +126,7 @@ abstract sealed class KeychainStore extends KeyStoreSpi { // Trusted certificates static class TrustedCertEntry { - Date date; // the creation date of this entry + Instant date; // the creation instant of this entry Certificate cert; long certRef; // SecCertificateRef for this key @@ -405,13 +407,32 @@ abstract sealed class KeychainStore extends KeyStoreSpi { * not exist */ public Date engineGetCreationDate(String alias) { - Object entry = entries.get(alias.toLowerCase(Locale.ROOT)); + final Instant instant = this.engineGetCreationInstant(alias); + if (instant == null) { + return null; + } + return Date.from(instant); + } + + /** + * Returns the instant that the entry identified by the given alias was + * created. + * + * @param alias the alias name + * + * @return the instant that the entry identified by the given alias + * was created, or {@code null} if the given alias does not exist + * + * @since 27 + */ + public Instant engineGetCreationInstant(String alias) { + final Object entry = entries.get(alias.toLowerCase(Locale.ROOT)); if (entry != null) { - if (entry instanceof TrustedCertEntry) { - return new Date(((TrustedCertEntry)entry).date.getTime()); + if (entry instanceof TrustedCertEntry trustedCertEntry) { + return trustedCertEntry.date; } else { - return new Date(((KeyEntry)entry).date.getTime()); + return ((KeyEntry)entry).date; } } else { return null; @@ -447,7 +468,7 @@ abstract sealed class KeychainStore extends KeyStoreSpi { synchronized(entries) { try { KeyEntry entry = new KeyEntry(); - entry.date = new Date(); + entry.date = Instant.now().truncatedTo(ChronoUnit.MILLIS); if (key instanceof PrivateKey) { if ((key.getFormat().equals("PKCS#8")) || @@ -525,7 +546,7 @@ abstract sealed class KeychainStore extends KeyStoreSpi { + "EncryptedPrivateKeyInfo"); } - entry.date = new Date(); + entry.date = Instant.now().truncatedTo(ChronoUnit.MILLIS); if ((chain != null) && (chain.length != 0)) { @@ -927,9 +948,9 @@ abstract sealed class KeychainStore extends KeyStoreSpi { // Make a creation date. if (creationDate != 0) - tce.date = new Date(creationDate); + tce.date = Instant.ofEpochMilli(creationDate); else - tce.date = new Date(); + tce.date = Instant.now().truncatedTo(ChronoUnit.MILLIS); entries.put(alias.toLowerCase(Locale.ROOT), tce); } catch (Exception e) { @@ -952,9 +973,9 @@ abstract sealed class KeychainStore extends KeyStoreSpi { // Make a creation date. if (creationDate != 0) - ke.date = new Date(creationDate); + ke.date = Instant.ofEpochMilli(creationDate); else - ke.date = new Date(); + ke.date = Instant.now().truncatedTo(ChronoUnit.MILLIS); // Next, create X.509 Certificate objects from the raw data. This is complicated // because a certificate's public key may be too long for Java's default encryption strength. diff --git a/src/java.base/share/classes/com/sun/crypto/provider/JceKeyStore.java b/src/java.base/share/classes/com/sun/crypto/provider/JceKeyStore.java index ad98653b9c2..1e45a4e6a20 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/JceKeyStore.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/JceKeyStore.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 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 @@ -29,6 +29,8 @@ import sun.security.util.Debug; import sun.security.util.IOUtils; import java.io.*; +import java.time.Instant; +import java.time.temporal.ChronoUnit; import java.util.*; import java.security.DigestInputStream; import java.security.DigestOutputStream; @@ -70,14 +72,14 @@ public final class JceKeyStore extends KeyStoreSpi { // Private key and supporting certificate chain private static final class PrivateKeyEntry { - Date date; // the creation date of this entry + Instant date; // the creation date of this entry byte[] protectedKey; Certificate[] chain; } // Secret key private static final class SecretKeyEntry { - Date date; // the creation date of this entry + Instant date; // the creation date of this entry SealedObject sealedKey; // Maximum possible length of sealedKey. Used to detect malicious @@ -89,7 +91,7 @@ public final class JceKeyStore extends KeyStoreSpi { // Trusted certificate private static final class TrustedCertEntry { - Date date; // the creation date of this entry + Instant date; // the creation date of this entry Certificate cert; } @@ -213,23 +215,38 @@ public final class JceKeyStore extends KeyStoreSpi { * not exist */ public Date engineGetCreationDate(String alias) { - Date date = null; + final Instant instant = this.engineGetCreationInstant(alias); + if (instant == null) { + return null; + } + return Date.from(instant); + } - Object entry = entries.get(alias.toLowerCase(Locale.ENGLISH)); + /** + * Returns the instant that the entry identified by the given alias was + * created. + * + * @param alias the alias name + * + * @return the instant that the entry identified by the given alias + * was created, or {@code null} if the given alias does not exist + * + * @since 27 + */ + public Instant engineGetCreationInstant(String alias) { + final Object entry = entries.get(alias.toLowerCase(Locale.ENGLISH)); if (entry != null) { - // We have to create a new instance of java.util.Date because - // dates are not immutable if (entry instanceof TrustedCertEntry) { - date = new Date(((TrustedCertEntry)entry).date.getTime()); + return ((TrustedCertEntry)entry).date; } else if (entry instanceof PrivateKeyEntry) { - date = new Date(((PrivateKeyEntry)entry).date.getTime()); + return ((PrivateKeyEntry)entry).date; } else { - date = new Date(((SecretKeyEntry)entry).date.getTime()); + return ((SecretKeyEntry)entry).date; } + } else { + return null; } - - return date; } /** @@ -264,7 +281,7 @@ public final class JceKeyStore extends KeyStoreSpi { if (key instanceof PrivateKey) { PrivateKeyEntry entry = new PrivateKeyEntry(); - entry.date = new Date(); + entry.date = Instant.now().truncatedTo(ChronoUnit.MILLIS); // protect the private key entry.protectedKey = keyProtector.protect((PrivateKey)key); @@ -282,7 +299,7 @@ public final class JceKeyStore extends KeyStoreSpi { } else { SecretKeyEntry entry = new SecretKeyEntry(); - entry.date = new Date(); + entry.date = Instant.now().truncatedTo(ChronoUnit.MILLIS); // seal and store the key entry.sealedKey = keyProtector.seal(key); @@ -325,7 +342,7 @@ public final class JceKeyStore extends KeyStoreSpi { // We assume it's a private key, because there is no standard // (ASN.1) encoding format for wrapped secret keys PrivateKeyEntry entry = new PrivateKeyEntry(); - entry.date = new Date(); + entry.date = Instant.now().truncatedTo(ChronoUnit.MILLIS); entry.protectedKey = key.clone(); if ((chain != null) && @@ -370,7 +387,7 @@ public final class JceKeyStore extends KeyStoreSpi { TrustedCertEntry trustedCertEntry = new TrustedCertEntry(); trustedCertEntry.cert = cert; - trustedCertEntry.date = new Date(); + trustedCertEntry.date = Instant.now().truncatedTo(ChronoUnit.MILLIS); entries.put(alias.toLowerCase(Locale.ENGLISH), trustedCertEntry); } } @@ -588,7 +605,7 @@ public final class JceKeyStore extends KeyStoreSpi { dos.writeUTF(alias); // write the (entry creation) date - dos.writeLong(pentry.date.getTime()); + dos.writeLong(pentry.date.toEpochMilli()); // write the protected private key dos.writeInt(pentry.protectedKey.length); @@ -618,7 +635,9 @@ public final class JceKeyStore extends KeyStoreSpi { dos.writeUTF(alias); // write the (entry creation) date - dos.writeLong(((TrustedCertEntry)entry).date.getTime()); + dos.writeLong( + ((TrustedCertEntry)entry).date.toEpochMilli() + ); // write the trusted certificate encoded = ((TrustedCertEntry)entry).cert.getEncoded(); @@ -635,7 +654,9 @@ public final class JceKeyStore extends KeyStoreSpi { dos.writeUTF(alias); // write the (entry creation) date - dos.writeLong(((SecretKeyEntry)entry).date.getTime()); + dos.writeLong( + ((SecretKeyEntry)entry).date.toEpochMilli() + ); // write the sealed key oos = new ObjectOutputStream(dos); @@ -753,7 +774,7 @@ public final class JceKeyStore extends KeyStoreSpi { alias = dis.readUTF(); // read the (entry creation) date - entry.date = new Date(dis.readLong()); + entry.date = Instant.ofEpochMilli(dis.readLong()); // read the private key entry.protectedKey = IOUtils.readExactlyNBytes(dis, dis.readInt()); @@ -798,7 +819,7 @@ public final class JceKeyStore extends KeyStoreSpi { alias = dis.readUTF(); // read the (entry creation) date - entry.date = new Date(dis.readLong()); + entry.date = Instant.ofEpochMilli(dis.readLong()); // read the trusted certificate if (xVersion == 2) { @@ -832,7 +853,7 @@ public final class JceKeyStore extends KeyStoreSpi { alias = dis.readUTF(); // read the (entry creation) date - entry.date = new Date(dis.readLong()); + entry.date = Instant.ofEpochMilli(dis.readLong()); // read the sealed key try { diff --git a/src/java.base/share/classes/java/security/KeyStore.java b/src/java.base/share/classes/java/security/KeyStore.java index 8f3d4ba29fd..83414082cab 100644 --- a/src/java.base/share/classes/java/security/KeyStore.java +++ b/src/java.base/share/classes/java/security/KeyStore.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -30,6 +30,7 @@ import java.security.cert.Certificate; import java.security.cert.X509Certificate; import java.security.cert.CertificateException; import java.security.spec.AlgorithmParameterSpec; +import java.time.Instant; import java.util.*; import javax.crypto.SecretKey; @@ -1182,6 +1183,9 @@ public class KeyStore { /** * Returns the creation date of the entry identified by the given alias. + *
+ * It is recommended to use the {@link #getCreationInstant(String)}
+ * method instead.
*
* @param alias the alias name
*
@@ -1200,6 +1204,32 @@ public class KeyStore {
return keyStoreSpi.engineGetCreationDate(alias);
}
+
+ /**
+ * Returns the instant that the entry identified by the given alias was
+ * created.
+ *
+ * @param alias the alias name
+ *
+ * @return the instant that the entry identified by the given alias
+ * was created, or {@code null} if the given alias does not exist
+ *
+ * @throws KeyStoreException if the keystore has not been initialized
+ * (loaded)
+ *
+ * @since 27
+ */
+ public final Instant getCreationInstant(String alias)
+ throws KeyStoreException
+ {
+ if (!initialized) {
+ throw new KeyStoreException("Uninitialized keystore");
+ }
+ return keyStoreSpi.engineGetCreationInstant(alias);
+ }
+
+
+
/**
* Assigns the given key to the given alias, protecting it with the given
* password.
diff --git a/src/java.base/share/classes/java/security/KeyStoreSpi.java b/src/java.base/share/classes/java/security/KeyStoreSpi.java
index 0b0aa8adf19..5c60f44e4e9 100644
--- a/src/java.base/share/classes/java/security/KeyStoreSpi.java
+++ b/src/java.base/share/classes/java/security/KeyStoreSpi.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 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,6 +26,7 @@
package java.security;
import java.io.*;
+import java.time.Instant;
import java.util.*;
import java.security.KeyStore.*;
@@ -127,6 +128,29 @@ public abstract class KeyStoreSpi {
*/
public abstract Date engineGetCreationDate(String alias);
+ /**
+ * Returns the instant that the entry identified by the given alias was
+ * created.
+ *
+ * @apiNote Subclasses should override this method to directly return an
+ * instant.
+ *
+ * @implSpec
+ * The default implementation calls {@code engineGetCreationDate(alias)}
+ * and returns the output as an {@code Instant} value.
+ *
+ * @param alias the alias name
+ *
+ * @return the instant that the entry identified by the given alias
+ * was created, or {@code null} if the given alias does not exist
+ *
+ * @since 27
+ */
+ public Instant engineGetCreationInstant(String alias) {
+ final Date date = engineGetCreationDate(alias);
+ return date == null ? null : date.toInstant();
+ }
+
/**
* Assigns the given key to the given alias, protecting it with the given
* password.
diff --git a/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java b/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java
index f85ba0f9c4b..33e8406a7f6 100644
--- a/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java
+++ b/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 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
@@ -35,6 +35,8 @@ import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.InvalidParameterSpecException;
import java.security.spec.KeySpec;
import java.security.spec.PKCS8EncodedKeySpec;
+import java.time.Instant;
+import java.time.temporal.ChronoUnit;
import java.util.*;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
@@ -179,7 +181,7 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
// A keystore entry and associated attributes
private static class Entry {
- Date date; // the creation date of this entry
+ Instant date; // the creation date of this entry
String alias;
byte[] keyId;
Set