Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/security/pkcs/PKCS8Key.java
38830 views
1
/*
2
* Copyright (c) 1996, 2017, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation. Oracle designates this
8
* particular file as subject to the "Classpath" exception as provided
9
* by Oracle in the LICENSE file that accompanied this code.
10
*
11
* This code is distributed in the hope that it will be useful, but WITHOUT
12
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14
* version 2 for more details (a copy is included in the LICENSE file that
15
* accompanied this code).
16
*
17
* You should have received a copy of the GNU General Public License version
18
* 2 along with this work; if not, write to the Free Software Foundation,
19
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20
*
21
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22
* or visit www.oracle.com if you need additional information or have any
23
* questions.
24
*/
25
26
package sun.security.pkcs;
27
28
import java.io.*;
29
import java.util.Properties;
30
import java.math.*;
31
import java.security.Key;
32
import java.security.KeyRep;
33
import java.security.PrivateKey;
34
import java.security.KeyFactory;
35
import java.security.MessageDigest;
36
import java.security.Security;
37
import java.security.Provider;
38
import java.security.InvalidKeyException;
39
import java.security.NoSuchAlgorithmException;
40
import java.security.spec.InvalidKeySpecException;
41
import java.security.spec.PKCS8EncodedKeySpec;
42
43
import sun.misc.HexDumpEncoder;
44
import sun.security.x509.*;
45
import sun.security.util.*;
46
47
/**
48
* Holds a PKCS#8 key, for example a private key
49
*
50
* @author Dave Brownell
51
* @author Benjamin Renaud
52
*/
53
public class PKCS8Key implements PrivateKey {
54
55
/** use serialVersionUID from JDK 1.1. for interoperability */
56
private static final long serialVersionUID = -3836890099307167124L;
57
58
/* The algorithm information (name, parameters, etc). */
59
protected AlgorithmId algid;
60
61
/* The key bytes, without the algorithm information */
62
protected byte[] key;
63
64
/* The encoded for the key. */
65
protected byte[] encodedKey;
66
67
/* The version for this key */
68
public static final BigInteger version = BigInteger.ZERO;
69
70
/**
71
* Default constructor. The key constructed must have its key
72
* and algorithm initialized before it may be used, for example
73
* by using <code>decode</code>.
74
*/
75
public PKCS8Key() { }
76
77
/*
78
* Build and initialize as a "default" key. All PKCS#8 key
79
* data is stored and transmitted losslessly, but no knowledge
80
* about this particular algorithm is available.
81
*/
82
private PKCS8Key (AlgorithmId algid, byte key [])
83
throws InvalidKeyException {
84
this.algid = algid;
85
this.key = key;
86
encode();
87
}
88
89
/*
90
* Binary backwards compatibility. New uses should call parseKey().
91
*/
92
public static PKCS8Key parse (DerValue in) throws IOException {
93
PrivateKey key;
94
95
key = parseKey(in);
96
if (key instanceof PKCS8Key)
97
return (PKCS8Key)key;
98
99
throw new IOException("Provider did not return PKCS8Key");
100
}
101
102
/**
103
* Construct PKCS#8 subject public key from a DER value. If
104
* the runtime environment is configured with a specific class for
105
* this kind of key, a subclass is returned. Otherwise, a generic
106
* PKCS8Key object is returned.
107
*
108
* <P>This mechanism gurantees that keys (and algorithms) may be
109
* freely manipulated and transferred, without risk of losing
110
* information. Also, when a key (or algorithm) needs some special
111
* handling, that specific need can be accomodated.
112
*
113
* @param in the DER-encoded SubjectPublicKeyInfo value
114
* @exception IOException on data format errors
115
*/
116
public static PrivateKey parseKey (DerValue in) throws IOException
117
{
118
AlgorithmId algorithm;
119
PrivateKey privKey;
120
121
if (in.tag != DerValue.tag_Sequence)
122
throw new IOException ("corrupt private key");
123
124
BigInteger parsedVersion = in.data.getBigInteger();
125
if (!version.equals(parsedVersion)) {
126
throw new IOException("version mismatch: (supported: " +
127
Debug.toHexString(version) +
128
", parsed: " +
129
Debug.toHexString(parsedVersion));
130
}
131
132
algorithm = AlgorithmId.parse (in.data.getDerValue ());
133
134
try {
135
privKey = buildPKCS8Key (algorithm, in.data.getOctetString ());
136
137
} catch (InvalidKeyException e) {
138
throw new IOException("corrupt private key");
139
}
140
141
if (in.data.available () != 0)
142
throw new IOException ("excess private key");
143
return privKey;
144
}
145
146
/**
147
* Parse the key bits. This may be redefined by subclasses to take
148
* advantage of structure within the key. For example, RSA public
149
* keys encapsulate two unsigned integers (modulus and exponent) as
150
* DER values within the <code>key</code> bits; Diffie-Hellman and
151
* DSS/DSA keys encapsulate a single unsigned integer.
152
*
153
* <P>This function is called when creating PKCS#8 SubjectPublicKeyInfo
154
* values using the PKCS8Key member functions, such as <code>parse</code>
155
* and <code>decode</code>.
156
*
157
* @exception IOException if a parsing error occurs.
158
* @exception InvalidKeyException if the key encoding is invalid.
159
*/
160
protected void parseKeyBits () throws IOException, InvalidKeyException {
161
encode();
162
}
163
164
/*
165
* Factory interface, building the kind of key associated with this
166
* specific algorithm ID or else returning this generic base class.
167
* See the description above.
168
*/
169
static PrivateKey buildPKCS8Key (AlgorithmId algid, byte[] key)
170
throws IOException, InvalidKeyException
171
{
172
/*
173
* Use the algid and key parameters to produce the ASN.1 encoding
174
* of the key, which will then be used as the input to the
175
* key factory.
176
*/
177
DerOutputStream pkcs8EncodedKeyStream = new DerOutputStream();
178
encode(pkcs8EncodedKeyStream, algid, key);
179
PKCS8EncodedKeySpec pkcs8KeySpec
180
= new PKCS8EncodedKeySpec(pkcs8EncodedKeyStream.toByteArray());
181
182
try {
183
// Instantiate the key factory of the appropriate algorithm
184
KeyFactory keyFac = KeyFactory.getInstance(algid.getName());
185
186
// Generate the private key
187
return keyFac.generatePrivate(pkcs8KeySpec);
188
} catch (NoSuchAlgorithmException e) {
189
// Return generic PKCS8Key with opaque key data (see below)
190
} catch (InvalidKeySpecException e) {
191
// Return generic PKCS8Key with opaque key data (see below)
192
}
193
194
/*
195
* Try again using JDK1.1-style for backwards compatibility.
196
*/
197
String classname = "";
198
try {
199
Properties props;
200
String keytype;
201
Provider sunProvider;
202
203
sunProvider = Security.getProvider("SUN");
204
if (sunProvider == null)
205
throw new InstantiationException();
206
classname = sunProvider.getProperty("PrivateKey.PKCS#8." +
207
algid.getName());
208
if (classname == null) {
209
throw new InstantiationException();
210
}
211
212
Class<?> keyClass = null;
213
try {
214
keyClass = Class.forName(classname);
215
} catch (ClassNotFoundException e) {
216
ClassLoader cl = ClassLoader.getSystemClassLoader();
217
if (cl != null) {
218
keyClass = cl.loadClass(classname);
219
}
220
}
221
222
Object inst = null;
223
PKCS8Key result;
224
225
if (keyClass != null)
226
inst = keyClass.newInstance();
227
if (inst instanceof PKCS8Key) {
228
result = (PKCS8Key) inst;
229
result.algid = algid;
230
result.key = key;
231
result.parseKeyBits();
232
return result;
233
}
234
} catch (ClassNotFoundException e) {
235
} catch (InstantiationException e) {
236
} catch (IllegalAccessException e) {
237
// this should not happen.
238
throw new IOException (classname + " [internal error]");
239
}
240
241
PKCS8Key result = new PKCS8Key();
242
result.algid = algid;
243
result.key = key;
244
return result;
245
}
246
247
/**
248
* Returns the algorithm to be used with this key.
249
*/
250
public String getAlgorithm() {
251
return algid.getName();
252
}
253
254
/**
255
* Returns the algorithm ID to be used with this key.
256
*/
257
public AlgorithmId getAlgorithmId () { return algid; }
258
259
/**
260
* PKCS#8 sequence on the DER output stream.
261
*/
262
public final void encode(DerOutputStream out) throws IOException
263
{
264
encode(out, this.algid, this.key);
265
}
266
267
/**
268
* Returns the DER-encoded form of the key as a byte array.
269
*/
270
public synchronized byte[] getEncoded() {
271
byte[] result = null;
272
try {
273
result = encode();
274
} catch (InvalidKeyException e) {
275
}
276
return result;
277
}
278
279
/**
280
* Returns the format for this key: "PKCS#8"
281
*/
282
public String getFormat() {
283
return "PKCS#8";
284
}
285
286
/**
287
* Returns the DER-encoded form of the key as a byte array.
288
*
289
* @exception InvalidKeyException if an encoding error occurs.
290
*/
291
public byte[] encode() throws InvalidKeyException {
292
if (encodedKey == null) {
293
try {
294
DerOutputStream out;
295
296
out = new DerOutputStream ();
297
encode (out);
298
encodedKey = out.toByteArray();
299
300
} catch (IOException e) {
301
throw new InvalidKeyException ("IOException : " +
302
e.getMessage());
303
}
304
}
305
return encodedKey.clone();
306
}
307
308
/**
309
* Initialize an PKCS8Key object from an input stream. The data
310
* on that input stream must be encoded using DER, obeying the
311
* PKCS#8 format: a sequence consisting of a version, an algorithm
312
* ID and a bit string which holds the key. (That bit string is
313
* often used to encapsulate another DER encoded sequence.)
314
*
315
* <P>Subclasses should not normally redefine this method; they should
316
* instead provide a <code>parseKeyBits</code> method to parse any
317
* fields inside the <code>key</code> member.
318
*
319
* @param in an input stream with a DER-encoded PKCS#8
320
* SubjectPublicKeyInfo value
321
*
322
* @exception InvalidKeyException if a parsing error occurs.
323
*/
324
public void decode(InputStream in) throws InvalidKeyException
325
{
326
DerValue val;
327
328
try {
329
val = new DerValue (in);
330
if (val.tag != DerValue.tag_Sequence)
331
throw new InvalidKeyException ("invalid key format");
332
333
334
BigInteger version = val.data.getBigInteger();
335
if (!version.equals(PKCS8Key.version)) {
336
throw new IOException("version mismatch: (supported: " +
337
Debug.toHexString(PKCS8Key.version) +
338
", parsed: " +
339
Debug.toHexString(version));
340
}
341
algid = AlgorithmId.parse (val.data.getDerValue ());
342
key = val.data.getOctetString ();
343
parseKeyBits ();
344
345
if (val.data.available () != 0) {
346
// OPTIONAL attributes not supported yet
347
}
348
349
} catch (IOException e) {
350
throw new InvalidKeyException("IOException : " +
351
e.getMessage());
352
}
353
}
354
355
public void decode(byte[] encodedKey) throws InvalidKeyException {
356
decode(new ByteArrayInputStream(encodedKey));
357
}
358
359
protected Object writeReplace() throws java.io.ObjectStreamException {
360
return new KeyRep(KeyRep.Type.PRIVATE,
361
getAlgorithm(),
362
getFormat(),
363
getEncoded());
364
}
365
366
/**
367
* Serialization read ... PKCS#8 keys serialize as
368
* themselves, and they're parsed when they get read back.
369
*/
370
private void readObject (ObjectInputStream stream)
371
throws IOException {
372
373
try {
374
decode(stream);
375
376
} catch (InvalidKeyException e) {
377
e.printStackTrace();
378
throw new IOException("deserialized key is invalid: " +
379
e.getMessage());
380
}
381
}
382
383
/*
384
* Produce PKCS#8 encoding from algorithm id and key material.
385
*/
386
static void encode(DerOutputStream out, AlgorithmId algid, byte[] key)
387
throws IOException {
388
DerOutputStream tmp = new DerOutputStream();
389
tmp.putInteger(version);
390
algid.encode(tmp);
391
tmp.putOctetString(key);
392
out.write(DerValue.tag_Sequence, tmp);
393
}
394
395
/**
396
* Compares two private keys. This returns false if the object with which
397
* to compare is not of type <code>Key</code>.
398
* Otherwise, the encoding of this key object is compared with the
399
* encoding of the given key object.
400
*
401
* @param object the object with which to compare
402
* @return <code>true</code> if this key has the same encoding as the
403
* object argument; <code>false</code> otherwise.
404
*/
405
public boolean equals(Object object) {
406
if (this == object) {
407
return true;
408
}
409
410
if (object instanceof Key) {
411
412
// this encoding
413
byte[] b1;
414
if (encodedKey != null) {
415
b1 = encodedKey;
416
} else {
417
b1 = getEncoded();
418
}
419
420
// that encoding
421
byte[] b2 = ((Key)object).getEncoded();
422
423
// time-constant comparison
424
return MessageDigest.isEqual(b1, b2);
425
}
426
return false;
427
}
428
429
/**
430
* Calculates a hash code value for this object. Objects
431
* which are equal will also have the same hashcode.
432
*/
433
public int hashCode() {
434
int retval = 0;
435
byte[] b1 = getEncoded();
436
437
for (int i = 1; i < b1.length; i++) {
438
retval += b1[i] * i;
439
}
440
return(retval);
441
}
442
}
443
444