1 /* 2 * Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 /* 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 */ SSLSecurity()56 private SSLSecurity() { 57 } 58 59 60 // ProviderList.getService() is not accessible now, implement our own loop getService(String type, String alg)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 */ getImpl1(String algName, String engineType, Service service)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 */ getImpl(String algName, String engineType, String provName)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 */ getImpl(String algName, String engineType, Provider prov)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 */ checkSuperclass(Class<?> subclass, Class<?> superclass)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 */ truncateArray(Object[] oldArray, Object[] newArray)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 final class SSLContextSpiWrapper extends SSLContextSpi { 280 281 private javax.net.ssl.SSLContext theSSLContext; 282 SSLContextSpiWrapper(String algName, Provider prov)283 SSLContextSpiWrapper(String algName, Provider prov) throws 284 NoSuchAlgorithmException { 285 theSSLContext = javax.net.ssl.SSLContext.getInstance(algName, prov); 286 } 287 engineInit(KeyManager[] kma, TrustManager[] tma, SecureRandom sr)288 protected void engineInit(KeyManager[] kma, TrustManager[] tma, 289 SecureRandom sr) throws KeyManagementException { 290 291 // Keep track of the actual number of array elements copied 292 int dst; 293 int src; 294 javax.net.ssl.KeyManager[] kmaw; 295 javax.net.ssl.TrustManager[] tmaw; 296 297 // Convert com.sun.net.ssl.kma to a javax.net.ssl.kma 298 // wrapper if need be. 299 if (kma != null) { 300 kmaw = new javax.net.ssl.KeyManager[kma.length]; 301 for (src = 0, dst = 0; src < kma.length; ) { 302 /* 303 * These key managers may implement both javax 304 * and com.sun interfaces, so if they do 305 * javax, there's no need to wrap them. 306 */ 307 if (!(kma[src] instanceof javax.net.ssl.KeyManager)) { 308 /* 309 * Do we know how to convert them? If not, oh well... 310 * We'll have to drop them on the floor in this 311 * case, cause we don't know how to handle them. 312 * This will be pretty rare, but put here for 313 * completeness. 314 */ 315 if (kma[src] instanceof X509KeyManager) { 316 kmaw[dst] = (javax.net.ssl.KeyManager) 317 new X509KeyManagerJavaxWrapper( 318 (X509KeyManager)kma[src]); 319 dst++; 320 } 321 } else { 322 // We can convert directly, since they implement. 323 kmaw[dst] = (javax.net.ssl.KeyManager)kma[src]; 324 dst++; 325 } 326 src++; 327 } 328 329 /* 330 * If dst != src, there were more items in the original array 331 * than in the new array. Compress the new elements to avoid 332 * any problems down the road. 333 */ 334 if (dst != src) { 335 kmaw = (javax.net.ssl.KeyManager []) 336 SSLSecurity.truncateArray(kmaw, 337 new javax.net.ssl.KeyManager [dst]); 338 } 339 } else { 340 kmaw = null; 341 } 342 343 // Now do the same thing with the TrustManagers. 344 if (tma != null) { 345 tmaw = new javax.net.ssl.TrustManager[tma.length]; 346 347 for (src = 0, dst = 0; src < tma.length; ) { 348 /* 349 * These key managers may implement both...see above... 350 */ 351 if (!(tma[src] instanceof javax.net.ssl.TrustManager)) { 352 // Do we know how to convert them? 353 if (tma[src] instanceof X509TrustManager) { 354 tmaw[dst] = (javax.net.ssl.TrustManager) 355 new X509TrustManagerJavaxWrapper( 356 (X509TrustManager)tma[src]); 357 dst++; 358 } 359 } else { 360 tmaw[dst] = (javax.net.ssl.TrustManager)tma[src]; 361 dst++; 362 } 363 src++; 364 } 365 366 if (dst != src) { 367 tmaw = (javax.net.ssl.TrustManager []) 368 SSLSecurity.truncateArray(tmaw, 369 new javax.net.ssl.TrustManager [dst]); 370 } 371 } else { 372 tmaw = null; 373 } 374 375 theSSLContext.init(kmaw, tmaw, sr); 376 } 377 378 protected javax.net.ssl.SSLSocketFactory engineGetSocketFactory()379 engineGetSocketFactory() { 380 return theSSLContext.getSocketFactory(); 381 } 382 383 protected javax.net.ssl.SSLServerSocketFactory engineGetServerSocketFactory()384 engineGetServerSocketFactory() { 385 return theSSLContext.getServerSocketFactory(); 386 } 387 388 } 389 390 final class TrustManagerFactorySpiWrapper extends TrustManagerFactorySpi { 391 392 private javax.net.ssl.TrustManagerFactory theTrustManagerFactory; 393 TrustManagerFactorySpiWrapper(String algName, Provider prov)394 TrustManagerFactorySpiWrapper(String algName, Provider prov) throws 395 NoSuchAlgorithmException { 396 theTrustManagerFactory = 397 javax.net.ssl.TrustManagerFactory.getInstance(algName, prov); 398 } 399 engineInit(KeyStore ks)400 protected void engineInit(KeyStore ks) throws KeyStoreException { 401 theTrustManagerFactory.init(ks); 402 } 403 engineGetTrustManagers()404 protected TrustManager[] engineGetTrustManagers() { 405 406 int dst; 407 int src; 408 409 javax.net.ssl.TrustManager[] tma = 410 theTrustManagerFactory.getTrustManagers(); 411 412 TrustManager[] tmaw = new TrustManager[tma.length]; 413 414 for (src = 0, dst = 0; src < tma.length; ) { 415 if (!(tma[src] instanceof com.sun.net.ssl.TrustManager)) { 416 // We only know how to wrap X509TrustManagers, as 417 // TrustManagers don't have any methods to wrap. 418 if (tma[src] instanceof javax.net.ssl.X509TrustManager) { 419 tmaw[dst] = (TrustManager) 420 new X509TrustManagerComSunWrapper( 421 (javax.net.ssl.X509TrustManager)tma[src]); 422 dst++; 423 } 424 } else { 425 tmaw[dst] = (TrustManager)tma[src]; 426 dst++; 427 } 428 src++; 429 } 430 431 if (dst != src) { 432 tmaw = (TrustManager []) 433 SSLSecurity.truncateArray(tmaw, new TrustManager [dst]); 434 } 435 436 return tmaw; 437 } 438 439 } 440 441 final class KeyManagerFactorySpiWrapper extends KeyManagerFactorySpi { 442 443 private javax.net.ssl.KeyManagerFactory theKeyManagerFactory; 444 KeyManagerFactorySpiWrapper(String algName, Provider prov)445 KeyManagerFactorySpiWrapper(String algName, Provider prov) throws 446 NoSuchAlgorithmException { 447 theKeyManagerFactory = 448 javax.net.ssl.KeyManagerFactory.getInstance(algName, prov); 449 } 450 engineInit(KeyStore ks, char[] password)451 protected void engineInit(KeyStore ks, char[] password) 452 throws KeyStoreException, NoSuchAlgorithmException, 453 UnrecoverableKeyException { 454 theKeyManagerFactory.init(ks, password); 455 } 456 engineGetKeyManagers()457 protected KeyManager[] engineGetKeyManagers() { 458 459 int dst; 460 int src; 461 462 javax.net.ssl.KeyManager[] kma = 463 theKeyManagerFactory.getKeyManagers(); 464 465 KeyManager[] kmaw = new KeyManager[kma.length]; 466 467 for (src = 0, dst = 0; src < kma.length; ) { 468 if (!(kma[src] instanceof com.sun.net.ssl.KeyManager)) { 469 // We only know how to wrap X509KeyManagers, as 470 // KeyManagers don't have any methods to wrap. 471 if (kma[src] instanceof javax.net.ssl.X509KeyManager) { 472 kmaw[dst] = (KeyManager) 473 new X509KeyManagerComSunWrapper( 474 (javax.net.ssl.X509KeyManager)kma[src]); 475 dst++; 476 } 477 } else { 478 kmaw[dst] = (KeyManager)kma[src]; 479 dst++; 480 } 481 src++; 482 } 483 484 if (dst != src) { 485 kmaw = (KeyManager []) 486 SSLSecurity.truncateArray(kmaw, new KeyManager [dst]); 487 } 488 489 return kmaw; 490 } 491 492 } 493 494 // ================================= 495 496 final class X509KeyManagerJavaxWrapper implements 497 javax.net.ssl.X509KeyManager { 498 499 private X509KeyManager theX509KeyManager; 500 X509KeyManagerJavaxWrapper(X509KeyManager obj)501 X509KeyManagerJavaxWrapper(X509KeyManager obj) { 502 theX509KeyManager = obj; 503 } 504 getClientAliases(String keyType, Principal[] issuers)505 public String[] getClientAliases(String keyType, Principal[] issuers) { 506 return theX509KeyManager.getClientAliases(keyType, issuers); 507 } 508 chooseClientAlias(String[] keyTypes, Principal[] issuers, Socket socket)509 public String chooseClientAlias(String[] keyTypes, Principal[] issuers, 510 Socket socket) { 511 String retval; 512 513 if (keyTypes == null) { 514 return null; 515 } 516 517 /* 518 * Scan the list, look for something we can pass back. 519 */ 520 for (int i = 0; i < keyTypes.length; i++) { 521 if ((retval = theX509KeyManager.chooseClientAlias(keyTypes[i], 522 issuers)) != null) 523 return retval; 524 } 525 return null; 526 527 } 528 529 /* 530 * JSSE 1.0.x was only socket based, but it's possible someone might 531 * want to install a really old provider. We should at least 532 * try to be nice. 533 */ chooseEngineClientAlias( String[] keyTypes, Principal[] issuers, javax.net.ssl.SSLEngine engine)534 public String chooseEngineClientAlias( 535 String[] keyTypes, Principal[] issuers, 536 javax.net.ssl.SSLEngine engine) { 537 String retval; 538 539 if (keyTypes == null) { 540 return null; 541 } 542 543 /* 544 * Scan the list, look for something we can pass back. 545 */ 546 for (int i = 0; i < keyTypes.length; i++) { 547 if ((retval = theX509KeyManager.chooseClientAlias(keyTypes[i], 548 issuers)) != null) 549 return retval; 550 } 551 552 return null; 553 } 554 getServerAliases(String keyType, Principal[] issuers)555 public String[] getServerAliases(String keyType, Principal[] issuers) { 556 return theX509KeyManager.getServerAliases(keyType, issuers); 557 } 558 chooseServerAlias(String keyType, Principal[] issuers, Socket socket)559 public String chooseServerAlias(String keyType, Principal[] issuers, 560 Socket socket) { 561 562 if (keyType == null) { 563 return null; 564 } 565 return theX509KeyManager.chooseServerAlias(keyType, issuers); 566 } 567 568 /* 569 * JSSE 1.0.x was only socket based, but it's possible someone might 570 * want to install a really old provider. We should at least 571 * try to be nice. 572 */ chooseEngineServerAlias( String keyType, Principal[] issuers, javax.net.ssl.SSLEngine engine)573 public String chooseEngineServerAlias( 574 String keyType, Principal[] issuers, 575 javax.net.ssl.SSLEngine engine) { 576 577 if (keyType == null) { 578 return null; 579 } 580 return theX509KeyManager.chooseServerAlias(keyType, issuers); 581 } 582 583 public java.security.cert.X509Certificate[] getCertificateChain(String alias)584 getCertificateChain(String alias) { 585 return theX509KeyManager.getCertificateChain(alias); 586 } 587 getPrivateKey(String alias)588 public PrivateKey getPrivateKey(String alias) { 589 return theX509KeyManager.getPrivateKey(alias); 590 } 591 } 592 593 final class X509TrustManagerJavaxWrapper implements 594 javax.net.ssl.X509TrustManager { 595 596 private X509TrustManager theX509TrustManager; 597 X509TrustManagerJavaxWrapper(X509TrustManager obj)598 X509TrustManagerJavaxWrapper(X509TrustManager obj) { 599 theX509TrustManager = obj; 600 } 601 checkClientTrusted( java.security.cert.X509Certificate[] chain, String authType)602 public void checkClientTrusted( 603 java.security.cert.X509Certificate[] chain, String authType) 604 throws java.security.cert.CertificateException { 605 if (!theX509TrustManager.isClientTrusted(chain)) { 606 throw new java.security.cert.CertificateException( 607 "Untrusted Client Certificate Chain"); 608 } 609 } 610 checkServerTrusted( java.security.cert.X509Certificate[] chain, String authType)611 public void checkServerTrusted( 612 java.security.cert.X509Certificate[] chain, String authType) 613 throws java.security.cert.CertificateException { 614 if (!theX509TrustManager.isServerTrusted(chain)) { 615 throw new java.security.cert.CertificateException( 616 "Untrusted Server Certificate Chain"); 617 } 618 } 619 getAcceptedIssuers()620 public java.security.cert.X509Certificate[] getAcceptedIssuers() { 621 return theX509TrustManager.getAcceptedIssuers(); 622 } 623 } 624 625 final class X509KeyManagerComSunWrapper implements X509KeyManager { 626 627 private javax.net.ssl.X509KeyManager theX509KeyManager; 628 X509KeyManagerComSunWrapper(javax.net.ssl.X509KeyManager obj)629 X509KeyManagerComSunWrapper(javax.net.ssl.X509KeyManager obj) { 630 theX509KeyManager = obj; 631 } 632 getClientAliases(String keyType, Principal[] issuers)633 public String[] getClientAliases(String keyType, Principal[] issuers) { 634 return theX509KeyManager.getClientAliases(keyType, issuers); 635 } 636 chooseClientAlias(String keyType, Principal[] issuers)637 public String chooseClientAlias(String keyType, Principal[] issuers) { 638 String [] keyTypes = new String [] { keyType }; 639 return theX509KeyManager.chooseClientAlias(keyTypes, issuers, null); 640 } 641 getServerAliases(String keyType, Principal[] issuers)642 public String[] getServerAliases(String keyType, Principal[] issuers) { 643 return theX509KeyManager.getServerAliases(keyType, issuers); 644 } 645 chooseServerAlias(String keyType, Principal[] issuers)646 public String chooseServerAlias(String keyType, Principal[] issuers) { 647 return theX509KeyManager.chooseServerAlias(keyType, issuers, null); 648 } 649 650 public java.security.cert.X509Certificate[] getCertificateChain(String alias)651 getCertificateChain(String alias) { 652 return theX509KeyManager.getCertificateChain(alias); 653 } 654 getPrivateKey(String alias)655 public PrivateKey getPrivateKey(String alias) { 656 return theX509KeyManager.getPrivateKey(alias); 657 } 658 } 659 660 final class X509TrustManagerComSunWrapper implements X509TrustManager { 661 662 private javax.net.ssl.X509TrustManager theX509TrustManager; 663 X509TrustManagerComSunWrapper(javax.net.ssl.X509TrustManager obj)664 X509TrustManagerComSunWrapper(javax.net.ssl.X509TrustManager obj) { 665 theX509TrustManager = obj; 666 } 667 isClientTrusted( java.security.cert.X509Certificate[] chain)668 public boolean isClientTrusted( 669 java.security.cert.X509Certificate[] chain) { 670 try { 671 theX509TrustManager.checkClientTrusted(chain, "UNKNOWN"); 672 return true; 673 } catch (java.security.cert.CertificateException e) { 674 return false; 675 } 676 } 677 isServerTrusted( java.security.cert.X509Certificate[] chain)678 public boolean isServerTrusted( 679 java.security.cert.X509Certificate[] chain) { 680 try { 681 theX509TrustManager.checkServerTrusted(chain, "UNKNOWN"); 682 return true; 683 } catch (java.security.cert.CertificateException e) { 684 return false; 685 } 686 } 687 getAcceptedIssuers()688 public java.security.cert.X509Certificate[] getAcceptedIssuers() { 689 return theX509TrustManager.getAcceptedIssuers(); 690 } 691 } 692