Change:
provisioned for specific hash functions. To mitigate these problems, external PSKs can be bound to a specific <del> hash function when used in TLS 1.3, even if they are associated with a different KDF (and hash function) when provisioned.  This document specifies an interface by which external PSKs may be imported for use in a TLS 1.3 connection to achieve this goal.  In particular, it describes how KDF-bound PSKs can be differentiated by different hash algorithms to produce a set of candidate PSKs, each of which are bound to a specific hash function.  This expands what would normally have been a single PSK identity into a set of PSK identities. However, it requires no change to the TLS 1.3 key schedule. </del> <ins> KDF and hash function when used in TLS 1.3, even if they are associated with a different hash function when provisioned.  This document specifies an interface by which external PSKs may be imported for use in a TLS 1.3 connection to achieve this goal.  In particular, it describes how KDF-bound PSKs can be differentiated by the target (D)TLS protocol version and KDF for which the PSK will be used.  This produces a set of candidate PSKs, each of which are bound to a specific target protocol and KDF.  This expands what would normally have been a single PSK identity into a set of PSK identities.  However, importantly, it requires no change to the TLS 1.3 key schedule. </ins> 2.

Discussion:
Also, remove PSK identity encryption sketch. This was underspecified and can always be done in a separate draft if desired. cc NAME
Note, we might want to simply consider merging and into the same field, since we have the registry. That'd save us two bytes. It seems to boil down to whether keeping protocol and KDF separate is better (long term) than merging them. I'm not sure what's the best answer there.
In reviewing the draft, it was not clear that the input PSK was also bound to a hash function, but that the process could produce a derived PSK bound to any hash function. As this is the primary function of the document, that seems problematic. This seems to be the answer to this: I assume that this means KDF rather than hash function throughout (the KDF-bound thing seems right). But it never really comes out and says that:
It's optionally bound to a hash function. In defining external PSKs, the document states that the "associated KDF (and hash function) may be undefined." Do you think it would be more clear to put this in the introduction? (Minimally, as you point out, the introduction should not assume that the KDF-bound PSK as input is not quite right, so that should probably change.) As for the second comment (KDF output), that's not quite the goal. The importer binds input PSKs to a hash via HKDF, not via the TLS KDF. (The TLS 1.2 PRF is not used.) To summarize, my view is that the contract is more or less: optional hash-bound PSK in, hash-bound PSK out. Does that seem incorrect to you?
Hmm, my understanding is that we don't have any support for optional bindings on input. I'm inclined to say that we need stricter constraints on input. Namely that they are bound to a specific KDF and that KDF needs to take a context struct in the form this document describes. Yes, limiting the concrete instantiation of this to HKDF is fine (and the only sensible option). However, if you don't bind the input key more tightly, you will end up shifting the problem you set out to solve one step further out.
I'm not sure I follow anymore!

In my view, the problem we aim to solve is one where the external PSK was not provisioned "correctly," i.e., with the right hash (KDF) function in mind. It's just a plain old n-bit key. The importer is designed to bind this key to a specific hash (KDF). If the machinery that produced external PSKs was forced to change to accommodate a KDF, then it seems that machinery could also vend PSKs that do precisely what the importer does. Namely, differentiate by (context, protocol, hash/KDF). Perhaps I'm misunderstanding your point. Can you please clarify? If you're looking for a specific change, could you please make a suggestion?
In TLS 1.2 and earlier, PSKs were not bound to a KDF. Now in TLS 1.3, a PSK is required to be bound to a KDF. I thought the goal was to start with a PSK that is not bound to a KDF and produce a PSK that can be used in the desired context. So, the input is always a "plain old n-bit key" (Chris' words). The output, when the desired context is TLS 1.3, must include the KDF.
This is exactly what the importer does. Do you disagree?
It is not clear to me what the importer does if I want the context to be TLS 1.2.
It changes the info (or proposed field) value and runs the key through a KDF.
Right, I get that, which I think will bind the resulting key to TLS 1.2 but allow any KDF. I think the document should be explicit if that is the case.
Looking at , I think that you want to bind this to the TLS 1.2 KDF differently by using a different KDF identifier. The identifiers you have are only good for TLS 1.3. You probably also want security considerations addressing the fact that the TLS 1.2 has this odd characteristic.
Can you please elaborate on why you think this is necessary? As an example, let's assume I have an external PSK and I want to import it for TLS 1.2 and 1.3, and I only want to support one hash function (or KDF).

Let's say that KDF is HKDFSHA256. I would then import with the tuples (0x0303, HKDFSHA256) and (0x0304, HKDF_SHA256), and it seems I'd have the desired separation. In other words, I don't see a technical reason why importing PSKs for TLS 1.2 requires use of the TLS 1.2 KDF (PRF).
I think we are saying the same thing, except that when the protocol version is TLS 1.2 that it will be used with the PRF that is negotiated in the TLS 1.2 handshake. I just think the document should say that explicitly.
This is not what I'm saying! I'm saying do not use the TLS 1.2 PRF. Rather, use HKDF. Can you clarify why you think the TLS 1.2 PRF should be used instead?
There are two thongs that are being confused here. First, the one used to create the protocol-version-specific key. This is the one that you want to always use HKDF. That is fine with me. Second, with TLS 1.3, it is bound to a particular hash function. I am saying that when a key is derived for TLS 1.2 the document should say that it will be used with whatever PRF is negotiated in the TLS handshake. Right now, I do d not see anything about that in the document at all.
Thanks for clarifying! If I use an external PSK for TLS 1.2 today, without any import step, it's already the case that it's used with whatever PRF is negotiated in the handshake. The importer does not change that, and therefore I think doesn't need to say anything about that.
I just think it would be better say it since TLS 1.3 had a binding but TLS 1.2 does not. You now understand my point, so I will leave it to you as author.
Why is this a string and not the protocol version number? It sure would be easier that way.
In writing up , I realize now that the combination of label and hash is what is being used to identify a KDF.

I think that you need to allow for the HashAlgorithm to be replaced by something else in future, or for different applications other than TLS. It might pay to instead reduce the tuple of (tls version, hash) to a single identifier that says tls12sha256, tls13hkdf_sha256, which might broaden applicability. That could be crazy-talk though. Either way, it would be good to understand this better in the abstract so as to make a less ad hoc decision about what is being identified and then how.
I agree that the info string should probably just be a version. I imagine there will be a use case where someone wants to, say, import with the label "tls1.3 special sauce". In this case, they could KDF their PSK with the the "special sauce" string and then import with the "tls13" label. And at this point, it might as well be the version number. Let's assume this will be done, and the new field will be called "protocol". So that leaves the question about what to do for the hash algorithm. As you point out, removing the HashAlgorithm dependency would be good for the future. (We have a TODO in the draft to that effect.) So the question then becomes, do we merge whatever this new field is with "protocol," or do we keeep them separate. I don't think we need to merge these for "level matching" or other purposes, so I'm inclined to keep them separate. Thus, how about thee following structure: Where is a uint16 codepoint, and is an HPKE-like identifier [1] for a KDF, such as HKDF-SHA256 or HKDF-SHA512. We could then define the importer with respect to this KDF, rather than baking in a hard dependency on HKDF. NAME NAME what do you think? [1] URL
That seems reasonable - I think that there is some reason to separate target protocol (and version, as a tuple) from the KDF that is used. There's a trick in terms of finding the right level of identification to use for the protocol. I suspect that seeding a registry with 0x0304 and 0x0303 is probably the right way to do this.

That has the effect of constraining TLS a little in how it chooses version numbers, but I think that's workable. (As a reminder, in case you thought this was too easy, QUIC uses a 32-bit identifier for versions. We'd need a mapping QUIC. NAME just makes this look simple.)
Currently the context binds the info string (or proposed field) to the version of TLS, not to the calling application or protocol (QUIC).
Do we want to allow the output of the KDF to be anything other that Nh? Right now, L is always URL, which I think i the Nh value associated with the HPKE-like identifier.
Correct! I can't see a reason why we'd want the KDF output to be something different. Do you have a use case in mind?
If we want this to apply to other contexts, like your special sauce above, it is unclear to me that URL is always the right answer.
The point of the importer is to produce a PSK for use in TLS. Why would the context affect the length?
The discussion of is opening this for other protocol contexts too.
NAME NAME I made the proposed change in . Please have a look!
Works for me