1 /* 2 * Copyright (c) 2003, 2013, 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 import sun.security.util.ECUtil; 51 52 /** 53 * Key implementation classes. 54 * 55 * In PKCS#11, the components of private and secret keys may or may not 56 * be accessible. If they are, we use the algorithm specific key classes 57 * (e.g. DSAPrivateKey) for compatibility with existing applications. 58 * If the components are not accessible, we use a generic class that 59 * only implements PrivateKey (or SecretKey). Whether the components of a 60 * key are extractable is automatically determined when the key object is 61 * created. 62 * 63 * @author Andreas Sterbenz 64 * @since 1.5 65 */ 66 abstract class P11Key implements Key, Length { 67 68 private static final long serialVersionUID = -2575874101938349339L; 69 70 private final static String PUBLIC = "public"; 71 private final static String PRIVATE = "private"; 72 private final static String SECRET = "secret"; 73 74 // type of key, one of (PUBLIC, PRIVATE, SECRET) 75 final String type; 76 77 // token instance 78 final Token token; 79 80 // algorithm name, returned by getAlgorithm(), etc. 81 final String algorithm; 82 83 // key id 84 final long keyID; 85 86 // effective key length of the key, e.g. 56 for a DES key 87 final int keyLength; 88 89 // flags indicating whether the key is a token object, sensitive, extractable 90 final boolean tokenObject, sensitive, extractable; 91 92 // phantom reference notification clean up for session keys 93 private final SessionKeyRef sessionKeyRef; 94 95 P11Key(String type, Session session, long keyID, String algorithm, 96 int keyLength, CK_ATTRIBUTE[] attributes) { 97 this.type = type; 98 this.token = session.token; 99 this.keyID = keyID; 100 this.algorithm = algorithm; 101 this.keyLength = keyLength; 102 boolean tokenObject = false; 103 boolean sensitive = false; 104 boolean extractable = true; 105 int n = (attributes == null) ? 0 : attributes.length; 106 for (int i = 0; i < n; i++) { 107 CK_ATTRIBUTE attr = attributes[i]; 108 if (attr.type == CKA_TOKEN) { 109 tokenObject = attr.getBoolean(); 110 } else if (attr.type == CKA_SENSITIVE) { 111 sensitive = attr.getBoolean(); 112 } else if (attr.type == CKA_EXTRACTABLE) { 113 extractable = attr.getBoolean(); 114 } 115 } 116 this.tokenObject = tokenObject; 117 this.sensitive = sensitive; 118 this.extractable = extractable; 119 if (tokenObject == false) { 120 sessionKeyRef = new SessionKeyRef(this, keyID, session); 121 } else { 122 sessionKeyRef = null; 123 } 124 } 125 126 // see JCA spec 127 public final String getAlgorithm() { 128 token.ensureValid(); 129 return algorithm; 130 } 131 132 // see JCA spec 133 public final byte[] getEncoded() { 134 byte[] b = getEncodedInternal(); 135 return (b == null) ? null : b.clone(); 136 } 137 138 abstract byte[] getEncodedInternal(); 139 140 public boolean equals(Object obj) { 141 if (this == obj) { 142 return true; 143 } 144 // equals() should never throw exceptions 145 if (token.isValid() == false) { 146 return false; 147 } 148 if (obj instanceof Key == false) { 149 return false; 150 } 151 String thisFormat = getFormat(); 152 if (thisFormat == null) { 153 // no encoding, key only equal to itself 154 // XXX getEncoded() for unextractable keys will change that 155 return false; 156 } 157 Key other = (Key)obj; 158 if (thisFormat.equals(other.getFormat()) == false) { 159 return false; 160 } 161 byte[] thisEnc = this.getEncodedInternal(); 162 byte[] otherEnc; 163 if (obj instanceof P11Key) { 164 otherEnc = ((P11Key)other).getEncodedInternal(); 165 } else { 166 otherEnc = other.getEncoded(); 167 } 168 return Arrays.equals(thisEnc, otherEnc); 169 } 170 171 public int hashCode() { 172 // hashCode() should never throw exceptions 173 if (token.isValid() == false) { 174 return 0; 175 } 176 byte[] b1 = getEncodedInternal(); 177 if (b1 == null) { 178 return 0; 179 } 180 int r = b1.length; 181 for (int i = 0; i < b1.length; i++) { 182 r += (b1[i] & 0xff) * 37; 183 } 184 return r; 185 } 186 187 protected Object writeReplace() throws ObjectStreamException { 188 KeyRep.Type type; 189 String format = getFormat(); 190 if (isPrivate() && "PKCS#8".equals(format)) { 191 type = KeyRep.Type.PRIVATE; 192 } else if (isPublic() && "X.509".equals(format)) { 193 type = KeyRep.Type.PUBLIC; 194 } else if (isSecret() && "RAW".equals(format)) { 195 type = KeyRep.Type.SECRET; 196 } else { 197 // XXX short term serialization for unextractable keys 198 throw new NotSerializableException 199 ("Cannot serialize sensitive and unextractable keys"); 200 } 201 return new KeyRep(type, getAlgorithm(), format, getEncoded()); 202 } 203 204 public String toString() { 205 token.ensureValid(); 206 String s1 = token.provider.getName() + " " + algorithm + " " + type 207 + " key, " + keyLength + " bits"; 208 s1 += " (id " + keyID + ", " 209 + (tokenObject ? "token" : "session") + " object"; 210 if (isPublic()) { 211 s1 += ")"; 212 } else { 213 s1 += ", " + (sensitive ? "" : "not ") + "sensitive"; 214 s1 += ", " + (extractable ? "" : "un") + "extractable)"; 215 } 216 return s1; 217 } 218 219 /** 220 * Return bit length of the key. 221 */ 222 @Override 223 public int length() { 224 return keyLength; 225 } 226 227 boolean isPublic() { 228 return type == PUBLIC; 229 } 230 231 boolean isPrivate() { 232 return type == PRIVATE; 233 } 234 235 boolean isSecret() { 236 return type == SECRET; 237 } 238 239 void fetchAttributes(CK_ATTRIBUTE[] attributes) { 240 Session tempSession = null; 241 try { 242 tempSession = token.getOpSession(); 243 token.p11.C_GetAttributeValue(tempSession.id(), keyID, attributes); 244 } catch (PKCS11Exception e) { 245 throw new ProviderException(e); 246 } finally { 247 token.releaseSession(tempSession); 248 } 249 } 250 251 private final static CK_ATTRIBUTE[] A0 = new CK_ATTRIBUTE[0]; 252 253 private static CK_ATTRIBUTE[] getAttributes(Session session, long keyID, 254 CK_ATTRIBUTE[] knownAttributes, CK_ATTRIBUTE[] desiredAttributes) { 255 if (knownAttributes == null) { 256 knownAttributes = A0; 257 } 258 for (int i = 0; i < desiredAttributes.length; i++) { 259 // For each desired attribute, check to see if we have the value 260 // available already. If everything is here, we save a native call. 261 CK_ATTRIBUTE attr = desiredAttributes[i]; 262 for (CK_ATTRIBUTE known : knownAttributes) { 263 if ((attr.type == known.type) && (known.pValue != null)) { 264 attr.pValue = known.pValue; 265 break; // break inner for loop 266 } 267 } 268 if (attr.pValue == null) { 269 // nothing found, need to call C_GetAttributeValue() 270 for (int j = 0; j < i; j++) { 271 // clear values copied from knownAttributes 272 desiredAttributes[j].pValue = null; 273 } 274 try { 275 session.token.p11.C_GetAttributeValue 276 (session.id(), keyID, desiredAttributes); 277 } catch (PKCS11Exception e) { 278 throw new ProviderException(e); 279 } 280 break; // break loop, goto return 281 } 282 } 283 return desiredAttributes; 284 } 285 286 static SecretKey secretKey(Session session, long keyID, String algorithm, 287 int keyLength, CK_ATTRIBUTE[] attributes) { 288 attributes = getAttributes(session, keyID, attributes, new CK_ATTRIBUTE[] { 289 new CK_ATTRIBUTE(CKA_TOKEN), 290 new CK_ATTRIBUTE(CKA_SENSITIVE), 291 new CK_ATTRIBUTE(CKA_EXTRACTABLE), 292 }); 293 return new P11SecretKey(session, keyID, algorithm, keyLength, attributes); 294 } 295 296 static SecretKey masterSecretKey(Session session, long keyID, String algorithm, 297 int keyLength, CK_ATTRIBUTE[] attributes, int major, int minor) { 298 attributes = getAttributes(session, keyID, attributes, new CK_ATTRIBUTE[] { 299 new CK_ATTRIBUTE(CKA_TOKEN), 300 new CK_ATTRIBUTE(CKA_SENSITIVE), 301 new CK_ATTRIBUTE(CKA_EXTRACTABLE), 302 }); 303 return new P11TlsMasterSecretKey 304 (session, keyID, algorithm, keyLength, attributes, major, minor); 305 } 306 307 // we assume that all components of public keys are always accessible 308 static PublicKey publicKey(Session session, long keyID, String algorithm, 309 int keyLength, CK_ATTRIBUTE[] attributes) { 310 switch (algorithm) { 311 case "RSA": 312 return new P11RSAPublicKey 313 (session, keyID, algorithm, keyLength, attributes); 314 case "DSA": 315 return new P11DSAPublicKey 316 (session, keyID, algorithm, keyLength, attributes); 317 case "DH": 318 return new P11DHPublicKey 319 (session, keyID, algorithm, keyLength, attributes); 320 case "EC": 321 return new P11ECPublicKey 322 (session, keyID, algorithm, keyLength, attributes); 323 default: 324 throw new ProviderException 325 ("Unknown public key algorithm " + algorithm); 326 } 327 } 328 329 static PrivateKey privateKey(Session session, long keyID, String algorithm, 330 int keyLength, CK_ATTRIBUTE[] attributes) { 331 attributes = getAttributes(session, keyID, attributes, new CK_ATTRIBUTE[] { 332 new CK_ATTRIBUTE(CKA_TOKEN), 333 new CK_ATTRIBUTE(CKA_SENSITIVE), 334 new CK_ATTRIBUTE(CKA_EXTRACTABLE), 335 }); 336 if (attributes[1].getBoolean() || (attributes[2].getBoolean() == false)) { 337 return new P11PrivateKey 338 (session, keyID, algorithm, keyLength, attributes); 339 } else { 340 switch (algorithm) { 341 case "RSA": 342 // XXX better test for RSA CRT keys (single getAttributes() call) 343 // we need to determine whether this is a CRT key 344 // see if we can obtain the public exponent 345 // this should also be readable for sensitive/extractable keys 346 CK_ATTRIBUTE[] attrs2 = new CK_ATTRIBUTE[] { 347 new CK_ATTRIBUTE(CKA_PUBLIC_EXPONENT), 348 }; 349 boolean crtKey; 350 try { 351 session.token.p11.C_GetAttributeValue 352 (session.id(), keyID, attrs2); 353 crtKey = (attrs2[0].pValue instanceof byte[]); 354 } catch (PKCS11Exception e) { 355 // ignore, assume not available 356 crtKey = false; 357 } 358 if (crtKey) { 359 return new P11RSAPrivateKey 360 (session, keyID, algorithm, keyLength, attributes); 361 } else { 362 return new P11RSAPrivateNonCRTKey 363 (session, keyID, algorithm, keyLength, attributes); 364 } 365 case "DSA": 366 return new P11DSAPrivateKey 367 (session, keyID, algorithm, keyLength, attributes); 368 case "DH": 369 return new P11DHPrivateKey 370 (session, keyID, algorithm, keyLength, attributes); 371 case "EC": 372 return new P11ECPrivateKey 373 (session, keyID, algorithm, keyLength, attributes); 374 default: 375 throw new ProviderException 376 ("Unknown private key algorithm " + algorithm); 377 } 378 } 379 } 380 381 // class for sensitive and unextractable private keys 382 private static final class P11PrivateKey extends P11Key 383 implements PrivateKey { 384 private static final long serialVersionUID = -2138581185214187615L; 385 386 P11PrivateKey(Session session, long keyID, String algorithm, 387 int keyLength, CK_ATTRIBUTE[] attributes) { 388 super(PRIVATE, session, keyID, algorithm, keyLength, attributes); 389 } 390 // XXX temporary encoding for serialization purposes 391 public String getFormat() { 392 token.ensureValid(); 393 return null; 394 } 395 byte[] getEncodedInternal() { 396 token.ensureValid(); 397 return null; 398 } 399 } 400 401 private static class P11SecretKey extends P11Key implements SecretKey { 402 private static final long serialVersionUID = -7828241727014329084L; 403 private volatile byte[] encoded; 404 P11SecretKey(Session session, long keyID, String algorithm, 405 int keyLength, CK_ATTRIBUTE[] attributes) { 406 super(SECRET, session, keyID, algorithm, keyLength, attributes); 407 } 408 public String getFormat() { 409 token.ensureValid(); 410 if (sensitive || (extractable == false)) { 411 return null; 412 } else { 413 return "RAW"; 414 } 415 } 416 byte[] getEncodedInternal() { 417 token.ensureValid(); 418 if (getFormat() == null) { 419 return null; 420 } 421 byte[] b = encoded; 422 if (b == null) { 423 synchronized (this) { 424 b = encoded; 425 if (b == null) { 426 Session tempSession = null; 427 try { 428 tempSession = token.getOpSession(); 429 CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] { 430 new CK_ATTRIBUTE(CKA_VALUE), 431 }; 432 token.p11.C_GetAttributeValue 433 (tempSession.id(), keyID, attributes); 434 b = attributes[0].getByteArray(); 435 } catch (PKCS11Exception e) { 436 throw new ProviderException(e); 437 } finally { 438 token.releaseSession(tempSession); 439 } 440 encoded = b; 441 } 442 } 443 } 444 return b; 445 } 446 } 447 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 = ECUtil.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 ECUtil.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 }