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