Signature Record

The NDEF Signature Record is a well-known record type defined by the NFC Forum. It contains three fields: a version field, a signature field and a certificate field.

The version field is static. Currently this implementation only supports v2.0 of the NDEF Signature Record.

The signature field contains the signature type, the message hash type and either the signature itself or a URI to the signature.

The certificate field contains the certificate format type, a certificate chain store and an option URI to the next certificate in the chain.

class ndef.SignatureRecord(signature_type=None, hash_type='SHA-256', signature=b'', signature_uri='', certificate_format='X.509', certificate_store=[], certificate_uri='')

The SignatureRecord class decodes or encodes an NDEF Signature Record.

Parameters:
  • signature_type (str) – initial value for the signature_type attribute, default None
  • hash_type (str) – initial value for the hash_type attribute, default ‘SHA-256’
  • signature (bytes) – initial value for the signature attribute, default b’‘
  • signature_uri (str) – initial value for the signature_uri attribute, default ‘’
  • certificate_format (str) – initial value for the certificate_format attribute, default ‘X.509’
  • certificate_store (list) – initial value for the certificate_store attribute, default []
  • certificate_uri (str) – initial value for the certificate_uri attribute, default ‘’
type

The Signature Record type is urn:nfc:wkt:Sig.

name

Value of the NDEF Record ID field, an empty str if not set.

data

A bytes object containing the NDEF Record PAYLOAD encoded from the current attributes.

version

The version of the NDEF Signature Record.

signature_type

The signature type used in the signature algorithm.

>>> import ndef
>>> print('\n'.join([str(x[1]) for x in ndef.signature.SignatureRecord()._mapping_signature_type]))
None
RSASSA-PSS-1024
RSASSA-PKCS1-v1_5-1024
DSA-1024
ECDSA-P192
RSASSA-PSS-2048
RSASSA-PKCS1-v1_5-2048
DSA-2048
ECDSA-P224
ECDSA-K233
ECDSA-B233
ECDSA-P256
hash_type

The hash type used in the signature algorithm.

>>> import ndef
>>> print("\n".join([str(x[1]) for x in ndef.signature.SignatureRecord()._mapping_hash_type]))
SHA-256
signature

The signature (if not specified by signature_uri).

signature_uri

The uniform resource identifier for the signature (if not specified by signature).

certificate_format

The format of the certificates in the chain.

>>> import ndef
>>> print("\n".join([str(x[1]) for x in ndef.signature.SignatureRecord()._mapping_certificate_format]))
X.509
M2M
certificate_store

A list of certificates in the certificate chain.

certificate_uri

The uniform resource identifier for the next certificate in the certificate chain.

This is default usage:

>>> import ndef
>>> signature_record = ndef.SignatureRecord(None, 'SHA-256', b'', '', 'X.509', [], '')

This is a full example creating records, signing them and verifying them:

>>> import ndef
>>> import io
>>> from cryptography.hazmat.backends import default_backend
>>> from cryptography.hazmat.primitives import hashes
>>> from cryptography.hazmat.primitives.asymmetric import ec
>>> from cryptography.hazmat.primitives.asymmetric import utils
>>> from cryptography.exceptions import InvalidSignature
>>> from asn1crypto.algos import DSASignature
>>> private_key = ec.generate_private_key(ec.SECP256K1(), default_backend())
>>> public_key = private_key.public_key()
>>> r1 = ndef.UriRecord("https://example.com")
>>> r2 = ndef.TextRecord("TEST")
>>> stream = io.BytesIO()
>>> records = [r1, r2, ndef.SignatureRecord("ECDSA-P256", "SHA-256")]
>>> encoder = ndef.message_encoder(records, stream)
>>> for _ in range(len(records) - 1): e=next(encoder)
>>> signature = private_key.sign(stream.getvalue(), ec.ECDSA(hashes.SHA256()))
>>> records[-1].signature = DSASignature.load(signature, strict=True).to_p1363()
>>> e=next(encoder)
>>> octets = stream.getvalue()
>>> records_verified = []
>>> records_to_verify = []
>>> known_types = {'urn:nfc:wkt:Sig': ndef.signature.SignatureRecord}
>>> for record in ndef.message_decoder(octets, known_types=known_types):
...     if not record.type == 'urn:nfc:wkt:Sig':
...         records_to_verify.append(record)
...     else:
...         stream_to_verify = io.BytesIO()
...         encoder_to_verify = ndef.message_encoder(records_to_verify + [record], stream_to_verify)
...         for _ in range(len(records_to_verify)): e=next(encoder_to_verify)
...         try:
...             public_key.verify(DSASignature.from_p1363(record.signature).dump(), stream_to_verify.getvalue(), ec.ECDSA(hashes.SHA256()))
...             records_verified.extend(records_to_verify)
...             records_to_verify = []
...         except InvalidSignature:
...             pass
>>> records_verified = list(ndef.message_decoder(b''.join(ndef.message_encoder(records_verified))))