Rev

Rev 2230 | Details | Compare with Previous | Last modification | View Log | SVN | Bug Tracker

Rev Author Line No. Line
1689 garciay 1
/**
2
 * @author      ETSI / STF481 / Yann Garcia
3
 * @version     $URL: file:///D:/RepositoriesNew/ITS/trunk/javasrc/certificatesio/org/etsi/certificates/io/CertificatesIO.java $
4
 *              $Id: CertificatesIO.java 2655 2017-01-26 10:46:08Z filatov $
5
 */
6
package org.etsi.certificates.io;
7
 
8
import java.io.ByteArrayOutputStream;
9
import java.io.File;
10
import java.io.FileInputStream;
11
import java.io.FileNotFoundException;
12
import java.io.IOException;
2230 mullers 13
import java.util.Arrays;
1689 garciay 14
import java.util.List;
15
import java.util.Map;
16
import java.util.concurrent.ConcurrentHashMap;
17
 
2655 filatov 18
import org.etsi.adapter.TERFactory;
1689 garciay 19
import org.etsi.certificates.Helpers;
1705 garciay 20
import org.etsi.common.ByteHelper;
1689 garciay 21
 
1917 berge 22
import de.fraunhofer.sit.c2x.CryptoLib;
23
 
1689 garciay 24
public class CertificatesIO implements ICertificatesIO {
25
 
26
    /**
2230 mullers 27
     *  Extension file for certificate
1689 garciay 28
     */
2230 mullers 29
    private static final String CERT_EXT = "crt";
1689 garciay 30
 
31
    /**
2230 mullers 32
     *  Extension file for digests
1689 garciay 33
     */
2230 mullers 34
    private static final String DIGESTS_EXT = "dgs";
1689 garciay 35
 
36
    /**
2230 mullers 37
     *  Excluded files while building the lists of certificates/private keys
1689 garciay 38
     */
2230 mullers 39
    private static final String[] EXCLUDED_PATTERNS = new String[] { /*for debug: */".svn", "._.DS_Store", ".DS_Store"};
1689 garciay 40
 
41
    /**
1917 berge 42
     * Full path to access certificate files
1689 garciay 43
     */
1917 berge 44
    private String _fullPathCerts;
1689 garciay 45
 
46
    /**
1917 berge 47
     * Memory cache for the certificates
1689 garciay 48
     */
1917 berge 49
    private Map<String, byte[]> _cachedCertificates;
1689 garciay 50
 
1917 berge 51
    private Map<String, byte[]> _cachedCertificatesDigest;
1689 garciay 52
 
1917 berge 53
    private Map<String, String> _cachedReverseCertificatesDigest;
1689 garciay 54
 
55
    /**
56
     * Memory cache for the signing private keys
57
     */
58
    private Map<String, byte[]> _cachedSigningPrivateKey;
59
 
60
    /**
61
     * Memory cache for the encrypt private keys
62
     */
63
    private Map<String, byte[]> _cachedEncryptPrivateKey;
64
 
65
    /**
2230 mullers 66
     * Set to true if loadCertificates was already called
67
     */
68
    private boolean _areCertificatesLoaded = false;
69
 
70
    /**
1689 garciay 71
     * Default constructor
72
     */
73
    public CertificatesIO() {
74
        _cachedCertificates = new ConcurrentHashMap<String, byte[]>();
1917 berge 75
        _cachedCertificatesDigest = new ConcurrentHashMap<String, byte[]>();
1689 garciay 76
        _cachedSigningPrivateKey = new ConcurrentHashMap<String, byte[]>();
77
        _cachedEncryptPrivateKey = new ConcurrentHashMap<String, byte[]>();
1917 berge 78
        _cachedReverseCertificatesDigest = new ConcurrentHashMap<String, String>();
1689 garciay 79
    } // End of Constructor
80
 
81
    /**
82
     * @desc    Load in memory cache the certificates available in the specified directory
83
     * @param   rootDirectory Root directory to access to the certificates identified by the certificate ID
84
     * @param   configId      A configuration identifier
85
     * @return  true on success, false otherwise
86
     */
87
    @Override
2230 mullers 88
    public boolean loadCertificates(final String p_rootDirectory, final String p_configId) { // E.g. <rootDirectory path>, cfg01
2655 filatov 89
        TERFactory.getInstance().logDebug(">>> CertificatesIO.loadCertificates: '" + p_rootDirectory + "', '" + p_configId + "' - " + _areCertificatesLoaded);
1689 garciay 90
 
2230 mullers 91
        // Sanity check
92
        if (_areCertificatesLoaded) {
93
            return true;
94
        }
95
 
1689 garciay 96
        // Build full path
2230 mullers 97
        if ((p_rootDirectory == null) || (p_rootDirectory.length() == 0)) {
1917 berge 98
            _fullPathCerts = System.getProperty("user.dir").replace("\\", "/");
1689 garciay 99
        } else {
2230 mullers 100
            _fullPathCerts = p_rootDirectory.replace("\\", "/");
1689 garciay 101
        }
1917 berge 102
        if (!_fullPathCerts.endsWith("/")) {
103
            _fullPathCerts += "/";
1689 garciay 104
        }
2230 mullers 105
 
1917 berge 106
        File certsPath = new File(_fullPathCerts);
107
        if (!certsPath.exists()) {
2655 filatov 108
            TERFactory.getInstance().logError("CertificatesIO.loadCertificates: path '" + _fullPathCerts + "' does not found");
1917 berge 109
            return false;
110
        }
1689 garciay 111
 
2230 mullers 112
        _areCertificatesLoaded = loadMemoryCache(certsPath); // Load certificates and keys and return
113
 
114
        if ((p_configId != null) && (p_configId.length() != 0)) {
115
            String path = new String(_fullPathCerts + "/" + p_configId);
116
            certsPath = new File(path);
117
            if (!certsPath.exists()) {
2655 filatov 118
                TERFactory.getInstance().logError("CertificatesIO.loadCertificates: path '" + path + "' does not found");
2230 mullers 119
                return false;
120
            }
121
            loadMemoryCache(certsPath); // Load certificates and keys and return
122
        }
123
 
124
        return _areCertificatesLoaded;
1689 garciay 125
    }
126
 
127
    /**
128
     * @desc    Unload from memory cache the certificates available
129
     * @return  true on success, false otherwise
130
     */
131
    @Override
132
    public boolean unloadCertificates() {
2230 mullers 133
        _areCertificatesLoaded = false;
1917 berge 134
        _fullPathCerts = null;
135
        _cachedCertificates.clear();
136
        _cachedCertificatesDigest.clear();
1689 garciay 137
        _cachedSigningPrivateKey.clear();
138
        _cachedEncryptPrivateKey.clear();
1917 berge 139
        _cachedReverseCertificatesDigest.clear();
1689 garciay 140
 
141
        return true;
142
    }
143
 
144
    /**
145
     * @desc    Read the specified certificate
146
     * @param   certificateId the certificate identifier
147
     * @param   certificate   the expected certificate
148
     * @return  true on success, false otherwise
149
     */
150
    @Override
151
    public boolean readCertificate(final String key, final ByteArrayOutputStream certificate) {
2655 filatov 152
//        TERFactory.getInstance().logDebug(">>> CertificatesIO.readCertificate: " + key);
2230 mullers 153
 
154
        String certKey;
155
        if (_cachedReverseCertificatesDigest.containsKey(key)) {
156
            certKey = _cachedReverseCertificatesDigest.get(key);
157
        }else{
158
            certKey = key;
1689 garciay 159
        }
160
 
2230 mullers 161
        if (_cachedCertificates.containsKey(certKey)) {
162
            try {
163
                certificate.write(_cachedCertificates.get(certKey));
164
                return true;
165
            } catch (IOException e) {
166
                e.printStackTrace();
167
            }
168
        }else{
2655 filatov 169
            TERFactory.getInstance().logError("CertificatesIO.readCertificate: key '" + key + "' not found");
1689 garciay 170
        }
171
        return false;
172
    }
173
 
1917 berge 174
    @Override
175
    public boolean readCertificateDigest(final String certificateId, final ByteArrayOutputStream digest) {
2655 filatov 176
//        TERFactory.getInstance().logDebug(">>> CertificatesIO.readCertificateDigest: " + certificateId);
2230 mullers 177
 
1917 berge 178
        // Sanity check
2230 mullers 179
        if (!_cachedCertificatesDigest.containsKey(certificateId)) {
2655 filatov 180
            TERFactory.getInstance().logError("CertificatesIO.readCertificateDigest: key '" + certificateId + "' not found");
1917 berge 181
            return false;
182
        }
183
 
184
        try {
2230 mullers 185
            digest.write(_cachedCertificatesDigest.get(certificateId));
186
            return true;
1917 berge 187
 
188
        } catch (IOException e) {
189
            e.printStackTrace();
190
        }
191
        return false;
192
    }
193
 
1689 garciay 194
    /**
2230 mullers 195
     * @desc    Read the signing private key for the specified certificate
196
     * @param   keysId  the keys identifier
197
     * @param   key     the signing private key
1689 garciay 198
     * @return  true on success, false otherwise
199
     */
200
    @Override
2230 mullers 201
    public boolean readSigningKey(final String keyName, final ByteArrayOutputStream key) {
2655 filatov 202
//        TERFactory.getInstance().logDebug(">>> CertificatesIO.readSigningKey: " + keyName);
1689 garciay 203
 
204
        try {
2230 mullers 205
            String certKey;
206
            if (_cachedReverseCertificatesDigest.containsKey(keyName)) {
207
                certKey = _cachedReverseCertificatesDigest.get(keyName);
208
            }else{
209
                certKey = keyName;
210
            }
211
            if (_cachedSigningPrivateKey.containsKey(certKey)) {
212
                key.write(_cachedSigningPrivateKey.get(certKey));
213
                return true;
214
            }
1689 garciay 215
        } catch (IOException e) {
216
            e.printStackTrace();
217
        }
218
        return false;
219
    }
220
 
1917 berge 221
    /**
2230 mullers 222
     * @desc    Read the encrypting private key for the specified certificate
223
     * @param   keysId  the keys identifier
224
     * @param   key     the signing private key
225
     * @return  true on success, false otherwise
226
     */
227
    @Override
228
    public boolean readEncryptingKey(final String keyName, final ByteArrayOutputStream key) {
229
        String certKey;
230
        try {
231
            if (_cachedReverseCertificatesDigest.containsKey(keyName)) {
232
                certKey = _cachedReverseCertificatesDigest.get(keyName);
233
            }else{
234
                certKey = keyName;
235
            }
236
            if (_cachedEncryptPrivateKey.containsKey(certKey)) {
237
                key.write(_cachedEncryptPrivateKey.get(certKey));
238
                return true;
239
            }
240
        } catch (IOException e) {
241
            e.printStackTrace();
242
        }
243
        return false;
244
    }
245
 
246
    /**
1917 berge 247
     * @desc Load certificates based on existing keys file, excluding xxx_at.bin files
248
     * @param p_keysPath    path for private key files
249
     * @param p_certsPath   Path for certificate files
250
     * @return true on success, false otherwise
251
     */
252
    private boolean loadMemoryCache(final File p_keysPath) { // E.g. <path>/keys, <path>/certs
253
        // Retrieve the list of the files in the p_keysPath
1689 garciay 254
        try {
2230 mullers 255
            List<File> files = Helpers.getInstance().getFileListing(p_keysPath, CERT_EXT, EXCLUDED_PATTERNS);
1689 garciay 256
            // Create the memory cache
257
            for (File file : files) {
2230 mullers 258
                try {
259
                    addCertItem(file);
260
                }catch(FileNotFoundException e){}
1689 garciay 261
            } // End of 'for' statement
262
 
263
        } catch (IOException e) {
264
            e.printStackTrace();
265
        }
2230 mullers 266
 
267
        // load digests
268
        try {
269
            List<File> files = Helpers.getInstance().getFileListing(p_keysPath, DIGESTS_EXT, EXCLUDED_PATTERNS);
270
            // Create the memory cache
271
            for (File file : files) {
272
                try {
273
                    addDigestItem(file);
274
                }catch(FileNotFoundException e){}
275
            } // End of 'for' statement
276
 
277
        } catch (IOException e) {
278
            e.printStackTrace();
279
        }
1689 garciay 280
 
2230 mullers 281
        return true;
1689 garciay 282
    }
1917 berge 283
 
2230 mullers 284
    private void addDigestItem(final File p_file)  throws FileNotFoundException, IOException {
285
        String filename = p_file.getName();
286
        String certName = filename.substring(0, filename.lastIndexOf(".")).toUpperCase();
287
 
288
        // Load certificate
289
        byte bytes[] = new byte[64];
290
        FileInputStream fs = new FileInputStream(p_file);
291
        int n = fs.read(bytes);
292
        fs.close();
293
 
294
        if(n == 32){
295
            // take last 8 bytes
296
                bytes = Arrays.copyOfRange(bytes, 24, 32);
297
        }else if(n >= 64){
298
                bytes = ByteHelper.hexStringToByteArray(new String(bytes).substring(48, 64));
299
        }else if(n >= 16){
300
                bytes = ByteHelper.hexStringToByteArray(new String(bytes).substring(0, 16));
301
        }else if(n == 8){
302
                bytes = Arrays.copyOfRange(bytes, 0, 8);
303
        }else{
2655 filatov 304
            TERFactory.getInstance().logError("CertificatesIO: " + filename + ": wrong digest file length\n");
1917 berge 305
            return;
306
        }
2230 mullers 307
        _cachedCertificatesDigest.put(certName, bytes);
2655 filatov 308
//        TERFactory.getInstance().logDebug("CertificatesIO.addDigestItem: Store digest: " + ByteHelper.byteArrayToString(bytes) + " - " + certName);
2230 mullers 309
    }
310
 
311
    private void addCertItem(final File p_certFile)  throws FileNotFoundException, IOException {
2655 filatov 312
//        TERFactory.getInstance().logDebug(">>> CertificatesIO.addItem: " + p_certFile);
1917 berge 313
 
314
        // Load the keys file name
2230 mullers 315
        String filename = p_certFile.getName();
316
        String certName = filename.substring(0, filename.lastIndexOf(".")).toUpperCase();
1917 berge 317
 
2230 mullers 318
        // Load certificate
319
        byte bytes[] = new byte[(int) p_certFile.length()];
320
        FileInputStream fsKeys = new FileInputStream(p_certFile);
321
        fsKeys.read(bytes);
322
        fsKeys.close();
323
        bytes = ByteHelper.hexStringToByteArray(new String(bytes));
324
        _cachedCertificates.put(certName, bytes);
2655 filatov 325
//        TERFactory.getInstance().logDebug("CertificatesIO.addItem: Store cert " + certName + " - " + ByteHelper.byteArrayToString(bytes));
1917 berge 326
 
2230 mullers 327
        // calculate digest
328
        bytes = calculateDigestFromCertificate(bytes);
329
        _cachedCertificatesDigest.put(certName, bytes);
2655 filatov 330
//        TERFactory.getInstance().logDebug("CertificatesIO.addItem: Store digest: " + ByteHelper.byteArrayToString(bytes) + " - " + certName);
2230 mullers 331
        _cachedReverseCertificatesDigest.put(ByteHelper.byteArrayToString(bytes), certName);
2655 filatov 332
//        TERFactory.getInstance().logDebug("CertificatesIO.addItem: Store reverse digest " + ByteHelper.byteArrayToString(bytes) + " - " + certName);
2230 mullers 333
 
334
        // Load Private Keys
335
        filename = p_certFile.getPath();
336
        filename = filename.substring(0, filename.lastIndexOf("."));
337
 
338
        try {
339
               File f = new File(filename+".vkey");
340
               if(f.exists()){
341
                   long l = f.length();
342
                   if(l == 32 || l == 64){
343
                    bytes = new byte[64];
344
                       fsKeys = new FileInputStream(f);
345
                       l = fsKeys.read(bytes);
346
                       fsKeys.close();
347
                       if(l == 64){
348
                           bytes = ByteHelper.hexStringToByteArray(new String(bytes));
349
                           l = 32;
350
                       }
351
                       if(l != 32){
2655 filatov 352
                        TERFactory.getInstance().logError("CertificatesIO: " + f.getName() + ": wrong data length[" + l + "\n");
2230 mullers 353
                       }
354
                    if (!_cachedSigningPrivateKey.containsKey(certName)) {
355
                        _cachedSigningPrivateKey.put(certName, bytes);
356
                    }
357
                   }else{
2655 filatov 358
                    TERFactory.getInstance().logError("CertificatesIO: " + f.getName() + ": wrong key file length\n");
2230 mullers 359
                   }
360
               }
361
        }catch(FileNotFoundException e){}
362
 
363
        try {
364
               File f = new File(filename+".ekey");
365
               if(f.exists()){
366
                   if(f.length() == 32 || f.length() == 64){
367
                    bytes = new byte[64];
368
                       fsKeys = new FileInputStream(f);
369
                       fsKeys.read(bytes);
370
                       fsKeys.close();
371
                       if(f.length() == 64){
372
                           bytes = ByteHelper.hexStringToByteArray(new String(bytes));
373
                       }
374
                    if (!_cachedEncryptPrivateKey.containsKey(certName)) {
375
                        _cachedEncryptPrivateKey.put(certName, bytes);
376
                    }
377
                   }
378
               }
379
        }catch(FileNotFoundException e){}
1689 garciay 380
    }
381
 
1917 berge 382
    @Override
383
    public String getKeyIdFromHashedId8(byte[] p_hashedId8ToBeUsed) {
384
        String key = ByteHelper.byteArrayToString(p_hashedId8ToBeUsed);
385
        if (!_cachedReverseCertificatesDigest.containsKey(key)) {
386
            return null;
387
        }
388
 
2230 mullers 389
        return _cachedReverseCertificatesDigest.get(key).substring(0, _cachedReverseCertificatesDigest.get(key).length() - 7/*.DIGEST*/);
1917 berge 390
    }
391
 
392
    private byte[] calculateDigestFromCertificate(final byte[] p_toBeHashedData) {
393
        byte[] hash = CryptoLib.hashWithSha256(p_toBeHashedData);
394
        return ByteHelper.extract(hash, hash.length - 8, 8);
395
    }
396
 
1689 garciay 397
} // End of class CertificatesIO