The original framing might have implied that they can't be sent, where it's just that they are the same as anything else.
In s 6: This is just a bit weird -- some may read it to mean that these messages can't be conveyed in this format.


For the avoidance of doubt. This makes encoding easier if you don't care about wasting a few bytes.
The binary messages draft uses QUIC variable-length integers. Those allow encoding numbers multiple ways (for example 42 can be encoded minimally as 0x2A but also non-minimally as 0x402A). The draft should clarify whether using non-minimal encoding is allowed or not.
Thanks!


by using a citation rather than a redundant and wrong statement. by removing the minimum length (zero is totally fine).
The Known-Length Messages section states that whereas the Header and Trailer Field Lines section allows empty field values. Which is it?
Editorial error on my part. Someone pointed out that fields can have empty values (yet another feature of the protocol that is weird and unnecessary). I fixed it one place, but not the other. Thanks for noticing.
The draft currently shows: This Length field isn't well defined. Is it the length of the Known-Length Field Section in bytes or in lines? If in bytes, does it include or exclude the length of the Length field itself? Either way, I don't understand why Length is at least 2. Either it's possible for there to not be any field lines, in which case maybe it should be zero. And if there needs to be at least one field line, then (we should say so, and) the minimum number should be 3, because a field line is two lengths and at least one byte of field name.
To pile on here, the spec also says in one place and in another It's a little ambiguous but f the value also can't be zero-length, then the minimum should be 4? (by David's second interpretation)
NAME see
Yeah saw that after hitting the button. Didn't intend to derail
Thanks!


Basically, it saves the effort of writing stuff that you know to be empty. It's not a critical feature, but it turns out to be a simple way to deal with not sending trailers or a body. In the extreme, you can also drop headers to produce the simplest and shortest HTTP message ever: 0x0140c8. CLoses .
Hey David, I've made some larger edits here to factor the truncation text better. I've included your normative language.
The draft mentions that messages can be truncated in some places, but not in others. I think it would help to explain why one would want to truncated a message.
This is really just a neat way to avoid having to write out all of the pieces of a message. So if you don't have trailers, it's OK not to say "I have 0 trailers". The decoder is required to deal with it. Before you say "that's hard", you don't need to change the parser to deal with truncation. Adding three zero-valued bytes to the end of any message you receive does the job just fine. If it isn't truncated, those will be treated as padding.
Thanks


The diagram resulted in a few double-takes that might be helped by a little bit of a note pointing this out.
I suspect that requests do not carry the Known-Length Informational Response field (otherwise how do you know how many of them there are?) but that should be spelled out explicitly. I'd suggest creating a different diagram for known-length request vs known-length responses to make this easier to reason about, and same for indeterminate length
I think the optionality is supposed to be indicated by the three trailing dots . I admit to doing a double-take on this during my initial review, similar to David's question. It's optional for a server, sure, but it's never optional for a request just wrong. I agree that separate diagrams would help, at the minor cost of some page space.


A combined "field value" is a term that HTTP defines, but we didn't link to that. Also, the structure of this paragraph was a little more terse than it needed to be.
Security Considerations state: but the Header and Trailer Field Lines section states: The same field name can be repeated in multiple field lines; see Section 5.2 of HTTP for the semantics of repeated field names and rules for combining values. This leaves me confused, why would it be necessary to produce a combined value if repeated field names are allowed?


Includes several document cleanups for signatures, to publish as -09
Also: If there is no query string should the corresponding signing text be or ie. should the query value be empty or just consist of one Should we return with this request and return on this request This is what I opted for in my implementation. See shows that http4s makes the distinction between blank queries and empty queries is simpler I think this is a corner case that is worth explicating very clearly, perhaps even with a test.
There are quite a few occurrences of the header in the draft. From an implementation point of view, Go "swallows" the header and it is not part of the standard Request structure. There's a good reason for the Go library to do it, and in fact the draft recommends to use NAME instead. Can we remove from examples, e.g. Sec. 2.1, so we don't train people to do the wrong thing?
There are only a couple instances of the "host" header in the current draft left, and one of them (section 2.1) is specifically about how to format headers. It could be removed from the other example signature input strings without affecting anything negatively. Same with the "date" header, which could be confused with the "created" parameter, see
This sentence is correct: But it's true for most reasonable uses of , and people will still be using this parameter. So why not add:
No, we explicitly did not want to conflate this with the jwa registry. We also didn't want to have a second tier choice like having "alg=jose" and then having the actual algorithm elsewhere, since a big problem with late editions of the Cavage draft were exactly that process. (See the mess around "hs2019"). The editors discussed this at length and decided the best compromise was to define a way that jwa algorithms could be used in an interoperable fashion, but not to allow runtime signaling with them. Better to have the choice of jwa be signaled within the application level. Additionally, it's preferable to not use the runtime parameter to signal the algorithm any way, which is discussed at length in the security considerations.
All good, so why aren't you using normative language?
It's not normative because this section defines the algorithms, not the parameter. We didn't want to make it seem like the parameter was the "right" way to signal algorithms here, and most certainly is not required. You'll notice that none of the other sections have "MUST use the alg parameter value of 'foo'" either. Older Cavage drafts relied on the parameter, albeit in a much less secure fashion, and implementations were susceptible to algorithm substitution in the same way that naive JOSE implementations tend to be -- the "alg: none" attack all over again, more or less. The value of the parameter already MUST be something from the registry, and the registry does not (and will not) contain JWA values. So you already aren't allowed to do it, normatively, and the note is our attempt at explaining the why. Ultimately, an implementation is allowed to use whatever algorithm they want and makes sense. What this whole section does is define a set of common usable algorithms as well as provide a pattern of applying crypto primitives that applications can follow for their own algorithms. If someone defines a new algorithm that's generally useful, like we recently did with the ed25519 here, it can be registered for use with the parameter. But if a system can base the algorithm selection off of the key material or another part of the protocol (like with GNAP), that's highly preferable and less vulnerable to substitution at runtime. I'd be happy to know how we can make this clearer in the text, but I'm not comfortable with that kind of normative construct in that section.
NAME -- would you like to chime in? I recall from our discussions you having another, more specific reason for this decision, but I can't remember the details beyond us agreeing to do it the way we have it in the spec right now.
Neither Java nor JS subtleCrypto come out of the box with PKCS1 PEM support. (for java ). It is not immediately obvious to work out that the PEM formats of the private key in in PKCS1 format (the spec could point that out). When building an implementation it helps to have the test suite clearly map to the data in the spec (e.g. ) so as to make error reporting clearer. That is even though using the following openssl command to convert the keys work, it makes it difficult to see if an error was introduced at some point. To support PKCS1 the developer has to depend on further less well tested libraries and add additional code (as I ) leading possibly to new bugs. Furthermore, I will need to go through the same process for JavaScript now, doubling the work. Since PKCS8 is as expressive as PKCS1 ( and see ), it would make life easier for devs if the keys were all in PKCS8 format. Unless there really is something that PKCS1 offers that PKCS8 does not? I will try doing this using the Web Crypto API next. But there we find that supports the PKCS format.
While I am at it. I am having trouble with verifying the signature for 3 out of 4 examples from the spec that I tried out in . Currently the only one that works is the . I am able to produce and verify a signature for , and examples, but the signatures don't correspond to what is in the spec. That may very well be a mistake in my code, which I am working on as a to bobcats scala and scala-js crypto library. But I just wanted to check how confident you were in your examples. I am going to re-implement next in JS, so that will give me another reference point.
I am working my way through this with JS. I was able to parse the and keys after translating them to pkcs8 format with openssl, but am having trouble importing in the console of Chrome, Chrome-beta, Chrome-Dev and Safari. I guess that is in pkcs8 format already. I don't have trouble parsing that key with BouncyCastle... I guess this is a little config problem, but it's difficult to work out what that could be... Perhaps someone has an idea?
NAME Since this all has to do with the examples in the text and not the spec itself, I think we'd be fine with having the keys in multiple formats if it's useful for developers. However I'll note that in many code libraries you need to add the PEM headers of and for their compliant parsers to parse an EC key in PEM format, for example. I've been able to parse these keys in both Java and Python, and in fact all the examples are generated using a python script: URL Also, note that RSA-PSS and ECDSA are non-deterministic signatures that incorporate a source of randomness into the signature calculation. This might be why you're getting valid signatures that look different from the examples -- you shouldn't expect to replicate the exact signature values. RSA 1.5 is deterministic, and will always give this same signature for the same input (as will HMAC). This is just one of the reasons why it's not recommended in many environments. I think we can add some text in the examples sections that points this out, if that would be helpful.
NAME You can also test keys and examples at URL for another implementation. I am pretty confident in the values in the examples, but if there are in fact bugs in these implementations (which is always possible!) I'd love to know and fix them.
NAME you were right. I had been verifying the keys by string comparison, so I fixed that. I also worked out what the Java names for the various algorithms were and got nearly all the tests to run on JS and Java platforms. But there is one error left that is consistent across both, so I wrote it up here. URL
Nevertheless, I have not yet been able to import the private key PEM file in JS. So I looked for a way to convert it to JWK to see how that would fare. I looked online, but none of the services worked, I looked at npm but that did not work, finally I found in Java that did the conversion in 2 lines of code. With this I could get signing to work: So there is something problematic with that PEM, at least insofar as it makes it very difficult to get the example to work in JS which should be one of the main platforms. (I have not yet verified the signature in JS as I am having trouble getting verification in JS to work with a valid PSS key, even though I can create the public key with the PEM, and am able to do that Scala-JS)
I think I found the problem to be with the private key. After going through this process: transforming the spec key to JWK as described above transforming the JWK to PEM PKCS1 using node's I get the following transforming the above using Java's Bouncy Castle to PEM I get this: And with that all the JS crypto API tests pass. See the .
I think to understand why that final private key works with the Java Web Crypto API but not the original one from which it was derived (which worked with Bouncy-Castle) we'd need the input of someone like NAME . With that public key replaced (in commit ) and a few others commits to get Continuous Integration to work, we have all the tests pass for Scala compiled to JavaScript Those running in the browser are a bit interleaved due to asynchronous execution, something that needs still to be fixed.
Looks good!


: These rules do not permit whitespace between a semicolon and a parameter, which was probably intended (judging from the examples and from similar rules elsewhere in HTTP). They should be rewritten as follows: and the import of the rule from RFC 7230 should be noted in the preceding text (“The "Encryption" header field uses the extended ABNF syntax . . .” and similarly for ).
Thanks for picking this up.


no normative text in security considerations.
no normative statements in security considerations
Separately, this could be read to imply that a TCP checksum is sufficient. I'm not enthusiastic about that, URL Originally posted by NAME in URL In reply, I said
This has been slightly modified by ... TLS can't probably be normative, but people already knows...


simplifies IANA field registration section obsolete Digest
Thanks for this, it's almost there. I suggest we just have two sections that ask IANA to do things directly, rather than giving any prelude to those instructions.


Includes some new text and several small cleanups.
did you forget to merge it?
Sorry, there was ice cream cake and I got distracted
Some header field values are case-insensitive, in whole or in part. The canonicalization rules do not account for this, thus a case change to a covered header field value causes verification to fail.
While I'd just put a warning on that, it would be great to have some examples/use cases for that.
Intermediaries are permitted to strip comments from the header field value, and consolidate related sequences of entries. The canonicalization rules do not account for these changes, and thus they cause signature verification to fail if the header is signed. At the very least, guidance on signing or not signing headers needs to be included.
Let's add a paragraph with some caveats and header examples.


I missed this from NAME but it's a point well-taken. Not defining this was sloppy.
This was buried inside which was closed so I'm opening a new issue. The draft currently shows: This Length field isn't well defined. Is it the length of the Known-Length Field Section in bytes or in lines? It would really help if this draft defined every single field it declares.
The draft currently shows: This Length field isn't well defined. Is it the length of the Known-Length Field Section in bytes or in lines? If in bytes, does it include or exclude the length of the Length field itself? Either way, I don't understand why Length is at least 2. Either it's possible for there to not be any field lines, in which case maybe it should be zero. And if there needs to be at least one field line, then (we should say so, and) the minimum number should be 3, because a field line is two lengths and at least one byte of field name.
To pile on here, the spec also says in one place and in another It's a little ambiguous but f the value also can't be zero-length, then the minimum should be 4? (by David's second interpretation)
NAME see
Yeah saw that after hitting the button. Didn't intend to derail
Thanks


S 3.6 says that extension pseudo header MAY be included but they have to appear before other field lines. An easy detail to miss buried in HTTP/2 is the requirement does that also apply here?
LGTM thanks


If it wasn't your thinking already, I'd like to suggest that the derived component be the singular instead. When canonicalizing individual query parameters, each component identifier references a single query parameter name/value pair. The use of singular feels more appropriate to me: In the rare case where there are multiple query parameters with the same name, each one's canonical representation is still referring to a single name/value pair, so the singular still feels more appropriate: When used in the list of covered components, we still include the parameter, so each component identifier is usually [1] referring to a single query parameter name/value pair: [1]: However, in that rare case of multiple query parameters having the same name, one instance of would cover all instances of that repeated query parameter named . Perhaps the plural does make more sense for this scenario. But if there must be a singular/plural mismatch somewhere, I'd rather see it in the more rare and exceptional case. So I would propose using the name instead of . In , I see that a recent addition implemented it as the singular . I wonder if drafters already had this change in mind or if it might have been an oversight that organically tended toward what feels more natural.
Thank you for bringing this up, I think this is a valid point. I don't think there's wide support for this derived component yet so now's a good time to change it for all the good reasons you mention.
Looks good to me, will leave for a beat to get feedback from others.


"The record starts and ends on multiples of the record size" sounds like a tautology.


NAME - that does not seem to work as expected. See the output at URL
Understood. I personally inline everything always, so outages, bugs, and not-yet-published states simply do not affect me :-)
Please note that, per the rest of this cluster of documents, the reference citation strings "[HTTP2]" and "[HTTP3]" have been changed to "[HTTP/2]" and "[HTTP/3]", respectively. Please let us know any objections.
That does not seem to work as expected, see output at URL
See URL for how to do this in Markdown
I struggled with this in my own draft, the instructions in the style guide didn't seem to work, guessing they will once the RFCs are actually published. I copied Mikes approach, but H3 dgram solved it with what looks like a simpler approach URL
They key part is that "/" can not be in the reference name (because it's not legal in an XML ID), thus needs to go into "title". That may not have worked locally unless you have a recent version of kramdown-rfc2629.
If I do and ref RFC91113. Then make causes kramdown to blurt out and the HTML output is Versions:
Oh, that's because the XML reference file will not exist until that RFC is published. You need to inline all the information.
yeah, that's what I meant by my unclear statement "Mike's approach" - see URL But that's like a million miles off what the style guide suggests, and is annoying while we are stuck in this temporary purgatory :D
So there are two issues here combined: citing something as RFC which is not published overwriting the reference name The latter thing is what the style guide describes; for the first issue only inlining everything helps. (I personally inline everything anyway, so it didn't occur to me that that's the problem you encountered :-)
AH! Thanks for the info and pointers. I've sent out to fix.
I didn't even know what David did was possible. Magic!


NAME I think I did the needful here by cargo-culting . Does this look good to you?
Thanks for the suggestions!
(not tested, but if it ends generating the desired output...)


Typi fix
I had to read that three times to spot your change. Something about that text blinded me to that.


Right now, it's inconsistent in the document. HTTP core just uses an unquoted version so I'm inclined to just use that


try to say that for multiple post-handshake client certificate authentications, only use the last one (to
TLS 1.3 post-handshake authentication enables the use of multiple client authentications. The draft probably needs to address this. Firstly, the proxy could be smart enough to know which certificate applies. After all, it needs to know how and when to ask for a certificate. If it is that smart, we don't have a problem. If not, then... For , this is easy. If there are multiple certificates and the reverse proxy doesn't know which to include, it can include all of them. It's easy enough to add extra values. For this is less easy. There would be no way to distinguish which intermediate related to which end-entity certificate if you just added them all. I don't think that's fatal though. Chain building for validation always has to deal with certificates that don't do anything, so maybe we can just dump them all in there and let the back-end server sort them out. In terms of actions, we can say something like:
The draft currently , which precludes multiple values/instances. I am very reluctant to change that in support of something that rarely if ever happens in practice (it would mean HTTP/1.1 with multiple TLS 1.3 post-handshake authentications or post-handshake authentication(s) after a client cert authenticated handshake). Could we instead just say the first/last one is used? Then it's predictable/defined should it ever happen. Or declare it out of scope. Existing related text from URL is copied here: >HTTP/2 restricts TLS 1.2 renegotiation ( of ]) and prohibits TLS 1.3 post-handshake authentication ]. However, they are sometimes used to implement reactive client certificate authentication in HTTP/1.1 ] where the server decides whether to request a client certificate based on the HTTP request. HTTP application data sent on such a connection after receipt and verification of the client certificate is also mutually-authenticated and thus suitable for the mechanisms described in this document.
I could live with picking the last in the absence of information that might allow for another to be selected. But what harm is there in using a list?
Makes it all more complicated b/c everything then needs to treat it as a list and reason about it being a list. The value in typing something as what it is seems self-evident so I'm at a bit of a lose as to how else to answer that question.
WFM.


add a note about cert retention on TLS session resumption (to
Hi, given that I had the question today relayed from a customer by our support team, I had a second look at the draft to see what was planned for resumed connections, and I'm seeing this: The problem is, on resumed connections, the client does not present the certificate again, it will use a ticket or a session ID to match a cached entry or any other mechanism I'm not familiar with (please bear with me, I'm not SSL-fluent). In our case when this happens, the related fields are empty (since the info is missing from the TLS stack), and we encourage customers to log something else as a complement to match new connections against a previously verified session (e.g. session ID). I think it's important to explicitly state that such a certificate info is not necessarily available in such a case, and that either the proxy+application have to find other ways to persist the information between connections, or that the cases where the certificate is matched need to be narrowed down to the strict minimum. For example, I remember a decade ago when working for a bank that the security team absolutely wanted to distinguish really authenticated connections and resumed ones and that in particular they refused to consider as 2FA something that resulted from a resumed connection because they wouldn't be able to prove that the authentication happened at this precise instant if they had to defend this in court. After the different versions of TLS evolved, I'm not sure whether there is a stable session identifier that's available across multiple versions, but I do think that if we document a common method to pass this client-cert info to the server, we also need to provide "something" for all the resumed connections that do not convey that info anymore, otherwise users might fall back to poor solutions due to the difficulty of understanding all the details of the various versions (and it's very likely that I've been one of those giving such wrong advices, not knowing how to do better). It's particularly important in load-balanced environments because you cannot count on the front LB to keep a copy of the client-cert, as the resumed connection might very well end up on another node, and you cannot count on the server either since different requests will often reach different servers. So the only thing that remains is that "thing" that the client uses to be recognized on resumption (sorry for the imprecise language, it seems for me that up to TLS1.2 it was a ticket but I'm not sure for 1.3).
Hi Willy, This is likely a limitation of your TLS implementation. A perfectly reasonable limitation, but not something that is consistent across all implementations. What happens with resumption is that any state from the initial connection can be carried across over into a resumed session. Obviously, things that happened on the first connection after a ticket was issued can't be assumed to be available, but generally anything that happened in the original handshake could be used. What the specification assumes is that the details of the handshake are remembered and can be used again. There's a bunch of other stuff like which TLS version and whatnot, some of which the specification requires endpoints to remember (see for example , which insists that the KDF remain the same). When it comes to authentication state, however, TLS is not very consistent and so implementations are not. Some implementations (like NSS and Boring SSL) remember the client certificate. The way they do this is they put the whole certificate chain in the session ticket. That makes the tickets pretty large, which can badly affect the resumption handshake: whatever you save on sending certificates is eaten up with a huge ticket in the first message. Worse, this first message is bad DoS mojo as you have to accept a whole lot of state before you are really sure that the client is OK (there are ways around this, but they are all pretty bad). Others might save the certificates server side, but that adds a whole different type of fragility. Others just "forget" that the client offered a certificate. That last one is probably what you are seeing here. This is a whole new sort of problem to solve. What you might need in this case is a way to recover an old certificate from a log based on some identifier. The problem here is that the identifier isn't stable either. TLS doesn't have a single consistent value you can use across all versions and all types of resumption.
Hi Martin, thanks for the detailed explanation. 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.


Comment by NAME , Figure 1: , Figure 2: For consistency with the rest of Figure 1, you could add a comma after Content(..) and Chunk (..) : Missing word "message" : s/intermediate/indeterminate
Comment by NAME The document uses "indeterminate length" and "indefinite length" interchangeably. I would suggest either using only one, or adding "indeterminate" when the first "indefinite" appear, i.e. in :
Comment by NAME : Should these be "informational" rather than "information"?
Comment by NAME : Please reference RFC-ietf-httpbis-semantics, or , or the IANA registry: URL after "status code".
Comment by NAME : : I think HTTP/2 should be a normative reference.
Comment by NAME : Might be worth clarifying that this integer value does not include the length bytes. My comment comes from the fact that "field section" is the name of the structure containing the length, so "number of bytes in the field section" could be interpreted to include the length bytes itself.
Comment by NAME : : At this point in the text I thought this was missing the optional Informational response field, but you say explain that several paragraph later. Maybe clarify here that this is for messages that are not responses containing informational status codes, or move those paragraphs closer together?
I think that moving the paragraphs works best here.


Just a little more explanation. And .
Comment by NAME : I see that the talks about "final status code": and that explains why you called it "final" in , but I think you need to define why "final" is used in the "final response control data" when it first appear (so in ), or you can remove "final" in 3.5 and explain that only in 3.5.1.


Arguably a technical change, though as it is in a picture, so I want to highlight it. This is on top of , so just look at 5468983321b104de62b1aae8df8963ad1abd5fa9 if you want to see the "technical" change.


I had to read this several times to understand what parts of the sentence were replicated into the "or" part of the statement. Duplicating some words makes it a tiny bit more comprehensible, I think.
LGTM


Moving normative language from Section 6 is the most useful, but there are a bunch of other stuff I noticed as I was reading through trying to implement James' other suggestion.
lgtm


... and apparently some other stuff.
Should we recognise e.g., binary content in cookie values? If so, how?
Do you mind expanding on what you mean?
This is for the retrofit spec's cookie mapping](URL). Since many cookie's payloads are base64, it seems like it'd be beneficial to figure out a way to carry them as binary. I've been meaning to start a discussion with the cookie authors about this section of the spec generally to a) make sure it's a good idea and b) it's correct / doesn't cause problems. PTAL if you have time.
Maybe the right thing to do here is to introduce a new parameter that indicates the type of the value.
... except parameters aren't available on Cookie; just Set-Cookie. hmm.
Perhaps the most we can do is to say that the SF-cookie headers can have a value in any type, but they get mapped to the string value in "normal" headers. That way you can automatically convert SF-cookie to cookie, but not the other way around. The only alternative I see is to carry the type information in a separate header, which is not great.


Cookie attribute names are case insensitive, this PR adds a note saying as much.
The grammar implies that set-cookie attribute names are case insensitive (because ABNF strings are), and the parsing algorithms say that they're case-insensitive, but I suspect many people may not realise this, because they're so often seen in CamelCase. Could we add a small statement to the Set-Cookie syntax section pointing this out?
It's also worth having a variety of styles in the examples to illustrate this.


I still believe this change should end up in the revision of SF.
That's
Some have pushed back on using integers for dates, see eg URL As I suggested there, one accommodation would be to define a new structured type for them. That could be done in retrofit, or separately.
I see no mention of fractional seconds ? I think we need to ponder that, if the goal is (eventual) convergence for all timestamps in HTTP ? Considering how much effort we spend on speeding up HTTP, I find the "human readable" argument utterly bogus. Only a very tiny fraction of these timestamps are ever read by humans, and most are in a context where software trivially can render the number in 8601 format if so desired. In terms of efficiency, I will concede that, in a HTTP context, it is almost always possible to perform the necessary calculations and comparisons on raw ISO-8601 timestamps, without resorting to the full calendrical conversions, but once all the necessary paranoia is included, I doubt it is an optimization. My preference is seconds since epoch, (and this is largely why has three decimals in the first place), because it gives us fast processing, good compression and millisecond resolution. PS: A Twitter poll with only 40 respondents, carried out on the first monday after new-years ? Really ?!
One argument against any "seconds since epoch" representation is that (at least under the ) it is incapable of representing an instant within a positive leap second (since "each and every day shall be accounted for by exactly 86400 seconds_", any such time would be interpreted as being in the first second of the following UTC day).
For HTTP I think subsecond precision is an overkill due to RTT / intermediaries.
IMHO: I like structured format. There are a lot of diagnostics and other software that would not want to do additional transcoding of header elements but just represent them verbatim as they occur. Those are helped if the verbatim representation is already easier readable. I do not think TZ belongs into a time/date representation. Aka: all date/times in UTC please. TZ can be added somehow as a "location" information, ideally in a different header field. If it is in the same header field, it would be confusing to show the time in UTC but ALSO to indicate the TZ. Maybe this can be resolved by coming up that would make it as obvious as possible that the date/time is NOT adjusted for the TZ shown. Maybe not call it "TZ" but "LOC" so that the "the date/time it TZ adjusted" recognition is not triggered. And of course waste the three characters on "UTC" in the representation. I do not believe the processing speed argument to be valid. The level of processing speed where just a (sub)second unstructured value would help goes IMHO into the space of CoAP, not HTTP. I'd first try to make HTTP better where it does not just duplicate CoAP efforts. All that binary stuff CoAP needs to do is severely making toolchains more complex IMHO. I do like the leap-second argument. I do think msec accuracy should be an option. RTTs within lan/metro environments can easily be in the single digit msec range and you want to be able to diagnose e.g.: REST based broker/bus-type transaction speeds, relative ordering of request/replies.
Seems reasonable to me. +1 Not sure this is an "interface" that HTTP exposes / should be relied upon.
I suspect the experience of pretty much everybody writing and deploying HTTP intermediaries and servers at scale is different -- at those rates, cycles wasted on parsing do matter, especially when architectures have many layers of intermediaries to go through.
See linked PR for a proposal.
Re leapseconds: as written ("excluding leap-seconds") means that timestamps will be illegal, effectively mandating POSIX leap-second (non-)handling. To make able to handle leap-seconds requires that every HTTP handling entity needs an up to date file, either at system level or application level, and that the upper limit on the "internal data model range" becomes indeterminable, since we cannot predict how many leap seconds will happen in the future, nor what sign they may have. That is a total no-go from a systems engineering and complexity point of view, in particular as the rest of the world converges on either papering over leap-seconds or abolishing them. If the textual format cannot handle leap-seconds (without requiring a boat-load of complexity), then, why take the extra expense in CPU-load and code complexity ? As stated earlier, we should go for the more efficient and less error-prone solution: POSIX time_t (with optional milliseconds) as a . (If we want to designate the timestamps with a senteniel, 'NAME is a particular bad choice, since the HPACK huffmann assigns it 13 bits.) PS: In context of four digit years: Century scale predictions, based on orbital considerations, expect the current leap-second regieme to break down in approx 2000 years, because we will need leap seconds more often than every month.
Do any current HTTP implementations take leap seconds into account? Regarding HPACK - it's one character. Let's not over-optimise here.
I don't know, but leap seconds are explicitly supported by : And the difference between 23:59:60 and following-day 00:00:00 would certainly be relevant for e.g. Last-Modified.
I have spent a lot of time over the years searching, but I have yet to see a 23:59:60 timestamp in the wild...
Now there's a picture in my mind of PHK walking the wilds, searching for an elusive date stamp.
I don't know what counts as "in the wild", but there is certainly documentation of and .
Discussion at IETF114 wasn't conclusive, but we now seem to be focusing on these options: Do nothing. Dates in SF are Integers (unless folks fall back to Strings), and recipients need to know that they're dates and how to handle them. Create a Date SF type along the lines of the PR. The textual representation is human-friendly, and it's identified as a date in a machine-readable way without special knowledge. Create a Date SF type but use an Integer; e.g., . The textual representation is not human-friendly, but it is identified as a date in a machine-readable way without special knowledge. I'll observe that if we believe that we'll eventually have a binary representation of structured fields widely in use, (2) is preferable in that it has the best properties -- it's both efficient and human-friendly. Of course, that's not at all certain. I'll also observe that in the discussions I've had, the people who want human-friendly representation are generally those who are working with tools and developers, "closer" to the application. The infrastructure folks and "lower layer" folks tend to minimise this aspect.
PR updated to reflect (3) above.
I personally support (2) or because it covers similar use cases than HTTP-date. In case of (3) I think we can just use an Integer SF, like we do Signatures and other specs. Side note: we sometimes hear that RFC3339 is ambiguous. I think it is, and after ~20 years it probably requires a RFC3339bis that clearly specifies a basic profile ( T, Z uppercase; Always ). I'd be happy to start this work.
Why do the number of decimals need to be specified? Surely we could just say the format is nnnnn[.ddddddd] or similar where an integer-only parser stops at whitespace or a '.' while those who care about sub-second parsing continue on until they are satisfied with the resolution or they run out of digits. The senders decides how many decimals to provide, perhaps with a recommendation of three or upto their clock resolution? So "123456789" and "123456789.1" and "123456789.123456789" are all equally valid.
I like this direction; thanks.


There are a few cases where the word is used. From the context, it appears that the intended word is .
Thanks! I have no idea why my spellcheck didn't catch those, and I appreciate it.


-
LGTM modulo nit
NAME 8972 Simple Two-Way Active Measurement Protocol Optional Extensions or URL line wrapping? Since 8792 is used in examples, dunno if that's normative but it's ok.
:-) Typo fixed. In any case, we need to reference it (IMHO). I would also suggest to avoid the escaping when not needed.


This adds a binary wrapper for fields that don't follow the List or Dictionary format for multiple values, such as Set-Cookie. The wrapper is selected using the parameter, and the component value is made by wrapping each individual field value in a Byte Sequence and putting them into a List, then doing a strict serialization on those values.
In general, is this even needed or are we over-engineering here? If the main use case is , do we think it is likely to be signed?
Some fields, like , have an internal syntax that allows unquoted commas and messes things up when multiple lines are combined for the signature base, leading to the potential case where two semantically different inputs have the same signature base. This means that: And: Both produce the same signature input line: Even though the two-line and single-line versions are processed differently by the application. To counter this, we could have a distinct encoding flag that wraps the field values, similar to . This can be used to protect problematic fields like Set-Cookie so that we get something like this for the multiple line version: But you'd get this for the single-line version: The background of this has been discussed in and


Section 1.1 is currently a bit confusing, because it leaves out sections, and does not present them in order (likely the cause of a recent re-org).
NAME do we need it?
it should either make sense, or should be removed.
NAME if it's not required, I think that the document is fine without.
mnot asked us to add one a while back, which I think helped at that point. Editorial changes in the meantime have had an effect though, so I tried to add some colour to the structure in URL Preview at URL The intention is that people can launch of from here to focus on bits they might need, like the field definitions or example. Since security and IANA sections are standard, mentioning them seems superfluous. If the opinion is that the proposal doesn't help, let's just remove the section.


Contains the following changes: Skip parsing the attribute on empty value. Skip parsing the attribute when given Max-Age=- Add mention of "base 10" as guidance for implementers parsing integers from Max-Age. Regarding browser interop: Skip parsing aligns on Safari behavior and against Chrome and Firefox, which will default to session lifetime when any invalid Max-Age attribute is found (based on manual testing, it's difficult to test this with WPT at the moment, see ).


While already discouraged by the grammar, this warning further discourages servers from sending nameless cookies which have a history of causing compatibility problems. It also reorders the notes in the syntax section to group similar notes together.
Ideally we'd define server-side parsing of cookie-string (or at least recommend behaviour here for things that don't match cookie-string!), given this does cause problems for some servers (e.g. URL). Until then we should at least make it clear that the "the algorithm to compute the cookie-string from a cookie store and a request-uri" can create things that don't match cookie-string (e.g., nameless cookies after ). There's a number of WPT expected results that don't match cookie-string.
Can you clarify what a fix would look like? Bonus points for a PR. (I mean, I can also attempt a PR, just not clear on what the recommended fix would be)
You attempting would probably be as good as me attempting!
I'm skeptical, however willing to try! And now I think I actually understand the bug report (and didn't when I commented). NAME is saying that the ABNF in URL has a bug, since is defined as: But nameless and valueless cookies exist. cf. URL URL
I think maybe this can be solved by making the following changes: This is pretty simple to grok: This is supposed to convey "a nameless cookie, OR a valueless cookie (but not both)" That should work for the following valid cookie-pairs: (nameless) (nameless2) (named cookie with empty , i.e., valueless) (name + value) If that's the route we go, then in URL cookie-string = cookie-pair *( ";" SP cookie-pair ) That should work. However... unless we tweak , I think you can end up with the following invalid cookie: . Will need to formalize "if no name, there must be a value". Maybe we can just add an and then do something like:
Actually that won't fix the bug I described. Maybe this super elegant solution (but the above ABNF would have to be tweaked):
FWIW nameless and valueless cookies are no longer RFC compliant after URL Up until then only Set-Cookie strings with empty names and empty values weren't accepted, but there were ways around this to get empty-name-empty-value cookies into user agents' cookie jar using the CookieStore API.
There are nameless cookies and there are valueless cookies (and, as you said, there are no nameless-and-valueless cookies). FWIW, the syntax in section 4.1.1 where is defined is a SHOULD, not a MUST, on the server's part. I think one issue is that reusing it to define makes that also implicitly a SHOULD, if I'm reading this correctly: Edit: To clarify, I'm thinking there's no accuracy issue with the spec as written, since if the server does things as recommended (and sends a cookie with name=value), then the user agent will respond as given by . But that is still totally confusing, at least to me, so I think we should still define this better.
(love the ambiguities of english -- thanks for the explicit callout and pointer to NAME
In the nameless cookie case, it seems that an unhandled edge case arises because of the following, from the section: To illustrate the problem with some examples: if is empty and is , the algorithm above works - the resulting cookie line would be if is empty and is , though, the resulting cookie line would be , which would be interpreted as a cookie with name and value . One solution for this, which is currently specified by the , is to forbid cookies with an empty name and a value containing '=' from being set. Limiting from containing a '=' is not mentioned in the section or the section of RFC6265bis, though. It seems like using the following in the section would be a better approach: This would fix the issue in the example above (the resulting cookie lines would be and respectively, both of which would be interpreted correctly). If we want to allow to be produced in the first case, we could replace step 2 above with something like: I'll submit a PR for this change.
The empty-name-but-nonempty-value case is serialized as and not for historical/compat reasons. There's some earlier discussion in . The case where the value contains an '=' is interesting though, and not tested by WPTs I believe. The Set-Cookie header can't produce a nameless cookie with value so this is only a concern for non-HTTP APIs that don't parse a set-cookie-string. Could we instead just add to the Storage Model section the restriction that the cookie-name and cookie-value cannot contain '=' or ';' characters? (Side note, more generally, this is getting out of hand and we should try to factor out common logic in the Storage Model and set-cookie-string parsing sections.)
hmm, looks like there is a WPT for this case, but the expected output for it would be interpreted incorrectly :( URL;l=22-26 Wouldn't be allowed in a Set-Cookie header? Also, '=' is a valid base64 character, so not allowing it in might cause a lot of headaches
Oh, my mistake, you're right that creates a nameless cookie with value . Chrome/Edge/Firefox agree on how to serialize these, but Safari ignores nameless cookies altogether. I would be a bit concerned about breaking stuff if this serialization changed. :-/ Theoretically there's a use case for this behavior... since and are the same cookie (the nameless cookie) but with different values, and they overwrite each other, a site could be relying on getting the output or (but never both) as a way of (sort of) setting two mutually exclusive cookies named and .
Maybe we just fix this with a note cautioning against using nameless cookies, and point to this issue as a warning.


Adds an optional parameter to signatures, to allow applications to signal specific usage between the signer and verifier. This PR does not add this to any examples yet, but we probably should if accepted.
NAME NAME I've walked the language in the definition back a bit and added it to an example. I think this is sufficient to include as a new feature.
[This came up at the IETF-113 session, credit to Jonathan Hoyland] A signature context mitigates oracle attacks, where a sender can be made to sign data that’s partly controlled by the attacker, and the signed string is then used for unexpected purposes, either within the same protocol or outside it. The context includes the higher level protocol that utilizes the signature mechanism, as well as other information such as sender and receiver identities. Signature context is used in TLS 1.3 (see RFC 8446, Sec. 4.4.3, “context string”) as well as the similar parameter in . The simplest way to add context to Message Signatures is as an additional parameter. We suggest that the context value should NOT be defined by this draft, but it should be mandatory to send, and mandatory to validate upon receipt. This prevents cross-protocol attacks but assumes that the higher level protocol is able to protect itself e.g. by ensuring that the receiver’s identity is included in the signed components. The context is fully defined by the higher level protocol, and no IANA registry is established for it. cc: NAME
Thanks for writing this up. I want to make sure I understand the request for addition: Define a signature parameter "context" as a string, whose content is outside the scope of this spec Define the use for this field aligned with the above Add a security considerations on the use of this in outside protocols I think this is a relatively light weight add, and I am ok with those pieces. Where I don't think I agree is the "mandatory to send and interpret" portion, if we're not going to define anything to put into the field. In this case is becomes just another value, right? I can see a lot of confusion in people trying to apply this without clear guidance. I would be fine with this field being recommended to send by the signer and mandatory to interpret by the verifier if it's present, and applications can make the field required and even have required values, like the example above.
Yes, you have it right. This is analogous to the JWT claim whose goal is to prevent cross-protocol (or really, cross-usage) attacks. So making this mandatory is important. I think mandating verification is nice in theory but I'm not sure it would be effective in practice. Instead, we could give guidance that makes it trivial to use, like in my example: include the protocol's name and possibly version. Just doing that would narrow the "blast radius" of cross-protocol attacks significantly. A "nonce" () is a well defined term. This is not a nonce. The on is weaker than I would like, but it's still a SHOULD for new types of JWTs. Here we have an opportunity to get it right from day one.
I appreciate the position, but what if the application is literally just "I am signing this message"? What would we put in that mandatory field that isn't either a random value or just "http"?
Then put the application/service name there, instead of a protocol name.
What's the application or service name, then? I don't think it's always as well defined as you're assuming it to be in practice.
It's guidance, not interoperable normative text. Whether people use "myapp" or "myapp/1" or even "myfile.c" doesn't matter all that much. Basically anything is better than a missing context.
If it's not interoperable normative text, then it has no business being a MUST here.
Existence and verification of the parameter are both normative. Its content is not.
NAME Could you provide an example attack scenario that cannot be mitigated by signing additional semantically relevant message components, and is mitigated by the addition of a parameter? The JWT claim is necessary because often there is nothing in a JWT that ties it to a particular message. This is a feature of JWTs, as it allows things like reusing JWT-formatted access tokens across multiple requests. I'm not familiar enough with TLS internals to say whether the same concept applies to the TLS "context string" parameter. In contrast, reuse across messages is not a use case for HTTP Message Signatures. If a signature is reusable across two semantically different messages, that would suggest to me that the signature is not covering the right message components. So cross-protocol attacks where the signature is presented as a message signature for a different message are mitigated by signing the semantically relevant components. (e.g., , or parts thereof, etc.) Attacks where the signature is presented as some other type of signature (i.e., not an HTTP message signature) are partially mitigated by the fact that the signature base includes the signature parameters, which is likely to distinguish it from content that may be signed in other contexts. For example, the format of the signature base means that an HTTP message signature cannot be passed off as a signature for a JWS. If the overall format and the footer is not already enough for this, I don't see how adding an additional parameter would help. If an attacker can mold the signature input in another context to match the HTTP message signature format as it is, it seems unlikely to me that adding to the end would help.
Hi NAME I'll start with your last paragraph. I agree what we have now is only partial mitigation. This kind of attacks is never fully mitigated, because you need to make assumptions on what implementations of a different, unknown protocol would do. But in general IMHO a unique prefix is a much better way to distinguish between signatures, because something further down in the signature base may be ignored by verifiers. Concretely, having a mandatory as the first line of the signature base would be a much better mitigation. Now back to the : again, we are talking about two different protocols, each of which may have both spec and implementation errors. Of course if both protocols are defined and implemented perfectly, the right fields would be covered and validated, and would also define unique semantics. Life is not perfect - people are lazy and will sign too few fields - and a context protects some protocols/implementations from others.
I'm not sure I buy this. If a non-HTTPSig consumer of signed content can be tricked into accepting as a valid message then I don't see why we should assume it would be any harder to get it to accept Okay, can we walk through the failure modes? An API that exposes multiple operations on different paths could fail to require callers to sign the target URI's path. In order for to help, it would have to be set to a unique value per operation, e.g., "ExampleApp.doExampleThing". That seems like way more work than just signing the right things. An app could fail to require all of an operation's inputs to be signed. In this case, the only way helps is if it is unique per request, e.g., a hash of all the operation inputs. This is definitely way more work than just signing the right things. Two apps could fail to require the request audience (e.g., the target URI authority) to be signed, allowing signatures to be replayed across them. Here only helps if it is set to something that is app specific. That rules out the use of standardized values based on protocol (e.g., ) or intent (e.g., ). And if is being set to something app-specific, why not just sign the app-specific thing that is already in the request? Are there other failure modes that I'm not considering, where would prove more useful? So far this leaves me feeling that is more likely to encourage bad habits and give implementers a false sense of security than it is to address any actual security risks.
I do not see how having a fixed signature prefix will solve any security issues with signature base generation. All the same problems with bad implementations occur internally in the signature base, the only difference is that you've got MAYBE a good first line -- and as NAME mentioned this is not stopping people from doing different bad things like having newlines in the content identifier. We can add a security or implementation considerations section on newlines in the signature base. Even then, I am failing to see how this prefix idea is related to the signature context concept. And as NAME said, apps failing to sign enough is an issue for the app. Having a signature context isn't going to magically get that necessary content signed, nor will it make a badly written verifier reject unsigned required content. Again, I'm fine with adding context as an optional parameter for applications that want to make use of it for signaling, but I don't think it solves things in the way that is being presented here.
Works for me. Thanks!


Editorial, since this is merely restating locally what was previously incorporated by reference.
In draft 00 it says: >The layout and semantics of the frame payload are identical to those of the HTTP/2 frame defined in ]. The ORIGIN frame type is 0xc (decimal 12), as in HTTP/2. I think this is the text as it was, before we ran HTTP/3 and HTTP/2 through the process. I think there's some room for editorial improvements to avoid the guesswork. Not least because HTTP/2 Origin has an errata on the payload definition (URL). My suggestion is to just admit defeat and define the whole frame like we do in HTTP/3 or ext priorities, something like Then we can say something like the semantics of the HTTP/3 ORIGIN frame payload are the same as those of the HTTP/2 ORIGIN frame, modulo the differences already described (control streams and whatnot).


Define a signature algorithm named that indicates the use of ECDSA using curve P-384 DSS and SHA-384. The algorithm description is probably just 3.3.4 with "256" replaced with "384", but should validate that assumption with actual crypto folks.
What's the push for this specific curve to be included here? The reason I ask is that we shouldn't necessarily try to define ALL known algorithms in here, when it's extensible.
I agree with not defining every possible algorithm; however we should include those with known use cases, and AWS intends to use -384. Since the spec isn't finalized and the addition is trivial, it seems reasonable to add it here rather than punting it to an extension spec.


Hello, URL introduced parameter, "to allow applications to signal specific usage between the signer and verifier". However, word context is already used more than 40 times, mostly meaning the context of HTTP message. In my opinion, it adds ambiguity to the used vocabulary. Please consider renaming the parameter, e.g. to application, app, usage, use, purpose. Best regards, Robert
Thanks, I noticed a similar term conflict when we added the functionality -- was the proposed name from the folks that suggested the function so that's what we put in. I'm happy to have something else in there: I think is a good suggestion.


update refs for HTTP Semantics, HTTP/3, and QPACK to point to the now RFCs 9110/9114/9204 for
Thanks Mike. That was much easier than using the "suggestions" option. I merged and then fixed(!?) the YAML header with . I think this one is good to go now?
Yes, good to go!
I-D.ietf-httpbis-semantics -> RFC 9110
Also HTTP/3 ietf-quic-http -> RFC9114 QPACK ietf-quic-qpack -> RFC9204


client-cert: Mention that origin server access control decisions can be conveyed with a 403 or by selecting response content
Do you envision that clients would drop their client cert cache in response to this 403? (They currently do not.) If so, how would that interact with subresources on the page?
I honestly don't envision any change in client behavior. I realize that doesn't address your concern. But I believe doing anything more is firmly beyond the scope of this draft. The sentence added by this PR is only aiming to fulfill Tommy's suggestion at the last virtual interim and in the issue URL
You might want to explain that David's concern is a genuine problem that this doesn't solve, something like:
Thanks Martin. I'll add that note.
From URL, it sounds like the intent with the client certs draft is that the proxy does little to no certificate validation and punts all of it to the origin. In that case, we need to sort out how errors work... Client cert UX is bad in part due to an impedance mismatch. In a user-facing client (like a browser), presenting a client certificate with a user-facing identity, we typically need to prompt the user to select an identity, reprompt on bad selection, etc. However, a single user-facing "session" covers multiple HTTP requests, which may then create or reuse connections depending on many factors. That means we cannot surface auth to the user at the connection- or request-. TLS session resumption and further complicate this. The consequence is clients cache client certificate decisions. (Non user-facing clients tend to have credentials preconfigured, which effectively also remembers the decision.) With a cache, clients need to know when to invalidate it. Otherwise the user can never recover from selecting the wrong identity. As this is TLS-level auth, today this is done by reacting to TLS-level alerts. draft-ietf-httpbis-client-cert-field breaks this correspondence by introducing a way to move half of TLS-level auth to HTTP. That is incompatible with today's client cert deployment assumptions, so we need to define something here. This is further complicated because the draft is shifting connection-level auth to a per-request scheme. I can see two options, but neither is very satisfying. Proxy translates HTTP error to TLS alert The most compatible option would be to define an HTTP error that the proxy must translate to a TLS alert on the client. The problem is TLS alerts tear down the connection, so this would be very disruptive in HTTP/2, where we may have other requests multiplexed. (The TLS-level mechanism does not have this problem because it happens in connection setup.) Modify clients to interpret HTTP error as TLS error The other option is to define an HTTP error and pass it through to the client. However, that means this draft is not only a proxy server protocol, but also changes HTTP clients. We would need to discuss the compatibility implications. Additionally, by introducing a brand new way to do client cert errors, we introduce some awkward quirks. Suppose the server sends a resource with subresources on the same origin. Unlike HTTP auth, client cert auth applies to the whole connection. There would be no way to fetch those subresources without re-triggering the auth prompt. Perhaps we include lots of warnings that the server need to keep all its error page resources inline or on a different origin? Perhaps we say the client should ignore the response and map the HTTP error to some network-level error page?
The use of post-handshake authentication is similarly fraught. I assume that you are looking to have a connection torn down if any certificate is not fit for purpose. Isn't that a bit of a blunt instrument? It makes the use of multiple certificates an interesting game: get one wrong and you lose. More so because the TLS-terminating proxy is the one that plays the game with the client the one that pays the price. My assumption was a far more narrowly scope scenario: The proxy asks for a certificate based on some condition it arranges with the origin server (this is proprietary and not our problem). The client provides a certificate with a signature. The proxy validates the signature and passes certificate information to the origin server with any requests (again, deciding which requests to annotate thus is proprietary). The origin server takes this information and authorizes requests, or not. That's it. The scope of the draft starts and ends at step 3 here. The holistic problem is that clients tend to stick to their choice of client certificate in the face of these HTTP errors, only changing their mind if TLS fails (with a specific subset of possible alerts). That seems like a poor design choice; a legacy of how HTTP/1.1 works and not suited to modern uses. For starters, the provision of the certificate was successful, it's just that it was not the one that the server wanted. Tearing the connection down is too strong a response when you consider that HTTP/2 and HTTP/3 have multiple concurrent requests, some of which might be affected by a TLS alert that brings the whole session down. I really do think that client changes are the right choice here. Clients can treat 401 (Unauthorized) as a signal that the credentials offered (zero or more certificates) are not adequate. At that point, it's probably safe to treat the cached choice of certificate as not useful for the next certificate request that comes along. Post-handshake authentication allows them to add to the pile of certificates, not jeopardizing credentials that are working. For the proxy, if it decides that it needs to ask for more credentials from a client that doesn't do post-handshake auth'n, then a TLS alert is an option. It's probably the only realistic option as things stand today. I'd prefer GOAWAY with a code that indicates that a new connection with different credentials is appropriate. For NAME benefit, I don't see any of this as affecting the client-cert-field work as long as it makes its scope clear. That work can probably just note that a proxy probably has to tear down the connection to the client after a 401 response so that the client won't fixate on the wrong certificate. Pick an appropriate alert. I don't think we need to go into defining new signaling arrangements. I don't think that it is worth the effort of doing more to improve client certificate-based authentication, unless there is some general trend toward enabling post-handshake auth, at which point we can talk about choosing a better solution.
While acknowledging that and associated issues, the scope of the draft is only about conveying the client cert info and not any new error signaling or attempts at addressing the larger problems.
It might be nice to still have some text to still mention that server can send back 403 status codes, etc, if they don't like the client certs. Don't add any new mechanisms, but explain that errors can happen, and there are ways to express them today.
If the server sends back a 403 mechanism, would you expect clients to act on this? I'm not aware of any client today that uses HTTP error codes to inform client certificate selection.
If a client without a client cert would see a 403, then I think it makes sense to mention that sending a 403 is what would reasonably happen here. I don't know if clients would do something automatically, but presenting the 403 error at least indicates that authentication was the problem.
PR basically adds this sentence, "Access control decisions based on the client certificate (or lack thereof) can be conveyed by selecting response content as appropriate or with an HTTP 403 response, if the certificate is deemed unacceptable for the given context."
This is sufficient. A similar experience exists today when a client presents a certificate which is valid, but which does not grant access to the requested resource. While it's not ideal in certain ways -- the client might possess other certificates that would grant access if given an appropriate selector -- the server might also prefer not to share that list. This draft isn't attempting to create new solutions from scratch -- it's attempting to outline what is currently done in assorted custom ways to help coalesce these into a single format. Those custom mechanisms don't provide TLS alert translation either, so far as I'm aware.


attempt NAME "simple alternative" in to say the chain is in the same order as it appears in TLS rather than copying the language from TLS
There's a bunch of text in the draft about putting the certificate chain in the right order. This tries to crib from TLS and ends up being somewhat tricky to get right as TLS has a bunch of carefully worded and - frankly - ambiguous rules. As a simple alternative, how about we just state that the certificates need to appear in the same order as the client sent them in TLS.
Makes sense. Will look at adjusting the text accordingly.
I think this is a bit more fundamental than just the order. It's really a question of whether this is a certificate path, or a pile of input certificates to run verification over. That is, either: The origin runs path building, taking the unordered/unverified pile of input certificates from the header, in TLS order. The proxy runs path building and passes the result in the header. The origin assumes a path has been built and is merely applying ACLs based on some aspect of the resulting path. A mismatch here could result in security issues. For instance, suppose the origin wants to only allow chains issued by intermediate certificate I1 to access . If the header means (1) but the origin expects (2), this ACL is trivially bypassable: Client has a certificate chain EE -> I2 -> CA. Client connects to proxy and sends {EE, I2, CA, I1}. (Or perhaps {EE, I2, I1, CA}. Or whatever else. Different verifiers are differently permissive about path-building. Perhaps it omits I2 altogether and the path-builder picks it up some other way.) Even if the proxy runs certificate verification, a path-building verifier will build the EE -> I2 -> CA path and just consider I1 as a random unused certificate. , per the TLS order rule, contains {EE, I2, CA, I1} Origin server checks this and concludes "aha, this was issued by I1 and can access the resource". Conversely, the semantics are (2), the proxy needs to have enough information to validate the certificate, up to a valid trust anchor for the application. If you all intended to punt that to the origin, that's a different protocol. If the spec says TLS order, it's implicitly saying the interpretation is (1). But as that leaves a security-critical check to the origin, it should be explicit about this. Also, as it leaves all certificate validity to the origin, it'd need to further define an error-handling story to properly tell the client the certificate was invalid. But I know of no client that uses HTTP-level errors to clear client certificate decisions, only TLS alerts. I think (2) may be a more robust/compatible.
It is definitely 1. You do 2 and you don't need this client-cert-chain field at all. That doesn't mean that a proxy can't be configured to do the work and pass the info along. But one of the two needs to be in the hook for enforcement. A consequence of 1 is that alerts at the TLS layer won't be used to signal errors, aside from those that the proxy detects (or has to, like if the signature is invalid). That is ok, mostly. The main protocol issue here that might be a problem is validation of signatureschemecert. I can't see how failing to validate that would be a significant problem though.
In on the PR that introduced the chain I was aiming for 2. But eventually relented to MT. Some additional considerations about the security implications are likely warranted though.
I see. If it's (1), that should probably be clearer in the draft. That also means the draft needs to define an error-signaling scheme. Moreover, if the proxy doesn't then translate that error into TLS alerts, we'd need changes in clients for servers relying on this to work right. I'll file a bug.
I ran into real reservations as I looked at making this change. I still don't like pushing the trust chain validation to the origin. For many reasons. The proxy also has no means of signaling to the client which trust anchors the origin is okay with. The current text is somewhat ambiguous about what goes in Client-Cert-Chain but I think that's actually better than saying it has to be same as in the TLS handshake. I dunno, I think I might raise the question of WTF actually goes in Client-Cert-Chain at the next interim or real meeting.
At the last virtual interim (in May/June yikes!) Martin kindly suggested that I was making this too complicated and to just make the change (paraphrasing). I've tried to do that with changes in PR .
This works well enough on the critical points. Some points about readability though.


briefly mentions security advantages See
Moved little changes into sec-: sensitive information can be in both and ; mention intermediaries.


Adds a citation in 1.4 for DIGEST and forward links to the security considerations sections for covered component selection and message body coverage.
Minor issue noted while reviewing. -13 does give a good overview of message content considerations, and mentions Content-Digest along with a citation to the digest headers draft. However, the earliest mention of Content-Digest is in section 1.4, and there are several examples through the text that use it. Simple fixup is to cite digest in section 1.4 too, and forward ref to 7.2.8 so anyone interested in this knows where to jump to.


to
Currently, the references to HTTP semantics and to all HTTP versions are informative. While there are only two references to RFC9110, I find myself skeptical that someone would be able to implement it without knowing HTTP. We might consider making 9110 an normative reference, even if we think the individual pointers into it don't rise to that level.
You could normatively depend on the intermediary definitions in URL
Agreed about making HTTP semantics a normative reference.
Using and alining with 9110's intermediary definitions is likely worthwhile too. However, that's a larger effort that should maybe be considered separately?
I'm not too bothered about just changing labels between informative or normative. Thats easy to do and can be changed easily enough at later date. I think this draft actually does a good job of talking about the specialist case of a TTRP and we should keep that without too much meddling. But if the prose would benefit from shaking out a stronger sense of if implementations have normative requirements (directly or via references), I think this is a good ticket to track that against.
Thanks for the thoughts, Lucas. I'm inclined to not do much meddling.


and use "describes" rather than "standardize" to better align w/ the Informational intended status
As Yoda might say, do or do not. We can lose the aspiration here and be assertive about the document consensus progress.
I have a tendency towards that kind of demure writing. But you and Yoda are right. Will change.
LGTM, too.LGTM


It might help to refer to the example in section 2.2 and/or 2.3.
Makes sense, can add a couple forward refs.


Intro para 3 has a chunk of text about fields not defined in this doc This could be condensed to say that the header fields in this document provide a standardized replacement for custom or proprietary fields that were known to be used prior to this document.
It is perhaps a bit long winded and admittedly not award winning literature. But I think it's useful context for the reader and prefer to keep it.
Right but in 20 years if the RFC says "a common practice today is using non-standard fields" it could read odd. Its clearer if this spec focuses on what it provides not what people came up with as custom solutions beforehand.
Thanks, looks good!


reword the header compression section with more consistent terms for the roles (to
LGTM modulo nit
This section talks about header compression and says Elsewhere in the document, you've used TTRP and Origin to identify the roles in play. I think it would be clearer to use them here. For instance, I might rewrite this as something like


Attempt to reword the 'Header Block Size' section to use more HTTP version neutral terms (for )
Is this a hangover from terminology changes elsewhere? URL says
Very possible that it's a hangover from terminology changes elsewhere. Very possible. But I'm not quite sure how to update it. HTTP/3 talks about the "size of the message header" (from your reference) while HTTP/2 talks about block size but now uses field block size URL rather than header block size URL How about the following though? Assuming I'm even adjusting the terminology you're suggesting needs adjusting. Message header seems more neutral and appropriate.
Thanks for the suggestion and PR. I think we're best off holding for NAME review since he had to do a similar renaming exercise for HTTP/3 and is an expert now
Makes sense. I, for one, would welcome such expertise.
URL Mike okayed it
Yes, this looks reasonable.


h/t NAME
The security considerations pay some good attention to the concerns of the actors that might deal with the headers defined in client-certs. It crossed my mind that you could mention header protection mechanisms, like Signatures, as one way to harden things.
Yeah, Signatures could be mentioned in there as a possible additional measure.


try to align better with the style guide on structured fields usage for
See URL, which would affect sections 2.2 and 2.3
Will update the structured fields parts to align with the style guide.
LGTM


The HTTP message in Sec. 2.1.4 of draft -14 is not formatted correctly (both HTML and plain text).
NAME


in the manner discussed in London: Admitting it exists, but we don't care.
Section 2 of includes these nuggets: to this specification MAY define flags. See . and but future updates to this specification (through IETF consensus) might use them to change its semantics. The first four flags (0x1, 0x2, 0x4, and 0x8) are reserved for backwards-incompatible changes; therefore, when any of them are set, the ORIGIN frame containing them MUST be ignored by clients conforming to this specification, unless the flag's semantics are understood. The remaining flags are reserved for backwards-compatible changes and do not affect processing by clients conformant to this specification. HTTP/3 frames don't have a Flags field in the generic frame layout. So, while I'm not sure we'll ever see a use of these flags in H2 ORIGIN, it might bite us later if it happened. I see a few options for dealing with this: Option 1) Defer. Future us will have a job to do trying to make H2 and H3 compatible if a flags related change is proposed. Perhaps its worth a little note to make sure people are aware of this divergence consideration. Option 2) Add a Flags field () to the HTTP/3 frame and add in all the same considerations about backards-(in)compatibility Option 3) Encode the flags in the frame type by picking a large enough value. A bit yuck. I'm leaning towards option 1.


correcting: The reference to RFC8740 is obsoleted by RFC9113 There are two separate references to RFC5246, once as "RFC5246" and once as "TLS1.2".


The draft currently has this example: I'd suggest always omitting trailing dots since it's clear that these names will be FQDNs, i.e.:


NAME Adds the BCP14 boilerplate in a Notation Conventions section. As part of that, I noticed we don't reference any explanation of the frame layout language used -- it's the same used in QUIC and HTTP/3 -- so I added an RFC 9000 ref to pick that up in the same section.


This draft (-00) is using the term "alias" in a slightly different way than used in DNS: A CNAME record has two names, the owner name on the left-hand side or "alias", and the target name on the right-hand side or "canonical name". RFC 8499 (DNS Terminology): In other words, to use the example in the draft: Which might correspond to a DNS response that looked something like: and are DNS aliases (because there are CNAME records with those owner names) whereas is a DNS "canonical name" without an alias. But is included in the example in this draft. This might be confusing for the DNS name at the end of the CNAME chain (which is not an alias from a DNS perspective), so I might suggest changing: to something like:


Agreed, but I don't see a way around having a "." be allowed there. If a system wants to further escape dots within labels if they know about them, that's OK...
The current text says names MUST be represented using a percent-encoded value instead. However, domain names can also contain and , so I think the escaping rule has to be a bit more generic than just escaping commas, as indicated in the current text.
Wire format DNS names can contain arbitrary octets. I'd suggest allowing characters in the set and %-encoding any other character. This is similar to the filtering that the glibc stub resolver performs on CNAME alias chains.
Reference RFC 1035 section 3.1 for the fact that these can be arbitrary Percent encode everything that it not alphanumeric or dash Mention in the security considerations that if you don't do this, you could inject newlines, etc.
Actually, sf-string already prohibits things like newlines:
The unreserved characters are: is a valid interior label character in a wire-format DNS name, which seems like it would allow spoofing a label boundary. Not sure how much of a problem this is.


Comment by NAME I would suggest being explicit about the meaning of "active" and especially "deprecated": these are terms everywhere in RFCs (I am aware), but sometimes they are open for interpretation, and we keep discussing their meaning. It would be good to avoid that situation from this doc.
Comment by NAME The new registries do not have any guidance for the designated experts as to what registrations should be accepted or denied (conformance with template, point squatting, availability of reference specification, etc). See of RFC8126: The required documentation and review criteria, giving clear guidance to the designated expert, should be provided when defining the registry. It is particularly important to lay out what should be considered when performing an evaluation and reasons for rejecting a request.


Clarify method case requirements. Add justification for use of empty query string.
Comment by NAME : >If the query string is absent from the request message, the value is the leading ? character alone: When would it make sense to sign this component although empty? Might be good to add some clarification for the reader.
URL I would drop the "and conventionally standardized method names are uppercase US-ASCII". Method names are case-sensitive, that's what is relevant. The second part somewhat weakens that statement.
This is a note to implementors and doesn't change the normative requirements or behaviors -- I think we should leave it in. Note that the text in question appears in section 9.1 as referenced:
Good catch, and I should have objected to that. Anyway; I don't think it makes sense to note it here. It doesn't help at all - the method name is what appears in the request message. The note doesn't add anything useful, but might cause confusion. Take this ticket as proof.
Having seen people try to normalize things by lowercasing because "it made sense", I disagree that the note doesn't add anything useful. I'd like to leave it in.
Just to clarify: my concern is that implementers will take that as a suggestion to uppercase.


URL This does not work. It's impossible to split multiple values (be it a list-based field or not) without knowledge of the field value's grammar. For example, what is the canonicalized value for: ?
The value would be Since it was sent as two instances, you combine the instances with a comma and space. The language to split the field values was added late based on several conversations about list type fields and how they can be combined, but we can remove this. If someone needs additional armoring they can use the "sf" flag on a list formatted field.
Ok, but what the spec currently says would result in: URL that sentence really needs to go.
No, it would not result in that, because as you point out those are not separate field values that can be separated.
So what does: mean then? When is it "necessary"? How does the code know that for any given field name?
I think what is meant is that you take a list of the values of a given field (one member of the list for each header line) and then concatenate them by separating them with ", ". In scala this is or just to make it explicit
Thanks NAME - I get that, but that doesn't address the question I asked...
Ok, I see the problem is: I would not know how to do that, whereas I do know how to seperate the fields in the list.
We need to be very clear with the terminology. What do you mean by "seperate the fields in the list"? Do you have an example?
If you are talking to me, I meant what the code above showed: the list is the list of header values (for a given header name). And I meant seperating the values of that list. I don't know how to write that up well in the spec though...
Ok, AFAIU: just drop "If necessary, separate individual values found in a field instance." from the spec.
URL I don't quite get the reasoning for the second "MUST". Why does it matter? What would break if the client uses a single comma, which is also allowed by HTTP? IMHO the exact delimiter sequence here does not matter at all, as long as it is allowed per HTTP. Note that HTTP allows combining field values, it does not allow splitting them afterwards.
This isn't combination at the HTTP level by the client or intermediary, this is combination by either the signer or verifier when making the signature base. It's a MUST here because there needs to be only one way to do it at that step. If the lines are already combined then leave them combined.
hm. ok. So one confusing thing here is that HTTP 5.2 is already only about combining field values. So the "Specifically" is a distraction. Also, 5.2 does not mandate using COMMA SP. The section doing that is 5.3.
Also...: I think I misread that as a recommendation to parse individual field values into a list, before recombining everything. Maybe "parsing out individual field values" needs to be rephrased.
You would only parse out individual values if you: 1: Know the overall syntax/grammar of the field 2: Know that it's a list separated by commas 3: Can't send everything as a single field line 4: Know that an intermediary is going to mess with things sent as multiple lines in a way that you don't want The recommendation is really only for that one corner case, not for every value.
I agree with that, but the spec really needs to be clearer here.
(but I'll note that github's way of displaying diffs in long lines makes it extrremely hard to find out what actually changed)


And how users of digests are the ones responsible for deciding what to do if something is ignore.
Great NAME , thank you!
Murray asked: on the email thread, I responded with To which Murray confirmed it would be a reasonable resolution. Lets get this fixed as discussed


NAME please check the new test vectors to make sure they pass in your system as well!
It looks good to me (If the tests are correct) URL
+1
The first example signature from fails signature verification. By changing the validity date from 1618884475 to 1618884473 the validation succeeds. I guessed that date as it is the one used in all the other signatures. So I guess that is a typo. (It would have been good to have a different created date, just to make testing less mechanical, but then the signature needs to be changed). There is then perhaps a logical mistake in the next example. The story goes that the proxy receiving the above request alters the message and signs it before sending it on. The original signature is kept and added as part of the signature. The proxy alters the header and adds a header along with a new Signature. But by changing the the proxy makes it impossible for the recipient to verify the initial signature, since that includes a component which was changed. So the spec has to either remove the component from the client request, or change the text at the end of the section which says Note: the proxy's signature does verify for me with the timestamp of the client as it appears in the spec.
Verification of claim above: The test on line 173 of had to be disabled for my tests to pass on the JVM (JS tests coming soon). All the other tests on requests from the spec (well on one I had to change the time for it to pass. Further commits should get the JS to work.
The proxy should not alter the original signature, and that signature does need to include the component. The whole point of the story is that the proxy verifies the first signature, and the service behind the proxy verifies the proxy's signature. If we can make that story more clear, I'd be glad to!
It is indeed an option to have the final recipient rely on the signature of the proxy as a verification of the originally signed message. But the text currently says "The proxy's signature and the client's original signature can be verified independently for the same message, based on the needs of the application." The "independently" reads to me as if the application (that is the server receiving the signature) should be able to verify both signatures. It seems to me that it can only verify the proxy's signature though. But perhaps I was just misreading... It seems there is a dependence of the final recipient on the signature of the proxy. I think there is still the problem of the time being wrong...
Yes, the signature needs to be recalculated and replaced due to the typo in the timestamp (I will need to check the generation script). I can see now how that line can be misread. Though it is definitely possible for the origin server to validate the client's signature if it has additional information, like that discussed in URL and URL -- but this could be made more clear.


Changes the reference to HTMLURL to use one of the newly-registered permanent anchors. Previously two different section anchors had been used, but I'm not sure how to put both of them into the references section. Is there a syntax for multiple target URLs?
I would know how to do that in RFCXML. Maybe it's good enough to tune in AUTH48.
Comment by NAME Thanks to Tommy for detailed shepherd write up, that tells me you have discussed this already. Seems obvious that the HTMLURL reference needs to be normative, so we might need to reference a snapshot of this instead. See the following text in the IESG statement: URL I'd like to get this fixed before starting the Last Call.
A permanent anchor has been requested of the WHATWG: URL
This has been implemented by the WHATWG in URL , so we just need to move our references to use the new permanent anchors.
Note that the question of stable anchors is somewhat orthogonal to the issue of stable specs. A stable anchor doesn't help if the thing being linked to changes.
NAME while true, as the target document is a "living standard" there is no way to guarantee a specific version. Nor is that reason to believe that the document is "unstable" in the way an I-D is. At the very least, implementors will be able to find the information they need at the referenced anchors.
Yes, I agree with that. I just wanted to mention that this might not address the AD feedback.


This is a non-normative suggestion for applications to define what to do when a signature is invalid.
This is not necessarily a spec issue, but I thought it should be recorded and maybe discussed here. Is there a recommendation how a server should respond when a request is signed but the signature is invalid. It's likely a 400, unless we want to define a more specific code? Maybe a pointer to the HTTP problem format would be useful?
Good question. If one was using signatures for authentication would 401 be correct? Clearly an additional error message would be useful.
This really depends on how the signature is applied, and I don't think that the signatures spec should really have a strong opinion on the matter.
I agree it depends on signature, but a bit of confrontation is beneficial. Even some non-normative guidance is ok to me. WDYT about: 400 in a generic case (malformed signature) 401/403 if signature is used for authnz This is the case of Content-Encoding and Content-Type. Eg.
Is this the problem format document: URL ?
Almost: URL
I like the approach in PR to make a suggestion on the error codes and leave it up to the application to determine what makes sense in its context.