1 /* 2 * Copyright (c) 2003, 2016, 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 // In order to decide if this is RSA CRT key, we first query 344 // and see if all extra CRT attributes are available. 345 CK_ATTRIBUTE[] attrs2 = new CK_ATTRIBUTE[] { 346 new CK_ATTRIBUTE(CKA_PUBLIC_EXPONENT), 347 new CK_ATTRIBUTE(CKA_PRIME_1), 348 new CK_ATTRIBUTE(CKA_PRIME_2), 349 new CK_ATTRIBUTE(CKA_EXPONENT_1), 350 new CK_ATTRIBUTE(CKA_EXPONENT_2), 351 new CK_ATTRIBUTE(CKA_COEFFICIENT), 352 }; 353 boolean crtKey; 354 try { 355 session.token.p11.C_GetAttributeValue 356 (session.id(), keyID, attrs2); 357 crtKey = ((attrs2[0].pValue instanceof byte[]) && 358 (attrs2[1].pValue instanceof byte[]) && 359 (attrs2[2].pValue instanceof byte[]) && 360 (attrs2[3].pValue instanceof byte[]) && 361 (attrs2[4].pValue instanceof byte[]) && 362 (attrs2[5].pValue instanceof byte[])) ; 363 } catch (PKCS11Exception e) { 364 // ignore, assume not available 365 crtKey = false; 366 } 367 if (crtKey) { 368 return new P11RSAPrivateKey 369 (session, keyID, algorithm, keyLength, attributes, attrs2); 370 } else { 371 return new P11RSAPrivateNonCRTKey 372 (session, keyID, algorithm, keyLength, attributes); 373 } 374 case "DSA": 375 return new P11DSAPrivateKey 376 (session, keyID, algorithm, keyLength, attributes); 377 case "DH": 378 return new P11DHPrivateKey 379 (session, keyID, algorithm, keyLength, attributes); 380 case "EC": 381 return new P11ECPrivateKey 382 (session, keyID, algorithm, keyLength, attributes); 383 default: 384 throw new ProviderException 385 ("Unknown private key algorithm " + algorithm); 386 } 387 } 388 } 389 390 // class for sensitive and unextractable private keys 391 private static final class P11PrivateKey extends P11Key 392 implements PrivateKey { 393 private static final long serialVersionUID = -2138581185214187615L; 394 395 P11PrivateKey(Session session, long keyID, String algorithm, 396 int keyLength, CK_ATTRIBUTE[] attributes) { 397 super(PRIVATE, session, keyID, algorithm, keyLength, attributes); 398 } 399 // XXX temporary encoding for serialization purposes 400 public String getFormat() { 401 token.ensureValid(); 402 return null; 403 } 404 byte[] getEncodedInternal() { 405 token.ensureValid(); 406 return null; 407 } 408 } 409 410 private static class P11SecretKey extends P11Key implements SecretKey { 411 private static final long serialVersionUID = -7828241727014329084L; 412 private volatile byte[] encoded; 413 P11SecretKey(Session session, long keyID, String algorithm, 414 int keyLength, CK_ATTRIBUTE[] attributes) { 415 super(SECRET, session, keyID, algorithm, keyLength, attributes); 416 } 417 public String getFormat() { 418 token.ensureValid(); 419 if (sensitive || (extractable == false)) { 420 return null; 421 } else { 422 return "RAW"; 423 } 424 } 425 byte[] getEncodedInternal() { 426 token.ensureValid(); 427 if (getFormat() == null) { 428 return null; 429 } 430 byte[] b = encoded; 431 if (b == null) { 432 synchronized (this) { 433 b = encoded; 434 if (b == null) { 435 Session tempSession = null; 436 try { 437 tempSession = token.getOpSession(); 438 CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] { 439 new CK_ATTRIBUTE(CKA_VALUE), 440 }; 441 token.p11.C_GetAttributeValue 442 (tempSession.id(), keyID, attributes); 443 b = attributes[0].getByteArray(); 444 } catch (PKCS11Exception e) { 445 throw new ProviderException(e); 446 } finally { 447 token.releaseSession(tempSession); 448 } 449 encoded = b; 450 } 451 } 452 } 453 return b; 454 } 455 } 456 457 @SuppressWarnings("deprecation") 458 private static class P11TlsMasterSecretKey extends P11SecretKey 459 implements TlsMasterSecret { 460 private static final long serialVersionUID = -1318560923770573441L; 461 462 private final int majorVersion, minorVersion; 463 P11TlsMasterSecretKey(Session session, long keyID, String algorithm, 464 int keyLength, CK_ATTRIBUTE[] attributes, int major, int minor) { 465 super(session, keyID, algorithm, keyLength, attributes); 466 this.majorVersion = major; 467 this.minorVersion = minor; 468 } 469 public int getMajorVersion() { 470 return majorVersion; 471 } 472 473 public int getMinorVersion() { 474 return minorVersion; 475 } 476 } 477 478 // RSA CRT private key 479 private static final class P11RSAPrivateKey extends P11Key 480 implements RSAPrivateCrtKey { 481 private static final long serialVersionUID = 9215872438913515220L; 482 483 private BigInteger n, e, d, p, q, pe, qe, coeff; 484 private byte[] encoded; 485 P11RSAPrivateKey(Session session, long keyID, String algorithm, 486 int keyLength, CK_ATTRIBUTE[] attrs, CK_ATTRIBUTE[] crtAttrs) { 487 super(PRIVATE, session, keyID, algorithm, keyLength, attrs); 488 489 for (CK_ATTRIBUTE a : crtAttrs) { 490 if (a.type == CKA_PUBLIC_EXPONENT) { 491 e = a.getBigInteger(); 492 } else if (a.type == CKA_PRIME_1) { 493 p = a.getBigInteger(); 494 } else if (a.type == CKA_PRIME_2) { 495 q = a.getBigInteger(); 496 } else if (a.type == CKA_EXPONENT_1) { 497 pe = a.getBigInteger(); 498 } else if (a.type == CKA_EXPONENT_2) { 499 qe = a.getBigInteger(); 500 } else if (a.type == CKA_COEFFICIENT) { 501 coeff = a.getBigInteger(); 502 } 503 } 504 } 505 private synchronized void fetchValues() { 506 token.ensureValid(); 507 if (n != null) { 508 return; 509 } 510 CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] { 511 new CK_ATTRIBUTE(CKA_MODULUS), 512 new CK_ATTRIBUTE(CKA_PRIVATE_EXPONENT), 513 }; 514 fetchAttributes(attributes); 515 n = attributes[0].getBigInteger(); 516 d = attributes[1].getBigInteger(); 517 } 518 519 public String getFormat() { 520 token.ensureValid(); 521 return "PKCS#8"; 522 } 523 synchronized byte[] getEncodedInternal() { 524 token.ensureValid(); 525 if (encoded == null) { 526 fetchValues(); 527 try { 528 // XXX make constructor in SunRsaSign provider public 529 // and call it directly 530 KeyFactory factory = KeyFactory.getInstance 531 ("RSA", P11Util.getSunRsaSignProvider()); 532 Key newKey = factory.translateKey(this); 533 encoded = newKey.getEncoded(); 534 } catch (GeneralSecurityException e) { 535 throw new ProviderException(e); 536 } 537 } 538 return encoded; 539 } 540 public BigInteger getModulus() { 541 fetchValues(); 542 return n; 543 } 544 public BigInteger getPublicExponent() { 545 return e; 546 } 547 public BigInteger getPrivateExponent() { 548 fetchValues(); 549 return d; 550 } 551 public BigInteger getPrimeP() { 552 return p; 553 } 554 public BigInteger getPrimeQ() { 555 return q; 556 } 557 public BigInteger getPrimeExponentP() { 558 return pe; 559 } 560 public BigInteger getPrimeExponentQ() { 561 return qe; 562 } 563 public BigInteger getCrtCoefficient() { 564 return coeff; 565 } 566 } 567 568 // RSA non-CRT private key 569 private static final class P11RSAPrivateNonCRTKey extends P11Key 570 implements RSAPrivateKey { 571 private static final long serialVersionUID = 1137764983777411481L; 572 573 private BigInteger n, d; 574 private byte[] encoded; 575 P11RSAPrivateNonCRTKey(Session session, long keyID, String algorithm, 576 int keyLength, CK_ATTRIBUTE[] attributes) { 577 super(PRIVATE, session, keyID, algorithm, keyLength, attributes); 578 } 579 private synchronized void fetchValues() { 580 token.ensureValid(); 581 if (n != null) { 582 return; 583 } 584 CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] { 585 new CK_ATTRIBUTE(CKA_MODULUS), 586 new CK_ATTRIBUTE(CKA_PRIVATE_EXPONENT), 587 }; 588 fetchAttributes(attributes); 589 n = attributes[0].getBigInteger(); 590 d = attributes[1].getBigInteger(); 591 } 592 public String getFormat() { 593 token.ensureValid(); 594 return "PKCS#8"; 595 } 596 synchronized byte[] getEncodedInternal() { 597 token.ensureValid(); 598 if (encoded == null) { 599 fetchValues(); 600 try { 601 // XXX make constructor in SunRsaSign provider public 602 // and call it directly 603 KeyFactory factory = KeyFactory.getInstance 604 ("RSA", P11Util.getSunRsaSignProvider()); 605 Key newKey = factory.translateKey(this); 606 encoded = newKey.getEncoded(); 607 } catch (GeneralSecurityException e) { 608 throw new ProviderException(e); 609 } 610 } 611 return encoded; 612 } 613 public BigInteger getModulus() { 614 fetchValues(); 615 return n; 616 } 617 public BigInteger getPrivateExponent() { 618 fetchValues(); 619 return d; 620 } 621 } 622 623 private static final class P11RSAPublicKey extends P11Key 624 implements RSAPublicKey { 625 private static final long serialVersionUID = -826726289023854455L; 626 627 private BigInteger n, e; 628 private byte[] encoded; 629 P11RSAPublicKey(Session session, long keyID, String algorithm, 630 int keyLength, CK_ATTRIBUTE[] attributes) { 631 super(PUBLIC, session, keyID, algorithm, keyLength, attributes); 632 } 633 private synchronized void fetchValues() { 634 token.ensureValid(); 635 if (n != null) { 636 return; 637 } 638 CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] { 639 new CK_ATTRIBUTE(CKA_MODULUS), 640 new CK_ATTRIBUTE(CKA_PUBLIC_EXPONENT), 641 }; 642 fetchAttributes(attributes); 643 n = attributes[0].getBigInteger(); 644 e = attributes[1].getBigInteger(); 645 } 646 public String getFormat() { 647 token.ensureValid(); 648 return "X.509"; 649 } 650 synchronized byte[] getEncodedInternal() { 651 token.ensureValid(); 652 if (encoded == null) { 653 fetchValues(); 654 try { 655 encoded = new RSAPublicKeyImpl(n, e).getEncoded(); 656 } catch (InvalidKeyException e) { 657 throw new ProviderException(e); 658 } 659 } 660 return encoded; 661 } 662 public BigInteger getModulus() { 663 fetchValues(); 664 return n; 665 } 666 public BigInteger getPublicExponent() { 667 fetchValues(); 668 return e; 669 } 670 public String toString() { 671 fetchValues(); 672 return super.toString() + "\n modulus: " + n 673 + "\n public exponent: " + e; 674 } 675 } 676 677 private static final class P11DSAPublicKey extends P11Key 678 implements DSAPublicKey { 679 private static final long serialVersionUID = 5989753793316396637L; 680 681 private BigInteger y; 682 private DSAParams params; 683 private byte[] encoded; 684 P11DSAPublicKey(Session session, long keyID, String algorithm, 685 int keyLength, CK_ATTRIBUTE[] attributes) { 686 super(PUBLIC, session, keyID, algorithm, keyLength, attributes); 687 } 688 private synchronized void fetchValues() { 689 token.ensureValid(); 690 if (y != null) { 691 return; 692 } 693 CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] { 694 new CK_ATTRIBUTE(CKA_VALUE), 695 new CK_ATTRIBUTE(CKA_PRIME), 696 new CK_ATTRIBUTE(CKA_SUBPRIME), 697 new CK_ATTRIBUTE(CKA_BASE), 698 }; 699 fetchAttributes(attributes); 700 y = attributes[0].getBigInteger(); 701 params = new DSAParameterSpec( 702 attributes[1].getBigInteger(), 703 attributes[2].getBigInteger(), 704 attributes[3].getBigInteger() 705 ); 706 } 707 public String getFormat() { 708 token.ensureValid(); 709 return "X.509"; 710 } 711 synchronized byte[] getEncodedInternal() { 712 token.ensureValid(); 713 if (encoded == null) { 714 fetchValues(); 715 try { 716 Key key = new sun.security.provider.DSAPublicKey 717 (y, params.getP(), params.getQ(), params.getG()); 718 encoded = key.getEncoded(); 719 } catch (InvalidKeyException e) { 720 throw new ProviderException(e); 721 } 722 } 723 return encoded; 724 } 725 public BigInteger getY() { 726 fetchValues(); 727 return y; 728 } 729 public DSAParams getParams() { 730 fetchValues(); 731 return params; 732 } 733 public String toString() { 734 fetchValues(); 735 return super.toString() + "\n y: " + y + "\n p: " + params.getP() 736 + "\n q: " + params.getQ() + "\n g: " + params.getG(); 737 } 738 } 739 740 private static final class P11DSAPrivateKey extends P11Key 741 implements DSAPrivateKey { 742 private static final long serialVersionUID = 3119629997181999389L; 743 744 private BigInteger x; 745 private DSAParams params; 746 private byte[] encoded; 747 P11DSAPrivateKey(Session session, long keyID, String algorithm, 748 int keyLength, CK_ATTRIBUTE[] attributes) { 749 super(PRIVATE, session, keyID, algorithm, keyLength, attributes); 750 } 751 private synchronized void fetchValues() { 752 token.ensureValid(); 753 if (x != null) { 754 return; 755 } 756 CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] { 757 new CK_ATTRIBUTE(CKA_VALUE), 758 new CK_ATTRIBUTE(CKA_PRIME), 759 new CK_ATTRIBUTE(CKA_SUBPRIME), 760 new CK_ATTRIBUTE(CKA_BASE), 761 }; 762 fetchAttributes(attributes); 763 x = attributes[0].getBigInteger(); 764 params = new DSAParameterSpec( 765 attributes[1].getBigInteger(), 766 attributes[2].getBigInteger(), 767 attributes[3].getBigInteger() 768 ); 769 } 770 public String getFormat() { 771 token.ensureValid(); 772 return "PKCS#8"; 773 } 774 synchronized byte[] getEncodedInternal() { 775 token.ensureValid(); 776 if (encoded == null) { 777 fetchValues(); 778 try { 779 Key key = new sun.security.provider.DSAPrivateKey 780 (x, params.getP(), params.getQ(), params.getG()); 781 encoded = key.getEncoded(); 782 } catch (InvalidKeyException e) { 783 throw new ProviderException(e); 784 } 785 } 786 return encoded; 787 } 788 public BigInteger getX() { 789 fetchValues(); 790 return x; 791 } 792 public DSAParams getParams() { 793 fetchValues(); 794 return params; 795 } 796 } 797 798 private static final class P11DHPrivateKey extends P11Key 799 implements DHPrivateKey { 800 private static final long serialVersionUID = -1698576167364928838L; 801 802 private BigInteger x; 803 private DHParameterSpec params; 804 private byte[] encoded; 805 P11DHPrivateKey(Session session, long keyID, String algorithm, 806 int keyLength, CK_ATTRIBUTE[] attributes) { 807 super(PRIVATE, session, keyID, algorithm, keyLength, attributes); 808 } 809 private synchronized void fetchValues() { 810 token.ensureValid(); 811 if (x != null) { 812 return; 813 } 814 CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] { 815 new CK_ATTRIBUTE(CKA_VALUE), 816 new CK_ATTRIBUTE(CKA_PRIME), 817 new CK_ATTRIBUTE(CKA_BASE), 818 }; 819 fetchAttributes(attributes); 820 x = attributes[0].getBigInteger(); 821 params = new DHParameterSpec( 822 attributes[1].getBigInteger(), 823 attributes[2].getBigInteger() 824 ); 825 } 826 public String getFormat() { 827 token.ensureValid(); 828 return "PKCS#8"; 829 } 830 synchronized byte[] getEncodedInternal() { 831 token.ensureValid(); 832 if (encoded == null) { 833 fetchValues(); 834 try { 835 DHPrivateKeySpec spec = new DHPrivateKeySpec 836 (x, params.getP(), params.getG()); 837 KeyFactory kf = KeyFactory.getInstance 838 ("DH", P11Util.getSunJceProvider()); 839 Key key = kf.generatePrivate(spec); 840 encoded = key.getEncoded(); 841 } catch (GeneralSecurityException e) { 842 throw new ProviderException(e); 843 } 844 } 845 return encoded; 846 } 847 public BigInteger getX() { 848 fetchValues(); 849 return x; 850 } 851 public DHParameterSpec getParams() { 852 fetchValues(); 853 return params; 854 } 855 public int hashCode() { 856 if (token.isValid() == false) { 857 return 0; 858 } 859 fetchValues(); 860 return Objects.hash(x, params.getP(), params.getG()); 861 } 862 public boolean equals(Object obj) { 863 if (this == obj) return true; 864 // equals() should never throw exceptions 865 if (token.isValid() == false) { 866 return false; 867 } 868 if (!(obj instanceof DHPrivateKey)) { 869 return false; 870 } 871 fetchValues(); 872 DHPrivateKey other = (DHPrivateKey) obj; 873 DHParameterSpec otherParams = other.getParams(); 874 return ((this.x.compareTo(other.getX()) == 0) && 875 (this.params.getP().compareTo(otherParams.getP()) == 0) && 876 (this.params.getG().compareTo(otherParams.getG()) == 0)); 877 } 878 } 879 880 private static final class P11DHPublicKey extends P11Key 881 implements DHPublicKey { 882 static final long serialVersionUID = -598383872153843657L; 883 884 private BigInteger y; 885 private DHParameterSpec params; 886 private byte[] encoded; 887 P11DHPublicKey(Session session, long keyID, String algorithm, 888 int keyLength, CK_ATTRIBUTE[] attributes) { 889 super(PUBLIC, session, keyID, algorithm, keyLength, attributes); 890 } 891 private synchronized void fetchValues() { 892 token.ensureValid(); 893 if (y != null) { 894 return; 895 } 896 CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] { 897 new CK_ATTRIBUTE(CKA_VALUE), 898 new CK_ATTRIBUTE(CKA_PRIME), 899 new CK_ATTRIBUTE(CKA_BASE), 900 }; 901 fetchAttributes(attributes); 902 y = attributes[0].getBigInteger(); 903 params = new DHParameterSpec( 904 attributes[1].getBigInteger(), 905 attributes[2].getBigInteger() 906 ); 907 } 908 public String getFormat() { 909 token.ensureValid(); 910 return "X.509"; 911 } 912 synchronized byte[] getEncodedInternal() { 913 token.ensureValid(); 914 if (encoded == null) { 915 fetchValues(); 916 try { 917 DHPublicKeySpec spec = new DHPublicKeySpec 918 (y, params.getP(), params.getG()); 919 KeyFactory kf = KeyFactory.getInstance 920 ("DH", P11Util.getSunJceProvider()); 921 Key key = kf.generatePublic(spec); 922 encoded = key.getEncoded(); 923 } catch (GeneralSecurityException e) { 924 throw new ProviderException(e); 925 } 926 } 927 return encoded; 928 } 929 public BigInteger getY() { 930 fetchValues(); 931 return y; 932 } 933 public DHParameterSpec getParams() { 934 fetchValues(); 935 return params; 936 } 937 public String toString() { 938 fetchValues(); 939 return super.toString() + "\n y: " + y + "\n p: " + params.getP() 940 + "\n g: " + params.getG(); 941 } 942 public int hashCode() { 943 if (token.isValid() == false) { 944 return 0; 945 } 946 fetchValues(); 947 return Objects.hash(y, params.getP(), params.getG()); 948 } 949 public boolean equals(Object obj) { 950 if (this == obj) return true; 951 // equals() should never throw exceptions 952 if (token.isValid() == false) { 953 return false; 954 } 955 if (!(obj instanceof DHPublicKey)) { 956 return false; 957 } 958 fetchValues(); 959 DHPublicKey other = (DHPublicKey) obj; 960 DHParameterSpec otherParams = other.getParams(); 961 return ((this.y.compareTo(other.getY()) == 0) && 962 (this.params.getP().compareTo(otherParams.getP()) == 0) && 963 (this.params.getG().compareTo(otherParams.getG()) == 0)); 964 } 965 } 966 967 private static final class P11ECPrivateKey extends P11Key 968 implements ECPrivateKey { 969 private static final long serialVersionUID = -7786054399510515515L; 970 971 private BigInteger s; 972 private ECParameterSpec params; 973 private byte[] encoded; 974 P11ECPrivateKey(Session session, long keyID, String algorithm, 975 int keyLength, CK_ATTRIBUTE[] attributes) { 976 super(PRIVATE, session, keyID, algorithm, keyLength, attributes); 977 } 978 private synchronized void fetchValues() { 979 token.ensureValid(); 980 if (s != null) { 981 return; 982 } 983 CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] { 984 new CK_ATTRIBUTE(CKA_VALUE), 985 new CK_ATTRIBUTE(CKA_EC_PARAMS, params), 986 }; 987 fetchAttributes(attributes); 988 s = attributes[0].getBigInteger(); 989 try { 990 params = P11ECKeyFactory.decodeParameters 991 (attributes[1].getByteArray()); 992 } catch (Exception e) { 993 throw new RuntimeException("Could not parse key values", e); 994 } 995 } 996 public String getFormat() { 997 token.ensureValid(); 998 return "PKCS#8"; 999 } 1000 synchronized byte[] getEncodedInternal() { 1001 token.ensureValid(); 1002 if (encoded == null) { 1003 fetchValues(); 1004 try { 1005 Key key = ECUtil.generateECPrivateKey(s, params); 1006 encoded = key.getEncoded(); 1007 } catch (InvalidKeySpecException e) { 1008 throw new ProviderException(e); 1009 } 1010 } 1011 return encoded; 1012 } 1013 public BigInteger getS() { 1014 fetchValues(); 1015 return s; 1016 } 1017 public ECParameterSpec getParams() { 1018 fetchValues(); 1019 return params; 1020 } 1021 } 1022 1023 private static final class P11ECPublicKey extends P11Key 1024 implements ECPublicKey { 1025 private static final long serialVersionUID = -6371481375154806089L; 1026 1027 private ECPoint w; 1028 private ECParameterSpec params; 1029 private byte[] encoded; 1030 P11ECPublicKey(Session session, long keyID, String algorithm, 1031 int keyLength, CK_ATTRIBUTE[] attributes) { 1032 super(PUBLIC, session, keyID, algorithm, keyLength, attributes); 1033 } 1034 private synchronized void fetchValues() { 1035 token.ensureValid(); 1036 if (w != null) { 1037 return; 1038 } 1039 CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] { 1040 new CK_ATTRIBUTE(CKA_EC_POINT), 1041 new CK_ATTRIBUTE(CKA_EC_PARAMS), 1042 }; 1043 fetchAttributes(attributes); 1044 1045 try { 1046 params = P11ECKeyFactory.decodeParameters 1047 (attributes[1].getByteArray()); 1048 byte[] ecKey = attributes[0].getByteArray(); 1049 1050 // Check whether the X9.63 encoding of an EC point is wrapped 1051 // in an ASN.1 OCTET STRING 1052 if (!token.config.getUseEcX963Encoding()) { 1053 DerValue wECPoint = new DerValue(ecKey); 1054 1055 if (wECPoint.getTag() != DerValue.tag_OctetString) { 1056 throw new IOException("Could not DER decode EC point." + 1057 " Unexpected tag: " + wECPoint.getTag()); 1058 } 1059 w = P11ECKeyFactory.decodePoint 1060 (wECPoint.getDataBytes(), params.getCurve()); 1061 1062 } else { 1063 w = P11ECKeyFactory.decodePoint(ecKey, params.getCurve()); 1064 } 1065 1066 } catch (Exception e) { 1067 throw new RuntimeException("Could not parse key values", e); 1068 } 1069 } 1070 public String getFormat() { 1071 token.ensureValid(); 1072 return "X.509"; 1073 } 1074 synchronized byte[] getEncodedInternal() { 1075 token.ensureValid(); 1076 if (encoded == null) { 1077 fetchValues(); 1078 try { 1079 return ECUtil.x509EncodeECPublicKey(w, params); 1080 } catch (InvalidKeySpecException e) { 1081 throw new ProviderException(e); 1082 } 1083 } 1084 return encoded; 1085 } 1086 public ECPoint getW() { 1087 fetchValues(); 1088 return w; 1089 } 1090 public ECParameterSpec getParams() { 1091 fetchValues(); 1092 return params; 1093 } 1094 public String toString() { 1095 fetchValues(); 1096 return super.toString() 1097 + "\n public x coord: " + w.getAffineX() 1098 + "\n public y coord: " + w.getAffineY() 1099 + "\n parameters: " + params; 1100 } 1101 } 1102 } 1103 1104 /* 1105 * NOTE: Must use PhantomReference here and not WeakReference 1106 * otherwise the key maybe cleared before other objects which 1107 * still use these keys during finalization such as SSLSocket. 1108 */ 1109 final class SessionKeyRef extends PhantomReference<P11Key> 1110 implements Comparable<SessionKeyRef> { 1111 private static ReferenceQueue<P11Key> refQueue = 1112 new ReferenceQueue<P11Key>(); 1113 private static Set<SessionKeyRef> refList = 1114 Collections.synchronizedSortedSet(new TreeSet<SessionKeyRef>()); 1115 1116 static ReferenceQueue<P11Key> referenceQueue() { 1117 return refQueue; 1118 } 1119 1120 private static void drainRefQueueBounded() { 1121 Session sess = null; 1122 Token tkn = null; 1123 while (true) { 1124 SessionKeyRef next = (SessionKeyRef) refQueue.poll(); 1125 if (next == null) { 1126 break; 1127 } 1128 1129 // If the token is still valid, try to remove the object 1130 if (next.session.token.isValid()) { 1131 // If this key's token is the same as the previous key, the 1132 // same session can be used for C_DestroyObject. 1133 try { 1134 if (next.session.token != tkn || sess == null) { 1135 // Release session if not using previous token 1136 if (tkn != null && sess != null) { 1137 tkn.releaseSession(sess); 1138 sess = null; 1139 } 1140 1141 tkn = next.session.token; 1142 sess = tkn.getOpSession(); 1143 } 1144 next.disposeNative(sess); 1145 } catch (PKCS11Exception e) { 1146 // ignore 1147 } 1148 } 1149 // Regardless of native results, dispose of java references 1150 next.dispose(); 1151 } 1152 1153 if (tkn != null && sess != null) { 1154 tkn.releaseSession(sess); 1155 } 1156 } 1157 1158 // handle to the native key 1159 private long keyID; 1160 private Session session; 1161 1162 SessionKeyRef(P11Key key , long keyID, Session session) { 1163 super(key, refQueue); 1164 this.keyID = keyID; 1165 this.session = session; 1166 this.session.addObject(); 1167 refList.add(this); 1168 drainRefQueueBounded(); 1169 } 1170 1171 private void disposeNative(Session s) throws PKCS11Exception { 1172 session.token.p11.C_DestroyObject(s.id(), keyID); 1173 } 1174 1175 private void dispose() { 1176 refList.remove(this); 1177 this.clear(); 1178 session.removeObject(); 1179 } 1180 1181 public int compareTo(SessionKeyRef other) { 1182 if (this.keyID == other.keyID) { 1183 return 0; 1184 } else { 1185 return (this.keyID < other.keyID) ? -1 : 1; 1186 } 1187 } 1188 }