001/** 002 * Copyright 2017 Emmanuel Bourg 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package net.jsign; 018 019import java.io.File; 020import java.io.FileInputStream; 021import java.io.IOException; 022import java.nio.ByteBuffer; 023import java.security.KeyStore; 024import java.security.KeyStoreException; 025import java.security.Provider; 026 027/** 028 * Helper class for loading KeyStores (JKS, JCEKS, PKCS#12 or PKCS#11). 029 * 030 * @author Emmanuel Bourg 031 * @since 2.0 032 */ 033public class KeyStoreUtils { 034 035 private KeyStoreUtils() { 036 } 037 038 /** 039 * Load the keystore from the specified file. 040 * 041 * @param keystore the file containing the keystore 042 * @param storetype the type of the keystore (either JKS, JCEKS, PKCS12 or PKCS11). 043 * If null the type is inferred from the extension of the file (.p12 or .pfx for PKCS#12 keystores) 044 * @param storepass The password of the keystore 045 * @param provider The security provider used to load the keystore (must be specified for PKCS#11 keystores) 046 * @return the keystore loaded 047 * @throws KeyStoreException thrown if the keystore cannot be loaded 048 */ 049 public static KeyStore load(File keystore, String storetype, String storepass, Provider provider) throws KeyStoreException { 050 return load(keystore != null ? keystore.getPath() : null, storetype, storepass, provider); 051 } 052 053 /** 054 * Load the keystore from the specified path. 055 * 056 * @param keystore the path to the keystore 057 * @param storetype the type of the keystore (either JKS, JCEKS, PKCS12 or PKCS11). 058 * If null the type is inferred from the extension of the file (.p12 or .pfx for PKCS#12 keystores) 059 * @param storepass The password of the keystore 060 * @param provider The security provider used to load the keystore (must be specified for PKCS#11 keystores) 061 * @return the keystore loaded 062 * @throws KeyStoreException thrown if the keystore cannot be loaded 063 */ 064 public static KeyStore load(String keystore, String storetype, String storepass, Provider provider) throws KeyStoreException { 065 if (keystore != null && storetype == null) { 066 storetype = getType(keystore); 067 } 068 069 KeyStore ks; 070 try { 071 if (provider != null) { 072 ks = KeyStore.getInstance(storetype, provider); 073 } else { 074 ks = KeyStore.getInstance(storetype); 075 } 076 } catch (KeyStoreException e) { 077 throw new KeyStoreException("keystore type '" + storetype + "' is not supported", e); 078 } 079 080 boolean filebased = "JKS".equals(storetype) || "JCEKS".equals(storetype) || "PKCS12".equals(storetype); 081 if (filebased && (keystore == null || !new File(keystore).exists())) { 082 throw new KeyStoreException("The keystore " + keystore + " couldn't be found"); 083 } 084 085 try { 086 try (FileInputStream in = !filebased ? null : new FileInputStream(keystore)) { 087 ks.load(in, storepass != null ? storepass.toCharArray() : null); 088 } 089 } catch (Exception e) { 090 throw new KeyStoreException("Unable to load the keystore " + keystore, e); 091 } 092 093 return ks; 094 } 095 096 /** 097 * Guess the type of the keystore from the header or the extension of the file. 098 * 099 * @param keystore the path to the keystore 100 */ 101 static String getType(String keystore) throws KeyStoreException { 102 if (keystore == null) { 103 return null; 104 } 105 106 // guess the type of the keystore from the header of the file 107 File file = new File(keystore); 108 if (file.exists()) { 109 try (FileInputStream in = new FileInputStream(file)) { 110 byte[] header = new byte[4]; 111 in.read(header); 112 ByteBuffer buffer = ByteBuffer.wrap(header); 113 if (buffer.get(0) == 0x30) { 114 return "PKCS12"; 115 } else if ((buffer.getInt(0) & 0xFFFFFFFFL) == 0xCECECECEL) { 116 return "JCEKS"; 117 } else if ((buffer.getInt(0) & 0xFFFFFFFFL) == 0xFEEDFEEDL) { 118 return "JKS"; 119 } 120 } catch (IOException e) { 121 throw new KeyStoreException("Unable to load the keystore " + keystore, e); 122 } 123 } 124 125 // guess the type of the keystore from the extension of the file 126 String filename = keystore.toLowerCase(); 127 if (filename.endsWith(".p12") || filename.endsWith(".pfx")) { 128 return "PKCS12"; 129 } else if (filename.endsWith(".jceks")) { 130 return "JCEKS"; 131 } else if (filename.endsWith(".jks")) { 132 return "JKS"; 133 } else { 134 return null; 135 } 136 } 137}