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/pkcs11/P11Key.java
38919 views
1
/*
2
* Copyright (c) 2003, 2020, 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.pkcs11;
27
28
import java.io.*;
29
import java.lang.ref.*;
30
import java.math.BigInteger;
31
import java.util.*;
32
import java.security.*;
33
import java.security.interfaces.*;
34
import java.security.spec.*;
35
36
import javax.crypto.*;
37
import javax.crypto.interfaces.*;
38
import javax.crypto.spec.*;
39
40
import sun.security.rsa.RSAUtil.KeyType;
41
import sun.security.rsa.RSAPublicKeyImpl;
42
import sun.security.rsa.RSAPrivateCrtKeyImpl;
43
44
import sun.security.internal.interfaces.TlsMasterSecret;
45
46
import sun.security.pkcs11.wrapper.*;
47
48
import static sun.security.pkcs11.TemplateManager.O_GENERATE;
49
import static sun.security.pkcs11.wrapper.PKCS11Constants.*;
50
51
import sun.security.util.DerValue;
52
import sun.security.util.Length;
53
54
import sun.security.jca.JCAUtil;
55
56
/**
57
* Key implementation classes.
58
*
59
* In PKCS#11, the components of private and secret keys may or may not
60
* be accessible. If they are, we use the algorithm specific key classes
61
* (e.g. DSAPrivateKey) for compatibility with existing applications.
62
* If the components are not accessible, we use a generic class that
63
* only implements PrivateKey (or SecretKey). Whether the components of a
64
* key are extractable is automatically determined when the key object is
65
* created.
66
*
67
* @author Andreas Sterbenz
68
* @since 1.5
69
*/
70
abstract class P11Key implements Key, Length {
71
72
private static final long serialVersionUID = -2575874101938349339L;
73
74
private final static String PUBLIC = "public";
75
private final static String PRIVATE = "private";
76
private final static String SECRET = "secret";
77
78
// type of key, one of (PUBLIC, PRIVATE, SECRET)
79
final String type;
80
81
// token instance
82
final Token token;
83
84
// algorithm name, returned by getAlgorithm(), etc.
85
final String algorithm;
86
87
// effective key length of the key, e.g. 56 for a DES key
88
final int keyLength;
89
90
// flags indicating whether the key is a token object, sensitive, extractable
91
final boolean tokenObject, sensitive, extractable;
92
93
private final NativeKeyHolder keyIDHolder;
94
95
private static final boolean DISABLE_NATIVE_KEYS_EXTRACTION;
96
97
/**
98
* {@systemProperty sun.security.pkcs11.disableKeyExtraction} property
99
* indicating whether or not cryptographic keys within tokens are
100
* extracted to a Java byte array for memory management purposes.
101
*
102
* Key extraction affects NSS PKCS11 library only.
103
*
104
*/
105
static {
106
PrivilegedAction<String> getKeyExtractionProp =
107
() -> System.getProperty(
108
"sun.security.pkcs11.disableKeyExtraction", "false");
109
String disableKeyExtraction =
110
AccessController.doPrivileged(getKeyExtractionProp);
111
DISABLE_NATIVE_KEYS_EXTRACTION =
112
"true".equalsIgnoreCase(disableKeyExtraction);
113
}
114
115
P11Key(String type, Session session, long keyID, String algorithm,
116
int keyLength, CK_ATTRIBUTE[] attributes) {
117
this.type = type;
118
this.token = session.token;
119
this.algorithm = algorithm;
120
this.keyLength = keyLength;
121
boolean tokenObject = false;
122
boolean sensitive = false;
123
boolean extractable = true;
124
int n = (attributes == null) ? 0 : attributes.length;
125
for (int i = 0; i < n; i++) {
126
CK_ATTRIBUTE attr = attributes[i];
127
if (attr.type == CKA_TOKEN) {
128
tokenObject = attr.getBoolean();
129
} else if (attr.type == CKA_SENSITIVE) {
130
sensitive = attr.getBoolean();
131
} else if (attr.type == CKA_EXTRACTABLE) {
132
extractable = attr.getBoolean();
133
}
134
}
135
this.tokenObject = tokenObject;
136
this.sensitive = sensitive;
137
this.extractable = extractable;
138
char[] tokenLabel = this.token.tokenInfo.label;
139
boolean isNSS = (tokenLabel[0] == 'N' && tokenLabel[1] == 'S'
140
&& tokenLabel[2] == 'S');
141
boolean extractKeyInfo = (!DISABLE_NATIVE_KEYS_EXTRACTION && isNSS &&
142
extractable && !tokenObject);
143
this.keyIDHolder = new NativeKeyHolder(this, keyID, session, extractKeyInfo,
144
tokenObject);
145
}
146
147
public long getKeyID() {
148
return keyIDHolder.getKeyID();
149
}
150
151
public void releaseKeyID() {
152
keyIDHolder.releaseKeyID();
153
}
154
155
// see JCA spec
156
public final String getAlgorithm() {
157
token.ensureValid();
158
return algorithm;
159
}
160
161
// see JCA spec
162
public final byte[] getEncoded() {
163
byte[] b = getEncodedInternal();
164
return (b == null) ? null : b.clone();
165
}
166
167
abstract byte[] getEncodedInternal();
168
169
public boolean equals(Object obj) {
170
if (this == obj) {
171
return true;
172
}
173
// equals() should never throw exceptions
174
if (token.isValid() == false) {
175
return false;
176
}
177
if (obj instanceof Key == false) {
178
return false;
179
}
180
String thisFormat = getFormat();
181
if (thisFormat == null) {
182
// no encoding, key only equal to itself
183
// XXX getEncoded() for unextractable keys will change that
184
return false;
185
}
186
Key other = (Key)obj;
187
if (thisFormat.equals(other.getFormat()) == false) {
188
return false;
189
}
190
byte[] thisEnc = this.getEncodedInternal();
191
byte[] otherEnc;
192
if (obj instanceof P11Key) {
193
otherEnc = ((P11Key)other).getEncodedInternal();
194
} else {
195
otherEnc = other.getEncoded();
196
}
197
return MessageDigest.isEqual(thisEnc, otherEnc);
198
}
199
200
public int hashCode() {
201
// hashCode() should never throw exceptions
202
if (token.isValid() == false) {
203
return 0;
204
}
205
byte[] b1 = getEncodedInternal();
206
if (b1 == null) {
207
return 0;
208
}
209
int r = b1.length;
210
for (int i = 0; i < b1.length; i++) {
211
r += (b1[i] & 0xff) * 37;
212
}
213
return r;
214
}
215
216
protected Object writeReplace() throws ObjectStreamException {
217
KeyRep.Type type;
218
String format = getFormat();
219
if (isPrivate() && "PKCS#8".equals(format)) {
220
type = KeyRep.Type.PRIVATE;
221
} else if (isPublic() && "X.509".equals(format)) {
222
type = KeyRep.Type.PUBLIC;
223
} else if (isSecret() && "RAW".equals(format)) {
224
type = KeyRep.Type.SECRET;
225
} else {
226
// XXX short term serialization for unextractable keys
227
throw new NotSerializableException
228
("Cannot serialize sensitive and unextractable keys");
229
}
230
return new KeyRep(type, getAlgorithm(), format, getEncoded());
231
}
232
233
public String toString() {
234
token.ensureValid();
235
String s1 = token.provider.getName() + " " + algorithm + " " + type
236
+ " key, " + keyLength + " bits";
237
s1 += (tokenObject ? "token" : "session") + " object";
238
if (isPublic()) {
239
s1 += ")";
240
} else {
241
s1 += ", " + (sensitive ? "" : "not ") + "sensitive";
242
s1 += ", " + (extractable ? "" : "un") + "extractable)";
243
}
244
return s1;
245
}
246
247
/**
248
* Return bit length of the key.
249
*/
250
@Override
251
public int length() {
252
return keyLength;
253
}
254
255
boolean isPublic() {
256
return type == PUBLIC;
257
}
258
259
boolean isPrivate() {
260
return type == PRIVATE;
261
}
262
263
boolean isSecret() {
264
return type == SECRET;
265
}
266
267
void fetchAttributes(CK_ATTRIBUTE[] attributes) {
268
Session tempSession = null;
269
long keyID = this.getKeyID();
270
try {
271
tempSession = token.getOpSession();
272
token.p11.C_GetAttributeValue(tempSession.id(), keyID,
273
attributes);
274
} catch (PKCS11Exception e) {
275
throw new ProviderException(e);
276
} finally {
277
this.releaseKeyID();
278
token.releaseSession(tempSession);
279
}
280
}
281
282
private final static CK_ATTRIBUTE[] A0 = new CK_ATTRIBUTE[0];
283
284
private static CK_ATTRIBUTE[] getAttributes(Session session, long keyID,
285
CK_ATTRIBUTE[] knownAttributes, CK_ATTRIBUTE[] desiredAttributes) {
286
if (knownAttributes == null) {
287
knownAttributes = A0;
288
}
289
for (int i = 0; i < desiredAttributes.length; i++) {
290
// For each desired attribute, check to see if we have the value
291
// available already. If everything is here, we save a native call.
292
CK_ATTRIBUTE attr = desiredAttributes[i];
293
for (CK_ATTRIBUTE known : knownAttributes) {
294
if ((attr.type == known.type) && (known.pValue != null)) {
295
attr.pValue = known.pValue;
296
break; // break inner for loop
297
}
298
}
299
if (attr.pValue == null) {
300
// nothing found, need to call C_GetAttributeValue()
301
for (int j = 0; j < i; j++) {
302
// clear values copied from knownAttributes
303
desiredAttributes[j].pValue = null;
304
}
305
try {
306
session.token.p11.C_GetAttributeValue
307
(session.id(), keyID, desiredAttributes);
308
} catch (PKCS11Exception e) {
309
throw new ProviderException(e);
310
}
311
break; // break loop, goto return
312
}
313
}
314
return desiredAttributes;
315
}
316
317
static SecretKey secretKey(Session session, long keyID, String algorithm,
318
int keyLength, CK_ATTRIBUTE[] attributes) {
319
attributes = getAttributes(session, keyID, attributes, new CK_ATTRIBUTE[] {
320
new CK_ATTRIBUTE(CKA_TOKEN),
321
new CK_ATTRIBUTE(CKA_SENSITIVE),
322
new CK_ATTRIBUTE(CKA_EXTRACTABLE),
323
});
324
return new P11SecretKey(session, keyID, algorithm, keyLength,
325
attributes);
326
}
327
328
static SecretKey masterSecretKey(Session session, long keyID, String algorithm,
329
int keyLength, CK_ATTRIBUTE[] attributes, int major, int minor) {
330
attributes = getAttributes(session, keyID, attributes, new CK_ATTRIBUTE[] {
331
new CK_ATTRIBUTE(CKA_TOKEN),
332
new CK_ATTRIBUTE(CKA_SENSITIVE),
333
new CK_ATTRIBUTE(CKA_EXTRACTABLE),
334
});
335
return new P11TlsMasterSecretKey(
336
session, keyID, algorithm, keyLength, attributes, major,
337
minor);
338
}
339
340
// we assume that all components of public keys are always accessible
341
static PublicKey publicKey(Session session, long keyID, String algorithm,
342
int keyLength, CK_ATTRIBUTE[] attributes) {
343
switch (algorithm) {
344
case "RSA":
345
return new P11RSAPublicKey(session, keyID, algorithm,
346
keyLength, attributes);
347
case "DSA":
348
return new P11DSAPublicKey(session, keyID, algorithm,
349
keyLength, attributes);
350
case "DH":
351
return new P11DHPublicKey(session, keyID, algorithm,
352
keyLength, attributes);
353
case "EC":
354
return new P11ECPublicKey(session, keyID, algorithm,
355
keyLength, attributes);
356
default:
357
throw new ProviderException
358
("Unknown public key algorithm " + algorithm);
359
}
360
}
361
362
static PrivateKey privateKey(Session session, long keyID, String algorithm,
363
int keyLength, CK_ATTRIBUTE[] attributes) {
364
attributes = getAttributes(session, keyID, attributes, new CK_ATTRIBUTE[] {
365
new CK_ATTRIBUTE(CKA_TOKEN),
366
new CK_ATTRIBUTE(CKA_SENSITIVE),
367
new CK_ATTRIBUTE(CKA_EXTRACTABLE),
368
});
369
if (attributes[1].getBoolean() || (attributes[2].getBoolean() == false)) {
370
return new P11PrivateKey
371
(session, keyID, algorithm, keyLength, attributes);
372
} else {
373
switch (algorithm) {
374
case "RSA":
375
// XXX better test for RSA CRT keys (single getAttributes() call)
376
// we need to determine whether this is a CRT key
377
// see if we can obtain the public exponent
378
// this should also be readable for sensitive/extractable keys
379
CK_ATTRIBUTE[] attrs2 = new CK_ATTRIBUTE[] {
380
new CK_ATTRIBUTE(CKA_PUBLIC_EXPONENT),
381
};
382
boolean crtKey;
383
try {
384
session.token.p11.C_GetAttributeValue
385
(session.id(), keyID, attrs2);
386
crtKey = (attrs2[0].pValue instanceof byte[]);
387
} catch (PKCS11Exception e) {
388
// ignore, assume not available
389
crtKey = false;
390
}
391
if (crtKey) {
392
return new P11RSAPrivateKey(session, keyID, algorithm,
393
keyLength, attributes);
394
} else {
395
return new P11RSAPrivateNonCRTKey(session, keyID,
396
algorithm, keyLength, attributes);
397
}
398
case "DSA":
399
return new P11DSAPrivateKey(session, keyID, algorithm,
400
keyLength, attributes);
401
case "DH":
402
return new P11DHPrivateKey(session, keyID, algorithm,
403
keyLength, attributes);
404
case "EC":
405
return new P11ECPrivateKey(session, keyID, algorithm,
406
keyLength, attributes);
407
default:
408
throw new ProviderException
409
("Unknown private key algorithm " + algorithm);
410
}
411
}
412
}
413
414
// class for sensitive and unextractable private keys
415
private static final class P11PrivateKey extends P11Key
416
implements PrivateKey {
417
private static final long serialVersionUID = -2138581185214187615L;
418
419
P11PrivateKey(Session session, long keyID, String algorithm,
420
int keyLength, CK_ATTRIBUTE[] attributes) {
421
super(PRIVATE, session, keyID, algorithm, keyLength, attributes);
422
}
423
// XXX temporary encoding for serialization purposes
424
public String getFormat() {
425
token.ensureValid();
426
return null;
427
}
428
byte[] getEncodedInternal() {
429
token.ensureValid();
430
return null;
431
}
432
}
433
434
private static class P11SecretKey extends P11Key implements SecretKey {
435
private static final long serialVersionUID = -7828241727014329084L;
436
private volatile byte[] encoded;
437
P11SecretKey(Session session, long keyID, String algorithm,
438
int keyLength, CK_ATTRIBUTE[] attributes) {
439
super(SECRET, session, keyID, algorithm, keyLength, attributes);
440
}
441
public String getFormat() {
442
token.ensureValid();
443
if (sensitive || (extractable == false)) {
444
return null;
445
} else {
446
return "RAW";
447
}
448
}
449
byte[] getEncodedInternal() {
450
token.ensureValid();
451
if (getFormat() == null) {
452
return null;
453
}
454
byte[] b = encoded;
455
if (b == null) {
456
synchronized (this) {
457
b = encoded;
458
if (b == null) {
459
Session tempSession = null;
460
long keyID = this.getKeyID();
461
try {
462
tempSession = token.getOpSession();
463
CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {
464
new CK_ATTRIBUTE(CKA_VALUE),
465
};
466
token.p11.C_GetAttributeValue
467
(tempSession.id(), keyID, attributes);
468
b = attributes[0].getByteArray();
469
} catch (PKCS11Exception e) {
470
throw new ProviderException(e);
471
} finally {
472
this.releaseKeyID();
473
token.releaseSession(tempSession);
474
}
475
encoded = b;
476
}
477
}
478
}
479
return b;
480
}
481
}
482
483
private static class P11TlsMasterSecretKey extends P11SecretKey
484
implements TlsMasterSecret {
485
private static final long serialVersionUID = -1318560923770573441L;
486
487
private final int majorVersion, minorVersion;
488
P11TlsMasterSecretKey(Session session, long keyID, String algorithm,
489
int keyLength, CK_ATTRIBUTE[] attributes, int major, int minor) {
490
super(session, keyID, algorithm, keyLength, attributes);
491
this.majorVersion = major;
492
this.minorVersion = minor;
493
}
494
public int getMajorVersion() {
495
return majorVersion;
496
}
497
498
public int getMinorVersion() {
499
return minorVersion;
500
}
501
}
502
503
// RSA CRT private key
504
private static final class P11RSAPrivateKey extends P11Key
505
implements RSAPrivateCrtKey {
506
private static final long serialVersionUID = 9215872438913515220L;
507
508
private BigInteger n, e, d, p, q, pe, qe, coeff;
509
private byte[] encoded;
510
P11RSAPrivateKey(Session session, long keyID, String algorithm,
511
int keyLength, CK_ATTRIBUTE[] attributes) {
512
super(PRIVATE, session, keyID, algorithm, keyLength, attributes);
513
}
514
private synchronized void fetchValues() {
515
token.ensureValid();
516
if (n != null) {
517
return;
518
}
519
CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {
520
new CK_ATTRIBUTE(CKA_MODULUS),
521
new CK_ATTRIBUTE(CKA_PUBLIC_EXPONENT),
522
new CK_ATTRIBUTE(CKA_PRIVATE_EXPONENT),
523
new CK_ATTRIBUTE(CKA_PRIME_1),
524
new CK_ATTRIBUTE(CKA_PRIME_2),
525
new CK_ATTRIBUTE(CKA_EXPONENT_1),
526
new CK_ATTRIBUTE(CKA_EXPONENT_2),
527
new CK_ATTRIBUTE(CKA_COEFFICIENT),
528
};
529
fetchAttributes(attributes);
530
n = attributes[0].getBigInteger();
531
e = attributes[1].getBigInteger();
532
d = attributes[2].getBigInteger();
533
p = attributes[3].getBigInteger();
534
q = attributes[4].getBigInteger();
535
pe = attributes[5].getBigInteger();
536
qe = attributes[6].getBigInteger();
537
coeff = attributes[7].getBigInteger();
538
}
539
public String getFormat() {
540
token.ensureValid();
541
return "PKCS#8";
542
}
543
synchronized byte[] getEncodedInternal() {
544
token.ensureValid();
545
if (encoded == null) {
546
fetchValues();
547
try {
548
Key newKey = RSAPrivateCrtKeyImpl.newKey
549
(KeyType.RSA, null, n, e, d, p, q, pe, qe, coeff);
550
encoded = newKey.getEncoded();
551
} catch (GeneralSecurityException e) {
552
throw new ProviderException(e);
553
}
554
}
555
return encoded;
556
}
557
public BigInteger getModulus() {
558
fetchValues();
559
return n;
560
}
561
public BigInteger getPublicExponent() {
562
fetchValues();
563
return e;
564
}
565
public BigInteger getPrivateExponent() {
566
fetchValues();
567
return d;
568
}
569
public BigInteger getPrimeP() {
570
fetchValues();
571
return p;
572
}
573
public BigInteger getPrimeQ() {
574
fetchValues();
575
return q;
576
}
577
public BigInteger getPrimeExponentP() {
578
fetchValues();
579
return pe;
580
}
581
public BigInteger getPrimeExponentQ() {
582
fetchValues();
583
return qe;
584
}
585
public BigInteger getCrtCoefficient() {
586
fetchValues();
587
return coeff;
588
}
589
}
590
591
// RSA non-CRT private key
592
private static final class P11RSAPrivateNonCRTKey extends P11Key
593
implements RSAPrivateKey {
594
private static final long serialVersionUID = 1137764983777411481L;
595
596
private BigInteger n, d;
597
private byte[] encoded;
598
P11RSAPrivateNonCRTKey(Session session, long keyID, String algorithm,
599
int keyLength, CK_ATTRIBUTE[] attributes) {
600
super(PRIVATE, session, keyID, algorithm, keyLength, attributes);
601
}
602
private synchronized void fetchValues() {
603
token.ensureValid();
604
if (n != null) {
605
return;
606
}
607
CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {
608
new CK_ATTRIBUTE(CKA_MODULUS),
609
new CK_ATTRIBUTE(CKA_PRIVATE_EXPONENT),
610
};
611
fetchAttributes(attributes);
612
n = attributes[0].getBigInteger();
613
d = attributes[1].getBigInteger();
614
}
615
public String getFormat() {
616
token.ensureValid();
617
return "PKCS#8";
618
}
619
synchronized byte[] getEncodedInternal() {
620
token.ensureValid();
621
if (encoded == null) {
622
fetchValues();
623
try {
624
// XXX make constructor in SunRsaSign provider public
625
// and call it directly
626
KeyFactory factory = KeyFactory.getInstance
627
("RSA", P11Util.getSunRsaSignProvider());
628
Key newKey = factory.translateKey(this);
629
encoded = newKey.getEncoded();
630
} catch (GeneralSecurityException e) {
631
throw new ProviderException(e);
632
}
633
}
634
return encoded;
635
}
636
public BigInteger getModulus() {
637
fetchValues();
638
return n;
639
}
640
public BigInteger getPrivateExponent() {
641
fetchValues();
642
return d;
643
}
644
}
645
646
private static final class P11RSAPublicKey extends P11Key
647
implements RSAPublicKey {
648
private static final long serialVersionUID = -826726289023854455L;
649
private BigInteger n, e;
650
private byte[] encoded;
651
P11RSAPublicKey(Session session, long keyID, String algorithm,
652
int keyLength, CK_ATTRIBUTE[] attributes) {
653
super(PUBLIC, session, keyID, algorithm, keyLength, attributes);
654
}
655
private synchronized void fetchValues() {
656
token.ensureValid();
657
if (n != null) {
658
return;
659
}
660
CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {
661
new CK_ATTRIBUTE(CKA_MODULUS),
662
new CK_ATTRIBUTE(CKA_PUBLIC_EXPONENT),
663
};
664
fetchAttributes(attributes);
665
n = attributes[0].getBigInteger();
666
e = attributes[1].getBigInteger();
667
}
668
public String getFormat() {
669
token.ensureValid();
670
return "X.509";
671
}
672
synchronized byte[] getEncodedInternal() {
673
token.ensureValid();
674
if (encoded == null) {
675
fetchValues();
676
try {
677
encoded = RSAPublicKeyImpl.newKey
678
(KeyType.RSA, null, n, e).getEncoded();
679
} catch (InvalidKeyException e) {
680
throw new ProviderException(e);
681
}
682
}
683
return encoded;
684
}
685
public BigInteger getModulus() {
686
fetchValues();
687
return n;
688
}
689
public BigInteger getPublicExponent() {
690
fetchValues();
691
return e;
692
}
693
public String toString() {
694
fetchValues();
695
return super.toString() + "\n modulus: " + n
696
+ "\n public exponent: " + e;
697
}
698
}
699
700
private static final class P11DSAPublicKey extends P11Key
701
implements DSAPublicKey {
702
private static final long serialVersionUID = 5989753793316396637L;
703
704
private BigInteger y;
705
private DSAParams params;
706
private byte[] encoded;
707
P11DSAPublicKey(Session session, long keyID, String algorithm,
708
int keyLength, CK_ATTRIBUTE[] attributes) {
709
super(PUBLIC, session, keyID, algorithm, keyLength, attributes);
710
}
711
private synchronized void fetchValues() {
712
token.ensureValid();
713
if (y != null) {
714
return;
715
}
716
CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {
717
new CK_ATTRIBUTE(CKA_VALUE),
718
new CK_ATTRIBUTE(CKA_PRIME),
719
new CK_ATTRIBUTE(CKA_SUBPRIME),
720
new CK_ATTRIBUTE(CKA_BASE),
721
};
722
fetchAttributes(attributes);
723
y = attributes[0].getBigInteger();
724
params = new DSAParameterSpec(
725
attributes[1].getBigInteger(),
726
attributes[2].getBigInteger(),
727
attributes[3].getBigInteger()
728
);
729
}
730
public String getFormat() {
731
token.ensureValid();
732
return "X.509";
733
}
734
synchronized byte[] getEncodedInternal() {
735
token.ensureValid();
736
if (encoded == null) {
737
fetchValues();
738
try {
739
Key key = new sun.security.provider.DSAPublicKey
740
(y, params.getP(), params.getQ(), params.getG());
741
encoded = key.getEncoded();
742
} catch (InvalidKeyException e) {
743
throw new ProviderException(e);
744
}
745
}
746
return encoded;
747
}
748
public BigInteger getY() {
749
fetchValues();
750
return y;
751
}
752
public DSAParams getParams() {
753
fetchValues();
754
return params;
755
}
756
public String toString() {
757
fetchValues();
758
return super.toString() + "\n y: " + y + "\n p: " + params.getP()
759
+ "\n q: " + params.getQ() + "\n g: " + params.getG();
760
}
761
}
762
763
private static final class P11DSAPrivateKey extends P11Key
764
implements DSAPrivateKey {
765
private static final long serialVersionUID = 3119629997181999389L;
766
767
private BigInteger x;
768
private DSAParams params;
769
private byte[] encoded;
770
P11DSAPrivateKey(Session session, long keyID, String algorithm,
771
int keyLength, CK_ATTRIBUTE[] attributes) {
772
super(PRIVATE, session, keyID, algorithm, keyLength, attributes);
773
}
774
private synchronized void fetchValues() {
775
token.ensureValid();
776
if (x != null) {
777
return;
778
}
779
CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {
780
new CK_ATTRIBUTE(CKA_VALUE),
781
new CK_ATTRIBUTE(CKA_PRIME),
782
new CK_ATTRIBUTE(CKA_SUBPRIME),
783
new CK_ATTRIBUTE(CKA_BASE),
784
};
785
fetchAttributes(attributes);
786
x = attributes[0].getBigInteger();
787
params = new DSAParameterSpec(
788
attributes[1].getBigInteger(),
789
attributes[2].getBigInteger(),
790
attributes[3].getBigInteger()
791
);
792
}
793
public String getFormat() {
794
token.ensureValid();
795
return "PKCS#8";
796
}
797
synchronized byte[] getEncodedInternal() {
798
token.ensureValid();
799
if (encoded == null) {
800
fetchValues();
801
try {
802
Key key = new sun.security.provider.DSAPrivateKey
803
(x, params.getP(), params.getQ(), params.getG());
804
encoded = key.getEncoded();
805
} catch (InvalidKeyException e) {
806
throw new ProviderException(e);
807
}
808
}
809
return encoded;
810
}
811
public BigInteger getX() {
812
fetchValues();
813
return x;
814
}
815
public DSAParams getParams() {
816
fetchValues();
817
return params;
818
}
819
}
820
821
private static final class P11DHPrivateKey extends P11Key
822
implements DHPrivateKey {
823
private static final long serialVersionUID = -1698576167364928838L;
824
825
private BigInteger x;
826
private DHParameterSpec params;
827
private byte[] encoded;
828
P11DHPrivateKey(Session session, long keyID, String algorithm,
829
int keyLength, CK_ATTRIBUTE[] attributes) {
830
super(PRIVATE, session, keyID, algorithm, keyLength, attributes);
831
}
832
private synchronized void fetchValues() {
833
token.ensureValid();
834
if (x != null) {
835
return;
836
}
837
CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {
838
new CK_ATTRIBUTE(CKA_VALUE),
839
new CK_ATTRIBUTE(CKA_PRIME),
840
new CK_ATTRIBUTE(CKA_BASE),
841
};
842
fetchAttributes(attributes);
843
x = attributes[0].getBigInteger();
844
params = new DHParameterSpec(
845
attributes[1].getBigInteger(),
846
attributes[2].getBigInteger()
847
);
848
}
849
public String getFormat() {
850
token.ensureValid();
851
return "PKCS#8";
852
}
853
synchronized byte[] getEncodedInternal() {
854
token.ensureValid();
855
if (encoded == null) {
856
fetchValues();
857
try {
858
DHPrivateKeySpec spec = new DHPrivateKeySpec
859
(x, params.getP(), params.getG());
860
KeyFactory kf = KeyFactory.getInstance
861
("DH", P11Util.getSunJceProvider());
862
Key key = kf.generatePrivate(spec);
863
encoded = key.getEncoded();
864
} catch (GeneralSecurityException e) {
865
throw new ProviderException(e);
866
}
867
}
868
return encoded;
869
}
870
public BigInteger getX() {
871
fetchValues();
872
return x;
873
}
874
public DHParameterSpec getParams() {
875
fetchValues();
876
return params;
877
}
878
public int hashCode() {
879
if (token.isValid() == false) {
880
return 0;
881
}
882
fetchValues();
883
return Objects.hash(x, params.getP(), params.getG());
884
}
885
public boolean equals(Object obj) {
886
if (this == obj) return true;
887
// equals() should never throw exceptions
888
if (token.isValid() == false) {
889
return false;
890
}
891
if (!(obj instanceof DHPrivateKey)) {
892
return false;
893
}
894
fetchValues();
895
DHPrivateKey other = (DHPrivateKey) obj;
896
DHParameterSpec otherParams = other.getParams();
897
return ((this.x.compareTo(other.getX()) == 0) &&
898
(this.params.getP().compareTo(otherParams.getP()) == 0) &&
899
(this.params.getG().compareTo(otherParams.getG()) == 0));
900
}
901
}
902
903
private static final class P11DHPublicKey extends P11Key
904
implements DHPublicKey {
905
static final long serialVersionUID = -598383872153843657L;
906
907
private BigInteger y;
908
private DHParameterSpec params;
909
private byte[] encoded;
910
P11DHPublicKey(Session session, long keyID, String algorithm,
911
int keyLength, CK_ATTRIBUTE[] attributes) {
912
super(PUBLIC, session, keyID, algorithm, keyLength, attributes);
913
}
914
private synchronized void fetchValues() {
915
token.ensureValid();
916
if (y != null) {
917
return;
918
}
919
CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {
920
new CK_ATTRIBUTE(CKA_VALUE),
921
new CK_ATTRIBUTE(CKA_PRIME),
922
new CK_ATTRIBUTE(CKA_BASE),
923
};
924
fetchAttributes(attributes);
925
y = attributes[0].getBigInteger();
926
params = new DHParameterSpec(
927
attributes[1].getBigInteger(),
928
attributes[2].getBigInteger()
929
);
930
}
931
public String getFormat() {
932
token.ensureValid();
933
return "X.509";
934
}
935
synchronized byte[] getEncodedInternal() {
936
token.ensureValid();
937
if (encoded == null) {
938
fetchValues();
939
try {
940
DHPublicKeySpec spec = new DHPublicKeySpec
941
(y, params.getP(), params.getG());
942
KeyFactory kf = KeyFactory.getInstance
943
("DH", P11Util.getSunJceProvider());
944
Key key = kf.generatePublic(spec);
945
encoded = key.getEncoded();
946
} catch (GeneralSecurityException e) {
947
throw new ProviderException(e);
948
}
949
}
950
return encoded;
951
}
952
public BigInteger getY() {
953
fetchValues();
954
return y;
955
}
956
public DHParameterSpec getParams() {
957
fetchValues();
958
return params;
959
}
960
public String toString() {
961
fetchValues();
962
return super.toString() + "\n y: " + y + "\n p: " + params.getP()
963
+ "\n g: " + params.getG();
964
}
965
public int hashCode() {
966
if (token.isValid() == false) {
967
return 0;
968
}
969
fetchValues();
970
return Objects.hash(y, params.getP(), params.getG());
971
}
972
public boolean equals(Object obj) {
973
if (this == obj) return true;
974
// equals() should never throw exceptions
975
if (token.isValid() == false) {
976
return false;
977
}
978
if (!(obj instanceof DHPublicKey)) {
979
return false;
980
}
981
fetchValues();
982
DHPublicKey other = (DHPublicKey) obj;
983
DHParameterSpec otherParams = other.getParams();
984
return ((this.y.compareTo(other.getY()) == 0) &&
985
(this.params.getP().compareTo(otherParams.getP()) == 0) &&
986
(this.params.getG().compareTo(otherParams.getG()) == 0));
987
}
988
}
989
990
private static final class P11ECPrivateKey extends P11Key
991
implements ECPrivateKey {
992
private static final long serialVersionUID = -7786054399510515515L;
993
994
private BigInteger s;
995
private ECParameterSpec params;
996
private byte[] encoded;
997
P11ECPrivateKey(Session session, long keyID, String algorithm,
998
int keyLength, CK_ATTRIBUTE[] attributes) {
999
super(PRIVATE, session, keyID, algorithm, keyLength, attributes);
1000
}
1001
private synchronized void fetchValues() {
1002
token.ensureValid();
1003
if (s != null) {
1004
return;
1005
}
1006
CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {
1007
new CK_ATTRIBUTE(CKA_VALUE),
1008
new CK_ATTRIBUTE(CKA_EC_PARAMS, params),
1009
};
1010
fetchAttributes(attributes);
1011
s = attributes[0].getBigInteger();
1012
try {
1013
params = P11ECKeyFactory.decodeParameters
1014
(attributes[1].getByteArray());
1015
} catch (Exception e) {
1016
throw new RuntimeException("Could not parse key values", e);
1017
}
1018
}
1019
public String getFormat() {
1020
token.ensureValid();
1021
return "PKCS#8";
1022
}
1023
synchronized byte[] getEncodedInternal() {
1024
token.ensureValid();
1025
if (encoded == null) {
1026
fetchValues();
1027
try {
1028
Key key = P11ECUtil.generateECPrivateKey(s, params);
1029
encoded = key.getEncoded();
1030
} catch (InvalidKeySpecException e) {
1031
throw new ProviderException(e);
1032
}
1033
}
1034
return encoded;
1035
}
1036
public BigInteger getS() {
1037
fetchValues();
1038
return s;
1039
}
1040
public ECParameterSpec getParams() {
1041
fetchValues();
1042
return params;
1043
}
1044
}
1045
1046
private static final class P11ECPublicKey extends P11Key
1047
implements ECPublicKey {
1048
private static final long serialVersionUID = -6371481375154806089L;
1049
1050
private ECPoint w;
1051
private ECParameterSpec params;
1052
private byte[] encoded;
1053
P11ECPublicKey(Session session, long keyID, String algorithm,
1054
int keyLength, CK_ATTRIBUTE[] attributes) {
1055
super(PUBLIC, session, keyID, algorithm, keyLength, attributes);
1056
}
1057
private synchronized void fetchValues() {
1058
token.ensureValid();
1059
if (w != null) {
1060
return;
1061
}
1062
CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {
1063
new CK_ATTRIBUTE(CKA_EC_POINT),
1064
new CK_ATTRIBUTE(CKA_EC_PARAMS),
1065
};
1066
fetchAttributes(attributes);
1067
1068
try {
1069
params = P11ECKeyFactory.decodeParameters
1070
(attributes[1].getByteArray());
1071
byte[] ecKey = attributes[0].getByteArray();
1072
1073
// Check whether the X9.63 encoding of an EC point is wrapped
1074
// in an ASN.1 OCTET STRING
1075
if (!token.config.getUseEcX963Encoding()) {
1076
DerValue wECPoint = new DerValue(ecKey);
1077
1078
if (wECPoint.getTag() != DerValue.tag_OctetString) {
1079
throw new IOException("Could not DER decode EC point." +
1080
" Unexpected tag: " + wECPoint.getTag());
1081
}
1082
w = P11ECKeyFactory.decodePoint
1083
(wECPoint.getDataBytes(), params.getCurve());
1084
1085
} else {
1086
w = P11ECKeyFactory.decodePoint(ecKey, params.getCurve());
1087
}
1088
1089
} catch (Exception e) {
1090
throw new RuntimeException("Could not parse key values", e);
1091
}
1092
}
1093
public String getFormat() {
1094
token.ensureValid();
1095
return "X.509";
1096
}
1097
synchronized byte[] getEncodedInternal() {
1098
token.ensureValid();
1099
if (encoded == null) {
1100
fetchValues();
1101
try {
1102
return P11ECUtil.x509EncodeECPublicKey(w, params);
1103
} catch (InvalidKeySpecException e) {
1104
throw new ProviderException(e);
1105
}
1106
}
1107
return encoded;
1108
}
1109
public ECPoint getW() {
1110
fetchValues();
1111
return w;
1112
}
1113
public ECParameterSpec getParams() {
1114
fetchValues();
1115
return params;
1116
}
1117
public String toString() {
1118
fetchValues();
1119
return super.toString()
1120
+ "\n public x coord: " + w.getAffineX()
1121
+ "\n public y coord: " + w.getAffineY()
1122
+ "\n parameters: " + params;
1123
}
1124
}
1125
}
1126
1127
final class NativeKeyHolder {
1128
1129
private static long nativeKeyWrapperKeyID = 0;
1130
private static CK_MECHANISM nativeKeyWrapperMechanism = null;
1131
private static long nativeKeyWrapperRefCount = 0;
1132
private static Session nativeKeyWrapperSession = null;
1133
1134
private final P11Key p11Key;
1135
private final byte[] nativeKeyInfo;
1136
private boolean wrapperKeyUsed;
1137
1138
// destroyed and recreated when refCount toggles to 1
1139
private long keyID;
1140
1141
// phantom reference notification clean up for session keys
1142
private SessionKeyRef ref;
1143
1144
private int refCount;
1145
1146
private static void createNativeKeyWrapper(Token token)
1147
throws PKCS11Exception {
1148
assert(nativeKeyWrapperKeyID == 0);
1149
assert(nativeKeyWrapperRefCount == 0);
1150
assert(nativeKeyWrapperSession == null);
1151
// Create a global wrapping/unwrapping key
1152
CK_ATTRIBUTE[] wrappingAttributes = token.getAttributes(O_GENERATE,
1153
CKO_SECRET_KEY, CKK_AES, new CK_ATTRIBUTE[] {
1154
new CK_ATTRIBUTE(CKA_CLASS, CKO_SECRET_KEY),
1155
new CK_ATTRIBUTE(CKA_VALUE_LEN, 256 >> 3)});
1156
Session s = null;
1157
try {
1158
s = token.getObjSession();
1159
nativeKeyWrapperKeyID = token.p11.C_GenerateKey(
1160
s.id(), new CK_MECHANISM(CKM_AES_KEY_GEN),
1161
wrappingAttributes);
1162
nativeKeyWrapperSession = s;
1163
nativeKeyWrapperSession.addObject();
1164
byte[] iv = new byte[16];
1165
JCAUtil.getSecureRandom().nextBytes(iv);
1166
nativeKeyWrapperMechanism = new CK_MECHANISM(CKM_AES_CBC_PAD, iv);
1167
} catch (PKCS11Exception e) {
1168
// best effort
1169
} finally {
1170
token.releaseSession(s);
1171
}
1172
}
1173
1174
private static void deleteNativeKeyWrapper() {
1175
Token token = nativeKeyWrapperSession.token;
1176
if (token.isValid()) {
1177
Session s = null;
1178
try {
1179
s = token.getOpSession();
1180
token.p11.C_DestroyObject(s.id(), nativeKeyWrapperKeyID);
1181
nativeKeyWrapperSession.removeObject();
1182
} catch (PKCS11Exception e) {
1183
// best effort
1184
} finally {
1185
token.releaseSession(s);
1186
}
1187
}
1188
nativeKeyWrapperKeyID = 0;
1189
nativeKeyWrapperMechanism = null;
1190
nativeKeyWrapperSession = null;
1191
}
1192
1193
static void decWrapperKeyRef() {
1194
synchronized(NativeKeyHolder.class) {
1195
assert(nativeKeyWrapperKeyID != 0);
1196
assert(nativeKeyWrapperRefCount > 0);
1197
nativeKeyWrapperRefCount--;
1198
if (nativeKeyWrapperRefCount == 0) {
1199
deleteNativeKeyWrapper();
1200
}
1201
}
1202
}
1203
1204
NativeKeyHolder(P11Key p11Key, long keyID, Session keySession,
1205
boolean extractKeyInfo, boolean isTokenObject) {
1206
this.p11Key = p11Key;
1207
this.keyID = keyID;
1208
this.refCount = -1;
1209
byte[] ki = null;
1210
if (isTokenObject) {
1211
this.ref = null;
1212
} else {
1213
// Try extracting key info, if any error, disable it
1214
Token token = p11Key.token;
1215
if (extractKeyInfo) {
1216
try {
1217
if (p11Key.sensitive) {
1218
// p11Key native key information has to be wrapped
1219
synchronized(NativeKeyHolder.class) {
1220
if (nativeKeyWrapperKeyID == 0) {
1221
createNativeKeyWrapper(token);
1222
}
1223
// If a wrapper-key was successfully created or
1224
// already exists, increment its reference
1225
// counter to keep it alive while native key
1226
// information is being held.
1227
if (nativeKeyWrapperKeyID != 0) {
1228
nativeKeyWrapperRefCount++;
1229
wrapperKeyUsed = true;
1230
}
1231
}
1232
}
1233
Session opSession = null;
1234
try {
1235
opSession = token.getOpSession();
1236
ki = p11Key.token.p11.getNativeKeyInfo(opSession.id(),
1237
keyID, nativeKeyWrapperKeyID,
1238
nativeKeyWrapperMechanism);
1239
} catch (PKCS11Exception e) {
1240
// best effort
1241
} finally {
1242
token.releaseSession(opSession);
1243
}
1244
} catch (PKCS11Exception e) {
1245
// best effort
1246
}
1247
}
1248
this.ref = new SessionKeyRef(p11Key, keyID, wrapperKeyUsed,
1249
keySession);
1250
}
1251
this.nativeKeyInfo = ((ki == null || ki.length == 0)? null : ki);
1252
}
1253
1254
long getKeyID() throws ProviderException {
1255
if (this.nativeKeyInfo != null) {
1256
synchronized(this.nativeKeyInfo) {
1257
if (this.refCount == -1) {
1258
this.refCount = 0;
1259
}
1260
int cnt = (this.refCount)++;
1261
if (keyID == 0) {
1262
if (cnt != 0) {
1263
throw new RuntimeException(
1264
"Error: null keyID with non-zero refCount " + cnt);
1265
}
1266
Token token = p11Key.token;
1267
// Create keyID using nativeKeyInfo
1268
Session session = null;
1269
try {
1270
session = token.getObjSession();
1271
this.keyID = token.p11.createNativeKey(session.id(),
1272
nativeKeyInfo, nativeKeyWrapperKeyID,
1273
nativeKeyWrapperMechanism);
1274
this.ref.registerNativeKey(this.keyID, session);
1275
} catch (PKCS11Exception e) {
1276
this.refCount--;
1277
throw new ProviderException("Error recreating native key", e);
1278
} finally {
1279
token.releaseSession(session);
1280
}
1281
} else {
1282
if (cnt < 0) {
1283
throw new RuntimeException("ERROR: negative refCount");
1284
}
1285
}
1286
}
1287
}
1288
return keyID;
1289
}
1290
1291
void releaseKeyID() {
1292
if (this.nativeKeyInfo != null) {
1293
synchronized(this.nativeKeyInfo) {
1294
if (this.refCount == -1) {
1295
throw new RuntimeException("Error: miss match getKeyID call");
1296
}
1297
int cnt = --(this.refCount);
1298
if (cnt == 0) {
1299
// destroy
1300
if (this.keyID == 0) {
1301
throw new RuntimeException("ERROR: null keyID can't be destroyed");
1302
}
1303
1304
// destroy
1305
this.keyID = 0;
1306
this.ref.removeNativeKey();
1307
} else {
1308
if (cnt < 0) {
1309
// should never happen as we start count at 1 and pair get/release calls
1310
throw new RuntimeException("wrong refCount value: " + cnt);
1311
}
1312
}
1313
}
1314
}
1315
}
1316
}
1317
1318
/*
1319
* NOTE: Must use PhantomReference here and not WeakReference
1320
* otherwise the key maybe cleared before other objects which
1321
* still use these keys during finalization such as SSLSocket.
1322
*/
1323
final class SessionKeyRef extends PhantomReference<P11Key> {
1324
private static ReferenceQueue<P11Key> refQueue =
1325
new ReferenceQueue<P11Key>();
1326
private static Set<SessionKeyRef> refSet =
1327
Collections.synchronizedSet(new HashSet<SessionKeyRef>());
1328
1329
static ReferenceQueue<P11Key> referenceQueue() {
1330
return refQueue;
1331
}
1332
1333
private static void drainRefQueueBounded() {
1334
while (true) {
1335
SessionKeyRef next = (SessionKeyRef) refQueue.poll();
1336
if (next == null) break;
1337
next.dispose();
1338
}
1339
}
1340
1341
// handle to the native key and the session it is generated under
1342
private long keyID;
1343
private Session session;
1344
private boolean wrapperKeyUsed;
1345
1346
SessionKeyRef(P11Key p11Key, long keyID, boolean wrapperKeyUsed,
1347
Session session) {
1348
super(p11Key, refQueue);
1349
if (session == null) {
1350
throw new ProviderException("key must be associated with a session");
1351
}
1352
registerNativeKey(keyID, session);
1353
this.wrapperKeyUsed = wrapperKeyUsed;
1354
1355
refSet.add(this);
1356
// TBD: run at some interval and not every time?
1357
drainRefQueueBounded();
1358
}
1359
1360
void registerNativeKey(long newKeyID, Session newSession) {
1361
assert(newKeyID != 0);
1362
assert(newSession != null);
1363
updateNativeKey(newKeyID, newSession);
1364
}
1365
1366
void removeNativeKey() {
1367
assert(session != null);
1368
updateNativeKey(0, null);
1369
}
1370
1371
private void updateNativeKey(long newKeyID, Session newSession) {
1372
if (newKeyID == 0) {
1373
assert(newSession == null);
1374
Token token = session.token;
1375
// If the token is still valid, try to remove the key object
1376
if (token.isValid()) {
1377
Session s = null;
1378
try {
1379
s = token.getOpSession();
1380
token.p11.C_DestroyObject(s.id(), this.keyID);
1381
} catch (PKCS11Exception e) {
1382
// best effort
1383
} finally {
1384
token.releaseSession(s);
1385
}
1386
}
1387
session.removeObject();
1388
} else {
1389
newSession.addObject();
1390
}
1391
keyID = newKeyID;
1392
session = newSession;
1393
}
1394
1395
// Called when the GC disposes a p11Key
1396
void dispose() {
1397
if (wrapperKeyUsed) {
1398
// Wrapper-key no longer needed for
1399
// p11Key native key information
1400
NativeKeyHolder.decWrapperKeyRef();
1401
}
1402
if (keyID != 0) {
1403
removeNativeKey();
1404
}
1405
refSet.remove(this);
1406
this.clear();
1407
}
1408
}
1409
1410