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