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

gurux.dlms.objects.GXDLMSAssociationShortName 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.objects;

import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.Signature;
import java.security.SignatureException;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.xml.stream.XMLStreamException;

import gurux.dlms.GXByteBuffer;
import gurux.dlms.GXDLMSClient;
import gurux.dlms.GXDLMSSettings;
import gurux.dlms.GXDLMSTranslator;
import gurux.dlms.ValueEventArgs;
import gurux.dlms.enums.AccessMode;
import gurux.dlms.enums.Authentication;
import gurux.dlms.enums.ConnectionState;
import gurux.dlms.enums.DataType;
import gurux.dlms.enums.ErrorCode;
import gurux.dlms.enums.MethodAccessMode;
import gurux.dlms.enums.ObjectType;
import gurux.dlms.internal.GXCommon;
import gurux.dlms.manufacturersettings.GXDLMSAttributeSettings;
import gurux.dlms.objects.enums.SecuritySuite;
import gurux.dlms.secure.GXSecure;

/**
 * Online help: 
* https://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSAssociationShortName */ public class GXDLMSAssociationShortName extends GXDLMSObject implements IGXDLMSBase { private static final Logger LOGGER = Logger.getLogger(GXDLMSAssociationShortName.class.getName()); private GXDLMSObjectCollection objectList; private String securitySetupReference; /** * Secret used in Authentication. */ private byte[] secret; /** * Constructor. */ public GXDLMSAssociationShortName() { this("0.0.40.0.0.255", 0xFA00); } /** * Constructor. * * @param ln * Logical Name of the object. * @param sn * Short Name of the object. */ public GXDLMSAssociationShortName(final String ln, final int sn) { super(ObjectType.ASSOCIATION_SHORT_NAME, ln, sn); objectList = new GXDLMSObjectCollection(this); setVersion(2); } /** * @return Secret used in LLS Authentication. */ public final byte[] getSecret() { return secret; } /** * @param value * Secret used in LLS Authentication. */ public final void setSecret(final byte[] value) { secret = value; } public final GXDLMSObjectCollection getObjectList() { return objectList; } public final String getSecuritySetupReference() { return securitySetupReference; } public final void setSecuritySetupReference(final String value) { securitySetupReference = value; } @Override public final Object[] getValues() { return new Object[] { getLogicalName(), getObjectList(), null, getSecuritySetupReference() }; } /* * Invokes method. * @param index Method index. */ @Override public final byte[] invoke(final GXDLMSSettings settings, final ValueEventArgs e) throws InvalidKeyException, NoSuchPaddingException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException, SignatureException { // Check reply_to_HLS_authentication if (e.getIndex() == 8) { byte[] serverChallenge = null, clientChallenge = null; long ic = 0; byte[] readSecret; boolean accept; Signature ver; if (settings.getAuthentication() == Authentication.HIGH_ECDSA) { try { GXByteBuffer signature = new GXByteBuffer((byte[]) e.getParameters()); if (settings.getCipher().getSecuritySuite() == SecuritySuite.SUITE_1) { ver = Signature.getInstance("SHA256withECDSA"); } else if (settings.getCipher().getSecuritySuite() == SecuritySuite.SUITE_2) { ver = Signature.getInstance("SHA384withECDSA"); } else { throw new IllegalArgumentException("Invalid security suite."); } ver.initVerify(settings.getCipher().getCertificates().get(0).getPublicKey()); GXByteBuffer bb = new GXByteBuffer(); bb.set(settings.getSourceSystemTitle()); bb.set(settings.getCipher().getSystemTitle()); bb.set(settings.getStoCChallenge()); bb.set(settings.getCtoSChallenge()); ver.update(bb.array()); accept = ver.verify(signature.array()); } catch (Exception ex) { throw new RuntimeException(ex.getMessage()); } } else { if (settings.getAuthentication() == Authentication.HIGH_GMAC) { readSecret = settings.getSourceSystemTitle(); GXByteBuffer bb = new GXByteBuffer((byte[]) e.getParameters()); bb.getUInt8(); ic = bb.getUInt32(); } else if (settings.getAuthentication() == Authentication.HIGH_SHA256) { GXByteBuffer tmp = new GXByteBuffer(); tmp.set(secret); tmp.set(settings.getSourceSystemTitle()); tmp.set(settings.getCipher().getSystemTitle()); tmp.set(settings.getStoCChallenge()); tmp.set(settings.getCtoSChallenge()); readSecret = tmp.array(); } else { readSecret = secret; } serverChallenge = GXSecure.secure(settings, settings.getCipher(), ic, settings.getStoCChallenge(), readSecret); clientChallenge = (byte[]) e.getParameters(); accept = GXCommon.compare(serverChallenge, clientChallenge); } if (accept) { if (settings.getAuthentication() == Authentication.HIGH_GMAC) { readSecret = settings.getCipher().getSystemTitle(); ic = settings.getCipher().getInvocationCounter(); } else { readSecret = secret; } settings.setConnected(settings.getConnected() | ConnectionState.DLMS); if (settings.getAuthentication() == Authentication.HIGH_SHA256) { GXByteBuffer tmp = new GXByteBuffer(); tmp.set(secret); tmp.set(settings.getCipher().getSystemTitle()); tmp.set(settings.getSourceSystemTitle()); tmp.set(settings.getCtoSChallenge()); tmp.set(settings.getStoCChallenge()); readSecret = tmp.array(); } return GXSecure.secure(settings, settings.getCipher(), ic, settings.getCtoSChallenge(), readSecret); } else { LOGGER.log(Level.INFO, "Invalid CtoS:" + GXCommon.toHex(serverChallenge, false) + "-" + GXCommon.toHex(clientChallenge, false)); return null; } } else { settings.setConnected(settings.getConnected() & ~ConnectionState.DLMS); e.setError(ErrorCode.READ_WRITE_DENIED); return null; } } /* * Returns collection of attributes to read. If attribute is static and * already read or device is returned HW error it is not returned. */ @Override public final int[] getAttributeIndexToRead(final boolean all) { java.util.ArrayList attributes = new java.util.ArrayList(); // LN is static and read only once. if (all || getLogicalName() == null || getLogicalName().compareTo("") == 0) { attributes.add(1); } // ObjectList is static and read only once. if (all || !isRead(2)) { attributes.add(2); } if (getVersion() > 1) { // AccessRightsList is static and read only once. if (all || !isRead(3)) { attributes.add(3); } // SecuritySetupReference is static and read only once. if (all || !isRead(4)) { attributes.add(4); } } return GXDLMSObjectHelpers.toIntArray(attributes); } @Override public final int getAttributeCount() { if (getVersion() < 2) { return 2; } return 4; } /* * Returns amount of methods. */ @Override public final int getMethodCount() { return 8; } private void getAccessRights(final GXDLMSObject item, final GXByteBuffer data) { data.setUInt8((byte) DataType.STRUCTURE.getValue()); data.setUInt8((byte) 3); GXCommon.setData(null, data, DataType.UINT16, item.getShortName()); data.setUInt8((byte) DataType.ARRAY.getValue()); data.setUInt8((byte) item.getAttributes().size()); for (GXDLMSAttributeSettings att : item.getAttributes()) { // attribute_access_item data.setUInt8((byte) DataType.STRUCTURE.getValue()); data.setUInt8((byte) 3); GXCommon.setData(null, data, DataType.INT8, att.getIndex()); GXCommon.setData(null, data, DataType.ENUM, att.getAccess().getValue()); GXCommon.setData(null, data, DataType.NONE, null); } data.setUInt8((byte) DataType.ARRAY.getValue()); data.setUInt8((byte) item.getMethodAttributes().size()); for (GXDLMSAttributeSettings it : item.getMethodAttributes()) { // attribute_access_item data.setUInt8((byte) DataType.STRUCTURE.getValue()); data.setUInt8((byte) 2); GXCommon.setData(null, data, DataType.INT8, it.getIndex()); GXCommon.setData(null, data, DataType.ENUM, it.getMethodAccess().getValue()); } } @Override public final DataType getDataType(final int index) { if (index == 1) { return DataType.OCTET_STRING; } else if (index == 2) { return DataType.ARRAY; } else if (index == 3) { return DataType.ARRAY; } else if (index == 4) { return DataType.OCTET_STRING; } throw new IllegalArgumentException("getDataType failed. Invalid attribute index."); } /** * Returns Association View. */ private byte[] getObjects(final GXDLMSSettings settings, final ValueEventArgs e) { GXByteBuffer bb = new GXByteBuffer(); int cnt = objectList.size(); // Add count only for first time. if (settings.getIndex() == 0) { settings.setCount(cnt); bb.setUInt8((byte) DataType.ARRAY.getValue()); // Add count GXCommon.setObjectCount(cnt, bb); } int pos = 0; if (cnt != 0) { for (GXDLMSObject it : objectList) { ++pos; if (!(pos <= settings.getIndex())) { bb.setUInt8((byte) DataType.STRUCTURE.getValue()); // Count bb.setUInt8((byte) 4); // base address. GXCommon.setData(null, bb, DataType.INT16, it.getShortName()); // ClassID GXCommon.setData(null, bb, DataType.UINT16, it.getObjectType().getValue()); // Version GXCommon.setData(null, bb, DataType.UINT8, 0); // LN GXCommon.setData(null, bb, DataType.OCTET_STRING, GXCommon.logicalNameToBytes(it.getLogicalName())); settings.setIndex(settings.getIndex() + 1); if (settings.isServer()) { // If PDU is full. if (!e.isSkipMaxPduSize() && bb.size() >= settings.getMaxPduSize()) { break; } } } } } return bb.array(); } /* * Returns value of given attribute. */ @Override public final Object getValue(final GXDLMSSettings settings, final ValueEventArgs e) { GXByteBuffer bb = new GXByteBuffer(); if (e.getIndex() == 1) { return GXCommon.logicalNameToBytes(getLogicalName()); } else if (e.getIndex() == 2) { return getObjects(settings, e); } else if (e.getIndex() == 3) { boolean lnExists = objectList.findBySN(this.getShortName()) != null; // Add count int cnt = objectList.size(); if (!lnExists) { ++cnt; } bb.setUInt8(DataType.ARRAY.getValue()); GXCommon.setObjectCount(cnt, bb); for (GXDLMSObject it : objectList) { getAccessRights(it, bb); } if (!lnExists) { getAccessRights(this, bb); } return bb.array(); } else if (e.getIndex() == 4) { return GXCommon.getBytes(securitySetupReference); } e.setError(ErrorCode.READ_WRITE_DENIED); return null; } final void updateAccessRights(final List buff) { for (Object access : buff) { List arr = (List) access; int sn = ((Number) arr.get(0)).intValue(); GXDLMSObject obj = objectList.findBySN(sn); if (obj != null) { for (Object attributeAccess : (List) arr.get(1)) { List arr1 = (List) attributeAccess; int id = ((Number) arr1.get(0)).intValue(); int tmp = ((Number) arr1.get(1)).intValue(); AccessMode mode = AccessMode.forValue(tmp); obj.setAccess(id, mode); } for (Object methodAccess : (List) arr.get(2)) { List arr1 = (List) methodAccess; int id = ((Number) arr1.get(0)).intValue(); int tmp = ((Number) arr1.get(1)).intValue(); MethodAccessMode mode = MethodAccessMode.forValue(tmp); obj.setMethodAccess(id, mode); } } } } /* * Set value of given attribute. */ @Override public final void setValue(final GXDLMSSettings settings, final ValueEventArgs e) { if (e.getIndex() == 1) { setLogicalName(GXCommon.toLogicalName(e.getValue())); } else if (e.getIndex() == 2) { objectList.clear(); if (e.getValue() != null) { for (Object item : (List) e.getValue()) { List arr = (List) item; int sn = ((Number) arr.get(0)).intValue() & 0xFFFF; ObjectType type = ObjectType.forValue(((Number) arr.get(1)).intValue()); int version = ((Number) arr.get(2)).intValue(); String ln = GXCommon.toLogicalName((byte[]) arr.get(3)); GXDLMSObject obj = GXDLMSClient.createObject(type); obj.setLogicalName(ln); obj.setShortName(sn); obj.setVersion(version); objectList.add(obj); } } } else if (e.getIndex() == 3) { if (e.getValue() == null) { for (GXDLMSObject it : objectList) { for (int pos = 1; pos != it.getAttributeCount(); ++pos) { it.setAccess(pos, AccessMode.NO_ACCESS); } } } else { updateAccessRights((List) e.getValue()); } } else if (e.getIndex() == 4) { if (e.getValue() instanceof String) { securitySetupReference = e.getValue().toString(); } else if (e.getValue() != null) { securitySetupReference = new String((byte[]) e.getValue()); } } else { e.setError(ErrorCode.READ_WRITE_DENIED); } } @Override public final void load(final GXXmlReader reader) throws XMLStreamException { String str = reader.readElementContentAsString("Secret"); if (str == null) { secret = null; } else { secret = GXDLMSTranslator.hexToBytes(str); } securitySetupReference = reader.readElementContentAsString("SecuritySetupReference"); } @Override public final void save(final GXXmlWriter writer) throws XMLStreamException { writer.writeElementString("Secret", GXDLMSTranslator.toHex(secret)); writer.writeElementString("SecuritySetupReference", securitySetupReference); } @Override public final void postLoad(final GXXmlReader reader) { } @Override public String[] getNames() { if (version < 2) { return new String[] { "Logical Name", "Object List" }; } return new String[] { "Logical Name", "Object List", "Access Rights List", "Security Setup Reference" }; } @Override public String[] getMethodNames() { return new String[] { "Getlist by classid", "Getobj by logicalname", "Read by logicalname", "Get attributes&services", "Change LLS secret", "Change HLS secret", "Get HLS challenge", "Reply to HLS challenge", "Add user", "Remove user" }; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy