Draft: draft-ietf-gnap-core-protocol

Commentary: Updates a number of syntacitcal and semantic requirements for key proofing mechanisms and makes the language more generic around the use of the mechanisms in the protocol and its extensions . change " htu " claim to " uri " for JOSE - based methods , - align token hash with latest dpop ' ath ' claim , - use body hash for detached  with body , - update HTTP message signature syntax , - include verification language , 
 ~At this time , cryptographic and encoded content of examples has not been regenerated and recalculated.~ 
 Deploy preview for gnap - core - protocol - editors - draft ready ! Built with commit https://deploy - preview-250 - -gnap - core - protocol - editors- 
 Cryptographic examples have all been updated . 
 The security considerations should discuss the differences between PKI - based ( with a CA ) and non - PKI keys . This is especially relevant to MTLS signing as it changes how the server - side of the TLS connection is deployed . 
 See discussion on different deployments at : 
 Addressed by security considerations : 
 Key proof sections do not currently detail how to verify each method , including requirements for verifying fields , this needs to be . 
 DPoP defines as not containing path or query components ,  's  methods use the full URL . The JOSE methods should move to a different claim name to avoid confusion with DPoP. 
 See comments at 
 Does n't make sense to me :  is published as an RFC and is well established , so this sounds like an error in DPoP - which should move away from ... What am I missing ? 
 We do n't have control over  's claims , those are defined by the OAuth WG . If we continue to keep  signing in GNAP , we will use what they define as much as we can .  as a signing suite is published as an RFC , GNAP is profiling  ( specifically  ) to have a simple detached HTTP message signature method . 
 The HTTP Message Signatures draft has changed formats , our examples need to be updated to incorporate these changes . 
 There have been several questions about the parameter currently used to convey the hash of an access token in requests to the RS . Right now we use the definition from OpenID Connect : In speaking with the  editors I 've proposed a simplified claim there : It 's functionally similar but does n't require the array truncation step , and it also fixes to a single hash algorithm ( SHA-256 ) instead of having to figure out which hash to use based on the external signing envelope . I think this change makes it both simpler to implement and to understand . 
 Also , for cryptographic agility here we would rely on defining a new claim name and updating the requirements about inclusion . So would always be SHA-256 and once that hash is sufficiently broken and discarded we would define a new claim like for whatever new target there is . 
 +1 for that , much more intuitive than truncating ( and the comment from DPoP editors seem to go in that direction too ) . In relation to what would happen if  gets deprecated : the current method is already based on SHA-256 , so it 's not a new downside an idea would be to name it for instance , to give a minimal versioning ( would currently relate to SHA2 ) and would simplify changes later on ( like avoiding ;-) ) 
 I personally think that naming the next version of the field should be left to the next version . Someone might want to specify or even , but the important thing is that we are n't defining plus parameters , we 're just defining and anything else comes along as its own unique string . That kind of guidance can be written around the registry for the claim and how it 'd get used . 
 works too 
 Reopening this issue : we are not providing cryto - agility , because : We do not indicate how the algorithm could change . Renaming the field to would remedy that . An implementation that did not include would formally be non - compliant , because the field is REQUIRED . We should say something about that . See 
 crypto agility would be provided by defining a new field entirely . The algorithm will not change for . This was discussed in the OAuth WG with  's field which has the same semantics as this . I do not recommend we re - open this . 
 I 'm not asking to reopen it . Just to add a note in the text . The IESG reviewers are bound to comment on this . 
 As I was working on a client implementation , it occurred to me that it would be a lot simpler and less error prone to include a hash of the request body in the JWS rather than doing the current " compute - the - JWS - then - remove - the - body " method . This would remove the and fields from the JWS header , and would add a new sentence describing how to calculate the body hash , dropping the dependency on RFC7797 : This significantly cleans up the client code , since previously the client would have to generate the  , the pull out the header and signature components and reassemble them with an empty body , creating a string like " XXXXX .. XXXXX " . Now it can use a JWS library without any additional hacks on top . 
 Such  header would n't qualify RFC7797 in this case then . 
 how so ? 
 RFC 7797 requires you to include " b64 " in the " crit " header parameter and set the " b64 " header parameter to . Lots of existing JWT parsers obey the " crit " parameter . As you mention , you may remove these parameters . Although , it will result in an inability to parse such JWTs by parsers that already support RFC 7797 . 
 Some of the existing parsers provide a convenient way to get " XXXXX .. XXXXX " without any hacks on top . For example , take a look at method in 
 Not relying on the additional rules specified in RFC7797 seems like a benefit , less specs to read and less edge cases to handle . Removing a dependency on another spec is a benefit . 
 Right , these would n't be RFC7797 values anymore , they would just be plain JWS objects with a specially calculated payload . We still will have the " XXXX .. XXXX " format for payload - less requests ( requests without the body , such as GET and DELETE ) . 
 I think I 'm in favor of this idea , personally . It still fulfills the requirement of covering the message body with the signature method , but it does so in a way that 's perhaps more native to most JOSE developers . It 's also more conducive to the kinds of deployment models discussed in 
 I hear you . I would like to add & emphasize that there are two parts to this story . The first part where we create JWTs and accordingly , there is the second part where we verify them . The beauty is that there are lots of libraries that support RFC 7797 . The rest of the decently implemented libraries JWTs because they do n't know how to proceed with b64 in the crit header parameter and it 's really great IMO . It reduces the chances of errors . Now , let ’s imagine we omitted b64 from the crit header parameter and started to put the SHA-256 hash in the payload of the JWS object . In this case , the verification process should fail by all existing libraries , right ? If you decide to put something like “ gnap - detached ” in the crit header parameter then you will also need to change the code of a JWT library so this library will be able to process it . I am guessing that is n't always possible , rational , or just easy to do . 
 The body of this new method would be a base64 encoded hash value , so we actually do n't : want : the header at all and we would n't be doing RFC7797 here . One thing that 's different from what many libraries may expect is that the body does n't decode into JSON -- but this was always a  , not a JWT . Just about every JWS library I 've used , these days , allows for an arbitrary payload . Even allows for signing an arbitrary string for the payload , but it will base64 encode it first . I think this new approach benefits from not requiring any parameter , enforcement of which I 've found hit - or - miss at best in the JOSE community . 
 will you require the " typ " header parameter to be presented in such JWSs ... with the values like " gnap+jwsd " and " gnap+jws " ? 
 The Proving Possession of a Key with a Request section explicitly states that , I do n't see how a client can make use of the jws param ( Attached JWS payload ) to make calls to " regular " RSs . Normally , they wo n't be ready to accept the " application / jose " content type and the corresponding payload for the endpoint that accepts say " application / json " and " application / xml " . also believe that this specification should n't require the payload ( HTTP Body ) to be included in the calculation of the JWS signature for RSs in case of Detached JWS payload . The reason is that the client ( or any logic that validates access tokens ) does n't always have access to the payload and the bright example for this would be NGinx and . Note , this approach is n't limited in any way to NGinx and is extremely popular among various cloud providers . There are also other minor reasons say just huge payloads ( like a movie upload ) or even a real - time stream ( WebRTC ) and so on and so forth . Both these items are totally fine and definitely should be required for any calls from a client to an AS though . 
 says this about the payload and HTTP headers and 
 Attached  is highly problematic and limited for exactly the reason you describe : it requires the API the client is calling to accept a JOSE encoded payload instead of its native payload ( see ) . Plus , this only works for requests with a message body ( POST / PUT ) so you need to fall back to the detached method for other verbs , and it 's really only mostly applicable for  payloads though technically you can serialize anything in a  so that 's just more it feeling " weird " than being wrong . I 'm personally not a fan of the method for all these reasons , but several members of the WG have stated that it fits their use cases better than other methods . Inclusion of the body ( when present ) in the detached JWS request allows it to be validated along with the signature in the reset of the request . A library outsourcing GNAP with something like an auth_request module would need to include the signature calculation in that module , like here : An AS is just as likely to be behind a security layer proxy , either externalized as you describe or internal to the app like in  's servlet filter system . In any event , to handle body integrity you 're going to have to handle this as part of the filtering system , like here : ... and to me , it 's really not any dissimilar to TLS reverse proxies . As for  , note that we 're only using the signature method of  here , not the whole protocol extension in its context . The restrictions and guidance you 've quoted come from the fact that  is targeted specifically at SPA 's running OAuth 2 , and so the advice does not apply here . 
 The changes to get the whole request body in such externalized components in the Kubernetes ( and its friends ) world are very slim as that somehow defeats the benefits of their use . Note , these components do n't act as a proxy . They receive all or only certain headers of an HTTP request , do their own business , and then finally tells whether access is granted . If granted , the whole initial HTTP request gets a couple of new headers like X - Auth - User- * and then forwarded to the right service to be processed further . If not , a caller gets 401 or an HTTP redirect , etc . is another example of a component that does pretty much the same as NGinx 's auth_request module . There is a bunch of other similar components . I do like that GNAP requires " body " integrity for all interactions between a client and an AS . It feels for me it should be optional for interactions between a client and an RS . 
 This is where things like the HTTP Message Signatures could help , since the body hash is separate from the signing . The client can calculate the body Digest header and pass that along to the signing component . It could also be that the security components get redesigned to accommodate the security protocols . We already saw that shift when API libraries started handling access tokens instead of just HTTP Basic username / password combos , which is all they used to do . Or when browsers adopted the fetch ( ) API as opposed to the deeply limited capabilities that were there before . Now , I 'm not saying that GNAP should count on the world bending to its will , or that we should ignore deployment patterns ; but we also should n't limit the protocol based on a design choice in software that makes sense today and might not in the future . These libraries only look at a couple headers because that 's all they need to do right now , much like in the past they would have just taken in a username and password . 
 These external components do n't really have a choice to read only certain headers or the whole request . They get only what they get from ingress controllers in a cluster . It 's very possible that in the future , these controllers ( like NGinx or Traefic ) will have to provide the SHA-256 hash of the request 's payload in order to accommodate the security protocols as you said . It 's hard to predict when and if it will happen at all . As of today , this is a very common and extremely popular deployment model . 
 The approach proposed in should address these concerns by and large , and this issue will close with 
 Looks fine , but tbh I must test to be sure
Paragraph (version B):
This document contains non-normative examples of partial and complete
HTTP messages.  Some examples use a single trailing backslash '' to
indicate line wrapping for long values, as per RFC8792.  The "\"
character and leading spaces on wrapped lines are not part of the
value.
Paragraph (version A):
All key binding methods used by this specification MUST cover all
relevant portions of the request, including anything that would
change the nature of the request, to allow for secure validation of
the request by the AS.  Relevant aspects include the URI being
called, the HTTP method being used, any relevant HTTP headers and
values, and the HTTP message body itself.  The recipient of the
signed message MUST validate all components of the signed message to
ensure that nothing has been tampered with or substituted in a way
that would change the nature of the request.
Paragraph (version A):
When a key proofing mechanism is bound to an access token, the access
token MUST be covered by the signature method of the proofing
mechanism.
Paragraph (version B):
All key binding methods used by this specification MUST cover all
relevant portions of the request, including anything that would
change the nature of the request, to allow for secure validation of
the request.  Relevant aspects include the URI being called, the HTTP
method being used, any relevant HTTP headers and values, and the HTTP
message body itself.  The verifier of the signed message MUST
validate all components of the signed message to ensure that nothing
has been tampered with or substituted in a way that would change the
nature of the request.  Key binding method definitions SHOULD
enumerate how these requirements are fulfilled.
Paragraph (version B):
When a key proofing mechanism is bound to an access token, the key
being presented MUST be the key associated with the access token and
the access token MUST be covered by the signature method of the
proofing mechanism.
Paragraph (version B):
The key binding methods in this section MAY be used by other
components making calls as part of GNAP, such as the extensions
allowing the RS to make calls to the AS defined in {{I-D.ietf-gnap-
resource-servers}}. To facilitate this extended use, the sections
below are defined in generic terms of the "sender" and "verifier" of
the HTTP message.  In the core functions of GNAP, the "sender" is the
client instance and the "verifier" is the AS or RS, as appropriate.
Paragraph (version A):
The JOSE (JSON Object Signing and Encryption) header MUST contain the
"kid" parameter of the key bound to this client instance for this
request.  The "alg" parameter MUST be set to a value appropriate for
the key identified by kid and MUST NOT be "none".  The "b64"
parameter MUST be set to "false" and the "crit" parameter MUST
contain at least "b64" as specified in RFC7797.
Paragraph (version A):
To protect the request, the JOSE header MUST contain the following
additional parameters.
Paragraph (version A):
The type header, value "gnap-binding+jwsd".
Paragraph (version A):
The HTTP Method used to make this request, as an uppercase ASCII
string.
Paragraph (version A):
The payload of the JWS object is the serialized body of the request,
and the object is signed according to detached JWS RFC7797.
Paragraph (version A):
If the request being made does not have a message body, such as an
HTTP GET, OPTIONS, or DELETE method, the JWS signature is calculated
over an empty payload.
Paragraph (version A):
When the server (AS or RS) receives the Detached-JWS header, it MUST
parse its contents as a detached JWS object.  The HTTP Body is used
as the payload for purposes of validating the JWS, with no
transformations.
Paragraph (version B):
The key identifier.  RECOMMENDED.  If the key is presented in JWK
format, this MUST be the value of the "kid" field of the key.
Paragraph (version B):
The algorithm used to sign the request.  REQUIRED.  MUST be
appropriate to the key presented.  If the key is presented as a
JWK, this MUST be equal to the "alg" parameter of the key.  MUST
NOT be "none".
Paragraph (version B):
When a request is bound to an access token, the access token hash
value.  The value MUST be the result of Base64url encoding (with
no padding) the SHA-256 digest of the ASCII encoding of the
associated access token's value.  REQUIRED if the request protects
an access token.
Paragraph (version B):
If the HTTP request has a message body, such as an HTTP POST or PUT
method, the payload of the JWS object is the Base64url encoding
(without padding) of the SHA256 digest of the bytes of the body.  If
the request being made does not have a message body, such as an HTTP
GET, OPTIONS, or DELETE method, the JWS signature is calculated over
an empty payload.
Paragraph (version B):
The client instance presents the signed object in compact form
RFC7515 in the Detached-JWS HTTP Header field.
Paragraph (version B):
When the verifier receives the Detached-JWS header, it MUST parse and
validate the JWS object.  The signature MUST be validated against the
expected key of the signer.  All required fields MUST be present and
their values MUST be valid.  If the HTTP message request contains a
body, the verifier MUST calculate the hash of body just as the signer
does, with no normalization or transformation of the request.
Paragraph (version A):
The payload of the JWS object is the JSON serialized body of the
request, and the object is signed according to JWS and serialized
into compact form RFC7515.
Paragraph (version A):
When used to present an access token as in use-access-token, the
Authorization header MUST be included in the signature.
Paragraph (version A):
The "b" (body hash) field MUST be calculated and supplied, unless
there is no entity body (such as a GET, OPTIONS, or DELETE
request).
Paragraph (version B):
The HTTP URI used for this request, including all path and query
components and no fragment component.
Paragraph (version B):
When a request is bound to an access token, the access token hash
value.  The value MUST be the result of Base64url encoding (with
no padding) the SHA-256 digest of the ASCII encoding of the
associated access token's value.
Paragraph (version B):
If the HTTP request has a message body, such as an HTTP POST or PUT
method, the payload of the JWS object is the JSON serialized body of
the request, and the object is signed according to JWS and serialized
into compact form RFC7515.  The client instance presents the JWS as
the body of the request along with a content type of "application/
jose".  The AS MUST extract the payload of the JWS and treat it as
the request body for further processing.
Paragraph (version B):
When the verifier receives an attached JWS request, it MUST parse and
validate the JWS object.  The signature MUST be validated against the
expected key of the signer.  All required fields MUST be present and
their values MUST be valid.  If the HTTP message request contains a
body, the verifier MUST decode the payload of the JWS object and
treat this as the HTTP message body.
Paragraph (version B):
This method is indicated by "mtls" in the "proof" field.  The signer
presents its TLS client certificate during TLS negotiation with the
verifier.
Paragraph (version B):
The verifier compares the TLS client certificate presented during
mutual TLS negotiation to the expected key of the signer.  Since the
TLS connection covers the entire message, there are no additional
requirements to check.
Paragraph (version B):
Note that in many instances, the verifier will not do a full
certificate chain validation of the presented TLS client certificate,
as the means of trust for this certificate could be in something
other than a PKI system, such as a static registration or trust-on-
first-use.
Paragraph (version B):
The verifier MUST parse and validate the DPoP proof header as defined
in I-D.ietf-oauth-dpop.  If the HTTP message request includes a
message body, the verifier MUST calculate the digest of the body and
compare it to the "htd" value.  The verifier MUST ensure the key
presented in the DPoP proof header is the same as the expected key of
the signer.
Paragraph (version B):
This method is indicated by "httpsig" in the "proof" field.  The
sender creates an HTTP Message Signature as described in I-D.ietf-
httpbis-message-signatures.
Paragraph (version B):
The Digest header as defined in RFC3230.  When the request message
has a body, the signer MUST calculate this header value and the
verifier MUST validate this header.
Paragraph (version B):
The Authorization header used to present the access token as
discussed in use-access-token.
Paragraph (version B):
Other covered content MAY also be included.
Paragraph (version B):
If the signer's key presented is a JWK, the "keyid" parameter of the
signature MUST be set to the "kid" value of the JWK, the signing
algorithm used MUST be the JWS algorithm denoted by the key's "alg"
field, and the explicit "alg" signature parameter MUST NOT be
included.
Paragraph (version B):
If the HTTP Message includes a message body, the verifier MUST
calculate and verify the value of the "Digest" header.  The verifier
MUST ensure that the signature includes all required covered content.
The verifier MUST validate the signature against the expected key of
the signer.
Paragraph (version B):
The "b" (body hash) field MUST be calculated and included, if the
message includes an entity body (such as a PUT or PATCH request).
Paragraph (version B):
All components of the URL MUST be calculated and included,
including query parameters "q", path "p", and host "u".
Paragraph (version B):
The verifier MUST parse the JWS object of the PoP header.  The
verifier MUST validate the signature of the header against the
expected key of the signer.  The verifier MUST ensure that all
required parts of the message are covered by the signature.  The
verifier MUST ensure that all components of the signature contain
correct values.