rfc: Attested Authority#7
Conversation
alanshaw
left a comment
There was a problem hiding this comment.
This is a really neat way to communicate the attestation. I didn't think of actually putting it in the signature 👏
| "alg": <bytes: authority's Varsig header for its own key type, e.g. Ed25519+DAG-CBOR> | ||
| }, | ||
| "sig": <bytes: authority's raw signature over the canonical DAG-CBOR encoding of "payload"> | ||
| } |
There was a problem hiding this comment.
This looks a lot like an invocation. I'm curious why we would not just put an invocation here? We'd get to re-use a lot of machinery to encode/decode and validate it, and it would be similar in concept to receipts, which are also invocations, with a /ucan/attest/receipt command.
There was a problem hiding this comment.
Yeah, I had the same thought but didn't pursue it. That might be the best version of this.
| ``` | ||
| { | ||
| "payload": { | ||
| "subject": <string: the attested subject DID>, |
There was a problem hiding this comment.
Why do we need subject repeated here?
There was a problem hiding this comment.
Oh, you're right, it's part of what's hashed in payload_hash as it is. We can scratch it here.
| { | ||
| "payload": { | ||
| "subject": <string: the attested subject DID>, | ||
| "payload_hash": <bytes: SHA-256 hash of the canonical DAG-CBOR encoding of the delegation payload>, |
There was a problem hiding this comment.
Yeah, that's what that should be really.
alanshaw
left a comment
There was a problem hiding this comment.
Happy for this to merge as is. I have left comments for your consideration.
|
|
||
| ## Abstract | ||
|
|
||
| This document proposes a generic scheme for using externally-verified identities as UCAN delegation subjects. Such identities, including email addresses, OAuth-based identities, and others, have no associated keypair under user control, and therefore cannot sign UCAN delegations directly. A trusted authority performs an out-of-band verification (email loop, OAuth exchange, etc.) and produces a cryptographic attestation on behalf of the subject identity. A generic Varsig signature type (`authority-attestation`) is defined that encodes the authority's attestation in place of a conventional asymmetric signature, with the specific verification method encoded in the attestation payload rather than the type. This allows attested identities to appear as `iss` in root UCAN delegations while remaining structurally honest about the nature of the verification performed. |
There was a problem hiding this comment.
| This document proposes a generic scheme for using externally-verified identities as UCAN delegation subjects. Such identities, including email addresses, OAuth-based identities, and others, have no associated keypair under user control, and therefore cannot sign UCAN delegations directly. A trusted authority performs an out-of-band verification (email loop, OAuth exchange, etc.) and produces a cryptographic attestation on behalf of the subject identity. A generic Varsig signature type (`authority-attestation`) is defined that encodes the authority's attestation in place of a conventional asymmetric signature, with the specific verification method encoded in the attestation payload rather than the type. This allows attested identities to appear as `iss` in root UCAN delegations while remaining structurally honest about the nature of the verification performed. | |
| This document proposes a generic scheme for using externally-verified identities as UCAN delegation subjects. Such identities, including email addresses, OAuth-based identities, and others, have no associated keypair under user control, and therefore cannot sign UCAN delegations directly. A trusted authority performs an out-of-band verification (email loop, OAuth exchange, etc.) and produces a cryptographic attestation on behalf of the subject identity. A new Varsig signature type (`authority-attestation`) is defined that encodes the authority's attestation in place of a conventional asymmetric signature, with the specific verification method encoded in the attestation payload rather than the signature type. This allows attested identities to appear as `iss` in root UCAN delegations while remaining structurally honest about the nature of the verification performed. |
|
|
||
| ### 3.1 `did:mailto` | ||
|
|
||
| 1. The client authors a delegation payload in which the `did:mailto` issues some capability to the client's agent identity, and issues an invocation to the authority asking for it to be signed. |
There was a problem hiding this comment.
| 1. The client authors a delegation payload in which the `did:mailto` issues some capability to the client's agent identity, and issues an invocation to the authority asking for it to be signed. | |
| 1. The client authors a payload that describes a delegation in which the `did:mailto` issues some capability to the client's agent identity, and issues an invocation to the authority asking for it to be signed. |
There was a problem hiding this comment.
"Delegation payload" here is meant to refer to a literal payload portion of a UCAN delegation, but it sounds like it's coming across as "a payload which is an entire delegation". Maybe I should make it "the payload portion of a delegation"?
| 1. The client authors a delegation payload in which the `did:mailto` issues some capability to the client's agent identity, and issues an invocation to the authority asking for it to be signed. | ||
| 2. The authority computes a an HMAC over `(delegation_payload, iat, exp)` using a key the authority controls, where `delegation_payload` is the canonical (DAG-CBOR) encoding of the delegation payload, `iat` is the time the link was issued, and `exp` is some expiration time for the link. `iat` is optional, but will result in a timestamp on the final signature for tracking purposes. | ||
| 3. The authority sends an email to the address encoded in the `did:mailto` DID, containing a verification link pointing back to the authority's web server. The URL's params include the delegation payload, the `exp`, and the HMAC, suitably encoded. | ||
| 4. When the user clicks the link, the authority validates the HMAC. |
There was a problem hiding this comment.
This is not how things currently are implemented (we use a signed invocation not HMAC), and I'd probably adjust the spec to allow this process to be done differently, perhaps within some guide rails.
I think you already know, but just incase, there's a description of the current process here: https://hackmd.io/VUuW15CeRI6J1ZIR2yZwpA?view#accessconfirm
There was a problem hiding this comment.
Yeah, I've been thinking this through, and I was sure there was a reason an invocation didn't make sense, but…I don't see it anymore. This section's evolved a bit so maybe I just worked myself into reimplementing a worse version of the invocation. 😅
|
|
||
| The authority MAY define a policy governing what delegations it will verify and attest to, and reject requests which are not permitted by that policy. For instance, the authority may reject delegations without a recent `nbf` ("not before"), or with an `exp` ("expiration") that is `null` or too far in the future. To reject an attestation request, the authority MUST return a failure for the original attestation request invocation. If it does not reject the request, the authority MUST use the delegation payload as given, with no changes. | ||
|
|
||
| The verification link should have a reasonably short expiration. 15–60 minutes is RECOMMENDED. |
There was a problem hiding this comment.
I think 60 minutes is a long time. I would say 10 minutes (or shorter) is usual for this type of thing. It really shouldn't take that long to log into your email nowadays. I'd perhaps rephrase to say something like "recommended to be no longer than 15 minutes".
|
|
||
| The verification link should have a reasonably short expiration. 15–60 minutes is RECOMMENDED. | ||
|
|
||
| The authority MAY use a digest in place of the full payload in the URL, but this requires it to store the pending payload while waiting for verification. In this configuration, the stored payload can be evicted from the store when the link expires. |
There was a problem hiding this comment.
Yeah I think enumerating all the different ways to do this is not necessary - just saying you get to choose how to do this (out of scope) is fine IMHO.
| 0x34 Varsig prefix | ||
| 0x01 Varsig version 1 | ||
| 0x300001 authority-attestation algorithm discriminant (varint) | ||
| 0x71 Payload encoding: DAG-CBOR |
There was a problem hiding this comment.
A previous version of this RFC included the authority DID here. Why would we not do that?
If we continue to not, then there is an earlier mention of it in the intro I think that would need to be removed.
There was a problem hiding this comment.
Oh, shoot, I thought I got them all.
I couldn't come up with a reason it was still useful, but maybe it is? You don't need to know it to interpret and validate the signature. On the other hand, it does correspond with the verification method's content. But back on the first hand, a public key appears in a Multikey verification method, and the key doesn't appear in a corresponding Varsig; you're expected to know the public key you expect already.
| * **`nonce`** is empty. As an assertion of fact, the invocation is inherently idempotent. | ||
| * **`exp`** is `null`. As an assertion of fact, the invocation cannot expire: the signature cannot have not happened because time has passed. The delegation's `exp` controls the expiration of the delegation. |
There was a problem hiding this comment.
Not sure about this. It feels valuable to be able to expire the attestation, but conversely I think "the signature cannot have not happened because time has passed" is a fair point.
Don't oauth access tokens have time bounds that would be useful to echo in exp?
Login session lengths are a thing - logging in again after a certain period of time seems like a good idea...
There was a problem hiding this comment.
Yes, but all of that is the delegation's exp, which is why the service is allowed to constrain what exps are allowed. But the signing still happened either way. It gets a bit weird if you can have a delegation which hasn't expired, but whose signature somehow has. I suppose the closest analog is when a principal rotates keys and invalidates their old signatures, but that's not a fun situation.
|
|
||
| ## 5. Verification | ||
|
|
||
| When a verifier encounters a delegation with a Varsig header with the algorithm discriminant `0x300001`, it should: |
There was a problem hiding this comment.
Just thinking about this, I'd implement as a varsig codec and did verifier resolver in libforge that we use in sprue (and elsewhere). That is to say, I'd not add it to ucantone - we have spec'd this here, but it is by no means canon and is certainly not part of the UCAN/varsig or DID specs.
There was a problem hiding this comment.
That makes sense to me. I also think it makes sense in ucantone, since the verifier resolvers are all registered extensions anyway, not core to the library—they could just as easily each be their own separate modules. But if we're worried about ucantone vouching for it too much by including the implementation in the module, libforge makes sense. The registry architecture makes it simple to move at any time.
📖 Preview
An attempt to solve the weirdness of how we do attestations, and to extend into OAuth and other systems. I'm going to hold a discussion session to talk through this.