|
1686 | 1686 | </ul> |
1687 | 1687 | </nav> |
1688 | 1688 |
|
| 1689 | +</li> |
| 1690 | + |
| 1691 | + <li class="md-nav__item"> |
| 1692 | + <a href="#subject-attestation" class="md-nav__link"> |
| 1693 | + <span class="md-ellipsis"> |
| 1694 | + |
| 1695 | + Subject Attestation |
| 1696 | + |
| 1697 | + </span> |
| 1698 | + </a> |
| 1699 | + |
| 1700 | + <nav class="md-nav" aria-label="Subject Attestation"> |
| 1701 | + <ul class="md-nav__list"> |
| 1702 | + |
| 1703 | + <li class="md-nav__item"> |
| 1704 | + <a href="#overview_2" class="md-nav__link"> |
| 1705 | + <span class="md-ellipsis"> |
| 1706 | + |
| 1707 | + Overview |
| 1708 | + |
| 1709 | + </span> |
| 1710 | + </a> |
| 1711 | + |
| 1712 | +</li> |
| 1713 | + |
| 1714 | + <li class="md-nav__item"> |
| 1715 | + <a href="#per-agent-signing-keys-should" class="md-nav__link"> |
| 1716 | + <span class="md-ellipsis"> |
| 1717 | + |
| 1718 | + Per-Agent Signing Keys (SHOULD) |
| 1719 | + |
| 1720 | + </span> |
| 1721 | + </a> |
| 1722 | + |
| 1723 | +</li> |
| 1724 | + |
| 1725 | + <li class="md-nav__item"> |
| 1726 | + <a href="#xrpl-credential-based-subject-attestation-should-for-xrpl-deployments" class="md-nav__link"> |
| 1727 | + <span class="md-ellipsis"> |
| 1728 | + |
| 1729 | + XRPL Credential-Based Subject Attestation (SHOULD for XRPL deployments) |
| 1730 | + |
| 1731 | + </span> |
| 1732 | + </a> |
| 1733 | + |
| 1734 | +</li> |
| 1735 | + |
| 1736 | + <li class="md-nav__item"> |
| 1737 | + <a href="#error-code_1" class="md-nav__link"> |
| 1738 | + <span class="md-ellipsis"> |
| 1739 | + |
| 1740 | + Error Code |
| 1741 | + |
| 1742 | + </span> |
| 1743 | + </a> |
| 1744 | + |
| 1745 | +</li> |
| 1746 | + |
| 1747 | + </ul> |
| 1748 | + </nav> |
| 1749 | + |
1689 | 1750 | </li> |
1690 | 1751 |
|
1691 | 1752 | <li class="md-nav__item"> |
|
2671 | 2732 | </ul> |
2672 | 2733 | </nav> |
2673 | 2734 |
|
| 2735 | +</li> |
| 2736 | + |
| 2737 | + <li class="md-nav__item"> |
| 2738 | + <a href="#subject-attestation" class="md-nav__link"> |
| 2739 | + <span class="md-ellipsis"> |
| 2740 | + |
| 2741 | + Subject Attestation |
| 2742 | + |
| 2743 | + </span> |
| 2744 | + </a> |
| 2745 | + |
| 2746 | + <nav class="md-nav" aria-label="Subject Attestation"> |
| 2747 | + <ul class="md-nav__list"> |
| 2748 | + |
| 2749 | + <li class="md-nav__item"> |
| 2750 | + <a href="#overview_2" class="md-nav__link"> |
| 2751 | + <span class="md-ellipsis"> |
| 2752 | + |
| 2753 | + Overview |
| 2754 | + |
| 2755 | + </span> |
| 2756 | + </a> |
| 2757 | + |
| 2758 | +</li> |
| 2759 | + |
| 2760 | + <li class="md-nav__item"> |
| 2761 | + <a href="#per-agent-signing-keys-should" class="md-nav__link"> |
| 2762 | + <span class="md-ellipsis"> |
| 2763 | + |
| 2764 | + Per-Agent Signing Keys (SHOULD) |
| 2765 | + |
| 2766 | + </span> |
| 2767 | + </a> |
| 2768 | + |
| 2769 | +</li> |
| 2770 | + |
| 2771 | + <li class="md-nav__item"> |
| 2772 | + <a href="#xrpl-credential-based-subject-attestation-should-for-xrpl-deployments" class="md-nav__link"> |
| 2773 | + <span class="md-ellipsis"> |
| 2774 | + |
| 2775 | + XRPL Credential-Based Subject Attestation (SHOULD for XRPL deployments) |
| 2776 | + |
| 2777 | + </span> |
| 2778 | + </a> |
| 2779 | + |
| 2780 | +</li> |
| 2781 | + |
| 2782 | + <li class="md-nav__item"> |
| 2783 | + <a href="#error-code_1" class="md-nav__link"> |
| 2784 | + <span class="md-ellipsis"> |
| 2785 | + |
| 2786 | + Error Code |
| 2787 | + |
| 2788 | + </span> |
| 2789 | + </a> |
| 2790 | + |
| 2791 | +</li> |
| 2792 | + |
| 2793 | + </ul> |
| 2794 | + </nav> |
| 2795 | + |
2674 | 2796 | </li> |
2675 | 2797 |
|
2676 | 2798 | <li class="md-nav__item"> |
@@ -2916,6 +3038,18 @@ <h3 id="policygrant-payload">PolicyGrant (payload)</h3> |
2916 | 3038 | <td>Hex-encoded credential type that approved merchants must hold (e.g. <code>hex("mpcp:approved-merchant")</code>). Used with <code>merchantCredentialIssuer</code>.</td> |
2917 | 3039 | </tr> |
2918 | 3040 | <tr> |
| 3041 | +<td>subjectCredentialIssuer</td> |
| 3042 | +<td>string</td> |
| 3043 | +<td>optional</td> |
| 3044 | +<td>XRPL address of the credential issuer that attests the subject's identity. When present, the gateway SHOULD verify on-chain that <code>subjectId</code>'s XRPL account holds a valid credential from this issuer. See <strong>Subject Attestation</strong> section below.</td> |
| 3045 | +</tr> |
| 3046 | +<tr> |
| 3047 | +<td>subjectCredentialType</td> |
| 3048 | +<td>string</td> |
| 3049 | +<td>optional</td> |
| 3050 | +<td>Hex-encoded credential type the subject must hold (e.g. <code>hex("mpcp:fleet-agent")</code>). Used with <code>subjectCredentialIssuer</code>.</td> |
| 3051 | +</tr> |
| 3052 | +<tr> |
2919 | 3053 | <td>offlineMaxSinglePayment</td> |
2920 | 3054 | <td>string</td> |
2921 | 3055 | <td>optional</td> |
@@ -3324,6 +3458,73 @@ <h3 id="error-codes">Error Codes</h3> |
3324 | 3458 | </tbody> |
3325 | 3459 | </table> |
3326 | 3460 | <hr /> |
| 3461 | +<h2 id="subject-attestation">Subject Attestation</h2> |
| 3462 | +<h3 id="overview_2">Overview</h3> |
| 3463 | +<p>The <code>subjectId</code> field identifies the entity receiving the grant (vehicle, agent, wallet). By |
| 3464 | +default, <code>subjectId</code> is self-reported and informational only — it cannot be cryptographically |
| 3465 | +verified. This means a compromised agent sharing a signing key with other agents can issue SBAs |
| 3466 | +that appear to come from any agent in the fleet.</p> |
| 3467 | +<p><strong>Problem:</strong> When multiple agents share the same SBA signing key, revoking a compromised |
| 3468 | +agent's grant affects all agents using that key. The fleet operator cannot isolate the |
| 3469 | +compromised agent without disrupting the entire fleet.</p> |
| 3470 | +<h3 id="per-agent-signing-keys-should">Per-Agent Signing Keys (SHOULD)</h3> |
| 3471 | +<p>Each agent or vehicle wallet SHOULD have a <strong>unique SBA signing key</strong>. This ensures:</p> |
| 3472 | +<ul> |
| 3473 | +<li>Revoking one agent's grant does not affect other agents</li> |
| 3474 | +<li>SBAs can be attributed to a specific agent for audit purposes</li> |
| 3475 | +<li>Compromised agents can be isolated without fleet-wide disruption</li> |
| 3476 | +</ul> |
| 3477 | +<p>Fleet operators SHOULD register each agent's public key in the Trust Bundle or JWKS endpoint |
| 3478 | +under a unique <code>kid</code> that includes the agent identity (e.g. <code>"sba-key:vehicle-1284"</code>).</p> |
| 3479 | +<h3 id="xrpl-credential-based-subject-attestation-should-for-xrpl-deployments">XRPL Credential-Based Subject Attestation (SHOULD for XRPL deployments)</h3> |
| 3480 | +<p>For XRPL deployments, the fleet operator or PA SHOULD issue an on-chain credential to each |
| 3481 | +agent's XRPL account using XLS-70 Credentials:</p> |
| 3482 | +<ul> |
| 3483 | +<li><code>Issuer</code> = Fleet operator's or PA's XRPL address</li> |
| 3484 | +<li><code>Subject</code> = Agent's XRPL account</li> |
| 3485 | +<li><code>CredentialType</code> = hex-encoded type (e.g. <code>hex("mpcp:fleet-agent")</code> or |
| 3486 | + <code>hex("mpcp:authorized-agent")</code>)</li> |
| 3487 | +</ul> |
| 3488 | +<p>The PolicyGrant binds to the specific agent via:</p> |
| 3489 | +<ul> |
| 3490 | +<li><code>subjectCredentialIssuer</code> — the XRPL address of the credential issuer</li> |
| 3491 | +<li><code>subjectCredentialType</code> — the hex-encoded credential type</li> |
| 3492 | +</ul> |
| 3493 | +<p><strong>Gateway enforcement (SHOULD):</strong> Before accepting SBAs from an agent, the gateway SHOULD |
| 3494 | +verify on-chain that the agent's account holds a valid, non-expired credential matching the |
| 3495 | +grant's <code>subjectCredentialIssuer</code> and <code>subjectCredentialType</code>:</p> |
| 3496 | +<div class="highlight"><pre><span></span><code>if PolicyGrant.subjectCredentialIssuer is present: |
| 3497 | + credential = lookupCredential( |
| 3498 | + subject: agent.xrplAddress, |
| 3499 | + issuer: PolicyGrant.subjectCredentialIssuer, |
| 3500 | + type: PolicyGrant.subjectCredentialType |
| 3501 | + ) |
| 3502 | + if credential does not exist or is expired: |
| 3503 | + → reject with SUBJECT_NOT_ATTESTED |
| 3504 | +</code></pre></div> |
| 3505 | +<p><strong>Isolation on compromise:</strong> When a single agent is compromised, the fleet operator:</p> |
| 3506 | +<ol> |
| 3507 | +<li>Deletes the agent's on-chain credential via <code>CredentialDelete</code></li> |
| 3508 | +<li>The gateway rejects further SBAs from that agent (credential check fails)</li> |
| 3509 | +<li>Other agents' credentials are unaffected — they continue operating normally</li> |
| 3510 | +<li>No grant reissuance needed for uncompromised agents</li> |
| 3511 | +</ol> |
| 3512 | +<h3 id="error-code_1">Error Code</h3> |
| 3513 | +<table> |
| 3514 | +<thead> |
| 3515 | +<tr> |
| 3516 | +<th>Code</th> |
| 3517 | +<th>Meaning</th> |
| 3518 | +</tr> |
| 3519 | +</thead> |
| 3520 | +<tbody> |
| 3521 | +<tr> |
| 3522 | +<td><code>SUBJECT_NOT_ATTESTED</code></td> |
| 3523 | +<td><code>subjectCredentialIssuer</code> is set but the agent does not hold a matching on-chain credential</td> |
| 3524 | +</tr> |
| 3525 | +</tbody> |
| 3526 | +</table> |
| 3527 | +<hr /> |
3327 | 3528 | <h2 id="summary">Summary</h2> |
3328 | 3529 | <p>PolicyGrant establishes the <strong>policy boundary</strong> for machine payments.</p> |
3329 | 3530 | <p>It ensures that downstream SBA artifacts are always derived from a <strong>validated policy evaluation</strong>.</p> |
|
0 commit comments