public final class PinSet

  1. Object
  2. PinSet

An immutable set of certificate pins, keyed by host, as published by the attestation service.

Pins are over the subject public key info, not the whole certificate, so a host can renew its certificate on the same key pair without invalidating the pin. A chain matches if any certificate in it matches any pin for the host, which is what makes it safe to pin an issuing CA as the backup.

The never-brick rules

Client-side pinning is the one part of the shield that can take an app offline for reasons the developer cannot fix without an app store release, so the failure behaviour is deliberately asymmetric:

  • A host with no pins is never enforced. That covers first run, a cold start with no network, and any host the service has not published pins for.
  • A failed pin fetch never fails a request. The last known set is kept.
  • Pins carry a soft expiry, after which a refresh is attempted, and a much later hard expiry. Past the hard expiry the set is dropped and enforcement stops. A device that cannot reach the service for weeks loses pinning; it does not lose the app.
  • Only an actual mismatch – a host that has pins presenting a chain that matches none of them – fails a request, and it fails before any request body is written.

Fields

public static final PinSet EMPTYA pin set with no hosts.

Constructors

public PinSet(Hashtable hostToPins, int version, long softExpiry, long hardExpiry)

Methods

public int getVersion()
public boolean isStale()True once the set should be refreshed.
public boolean isExpired()True once the set is too old to keep enforcing.
public boolean isEnforcedFor(String host)True when this set has at least one pin for the host and has not hard-expired, i.e. when a chain for this host is actually going to be checked.
public int hostCount()Number of hosts with at least one pin.
public Vector pinsFor(String host)The pins registered for a host, honouring a leading *. wildcard, or null when the host is not pinned.
public boolean matches(String host, String[] chainSpkiDigests)True when at least one of the supplied chain digests matches a pin for the host.
public boolean isEmpty()True when no host is pinned.
public String toString()Returns a string representation of the object.

Inherited methods

Field details

EMPTY

public static final PinSet EMPTY
A pin set with no hosts. Enforces nothing.

Constructor details

PinSet

public PinSet(Hashtable hostToPins, int version, long softExpiry, long hardExpiry)

Parameters

hostToPins Hashtable
host (lowercase) to a Vector of base64 SHA-256 SPKI digests
version int
monotonic version from the service, used to detect a newer published set
softExpiry long
local millis after which a refresh should be attempted, 0 for never
hardExpiry long
local millis after which the set is discarded entirely, 0 for never

Method details

getVersion

public int getVersion()

isStale

public boolean isStale()
True once the set should be refreshed. Does not mean it has stopped being enforced.

isExpired

public boolean isExpired()
True once the set is too old to keep enforcing. At this point pinning disables itself rather than risk locking a long-offline device out of its own app.

isEnforcedFor

public boolean isEnforcedFor(String host)
True when this set has at least one pin for the host and has not hard-expired, i.e. when a chain for this host is actually going to be checked.

hostCount

public int hostCount()
Number of hosts with at least one pin. Used by tests and diagnostics.

pinsFor

public Vector pinsFor(String host)
The pins registered for a host, honouring a leading *. wildcard, or null when the host is not pinned.

matches

public boolean matches(String host, String[] chainSpkiDigests)

True when at least one of the supplied chain digests matches a pin for the host.

Returns true when the host is not pinned at all – “no opinion” must never be reported as a mismatch, or an unpinned host would start failing.

isEmpty

public boolean isEmpty()
True when no host is pinned.

toString

public String toString()
Returns a string representation of the object. In general, the toString method returns a string that “textually represents” this object. The result should be a concise but informative representation that is easy for a person to read. It is recommended that all subclasses override this method. The toString method for class Object returns a string consisting of the name of the class of which the object is an instance, the at-sign character `@’, and the unsigned hexadecimal representation of the hash code of the object. In other words, this method returns a string equal to the value of: getClass().getName() + ‘@’ + Integer.toHexString(hashCode())