8302111: Serialization considerations

Reviewed-by: skoivu, rhalade, weijun, wetmore
This commit is contained in:
Valerie Peng 2024-02-05 22:53:51 +00:00 committed by Jaikiran Pai
parent df7d6e081f
commit 369c573383
21 changed files with 747 additions and 468 deletions

View file

@ -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 <code>x</code>, a prime
* modulus <code>p</code>, and a base generator <code>g</code>.
@ -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, <code>x</code>.
*
@ -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;
}
}

View file

@ -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 <code>y</code>, a prime
* modulus <code>p</code>, and a base generator <code>g</code>.
@ -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;
}
}

View file

@ -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);
}
}
}

View file

@ -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<Class<?>, PermissionCollection> perms =
(Hashtable<Class<?>, 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);

View file

@ -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;
}
}

View file

@ -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);
}
}

View file

@ -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<String, Vector<UnresolvedPermission>>
// for the permissions key, so this cast is safe, unless the data is corrupt.
Hashtable<String, Vector<UnresolvedPermission>> permissions =
(Hashtable<String, Vector<UnresolvedPermission>>)
gfields.get("permissions", null);
perms = new ConcurrentHashMap<>(permissions.size()*2);
try {
@SuppressWarnings("unchecked")
Hashtable<String, Vector<UnresolvedPermission>> permissions =
(Hashtable<String, Vector<UnresolvedPermission>>)
gfields.get("permissions", null);
// Convert each entry (Vector) into a List
Set<Map.Entry<String, Vector<UnresolvedPermission>>> set = permissions.entrySet();
for (Map.Entry<String, Vector<UnresolvedPermission>> e : set) {
// Convert Vector into ArrayList
Vector<UnresolvedPermission> vec = e.getValue();
List<UnresolvedPermission> 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<Map.Entry<String, Vector<UnresolvedPermission>>> set = permissions.entrySet();
for (Map.Entry<String, Vector<UnresolvedPermission>> e : set) {
// Convert Vector into ArrayList
Vector<UnresolvedPermission> vec = e.getValue();
List<UnresolvedPermission> list = new CopyOnWriteArrayList<>(vec);
// Add to Hashtable being serialized
perms.put(e.getKey(), list);
}
} catch (ClassCastException cce) {
throw new InvalidObjectException("Invalid type for permissions");
}
}
}

View file

@ -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<String, Extension> extensions;
private static boolean isNull(Date revocationDate,
CRLReason reason, X500Principal authority,
Map<String, Extension> 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<String, Extension> 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++) {

View file

@ -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 <code>key</code> 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;
}
}

View file

@ -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;
}
}

View file

@ -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);
}
}
}

View file

@ -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));
}

View file

@ -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();

View file

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

View file

@ -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();
}
}