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