All Downloads are FREE. Search and download functionalities are using the official Maven repository.

gurux.dlms.GXDLMSSettings Maven / Gradle / Ivy

There is a newer version: 4.0.72
Show newest version
//
// --------------------------------------------------------------------------
//  Gurux Ltd
// 
//
//
// Filename:        $HeadURL$
//
// Version:         $Revision$,
//                  $Date$
//                  $Author$
//
// Copyright (c) Gurux Ltd
//
//---------------------------------------------------------------------------
//
//  DESCRIPTION
//
// This file is a part of Gurux Device Framework.
//
// Gurux Device Framework is Open Source software; you can redistribute it
// and/or modify it under the terms of the GNU General Public License 
// as published by the Free Software Foundation; version 2 of the License.
// Gurux Device Framework is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of 
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
// See the GNU General Public License for more details.
//
// More information of Gurux products: https://www.gurux.org
//
// This code is licensed under the GNU General Public License v2. 
// Full text may be retrieved at http://www.gnu.org/licenses/gpl-2.0.txt
//---------------------------------------------------------------------------

package gurux.dlms;

import java.security.KeyPair;
import java.security.PublicKey;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;

import gurux.dlms.asn.GXPkcs8;
import gurux.dlms.asn.GXx509Certificate;
import gurux.dlms.asn.enums.KeyUsage;
import gurux.dlms.enums.Authentication;
import gurux.dlms.enums.Conformance;
import gurux.dlms.enums.ConnectionState;
import gurux.dlms.enums.DataType;
import gurux.dlms.enums.DateTimeSkips;
import gurux.dlms.enums.InterfaceType;
import gurux.dlms.enums.ObjectType;
import gurux.dlms.enums.Priority;
import gurux.dlms.enums.Security;
import gurux.dlms.enums.ServiceClass;
import gurux.dlms.enums.Signing;
import gurux.dlms.enums.Standard;
import gurux.dlms.objects.GXDLMSAssociationLogicalName;
import gurux.dlms.objects.GXDLMSData;
import gurux.dlms.objects.GXDLMSHdlcSetup;
import gurux.dlms.objects.GXDLMSObjectCollection;
import gurux.dlms.objects.GXDLMSSecuritySetup;
import gurux.dlms.objects.GXDLMSTcpUdpSetup;
import gurux.dlms.objects.enums.ApplicationContextName;
import gurux.dlms.objects.enums.AssociationStatus;
import gurux.dlms.objects.enums.CertificateType;
import gurux.dlms.objects.enums.SecuritySuite;

/**
 * This class includes DLMS communication settings.
 * 
 * @author Gurux Ltd.
 */
public class GXDLMSSettings {

    /**
     * The version can be used for backward compatibility.
     */
    private int version = 4;

    /**
     * HDLC settings.
     */
    private GXDLMSHdlcSetup hdlc;

    /**
     * Wrapper settings.
     */
    private GXDLMSTcpUdpSetup wrapper;

    /**
     * Frame check is skipped for some unit tests. This is internal use only.
     */
    private boolean skipFrameCheck = false;
    /**
     * Server sender frame sequence starting number.
     */
    static final short SERVER_START_SENDER_FRAME_SEQUENCE = 0x1E;

    /**
     * Server receiver frame sequence starting number.
     */
    static final short SERVER_START_RECEIVER_FRAME_SEQUENCE = 0xFE;

    /**
     * Client sender frame sequence starting number.
     */
    static final short CLIENT_START_SENDER_FRAME_SEQUENCE = 0xFE;

    /**
     * Client receiver frame sequence starting number.
     */
    static final short CLIENT_START_RCEIVER_FRAME_SEQUENCE = 0xE;

    /**
     * DLMS version number.
     */
    static final byte DLMS_VERSION = 6;

    static final int MAX_RECEIVE_PDU_SIZE = 0xFFFF;

    /**
     * Is custom challenges used. If custom challenge is used new challenge is
     * not generated if it is set. This is for debugging purposes.
     */
    private boolean customChallenges = false;

    /**
     * Source challenge.
     */
    private byte[] ctoSChallenge;
    /**
     * Server to Client challenge.
     */
    private byte[] stoCChallenge;

    /**
     * Source system title.
     */
    private byte[] sourceSystemTitle;

    /**
     * Pre-established system title.
     */
    private byte[] preEstablishedSystemTitle;

    /**
     * Invoke ID.
     */
    private byte invokeID = 0x1;
    /**
     * Long Invoke ID.
     */
    private long longInvokeID = 0x1;

    /**
     * Priority.
     */
    private Priority priority = Priority.HIGH;
    /**
     * Service class.
     */
    private ServiceClass serviceClass = ServiceClass.CONFIRMED;

    /**
     * Assigned association for the server.
     */
    GXDLMSAssociationLogicalName assignedAssociation;

    /**
     * Client address.
     */
    private int clientAddress;
    /**
     * Server address.
     */
    private int serverAddress;

    /**
     * Server is using push client address when sending push messages. Client
     * address is used if PushAddress is zero.
     */
    private int pushClientAddress;

    /**
     * Server address side.
     */
    private int serverAddressSize = 0;

    /**
     * Is Logical Name referencing used.
     */
    private boolean useLogicalNameReferencing;
    /**
     * Interface type.
     */
    private InterfaceType interfaceType = InterfaceType.HDLC;
    /**
     * User authentication.
     */
    private Authentication authentication = Authentication.NONE;
    /**
     * User password.
     */
    private byte[] password;

    /**
     * Key Encrypting Key, also known as Master key.
     */
    private byte[] kek;

    /**
     * Long data count.
     */
    private long count;

    /**
     * Long data index.
     */
    private long index;

    /**
     * Target ephemeral public key.
     */
    private PublicKey targetEphemeralKey;

    /**
     * DLMS version number.
     */
    private int dlmsVersionNumber = DLMS_VERSION;

    private byte connected = ConnectionState.NONE;

    /**
     * Maximum receivers PDU size.
     */
    private int maxPduSize = MAX_RECEIVE_PDU_SIZE;

    /**
     * Server maximum PDU size.
     */
    private int maxServerPDUSize = MAX_RECEIVE_PDU_SIZE;

    /**
     * When connection is made client tells what kind of services it want's to
     * use.
     */
    private Set proposedConformance = new HashSet();

    /**
     * Server tells what functionality is available and client will know it.
     */
    private Set negotiatedConformance = new HashSet();

    /**
     * HDLC sender frame sequence number.
     */
    short senderFrame;

    /**
     * HDLC receiver frame sequence number.
     */
    short receiverFrame;

    /**
     * Is this server or client.
     */
    private boolean server;

    /**
     * HDLC framing settings.
     */
    private GXHdlcSettings hdlcSettings;

    /**
     * Gateway settings.
     */
    private GXDLMSGateway gateway;

    /**
     * PLC settings.
     */
    private GXPlcSettings plc;

    /**
     * M-Bus settings.
     */
    private GXMBusSettings mBus;

    /**
     * CoAP settings.
     */
    private GXCoAPSettings coap;

    private int startingPacketIndex = 1;

    /**
     * Block packet index.
     */
    private int blockIndex = 1;
    /**
     * List of server or client objects.
     */
    private final GXDLMSObjectCollection objects;

    /**
     * Cipher interface that is used to cipher PDU.
     */
    private GXICipher cipher;

    /**
     * Crypto notifier.
     */
    private final IGXCryptoNotifier cryptoNotifier;

    /**
     * Custom object notifier.
     */
    private final IGXCustomObjectNotifier customObjectNotifier;

    /**
     * Block number acknowledged in GBT.
     */
    private int blockNumberAck;

    /**
     * GBT window size.
     */
    private byte gbtWindowSize;

    /*
     * User id is the identifier of the user. This value is used if user list on
     * Association LN is used.
     */
    private int userId;

    /*
     * Quality of service.
     */
    private byte qualityOfService;

    /**
     * Standard says that Time zone is from normal time to UTC in minutes. If
     * meter is configured to use UTC time (UTC to normal time) set this to
     * true.
     */
    private boolean useUtc2NormalTime;

    /**
     * Some meters expect that Invocation Counter is increased for
     * Authentication when connection is established.
     */
    private boolean increaseInvocationCounterForGMacAuthentication;

    /**
     * Skipped fields.
     */
    private java.util.Set dateTimeSkips = new HashSet();

    /**
     * Skipped fields.
     */
    private java.util.Set readDateTimeSkips = new HashSet();

    private Standard standard;

    /**
     * Last executed command.
     */
    private int command;

    /**
     * Last executed command type
     */
    private byte commandType;

    /**
     * Protocol version.
     */
    private String protocolVersion = null;

    /**
     * Auto increase Invoke ID.
     */
    private boolean autoIncreaseInvokeID = false;

    GXDLMSData invocationCounter;

    /**
     * Ephemeral Block cipher key.
     */
    private byte[] ephemeralBlockCipherKey;

    /**
     * Ephemeral broadcast block cipher key.
     */
    private byte[] ephemeralBroadcastBlockCipherKey;
    /**
     * Ephemeral authentication key.
     */
    private byte[] ephemeralAuthenticationKey;

    /**
     * Data is only decrypted and PDU is not parsed.
     */
    private boolean decryptOnly;

    /**
     * XML needs list of certificates to decrypt the data.
     */
    private List> keys;

    /**
     * Size of the challenge.
     */
    private byte challengeSize = 16;

    private boolean overwriteAttributeAccessRights;

    /**
     * Optional ECDSA public key certificate that is send in part of AARQ.
     */
    private GXx509Certificate clientPublicKeyCertificate;

    /**
     * Optional ECDSA public key certificate that is send in part of AARE.
     */
    private GXx509Certificate serverPublicKeyCertificate;

    /**
     * @return Ephemeral Block cipher key.
     */
    public final byte[] getEphemeralBlockCipherKey() {
        return ephemeralBlockCipherKey;
    }

    /**
     * @param value
     *            Ephemeral Block cipher key.
     */
    public final void setEphemeralBlockCipherKey(final byte[] value) {
        ephemeralBlockCipherKey = value;
    }

    /**
     * @return Ephemeral broadcast block cipher key.
     */
    public final byte[] getEphemeralBroadcastBlockCipherKey() {
        return ephemeralBroadcastBlockCipherKey;
    }

    /**
     * @param value
     *            Ephemeral broadcast block cipher key.
     */
    public final void setEphemeralBroadcastBlockCipherKey(final byte[] value) {
        ephemeralBroadcastBlockCipherKey = value;
    }

    /**
     * @return Ephemeral authentication key.
     */
    public final byte[] getEphemeralAuthenticationKey() {
        return ephemeralAuthenticationKey;
    }

    /**
     * @param value
     *            Ephemeral authentication key.
     */
    public final void setEphemeralAuthenticationKey(final byte[] value) {
        ephemeralAuthenticationKey = value;
    }

    /*
     * Constructor.
     */
    GXDLMSSettings(final boolean isServer, final IGXCryptoNotifier notifier, final IGXCustomObjectNotifier notifier2) {
        server = isServer;
        cryptoNotifier = notifier;
        customObjectNotifier = notifier2;
        objects = new GXDLMSObjectCollection();
        hdlcSettings = new GXDLMSLimits(this);
        plc = new GXPlcSettings(this);
        mBus = new GXMBusSettings();
        coap = new GXCoAPSettings();
        gateway = null;
        proposedConformance.addAll(GXDLMSClient.getInitialConformance(false));
        if (isServer) {
            proposedConformance.add(Conformance.GENERAL_PROTECTION);
        }
        resetFrameSequence();
        gbtWindowSize = 1;
        userId = -1;
        standard = Standard.DLMS;
        keys = new ArrayList>();
    }

    /**
     * @param value
     *            Cipher interface that is used to cipher PDU.
     */
    final void setCipher(final GXICipher value) {
        cipher = value;
    }

    /**
     * @return Cipher interface that is used to cipher PDU.
     */
    public final GXICipher getCipher() {
        return cipher;
    }

    /**
     * @return Client to Server challenge.
     */
    public final byte[] getCtoSChallenge() {
        return ctoSChallenge;
    }

    /**
     * @param value
     *            Client to Server challenge.
     */
    public final void setCtoSChallenge(final byte[] value) {
        if (!customChallenges || ctoSChallenge == null) {
            ctoSChallenge = value;
        }
    }

    /**
     * @return Server to Client challenge.
     */
    public final byte[] getStoCChallenge() {
        return stoCChallenge;
    }

    /**
     * @param value
     *            Server to Client challenge.
     */
    public final void setStoCChallenge(final byte[] value) {
        if (!customChallenges || stoCChallenge == null) {
            stoCChallenge = value;
        }
    }

    /**
     * @return Used authentication.
     */
    public final Authentication getAuthentication() {
        return authentication;
    }

    /**
     * @param value
     *            Used authentication.
     */
    public final void setAuthentication(final Authentication value) {
        authentication = value;
    }

    /**
     * @return Gets password.
     */
    public final byte[] getPassword() {
        return password;
    }

    /**
     * @param value
     *            Sets password.
     */
    public final void setPassword(final byte[] value) {
        password = value;
    }

    /**
     * @return Used DLMS version number.
     */
    public final int getDlmsVersionNumber() {
        return dlmsVersionNumber;
    }

    /**
     * @param value
     *            Used DLMS version number.
     */
    public final void setDlmsVersionNumber(final int value) {
        dlmsVersionNumber = value;
    }

    /**
     * @return Is connected to the meter.
     */
    public final byte getConnected() {
        return connected;
    }

    /**
     * @param value
     *            Is connected to the meter.
     */
    public final void setConnected(final int value) {
        connected = (byte) value;
    }

    /**
     * Reset frame sequence.
     */
    public final void resetFrameSequence() {
        if (server) {
            senderFrame = SERVER_START_SENDER_FRAME_SEQUENCE;
            receiverFrame = SERVER_START_RECEIVER_FRAME_SEQUENCE;
        } else {
            senderFrame = CLIENT_START_SENDER_FRAME_SEQUENCE;
            receiverFrame = CLIENT_START_RCEIVER_FRAME_SEQUENCE;
        }
    }

    final boolean checkFrame(final short frame) {
        // If notify
        if (frame == 0x13) {
            return true;
        }
        // If U frame.
        if ((frame & HdlcFrameType.U_FRAME.getValue()) == HdlcFrameType.U_FRAME.getValue()) {
            if (frame == 0x73 || frame == 0x93) {
                resetFrameSequence();
                return true;
            }
        }
        // If S -frame.
        if ((frame & HdlcFrameType.S_FRAME.getValue()) == HdlcFrameType.S_FRAME.getValue()) {
            receiverFrame = increaseReceiverSequence(receiverFrame);
            return true;
        }
        // Handle I-frame.
        short expected;
        if ((senderFrame & 0x1) == 0) {
            expected = (short) (increaseReceiverSequence(increaseSendSequence(receiverFrame)) & 0xFF);
            if (frame == expected) {
                receiverFrame = frame;
                return true;
            }
        } else {
            expected = (short) (increaseSendSequence(receiverFrame) & 0xFF);
            // If answer for RR.
            if (frame == expected) {
                receiverFrame = frame;
                return true;
            }
        }
        // This is for unit tests.
        if (skipFrameCheck) {
            receiverFrame = frame;
            return true;
        }
        Logger.getLogger(GXDLMS.class.getName()).log(Level.INFO,
                "Invalid HDLC Frame: " + Long.toString(frame, 16) + " Expected: " + Long.toString(expected, 16));
        return false;
    }

    /**
     * Increase receiver sequence.
     * 
     * @param value
     *            Frame value.
     * @return Increased receiver frame sequence.
     */
    static byte increaseReceiverSequence(final short value) {
        return (byte) ((value & 0xFF) + 0x20 | 0x10 | value & 0xE);
    }

    /**
     * Increase sender sequence.
     * 
     * @param value
     *            Frame value.
     * @return Increased sender frame sequence.
     */
    static short increaseSendSequence(final short value) {
        return (short) ((value & 0xF0 | (value + 0x2) & 0xE) & 0xFF);
    }

    /**
     * @param first
     *            Is this first packet.
     * @return Generated I-frame
     */
    final byte getNextSend(final boolean first) {
        if (first) {
            senderFrame = increaseReceiverSequence(increaseSendSequence((byte) senderFrame));
        } else {
            senderFrame = increaseSendSequence((byte) senderFrame);
        }
        return (byte) senderFrame;
    }

    /**
     * @return Generates Receiver Ready S-frame.
     */
    final byte getReceiverReady() {
        senderFrame = increaseReceiverSequence((byte) (senderFrame | 1));
        return (byte) (senderFrame & 0xF1);
    }

    /**
     * @return Generates Keep Alive S-frame.
     */
    final byte getKeepAlive() {
        senderFrame = (byte) (senderFrame | 1);
        return (byte) (senderFrame & 0xF1);
    }

    /**
     * Gets current block index.
     * 
     * @return Current block index.
     */
    final int getBlockIndex() {
        return blockIndex;
    }

    /**
     * Gets starting block index in HDLC framing. Default is One based, but some
     * meters use Zero based value. Usually this is not used.
     * 
     * @return Current block index.
     */
    final int getStartingPacketIndex() {
        return startingPacketIndex;
    }

    /**
     * Set starting block index in HDLC framing. Default is One based, but some
     * meters use Zero based value. Usually this is not used.
     * 
     * @param value
     *            Zero based starting index.
     */
    public final void setStartingPacketIndex(final int value) {
        startingPacketIndex = value;
        resetBlockIndex();
    }

    /**
     * Sets current block index.
     * 
     * @param value
     *            Block index.
     */
    final void setBlockIndex(final int value) {
        blockIndex = value;
    }

    /**
     * @return Block number acknowledged in GBT.
     */
    public final int getBlockNumberAck() {
        return blockNumberAck;
    }

    /**
     * @param value
     *            Block number acknowledged in GBT.
     */
    public final void setBlockNumberAck(final int value) {
        blockNumberAck = value;
    }

    /**
     * Resets block index to default value.
     */
    final void resetBlockIndex() {
        blockIndex = startingPacketIndex;
        blockNumberAck = 0;
    }

    /**
     * Increases block index.
     */
    final void increaseBlockIndex() {
        blockIndex += 1;
    }

    /**
     * @return Is server or client.
     */
    public final boolean isServer() {
        return server;
    }

    /**
     * @param value
     *            Is server or client.
     */
    public final void setServer(final boolean value) {
        server = value;
    }

    /**
     * @return Information from the frame size that server can handle.
     */
    public final GXHdlcSettings getHdlcSettings() {
        return hdlcSettings;
    }

    /**
     * @return Gateway settings.
     */
    public final GXDLMSGateway getGateway() {
        return gateway;
    }

    /**
     * @param value
     *            Gateway settings.
     */
    public final void setGateway(final GXDLMSGateway value) {
        gateway = value;
    }

    /**
     * @return PLC settings.
     */
    public final GXPlcSettings getPlc() {
        return plc;
    }

    /**
     * @param value
     *            PLC settings.
     */
    public final void setPlc(GXPlcSettings value) {
        plc = value;
    }

    /**
     * @param value
     *            HDLC connection settings.
     */
    public final void setLimits(final GXHdlcSettings value) {
        hdlcSettings = value;
    }

    /**
     * @return Used interface.
     */
    public final InterfaceType getInterfaceType() {
        return interfaceType;
    }

    /**
     * @param value
     *            Used interface.
     */
    public final void setInterfaceType(final InterfaceType value) {
        interfaceType = value;
    }

    /**
     * @return Client address.
     */
    public final int getClientAddress() {
        return clientAddress;
    }

    /*
     * General Block Transfer count in server.
     */
    private int gbtCount;

    /**
     * @param value
     *            General Block Transfer count in server.
     */
    public final void setGbtCount(final int value) {
        gbtCount = value;
    }

    /**
     * @return General Block Transfer count in server.
     */
    public final int getGbtCount() {
        return gbtCount;
    }

    /**
     * @param value
     *            Client address.
     */
    public final void setClientAddress(final int value) {
        clientAddress = value;
    }

    /**
     * @return Server address size in bytes. If it is Zero it is counted
     *         automatically.
     */
    public final int getServerAddressSize() {
        return serverAddressSize;
    }

    /**
     * @param value
     *            Server address size in bytes. If it is Zero it is counted
     *            automatically.
     */
    public final void setServerAddressSize(final int value) {
        serverAddressSize = value;
    }

    /**
     * @return Server address.
     */
    public final int getServerAddress() {
        return serverAddress;
    }

    /**
     * @param value
     *            Server address.
     */
    public final void setServerAddress(final int value) {
        serverAddress = value;
    }

    /**
     * @return DLMS version number.
     */
    public final int getDLMSVersion() {
        return dlmsVersionNumber;
    }

    /**
     * @param value
     *            DLMS version number.
     */
    public final void setDLMSVersion(final int value) {
        dlmsVersionNumber = value;
    }

    /**
     * @return Maximum PDU size.
     */
    public final int getMaxPduSize() {
        return maxPduSize;
    }

    /**
     * @param value
     *            Maximum PDU size.
     */
    public final void setMaxPduSize(final int value) {
        maxPduSize = value;
    }

    /**
     * @return Server maximum PDU size.
     */
    public final int getMaxServerPDUSize() {
        return maxServerPDUSize;
    }

    /**
     * @param value
     *            Server maximum PDU size.
     */
    public final void setMaxServerPDUSize(final int value) {
        maxServerPDUSize = value;
    }

    /**
     * @return Is Logical Name Referencing used.
     */
    public final boolean getUseLogicalNameReferencing() {
        return useLogicalNameReferencing;
    }

    /**
     * @param value
     *            Is Logical Name Referencing used.
     */
    public final void setUseLogicalNameReferencing(final boolean value) {
        if (useLogicalNameReferencing != value) {
            useLogicalNameReferencing = value;
            proposedConformance.clear();
            proposedConformance.addAll(GXDLMSClient.getInitialConformance(getUseLogicalNameReferencing()));
            if (isServer()) {
                proposedConformance.add(Conformance.GENERAL_PROTECTION);
            }
        }
    }

    /**
     * @return Used priority.
     */
    public final Priority getPriority() {
        return priority;
    }

    /**
     * @param value
     *            Used priority.
     */
    public final void setPriority(final Priority value) {
        priority = value;
    }

    /**
     * @return Used service class.
     */
    public final ServiceClass getServiceClass() {
        return serviceClass;
    }

    /**
     * @param value
     *            Used service class.
     */
    public final void setServiceClass(final ServiceClass value) {
        serviceClass = value;
    }

    private void updateSecurity(byte[] systemTitle, GXDLMSSecuritySetup ss) {
        if (ss != null) {
            getCipher().setSecuritySuite(ss.getSecuritySuite());
            getCipher().setSecurityPolicy(ss.getSecurityPolicy());
            getCipher().setBlockCipherKey(ss.getGuek());
            getCipher().setBroadcastBlockCipherKey(ss.getGbek());
            getCipher().setAuthenticationKey(ss.getGak());
            setEphemeralBlockCipherKey(ss.getGuek());
            setEphemeralBroadcastBlockCipherKey(ss.getGbek());
            setEphemeralAuthenticationKey(ss.getGak());
            setKek(ss.getKek());
            // Update certificates for pre-established connections.
            byte[] st;
            if (systemTitle == null) {
                st = ss.getClientSystemTitle();
            } else {
                st = systemTitle;
            }
            if (st != null) {
                GXx509Certificate cert = ss.serverCertificates.findBySystemTitle(st, KeyUsage.DIGITAL_SIGNATURE);
                if (cert != null) {
                    getCipher().setSigningKeyPair(new KeyPair(cert.getPublicKey(), ss.signingKey.getPrivate()));
                }
                cert = ss.serverCertificates.findBySystemTitle(st, KeyUsage.KEY_AGREEMENT);
                if (cert != null) {
                    getCipher().setKeyAgreementKeyPair(new KeyPair(cert.getPublicKey(), ss.keyAgreement.getPrivate()));
                }
                setSourceSystemTitle(st);
            }
            getCipher().setSystemTitle(ss.getServerSystemTitle());
            // Find Invocation counter and use it if it exists.
            String ln = "0.0.43.1." + ss.getLogicalName().split("[.]")[4] + ".255";
            invocationCounter = (GXDLMSData) getObjects().findByLN(ObjectType.DATA, ln);
            if (invocationCounter != null && invocationCounter.getValue() == null) {
                if (invocationCounter.getDataType(2) == DataType.NONE) {
                    invocationCounter.setDataType(2, DataType.UINT32);
                }
                invocationCounter.setValue(0);
            }
        } else {
            assignedAssociation.getApplicationContextName().setContextId(ApplicationContextName.LOGICAL_NAME);
        }
    }

    void updateSecuritySettings(final byte[] systemTitle) {
        if (assignedAssociation != null) {
            // Update security settings.
            if (assignedAssociation.getSecuritySetupReference() != null && (assignedAssociation
                    .getApplicationContextName().getContextId() == ApplicationContextName.LOGICAL_NAME_WITH_CIPHERING
                    || assignedAssociation.getAuthenticationMechanismName().getMechanismId() == Authentication.HIGH_GMAC
                    || assignedAssociation.getAuthenticationMechanismName()
                            .getMechanismId() == Authentication.HIGH_ECDSA)) {
                GXDLMSSecuritySetup ss = (GXDLMSSecuritySetup) assignedAssociation.getObjectList()
                        .findByLN(ObjectType.SECURITY_SETUP, assignedAssociation.getSecuritySetupReference());
                updateSecurity(systemTitle, ss);
            } else {
                GXDLMSSecuritySetup ss = (GXDLMSSecuritySetup) assignedAssociation.getObjectList()
                        .findByLN(ObjectType.SECURITY_SETUP, assignedAssociation.getSecuritySetupReference());
                updateSecurity(systemTitle, ss);
            }
        }
    }

    /**
     * @param value
     *            Current association of the server.
     */
    public final void setAssignedAssociation(final GXDLMSAssociationLogicalName value) {
        if (assignedAssociation != null) {
            assignedAssociation.setAssociationStatus(AssociationStatus.NON_ASSOCIATED);
            assignedAssociation.getXDLMSContextInfo().setCypheringInfo(null);
            invocationCounter = null;
            getCipher().getSecurityPolicy().clear();
            setEphemeralBlockCipherKey(null);
            setEphemeralBroadcastBlockCipherKey(null);
            setEphemeralAuthenticationKey(null);
            getCipher().setSecuritySuite(SecuritySuite.SUITE_0);
        }

        assignedAssociation = value;
        if (assignedAssociation != null) {
            proposedConformance = assignedAssociation.getXDLMSContextInfo().getConformance();
            maxServerPDUSize = assignedAssociation.getXDLMSContextInfo().getMaxReceivePduSize();
            authentication = assignedAssociation.getAuthenticationMechanismName().getMechanismId();
            updateSecuritySettings(null);
        }
    }

    /**
     * @return Current server association.
     */
    public final GXDLMSAssociationLogicalName getAssignedAssociation() {
        return assignedAssociation;
    }

    /**
     * @return Invoke ID.
     */
    public final int getInvokeID() {
        return invokeID;
    }

    /**
     * @param value
     *            update invoke ID.
     */
    final void updateInvokeId(final short value) {
        if ((value & 0x80) != 0) {
            setPriority(Priority.HIGH);
        } else {
            setPriority(Priority.NORMAL);
        }
        if ((value & 0x40) != 0) {
            setServiceClass(ServiceClass.CONFIRMED);
        } else {
            setServiceClass(ServiceClass.UN_CONFIRMED);
        }
        invokeID = (byte) (value & 0xF);
    }

    /**
     * @param value
     *            Invoke ID.
     */
    public final void setInvokeID(final int value) {
        if (value > 0xF) {
            throw new IllegalArgumentException("Invalid InvokeID");
        }
        invokeID = (byte) value;
    }

    /**
     * @return Invoke ID.
     */
    public final long getLongInvokeID() {
        return longInvokeID;
    }

    /**
     * @param value
     *            Invoke ID.
     */
    public final void setLongInvokeID(final long value) {
        if (value < 0) {
            throw new IllegalArgumentException("Invalid InvokeID");
        }
        longInvokeID = value;
    }

    /**
     * @return Collection of the objects.
     */
    public final GXDLMSObjectCollection getObjects() {
        return objects;
    }

    /**
     * @return Is custom challenges used.
     */
    public final boolean isCustomChallenges() {
        return customChallenges;
    }

    /**
     * @param value
     *            Is custom challenges used.
     */
    public final void setUseCustomChallenge(final boolean value) {
        customChallenges = value;
    }

    public boolean isCiphered(boolean checkGeneralSigning) {
        if (cipher == null) {
            return false;
        }
        return cipher.getSecurity() != Security.NONE
                || (checkGeneralSigning && cipher.getSigning() == Signing.GENERAL_SIGNING);
    }

    /**
     * @return Source system title.
     */
    public final byte[] getSourceSystemTitle() {
        return sourceSystemTitle;
    }

    /**
     * @param value
     *            Source system title.
     */
    public final void setSourceSystemTitle(final byte[] value) {
        if (value != null && value.length != 0 && value.length != 8) {
            throw new IllegalArgumentException("Invalid client system title.");
        }
        sourceSystemTitle = value;
    }

    /**
     * @return Key Encrypting Key, also known as Master key.
     */
    public final byte[] getKek() {
        return kek;
    }

    /**
     * @param value
     *            Key Encrypting Key, also known as Master key.
     */
    public final void setKek(final byte[] value) {
        kek = value;
    }

    /**
     * @return Long data count.
     */
    public final long getCount() {
        return count;
    }

    /**
     * @param value
     *            Data count.
     */
    public final void setCount(final long value) {
        if (value < 0) {
            throw new IllegalArgumentException("Invalid count.");
        }
        count = value;
    }

    /**
     * @return Long data index.
     */
    public final long getIndex() {
        return index;
    }

    /**
     * @param value
     *            Long data index
     */
    public final void setIndex(final long value) {
        if (value < 0) {
            throw new IllegalArgumentException("Invalid Index.");
        }
        index = value;
    }

    /**
     * @return Target ephemeral public key.
     */
    public PublicKey getTargetEphemeralKey() {
        return targetEphemeralKey;
    }

    /**
     * @param value
     *            Target ephemeral public key .
     */
    public void setTargetEphemeralKey(final PublicKey value) {
        targetEphemeralKey = value;
    }

    /**
     * @return Proposed conformance block.
     */
    public Set getProposedConformance() {
        return proposedConformance;
    }

    /**
     * @param value
     *            Proposed conformance block.
     */
    public void setProposedConformance(final Set value) {
        proposedConformance = value;
    }

    /**
     * @return Server tells what functionality is available and client will know
     *         it.
     */
    public Set getNegotiatedConformance() {
        return negotiatedConformance;
    }

    /**
     * @param value
     *            Server tells what functionality is available and client will
     *            know it.
     */
    public void setNegotiatedConformance(final Set value) {
        negotiatedConformance = value;
    }

    /*
     * @param value Frame check is skipped for some unit tests.
     */
    final void setSkipFrameCheck(final boolean value) {
        skipFrameCheck = value;
    }

    /**
     * @return HDLC settings.
     */
    public GXDLMSHdlcSetup getHdlc() {
        return hdlc;
    }

    /**
     * @param value
     *            HDLC settings.
     */
    public void setHdlc(final GXDLMSHdlcSetup value) {
        hdlc = value;
    }

    /**
     * @return Wrapper settings.
     */
    public GXDLMSTcpUdpSetup getWrapper() {
        return wrapper;
    }

    /**
     * @param value
     *            Wrapper settings.
     */
    public void setWrapper(final GXDLMSTcpUdpSetup value) {
        wrapper = value;
    }

    /**
     * @return GBT window size.
     */
    public final byte getGbtWindowSize() {
        return gbtWindowSize;
    }

    /**
     * @param value
     *            GBT window size.
     */
    public final void setGbtWindowSize(final byte value) {
        gbtWindowSize = value;
    }

    /**
     * @return User id is the identifier of the user.
     */
    public final int getUserId() {
        return userId;
    }

    /**
     * @param value
     *            User id is the identifier of the user.
     */
    public final void setUserId(final int value) {
        userId = value;
    }

    /**
     * Standard says that Time zone is from normal time to UTC in minutes. If
     * meter is configured to use UTC time (UTC to normal time) set this to
     * true.
     * 
     * @return True, if UTC time is used.
     */
    public boolean getUseUtc2NormalTime() {
        return useUtc2NormalTime;
    }

    /**
     * * Standard says that Time zone is from normal time to UTC in minutes. If
     * meter is configured to use UTC time (UTC to normal time) set this to
     * true.
     * 
     * @param value
     *            True, if UTC time is used.
     */
    public void setUseUtc2NormalTime(final boolean value) {
        useUtc2NormalTime = value;
    }

    /**
     * @return Some meters expect that Invocation Counter is increased for
     *         Authentication when connection is established.
     */
    public boolean getIncreaseInvocationCounterForGMacAuthentication() {
        return increaseInvocationCounterForGMacAuthentication;
    }

    /**
     * @param value
     *            Some meters expect that Invocation Counter is increased for
     *            Authentication when connection is established.
     */
    public void setIncreaseInvocationCounterForGMacAuthentication(final boolean value) {
        increaseInvocationCounterForGMacAuthentication = value;
    }

    /**
     * @return Skipped date time fields. This value can be used if meter can't
     *         handle deviation or status.
     */
    public java.util.Set getDateTimeSkips() {
        return dateTimeSkips;
    }

    /**
     * @param value
     *            Skipped date time fields. This value can be used if meter
     *            can't handle deviation or status.
     */
    public void setDateTimeSkips(final java.util.Set value) {
        dateTimeSkips = value;
    }

    /**
     * @return Skipped date time fields on read. This value can be used if meter
     *         returns invalid deviation on read.
     */
    public java.util.Set getDateTimeSkipsOnRead() {
        return readDateTimeSkips;
    }

    /**
     * @param value
     *            Skipped date time fields on read. This value can be used if
     *            meter returns invalid deviation on read.
     */
    public void setDateTimeSkipsOnRead(final java.util.Set value) {
        readDateTimeSkips = value;
    }

    /**
     * @return Used standard.
     */
    public Standard getStandard() {
        return standard;
    }

    /**
     * @param value
     *            Used standard.
     */
    public void setStandard(final Standard value) {
        standard = value;
    }

    /**
     * @return Protocol version.
     */
    public String getProtocolVersion() {
        return protocolVersion;
    }

    /**
     * @param value
     *            Protocol version.
     */
    public void setProtocolVersion(final String value) {
        protocolVersion = value;
    }

    /**
     * @return Pre-established system title.
     */
    public byte[] getPreEstablishedSystemTitle() {
        return preEstablishedSystemTitle;
    }

    /**
     * @param value
     *            Pre-established system title.
     */
    public void setPreEstablishedSystemTitle(final byte[] value) {
        if (value != null && value.length != 8) {
            throw new IllegalArgumentException("Invalid system title.");
        }
        preEstablishedSystemTitle = value;
    }

    /**
     * @return the command
     */
    public int getCommand() {
        return command;
    }

    /**
     * @param value
     *            the command to set
     */
    public void setCommand(final int value) {
        command = value;
    }

    /**
     * @return the commandType
     */
    public byte getCommandType() {
        return commandType;
    }

    /**
     * @param value
     *            the commandType to set
     */
    public void setCommandType(final byte value) {
        commandType = value;
    }

    /**
     * @return Quality of service.
     */
    public byte getQualityOfService() {
        return qualityOfService;
    }

    /**
     * @param value
     *            Quality of service.
     */
    public void setQualityOfService(final byte value) {
        qualityOfService = value;
    }

    /**
     * @return Auto increase Invoke ID.
     */
    public final boolean getAutoIncreaseInvokeID() {
        return autoIncreaseInvokeID;
    }

    /**
     * @param value
     *            Auto increase Invoke ID.
     */
    public final void setAutoIncreaseInvokeID(final boolean value) {
        autoIncreaseInvokeID = value;
    }

    /**
     * @return The version can be used for backward compatibility.
     */
    public int getVersion() {
        return version;
    }

    /**
     * @param value
     *            The version can be used for backward compatibility.
     */
    public void setVersion(final int value) {
        if (value != 3 && value != 4) {
            throw new IllegalArgumentException("Invalid version.");
        }
        version = value;
    }

    /**
     * @return Server is using push client address when sending push messages.
     *         Client address is used if PushAddress is zero.
     */
    public int getPushClientAddress() {
        return pushClientAddress;
    }

    /**
     * @param value
     *            Server is using push client address when sending push
     *            messages. Client address is used if PushAddress is zero.
     */
    public void setPushClientAddress(final int value) {
        pushClientAddress = value;
    }

    /**
     * @return XML needs list of certificates to decrypt the data.
     */
    public List> getKeys() {
        return keys;
    }

    /**
     * @param value
     *            XML needs list of certificates to decrypt the data.
     */
    public void setKeys(final List> value) {
        keys = value;
    }

    public GXDLMSData getInvocationCounter() {
        return invocationCounter;
    }

    /**
     * @return Crypto notifier.
     */
    public IGXCryptoNotifier getCryptoNotifier() {
        return cryptoNotifier;
    }

    public Object getKey(CertificateType certificateType, byte[] systemTitle, boolean encrypt) {
        if (cryptoNotifier == null) {
            throw new RuntimeException("Failed to get the certificate.");
        }
        if (certificateType == CertificateType.DIGITAL_SIGNATURE && cipher.getSigningKeyPair() != null) {
            if (encrypt) {
                if (cipher.getSigningKeyPair().getPrivate() != null) {
                    return cipher.getSigningKeyPair().getPrivate();
                }
            } else if (cipher.getSigningKeyPair().getPublic() != null) {
                return cipher.getSigningKeyPair().getPublic();
            }
        } else if (certificateType == CertificateType.KEY_AGREEMENT && cipher.getKeyAgreementKeyPair() != null) {
            if (encrypt) {
                if (cipher.getKeyAgreementKeyPair().getPrivate() != null) {
                    return cipher.getKeyAgreementKeyPair().getPrivate();
                }
            } else if (cipher.getKeyAgreementKeyPair().getPublic() != null) {
                return cipher.getKeyAgreementKeyPair().getPublic();
            }
        }
        GXCryptoKeyParameter args = new GXCryptoKeyParameter();
        args.setEncrypt(encrypt);
        args.setSecuritySuite(cipher.getSecuritySuite());
        args.setCertificateType(certificateType);
        args.setSystemTitle(systemTitle);
        cryptoNotifier.onKey(cryptoNotifier, args);
        if (encrypt) {
            return args.getPrivateKey();
        } else {
            return args.getPublicKey();
        }
    }

    /**
     * @return Size of the challenge.
     */
    public byte getChallengeSize() {
        return challengeSize;
    }

    /**
     * @param value
     *            Size of the challenge.
     */
    public void setChallengeSize(byte value) {
        if (authentication == Authentication.HIGH_ECDSA && value < 32) {
            throw new IllegalArgumentException(
                    "Invalid challenge size. ECDSA challenge must be between 32 to 64 bytes.");
        } else if (value < 8 || value > 64) {
            throw new IllegalArgumentException("Invalid challenge size. Challenge must be between 8 to 64 bytes.");
        }
        challengeSize = value;
    }

    /**
     * @return Overwrite attribute access rights if association view tells wrong
     *         access rights and they need to be overwritten.
     */
    public final boolean getOverwriteAttributeAccessRights() {
        return overwriteAttributeAccessRights;
    }

    /**
     * @param value
     *            Overwrite attribute access rights if association view tells
     *            wrong access rights and they need to be overwritten.
     */
    public final void setOverwriteAttributeAccessRights(boolean value) {
        overwriteAttributeAccessRights = value;
    }

    /**
     * @return M-Bus settings.
     */
    public GXMBusSettings getMbus() {
        return mBus;
    }

    /**
     * @return CoAP settings.
     */
    public GXCoAPSettings getCoap() {
        return coap;
    }

    /**
     * @return Optional ECDSA public key certificate that is send in part of
     *         AARQ.
     */
    public GXx509Certificate getClientPublicKeyCertificate() {
        return clientPublicKeyCertificate;
    }

    /**
     * @param value
     *            Optional ECDSA public key certificate that is send in part of
     *            AARQ.
     */
    public void setClientPublicKeyCertificate(final GXx509Certificate value) {
        clientPublicKeyCertificate = value;
    }

    /**
     * @return Optional ECDSA public key certificate that is send in part of
     *         AARE.
     */
    public GXx509Certificate getServerPublicKeyCertificate() {
        return serverPublicKeyCertificate;
    }

    /**
     * @param value
     *            Optional ECDSA public key certificate that is send in part of
     *            AARE.
     */
    public void setServerPublicKeyCertificate(final GXx509Certificate value) {
        serverPublicKeyCertificate = value;
    }

    /**
     * @return Data is only decrypted and PDU is not parsed.
     */
    public boolean isDecryptOnly() {
        return decryptOnly;
    }

    /**
     * @param value
     *            Data is only decrypted and PDU is not parsed.
     */
    public void setDecryptOnly(final boolean value) {
        decryptOnly = value;
    }

    /**
     * @return Custom object notifier.
     */
    public IGXCustomObjectNotifier getCustomObjectNotifier() {
        return customObjectNotifier;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy