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