1
1
/*
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.
3
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
4
*
5
5
* This code is free software; you can redistribute it and/or modify it
@@ -57,6 +57,7 @@ final class DHPrivateKey implements PrivateKey,
57
57
private BigInteger x ;
58
58
59
59
// the key bytes, without the algorithm information
60
+ // cannot be final as it's re-assigned for deserialization
60
61
private byte [] key ;
61
62
62
63
// the encoded key
@@ -71,6 +72,135 @@ final class DHPrivateKey implements PrivateKey,
71
72
// the private-value length (optional)
72
73
private int l ;
73
74
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
+
74
204
/**
75
205
* Make a DH private key out of a private value <code>x</code>, a prime
76
206
* modulus <code>p</code>, and a base generator <code>g</code>.
@@ -82,7 +212,7 @@ final class DHPrivateKey implements PrivateKey,
82
212
* @throws ProviderException if the key cannot be encoded
83
213
*/
84
214
DHPrivateKey (BigInteger x , BigInteger p , BigInteger g )
85
- throws InvalidKeyException {
215
+ throws InvalidKeyException {
86
216
this (x , p , g , 0 );
87
217
}
88
218
@@ -103,16 +233,18 @@ final class DHPrivateKey implements PrivateKey,
103
233
this .p = p ;
104
234
this .g = g ;
105
235
this .l = l ;
236
+
237
+ byte [] xbytes = x .toByteArray ();
238
+ DerValue val = new DerValue (DerValue .tag_Integer , xbytes );
106
239
try {
107
- byte [] xbytes = x .toByteArray ();
108
- DerValue val = new DerValue (DerValue .tag_Integer , xbytes );
109
240
this .key = val .toByteArray ();
110
- val .clear ();
111
- Arrays .fill (xbytes , (byte )0 );
112
- encode ();
113
241
} catch (IOException e ) {
114
242
throw new ProviderException ("Cannot produce ASN.1 encoding" , e );
243
+ } finally {
244
+ val .clear ();
245
+ Arrays .fill (xbytes , (byte ) 0 );
115
246
}
247
+ this .encodedKey = encode (p , g , l , key );
116
248
}
117
249
118
250
/**
@@ -124,71 +256,18 @@ final class DHPrivateKey implements PrivateKey,
124
256
* a Diffie-Hellman private key
125
257
*/
126
258
DHPrivateKey (byte [] encodedKey ) throws InvalidKeyException {
127
- DerValue val = null ;
259
+ this .encodedKey = encodedKey .clone ();
260
+ DHComponents dc ;
128
261
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 );
191
265
}
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 ;
192
271
}
193
272
194
273
/**
@@ -209,59 +288,9 @@ public String getAlgorithm() {
209
288
* Get the encoding of the key.
210
289
*/
211
290
public synchronized byte [] getEncoded () {
212
- encode ();
213
291
return encodedKey .clone ();
214
292
}
215
293
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
-
265
294
/**
266
295
* Returns the private value, <code>x</code>.
267
296
*
@@ -284,18 +313,6 @@ public DHParameterSpec getParams() {
284
313
}
285
314
}
286
315
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
-
299
316
/**
300
317
* Calculates a hash code value for the object.
301
318
* Objects that are equal will also have the same hashcode.
@@ -328,10 +345,7 @@ public boolean equals(Object obj) {
328
345
*/
329
346
@ java .io .Serial
330
347
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 (),
335
349
encodedKey );
336
350
}
337
351
@@ -351,11 +365,30 @@ private void readObject(ObjectInputStream stream)
351
365
if ((key == null ) || (key .length == 0 )) {
352
366
throw new InvalidObjectException ("key not deserializable" );
353
367
}
354
- this .key = key .clone ();
355
368
if ((encodedKey == null ) || (encodedKey .length == 0 )) {
356
369
throw new InvalidObjectException (
357
370
"encoded key not deserializable" );
358
371
}
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 ;
360
393
}
361
394
}
0 commit comments