jdk/src/java.base/share/classes/sun/security/util/KeyStoreDelegator.java
changeset 28243 47080f9ae750
child 32661 42a0bafb4767
equal deleted inserted replaced
28242:0cbef7c46996 28243:47080f9ae750
       
     1 /*
       
     2  * Copyright (c) 2014, 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.util;
       
    27 
       
    28 import java.io.*;
       
    29 import java.security.*;
       
    30 import java.security.cert.Certificate;
       
    31 import java.security.cert.CertificateFactory;
       
    32 import java.security.cert.CertificateException;
       
    33 import java.util.*;
       
    34 
       
    35 import sun.security.util.Debug;
       
    36 
       
    37 /**
       
    38  * This class delegates to a primary or secondary keystore implementation.
       
    39  *
       
    40  * @since 1.9
       
    41  */
       
    42 
       
    43 public class KeyStoreDelegator extends KeyStoreSpi {
       
    44 
       
    45     private static final String KEYSTORE_TYPE_COMPAT = "keystore.type.compat";
       
    46     private static final Debug debug = Debug.getInstance("keystore");
       
    47 
       
    48     private String primaryType;   // the primary keystore's type
       
    49     private String secondaryType; // the secondary keystore's type
       
    50     private Class<? extends KeyStoreSpi> primaryKeyStore;
       
    51                                   // the primary keystore's class
       
    52     private Class<? extends KeyStoreSpi> secondaryKeyStore;
       
    53                                   // the secondary keystore's class
       
    54     private String type; // the delegate's type
       
    55     private KeyStoreSpi keystore; // the delegate
       
    56     private boolean compatModeEnabled = true;
       
    57 
       
    58     public KeyStoreDelegator(
       
    59         String primaryType,
       
    60         Class<? extends KeyStoreSpi> primaryKeyStore,
       
    61         String secondaryType,
       
    62         Class<? extends KeyStoreSpi> secondaryKeyStore) {
       
    63 
       
    64         // Check whether compatibility mode has been disabled
       
    65         compatModeEnabled = "true".equalsIgnoreCase(
       
    66             AccessController.doPrivileged((PrivilegedAction<String>) () ->
       
    67                 Security.getProperty(KEYSTORE_TYPE_COMPAT)));
       
    68 
       
    69         if (compatModeEnabled) {
       
    70             this.primaryType = primaryType;
       
    71             this.secondaryType = secondaryType;
       
    72             this.primaryKeyStore = primaryKeyStore;
       
    73             this.secondaryKeyStore = secondaryKeyStore;
       
    74         } else {
       
    75             this.primaryType = primaryType;
       
    76             this.secondaryType = null;
       
    77             this.primaryKeyStore = primaryKeyStore;
       
    78             this.secondaryKeyStore = null;
       
    79 
       
    80             if (debug != null) {
       
    81                 debug.println("WARNING: compatibility mode disabled for " +
       
    82                     primaryType + " and " + secondaryType + " keystore types");
       
    83             }
       
    84         }
       
    85     }
       
    86 
       
    87     @Override
       
    88     public Key engineGetKey(String alias, char[] password)
       
    89         throws NoSuchAlgorithmException, UnrecoverableKeyException {
       
    90         return keystore.engineGetKey(alias, password);
       
    91     }
       
    92 
       
    93     @Override
       
    94     public Certificate[] engineGetCertificateChain(String alias) {
       
    95         return keystore.engineGetCertificateChain(alias);
       
    96     }
       
    97 
       
    98     @Override
       
    99     public Certificate engineGetCertificate(String alias) {
       
   100         return keystore.engineGetCertificate(alias);
       
   101     }
       
   102 
       
   103     @Override
       
   104     public Date engineGetCreationDate(String alias) {
       
   105         return keystore.engineGetCreationDate(alias);
       
   106     }
       
   107 
       
   108     @Override
       
   109     public void engineSetKeyEntry(String alias, Key key, char[] password,
       
   110         Certificate[] chain) throws KeyStoreException {
       
   111         keystore.engineSetKeyEntry(alias, key, password, chain);
       
   112     }
       
   113 
       
   114     @Override
       
   115     public void engineSetKeyEntry(String alias, byte[] key, Certificate[] chain)
       
   116         throws KeyStoreException {
       
   117         keystore.engineSetKeyEntry(alias, key, chain);
       
   118     }
       
   119 
       
   120     @Override
       
   121     public void engineSetCertificateEntry(String alias, Certificate cert)
       
   122         throws KeyStoreException {
       
   123         keystore.engineSetCertificateEntry(alias, cert);
       
   124     }
       
   125 
       
   126     @Override
       
   127     public void engineDeleteEntry(String alias) throws KeyStoreException {
       
   128         keystore.engineDeleteEntry(alias);
       
   129     }
       
   130 
       
   131     @Override
       
   132     public Enumeration<String> engineAliases() {
       
   133         return keystore.engineAliases();
       
   134     }
       
   135 
       
   136     @Override
       
   137     public boolean engineContainsAlias(String alias) {
       
   138         return keystore.engineContainsAlias(alias);
       
   139     }
       
   140 
       
   141     @Override
       
   142     public int engineSize() {
       
   143         return keystore.engineSize();
       
   144     }
       
   145 
       
   146     @Override
       
   147     public boolean engineIsKeyEntry(String alias) {
       
   148         return keystore.engineIsKeyEntry(alias);
       
   149     }
       
   150 
       
   151     @Override
       
   152     public boolean engineIsCertificateEntry(String alias) {
       
   153         return keystore.engineIsCertificateEntry(alias);
       
   154     }
       
   155 
       
   156     @Override
       
   157     public String engineGetCertificateAlias(Certificate cert) {
       
   158         return keystore.engineGetCertificateAlias(cert);
       
   159     }
       
   160 
       
   161     @Override
       
   162     public KeyStore.Entry engineGetEntry(String alias,
       
   163         KeyStore.ProtectionParameter protParam)
       
   164             throws KeyStoreException, NoSuchAlgorithmException,
       
   165                 UnrecoverableEntryException {
       
   166         return keystore.engineGetEntry(alias, protParam);
       
   167     }
       
   168 
       
   169     @Override
       
   170     public void engineSetEntry(String alias, KeyStore.Entry entry,
       
   171         KeyStore.ProtectionParameter protParam)
       
   172             throws KeyStoreException {
       
   173         keystore.engineSetEntry(alias, entry, protParam);
       
   174     }
       
   175 
       
   176     @Override
       
   177     public boolean engineEntryInstanceOf(String alias,
       
   178         Class<? extends KeyStore.Entry> entryClass) {
       
   179         return keystore.engineEntryInstanceOf(alias, entryClass);
       
   180     }
       
   181 
       
   182     @Override
       
   183     public void engineStore(OutputStream stream, char[] password)
       
   184         throws IOException, NoSuchAlgorithmException, CertificateException {
       
   185 
       
   186         if (debug != null) {
       
   187             debug.println("Storing keystore in " + type + " format");
       
   188         }
       
   189         keystore.engineStore(stream, password);
       
   190     }
       
   191 
       
   192     @Override
       
   193     public void engineLoad(InputStream stream, char[] password)
       
   194         throws IOException, NoSuchAlgorithmException, CertificateException {
       
   195 
       
   196         // A new keystore is always created in the primary keystore format
       
   197         if (stream == null) {
       
   198             try {
       
   199                 keystore = primaryKeyStore.newInstance();
       
   200 
       
   201             } catch (InstantiationException | IllegalAccessException e) {
       
   202                 // can safely ignore
       
   203             }
       
   204             type = primaryType;
       
   205 
       
   206             if (debug != null) {
       
   207                 debug.println("Creating a new keystore in " + type + " format");
       
   208             }
       
   209             keystore.engineLoad(stream, password);
       
   210 
       
   211         } else {
       
   212             // First try the primary keystore then try the secondary keystore
       
   213             try (InputStream bufferedStream = new BufferedInputStream(stream)) {
       
   214                 bufferedStream.mark(Integer.MAX_VALUE);
       
   215 
       
   216                 try {
       
   217                     keystore = primaryKeyStore.newInstance();
       
   218                     type = primaryType;
       
   219                     keystore.engineLoad(bufferedStream, password);
       
   220 
       
   221                 } catch (Exception e) {
       
   222 
       
   223                     // incorrect password
       
   224                     if (e instanceof IOException &&
       
   225                         e.getCause() instanceof UnrecoverableKeyException) {
       
   226                         throw (IOException)e;
       
   227                     }
       
   228 
       
   229                     try {
       
   230                         // Ignore secondary keystore when no compatibility mode
       
   231                         if (!compatModeEnabled) {
       
   232                             throw e;
       
   233                         }
       
   234 
       
   235                         keystore = secondaryKeyStore.newInstance();
       
   236                         type = secondaryType;
       
   237                         bufferedStream.reset();
       
   238                         keystore.engineLoad(bufferedStream, password);
       
   239 
       
   240                         if (debug != null) {
       
   241                             debug.println("WARNING: switching from " +
       
   242                               primaryType + " to " + secondaryType +
       
   243                               " keystore file format has altered the " +
       
   244                               "keystore security level");
       
   245                         }
       
   246 
       
   247                     } catch (InstantiationException |
       
   248                         IllegalAccessException e2) {
       
   249                         // can safely ignore
       
   250 
       
   251                     } catch (IOException |
       
   252                         NoSuchAlgorithmException |
       
   253                         CertificateException e3) {
       
   254 
       
   255                         // incorrect password
       
   256                         if (e3 instanceof IOException &&
       
   257                             e3.getCause() instanceof
       
   258                                 UnrecoverableKeyException) {
       
   259                             throw (IOException)e3;
       
   260                         }
       
   261                         // rethrow the outer exception
       
   262                         if (e instanceof IOException) {
       
   263                             throw (IOException)e;
       
   264                         } else if (e instanceof CertificateException) {
       
   265                             throw (CertificateException)e;
       
   266                         } else if (e instanceof NoSuchAlgorithmException) {
       
   267                             throw (NoSuchAlgorithmException)e;
       
   268                         }
       
   269                     }
       
   270                 }
       
   271             }
       
   272 
       
   273             if (debug != null) {
       
   274                 debug.println("Loaded a keystore in " + type + " format");
       
   275             }
       
   276         }
       
   277     }
       
   278 
       
   279     /**
       
   280      * Probe the first few bytes of the keystore data stream for a valid
       
   281      * keystore encoding. Only the primary keystore implementation is probed.
       
   282      */
       
   283     @Override
       
   284     public boolean engineProbe(InputStream stream) throws IOException {
       
   285 
       
   286         boolean result = false;
       
   287 
       
   288         try {
       
   289             keystore = primaryKeyStore.newInstance();
       
   290             type = primaryType;
       
   291             result = keystore.engineProbe(stream);
       
   292 
       
   293         } catch (Exception e) {
       
   294             throw new IOException(e);
       
   295 
       
   296         } finally {
       
   297             // reset
       
   298             if (result == false) {
       
   299                 type = null;
       
   300                 keystore = null;
       
   301             }
       
   302         }
       
   303 
       
   304         return result;
       
   305     }
       
   306 }