Hi, I am using meter, which is not on manufacturers (ZPA meter) list, so I added it manually. It uses HighGMAC with keys and certs. I really struggled to make it connect with the meter by GXDLMSDirector app, but I somehow managed to make it work. But after I tried it with python code, it's unable to read anything and disconnects with "Connection is permanently rejected"/"No reason is given.". Below is data after launching python code:
gurux_dlms version: 1.0.173
gurux_net version: 1.0.19
gurux_serial version: 1.0.20
Authentication: 5
ClientAddress: 0x1
ServerAddress: 0x1
Standard: 0
Security: 48
System title: 43 54 54 30 30 30 30 30
Authentication key: xxx
Block cipher key: xxx
TX: 08:11:59 00 01 00 10 00 01 00 1F 60 1D A1 09 06 07 60 85 74 05 08 01 01 BE 10 04 0E 01 00 00 00 06 5F 1F 04 00 40 7E 1D FF FF
Data length is 43and there are 44 bytes.
RX: 08:12:00 00 01 00 01 00 10 00 2B 61 29 A1 09 06 07 60 85 74 05 08 01 01 A2 03 02 01 00 A3 05 A1 03 02 01 00 BE 10 04 0E 08 00 06 5F 1F 04 00 00 3C 1D 07 D0 00 07 00
TX: 08:12:00 00 01 00 10 00 01 00 0D C0 01 C1 00 01 00 00 2B 01 01 FF 02 00
Data length is 9and there are 10 bytes.
RX: 08:12:01 00 01 00 01 00 10 00 09 C4 01 C1 00 06 00 02 8F A9 00
Invocation counter: 167850
DisconnectRequest
TX: 08:12:01 00 01 00 10 00 01 00 09 62 03 80 01 00 03 80 01 00
Data length is 5and there are 6 bytes.
RX: 08:12:02 00 01 00 01 00 10 00 05 63 03 80 01 00 00
TX: 08:12:02 00 01 00 01 00 01 00 5F 60 5D A1 09 06 07 60 85 74 05 08 01 03 A6 0A 04 08 43 54 54 30 30 30 30 30 8A 02 07 80 8B 07 60 85 74 05 08 02 05 AC 12 80 10 29 E6 F0 D6 58 5B 41 76 F1 17 CF EE 84 7F 8A 34 BE 23 04 21 21 1F 30 00 02 8F AA 1B 03 BA 06 9B 43 C2 6F A9 2D 73 9D 9C 45 54 CD CA 95 D5 A1 BC 86 2E C6 55 43
Data length is 107and there are 108 bytes.
RX: 08:12:03 00 01 00 01 00 01 00 6B 61 69 A1 09 06 07 60 85 74 05 08 01 03 A2 03 02 01 00 A3 05 A1 03 02 01 0E A4 0A 04 08 5A 50 41 00 3B 9C 25 32 88 02 07 80 89 07 60 85 74 05 08 02 05 AA 12 80 10 32 89 D6 2E 4E C5 B2 90 6A B4 A5 4D 2E 80 39 AF BE 23 04 21 28 1F 32 00 02 98 A7 E2 FF A4 FA 91 27 8E B1 9C F5 DB E7 5D 2E 9C AB 7B 16 3A 3F DF B6 50 CB 02 34 00
DisconnectRequest
Connection is permanently rejected
No reason is given.
Ended. Press any key to continue.
And below is this data, but translated:
1) 00 01 00 10 00 01 00 1F 60 1D A1 09 06 07 60 85 74 05 08 01 01 BE 10 04 0E 01 00 00 00 06 5F 1F 04 00 40 7E 1D FF FF
2) 00 01 00 01 00 10 00 2B 61 29 A1 09 06 07 60 85 74 05 08 01 01 A2 03 02 01 00 A3 05 A1 03 02 01 00 BE 10 04 0E 08 00 06 5F 1F 04 00 00 3C 1D 07 D0 00 07 00
TRANSLATE:
1: 00 01 00 10 00 01 00 1F 60 1D A1 09 06 07 60 85 74 05 08 01 01 BE 10 04 0E 01 00 00 00 06 5F 1F 04 00 40 7E 1D FF FF
<WRAPPER len="1F" >
<SourceAddress Value="10" />
<TargetAddress Value="1" />
<PDU>
<AssociationRequest>
<ApplicationContextName Value="LN" />
<InitiateRequest>
<ProposedDlmsVersionNumber Value="06" />
<ProposedConformance>
<ConformanceBit Name="GeneralProtection" />
<ConformanceBit Name="PriorityMgmtSupported" />
<ConformanceBit Name="Attribute0SupportedWithGet" />
<ConformanceBit Name="BlockTransferWithGetOrRead" />
<ConformanceBit Name="BlockTransferWithSetOrWrite" />
<ConformanceBit Name="BlockTransferWithAction" />
<ConformanceBit Name="MultipleReferences" />
<ConformanceBit Name="Get" />
<ConformanceBit Name="Set" />
<ConformanceBit Name="SelectiveAccess" />
<ConformanceBit Name="Action" />
</ProposedConformance>
<ProposedMaxPduSize Value="FFFF" />
</InitiateRequest>
</AssociationRequest>
</PDU>
</WRAPPER>
2: 00 01 00 01 00 10 00 2B 61 29 A1 09 06 07 60 85 74 05 08 01 01 A2 03 02 01 00 A3 05 A1 03 02 01 00 BE 10 04 0E 08 00 06 5F 1F 04 00 00 3C 1D 07 D0 00 07
<WRAPPER len="2B" >
<SourceAddress Value="1" />
<TargetAddress Value="10" />
<PDU>
<AssociationResponse>
<ApplicationContextName Value="LN" />
<AssociationResult Value="00" />
<ResultSourceDiagnostic>
<ACSEServiceUser Value="00" />
</ResultSourceDiagnostic>
<InitiateResponse>
<NegotiatedDlmsVersionNumber Value="06" />
<NegotiatedConformance>
<ConformanceBit Name="Attribute0SupportedWithGet" />
<ConformanceBit Name="BlockTransferWithGetOrRead" />
<ConformanceBit Name="BlockTransferWithSetOrWrite" />
<ConformanceBit Name="BlockTransferWithAction" />
<ConformanceBit Name="Get" />
<ConformanceBit Name="Set" />
<ConformanceBit Name="SelectiveAccess" />
<ConformanceBit Name="Action" />
</NegotiatedConformance>
<NegotiatedMaxPduSize Value="07D0" />
<VaaName Value="0007" />
</InitiateResponse>
</AssociationResponse>
</PDU>
</WRAPPER>
1) 00 01 00 10 00 01 00 0D C0 01 C1 00 01 00 00 2B 01 01 FF 02 00
2) 00 01 00 01 00 10 00 09 C4 01 C1 00 06 00 02 8F A9 00
TRANSLATED:
1: 00 01 00 10 00 01 00 0D C0 01 C1 00 01 00 00 2B 01 01 FF 02 00
<WRAPPER len="D" >
<SourceAddress Value="10" />
<TargetAddress Value="1" />
<PDU>
<GetRequest>
<GetRequestNormal>
<!-- Priority: High, ServiceClass: Confirmed, Invoke ID: 1 -->
<InvokeIdAndPriority Value="C1" />
<AttributeDescriptor>
<!-- Data -->
<ClassId Value="0001" />
<!-- 0.0.43.1.1.255 -->
<InstanceId Value="00002B0101FF" />
<!-- Value -->
<AttributeId Value="02" />
</AttributeDescriptor>
</GetRequestNormal>
</GetRequest>
</PDU>
</WRAPPER>
2: 00 01 00 01 00 10 00 09 C4 01 C1 00 06 00 02 8F A9
<WRAPPER len="9" >
<SourceAddress Value="1" />
<TargetAddress Value="10" />
<PDU>
<GetResponse>
<GetResponseNormal>
<!-- Priority: High, ServiceClass: Confirmed, Invoke ID: 1 -->
<InvokeIdAndPriority Value="C1" />
<Result>
<Data>
<UInt32 Value="00028FA9" />
</Data>
</Result>
</GetResponseNormal>
</GetResponse>
</PDU>
</WRAPPER>
1) 00 01 00 10 00 01 00 09 62 03 80 01 00 03 80 01 00
2) 00 01 00 01 00 10 00 05 63 03 80 01 00 00
TRANSLATED:
1: 00 01 00 10 00 01 00 09 62 03 80 01 00 03 80 01 00
<WRAPPER len="9" >
<SourceAddress Value="10" />
<TargetAddress Value="1" />
<PDU>
<ReleaseRequest>
<Reason Value="Normal" />
</ReleaseRequest>
</PDU>
</WRAPPER>
2: 00 01 00 01 00 10 00 05 63 03 80 01 00
<WRAPPER len="5" >
<SourceAddress Value="1" />
<TargetAddress Value="10" />
<PDU>
<ReleaseResponse>
<Reason Value="Normal" />
</ReleaseResponse>
</PDU>
</WRAPPER>
1) 00 01 00 01 00 01 00 5F 60 5D A1 09 06 07 60 85 74 05 08 01 03 A6 0A 04 08 43 54 54 30 30 30 30 30 8A 02 07 80 8B 07 60 85 74 05 08 02 05 AC 12 80 10 29 E6 F0 D6 58 5B 41 76 F1 17 CF EE 84 7F 8A 34 BE 23 04 21 21 1F 30 00 02 8F AA 1B 03 BA 06 9B 43 C2 6F A9 2D 73 9D 9C 45 54 CD CA 95 D5 A1 BC 86 2E C6 55 43
2) 00 01 00 01 00 01 00 6B 61 69 A1 09 06 07 60 85 74 05 08 01 03 A2 03 02 01 00 A3 05 A1 03 02 01 0E A4 0A 04 08 5A 50 41 00 3B 9C 25 32 88 02 07 80 89 07 60 85 74 05 08 02 05 AA 12 80 10 32 89 D6 2E 4E C5 B2 90 6A B4 A5 4D 2E 80 39 AF BE 23 04 21 28 1F 32 00 02 98 A7 E2 FF A4 FA 91 27 8E B1 9C F5 DB E7 5D 2E 9C AB 7B 16 3A 3F DF B6 50 CB 02 34 00
TRANSLATED:
1: 00 01 00 01 00 01 00 5F 60 5D A1 09 06 07 60 85 74 05 08 01 03 A6 0A 04 08 43 54 54 30 30 30 30 30 8A 02 07 80 8B 07 60 85 74 05 08 02 05 AC 12 80 10 29 E6 F0 D6 58 5B 41 76 F1 17 CF EE 84 7F 8A 34 BE 23 04 21 21 1F 30 00 02 8F AA 1B 03 BA 06 9B 43 C2 6F A9 2D 73 9D 9C 45 54 CD CA 95 D5 A1 BC 86 2E C6 55 43
<WRAPPER len="E" >
<SourceAddress Value="1" />
<TargetAddress Value="1" />
<PDU>
<AssociationRequest>
<ApplicationContextName Value="LN_WITH_CIPHERING" />
<CallingAPTitle Value="4354543030303030" />
<SenderACSERequirements Value="1" />
<MechanismName Value="HighGMAC" />
<CallingAuthentication Value="29E6F0D6585B4176F117CFEE847F8A34" />
<!-- Decrypted data:
Security: AuthenticationEncryption
Invocation Counter: 167850
<InitiateRequest>
<ProposedDlmsVersionNumber Value="06" />
<ProposedConformance>
<ConformanceBit Name="GeneralProtection" />
<ConformanceBit Name="PriorityMgmtSupported" />
<ConformanceBit Name="Attribute0SupportedWithGet" />
<ConformanceBit Name="BlockTransferWithGetOrRead" />
<ConformanceBit Name="BlockTransferWithSetOrWrite" />
<ConformanceBit Name="BlockTransferWithAction" />
<ConformanceBit Name="MultipleReferences" />
<ConformanceBit Name="Get" />
<ConformanceBit Name="Set" />
<ConformanceBit Name="SelectiveAccess" />
<ConformanceBit Name="Action" />
</ProposedConformance>
<ProposedMaxPduSize Value="FFFF" />
</InitiateRequest>
-->
<glo_InitiateRequest Value="3000028FAA1B03BA069B43C26FA92D739D9C4554CDCA95D5A1BC862EC65543" />
</AssociationRequest>
</PDU>
</WRAPPER>
2: 00 01 00 01 00 01 00 6B 61 69 A1 09 06 07 60 85 74 05 08 01 03 A2 03 02 01 00 A3 05 A1 03 02 01 0E A4 0A 04 08 5A 50 41 00 3B 9C 25 32 88 02 07 80 89 07 60 85 74 05 08 02 05 AA 12 80 10 32 89 D6 2E 4E C5 B2 90 6A B4 A5 4D 2E 80 39 AF BE 23 04 21 28 1F 32 00 02 98 A7 E2 FF A4 FA 91 27 8E B1 9C F5 DB E7 5D 2E 9C AB 7B 16 3A 3F DF B6 50 CB 02 34
<WRAPPER len="E" >
<SourceAddress Value="1" />
<TargetAddress Value="1" />
<PDU>
<AssociationResponse>
<ApplicationContextName Value="LN_WITH_CIPHERING" />
<AssociationResult Value="00" />
<ResultSourceDiagnostic>
<!-- AuthenticationRequired -->
<ACSEServiceUser Value="0E" />
</ResultSourceDiagnostic>
<!-- DLMS system title:
Manufacturer Code: ZPA
Serial number: 10233138
-->
<RespondingAPTitle Value="5A5041003B9C2532" />
<ResponderACSERequirement Value="1" />
<MechanismName Value="HighGMAC" />
<RespondingAuthentication Value="3289D62E4EC5B2906AB4A54D2E8039AF" />
<!-- Decrypted data:
Security: AuthenticationEncryption
Invocation Counter: 170151
<InitiateResponse>
<NegotiatedDlmsVersionNumber Value="06" />
<NegotiatedConformance>
<ConformanceBit Name="Attribute0SupportedWithGet" />
<ConformanceBit Name="BlockTransferWithGetOrRead" />
<ConformanceBit Name="BlockTransferWithSetOrWrite" />
<ConformanceBit Name="BlockTransferWithAction" />
<ConformanceBit Name="Get" />
<ConformanceBit Name="Set" />
<ConformanceBit Name="SelectiveAccess" />
<ConformanceBit Name="Action" />
</NegotiatedConformance>
<NegotiatedMaxPduSize Value="07D0" />
<VaaName Value="0007" />
</InitiateResponse>
-->
<glo_InitiateResponse Value="32000298A7E2FFA4FA91278EB19CF5DBE75D2E9CAB7B163A3FDFB650CB0234" />
</AssociationResponse>
</PDU>
</WRAPPER>
So, how to make it work with python? I used same values in both python and GXDLMSDirector.
Also - how can I import certificates/keys in python code? I saw there's something like "self.certificates = []" and "self.publicKeys = []" - should I just put path to key/cert in array? My python code is below (it's just slightly changed GXSettings.py file, running main.py makes it work like passing flags in cmd):
def getParameters(self, args):
parameters = GXSettings.__getParameters(args, "h:p:c:s:r:i:It:a:p:P:g:S:n:C:v:o:T:A:B:D:d:l:W:w:f:L:M:")
self.client.useLogicalNameReferencing = True
self.client.interfaceType = InterfaceType.WRAPPER
self.trace = TraceLevel.VERBOSE
self.client.authentication = Authentication.HIGH_GMAC
self.client.ciphering.security = Security.AUTHENTICATION_ENCRYPTION
self.client.standard = Standard.DLMS
self.media = GXNet(NetworkType.TCP, "IP_is_here", 4058)
self.media.port = int(4058)
self.client.password = "xxx"
self.invocationCounter = "0.0.43.1.1.255"
GXDLMSObject.validateLogicalName(self.invocationCounter)
self.client.ciphering.systemTitle = GXByteBuffer.hexToBytes("4354543030303030")
self.client.ciphering.authenticationKey = GXByteBuffer.hexToBytes("xxx")
self.client.ciphering.blockCipherKey = GXByteBuffer.hexToBytes("xxx")
self.client.clientAddress = int(1)
self.client.serverAddress = int(1)
self.client.manufacturerId = "ZPA"
self.serviceClass = ServiceClass.CONFIRMED
self.priority = Priority.HIGH
self.userId = 0
self.maxPduSize = int(2000)
self.securitySuite = SecuritySuite.SUITE_2
self.publicKeys = []
self.certificates = []
self.encrypt = True
self.encrypted = True
self.client.proposedConformance = Conformance.ACTION | Conformance.SELECTIVE_ACCESS | Conformance.SET | Conformance.GET | Conformance.MULTIPLE_REFERENCES | Conformance.BLOCK_TRANSFER_WITH_ACTION | Conformance.BLOCK_TRANSFER_WITH_SET_OR_WRITE | Conformance.BLOCK_TRANSFER_WITH_GET_OR_READ | Conformance.ATTRIBUTE_0_SUPPORTED_WITH_GET | Conformance.ACCESS
if not self.media:
GXSettings.showHelp()
return 1
return 0
Also, I have access to the following keys/certificates:
-LLS Password/HLS secret
-global encryption key
-authentication key
-key encryption key
-meter signing certificate (DER format HEX)
-private signing key (hex)
-client signing certificate (DER format HEX)
Working settings in GXDLMSDirector are on image: https://ibb.co/nMzGddwR
Hi, The connection fails…
Hi,
The connection fails because Python currently does not support security suite 2.
BR,
Mikko
Hi, thanks for response!…
Hi,
thanks for response! Will it work with python someday, too? Does suite2 work with java or C? Thanks!
Hi, Yes, it's coming to…
Hi,
Yes, it's coming to Python, but I don't know the release day yet.
ANSI C is supporting Security Suite 2 with GMAC, put the ECDSA is not supported.
Java is supporting Security Suite 2.
BR,
Mikko