FHIR Chat · Backend Services - Public keys · smart

Stream: smart

Topic: Backend Services - Public keys


view this post on Zulip Sagar Shah (Aug 12 2021 at 22:12):

Hello everyone,
For SMART backend services, for the jwks public keys, what format is expected. Does it need to have "use":"sig" param in the body or not? I could not find any concrete example for the same? Our OpenID server requires tihs parameter, while I could not find an example on SMART on FHIR website as this link is broken there (http://build.fhir.org/ig/HL7/bulk-data-export/authorization/sample-jwks/RS384.public.json) and inferno jwks keys does not have "use" in the json body.
Any clarification on this is appreciated

view this post on Zulip Josh Mandel (Aug 12 2021 at 22:52):

We don't say anything about this specifically, and the base jwk specification leaves this optional. https://github.com/smart-on-fhir/bulk-data-server/blob/master/static/keys/RS384.public.json is a working link to our example keys, and looks like it omits this property.

So: as a client, you shouldn't depend on this property

view this post on Zulip Vladimir Ignatov (Aug 12 2021 at 23:10):

In my experience, depending on how the key has been generated, this property may or may not be included. If you know that this is a public key you can assume use: "sig". This is similar to "key_ops": ["verify"].

However, a JWKS is just a collection of JWK keys and in theory you might have anything in there (including private keys). A strict implementation on the client side may/should not trust that all keys in the JWKS are public and may want to filter out any private keys using the use or key_ops properties.

In this case the important thing is to make sure you ONLY host public keys in that JWKS. Once you are certain of that, you can even manually add use or key_ops to those keys if needed, and that will not invalidate them in any way.

view this post on Zulip Sagar Shah (Aug 13 2021 at 13:38):

Thank you for the responses. It seems we are blocked on this with our Open ID implementation tool as it does require use parameter only and as per specs it says - Use of the "use" member is OPTIONAL, unless the application requires its presence.

view this post on Zulip Josh Mandel (Aug 13 2021 at 14:19):

You can just add this field to any keys you want to parse in your library, if needed --- are you saying that your library is responsible for fetching and parsing jwks files directly, with no opportunity for intervention?

view this post on Zulip Sagar Shah (Aug 13 2021 at 15:16):

Our auth server (Open ID) is an open source product Ory Hydra, so I have put up a request on their github as well if this change can be accomodated there. but if they are still compliant with OIDC, then they may not take this up. and as a result inferno keys (I believe inferno is one of the tools to be used for certifications for Cures Act) won't work with our OpenID solution. Our Auth server only stores the public url of jwks keys and connect to that endpoint and retrieve keys "as is". It does support storing keys in raw format as well, but inferno does not recommend that approach for certification needs

view this post on Zulip Yunwei Wang (Aug 14 2021 at 04:15):

According to Bulk Data Backend Service Authorization Guide, using JWK Set directly is strongly discouraged

view this post on Zulip Yunwei Wang (Aug 17 2021 at 15:35):

A broader question is that if Inferno add "use": "sig" to its public key, would that cause other servers to fail because "The "use" and "key_ops" JWK members SHOULD NOT be used together"

view this post on Zulip Sagar Shah (Aug 17 2021 at 16:41):

Thanks @Yunwei Wang for your response. We are using public Jwk url of the client and that seems to be working as long as that url provides "use":"sig" in its key because our Open ID implementation uses this key. Even though use of both key_ops and use together is discouraged it should still support and allow as long as the values for both key_ops and use are consistent. Also is it not possible to have a different public key with use instead of key_ops as we can have multiple jwks keys exposed via that url?

view this post on Zulip Yunwei Wang (Aug 17 2021 at 17:10):

Have you tried save the public key locally, insert the use property, and register Inferno using that modified key?

view this post on Zulip Sagar Shah (Aug 17 2021 at 17:20):

Yes. I tried that option and verified that it solved the issue

view this post on Zulip Yunwei Wang (Aug 17 2021 at 17:41):

OK. That confirms that the use tag does not actually impact the encryption and decryption. Is that right?

view this post on Zulip Sagar Shah (Aug 17 2021 at 17:52):

Not sure, if I understood your queston correctly.

As I see use can have two values.

  1. sig - indicating its used for verifying signature (equivalent to key_ops=[verify]
  2. enc - indicating its used for encryption

When I used sig='use' for the inferno keys in raw format for my regitered client(for testing), I found that token endpoint was working fine

view this post on Zulip Yunwei Wang (Aug 17 2021 at 17:54):

Does BDA-07 and BDA-08 pass?

view this post on Zulip Sagar Shah (Aug 17 2021 at 18:04):

I am not able to test it from inferno as I cannot change publi inferno jwks url, but I verified that for BDA-07, I was getting token using postman. if we have inferno url with use:sig then I can verify that from inferno. For now, I am not sure how do I bypass and use a different key when testing from inferno. Because of this, BDA-08 is being skipped as well

view this post on Zulip Yunwei Wang (Aug 17 2021 at 18:18):

Inferno need to be preregistered as client with its public key to get client_id from authorization server. I assume you can: register Inferno using the locally saved JWKS instead of the JWKS url. Then run the Inferno Multi-Patient tests. I am wondering if that works.

view this post on Zulip Sagar Shah (Aug 17 2021 at 19:02):

Yes, with that approach it did pass. image.png However, BDA-06 failed for a different reason. This issue is of invalid client and OpenID implementation is returning 401 instead of 400 (which is another issue that I am investigating) as there too OpenID spec says it can return 401 when invalid_client error is returned

view this post on Zulip Sagar Shah (Aug 17 2021 at 19:09):

So I am also wondering if this (other issue about invalid client on BDA-06) should be reported as a bug on inferno or not?

view this post on Zulip Yunwei Wang (Aug 17 2021 at 19:27):

Can you post the server response headers?

view this post on Zulip Sagar Shah (Aug 17 2021 at 19:30):

For BDA-06:
Headers
date: Tue, 17 Aug 2021 18:56:26 GMT
content_type: application/json;charset=ISO-8859-1
content_length: 262
connection: keep-alive
cache_control: no-cache, no-store, max-age=0, must-revalidate
pragma: no-cache
expires: 0
strict_transport_security: max-age=31536000; includeSubDomains
x_frame_options: ALLOWALL
x_xss_protection: 1; mode=block
x_content_type_options: nosniff
referrer_policy: no-referrer
content_security_policy: default-src https:; connect-src https: wss:; font-src https: data:; frame-src https:; frame-ancestors https: http:; img-src https: data:; media-src https:; object-src https:; script-src 'unsafe-inline' 'unsafe-eval' https:; style-src 'unsafe-inline' https:;
feature_policy: payment 'none';

For BDA-07:
date: Tue, 17 Aug 2021 18:56:26 GMT
content_type: application/json;charset=UTF-8
transfer_encoding: chunked
connection: keep-alive
cache_control: no-cache, no-store, max-age=0, must-revalidate
pragma: no-cache
expires: 0
strict_transport_security: max-age=31536000; includeSubDomains
x_frame_options: ALLOWALL
x_xss_protection: 1; mode=block
x_content_type_options: nosniff
referrer_policy: no-referrer
content_security_policy: default-src https:; connect-src https: wss:; font-src https: data:; frame-src https:; frame-ancestors https: http:; img-src https: data:; media-src https:; object-src https:; script-src 'unsafe-inline' 'unsafe-eval' https:; style-src 'unsafe-inline' https:;
feature_policy: payment 'none';

Does this help?

view this post on Zulip Yunwei Wang (Aug 17 2021 at 19:35):

RFC6749 section 5.2 states that

The authorization server MAY
return an HTTP 401 (Unauthorized) status code to indicate
which HTTP authentication schemes are supported.

That does make sense I think. Please create a github issue on Inferno Program for this. We will add 401 as expected status code. Thanks @Sagar Shah

view this post on Zulip Sagar Shah (Aug 17 2021 at 19:40):

Thanks a lot for confirmation @Yunwei Wang . I will create a ticket for this shortly today.

view this post on Zulip Sagar Shah (Aug 17 2021 at 19:42):

Also do you consider adding "use":"sig" as well in the inferno keys? Or that still requires more investigation and research? Please advise

view this post on Zulip Sagar Shah (Aug 17 2021 at 19:52):

Created https://github.com/onc-healthit/inferno-program/issues/345

view this post on Zulip Yunwei Wang (Aug 17 2021 at 19:54):

It is up to the server on how to register a client using public key. This is out of Inferno testing process. As we have tested, it does not prevent a server from registering Inferno as a client (with a work around) and it does not affect encryption and decryption. IMO Infenro does not need to accommodate that optional parameter to avoid any side effects on other servers.

view this post on Zulip Sagar Shah (Aug 17 2021 at 19:59):

Ok. I understand. But would/can that cause an impact on certification process as inferno is the tool (as I have heard) being used for certification. Of course with workaround it works fine, but not certain if that's acceotable to certifying agencies. So I was suggesting a change in public keys or maybe additional keys using the "use" parameter

view this post on Zulip Jim Dow (Aug 20 2021 at 15:20):

At Drummond, we also have a couple of customers using an open source Hydra that passes a "use:sig" and Inferno fails their testing. This is blocking them from passing the required ONC testing for g.10. There are currently multiple issues open on this in the Inferno github; however, we cannot allow them to pass testing until it is at least acknowledged that this is a bug that Inferno does not allow "use" as an OAUTH key.

view this post on Zulip Yunwei Wang (Aug 20 2021 at 16:49):

Inferno does not "allow" or "disallow" any JWK parameter. Inferno doesn't provide use parameter because 1) the parameter is optional, and 2) Inferno uses the key_ops parameter to convey the same message. Since the parameter is optional in RFC 7515, then server shall be able to register a public key with or without that parameter.

view this post on Zulip Yunwei Wang (Aug 25 2021 at 18:57):

I am coming back to the this question again. Inferno is considering to add use: sig to the public keys.

According to RFC-7517

The "use" and "key_ops" JWK members SHOULD NOT be used together;
however, if both are used, the information they convey MUST be
consistent.

It should be fine to have both values in the same key, like

            "use": "sig",
            "key_ops": [
                "verify"
            ],

Will there be a problem to have both in the same public key? Thought?
@Josh Mandel @Vladimir Ignatov

view this post on Zulip Josh Mandel (Aug 25 2021 at 18:59):

That'd be an inferno product decision. I think the downside is that it might provide rigid/narrow information about compatibility --- like, systems with hard-coded dependencies on specific optional properties might pass against Inferno but still fail against real-world, spec-compliant endpoints.

view this post on Zulip Josh Mandel (Aug 25 2021 at 19:01):

(To my mind, ideally a testing tool like Inferno would be designed so that systems that "pass" tests with Inferno have the greatest possible chance of working with the whole spectrum of real-world spec-compliant endpoints.)

view this post on Zulip Vladimir Ignatov (Aug 25 2021 at 19:14):

Perhaps you can also list the same key twice. Once with key_ops and once with use. Servers should try every key in the set and only fail if none of them works (although that is not something I have tested). Also, that may be problematic if those keys have kid which should be unique within the set.

view this post on Zulip Yunwei Wang (Aug 25 2021 at 19:47):

@Josh Mandel In this specific test case, we cannot say that a server requiring use parameter is non conformant to RFC-7517 because the RFC does say

Use of the "use" member is OPTIONAL, unless the application requires its presence.

view this post on Zulip Yunwei Wang (Aug 25 2021 at 19:53):

To clarify, client registration is not in Inferno test sequences. Inferno provides the key for server to register Inferno as a bulk data client before tsting

view this post on Zulip Josh Mandel (Aug 25 2021 at 19:58):

I'm saying that if backend service providers want to be widely compatible, they should avoid depending on specific optional properties as much as possible. If Inferno can nudge them in that direction (e.g, by omitting these optional properties), it'd improve interop overall.

view this post on Zulip Sagar Shah (Aug 26 2021 at 19:46):

To my understanding both key_ops and use properties are optional, unless required by the application (OpenID provider). So if Authorization server requires "use" (or the "key_ops"), the client may have to register using that property on Authorization server. At present, inferno does not give that option and always assumes that OpenID provider will support key_ops parameter. That's where I am suggesting that if inferno could support any of the following, then that would work

  • Allow option on the UI to choose between "use" or "key_ops" from public key on the interface when running Bulk Data Tests and accordingly use a url that either produces key with "use" or "key_ops"
  • Include both key_ops and use in the jwks keys
  • Have separate public keys(with different kid) in the set as Vladimir suggested. One of them with "use" and other using "key_ops"

Suggestions are welcome!

view this post on Zulip Josh Mandel (Aug 26 2021 at 20:05):

I'm confused by the mention of Open ID providers here -- neither party in the backend services interaction is necessarily an open ID provider (and if one of the parties happens to be that doesn't surface in this particular interaction), right?

view this post on Zulip Sagar Shah (Aug 26 2021 at 20:06):

By OpenID Provider I meant the Authz server (Authorization server), which complies with Open ID/Auth 2.0 Spec

view this post on Zulip Josh Mandel (Aug 26 2021 at 20:07):

From my perspective, the most helpful thing Inferno could do (given the current specification language) is to publish keys omitting these optional properties. This helps to ensure that authorization servers are robust to their absence. (If we think it's important for them to be present, the specification needs to make this clear. Otherwise we'll just see fragmentation in requirements across different authorization servers.)

view this post on Zulip Sagar Shah (Aug 26 2021 at 20:12):

Right but as I see in specs,
Use of the "use" member is OPTIONAL, unless the application requires its presence
So application may still require it. so simply removing it (use or key_ops) from keys won't work either with many authz servers

view this post on Zulip Josh Mandel (Aug 26 2021 at 20:17):

You're citing an underlying framework specification; I'm talking about what we say at the level of the SMART Backend Services IG, which is intended to provide a profile for consistent use of those underlying specifications. Currently we do not require either field. If one server wants to require key_ops, and another server wants to require use, and another server wants to impose no requirements... This leads to a non interoperable situation.

We should tighten down our specification to be clear about what we mean, or else we should ensure that services are robust too any of these cases.

view this post on Zulip Vladimir Ignatov (Aug 26 2021 at 20:46):

Ideally, auth should work in any of the following cases:

  • the public key has no key_ops or use
  • the public key has key_ops but does not have use
  • the public key has use but does not have key_ops
  • the public key has both key_ops and use

However, we are dealing with an auth server that refuses to trust us by assuming that all the keys in the JWKS are indeed public. I think that is good behavior so far (or at least a good intention :) ). It then excludes case 1 and case 2, picks use (case 3) as the only acceptable option and might also work with case 4.

That said, my opinion is that:

  1. If an auth server wants to "validate" the keys, then it must work with either use or key_ops. It is not correct to require one and disregard the other
  2. Inferno - considering the nature of this tool it probably makes sense to provide as much flexibility as possible (eg. by having multiple keys), as long as that does not violate any specification.
  3. The Backend Services spec itself is probably OK as it is now, although this does point out a weak spot with JWKS URL auth type - since there is no opportunity for manual intervention and key manipulation with this type of auth, clients need to be aware ahead of time if the server has specific expectation for the key structure.

view this post on Zulip Josh Mandel (Aug 26 2021 at 20:52):

Really like this analysis. I'd re-examine (2) -- if the spec is correct, then I'm not sure it's good for Inferno to be "flexible" because it's used for certification of other systems, and a "flexible" Inferno can lead to "brittle" servers being certified. As I said earlier, that's a product decision for the inferno team; and not something for HL7 process to decide.

view this post on Zulip Yunwei Wang (Aug 26 2021 at 23:20):

@Vladimir Ignatov
As stated in RFC-7515, an application can require that parameter though I am not so sure what "application" mean in that RFC.
@Josh Mandel
Bulk Data client registration is not part of Inferno Program testing. It is a prerequisite. So this has nothing to do with the certification. The purpose to include use parameter is to help tester and implementer to register bulk data client.

view this post on Zulip Vladimir Ignatov (Aug 26 2021 at 23:32):

I think that language is too abstract to be taken literally. For example, if you develop a client (like Inferno) and a server to connect to, then you control both sides and you can decide that your server will require use and your client's key will provide it.

However, if you only control the client and that client should be able to connect to multiple servers (not under your control), then I cannot agree that any of those servers should be allowed to require something that is otherwise optional.

P.S. I think "application" is the app that "consumes" the public key. That would be the bulk data server in this case, or it's authorization server.

view this post on Zulip Yunwei Wang (Aug 27 2021 at 01:21):

Maybe Bulk Data IG could add a clarification that client MAY use either use or key_ops parameters and server SHALL be able to handle both of them.

view this post on Zulip Josh Mandel (Aug 27 2021 at 15:53):

Yunwei Wang: Maybe Bulk Data IG could add a clarification that client MAY use either use or key_ops parameters and server SHALL be able to handle both of them.

Would this mean the server SHALL be able to handle

  • the case were neither is present, and
  • the case where only use is present, and
  • the case where only key_ops is present?

Or just that servers SHALL handle the case where both are present? (If it's just "SHALL handle the case when both are present", then we might as well require clients to provide both all the time, because that'd be the only reliably support client behavior.)

view this post on Zulip Josh Mandel (Aug 27 2021 at 15:55):

Bulk Data client registration is not part of Inferno Program testing. It is a prerequisite. So this has nothing to do with the certification.

The end result is a JWKS URL binding to a client -- however that binding is established at registration time, the question is whether the contents a server receives when it dereferences the JWKS URL at runtime are going to work with a given server, or fail. So outside of registration, this is still an important runtime test that's part of certification.

view this post on Zulip Lee Surprenant (Aug 31 2021 at 15:48):

FWIW I just tried this with keycloak and I believe that auth server is also requiring the use field to be present. The only documentation I've found to that effect is in an old issue tracker: https://issues.redhat.com/browse/KEYCLOAK-11156

Consuming keys without validating alg and use is dangerous as such Keycloak requires these to be present. Hence the "application" in this case is Keycloak and we do require these for security reasons.

view this post on Zulip Sagar Shah (Aug 31 2021 at 22:33):

True. I have seen many libraries that work with "use" parameter than key_ops. I would suppose client public keys should include both for compatibility with more authz servers as most authz server are more likely to support one or the other parameter if not both and and still comply with auth specs for jwks keys structure

view this post on Zulip Josh Mandel (Aug 31 2021 at 23:27):

Has anybody encountered real-world issues with software that refuses to import JWKs because they have both use and key_ops designations?

view this post on Zulip Josh Mandel (Aug 31 2021 at 23:28):

(I know that officially there is a recommendation against including these together, but I am curious whether there are real world issues with this practice.)

view this post on Zulip Lee Surprenant (Sep 02 2021 at 13:05):

FYI I opened https://issues.redhat.com/browse/KEYCLOAK-19166 but I would prefer for the keys used in conformance testing to just include the use field. And if we had to pick one between the use field and the key_ops fields, I would recommend the use field at this point because
rfc7517 says

The "key_ops" parameter is intended for use cases in which public, private, or symmetric keys may be present.

The "or" there is rather vague: does it mean any of those 3 (so basically every JWKS) or does it mean in cases where you are likely to have a mix of them?
My interpretation was the latter and so, because the JWKS URLs we're dealing with here should only have public keys (right?), the use field seems more appropriate.

view this post on Zulip Josh Mandel (Sep 02 2021 at 15:09):

JWKS URLs we're dealing with here should only have public keys (right?)

Yes, that's true for sure :-)

Re: proposed changes on keycloak, I'm curious whether you've considered a change that makes keycloak work when neither use nor key_ops is present (e.g., an algorithm like: filter keys by kid; assert use is consistent with signature verification if present; assert that key_ops is consistent with signature verification if present; proceed to signature verification if you haven't blown up yet.)

view this post on Zulip Lee Surprenant (Sep 02 2021 at 16:25):

I'm not a maintainer of the keycloak project, but in past issues they've expressed the opinion I shared earlier that verifying the use of the key is important. I'm happy to suggest your revised algorithm in this issue I opened, but I lack the real-world experience to know how common it is for use to be omitted (with or without a key_ops field)...my assumption is that use must be pretty common for 2 independent OIDC implementations to both get away with requiring it


Last updated: Apr 12 2022 at 19:14 UTC