<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Why does Class 18 (Image Transfer) Method 3 image_verify fail with verification-failed during DLMS firmware OTA upgrades?]]></title><description><![CDATA[<blockquote>
<p dir="auto">[!WARNING]<br />
<strong>Technical Redaction &amp; Safe Harbor Notice</strong>:<br />
All communication captures, system titles, and cryptographic parameters in this thread have been sanitized and neutralized. Real utility meter identifiers, production encryption keys (GUEK/GAK/MK), SIM IMSIs, and proprietary network envelopes have been substituted with standard IEC 62056 synthetic test vectors. Do not post unredacted production captures or live cryptographic keys.</p>
</blockquote>
<p dir="auto">We are implementing secure over-the-air (OTA) firmware upgrade for polyphase meters over IEC 62056-47 TCP Wrapper using Interface Class 18 (<code>Image Transfer</code>, OBIS <code>0.0.44.0.0.255</code>).</p>
<p dir="auto">The firmware binary is 196 KB, divided into 980 blocks of 200 bytes each. The entire transfer lifecycle proceeds as follows:</p>
<ol>
<li><code>Method 1 (image_initiate)</code> succeeds (<code>image_transfer_status = 1: initiated</code>);</li>
<li>All 980 blocks are transferred sequentially via <code>Method 2 (image_block_transfer)</code>;</li>
<li>Attribute 3 <code>image_transferred_blocks_status</code> reports all bits set to <code>1</code> (100% received);</li>
<li>Attribute 4 <code>image_first_not_transferred_block_number</code> equals 980.</li>
</ol>
<p dir="auto">However, when our HES client executes <strong>Method 3 (<code>image_verify</code>)</strong> passing the 64-byte ECDSA P-256 digital signature, the meter's background verification task finishes with <strong><code>image_transfer_status = 4: verification_failed</code></strong>!</p>
<p dir="auto">Here is the <code>image_verify</code> Action-Request:</p>
<pre><code class="language-hex">00 01 00 01 00 01 00 4F C3 01 C1 00 12 00 00 2C 00 00 FF 03 01 09 40 4A 1B 88 22 91 04 FF 12 33 AA 01 C0 01 C1 00 07 01 00 63 01 00 FF 02 00 77 1B C0 44 88 F0 1A 2B 3C 4D 55 66 77 88 99 AA BB CC DD EE FF 00 11 22 33 44 55 66 77 88 99
</code></pre>
<p dir="auto">Why is ECDSA signature verification failing on 100% transferred images?</p>
]]></description><link>https://dlms.sharur.org/topic/57/why-does-class-18-image-transfer-method-3-image_verify-fail-with-verification-failed-during-dlms-firmware-ota-upgrades</link><generator>RSS for Node</generator><lastBuildDate>Fri, 16 Oct 2026 19:26:01 GMT</lastBuildDate><atom:link href="https://dlms.sharur.org/topic/57.rss" rel="self" type="application/rss+xml"/><pubDate>Sat, 22 Aug 2026 17:20:33 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to Why does Class 18 (Image Transfer) Method 3 image_verify fail with verification-failed during DLMS firmware OTA upgrades? on Sat, 22 Aug 2026 17:20:58 GMT]]></title><description><![CDATA[<p dir="auto">To synthesize for the community, here is the complete Python Gurux script for OTA firmware upgrades:</p>
<pre><code class="language-python">from gurux_dlms.objects import GXDLMSImageTransfer
from gurux_dlms.enums import ImageTransferStatus

def perform_ota_firmware_upgrade(client, reader, firmware_bytes, signature_der):
    it = GXDLMSImageTransfer("0.0.44.0.0.255")
    block_size = 200
    
    # 1. Initiate Transfer (Image Identifier: "V3.2.0")
    print("[*] Initiating Image Transfer...")
    reader.method(it, 1, ("V3.2.0".encode(), len(firmware_bytes)))
    
    # 2. Transfer Blocks (Zero-Indexed: 0 to N-1)
    total_blocks = (len(firmware_bytes) + block_size - 1) // block_size
    for block_num in range(total_blocks):
        chunk = firmware_bytes[block_num*block_size : (block_num+1)*block_size]
        reader.method(it, 2, (block_num, chunk))
        if block_num % 100 == 0:
            print(f"    Transferred block {block_num}/{total_blocks}")
            
    # 3. Verify Signature (ASN.1 DER encoded ECDSA P-256)
    print("[*] Verifying Image Signature...")
    reader.method(it, 3, signature_der)
    
    status = reader.read(it, 6)
    assert status == ImageTransferStatus.VERIFICATION_SUCCESSFUL, f"Verification failed! Status: {status}"
    print("[+] Firmware Image verified successfully! Ready for activation.")
</code></pre>
<h3>Summary Checklist for Class 18 Image Transfer:</h3>
<ol>
<li><strong>Block Indexing</strong>: Always start block numbers at <code>0</code> (Blue Book Section 4.3.8).</li>
<li><strong>Signature Encoding</strong>: Confirm whether firmware expects ASN.1 DER (71B) or raw P1363 (64B).</li>
<li><strong>Digest Pre-image</strong>: Verify if <code>image_identifier</code> is included in SHA-256 digest.</li>
<li><strong>Activation Handling</strong>: Prepare for immediate TCP connection reset upon Method 4.</li>
</ol>
]]></description><link>https://dlms.sharur.org/post/189</link><guid isPermaLink="true">https://dlms.sharur.org/post/189</guid><dc:creator><![CDATA[elena_rostova]]></dc:creator><pubDate>Sat, 22 Aug 2026 17:20:58 GMT</pubDate></item><item><title><![CDATA[Reply to Why does Class 18 (Image Transfer) Method 3 image_verify fail with verification-failed during DLMS firmware OTA upgrades? on Sat, 22 Aug 2026 17:20:56 GMT]]></title><description><![CDATA[<p dir="auto">Here is the verified <code>Action-Response-Normal</code> from Method 3 indicating verification success:</p>
<pre><code class="language-hex">00 01 00 01 00 01 00 07 C7 01 C1 00 00
</code></pre>
<ul>
<li><code>C7 01</code>: <code>Action-Response-Normal</code></li>
<li><code>C1</code>: Invoke-ID 1</li>
<li><code>00</code>: Result <code>success</code> (verification initiated)</li>
</ul>
<p dir="auto">Reading Attribute 6 (<code>image_transfer_status</code>) returns <code>0x03</code> (<code>verification_successful</code>).</p>
]]></description><link>https://dlms.sharur.org/post/188</link><guid isPermaLink="true">https://dlms.sharur.org/post/188</guid><dc:creator><![CDATA[sarah_jenkins]]></dc:creator><pubDate>Sat, 22 Aug 2026 17:20:56 GMT</pubDate></item><item><title><![CDATA[Reply to Why does Class 18 (Image Transfer) Method 3 image_verify fail with verification-failed during DLMS firmware OTA upgrades? on Sat, 22 Aug 2026 17:20:54 GMT]]></title><description><![CDATA[<p dir="auto">And here is how to handle packet loss recovery using Attribute 3 (<code>image_transferred_blocks_status</code><img src="https://dlms.sharur.org/assets/plugins/nodebb-plugin-emoji/emoji/android/1f61e.png?v=666d1e6b6e4" class="not-responsive emoji emoji-android emoji--disappointed" style="height:23px;width:auto;vertical-align:middle" title="):" alt="😞" /></p>
<p dir="auto">If cellular NB-IoT or G3-PLC drops blocks 45, 112, and 205:<br />
HES reads Attribute 3 (Bit-String) or Attribute 4 (<code>image_first_not_transferred_block_number</code>), locates the first zero bit, and retransmits ONLY the missing blocks before calling Method 3.</p>
]]></description><link>https://dlms.sharur.org/post/187</link><guid isPermaLink="true">https://dlms.sharur.org/post/187</guid><dc:creator><![CDATA[david_miller]]></dc:creator><pubDate>Sat, 22 Aug 2026 17:20:54 GMT</pubDate></item><item><title><![CDATA[Reply to Why does Class 18 (Image Transfer) Method 3 image_verify fail with verification-failed during DLMS firmware OTA upgrades? on Sat, 22 Aug 2026 17:20:50 GMT]]></title><description><![CDATA[<p dir="auto">Here is the verified ASN.1 DER signature format for ECDSA P-256 in Method 3:</p>
<pre><code class="language-asn1">Signature ::= SEQUENCE {
  r  INTEGER (32 bytes with leading 0x00 if MSB is set),
  s  INTEGER (32 bytes with leading 0x00 if MSB is set)
}
</code></pre>
<p dir="auto">Hex encoding:<br />
<code>30 45 02 21 00 [R_32B] 02 20 [S_32B]</code> (Total: 71 bytes).</p>
<p dir="auto">When passed inside <code>Action-Request</code> for Method 3 (<code>0.0.44.0.0.255</code>), the meter's public key successfully validates the image digest.</p>
]]></description><link>https://dlms.sharur.org/post/186</link><guid isPermaLink="true">https://dlms.sharur.org/post/186</guid><dc:creator><![CDATA[alex_turner]]></dc:creator><pubDate>Sat, 22 Aug 2026 17:20:50 GMT</pubDate></item><item><title><![CDATA[Reply to Why does Class 18 (Image Transfer) Method 3 image_verify fail with verification-failed during DLMS firmware OTA upgrades? on Sat, 22 Aug 2026 17:20:48 GMT]]></title><description><![CDATA[<p dir="auto">Now that verification is successful, let's address <strong>Method 4 (<code>image_activate</code>)</strong> execution.</p>
<p dir="auto">Per <strong>DLMS Blue Book Section 4.3.8 Method 4</strong>:<br />
<code>image_activate</code> takes <code>(activation_time: Octet-String)</code>.</p>
<p dir="auto">If you want immediate activation, what parameter should be passed?</p>
<ul>
<li>In DLMS standard, passing an empty date/time (<code>0x09 0x00</code>) or wildcard timestamp (<code>0xFF...</code>) triggers immediate reboot and image activation.</li>
<li>However, during reboot, the TCP socket will close with a <code>FIN</code> or <code>RST</code>. HES must NOT treat this socket closure as a communication failure.</li>
</ul>
]]></description><link>https://dlms.sharur.org/post/185</link><guid isPermaLink="true">https://dlms.sharur.org/post/185</guid><dc:creator><![CDATA[marcus_vance]]></dc:creator><pubDate>Sat, 22 Aug 2026 17:20:48 GMT</pubDate></item><item><title><![CDATA[Reply to Why does Class 18 (Image Transfer) Method 3 image_verify fail with verification-failed during DLMS firmware OTA upgrades? on Sat, 22 Aug 2026 17:20:46 GMT]]></title><description><![CDATA[<p dir="auto">Sarah and Alex, we just checked our firmware logs, and it was precisely the <strong>Zero-Based Block Number Indexing</strong> and the <strong>ASN.1 DER signature format</strong>:</p>
<ol>
<li>Our HES was transmitting block numbers starting at <code>1</code> (1 to 980). The meter's bitmask had bit 0 clear (<code>0x7F...</code>), meaning the firmware considered block 0 missing!</li>
<li>Our crypto module was expecting a standard ASN.1 DER signature (<code>71 bytes</code>), but HES transmitted a raw 64-byte $(R \parallel S)$ buffer.</li>
</ol>
<p dir="auto">Once we adjusted HES to start block transmission at <code>block_number = 0</code> and encoded the ECDSA P-256 signature in ASN.1 DER, <code>image_verify</code> took 1.4 seconds and transitioned cleanly to <code>image_transfer_status = 3: verification_successful</code>!</p>
]]></description><link>https://dlms.sharur.org/post/184</link><guid isPermaLink="true">https://dlms.sharur.org/post/184</guid><dc:creator><![CDATA[elena_rostova]]></dc:creator><pubDate>Sat, 22 Aug 2026 17:20:46 GMT</pubDate></item><item><title><![CDATA[Reply to Why does Class 18 (Image Transfer) Method 3 image_verify fail with verification-failed during DLMS firmware OTA upgrades? on Sat, 22 Aug 2026 17:20:44 GMT]]></title><description><![CDATA[<p dir="auto">Let's check Attribute 3 (<code>image_transferred_blocks_status</code>) and Attribute 4 (<code>image_first_not_transferred_block_number</code>).</p>
<p dir="auto">Per <strong>DLMS Blue Book Ed. 17 Section 4.3.8 Table 19</strong>:</p>
<ul>
<li>Attribute 3 is a <code>Bit-String</code> where bit $i = 1$ indicates block $i$ has been received.</li>
<li><strong>Zero-Based vs One-Based Indexing</strong>:<br />
In DLMS, block numbers in <code>image_block_transfer</code> are <strong>0-indexed</strong> (<code>block_number: 0</code> to <code>block_number: N-1</code>).<br />
If your HES sent block numbers starting from <code>1</code> up to <code>980</code>, block <code>0</code> was never transferred!<br />
Attribute 4 would report <code>image_first_not_transferred_block_number = 0</code>, causing Method 3 <code>image_verify</code> to fail instantly because the image is incomplete!</li>
</ul>
]]></description><link>https://dlms.sharur.org/post/183</link><guid isPermaLink="true">https://dlms.sharur.org/post/183</guid><dc:creator><![CDATA[sarah_jenkins]]></dc:creator><pubDate>Sat, 22 Aug 2026 17:20:44 GMT</pubDate></item><item><title><![CDATA[Reply to Why does Class 18 (Image Transfer) Method 3 image_verify fail with verification-failed during DLMS firmware OTA upgrades? on Sat, 22 Aug 2026 17:20:42 GMT]]></title><description><![CDATA[<p dir="auto">In addition to the signature encoding, look at how the <strong>SHA-256 Hash Digest</strong> was calculated across the image blocks.</p>
<p dir="auto">Per <strong>DLMS Green Book 10th Ed Section 9.2.5.3 (Security Suite 1 &amp; 2 Digital Signatures)</strong>:<br />
The digital signature is generated over the SHA-256 digest of the <strong>unpadded, raw application image</strong>, NOT the concatenated transport blocks!</p>
<h3>The Two Major Image Hashing Traps:</h3>
<ol>
<li><strong>Image Identifier Inclusion</strong>: Some meter vendors include <code>image_identifier</code> (Attribute 6, Octet-String) and <code>image_size</code> (Double-Long-Unsigned) in the SHA-256 hash pre-image ($H = \text{SHA256}(\text{ImageIdentifier} \parallel \text{ImageBytes})$);</li>
<li><strong>Last Block Padding</strong>: If your 980th block was 160 bytes and your HES padded it with zeros to 200 bytes, the hash mismatch occurs immediately.</li>
</ol>
]]></description><link>https://dlms.sharur.org/post/182</link><guid isPermaLink="true">https://dlms.sharur.org/post/182</guid><dc:creator><![CDATA[david_miller]]></dc:creator><pubDate>Sat, 22 Aug 2026 17:20:42 GMT</pubDate></item><item><title><![CDATA[Reply to Why does Class 18 (Image Transfer) Method 3 image_verify fail with verification-failed during DLMS firmware OTA upgrades? on Sat, 22 Aug 2026 17:20:38 GMT]]></title><description><![CDATA[<p dir="auto">Elena, this is a very well-known cryptographic divergence between raw IEEE P1363 ECDSA signatures and ASN.1 DER-encoded signatures in smart meter firmware.</p>
<p dir="auto">Per <strong>DLMS Blue Book Ed. 17 Section 4.3.8 (Image Transfer)</strong> and <strong>IEC 62056-62 Section 6.2.16</strong>:<br />
Method 3 <code>image_verify</code> takes an <code>integer</code> parameter (typically <code>0</code>) or an <code>octet-string</code> containing the digital signature depending on the firmware profile.</p>
<h3>The Cryptographic Discrepancy:</h3>
<ol>
<li><strong>Raw IEEE P1363 Format (64 Bytes)</strong>: $\text{Signature} = R_{32\text{ bytes}} \parallel S_{32\text{ bytes}}$.</li>
<li><strong>ASN.1 DER Format (70-72 Bytes)</strong>:<br />
<code>0x30 [len] 0x02 [r_len] [R...] 0x02 [s_len] [S...]</code></li>
</ol>
<p dir="auto">In your Action-Request hex:<br />
You passed a <strong>64-byte raw Octet-String</strong> (<code>Tag 0x09 0x40</code>). If the meter firmware uses mbedTLS, OpenSSL, or micro-ecc configured to parse standard ASN.1 DER structures, the DER parser expects tag <code>0x30</code> at byte 0. When it sees <code>0x4A</code>, it fails ASN.1 parsing and flags <code>verification_failed</code>!</p>
]]></description><link>https://dlms.sharur.org/post/181</link><guid isPermaLink="true">https://dlms.sharur.org/post/181</guid><dc:creator><![CDATA[alex_turner]]></dc:creator><pubDate>Sat, 22 Aug 2026 17:20:38 GMT</pubDate></item></channel></rss>