Reads a signed licence file and checks every signature and field in it.
The file is one JSON object with four base64 fields:
licence: the licence JSON bytes, signed by the issuer's working key;signature: that signature, 64 bytes of Ed25519;certificate: the working key's certificate JSON bytes;certificate_signature: the root key's signature of the certificate.
verify/2 checks the signature over the exact bytes it received before
it parses them, and never re-encodes the JSON. Each refusal is its own
atom and its own log line.
The checks run in this order, and the first failure answers:
:bad_envelope: the file is over 64 KB, is not the four-field object, or a field has the wrong length or is not base64. Sizes are checked before anything is decoded.:unknown_root: no root key in:root_keyssigned the certificate. An empty list refuses every file here.:bad_certificate: the certificate's fields are malformed, or it is not for a licence working key.:bad_signature: the certificate's key did not sign the licence.:bad_licence: the licence's fields are malformed.:wrong_working_key: the licence names another working key id.:certificate_out_of_date: the certificate was not in date when the licence was issued, or is not now.:wrong_product: the licence is for another product. One root key can sign for several products, so this check keeps one product's licence off another.:wrong_machine: the licence names another machine id.:wrong_install_key: the licence names another install key, or the install key's own error (:install_key_missing,:install_key_unreadable,:install_key_timeout) when this install has none to compare.:install_key_proof_failed: this install's key did not sign a fresh random value that verifies against the licence's key.:clock_behind: the clock reads more than a day before the latest time the app has seen, so setting it back cannot extend a term.:term_not_startedor:term_ended.:older_serial: the licence is older than the one already stored.
Summary
Functions
What a working key's certificate says it is for. A root key's signature on any other JSON never passes as a certificate.
The four parts as the file's bytes. Aker.Issuer writes a
licence through this, so the issuer and the reader share one shape.
Whether features is a list a licence may carry: at most 32 names, each
1 to 32 bytes of a-z, 0-9, _, . and -.
Whether licence JSON bytes fit the size this module reads.
The largest licence file verify/2 reads, in bytes.
The licence in bytes as Aker.Terms, when every check
passes for this install.
Types
@type refusal() ::
:bad_envelope
| :unknown_root
| :bad_certificate
| :bad_signature
| :bad_licence
| :wrong_working_key
| :certificate_out_of_date
| :wrong_product
| :wrong_machine
| :wrong_install_key
| :install_key_missing
| :install_key_unreadable
| :install_key_timeout
| :install_key_proof_failed
| :clock_behind
| :term_not_started
| :term_ended
| :older_serial
Functions
@spec certificate_purpose() :: String.t()
What a working key's certificate says it is for. A root key's signature on any other JSON never passes as a certificate.
@spec encode(%{ licence: binary(), signature: binary(), certificate: binary(), certificate_signature: binary() }) :: binary()
The four parts as the file's bytes. Aker.Issuer writes a
licence through this, so the issuer and the reader share one shape.
Whether features is a list a licence may carry: at most 32 names, each
1 to 32 bytes of a-z, 0-9, _, . and -.
Whether licence JSON bytes fit the size this module reads.
@spec max_bytes() :: pos_integer()
The largest licence file verify/2 reads, in bytes.
@spec verify(binary(), keyword()) :: {:ok, Aker.Terms.t()} | {:error, refusal()}
The licence in bytes as Aker.Terms, when every check
passes for this install.
Options:
:product: the product this app is (required);:root_keys: the trusted Ed25519 root public keys, raw 32-byte binaries (required; seeAker.PublicKeys.decode/1);:machine_id_hash: this host's machine id hash (required);:install_key:{module, opts}of this install's key (required);:now: the time to check against (default now);:last_seen: the latest time the app has seen, or nil;:stored_serial: the serial of the licence already stored, or nil.