Remote Identity attestation#130
Conversation
- Move jku from payload claim to COSE protected header (label 32, RFC 9596) - Drop aud claim; session binding via external_aad already ties the token to a specific peer pair, making aud redundant - Redraw overview diagram to show the three-party flow clearly - Fix stale cross-references and RFC 8152 citation - Add security note explaining why session binding subsumes both jti replay prevention and aud audience binding - Add EAT alignment and custom claim vocabulary to open items - Trim references to only those cited in the document body
iinuwa
left a comment
There was a problem hiding this comment.
Looks good overall; added things that might be useful additions, and one question about the evaluation of exp in the verification logic.
| └──────── (3) fetch JWKS ──────────────────│ UserClient │ | ||
| │ (verifies) │ | ||
| └──────────────┘ | ||
| ``` |
There was a problem hiding this comment.
Just a nit: the main document presents the remote client on the right and the user client on the left. It might be worth swapping these to be something like this
UserClient Remote Client Vendor
| | | <Publishes signing keys>
| <-- establishes Noise tunnel --> | |
| | - requests attestation -> |
| | <--- signs attestation--- |
| <------- presents attestation -------- | |
| -------------------- requests signing keys ----------------------> |
| <verifies attestation> | |
| <----- continues communication ------> | |
| ### 4.2 JWKS publication (issuer requirements) | ||
|
|
||
| The issuer MUST publish a JWKS (RFC 7517) at an HTTPS URL on the | ||
| same origin as `iss`. The token names this URL via the `jku` header |
There was a problem hiding this comment.
"origin" typically refers to scheme + hostname (e.g. https://example.com/) in the web world, but below, we define iss to be equal to just a hostname. We should either use the full origin for iss, or use the term "hostname" here. Doesn't matter to me which.
There was a problem hiding this comment.
@iinuwa Yeah to be honest I sort of want to do away with jkuand just have iss that points to the public key. And we grab the hostname of iss as the Vendor.
There was a problem hiding this comment.
Hmm. I started thinking that would require a tiny bit more parsing on the client side, which might cause some issues, but they should be validating that that the jku hostname matches iss, so they have to do URL parsing regardless. On the other hand, splitting jku from iss means you need to make sure to validate that they match, which a client might forget to do and trust
{
"iss":"app.com",
"jku":"https://evil.com/jwks.json"
}It'd be slightly abnormal to have a URL directly to the key in iss though. OIdC/OAuth2 handles this by having a .well-known address based on the issuer. In our case, the path can be anything. For that reason, I like splitting jku over iss, but I can see both sides.
Another alternative is following OIdC a .well-known path, which might not be a bad idea. Hosting .well-known on top-level domains can be annoying, but since the organization providing an agent is probably technically savvy, it can be worked around.
There was a problem hiding this comment.
While abnormal, I still don't see any downsides with it, and you would need to do less comparisons as you point out.
I haven't fully considered if redirect impact things or not.
Well-known is not a bad idea, and may serve as a compliment but I worry about it being seen as more complex. A direct url is easy to reason about.
| Implementations are free to express the same policy in any form | ||
| (config file, API, UI, code). | ||
|
|
||
| ## 8. Security considerations |
There was a problem hiding this comment.
Another consideration is security UX for domains:
If the hostname is displayed in clients for TOFU attestations, the client SHOULD use some means for the user to securely display those to users to make appropriate trust decisions. These techniques can be borrowed from browsers, e.g.:
- assist with detecting homograph attacks by rendering with Punycode orshowing warnings when non-ASCII characters are present
- highlighting the registrable domain suffix according to PSL, while de-emphasizing subdomains underneath that
- etc.
There was a problem hiding this comment.
Yeah, agreed! Is there a complete list of advice to follow that we may want to add here?
There was a problem hiding this comment.
I don't see a W3C or IETF standard, but I found this list of guidelines from Chromium: https://chromium.googlesource.com/chromium/src/+/HEAD/docs/security/url_display_guidelines/url_display_guidelines.md.
| 2. `sub` equals `hex(SHA256(remote_client_pubkey))` of the peer that | ||
| completed the Noise handshake. | ||
| 3. `iat` is within `[now - SKEW, now + SKEW]`. | ||
| 4. `exp`, if present, satisfies `exp ∈ (now, now + MAX_LIFETIME]` and |
There was a problem hiding this comment.
I think if signer's clock is ahead at all, all tokens will fail validation on this step:
now = 0
iat = 1
exp = 301
exp - iat = 300 <= MAX_LIFETIME = true
(now, now + MAX_LIFETIME] = (1-300]
301 ∈ (1-300] = False
I think we need to compare (iat, iat + MAX_LIFETIME] instead, which should be fine since we checked that the clock skew was acceptable, and the period between iat and exp is valid.
now = 0
iat = 1
exp = 301
exp - iat = 300 <= MAX_LIFETIME = true
(iat, iat + MAX_LIFETIME] = (1-301]
301 ∈ (1-301] = False
also works if the signer's clock is slow:
now = 30
iat = 0
exp = 300
exp - iat = 300 <= MAX_LIFETIME = true
(iat, iat + MAX_LIFETIME] = (1, 301]
300 ∈ (1, 301] = true
📔 Objective
This PR adds Remote Identity Attestation.
Today, when an remote client (agent) connects to your client, the protocol gives you no way to know which platform it's running on. It's Trust-on-first-use, without any confirmed identity.
This PR adds a draft spec for an optional attestation extension: the agent's platform signs a short-lived token during pairing, vouching for the clients's identity, and the client can show additional UI or enforce policy ("only accept connections from this platform") before serving any credentials.
The token is cryptographically bound to the exact Noise session, so it can't be replayed or redirected.
The token adds authenticated metadata about the requester without requiring user configuration (e.g. domain name of the remote, and possible other relevant metadata)
📸 Screenshots
⏰ Reminders before review
🦮 Reviewer guidelines
:+1:) or similar for great changes:memo:) or ℹ️ (:information_source:) for notes or general info:question:) for questions:thinking:) or 💭 (:thought_balloon:) for more open inquiry that's not quite a confirmed issue and could potentially benefit from discussion:art:) for suggestions / improvements:x:) or:warning:) for more significant problems or concerns needing attention:seedling:) or ♻️ (:recycle:) for future improvements or indications of technical debt:pick:) for minor or nitpick changes