DLMS security basics

This page shortly describes the basic concepts of the DLMS/COSEM access and transfer security. It is certainly very incomplete and somewhat over simplified. The definitive reference about the COSEM/DLMS security remains the '''colored books''  (Green Book, Blue Book) of the DLMS User Association.

Two kinds of security: access security and transport security

Access security concerns the rights of a client (for example an application running on a PC) to access to data stored in a given server (for example an electricity meter).

Transport security concerns the ''ciphering'' applied to the information exchanged between the server and the client.

Access security: the association request

In COSEM the access security is implemented by the AssociationRequest/AssociationResponse exchange. The client and the server are identified (to each other) by their addresses and they negotiate an authentication context. The member AssociationRequest.MechanismName specifies the security level that the client uses to access the server. There are several possible values:

  • Lowest level security: this is in fact ''no security'' at all.
  • Low Level security: the client has to provide a valid password
  • High Level security: the client and the server have to identify themselves using a 4 passes process.

If the client doesn't specify a MechanismName then the security level is Lowest level security  which is indeed no security at all. This kind of association is always available to the public client (client address = 16) when accessing the management logical device (logical device address = 1):

<AssociationRequest>
  <ApplicationContextName Value="LN" />
  <InitiateRequest>
    <ProposedDlmsVersionNumber Value="06" />
    <ProposedConformance>
      <ConformanceBit Name="Action" />
      <ConformanceBit Name="Set" />
      <ConformanceBit Name="Get" />
    </ProposedConformance>
    <ProposedMaxPduSize Value="FFFF" />
  </InitiateRequest>
</AssociationRequest>

Within this association, the public client has the right to read only a subset of the data, including the object-list.

If a client needs more rights (for example a hand-held device), it has to establish an association using low level security, with a password in the  CallingAuthentication member. In the following example, the password is the (visible) string "ABCDEFGH" encoded in hex as  "4142434445464748".

<AssociationRequest>
  <ApplicationContextName Value="LN" />
  <SenderACSERequirements Value="1" />
  <MechanismName Value="LOW_SECURITY" />
  <CallingAuthenticationValue Value="4142424445464748" />
  <InitiateRequest>
    <ProposedDlmsVersionNumber Value="06" />
    <ProposedConformance>
      <ConformanceBit Name="Action" />
      <ConformanceBit Name="SelectiveAccess" />
      <ConformanceBit Name="Set" />
      <ConformanceBit Name="Get" />
      <ConformanceBit Name="MultipleReferences" />
      <ConformanceBit Name="BlockTransferWithAction" />
      <ConformanceBit Name="BlockTransferWithSetOrWrite" />
      <ConformanceBit Name="BlockTransferWithGetOrRead" />
    </ProposedConformance>
    <ProposedMaxPduSize Value="FFFF" />
  </InitiateRequest>
</AssociationRequest>

Finally, a remote client (for example a head end system) may require a high level security mechanism. HLS requires that both the client and the server mutually authenticate each other. This is a 4 passes process. The algorithm used during the authentication depends on the MechanismName. For example, the HIGH_SECURITY_SHA1 variant goes as follows:

During the first phase, the client sends an association request with a client-to-server challenge (a random string) in the CallingAuthenticationValue member:

<AssociationRequest>
  <ApplicationContextName Value="LN" />
  <SenderACSERequirements Value="1" />
  <MechanismName Value="HIGH_SECURITY_SHA1" />
  <CallingAuthenticationValue Value="3132333435363738" />
  <InitiateRequest>
    <ProposedDlmsVersionNumber Value="06" />
    <ProposedConformance>
      <ConformanceBit Name="Action" />
      <ConformanceBit Name="EventNotification" />
      <ConformanceBit Name="SelectiveAccess" />
      <ConformanceBit Name="Set" />
      <ConformanceBit Name="Get" />
      <ConformanceBit Name="MultipleReferences" />
      <ConformanceBit Name="BlockTransferWithAction" />
      <ConformanceBit Name="BlockTransferWithSetOrWrite" />
      <ConformanceBit Name="BlockTransferWithGetOrRead" />
      <ConformanceBit Name="Attribute0SupportedWithGet" />
      <ConformanceBit Name="PriorityMgmtSupported" />
      <ConformanceBit Name="Attribute0SupportedWithSet" />
    </ProposedConformance>
    <ProposedMaxPduSize Value="FFFF" />
  </InitiateRequest>
</AssociationRequest>

The server accepts the association (AssociationResult = 0), tells that the association is not yet completed (ACSEServiceUser = 14, (more authentication-required) and provides a server-to-client challenge in the RespondingAuthenticationValue member:

<AssociationResponse>
  <ApplicationContextName Value="LN" />
  <AssociationResult Value="00" />
  <ResultSourceDiagnostic>
    <ACSEServiceUser Value="0E" />
  </ResultSourceDiagnostic>
  <ResponderACSERequirement Value="1" />
  <MechanismName Value="HIGH_SECURITY_SHA1" />
  <RespondingAuthenticationValue Value="AA0237C0D76C1245" />
  <InitiateResponse>
    <NegotiatedDlmsVersionNumber Value="06" />
    <NegotiatedConformance>
      <ConformanceBit Name="Action" />
      <ConformanceBit Name="EventNotification" />
      <ConformanceBit Name="SelectiveAccess" />
      <ConformanceBit Name="Set" />
      <ConformanceBit Name="Get" />
      <ConformanceBit Name="MultipleReferences" />
      <ConformanceBit Name="BlockTransferWithAction" />
      <ConformanceBit Name="BlockTransferWithSetOrWrite" />
      <ConformanceBit Name="BlockTransferWithGetOrRead" />
    </NegotiatedConformance>
    <NegotiatedMaxPduSize Value="05DC" />
    <VaaName Value="0007" />
  </InitiateResponse>
</AssociationResponse>

Then, both the client and the server process the remote challenge. With HIGH_SECURITY_SHA1, the received challenge is first appended to a shared secret and the resulting concatenation is passed through SHA1, the resulting hash-value is a 20 octets string.

The client sends its hash-value to the server using an ActionRequest to the method reply_to_hls_authentication (MethodId = 1) of the association object (ClassId = 15, InstanceId = 0000280000FF)

<ActionRequest>
  <ActionRequestNormal>
    <InvokeIdAndPriority Value="C1" />
    <MethodDescriptor>
      <ClassId Value="000F" />
      <InstanceId Value="0000280000FF" />
      <MethodId Value="01" />
    </MethodDescriptor>
    <MethodInvocationParameters>
      <OctetString Value="6414B618391E0A60C631D90711C9599A850C0AFB" />
    </MethodInvocationParameters>
  </ActionRequestNormal>
</ActionRequest>

If the received hash-value is correct, then the client is authenticated. The server responds with its own hash-value:

<ActionResponse>
  <ActionResponseNormal>
    <InvokeIdAndPriority Value="C1" />
    <Result Value="Success" />
    <ReturnParameters>
      <Data>
        <OctetString Value="23DC6C136051CEED56C04C00BA7C814B3802D556" />
      </Data>
    </ReturnParameters>
  </ActionResponseNormal>
</ActionResponse>

The client checks the returned hash-value and if correct, accepts the server authentication.

Transport security: plain services and glo_ services

The transport security is achieved by using ciphered COSEM services (glo_...services) instead of plain COSEM services.

All the plain COSEM services (ReadRequest, GetRequest, ReadResponse, WriteResponse, etc...) have a matching ciphered variant (glo_ReadRequest, glo_GetRequest, glo_ReadResponse, glo_WriteResponse, etc...).

Ciphered services can only be used within a ciphered application context established by an AssociationRequest ''with ciphering'', for example:

<AssociationRequest>
  <ApplicationContextName Value="LN_WITH_CIPHERING" />
  ..........
  ..........
</AssociationRequest>

The step by step procedure to perform a GetRequest using glo_ services goes as follows:

1 - Convert the plain xml to APDU

We start with a plain GetRequest:

<GetRequest>
  <GetRequestNormal>
    <InvokeIdAndPriority Value="C1" />
    <AttributeDescriptor>
      <ClassId Value="0001" />
      <InstanceId Value="0000600101FF" />
      <AttributeId Value="01" />
    </AttributeDescriptor>
  </GetRequestNormal>
</GetRequest>

The corresponding APDU is:

C001C100010000600101FF0200

2 - Cipher the APDU

The COSEM/DLMS symmetric key security system uses the  Gallois Counter Mode with AES-128 algorithm. The ciphering procedure has 6 inputs and delivers one output. The inputs are:

  • An APDU
  • A global encryption key, 16 bytes
  • An authentication key, 16 bytes
  • The system-title of the system that does the ciphering. The system-title is a 8 octets value that completely identifies a partner of the communication. In COSEM, the first 3 octets of the system-title hold the three-letters manufacturer ID. The remainder of the system title holds for example a serial number. When establishing an association with a ciphered context, the AssociationRequest communicates the sender system-title to the other party using the CallingAPTitle member. Similarly, the responder returns its system-title in the RespondingAPTitle member.
  • A security control parameter holding the kind of ciphering requested. There are 3 variants: Authentication only, Encryption only and Authentication and Encryption. With Authentication only, the ciphered frame contains the plain APDU together with an authentication tag. With Encryption only, the ciphered frame only contains the the encrypted APDU. Finally, with Authentication and Encryption, the ciphered frame contains the encrypted APDU and an authentication tag.
  • A frame-counter. The ciphering algorithm requires a ''nonce'', i.e. (more or less) a value that must be different in each invocation of the algorithm. In COSEM, the nonce consists of a fixed part and a variable part: the frame-counter. It is a 32 bits unsigned integer that grows at each invocation of the algorithm so that the output of the ciphering procedure is always different even for the same input APDU. This mechanism allows the receiver to verify that successive received ciphered frames have increasing values of the frame-counter and are not ''replayed''.
  • The ciphering procedure outputs the ciphered frame of the original APDU.

3000000001345E30E4BB901D8B819EEE779CCD90BDEFFB98AE45BAFF7A3A

3 - Create the glo_ service

The ciphered frame is the payload of a glo_GetRequest:

<glo_GetRequest Value="3000000001345E30E4BB901D8B819EEE779CCD90BDEFFB98AE45BAFF7A3A" />

4 - Convert to APDU and transmit to the other side, using HDLC or WRAPPER

 Here is the glo_ service APDU:

C81E3000000001345E30E4BB901D8B819EEE779CCD90BDEFFB98AE45BAFF7A3A 

4 - Receive the response APDU

CC1D300000010C90F4DD67EA06CE1207E2F85BBC9375E2F14CEDC8F39393D4

5 - Convert to xml to have the glo_ service

 <glo_GetResponse Value="300000010C90F4DD67EA06CE1207E2F85BBC9375E2F14CEDC8F39393D4" />

6 - Extract the embedded ciphered frame

300000010C90F4DD67EA06CE1207E2F85BBC9375E2F14CEDC8F39393D4

7 - Decipher to a GetResponse APDU

The deciphering procedure has 4 parameters:

  • A ciphered frame
  • A global encryption key, 16 bytes
  • An authentication key, 16 bytes
  • The system-title of the sending system. The output is either an APDU of a COSEM service or ''FAILED'' when the ciphered PDU contains an authentication tag that cannot be verified.
  • The output is a plain APDU :

C401C10009060000600101FF

7 - Convert the plain APDU to xml

<GetResponse>
  <GetResponsenormal>
    <InvokeIdAndPriority Value="C1" />
    <Result>
      <Data>
        <OctetString Value="0000600101FF" />
      </Data>
    </Result>
  </GetResponsenormal>
</GetResponse>