diff --git a/src/java.base/share/classes/com/sun/crypto/provider/DHPrivateKey.java b/src/java.base/share/classes/com/sun/crypto/provider/DHPrivateKey.java
index 0d5363e866a..fcdc3fbea49 100644
--- a/src/java.base/share/classes/com/sun/crypto/provider/DHPrivateKey.java
+++ b/src/java.base/share/classes/com/sun/crypto/provider/DHPrivateKey.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2024, 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
@@ -56,6 +56,7 @@ final class DHPrivateKey implements PrivateKey,
private final BigInteger x;
// the key bytes, without the algorithm information
+ // cannot be final as it's re-assigned for deserialization
private byte[] key;
// the encoded key
@@ -70,6 +71,131 @@ final class DHPrivateKey implements PrivateKey,
// the private-value length (optional)
private final int l;
+ private static class DHComponents {
+ final BigInteger x;
+ final BigInteger p;
+ final BigInteger g;
+ final int l;
+ final byte[] key;
+
+ DHComponents(BigInteger x, BigInteger p, BigInteger g, int l,
+ byte[] key) {
+ this.x = x;
+ this.p = p;
+ this.g = g;
+ this.l = l;
+ this.key = key;
+ }
+ }
+
+ // parses the specified encoding into a DHComponents object
+ private static DHComponents decode(byte[] encodedKey)
+ throws IOException {
+ DerValue val = null;
+
+ try {
+ val = new DerValue(encodedKey);
+ if (val.tag != DerValue.tag_Sequence) {
+ throw new IOException("Key not a SEQUENCE");
+ }
+
+ // version
+ BigInteger parsedVersion = val.data.getBigInteger();
+ if (!parsedVersion.equals(PKCS8_VERSION)) {
+ throw new IOException("version mismatch: (supported: " +
+ PKCS8_VERSION + ", parsed: " + parsedVersion);
+ }
+
+ // privateKeyAlgorithm
+ DerValue algid = val.data.getDerValue();
+ if (algid.tag != DerValue.tag_Sequence) {
+ throw new IOException("AlgId is not a SEQUENCE");
+ }
+ DerInputStream derInStream = algid.toDerInputStream();
+ ObjectIdentifier oid = derInStream.getOID();
+ if (oid == null) {
+ throw new IOException("Null OID");
+ }
+ if (derInStream.available() == 0) {
+ throw new IOException("Parameters missing");
+ }
+ // parse the parameters
+ DerValue params = derInStream.getDerValue();
+ if (params.tag == DerValue.tag_Null) {
+ throw new IOException("Null parameters");
+ }
+ if (params.tag != DerValue.tag_Sequence) {
+ throw new IOException("Parameters not a SEQUENCE");
+ }
+ params.data.reset();
+ BigInteger p = params.data.getBigInteger();
+ BigInteger g = params.data.getBigInteger();
+ // Private-value length is OPTIONAL
+ int l = (params.data.available() != 0 ?
+ params.data.getInteger() : 0);
+ // should have no trailing data
+ if (params.data.available() != 0) {
+ throw new IOException("Extra parameter data");
+ }
+
+ // privateKey
+ byte[] key = val.data.getOctetString();
+ DerInputStream in = new DerInputStream(key);
+ BigInteger x = in.getBigInteger();
+
+ // should have no trailing data
+ if (val.data.available() != 0) {
+ throw new IOException("Excess trailing data");
+ }
+ return new DHComponents(x, p, g, l, key);
+ } catch (NumberFormatException e) {
+ throw new IOException("Error parsing key encoding", e);
+ } finally {
+ if (val != null) {
+ val.clear();
+ }
+ }
+ }
+
+ // Generates the ASN.1 encoding
+ private static byte[] encode(BigInteger p, BigInteger g, int l,
+ byte[] key) {
+ DerOutputStream tmp = new DerOutputStream();
+
+ // version
+ tmp.putInteger(PKCS8_VERSION);
+
+ // privateKeyAlgorithm
+ DerOutputStream algid = new DerOutputStream();
+
+ // store OID
+ algid.putOID(DHPublicKey.DH_OID);
+ // encode parameters
+ DerOutputStream params = new DerOutputStream();
+ params.putInteger(p);
+ params.putInteger(g);
+ if (l != 0) {
+ params.putInteger(l);
+ }
+ // wrap parameters into SEQUENCE
+ DerValue paramSequence = new DerValue(DerValue.tag_Sequence,
+ params.toByteArray());
+ // store parameter SEQUENCE in algid
+ algid.putDerValue(paramSequence);
+ // wrap algid into SEQUENCE
+ tmp.write(DerValue.tag_Sequence, algid);
+
+ // privateKey
+ tmp.putOctetString(key);
+
+ // make it a SEQUENCE
+ DerValue val = DerValue.wrap(DerValue.tag_Sequence, tmp);
+ byte[] encoded = val.toByteArray();
+ val.clear();
+
+ return encoded;
+ }
+
/**
* Make a DH private key out of a private value x
, a prime
* modulus p
, and a base generator g
.
@@ -79,7 +205,7 @@ final class DHPrivateKey implements PrivateKey,
* @param g the base generator
*/
DHPrivateKey(BigInteger x, BigInteger p, BigInteger g)
- throws InvalidKeyException {
+ throws InvalidKeyException {
this(x, p, g, 0);
}
@@ -98,12 +224,16 @@ final class DHPrivateKey implements PrivateKey,
this.p = p;
this.g = g;
this.l = l;
+
byte[] xbytes = x.toByteArray();
DerValue val = new DerValue(DerValue.tag_Integer, xbytes);
- this.key = val.toByteArray();
- val.clear();
- Arrays.fill(xbytes, (byte) 0);
- encode();
+ try {
+ this.key = val.toByteArray();
+ } finally {
+ val.clear();
+ Arrays.fill(xbytes, (byte) 0);
+ }
+ this.encodedKey = encode(p, g, l, key);
}
/**
@@ -115,75 +245,18 @@ final class DHPrivateKey implements PrivateKey,
* a Diffie-Hellman private key
*/
DHPrivateKey(byte[] encodedKey) throws InvalidKeyException {
- DerValue val = null;
+ this.encodedKey = encodedKey.clone();
+ DHComponents dc;
try {
- val = new DerValue(encodedKey);
- if (val.tag != DerValue.tag_Sequence) {
- throw new InvalidKeyException ("Key not a SEQUENCE");
- }
-
- //
- // version
- //
- BigInteger parsedVersion = val.data.getBigInteger();
- if (!parsedVersion.equals(PKCS8_VERSION)) {
- throw new IOException("version mismatch: (supported: " +
- PKCS8_VERSION + ", parsed: " +
- parsedVersion);
- }
-
- //
- // privateKeyAlgorithm
- //
- DerValue algid = val.data.getDerValue();
- if (algid.tag != DerValue.tag_Sequence) {
- throw new InvalidKeyException("AlgId is not a SEQUENCE");
- }
- DerInputStream derInStream = algid.toDerInputStream();
- ObjectIdentifier oid = derInStream.getOID();
- if (oid == null) {
- throw new InvalidKeyException("Null OID");
- }
- if (derInStream.available() == 0) {
- throw new InvalidKeyException("Parameters missing");
- }
- // parse the parameters
- DerValue params = derInStream.getDerValue();
- if (params.tag == DerValue.tag_Null) {
- throw new InvalidKeyException("Null parameters");
- }
- if (params.tag != DerValue.tag_Sequence) {
- throw new InvalidKeyException("Parameters not a SEQUENCE");
- }
- params.data.reset();
- this.p = params.data.getBigInteger();
- this.g = params.data.getBigInteger();
- // Private-value length is OPTIONAL
- if (params.data.available() != 0) {
- this.l = params.data.getInteger();
- } else {
- this.l = 0;
- }
- if (params.data.available() != 0) {
- throw new InvalidKeyException("Extra parameter data");
- }
-
- //
- // privateKey
- //
- this.key = val.data.getOctetString();
-
- DerInputStream in = new DerInputStream(this.key);
- this.x = in.getBigInteger();
-
- this.encodedKey = encodedKey.clone();
- } catch (IOException | NumberFormatException e) {
- throw new InvalidKeyException("Error parsing key encoding", e);
- } finally {
- if (val != null) {
- val.clear();
- }
+ dc = decode(this.encodedKey);
+ } catch (IOException e) {
+ throw new InvalidKeyException("Invalid encoding", e);
}
+ this.x = dc.x;
+ this.p = dc.p;
+ this.g = dc.g;
+ this.l = dc.l;
+ this.key = dc.key;
}
/**
@@ -204,55 +277,9 @@ final class DHPrivateKey implements PrivateKey,
* Get the encoding of the key.
*/
public synchronized byte[] getEncoded() {
- encode();
return encodedKey.clone();
}
- /**
- * Generate the encodedKey field if it has not been calculated.
- * Could generate null.
- */
- private void encode() {
- if (this.encodedKey == null) {
- DerOutputStream tmp = new DerOutputStream();
-
- //
- // version
- //
- tmp.putInteger(PKCS8_VERSION);
-
- //
- // privateKeyAlgorithm
- //
- DerOutputStream algid = new DerOutputStream();
-
- // store OID
- algid.putOID(DHPublicKey.DH_OID);
- // encode parameters
- DerOutputStream params = new DerOutputStream();
- params.putInteger(this.p);
- params.putInteger(this.g);
- if (this.l != 0) {
- params.putInteger(this.l);
- }
- // wrap parameters into SEQUENCE
- DerValue paramSequence = new DerValue(DerValue.tag_Sequence,
- params.toByteArray());
- // store parameter SEQUENCE in algid
- algid.putDerValue(paramSequence);
- // wrap algid into SEQUENCE
- tmp.write(DerValue.tag_Sequence, algid);
-
- // privateKey
- tmp.putOctetString(this.key);
-
- // make it a SEQUENCE
- DerValue val = DerValue.wrap(DerValue.tag_Sequence, tmp);
- this.encodedKey = val.toByteArray();
- val.clear();
- }
- }
-
/**
* Returns the private value, x
.
*
@@ -307,10 +334,7 @@ final class DHPrivateKey implements PrivateKey,
*/
@java.io.Serial
private Object writeReplace() throws java.io.ObjectStreamException {
- encode();
- return new KeyRep(KeyRep.Type.PRIVATE,
- getAlgorithm(),
- getFormat(),
+ return new KeyRep(KeyRep.Type.PRIVATE, getAlgorithm(), getFormat(),
encodedKey);
}
@@ -330,11 +354,28 @@ final class DHPrivateKey implements PrivateKey,
if ((key == null) || (key.length == 0)) {
throw new InvalidObjectException("key not deserializable");
}
- this.key = key.clone();
if ((encodedKey == null) || (encodedKey.length == 0)) {
throw new InvalidObjectException(
"encoded key not deserializable");
}
- this.encodedKey = encodedKey.clone();
+ // check if the "encodedKey" value matches the deserialized fields
+ DHComponents c;
+ byte[] encodedKeyIntern = encodedKey.clone();
+ try {
+ c = decode(encodedKeyIntern);
+ } catch (IOException e) {
+ throw new InvalidObjectException("Invalid encoding", e);
+ }
+ if (!Arrays.equals(c.key, key) || !c.x.equals(x) || !c.p.equals(p)
+ || !c.g.equals(g) || c.l != l) {
+ throw new InvalidObjectException(
+ "encoded key not matching internal fields");
+ }
+ // zero out external arrays
+ Arrays.fill(key, (byte)0x00);
+ Arrays.fill(encodedKey, (byte)0x00);
+ // use self-created internal copies
+ this.key = c.key;
+ this.encodedKey = encodedKeyIntern;
}
}
diff --git a/src/java.base/share/classes/com/sun/crypto/provider/DHPublicKey.java b/src/java.base/share/classes/com/sun/crypto/provider/DHPublicKey.java
index 47727c432a6..c95b40482d5 100644
--- a/src/java.base/share/classes/com/sun/crypto/provider/DHPublicKey.java
+++ b/src/java.base/share/classes/com/sun/crypto/provider/DHPublicKey.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2024, 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 com.sun.crypto.provider;
import java.io.*;
+import java.util.Arrays;
import java.util.Objects;
import java.math.BigInteger;
import java.security.KeyRep;
@@ -70,6 +71,116 @@ javax.crypto.interfaces.DHPublicKey, Serializable {
static final ObjectIdentifier DH_OID =
ObjectIdentifier.of(KnownOIDs.DiffieHellman);
+ private static class DHComponents {
+ final BigInteger y;
+ final BigInteger p;
+ final BigInteger g;
+ final int l;
+ final byte[] key;
+
+ DHComponents(BigInteger y, BigInteger p, BigInteger g, int l,
+ byte[] key) {
+ this.y = y;
+ this.p = p;
+ this.g = g;
+ this.l = l;
+ this.key = key;
+ }
+ }
+
+ // parses the specified encoding into a DHComponents object
+ private static DHComponents decode(byte[] encodedKey)
+ throws IOException {
+ DerValue val = null;
+
+ try {
+ val = new DerValue(encodedKey);
+ if (val.tag != DerValue.tag_Sequence) {
+ throw new IOException("Invalid key format");
+ }
+
+ // algorithm identifier
+ DerValue algid = val.data.getDerValue();
+ if (algid.tag != DerValue.tag_Sequence) {
+ throw new IOException("AlgId is not a SEQUENCE");
+ }
+ DerInputStream derInStream = algid.toDerInputStream();
+ ObjectIdentifier oid = derInStream.getOID();
+ if (oid == null) {
+ throw new IOException("Null OID");
+ }
+ if (derInStream.available() == 0) {
+ throw new IOException("Parameters missing");
+ }
+
+ // parse the parameters
+ DerValue params = derInStream.getDerValue();
+ if (params.tag == DerValue.tag_Null) {
+ throw new IOException("Null parameters");
+ }
+ if (params.tag != DerValue.tag_Sequence) {
+ throw new IOException("Parameters not a SEQUENCE");
+ }
+ params.data.reset();
+
+ BigInteger p = params.data.getBigInteger();
+ BigInteger g = params.data.getBigInteger();
+ // Private-value length is OPTIONAL
+ int l = (params.data.available() != 0 ? params.data.getInteger() :
+ 0);
+ if (params.data.available() != 0) {
+ throw new IOException("Extra parameter data");
+ }
+
+ // publickey
+ byte[] key = val.data.getBitString();
+ DerInputStream in = new DerInputStream(key);
+ BigInteger y = in.getBigInteger();
+
+ if (val.data.available() != 0) {
+ throw new IOException("Excess key data");
+ }
+ return new DHComponents(y, p, g, l, key);
+ } catch (NumberFormatException e) {
+ throw new IOException("Error parsing key encoding", e);
+ }
+ }
+
+ // generates the ASN.1 encoding
+ private static byte[] encode(BigInteger p, BigInteger g, int l,
+ byte[] key) {
+ DerOutputStream algid = new DerOutputStream();
+
+ // store oid in algid
+ algid.putOID(DH_OID);
+
+ // encode parameters
+ DerOutputStream params = new DerOutputStream();
+ params.putInteger(p);
+ params.putInteger(g);
+ if (l != 0) {
+ params.putInteger(l);
+ }
+
+ // wrap parameters into SEQUENCE
+ DerValue paramSequence = new DerValue(DerValue.tag_Sequence,
+ params.toByteArray());
+ // store parameter SEQUENCE in algid
+ algid.putDerValue(paramSequence);
+
+ // wrap algid into SEQUENCE, and store it in key encoding
+ DerOutputStream tmpDerKey = new DerOutputStream();
+ tmpDerKey.write(DerValue.tag_Sequence, algid);
+
+ // store key data
+ tmpDerKey.putBitString(key);
+
+ // wrap algid and key into SEQUENCE
+ DerOutputStream derKey = new DerOutputStream();
+ derKey.write(DerValue.tag_Sequence, tmpDerKey);
+ return derKey.toByteArray();
+ }
+
/**
* Make a DH public key out of a public value y
, a prime
* modulus p
, and a base generator g
.
@@ -102,7 +213,7 @@ javax.crypto.interfaces.DHPublicKey, Serializable {
this.l = l;
this.key = new DerValue(DerValue.tag_Integer,
this.y.toByteArray()).toByteArray();
- this.encodedKey = getEncoded();
+ this.encodedKey = encode(p, g, l, key);
}
/**
@@ -114,68 +225,19 @@ javax.crypto.interfaces.DHPublicKey, Serializable {
* a Diffie-Hellman public key
*/
DHPublicKey(byte[] encodedKey) throws InvalidKeyException {
- InputStream inStream = new ByteArrayInputStream(encodedKey);
+ this.encodedKey = encodedKey.clone();
+
+ DHComponents dc;
try {
- DerValue derKeyVal = new DerValue(inStream);
- if (derKeyVal.tag != DerValue.tag_Sequence) {
- throw new InvalidKeyException ("Invalid key format");
- }
-
- /*
- * Parse the algorithm identifier
- */
- DerValue algid = derKeyVal.data.getDerValue();
- if (algid.tag != DerValue.tag_Sequence) {
- throw new InvalidKeyException("AlgId is not a SEQUENCE");
- }
- DerInputStream derInStream = algid.toDerInputStream();
- ObjectIdentifier oid = derInStream.getOID();
- if (oid == null) {
- throw new InvalidKeyException("Null OID");
- }
- if (derInStream.available() == 0) {
- throw new InvalidKeyException("Parameters missing");
- }
-
- /*
- * Parse the parameters
- */
- DerValue params = derInStream.getDerValue();
- if (params.tag == DerValue.tag_Null) {
- throw new InvalidKeyException("Null parameters");
- }
- if (params.tag != DerValue.tag_Sequence) {
- throw new InvalidKeyException("Parameters not a SEQUENCE");
- }
- params.data.reset();
- this.p = params.data.getBigInteger();
- this.g = params.data.getBigInteger();
- // Private-value length is OPTIONAL
- if (params.data.available() != 0) {
- this.l = params.data.getInteger();
- } else {
- this.l = 0;
- }
- if (params.data.available() != 0) {
- throw new InvalidKeyException("Extra parameter data");
- }
-
- /*
- * Parse the key
- */
- this.key = derKeyVal.data.getBitString();
-
- DerInputStream in = new DerInputStream(this.key);
- this.y = in.getBigInteger();
-
- if (derKeyVal.data.available() != 0) {
- throw new InvalidKeyException("Excess key data");
- }
-
- this.encodedKey = encodedKey.clone();
- } catch (IOException | NumberFormatException e) {
- throw new InvalidKeyException("Error parsing key encoding", e);
+ dc = decode(this.encodedKey);
+ } catch (IOException e) {
+ throw new InvalidKeyException("Invalid encoding", e);
}
+ this.y = dc.y;
+ this.p = dc.p;
+ this.g = dc.g;
+ this.l = dc.l;
+ this.key = dc.key;
}
/**
@@ -196,37 +258,6 @@ javax.crypto.interfaces.DHPublicKey, Serializable {
* Get the encoding of the key.
*/
public synchronized byte[] getEncoded() {
- if (this.encodedKey == null) {
- DerOutputStream algid = new DerOutputStream();
-
- // store oid in algid
- algid.putOID(DH_OID);
-
- // encode parameters
- DerOutputStream params = new DerOutputStream();
- params.putInteger(this.p);
- params.putInteger(this.g);
- if (this.l != 0) {
- params.putInteger(this.l);
- }
- // wrap parameters into SEQUENCE
- DerValue paramSequence = new DerValue(DerValue.tag_Sequence,
- params.toByteArray());
- // store parameter SEQUENCE in algid
- algid.putDerValue(paramSequence);
-
- // wrap algid into SEQUENCE, and store it in key encoding
- DerOutputStream tmpDerKey = new DerOutputStream();
- tmpDerKey.write(DerValue.tag_Sequence, algid);
-
- // store key data
- tmpDerKey.putBitString(this.key);
-
- // wrap algid and key into SEQUENCE
- DerOutputStream derKey = new DerOutputStream();
- derKey.write(DerValue.tag_Sequence, tmpDerKey);
- this.encodedKey = derKey.toByteArray();
- }
return this.encodedKey.clone();
}
@@ -263,8 +294,9 @@ javax.crypto.interfaces.DHPublicKey, Serializable {
+ Debug.toHexString(this.p)
+ LINE_SEP + "g:" + LINE_SEP
+ Debug.toHexString(this.g));
- if (this.l != 0)
+ if (this.l != 0) {
sb.append(LINE_SEP + "l:" + LINE_SEP + " " + this.l);
+ }
return sb.toString();
}
@@ -304,7 +336,7 @@ javax.crypto.interfaces.DHPublicKey, Serializable {
return new KeyRep(KeyRep.Type.PUBLIC,
getAlgorithm(),
getFormat(),
- getEncoded());
+ encodedKey);
}
/**
@@ -323,11 +355,28 @@ javax.crypto.interfaces.DHPublicKey, Serializable {
if ((key == null) || (key.length == 0)) {
throw new InvalidObjectException("key not deserializable");
}
- this.key = key.clone();
if ((encodedKey == null) || (encodedKey.length == 0)) {
throw new InvalidObjectException(
"encoded key not deserializable");
}
- this.encodedKey = encodedKey.clone();
+ // check if the "encodedKey" value matches the deserialized fields
+ DHComponents c;
+ byte[] encodedKeyIntern = encodedKey.clone();
+ try {
+ c = decode(encodedKeyIntern);
+ } catch (IOException e) {
+ throw new InvalidObjectException("Invalid encoding", e);
+ }
+ if (!Arrays.equals(c.key, key) || !c.y.equals(y) || !c.p.equals(p)
+ || !c.g.equals(g) || c.l != l) {
+ throw new InvalidObjectException(
+ "encoded key not matching internal fields");
+ }
+ // zero out external arrays
+ Arrays.fill(key, (byte)0x00);
+ Arrays.fill(encodedKey, (byte)0x00);
+ // use self-created internal copies
+ this.key = c.key;
+ this.encodedKey = encodedKeyIntern;
}
}
diff --git a/src/java.base/share/classes/com/sun/crypto/provider/TlsMasterSecretGenerator.java b/src/java.base/share/classes/com/sun/crypto/provider/TlsMasterSecretGenerator.java
index 14ada1699c1..2762fb3751c 100644
--- a/src/java.base/share/classes/com/sun/crypto/provider/TlsMasterSecretGenerator.java
+++ b/src/java.base/share/classes/com/sun/crypto/provider/TlsMasterSecretGenerator.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2024, 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
@@ -194,22 +194,24 @@ public final class TlsMasterSecretGenerator extends KeyGeneratorSpi {
return key.clone();
}
- /**
- * Restores the state of this object from the stream.
- *
- * @param stream the {@code ObjectInputStream} from which data is read
- * @throws IOException if an I/O error occurs
- * @throws ClassNotFoundException if a serialized class cannot be loaded
- */
- @java.io.Serial
- private void readObject(ObjectInputStream stream)
- throws IOException, ClassNotFoundException {
- stream.defaultReadObject();
- if ((key == null) || (key.length == 0)) {
- throw new InvalidObjectException("TlsMasterSecretKey is null");
- }
- key = key.clone();
- }
- }
+ /**
+ * Restores the state of this object from the stream.
+ *
+ * @param stream the {@code ObjectInputStream} from which data is read
+ * @throws IOException if an I/O error occurs
+ * @throws ClassNotFoundException if a serialized class cannot be loaded
+ */
+ @java.io.Serial
+ private void readObject(ObjectInputStream stream)
+ throws IOException, ClassNotFoundException {
+ stream.defaultReadObject();
+ if (key == null || key.length == 0) {
+ throw new InvalidObjectException("TlsMasterSecretKey is null");
+ }
+ byte[] temp = key;
+ this.key = temp.clone();
+ Arrays.fill(temp, (byte)0);
+ }
+ }
}
diff --git a/src/java.base/share/classes/java/security/Permissions.java b/src/java.base/share/classes/java/security/Permissions.java
index 42c1adc9002..3bdeac6f929 100644
--- a/src/java.base/share/classes/java/security/Permissions.java
+++ b/src/java.base/share/classes/java/security/Permissions.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2024, 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
@@ -407,6 +407,11 @@ implements Serializable
@SuppressWarnings("unchecked")
Hashtable, PermissionCollection> perms =
(Hashtable, PermissionCollection>)gfields.get("perms", null);
+
+ if (perms == null) {
+ throw new InvalidObjectException("perms can't be null");
+ }
+
permsMap = new ConcurrentHashMap<>(perms.size()*2);
permsMap.putAll(perms);
diff --git a/src/java.base/share/classes/java/security/SignedObject.java b/src/java.base/share/classes/java/security/SignedObject.java
index e2f9c764ec2..f65300fc808 100644
--- a/src/java.base/share/classes/java/security/SignedObject.java
+++ b/src/java.base/share/classes/java/security/SignedObject.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2024, 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
@@ -152,20 +152,20 @@ public final class SignedObject implements Serializable {
*/
public SignedObject(Serializable object, PrivateKey signingKey,
Signature signingEngine)
- throws IOException, InvalidKeyException, SignatureException {
- // creating a stream pipe-line, from a to b
- ByteArrayOutputStream b = new ByteArrayOutputStream();
- ObjectOutput a = new ObjectOutputStream(b);
+ throws IOException, InvalidKeyException, SignatureException {
+ // creating a stream pipe-line, from a to b
+ ByteArrayOutputStream b = new ByteArrayOutputStream();
+ ObjectOutput a = new ObjectOutputStream(b);
- // write and flush the object content to byte array
- a.writeObject(object);
- a.flush();
- a.close();
- this.content = b.toByteArray();
- b.close();
+ // write and flush the object content to byte array
+ a.writeObject(object);
+ a.flush();
+ a.close();
+ this.content = b.toByteArray();
+ b.close();
- // now sign the encapsulated object
- this.sign(signingKey, signingEngine);
+ // now sign the encapsulated object
+ this.sign(signingKey, signingEngine);
}
/**
@@ -245,12 +245,12 @@ public final class SignedObject implements Serializable {
* @throws SignatureException if signing fails.
*/
private void sign(PrivateKey signingKey, Signature signingEngine)
- throws InvalidKeyException, SignatureException {
- // initialize the signing engine
- signingEngine.initSign(signingKey);
- signingEngine.update(this.content.clone());
- this.signature = signingEngine.sign().clone();
- this.thealgorithm = signingEngine.getAlgorithm();
+ throws InvalidKeyException, SignatureException {
+ // initialize the signing engine
+ signingEngine.initSign(signingKey);
+ signingEngine.update(this.content.clone());
+ this.signature = signingEngine.sign();
+ this.thealgorithm = signingEngine.getAlgorithm();
}
/**
@@ -263,10 +263,16 @@ public final class SignedObject implements Serializable {
*/
@Serial
private void readObject(ObjectInputStream s)
- throws IOException, ClassNotFoundException {
- ObjectInputStream.GetField fields = s.readFields();
- content = ((byte[])fields.get("content", null)).clone();
- signature = ((byte[])fields.get("signature", null)).clone();
- thealgorithm = (String)fields.get("thealgorithm", null);
+ throws IOException, ClassNotFoundException {
+ ObjectInputStream.GetField fields = s.readFields();
+ byte[] c = (byte[]) fields.get("content", null);
+ byte[] sig = (byte[]) fields.get("signature", null);
+ String a = (String) fields.get("thealgorithm", null);
+ if (c == null || sig == null || a == null) {
+ throw new InvalidObjectException("One or more null fields");
+ }
+ content = c.clone();
+ signature = sig.clone();
+ thealgorithm = a;
}
}
diff --git a/src/java.base/share/classes/java/security/Timestamp.java b/src/java.base/share/classes/java/security/Timestamp.java
index 10a93a9b180..96df37a8c1f 100644
--- a/src/java.base/share/classes/java/security/Timestamp.java
+++ b/src/java.base/share/classes/java/security/Timestamp.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2024, 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
@@ -27,6 +27,7 @@ package java.security;
import java.io.IOException;
import java.io.ObjectInputStream;
+import java.io.InvalidObjectException;
import java.io.Serializable;
import java.security.cert.CertPath;
import java.security.cert.Certificate;
@@ -78,7 +79,7 @@ public final class Timestamp implements Serializable {
* {@code null}.
*/
public Timestamp(Date timestamp, CertPath signerCertPath) {
- if (timestamp == null || signerCertPath == null) {
+ if (isNull(timestamp, signerCertPath)) {
throw new NullPointerException();
}
this.timestamp = new Date(timestamp.getTime()); // clone
@@ -166,9 +167,16 @@ public final class Timestamp implements Serializable {
*/
@java.io.Serial
private void readObject(ObjectInputStream ois)
- throws IOException, ClassNotFoundException {
+ throws IOException, ClassNotFoundException {
ois.defaultReadObject();
+ if (isNull(timestamp, signerCertPath)) {
+ throw new InvalidObjectException("Invalid null field(s)");
+ }
myhash = -1;
timestamp = new Date(timestamp.getTime());
}
+
+ private static boolean isNull(Date d, CertPath c) {
+ return (d == null || c == null);
+ }
}
diff --git a/src/java.base/share/classes/java/security/UnresolvedPermissionCollection.java b/src/java.base/share/classes/java/security/UnresolvedPermissionCollection.java
index a5f4de22d89..c0bdf5fc2a1 100644
--- a/src/java.base/share/classes/java/security/UnresolvedPermissionCollection.java
+++ b/src/java.base/share/classes/java/security/UnresolvedPermissionCollection.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2024, 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,7 @@ import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.ObjectStreamField;
+import java.io.InvalidObjectException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
@@ -196,23 +197,32 @@ implements java.io.Serializable
ObjectInputStream.GetField gfields = in.readFields();
// Get permissions
- @SuppressWarnings("unchecked")
// writeObject writes a Hashtable>
// for the permissions key, so this cast is safe, unless the data is corrupt.
- Hashtable> permissions =
- (Hashtable>)
- gfields.get("permissions", null);
- perms = new ConcurrentHashMap<>(permissions.size()*2);
+ try {
+ @SuppressWarnings("unchecked")
+ Hashtable> permissions =
+ (Hashtable>)
+ gfields.get("permissions", null);
- // Convert each entry (Vector) into a List
- Set>> set = permissions.entrySet();
- for (Map.Entry> e : set) {
- // Convert Vector into ArrayList
- Vector vec = e.getValue();
- List list = new CopyOnWriteArrayList<>(vec);
+ if (permissions == null) {
+ throw new InvalidObjectException("Invalid null permissions");
+ }
- // Add to Hashtable being serialized
- perms.put(e.getKey(), list);
+ perms = new ConcurrentHashMap<>(permissions.size()*2);
+
+ // Convert each entry (Vector) into a List
+ Set>> set = permissions.entrySet();
+ for (Map.Entry> e : set) {
+ // Convert Vector into ArrayList
+ Vector vec = e.getValue();
+ List list = new CopyOnWriteArrayList<>(vec);
+
+ // Add to Hashtable being serialized
+ perms.put(e.getKey(), list);
+ }
+ } catch (ClassCastException cce) {
+ throw new InvalidObjectException("Invalid type for permissions");
}
}
}
diff --git a/src/java.base/share/classes/java/security/cert/CertificateRevokedException.java b/src/java.base/share/classes/java/security/cert/CertificateRevokedException.java
index 70083033fc6..6649dcda6cc 100644
--- a/src/java.base/share/classes/java/security/cert/CertificateRevokedException.java
+++ b/src/java.base/share/classes/java/security/cert/CertificateRevokedException.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2007, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2024, 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
@@ -28,6 +28,7 @@ package java.security.cert;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.IOException;
+import java.io.InvalidObjectException;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
@@ -70,6 +71,13 @@ public class CertificateRevokedException extends CertificateException {
private transient Map extensions;
+ private static boolean isNull(Date revocationDate,
+ CRLReason reason, X500Principal authority,
+ Map extensions) {
+ return (revocationDate == null || reason == null || authority == null
+ || extensions == null);
+ }
+
/**
* Constructs a {@code CertificateRevokedException} with
* the specified revocation date, reason code, authority name, and map
@@ -92,8 +100,7 @@ public class CertificateRevokedException extends CertificateException {
*/
public CertificateRevokedException(Date revocationDate, CRLReason reason,
X500Principal authority, Map extensions) {
- if (revocationDate == null || reason == null || authority == null ||
- extensions == null) {
+ if (isNull(revocationDate, reason, authority, extensions)) {
throw new NullPointerException();
}
this.revocationDate = new Date(revocationDate.getTime());
@@ -234,9 +241,6 @@ public class CertificateRevokedException extends CertificateException {
// (revocationDate, reason, authority)
ois.defaultReadObject();
- // Defensively copy the revocation date
- revocationDate = new Date(revocationDate.getTime());
-
// Read in the size (number of mappings) of the extensions map
// and create the extensions map
int size = ois.readInt();
@@ -247,6 +251,13 @@ public class CertificateRevokedException extends CertificateException {
} else {
extensions = HashMap.newHashMap(Math.min(size, 20));
}
+ // make sure all fields are set before checking
+ if (isNull(revocationDate, reason, authority, extensions)) {
+ throw new InvalidObjectException("Invalid null field(s)");
+ }
+
+ // Defensively copy the revocation date
+ revocationDate = new Date(revocationDate.getTime());
// Read in the extensions and put the mappings in the extensions map
for (int i = 0; i < size; i++) {
diff --git a/src/java.base/share/classes/javax/crypto/spec/SecretKeySpec.java b/src/java.base/share/classes/javax/crypto/spec/SecretKeySpec.java
index e76a51e5d68..2ad9a7748f2 100644
--- a/src/java.base/share/classes/javax/crypto/spec/SecretKeySpec.java
+++ b/src/java.base/share/classes/javax/crypto/spec/SecretKeySpec.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2024, 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
@@ -100,11 +100,9 @@ public class SecretKeySpec implements KeySpec, SecretKey {
* is null or key
is null or empty.
*/
public SecretKeySpec(byte[] key, String algorithm) {
- if (key == null || algorithm == null) {
- throw new IllegalArgumentException("Missing argument");
- }
- if (key.length == 0) {
- throw new IllegalArgumentException("Empty key");
+ String errMsg = doSanityCheck(key, algorithm);
+ if (errMsg != null) {
+ throw new IllegalArgumentException(errMsg);
}
this.key = key.clone();
this.algorithm = algorithm;
@@ -266,14 +264,22 @@ public class SecretKeySpec implements KeySpec, SecretKey {
private void readObject(ObjectInputStream stream)
throws IOException, ClassNotFoundException {
stream.defaultReadObject();
+ String errMsg = doSanityCheck(key, algorithm);
+ if (errMsg != null) {
+ throw new InvalidObjectException(errMsg);
+ }
+ byte[] temp = key;
+ this.key = temp.clone();
+ Arrays.fill(temp, (byte) 0);
+ }
+ private static String doSanityCheck(byte[] key, String algorithm) {
+ String errMsg = null;
if (key == null || algorithm == null) {
- throw new InvalidObjectException("Missing argument");
- }
-
- this.key = key.clone();
- if (key.length == 0) {
- throw new InvalidObjectException("Invalid key length");
+ errMsg = "Missing argument";
+ } else if (key.length == 0) {
+ errMsg = "Empty key";
}
+ return errMsg;
}
}
diff --git a/src/java.base/share/classes/javax/security/auth/callback/ChoiceCallback.java b/src/java.base/share/classes/javax/security/auth/callback/ChoiceCallback.java
index c005b4ea02b..1c35491e4e2 100644
--- a/src/java.base/share/classes/javax/security/auth/callback/ChoiceCallback.java
+++ b/src/java.base/share/classes/javax/security/auth/callback/ChoiceCallback.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2024, 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
@@ -102,20 +102,18 @@ public class ChoiceCallback implements Callback, java.io.Serializable {
public ChoiceCallback(String prompt, String[] choices,
int defaultChoice, boolean multipleSelectionsAllowed) {
- if (prompt == null || prompt.isEmpty() ||
- choices == null || choices.length == 0 ||
- defaultChoice < 0 || defaultChoice >= choices.length)
- throw new IllegalArgumentException();
-
+ choices = (choices == null || choices.length == 0 ? choices :
+ choices.clone());
+ String errMsg = doSanityCheck(prompt, choices, defaultChoice,
+ multipleSelectionsAllowed);
+ if (errMsg != null) {
+ throw new IllegalArgumentException(errMsg);
+ }
this.prompt = prompt;
this.defaultChoice = defaultChoice;
this.multipleSelectionsAllowed = multipleSelectionsAllowed;
- this.choices = choices.clone();
- for (int i = 0; i < choices.length; i++) {
- if (choices[i] == null || choices[i].isEmpty())
- throw new IllegalArgumentException();
- }
+ this.choices = choices;
}
/**
@@ -183,9 +181,11 @@ public class ChoiceCallback implements Callback, java.io.Serializable {
* @see #getSelectedIndexes
*/
public void setSelectedIndexes(int[] selections) {
- if (!multipleSelectionsAllowed)
+ if (!multipleSelectionsAllowed) {
throw new UnsupportedOperationException();
- this.selections = selections == null ? null : selections.clone();
+ }
+ this.selections = ((selections == null || selections.length == 0) ?
+ selections : selections.clone());
}
/**
@@ -211,26 +211,35 @@ public class ChoiceCallback implements Callback, java.io.Serializable {
private void readObject(ObjectInputStream stream)
throws IOException, ClassNotFoundException {
stream.defaultReadObject();
+ choices = (choices == null || choices.length == 0 ?
+ choices : choices.clone());
+ String errMsg = doSanityCheck(prompt, choices, defaultChoice,
+ multipleSelectionsAllowed);
+ if (errMsg != null) {
+ throw new InvalidObjectException(errMsg);
+ }
+ selections = (selections == null || selections.length == 0 ?
+ selections : selections.clone());
+ if (selections != null && selections.length > 1 &&
+ !multipleSelectionsAllowed) {
+ throw new InvalidObjectException("Multiple selections not allowed");
+ }
+ }
+
+ private static String doSanityCheck(String prompt, String[] choices,
+ int defaultChoice, boolean allowMultiple) {
if ((prompt == null) || prompt.isEmpty() ||
(choices == null) || (choices.length == 0) ||
(defaultChoice < 0) || (defaultChoice >= choices.length)) {
- throw new InvalidObjectException(
- "Missing/invalid prompt/choices");
+ return "Missing/invalid prompt/choices";
}
- choices = choices.clone();
for (int i = 0; i < choices.length; i++) {
- if ((choices[i] == null) || choices[i].isEmpty())
- throw new InvalidObjectException("Null/empty choices");
- }
-
- if (selections != null) {
- selections = selections.clone();
- if (!multipleSelectionsAllowed && (selections.length != 1)) {
- throw new InvalidObjectException(
- "Multiple selections not allowed");
+ if ((choices[i] == null) || choices[i].isEmpty()) {
+ return "Null/empty choices value";
}
}
+ return null;
}
}
diff --git a/src/java.base/share/classes/javax/security/auth/callback/ConfirmationCallback.java b/src/java.base/share/classes/javax/security/auth/callback/ConfirmationCallback.java
index 437ce7041a7..a00fc7013ec 100644
--- a/src/java.base/share/classes/javax/security/auth/callback/ConfirmationCallback.java
+++ b/src/java.base/share/classes/javax/security/auth/callback/ConfirmationCallback.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2024, 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 javax.security.auth.callback;
import java.io.IOException;
+import java.io.InvalidObjectException;
import java.io.ObjectInputStream;
/**
@@ -189,25 +190,10 @@ public class ConfirmationCallback implements Callback, java.io.Serializable {
*/
public ConfirmationCallback(int messageType,
int optionType, int defaultOption) {
-
- if (messageType < INFORMATION || messageType > ERROR ||
- optionType < YES_NO_OPTION || optionType > OK_CANCEL_OPTION)
- throw new IllegalArgumentException();
-
- switch (optionType) {
- case YES_NO_OPTION:
- if (defaultOption != YES && defaultOption != NO)
- throw new IllegalArgumentException();
- break;
- case YES_NO_CANCEL_OPTION:
- if (defaultOption != YES && defaultOption != NO &&
- defaultOption != CANCEL)
- throw new IllegalArgumentException();
- break;
- case OK_CANCEL_OPTION:
- if (defaultOption != OK && defaultOption != CANCEL)
- throw new IllegalArgumentException();
- break;
+ String errMsg = doSanityCheck(messageType, optionType, false, null,
+ defaultOption, null, false);
+ if (errMsg != null) {
+ throw new IllegalArgumentException(errMsg);
}
this.prompt = null;
@@ -250,21 +236,20 @@ public class ConfirmationCallback implements Callback, java.io.Serializable {
public ConfirmationCallback(int messageType,
String[] options, int defaultOption) {
- if (messageType < INFORMATION || messageType > ERROR ||
- options == null || options.length == 0 ||
- defaultOption < 0 || defaultOption >= options.length)
- throw new IllegalArgumentException();
+ if (options != null) {
+ options = options.clone();
+ }
+ String errMsg = doSanityCheck(messageType, UNSPECIFIED_OPTION, true,
+ options, defaultOption, null, false);
+ if (errMsg != null) {
+ throw new IllegalArgumentException(errMsg);
+ }
this.prompt = null;
this.messageType = messageType;
this.optionType = UNSPECIFIED_OPTION;
this.defaultOption = defaultOption;
-
- this.options = options.clone();
- for (int i = 0; i < options.length; i++) {
- if (options[i] == null || options[i].isEmpty())
- throw new IllegalArgumentException();
- }
+ this.options = options;
}
/**
@@ -304,27 +289,11 @@ public class ConfirmationCallback implements Callback, java.io.Serializable {
public ConfirmationCallback(String prompt, int messageType,
int optionType, int defaultOption) {
- if (prompt == null || prompt.isEmpty() ||
- messageType < INFORMATION || messageType > ERROR ||
- optionType < YES_NO_OPTION || optionType > OK_CANCEL_OPTION)
- throw new IllegalArgumentException();
-
- switch (optionType) {
- case YES_NO_OPTION:
- if (defaultOption != YES && defaultOption != NO)
- throw new IllegalArgumentException();
- break;
- case YES_NO_CANCEL_OPTION:
- if (defaultOption != YES && defaultOption != NO &&
- defaultOption != CANCEL)
- throw new IllegalArgumentException();
- break;
- case OK_CANCEL_OPTION:
- if (defaultOption != OK && defaultOption != CANCEL)
- throw new IllegalArgumentException();
- break;
+ String errMsg = doSanityCheck(messageType, optionType, false, null,
+ defaultOption, prompt, true);
+ if (errMsg != null) {
+ throw new IllegalArgumentException(errMsg);
}
-
this.prompt = prompt;
this.messageType = messageType;
this.optionType = optionType;
@@ -369,22 +338,20 @@ public class ConfirmationCallback implements Callback, java.io.Serializable {
public ConfirmationCallback(String prompt, int messageType,
String[] options, int defaultOption) {
- if (prompt == null || prompt.isEmpty() ||
- messageType < INFORMATION || messageType > ERROR ||
- options == null || options.length == 0 ||
- defaultOption < 0 || defaultOption >= options.length)
- throw new IllegalArgumentException();
+ if (options != null) {
+ options = options.clone();
+ }
+ String errMsg = doSanityCheck(messageType, UNSPECIFIED_OPTION, true,
+ options, defaultOption, prompt, true);
+ if (errMsg != null) {
+ throw new IllegalArgumentException(errMsg);
+ }
this.prompt = prompt;
this.messageType = messageType;
this.optionType = UNSPECIFIED_OPTION;
this.defaultOption = defaultOption;
-
- this.options = options.clone();
- for (int i = 0; i < options.length; i++) {
- if (options[i] == null || options[i].isEmpty())
- throw new IllegalArgumentException();
- }
+ this.options = options;
}
/**
@@ -491,6 +458,49 @@ public class ConfirmationCallback implements Callback, java.io.Serializable {
return selection;
}
+ private static String doSanityCheck(int msgType, int optionType,
+ boolean isUnspecifiedOption, String[] options, int defOption,
+ String prompt, boolean checkPrompt) {
+ // validate msgType
+ if (msgType < INFORMATION || msgType > ERROR) {
+ return "Invalid msgType";
+ }
+ // validate prompt if checkPrompt == true
+ if (checkPrompt && (prompt == null || prompt.isEmpty())) {
+ return "Invalid prompt";
+ }
+ // validate optionType
+ if (isUnspecifiedOption) {
+ if (optionType != UNSPECIFIED_OPTION) {
+ return "Invalid optionType";
+ }
+ // check options
+ if (options == null || options.length == 0 ||
+ defOption < 0 || defOption >= options.length) {
+ return "Invalid options and/or default option";
+ }
+ for (String ov : options) {
+ if (ov == null || ov.isEmpty()) {
+ return "Invalid option value";
+ }
+ }
+ } else {
+ if (optionType < YES_NO_OPTION || optionType > OK_CANCEL_OPTION) {
+ return "Invalid optionType";
+ }
+ // validate defOption based on optionType
+ if ((optionType == YES_NO_OPTION && (defOption != YES &&
+ defOption != NO)) ||
+ (optionType == YES_NO_CANCEL_OPTION && (defOption != YES &&
+ defOption != NO && defOption != CANCEL)) ||
+ (optionType == OK_CANCEL_OPTION && (defOption != OK &&
+ defOption != CANCEL))) {
+ return "Invalid default option";
+ }
+ }
+ return null;
+ }
+
/**
* Restores the state of this object from the stream.
*
@@ -502,8 +512,15 @@ public class ConfirmationCallback implements Callback, java.io.Serializable {
private void readObject(ObjectInputStream stream)
throws IOException, ClassNotFoundException {
stream.defaultReadObject();
+
if (options != null) {
options = options.clone();
}
+ String errMsg = doSanityCheck(messageType, optionType,
+ (optionType == UNSPECIFIED_OPTION), options, defaultOption,
+ prompt, false);
+ if (errMsg != null) {
+ throw new InvalidObjectException(errMsg);
+ }
}
}
diff --git a/src/java.base/share/classes/javax/security/auth/callback/PasswordCallback.java b/src/java.base/share/classes/javax/security/auth/callback/PasswordCallback.java
index bbe7ab882a6..2bee38ceaaa 100644
--- a/src/java.base/share/classes/javax/security/auth/callback/PasswordCallback.java
+++ b/src/java.base/share/classes/javax/security/auth/callback/PasswordCallback.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2024, 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
@@ -178,7 +178,9 @@ public class PasswordCallback implements Callback, java.io.Serializable {
}
if (inputPassword != null) {
- inputPassword = inputPassword.clone();
+ char[] temp = inputPassword;
+ inputPassword = temp.clone();
+ Arrays.fill(temp, '0');
cleanable = CleanerFactory.cleaner().register(
this, cleanerFor(inputPassword));
}
diff --git a/src/java.base/share/classes/sun/security/provider/DRBG.java b/src/java.base/share/classes/sun/security/provider/DRBG.java
index 923c8c3aa54..01958285e43 100644
--- a/src/java.base/share/classes/sun/security/provider/DRBG.java
+++ b/src/java.base/share/classes/sun/security/provider/DRBG.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2024, 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 sun.security.provider;
import java.io.IOException;
+import java.io.InvalidObjectException;
import java.security.AccessController;
import java.security.DrbgParameters;
import java.security.PrivilegedAction;
@@ -272,11 +273,18 @@ public final class DRBG extends SecureRandomSpi {
}
}
+ /**
+ * Restores the state of this object from the stream.
+ *
+ * @param s the {@code ObjectInputStream} from which data is read
+ * @throws IOException if an I/O error occurs
+ * @throws ClassNotFoundException if a serialized class cannot be loaded
+ */
@java.io.Serial
private void readObject(java.io.ObjectInputStream s)
throws IOException, ClassNotFoundException {
s.defaultReadObject();
- if (mdp.mech == null) {
+ if (mdp == null || mdp.mech == null) {
throw new IllegalArgumentException("Input data is corrupted");
}
createImpl();
diff --git a/src/java.base/share/classes/sun/security/util/ObjectIdentifier.java b/src/java.base/share/classes/sun/security/util/ObjectIdentifier.java
index 6181bf223e9..306d34d7149 100644
--- a/src/java.base/share/classes/sun/security/util/ObjectIdentifier.java
+++ b/src/java.base/share/classes/sun/security/util/ObjectIdentifier.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2024, 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
@@ -127,13 +127,24 @@ public final class ObjectIdentifier implements Serializable {
// Is the component's field calculated?
private transient boolean componentsCalculated = false;
+ /**
+ * Restores the state of this object from the stream.
+ *
+ * @param is the {@code ObjectInputStream} from which data is read
+ * @throws IOException if an I/O error occurs
+ * @throws ClassNotFoundException if a serialized class cannot be loaded
+ */
@java.io.Serial
private void readObject(ObjectInputStream is)
throws IOException, ClassNotFoundException {
is.defaultReadObject();
if (encoding == null) { // from an old version
- int[] comp = (int[])components;
+ if (components == null) {
+ throw new InvalidObjectException("OID components is null");
+ }
+
+ int[] comp = ((int[]) components).clone();
if (componentLen > comp.length) {
componentLen = comp.length;
}
@@ -142,7 +153,9 @@ public final class ObjectIdentifier implements Serializable {
// will be performed again in init().
checkOidSize(componentLen);
init(comp, componentLen);
+ components = comp;
} else {
+ encoding = encoding.clone(); // defensive copying
checkOidSize(encoding.length);
check(encoding);
}
@@ -261,6 +274,7 @@ public final class ObjectIdentifier implements Serializable {
encoding = in.getDerValue().getOID().encoding;
}
+ // set 'encoding' field based on the specified 'components' and 'length'
private void init(int[] components, int length) throws IOException {
int pos = 0;
byte[] tmp = new byte[length * 5 + 1]; // +1 for empty input
diff --git a/src/java.base/share/classes/sun/security/x509/AlgIdDSA.java b/src/java.base/share/classes/sun/security/x509/AlgIdDSA.java
index 3a3d384a0e8..764d77e6da8 100644
--- a/src/java.base/share/classes/sun/security/x509/AlgIdDSA.java
+++ b/src/java.base/share/classes/sun/security/x509/AlgIdDSA.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2024, 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
@@ -25,11 +25,13 @@
package sun.security.x509;
+import java.io.ObjectInputStream;
import java.io.IOException;
+import java.io.InvalidObjectException;
import java.math.BigInteger;
import java.security.*;
import java.security.interfaces.DSAParams;
-
+import java.util.Arrays;
import sun.security.util.*;
@@ -72,33 +74,42 @@ import sun.security.util.*;
*
* @author David Brownell
*/
-public final
-class AlgIdDSA extends AlgorithmId implements DSAParams
-{
+public final class AlgIdDSA extends AlgorithmId implements DSAParams {
@java.io.Serial
private static final long serialVersionUID = 3437177836797504046L;
+ private static class DSAComponents {
+ private final BigInteger p;
+ private final BigInteger q;
+ private final BigInteger g;
+ DSAComponents(BigInteger p, BigInteger q, BigInteger g) {
+ this.p = p;
+ this.q = q;
+ this.g = g;
+ }
+ }
+
/*
* The three unsigned integer parameters.
*/
- private BigInteger p , q, g;
+ private BigInteger p, q, g;
/** Returns the DSS/DSA parameter "P" */
- public BigInteger getP () { return p; }
+ public BigInteger getP() { return p; }
/** Returns the DSS/DSA parameter "Q" */
- public BigInteger getQ () { return q; }
+ public BigInteger getQ() { return q; }
/** Returns the DSS/DSA parameter "G" */
- public BigInteger getG () { return g; }
+ public BigInteger getG() { return g; }
/**
* Default constructor. The OID and parameters must be
* deserialized before this algorithm ID is used.
*/
@Deprecated
- public AlgIdDSA () {}
+ public AlgIdDSA() {}
/**
* Constructs a DSS/DSA Algorithm ID from numeric parameters.
@@ -109,7 +120,7 @@ class AlgIdDSA extends AlgorithmId implements DSAParams
* @param q the DSS/DSA parameter "Q"
* @param g the DSS/DSA parameter "G"
*/
- public AlgIdDSA (BigInteger p, BigInteger q, BigInteger g) {
+ public AlgIdDSA(BigInteger p, BigInteger q, BigInteger g) {
super (DSA_oid);
if (p != null || q != null || g != null) {
@@ -120,8 +131,10 @@ class AlgIdDSA extends AlgorithmId implements DSAParams
this.p = p;
this.q = q;
this.g = g;
- initializeParams ();
-
+ // For algorithm IDs which haven't been created from a DER
+ // encoded value, need to create DER encoding and store it
+ // into "encodedParams"
+ encodedParams = encode(p, q, g);
} catch (IOException e) {
/* this should not happen */
throw new ProviderException ("Construct DSS/DSA Algorithm ID");
@@ -133,50 +146,10 @@ class AlgIdDSA extends AlgorithmId implements DSAParams
* Returns "DSA", indicating the Digital Signature Algorithm (DSA) as
* defined by the Digital Signature Standard (DSS), FIPS 186.
*/
- public String getName ()
- { return "DSA"; }
-
-
- /*
- * For algorithm IDs which haven't been created from a DER encoded
- * value, "params" must be created.
- */
- private void initializeParams () throws IOException {
- DerOutputStream out = new DerOutputStream();
- out.putInteger(p);
- out.putInteger(q);
- out.putInteger(g);
- DerOutputStream result = new DerOutputStream();
- result.write(DerValue.tag_Sequence, out);
- encodedParams = result.toByteArray();
+ public String getName() {
+ return "DSA";
}
- /**
- * Parses algorithm parameters P, Q, and G. They're found
- * in the "params" member, which never needs to be changed.
- */
- protected void decodeParams () throws IOException {
- if (encodedParams == null) {
- throw new IOException("DSA alg params are null");
- }
-
- DerValue params = new DerValue(encodedParams);
- if (params.tag != DerValue.tag_Sequence) {
- throw new IOException("DSA alg parsing error");
- }
-
- params.data.reset ();
-
- this.p = params.data.getBigInteger();
- this.q = params.data.getBigInteger();
- this.g = params.data.getBigInteger();
-
- if (params.data.available () != 0)
- throw new IOException ("AlgIdDSA params, extra="+
- params.data.available ());
- }
-
-
/*
* Returns a formatted string describing the parameters.
*/
@@ -197,4 +170,44 @@ class AlgIdDSA extends AlgorithmId implements DSAParams
"\n";
}
}
+
+ /**
+ * Restores the state of this object from the stream. Override to check
+ * on the 'p', 'q', 'g', and 'encodedParams'.
+ *
+ * @param stream the {@code ObjectInputStream} from which data is read
+ * @throws IOException if an I/O error occurs
+ * @throws ClassNotFoundException if a serialized class cannot be loaded
+ */
+ @java.io.Serial
+ private void readObject(ObjectInputStream stream) throws IOException {
+ try {
+ stream.defaultReadObject();
+ // if any of the 'p', 'q', 'g', 'encodedParams' is non-null,
+ // then they must be all non-null w/ matching encoding
+ if ((p != null || q != null || g != null || encodedParams != null)
+ && !Arrays.equals(encodedParams, encode(p, q, g))) {
+ throw new InvalidObjectException("Invalid DSA alg params");
+ }
+ } catch (ClassNotFoundException e) {
+ throw new IOException(e);
+ }
+ }
+
+ /*
+ * Create the DER encoding w/ the specified 'p', 'q', 'g'
+ */
+ private static byte[] encode(BigInteger p, BigInteger q,
+ BigInteger g) throws IOException {
+ if (p == null || q == null || g == null) {
+ throw new InvalidObjectException("invalid null value");
+ }
+ DerOutputStream out = new DerOutputStream();
+ out.putInteger(p);
+ out.putInteger(q);
+ out.putInteger(g);
+ DerOutputStream result = new DerOutputStream();
+ result.write(DerValue.tag_Sequence, out);
+ return result.toByteArray();
+ }
}
diff --git a/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5Context.java b/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5Context.java
index fa596fc6a1e..cb9b8746994 100644
--- a/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5Context.java
+++ b/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5Context.java
@@ -33,8 +33,10 @@ import sun.security.jgss.spi.*;
import sun.security.jgss.TokenTracker;
import sun.security.krb5.*;
import java.io.InputStream;
-import java.io.OutputStream;
+import java.io.InvalidObjectException;
import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.OutputStream;
import java.security.*;
import javax.security.auth.Subject;
import javax.security.auth.kerberos.ServicePermission;
@@ -1408,6 +1410,20 @@ class Krb5Context implements GSSContextSpi {
return "Kerberos session key: etype: " + key.getEType() + "\n" +
new HexDumpEncoder().encodeBuffer(key.getBytes());
}
+
+ /**
+ * Restores the state of this object from the stream.
+ *
+ * @param stream the {@code ObjectInputStream} from which data is read
+ * @throws IOException if an I/O error occurs
+ * @throws ClassNotFoundException if a serialized class cannot be loaded
+ */
+ @java.io.Serial
+ private void readObject(ObjectInputStream stream)
+ throws IOException, ClassNotFoundException {
+ throw new InvalidObjectException
+ ("KerberosSessionKey not directly deserializable");
+ }
}
/**
@@ -1477,5 +1493,4 @@ class Krb5Context implements GSSContextSpi {
public void setAuthzData(AuthorizationData authzData) {
this.authzData = authzData;
}
-
}
diff --git a/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5InitCredential.java b/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5InitCredential.java
index 1b109cc881f..4cc306282e6 100644
--- a/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5InitCredential.java
+++ b/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5InitCredential.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2024, 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
@@ -33,7 +33,9 @@ import javax.security.auth.kerberos.KerberosTicket;
import javax.security.auth.kerberos.KerberosPrincipal;
import java.io.Serial;
import java.net.InetAddress;
+import java.io.InvalidObjectException;
import java.io.IOException;
+import java.io.ObjectInputStream;
import java.util.Date;
import java.security.AccessController;
import java.security.PrivilegedExceptionAction;
@@ -400,4 +402,17 @@ public class Krb5InitCredential
throw ge;
}
}
+
+ /**
+ * Restores the state of this object from the stream.
+ *
+ * @param stream the {@code ObjectInputStream} from which data is read
+ * @throws IOException if an I/O error occurs
+ * @throws ClassNotFoundException if a serialized class cannot be loaded
+ */
+ @java.io.Serial
+ private void readObject(ObjectInputStream stream)
+ throws IOException, ClassNotFoundException {
+ throw new InvalidObjectException("Krb5InitCredential not deserializable");
+ }
}
diff --git a/src/java.security.jgss/share/classes/sun/security/krb5/internal/KRBError.java b/src/java.security.jgss/share/classes/sun/security/krb5/internal/KRBError.java
index b93ced00c65..db6192ce9ee 100644
--- a/src/java.security.jgss/share/classes/sun/security/krb5/internal/KRBError.java
+++ b/src/java.security.jgss/share/classes/sun/security/krb5/internal/KRBError.java
@@ -83,28 +83,36 @@ import static sun.security.krb5.internal.Krb5.DEBUG;
*
* http://www.ietf.org/rfc/rfc4120.txt.
*/
-// The instance fields not statically typed as Serializable are ASN.1
-// encoded and written by the writeObject method.
-@SuppressWarnings("serial")
+
public class KRBError implements java.io.Serializable {
static final long serialVersionUID = 3643809337475284503L;
- private int pvno;
- private int msgType;
- private KerberosTime cTime; //optional
- private Integer cuSec; //optional
- private KerberosTime sTime;
- private Integer suSec;
- private int errorCode;
- private Realm crealm; //optional
- private PrincipalName cname; //optional
- private PrincipalName sname;
- private String eText; //optional
- private byte[] eData; //optional
- private Checksum eCksum; //optional
+ private transient int pvno;
+ private transient int msgType;
+ private transient KerberosTime cTime; //optional
+ private transient Integer cuSec; //optional
+ private transient KerberosTime sTime;
+ private transient Integer suSec;
+ private transient int errorCode;
+ private transient Realm crealm; //optional
+ private transient PrincipalName cname; //optional
+ private transient PrincipalName sname;
+ private transient String eText; //optional
+ private transient byte[] eData; //optional
+ private transient Checksum eCksum; //optional
- private PAData[] pa; // PA-DATA in eData
+ private transient PAData[] pa; // PA-DATA in eData
+
+
+ /**
+ * Restores the state of this object from the stream.
+ *
+ * @param is the {@code ObjectInputStream} from which data is read
+ * @throws IOException if an I/O error occurs
+ * @throws ClassNotFoundException if a serialized class cannot be loaded
+ */
+ @java.io.Serial
private void readObject(ObjectInputStream is)
throws IOException, ClassNotFoundException {
try {
diff --git a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Key.java b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Key.java
index d528f1b8485..49718e254b3 100644
--- a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Key.java
+++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Key.java
@@ -240,6 +240,19 @@ abstract class P11Key implements Key, Length {
return new KeyRep(type, getAlgorithm(), format, getEncodedInternal());
}
+ /**
+ * Restores the state of this object from the stream.
+ *
+ * @param stream the {@code ObjectInputStream} from which data is read
+ * @throws IOException if an I/O error occurs
+ * @throws ClassNotFoundException if a serialized class cannot be loaded
+ */
+ @java.io.Serial
+ private void readObject(ObjectInputStream stream)
+ throws IOException, ClassNotFoundException {
+ throw new InvalidObjectException("P11Key not directly deserializable");
+ }
+
public String toString() {
token.ensureValid();
String s1 = token.provider.getName() + " " + algorithm + " " + type
diff --git a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11SecureRandom.java b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11SecureRandom.java
index 70effc141bc..7ef8510ddee 100644
--- a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11SecureRandom.java
+++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11SecureRandom.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2024, 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
@@ -187,9 +187,23 @@ final class P11SecureRandom extends SecureRandomSpi {
}
}
+ /**
+ * Restores the state of this object from the stream.
+ *
+ * @param in the {@code ObjectInputStream} from which data is read
+ * @throws IOException if an I/O error occurs
+ * @throws ClassNotFoundException if a serialized class cannot be loaded
+ */
+ @java.io.Serial
private void readObject(ObjectInputStream in)
throws IOException, ClassNotFoundException {
in.defaultReadObject();
+ if (token == null) {
+ throw new InvalidObjectException("token is null");
+ }
+ if (mixBuffer != null) {
+ mixBuffer = mixBuffer.clone();
+ }
// assign default values to non-null transient fields
iBuffer = new byte[IBUFFER_SIZE];
ibuffered = 0;
diff --git a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/SunPKCS11.java b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/SunPKCS11.java
index 44a2c4efb06..e77edc98399 100644
--- a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/SunPKCS11.java
+++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/SunPKCS11.java
@@ -1947,6 +1947,19 @@ public final class SunPKCS11 extends AuthProvider {
return new SunPKCS11Rep(this);
}
+ /**
+ * Restores the state of this object from the stream.
+ *
+ * @param stream the {@code ObjectInputStream} from which data is read
+ * @throws IOException if an I/O error occurs
+ * @throws ClassNotFoundException if a serialized class cannot be loaded
+ */
+ @java.io.Serial
+ private void readObject(ObjectInputStream stream)
+ throws IOException, ClassNotFoundException {
+ throw new InvalidObjectException("SunPKCS11 not directly deserializable");
+ }
+
/**
* Serialized representation of the SunPKCS11 provider.
*/