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