Class LicenseVerifier

java.lang.Object
com.iizix.license.v2.LicenseVerifier

public final class LicenseVerifier extends Object
The verifier of licence documents and key certificates: the five steps of LICENSE-V2-DESIGN.md section 2.5, in this order and no other, for the licence client, the MLS and the hub principal alike (design 13, 14):
  1. The envelope is well-formed; cert verifies under a pinned root and the clock is inside its notBefore - notAfter.
  2. sig verifies over the payload bytes under the certified key, and kid equals the certificate's.
  3. The payload parses under the rules of 2.2 and v is 2.
  4. lic is this installation's licence UUID and ikey its public key. On the MLS and the hub principal the expectation is the connection's proven key (5); a caller that proves possession of ikey another way (5.2, 5.4) passes null and the step is skipped, which the JavaDoc of verify(byte[], UUID, PublicKey) spells out.
  5. expires is in the future by the clock. The only step that never refuses: the document is returned with LicenseDocument.isExpired() set.

A document failing 1 to 4 is refused with a LicenseRefusal naming the step and the rule, never a byte of the document, and is never stored. The clock is injected: the client's and the MLS's is the system clock, a test's is fixed. The roots are given at construction (PinnedRoots.ROOTS through pinned(Clock, boolean) in production, test roots in a test); with no root the verifier refuses everything at step 1 and says so once at construction: SEVERE where the product applies the verdicts, INFO where it observes only (order CC-LIC-V5-OBSERVE-DESIGNER: iiziGo and iiziServer in this release).

Thread-safe: no state changes after construction.

Author:
Christopher Mindus
  • Constructor Details

    • LicenseVerifier

      public LicenseVerifier(Collection<RootKey> roots, Clock clock)
      Constructor.
      Parameters:
      roots - The pinned roots; empty refuses everything, with a SEVERE logged here.
      clock - The clock steps 1 and 5 read.
      Throws:
      IllegalArgumentException - If two roots share a key ID.
    • LicenseVerifier

      public LicenseVerifier(Collection<RootKey> roots, Clock clock, boolean enforced)
      Constructor, for a product that applies or observes the verdicts.
      Parameters:
      roots - The pinned roots; empty refuses everything, and says so here.
      clock - The clock steps 1 and 5 read.
      enforced - true where the product applies what this verifier refuses (the MLS, the hub, a release that enforces the licence): an empty root set is SEVERE; false where it observes only (iiziGo's gate and iiziServer's counter in this release, order CC-LIC-V5-OBSERVE-DESIGNER): INFO. Nothing else depends on it.
      Throws:
      IllegalArgumentException - If two roots share a key ID.
  • Method Details

    • pinned

      public static LicenseVerifier pinned(Clock clock)
      Creates the production verifier of a product that applies the verdicts: PinnedRoots.ROOTS and a clock.
      Parameters:
      clock - The clock, Clock.systemUTC() on a client, the MLS and a hub.
      Returns:
      The verifier.
    • pinned

      public static LicenseVerifier pinned(Clock clock, boolean enforced)
      Creates the production verifier: PinnedRoots.ROOTS and a clock, for a product that applies or observes the verdicts.
      Parameters:
      clock - The clock, Clock.systemUTC() on a client, the MLS and a hub.
      enforced - true where the product applies what the verifier refuses, false where it observes only: how an empty root set is logged, SEVERE or INFO.
      Returns:
      The verifier.
    • getRoots

      public Collection<RootKey> getRoots()
      Gets the pinned roots.
      Returns:
      The roots, unmodifiable.
    • getClock

      public Clock getClock()
      Gets the clock.
      Returns:
      The clock.
    • verify

      public LicenseDocument verify(String document, UUID lic, PublicKey ikey) throws LicenseRefusal
      Verifies a licence document given as text: verify(byte[], UUID, PublicKey) on its UTF-8 bytes (the envelope is ASCII; anything else is refused at step 1).
      Parameters:
      document - The document text.
      lic - This installation's licence UUID, or null to skip that half of step 4.
      ikey - This installation's public key, or null to skip that half of step 4.
      Returns:
      The verified document, expired or not.
      Throws:
      LicenseRefusal - If a step of 1 to 4 fails.
    • verify

      public LicenseDocument verify(byte[] document, UUID lic, PublicKey ikey) throws LicenseRefusal
      Verifies a licence document: the steps of 2.5 in order.

      Step 4 and null. An installation passes its own licence UUID and public key. The MLS passes the values of the installation row the connection proved (5.2). The hub principal passes null for both when it verifies a member's REGISTER: it takes ikey from the returned document and checks the member's signature over Hello.hubRegister(byte[], String, String) with it (5.4) - possession of the key, proved that way, replaces the comparison. A null skips the half of step 4 it stands for and nothing else.

      Parameters:
      document - The document bytes, the envelope as received.
      lic - This installation's licence UUID, or null to skip that half of step 4.
      ikey - This installation's Ed25519 public key, or null to skip that half of step 4.
      Returns:
      The verified document, expired or not: step 5 is LicenseDocument.isExpired().
      Throws:
      LicenseRefusal - If a step of 1 to 4 fails: the step and the rule, never the bytes.
      IllegalArgumentException - If ikey is not an Ed25519 key.
    • verifyCertificate

      public KeyCertificate verifyCertificate(byte[] certificate) throws LicenseRefusal
      Verifies a key certificate on its own: the certificate half of step 1 - the envelope, the signature under a pinned root, the payload, and the validity by the clock. The MLS verifies its own certificate this way at startup before it signs anything with the certified key.
      Parameters:
      certificate - The certificate bytes, the IIZI-KEYCERT/1 envelope.
      Returns:
      The certificate.
      Throws:
      LicenseRefusal - At step 1, naming the rule and never the bytes.