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