History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/sun/security/pkcs11/P11Key.java (1 of 18352 files). Show all

Unified · Split

java/pkg/sun/security/pkcs11/P11Key.java+1132−0
@@ -0,0 +1,1132 @@
1/*
2 * Copyright (c) 2003, 2011, 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
26package sun.security.pkcs11;
27
28import java.io.*;
29import java.lang.ref.*;
30import java.math.BigInteger;
31import java.util.*;
32
33import java.security.*;
34import java.security.interfaces.*;
35import java.security.spec.*;
36
37import javax.crypto.*;
38import javax.crypto.interfaces.*;
39import javax.crypto.spec.*;
40
41import sun.security.rsa.RSAPublicKeyImpl;
42
43import sun.security.internal.interfaces.TlsMasterSecret;
44
45import sun.security.pkcs11.wrapper.*;
46import static sun.security.pkcs11.wrapper.PKCS11Constants.*;
47
48import sun.security.util.DerValue;
49
50/**
51 * Key implementation classes.
52 *
53 * In PKCS#11, the components of private and secret keys may or may not
54 * be accessible. If they are, we use the algorithm specific key classes
55 * (e.g. DSAPrivateKey) for compatibility with existing applications.
56 * If the components are not accessible, we use a generic class that
57 * only implements PrivateKey (or SecretKey). Whether the components of a
58 * key are extractable is automatically determined when the key object is
59 * created.
60 *
61 * @author Andreas Sterbenz
62 * @since 1.5
63 */
64abstract class P11Key implements Key {
65
66 private final static String PUBLIC = "public";
67 private final static String PRIVATE = "private";
68 private final static String SECRET = "secret";
69
70 // type of key, one of (PUBLIC, PRIVATE, SECRET)
71 final String type;
72
73 // token instance
74 final Token token;
75
76 // algorithm name, returned by getAlgorithm(), etc.
77 final String algorithm;
78
79 // key id
80 final long keyID;
81
82 // effective key length of the key, e.g. 56 for a DES key
83 final int keyLength;
84
85 // flags indicating whether the key is a token object, sensitive, extractable
86 final boolean tokenObject, sensitive, extractable;
87
88 // phantom reference notification clean up for session keys
89 private final SessionKeyRef sessionKeyRef;
90
91 P11Key(String type, Session session, long keyID, String algorithm,
92 int keyLength, CK_ATTRIBUTE[] attributes) {
93 this.type = type;
94 this.token = session.token;
95 this.keyID = keyID;
96 this.algorithm = algorithm;
97 this.keyLength = keyLength;
98 boolean tokenObject = false;
99 boolean sensitive = false;
100 boolean extractable = true;
101 int n = (attributes == null) ? 0 : attributes.length;
102 for (int i = 0; i < n; i++) {
103 CK_ATTRIBUTE attr = attributes[i];
104 if (attr.type == CKA_TOKEN) {
105 tokenObject = attr.getBoolean();
106 } else if (attr.type == CKA_SENSITIVE) {
107 sensitive = attr.getBoolean();
108 } else if (attr.type == CKA_EXTRACTABLE) {
109 extractable = attr.getBoolean();
110 }
111 }
112 this.tokenObject = tokenObject;
113 this.sensitive = sensitive;
114 this.extractable = extractable;
115 if (tokenObject == false) {
116 sessionKeyRef = new SessionKeyRef(this, keyID, session);
117 } else {
118 sessionKeyRef = null;
119 }
120 }
121
122 // see JCA spec
123 public final String getAlgorithm() {
124 token.ensureValid();
125 return algorithm;
126 }
127
128 // see JCA spec
129 public final byte[] getEncoded() {
130 byte[] b = getEncodedInternal();
131 return (b == null) ? null : (byte[])b.clone();
132 }
133
134 abstract byte[] getEncodedInternal();
135
136 public boolean equals(Object obj) {
137 if (this == obj) {
138 return true;
139 }
140 // equals() should never throw exceptions
141 if (token.isValid() == false) {
142 return false;
143 }
144 if (obj instanceof Key == false) {
145 return false;
146 }
147 String thisFormat = getFormat();
148 if (thisFormat == null) {
149 // no encoding, key only equal to itself
150 // XXX getEncoded() for unextractable keys will change that
151 return false;
152 }
153 Key other = (Key)obj;
154 if (thisFormat.equals(other.getFormat()) == false) {
155 return false;
156 }
157 byte[] thisEnc = this.getEncodedInternal();
158 byte[] otherEnc;
159 if (obj instanceof P11Key) {
160 otherEnc = ((P11Key)other).getEncodedInternal();
161 } else {
162 otherEnc = other.getEncoded();
163 }
164 return Arrays.equals(thisEnc, otherEnc);
165 }
166
167 public int hashCode() {
168 // hashCode() should never throw exceptions
169 if (token.isValid() == false) {
170 return 0;
171 }
172 byte[] b1 = getEncodedInternal();
173 if (b1 == null) {
174 return 0;
175 }
176 int r = b1.length;
177 for (int i = 0; i < b1.length; i++) {
178 r += (b1[i] & 0xff) * 37;
179 }
180 return r;
181 }
182
183 protected Object writeReplace() throws ObjectStreamException {
184 KeyRep.Type type;
185 String format = getFormat();
186 if (isPrivate() && "PKCS#8".equals(format)) {
187 type = KeyRep.Type.PRIVATE;
188 } else if (isPublic() && "X.509".equals(format)) {
189 type = KeyRep.Type.PUBLIC;
190 } else if (isSecret() && "RAW".equals(format)) {
191 type = KeyRep.Type.SECRET;
192 } else {
193 // XXX short term serialization for unextractable keys
194 throw new NotSerializableException
195 ("Cannot serialize sensitive and unextractable keys");
196 }
197 return new KeyRep(type, getAlgorithm(), format, getEncoded());
198 }
199
200 public String toString() {
201 token.ensureValid();
202 String s1 = token.provider.getName() + " " + algorithm + " " + type
203 + " key, " + keyLength + " bits";
204 s1 += " (id " + keyID + ", "
205 + (tokenObject ? "token" : "session") + " object";
206 if (isPublic()) {
207 s1 += ")";
208 } else {
209 s1 += ", " + (sensitive ? "" : "not ") + "sensitive";
210 s1 += ", " + (extractable ? "" : "un") + "extractable)";
211 }
212 return s1;
213 }
214
215 int keyLength() {
216 return keyLength;
217 }
218
219 boolean isPublic() {
220 return type == PUBLIC;
221 }
222
223 boolean isPrivate() {
224 return type == PRIVATE;
225 }
226
227 boolean isSecret() {
228 return type == SECRET;
229 }
230
231 void fetchAttributes(CK_ATTRIBUTE[] attributes) {
232 Session tempSession = null;
233 try {
234 tempSession = token.getOpSession();
235 token.p11.C_GetAttributeValue(tempSession.id(), keyID, attributes);
236 } catch (PKCS11Exception e) {
237 throw new ProviderException(e);
238 } finally {
239 token.releaseSession(tempSession);
240 }
241 }
242
243 private final static CK_ATTRIBUTE[] A0 = new CK_ATTRIBUTE[0];
244
245 private static CK_ATTRIBUTE[] getAttributes(Session session, long keyID,
246 CK_ATTRIBUTE[] knownAttributes, CK_ATTRIBUTE[] desiredAttributes) {
247 if (knownAttributes == null) {
248 knownAttributes = A0;
249 }
250 for (int i = 0; i < desiredAttributes.length; i++) {
251 // For each desired attribute, check to see if we have the value
252 // available already. If everything is here, we save a native call.
253 CK_ATTRIBUTE attr = desiredAttributes[i];
254 for (CK_ATTRIBUTE known : knownAttributes) {
255 if ((attr.type == known.type) && (known.pValue != null)) {
256 attr.pValue = known.pValue;
257 break; // break inner for loop
258 }
259 }
260 if (attr.pValue == null) {
261 // nothing found, need to call C_GetAttributeValue()
262 for (int j = 0; j < i; j++) {
263 // clear values copied from knownAttributes
264 desiredAttributes[j].pValue = null;
265 }
266 try {
267 session.token.p11.C_GetAttributeValue
268 (session.id(), keyID, desiredAttributes);
269 } catch (PKCS11Exception e) {
270 throw new ProviderException(e);
271 }
272 break; // break loop, goto return
273 }
274 }
275 return desiredAttributes;
276 }
277
278 static SecretKey secretKey(Session session, long keyID, String algorithm,
279 int keyLength, CK_ATTRIBUTE[] attributes) {
280 attributes = getAttributes(session, keyID, attributes, new CK_ATTRIBUTE[] {
281 new CK_ATTRIBUTE(CKA_TOKEN),
282 new CK_ATTRIBUTE(CKA_SENSITIVE),
283 new CK_ATTRIBUTE(CKA_EXTRACTABLE),
284 });
285 return new P11SecretKey(session, keyID, algorithm, keyLength, attributes);
286 }
287
288 static SecretKey masterSecretKey(Session session, long keyID, String algorithm,
289 int keyLength, CK_ATTRIBUTE[] attributes, int major, int minor) {
290 attributes = getAttributes(session, keyID, attributes, new CK_ATTRIBUTE[] {
291 new CK_ATTRIBUTE(CKA_TOKEN),
292 new CK_ATTRIBUTE(CKA_SENSITIVE),
293 new CK_ATTRIBUTE(CKA_EXTRACTABLE),
294 });
295 return new P11TlsMasterSecretKey
296 (session, keyID, algorithm, keyLength, attributes, major, minor);
297 }
298
299 // we assume that all components of public keys are always accessible
300 static PublicKey publicKey(Session session, long keyID, String algorithm,
301 int keyLength, CK_ATTRIBUTE[] attributes) {
302 if (algorithm.equals("RSA")) {
303 return new P11RSAPublicKey
304 (session, keyID, algorithm, keyLength, attributes);
305 } else if (algorithm.equals("DSA")) {
306 return new P11DSAPublicKey
307 (session, keyID, algorithm, keyLength, attributes);
308 } else if (algorithm.equals("DH")) {
309 return new P11DHPublicKey
310 (session, keyID, algorithm, keyLength, attributes);
311 } else if (algorithm.equals("EC")) {
312 return new P11ECPublicKey
313 (session, keyID, algorithm, keyLength, attributes);
314 } else {
315 throw new ProviderException
316 ("Unknown public key algorithm " + algorithm);
317 }
318 }
319
320 static PrivateKey privateKey(Session session, long keyID, String algorithm,
321 int keyLength, CK_ATTRIBUTE[] attributes) {
322 attributes = getAttributes(session, keyID, attributes, new CK_ATTRIBUTE[] {
323 new CK_ATTRIBUTE(CKA_TOKEN),
324 new CK_ATTRIBUTE(CKA_SENSITIVE),
325 new CK_ATTRIBUTE(CKA_EXTRACTABLE),
326 });
327 if (attributes[1].getBoolean() || (attributes[2].getBoolean() == false)) {
328 return new P11PrivateKey
329 (session, keyID, algorithm, keyLength, attributes);
330 } else {
331 if (algorithm.equals("RSA")) {
332 // XXX better test for RSA CRT keys (single getAttributes() call)
333 // we need to determine whether this is a CRT key
334 // see if we can obtain the public exponent
335 // this should also be readable for sensitive/extractable keys
336 CK_ATTRIBUTE[] attrs2 = new CK_ATTRIBUTE[] {
337 new CK_ATTRIBUTE(CKA_PUBLIC_EXPONENT),
338 };
339 boolean crtKey;
340 try {
341 session.token.p11.C_GetAttributeValue
342 (session.id(), keyID, attrs2);
343 crtKey = (attrs2[0].pValue instanceof byte[]);
344 } catch (PKCS11Exception e) {
345 // ignore, assume not available
346 crtKey = false;
347 }
348 if (crtKey) {
349 return new P11RSAPrivateKey
350 (session, keyID, algorithm, keyLength, attributes);
351 } else {
352 return new P11RSAPrivateNonCRTKey
353 (session, keyID, algorithm, keyLength, attributes);
354 }
355 } else if (algorithm.equals("DSA")) {
356 return new P11DSAPrivateKey
357 (session, keyID, algorithm, keyLength, attributes);
358 } else if (algorithm.equals("DH")) {
359 return new P11DHPrivateKey
360 (session, keyID, algorithm, keyLength, attributes);
361 } else if (algorithm.equals("EC")) {
362 return new P11ECPrivateKey
363 (session, keyID, algorithm, keyLength, attributes);
364 } else {
365 throw new ProviderException
366 ("Unknown private key algorithm " + algorithm);
367 }
368 }
369 }
370
371 // class for sensitive and unextractable private keys
372 private static final class P11PrivateKey extends P11Key
373 implements PrivateKey {
374 P11PrivateKey(Session session, long keyID, String algorithm,
375 int keyLength, CK_ATTRIBUTE[] attributes) {
376 super(PRIVATE, session, keyID, algorithm, keyLength, attributes);
377 }
378 // XXX temporary encoding for serialization purposes
379 public String getFormat() {
380 token.ensureValid();
381 return null;
382 }
383 byte[] getEncodedInternal() {
384 token.ensureValid();
385 return null;
386 }
387 }
388
389 private static class P11SecretKey extends P11Key implements SecretKey {
390 private volatile byte[] encoded;
391 P11SecretKey(Session session, long keyID, String algorithm,
392 int keyLength, CK_ATTRIBUTE[] attributes) {
393 super(SECRET, session, keyID, algorithm, keyLength, attributes);
394 }
395 public String getFormat() {
396 token.ensureValid();
397 if (sensitive || (extractable == false)) {
398 return null;
399 } else {
400 return "RAW";
401 }
402 }
403 byte[] getEncodedInternal() {
404 token.ensureValid();
405 if (getFormat() == null) {
406 return null;
407 }
408 byte[] b = encoded;
409 if (b == null) {
410 synchronized (this) {
411 b = encoded;
412 if (b == null) {
413 Session tempSession = null;
414 try {
415 tempSession = token.getOpSession();
416 CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {
417 new CK_ATTRIBUTE(CKA_VALUE),
418 };
419 token.p11.C_GetAttributeValue
420 (tempSession.id(), keyID, attributes);
421 b = attributes[0].getByteArray();
422 } catch (PKCS11Exception e) {
423 throw new ProviderException(e);
424 } finally {
425 token.releaseSession(tempSession);
426 }
427 encoded = b;
428 }
429 }
430 }
431 return b;
432 }
433 }
434
435 private static class P11TlsMasterSecretKey extends P11SecretKey
436 implements TlsMasterSecret {
437 private final int majorVersion, minorVersion;
438 P11TlsMasterSecretKey(Session session, long keyID, String algorithm,
439 int keyLength, CK_ATTRIBUTE[] attributes, int major, int minor) {
440 super(session, keyID, algorithm, keyLength, attributes);
441 this.majorVersion = major;
442 this.minorVersion = minor;
443 }
444 public int getMajorVersion() {
445 return majorVersion;
446 }
447
448 public int getMinorVersion() {
449 return minorVersion;
450 }
451 }
452
453 // RSA CRT private key
454 private static final class P11RSAPrivateKey extends P11Key
455 implements RSAPrivateCrtKey {
456 private BigInteger n, e, d, p, q, pe, qe, coeff;
457 private byte[] encoded;
458 P11RSAPrivateKey(Session session, long keyID, String algorithm,
459 int keyLength, CK_ATTRIBUTE[] attributes) {
460 super(PRIVATE, session, keyID, algorithm, keyLength, attributes);
461 }
462 private synchronized void fetchValues() {
463 token.ensureValid();
464 if (n != null) {
465 return;
466 }
467 CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {
468 new CK_ATTRIBUTE(CKA_MODULUS),
469 new CK_ATTRIBUTE(CKA_PUBLIC_EXPONENT),
470 new CK_ATTRIBUTE(CKA_PRIVATE_EXPONENT),
471 new CK_ATTRIBUTE(CKA_PRIME_1),
472 new CK_ATTRIBUTE(CKA_PRIME_2),
473 new CK_ATTRIBUTE(CKA_EXPONENT_1),
474 new CK_ATTRIBUTE(CKA_EXPONENT_2),
475 new CK_ATTRIBUTE(CKA_COEFFICIENT),
476 };
477 fetchAttributes(attributes);
478 n = attributes[0].getBigInteger();
479 e = attributes[1].getBigInteger();
480 d = attributes[2].getBigInteger();
481 p = attributes[3].getBigInteger();
482 q = attributes[4].getBigInteger();
483 pe = attributes[5].getBigInteger();
484 qe = attributes[6].getBigInteger();
485 coeff = attributes[7].getBigInteger();
486 }
487 public String getFormat() {
488 token.ensureValid();
489 return "PKCS#8";
490 }
491 synchronized byte[] getEncodedInternal() {
492 token.ensureValid();
493 if (encoded == null) {
494 fetchValues();
495 try {
496 // XXX make constructor in SunRsaSign provider public
497 // and call it directly
498 KeyFactory factory = KeyFactory.getInstance
499 ("RSA", P11Util.getSunRsaSignProvider());
500 Key newKey = factory.translateKey(this);
501 encoded = newKey.getEncoded();
502 } catch (GeneralSecurityException e) {
503 throw new ProviderException(e);
504 }
505 }
506 return encoded;
507 }
508 public BigInteger getModulus() {
509 fetchValues();
510 return n;
511 }
512 public BigInteger getPublicExponent() {
513 fetchValues();
514 return e;
515 }
516 public BigInteger getPrivateExponent() {
517 fetchValues();
518 return d;
519 }
520 public BigInteger getPrimeP() {
521 fetchValues();
522 return p;
523 }
524 public BigInteger getPrimeQ() {
525 fetchValues();
526 return q;
527 }
528 public BigInteger getPrimeExponentP() {
529 fetchValues();
530 return pe;
531 }
532 public BigInteger getPrimeExponentQ() {
533 fetchValues();
534 return qe;
535 }
536 public BigInteger getCrtCoefficient() {
537 fetchValues();
538 return coeff;
539 }
540 public String toString() {
541 fetchValues();
542 StringBuilder sb = new StringBuilder(super.toString());
543 sb.append("\n modulus: ");
544 sb.append(n);
545 sb.append("\n public exponent: ");
546 sb.append(e);
547 sb.append("\n private exponent: ");
548 sb.append(d);
549 sb.append("\n prime p: ");
550 sb.append(p);
551 sb.append("\n prime q: ");
552 sb.append(q);
553 sb.append("\n prime exponent p: ");
554 sb.append(pe);
555 sb.append("\n prime exponent q: ");
556 sb.append(qe);
557 sb.append("\n crt coefficient: ");
558 sb.append(coeff);
559 return sb.toString();
560 }
561 }
562
563 // RSA non-CRT private key
564 private static final class P11RSAPrivateNonCRTKey extends P11Key
565 implements RSAPrivateKey {
566 private BigInteger n, d;
567 private byte[] encoded;
568 P11RSAPrivateNonCRTKey(Session session, long keyID, String algorithm,
569 int keyLength, CK_ATTRIBUTE[] attributes) {
570 super(PRIVATE, session, keyID, algorithm, keyLength, attributes);
571 }
572 private synchronized void fetchValues() {
573 token.ensureValid();
574 if (n != null) {
575 return;
576 }
577 CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {
578 new CK_ATTRIBUTE(CKA_MODULUS),
579 new CK_ATTRIBUTE(CKA_PRIVATE_EXPONENT),
580 };
581 fetchAttributes(attributes);
582 n = attributes[0].getBigInteger();
583 d = attributes[1].getBigInteger();
584 }
585 public String getFormat() {
586 token.ensureValid();
587 return "PKCS#8";
588 }
589 synchronized byte[] getEncodedInternal() {
590 token.ensureValid();
591 if (encoded == null) {
592 fetchValues();
593 try {
594 // XXX make constructor in SunRsaSign provider public
595 // and call it directly
596 KeyFactory factory = KeyFactory.getInstance
597 ("RSA", P11Util.getSunRsaSignProvider());
598 Key newKey = factory.translateKey(this);
599 encoded = newKey.getEncoded();
600 } catch (GeneralSecurityException e) {
601 throw new ProviderException(e);
602 }
603 }
604 return encoded;
605 }
606 public BigInteger getModulus() {
607 fetchValues();
608 return n;
609 }
610 public BigInteger getPrivateExponent() {
611 fetchValues();
612 return d;
613 }
614 public String toString() {
615 fetchValues();
616 StringBuilder sb = new StringBuilder(super.toString());
617 sb.append("\n modulus: ");
618 sb.append(n);
619 sb.append("\n private exponent: ");
620 sb.append(d);
621 return sb.toString();
622 }
623 }
624
625 private static final class P11RSAPublicKey extends P11Key
626 implements RSAPublicKey {
627 private BigInteger n, e;
628 private byte[] encoded;
629 P11RSAPublicKey(Session session, long keyID, String algorithm,
630 int keyLength, CK_ATTRIBUTE[] attributes) {
631 super(PUBLIC, session, keyID, algorithm, keyLength, attributes);
632 }
633 private synchronized void fetchValues() {
634 token.ensureValid();
635 if (n != null) {
636 return;
637 }
638 CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {
639 new CK_ATTRIBUTE(CKA_MODULUS),
640 new CK_ATTRIBUTE(CKA_PUBLIC_EXPONENT),
641 };
642 fetchAttributes(attributes);
643 n = attributes[0].getBigInteger();
644 e = attributes[1].getBigInteger();
645 }
646 public String getFormat() {
647 token.ensureValid();
648 return "X.509";
649 }
650 synchronized byte[] getEncodedInternal() {
651 token.ensureValid();
652 if (encoded == null) {
653 fetchValues();
654 try {
655 encoded = new RSAPublicKeyImpl(n, e).getEncoded();
656 } catch (InvalidKeyException e) {
657 throw new ProviderException(e);
658 }
659 }
660 return encoded;
661 }
662 public BigInteger getModulus() {
663 fetchValues();
664 return n;
665 }
666 public BigInteger getPublicExponent() {
667 fetchValues();
668 return e;
669 }
670 public String toString() {
671 fetchValues();
672 return super.toString() + "\n modulus: " + n
673 + "\n public exponent: " + e;
674 }
675 }
676
677 private static final class P11DSAPublicKey extends P11Key
678 implements DSAPublicKey {
679 private BigInteger y;
680 private DSAParams params;
681 private byte[] encoded;
682 P11DSAPublicKey(Session session, long keyID, String algorithm,
683 int keyLength, CK_ATTRIBUTE[] attributes) {
684 super(PUBLIC, session, keyID, algorithm, keyLength, attributes);
685 }
686 private synchronized void fetchValues() {
687 token.ensureValid();
688 if (y != null) {
689 return;
690 }
691 CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {
692 new CK_ATTRIBUTE(CKA_VALUE),
693 new CK_ATTRIBUTE(CKA_PRIME),
694 new CK_ATTRIBUTE(CKA_SUBPRIME),
695 new CK_ATTRIBUTE(CKA_BASE),
696 };
697 fetchAttributes(attributes);
698 y = attributes[0].getBigInteger();
699 params = new DSAParameterSpec(
700 attributes[1].getBigInteger(),
701 attributes[2].getBigInteger(),
702 attributes[3].getBigInteger()
703 );
704 }
705 public String getFormat() {
706 token.ensureValid();
707 return "X.509";
708 }
709 synchronized byte[] getEncodedInternal() {
710 token.ensureValid();
711 if (encoded == null) {
712 fetchValues();
713 try {
714 Key key = new sun.security.provider.DSAPublicKey
715 (y, params.getP(), params.getQ(), params.getG());
716 encoded = key.getEncoded();
717 } catch (InvalidKeyException e) {
718 throw new ProviderException(e);
719 }
720 }
721 return encoded;
722 }
723 public BigInteger getY() {
724 fetchValues();
725 return y;
726 }
727 public DSAParams getParams() {
728 fetchValues();
729 return params;
730 }
731 public String toString() {
732 fetchValues();
733 return super.toString() + "\n y: " + y + "\n p: " + params.getP()
734 + "\n q: " + params.getQ() + "\n g: " + params.getG();
735 }
736 }
737
738 private static final class P11DSAPrivateKey extends P11Key
739 implements DSAPrivateKey {
740 private BigInteger x;
741 private DSAParams params;
742 private byte[] encoded;
743 P11DSAPrivateKey(Session session, long keyID, String algorithm,
744 int keyLength, CK_ATTRIBUTE[] attributes) {
745 super(PRIVATE, session, keyID, algorithm, keyLength, attributes);
746 }
747 private synchronized void fetchValues() {
748 token.ensureValid();
749 if (x != null) {
750 return;
751 }
752 CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {
753 new CK_ATTRIBUTE(CKA_VALUE),
754 new CK_ATTRIBUTE(CKA_PRIME),
755 new CK_ATTRIBUTE(CKA_SUBPRIME),
756 new CK_ATTRIBUTE(CKA_BASE),
757 };
758 fetchAttributes(attributes);
759 x = attributes[0].getBigInteger();
760 params = new DSAParameterSpec(
761 attributes[1].getBigInteger(),
762 attributes[2].getBigInteger(),
763 attributes[3].getBigInteger()
764 );
765 }
766 public String getFormat() {
767 token.ensureValid();
768 return "PKCS#8";
769 }
770 synchronized byte[] getEncodedInternal() {
771 token.ensureValid();
772 if (encoded == null) {
773 fetchValues();
774 try {
775 Key key = new sun.security.provider.DSAPrivateKey
776 (x, params.getP(), params.getQ(), params.getG());
777 encoded = key.getEncoded();
778 } catch (InvalidKeyException e) {
779 throw new ProviderException(e);
780 }
781 }
782 return encoded;
783 }
784 public BigInteger getX() {
785 fetchValues();
786 return x;
787 }
788 public DSAParams getParams() {
789 fetchValues();
790 return params;
791 }
792 public String toString() {
793 fetchValues();
794 return super.toString() + "\n x: " + x + "\n p: " + params.getP()
795 + "\n q: " + params.getQ() + "\n g: " + params.getG();
796 }
797 }
798
799 private static final class P11DHPrivateKey extends P11Key
800 implements DHPrivateKey {
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();
827 return "PKCS#8";
828 }
829 synchronized byte[] getEncodedInternal() {
830 token.ensureValid();
831 if (encoded == null) {
832 fetchValues();
833 try {
834 DHPrivateKeySpec spec = new DHPrivateKeySpec
835 (x, params.getP(), params.getG());
836 KeyFactory kf = KeyFactory.getInstance
837 ("DH", P11Util.getSunJceProvider());
838 Key key = kf.generatePrivate(spec);
839 encoded = key.getEncoded();
840 } catch (GeneralSecurityException e) {
841 throw new ProviderException(e);
842 }
843 }
844 return encoded;
845 }
846 public BigInteger getX() {
847 fetchValues();
848 return x;
849 }
850 public DHParameterSpec getParams() {
851 fetchValues();
852 return params;
853 }
854 public String toString() {
855 fetchValues();
856 return super.toString() + "\n x: " + x + "\n p: " + params.getP()
857 + "\n g: " + params.getG();
858 }
859 }
860
861 private static final class P11DHPublicKey extends P11Key
862 implements DHPublicKey {
863 private BigInteger y;
864 private DHParameterSpec params;
865 private byte[] encoded;
866 P11DHPublicKey(Session session, long keyID, String algorithm,
867 int keyLength, CK_ATTRIBUTE[] attributes) {
868 super(PUBLIC, session, keyID, algorithm, keyLength, attributes);
869 }
870 private synchronized void fetchValues() {
871 token.ensureValid();
872 if (y != null) {
873 return;
874 }
875 CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {
876 new CK_ATTRIBUTE(CKA_VALUE),
877 new CK_ATTRIBUTE(CKA_PRIME),
878 new CK_ATTRIBUTE(CKA_BASE),
879 };
880 fetchAttributes(attributes);
881 y = attributes[0].getBigInteger();
882 params = new DHParameterSpec(
883 attributes[1].getBigInteger(),
884 attributes[2].getBigInteger()
885 );
886 }
887 public String getFormat() {
888 token.ensureValid();
889 return "X.509";
890 }
891 synchronized byte[] getEncodedInternal() {
892 token.ensureValid();
893 if (encoded == null) {
894 fetchValues();
895 try {
896 DHPublicKeySpec spec = new DHPublicKeySpec
897 (y, params.getP(), params.getG());
898 KeyFactory kf = KeyFactory.getInstance
899 ("DH", P11Util.getSunJceProvider());
900 Key key = kf.generatePublic(spec);
901 encoded = key.getEncoded();
902 } catch (GeneralSecurityException e) {
903 throw new ProviderException(e);
904 }
905 }
906 return encoded;
907 }
908 public BigInteger getY() {
909 fetchValues();
910 return y;
911 }
912 public DHParameterSpec getParams() {
913 fetchValues();
914 return params;
915 }
916 public String toString() {
917 fetchValues();
918 return super.toString() + "\n y: " + y + "\n p: " + params.getP()
919 + "\n g: " + params.getG();
920 }
921 }
922
923 private static final class P11ECPrivateKey extends P11Key
924 implements ECPrivateKey {
925 private BigInteger s;
926 private ECParameterSpec params;
927 private byte[] encoded;
928 P11ECPrivateKey(Session session, long keyID, String algorithm,
929 int keyLength, CK_ATTRIBUTE[] attributes) {
930 super(PRIVATE, session, keyID, algorithm, keyLength, attributes);
931 }
932 private synchronized void fetchValues() {
933 token.ensureValid();
934 if (s != null) {
935 return;
936 }
937 CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {
938 new CK_ATTRIBUTE(CKA_VALUE),
939 new CK_ATTRIBUTE(CKA_EC_PARAMS, params),
940 };
941 fetchAttributes(attributes);
942 s = attributes[0].getBigInteger();
943 try {
944 params = P11ECKeyFactory.decodeParameters
945 (attributes[1].getByteArray());
946 } catch (Exception e) {
947 throw new RuntimeException("Could not parse key values", e);
948 }
949 }
950 public String getFormat() {
951 token.ensureValid();
952 return "PKCS#8";
953 }
954 synchronized byte[] getEncodedInternal() {
955 token.ensureValid();
956 if (encoded == null) {
957 fetchValues();
958 try {
959 Key key = new sun.security.ec.ECPrivateKeyImpl(s, params);
960 encoded = key.getEncoded();
961 } catch (InvalidKeyException e) {
962 throw new ProviderException(e);
963 }
964 }
965 return encoded;
966 }
967 public BigInteger getS() {
968 fetchValues();
969 return s;
970 }
971 public ECParameterSpec getParams() {
972 fetchValues();
973 return params;
974 }
975 public String toString() {
976 fetchValues();
977 return super.toString()
978 + "\n private value: " + s
979 + "\n parameters: " + params;
980 }
981 }
982
983 private static final class P11ECPublicKey extends P11Key
984 implements ECPublicKey {
985 private ECPoint w;
986 private ECParameterSpec params;
987 private byte[] encoded;
988 P11ECPublicKey(Session session, long keyID, String algorithm,
989 int keyLength, CK_ATTRIBUTE[] attributes) {
990 super(PUBLIC, session, keyID, algorithm, keyLength, attributes);
991 }
992 private synchronized void fetchValues() {
993 token.ensureValid();
994 if (w != null) {
995 return;
996 }
997 CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {
998 new CK_ATTRIBUTE(CKA_EC_POINT),
999 new CK_ATTRIBUTE(CKA_EC_PARAMS),
1000 };
1001 fetchAttributes(attributes);
1002
1003 try {
1004 params = P11ECKeyFactory.decodeParameters
1005 (attributes[1].getByteArray());
1006
1007 /*
1008 * An uncompressed EC point may be in either of two formats.
1009 * First try the OCTET STRING encoding:
1010 * 04 <length> 04 <X-coordinate> <Y-coordinate>
1011 *
1012 * Otherwise try the raw encoding:
1013 * 04 <X-coordinate> <Y-coordinate>
1014 */
1015 byte[] ecKey = attributes[0].getByteArray();
1016
1017 try {
1018 DerValue wECPoint = new DerValue(ecKey);
1019 if (wECPoint.getTag() != DerValue.tag_OctetString)
1020 throw new IOException("Unexpected tag: " +
1021 wECPoint.getTag());
1022
1023 w = P11ECKeyFactory.decodePoint
1024 (wECPoint.getDataBytes(), params.getCurve());
1025
1026 } catch (IOException e) {
1027 // Failover
1028 w = P11ECKeyFactory.decodePoint(ecKey, params.getCurve());
1029 }
1030
1031 } catch (Exception e) {
1032 throw new RuntimeException("Could not parse key values", e);
1033 }
1034 }
1035 public String getFormat() {
1036 token.ensureValid();
1037 return "X.509";
1038 }
1039 synchronized byte[] getEncodedInternal() {
1040 token.ensureValid();
1041 if (encoded == null) {
1042 fetchValues();
1043 try {
1044 Key key = new sun.security.ec.ECPublicKeyImpl(w, params);
1045 encoded = key.getEncoded();
1046 } catch (InvalidKeyException e) {
1047 throw new ProviderException(e);
1048 }
1049 }
1050 return encoded;
1051 }
1052 public ECPoint getW() {
1053 fetchValues();
1054 return w;
1055 }
1056 public ECParameterSpec getParams() {
1057 fetchValues();
1058 return params;
1059 }
1060 public String toString() {
1061 fetchValues();
1062 return super.toString()
1063 + "\n public x coord: " + w.getAffineX()
1064 + "\n public y coord: " + w.getAffineY()
1065 + "\n parameters: " + params;
1066 }
1067 }
1068}
1069
1070/*
1071 * NOTE: Must use PhantomReference here and not WeakReference
1072 * otherwise the key maybe cleared before other objects which
1073 * still use these keys during finalization such as SSLSocket.
1074 */
1075final class SessionKeyRef extends PhantomReference<P11Key>
1076 implements Comparable<SessionKeyRef> {
1077 private static ReferenceQueue<P11Key> refQueue =
1078 new ReferenceQueue<P11Key>();
1079 private static Set<SessionKeyRef> refList =
1080 Collections.synchronizedSortedSet(new TreeSet<SessionKeyRef>());
1081
1082 static ReferenceQueue<P11Key> referenceQueue() {
1083 return refQueue;
1084 }
1085
1086 private static void drainRefQueueBounded() {
1087 while (true) {
1088 SessionKeyRef next = (SessionKeyRef) refQueue.poll();
1089 if (next == null) break;
1090 next.dispose();
1091 }
1092 }
1093
1094 // handle to the native key
1095 private long keyID;
1096 private Session session;
1097
1098 SessionKeyRef(P11Key key , long keyID, Session session) {
1099 super(key, refQueue);
1100 this.keyID = keyID;
1101 this.session = session;
1102 this.session.addObject();
1103 refList.add(this);
1104 // TBD: run at some interval and not every time?
1105 drainRefQueueBounded();
1106 }
1107
1108 private void dispose() {
1109 refList.remove(this);
1110 if (session.token.isValid()) {
1111 Session newSession = null;
1112 try {
1113 newSession = session.token.getOpSession();
1114 session.token.p11.C_DestroyObject(newSession.id(), keyID);
1115 } catch (PKCS11Exception e) {
1116 // ignore
1117 } finally {
1118 this.clear();
1119 session.token.releaseSession(newSession);
1120 session.removeObject();
1121 }
1122 }
1123 }
1124
1125 public int compareTo(SessionKeyRef other) {
1126 if (this.keyID == other.keyID) {
1127 return 0;
1128 } else {
1129 return (this.keyID < other.keyID) ? -1 : 1;
1130 }
1131 }
1132}