Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[OpenAPI.Next Proposal] Add client certificate to authentication methods #1004

Closed
jimfox opened this issue Mar 23, 2017 · 74 comments
Closed
Labels

Comments

@jimfox
Copy link

jimfox commented Mar 23, 2017

Use of client certificate for authn is very popular and support is ubiquitous.

@jimfox jimfox changed the title Add client certificate to authentication methods [OpenAPI.Next Proposal] Add client certificate to authentication methods Mar 23, 2017
@khazelton
Copy link

There are a number of client/service interactions where this would be a good choice. In particular this fits when the security requirements can be met by mutual authentication of client and server.

@tobilarscheid
Copy link

tobilarscheid commented Sep 28, 2017

I vote for this, we have some real world use cases where we would like to use something like this. Also, this feature has already been proposed but than somehow got ignored: #451 (comment)

One thing though that from my point of view requires consideration:
When I talk about "client certificate authentication" I typically mean a client presenting a certificate during the TLS handshake and the server granting or denying access based on that (as in rfc5264#section-7.4.6) This is not part of any HTTP interaction at all, it's actually one OSI-Layer lower.
There is now two points of view that you could take:

  • The Extremist:
    OpenAPI is about RESTful APIs, RESTful is HTTP based and happens on Layer 7, let's leave out all this TLS stuff
  • The Realist:
    In reality, RESTful APIs should be served over a TLS secured connection. To access a number of RESTful APIs, certificate based authentication on TLS Level is required and it is therefore reasonable for OpenAPI Spec to acknowledge this fact and allow documentation of it in the Spec.

I personally take the realist's view.

Still, it will be somewhat hard to cramp a TLS based client certificate authentication into the existing Security Scheme Object - this one is heavily based on HTTP. Smartest solution I see for now is adding another type and making all the other fields optional for it.
As for the name of this new type I am not really sure what is the standard name for client certificates in the TLS handshake, I have read mTLS (for mutual TLS) in some contexts, but never really in RFCs. Also, the term mutual makes it somewhat confusable with mutual HTTP authentication - a whole different story. I therefore propose to simply name the type tls - the authentication is based on TLS.
Users might then want to use the description to state the requirements for the cert, but this is optional as servers typically send a list of accepted CAs during the handshake (rfc5246#section-7.4.4).

A typical client certificate security definition would therefore then look like this:

{
   "type": "tls",
   "description": "Cert must be signed by evilcorp.com CA"
}
type: tls
description: Cert must be signed by evilcorp.com CA

@cmheazel
Copy link
Contributor

Concur. I have a number of customers who require TLS with client certificates. If we don't add it to OpenAPI I'll have to write an extension. Better to have it as part of the spec.

@MikeRalphson
Copy link
Member

@cmheazel thanks for the additional data-point. As per #1466 this request is under consideration for OAS 3.1

@fterpstra
Copy link

Within the Dutch public sector we have identified this requirement as well.
b.t.w. @cmheazel nice to see you here as well ;)

@bourgpa
Copy link

bourgpa commented Feb 10, 2018

We also plan to implement a REST API service for EU Customs & Taxations IAM system between European Commision and member states. In that case, it is far more easier for us to use two-way SSL as it is already the case for the SOAP WS already exposed. But for the moment my major problem is the lack of implementation at server-side. I had to switch back to Swager 2.0 api because of that. I hope that a 3.0 implementation will come soon, but I have doubt that the 3.1 will met my dead lines. Do we have an idea when 3.1 specifications will be frozen?

@arnoudquanjer
Copy link

@tobilarscheid I support your realist view. The Dutch municipalities are aiming to convert/replace their current monolithic information systems with an API-first software landscape, fulfilling societal demand for automation, transparency and privacy. To facilitate this we are setting up an open source inter-organisational system facilitating federated authentication, secure connecting and protocolling in a large-scale, dynamic API landscape. In this landscape we want to use two-way TLS.

@MikeRalphson
Copy link
Member

On the subject of TLS client certificate authentication, as a straw man, would the following be sufficient to indicate that the client MUST provide a TLS certificate?

components:
  securitySchemes:
    clientCert:
      type: clientTLS
      serverSelfSigned: true

The default value of serverSelfSigned would be false. A true value would indicate that the client MUST accept self-signed certificates from the server.

Client-side tools would be free to identify or prompt for the relevant certificate using any means they wish.

@tobilarscheid
Copy link

Hi @MikeRalphson, thanks for your input. The solution looks like a good first step to me. However I do not quiet understand the emphasis on serverSelfSigned - why would that be something so important to include it here right away?

@bourgpa
Copy link

bourgpa commented May 15, 2018 via email

@MikeRalphson
Copy link
Member

@tobilarscheid @bourgpa re: self-signed certificates, this is completely up for debate, and is potentially an unwanted feature / in the wrong place, but I wanted to bring up the subject.

Moreover, self-signed certificates are not used in production environements.

This, unfortunately. is not the case in my experience. When an organisation manages their own CA, they sometimes issue self-signed certificates both for servers and clients. They may also have a place in microservice environments.

Personally, my feeling is that we should not list CAs, root certificates, CNs, or tread on the toes of TLS's negotiation of ciphers etc by including this information, but we are open to all use-cases and perspectives regarding this feature.

@tobilarscheid
Copy link

tobilarscheid commented May 15, 2018

When an organisation manages their own CA, they sometimes issue self-signed certificates both for servers and clients. They may also have a place in microservice environments.

It really does not matter for security who signed the certificate as long as you trust the signee - on the other hand accepting a certificate that is signed by someone you don't trust / know is typically a bad idea. Because of this I deem the flag unnecessary / even misleading.

Personally, my feeling is that we should not list CAs, root certificates, CNs, or tread on the toes of TLS's negotiation of ciphers etc by including this information, but we are open to all use-cases and perspectives regarding this feature.

You are right that this is part of the TLS handshake already. Might still be nice to include just for informational purpose, but that could be something that can live in a comment field or the like as well IMHO.

@MikeRalphson
Copy link
Member

@tobilarscheid

It really does not matter for security who signed the certificate as long as you trust the signee - on the other hand accepting a certificate that is signed by someone you don't trust / know is typically a bad idea. Because of this I deem the flag unnecessary / even misleading.

It may matter to the client's authentication libraries, which often must be passed a flag to disable the checking for self-signed certificates.

You are right that this is part of the TLS handshake already. Might still be nice to include just for informational purpose, but that could be something that can live in a comment field or the like as well IMHO.

Indeed, specification extensions / the new draft features approach may be a way to make this extensible.

@tobilarscheid
Copy link

It may matter to the client's authentication libraries, which often must be passed a flag to disable the checking for self-signed certificates.

that's what I say you should never do and specifically should not be promoted by this standard here.

@MikeRalphson
Copy link
Member

that's what I say you should never do and specifically should not be promoted by this standard here.

I understand your concern, but allowing the description of a particular API implementation is not necessarily promoting it. cf. cookie parameters. The OAS is a specification for describing APIs, not a standard or a set of best-practices. My intention in including it was so this issue got debated.

@cmheazel
Copy link
Contributor

cmheazel commented May 15, 2018

We may be making this harder than it has to be.
TLS runs below HTTP on the protocol stack. The scope of an OpenAPI document, and the software processing it, is not likely to extend to that level. So anything the OAS document has to say about TLS client certificates is informative. A Security Requirement Object of:
{
"authentication:ietf:5246:client_certificate": []
}
may be sufficient.
The only impact this will have on the OAS specification is that we would have to:
a) allow Security Requirements that do not map to a Security Schem or
b) allow more values in the type field of the Security Scheme objects or
c) both a and b.
Option B may also be useful for implementing the cryptographic extension discussed a couple weeks ago.

@darrelmiller
Copy link
Member

@cmheazel If docs tools are going to implement "try it" functionality against servers that are in a dev environment where certs are self-signed, they are going to need to know to turn off any cert validation.

@MikeRalphson
Copy link
Member

@cmheazel

b) allow more values in the type field of the Security Scheme objects or

As above, this is the option we're discussing.

@cmheazel
Copy link
Contributor

Sorry, I miss-read the example. This relates to issue #1552

@cmheazel
Copy link
Contributor

@darrelmiller But is that in-scope for OAS? In my experience, client side certificates are configured once and never modified. Any changes required for a dev environment are passed out of band.

@ioggstream
Copy link
Contributor

@bourgpa I have similar requirements too (always for public administrations).

@MikeRalphson what do you think of using the more general x509 reference?

components:
  securitySchemes:
    clientCert:
      type: x509

@MikeRalphson
Copy link
Member

MikeRalphson commented May 17, 2018

@ioggstream fair question. All TLS communication uses x509 certificates, but we probably want to make it clear that for this type of securityScheme the client must additionally present a certificate (in the above example clientCert is an arbitrary identifier, and could be anything). Perhaps to disambiguate any future client certificate types and to indicate the x509 certificate should have the Client Authentication extended key usage, we could use x509client or similar?

@cmheazel
Copy link
Contributor

Perhaps we should introduce security scheme types for both TLS and TLS_Mutual_Authentication. This makes it clear that the client certificate is being used within the context of the TLS protocol.
This is probably a good time to dust off the crypto extension proposal.

@MikeRalphson
Copy link
Member

Perhaps we should introduce security scheme types for both TLS and TLS_Mutual_Authentication

How does this square with your earlier comment

TLS runs below HTTP on the protocol stack. The scope of an OpenAPI document, and the software processing it, is not likely to extend to that level. So anything the OAS document has to say about TLS ... is informative

? TLS usage is a function of the server in use for communication and does not directly relate to the OAS concept of security.

This is probably a good time to dust off the crypto extension proposal.

Not directly in this issue, I feel. That is a much bigger change and focuses on one particular approach to crypto. I expect @isamauny and other interested parties to comment here if this particular proposal conflicts with the crypto extension proposal.

@cmheazel
Copy link
Contributor

cmheazel commented May 17, 2018

@MikeRalphson I made my point. Since the consensus seems to be that TLS-level security is in scope for OAS, we move on.
What I'm trying to avoid here is a point solution. If we are going to support one optional TLS capability, then we should do it in a way that is extensible.

@ioggstream
Copy link
Contributor

ioggstream commented May 25, 2018

@MikeRalphson

To me, just introducing x509client is fine.

type: x509Client
spec: rfc5246
subjectAltName:  # if any of those fields in subjectAltName is required
- DNS
- IP

@MikeRalphson
Copy link
Member

@pleothaud @simo5

These constraints should express at least:
* the accepted TLS protocol version,
* the accepted TLS Cipher Suites,
* if the server certificate will be self-signed or not (at least for the development environments...)

My understanding is that the first two are always negotiated from a common set of values between the client and the server. I understand the possible need to constrain those sets to comply with certain crypto standards but I think this is at least an issue to be addressed once we have consensus on adding the new securityScheme type.

The third is (I still believe) a slightly different case. The use of self-signed certificates is not negotiated between client and server, and in order to make any kind of connection, a hint is required to the client side by the OAS document, not the server that it should enable this mode. In my experience it is difficult to obtain useful connection error messages from aborted TLS connections and always diagnose the cause. Providing this hint is a security feature, in that the client knows not to try and attempt a second connection with 'defences lowered' if this hint is not present.

One argument is that this hint should be at the server level and not at the securityScheme level, to address any development/production issues. We can address that either in the same PR or a following one.

I'm leaning towards tlsClientCert as the securityScheme type value. There seems to be no added value in specifying that such certificates will be x509 in nature, nor which RFCs define TLS today.

@simo5
Copy link

simo5 commented Jun 4, 2018

@MikeRalphson
Version and suites can be probed by the client by directly connecting to the server, I do not understand what purpose it would serve to publish a potentially conflicting policy in an API document. Leave TLS negotiation where it belongs.

As for the self-signed certificates.
If the server certificate is untrusted, the error caused by untrusted certificates is extremely clear and is a completely client side thing (the client aborts the connection). There is no client I know of that would ever retry a connection after such an error, given it is fatal.
If the client certificate is untrusted, likewise th server will return a very clear error.

Last, but definitely not least, whether a certificate is self-signed or signed by a Certitificate Authority (which could be self-signed, non-WebPKI or anything really) is not important, what is important is whether the certificate is trusted (directly or indirectly via trust chain) or untrusted. And that is not a binary option, it is a property of the client, so there is nothing really you can say unambiguoasly from the server about that.

@darrelmiller
Copy link
Member

The following property would be sufficient to indicate a client certificate is required. This does not allow the certificate selection to be automated.

type: mutualTLS

Meta data necessary to allow automated selection of certificate:

issuer: List<Common Name>   
selfSigned: bool
subjectAltName: List<string>

Can we do this as a draft feature?

@pleothaud
Copy link

@MikeRalphson
Specifying version and suites for TLS allow:

  • to know if a client will be able to connect and consume the API before trying (typically some old Java TLS stacks will not support latest suites, for example)
  • to know if the security level of the server is acceptable considering the data you want to transmit to the API backend (example, the company security policy forbids to send healthcare personal data if TLS protocol is not v1.2)

This information should IMHO be at the server level as it's not Authentication related.

@simo5
Copy link

simo5 commented Jun 4, 2018

@pleothaud
all that information is available by simply connecting to the server.
If the OpenAPI spec is being delivered by the same server, then the client already knows the answer to both thos epoints.
If the OpenAPI spec is being delivered by a different server now you have the problem of keeping that data true, better to just probe the target server and see for yourself than rely on Chinese Whispers

@simo5
Copy link

simo5 commented Jun 4, 2018

@darrelmiller what does "selfsigned: bool" indicate ?

@tobilarscheid
Copy link

all that information is available by simply connecting to the server.

fully agree on that one. Authentication generally and client certificate authentication over tls make sense to document in the API spec, as it typically has a "business" meaning for using the API. TLS Versions and protocol details should really be left to be documented by their appropriate means (= tls handshake) as there are purely infrastructural.

@pleothaud
Copy link

@simo5 @tobilarscheid

My point here is that a client should be able to know if it can/want to consume an API based on this API's contract, which is the OAS file.

So, as TLS protocol version and suites have an impact on this decision it makes IMHO sense to provide this information in the OAS file.

WDYT?

@simo5
Copy link

simo5 commented Jun 4, 2018

No I do not think the TLS version has any bearning on whther the app wants to use an API.
Some security policies may prevent talking to a server that only supports outdated TLS versions, but you won't know until you try. Whatever the OAS says the client still has to try to connect an may eventually fail, so trusting that info is redundant and flawed at best.

@darrelmiller
Copy link
Member

@tobilarscheid It means that the certificate being presented by the client is one of these https://en.wikipedia.org/wiki/Self-signed_certificate. The property MUST only have the value true in development scenarios.

@simo5
Copy link

simo5 commented Jun 4, 2018

@darrelmiller what if the client send a certificate signed by a CA that is not trusted by the server ?
do you consider it self-signed or not ?
I think what you want to say is that you want to accept untrusted client certificates ?

@tobilarscheid
Copy link

@tobilarscheid It means that the certificate being presented by the client is one of these https://en.wikipedia.org/wiki/Self-signed_certificate. The property MUST only have the value true in development scenarios.

As others pointed out this is at best misleading. A self signed certificate can be absolutely fine in various scenarios, including production ones. Being self signed says nothing about the trust the server gives to this certificate. IMHO by adding this strange property to the spec we would only contribute to more people misunderstanding the whole certificate / trust / CA / signing complexity!

@darrelmiller
Copy link
Member

@tobilarscheid As I understand it, a self-signed certificate is the most common way that developers create certificates for testing purposes. Unless a server explicitly has this certificate in it's trusted root store then I'm assuming the self-signed certificate would be considered untrusted.

Do you think it would be better to name the property "untrusted" and include the explanation that this would allow a certificate to be used that includes some certificate in it's chain of trust that is untrusted by the server?

@simo5
Copy link

simo5 commented Jun 4, 2018

untrusted would definitely be a much better definition, I am still unsure you need/want it, but at least it would be more accurate

@tobilarscheid
Copy link

so when our team is testing / developing with certificate based authentication we always use a dummy CA who's key is shared among all developers. But I get that this is just anecdotal evidence as well.
Anyways, I hold it with @simo5 - I do not see why you would want that. For other authentication mechanisms there is nothing like this - e.g. for password based, we do not have an option like "accept all passwords".

@isamauny
Copy link

isamauny commented Jun 5, 2018

All, why don't we take a step back and look what we are trying to achieve: documenting the API contract. And transport is part of the contract even if, as you all mention, the TLS negotiation happens at a different level. Let's take this security profile as an example, as it's the kind of information we are trying to capture by extending the specification: http://openid.net/specs/openid-financial-api-part-2.html#tls-considerations.

At the TLS level, there are two things we need to be able to express:
a) I require TLS protocol level x.y and those are the cipher suites I will accept. Is this something that will be setup at the provider level and negotiated at part of TLS protocol ? Yes, absolutely.
b) I require a client cert for mutual TLS (some of the exchanges in that security profile above require that). Again, is that something that's part of the protocol , yes. And the server will advertise the CA it accepts and the client can pick a cert from a list in a browser when asked to present one.

So yes, this is all happening magically behind the scenes... But how will the API consumer know about those constraints ?

The issue with protocol-level negotiation is that if it fails ( because you present the wrong cert, self-signed or not, because you don't support the cipher suites the server requires, etc.) all you get is a protocol level error, which we all know are hard to debug. Put yourself in the position where you consume APIs you have no control over, how will you know a cert is required, that the protocol is TLS 1.2 (what happens when this becomes 1.3 and some old clients don't support it), etc. I guess you can say: run openssl -connect xxx and you will know. You guys know that because you are security specialists, but most people don't master this stuff at all, and that's why it's complicated for many people to understand what the problem can be. If you have helped debug as many TLS connections issues as we have, I am sure you will agree.

If you write, plain and clear:

  • I need a client cert
  • It can/can't be self-signed (as you say, it's all about trust and if you choose to trust self-signed in production, then fine)
  • It has to be signed by these CAs (because I won't trust any other)
  • And the value of subject name must be XXX (because I will verify it)

Then Yes, you repeat what the protocol will negotiate , but at least it's clear to the consumer. The inherent complexity of the TLS protocol is such that to precise what the server expects you have to add multiple meta-data. That does not happen with Basic.

Or you just say: I need a cert, you figure out how to talk to me. And if it fails, you figure out how it fails by opening a ticket with the provider, play with openssl, or whatever means at your disposal to understand the source of the issue at the TLS level.

We opted for the first approach, because:
a) it's clearer as it describes the server setup.
b) it allows the client/test tooling to automatically validate that the cert it has is actually valid according to the specs (with no need to connect and fail)
c) it allows to generate a clear description of the transport contract as part of the API documentation.

We are not trying to replace the TLS transport negotiation here, we are just trying to express as clearly as possible the transport constraints for the API consumer benefit.

@ioggstream
Copy link
Contributor

ioggstream commented Jun 5, 2018

@isamauny @tobilarscheid I stand on those points:

  • no self-signed flag: trusting a given cert is not an API spec

  • TLS algos:

    • they are variable
    • they are possibly enforced by a gateway and spec writers won't even know the values

@darrelmiller I suggest just to reference the certificate fields to be examinated not their values. Eg the authentication layer validates:

  • the client ip to have that IP listed in the cert subjectAltName
  • the certificate subject

But the OpenAPI doesn't list all possible IP values (which could be thousands).

The same for issuers: you might advertise that you're validating the issuer, but not listing the valid issuers as that may vary.

@simo5
Copy link

simo5 commented Jun 5, 2018 via email

@isamauny
Copy link

isamauny commented Jun 5, 2018

Thanks Simo. We obviously come to this from different angles, and I totally understand and respect your position, even if I still think we could do a better job at documenting TLS requirements. Not pre-negotiate, not replace trust mechanisms, just document.

And yes, there are potential issues for contract being disconnected from reality, but if we say that the transport requirements are actually part of the API contract, then changing the server setup does indeed change the contract and therefore the API definition will have to be kept up to date with those changes.

So it all comes down to deciding that the transport setup is of the contract, you say No and you have your reasons, I say Yes and I have mine.

Peace :)

@simo5
Copy link

simo5 commented Jun 5, 2018

Although I understand your angle Isabelle, what I am saying is that the API cannot faithfully report on the (TLS) transport layer, so it shouldn't; doing so would cause the API to lie most of the time and that is not good for anyone.

@ioggstream
Copy link
Contributor

Hi everybody! @MikeRalphson @darrelmiller any news on the subject?

My proposal on which there was some consensus was:

For securitySchemes.type I have no preferences, so all of those are fine:

@ioggstream
Copy link
Contributor

@MikeRalphson @darrelmiller as we merged #1764, we could:

  • close this issue
  • open a new one, like add details for type: mutualTLS

feedback wellcome!

@MikeRalphson
Copy link
Member

As long as we link back to this issue and summarise people's suggestions (not easy!) I'd be happy to close this issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests