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
33 import java.security.*;
34 import java.security.interfaces.*;
35 import java.security.spec.*;
36
37 import javax.crypto.*;
38 import javax.crypto.interfaces.*;
39 import javax.crypto.spec.*;
40
41 import sun.security.rsa.RSAUtil.KeyType;
42 import sun.security.rsa.RSAPublicKeyImpl;
43 import sun.security.rsa.RSAPrivateCrtKeyImpl;
44
45 import sun.security.internal.interfaces.TlsMasterSecret;
46
47 import sun.security.pkcs11.wrapper.*;
48 import static sun.security.pkcs11.wrapper.PKCS11Constants.*;
49
50 import sun.security.util.Debug;
51 import sun.security.util.DerValue;
52 import sun.security.util.Length;
53 import sun.security.util.ECUtil;
54
55 /**
56 * Key implementation classes.
57 *
58 * In PKCS#11, the components of private and secret keys may or may not
59 * be accessible. If they are, we use the algorithm specific key classes
60 * (e.g. DSAPrivateKey) for compatibility with existing applications.
61 * If the components are not accessible, we use a generic class that
62 * only implements PrivateKey (or SecretKey). Whether the components of a
63 * key are extractable is automatically determined when the key object is
64 * created.
65 *
66 * @author Andreas Sterbenz
67 * @since 1.5
68 */
69 abstract class P11Key implements Key, Length {
70
71 private static final long serialVersionUID = -2575874101938349339L;
72
73 private final static String PUBLIC = "public";
74 private final static String PRIVATE = "private";
75 private final static String SECRET = "secret";
76
77 // type of key, one of (PUBLIC, PRIVATE, SECRET)
78 final String type;
79
80 // token instance
81 final Token token;
82
83 // algorithm name, returned by getAlgorithm(), etc.
84 final String algorithm;
85
86 // key id
87 final long keyID;
88
89 // effective key length of the key, e.g. 56 for a DES key
90 final int keyLength;
91
92 // flags indicating whether the key is a token object, sensitive, extractable
93 final boolean tokenObject, sensitive, extractable;
94
95 // phantom reference notification clean up for session keys
96 private final SessionKeyRef sessionKeyRef;
97
98 P11Key(String type, Session session, long keyID, String algorithm,
99 int keyLength, CK_ATTRIBUTE[] attributes) {
100 this.type = type;
101 this.token = session.token;
102 this.keyID = keyID;
103 this.algorithm = algorithm;
104 this.keyLength = keyLength;
105 boolean tokenObject = false;
106 boolean sensitive = false;
107 boolean extractable = true;
108 int n = (attributes == null) ? 0 : attributes.length;
109 for (int i = 0; i < n; i++) {
110 CK_ATTRIBUTE attr = attributes[i];
111 if (attr.type == CKA_TOKEN) {
112 tokenObject = attr.getBoolean();
113 } else if (attr.type == CKA_SENSITIVE) {
114 sensitive = attr.getBoolean();
115 } else if (attr.type == CKA_EXTRACTABLE) {
116 extractable = attr.getBoolean();
117 }
118 }
119 this.tokenObject = tokenObject;
120 this.sensitive = sensitive;
121 this.extractable = extractable;
122 if (tokenObject == false) {
123 sessionKeyRef = new SessionKeyRef(this, keyID, session);
124 } else {
125 sessionKeyRef = null;
126 }
127 }
128
129 // see JCA spec
130 public final String getAlgorithm() {
131 token.ensureValid();
132 return algorithm;
133 }
134
135 // see JCA spec
136 public final byte[] getEncoded() {
137 byte[] b = getEncodedInternal();
138 return (b == null) ? null : b.clone();
139 }
140
141 abstract byte[] getEncodedInternal();
142
143 public boolean equals(Object obj) {
144 if (this == obj) {
145 return true;
146 }
147 // equals() should never throw exceptions
148 if (token.isValid() == false) {
226 public int length() {
227 return keyLength;
228 }
229
230 boolean isPublic() {
231 return type == PUBLIC;
232 }
233
234 boolean isPrivate() {
235 return type == PRIVATE;
236 }
237
238 boolean isSecret() {
239 return type == SECRET;
240 }
241
242 void fetchAttributes(CK_ATTRIBUTE[] attributes) {
243 Session tempSession = null;
244 try {
245 tempSession = token.getOpSession();
246 token.p11.C_GetAttributeValue(tempSession.id(), keyID, attributes);
247 } catch (PKCS11Exception e) {
248 throw new ProviderException(e);
249 } finally {
250 token.releaseSession(tempSession);
251 }
252 }
253
254 private final static CK_ATTRIBUTE[] A0 = new CK_ATTRIBUTE[0];
255
256 private static CK_ATTRIBUTE[] getAttributes(Session session, long keyID,
257 CK_ATTRIBUTE[] knownAttributes, CK_ATTRIBUTE[] desiredAttributes) {
258 if (knownAttributes == null) {
259 knownAttributes = A0;
260 }
261 for (int i = 0; i < desiredAttributes.length; i++) {
262 // For each desired attribute, check to see if we have the value
263 // available already. If everything is here, we save a native call.
264 CK_ATTRIBUTE attr = desiredAttributes[i];
265 for (CK_ATTRIBUTE known : knownAttributes) {
266 if ((attr.type == known.type) && (known.pValue != null)) {
270 }
271 if (attr.pValue == null) {
272 // nothing found, need to call C_GetAttributeValue()
273 for (int j = 0; j < i; j++) {
274 // clear values copied from knownAttributes
275 desiredAttributes[j].pValue = null;
276 }
277 try {
278 session.token.p11.C_GetAttributeValue
279 (session.id(), keyID, desiredAttributes);
280 } catch (PKCS11Exception e) {
281 throw new ProviderException(e);
282 }
283 break; // break loop, goto return
284 }
285 }
286 return desiredAttributes;
287 }
288
289 static SecretKey secretKey(Session session, long keyID, String algorithm,
290 int keyLength, CK_ATTRIBUTE[] attributes) {
291 attributes = getAttributes(session, keyID, attributes, new CK_ATTRIBUTE[] {
292 new CK_ATTRIBUTE(CKA_TOKEN),
293 new CK_ATTRIBUTE(CKA_SENSITIVE),
294 new CK_ATTRIBUTE(CKA_EXTRACTABLE),
295 });
296 return new P11SecretKey(session, keyID, algorithm, keyLength, attributes);
297 }
298
299 static SecretKey masterSecretKey(Session session, long keyID, String algorithm,
300 int keyLength, CK_ATTRIBUTE[] attributes, int major, int minor) {
301 attributes = getAttributes(session, keyID, attributes, new CK_ATTRIBUTE[] {
302 new CK_ATTRIBUTE(CKA_TOKEN),
303 new CK_ATTRIBUTE(CKA_SENSITIVE),
304 new CK_ATTRIBUTE(CKA_EXTRACTABLE),
305 });
306 return new P11TlsMasterSecretKey
307 (session, keyID, algorithm, keyLength, attributes, major, minor);
308 }
309
310 // we assume that all components of public keys are always accessible
311 static PublicKey publicKey(Session session, long keyID, String algorithm,
312 int keyLength, CK_ATTRIBUTE[] attributes) {
313 switch (algorithm) {
314 case "RSA":
315 return new P11RSAPublicKey
316 (session, keyID, algorithm, keyLength, attributes);
317 case "DSA":
318 return new P11DSAPublicKey
319 (session, keyID, algorithm, keyLength, attributes);
320 case "DH":
321 return new P11DHPublicKey
322 (session, keyID, algorithm, keyLength, attributes);
323 case "EC":
324 return new P11ECPublicKey
325 (session, keyID, algorithm, keyLength, attributes);
326 default:
327 throw new ProviderException
328 ("Unknown public key algorithm " + algorithm);
329 }
330 }
331
332 static PrivateKey privateKey(Session session, long keyID, String algorithm,
333 int keyLength, CK_ATTRIBUTE[] attributes) {
334 attributes = getAttributes(session, keyID, attributes, new CK_ATTRIBUTE[] {
335 new CK_ATTRIBUTE(CKA_TOKEN),
336 new CK_ATTRIBUTE(CKA_SENSITIVE),
337 new CK_ATTRIBUTE(CKA_EXTRACTABLE),
338 });
339 if (attributes[1].getBoolean() || (attributes[2].getBoolean() == false)) {
340 return new P11PrivateKey
341 (session, keyID, algorithm, keyLength, attributes);
342 } else {
343 switch (algorithm) {
344 case "RSA":
345 // In order to decide if this is RSA CRT key, we first query
346 // and see if all extra CRT attributes are available.
347 CK_ATTRIBUTE[] attrs2 = new CK_ATTRIBUTE[] {
348 new CK_ATTRIBUTE(CKA_PUBLIC_EXPONENT),
349 new CK_ATTRIBUTE(CKA_PRIME_1),
350 new CK_ATTRIBUTE(CKA_PRIME_2),
351 new CK_ATTRIBUTE(CKA_EXPONENT_1),
352 new CK_ATTRIBUTE(CKA_EXPONENT_2),
353 new CK_ATTRIBUTE(CKA_COEFFICIENT),
354 };
355 boolean crtKey;
356 try {
357 session.token.p11.C_GetAttributeValue
358 (session.id(), keyID, attrs2);
359 crtKey = ((attrs2[0].pValue instanceof byte[]) &&
360 (attrs2[1].pValue instanceof byte[]) &&
361 (attrs2[2].pValue instanceof byte[]) &&
362 (attrs2[3].pValue instanceof byte[]) &&
363 (attrs2[4].pValue instanceof byte[]) &&
364 (attrs2[5].pValue instanceof byte[])) ;
365 } catch (PKCS11Exception e) {
366 // ignore, assume not available
367 crtKey = false;
368 }
369 if (crtKey) {
370 return new P11RSAPrivateKey
371 (session, keyID, algorithm, keyLength, attributes, attrs2);
372 } else {
373 return new P11RSAPrivateNonCRTKey
374 (session, keyID, algorithm, keyLength, attributes);
375 }
376 case "DSA":
377 return new P11DSAPrivateKey
378 (session, keyID, algorithm, keyLength, attributes);
379 case "DH":
380 return new P11DHPrivateKey
381 (session, keyID, algorithm, keyLength, attributes);
382 case "EC":
383 return new P11ECPrivateKey
384 (session, keyID, algorithm, keyLength, attributes);
385 default:
386 throw new ProviderException
387 ("Unknown private key algorithm " + algorithm);
388 }
389 }
390 }
391
392 // class for sensitive and unextractable private keys
393 private static final class P11PrivateKey extends P11Key
394 implements PrivateKey {
395 private static final long serialVersionUID = -2138581185214187615L;
396
397 P11PrivateKey(Session session, long keyID, String algorithm,
398 int keyLength, CK_ATTRIBUTE[] attributes) {
399 super(PRIVATE, session, keyID, algorithm, keyLength, attributes);
400 }
401 // XXX temporary encoding for serialization purposes
402 public String getFormat() {
403 token.ensureValid();
404 return null;
405 }
406 byte[] getEncodedInternal() {
407 token.ensureValid();
408 return null;
409 }
410 }
411
412 private static class P11SecretKey extends P11Key implements SecretKey {
413 private static final long serialVersionUID = -7828241727014329084L;
414 private volatile byte[] encoded;
415 P11SecretKey(Session session, long keyID, String algorithm,
416 int keyLength, CK_ATTRIBUTE[] attributes) {
417 super(SECRET, session, keyID, algorithm, keyLength, attributes);
418 }
419 public String getFormat() {
420 token.ensureValid();
421 if (sensitive || (extractable == false)) {
422 return null;
423 } else {
424 return "RAW";
425 }
426 }
427 byte[] getEncodedInternal() {
428 token.ensureValid();
429 if (getFormat() == null) {
430 return null;
431 }
432 byte[] b = encoded;
433 if (b == null) {
434 synchronized (this) {
435 b = encoded;
436 if (b == null) {
437 Session tempSession = null;
438 try {
439 tempSession = token.getOpSession();
440 CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {
441 new CK_ATTRIBUTE(CKA_VALUE),
442 };
443 token.p11.C_GetAttributeValue
444 (tempSession.id(), keyID, attributes);
445 b = attributes[0].getByteArray();
446 } catch (PKCS11Exception e) {
447 throw new ProviderException(e);
448 } finally {
449 token.releaseSession(tempSession);
450 }
451 encoded = b;
452 }
453 }
454 }
455 return b;
456 }
457 }
458
459 @SuppressWarnings("deprecation")
460 private static class P11TlsMasterSecretKey extends P11SecretKey
461 implements TlsMasterSecret {
462 private static final long serialVersionUID = -1318560923770573441L;
463
464 private final int majorVersion, minorVersion;
465 P11TlsMasterSecretKey(Session session, long keyID, String algorithm,
466 int keyLength, CK_ATTRIBUTE[] attributes, int major, int minor) {
467 super(session, keyID, algorithm, keyLength, attributes);
468 this.majorVersion = major;
469 this.minorVersion = minor;
470 }
471 public int getMajorVersion() {
472 return majorVersion;
473 }
474
475 public int getMinorVersion() {
476 return minorVersion;
477 }
478 }
479
480 // RSA CRT private key
481 private static final class P11RSAPrivateKey extends P11Key
482 implements RSAPrivateCrtKey {
483 private static final long serialVersionUID = 9215872438913515220L;
484
485 private BigInteger n, e, d, p, q, pe, qe, coeff;
486 private byte[] encoded;
487 P11RSAPrivateKey(Session session, long keyID, String algorithm,
488 int keyLength, CK_ATTRIBUTE[] attrs, CK_ATTRIBUTE[] crtAttrs) {
489 super(PRIVATE, session, keyID, algorithm, keyLength, attrs);
490
491 for (CK_ATTRIBUTE a : crtAttrs) {
492 if (a.type == CKA_PUBLIC_EXPONENT) {
493 e = a.getBigInteger();
494 } else if (a.type == CKA_PRIME_1) {
495 p = a.getBigInteger();
496 } else if (a.type == CKA_PRIME_2) {
497 q = a.getBigInteger();
498 } else if (a.type == CKA_EXPONENT_1) {
499 pe = a.getBigInteger();
500 } else if (a.type == CKA_EXPONENT_2) {
501 qe = a.getBigInteger();
502 } else if (a.type == CKA_COEFFICIENT) {
503 coeff = a.getBigInteger();
504 }
505 }
506 }
507 private synchronized void fetchValues() {
508 token.ensureValid();
509 if (n != null) {
555 }
556 public BigInteger getPrimeExponentP() {
557 return pe;
558 }
559 public BigInteger getPrimeExponentQ() {
560 return qe;
561 }
562 public BigInteger getCrtCoefficient() {
563 return coeff;
564 }
565 }
566
567 // RSA non-CRT private key
568 private static final class P11RSAPrivateNonCRTKey extends P11Key
569 implements RSAPrivateKey {
570 private static final long serialVersionUID = 1137764983777411481L;
571
572 private BigInteger n, d;
573 private byte[] encoded;
574 P11RSAPrivateNonCRTKey(Session session, long keyID, String algorithm,
575 int keyLength, CK_ATTRIBUTE[] attributes) {
576 super(PRIVATE, session, keyID, algorithm, keyLength, attributes);
577 }
578 private synchronized void fetchValues() {
579 token.ensureValid();
580 if (n != null) {
581 return;
582 }
583 CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {
584 new CK_ATTRIBUTE(CKA_MODULUS),
585 new CK_ATTRIBUTE(CKA_PRIVATE_EXPONENT),
586 };
587 fetchAttributes(attributes);
588 n = attributes[0].getBigInteger();
589 d = attributes[1].getBigInteger();
590 }
591 public String getFormat() {
592 token.ensureValid();
593 return "PKCS#8";
594 }
595 synchronized byte[] getEncodedInternal() {
596 token.ensureValid();
608 }
609 }
610 return encoded;
611 }
612 public BigInteger getModulus() {
613 fetchValues();
614 return n;
615 }
616 public BigInteger getPrivateExponent() {
617 fetchValues();
618 return d;
619 }
620 }
621
622 private static final class P11RSAPublicKey extends P11Key
623 implements RSAPublicKey {
624 private static final long serialVersionUID = -826726289023854455L;
625 private BigInteger n, e;
626 private byte[] encoded;
627 P11RSAPublicKey(Session session, long keyID, String algorithm,
628 int keyLength, CK_ATTRIBUTE[] attributes) {
629 super(PUBLIC, session, keyID, algorithm, keyLength, attributes);
630 }
631 private synchronized void fetchValues() {
632 token.ensureValid();
633 if (n != null) {
634 return;
635 }
636 CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {
637 new CK_ATTRIBUTE(CKA_MODULUS),
638 new CK_ATTRIBUTE(CKA_PUBLIC_EXPONENT),
639 };
640 fetchAttributes(attributes);
641 n = attributes[0].getBigInteger();
642 e = attributes[1].getBigInteger();
643 }
644 public String getFormat() {
645 token.ensureValid();
646 return "X.509";
647 }
648 synchronized byte[] getEncodedInternal() {
649 token.ensureValid();
664 }
665 public BigInteger getPublicExponent() {
666 fetchValues();
667 return e;
668 }
669 public String toString() {
670 fetchValues();
671 return super.toString() + "\n modulus: " + n
672 + "\n public exponent: " + e;
673 }
674 }
675
676 private static final class P11DSAPublicKey extends P11Key
677 implements DSAPublicKey {
678 private static final long serialVersionUID = 5989753793316396637L;
679
680 private BigInteger y;
681 private DSAParams params;
682 private byte[] encoded;
683 P11DSAPublicKey(Session session, long keyID, String algorithm,
684 int keyLength, CK_ATTRIBUTE[] attributes) {
685 super(PUBLIC, session, keyID, algorithm, keyLength, attributes);
686 }
687 private synchronized void fetchValues() {
688 token.ensureValid();
689 if (y != null) {
690 return;
691 }
692 CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {
693 new CK_ATTRIBUTE(CKA_VALUE),
694 new CK_ATTRIBUTE(CKA_PRIME),
695 new CK_ATTRIBUTE(CKA_SUBPRIME),
696 new CK_ATTRIBUTE(CKA_BASE),
697 };
698 fetchAttributes(attributes);
699 y = attributes[0].getBigInteger();
700 params = new DSAParameterSpec(
701 attributes[1].getBigInteger(),
702 attributes[2].getBigInteger(),
703 attributes[3].getBigInteger()
704 );
705 }
727 }
728 public DSAParams getParams() {
729 fetchValues();
730 return params;
731 }
732 public String toString() {
733 fetchValues();
734 return super.toString() + "\n y: " + y + "\n p: " + params.getP()
735 + "\n q: " + params.getQ() + "\n g: " + params.getG();
736 }
737 }
738
739 private static final class P11DSAPrivateKey extends P11Key
740 implements DSAPrivateKey {
741 private static final long serialVersionUID = 3119629997181999389L;
742
743 private BigInteger x;
744 private DSAParams params;
745 private byte[] encoded;
746 P11DSAPrivateKey(Session session, long keyID, String algorithm,
747 int keyLength, CK_ATTRIBUTE[] attributes) {
748 super(PRIVATE, session, keyID, algorithm, keyLength, attributes);
749 }
750 private synchronized void fetchValues() {
751 token.ensureValid();
752 if (x != null) {
753 return;
754 }
755 CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {
756 new CK_ATTRIBUTE(CKA_VALUE),
757 new CK_ATTRIBUTE(CKA_PRIME),
758 new CK_ATTRIBUTE(CKA_SUBPRIME),
759 new CK_ATTRIBUTE(CKA_BASE),
760 };
761 fetchAttributes(attributes);
762 x = attributes[0].getBigInteger();
763 params = new DSAParameterSpec(
764 attributes[1].getBigInteger(),
765 attributes[2].getBigInteger(),
766 attributes[3].getBigInteger()
767 );
768 }
785 return encoded;
786 }
787 public BigInteger getX() {
788 fetchValues();
789 return x;
790 }
791 public DSAParams getParams() {
792 fetchValues();
793 return params;
794 }
795 }
796
797 private static final class P11DHPrivateKey extends P11Key
798 implements DHPrivateKey {
799 private static final long serialVersionUID = -1698576167364928838L;
800
801 private BigInteger x;
802 private DHParameterSpec params;
803 private byte[] encoded;
804 P11DHPrivateKey(Session session, long keyID, String algorithm,
805 int keyLength, CK_ATTRIBUTE[] attributes) {
806 super(PRIVATE, session, keyID, algorithm, keyLength, attributes);
807 }
808 private synchronized void fetchValues() {
809 token.ensureValid();
810 if (x != null) {
811 return;
812 }
813 CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {
814 new CK_ATTRIBUTE(CKA_VALUE),
815 new CK_ATTRIBUTE(CKA_PRIME),
816 new CK_ATTRIBUTE(CKA_BASE),
817 };
818 fetchAttributes(attributes);
819 x = attributes[0].getBigInteger();
820 params = new DHParameterSpec(
821 attributes[1].getBigInteger(),
822 attributes[2].getBigInteger()
823 );
824 }
825 public String getFormat() {
826 token.ensureValid();
867 if (!(obj instanceof DHPrivateKey)) {
868 return false;
869 }
870 fetchValues();
871 DHPrivateKey other = (DHPrivateKey) obj;
872 DHParameterSpec otherParams = other.getParams();
873 return ((this.x.compareTo(other.getX()) == 0) &&
874 (this.params.getP().compareTo(otherParams.getP()) == 0) &&
875 (this.params.getG().compareTo(otherParams.getG()) == 0));
876 }
877 }
878
879 private static final class P11DHPublicKey extends P11Key
880 implements DHPublicKey {
881 static final long serialVersionUID = -598383872153843657L;
882
883 private BigInteger y;
884 private DHParameterSpec params;
885 private byte[] encoded;
886 P11DHPublicKey(Session session, long keyID, String algorithm,
887 int keyLength, CK_ATTRIBUTE[] attributes) {
888 super(PUBLIC, session, keyID, algorithm, keyLength, attributes);
889 }
890 private synchronized void fetchValues() {
891 token.ensureValid();
892 if (y != null) {
893 return;
894 }
895 CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {
896 new CK_ATTRIBUTE(CKA_VALUE),
897 new CK_ATTRIBUTE(CKA_PRIME),
898 new CK_ATTRIBUTE(CKA_BASE),
899 };
900 fetchAttributes(attributes);
901 y = attributes[0].getBigInteger();
902 params = new DHParameterSpec(
903 attributes[1].getBigInteger(),
904 attributes[2].getBigInteger()
905 );
906 }
907 public String getFormat() {
908 token.ensureValid();
954 if (!(obj instanceof DHPublicKey)) {
955 return false;
956 }
957 fetchValues();
958 DHPublicKey other = (DHPublicKey) obj;
959 DHParameterSpec otherParams = other.getParams();
960 return ((this.y.compareTo(other.getY()) == 0) &&
961 (this.params.getP().compareTo(otherParams.getP()) == 0) &&
962 (this.params.getG().compareTo(otherParams.getG()) == 0));
963 }
964 }
965
966 private static final class P11ECPrivateKey extends P11Key
967 implements ECPrivateKey {
968 private static final long serialVersionUID = -7786054399510515515L;
969
970 private BigInteger s;
971 private ECParameterSpec params;
972 private byte[] encoded;
973 P11ECPrivateKey(Session session, long keyID, String algorithm,
974 int keyLength, CK_ATTRIBUTE[] attributes) {
975 super(PRIVATE, session, keyID, algorithm, keyLength, attributes);
976 }
977 private synchronized void fetchValues() {
978 token.ensureValid();
979 if (s != null) {
980 return;
981 }
982 CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {
983 new CK_ATTRIBUTE(CKA_VALUE),
984 new CK_ATTRIBUTE(CKA_EC_PARAMS, params),
985 };
986 fetchAttributes(attributes);
987 s = attributes[0].getBigInteger();
988 try {
989 params = P11ECKeyFactory.decodeParameters
990 (attributes[1].getByteArray());
991 } catch (Exception e) {
992 throw new RuntimeException("Could not parse key values", e);
993 }
994 }
995 public String getFormat() {
1010 return encoded;
1011 }
1012 public BigInteger getS() {
1013 fetchValues();
1014 return s;
1015 }
1016 public ECParameterSpec getParams() {
1017 fetchValues();
1018 return params;
1019 }
1020 }
1021
1022 private static final class P11ECPublicKey extends P11Key
1023 implements ECPublicKey {
1024 private static final long serialVersionUID = -6371481375154806089L;
1025
1026 private ECPoint w;
1027 private ECParameterSpec params;
1028 private byte[] encoded;
1029 P11ECPublicKey(Session session, long keyID, String algorithm,
1030 int keyLength, CK_ATTRIBUTE[] attributes) {
1031 super(PUBLIC, session, keyID, algorithm, keyLength, attributes);
1032 }
1033 private synchronized void fetchValues() {
1034 token.ensureValid();
1035 if (w != null) {
1036 return;
1037 }
1038 CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {
1039 new CK_ATTRIBUTE(CKA_EC_POINT),
1040 new CK_ATTRIBUTE(CKA_EC_PARAMS),
1041 };
1042 fetchAttributes(attributes);
1043
1044 try {
1045 params = P11ECKeyFactory.decodeParameters
1046 (attributes[1].getByteArray());
1047 byte[] ecKey = attributes[0].getByteArray();
1048
1049 // Check whether the X9.63 encoding of an EC point is wrapped
1050 // in an ASN.1 OCTET STRING
1051 if (!token.config.getUseEcX963Encoding()) {
1109 implements Comparable<SessionKeyRef> {
1110 private static ReferenceQueue<P11Key> refQueue =
1111 new ReferenceQueue<P11Key>();
1112 private static Set<SessionKeyRef> refList =
1113 Collections.synchronizedSortedSet(new TreeSet<SessionKeyRef>());
1114
1115 static ReferenceQueue<P11Key> referenceQueue() {
1116 return refQueue;
1117 }
1118
1119 private static void drainRefQueueBounded() {
1120 Session sess = null;
1121 Token tkn = null;
1122 while (true) {
1123 SessionKeyRef next = (SessionKeyRef) refQueue.poll();
1124 if (next == null) {
1125 break;
1126 }
1127
1128 // If the token is still valid, try to remove the object
1129 if (next.session.token.isValid()) {
1130 // If this key's token is the same as the previous key, the
1131 // same session can be used for C_DestroyObject.
1132 try {
1133 if (next.session.token != tkn || sess == null) {
1134 // Release session if not using previous token
1135 if (tkn != null && sess != null) {
1136 tkn.releaseSession(sess);
1137 sess = null;
1138 }
1139
1140 tkn = next.session.token;
1141 sess = tkn.getOpSession();
1142 }
1143 next.disposeNative(sess);
1144 } catch (PKCS11Exception e) {
1145 // ignore
1146 }
1147 }
1148 // Regardless of native results, dispose of java references
1149 next.dispose();
1150 }
1151
1152 if (tkn != null && sess != null) {
1153 tkn.releaseSession(sess);
1154 }
1155 }
1156
1157 // handle to the native key
1158 private long keyID;
1159 private Session session;
1160
1161 SessionKeyRef(P11Key key , long keyID, Session session) {
1162 super(key, refQueue);
1163 this.keyID = keyID;
1164 this.session = session;
1165 this.session.addObject();
1166 refList.add(this);
1167 drainRefQueueBounded();
1168 }
1169
1170 private void disposeNative(Session s) throws PKCS11Exception {
1171 session.token.p11.C_DestroyObject(s.id(), keyID);
1172 }
1173
1174 private void dispose() {
1175 refList.remove(this);
1176 this.clear();
1177 session.removeObject();
1178 }
1179
1180 public int compareTo(SessionKeyRef other) {
1181 if (this.keyID == other.keyID) {
1182 return 0;
1183 } else {
1184 return (this.keyID < other.keyID) ? -1 : 1;
1185 }
1186 }
1187 }
|
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.Debug;
52 import sun.security.util.DerValue;
53 import sun.security.util.Length;
54 import sun.security.util.ECUtil;
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 // key id
88 long keyID;
89
90 // effective key length of the key, e.g. 56 for a DES key
91 final int keyLength;
92
93 // flags indicating whether the key is a token object, sensitive, extractable
94 final boolean tokenObject, sensitive, extractable;
95
96 // phantom reference notification clean up for session keys
97 private final SessionKeyRef sessionKeyRef;
98
99 // Temporary native keys feature enabled or not.
100 // When enabled, keys are packed and stored in the Java heap
101 // while not in use.
102 private boolean tmpNativeKey;
103
104 private int nativeKeyRefCounting;
105
106 private static long nativeKeyWrapperKeyID = -1;
107
108 // Buffer to hold native key objects info in Java heap in order to
109 // re-create them if needed.
110 private byte[] nativeKeyInfo;
111
112 P11Key(String type, Session session, long keyID, String algorithm,
113 int keyLength, CK_ATTRIBUTE[] attributes, boolean tmpNativeKey) {
114 this.type = type;
115 this.token = session.token;
116 this.keyID = keyID;
117 this.algorithm = algorithm;
118 this.keyLength = keyLength;
119 boolean tokenObject = false;
120 boolean sensitive = false;
121 boolean extractable = true;
122 int n = (attributes == null) ? 0 : attributes.length;
123 for (int i = 0; i < n; i++) {
124 CK_ATTRIBUTE attr = attributes[i];
125 if (attr.type == CKA_TOKEN) {
126 tokenObject = attr.getBoolean();
127 } else if (attr.type == CKA_SENSITIVE) {
128 sensitive = attr.getBoolean();
129 } else if (attr.type == CKA_EXTRACTABLE) {
130 extractable = attr.getBoolean();
131 }
132 }
133 this.tokenObject = tokenObject;
134 this.sensitive = sensitive;
135 this.extractable = extractable;
136 if (token.tokenInfo.label[0] == 'N'
137 && token.tokenInfo.label[1] == 'S'
138 && token.tokenInfo.label[2] == 'S') {
139 this.tmpNativeKey = tmpNativeKey;
140 } else {
141 // Disabled if token is not NSS
142 this.tmpNativeKey = false;
143 }
144 if (!extractable || tokenObject) {
145 this.tmpNativeKey = false;
146 }
147 if (this.tmpNativeKey) {
148 nativeKeyRefCounting = 0;
149 try {
150 if (sensitive && nativeKeyWrapperKeyID == -1) {
151 synchronized(P11Key.class) {
152 if (nativeKeyWrapperKeyID == -1) {
153 // Create a global wrapping/unwrapping key
154 CK_ATTRIBUTE[] wrappingAttributes = token.getAttributes
155 (O_GENERATE, CKO_SECRET_KEY, CKK_AES, new CK_ATTRIBUTE[] {
156 new CK_ATTRIBUTE(CKA_CLASS, CKO_SECRET_KEY),
157 new CK_ATTRIBUTE(CKA_VALUE_LEN, 256 >> 3),
158 });
159 Session wrappingSession = null;
160 try {
161 wrappingSession = token.getObjSession();
162 nativeKeyWrapperKeyID = token.p11.C_GenerateKey(
163 wrappingSession.id(),
164 new CK_MECHANISM(CKM_AES_KEY_GEN),
165 wrappingAttributes);
166 } finally {
167 token.releaseSession(wrappingSession);
168 }
169 }
170 }
171 }
172 nativeKeyInfo = token.p11.getNativeKeyInfo(session.id(),
173 keyID, nativeKeyWrapperKeyID);
174 if (nativeKeyInfo != null && nativeKeyInfo.length > 0) {
175 destroyNativeKey();
176 // If extracted, it's not a token object anymore
177 tokenObject = false;
178 } else {
179 this.tmpNativeKey = false;
180 }
181 } catch (PKCS11Exception e) {
182 // Unexpected behaviour when trying to manage the key life-time.
183 // Don't manage the native key.
184 this.tmpNativeKey = false;
185 }
186 }
187 if (tokenObject == false) {
188 sessionKeyRef = new SessionKeyRef(this, this.keyID, session);
189 } else {
190 sessionKeyRef = null;
191 }
192 }
193
194 public void incNativeKeyRef() throws PKCS11Exception {
195 if (tmpNativeKey) {
196 synchronized(this) {
197 if (++nativeKeyRefCounting == 1 && nativeKeyInfo != null) {
198 // Create a Native Key
199 Session session = null;
200 try {
201 session = token.getObjSession();
202 keyID = token.p11.createNativeKey(session.id(),
203 nativeKeyInfo, nativeKeyWrapperKeyID);
204 if (sessionKeyRef != null) {
205 sessionKeyRef.setKeyIDAndSession(keyID, session);
206 }
207 } catch (PKCS11Exception e) {
208 nativeKeyRefCounting--;
209 throw e;
210 } finally {
211 token.releaseSession(session);
212 }
213 }
214 }
215 }
216 }
217
218 public void makeNativeKeyPersistent() throws PKCS11Exception {
219 if (tmpNativeKey) {
220 synchronized(this) {
221 if (nativeKeyRefCounting == 0) {
222 this.incNativeKeyRef();
223 }
224
225 // This write is not sync protected because reads are done out
226 // of the synchronization block. It's just a best-effort.
227 tmpNativeKey = false;
228
229 // This write is sync protected and provides the real guarantee
230 // to avoid native key creation or destruction.
231 nativeKeyInfo = null;
232 }
233 }
234 }
235
236 public void decNativeKeyRef() {
237 if (tmpNativeKey) {
238 synchronized(this) {
239 if(--nativeKeyRefCounting == 0 && nativeKeyInfo != null) {
240 try {
241 destroyNativeKey();
242 } catch (PKCS11Exception e) {
243 // This is a best-effort.
244 }
245 }
246 if (nativeKeyRefCounting < 0) {
247 nativeKeyRefCounting = 0;
248 }
249 }
250 }
251 }
252
253 private void destroyNativeKey() throws PKCS11Exception {
254 // There is no synchronization needed between
255 // SessionKeyRef.disposeNative and this method.
256 // When SessionKeyRef.disposeNative method is
257 // executed, no P11Key object exists.
258 Session session = null;
259 try {
260 session = token.getObjSession();
261 token.p11.C_DestroyObject(session.id(), keyID);
262 } finally {
263 if (sessionKeyRef != null) {
264 sessionKeyRef.setKeyIDAndSession(0, null);
265 }
266 keyID = 0;
267 token.releaseSession(session);
268 }
269 }
270
271 // see JCA spec
272 public final String getAlgorithm() {
273 token.ensureValid();
274 return algorithm;
275 }
276
277 // see JCA spec
278 public final byte[] getEncoded() {
279 byte[] b = getEncodedInternal();
280 return (b == null) ? null : b.clone();
281 }
282
283 abstract byte[] getEncodedInternal();
284
285 public boolean equals(Object obj) {
286 if (this == obj) {
287 return true;
288 }
289 // equals() should never throw exceptions
290 if (token.isValid() == false) {
368 public int length() {
369 return keyLength;
370 }
371
372 boolean isPublic() {
373 return type == PUBLIC;
374 }
375
376 boolean isPrivate() {
377 return type == PRIVATE;
378 }
379
380 boolean isSecret() {
381 return type == SECRET;
382 }
383
384 void fetchAttributes(CK_ATTRIBUTE[] attributes) {
385 Session tempSession = null;
386 try {
387 tempSession = token.getOpSession();
388 this.incNativeKeyRef();
389 try {
390 token.p11.C_GetAttributeValue(tempSession.id(), keyID,
391 attributes);
392 } finally {
393 this.decNativeKeyRef();
394 }
395 } catch (PKCS11Exception e) {
396 throw new ProviderException(e);
397 } finally {
398 token.releaseSession(tempSession);
399 }
400 }
401
402 private final static CK_ATTRIBUTE[] A0 = new CK_ATTRIBUTE[0];
403
404 private static CK_ATTRIBUTE[] getAttributes(Session session, long keyID,
405 CK_ATTRIBUTE[] knownAttributes, CK_ATTRIBUTE[] desiredAttributes) {
406 if (knownAttributes == null) {
407 knownAttributes = A0;
408 }
409 for (int i = 0; i < desiredAttributes.length; i++) {
410 // For each desired attribute, check to see if we have the value
411 // available already. If everything is here, we save a native call.
412 CK_ATTRIBUTE attr = desiredAttributes[i];
413 for (CK_ATTRIBUTE known : knownAttributes) {
414 if ((attr.type == known.type) && (known.pValue != null)) {
418 }
419 if (attr.pValue == null) {
420 // nothing found, need to call C_GetAttributeValue()
421 for (int j = 0; j < i; j++) {
422 // clear values copied from knownAttributes
423 desiredAttributes[j].pValue = null;
424 }
425 try {
426 session.token.p11.C_GetAttributeValue
427 (session.id(), keyID, desiredAttributes);
428 } catch (PKCS11Exception e) {
429 throw new ProviderException(e);
430 }
431 break; // break loop, goto return
432 }
433 }
434 return desiredAttributes;
435 }
436
437 static SecretKey secretKey(Session session, long keyID, String algorithm,
438 int keyLength, CK_ATTRIBUTE[] attributes, boolean tmpNativeKey) {
439 attributes = getAttributes(session, keyID, attributes, new CK_ATTRIBUTE[] {
440 new CK_ATTRIBUTE(CKA_TOKEN),
441 new CK_ATTRIBUTE(CKA_SENSITIVE),
442 new CK_ATTRIBUTE(CKA_EXTRACTABLE),
443 });
444 return new P11SecretKey(session, keyID, algorithm, keyLength,
445 attributes, tmpNativeKey);
446 }
447
448 static SecretKey masterSecretKey(Session session, long keyID, String algorithm,
449 int keyLength, CK_ATTRIBUTE[] attributes, int major, int minor,
450 boolean tmpNativeKey) {
451 attributes = getAttributes(session, keyID, attributes, new CK_ATTRIBUTE[] {
452 new CK_ATTRIBUTE(CKA_TOKEN),
453 new CK_ATTRIBUTE(CKA_SENSITIVE),
454 new CK_ATTRIBUTE(CKA_EXTRACTABLE),
455 });
456 return new P11TlsMasterSecretKey(
457 session, keyID, algorithm, keyLength, attributes, major,
458 minor, tmpNativeKey);
459 }
460
461 // we assume that all components of public keys are always accessible
462 static PublicKey publicKey(Session session, long keyID, String algorithm,
463 int keyLength, CK_ATTRIBUTE[] attributes, boolean tmpNativeKey) {
464 switch (algorithm) {
465 case "RSA":
466 return new P11RSAPublicKey(session, keyID, algorithm,
467 keyLength, attributes, tmpNativeKey);
468 case "DSA":
469 return new P11DSAPublicKey(session, keyID, algorithm,
470 keyLength, attributes, tmpNativeKey);
471 case "DH":
472 return new P11DHPublicKey(session, keyID, algorithm,
473 keyLength, attributes, tmpNativeKey);
474 case "EC":
475 return new P11ECPublicKey(session, keyID, algorithm,
476 keyLength, attributes, tmpNativeKey);
477 default:
478 throw new ProviderException
479 ("Unknown public key algorithm " + algorithm);
480 }
481 }
482
483 static PrivateKey privateKey(Session session, long keyID, String algorithm,
484 int keyLength, CK_ATTRIBUTE[] attributes, boolean tmpNativeKey) {
485 attributes = getAttributes(session, keyID, attributes, new CK_ATTRIBUTE[] {
486 new CK_ATTRIBUTE(CKA_TOKEN),
487 new CK_ATTRIBUTE(CKA_SENSITIVE),
488 new CK_ATTRIBUTE(CKA_EXTRACTABLE),
489 });
490 if (attributes[1].getBoolean() || (attributes[2].getBoolean() == false)) {
491 return new P11PrivateKey
492 (session, keyID, algorithm, keyLength, attributes, tmpNativeKey);
493 } else {
494 switch (algorithm) {
495 case "RSA":
496 // In order to decide if this is RSA CRT key, we first query
497 // and see if all extra CRT attributes are available.
498 CK_ATTRIBUTE[] attrs2 = new CK_ATTRIBUTE[] {
499 new CK_ATTRIBUTE(CKA_PUBLIC_EXPONENT),
500 new CK_ATTRIBUTE(CKA_PRIME_1),
501 new CK_ATTRIBUTE(CKA_PRIME_2),
502 new CK_ATTRIBUTE(CKA_EXPONENT_1),
503 new CK_ATTRIBUTE(CKA_EXPONENT_2),
504 new CK_ATTRIBUTE(CKA_COEFFICIENT),
505 };
506 boolean crtKey;
507 try {
508 session.token.p11.C_GetAttributeValue
509 (session.id(), keyID, attrs2);
510 crtKey = ((attrs2[0].pValue instanceof byte[]) &&
511 (attrs2[1].pValue instanceof byte[]) &&
512 (attrs2[2].pValue instanceof byte[]) &&
513 (attrs2[3].pValue instanceof byte[]) &&
514 (attrs2[4].pValue instanceof byte[]) &&
515 (attrs2[5].pValue instanceof byte[])) ;
516 } catch (PKCS11Exception e) {
517 // ignore, assume not available
518 crtKey = false;
519 }
520 if (crtKey) {
521 return new P11RSAPrivateKey(session, keyID, algorithm,
522 keyLength, attributes, attrs2, tmpNativeKey);
523 } else {
524 return new P11RSAPrivateNonCRTKey(session, keyID,
525 algorithm, keyLength, attributes, tmpNativeKey);
526 }
527 case "DSA":
528 return new P11DSAPrivateKey(session, keyID, algorithm,
529 keyLength, attributes, tmpNativeKey);
530 case "DH":
531 return new P11DHPrivateKey(session, keyID, algorithm,
532 keyLength, attributes, tmpNativeKey);
533 case "EC":
534 return new P11ECPrivateKey(session, keyID, algorithm,
535 keyLength, attributes, tmpNativeKey);
536 default:
537 throw new ProviderException
538 ("Unknown private key algorithm " + algorithm);
539 }
540 }
541 }
542
543 // class for sensitive and unextractable private keys
544 private static final class P11PrivateKey extends P11Key
545 implements PrivateKey {
546 private static final long serialVersionUID = -2138581185214187615L;
547
548 P11PrivateKey(Session session, long keyID, String algorithm,
549 int keyLength, CK_ATTRIBUTE[] attributes, boolean tmpNativeKey) {
550 super(PRIVATE, session, keyID, algorithm, keyLength, attributes,
551 tmpNativeKey);
552 }
553 // XXX temporary encoding for serialization purposes
554 public String getFormat() {
555 token.ensureValid();
556 return null;
557 }
558 byte[] getEncodedInternal() {
559 token.ensureValid();
560 return null;
561 }
562 }
563
564 private static class P11SecretKey extends P11Key implements SecretKey {
565 private static final long serialVersionUID = -7828241727014329084L;
566 private volatile byte[] encoded;
567 P11SecretKey(Session session, long keyID, String algorithm,
568 int keyLength, CK_ATTRIBUTE[] attributes, boolean tmpNativeKey) {
569 super(SECRET, session, keyID, algorithm, keyLength, attributes,
570 tmpNativeKey);
571 }
572 public String getFormat() {
573 token.ensureValid();
574 if (sensitive || (extractable == false)) {
575 return null;
576 } else {
577 return "RAW";
578 }
579 }
580 byte[] getEncodedInternal() {
581 token.ensureValid();
582 if (getFormat() == null) {
583 return null;
584 }
585 byte[] b = encoded;
586 if (b == null) {
587 synchronized (this) {
588 b = encoded;
589 if (b == null) {
590 Session tempSession = null;
591 try {
592 tempSession = token.getOpSession();
593 CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {
594 new CK_ATTRIBUTE(CKA_VALUE),
595 };
596 this.incNativeKeyRef();
597 try {
598 token.p11.C_GetAttributeValue
599 (tempSession.id(), keyID, attributes);
600 } finally {
601 this.decNativeKeyRef();
602 }
603 b = attributes[0].getByteArray();
604 } catch (PKCS11Exception e) {
605 throw new ProviderException(e);
606 } finally {
607 token.releaseSession(tempSession);
608 }
609 encoded = b;
610 }
611 }
612 }
613 return b;
614 }
615 }
616
617 @SuppressWarnings("deprecation")
618 private static class P11TlsMasterSecretKey extends P11SecretKey
619 implements TlsMasterSecret {
620 private static final long serialVersionUID = -1318560923770573441L;
621
622 private final int majorVersion, minorVersion;
623 P11TlsMasterSecretKey(Session session, long keyID, String algorithm,
624 int keyLength, CK_ATTRIBUTE[] attributes, int major, int minor,
625 boolean tmpNativeKey) {
626 super(session, keyID, algorithm, keyLength, attributes, tmpNativeKey);
627 this.majorVersion = major;
628 this.minorVersion = minor;
629 }
630 public int getMajorVersion() {
631 return majorVersion;
632 }
633
634 public int getMinorVersion() {
635 return minorVersion;
636 }
637 }
638
639 // RSA CRT private key
640 private static final class P11RSAPrivateKey extends P11Key
641 implements RSAPrivateCrtKey {
642 private static final long serialVersionUID = 9215872438913515220L;
643
644 private BigInteger n, e, d, p, q, pe, qe, coeff;
645 private byte[] encoded;
646 P11RSAPrivateKey(Session session, long keyID, String algorithm,
647 int keyLength, CK_ATTRIBUTE[] attrs, CK_ATTRIBUTE[] crtAttrs,
648 boolean tmpNativeKey) {
649 super(PRIVATE, session, keyID, algorithm, keyLength, attrs,
650 tmpNativeKey);
651
652 for (CK_ATTRIBUTE a : crtAttrs) {
653 if (a.type == CKA_PUBLIC_EXPONENT) {
654 e = a.getBigInteger();
655 } else if (a.type == CKA_PRIME_1) {
656 p = a.getBigInteger();
657 } else if (a.type == CKA_PRIME_2) {
658 q = a.getBigInteger();
659 } else if (a.type == CKA_EXPONENT_1) {
660 pe = a.getBigInteger();
661 } else if (a.type == CKA_EXPONENT_2) {
662 qe = a.getBigInteger();
663 } else if (a.type == CKA_COEFFICIENT) {
664 coeff = a.getBigInteger();
665 }
666 }
667 }
668 private synchronized void fetchValues() {
669 token.ensureValid();
670 if (n != null) {
716 }
717 public BigInteger getPrimeExponentP() {
718 return pe;
719 }
720 public BigInteger getPrimeExponentQ() {
721 return qe;
722 }
723 public BigInteger getCrtCoefficient() {
724 return coeff;
725 }
726 }
727
728 // RSA non-CRT private key
729 private static final class P11RSAPrivateNonCRTKey extends P11Key
730 implements RSAPrivateKey {
731 private static final long serialVersionUID = 1137764983777411481L;
732
733 private BigInteger n, d;
734 private byte[] encoded;
735 P11RSAPrivateNonCRTKey(Session session, long keyID, String algorithm,
736 int keyLength, CK_ATTRIBUTE[] attributes, boolean tmpNativeKey) {
737 super(PRIVATE, session, keyID, algorithm, keyLength, attributes,
738 tmpNativeKey);
739 }
740 private synchronized void fetchValues() {
741 token.ensureValid();
742 if (n != null) {
743 return;
744 }
745 CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {
746 new CK_ATTRIBUTE(CKA_MODULUS),
747 new CK_ATTRIBUTE(CKA_PRIVATE_EXPONENT),
748 };
749 fetchAttributes(attributes);
750 n = attributes[0].getBigInteger();
751 d = attributes[1].getBigInteger();
752 }
753 public String getFormat() {
754 token.ensureValid();
755 return "PKCS#8";
756 }
757 synchronized byte[] getEncodedInternal() {
758 token.ensureValid();
770 }
771 }
772 return encoded;
773 }
774 public BigInteger getModulus() {
775 fetchValues();
776 return n;
777 }
778 public BigInteger getPrivateExponent() {
779 fetchValues();
780 return d;
781 }
782 }
783
784 private static final class P11RSAPublicKey extends P11Key
785 implements RSAPublicKey {
786 private static final long serialVersionUID = -826726289023854455L;
787 private BigInteger n, e;
788 private byte[] encoded;
789 P11RSAPublicKey(Session session, long keyID, String algorithm,
790 int keyLength, CK_ATTRIBUTE[] attributes, boolean tmpNativeKey) {
791 super(PUBLIC, session, keyID, algorithm, keyLength, attributes,
792 tmpNativeKey);
793 }
794 private synchronized void fetchValues() {
795 token.ensureValid();
796 if (n != null) {
797 return;
798 }
799 CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {
800 new CK_ATTRIBUTE(CKA_MODULUS),
801 new CK_ATTRIBUTE(CKA_PUBLIC_EXPONENT),
802 };
803 fetchAttributes(attributes);
804 n = attributes[0].getBigInteger();
805 e = attributes[1].getBigInteger();
806 }
807 public String getFormat() {
808 token.ensureValid();
809 return "X.509";
810 }
811 synchronized byte[] getEncodedInternal() {
812 token.ensureValid();
827 }
828 public BigInteger getPublicExponent() {
829 fetchValues();
830 return e;
831 }
832 public String toString() {
833 fetchValues();
834 return super.toString() + "\n modulus: " + n
835 + "\n public exponent: " + e;
836 }
837 }
838
839 private static final class P11DSAPublicKey extends P11Key
840 implements DSAPublicKey {
841 private static final long serialVersionUID = 5989753793316396637L;
842
843 private BigInteger y;
844 private DSAParams params;
845 private byte[] encoded;
846 P11DSAPublicKey(Session session, long keyID, String algorithm,
847 int keyLength, CK_ATTRIBUTE[] attributes, boolean tmpNativeKey) {
848 super(PUBLIC, session, keyID, algorithm, keyLength, attributes,
849 tmpNativeKey);
850 }
851 private synchronized void fetchValues() {
852 token.ensureValid();
853 if (y != null) {
854 return;
855 }
856 CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {
857 new CK_ATTRIBUTE(CKA_VALUE),
858 new CK_ATTRIBUTE(CKA_PRIME),
859 new CK_ATTRIBUTE(CKA_SUBPRIME),
860 new CK_ATTRIBUTE(CKA_BASE),
861 };
862 fetchAttributes(attributes);
863 y = attributes[0].getBigInteger();
864 params = new DSAParameterSpec(
865 attributes[1].getBigInteger(),
866 attributes[2].getBigInteger(),
867 attributes[3].getBigInteger()
868 );
869 }
891 }
892 public DSAParams getParams() {
893 fetchValues();
894 return params;
895 }
896 public String toString() {
897 fetchValues();
898 return super.toString() + "\n y: " + y + "\n p: " + params.getP()
899 + "\n q: " + params.getQ() + "\n g: " + params.getG();
900 }
901 }
902
903 private static final class P11DSAPrivateKey extends P11Key
904 implements DSAPrivateKey {
905 private static final long serialVersionUID = 3119629997181999389L;
906
907 private BigInteger x;
908 private DSAParams params;
909 private byte[] encoded;
910 P11DSAPrivateKey(Session session, long keyID, String algorithm,
911 int keyLength, CK_ATTRIBUTE[] attributes, boolean tmpNativeKey) {
912 super(PRIVATE, session, keyID, algorithm, keyLength, attributes,
913 tmpNativeKey);
914 }
915 private synchronized void fetchValues() {
916 token.ensureValid();
917 if (x != null) {
918 return;
919 }
920 CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {
921 new CK_ATTRIBUTE(CKA_VALUE),
922 new CK_ATTRIBUTE(CKA_PRIME),
923 new CK_ATTRIBUTE(CKA_SUBPRIME),
924 new CK_ATTRIBUTE(CKA_BASE),
925 };
926 fetchAttributes(attributes);
927 x = attributes[0].getBigInteger();
928 params = new DSAParameterSpec(
929 attributes[1].getBigInteger(),
930 attributes[2].getBigInteger(),
931 attributes[3].getBigInteger()
932 );
933 }
950 return encoded;
951 }
952 public BigInteger getX() {
953 fetchValues();
954 return x;
955 }
956 public DSAParams getParams() {
957 fetchValues();
958 return params;
959 }
960 }
961
962 private static final class P11DHPrivateKey extends P11Key
963 implements DHPrivateKey {
964 private static final long serialVersionUID = -1698576167364928838L;
965
966 private BigInteger x;
967 private DHParameterSpec params;
968 private byte[] encoded;
969 P11DHPrivateKey(Session session, long keyID, String algorithm,
970 int keyLength, CK_ATTRIBUTE[] attributes, boolean tmpNativeKey) {
971 super(PRIVATE, session, keyID, algorithm, keyLength, attributes,
972 tmpNativeKey);
973 }
974 private synchronized void fetchValues() {
975 token.ensureValid();
976 if (x != null) {
977 return;
978 }
979 CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {
980 new CK_ATTRIBUTE(CKA_VALUE),
981 new CK_ATTRIBUTE(CKA_PRIME),
982 new CK_ATTRIBUTE(CKA_BASE),
983 };
984 fetchAttributes(attributes);
985 x = attributes[0].getBigInteger();
986 params = new DHParameterSpec(
987 attributes[1].getBigInteger(),
988 attributes[2].getBigInteger()
989 );
990 }
991 public String getFormat() {
992 token.ensureValid();
1033 if (!(obj instanceof DHPrivateKey)) {
1034 return false;
1035 }
1036 fetchValues();
1037 DHPrivateKey other = (DHPrivateKey) obj;
1038 DHParameterSpec otherParams = other.getParams();
1039 return ((this.x.compareTo(other.getX()) == 0) &&
1040 (this.params.getP().compareTo(otherParams.getP()) == 0) &&
1041 (this.params.getG().compareTo(otherParams.getG()) == 0));
1042 }
1043 }
1044
1045 private static final class P11DHPublicKey extends P11Key
1046 implements DHPublicKey {
1047 static final long serialVersionUID = -598383872153843657L;
1048
1049 private BigInteger y;
1050 private DHParameterSpec params;
1051 private byte[] encoded;
1052 P11DHPublicKey(Session session, long keyID, String algorithm,
1053 int keyLength, CK_ATTRIBUTE[] attributes, boolean tmpNativeKey) {
1054 super(PUBLIC, session, keyID, algorithm, keyLength, attributes,
1055 tmpNativeKey);
1056 }
1057 private synchronized void fetchValues() {
1058 token.ensureValid();
1059 if (y != null) {
1060 return;
1061 }
1062 CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {
1063 new CK_ATTRIBUTE(CKA_VALUE),
1064 new CK_ATTRIBUTE(CKA_PRIME),
1065 new CK_ATTRIBUTE(CKA_BASE),
1066 };
1067 fetchAttributes(attributes);
1068 y = attributes[0].getBigInteger();
1069 params = new DHParameterSpec(
1070 attributes[1].getBigInteger(),
1071 attributes[2].getBigInteger()
1072 );
1073 }
1074 public String getFormat() {
1075 token.ensureValid();
1121 if (!(obj instanceof DHPublicKey)) {
1122 return false;
1123 }
1124 fetchValues();
1125 DHPublicKey other = (DHPublicKey) obj;
1126 DHParameterSpec otherParams = other.getParams();
1127 return ((this.y.compareTo(other.getY()) == 0) &&
1128 (this.params.getP().compareTo(otherParams.getP()) == 0) &&
1129 (this.params.getG().compareTo(otherParams.getG()) == 0));
1130 }
1131 }
1132
1133 private static final class P11ECPrivateKey extends P11Key
1134 implements ECPrivateKey {
1135 private static final long serialVersionUID = -7786054399510515515L;
1136
1137 private BigInteger s;
1138 private ECParameterSpec params;
1139 private byte[] encoded;
1140 P11ECPrivateKey(Session session, long keyID, String algorithm,
1141 int keyLength, CK_ATTRIBUTE[] attributes, boolean tmpNativeKey) {
1142 super(PRIVATE, session, keyID, algorithm, keyLength, attributes,
1143 tmpNativeKey);
1144 }
1145 private synchronized void fetchValues() {
1146 token.ensureValid();
1147 if (s != null) {
1148 return;
1149 }
1150 CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {
1151 new CK_ATTRIBUTE(CKA_VALUE),
1152 new CK_ATTRIBUTE(CKA_EC_PARAMS, params),
1153 };
1154 fetchAttributes(attributes);
1155 s = attributes[0].getBigInteger();
1156 try {
1157 params = P11ECKeyFactory.decodeParameters
1158 (attributes[1].getByteArray());
1159 } catch (Exception e) {
1160 throw new RuntimeException("Could not parse key values", e);
1161 }
1162 }
1163 public String getFormat() {
1178 return encoded;
1179 }
1180 public BigInteger getS() {
1181 fetchValues();
1182 return s;
1183 }
1184 public ECParameterSpec getParams() {
1185 fetchValues();
1186 return params;
1187 }
1188 }
1189
1190 private static final class P11ECPublicKey extends P11Key
1191 implements ECPublicKey {
1192 private static final long serialVersionUID = -6371481375154806089L;
1193
1194 private ECPoint w;
1195 private ECParameterSpec params;
1196 private byte[] encoded;
1197 P11ECPublicKey(Session session, long keyID, String algorithm,
1198 int keyLength, CK_ATTRIBUTE[] attributes, boolean tmpNativeKey) {
1199 super(PUBLIC, session, keyID, algorithm, keyLength, attributes,
1200 tmpNativeKey);
1201 }
1202 private synchronized void fetchValues() {
1203 token.ensureValid();
1204 if (w != null) {
1205 return;
1206 }
1207 CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {
1208 new CK_ATTRIBUTE(CKA_EC_POINT),
1209 new CK_ATTRIBUTE(CKA_EC_PARAMS),
1210 };
1211 fetchAttributes(attributes);
1212
1213 try {
1214 params = P11ECKeyFactory.decodeParameters
1215 (attributes[1].getByteArray());
1216 byte[] ecKey = attributes[0].getByteArray();
1217
1218 // Check whether the X9.63 encoding of an EC point is wrapped
1219 // in an ASN.1 OCTET STRING
1220 if (!token.config.getUseEcX963Encoding()) {
1278 implements Comparable<SessionKeyRef> {
1279 private static ReferenceQueue<P11Key> refQueue =
1280 new ReferenceQueue<P11Key>();
1281 private static Set<SessionKeyRef> refList =
1282 Collections.synchronizedSortedSet(new TreeSet<SessionKeyRef>());
1283
1284 static ReferenceQueue<P11Key> referenceQueue() {
1285 return refQueue;
1286 }
1287
1288 private static void drainRefQueueBounded() {
1289 Session sess = null;
1290 Token tkn = null;
1291 while (true) {
1292 SessionKeyRef next = (SessionKeyRef) refQueue.poll();
1293 if (next == null) {
1294 break;
1295 }
1296
1297 // If the token is still valid, try to remove the object
1298 if (next.session != null && next.session.token.isValid()) {
1299 // If this key's token is the same as the previous key, the
1300 // same session can be used for C_DestroyObject.
1301 try {
1302 if (next.session.token != tkn || sess == null) {
1303 // Release session if not using previous token
1304 if (tkn != null && sess != null) {
1305 tkn.releaseSession(sess);
1306 sess = null;
1307 }
1308
1309 tkn = next.session.token;
1310 sess = tkn.getOpSession();
1311 }
1312 next.disposeNative(sess);
1313 } catch (PKCS11Exception e) {
1314 // ignore
1315 }
1316 }
1317 // Regardless of native results, dispose of java references
1318 next.dispose();
1319 }
1320
1321 if (tkn != null && sess != null) {
1322 tkn.releaseSession(sess);
1323 }
1324 }
1325
1326 // handle to the native key
1327 private long keyID;
1328 private Session session;
1329
1330 SessionKeyRef(P11Key key , long keyID, Session session) {
1331 super(key, refQueue);
1332 setKeyIDAndSession(keyID, session);
1333 refList.add(this);
1334 drainRefQueueBounded();
1335 }
1336
1337 public void setKeyIDAndSession(long keyID, Session session) {
1338 if (this.session != null) {
1339 this.session.removeObject();
1340 }
1341 this.keyID = keyID;
1342 this.session = session;
1343 if (this.session != null) {
1344 this.session.addObject();
1345 }
1346 }
1347
1348 private void disposeNative(Session s) throws PKCS11Exception {
1349 if(this.session != null) {
1350 session.token.p11.C_DestroyObject(s.id(), keyID);
1351 }
1352 }
1353
1354 private void dispose() {
1355 refList.remove(this);
1356 this.clear();
1357 setKeyIDAndSession(0, null);
1358 }
1359
1360 public int compareTo(SessionKeyRef other) {
1361 if (this.keyID == other.keyID) {
1362 return 0;
1363 } else {
1364 return (this.keyID < other.keyID) ? -1 : 1;
1365 }
1366 }
1367 }
|