1 /*
   2  * Copyright (c) 2019, 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.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 package jdk.test.lib.security;
  25 
  26 import java.io.ByteArrayInputStream;
  27 import java.io.FileInputStream;
  28 import java.io.InputStream;
  29 import java.security.KeyStore;
  30 import java.security.PrivateKey;
  31 import java.security.cert.Certificate;
  32 import java.util.ArrayList;
  33 import java.util.Base64;
  34 import java.util.List;
  35 
  36 /*
  37  * Utilities for creating key store.
  38  */
  39 public class KeyStoreUtils {
  40 
  41     private static final String DEFAULT_TYPE = KeyStore.getDefaultType();
  42 
  43     /**
  44      * Create key store with a given input stream.
  45      *
  46      * @param type the key store type
  47      * @param input the input stream containing a key store
  48      * @param password the password used to check the integrity of the key store
  49      * @return the key store
  50      * @throws Exception on errors
  51      */
  52     public static KeyStore loadKeyStore(String type, InputStream input,
  53             String password) throws Exception {
  54         KeyStore keyStore = KeyStore.getInstance(type);
  55         try {
  56             keyStore.load(input,
  57                     password == null ? null : password.toCharArray());
  58             return keyStore;
  59         } finally {
  60             if (input != null) {
  61                 input.close();
  62             }
  63         }
  64     }
  65 
  66     /**
  67      * Create key store with a given input stream.
  68      *
  69      * @param input the input stream containing a key store
  70      * @param password the password used to check the integrity of the key store
  71      * @return the key store
  72      * @throws Exception on errors
  73      */
  74     public static KeyStore loadKeyStore(InputStream input, String password)
  75             throws Exception {
  76         return loadKeyStore(DEFAULT_TYPE, input, password);
  77     }
  78 
  79     /**
  80      * Create key store with given Base64-encoded string.
  81      *
  82      * @param keyStoreBase64 the Base64-encoded string containing a key store
  83      * @param password the password used to check the integrity of the key store
  84      * @return the key store
  85      * @throws Exception on errors
  86      */
  87     public static KeyStore loadKeyStoreBase64(String keyStoreBase64,
  88             String password) throws Exception {
  89         return loadKeyStore(DEFAULT_TYPE, new ByteArrayInputStream(
  90                 Base64.getDecoder().decode(keyStoreBase64)), password);
  91     }
  92 
  93     /**
  94      * Create key store with a given file.
  95      *
  96      * @param type the key store type
  97      * @param path the path to file containing a key store
  98      * @param password the password used to check the integrity of the key store
  99      * @return the key store
 100      * @throws Exception on errors
 101      */
 102     public static KeyStore loadKeyStore(String type, String path,
 103             String password) throws Exception {
 104         return loadKeyStore(type, new FileInputStream(path), password);
 105     }
 106 
 107     /**
 108      * Create key store with a given file.
 109      *
 110      * @param path the path to file containing a key store
 111      * @param password the password used to check the integrity of the key store
 112      * @return the key store
 113      * @throws Exception on errors
 114      */
 115     public static KeyStore loadKeyStore(String path, String password)
 116             throws Exception {
 117         return loadKeyStore(DEFAULT_TYPE, path, password);
 118     }
 119 
 120     /**
 121      * Create trust store with given certificates.
 122      *
 123      * @param type the key store type
 124      * @param certStrs the certificates added to the trust store
 125      * @return the trust store
 126      * @throws Exception on errors
 127      */
 128     public static KeyStore createTrustStore(String type, String[] certStrs)
 129             throws Exception {
 130         KeyStore trustStore = initKeyStore(type);
 131 
 132         for (int i = 0; i < certStrs.length; i++) {
 133             trustStore.setCertificateEntry("trust-" + i,
 134                     CertUtils.getCertFromString(certStrs[i]));
 135         }
 136 
 137         return trustStore;
 138     }
 139 
 140     /**
 141      * Create trust store with given certificates.
 142      *
 143      * @param certStrs the certificates added to the trust store
 144      * @return the trust store
 145      * @throws Exception on errors
 146      */
 147     public static KeyStore createTrustStore(String[] certStrs)
 148             throws Exception {
 149         return createTrustStore(DEFAULT_TYPE, certStrs);
 150     }
 151 
 152     /**
 153      * Create key store with given entries.
 154      *
 155      * @param type the key store type
 156      * @param entries the key entries added to the key store
 157      * @return the key store
 158      * @throws Exception on errors
 159      */
 160     public static KeyStore createKeyStore(String type, KeyEntry[] entries)
 161             throws Exception {
 162         KeyStore keyStore = initKeyStore(type);
 163 
 164         for (int i = 0; i < entries.length; i++) {
 165             KeyEntry entry = entries[i];
 166             PrivateKey key = CertUtils.getKeyFromString(
 167                     entry.keyAlgo, entry.keyStr);
 168             char[] password = entry.password == null
 169                     ? null
 170                     : entry.password.toCharArray();
 171             Certificate[] chain = new Certificate[entry.certStrs.length];
 172             for (int j = 0; j < chain.length; j++) {
 173                 chain[j] = CertUtils.getCertFromString(entry.certStrs[j]);
 174             }
 175 
 176             keyStore.setKeyEntry("cert-" + i, key, password, chain);
 177         }
 178 
 179         return keyStore;
 180     }
 181 
 182     /**
 183      * Create key store with given entries.
 184      *
 185      * @param entries the key entries added to the key store
 186      * @return the key store
 187      * @throws Exception on errors
 188      */
 189     public static KeyStore createKeyStore(KeyEntry[] entries)
 190             throws Exception {
 191         return createKeyStore(DEFAULT_TYPE, entries);
 192     }
 193 
 194     /**
 195      * Create key store with given private keys and associated certificate chains.
 196      * Note that here one chain contains only one certificate. If a chain needs
 197      * to contain multiple certificates, please use the following methods:
 198      * createKeyStore(String type, KeyEntry[] entries);
 199      * createKeyStore(KeyEntry[] entries)
 200      *
 201      * @param type the key store type
 202      * @param keyAlgos the key algorithm array
 203      * @param keyStrs the PEM-encoded PKCS8 key string array
 204      * @param passwords the key-associated password array
 205      * @param certStrs the key-associated certificate array
 206      * @return  the key store
 207      * @throws Exception on errors
 208      */
 209     public static KeyStore createKeyStore(String type, String[] keyAlgos,
 210             String[] keyStrs, String[] passwords, String[] certStrs)
 211             throws Exception {
 212         KeyEntry[] entries = new KeyEntry[keyStrs.length];
 213         for (int i = 0; i < entries.length; i++) {
 214             entries[i] = new KeyEntry(
 215                     keyAlgos[i],
 216                     keyStrs[i],
 217                     passwords == null ? null : passwords[i],
 218                     new String[] { certStrs[i] });
 219         }
 220         return createKeyStore(type, entries);
 221     }
 222 
 223     /**
 224      * Create key store with given private keys and associated certificate chains.
 225      * Note that here one chain contains only one certificate. If a chain needs
 226      * to contain multiple certificates, please use the following methods:
 227      * createKeyStore(String type, KeyEntry[] entries);
 228      * createKeyStore(KeyEntry[] entries)
 229      *
 230      * @param keyAlgos the key algorithm array
 231      * @param keyStrs the PEM-encoded PKCS8 key string array
 232      * @param passwords the key-associated password array
 233      * @param certStrs the key-associated certificate array
 234      * @return  the key store
 235      * @throws Exception on errors
 236      */
 237     public static KeyStore createKeyStore(String[] keyAlgos, String[] keyStrs,
 238             String[] passwords, String[] certStrs) throws Exception {
 239         return createKeyStore(DEFAULT_TYPE, keyAlgos, keyStrs, passwords,
 240                 certStrs);
 241     }
 242 
 243     private static KeyStore initKeyStore(String type) throws Exception {
 244         KeyStore keyStore = KeyStore.getInstance(type);
 245         keyStore.load(null, null);
 246         return keyStore;
 247     }
 248 
 249     /**
 250      * The default trust store that contains RSA, ECDSA, RSASSA-PSS and DSA
 251      * certificates.
 252      */
 253     public static KeyStore defaultTrustStore() throws Exception {
 254         return createTrustStore(
 255                 new String[] { CertUtils.RSA_CERT, CertUtils.ECDSA_CERT,
 256                         CertUtils.RSASSAPSS_CERT, CertUtils.DSA_CERT });
 257     }
 258 
 259     /**
 260      * The default key store that contains RSA, ECDSA, RSASSA-PSS and DSA
 261      * certificates.
 262      */
 263     public static KeyStore defaultKeyStore() throws Exception {
 264         List<KeyEntry> entries = new ArrayList<>();
 265         entries.add(new KeyEntry("RSA", CertUtils.RSA_KEY,
 266                 new String[] { CertUtils.RSA_CERT }));
 267         entries.add(new KeyEntry("EC", CertUtils.ECDSA_KEY,
 268                 new String[] { CertUtils.ECDSA_CERT }));
 269         entries.add(new KeyEntry("RSASSA-PSS", CertUtils.RSASSAPSS_KEY,
 270                 new String[] { CertUtils.RSASSAPSS_CERT }));
 271         entries.add(new KeyEntry("DSA", CertUtils.DSA_KEY,
 272                 new String[] { CertUtils.DSA_CERT }));
 273         return createKeyStore(entries.toArray(new KeyEntry[entries.size()]));
 274     }
 275 }