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