Note
This draft extension is not yet implemented in any device or reader. The choice of algorithm, key management and generator id conventions may still change.
Note
  • The signature covers the entire .bor archive and is stored in a block appended after the ZIP End of Central Directory (EOCD) record, not as a regular ZIP entry. Proposed by Salem. This avoids known ambiguity issues from JAR signing v1 (duplicate entries, unordered central directory) and keeps the file backward-compatible, since standard ZIP libraries already ignore bytes after the EOCD.

  • The public key is embedded directly in the signature block, PEM-encoded. Proposed by Salem. Anyone can verify the signature using the embedded public key. Whether a key belongs to a trusted generator is a separate concern, kept internal to LIM.

  • algorithm is an explicit field rather than a fixed choice. Proposed by Salem. This allows adding a future algorithm (e.g. Ed25519) without a new block format. The proposed default algorithm is SIGALG_RSA_PSS_SHA256; PocketLim’s embedded crypto library may require SIGALG_RSA_PKCS1_SHA256 instead - to confirm with the firmware team.

  • The signing key for PocketLim devices has not yet been chosen. Proposed by Salem. Preference order: (1) a dedicated signing keypair generated and stored on the device, independent from its VPN/SSH key; (2) the VPN/SSH key used only to bootstrap a dedicated on-device key; (3) the VPN/SSH key reused directly as a last resort. Mixing a network authentication key with a document-signing key couples two trust domains with unrelated lifecycles - to confirm with the firmware team.

  • <generator> is added alongside the existing <device>, not instead of it. Proposed by Salem. <device> stays as-is for readers that only know it (e.g. azurite). A physical device fills in both; a software generator fills in only <generator>.

  • The generator id is self-chosen by whoever signs, not centrally allocated by LIM. Proposed by Salem. For GEN_DEVICE, id matches device/serial. For GEN_APPLICATION, id is free-form (reverse-DNS style recommended, e.g. eu.lim.example-app). The real security identity is the embedded public key; id is only a human-readable label.

  • A .bor file has at most one generator and one signature. Proposed by Salem. Re-exporting creates a new file with its own identity and, if signed, its own signature; the new signature does not link back to the source file. Values may have changed during re-export, so the new file does not inherit the source file’s non-modification guarantee.

  • Signing is optional, including for newly approved generators. Readers are not required to support this extension. Proposed by Salem.

  • Trust management (which key belongs to which approved generator, key revocation) is not part of this draft - kept as an internal LIM mechanism, same treatment as device serial allocation.

Generator identity

<generator> is added under the root <description> element, alongside <device>. A physical device includes both <device> and <generator type="GEN_DEVICE">. The generator’s id matches the device’s serial. A software generator includes only <generator type="GEN_APPLICATION">.

Table 1. Generator properties
Property Description Type Required Example

type

Kind of generator, specified as an XML attribute (see below)

code (see below)

required

GEN_APPLICATION

id

Self-chosen identifier of the generator [1]

text

required

50000 / eu.lim.example-app

Table 2. Generator type codes
Generator type Description

GEN_DEVICE

Physical measurement device (also described by <device>)

GEN_APPLICATION

Software application

Example description.xml excerpt
  <device>
    <serial>50000</serial>
    <version>1.0</version>
    <build>20190104</build>
  </device>
  <generator type="GEN_DEVICE" id="50000"/>
Example description.xml excerpt (software generator, no physical device)
  <generator type="GEN_APPLICATION" id="eu.lim.example-app"/>

Signature block

The signature is not a ZIP entry: it is a block appended after the ZIP End of Central Directory (EOCD) record. A reader unaware of this extension parses the file as an ordinary ZIP archive, finds the original EOCD, and simply ignores the trailing bytes - this is standard ZIP library behavior.

The signature is computed over all bytes preceding the signature block, starting at offset 0. This covers the complete ZIP archive.

Example signature block
<?xml version="1.0" encoding="UTF-8"?>
<signature xmlns="http://www.lim.eu/bor-signature">
  <algorithm>SIGALG_RSA_PSS_SHA256</algorithm>
  <generator type="GEN_APPLICATION" id="eu.lim.example-app"/>
  <public_key encoding="pem">-----BEGIN PUBLIC KEY-----
...
-----END PUBLIC KEY-----</public_key>
  <value encoding="base64">...</value>
</signature>
Table 3. Signature block properties
Property Description Type Required

algorithm

Signature algorithm (see below)

code (see below)

required

generator

Generator that produced the file, same structure as <generator> in description.xml

structure

required

public_key

Signer’s public key, PEM-encoded

text

required

value

Signature value, base64-encoded

text

required

Table 4. Signature algorithm codes
Algorithm Description

SIGALG_RSA_PSS_SHA256

RSA-PSS signature, SHA-256 digest (RFC 8017) - proposed default

SIGALG_RSA_PKCS1_SHA256

RSASSA-PKCS1-v1_5 signature, SHA-256 digest - fallback for embedded crypto libraries without PSS support

Out of scope

This draft specifies how to sign a .bor file and verify its signature using the embedded public key. Generator approval, key ownership and key revocation are managed internally by LIM and are outside the scope of this specification.


1. for GEN_DEVICE, id matches device/serial; for GEN_APPLICATION, id is a free-form identifier chosen by the generator, reverse-DNS style recommended - not centrally allocated by LIM