How To Get Signatures On Smaller NFC Tags
BlackSeal currently requires NFC tags with about 500 bytes of memory available to be able to fit a URL plus a signature on the tag. But is it possible to use a lower cost tag with less memory available? The theoretical answer is yes, however, it does come with some caveats. Let's look into some of the technical details.
At a high level, a BlackSeal NFC tag contains two things: (1) a URL and (2) a signature. The size of the URL for BlackSeal is a fixed length since it uses a URL redirect service. So at a minimum all URLs look something like this:
However, to protect against tag cloning, we also include some hardware attributes of the tag you are writing to. So URLs will actually look more like this:
The amount of memory required to store the URI record breaks down as follows:
= 4 bytes - NDEF Header = 15 bytes - URL ~ 15 bytes - Hardware Attributes
~ 34 bytes - Total
The larger portion of the data is the signature record. The signature record contains a few things: (1) a version, (2) a signature and (3) a certificate chain. The version field is always a fixed length of 1 byte. The signature itself is 68 bytes — 64 bytes for the signature* plus 4 bytes of metadata. And finally, the certificate chain contains the certificates of the entities used to create the signature, minus the root certificate. In the case of BlackSeal, the certificate chain contains two certificates, an issuer certificate and a signer certificate. For the BlackSeal trial period, all messages are signed by the same entity resulting in the certificate chain being 301 bytes — 141 bytes for the signing certificate, 155 bytes for the issuing certificate and 5 bytes of metadata.
The amount of memory required to store the signature record breaks down as follows:
= 9 bytes - NDEF Header = 1 byte - Version = 68 bytes - Signature 64 bytes - Signature 4 bytes - Metadata = 301 bytes - Certificate Chain 141 bytes - Certificate #1 155 bytes - Certificate #2 5 bytes - Metadata
= 379 bytes - Total
So in total, for the complete NDEF message we get the following:
~ 34 bytes - URI Record = 379 bytes - Signature Record
~ 413 bytes - Total
So how can we make this smaller? The solution is in the details of the Signature RTD specification. There are a couple of things we can change to use less data: (1) how we store the signature and (2) how we store the certificate chain. In both cases, the Signature RTD specification shows that a URI reference can be used instead of the raw data. So if we use a short URL, like above – assuming a URL can fit into 22 bytes, we can reference the Signature and the Certificate Chain with a URL resulting in each of those values reducing from 68 bytes and 301 bytes to 26 bytes and 23 bytes, respectively. Total savings = 323 bytes! The signature record now breaks down as:
= 6 bytes - NDEF Header Saved 3 bytes here for it becoming a short record = 1 byte - Version = 26 bytes - Signature 22 bytes - URI reference 4 bytes - Metadata = 23 bytes - Certificate Chain 22 bytes - URI reference 1 byte - Metadata
= 56 bytes - Total
So we can store an equivalent BlackSeal NDEF message in 90 bytes instead of the current 413 bytes. So why isn't this the default storage mechanism? It comes down to verification. The current format allows you to verify a message offline since the message itself contains all the required data to do the verification. By changing the signature and certificate chain to use URI references, verification can only be done online since the data needs to be fetched from those URLs before verification can be done.
* The signature is 64 bytes due to using curve P-256.