8374808: Add new methods to KeyStore and KeyStoreSpi that return the creation date as an Instant instead of Date

Reviewed-by: weijun
This commit is contained in:
Mikhail Yankelevich 2026-02-10 12:18:03 +00:00
parent bfb6de5b2b
commit 264fdc5b4e
9 changed files with 291 additions and 89 deletions

View File

@ -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.

View File

@ -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 {

View File

@ -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.
* <p>
* 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.

View File

@ -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.

View File

@ -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<KeyStore.Entry.Attribute> attributes;
@ -212,7 +214,7 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
CertEntry(X509Certificate cert, byte[] keyId, String alias,
ObjectIdentifier[] trustedKeyUsage,
Set<? extends KeyStore.Entry.Attribute> attributes) {
this.date = new Date();
this.date = Instant.now().truncatedTo(ChronoUnit.MILLIS);
this.cert = cert;
this.keyId = keyId;
this.alias = alias;
@ -541,9 +543,28 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
* not exist
*/
public Date engineGetCreationDate(String alias) {
Entry entry = entries.get(alias.toLowerCase(Locale.ENGLISH));
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 Entry entry = entries.get(alias.toLowerCase(Locale.ENGLISH));
if (entry != null) {
return new Date(entry.date.getTime());
return entry.date;
} else {
return null;
}
@ -606,7 +627,7 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
checkX509Certs(chain);
PrivateKeyEntry keyEntry = new PrivateKeyEntry();
keyEntry.date = new Date();
keyEntry.date = Instant.now().truncatedTo(ChronoUnit.MILLIS);
if ((key.getFormat().equals("PKCS#8")) ||
(key.getFormat().equals("PKCS8"))) {
@ -651,7 +672,7 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
} else if (key instanceof SecretKey) {
SecretKeyEntry keyEntry = new SecretKeyEntry();
keyEntry.date = new Date();
keyEntry.date = Instant.now().truncatedTo(ChronoUnit.MILLIS);
// Encode secret key in a PKCS#8
DerOutputStream secretKeyInfo = new DerOutputStream();
@ -690,7 +711,7 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
entry.attributes.addAll(attributes);
}
// set the keyId to current date
entry.keyId = ("Time " + (entry.date).getTime()).getBytes(UTF_8);
entry.keyId = ("Time " + entry.date.toEpochMilli()).getBytes(UTF_8);
// set the alias
entry.alias = alias.toLowerCase(Locale.ENGLISH);
// add the entry
@ -745,7 +766,7 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
}
PrivateKeyEntry entry = new PrivateKeyEntry();
entry.date = new Date();
entry.date = Instant.now().truncatedTo(ChronoUnit.MILLIS);
if (debug != null) {
debug.println("Setting a protected private key at alias '" +
@ -753,7 +774,7 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
}
// set the keyId to current date
entry.keyId = ("Time " + (entry.date).getTime()).getBytes(UTF_8);
entry.keyId = ("Time " + entry.date.toEpochMilli()).getBytes(UTF_8);
// set the alias
entry.alias = alias.toLowerCase(Locale.ENGLISH);
@ -2411,21 +2432,22 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
}
}
entry.keyId = keyId;
// restore date if it exists
// restore instant if it exists
String keyIdStr = new String(keyId, UTF_8);
Date date = null;
Instant instant = null;
if (keyIdStr.startsWith("Time ")) {
try {
date = new Date(
Long.parseLong(keyIdStr.substring(5)));
instant = Instant.ofEpochMilli(
Long.parseLong(keyIdStr.substring(5))
);
} catch (Exception e) {
// date has been initialized to null
// instant has been initialized to null
}
}
if (date == null) {
date = new Date();
if (instant == null) {
instant = Instant.now().truncatedTo(ChronoUnit.MILLIS);
}
entry.date = date;
entry.date = instant;
if (bagItem instanceof PrivateKeyEntry) {
keyList.add(entry);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2013, 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.net.*;
import java.security.*;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.time.Instant;
import java.util.*;
import static java.nio.charset.StandardCharsets.UTF_8;
@ -214,16 +215,32 @@ abstract class DomainKeyStore extends KeyStoreSpi {
* not exist
*/
public Date engineGetCreationDate(String alias) {
final Instant instant = this.engineGetCreationInstant(alias);
return (instant == null) ? null : 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) {
AbstractMap.SimpleEntry<String, Collection<KeyStore>> pair =
getKeystoresForReading(alias);
Date date = null;
Instant instant = null;
try {
String entryAlias = pair.getKey();
for (KeyStore keystore : pair.getValue()) {
date = keystore.getCreationDate(entryAlias);
if (date != null) {
instant = keystore.getCreationInstant(entryAlias);
if (instant != null) {
break;
}
}
@ -231,7 +248,7 @@ abstract class DomainKeyStore extends KeyStoreSpi {
throw new IllegalStateException(e);
}
return date;
return instant;
}
@Override

View File

@ -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,8 @@ import java.security.*;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.cert.CertificateException;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.*;
import static java.nio.charset.StandardCharsets.UTF_8;
@ -100,14 +102,14 @@ public abstract sealed class JavaKeyStore extends KeyStoreSpi {
// Private keys and their supporting certificate chains
private static class KeyEntry {
Date date; // the creation date of this entry
Instant date; // the creation date of this entry
byte[] protectedPrivKey;
Certificate[] chain;
}
// Trusted certificates
private static class TrustedCertEntry {
Date date; // the creation date of this entry
Instant date; // the creation date of this entry
Certificate cert;
}
@ -236,13 +238,31 @@ public abstract sealed class JavaKeyStore extends KeyStoreSpi {
* not exist
*/
public Date engineGetCreationDate(String alias) {
Object entry = entries.get(convertAlias(alias));
final Instant instant = this.engineGetCreationInstant(alias);
return instant == null ? null : 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(convertAlias(alias));
if (entry != null) {
if (entry instanceof TrustedCertEntry) {
return new Date(((TrustedCertEntry)entry).date.getTime());
return ((TrustedCertEntry)entry).date;
} else {
return new Date(((KeyEntry)entry).date.getTime());
return((KeyEntry)entry).date;
}
} else {
return null;
@ -287,7 +307,7 @@ public abstract sealed class JavaKeyStore extends KeyStoreSpi {
try {
synchronized(entries) {
KeyEntry entry = new KeyEntry();
entry.date = new Date();
entry.date = Instant.now().truncatedTo(ChronoUnit.MILLIS);
// Protect the encoding of the key
passwordBytes = convertToBytes(password);
@ -350,7 +370,7 @@ public abstract sealed class JavaKeyStore extends KeyStoreSpi {
}
KeyEntry entry = new KeyEntry();
entry.date = new Date();
entry.date = Instant.now().truncatedTo(ChronoUnit.MILLIS);
entry.protectedPrivKey = key.clone();
if ((chain != null) &&
@ -391,7 +411,7 @@ public abstract sealed class JavaKeyStore extends KeyStoreSpi {
TrustedCertEntry trustedCertEntry = new TrustedCertEntry();
trustedCertEntry.cert = cert;
trustedCertEntry.date = new Date();
trustedCertEntry.date = Instant.now().truncatedTo(ChronoUnit.MILLIS);
entries.put(convertAlias(alias), trustedCertEntry);
}
}
@ -579,7 +599,7 @@ public abstract sealed class JavaKeyStore extends KeyStoreSpi {
dos.writeUTF(alias);
// Write the (entry creation) date
dos.writeLong(((KeyEntry)entry).date.getTime());
dos.writeLong(((KeyEntry)entry).date.toEpochMilli());
// Write the protected private key
dos.writeInt(((KeyEntry)entry).protectedPrivKey.length);
@ -608,7 +628,9 @@ public abstract sealed class JavaKeyStore 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();
@ -707,7 +729,7 @@ public abstract sealed class JavaKeyStore 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.protectedPrivKey =
@ -756,7 +778,7 @@ public abstract sealed class JavaKeyStore 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) {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2001, 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,13 +24,18 @@
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.security.*;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.PEMDecoder;
import java.security.PrivateKey;
import java.security.UnrecoverableKeyException;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.time.Instant;
/*
* @test
* @bug 8048621 8133090 8167371 8236671
* @bug 8048621 8133090 8167371 8236671 8374808
* @enablePreview
* @summary Test basic operations with keystores (jks, jceks, pkcs12)
* @author Yu-Ching Valerie PENG
@ -177,6 +182,8 @@ public class TestKeyStoreBasic {
// compare the creation date of the 2 key stores for all aliases
compareCreationDate(ks, ks2, numEntries);
compareCreationInstant(ks, ks2, numEntries);
// remove the last entry from the 2nd key store
numEntries--;
ks2.deleteEntry(ALIAS_HEAD + numEntries);
@ -213,6 +220,7 @@ public class TestKeyStoreBasic {
// compare the creation date of the 2 key stores for all aliases
compareCreationDate(ks, ks2, numEntries);
compareCreationInstant(ks, ks2, numEntries);
// check setEntry/getEntry with a password protection algorithm
if ("PKCS12".equalsIgnoreCase(ks.getType())) {
@ -284,6 +292,23 @@ public class TestKeyStoreBasic {
}
}
// compare the creation instants - true if all the same
private void compareCreationInstant(KeyStore o1, KeyStore o2, int range)
throws KeyStoreException {
String alias;
for (int k = 0; k < range; k++) {
alias = ALIAS_HEAD + k;
final Instant instant1 = o1.getCreationInstant(alias);
final Instant instant2 = o2.getCreationInstant(alias);
if (!(instant1.equals(instant2))) {
throw new RuntimeException("ERROR: entry creation time (" + k
+ ") differs Instants {"
+ instant1 + " - "
+ instant2 + "}");
}
}
}
// checks if an exception was caused by specified exception class
private static boolean causedBy(Exception e, Class klass) {
Throwable cause = e;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2013, 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
@ -23,19 +23,30 @@
/*
* @test
* @bug 8007755
* @bug 8007755 8374808
* @library /test/lib
* @summary Support the logical grouping of keystores
*/
import java.io.*;
import java.net.*;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URI;
import java.nio.file.Paths;
import java.security.*;
import java.security.DomainLoadStoreParameter;
import java.security.KeyStore;
import java.security.cert.*;
import java.security.UnrecoverableKeyException;
import java.security.cert.Certificate;
import java.util.*;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import jdk.test.lib.process.ProcessTools;
import jdk.test.lib.process.OutputAnalyzer;
@ -205,17 +216,26 @@ public class DKSTest {
new KeyStore.TrustedCertificateEntry(cert), null);
}
private static void checkEntries(KeyStore keystore, int expected)
private static void checkEntries(KeyStore keystore, int expectedCount)
throws Exception {
int i = 0;
int currCount = 0;
for (String alias : Collections.list(keystore.aliases())) {
System.out.print(".");
i++;
currCount++;
// check creation date and instant
if(!keystore.getCreationDate(alias).equals(
Date.from(keystore.getCreationInstant(alias)))
){
throw new RuntimeException(
"Creation Date is not the same as Instant timestamp");
}
}
System.out.println();
if (expected != i) {
// Check if current count is expected
if (expectedCount != currCount) {
throw new Exception("Error: unexpected entry count in keystore: " +
"loaded=" + i + ", expected=" + expected);
"loaded=" + currCount + ", expected=" + expectedCount);
}
}