11/*
2- * Copyright (c) 1997, 2023 , Oracle and/or its affiliates. All rights reserved.
2+ * Copyright (c) 1997, 2024 , Oracle and/or its affiliates. All rights reserved.
33 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44 *
55 * This code is free software; you can redistribute it and/or modify it
@@ -57,6 +57,7 @@ final class DHPrivateKey implements PrivateKey,
5757 private BigInteger x ;
5858
5959 // the key bytes, without the algorithm information
60+ // cannot be final as it's re-assigned for deserialization
6061 private byte [] key ;
6162
6263 // the encoded key
@@ -71,6 +72,135 @@ final class DHPrivateKey implements PrivateKey,
7172 // the private-value length (optional)
7273 private int l ;
7374
75+ private static class DHComponents {
76+ final BigInteger x ;
77+ final BigInteger p ;
78+ final BigInteger g ;
79+ final int l ;
80+ final byte [] key ;
81+
82+ DHComponents (BigInteger x , BigInteger p , BigInteger g , int l ,
83+ byte [] key ) {
84+ this .x = x ;
85+ this .p = p ;
86+ this .g = g ;
87+ this .l = l ;
88+ this .key = key ;
89+ }
90+ }
91+
92+ // parses the specified encoding into a DHComponents object
93+ private static DHComponents decode (byte [] encodedKey )
94+ throws IOException {
95+ DerValue val = null ;
96+
97+ try {
98+ val = new DerValue (encodedKey );
99+ if (val .tag != DerValue .tag_Sequence ) {
100+ throw new IOException ("Key not a SEQUENCE" );
101+ }
102+
103+ // version
104+ BigInteger parsedVersion = val .data .getBigInteger ();
105+ if (!parsedVersion .equals (PKCS8_VERSION )) {
106+ throw new IOException ("version mismatch: (supported: " +
107+ PKCS8_VERSION + ", parsed: " + parsedVersion );
108+ }
109+
110+ // privateKeyAlgorithm
111+ DerValue algid = val .data .getDerValue ();
112+ if (algid .tag != DerValue .tag_Sequence ) {
113+ throw new IOException ("AlgId is not a SEQUENCE" );
114+ }
115+ DerInputStream derInStream = algid .toDerInputStream ();
116+ ObjectIdentifier oid = derInStream .getOID ();
117+ if (oid == null ) {
118+ throw new IOException ("Null OID" );
119+ }
120+ if (derInStream .available () == 0 ) {
121+ throw new IOException ("Parameters missing" );
122+ }
123+ // parse the parameters
124+ DerValue params = derInStream .getDerValue ();
125+ if (params .tag == DerValue .tag_Null ) {
126+ throw new IOException ("Null parameters" );
127+ }
128+ if (params .tag != DerValue .tag_Sequence ) {
129+ throw new IOException ("Parameters not a SEQUENCE" );
130+ }
131+ params .data .reset ();
132+ BigInteger p = params .data .getBigInteger ();
133+ BigInteger g = params .data .getBigInteger ();
134+ // Private-value length is OPTIONAL
135+ int l = (params .data .available () != 0 ?
136+ params .data .getInteger () : 0 );
137+ // should have no trailing data
138+ if (params .data .available () != 0 ) {
139+ throw new IOException ("Extra parameter data" );
140+ }
141+
142+ // privateKey
143+ byte [] key = val .data .getOctetString ();
144+ DerInputStream in = new DerInputStream (key );
145+ BigInteger x = in .getBigInteger ();
146+
147+ // should have no trailing data
148+ if (val .data .available () != 0 ) {
149+ throw new IOException ("Excess trailing data" );
150+ }
151+ return new DHComponents (x , p , g , l , key );
152+ } catch (NumberFormatException e ) {
153+ throw new IOException ("Error parsing key encoding" , e );
154+ } finally {
155+ if (val != null ) {
156+ val .clear ();
157+ }
158+ }
159+ }
160+
161+ // Generates the ASN.1 encoding
162+ private static byte [] encode (BigInteger p , BigInteger g , int l ,
163+ byte [] key ) {
164+ try {
165+ DerOutputStream tmp = new DerOutputStream ();
166+
167+ // version
168+ tmp .putInteger (PKCS8_VERSION );
169+
170+ // privateKeyAlgorithm
171+ DerOutputStream algid = new DerOutputStream ();
172+
173+ // store OID
174+ algid .putOID (DHPublicKey .DH_OID );
175+ // encode parameters
176+ DerOutputStream params = new DerOutputStream ();
177+ params .putInteger (p );
178+ params .putInteger (g );
179+ if (l != 0 ) {
180+ params .putInteger (l );
181+ }
182+ // wrap parameters into SEQUENCE
183+ DerValue paramSequence = new DerValue (DerValue .tag_Sequence ,
184+ params .toByteArray ());
185+ // store parameter SEQUENCE in algid
186+ algid .putDerValue (paramSequence );
187+ // wrap algid into SEQUENCE
188+ tmp .write (DerValue .tag_Sequence , algid );
189+
190+ // privateKey
191+ tmp .putOctetString (key );
192+
193+ // make it a SEQUENCE
194+ DerValue val = DerValue .wrap (DerValue .tag_Sequence , tmp );
195+ byte [] encoded = val .toByteArray ();
196+ val .clear ();
197+
198+ return encoded ;
199+ } catch (IOException e ) {
200+ throw new AssertionError (e );
201+ }
202+ }
203+
74204 /**
75205 * Make a DH private key out of a private value <code>x</code>, a prime
76206 * modulus <code>p</code>, and a base generator <code>g</code>.
@@ -82,7 +212,7 @@ final class DHPrivateKey implements PrivateKey,
82212 * @throws ProviderException if the key cannot be encoded
83213 */
84214 DHPrivateKey (BigInteger x , BigInteger p , BigInteger g )
85- throws InvalidKeyException {
215+ throws InvalidKeyException {
86216 this (x , p , g , 0 );
87217 }
88218
@@ -103,16 +233,18 @@ final class DHPrivateKey implements PrivateKey,
103233 this .p = p ;
104234 this .g = g ;
105235 this .l = l ;
236+
237+ byte [] xbytes = x .toByteArray ();
238+ DerValue val = new DerValue (DerValue .tag_Integer , xbytes );
106239 try {
107- byte [] xbytes = x .toByteArray ();
108- DerValue val = new DerValue (DerValue .tag_Integer , xbytes );
109240 this .key = val .toByteArray ();
110- val .clear ();
111- Arrays .fill (xbytes , (byte )0 );
112- encode ();
113241 } catch (IOException e ) {
114242 throw new ProviderException ("Cannot produce ASN.1 encoding" , e );
243+ } finally {
244+ val .clear ();
245+ Arrays .fill (xbytes , (byte ) 0 );
115246 }
247+ this .encodedKey = encode (p , g , l , key );
116248 }
117249
118250 /**
@@ -124,71 +256,18 @@ final class DHPrivateKey implements PrivateKey,
124256 * a Diffie-Hellman private key
125257 */
126258 DHPrivateKey (byte [] encodedKey ) throws InvalidKeyException {
127- DerValue val = null ;
259+ this .encodedKey = encodedKey .clone ();
260+ DHComponents dc ;
128261 try {
129- val = new DerValue (encodedKey );
130- if (val .tag != DerValue .tag_Sequence ) {
131- throw new InvalidKeyException ("Key not a SEQUENCE" );
132- }
133-
134- //
135- // version
136- //
137- BigInteger parsedVersion = val .data .getBigInteger ();
138- if (!parsedVersion .equals (PKCS8_VERSION )) {
139- throw new IOException ("version mismatch: (supported: " +
140- PKCS8_VERSION + ", parsed: " +
141- parsedVersion );
142- }
143-
144- //
145- // privateKeyAlgorithm
146- //
147- DerValue algid = val .data .getDerValue ();
148- if (algid .tag != DerValue .tag_Sequence ) {
149- throw new InvalidKeyException ("AlgId is not a SEQUENCE" );
150- }
151- DerInputStream derInStream = algid .toDerInputStream ();
152- ObjectIdentifier oid = derInStream .getOID ();
153- if (oid == null ) {
154- throw new InvalidKeyException ("Null OID" );
155- }
156- if (derInStream .available () == 0 ) {
157- throw new InvalidKeyException ("Parameters missing" );
158- }
159- // parse the parameters
160- DerValue params = derInStream .getDerValue ();
161- if (params .tag == DerValue .tag_Null ) {
162- throw new InvalidKeyException ("Null parameters" );
163- }
164- if (params .tag != DerValue .tag_Sequence ) {
165- throw new InvalidKeyException ("Parameters not a SEQUENCE" );
166- }
167- params .data .reset ();
168- this .p = params .data .getBigInteger ();
169- this .g = params .data .getBigInteger ();
170- // Private-value length is OPTIONAL
171- if (params .data .available () != 0 ) {
172- this .l = params .data .getInteger ();
173- }
174- if (params .data .available () != 0 ) {
175- throw new InvalidKeyException ("Extra parameter data" );
176- }
177-
178- //
179- // privateKey
180- //
181- this .key = val .data .getOctetString ();
182- parseKeyBits ();
183-
184- this .encodedKey = encodedKey .clone ();
185- } catch (IOException | NumberFormatException e ) {
186- throw new InvalidKeyException ("Error parsing key encoding" , e );
187- } finally {
188- if (val != null ) {
189- val .clear ();
190- }
262+ dc = decode (this .encodedKey );
263+ } catch (IOException e ) {
264+ throw new InvalidKeyException ("Invalid encoding" , e );
191265 }
266+ this .x = dc .x ;
267+ this .p = dc .p ;
268+ this .g = dc .g ;
269+ this .l = dc .l ;
270+ this .key = dc .key ;
192271 }
193272
194273 /**
@@ -209,59 +288,9 @@ public String getAlgorithm() {
209288 * Get the encoding of the key.
210289 */
211290 public synchronized byte [] getEncoded () {
212- encode ();
213291 return encodedKey .clone ();
214292 }
215293
216- /**
217- * Generate the encodedKey field if it has not been calculated.
218- * Could generate null.
219- */
220- private void encode () {
221- if (this .encodedKey == null ) {
222- try {
223- DerOutputStream tmp = new DerOutputStream ();
224-
225- //
226- // version
227- //
228- tmp .putInteger (PKCS8_VERSION );
229-
230- //
231- // privateKeyAlgorithm
232- //
233- DerOutputStream algid = new DerOutputStream ();
234-
235- // store OID
236- algid .putOID (DHPublicKey .DH_OID );
237- // encode parameters
238- DerOutputStream params = new DerOutputStream ();
239- params .putInteger (this .p );
240- params .putInteger (this .g );
241- if (this .l != 0 ) {
242- params .putInteger (this .l );
243- }
244- // wrap parameters into SEQUENCE
245- DerValue paramSequence = new DerValue (DerValue .tag_Sequence ,
246- params .toByteArray ());
247- // store parameter SEQUENCE in algid
248- algid .putDerValue (paramSequence );
249- // wrap algid into SEQUENCE
250- tmp .write (DerValue .tag_Sequence , algid );
251-
252- // privateKey
253- tmp .putOctetString (this .key );
254-
255- // make it a SEQUENCE
256- DerValue val = DerValue .wrap (DerValue .tag_Sequence , tmp );
257- this .encodedKey = val .toByteArray ();
258- val .clear ();
259- } catch (IOException e ) {
260- throw new AssertionError (e );
261- }
262- }
263- }
264-
265294 /**
266295 * Returns the private value, <code>x</code>.
267296 *
@@ -284,18 +313,6 @@ public DHParameterSpec getParams() {
284313 }
285314 }
286315
287- private void parseKeyBits () throws InvalidKeyException {
288- try {
289- DerInputStream in = new DerInputStream (this .key );
290- this .x = in .getBigInteger ();
291- } catch (IOException e ) {
292- InvalidKeyException ike = new InvalidKeyException (
293- "Error parsing key encoding: " + e .getMessage ());
294- ike .initCause (e );
295- throw ike ;
296- }
297- }
298-
299316 /**
300317 * Calculates a hash code value for the object.
301318 * Objects that are equal will also have the same hashcode.
@@ -328,10 +345,7 @@ public boolean equals(Object obj) {
328345 */
329346 @ java .io .Serial
330347 private Object writeReplace () throws java .io .ObjectStreamException {
331- encode ();
332- return new KeyRep (KeyRep .Type .PRIVATE ,
333- getAlgorithm (),
334- getFormat (),
348+ return new KeyRep (KeyRep .Type .PRIVATE , getAlgorithm (), getFormat (),
335349 encodedKey );
336350 }
337351
@@ -351,11 +365,30 @@ private void readObject(ObjectInputStream stream)
351365 if ((key == null ) || (key .length == 0 )) {
352366 throw new InvalidObjectException ("key not deserializable" );
353367 }
354- this .key = key .clone ();
355368 if ((encodedKey == null ) || (encodedKey .length == 0 )) {
356369 throw new InvalidObjectException (
357370 "encoded key not deserializable" );
358371 }
359- this .encodedKey = encodedKey .clone ();
372+ // check if the "encodedKey" value matches the deserialized fields
373+ DHComponents c ;
374+ byte [] encodedKeyIntern = encodedKey .clone ();
375+ try {
376+ c = decode (encodedKeyIntern );
377+ } catch (IOException e ) {
378+ InvalidObjectException ioe = new InvalidObjectException ("Invalid encoding" );
379+ ioe .initCause (e );
380+ throw ioe ;
381+ }
382+ if (!Arrays .equals (c .key , key ) || !c .x .equals (x ) || !c .p .equals (p )
383+ || !c .g .equals (g ) || c .l != l ) {
384+ throw new InvalidObjectException (
385+ "encoded key not matching internal fields" );
386+ }
387+ // zero out external arrays
388+ Arrays .fill (key , (byte )0x00 );
389+ Arrays .fill (encodedKey , (byte )0x00 );
390+ // use self-created internal copies
391+ this .key = c .key ;
392+ this .encodedKey = encodedKeyIntern ;
360393 }
361394}
0 commit comments