pulseproof-sentinel

PPS Policy Guide

This guide explains dynamic policy binding in PulseProof Sentinel Protocol, abbreviated PPS.

Policy binding allows the relying party to require specific security properties for a given authentication or transaction.


1. Why Policy Binding?

Different operations require different security levels.

Examples:

Login:
  require biometric
  8-digit Trust Code

Withdrawal:
  require biometric
  require secure enclave
  require AmountMark
  threshold = 2

Admin action:
  require hardware key
  threshold = 3
  require proximity

PPS allows the server to send a policy object.

The authenticator hashes the policy and binds it to the Pulse.

The server verifies that the Pulse was created under the expected policy.


2. Policy Object

The PPS policy object is a CBOR map.

Fields:

1: min_trust_digits
2: require_biometric
3: require_secure_enclave
4: threshold
5: max_amount_minor
6: require_proximity
7: max_clock_skew
8: allow_offline
9: require_amount_mark
10: require_duress_support

All fields are optional.

Absent fields mean the policy does not impose that requirement.


3. Field Descriptions

3.1. min_trust_digits

Minimum total Trust Code digits.

Example:

{
  "1": 8
}

If AmountMark is present, total digits include the two AmountMark digits.

Recommended minimum:

8

For high-risk typed fallback:

10 or 12

3.2. require_biometric

Requires user verification with biometrics.

Example:

{
  "2": true
}

The authenticator should enforce this locally.

The server may also rely on device attestation if available.


3.3. require_secure_enclave

Requires private key operations inside secure hardware.

Example:

{
  "3": true
}

Secure hardware may include:


3.4. threshold

Required number of approving devices.

Example:

{
  "4": 2
}

This is relevant for threshold mode.

The server MUST also enforce the stored group threshold.

Do not rely only on the policy object.


3.5. max_amount_minor

Maximum transaction amount in minor units.

Example:

{
  "5": 10000000
}

If the transaction amount exceeds this value, the authenticator should reject signing.

The server should also enforce this independently.


3.6. require_proximity

Requires proof that authenticator and initiating device are close.

Example:

{
  "6": true
}

Proximity proof may use:

Proximity proofs are heuristic, not absolute.


3.7. max_clock_skew

Maximum allowed clock skew in epochs.

Example:

{
  "7": 1
}

Default recommendation:

1

Larger values reduce security.


3.8. allow_offline

Indicates whether offline Pulses are allowed.

Example:

{
  "8": true
}

If false, the server should reject Pulses without a valid nonce.


3.9. require_amount_mark

Requires AmountMark in Trust Code and Pulse.

Example:

{
  "9": true
}

Useful for transaction signing.


3.10. require_duress_support

Indicates the authenticator should support duress signaling.

Example:

{
  "10": true
}

This does not force the user to use duress.

It indicates the deployment expects duress capability.


4. Policy Hash

The policy object is encoded using deterministic CBOR.

pol = SHA256(cbor(policy_object))

The Pulse payload includes:

13: pol

The server compares this hash with the expected policy hash.


5. Policy Negotiation Flow

1. RP decides required policy for the operation.
2. RP encodes policy object.
3. RP sends policy to authenticator.
   - QR code
   - deep link
   - SDK challenge
   - API response
4. Authenticator displays policy-relevant details.
5. Authenticator hashes policy.
6. Authenticator includes pol in Pulse.
7. RP verifies pol matches expected policy.

6. Example Policies

6.1. Low-Risk Login

{
  "1": 8,
  "2": true,
  "8": true
}

Meaning:


6.2. Standard Login

{
  "1": 8,
  "2": true,
  "3": true,
  "8": false
}

Meaning:


6.3. High-Value Transfer

{
  "1": 8,
  "2": true,
  "3": true,
  "4": 2,
  "5": 10000000,
  "6": true,
  "9": true
}

Meaning:


6.4. Admin Action

{
  "1": 10,
  "2": true,
  "3": true,
  "4": 3,
  "6": true,
  "8": false
}

Meaning:


6.5. Offline Low-Risk Access

{
  "1": 10,
  "7": 2,
  "8": true
}

Meaning:


7. Downgrade Protection

Policy binding prevents simple downgrade attacks.

If an attacker removes or weakens policy fields, the policy hash changes.

The server MUST reject Pulses with unexpected policy hashes.

The server SHOULD NOT accept a weaker policy than required.

Example:

Expected policy hash: A
Pulse policy hash: B
Result: reject

8. Server Enforcement

The server is ultimately responsible for enforcement.

Even if the authenticator enforces policy, the server MUST verify:

Do not trust the client alone.


9. Authenticator Behavior

When receiving a policy, the authenticator should:

  1. Parse policy fields.
  2. Check local capabilities.
  3. Reject if policy cannot be satisfied.
  4. Display relevant requirements to the user.
  5. Enforce biometric or PIN if required.
  6. Use secure hardware if required.
  7. Require threshold devices if required.
  8. Include policy hash in Pulse.

Example user screen:

High-value approval required

Requirements:
  Biometric: required
  Secure enclave: required
  Devices: 2
  Maximum amount: 10,000,000
  Proximity: required

Amount: 2,500,067 IRR
Trust Code: 49371867

[Reject] [Approve]

10. Risk-Adaptive Policy

Servers can choose policies dynamically based on risk.

Risk signals:

Example:

Low risk:
  single device
  8-digit Trust Code

Medium risk:
  single device
  biometric required
  secure enclave required

High risk:
  threshold = 2
  proximity required
  AmountMark required

Very high risk:
  threshold = 3
  no offline fallback
  manual review

11. Policy and Privacy

Policy objects may reveal internal risk logic.

This is usually acceptable, but consider:

If custom policy fields are needed, define them carefully and canonically.


12. Policy Versioning

If policy semantics change, use a new policy version or new field labels.

Do not silently reinterpret existing fields.

This avoids ambiguous verification.


13. Common Mistakes

Avoid:

  1. Trusting client-provided threshold without server state.
  2. Accepting missing policy hash when policy is required.
  3. Accepting weaker policy than expected.
  4. Using non-canonical CBOR for policy object.
  5. Including unstable or ambiguous custom fields.
  6. Forgetting to enforce amount limits server-side.
  7. Allowing offline mode for high-risk operations.
  8. Using large clock-skew windows unnecessarily.
  9. Not displaying policy requirements to the user.
  10. Not testing downgrade attacks.

14. Summary

Policy binding allows PPS to support flexible, risk-adaptive security requirements.

The policy object is hashed and bound to the Pulse.

The server verifies the hash and independently enforces the requirements.

Policy binding is one of the main mechanisms that makes PPS suitable for transaction signing and high-security flows.