Subject: [CDNi] Benjamin Kaduk's Discuss on draft-ietf-cdni-uri-signing-21: (with DISCUSS and COMMENT)

From: Benjamin Kaduk via Datatracker <[email-masked]>
Date: Wed, 24 Feb 2021 23:17:50 -0800

Benjamin Kaduk has entered the following ballot position for
draft-ietf-cdni-uri-signing-21: Discuss

When responding, please keep the subject line intact and reply to all
email addresses included in the To and CC lines. (Feel free to cut this
introductory paragraph, however.)

Please refer to https://www.ietf.org/iesg/statement/discuss-criteria.html
for more information about IESG DISCUSS and COMMENT positions.

The document, along with other ballot positions, can be found here:
https://datatracker.ietf.org/doc/draft-ietf-cdni-uri-signing/

----------------------------------------------------------------------
DISCUSS:
----------------------------------------------------------------------

I support Éric's and Erik's and Roman's Discusses.

We've had similar issues with embedding client IP addresses in security
tokens all over the place, e.g., in Kerberos tickets, where it provided
negligible security benefit and frequently caused (hard to diagnose!)
breakage.
I further note based on some of the responses so far that (as I
understand it) the issues of multiple client IPs is quite realistic just
for making requests to the CSP vs the uCDN, and no amount of
time-locality can save us.
I expect that the IESG will have some in-person discussion of this topic
and what we are willing to put in an IETF-stream RFC.  (My own personal
opinion is that we have a fair amount of leeway to document "some people
are doing this thing" accompanied by explanations of the flaws in that
practice, but that we have very limited scope to recommend bad
practices.)

I think we should also discuss the proposed technique of redistributing
shared secrets used to generate MACs for signed JWTs.  I see a minimal
acknowledgment that there is potential cause concern in the penultimate
paragraph of the security considerations that "it is important to know
the implications of a compromised shared key", but in my mind the text
there does not really call out the severity of those implications.  I
would have expected something like "redistributing the shared key in
this manner allows the dCDNs to impersonate the CSP to the uCDN and
produce arbitrary signed URLs that are accepted by the uCDN as
authentic".  Well, what I *actually* would have expected was to just not
define this mechanism at all, as it is too risky to use a group-shared
symmetric key in a group where participants are at different trust
levels.  But perhaps the WG can produce some explanation of why this is
acceptable...

I also have concerns about our guidance to leave the JWT "jti" unchanged
when re-signing with different contents, e.g., changing Issuer and/or
Audience, etc..  We don't seem to mention one way or another whether
"jti" needs to be preserved while performing Signed Token Renewal, but
changing the "exp" while preserving "jti" seems like it would be
problematic as well.  The guidance in RFC 7519 is somewhat vague
(basically, that it needs to change if it identifies a "different data
object"), so we may want to consult the broader OAuth WG (not
necessarily just the IANA DE) for further interpretation.  I can also
add based on the responses so far that the "jti" is not solely to be
used to prevent replay, and so I am skeptical of reasoning based on such
an argument.

The combined defaults for the CDNI Metadata Interface for URI Signing
seem to be an unsafe combination.  Specifically, the default behavior
for the "issuers" property is to allow any Issuer, and the default for
the "jwt-header" property is to take the header from the JWT in band.
As far as I can tell, this means that the dCDN will just blindly accept
anything that is formatted as a JWT and signed by any key nown to the
dCDN.  The authentication and authorization properties of such behavior
are so poor so as to effectively be useless, absent some level of care
surrounding key management to isolate keys to given URIs.  In fact, the
lack of substantive discussion of key
management and requirements thereof seems Discuss-worthy in its own
right.  We need to say something about obtaining a key along with a
trust path to what it's authorized to be used for, even if the specific
protocol mechanism for doing so is left out of scope.

----------------------------------------------------------------------
COMMENT:
----------------------------------------------------------------------

Balloting late in the week I have the benefit of seeing the comments of
the other ADs.  I've tried to suppress duplicates but no doubt have
missed a few; sorry for the extra work and feel free to just reference
some other discussions instead of repeating their contents.

Please don't refer to the "jti" claim as a "Nonce".  There is a separate
registered "nonce" JWT claim that plays a different role, and mixing up
the terminology is confusing, even if the JWT ID value can be used as a
nonce in some circumstances (but not all).

Please reference (and act on, if/as appropriate) the JWT BCP (RFC 8725).

Section 1

   Specifically, the CDNI Framework [RFC7336] states:

      The CSP may also trust the CDN operator to perform actions such as
      delegating traffic to additional downstream CDNs, and to enforce
      per-request authorization performed by the CSP using techniques
      such as URI Signing.

   In particular, the following requirement is listed in the CDNI
   Requirements [RFC7337]:

(editorial) It reads a bit oddly to have both a "specifically" and an
"in particular"; the second line might be reframed as more of an
"additionally" or "also" type remark.

Section 1.2

   A CSP and CDN are assumed to have a trust relationship that enables
   the CSP to authorize access to a content item by including a set of
   claims in the form of a signed JWT in the URI before redirecting a UA
   to the CDN.  [...]

nit/editorial: the trust relationship is what enables the authorization
of access, but using claims in a signed JWT to effectuate that is more
of an implementation agreement that builds on the trust relationship
than an aspect of the trust relationship itself.  So this could be
"enables the CSP to authorize access to a content item, which is
realized in practice by including a set of claims in a signed JWT", or
similar.

Section 1.3

                       In step #3, the UA may send an HTTP request or a
   DNS request.  Depending on whether HTTP-based or DNS-based request
   routing is used.  [...]

nit: sentence fragment.

                                         Regardless of the type of keys
   used, the verifying entity has to obtain the key (either the public
   or the symmetric key).  [...]

Not just obtain the key, but obtain it in a manner that allows trust to
be placed in the assertions made using that key.

Section 2

   o  URI Signing Package (URISigningPackage): The URI attribute that
      encapsulates all the URI Signing claims in a signed JWT encoded
      format.  This attribute is exposed in the Signed URI as a path-
      style parameter or a form-style parameter.

Is there a good reference for "URI attribute"?  It sounds like should be
a technical term but I couldn't find a clear definition.

   The URI Signing Package will be found by parsing any path-style
   parameters and form-style parameters looking for a key name matching
   the URI Signing Package Attribute.  Both parameter styles MUST be
   supported to allow flexibility of operation.  The first matching
   parameter SHOULD be taken to provide the signed JWT, though providing
   more than one matching key is undefined behavior.

Shouldn't the metadata specify which parameter style is going to be
used?  (Perhaps two, rather than one, new values for cdnistt?)

Section 2.1

   The following claims (where the "JSON Web Token Claims" registry
   claim name is specified in parenthesis below) are used to enforce the
   distribution policies.  All of the listed claims are mandatory to
   implement in a URI Signing implementation, but are not mandatory to
   use in a given signed JWT.  (The "optional" and "mandatory"
   identifiers in square brackets refer to whether or not a given claim
   MUST be present in a URI Signing JWT.)

The final parenthetical suggests that the previous sentence should read
"not necessarily mandatory to use" (since apparently some of them *are*
mandatory to use).  Though I do see this was noted by Roman as well.  I
would be interested to hear why cdniuc is not mandatory (see below)...

   Note: The time on the entities that generate and verify the signed
   URI SHOULD be in sync.  In the CDNI case, this means that CSP, uCDN,
   and dCDN servers need to be time-synchronized.  It is RECOMMENDED to
   use NTP [RFC5905] for time synchronization.

It's surprising that this is only a SHOULD-level requirement for time
synchronization, given the scope of issues that can result if time is
not synchronized.  When would it be okay to ignore the SHOULD?

Also, separately, I note that RFC 8915 presents Network Time Security
for NTP, which might be a helpful reference (and, arguably, worth
recommending in its own right).

Section 2.1.x

In general, my stance is that it's redundant to say that "the semantics
in Section X of RFC 7519 MUST be followed", because that's inherent in
the definition of the JWT claim.  But you're free to write the text as
you wish.

Section 2.1.1

   Issuer (iss) [optional] - The semantics in [RFC7519] Section 4.1.1
   MUST be followed.  This claim MAY be used to verify authorization of
   the issuer of a signed JWT and also MAY be used to confirm that the
   indicated key was provided by said issuer.  If the CDN verifying the

What is meant by "to verify authorization of the issuer of a signed
JWT"?  In some sense, the "iss" claim is meaningless unless the JWT
signature is validated as having been generated by a trusted key
associated that belongs to the "iss" identity (or the JWT was received
on a trusted channel, which of course does not apply here since it's via
the UA).  (Also note that the JWT BCP (RFC 8725) has some things to say
about when to use "iss" and how that relates to whether a given key is
used in more than one context...)

   signed JWT does not support Issuer verification, or if the Issuer in

I think this is intended to be "If an Issuer claim is present and the
CDN verifying the signed JWT [...]".

   the signed JWT does not match the list of known acceptable Issuers,
   the CDN MUST reject the request.  [...]

I think this list also needs to include "if the Issuer claim does not
match the key used to sign the JWT".

Section 2.1.2

   Subject (sub) [optional] - The semantics in [RFC7519] Section 4.1.2
   MUST be followed.  If this claim is used, it MUST be a JSON Web
   Encryption (JWE [RFC7516]) Object in compact serialization form,
   because it contains personally identifiable information.  This claim

While I am happy to see that the subject information is recognized as
PII and required to be protected, it seems that this formulation is
over-constrained.  Why does the Subject specifically need to be
compact-serialization-form JWE, as opposed to some other encrypted form
(that cannot be correlated to other instances of the same encrypted
Subject?  Why does just using a signed-and-encrypted JWT for the
containing JWT not suffice?

   contains information about the subject (for example, a user or an
   agent) that MAY be used to verify the signed JWT.  If the received
   signed JWT contains a Subject claim, then any JWT subsequently
   generated for CDNI redirection MUST also contain a Subject claim, and
   the Subject value MUST be the same as in the received signed JWT.  [...]

Strict value equivalence seems problematic (given that we mandate
compact-form JWE), since there is a key (re)distribution problem for
making the information usable to any dCDN that is involved.  If it's
encrypted using a symmetric key, then the uCDN sharing it to the dCDN
introduces the same issue as for "signed" JWTs -- the dCDN can
impersonate the CSP; if it's using an asymmetric key then the set of
recipients is fixed at JWE creation (by the CSP) and we either lose the
ability to seamlessly add CDN tiers or have to redistribute the private
key (which is against best practices), in order to meet the "byte for
byte the same value" requirement.  What motivates the prohibition of
re-encrypting for the next level of hierarchy?

Section 2.1.3

   Audience (aud) [optional] - The semantics in [RFC7519] Section 4.1.3
   MUST be followed.  This claim is used to ensure that the CDN verifing
   the JWT is an intended recipient of the request.  The claim should
   contain an identity on behalf of whom the CDN can verify the token
   (e.g., the CSP or any uCDN in the chain).  A dCDN MAY modify the
   claim as long it can generate a valid signature.

While RFC 7519 does say that "[t]he processing of this claim is
generally application specific", the description here doesn't seem to
make a whole lot of sense.  It's supposed to be used by the entity
receiving the JWT, which is never going to be the CSP (which generates
the JWT).  My intuition is that typically the CSP would issue a JWT with
Audience of the uCDN (or some meta-Audience for the combination of uCDN
and dCDN), and then either the uCDN would re-sign with the dCDN as the
Audience or the dCDN would be configured to recognize the Audience used
by the CSP as being valid for itself.

Also, "the Audience used by the CSP" is perhaps ambiguous as to whether
that's the one inserted by the CSP or recognized by the CSP as being
itself.  So maybe "recognize the Audience inserted in the JWT by the
CSP"?

Section 2.1.4

   Expiry Time (exp) [optional] - The semantics in [RFC7519]
   Section 4.1.4 MUST be followed, though URI Signing implementations
   MUST NOT allow for any time synchronization "leeway".  If the CDN

Why do we have "MUST NOT allow for any [leeway]" when it's only
RECOMMENDED to have synchronized time?

   verifying the signed JWT does not support Expiry Time verification,

As above, I think this is meant to be "If the Expiry Time claim is
present and the CDN verifying [...]".

   or if the Expiry Time in the signed JWT corresponds to a time equal
   to or earlier than the time of the content request, the CDN MUST
   reject the request.  [...]

Section 2.1.5

[conceptually same comments as for §2.1.4, adjusted for the "nbf" claim]

Section 2.1.6

   Issued At (iat) [optional] - The semantics in [RFC7519] Section 4.1.6
   MUST be followed.  If the received signed JWT contains an Issued At
   claim, then any JWT subsequently generated for CDNI redirection MUST
   also contain an Issued At claim, and the Issuer value MUST be updated

nit: s/Issuer value/Issued At value/

Section 2.1.7

            If the signed JWT contains a Nonce claim and the CDN
   verifying the signed JWT either does not support Nonce storage or has
   previously seen the Nonce used in a request for the same content,
   then the CDN MUST reject the request.  [...]

As above, this seems predicated on the "jti" claim being present in a
received token.

Section 2.1.9

It might be worth asking the OAuth WG if there's seen to be value in
having a generic "crit" claim that protocols can require comprehension
of, to hold a list of claims that are critical for that token in that
protocol.

                               If any of the listed extension claims are
   not understood and supported by the recipient, then the Signed JWT is
   invalid.  [...]

(editorial) In the other sections we seem to use language about "MUST
reject the request" or "MUST reject the JWT" rather than just saying
that the JWT "is invalid"

Section 2.1.10

[same comments about encryption as for Subject]

Section 2.1.11

Why is the CDNI URI Container claim optional?  It seems like the URI
Signing cannot be fit for purpose if the URI being signed is not
contained in the token...

Section 2.1.12

Can we give any guidance on what kind of values might make sense for the
CDNI Expiration Time Setting field and still providing some reasonable
security properties?  (Conversely, what kind of values are so large so
as to be nonsensical?)

Section 2.1.14

The first two paragraphs seem to talk about this claim as being a
direction to the client of when to send such a token along with a
request, but the third paragraph seems to talk about it as being a
direction to the CDN for generating new tokens as part of Signed Token
Renewal.  This leaves me confused about what the intended usage actually
is.

Section 2.1.15

   The URI Container (cdniuc) claim takes one of the following forms:
   'hash:' or 'regex:'.  More forms may be added in the future to extend
   the capabilities.

How will a JWT producer know whether a JWT consumer knows about any such
extended functionality?

Section 2.1.15.2

   An example of a 'regex:' is the following:

  [^:]*\\://[^/]*/folder/content/quality_[^/]*/segment.{3}\\.mp4(\\?.*)?

It seems a bit surprising to just do a wildcard match on scheme and
assume that the path components will be meaningful for that scheme.
Perhaps a variation that used branches to match only http or https
schemes would be preferred?

Section 3.2

   this document.  However, in order to also support legacy UAs that do
   not include any specific provisions for the handling of signed JWTs,
   Section 3.3 defines a mechanism using HTTP Cookies [RFC6265] that
   allows such UAs to support the concept of renewing signed JWTs
   without requiring any additional UA support.

(editorial) the way this sentence is written suggests that the §3.3
cookie-based mechanism is distinct from the mechanism described here
(most notably due to the use of the word "also"), but it looks like the
mechanism described here also uses cookies.  Are the two actually
distinct?

Section 3.2.1

(editorial) typically we don't use second-person language ("you") in RFC
style.

Section 3.3.1

   In such scenarios, Signed Token Renewal of a signed JWT SHOULD be
   communicated via the query string instead, in a similar fashion to
   how regular signed JWTs (outside of Signed Token Renewal) are
   communicated.  Note that the use of URL embedded signed JWTs SHOULD
   NOT be used in HTTP 2xx Successful messages, since UAs might not know
   how to extract the signed JWTs.

I don't think I understand how (in the last sentence) a URL embedded
signed JWT would be used in an HTTP 2xx response, since the response
would just be normal application content and there's not a particularly
well-defined place to put a URL with embedded JWT.

Section 4

   necessary to allow the dCDN to verify a Signed URI.  Events that
   pertain to URI Signing (e.g., request denial or delivery after access
   authorization) need to be included in the logs communicated through
   the CDNI Logging interface.

(editorial) I don't think I understand what is meant by "e.g., request
denial or delivery after access authorization".  I'm not even 100% sure
if I'm supposed to group thing as "(request denial or delivery) (after
access authorization)" or "(request denial) or (delivery after access
authorization)".  My initial thought was the latter, but "delivery after
access authorization" really doesn't make much sense to me; my current
thinking is that it's the former and that s/after access
authorization/after an access authorization decision has been made/
would clarify.

Section 4.4

      Property: issuers

         Description: A list of valid Issuers against which the Issuer
         claim in the signed JWT may be verified.

Issuers should always be tied to keys that they control.  Leaving keys
and issuer identities to be managed separately invites identity
misbinding attacks.

      Property: package-attribute

         Description: The name to use for the URI Signing Package.

(nit?) Should this be "The attribute name to use"?

      Property: jwt-header

         Description: The header part of JWT that is used for generating
         or verifying a signed JWT when the JWT token in the URI Signing
         Package does not contain a header part.

(editorial) IIUC this metadata interface is for the uCDN to provide
information to the dCDN that the dCDN will use for processing requests
(i.e., in this case, for verifying JWTs).  In that context, I don't see
how it's useful to say that this is the header part of the JWT "that is
used for generating", since the dCDN only needs to verify these JWTs.
If the dCDN is issuing its own JWTs when acting as an uCDN in a
hierarchy, it can list its own jwt-header in its own published metadata.

   The following is an example of a URI Signing metadata payload with
   explicit values:

   {
     "generic-metadata-type": "MI.UriSigning"
     "generic-metadata-value":
       {
         "enforce": true,
         "issuers": ["csp", "ucdn1", "ucdn2"],

It might be more helpful to use the URI form of the Issuer names, since
in this generic RFC we do not have any deployment-specific context that
would allow the use of a short string issuer identifier.

Section 5

   URI Signing supports both HTTP-based and DNS-based request routing.
   JSON Web Token (JWT) [RFC7519] defines a compact, URL-safe means of
   representing claims to be transferred between two parties.  The
   claims in a signed JWT are encoded as a JSON object that is used as
   the payload of a JSON Web Signature (JWS) structure or as the
   plaintext of a JSON Web Encryption (JWE) structure, enabling the
   claims to be digitally signed or integrity protected with a Message
   Authentication Code (MAC) and/or encrypted.

AFAICT this is the only place in the document where we refer to a
possibility of using JWE over the entire JWT (as opposed to just the
Subject or IP address claim bodies).  Yes, this is in some sense a
generic statement about JWT and not necessarily attempting to apply to
the URI Signing usage of JWT, but it still seems out of place.  I would
have expected that we just stick to talking about JWS (or, I suppose,
that JWE was mentioned consistently throughout, but it doesn't seem to
be a great fit for this application anyway).

Section 5.1

   2.   CSP provides to the uCDN the information needed to verify signed
        JWTs from that CSP.  For example, this information may include a
        key value.

When would it not include a key value?

   3.   Using the CDNI Metadata interface, the uCDN communicates to a
        dCDN the information needed to verify signed JWTs from the uCDN
        for the given CSP.  For example, this information may include
        the URI query string parameter name for the URI Signing Package
        Attribute.

It would also include key material if the uCDN is re-signing, right?
So either we should mention key material here or change (9) to not
mention "computes".

   4.   When a UA requests a piece of protected content from the CSP,
        the CSP makes a specific authorization decision for this unique
        request based on its personal distribution policy.

(nit) I'd suggest s/personal/local/, since the CSP is typically not a
person.

Section 5.2

   2.   CSP provides to the uCDN the information needed to verify
        cryptographic signatures from that CSP.  For example, this
        information may include a key.

As above, when would this not include a key value?

   4.   When a UA requests a piece of protected content from the CSP,
        the CSP makes a specific authorization decision for this unique
        request based on its arbitrary distribution policy.

We should use a consistent term between the previous section and here (I
still prefer "local" but the actual word doesn't matter very much).
In general, I'd recomment harmonizing the phrasing between the two
sections; there are several differences that appear when I run a diff,
including "Signed URI" vs "cryptographic signature" or "signed JWTs" vs
"cryptographic signatures".

   12.  If the verification is negative, the dCDN rejects the request
        and sends an error code 403 Forbidden in the HTTP response.

   13.  If the verification is positive, the dCDN serves the request and
        delivers the content.

(nit) I'd suggest "verification result" both here and above.

Section 6.4

   is a 3DIGIT value as defined in Section 4.5.  Additions to the CDNI
   URI Signing Verification Code namespace will conform to the
   "Specification Required" policy as defined in [RFC8126].  Updates to
   this subregistry are expected to be sparse.

(nit) one might interpret "sparse" either as meaning a long time between
allocations or that the numerical values assigned will not be contiguous
ranges, which might be worth clarifying.
(This holds for both the new registries, I think.)

   | 406   | RFCthis   | Signed JWT verification performed and         |
   |       |           | rejected because of Issued At enforcement     |

It's not clear to me what kind of Issued At enforcement might lead to
rejection -- there is no mention of rejection made in §2.1.6, for
example.

Should there be a code for "only one of cdnistt and cdniets present"?

Section 7

                              Whenever the dCDN receives a request with
      a given unique ID, it adds that ID to the list of 'used' IDs.  In
      the case an illegitimate UA tries to use the same URI through a
      replay attack, the dCDN can deny the request based on the already-
      used access ID.

You probably also want to mention expiring out IDs from the list of
'used' IDs when they expire, or this becomes an unbounded state-keeping
requirement...

Section 8

The main body text mentioned both Subject and IP address as having
potential privacy concerns; why do we only mention IP address here?

Section 11.2

https://www.ietf.org/about/groups/iesg/statements/normative-informative-references/
suggests that with NTP being RECOMMENDED, RFC 5905 would be classified
as normative.

Appendix A

The "exp" times are in 2016; if regenerating the examples is automated
using newer dates might be nice (but the risk of getting into an
inconsistent state if redoing them by hand is too big to merit changing
the dates in that case, IMO).

Appendix A.3

   Once the server verifies the signed JWT it will return a new signed
   JWT with an updated expiry time (exp) as shown below.  Note the
   expiry time is increased by the expiration time setting (cdniets)
   value.

This example is adding the "cdniets" value to the previous "exp" value,
but the specification for this claim says that it is added to the "time
at which the JWT is verified", which is unlikely to be exactly the
previous "exp" value.  I suggest adding a few words about this and using
a different (earlier) "exp" in the re-signing example.