jiebi/CodeConvo huggingface dataset:
The only viable way to convery the cert info is via the ticket anyway, because several consecutive connections may reach different LBs and there's no way to be faster than light to synchronize them on any external data. What you mention about BoringSSL is interesting given that it derives from OpenSSL. I'll suggest my coworkers to have a look there, in case we'd find that the behavior is configurable. Anyway, my point remains about the importance of mentioning this in the spec (not the details). Just putting a big warning about the fact that the presence of certificate information in resumed sessions is implementation-dependent, because that's an easy trap everyone falls into, and that's too bad when it serves to design an architecture and is discovered after deployment.
(BoringSSL's behavior was one of the things we changed from OpenSSL's. OpenSSL only retains the leaf certificate across resumption. We found that having different information available across resumptions led to bugs.) That, alas, does lead to a huge ticket as NAME mentioned. There's a third solution which avoids this and I think demonstrates an issue with this draft's kind of TLS/HTTP split. (We haven't implemented this in BoringSSL, as client certs aren't a huge priority for us, but I think it's clearly the right design.) At the end of the day, your server presumably uses client certificates as the proof for some sort of application-specific identity. That identity may be an email address, a username, or something else entirely. You can think of the VerifyCertificate process not as returning yes/no, but as returning the verified identity or an error. If you can capture your application-specific notion of identity, that's all you need to retain after the handshake and in the ticket. It's also all you need to pass down to the application. This will be much more compact than the input certificate chain. But it's incompatible with this and headers, which use a much larger intermediate representation. Of course, per the "don't make resumption behave differently" rule, any application which does this should make the full chain equally unavailable on initial and resumption handshakes. (As an analogy, when clients verify server certificates, the identity is the SAN list, perhaps with some metadata like expiry. We don't really need the original certificates.
Though browsers tend to provide these silly "view certificate" buttons, so we've got a bit of a hard time there.) Back to the original topic, I think we need to treat resumption behavior as a prerequisite to deploying a system around or . If you retain the EE certificate across resumption, you can use and enable resumption. If the full chain is only available on initial handshakes, you must either disable resumption or not implement . Trying to do something clever across TLS and HTTP session state will not work. I've seen far too many cases of bad server deployments breaking flakily because the system made assumptions about the relationship between HTTP requests, connections, and TLS sessions.
I did have a moment of hesitation when writing "... or the resumption of such a connection ..." as I didn't know the details but figured there might be implementation-dependent limitations or variations around what/how data is retained across resumption. I don't think this draft can do anything about it. Other than a mention? What else can be said? Please propose some text, if you can.
Is there a reasonable way to say that, in order to use / , the TLS implementation needs to retain the client cert info across resumption or not offer resumption to clients that established mutually authenticated connections?
For me it's not possible to "maintain" it as it's not necessarily the same physical machine. And one essential property of tickets is that they're usable across a fleet of reverse-proxies who share the same keys. I tend to think that it's not this draft's business to try to solve the TLS-level problems nor architectural shortcomings, however the draft needs to warn unsuspecting adopters about them. Something around this maybe ? "The ability to extract a client certificate and/or an issuer chain from a resumed TLS connection is entirely specific to the implementation and sometimes also to the TLS version in use. Implementers are strongly encouraged to verify if their implementation matches their expectations or to make sure the application has some way of retaining such information once already learned. One possibility to work around implementation limits is to completely disable resumption when client-cert is needed".
Thanks NAME I can work with that or similar. Probably/maybe in the Deployment Considerations somewhere like a new subsection. I'd love for NAME to take a look and tell us why it's wrong though and how it could be better.
I might add David's suggestion to recommend against providing a value that won't be consistent after resumption, so:
I guess I'm fine with Martin's proposal.
I'll borrow from both suggestions to piece something together.
Opened since it would be good to also have discussion in Security Considerations. There are some very sharp edges here (beyond the ones mentioned already) due to variations in how implementations do resumption and client certs in combination in ways that could be surprising to people who are not experts in TLS implementations.
Clarify validation around no duplicate digests in the payload (directly or recursively) and no unused disclosures at the end of processing (to & )
SD-JWT validation processes should require that the validating party (Holder or Verifier) validate that the hash of each disclosure object appears in the Issuer JWT claims. If this validation is not performed, then the SD-JWT format is malleable, in the sense that arbitrary additional disclosure objects can be added beyond those that the issuer intended. This creates the opportunity for mischief, from bugs to covert channels. This is not a difficult property to enforce. The already has the validating party compute the lists of (1) hashes of disclosure objects and (2) disclosure hashes in the Issuer JWT. So the only additional step required is to check that (1) is a subset of (2).
That requirement that the hash of each disclosure must appear in the Issuer-singed JWT is in the current draft text - near the top of has "a Holder or a Verifier MUST ensure that ... all Disclosures are correct, i.e., their digests are referenced in the Issuer-signed JWT". Seems it could be made more explicit or clear? But it is there.
Ah, thanks, I had missed that. Even given that though: I would not call this property "correct". The only other place that property appears is in 11.2, so maybe it can just be dropped, and we can just say directly "All disclosures correspond to a hash value that appears in the Issuer JWT" Given recursive disclosure, though, even that's not really sufficient. A recursively disclosed claim does not in fact appear in the Issuer JWT -- you basically need to verify that it hash-chains into the Issuer JWT via a series of disclosures If we're going to eliminate recursive disclosure, I think the current text probably suffices (modulo "correct"). But if we're going to keep it, we need to elaborate the algorithm. Maybe it can be folded into the existing recursive algorithm as a termination condition. If you're adding the hashes inside disclosed values as you restore them, then if you get to the point where none of the claim hashes are in the set of disclosure hashes, then if the set of disclosure hashes is non-empty, the object is invalid.
Assuming here in this ticket at least that we are not going to eliminate recursive disclosure.
The use of "correct" is indeed awkward and that whole bit of text could be improved. There's room for a lot of improvement there. I've always understood text like "referenced in the Issuer-signed JWT" as intending to mean included directly in that JWT but also included recursively. But being more explicit is probably worthwhile. I think it'd be sufficient to say somewhere something like "all disclosures must correspond to a hash value that appears (either directly or recursively) in the Issuer-signed JWT". That somewhere could be in place of the "all Disclosures are correct" text and/or a step in the validation steps near . To you earlier point - it's not a difficult property to enforce. Even with the recursion. A validating party needs to compute the lists of (1) hashes of the disclosure objects and has to look at (2) all disclosure hashes in the Issuer JWT (including by recursive inclusion). The only additional step is still just to check that (1) is a subset of (2). Which is basically just checking that there were no unused disclosures at the end of processing.
Agreed, if we can update the algorithm to reject if any hashes are left over, then that would fix this issue.
Great, I think we can update the the algorithm to reject if any disclosures are left over. It'd probably go near the check to ensure that no digest value is repeated in the whole of the SD-JWT - either in the payload directly or recursively in any disclosure (that check about duplicate digests needs a bit of improvement too). Also we should tidy up that text with "correct".
From the mailing list Hi Jacob, the intention was to cover the first case you listed. We should clarify this. -Daniel Am 20.10.23 um 15:02 schrieb Jacob Ward:
my 2 cents at/from URL
Also... um, wouldn't "More than one Disclosure have[ing] the same digest" imply a collision in the hash function? And therefore infeasible to actually happen. Agree that it should be clarified. Being precise with language around this stuff is tricky. But my understanding of the intent was to ensure that no digest value is repeated in the whole of the SD-JWT - either in the payload directly or recursively in any Disclosure.
... or the analysis in the security considerations. We had to walk a more careful path when RFC 7540 was published, so we were careful to legitimize h2c. In the years since, things have changed and we can be more direct. This isn't a "don't use h2c", but more of a disclaimer as far as security goes.
Maybe a hangover from trying to tear up the photos of the "http" URI and upgrade dance. But this seems to read oddly. On one hand: on the other: I don't have a solid suggestion to improve things.
How about we just remove "h2c" from the latter statement.
OK, that isn't going to fly. I just tried it. Pulling that string is unwise. We agreed to keep "prior knowledge" in the document, and the "h2c" ALPN token is part of that. The "h2c" upgrade token has been removed already. (Too subtle? Probably.)
though I'm not sure it's yet precise enough. There are three general classes of errors: The peer did something wrong. There are relatively few of these possible -- indicating more certificates to use than were requested, or more than one unsolicited certificate; sending CERTIFICATE_NEEDED to a peer that didn't indicate support for this extension. The authenticator is corrupt. This might indicate a problem with the TLS connection. The certificate isn't acceptable. There are lots of reasons this might happen. The first two should be at least stream and possibly connection errors. The latter should be handled at the HTTP layer, but previously had error codes defined for them. This PR removes several error codes and recommends handling at the HTTP layer if the certificate isn't accepted.
It is very unclear from the draft how exactly the client should handle a secondary server certificate it rejects. Presumably a bad secondary certificate should not be fatal to streams which don't use it. The draft seems to handwaive at this (though not very clearly, which means uncertainty for the server) in section 4. At the same time, the draft says: This is inconsistent with that idea. Suppose the server pushes some CERTIFICATE frame along with some resources it thinks the client would want. If the client rejects that certificate, this text implies the client must tear down the entire connection, interrupting unrelated requests. A useful heuristic for reasoning through all this would be to consider a client which blindly rejects every secondary certificate. This is especially relevant if the draft does not act on .
The restriction on the server is that it not push unless it has first sent the certificate. If the client rejects the certificate, clearly it will discard the push; the question is whether the client will be able to differentiate failure-to-send from cert-not-accepted. That depends on whether you assume that clients will look at the certificates, even if they aren't accepted; otherwise, I suspect that it can't. However, I think you're right that this is an overreaction. RFC7540 requires that a PUSH_PROMISE for an unproven origin be treated as a stream error, but doesn't specify on which stream. The parent stream still seems excessive, since the server can't know for which origins the client considers it authoritative.
addresses issue
The way it is written now does not look like terms and definitions. It would also be a good practice to make it possible to the definition to replace the terms that appear in the main text. With this respect, verbose explanations especially the mechanisms should be done in the "Concepts" section in the main text. In fact, much of the text in the current "terminology" mostly duplicates what is being explained in 3. Concept Also, examples etc. should be added as a note to the definition and not as part of the definition text. Proposes the following as amended text Terms and definitions 2.1 SD-JWT signed JWT ], that supports selective disclosure as defined in this document Note to entry: Signed JWT is JWS. 2.2 release (SD-JWT-R) document that contains a subset of the claim values of an SD-JWT in a verifiable way Note to entry: Holder binding is also possible. 2.3 issuer entity that create SD-JWTs (2.1) 2.4 holder entity that has control over SD-JWTs (2.1) Note to entry: If holder binding is desired, the holder also has the signing key for the verification key contained in the SD-JWT. 2.5 verifier entity that checks and extracts the claims from SSD-JWT-R (2.2)
closing with PR
Currently, it has Conventions and Terminology Terminology Having two "Terminology" as consecutive headings is not good. I propose to change 2 as follows: Terms and Definitions
closing with PR
Addresses Issue
I also revisited the security recommendations for the salt and made some smaller changes there.
user has 2 SD-JWTs from the same issuer, same blinded claim names can be used to correlate the user. advice to have a fresh blinded claim name for each credential.
Instead of opening a new issue from our conversation this morning - here is the excerpt & suggestion from the document we discussed: First off, maybe it's informational or maybe it's specified - issuers should not include "secrets" in claim labels. If a label for something is actually a secret, it should be treated as such. That said, I get that this scenario must be addressed. Sensitive predicates or graduated disclosure contexts can benefit from this capability. It seems to me that the most useful and easy algorithm to implement is to use the same hash algorithm + salt for the node value to blind the label where: SALTED LABEL = HASHALGO(LABEL + SALT) Of course, this assumes that specific guidance is included for best practice salt generation (fresh entropy gathering for each attribute block salt, sufficient bits of entropy, etc.) for strong cryptographic outcomes. In this representation, the salted hash of the label's value ("name") "9-J2445ap91..." can be addressed directly by the digest "h" value in compact form: Side-note: Informative statements that recommend large sd-jwt claim sets should be 'broken down' into much smaller sets, or individual claims, then wrapped and sealed as a JWP may be better than including too many claims in an sd-jwt.
Right now, it is RECOMMENDED that a random string is chosen for the blinded claim name. HMAC(salt, claim-name) and HASHALGO(LABEL + SALT) would be fine as well, but there's more room for errors, especially as holders/verifiers might expect a specific format and then reject an SD-JWT when, e.g., the issuer chose a wrong encoding or similar. I don't see a real advantage of using HMAC/HASHALGO for the blinded claim name. I therefore propose to stick with the current recommendation. We should stress that a fresh random value must be chosen for each claim in each issued credential.
NAME it's not super clear to me how: would alleviate your concerns here: "but there's more room for errors, especially as holders/verifiers might expect a specific format and then reject an SD-JWT when, e.g., the issuer chose a wrong encoding or similar" Maybe I'm missing something obvious but I don't see much difference in how holders & verifiers would treat these various approaches. They still have to reconcile with the encoding and/or hashing algorithms expressed in the security envelope.
My point was about the selection of the blinded clame name (or 'placeholder claim name' as it is called in the current draft). We have two options on the table: Select a random string as the placeholder Select the placeholder as some function of the original claim name (the label in your proposal) and the salt What I wanted to express is that I think option 1 is better. From a security perspective, both are equivalent. There is no need to choose the placeholder claim name in a particular way, we just need to ensure that it does not leak information about the original claim name. Just numbering all placeholder claim names would be fine as well (as long as the numbering does not reveal anything, e.g., the position of the original claim in the list of claims.) But for option 2, I see two drawbacks: We need to explain more, in particular how to assemble the input for the function, similar to the discussion we had about the hidden claim values. For example, we need to define how the original claim name and the salt are concatenated such that there can be no prefix collisions. A verifier receiving an SD-JWT with blinded claim names according to option 2 may be tempted to (needlessly) check that the claim name was created in a particular way by recalculating the hash. If the issuer has made a mistake when calculating the hash or the verifier makes a mistake, this check will fail. Since such a check is not needed, it would be better if we don't set this trap in the first place. I see no advantages of option 2 over option 1, so I propose to go for option 1.
I see, thanks for explaining that. I'm fine with option 1 if the goal is to reduce cognitive complexity for the application developers - it makes sense.
says: [...] says about : [...] Because we're saying that validation occurs against all responses for a given URI (see ), this has the effect of allowing a response with a header to update all of the responses sent for that URI in that second (provided the requirement about is met) -- which would lead to e.g., response with updating other languages. That probably isn't desirable. The obvious way to fix this is to avoid promoting to a strong validator when it's being used by a cache. However, see -- it's necessary for it to be strong for . It might also be worth refining caching 3.4.3 to differentiate between entity-tag updates and last-modified updates.
In 4.3.5, updating is done like this: Note that it's specified in terms of responses that could have been selected for that request, rather than "stored... responses for the applicable request URI." If we modified 4.3.4 to specify that responses that could have been selected for the request sent are updated (still subject to further filtering down by any validators in the 304 response), I think it should work.
Feel free to change the numbers to any ones you prefer.
There's a single SETUP message, but the contents change based on if the endpoint is a server or a client. . This is difficult to implement in type safe languages. I would implement and , sharing the same ID. However, it's then difficult to implement a generic method as it needs to know the expected role to distinguish between the two. I propose a separate and message akin to how TLS has a separate and . Alternatively, implement to reclassify SETUP and OBJECT as control and data stream headers respectively.
Hmm, so this isn't a problem in my code any longer since made SETUP a special message type. We should still figure out if both the client and server SETUP use the same ID, or separate IDs like TLS.
I still like the idea of, if these message are different, they should have different names as it will just be confusing if they do not.
Agreement these should be different message types, just like TLS.
Conveniently, message id=2 is currently not used. I propose ClientSetup = 1 and ServerSetup = 2.
Thinking about this a bit more, do we want to bake in the assumption that the client always speaks first into the protocol? For raw QUIC, typically, the server would have 1-RTT keys first.
I would love to see something like HTTP/3 SETTINGS where both endpoints can send the message in parallel. That requires version negotiation at a lower level in something like ALPN though. The SERVER SETUP would be sent first in native QUIC while the CLIENT SETUP could be sent first with WebTransport (in parallel with CONNECT).
LGTM
If merged this
Our abstract starts: "The IETF's standard congestion control schemes have been widely shown to be inadequate for various environments (e.g., high-speed networks, wireless technologies such as 3GPP and WiFi, long distance satellite links) and also in conflict with the needed, more isochronous, behaviors of VoIP, gaming, and videoconferencing traffic." ... is it just me, or does "inadequate" and "at conflict" seem an odd BCP statement from the IETF itself.
Agreed. How about something closer to: "The IETF's standard congestion control schemes have been shown to have performance challenges in various environments (e.g., high-speed networks, cellular and WiFi wireless technologies, long distance satellite links) and also for interactive traffic workloads (VoIP, gaming, and videoconferencing)." cc: NAME NAME
Clarifies the "returned value" expression.
There are two occurences of the fragment This is not the most helpful of statements, when we say "returned value" what exactly are we trying to convey. I think it would help to be a bit more exact.
Thanks. Longer term, I'd like to do an broad editorial sweep to tighten up document and this is an enabling step that I think this takes us most of the way there. I made some suggestions to move words around a bit.