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+
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.RSAPublicKeyImpl;
42+
43+import sun.security.internal.interfaces.TlsMasterSecret;
44+
45+import sun.security.pkcs11.wrapper.*;
46+import static sun.security.pkcs11.wrapper.PKCS11Constants.*;
47+
48+import 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+ */
64+abstract 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+ */
1075+final 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+}