1 /* 2 * Copyright (c) 2000, 2006, 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 /* 27 * NOTE: this file was copied from javax.net.ssl.SSLSecurity, 28 * but was heavily modified to allow com.sun.* users to 29 * access providers written using the javax.sun.* APIs. 30 */ 31 32 package com.sun.net.ssl; 33 34 import java.util.*; 35 import java.io.*; 36 import java.security.*; 37 import java.security.Provider.Service; 38 import java.net.Socket; 39 40 import sun.security.jca.*; 41 42 /** 43 * This class instantiates implementations of JSSE engine classes from 44 * providers registered with the java.security.Security object. 45 * 46 * @author Jan Luehe 47 * @author Jeff Nisewanger 48 * @author Brad Wetmore 49 */ 50 51 final class SSLSecurity { 52 53 /* 54 * Don't let anyone instantiate this. 55 */ 56 private SSLSecurity() { 57 } 58 59 60 // ProviderList.getService() is not accessible now, implement our own loop 61 private static Service getService(String type, String alg) { 62 ProviderList list = Providers.getProviderList(); 63 for (Provider p : list.providers()) { 64 Service s = p.getService(type, alg); 65 if (s != null) { 66 return s; 67 } 68 } 69 return null; 70 } 71 72 /** 73 * The body of the driver for the getImpl method. 74 */ 75 private static Object[] getImpl1(String algName, String engineType, 76 Service service) throws NoSuchAlgorithmException 77 { 78 Provider provider = service.getProvider(); 79 String className = service.getClassName(); 80 Class implClass; 81 try { 82 ClassLoader cl = provider.getClass().getClassLoader(); 83 if (cl == null) { 84 // system class 85 implClass = Class.forName(className); 86 } else { 87 implClass = cl.loadClass(className); 88 } 89 } catch (ClassNotFoundException e) { 90 throw new NoSuchAlgorithmException("Class " + className + 91 " configured for " + 92 engineType + 93 " not found: " + 94 e.getMessage()); 95 } catch (SecurityException e) { 96 throw new NoSuchAlgorithmException("Class " + className + 97 " configured for " + 98 engineType + 99 " cannot be accessed: " + 100 e.getMessage()); 101 } 102 103 /* 104 * JSSE 1.0, 1.0.1, and 1.0.2 used the com.sun.net.ssl API as the 105 * API was being developed. As JSSE was folded into the main 106 * release, it was decided to promote the com.sun.net.ssl API to 107 * be javax.net.ssl. It is desired to keep binary compatibility 108 * with vendors of JSSE implementation written using the 109 * com.sun.net.sll API, so we do this magic to handle everything. 110 * 111 * API used Implementation used Supported? 112 * ======== =================== ========== 113 * com.sun javax Yes 114 * com.sun com.sun Yes 115 * javax javax Yes 116 * javax com.sun Not Currently 117 * 118 * Make sure the implementation class is a subclass of the 119 * corresponding engine class. 120 * 121 * In wrapping these classes, there's no way to know how to 122 * wrap all possible classes that extend the TrustManager/KeyManager. 123 * We only wrap the x509 variants. 124 */ 125 126 try { // catch instantiation errors 127 128 /* 129 * (The following Class.forName()s should alway work, because 130 * this class and all the SPI classes in javax.crypto are 131 * loaded by the same class loader.) That is, unless they 132 * give us a SPI class that doesn't exist, say SSLFoo, 133 * or someone has removed classes from the jsse.jar file. 134 */ 135 136 Class typeClassJavax; 137 Class typeClassCom; 138 Object obj = null; 139 140 /* 141 * Odds are more likely that we have a javax variant, try this 142 * first. 143 */ 144 if (((typeClassJavax = Class.forName("javax.net.ssl." + 145 engineType + "Spi")) != null) && 146 (checkSuperclass(implClass, typeClassJavax))) { 147 148 if (engineType.equals("SSLContext")) { 149 obj = new SSLContextSpiWrapper(algName, provider); 150 } else if (engineType.equals("TrustManagerFactory")) { 151 obj = new TrustManagerFactorySpiWrapper(algName, provider); 152 } else if (engineType.equals("KeyManagerFactory")) { 153 obj = new KeyManagerFactorySpiWrapper(algName, provider); 154 } else { 155 /* 156 * We should throw an error if we get 157 * something totally unexpected. Don't ever 158 * expect to see this one... 159 */ 160 throw new IllegalStateException( 161 "Class " + implClass.getName() + 162 " unknown engineType wrapper:" + engineType); 163 } 164 165 } else if (((typeClassCom = Class.forName("com.sun.net.ssl." + 166 engineType + "Spi")) != null) && 167 (checkSuperclass(implClass, typeClassCom))) { 168 obj = service.newInstance(null); 169 } 170 171 if (obj != null) { 172 return new Object[] { obj, provider }; 173 } else { 174 throw new NoSuchAlgorithmException( 175 "Couldn't locate correct object or wrapper: " + 176 engineType + " " + algName); 177 } 178 179 } catch (ClassNotFoundException e) { 180 IllegalStateException exc = new IllegalStateException( 181 "Engine Class Not Found for " + engineType); 182 exc.initCause(e); 183 throw exc; 184 } 185 } 186 187 /** 188 * Returns an array of objects: the first object in the array is 189 * an instance of an implementation of the requested algorithm 190 * and type, and the second object in the array identifies the provider 191 * of that implementation. 192 * The <code>provName</code> argument can be null, in which case all 193 * configured providers will be searched in order of preference. 194 */ 195 static Object[] getImpl(String algName, String engineType, String provName) 196 throws NoSuchAlgorithmException, NoSuchProviderException 197 { 198 Service service; 199 if (provName != null) { 200 ProviderList list = Providers.getProviderList(); 201 Provider prov = list.getProvider(provName); 202 if (prov == null) { 203 throw new NoSuchProviderException("No such provider: " + 204 provName); 205 } 206 service = prov.getService(engineType, algName); 207 } else { 208 service = getService(engineType, algName); 209 } 210 if (service == null) { 211 throw new NoSuchAlgorithmException("Algorithm " + algName 212 + " not available"); 213 } 214 return getImpl1(algName, engineType, service); 215 } 216 217 218 /** 219 * Returns an array of objects: the first object in the array is 220 * an instance of an implementation of the requested algorithm 221 * and type, and the second object in the array identifies the provider 222 * of that implementation. 223 * The <code>prov</code> argument can be null, in which case all 224 * configured providers will be searched in order of preference. 225 */ 226 static Object[] getImpl(String algName, String engineType, Provider prov) 227 throws NoSuchAlgorithmException 228 { 229 Service service = prov.getService(engineType, algName); 230 if (service == null) { 231 throw new NoSuchAlgorithmException("No such algorithm: " + 232 algName); 233 } 234 return getImpl1(algName, engineType, service); 235 } 236 237 /* 238 * Checks whether one class is the superclass of another 239 */ 240 private static boolean checkSuperclass(Class subclass, Class superclass) { 241 if ((subclass == null) || (superclass == null)) 242 return false; 243 244 while (!subclass.equals(superclass)) { 245 subclass = subclass.getSuperclass(); 246 if (subclass == null) { 247 return false; 248 } 249 } 250 return true; 251 } 252 253 /* 254 * Return at most the first "resize" elements of an array. 255 * 256 * Didn't want to use java.util.Arrays, as PJava may not have it. 257 */ 258 static Object[] truncateArray(Object[] oldArray, Object[] newArray) { 259 260 for (int i = 0; i < newArray.length; i++) { 261 newArray[i] = oldArray[i]; 262 } 263 264 return newArray; 265 } 266 267 } 268 269 270 /* 271 * ================================================================= 272 * The remainder of this file is for the wrapper and wrapper-support 273 * classes. When SSLSecurity finds something which extends the 274 * javax.net.ssl.*Spi, we need to go grab a real instance of the 275 * thing that the Spi supports, and wrap into a com.sun.net.ssl.*Spi 276 * object. This also mean that anything going down into the SPI 277 * needs to be wrapped, as well as anything coming back up. 278 */ 279 280 final class SSLContextSpiWrapper extends SSLContextSpi { 281 282 private javax.net.ssl.SSLContext theSSLContext; 283 284 SSLContextSpiWrapper(String algName, Provider prov) throws 285 NoSuchAlgorithmException { 286 theSSLContext = javax.net.ssl.SSLContext.getInstance(algName, prov); 287 } 288 289 protected void engineInit(KeyManager[] kma, TrustManager[] tma, 290 SecureRandom sr) throws KeyManagementException { 291 292 // Keep track of the actual number of array elements copied 293 int dst; 294 int src; 295 javax.net.ssl.KeyManager[] kmaw; 296 javax.net.ssl.TrustManager[] tmaw; 297 298 // Convert com.sun.net.ssl.kma to a javax.net.ssl.kma 299 // wrapper if need be. 300 if (kma != null) { 301 kmaw = new javax.net.ssl.KeyManager[kma.length]; 302 for (src = 0, dst = 0; src < kma.length; ) { 303 /* 304 * These key managers may implement both javax 305 * and com.sun interfaces, so if they do 306 * javax, there's no need to wrap them. 307 */ 308 if (!(kma[src] instanceof javax.net.ssl.KeyManager)) { 309 /* 310 * Do we know how to convert them? If not, oh well... 311 * We'll have to drop them on the floor in this 312 * case, cause we don't know how to handle them. 313 * This will be pretty rare, but put here for 314 * completeness. 315 */ 316 if (kma[src] instanceof X509KeyManager) { 317 kmaw[dst] = (javax.net.ssl.KeyManager) 318 new X509KeyManagerJavaxWrapper( 319 (X509KeyManager)kma[src]); 320 dst++; 321 } 322 } else { 323 // We can convert directly, since they implement. 324 kmaw[dst] = (javax.net.ssl.KeyManager)kma[src]; 325 dst++; 326 } 327 src++; 328 } 329 330 /* 331 * If dst != src, there were more items in the original array 332 * than in the new array. Compress the new elements to avoid 333 * any problems down the road. 334 */ 335 if (dst != src) { 336 kmaw = (javax.net.ssl.KeyManager []) 337 SSLSecurity.truncateArray(kmaw, 338 new javax.net.ssl.KeyManager [dst]); 339 } 340 } else { 341 kmaw = null; 342 } 343 344 // Now do the same thing with the TrustManagers. 345 if (tma != null) { 346 tmaw = new javax.net.ssl.TrustManager[tma.length]; 347 348 for (src = 0, dst = 0; src < tma.length; ) { 349 /* 350 * These key managers may implement both...see above... 351 */ 352 if (!(tma[src] instanceof javax.net.ssl.TrustManager)) { 353 // Do we know how to convert them? 354 if (tma[src] instanceof X509TrustManager) { 355 tmaw[dst] = (javax.net.ssl.TrustManager) 356 new X509TrustManagerJavaxWrapper( 357 (X509TrustManager)tma[src]); 358 dst++; 359 } 360 } else { 361 tmaw[dst] = (javax.net.ssl.TrustManager)tma[src]; 362 dst++; 363 } 364 src++; 365 } 366 367 if (dst != src) { 368 tmaw = (javax.net.ssl.TrustManager []) 369 SSLSecurity.truncateArray(tmaw, 370 new javax.net.ssl.TrustManager [dst]); 371 } 372 } else { 373 tmaw = null; 374 } 375 376 theSSLContext.init(kmaw, tmaw, sr); 377 } 378 379 protected javax.net.ssl.SSLSocketFactory 380 engineGetSocketFactory() { 381 return theSSLContext.getSocketFactory(); 382 } 383 384 protected javax.net.ssl.SSLServerSocketFactory 385 engineGetServerSocketFactory() { 386 return theSSLContext.getServerSocketFactory(); 387 } 388 389 } 390 391 final class TrustManagerFactorySpiWrapper extends TrustManagerFactorySpi { 392 393 private javax.net.ssl.TrustManagerFactory theTrustManagerFactory; 394 395 TrustManagerFactorySpiWrapper(String algName, Provider prov) throws 396 NoSuchAlgorithmException { 397 theTrustManagerFactory = 398 javax.net.ssl.TrustManagerFactory.getInstance(algName, prov); 399 } 400 401 protected void engineInit(KeyStore ks) throws KeyStoreException { 402 theTrustManagerFactory.init(ks); 403 } 404 405 protected TrustManager[] engineGetTrustManagers() { 406 407 int dst; 408 int src; 409 410 javax.net.ssl.TrustManager[] tma = 411 theTrustManagerFactory.getTrustManagers(); 412 413 TrustManager[] tmaw = new TrustManager[tma.length]; 414 415 for (src = 0, dst = 0; src < tma.length; ) { 416 if (!(tma[src] instanceof com.sun.net.ssl.TrustManager)) { 417 // We only know how to wrap X509TrustManagers, as 418 // TrustManagers don't have any methods to wrap. 419 if (tma[src] instanceof javax.net.ssl.X509TrustManager) { 420 tmaw[dst] = (TrustManager) 421 new X509TrustManagerComSunWrapper( 422 (javax.net.ssl.X509TrustManager)tma[src]); 423 dst++; 424 } 425 } else { 426 tmaw[dst] = (TrustManager)tma[src]; 427 dst++; 428 } 429 src++; 430 } 431 432 if (dst != src) { 433 tmaw = (TrustManager []) 434 SSLSecurity.truncateArray(tmaw, new TrustManager [dst]); 435 } 436 437 return tmaw; 438 } 439 440 } 441 442 final class KeyManagerFactorySpiWrapper extends KeyManagerFactorySpi { 443 444 private javax.net.ssl.KeyManagerFactory theKeyManagerFactory; 445 446 KeyManagerFactorySpiWrapper(String algName, Provider prov) throws 447 NoSuchAlgorithmException { 448 theKeyManagerFactory = 449 javax.net.ssl.KeyManagerFactory.getInstance(algName, prov); 450 } 451 452 protected void engineInit(KeyStore ks, char[] password) 453 throws KeyStoreException, NoSuchAlgorithmException, 454 UnrecoverableKeyException { 455 theKeyManagerFactory.init(ks, password); 456 } 457 458 protected KeyManager[] engineGetKeyManagers() { 459 460 int dst; 461 int src; 462 463 javax.net.ssl.KeyManager[] kma = 464 theKeyManagerFactory.getKeyManagers(); 465 466 KeyManager[] kmaw = new KeyManager[kma.length]; 467 468 for (src = 0, dst = 0; src < kma.length; ) { 469 if (!(kma[src] instanceof com.sun.net.ssl.KeyManager)) { 470 // We only know how to wrap X509KeyManagers, as 471 // KeyManagers don't have any methods to wrap. 472 if (kma[src] instanceof javax.net.ssl.X509KeyManager) { 473 kmaw[dst] = (KeyManager) 474 new X509KeyManagerComSunWrapper( 475 (javax.net.ssl.X509KeyManager)kma[src]); 476 dst++; 477 } 478 } else { 479 kmaw[dst] = (KeyManager)kma[src]; 480 dst++; 481 } 482 src++; 483 } 484 485 if (dst != src) { 486 kmaw = (KeyManager []) 487 SSLSecurity.truncateArray(kmaw, new KeyManager [dst]); 488 } 489 490 return kmaw; 491 } 492 493 } 494 495 // ================================= 496 497 final class X509KeyManagerJavaxWrapper implements 498 javax.net.ssl.X509KeyManager { 499 500 private X509KeyManager theX509KeyManager; 501 502 X509KeyManagerJavaxWrapper(X509KeyManager obj) { 503 theX509KeyManager = obj; 504 } 505 506 public String[] getClientAliases(String keyType, Principal[] issuers) { 507 return theX509KeyManager.getClientAliases(keyType, issuers); 508 } 509 510 public String chooseClientAlias(String[] keyTypes, Principal[] issuers, 511 Socket socket) { 512 String retval; 513 514 if (keyTypes == null) { 515 return null; 516 } 517 518 /* 519 * Scan the list, look for something we can pass back. 520 */ 521 for (int i = 0; i < keyTypes.length; i++) { 522 if ((retval = theX509KeyManager.chooseClientAlias(keyTypes[i], 523 issuers)) != null) 524 return retval; 525 } 526 return null; 527 528 } 529 530 /* 531 * JSSE 1.0.x was only socket based, but it's possible someone might 532 * want to install a really old provider. We should at least 533 * try to be nice. 534 */ 535 public String chooseEngineClientAlias( 536 String[] keyTypes, Principal[] issuers, 537 javax.net.ssl.SSLEngine engine) { 538 String retval; 539 540 if (keyTypes == null) { 541 return null; 542 } 543 544 /* 545 * Scan the list, look for something we can pass back. 546 */ 547 for (int i = 0; i < keyTypes.length; i++) { 548 if ((retval = theX509KeyManager.chooseClientAlias(keyTypes[i], 549 issuers)) != null) 550 return retval; 551 } 552 553 return null; 554 } 555 556 public String[] getServerAliases(String keyType, Principal[] issuers) { 557 return theX509KeyManager.getServerAliases(keyType, issuers); 558 } 559 560 public String chooseServerAlias(String keyType, Principal[] issuers, 561 Socket socket) { 562 563 if (keyType == null) { 564 return null; 565 } 566 return theX509KeyManager.chooseServerAlias(keyType, issuers); 567 } 568 569 /* 570 * JSSE 1.0.x was only socket based, but it's possible someone might 571 * want to install a really old provider. We should at least 572 * try to be nice. 573 */ 574 public String chooseEngineServerAlias( 575 String keyType, Principal[] issuers, 576 javax.net.ssl.SSLEngine engine) { 577 578 if (keyType == null) { 579 return null; 580 } 581 return theX509KeyManager.chooseServerAlias(keyType, issuers); 582 } 583 584 public java.security.cert.X509Certificate[] 585 getCertificateChain(String alias) { 586 return theX509KeyManager.getCertificateChain(alias); 587 } 588 589 public PrivateKey getPrivateKey(String alias) { 590 return theX509KeyManager.getPrivateKey(alias); 591 } 592 } 593 594 final class X509TrustManagerJavaxWrapper implements 595 javax.net.ssl.X509TrustManager { 596 597 private X509TrustManager theX509TrustManager; 598 599 X509TrustManagerJavaxWrapper(X509TrustManager obj) { 600 theX509TrustManager = obj; 601 } 602 603 public void checkClientTrusted( 604 java.security.cert.X509Certificate[] chain, String authType) 605 throws java.security.cert.CertificateException { 606 if (!theX509TrustManager.isClientTrusted(chain)) { 607 throw new java.security.cert.CertificateException( 608 "Untrusted Client Certificate Chain"); 609 } 610 } 611 612 public void checkServerTrusted( 613 java.security.cert.X509Certificate[] chain, String authType) 614 throws java.security.cert.CertificateException { 615 if (!theX509TrustManager.isServerTrusted(chain)) { 616 throw new java.security.cert.CertificateException( 617 "Untrusted Server Certificate Chain"); 618 } 619 } 620 621 public java.security.cert.X509Certificate[] getAcceptedIssuers() { 622 return theX509TrustManager.getAcceptedIssuers(); 623 } 624 } 625 626 final class X509KeyManagerComSunWrapper implements X509KeyManager { 627 628 private javax.net.ssl.X509KeyManager theX509KeyManager; 629 630 X509KeyManagerComSunWrapper(javax.net.ssl.X509KeyManager obj) { 631 theX509KeyManager = obj; 632 } 633 634 public String[] getClientAliases(String keyType, Principal[] issuers) { 635 return theX509KeyManager.getClientAliases(keyType, issuers); 636 } 637 638 public String chooseClientAlias(String keyType, Principal[] issuers) { 639 String [] keyTypes = new String [] { keyType }; 640 return theX509KeyManager.chooseClientAlias(keyTypes, issuers, null); 641 } 642 643 public String[] getServerAliases(String keyType, Principal[] issuers) { 644 return theX509KeyManager.getServerAliases(keyType, issuers); 645 } 646 647 public String chooseServerAlias(String keyType, Principal[] issuers) { 648 return theX509KeyManager.chooseServerAlias(keyType, issuers, null); 649 } 650 651 public java.security.cert.X509Certificate[] 652 getCertificateChain(String alias) { 653 return theX509KeyManager.getCertificateChain(alias); 654 } 655 656 public PrivateKey getPrivateKey(String alias) { 657 return theX509KeyManager.getPrivateKey(alias); 658 } 659 } 660 661 final class X509TrustManagerComSunWrapper implements X509TrustManager { 662 663 private javax.net.ssl.X509TrustManager theX509TrustManager; 664 665 X509TrustManagerComSunWrapper(javax.net.ssl.X509TrustManager obj) { 666 theX509TrustManager = obj; 667 } 668 669 public boolean isClientTrusted( 670 java.security.cert.X509Certificate[] chain) { 671 try { 672 theX509TrustManager.checkClientTrusted(chain, "UNKNOWN"); 673 return true; 674 } catch (java.security.cert.CertificateException e) { 675 return false; 676 } 677 } 678 679 public boolean isServerTrusted( 680 java.security.cert.X509Certificate[] chain) { 681 try { 682 theX509TrustManager.checkServerTrusted(chain, "UNKNOWN"); 683 return true; 684 } catch (java.security.cert.CertificateException e) { 685 return false; 686 } 687 } 688 689 public java.security.cert.X509Certificate[] getAcceptedIssuers() { 690 return theX509TrustManager.getAcceptedIssuers(); 691 } 692 }