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