Newer
Older
/**
* @author ETSI / STF481 / Yann Garcia
* @version $URL$
* $Id$
*/
package org.etsi.certificates.io;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.etsi.certificates.Helpers;
import org.etsi.common.ByteHelper;
import de.fraunhofer.sit.c2x.CryptoLib;
public class CertificatesIO implements ICertificatesIO {
/**
* Relative path for to extract certificates
private static final String CERTS_PATH = "/certs_store";
* Extension file for private keys
private static final String KEYS_EXT = "bin";
* Relative path for to extract private keys
private static final String KEYS_PATH = "/priv_keys";
* Full path to access certificate files
private String _fullPathCerts;
* Full path to access key files
private String _fullPathKeys;
/**
* Memory cache for the certificates
*/
private Map<String, byte[]> _cachedCertificates;
private Map<String, byte[]> _cachedCertificatesDigest;
private Map<String, String> _cachedReverseCertificatesDigest;
/**
* Memory cache for the signing private keys
*/
private Map<String, byte[]> _cachedSigningPrivateKey;
/**
* Memory cache for the encrypt private keys
*/
private Map<String, byte[]> _cachedEncryptPrivateKey;
/**
* Default constructor
*/
public CertificatesIO() {
_cachedCertificates = new ConcurrentHashMap<String, byte[]>();
_cachedCertificatesDigest = new ConcurrentHashMap<String, byte[]>();
_cachedSigningPrivateKey = new ConcurrentHashMap<String, byte[]>();
_cachedEncryptPrivateKey = new ConcurrentHashMap<String, byte[]>();
_cachedReverseCertificatesDigest = new ConcurrentHashMap<String, String>();
} // End of Constructor
/**
* @desc Load in memory cache the certificates available in the specified directory
* @param rootDirectory Root directory to access to the certificates identified by the certificate ID
* @param configId A configuration identifier
* @return true on success, false otherwise
*/
@Override
public boolean loadCertificates(final String rootDirectory, final String configId) { // E.g. <rootDirectory path>, cfg01
// Initialise the memory caches
// Build full path
if ((rootDirectory == null) || (rootDirectory.length() == 0)) {
_fullPathCerts = System.getProperty("user.dir").replace("\\", "/");
_fullPathCerts = rootDirectory.replace("\\", "/");
if (!_fullPathCerts.endsWith("/")) {
_fullPathCerts += "/";
}
if ((configId != null) && (configId.length() != 0)) {
_fullPathCerts += configId.replace('.', '/');
_fullPathCerts = _fullPathCerts.toLowerCase();
_fullPathKeys = _fullPathCerts + KEYS_PATH;
_fullPathCerts += CERTS_PATH;
// Check the paths
File keysPath = new File(_fullPathKeys);
if (!keysPath.exists()) {
System.err.println("CertificatesIO.readCertificate: path '" + _fullPathKeys + "' does not found");
return false;
}
File certsPath = new File(_fullPathCerts);
if (!certsPath.exists()) {
System.err.println("CertificatesIO.readCertificate: path '" + _fullPathCerts + "' does not found");
return loadMemoryCache(keysPath); // Load certificates and keys and return
}
/**
* @desc Unload from memory cache the certificates available
* @return true on success, false otherwise
*/
@Override
public boolean unloadCertificates() {
_fullPathKeys = null;
_fullPathCerts = null;
_cachedCertificates.clear();
_cachedCertificatesDigest.clear();
_cachedSigningPrivateKey.clear();
_cachedEncryptPrivateKey.clear();
_cachedReverseCertificatesDigest.clear();
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
return true;
}
/**
* @desc Read the specified certificate
* @param certificateId the certificate identifier
* @param certificate the expected certificate
* @return true on success, false otherwise
*/
@Override
public boolean readCertificate(final String key, final ByteArrayOutputStream certificate) {
// Sanity check
if (!_cachedCertificates.containsKey(key)) {
System.err.println("CertificatesIO.readCertificate: key '" + key + "' not found");
return false;
}
try {
certificate.write(_cachedCertificates.get(key));
return true;
} catch (IOException e) {
e.printStackTrace();
}
return false;
}
@Override
public boolean readCertificateDigest(final String certificateId, final ByteArrayOutputStream digest) {
// Sanity check
String key = certificateId + ".DIGEST";
if (!_cachedCertificatesDigest.containsKey(key)) {
System.err.println("CertificatesIO.readCertificate: key '" + key + "' not found");
return false;
}
try {
digest.write(_cachedCertificatesDigest.get(key));
return true;
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return false;
}
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
/**
* @desc Read the private keys for the specified certificate
* @param keysId the keys identifier
* @param signingPrivateKey the signing private key
* @param encryptPrivateKey the encrypt private key
* @return true on success, false otherwise
*/
@Override
public boolean readPrivateKeys(final String key, final ByteArrayOutputStream signingPrivateKey, final ByteArrayOutputStream encryptPrivateKey) {
// Sanity check
if (!_cachedSigningPrivateKey.containsKey(key) || !_cachedEncryptPrivateKey.containsKey(key)) {
System.err.println("CertificatesIO.readPrivateKeys: key '" + key + "' not found");
return false;
}
try {
signingPrivateKey.write(_cachedSigningPrivateKey.get(key));
encryptPrivateKey.write(_cachedEncryptPrivateKey.get(key));
return true;
} catch (IOException e) {
e.printStackTrace();
}
return false;
}
/**
* @desc Load certificates based on existing keys file, excluding xxx_at.bin files
* @param p_keysPath path for private key files
* @param p_certsPath Path for certificate files
* @return true on success, false otherwise
*/
private boolean loadMemoryCache(final File p_keysPath) { // E.g. <path>/keys, <path>/certs
// Retrieve the list of the files in the p_keysPath
List<File> files = Helpers.getInstance().getFileListing(p_keysPath, KEYS_EXT, new String[] { "_at", "_aa", /*for debug: */".svn", "._.DS_Store", ".DS_Store"});
// Create the memory cache
for (File file : files) {
addItem(file);
} // End of 'for' statement
return true;
} catch (IOException e) {
e.printStackTrace();
}
return false;
}
private void addItem(final File p_keysFile) throws FileNotFoundException, IOException {
// Sanity checks
if (p_keysFile.length() != 32) { // FIXME Should have both encrypt and singing keys
return;
}
// Load the keys file name
String filename = p_keysFile.getName().toLowerCase();
String keysFileName = filename.substring(0, filename.indexOf("_ca"));
File caFile = new File(_fullPathCerts + "/" + keysFileName + "_ca.crt");
File aaFile = new File(_fullPathCerts + "/" + keysFileName + "_aa.crt");
File atFile = new File(_fullPathCerts + "/" + keysFileName + "_at.crt");
String key = keysFileName.toUpperCase();
if (!_cachedCertificates.containsKey(key)) {
// Open CA keys file
FileInputStream fsKeys = new FileInputStream(p_keysFile.getCanonicalPath());
// Load keys
byte bytes[] = new byte[(int) p_keysFile.length()];
fsKeys.read(bytes);
_cachedSigningPrivateKey.put(key + ".CA_PRIVATE_KEYS", ByteHelper.extract(bytes, 0, 32));
// FIXME Should have both encrypt and singing keys _cachedEncryptPrivateKey.put(key + ".PRIVATE_KEYS", ByteHelper.extract(bytes, 32, 32));
_cachedEncryptPrivateKey.put(key + ".CA_PRIVATE_KEYS", ByteHelper.extract(bytes, 0, 32));
// Close file stream
fsKeys.close();
// Open CA keys file
fsKeys = new FileInputStream(p_keysFile.getCanonicalPath().toLowerCase().replaceAll("_ca", "_at"));
// Load keys
bytes = new byte[(int) p_keysFile.length()];
fsKeys.read(bytes);
_cachedSigningPrivateKey.put(key + ".AT_PRIVATE_KEYS", ByteHelper.extract(bytes, 0, 32));
// FIXME Should have both encrypt and singing keys _cachedEncryptPrivateKey.put(key + ".PRIVATE_KEYS", ByteHelper.extract(bytes, 32, 32));
_cachedEncryptPrivateKey.put(key + ".AT_PRIVATE_KEYS", ByteHelper.extract(bytes, 0, 32));
// Close file stream
fsKeys.close();
// Open CA certificate
FileInputStream fsCaFile = new FileInputStream(caFile.getCanonicalPath());
bytes = new byte[(int) caFile.length()];
fsCaFile.read(bytes);
_cachedCertificates.put(key + ".CA_CERT", bytes);
// Close file streams
fsCaFile.close();
// Open AA certificate
FileInputStream fsAaFile = new FileInputStream(aaFile.getCanonicalPath());
bytes = new byte[(int) aaFile.length()];
fsAaFile.read(bytes);
_cachedCertificates.put(key + ".AA_CERT", bytes);
// Close file streams
fsAaFile.close();
// Open AT certificate
FileInputStream fsAtFile = new FileInputStream(atFile.getCanonicalPath());
bytes = new byte[(int) atFile.length()];
fsAtFile.read(bytes);
_cachedCertificates.put(key + ".AT_CERT", bytes);
byte[] digest = calculateDigestFromCertificate(bytes);
_cachedCertificatesDigest.put(key + ".AT_CERT.DIGEST", digest);
_cachedReverseCertificatesDigest.put(ByteHelper.byteArrayToString(digest), key + ".AT_CERT.DIGEST");
// Close file streams
fsAtFile.close();
} // else, ignore it
}
@Override
public String getKeyIdFromHashedId8(byte[] p_hashedId8ToBeUsed) {
String key = ByteHelper.byteArrayToString(p_hashedId8ToBeUsed);
if (!_cachedReverseCertificatesDigest.containsKey(key)) {
return null;
}
return _cachedReverseCertificatesDigest.get(key).substring(0, key.length() - 7/*.DIGEST*/);
}
private byte[] calculateDigestFromCertificate(final byte[] p_toBeHashedData) {
byte[] hash = CryptoLib.hashWithSha256(p_toBeHashedData);
return ByteHelper.extract(hash, hash.length - 8, 8);
}
} // End of class CertificatesIO