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 }