JDK-6536046 : Serialization and javax.security interface classes (e.g. PublicKey)
  • Type: Enhancement
  • Component: security-libs
  • Sub-Component: java.security
  • Affected Version: 6
  • Priority: P5
  • Status: Closed
  • Resolution: Duplicate
  • OS: windows_xp
  • CPU: x86
  • Submitted: 2007-03-19
  • Updated: 2010-04-04
  • Resolved: 2007-03-20
Related Reports
Duplicate :  
Description
A DESCRIPTION OF THE REQUEST :
Request for clarification on documentations of Key and Certificate objects generated by Security Providers are not serializable.

For example, even though most KeyFactory actually return intances of PublicKey, the class being return is part of the actual implementation class, and thus are not guranteed to stay the same across the different JDK releases.

I think a notice in the Javadoc about serialization should be included in these security artifacts interfaces (e.g. java.security.PublicKey)


JUSTIFICATION :
The PublicKey extends serializable interface, so they expected that instances of the PublicKey can be serialize and being mislead to believe that theses implementation classes have the general JDK serialization contract: if you serialize a JDK classes they should be compatible across different release, just like serializing an ArrayList.

We had seen a few situation which a user using RMI on a 1.4.2_05 attempted to communicate to a client using 1.4.2, they get this error:

java.io.InvalidClassException: COM.rsa.jsafe.SunJSSE_dr; local class incompatible: stream classdesc serialVersionUID = -8679601579857181180, local class serialVersionUID = -7264885549576920566

In fact if you do exactly the same thing with security classes in 1.4 and deserialize them in 1.6 you get stream corruption error.


EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
If we serialize an instance of object that implements javas.security.PublicKey with one version of JDK then they should  be able deserialize the object in a newer version of the JDK
ACTUAL -
prompt>c:\jdk1.4.2\bin\java -classpath . PublicKeySerialization -serialize pubk
ey.ser
Java version = 1.4.2
  Public Key = SunJSSE RSA public key:
  public exponent:
    010001
  modulus:
    b24a9b5b ba01c0cd 65096370 0b5a1b92 08f8555e 7c1b5017 ec444c58 422b4109
    59f2e15d 43714d92 031db66c 7f5d48cd 17ecd74c 39b17be2 bf9677be d0a0f02d
    6b24aa14 ba827910 9b166847 8154a2fa 919e0a2a 53a6e79e 7d2933d8 05fc023f
    bdc76eed aa306c5f 52ed3565 4b0ec8a7 12105637 af11fa21 0e99fffa 8c658e6d
  Public Key class: com.sun.net.ssl.internal.ssl.JSA_RSAPublicKey

prompt>c:\jdk1.6.0\bin\java -classpath . PublicKeySerialization -deserialize pub
key.ser
Object comes from: 1.4.2
Exception in thread "main" java.lang.ClassNotFoundException: com.sun.net.ssl.int
ernal.ssl.JSA_RSAPublicKey
        at java.net.URLClassLoader$1.run(URLClassLoader.java:200)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.net.URLClassLoader.findClass(URLClassLoader.java:188)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
        at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:276)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:251)
        at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:319)
        at java.lang.Class.forName0(Native Method)
        at java.lang.Class.forName(Class.java:247)
        at java.io.ObjectInputStream.resolveClass(ObjectInputStream.java:604)
        at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:157
5)
        at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1496)
        at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1
732)
        at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1329)
        at java.io.ObjectInputStream.readObject(ObjectInputStream.java:351)
        at PublicKeySerialization.DeSerializePublicKey(PublicKeySerialization.ja
va:43)
        at PublicKeySerialization.main(PublicKeySerialization.java:68)


---------- BEGIN SOURCE ----------
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.spec.InvalidKeySpecException;

public class PublicKeySerialization {

	private static void usage() {
		System.out.println("Usage: " + PublicKeySerialization.class.getName()
				+ " [options] <filename>");
		System.out.println(" where option:");
		System.out.println(" -serialize Serialize a key");
		System.out.println(" -deserialize deserialize a key");
	}

	public static void SerializePublicKey(OutputStream os, PublicKey key)
			throws IOException {
		ObjectOutputStream oos = new ObjectOutputStream(os);
		oos.writeObject(System.getProperty("java.version"));
		oos.writeObject(key);
		oos.close();
	}

	public static PublicKey DeSerializePublicKey(InputStream is)
			throws IOException, ClassNotFoundException, NoSuchAlgorithmException, InvalidKeySpecException {
		ObjectInputStream ois = new ObjectInputStream(is);
		System.out.println("Object comes from: " + ois.readObject());
		PublicKey result = (PublicKey) ois.readObject();
		ois.close();
		return result;
	}

	public static void main(String[] args) throws Exception {
		if (args.length < 2) {
			usage();
			System.exit(1);
		}

		if ("-serialize".equals(args[0])) {
			PublicKey pubKey = KeyPairGenerator.getInstance("RSA").generateKeyPair().getPublic();
			System.out.println("Java version = "
					+ System.getProperty("java.version"));
			System.out.println("Public Key = "+pubKey);
			FileOutputStream fos = new FileOutputStream(new File(args[1]));
			SerializePublicKey(fos, pubKey);
			System.out.println("Public Key class: "+pubKey.getClass().getName());
			fos.close();
			System.exit(0);
		}

		if ("-deserialize".equals(args[0])) {
			FileInputStream fis = new FileInputStream(new File(args[1]));
			PublicKey pubKey = DeSerializePublicKey(fis);
			System.out.println("Current JDK version:"
					+ System.getProperty("java.version"));
			System.out.println("Public Key = "+pubKey);
			fis.close();
			System.exit(0);
		}
	}
}

---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
The right practise is to transmit these security artifacts using an encoded form (e.g key.getEncoded()) rather than serialized these objects.

Comments
EVALUATION Duplicate of 4532506.
20-03-2007