@nfid/embed
How it works
Signatures

Introduction

Digital signature schemes are used for authenticating messages in various parts of the IC infrastructure. Signatures are domain separated, which means that every message is prefixed with a byte string that is unique to the purpose of the signature.

The IC supports multiple signature schemes, with details given in the following subsections. For each scheme, we specify the data encoded in the public key (which is always DER-encoded and indicates the scheme to use) as well as the form of the signatures (which are opaque blobs for the purposes of the rest of this specification).

In all cases, the signed payload is the concatenation of the domain separator and the message. All uses of signatures in this specification indicate a domain separator, to uniquely identify the purpose of the signature. The domain separators are prefix-free by construction, as their first byte indicates their length.

Ed25519 and ECDSA Signatures

  • Plain signatures are supported for the schemes Ed25519 (opens in a new tab) or ECDSA (opens in a new tab) on curve P-256 (secp256r1), using SHA-256 as the hash function, as well as on the Koblitz curve (secp256k1).
  • Public keys must be valid for signature schemes Ed25519 or ECDSA and are encoded as DER.
    • See RFC 8410 (opens in a new tab) for DER encoding of Ed25519 public keys.
    • See RFC 5480 (opens in a new tab) for DER encoding of ECDSA public keys.
      • The DER encoding must not specify a hash function. For curve secp256k1, the OID 1.3.132.0.10 is used. The points must be specified in uncompressed form (i.e. 0x04 followed by the big-endian 32-byte encodings of x and y).
  • The signatures are encoded as the concatenation of the 32-byte big-endian encodings of the two values r and s.

Web Authentication

The allowed signature schemes for web authentication are:

The signature is calculated by using the payload as the challenge in the web authentication assertion.

The signature is checked by verifying that the challenge field contains the base64url (opens in a new tab) encoding of the payload, and that signature verifies on authenticatorData · SHA-256(utf8(clientDataJSON)), as specified in the WebAuthn w3c recommendation (opens in a new tab).

The public key is encoded as a DER-wrapped COSE key.

It uses the SubjectPublicKeyInfo type used for other types of public keys (see, e.g., RFC 8410, Section 4 (opens in a new tab)), with OID 1.3.6.1.4.1.56387.1.1 (iso.org.dod.internet.private.enterprise.dfinity.mechanisms.der-wrapped-cose). The BIT STRING field subjectPublicKey contains the COSE encoding. See WebAuthn w3c recommendation (opens in a new tab) or RFC 8152 (opens in a new tab) for details on the COSE encoding.

The signature is a CBOR (opens in a new tab) value consisting of a data item with major type 6 ("Semantic tag") and tag value 55799, followed by a map with three mandatory fields:

  • authenticator_data (blob): WebAuthn authenticator data.
  • client_data_json (text): WebAuthn client data in JSON representation.
  • signature (blob): Signature as specified in the WebAuthn w3c recommendation (opens in a new tab), which means DER encoding in the case of an ECDSA signature.

Canister Signatures

The IC also supports a scheme where a canister can sign a payload by declaring a special "certified variable".

This section makes forward references to other concepts in this document, in particular the certification (opens in a new tab) section.

  • The public key is a DER-wrapped structure that indicates the signing canister, and includes a freely choosable seed. Each choice of seed yields a distinct public key for the canister, and the canister can choose to encode information, such as a user id, in the seed. More concretely, it uses the SubjectPublicKeyInfo type used for other types of public keys (see, e.g., RFC 8410, Section 4 (opens in a new tab)), with OID 1.3.6.1.4.1.56387.1.2 (iso.org.dod.internet.private.enterprise.dfinity.mechanisms.canister-signature). The BIT STRING field subjectPublicKey is the blob |signing_canister_id| · signing_canister_id · seed, where |signing_canister_id| is the one-byte encoding of the length of the signing_canister_id and · denotes blob concatenation.
  • The signature is a CBOR (opens in a new tab) value consisting of a data item with major type 6 ("Semantic tag") and tag value 55799, followed by a map with two mandatory fields:
  • Given a payload together with public key and signature in the format described above the signature can be verified by checking the following two conditions:
    • The certificate must be a valid certificate as described in certification (opens in a new tab), with
      lookup(/canister/<signing_canister_id>/certified_data, certificate.tree) = Found (reconstruct(tree))
      where signing_canister_id is the id of the signing canister and reconstruct is a function that computes a root-hash for the tree.
      • If the certificate includes subnet delegations (possibly nested), then the signing_canister_id must be included in each delegation's canister id range (see Delegation (opens in a new tab)).
    • The tree must be a well-formed tree with
      lookup(/sig/<s>/<m>, tree) = Found ""
      where s is the SHA-256 hash of the seed used in the public key and m is the SHA-256 hash of the payload.