Use of client certificate for authn is very popular and support is ubiquitous.
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.
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: https://github.com/OAI/OpenAPI-Specification/issues/451#issuecomment-135856998
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:
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
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.
@cmheazel thanks for the additional data-point. As per #1466 this request is under consideration for OAS 3.1
Within the Dutch public sector we have identified this requirement as well.
b.t.w. @cmheazel nice to see you here as well ;)
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?
@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.
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.
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?
Hello,
I agree. Moreover, self-signed certificates are not used in production
environements.
If you want to put more information useful for the client side, you could
optionally list the CA certificates or URL of CA or eIDAS / alternate LOTL
(for European Union) that are trusted for an 2 WAY SSL authentification
with this service. But it should only be informative.
Pascal
On 15 May 2018 at 09:55, tobilarscheid notifications@github.com wrote:
Hi @MikeRalphson https://github.com/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?—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
https://github.com/OAI/OpenAPI-Specification/issues/1004#issuecomment-389077541,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AiSLQN7RoFEVJbRJioNpVCP_r5vMt_-_ks5tyonbgaJpZM4MmFhZ
.
@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.
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.
@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.
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.
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.
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.
@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.
@cmheazel
b) allow more values in the type field of the Security Scheme objects or
As above, this is the option we're discussing.
Sorry, I miss-read the example. This relates to issue #1552
@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.
@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
@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?
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.
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.
@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.
@MikeRalphson I agree that crypto is a separate issue. But it is related and should be coordinated.
Hi @MikeRalphson, and thanks for your time!
we probably want to make it clear that for this type of securityScheme
the client must additionally present a certificate [...] with the Client Authentication extended key usage
Fair. The goal is to support future definitions based on x509 (eg. SSL -> TLS -> ULS -> WLS ;) )
components:
securitySchemes:
clientCert:
type: x509client
@simo5 could it be ok for that case? https://github.com/openshift/origin/pull/14745#discussion-diff-123263482R683
@darrelmiller not sure that we can manage to always tryit with mutal-tls. The server should be willing to accept an untrusted cert too. We could just provide something in the swagger-ui for that, but not in the spec.
@ioggstream our intent is to only convey what authentications schemes are accepted, and mTLS is one of them.
Note that a server will never accept an untrusted cert, but also that you do not have to use a client cert, mTLS can be optional, if you come with a cert you are implicitly authenticated (or not, depending on configuration) at the HTTP layer, if you come without a cert then you are just anonymous.
@simo5 thx for your reply!
our intent is to only convey what authentications schemes are accepted, and mTLS is one of them.
Sure: do you think the above spec proposal x509client will cover your use case?
Note that a server will never accept an untrusted cert
Sure: that's why I said that the specs shouldn't tell anything on trust (see https://github.com/OAI/OpenAPI-Specification/issues/1004#issuecomment-389184421)
mTLS can be optional, [..] if you come without a cert then you are just anonymous.
afaik OpenAPI allows multiple securitySchemes, eg
components:
securitySchemes:
clientCert:
type: x509client
BasicAuth:
type: http
scheme: basic
@MikeRalphson iiuc https://github.com/OAI/OpenAPI-Specification/issues/14#issuecomment-297457320 says the following, right?
paths:
/ping:
get:
summary: Checks if the server is running
# Both unauthenticated and x509client
security:
-
- x509client
...
how do you specify a path with both anonymous and clientCert?
The syntax is non-obvious (and we have previously solicited PRs to make it clearer / provide an example in spec), but providing optional security requirements is explained in this comment (which it has taken me :rage: amount of time to locate):
https://github.com/OAI/OpenAPI-Specification/issues/14#issuecomment-297457320
@simo5 : some servers will definitely accept untrusted certificates (ssl_verify_client optional_no_ca in NGINX conf or SSLVerifyClient optional_no_ca in Apache conf, for example). It means that you don't want to use TLS for Authentication but only for integrity and confidentiality of exchanged messages. There are a few use-cases for that, specially when you already convey Authentication information using another mechanism.
It could be nice to add two Security Scheme Object types, x509client to require client certificate based mTLS AuthN and none, to solve elegantly the "both anonymous and clientCert" problem.
@pleothaud
It could be nice to add [...]
none, to solve elegantly the "both anonymous and clientCert" problem.
none would just be another way of writing
security:
- {}
and though it may be clearer, the OAS currently favours a more Pythonic ("There should be one - and preferably only one - obvious way to do it")* approach rather than a Perl-style TMTOWTDI approach.
* For some value of "obvious".
@pleothaud from the POV of the securityScheme, that is equivalent to not specifying x509client at all.
We care for exposing a x509 Certificate label only if the client can use a cert to authenticate.
@simo5 from the POV of securityScheme (and hence AuthN) you're right, but for the POV of the ability to consume the API you have to express that the client will have to provide a client certificate to be able to connect.
This is why in addition to the AuthN related requirements (expressed in the Security Scheme, Security Requirement objects and finally in the security fixed field of the Operation object), we should be able to express constraints at the Server object level.
These constraints should express at least:
If a client certificate is required or accepted we should have in addition:
WDYT?
Such an extension to the Server object plus the addition of a x509client Security Scheme Object types would allow to express all combinations of mTLS optional or required, as well as mixing operations requiring no authentication, some other requiring Basic or OAuth only and others requiring mTLS (potentially in addition to Basic or OAuth)
If clientCertificateRequired is required, the Security Requirement stating that an x509client Security Scheme is required to consume a specific Operation will be redundant information (as mTLS AuthN is in this case sort of a side effect of Transport level TLS configuration) but it will anyway be more readable for developers, IMHO
@MikeRalphson I'd never dare to say that Perl is more elegant than Python ;-)
@pleothaud I do not think it makes sense to notify whether the server certificate is self-signed or not.
Either the client trusts it or it doesn't, the server doesn't get to tell the client "I am self signed TRUST me".
Servers need to accept connections w/o client certificates (otherwise you can't even get the OpenAPI definitions without prior knowledge). I am not sure that it makes any sense to advertize the server accepts self-signed but untrusted client certs, it has no purpose.
If the server advertizes that it accepts x509client authentication, then a client can try to use the certs it has, if all of them fail it can try to fallback to non cert based auth. The client can autodetect if a server accepts untrusted certificates [because the connection will go through the TLS layer but requests will fail as unauthenticated as opposed to fail at the TLS connection layer], so the client can decide whether it wants to use a client cert or not; from the POV of a server it makes no sense to require an untrusted client cert as it provides no additional security.
So I am definitely against codifying any option that hints at accepting untrusted certificates, as it is useless from a security POV and/or can be simply probed by the client.
@simo5
2.a. OAS files can be retrieved by other means than an HTTP(S) request
2.b. OAS files can be retrieved for instance from an API developer portal (or any other kind of repo) and then do not have to be retrieved on the backend server exposing directly the API
I'm not sure your assertion that an API backend cannot require a client certificate at TLS level for the whole server can be accepted in any high security environment.
I personnally don't like neither the use of untrusted certificates but in the end it exists, for some good or bad reasons... As they say, "be liberal in what you accept" otherwise you block adoption.
@pleothaud I understand the use case for (1), but it is simply misguided.
A client can never trust a server to tell it to lower all security, otherwise that client is broken by definition (as it can be told the same when in production). Therefore advertizing anything of the sort is simply useless, the developer still need to actively tell the client it is ok to trust an untrusted server. It is therefore something that a server has no reason to advertize to start with.
ok on (2).
On (3) please do not mix TLS with PKI and/or x509 certs, these 3 technologies are inter-related but not mutually interchangeable concepts.
In that oauth drafta a very contrived method is used to postpone validation of certificates to the application layer. But this simply means that the server is not doing mTLS, it is just accepting connnections where clients happen to present an untrusted client certificate and then the server also allows the application to request data on that certificate.
This kind of authentication need to be advertized in a different way via a specific oauth+x509cert label or similar, it has nothing to do with regular x509client and should not be mixed in here.
The point is, you can use untrusted certificates, but it makes no sense for a server to advertize it explicitly, because there is nothing the client can do and nothing the client should do. Either the client has certs to use or it doesn't, either the client trusts the server cert or it doesn't, nothing the server will say about the trustworthiness of certs matters.
@pleothaud imho
components:
securitySchemes:
clientCert:
type: x509client
subjectAltName:
- DNS
@MikeRalphson @simo5 if we all agree at least on this model we could make an RFE and push for that.
components:
securitySchemes:
clientCert:
type: x509client
# We are still free to add stuff here.
BasicAuth:
type: http
scheme: basic
paths:
/ping:
get:
summary: Both unauthenticated and x509client
security:
- {}
- clientCert: []
...
post:
summary: >-
Only with x509client. The server (un)trust configuration shouldn't be in the contract as it may
vary between different environments. The API shouldn't vary b/w dev/test/prod.
security:
- clientCert: []
@ioggstream sounds reasonable to me
@ioggstream I think your example should have said...
security:
- {}
- clientCert
Security Requirement objects reference the key of the security scheme.
@darrelmiller thx++ Fixed (see above).
Final sanity check, is the security scheme type sufficiently unambiguous?
1) Might there be a case where we are using X.509 client certs but not over TLS?
2) Might there be a case where the TLS client cert is not X.509?
3) Is there a case where a client certificate is used that is neither TLS nor X.509?
4) Are there other variants we may have missed?
Keep in mind that we are still running code written 30 years ago. Plan for the future.
I guess you could call it TLSClientCertificate, and avoid all of the above questions.
@cmheazel imho:
SSLNothing you can't specify in scheme ;)
if we disambiguate with TLSClientCertificate then a newer spec (eg. ULS ;) ) means a rename. I'd rather use a scheme.
securitySchemes:
clientCert:
type: x509client
spec: tls # or rfc5246|mtls|whatever
@ioggstream You win the prize.
Thank you everyone for the comments - I'm still going through them. I hope to be able to summarise where we're at in time for the next TSC meeting on June 4th.
Just a note @darrelmiller and @ioggstream :
security:
-
````
does not mean the same as
```yaml
security:
- {}
An empty definition in YAML is shorthand for null, not the empty object, as is required to indicate a none security requirement.
Final sanity check, is the security scheme type sufficiently unambiguous?
@cmheazel The unambiguity will be addressed by the spec. defining its terms (i.e. what it means by tlsClientCert or whatever type value we agree on). What we're primarily seeking is clarity.
@ioggstream: scheme is a term with a defined meaning in RFC7235 - which effectively defines a subtype of http authentication, 'Scheme' in TLS seems generally to be used with regard to "signature schemes". Even if we are defining a subtype here I think we should avoid the term 'scheme'. If we are in fact defining a supertype, then we probably have our type value wrong.
@MikeRalphson
None vs object(): fixed in https://github.com/OAI/OpenAPI-Specification/issues/1004#issuecomment-391415381scheme: ok, is thus reserved for https://tools.ietf.org/html/rfc7235#section-5.1. To me, just introducing x509client is fine.
type: x509Client
spec: rfc5246
subjectAltName: # if any of those fields in subjectAltName is required
- DNS
- IP
@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.
@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.
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?
@MikeRalphson
Specifying version and suites for TLS allow:
This information should IMHO be at the server level as it's not Authentication related.
@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
@darrelmiller what does "selfsigned: bool" indicate ?
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.
@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?
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.
@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.
@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 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!
@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?
untrusted would definitely be a much better definition, I am still unsure you need/want it, but at least it would be more accurate
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".
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:
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.
@isamauny @tobilarscheid I stand on those points:
TLS algos:
@darrelmiller I suggest just to reference the certificate fields to be examinated not their values. Eg the authentication layer validates:
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.
Sorry for the long reply.
TL;DR: we only need to tell the client needs a cert, and nothing else
Isabelle wrote:
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.
This is a normative spec not data exposed at runtime, not the same
thing.
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.
It can be influenced by proxies and other middle boxes, not something
the OAI provider have necessarily direct knowledge.
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.
The server may not want to advertise (or know) all the CAs it trusts.
May even be different CA sets depending on which frontend the client
ends up hitting (on premise client vs off-premise, proxied vs direct,
etc..)
So yes, this is all happening magically behind the scenes... But how
will the API consumer know about those constraints ?
The only thing the API consumer really needs to know is if it
can/should use a certificate to access an API, the rest is better
handled at connection time by proper error reporting.
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.
It may be hard with bad clients, but TLS gives you specific errors,
from the RFC of TLS v1.0:
bad_certificate
A certificate was corrupt, contained signatures that did not
verify correctly, etc.
unsupported_certificate
A certificate was of an unsupported type.
certificate_revoked
A certificate was revoked by its signer.
certificate_expired
A certificate has expired or is not currently valid.
certificate_unknown
Some other (unspecified) issue arose in processing the
certificate, rendering it unacceptable.
unknown_ca
A valid certificate chain or partial chain was received, but the
certificate was not accepted because the CA certificate could
not be located or couldn`t be matched with a known, trusted
CA. This message is always fatal.
Put yourself in the position where you consume APIs you have no
control over, how will you know a cert is required,
This is the only information we need to publish, that the API requires
a client cert.
that the protocol is TLS 1.2 (what happens when this becomes 1.3 and
some old clients don't support it), etc.
This is discoverable, you connect to the server and it will tell you if
the TLS versions your client supports are acceptable, if they aren't
there is nothing the client can do anyway.
I guess you can say: run openssl -connect xxx and you will know.
No, you just connect to the server and handle an error of:
handshake_failure
Reception of a handshake_failure alert message indicates that
the sender was unable to negotiate an acceptable set of security
parameters given the options available. This is a fatal error.
And properly translate it to the user
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.
And we do not need to make the problem worse by publishing redundant
information that quickly gets out of sync with reality, and worse, may
be actually believed as truth by the client.
If you have helped debug as many TLS connections issues as we have,
I am sure you will agree.
I agree software needs to properly handle errors, adding a second layer
of negotiation for the same parameters is just going to make problems
worse, not easier.
If you write, plain and clear:
- I need a client cert
This is what this issue is about, exposing an indicator that a client
cert is needed.
- 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)
This is not a binary option, so whatever is said by the server will be
meaningless. Self-signed is inherently not trusted, "trust self-
signed" really just means "accept untrusted" unless you use a scheme
like TOFU, but no TLS client or server implementation does that today,
and again requires no indication if that were the case.
- It has to be signed by these CAs (because I won't trust any other)
This could be published, but often people do not want to disclose
this information to anonymous clients, it also, again requires a way to
make sure the exposed data is true, and if you have middleboxes doing
the auth part for you, then you may not know what certs are accepted by
the middle box.
- And the value of subject name must be XXX (because I will verify
it)
This is not necessarily a valid criteria, people may accept any cert
from Issuer X, or expect other extended attributes to match or a
million different criteria.
Then Yes, you repeat what the protocol will negotiate , but at least
it's clear to the consumer.
It will be as clear as it is today, only with double the failure
points, where reality does not match the lies published.
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.
No web server published TLS protocol details on port 80, end browsers
have mostly no issues using HTTPS every day.
Or you just say: I need a cert, you figure out how to talk to me.
This is the only sane way unless you can guarantee your application
stack is fully integrated 100% all the way down to the TLS crypto
library used on the frontend terminating server (think cloudflare,
akamai, etc..), something less and less true in this day and age. Often
between the client and the application there are multiple hops an re-
encryption.
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.
If you do not have a valid cert, you need to get a valid cert from
whomever owns the authentication infrastructure anyway. If your client
does not support a TLS version new enough to connect likewise your only
recourse is to change client. The fact OAI publishes some duplicated
meta-data is not going to help with those issues anyway.
We opted for the first approach, because:
a) it's clearer as it describes the server setup.
Aside for requiring a client cert (which is what we want to express
here) everything else is exposed by the [frontend] server already via
the TLS protocol, and can be easily probed if that is what you really
want (I think you don't, except for QA or similar scenarios where yes
they can use things like openssl -connect if they have specific
requirements for testing).
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)
And then you still have to handle the fallout when the validation was
faulty and the certificate is not accepted by the server anyway. You've
just done the work twice needlessly, connects are cheap.
c) it allows to generate a clear description of the transport
contract as part of the API documentation.
If that was needed you'd have this in since the start, as most servers
run on HTTPS, yet no API spec I know of goes out and publishes the TLS
parameters just because the API will be exposed over HTTPS instead of
port 80, I don't buy this argument.
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.
you seem to advocate for client to get protocol version and certificate
authority information and fundamentally pre-negotiate assuming that
info is valid when all that is needed is for the client to just handle
errors and translate them to users in a comprehensible way.
The same error messages you could give to users based on version field
in the API can be given if the negotiation fails which boils down to:
your client can't connect to this server. Telling a user "because the
version is x.y.z instead of x.y.f" won't really make a useful
difference it's not like they can tweak a knob in the client
configuration to get a new (or old) TLS version magically supported.
Simo.
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 :)
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.
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:
mutualTLS @darrelmiller tlsClientCert @MikeRalphson @MikeRalphson @darrelmiller as we merged #1764, we could:
add details for type: mutualTLSfeedback wellcome!
As long as we link back to this issue and summarise people's suggestions (not easy!) I'd be happy to close this issue.
Most helpful comment
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: https://github.com/OAI/OpenAPI-Specification/issues/451#issuecomment-135856998
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:
OpenAPI is about RESTful APIs, RESTful is HTTP based and happens on Layer 7, let's leave out all this TLS stuff
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: