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

Client rejects server request when using "CA constraint" and "trust anchor" assertion certificate usage #992

Closed
sbernard31 opened this issue Mar 29, 2021 · 10 comments · Fixed by #995
Labels
bug Dysfunctionnal behavior client Impact LWM2M client

Comments

@sbernard31
Copy link
Contributor

sbernard31 commented Mar 29, 2021

If fact this affects all certificate usage case where Server Public Key (0/?/4) resource does not contain the end entity certificate.
Meaning it works only for Domain issued certificate(3) and Service certificate constraint (1) certificate usage.

For CA constraint (0) and trust anchor assertion (2) usage, servers will receive : error 500 INTERNAL_SERVER_ERROR unknown server for any request sent.

(Issue discovered at #983 (comment))

@sbernard31 sbernard31 added bug Dysfunctionnal behavior client Impact LWM2M client labels Mar 29, 2021
@sbernard31 sbernard31 changed the title Client can not receive request with "CA constraint" and "trust anchor" assertion certificate usage Client rejects server request when using "CA constraint" and "trust anchor" assertion certificate usage Mar 29, 2021
@sbernard31
Copy link
Contributor Author

What happens ?

The identity class aims to abstract identity of a foreign peer.
For PSK this is the PSK identity.
For RPK this is the Raw Public key.
For X509 that was the CN value of the certificate.

This identity is created from different way.
From data of the DTLS Layer to identify current foreign peer. (see EndpointContextUtil )
From Security Object to know the expected identity for a given server. (see CaliforniumEndpointsManager)

Client checks current identity with expected one to answer to a server : see DefaultRegistrationEngine.getServer()

For expected X509 Identity, we create from CN value of Server Public Key (0/?/4) resource.
That is OK when this resource contains the the server certificate (the end entity certificate).
But since LWM2M v1.1 with CA constraint (0) and trust anchor assertion (2) certificate usage, Server Public Key (0/?/4) does not contains the server certificate but another one from the whole certchain.

So how to solve this :

1) Remove the identity check by an IP address check

This is probably the simple way to fix the issue at first sight but with more consequence when look at it deeper.
In term of security, I'm not sure if this OK, I feel that with multi server support this could be an issue.
Even if this is OK, this means that we still create unusable identity for X509 for those specific use case which is not so good...
If we decide to remove identity check that means that the security Identity abstraction should maybe be removed or replaced by something else. (As we create 1 coap endpoint by server maybe we can use the coap endpoint as identifier 🤔)

2) Find a better way than using Server Public Key (0/?/4) resource to create the expected CN.

The other solution which could be less impacting would be to create the right expected Identity.
But not sure how ? 🤔
Maybe we can find the right CN (CN is maybe not the appropriate term) by using domain name or IP address in LWM2M Server URI (0/?/0) or resource SNI (0/?/14) ?

@dachaac
Copy link
Contributor

dachaac commented Mar 29, 2021

About 1) I believe you cannot just check peer address -- you also need to check port.

So connection mapping is combination of peer address:port <-> local address:port.

I believe this is needed for supporting devices behind NAT that are in different ports (in NAT gw).

@dachaac
Copy link
Contributor

dachaac commented Mar 29, 2021

When DTLS is active on connection it remembers its communication partner -- if there is a breakup in communication then we do not get CoAP messages at all in upper protocol layers -- thus we do not get called at all.

If this is combined with port mapping shouldn't it solve the problem?

@dachaac
Copy link
Contributor

dachaac commented Mar 29, 2021

From client point of view the picture is a bit cleaner as it has very few communication partners for CoAP seession. Often just one (or two when bootstrapping). So as long as we are sure that we can safely communicate we should be fine?

@dachaac
Copy link
Contributor

dachaac commented Mar 29, 2021

About 2)

2) Find a better way than using Server Public Key (0/?/4) resource to create the expected CN.

The other solution which could be less impacting would be to create the right expected Identity.
But not sure how ?
Maybe we can find the right CN (CN is maybe not the appropriate term) by using domain name or IP address in LWM2M Server URI (0/?/0) or resource SNI (0/?/14) ?

Also remember that Subject Alternative Names should be used in normal configurations and in theory one could have either IPv4 or IPv6 addresses also defined. I would recommend to try to avoid parsing X509Certificate objects for every UDP frame as that is going to slow down the system -- doing that once during DTLS session setup is OK.

Please note that we do have DNS and IP Address information available in InetSocketAddress which we can get from Identity.getPeerAddress().

@sbernard31
Copy link
Contributor Author

About 1) I believe you cannot just check peer address -- you also need to check port.

We agree. That was I have in mind.

When DTLS is active on connection it remembers its communication partner -- if there is a breakup in communication then we do not get CoAP messages at all in upper protocol layers -- thus we do not get called at all.
If this is combined with port mapping shouldn't it solve the problem?

As long as we support only 1 server at the time it's OK. (BS server and DM server is never active at same time)
But the LWM2M specification says that you could have several LWM2M server and I don't want to choose a design which closes this door.
In the case of several server, I can imagine a use case where this check is not enough:

  • you have 2 registered server , one with PSK and other with X509 with different rights (ACL)
  • you have 2 active CoAP endpoint .(1 for each servers)
  • The way it is coded, you can be sure that all traffic which is received to one endpoint come from the same server. but in DefaultRegistrationEngine.getServer() we don't check from which endpoint we comes.

So if PSK is compromised (or just if owner wih PSK server is malicious), it can used its credentials and spoof the X509 ipaddress-port to send request like if it was the X509 server.


The other issue with solution 1) is that even if this fix this bug the current Identity for X509 still does not make sense and so we stay with a bad design ... 🤔

@sbernard31
Copy link
Contributor Author

About 2) the more I thought about it the less I can imagine it could work.

@sbernard31
Copy link
Contributor Author

sbernard31 commented Mar 30, 2021

I need to think more about it ...
Ideas I have in mind is :

  • using coap client endpoint (but not so good in term of separation of concern/layer abstraction)
  • OR maybe playing with californium ApplicationLevelInfoSupplier and set here the Server Short ID

@sbernard31
Copy link
Contributor Author

sbernard31 commented Mar 31, 2021

#995 aims to fix the issue.

@sbernard31
Copy link
Contributor Author

sbernard31 commented Apr 1, 2021

Some more explanation about #995.

To solve this problem, there was 4 different ideas :
[1] Replace the identity check by an IP address:port check
[2] Find a better way than using Server Public Key (0/?/4) resource to create the expected CN.
[3] Using client coap endpoint to identity the server
[4] Using ApplicationLevelInfoSupplier + use short server ID as identifier.

My understanding :
[1] it seems it doesn't work with multi server ( #992 (comment))
[2] it seems there is no good way to do that (#992 (comment))
[4] it could be the right way but it implies some redesign of Identity class which is largely used at Server side too. So I would prefer to have the big picture in mind before to go in this way.

So #995 is based on [3] which is maybe not so clean in term of separation of concern/layer abstraction but it should work because :
For DTLS we can rely on coap endpoint used because :

  • we use 1 endpoint by server
  • DTLS connector is configured in a way it accept only the expected server.
  • For UDP, checking coap endpoint is not enough we need to check ip address:port too (even if we don't care as this is an unsecured way anyway)

(I'm curious to see how we will deal with Idenity at server side for handling client using x509 and if current assertion to rely on certificate CN will be enough 🤔)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Dysfunctionnal behavior client Impact LWM2M client
Projects
None yet
2 participants