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 } |