Newer
Older
/**
* This class is used to centralise test adapter configuration and execution parameters
* All settings are component specific (multiton)
*
* @author ETSI / STF424
* @version $URL$
* $Id$
*
*/
package org.etsi.its.adapter;
import java.io.ByteArrayOutputStream;
import java.math.BigInteger;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import org.etsi.adapter.TERFactory;
import org.etsi.certificates.CertificatesIOFactory;
import org.etsi.certificates.io.ICertificatesIO;
import org.etsi.common.ByteHelper;
import org.etsi.common.ITuple;
import org.etsi.common.Tuple;
import org.etsi.its.adapter.ports.GnPort;
import org.etsi.ttcn.tci.CharstringValue;
import de.fraunhofer.sit.c2x.CryptoLib;
/**
* This class is used to centralise test adapter configuration and execution parameters
* All settings are component specific (multiton)
*/
public class Management implements IManagementTA, IManagementLayers {
/**
* Instances of Management
*/
private static final ConcurrentMap<String, Management> instances = new ConcurrentHashMap<String, Management>();
/**
* GeoNetworking beaconning interval
*/
private static final int GN_BEACON_INTERVAL = Integer.decode(((CharstringValue)TERFactory.getInstance().getTaParameter("TsBeaconInterval")).getString());
/**
* Maximum time for getting Long position vector (in seconds)
*/
private static final int GET_LPV_TIMEOUT = 10; //FIXME: Might be a parameter rather than a constant
/**
* Interval for polling the location table during GetLpv (in ms)
*/
private static final long GET_LPV_POLL_INTERVAL = 1000;
/**
* Test system latitude
*/
private static final int latitude = Integer.decode(((CharstringValue)TERFactory.getInstance().getTaParameter("TsLatitude")).getString());
/**
* Test system longitude
*/
private static final int longitude = Integer.decode(((CharstringValue)TERFactory.getInstance().getTaParameter("TsLongitude")).getString());
* Enforce secured mode status
//private static String TsEnforceSecuredMode = ((CharstringValue)TERFactory.getInstance().getTaParameter("TsEnforceSecuredMode")).getString();
private static String TsEnforceSecuredMode = "false";
/**
* Secured root path to access certificates & private keys
*/
private static final String TsSecuredRootPath = ((CharstringValue)TERFactory.getInstance().getTaParameter("TsSecuredRootPath")).getString();
/**
* Secured configuration identifier
*/
private static final String TsSecuredConfiId = ((CharstringValue)TERFactory.getInstance().getTaParameter("TsSecuredConfiId")).getString();
/**
* ITS-AID for Secure other profile
*/
private static final String TsItsAidOther = ((CharstringValue)TERFactory.getInstance().getTaParameter("TsItsAidOther")).getString();
/**
* Link-layer address of Component
*/
private byte[] linkLayerAddress = null;
/**
* Registered GN Port
*/
private GnPort gnPort = null;
/**
* Registered FSAP Port
*/
private FsapPort fsapPort = null; // FIXME Enhance this using Fsap.send() method
/**
* Set to true is secured mode is set
*/
private boolean securedMode = false;
/**
* The certificate identifier to used
*/
private String certificateId = "CERT_TS_A_AT";
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
/**
* The AT certificate
*/
private byte[] atCertificate = null;
/**
* The certificate digest to used
*/
private byte[] atCertificateDigest = null;
/**
* The private signing key to used
*/
private byte[] signingPrivateKey = null;
/**
* The public signing key X to used
*/
private byte[] signingPublicKeyX = null;
/**
* The public signing key Y to used
*/
private byte[] signingPublicKeyY = null;
// private byte[] toBeSignedDataDigest = null;
// private byte[] toBeSignedDataCertificate = null;
/**
* Private constructor (Multiton pattern)
*/
private Management() {
// For debug only:
byte[] mid = new byte[] {(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
(byte)0x00, (byte)0x00};
byte[] lpv = new byte[] {(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00};
gnUpdateLocTable(mid, 0, lpv);
}
* Gets the Management instance associated to a component
* @param key Component name
* @return Management instance
*/
public static Management getInstance(String key) {
if (instances.get(key) == null){
// Lazily create instance and try to add it to the map
Management instance = new Management();
instances.putIfAbsent(key, instance);
}
return instances.get(key);
}
/* (non-Javadoc)
* @see org.etsi.its.adapter.IManagementTA#startBeaconing(byte[])
*/
@Override
public void startBeaconing(byte[] beaconHeader) {
this.beaconHeader = beaconHeader;
if(gnPort != null) {
gnPort.startBeaconning();
}
}
/* (non-Javadoc)
* @see org.etsi.its.adapter.IManagementTA#stopBeaconing()
*/
@Override
public void stopBeaconing() {
this.beaconHeader = null;
if(gnPort != null) {
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
}
/* (non-Javadoc)
* @see org.etsi.its.adapter.IManagementTA#startEnqueueingBeacons(byte[])
*/
@Override
public void startEnqueueingBeacons(byte[] beaconHeader) {
this.enqueueBeacon = beaconHeader;
}
/* (non-Javadoc)
* @see org.etsi.its.adapter.IManagementTA#stopEnqueueingBeacons()
*/
@Override
public void stopEnqueueingBeacons() {
this.enqueueBeacon = null;
}
/* (non-Javadoc)
* @see org.etsi.its.adapter.IManagementTA#startMultipleBeaconing(byte[], int)
*/
@Override
public void startMultipleBeaconing(byte[] beaconHeader, int nbNeighbours) {
/* TODO: Multiple beacons */
}
/* (non-Javadoc)
* @see org.etsi.its.adapter.IManagementTA#stopMultipleBeaconing()
*/
@Override
public void stopMultipleBeaconing() {
/* TODO: Multiple beacons */
}
/* (non-Javadoc)
* @see org.etsi.its.adapter.IManagementTA#getLongPositionVector(byte[])
*/
@Override
public byte[] getLongPositionVector(byte[] targetGnAddress) {
byte[] mid = ByteHelper.extract(targetGnAddress, 2, 6);
TERFactory.getInstance().logDebug("getLongPositionVector: Looking for Loc Entry: " + ByteHelper.byteArrayToString(mid));
long key = ByteHelper.byteArrayToLong(mid);
for(int i = 0; i < GET_LPV_TIMEOUT; ++i) {
if (locTable.containsKey(key)) {
ITuple<Long, byte[]> entry = locTable.get(key);
return entry.getB();
}
try {
Thread.sleep(GET_LPV_POLL_INTERVAL);
} catch (InterruptedException e) {
// Do nothing, we do not care
}
}
return null;
}
/* (non-Javadoc)
* @see org.etsi.its.adapter.IManagementLayers#getGnBeacon()
*/
@Override
public byte[] getGnBeacon() {
return beaconHeader;
}
/* (non-Javadoc)
* @see org.etsi.its.adapter.IManagementLayers#getGnBeaconInterval()
*/
@Override
public int getGnBeaconInterval() {
return GN_BEACON_INTERVAL;
}
/* (non-Javadoc)
* @see org.etsi.its.adapter.IManagementLayers#getGnEnqueueBeacon()
*/
@Override
public byte[] getGnEnqueueBeacon() {
return enqueueBeacon;
}
/* (non-Javadoc)
* @see org.etsi.its.adapter.IManagementLayers#gnUpdateLocTable(byte[], long, byte[])
*/
@Override
public void gnUpdateLocTable(byte[] mid, long timestamp, byte[] lpv) {
// Java does not provide unsigned int
timestamp &= 0xffffffffL;
long key = ByteHelper.byteArrayToLong(mid);
ITuple<Long, byte[]> entry = locTable.get(key);
if(entry == null || entry.getA() < timestamp) {
// TERFactory.getInstance().logDebug("gnUpdateLocTable: Adding Loc Entry for: " + ByteHelper.byteArrayToString(mid));
locTable.put(key, new Tuple<Long, byte[]>(timestamp, lpv));
}
}
/* (non-Javadoc)
* @see org.etsi.its.adapter.IManagementLayers#getLinkLayerAddress()
*/
@Override
public byte[] getLinkLayerAddress() {
return linkLayerAddress;
}
/* (non-Javadoc)
* @see org.etsi.its.adapter.IManagementLayers#getLinkLayerAddress()
*/
@Override
public void setLinkLayerAddress(byte[] linkLayerAddress) {
this.linkLayerAddress = linkLayerAddress;
}
/* (non-Javadoc)
* @see org.etsi.its.adapter.IManagementLayers#getLatitude()
*/
@Override
public byte[] getLatitude() {
return ByteHelper.intToByteArray(latitude, 4);
}
/* (non-Javadoc)
* @see org.etsi.its.adapter.IManagementLayers#getLongitude()
*/
@Override
public byte[] getLongitude() {
return ByteHelper.intToByteArray(longitude, 4);
}
/**
* Set to null in order to prevent Test Adapter from sending beacons
* Otherwise, it shall be set to a valid encoded beacon header to be send periodically by Test Adapter
* @see startEnqueueingBeacons
* @see stopEnqueueingBeacons
*/
private byte[] beaconHeader = null;
/**
* Set to null if received Beacon messages have to be discarded by test adapter (= not enqueued)
* Otherwise, it shall be set to the to an encoded beacon header value acting as a filter for enqueueing received beacons
* @see startBeaconing
* @see stopBeaconing
*/
private byte[] enqueueBeacon = null;
/**
* Table used to store neighbours (= SUT) position vectors
* @see gnUpdateLocTable
* @see getLongPositionVector
*/
private static Map<Long, ITuple<Long, byte[]>> locTable = new HashMap<Long, ITuple<Long, byte[]>>();
/* (non-Javadoc)
* @see org.etsi.its.adapter.IManagementLayers#registerBeaconThread(java.lang.Thread)
*/
@Override
public void registerGnPort(GnPort gnPort) {
this.gnPort = gnPort;
// Ensure that management settings are reset
beaconHeader = null;
enqueueBeacon = null;
@Override
public void setSecuredMode(final byte[] securityData) {
certificateId = ByteHelper.byteArrayWithLengthToString(ByteHelper.concat(ByteHelper.intToByteArray(securityData.length - 1, 4), securityData));
if (securityData[securityData.length - 1] == 0x01) {
TsEnforceSecuredMode = "true";
} else {
TsEnforceSecuredMode = "false";
}
setupSecuredMode();
}
@Override
public void unsetSecuredMode() {
securedMode = false;
signingPrivateKey = null;
signingPublicKeyX = null;
signingPublicKeyY = null;
atCertificate = null;
atCertificateDigest = null;
}
@Override
public boolean isEnforceSecuredModeSet() {
return TsEnforceSecuredMode.equals("true");
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
@Override
public boolean isSecuredModeSet() {
return securedMode;
}
@Override
public BigInteger getSigningPrivateKey() {
return new BigInteger(signingPrivateKey);
}
@Override
public byte[] getSigningPublicKeyX() {
return signingPublicKeyX;
}
@Override
public byte[] getSigningPublicKeyY() {
return signingPublicKeyY;
}
@Override
public byte[] getAtCertificate() {
return atCertificate;
}
@Override
public byte[] getAtCertificateDigest() {
return atCertificateDigest;
}
@Override
public int getItsAidOther() {
return new Integer(TsItsAidOther).intValue();
}
* @desc This method setup secured mode according to ATS settings (AcSecPrimitive) and the Test adapter settings (TsEnforceSecuredMode flags)
* @see TsEnforceSecuredMode flags.
* @remark This method shall be called by the constructor only
*/
private void setupSecuredMode() {
TERFactory.getInstance().logDebug(">>> setupSecuredMode: " + certificateId);
securedMode = true;
ICertificatesIO _certCache = CertificatesIOFactory.getInstance();
if (!_certCache.loadCertificates(TsSecuredRootPath, TsSecuredConfiId)) {
securedMode = false;
} else {
ByteArrayOutputStream certificate = new ByteArrayOutputStream();
_certCache.readCertificate(certificateId, certificate);
// Extract public keys
atCertificate = certificate.toByteArray();
TERFactory.getInstance().logDebug("Management.setupSecuredModeFromTaConfig: certificate=" + ByteHelper.byteArrayToString(atCertificate));
// Compute AT certificate digest
byte[] atHash = CryptoLib.hashWithSha256(atCertificate);
atCertificateDigest = ByteHelper.extract(atHash, atHash.length - 8, 8);
TERFactory.getInstance().logDebug("Management.setupSecuredModeFromTaConfig: atCertificateDigest=" + ByteHelper.byteArrayToString(atCertificateDigest));
int offset = 16; // FIXME To be enhanced
// KeyX
signingPublicKeyX = new byte[32];
System.arraycopy(atCertificate, offset, signingPublicKeyX, 0, 32);
offset += 32;
TERFactory.getInstance().logDebug("Management.setupSecuredModeFromTaConfig: signingPublicKeyX=" + ByteHelper.byteArrayToString(signingPublicKeyX));
// KeyY
signingPublicKeyY = new byte[32];
System.arraycopy(atCertificate, offset, signingPublicKeyY, 0, 32);
TERFactory.getInstance().logDebug("Management.setupSecuredModeFromTaConfig: signingPublicKeyY=" + ByteHelper.byteArrayToString(signingPublicKeyY));
// Extract private keys
ByteArrayOutputStream signingPrivateKey = new ByteArrayOutputStream();
_certCache.readSigningKey(certificateId, signingPrivateKey);
this.signingPrivateKey = signingPrivateKey.toByteArray().clone();
TERFactory.getInstance().logDebug("Management.setupSecuredModeFromTaConfig: signingPrivateKey=" + ByteHelper.byteArrayToString(this.signingPrivateKey));
// TODO Add support of encryption
}
}
/**
* Registers a FSAP port
* @param The FSAP port to register
*/
@Override
public void registerFsapPort(final FsapPort fsapPort) {
this.fsapPort = fsapPort;
}
@Override
public void startSamTransmission(final byte[] sam) {
if(fsapPort != null) {
fsapPort.startSamTransmission(sam);
}
}
@Override
public void stopSamTransmission() {
if(fsapPort != null) {
fsapPort.stopSamTransmission();
}
}
} // End of class Management