< prev index next >

src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Key.java

Print this page




  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package sun.security.pkcs11;
  27 
  28 import java.io.*;
  29 import java.lang.ref.*;
  30 import java.math.BigInteger;
  31 import java.util.*;
  32 
  33 import java.security.*;
  34 import java.security.interfaces.*;
  35 import java.security.spec.*;
  36 
  37 import javax.crypto.*;
  38 import javax.crypto.interfaces.*;
  39 import javax.crypto.spec.*;
  40 
  41 import sun.security.rsa.RSAUtil.KeyType;
  42 import sun.security.rsa.RSAPublicKeyImpl;
  43 import sun.security.rsa.RSAPrivateCrtKeyImpl;
  44 
  45 import sun.security.internal.interfaces.TlsMasterSecret;
  46 
  47 import sun.security.pkcs11.wrapper.*;


  48 import static sun.security.pkcs11.wrapper.PKCS11Constants.*;
  49 
  50 import sun.security.util.Debug;
  51 import sun.security.util.DerValue;
  52 import sun.security.util.Length;
  53 import sun.security.util.ECUtil;
  54 
  55 /**
  56  * Key implementation classes.
  57  *
  58  * In PKCS#11, the components of private and secret keys may or may not
  59  * be accessible. If they are, we use the algorithm specific key classes
  60  * (e.g. DSAPrivateKey) for compatibility with existing applications.
  61  * If the components are not accessible, we use a generic class that
  62  * only implements PrivateKey (or SecretKey). Whether the components of a
  63  * key are extractable is automatically determined when the key object is
  64  * created.
  65  *
  66  * @author  Andreas Sterbenz
  67  * @since   1.5
  68  */
  69 abstract class P11Key implements Key, Length {
  70 
  71     private static final long serialVersionUID = -2575874101938349339L;
  72 
  73     private final static String PUBLIC = "public";
  74     private final static String PRIVATE = "private";
  75     private final static String SECRET = "secret";
  76 
  77     // type of key, one of (PUBLIC, PRIVATE, SECRET)
  78     final String type;
  79 
  80     // token instance
  81     final Token token;
  82 
  83     // algorithm name, returned by getAlgorithm(), etc.
  84     final String algorithm;
  85 
  86     // key id
  87     final long keyID;
  88 
  89     // effective key length of the key, e.g. 56 for a DES key
  90     final int keyLength;
  91 
  92     // flags indicating whether the key is a token object, sensitive, extractable
  93     final boolean tokenObject, sensitive, extractable;
  94 
  95     // phantom reference notification clean up for session keys
  96     private final SessionKeyRef sessionKeyRef;
  97 











  98     P11Key(String type, Session session, long keyID, String algorithm,
  99             int keyLength, CK_ATTRIBUTE[] attributes) {
 100         this.type = type;
 101         this.token = session.token;
 102         this.keyID = keyID;
 103         this.algorithm = algorithm;
 104         this.keyLength = keyLength;
 105         boolean tokenObject = false;
 106         boolean sensitive = false;
 107         boolean extractable = true;
 108         int n = (attributes == null) ? 0 : attributes.length;
 109         for (int i = 0; i < n; i++) {
 110             CK_ATTRIBUTE attr = attributes[i];
 111             if (attr.type == CKA_TOKEN) {
 112                 tokenObject = attr.getBoolean();
 113             } else if (attr.type == CKA_SENSITIVE) {
 114                 sensitive = attr.getBoolean();
 115             } else if (attr.type == CKA_EXTRACTABLE) {
 116                 extractable = attr.getBoolean();
 117             }
 118         }
 119         this.tokenObject = tokenObject;
 120         this.sensitive = sensitive;
 121         this.extractable = extractable;























































 122         if (tokenObject == false) {
 123             sessionKeyRef = new SessionKeyRef(this, keyID, session);
 124         } else {
 125             sessionKeyRef = null;
 126         }
 127     }
 128 











































































 129     // see JCA spec
 130     public final String getAlgorithm() {
 131         token.ensureValid();
 132         return algorithm;
 133     }
 134 
 135     // see JCA spec
 136     public final byte[] getEncoded() {
 137         byte[] b = getEncodedInternal();
 138         return (b == null) ? null : b.clone();
 139     }
 140 
 141     abstract byte[] getEncodedInternal();
 142 
 143     public boolean equals(Object obj) {
 144         if (this == obj) {
 145             return true;
 146         }
 147         // equals() should never throw exceptions
 148         if (token.isValid() == false) {


 226     public int length() {
 227         return keyLength;
 228     }
 229 
 230     boolean isPublic() {
 231         return type == PUBLIC;
 232     }
 233 
 234     boolean isPrivate() {
 235         return type == PRIVATE;
 236     }
 237 
 238     boolean isSecret() {
 239         return type == SECRET;
 240     }
 241 
 242     void fetchAttributes(CK_ATTRIBUTE[] attributes) {
 243         Session tempSession = null;
 244         try {
 245             tempSession = token.getOpSession();


 246             token.p11.C_GetAttributeValue(tempSession.id(), keyID, attributes);



 247         } catch (PKCS11Exception e) {
 248             throw new ProviderException(e);
 249         } finally {
 250             token.releaseSession(tempSession);
 251         }
 252     }
 253 
 254     private final static CK_ATTRIBUTE[] A0 = new CK_ATTRIBUTE[0];
 255 
 256     private static CK_ATTRIBUTE[] getAttributes(Session session, long keyID,
 257             CK_ATTRIBUTE[] knownAttributes, CK_ATTRIBUTE[] desiredAttributes) {
 258         if (knownAttributes == null) {
 259             knownAttributes = A0;
 260         }
 261         for (int i = 0; i < desiredAttributes.length; i++) {
 262             // For each desired attribute, check to see if we have the value
 263             // available already. If everything is here, we save a native call.
 264             CK_ATTRIBUTE attr = desiredAttributes[i];
 265             for (CK_ATTRIBUTE known : knownAttributes) {
 266                 if ((attr.type == known.type) && (known.pValue != null)) {


 270             }
 271             if (attr.pValue == null) {
 272                 // nothing found, need to call C_GetAttributeValue()
 273                 for (int j = 0; j < i; j++) {
 274                     // clear values copied from knownAttributes
 275                     desiredAttributes[j].pValue = null;
 276                 }
 277                 try {
 278                     session.token.p11.C_GetAttributeValue
 279                             (session.id(), keyID, desiredAttributes);
 280                 } catch (PKCS11Exception e) {
 281                     throw new ProviderException(e);
 282                 }
 283                 break; // break loop, goto return
 284             }
 285         }
 286         return desiredAttributes;
 287     }
 288 
 289     static SecretKey secretKey(Session session, long keyID, String algorithm,
 290             int keyLength, CK_ATTRIBUTE[] attributes) {
 291         attributes = getAttributes(session, keyID, attributes, new CK_ATTRIBUTE[] {
 292             new CK_ATTRIBUTE(CKA_TOKEN),
 293             new CK_ATTRIBUTE(CKA_SENSITIVE),
 294             new CK_ATTRIBUTE(CKA_EXTRACTABLE),
 295         });
 296         return new P11SecretKey(session, keyID, algorithm, keyLength, attributes);
 297     }
 298 
 299     static SecretKey masterSecretKey(Session session, long keyID, String algorithm,
 300             int keyLength, CK_ATTRIBUTE[] attributes, int major, int minor) {

 301         attributes = getAttributes(session, keyID, attributes, new CK_ATTRIBUTE[] {
 302             new CK_ATTRIBUTE(CKA_TOKEN),
 303             new CK_ATTRIBUTE(CKA_SENSITIVE),
 304             new CK_ATTRIBUTE(CKA_EXTRACTABLE),
 305         });
 306         return new P11TlsMasterSecretKey
 307                 (session, keyID, algorithm, keyLength, attributes, major, minor);

 308     }
 309 
 310     // we assume that all components of public keys are always accessible
 311     static PublicKey publicKey(Session session, long keyID, String algorithm,
 312             int keyLength, CK_ATTRIBUTE[] attributes) {
 313         switch (algorithm) {
 314             case "RSA":
 315                 return new P11RSAPublicKey
 316                     (session, keyID, algorithm, keyLength, attributes);
 317             case "DSA":
 318                 return new P11DSAPublicKey
 319                     (session, keyID, algorithm, keyLength, attributes);
 320             case "DH":
 321                 return new P11DHPublicKey
 322                     (session, keyID, algorithm, keyLength, attributes);
 323             case "EC":
 324                 return new P11ECPublicKey
 325                     (session, keyID, algorithm, keyLength, attributes);
 326             default:
 327                 throw new ProviderException
 328                     ("Unknown public key algorithm " + algorithm);
 329         }
 330     }
 331 
 332     static PrivateKey privateKey(Session session, long keyID, String algorithm,
 333             int keyLength, CK_ATTRIBUTE[] attributes) {
 334         attributes = getAttributes(session, keyID, attributes, new CK_ATTRIBUTE[] {
 335             new CK_ATTRIBUTE(CKA_TOKEN),
 336             new CK_ATTRIBUTE(CKA_SENSITIVE),
 337             new CK_ATTRIBUTE(CKA_EXTRACTABLE),
 338         });
 339         if (attributes[1].getBoolean() || (attributes[2].getBoolean() == false)) {
 340             return new P11PrivateKey
 341                 (session, keyID, algorithm, keyLength, attributes);
 342         } else {
 343             switch (algorithm) {
 344                 case "RSA":
 345                     // In order to decide if this is RSA CRT key, we first query
 346                     // and see if all extra CRT attributes are available.
 347                     CK_ATTRIBUTE[] attrs2 = new CK_ATTRIBUTE[] {
 348                         new CK_ATTRIBUTE(CKA_PUBLIC_EXPONENT),
 349                         new CK_ATTRIBUTE(CKA_PRIME_1),
 350                         new CK_ATTRIBUTE(CKA_PRIME_2),
 351                         new CK_ATTRIBUTE(CKA_EXPONENT_1),
 352                         new CK_ATTRIBUTE(CKA_EXPONENT_2),
 353                         new CK_ATTRIBUTE(CKA_COEFFICIENT),
 354                     };
 355                     boolean crtKey;
 356                     try {
 357                         session.token.p11.C_GetAttributeValue
 358                             (session.id(), keyID, attrs2);
 359                         crtKey = ((attrs2[0].pValue instanceof byte[]) &&
 360                                   (attrs2[1].pValue instanceof byte[]) &&
 361                                   (attrs2[2].pValue instanceof byte[]) &&
 362                                   (attrs2[3].pValue instanceof byte[]) &&
 363                                   (attrs2[4].pValue instanceof byte[]) &&
 364                                   (attrs2[5].pValue instanceof byte[])) ;
 365                     } catch (PKCS11Exception e) {
 366                         // ignore, assume not available
 367                         crtKey = false;
 368                     }
 369                     if (crtKey) {
 370                         return new P11RSAPrivateKey
 371                                 (session, keyID, algorithm, keyLength, attributes, attrs2);
 372                     } else {
 373                         return new P11RSAPrivateNonCRTKey
 374                                 (session, keyID, algorithm, keyLength, attributes);
 375                     }
 376                 case "DSA":
 377                     return new P11DSAPrivateKey
 378                             (session, keyID, algorithm, keyLength, attributes);
 379                 case "DH":
 380                     return new P11DHPrivateKey
 381                             (session, keyID, algorithm, keyLength, attributes);
 382                 case "EC":
 383                     return new P11ECPrivateKey
 384                             (session, keyID, algorithm, keyLength, attributes);
 385                 default:
 386                     throw new ProviderException
 387                             ("Unknown private key algorithm " + algorithm);
 388             }
 389         }
 390     }
 391 
 392     // class for sensitive and unextractable private keys
 393     private static final class P11PrivateKey extends P11Key
 394                                                 implements PrivateKey {
 395         private static final long serialVersionUID = -2138581185214187615L;
 396 
 397         P11PrivateKey(Session session, long keyID, String algorithm,
 398                 int keyLength, CK_ATTRIBUTE[] attributes) {
 399             super(PRIVATE, session, keyID, algorithm, keyLength, attributes);
 400         }
 401         // XXX temporary encoding for serialization purposes
 402         public String getFormat() {
 403             token.ensureValid();
 404             return null;
 405         }
 406         byte[] getEncodedInternal() {
 407             token.ensureValid();
 408             return null;
 409         }
 410     }
 411 
 412     private static class P11SecretKey extends P11Key implements SecretKey {
 413         private static final long serialVersionUID = -7828241727014329084L;
 414         private volatile byte[] encoded;
 415         P11SecretKey(Session session, long keyID, String algorithm,
 416                 int keyLength, CK_ATTRIBUTE[] attributes) {
 417             super(SECRET, session, keyID, algorithm, keyLength, attributes);
 418         }
 419         public String getFormat() {
 420             token.ensureValid();
 421             if (sensitive || (extractable == false)) {
 422                 return null;
 423             } else {
 424                 return "RAW";
 425             }
 426         }
 427         byte[] getEncodedInternal() {
 428             token.ensureValid();
 429             if (getFormat() == null) {
 430                 return null;
 431             }
 432             byte[] b = encoded;
 433             if (b == null) {
 434                 synchronized (this) {
 435                     b = encoded;
 436                     if (b == null) {
 437                         Session tempSession = null;
 438                         try {
 439                             tempSession = token.getOpSession();
 440                             CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {
 441                                 new CK_ATTRIBUTE(CKA_VALUE),
 442                             };


 443                             token.p11.C_GetAttributeValue
 444                                 (tempSession.id(), keyID, attributes);



 445                             b = attributes[0].getByteArray();
 446                         } catch (PKCS11Exception e) {
 447                             throw new ProviderException(e);
 448                         } finally {
 449                             token.releaseSession(tempSession);
 450                         }
 451                         encoded = b;
 452                     }
 453                 }
 454             }
 455             return b;
 456         }
 457     }
 458 
 459     @SuppressWarnings("deprecation")
 460     private static class P11TlsMasterSecretKey extends P11SecretKey
 461             implements TlsMasterSecret {
 462         private static final long serialVersionUID = -1318560923770573441L;
 463 
 464         private final int majorVersion, minorVersion;
 465         P11TlsMasterSecretKey(Session session, long keyID, String algorithm,
 466                 int keyLength, CK_ATTRIBUTE[] attributes, int major, int minor) {
 467             super(session, keyID, algorithm, keyLength, attributes);

 468             this.majorVersion = major;
 469             this.minorVersion = minor;
 470         }
 471         public int getMajorVersion() {
 472             return majorVersion;
 473         }
 474 
 475         public int getMinorVersion() {
 476             return minorVersion;
 477         }
 478     }
 479 
 480     // RSA CRT private key
 481     private static final class P11RSAPrivateKey extends P11Key
 482                 implements RSAPrivateCrtKey {
 483         private static final long serialVersionUID = 9215872438913515220L;
 484 
 485         private BigInteger n, e, d, p, q, pe, qe, coeff;
 486         private byte[] encoded;
 487         P11RSAPrivateKey(Session session, long keyID, String algorithm,
 488                 int keyLength, CK_ATTRIBUTE[] attrs, CK_ATTRIBUTE[] crtAttrs) {
 489             super(PRIVATE, session, keyID, algorithm, keyLength, attrs);
 490 
 491             for (CK_ATTRIBUTE a : crtAttrs) {
 492                 if (a.type == CKA_PUBLIC_EXPONENT) {
 493                     e = a.getBigInteger();
 494                 } else if (a.type == CKA_PRIME_1) {
 495                     p = a.getBigInteger();
 496                 } else if (a.type == CKA_PRIME_2) {
 497                     q = a.getBigInteger();
 498                 } else if (a.type == CKA_EXPONENT_1) {
 499                     pe = a.getBigInteger();
 500                 } else if (a.type == CKA_EXPONENT_2) {
 501                     qe = a.getBigInteger();
 502                 } else if (a.type == CKA_COEFFICIENT) {
 503                     coeff = a.getBigInteger();
 504                 }
 505             }
 506         }
 507         private synchronized void fetchValues() {
 508             token.ensureValid();
 509             if (n != null) {


 555         }
 556         public BigInteger getPrimeExponentP() {
 557             return pe;
 558         }
 559         public BigInteger getPrimeExponentQ() {
 560             return qe;
 561         }
 562         public BigInteger getCrtCoefficient() {
 563             return coeff;
 564         }
 565     }
 566 
 567     // RSA non-CRT private key
 568     private static final class P11RSAPrivateNonCRTKey extends P11Key
 569                 implements RSAPrivateKey {
 570         private static final long serialVersionUID = 1137764983777411481L;
 571 
 572         private BigInteger n, d;
 573         private byte[] encoded;
 574         P11RSAPrivateNonCRTKey(Session session, long keyID, String algorithm,
 575                 int keyLength, CK_ATTRIBUTE[] attributes) {
 576             super(PRIVATE, session, keyID, algorithm, keyLength, attributes);
 577         }
 578         private synchronized void fetchValues() {
 579             token.ensureValid();
 580             if (n != null) {
 581                 return;
 582             }
 583             CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {
 584                 new CK_ATTRIBUTE(CKA_MODULUS),
 585                 new CK_ATTRIBUTE(CKA_PRIVATE_EXPONENT),
 586             };
 587             fetchAttributes(attributes);
 588             n = attributes[0].getBigInteger();
 589             d = attributes[1].getBigInteger();
 590         }
 591         public String getFormat() {
 592             token.ensureValid();
 593             return "PKCS#8";
 594         }
 595         synchronized byte[] getEncodedInternal() {
 596             token.ensureValid();


 608                 }
 609             }
 610             return encoded;
 611         }
 612         public BigInteger getModulus() {
 613             fetchValues();
 614             return n;
 615         }
 616         public BigInteger getPrivateExponent() {
 617             fetchValues();
 618             return d;
 619         }
 620     }
 621 
 622     private static final class P11RSAPublicKey extends P11Key
 623                                                 implements RSAPublicKey {
 624         private static final long serialVersionUID = -826726289023854455L;
 625         private BigInteger n, e;
 626         private byte[] encoded;
 627         P11RSAPublicKey(Session session, long keyID, String algorithm,
 628                 int keyLength, CK_ATTRIBUTE[] attributes) {
 629             super(PUBLIC, session, keyID, algorithm, keyLength, attributes);
 630         }
 631         private synchronized void fetchValues() {
 632             token.ensureValid();
 633             if (n != null) {
 634                 return;
 635             }
 636             CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {
 637                 new CK_ATTRIBUTE(CKA_MODULUS),
 638                 new CK_ATTRIBUTE(CKA_PUBLIC_EXPONENT),
 639             };
 640             fetchAttributes(attributes);
 641             n = attributes[0].getBigInteger();
 642             e = attributes[1].getBigInteger();
 643         }
 644         public String getFormat() {
 645             token.ensureValid();
 646             return "X.509";
 647         }
 648         synchronized byte[] getEncodedInternal() {
 649             token.ensureValid();


 664         }
 665         public BigInteger getPublicExponent() {
 666             fetchValues();
 667             return e;
 668         }
 669         public String toString() {
 670             fetchValues();
 671             return super.toString() +  "\n  modulus: " + n
 672                 + "\n  public exponent: " + e;
 673         }
 674     }
 675 
 676     private static final class P11DSAPublicKey extends P11Key
 677                                                 implements DSAPublicKey {
 678         private static final long serialVersionUID = 5989753793316396637L;
 679 
 680         private BigInteger y;
 681         private DSAParams params;
 682         private byte[] encoded;
 683         P11DSAPublicKey(Session session, long keyID, String algorithm,
 684                 int keyLength, CK_ATTRIBUTE[] attributes) {
 685             super(PUBLIC, session, keyID, algorithm, keyLength, attributes);
 686         }
 687         private synchronized void fetchValues() {
 688             token.ensureValid();
 689             if (y != null) {
 690                 return;
 691             }
 692             CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {
 693                 new CK_ATTRIBUTE(CKA_VALUE),
 694                 new CK_ATTRIBUTE(CKA_PRIME),
 695                 new CK_ATTRIBUTE(CKA_SUBPRIME),
 696                 new CK_ATTRIBUTE(CKA_BASE),
 697             };
 698             fetchAttributes(attributes);
 699             y = attributes[0].getBigInteger();
 700             params = new DSAParameterSpec(
 701                 attributes[1].getBigInteger(),
 702                 attributes[2].getBigInteger(),
 703                 attributes[3].getBigInteger()
 704             );
 705         }


 727         }
 728         public DSAParams getParams() {
 729             fetchValues();
 730             return params;
 731         }
 732         public String toString() {
 733             fetchValues();
 734             return super.toString() +  "\n  y: " + y + "\n  p: " + params.getP()
 735                 + "\n  q: " + params.getQ() + "\n  g: " + params.getG();
 736         }
 737     }
 738 
 739     private static final class P11DSAPrivateKey extends P11Key
 740                                                 implements DSAPrivateKey {
 741         private static final long serialVersionUID = 3119629997181999389L;
 742 
 743         private BigInteger x;
 744         private DSAParams params;
 745         private byte[] encoded;
 746         P11DSAPrivateKey(Session session, long keyID, String algorithm,
 747                 int keyLength, CK_ATTRIBUTE[] attributes) {
 748             super(PRIVATE, session, keyID, algorithm, keyLength, attributes);
 749         }
 750         private synchronized void fetchValues() {
 751             token.ensureValid();
 752             if (x != null) {
 753                 return;
 754             }
 755             CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {
 756                 new CK_ATTRIBUTE(CKA_VALUE),
 757                 new CK_ATTRIBUTE(CKA_PRIME),
 758                 new CK_ATTRIBUTE(CKA_SUBPRIME),
 759                 new CK_ATTRIBUTE(CKA_BASE),
 760             };
 761             fetchAttributes(attributes);
 762             x = attributes[0].getBigInteger();
 763             params = new DSAParameterSpec(
 764                 attributes[1].getBigInteger(),
 765                 attributes[2].getBigInteger(),
 766                 attributes[3].getBigInteger()
 767             );
 768         }


 785             return encoded;
 786         }
 787         public BigInteger getX() {
 788             fetchValues();
 789             return x;
 790         }
 791         public DSAParams getParams() {
 792             fetchValues();
 793             return params;
 794         }
 795     }
 796 
 797     private static final class P11DHPrivateKey extends P11Key
 798                                                 implements DHPrivateKey {
 799         private static final long serialVersionUID = -1698576167364928838L;
 800 
 801         private BigInteger x;
 802         private DHParameterSpec params;
 803         private byte[] encoded;
 804         P11DHPrivateKey(Session session, long keyID, String algorithm,
 805                 int keyLength, CK_ATTRIBUTE[] attributes) {
 806             super(PRIVATE, session, keyID, algorithm, keyLength, attributes);
 807         }
 808         private synchronized void fetchValues() {
 809             token.ensureValid();
 810             if (x != null) {
 811                 return;
 812             }
 813             CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {
 814                 new CK_ATTRIBUTE(CKA_VALUE),
 815                 new CK_ATTRIBUTE(CKA_PRIME),
 816                 new CK_ATTRIBUTE(CKA_BASE),
 817             };
 818             fetchAttributes(attributes);
 819             x = attributes[0].getBigInteger();
 820             params = new DHParameterSpec(
 821                 attributes[1].getBigInteger(),
 822                 attributes[2].getBigInteger()
 823             );
 824         }
 825         public String getFormat() {
 826             token.ensureValid();


 867             if (!(obj instanceof DHPrivateKey)) {
 868                 return false;
 869             }
 870             fetchValues();
 871             DHPrivateKey other = (DHPrivateKey) obj;
 872             DHParameterSpec otherParams = other.getParams();
 873             return ((this.x.compareTo(other.getX()) == 0) &&
 874                     (this.params.getP().compareTo(otherParams.getP()) == 0) &&
 875                     (this.params.getG().compareTo(otherParams.getG()) == 0));
 876         }
 877     }
 878 
 879     private static final class P11DHPublicKey extends P11Key
 880                                                 implements DHPublicKey {
 881         static final long serialVersionUID = -598383872153843657L;
 882 
 883         private BigInteger y;
 884         private DHParameterSpec params;
 885         private byte[] encoded;
 886         P11DHPublicKey(Session session, long keyID, String algorithm,
 887                 int keyLength, CK_ATTRIBUTE[] attributes) {
 888             super(PUBLIC, session, keyID, algorithm, keyLength, attributes);
 889         }
 890         private synchronized void fetchValues() {
 891             token.ensureValid();
 892             if (y != null) {
 893                 return;
 894             }
 895             CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {
 896                 new CK_ATTRIBUTE(CKA_VALUE),
 897                 new CK_ATTRIBUTE(CKA_PRIME),
 898                 new CK_ATTRIBUTE(CKA_BASE),
 899             };
 900             fetchAttributes(attributes);
 901             y = attributes[0].getBigInteger();
 902             params = new DHParameterSpec(
 903                 attributes[1].getBigInteger(),
 904                 attributes[2].getBigInteger()
 905             );
 906         }
 907         public String getFormat() {
 908             token.ensureValid();


 954             if (!(obj instanceof DHPublicKey)) {
 955                 return false;
 956             }
 957             fetchValues();
 958             DHPublicKey other = (DHPublicKey) obj;
 959             DHParameterSpec otherParams = other.getParams();
 960             return ((this.y.compareTo(other.getY()) == 0) &&
 961                     (this.params.getP().compareTo(otherParams.getP()) == 0) &&
 962                     (this.params.getG().compareTo(otherParams.getG()) == 0));
 963         }
 964     }
 965 
 966     private static final class P11ECPrivateKey extends P11Key
 967                                                 implements ECPrivateKey {
 968         private static final long serialVersionUID = -7786054399510515515L;
 969 
 970         private BigInteger s;
 971         private ECParameterSpec params;
 972         private byte[] encoded;
 973         P11ECPrivateKey(Session session, long keyID, String algorithm,
 974                 int keyLength, CK_ATTRIBUTE[] attributes) {
 975             super(PRIVATE, session, keyID, algorithm, keyLength, attributes);
 976         }
 977         private synchronized void fetchValues() {
 978             token.ensureValid();
 979             if (s != null) {
 980                 return;
 981             }
 982             CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {
 983                 new CK_ATTRIBUTE(CKA_VALUE),
 984                 new CK_ATTRIBUTE(CKA_EC_PARAMS, params),
 985             };
 986             fetchAttributes(attributes);
 987             s = attributes[0].getBigInteger();
 988             try {
 989                 params = P11ECKeyFactory.decodeParameters
 990                             (attributes[1].getByteArray());
 991             } catch (Exception e) {
 992                 throw new RuntimeException("Could not parse key values", e);
 993             }
 994         }
 995         public String getFormat() {


1010             return encoded;
1011         }
1012         public BigInteger getS() {
1013             fetchValues();
1014             return s;
1015         }
1016         public ECParameterSpec getParams() {
1017             fetchValues();
1018             return params;
1019         }
1020     }
1021 
1022     private static final class P11ECPublicKey extends P11Key
1023                                                 implements ECPublicKey {
1024         private static final long serialVersionUID = -6371481375154806089L;
1025 
1026         private ECPoint w;
1027         private ECParameterSpec params;
1028         private byte[] encoded;
1029         P11ECPublicKey(Session session, long keyID, String algorithm,
1030                 int keyLength, CK_ATTRIBUTE[] attributes) {
1031             super(PUBLIC, session, keyID, algorithm, keyLength, attributes);
1032         }
1033         private synchronized void fetchValues() {
1034             token.ensureValid();
1035             if (w != null) {
1036                 return;
1037             }
1038             CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {
1039                 new CK_ATTRIBUTE(CKA_EC_POINT),
1040                 new CK_ATTRIBUTE(CKA_EC_PARAMS),
1041             };
1042             fetchAttributes(attributes);
1043 
1044             try {
1045                 params = P11ECKeyFactory.decodeParameters
1046                             (attributes[1].getByteArray());
1047                 byte[] ecKey = attributes[0].getByteArray();
1048 
1049                 // Check whether the X9.63 encoding of an EC point is wrapped
1050                 // in an ASN.1 OCTET STRING
1051                 if (!token.config.getUseEcX963Encoding()) {


1109     implements Comparable<SessionKeyRef> {
1110     private static ReferenceQueue<P11Key> refQueue =
1111         new ReferenceQueue<P11Key>();
1112     private static Set<SessionKeyRef> refList =
1113         Collections.synchronizedSortedSet(new TreeSet<SessionKeyRef>());
1114 
1115     static ReferenceQueue<P11Key> referenceQueue() {
1116         return refQueue;
1117     }
1118 
1119     private static void drainRefQueueBounded() {
1120         Session sess = null;
1121         Token tkn = null;
1122         while (true) {
1123             SessionKeyRef next = (SessionKeyRef) refQueue.poll();
1124             if (next == null) {
1125                 break;
1126             }
1127 
1128             // If the token is still valid, try to remove the object
1129             if (next.session.token.isValid()) {
1130                 // If this key's token is the same as the previous key, the
1131                 // same session can be used for C_DestroyObject.
1132                 try {
1133                     if (next.session.token != tkn || sess == null) {
1134                         // Release session if not using previous token
1135                         if (tkn != null && sess != null) {
1136                             tkn.releaseSession(sess);
1137                             sess = null;
1138                         }
1139 
1140                         tkn = next.session.token;
1141                         sess = tkn.getOpSession();
1142                     }
1143                     next.disposeNative(sess);
1144                 } catch (PKCS11Exception e) {
1145                     // ignore
1146                 }
1147             }
1148             // Regardless of native results, dispose of java references
1149             next.dispose();
1150         }
1151 
1152         if (tkn != null && sess != null) {
1153             tkn.releaseSession(sess);
1154         }
1155     }
1156 
1157     // handle to the native key
1158     private long keyID;
1159     private Session session;
1160 
1161     SessionKeyRef(P11Key key , long keyID, Session session) {
1162         super(key, refQueue);









1163         this.keyID = keyID;
1164         this.session = session;

1165         this.session.addObject();
1166         refList.add(this);
1167         drainRefQueueBounded();
1168     }
1169 
1170     private void disposeNative(Session s) throws PKCS11Exception {

1171         session.token.p11.C_DestroyObject(s.id(), keyID);
1172     }

1173 
1174     private void dispose() {
1175         refList.remove(this);
1176         this.clear();
1177         session.removeObject();
1178     }
1179 
1180     public int compareTo(SessionKeyRef other) {
1181         if (this.keyID == other.keyID) {
1182             return 0;
1183         } else {
1184             return (this.keyID < other.keyID) ? -1 : 1;
1185         }
1186     }
1187 }


  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package sun.security.pkcs11;
  27 
  28 import java.io.*;
  29 import java.lang.ref.*;
  30 import java.math.BigInteger;
  31 import java.util.*;

  32 import java.security.*;
  33 import java.security.interfaces.*;
  34 import java.security.spec.*;
  35 
  36 import javax.crypto.*;
  37 import javax.crypto.interfaces.*;
  38 import javax.crypto.spec.*;
  39 
  40 import sun.security.rsa.RSAUtil.KeyType;
  41 import sun.security.rsa.RSAPublicKeyImpl;
  42 import sun.security.rsa.RSAPrivateCrtKeyImpl;
  43 
  44 import sun.security.internal.interfaces.TlsMasterSecret;
  45 
  46 import sun.security.pkcs11.wrapper.*;
  47 
  48 import static sun.security.pkcs11.TemplateManager.O_GENERATE;
  49 import static sun.security.pkcs11.wrapper.PKCS11Constants.*;
  50 
  51 import sun.security.util.Debug;
  52 import sun.security.util.DerValue;
  53 import sun.security.util.Length;
  54 import sun.security.util.ECUtil;
  55 
  56 /**
  57  * Key implementation classes.
  58  *
  59  * In PKCS#11, the components of private and secret keys may or may not
  60  * be accessible. If they are, we use the algorithm specific key classes
  61  * (e.g. DSAPrivateKey) for compatibility with existing applications.
  62  * If the components are not accessible, we use a generic class that
  63  * only implements PrivateKey (or SecretKey). Whether the components of a
  64  * key are extractable is automatically determined when the key object is
  65  * created.
  66  *
  67  * @author  Andreas Sterbenz
  68  * @since   1.5
  69  */
  70 abstract class P11Key implements Key, Length {
  71 
  72     private static final long serialVersionUID = -2575874101938349339L;
  73 
  74     private final static String PUBLIC = "public";
  75     private final static String PRIVATE = "private";
  76     private final static String SECRET = "secret";
  77 
  78     // type of key, one of (PUBLIC, PRIVATE, SECRET)
  79     final String type;
  80 
  81     // token instance
  82     final Token token;
  83 
  84     // algorithm name, returned by getAlgorithm(), etc.
  85     final String algorithm;
  86 
  87     // key id
  88     long keyID;
  89 
  90     // effective key length of the key, e.g. 56 for a DES key
  91     final int keyLength;
  92 
  93     // flags indicating whether the key is a token object, sensitive, extractable
  94     final boolean tokenObject, sensitive, extractable;
  95 
  96     // phantom reference notification clean up for session keys
  97     private final SessionKeyRef sessionKeyRef;
  98 
  99     // Native key objects may be temporal: only exist if in use.
 100     private boolean tmpNativeKey;
 101 
 102     private int nativeKeyRefCounting;
 103 
 104     private static long nativeKeyWrapperKeyID = -1;
 105 
 106     // Buffer to hold native key objects info in Java heap in order to
 107     // re-create them if needed.
 108     private byte[] nativeKeyInfo;
 109 
 110     P11Key(String type, Session session, long keyID, String algorithm,
 111             int keyLength, CK_ATTRIBUTE[] attributes, boolean tmpNativeKey) {
 112         this.type = type;
 113         this.token = session.token;
 114         this.keyID = keyID;
 115         this.algorithm = algorithm;
 116         this.keyLength = keyLength;
 117         boolean tokenObject = false;
 118         boolean sensitive = false;
 119         boolean extractable = true;
 120         int n = (attributes == null) ? 0 : attributes.length;
 121         for (int i = 0; i < n; i++) {
 122             CK_ATTRIBUTE attr = attributes[i];
 123             if (attr.type == CKA_TOKEN) {
 124                 tokenObject = attr.getBoolean();
 125             } else if (attr.type == CKA_SENSITIVE) {
 126                 sensitive = attr.getBoolean();
 127             } else if (attr.type == CKA_EXTRACTABLE) {
 128                 extractable = attr.getBoolean();
 129             }
 130         }
 131         this.tokenObject = tokenObject;
 132         this.sensitive = sensitive;
 133         this.extractable = extractable;
 134         if (token.tokenInfo.label[0] == 'N'
 135                 && token.tokenInfo.label[1] == 'S'
 136                 && token.tokenInfo.label[2] == 'S') {
 137             this.tmpNativeKey = tmpNativeKey;
 138         } else {
 139             // Disabled if token is not NSS
 140             this.tmpNativeKey = false;
 141         }
 142         // Disable temporary native keys if the key is not extractable or sensitive
 143         // (when key is a token "secret").
 144         // The foundation for extracting wrapped sensitive keys is in
 145         // place but it's currently disabled for token secrets because:
 146         //      1) there is a bug in NSSDB for persisting CKO_SECRET_KEY
 147         //         in legacy DB (key3.db) which corrupts the key; and,
 148         //      2) sqlite DB (key4.db) is still not supported by SunPKCS11 (see JDK-8165996).
 149         if (!extractable || (sensitive && type.equals(SECRET) && tokenObject)) {
 150             this.tmpNativeKey = false;
 151         }
 152         if (this.tmpNativeKey) {
 153             nativeKeyRefCounting = 0;
 154             try {
 155                 if (sensitive && nativeKeyWrapperKeyID == -1) {
 156                     synchronized(this) {
 157                         if (nativeKeyWrapperKeyID == -1) {
 158                             // Create a global wrapping/unwrapping key
 159                             CK_ATTRIBUTE[] wrappingAttributes = token.getAttributes
 160                             (O_GENERATE, CKO_SECRET_KEY, CKK_AES, new CK_ATTRIBUTE[] {
 161                                     new CK_ATTRIBUTE(CKA_CLASS, CKO_SECRET_KEY),
 162                                     new CK_ATTRIBUTE(CKA_VALUE_LEN, 256 >> 3),
 163                                 });
 164                             Session wrappingSession = null;
 165                             try {
 166                                 wrappingSession = token.getObjSession();
 167                                 nativeKeyWrapperKeyID = token.p11.C_GenerateKey
 168                                         (wrappingSession.id(), new CK_MECHANISM(CKM_AES_KEY_GEN), wrappingAttributes);
 169                             } finally {
 170                                 token.releaseSession(wrappingSession);
 171                             }
 172                         }
 173                     }
 174                 }
 175                 nativeKeyInfo = token.p11.getNativeKeyInfo(session.id(), keyID, nativeKeyWrapperKeyID);
 176                 if (nativeKeyInfo != null && nativeKeyInfo.length > 0) {
 177                     destroyNativeKey();
 178                     // If extracted, it's not a token object anymore
 179                     tokenObject = false;
 180                 } else {
 181                     this.tmpNativeKey = false;
 182                 }
 183             } catch (PKCS11Exception e) {
 184                 // Unexpected behaviour when trying to manage the key life-time.
 185                 // Don't manage the native key.
 186                 this.tmpNativeKey = false;
 187             }
 188         }
 189         if (tokenObject == false) {
 190             sessionKeyRef = new SessionKeyRef(this, this.keyID, session);
 191         } else {
 192             sessionKeyRef = null;
 193         }
 194     }
 195 
 196     public void incNativeKeyRef() throws PKCS11Exception {
 197         if (tmpNativeKey) {
 198             synchronized(this) {
 199                 if (++nativeKeyRefCounting == 1 && nativeKeyInfo != null) {
 200                     // Create a Native Key
 201                     Session session = null;
 202                     try {
 203                         session = token.getObjSession();
 204                         keyID = token.p11.createNativeKey(session.id(), nativeKeyInfo, nativeKeyWrapperKeyID);
 205                         if (sessionKeyRef != null) {
 206                             sessionKeyRef.setKeyIDAndSession(keyID, session);
 207                         }
 208                     } catch (PKCS11Exception e) {
 209                         nativeKeyRefCounting--;
 210                         throw e;
 211                     } finally {
 212                         token.releaseSession(session);
 213                     }
 214                 }
 215             }
 216         }
 217     }
 218 
 219     public void makeNativeKeyPersistent() throws PKCS11Exception {
 220         if (tmpNativeKey) {
 221             synchronized(this) {
 222                 if (nativeKeyRefCounting == 0) {
 223                     this.incNativeKeyRef();
 224                 }
 225 
 226                 // This write is not sync protected because reads are done out of the
 227                 // synchronization block. It's just a best-effort.
 228                 tmpNativeKey = false;
 229 
 230                 // This write is sync protected and provides the real guarantee to avoid
 231                 // native key creation or destruction.
 232                 nativeKeyInfo = null;
 233             }
 234         }
 235     }
 236 
 237     public void decNativeKeyRef() {
 238         if (tmpNativeKey) {
 239             synchronized(this) {
 240                 if(--nativeKeyRefCounting == 0  && nativeKeyInfo != null) {
 241                     try {
 242                         destroyNativeKey();
 243                     } catch (PKCS11Exception e) {
 244                         // This is a best-effort.
 245                     }
 246                 }
 247                 if (nativeKeyRefCounting < 0) {
 248                     nativeKeyRefCounting = 0;
 249                 }
 250             }
 251         }
 252     }
 253 
 254     private void destroyNativeKey() throws PKCS11Exception {
 255         // There is no synchronization needed between SessionKeyRef.disposeNative and
 256         // this method. When SessionKeyRef.disposeNative method is executed, no P11Key
 257         // object exists.
 258         Session session = null;
 259         try {
 260             session = token.getObjSession();
 261             token.p11.C_DestroyObject(session.id(), keyID);
 262         } finally {
 263             if (sessionKeyRef != null) {
 264                 sessionKeyRef.setKeyIDAndSession(0, null);
 265             }
 266             keyID = 0;
 267             token.releaseSession(session);
 268         }
 269     }
 270 
 271     // see JCA spec
 272     public final String getAlgorithm() {
 273         token.ensureValid();
 274         return algorithm;
 275     }
 276 
 277     // see JCA spec
 278     public final byte[] getEncoded() {
 279         byte[] b = getEncodedInternal();
 280         return (b == null) ? null : b.clone();
 281     }
 282 
 283     abstract byte[] getEncodedInternal();
 284 
 285     public boolean equals(Object obj) {
 286         if (this == obj) {
 287             return true;
 288         }
 289         // equals() should never throw exceptions
 290         if (token.isValid() == false) {


 368     public int length() {
 369         return keyLength;
 370     }
 371 
 372     boolean isPublic() {
 373         return type == PUBLIC;
 374     }
 375 
 376     boolean isPrivate() {
 377         return type == PRIVATE;
 378     }
 379 
 380     boolean isSecret() {
 381         return type == SECRET;
 382     }
 383 
 384     void fetchAttributes(CK_ATTRIBUTE[] attributes) {
 385         Session tempSession = null;
 386         try {
 387             tempSession = token.getOpSession();
 388             this.incNativeKeyRef();
 389             try {
 390                 token.p11.C_GetAttributeValue(tempSession.id(), keyID, attributes);
 391             } finally {
 392                 this.decNativeKeyRef();
 393             }
 394         } catch (PKCS11Exception e) {
 395             throw new ProviderException(e);
 396         } finally {
 397             token.releaseSession(tempSession);
 398         }
 399     }
 400 
 401     private final static CK_ATTRIBUTE[] A0 = new CK_ATTRIBUTE[0];
 402 
 403     private static CK_ATTRIBUTE[] getAttributes(Session session, long keyID,
 404             CK_ATTRIBUTE[] knownAttributes, CK_ATTRIBUTE[] desiredAttributes) {
 405         if (knownAttributes == null) {
 406             knownAttributes = A0;
 407         }
 408         for (int i = 0; i < desiredAttributes.length; i++) {
 409             // For each desired attribute, check to see if we have the value
 410             // available already. If everything is here, we save a native call.
 411             CK_ATTRIBUTE attr = desiredAttributes[i];
 412             for (CK_ATTRIBUTE known : knownAttributes) {
 413                 if ((attr.type == known.type) && (known.pValue != null)) {


 417             }
 418             if (attr.pValue == null) {
 419                 // nothing found, need to call C_GetAttributeValue()
 420                 for (int j = 0; j < i; j++) {
 421                     // clear values copied from knownAttributes
 422                     desiredAttributes[j].pValue = null;
 423                 }
 424                 try {
 425                     session.token.p11.C_GetAttributeValue
 426                             (session.id(), keyID, desiredAttributes);
 427                 } catch (PKCS11Exception e) {
 428                     throw new ProviderException(e);
 429                 }
 430                 break; // break loop, goto return
 431             }
 432         }
 433         return desiredAttributes;
 434     }
 435 
 436     static SecretKey secretKey(Session session, long keyID, String algorithm,
 437             int keyLength, CK_ATTRIBUTE[] attributes, boolean tmpNativeKey) {
 438         attributes = getAttributes(session, keyID, attributes, new CK_ATTRIBUTE[] {
 439             new CK_ATTRIBUTE(CKA_TOKEN),
 440             new CK_ATTRIBUTE(CKA_SENSITIVE),
 441             new CK_ATTRIBUTE(CKA_EXTRACTABLE),
 442         });
 443         return new P11SecretKey(session, keyID, algorithm, keyLength, attributes, tmpNativeKey);
 444     }
 445 
 446     static SecretKey masterSecretKey(Session session, long keyID, String algorithm,
 447             int keyLength, CK_ATTRIBUTE[] attributes, int major, int minor,
 448             boolean tmpNativeKey) {
 449         attributes = getAttributes(session, keyID, attributes, new CK_ATTRIBUTE[] {
 450             new CK_ATTRIBUTE(CKA_TOKEN),
 451             new CK_ATTRIBUTE(CKA_SENSITIVE),
 452             new CK_ATTRIBUTE(CKA_EXTRACTABLE),
 453         });
 454         return new P11TlsMasterSecretKey
 455                 (session, keyID, algorithm, keyLength, attributes, major, minor,
 456                 tmpNativeKey);
 457     }
 458 
 459     // we assume that all components of public keys are always accessible
 460     static PublicKey publicKey(Session session, long keyID, String algorithm,
 461             int keyLength, CK_ATTRIBUTE[] attributes, boolean tmpNativeKey) {
 462         switch (algorithm) {
 463             case "RSA":
 464                 return new P11RSAPublicKey
 465                     (session, keyID, algorithm, keyLength, attributes, tmpNativeKey);
 466             case "DSA":
 467                 return new P11DSAPublicKey
 468                     (session, keyID, algorithm, keyLength, attributes, tmpNativeKey);
 469             case "DH":
 470                 return new P11DHPublicKey
 471                     (session, keyID, algorithm, keyLength, attributes, tmpNativeKey);
 472             case "EC":
 473                 return new P11ECPublicKey
 474                     (session, keyID, algorithm, keyLength, attributes, tmpNativeKey);
 475             default:
 476                 throw new ProviderException
 477                     ("Unknown public key algorithm " + algorithm);
 478         }
 479     }
 480 
 481     static PrivateKey privateKey(Session session, long keyID, String algorithm,
 482             int keyLength, CK_ATTRIBUTE[] attributes, boolean tmpNativeKey) {
 483         attributes = getAttributes(session, keyID, attributes, new CK_ATTRIBUTE[] {
 484             new CK_ATTRIBUTE(CKA_TOKEN),
 485             new CK_ATTRIBUTE(CKA_SENSITIVE),
 486             new CK_ATTRIBUTE(CKA_EXTRACTABLE),
 487         });
 488         if (attributes[1].getBoolean() || (attributes[2].getBoolean() == false)) {
 489             return new P11PrivateKey
 490                 (session, keyID, algorithm, keyLength, attributes, tmpNativeKey);
 491         } else {
 492             switch (algorithm) {
 493                 case "RSA":
 494                     // In order to decide if this is RSA CRT key, we first query
 495                     // and see if all extra CRT attributes are available.
 496                     CK_ATTRIBUTE[] attrs2 = new CK_ATTRIBUTE[] {
 497                         new CK_ATTRIBUTE(CKA_PUBLIC_EXPONENT),
 498                         new CK_ATTRIBUTE(CKA_PRIME_1),
 499                         new CK_ATTRIBUTE(CKA_PRIME_2),
 500                         new CK_ATTRIBUTE(CKA_EXPONENT_1),
 501                         new CK_ATTRIBUTE(CKA_EXPONENT_2),
 502                         new CK_ATTRIBUTE(CKA_COEFFICIENT),
 503                     };
 504                     boolean crtKey;
 505                     try {
 506                         session.token.p11.C_GetAttributeValue
 507                             (session.id(), keyID, attrs2);
 508                         crtKey = ((attrs2[0].pValue instanceof byte[]) &&
 509                                   (attrs2[1].pValue instanceof byte[]) &&
 510                                   (attrs2[2].pValue instanceof byte[]) &&
 511                                   (attrs2[3].pValue instanceof byte[]) &&
 512                                   (attrs2[4].pValue instanceof byte[]) &&
 513                                   (attrs2[5].pValue instanceof byte[])) ;
 514                     } catch (PKCS11Exception e) {
 515                         // ignore, assume not available
 516                         crtKey = false;
 517                     }
 518                     if (crtKey) {
 519                         return new P11RSAPrivateKey
 520                                 (session, keyID, algorithm, keyLength, attributes, attrs2, tmpNativeKey);
 521                     } else {
 522                         return new P11RSAPrivateNonCRTKey
 523                                 (session, keyID, algorithm, keyLength, attributes, tmpNativeKey);
 524                     }
 525                 case "DSA":
 526                     return new P11DSAPrivateKey
 527                             (session, keyID, algorithm, keyLength, attributes, tmpNativeKey);
 528                 case "DH":
 529                     return new P11DHPrivateKey
 530                             (session, keyID, algorithm, keyLength, attributes, tmpNativeKey);
 531                 case "EC":
 532                     return new P11ECPrivateKey
 533                             (session, keyID, algorithm, keyLength, attributes, tmpNativeKey);
 534                 default:
 535                     throw new ProviderException
 536                             ("Unknown private key algorithm " + algorithm);
 537             }
 538         }
 539     }
 540 
 541     // class for sensitive and unextractable private keys
 542     private static final class P11PrivateKey extends P11Key
 543                                                 implements PrivateKey {
 544         private static final long serialVersionUID = -2138581185214187615L;
 545 
 546         P11PrivateKey(Session session, long keyID, String algorithm,
 547                 int keyLength, CK_ATTRIBUTE[] attributes, boolean tmpNativeKey) {
 548             super(PRIVATE, session, keyID, algorithm, keyLength, attributes, tmpNativeKey);
 549         }
 550         // XXX temporary encoding for serialization purposes
 551         public String getFormat() {
 552             token.ensureValid();
 553             return null;
 554         }
 555         byte[] getEncodedInternal() {
 556             token.ensureValid();
 557             return null;
 558         }
 559     }
 560 
 561     private static class P11SecretKey extends P11Key implements SecretKey {
 562         private static final long serialVersionUID = -7828241727014329084L;
 563         private volatile byte[] encoded;
 564         P11SecretKey(Session session, long keyID, String algorithm,
 565                 int keyLength, CK_ATTRIBUTE[] attributes, boolean tmpNativeKey) {
 566             super(SECRET, session, keyID, algorithm, keyLength, attributes, tmpNativeKey);
 567         }
 568         public String getFormat() {
 569             token.ensureValid();
 570             if (sensitive || (extractable == false)) {
 571                 return null;
 572             } else {
 573                 return "RAW";
 574             }
 575         }
 576         byte[] getEncodedInternal() {
 577             token.ensureValid();
 578             if (getFormat() == null) {
 579                 return null;
 580             }
 581             byte[] b = encoded;
 582             if (b == null) {
 583                 synchronized (this) {
 584                     b = encoded;
 585                     if (b == null) {
 586                         Session tempSession = null;
 587                         try {
 588                             tempSession = token.getOpSession();
 589                             CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {
 590                                 new CK_ATTRIBUTE(CKA_VALUE),
 591                             };
 592                             this.incNativeKeyRef();
 593                             try {
 594                                 token.p11.C_GetAttributeValue
 595                                     (tempSession.id(), keyID, attributes);
 596                             } finally {
 597                                 this.decNativeKeyRef();
 598                             }
 599                             b = attributes[0].getByteArray();
 600                         } catch (PKCS11Exception e) {
 601                             throw new ProviderException(e);
 602                         } finally {
 603                             token.releaseSession(tempSession);
 604                         }
 605                         encoded = b;
 606                     }
 607                 }
 608             }
 609             return b;
 610         }
 611     }
 612 
 613     @SuppressWarnings("deprecation")
 614     private static class P11TlsMasterSecretKey extends P11SecretKey
 615             implements TlsMasterSecret {
 616         private static final long serialVersionUID = -1318560923770573441L;
 617 
 618         private final int majorVersion, minorVersion;
 619         P11TlsMasterSecretKey(Session session, long keyID, String algorithm,
 620                 int keyLength, CK_ATTRIBUTE[] attributes, int major, int minor,
 621                 boolean tmpNativeKey) {
 622             super(session, keyID, algorithm, keyLength, attributes, tmpNativeKey);
 623             this.majorVersion = major;
 624             this.minorVersion = minor;
 625         }
 626         public int getMajorVersion() {
 627             return majorVersion;
 628         }
 629 
 630         public int getMinorVersion() {
 631             return minorVersion;
 632         }
 633     }
 634 
 635     // RSA CRT private key
 636     private static final class P11RSAPrivateKey extends P11Key
 637                 implements RSAPrivateCrtKey {
 638         private static final long serialVersionUID = 9215872438913515220L;
 639 
 640         private BigInteger n, e, d, p, q, pe, qe, coeff;
 641         private byte[] encoded;
 642         P11RSAPrivateKey(Session session, long keyID, String algorithm,
 643                 int keyLength, CK_ATTRIBUTE[] attrs, CK_ATTRIBUTE[] crtAttrs, boolean tmpNativeKey) {
 644             super(PRIVATE, session, keyID, algorithm, keyLength, attrs, tmpNativeKey);
 645 
 646             for (CK_ATTRIBUTE a : crtAttrs) {
 647                 if (a.type == CKA_PUBLIC_EXPONENT) {
 648                     e = a.getBigInteger();
 649                 } else if (a.type == CKA_PRIME_1) {
 650                     p = a.getBigInteger();
 651                 } else if (a.type == CKA_PRIME_2) {
 652                     q = a.getBigInteger();
 653                 } else if (a.type == CKA_EXPONENT_1) {
 654                     pe = a.getBigInteger();
 655                 } else if (a.type == CKA_EXPONENT_2) {
 656                     qe = a.getBigInteger();
 657                 } else if (a.type == CKA_COEFFICIENT) {
 658                     coeff = a.getBigInteger();
 659                 }
 660             }
 661         }
 662         private synchronized void fetchValues() {
 663             token.ensureValid();
 664             if (n != null) {


 710         }
 711         public BigInteger getPrimeExponentP() {
 712             return pe;
 713         }
 714         public BigInteger getPrimeExponentQ() {
 715             return qe;
 716         }
 717         public BigInteger getCrtCoefficient() {
 718             return coeff;
 719         }
 720     }
 721 
 722     // RSA non-CRT private key
 723     private static final class P11RSAPrivateNonCRTKey extends P11Key
 724                 implements RSAPrivateKey {
 725         private static final long serialVersionUID = 1137764983777411481L;
 726 
 727         private BigInteger n, d;
 728         private byte[] encoded;
 729         P11RSAPrivateNonCRTKey(Session session, long keyID, String algorithm,
 730                 int keyLength, CK_ATTRIBUTE[] attributes, boolean tmpNativeKey) {
 731             super(PRIVATE, session, keyID, algorithm, keyLength, attributes, tmpNativeKey);
 732         }
 733         private synchronized void fetchValues() {
 734             token.ensureValid();
 735             if (n != null) {
 736                 return;
 737             }
 738             CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {
 739                 new CK_ATTRIBUTE(CKA_MODULUS),
 740                 new CK_ATTRIBUTE(CKA_PRIVATE_EXPONENT),
 741             };
 742             fetchAttributes(attributes);
 743             n = attributes[0].getBigInteger();
 744             d = attributes[1].getBigInteger();
 745         }
 746         public String getFormat() {
 747             token.ensureValid();
 748             return "PKCS#8";
 749         }
 750         synchronized byte[] getEncodedInternal() {
 751             token.ensureValid();


 763                 }
 764             }
 765             return encoded;
 766         }
 767         public BigInteger getModulus() {
 768             fetchValues();
 769             return n;
 770         }
 771         public BigInteger getPrivateExponent() {
 772             fetchValues();
 773             return d;
 774         }
 775     }
 776 
 777     private static final class P11RSAPublicKey extends P11Key
 778                                                 implements RSAPublicKey {
 779         private static final long serialVersionUID = -826726289023854455L;
 780         private BigInteger n, e;
 781         private byte[] encoded;
 782         P11RSAPublicKey(Session session, long keyID, String algorithm,
 783                 int keyLength, CK_ATTRIBUTE[] attributes, boolean tmpNativeKey) {
 784             super(PUBLIC, session, keyID, algorithm, keyLength, attributes, tmpNativeKey);
 785         }
 786         private synchronized void fetchValues() {
 787             token.ensureValid();
 788             if (n != null) {
 789                 return;
 790             }
 791             CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {
 792                 new CK_ATTRIBUTE(CKA_MODULUS),
 793                 new CK_ATTRIBUTE(CKA_PUBLIC_EXPONENT),
 794             };
 795             fetchAttributes(attributes);
 796             n = attributes[0].getBigInteger();
 797             e = attributes[1].getBigInteger();
 798         }
 799         public String getFormat() {
 800             token.ensureValid();
 801             return "X.509";
 802         }
 803         synchronized byte[] getEncodedInternal() {
 804             token.ensureValid();


 819         }
 820         public BigInteger getPublicExponent() {
 821             fetchValues();
 822             return e;
 823         }
 824         public String toString() {
 825             fetchValues();
 826             return super.toString() +  "\n  modulus: " + n
 827                 + "\n  public exponent: " + e;
 828         }
 829     }
 830 
 831     private static final class P11DSAPublicKey extends P11Key
 832                                                 implements DSAPublicKey {
 833         private static final long serialVersionUID = 5989753793316396637L;
 834 
 835         private BigInteger y;
 836         private DSAParams params;
 837         private byte[] encoded;
 838         P11DSAPublicKey(Session session, long keyID, String algorithm,
 839                 int keyLength, CK_ATTRIBUTE[] attributes, boolean tmpNativeKey) {
 840             super(PUBLIC, session, keyID, algorithm, keyLength, attributes, tmpNativeKey);
 841         }
 842         private synchronized void fetchValues() {
 843             token.ensureValid();
 844             if (y != null) {
 845                 return;
 846             }
 847             CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {
 848                 new CK_ATTRIBUTE(CKA_VALUE),
 849                 new CK_ATTRIBUTE(CKA_PRIME),
 850                 new CK_ATTRIBUTE(CKA_SUBPRIME),
 851                 new CK_ATTRIBUTE(CKA_BASE),
 852             };
 853             fetchAttributes(attributes);
 854             y = attributes[0].getBigInteger();
 855             params = new DSAParameterSpec(
 856                 attributes[1].getBigInteger(),
 857                 attributes[2].getBigInteger(),
 858                 attributes[3].getBigInteger()
 859             );
 860         }


 882         }
 883         public DSAParams getParams() {
 884             fetchValues();
 885             return params;
 886         }
 887         public String toString() {
 888             fetchValues();
 889             return super.toString() +  "\n  y: " + y + "\n  p: " + params.getP()
 890                 + "\n  q: " + params.getQ() + "\n  g: " + params.getG();
 891         }
 892     }
 893 
 894     private static final class P11DSAPrivateKey extends P11Key
 895                                                 implements DSAPrivateKey {
 896         private static final long serialVersionUID = 3119629997181999389L;
 897 
 898         private BigInteger x;
 899         private DSAParams params;
 900         private byte[] encoded;
 901         P11DSAPrivateKey(Session session, long keyID, String algorithm,
 902                 int keyLength, CK_ATTRIBUTE[] attributes, boolean tmpNativeKey) {
 903             super(PRIVATE, session, keyID, algorithm, keyLength, attributes, tmpNativeKey);
 904         }
 905         private synchronized void fetchValues() {
 906             token.ensureValid();
 907             if (x != null) {
 908                 return;
 909             }
 910             CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {
 911                 new CK_ATTRIBUTE(CKA_VALUE),
 912                 new CK_ATTRIBUTE(CKA_PRIME),
 913                 new CK_ATTRIBUTE(CKA_SUBPRIME),
 914                 new CK_ATTRIBUTE(CKA_BASE),
 915             };
 916             fetchAttributes(attributes);
 917             x = attributes[0].getBigInteger();
 918             params = new DSAParameterSpec(
 919                 attributes[1].getBigInteger(),
 920                 attributes[2].getBigInteger(),
 921                 attributes[3].getBigInteger()
 922             );
 923         }


 940             return encoded;
 941         }
 942         public BigInteger getX() {
 943             fetchValues();
 944             return x;
 945         }
 946         public DSAParams getParams() {
 947             fetchValues();
 948             return params;
 949         }
 950     }
 951 
 952     private static final class P11DHPrivateKey extends P11Key
 953                                                 implements DHPrivateKey {
 954         private static final long serialVersionUID = -1698576167364928838L;
 955 
 956         private BigInteger x;
 957         private DHParameterSpec params;
 958         private byte[] encoded;
 959         P11DHPrivateKey(Session session, long keyID, String algorithm,
 960                 int keyLength, CK_ATTRIBUTE[] attributes, boolean tmpNativeKey) {
 961             super(PRIVATE, session, keyID, algorithm, keyLength, attributes, tmpNativeKey);
 962         }
 963         private synchronized void fetchValues() {
 964             token.ensureValid();
 965             if (x != null) {
 966                 return;
 967             }
 968             CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {
 969                 new CK_ATTRIBUTE(CKA_VALUE),
 970                 new CK_ATTRIBUTE(CKA_PRIME),
 971                 new CK_ATTRIBUTE(CKA_BASE),
 972             };
 973             fetchAttributes(attributes);
 974             x = attributes[0].getBigInteger();
 975             params = new DHParameterSpec(
 976                 attributes[1].getBigInteger(),
 977                 attributes[2].getBigInteger()
 978             );
 979         }
 980         public String getFormat() {
 981             token.ensureValid();


1022             if (!(obj instanceof DHPrivateKey)) {
1023                 return false;
1024             }
1025             fetchValues();
1026             DHPrivateKey other = (DHPrivateKey) obj;
1027             DHParameterSpec otherParams = other.getParams();
1028             return ((this.x.compareTo(other.getX()) == 0) &&
1029                     (this.params.getP().compareTo(otherParams.getP()) == 0) &&
1030                     (this.params.getG().compareTo(otherParams.getG()) == 0));
1031         }
1032     }
1033 
1034     private static final class P11DHPublicKey extends P11Key
1035                                                 implements DHPublicKey {
1036         static final long serialVersionUID = -598383872153843657L;
1037 
1038         private BigInteger y;
1039         private DHParameterSpec params;
1040         private byte[] encoded;
1041         P11DHPublicKey(Session session, long keyID, String algorithm,
1042                 int keyLength, CK_ATTRIBUTE[] attributes, boolean tmpNativeKey) {
1043             super(PUBLIC, session, keyID, algorithm, keyLength, attributes, tmpNativeKey);
1044         }
1045         private synchronized void fetchValues() {
1046             token.ensureValid();
1047             if (y != null) {
1048                 return;
1049             }
1050             CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {
1051                 new CK_ATTRIBUTE(CKA_VALUE),
1052                 new CK_ATTRIBUTE(CKA_PRIME),
1053                 new CK_ATTRIBUTE(CKA_BASE),
1054             };
1055             fetchAttributes(attributes);
1056             y = attributes[0].getBigInteger();
1057             params = new DHParameterSpec(
1058                 attributes[1].getBigInteger(),
1059                 attributes[2].getBigInteger()
1060             );
1061         }
1062         public String getFormat() {
1063             token.ensureValid();


1109             if (!(obj instanceof DHPublicKey)) {
1110                 return false;
1111             }
1112             fetchValues();
1113             DHPublicKey other = (DHPublicKey) obj;
1114             DHParameterSpec otherParams = other.getParams();
1115             return ((this.y.compareTo(other.getY()) == 0) &&
1116                     (this.params.getP().compareTo(otherParams.getP()) == 0) &&
1117                     (this.params.getG().compareTo(otherParams.getG()) == 0));
1118         }
1119     }
1120 
1121     private static final class P11ECPrivateKey extends P11Key
1122                                                 implements ECPrivateKey {
1123         private static final long serialVersionUID = -7786054399510515515L;
1124 
1125         private BigInteger s;
1126         private ECParameterSpec params;
1127         private byte[] encoded;
1128         P11ECPrivateKey(Session session, long keyID, String algorithm,
1129                 int keyLength, CK_ATTRIBUTE[] attributes, boolean tmpNativeKey) {
1130             super(PRIVATE, session, keyID, algorithm, keyLength, attributes, tmpNativeKey);
1131         }
1132         private synchronized void fetchValues() {
1133             token.ensureValid();
1134             if (s != null) {
1135                 return;
1136             }
1137             CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {
1138                 new CK_ATTRIBUTE(CKA_VALUE),
1139                 new CK_ATTRIBUTE(CKA_EC_PARAMS, params),
1140             };
1141             fetchAttributes(attributes);
1142             s = attributes[0].getBigInteger();
1143             try {
1144                 params = P11ECKeyFactory.decodeParameters
1145                             (attributes[1].getByteArray());
1146             } catch (Exception e) {
1147                 throw new RuntimeException("Could not parse key values", e);
1148             }
1149         }
1150         public String getFormat() {


1165             return encoded;
1166         }
1167         public BigInteger getS() {
1168             fetchValues();
1169             return s;
1170         }
1171         public ECParameterSpec getParams() {
1172             fetchValues();
1173             return params;
1174         }
1175     }
1176 
1177     private static final class P11ECPublicKey extends P11Key
1178                                                 implements ECPublicKey {
1179         private static final long serialVersionUID = -6371481375154806089L;
1180 
1181         private ECPoint w;
1182         private ECParameterSpec params;
1183         private byte[] encoded;
1184         P11ECPublicKey(Session session, long keyID, String algorithm,
1185                 int keyLength, CK_ATTRIBUTE[] attributes, boolean tmpNativeKey) {
1186             super(PUBLIC, session, keyID, algorithm, keyLength, attributes, tmpNativeKey);
1187         }
1188         private synchronized void fetchValues() {
1189             token.ensureValid();
1190             if (w != null) {
1191                 return;
1192             }
1193             CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {
1194                 new CK_ATTRIBUTE(CKA_EC_POINT),
1195                 new CK_ATTRIBUTE(CKA_EC_PARAMS),
1196             };
1197             fetchAttributes(attributes);
1198 
1199             try {
1200                 params = P11ECKeyFactory.decodeParameters
1201                             (attributes[1].getByteArray());
1202                 byte[] ecKey = attributes[0].getByteArray();
1203 
1204                 // Check whether the X9.63 encoding of an EC point is wrapped
1205                 // in an ASN.1 OCTET STRING
1206                 if (!token.config.getUseEcX963Encoding()) {


1264     implements Comparable<SessionKeyRef> {
1265     private static ReferenceQueue<P11Key> refQueue =
1266         new ReferenceQueue<P11Key>();
1267     private static Set<SessionKeyRef> refList =
1268         Collections.synchronizedSortedSet(new TreeSet<SessionKeyRef>());
1269 
1270     static ReferenceQueue<P11Key> referenceQueue() {
1271         return refQueue;
1272     }
1273 
1274     private static void drainRefQueueBounded() {
1275         Session sess = null;
1276         Token tkn = null;
1277         while (true) {
1278             SessionKeyRef next = (SessionKeyRef) refQueue.poll();
1279             if (next == null) {
1280                 break;
1281             }
1282 
1283             // If the token is still valid, try to remove the object
1284             if (next.session != null && next.session.token.isValid()) {
1285                 // If this key's token is the same as the previous key, the
1286                 // same session can be used for C_DestroyObject.
1287                 try {
1288                     if (next.session.token != tkn || sess == null) {
1289                         // Release session if not using previous token
1290                         if (tkn != null && sess != null) {
1291                             tkn.releaseSession(sess);
1292                             sess = null;
1293                         }
1294 
1295                         tkn = next.session.token;
1296                         sess = tkn.getOpSession();
1297                     }
1298                     next.disposeNative(sess);
1299                 } catch (PKCS11Exception e) {
1300                     // ignore
1301                 }
1302             }
1303             // Regardless of native results, dispose of java references
1304             next.dispose();
1305         }
1306 
1307         if (tkn != null && sess != null) {
1308             tkn.releaseSession(sess);
1309         }
1310     }
1311 
1312     // handle to the native key
1313     private long keyID;
1314     private Session session;
1315 
1316     SessionKeyRef(P11Key key , long keyID, Session session) {
1317         super(key, refQueue);
1318         setKeyIDAndSession(keyID, session);
1319         refList.add(this);
1320         drainRefQueueBounded();
1321     }
1322 
1323     public void setKeyIDAndSession(long keyID, Session session) {
1324         if (this.session != null) {
1325             this.session.removeObject();
1326         }
1327         this.keyID = keyID;
1328         this.session = session;
1329         if (this.session != null) {
1330             this.session.addObject();
1331         }

1332     }
1333 
1334     private void disposeNative(Session s) throws PKCS11Exception {
1335         if(this.session != null) {
1336             session.token.p11.C_DestroyObject(s.id(), keyID);
1337         }
1338     }
1339 
1340     private void dispose() {
1341         refList.remove(this);
1342         this.clear();
1343         setKeyIDAndSession(0, null);
1344     }
1345 
1346     public int compareTo(SessionKeyRef other) {
1347         if (this.keyID == other.keyID) {
1348             return 0;
1349         } else {
1350             return (this.keyID < other.keyID) ? -1 : 1;
1351         }
1352     }
1353 }
< prev index next >