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

Some ideas about OSCORE Store #1212

Closed
wants to merge 8 commits into from
Closed

Conversation

sbernard31
Copy link
Contributor

@sbernard31 sbernard31 commented Feb 23, 2022

This aims to clarify the ideas I try to explain at #920.

This is a kind of "fill-in-the-blank code" but the bootstrap server part is not done.

(I reuse the @Michal-Wadowski's OscoreIdentity from #1175 )

OscoreSetting and OscoreParameters looks like the same but one is intended to be pushed in californium and the other is abstraction intended to be used in code without californium dependency.

@sbernard31
Copy link
Contributor Author

sbernard31 commented Mar 17, 2022

@rikard-sics I implemented ideas we talked about at (#1212 (comment))

So I'm now able to execute the test below successfully :
org.eclipse.leshan.integration.tests.SecurityTest.registered_device_with_oscore_to_server_with_oscore()

I implement the get by uri at client side, easy as it's static. (See CaliforniumEndpointsManager changes)
I should be able to implement it at server side searching in RegistrationStore (I added a ref to it in LwM2mOscoreStore) but maybe we can do better with californium modification.

The test starts by a register request then the server send a read request.
The register seems to be OK using OSCORE.
As I didn't implement the get by uri at server side, I was expected that the read request failed BUT it is just done without usage of OSCORE (I mean in clear coap successfully)

I guess in term of security this is not what we want. Any thoughts about that ?

@rikard-sics
Copy link
Contributor

rikard-sics commented Mar 18, 2022

I implement the get by uri at client side, easy as it's static. (See CaliforniumEndpointsManager changes)
I should be able to implement it at server side searching in RegistrationStore (I added a ref to it in LwM2mOscoreStore) but maybe we can do better with californium modification.

Sounds very nice, yes we can definitely consider modifications to Californium.

The test starts by a register request then the server send a read request. The register seems to be OK using OSCORE. As I didn't implement the get by uri at server side, I was expected that the read request failed BUT it is just done without usage of OSCORE (I mean in clear coap successfully)

I guess in term of security this is not what we want. Any thoughts about that ?

I see, yes as the get by uri is not implemented on the server side it cannot find an OSCORE context to use for protecting the request. But I see your point, basically if an outgoing request has the OSCORE option but a context cannot be found, this request should not be sent at all. I will add that to the list of changes to do in Californium. This should be a quick fix.

One possibility for now is to utilize the information in an EndpointContext of an incoming request. See for instance:
https://github.com/eclipse/californium/blob/ee65f934ddb7d40eddd0b0feb91eb8155839fc5a/cf-oscore/src/test/java/org/eclipse/californium/oscore/EndpointContextInfoTest.java#L158
By using that you can see explicitly for a request what Sender ID, Recipient ID, ID Context and URI its associated OSCORE context has (if any). If this information does not exist in the EndpointContext you can tell that the request did not use OSCORE. Perhaps this is good either way for matching the expected security information for a client endpoint name with what it is actually using? I recall something like this was used in other code, for instance here:
https://github.com/eclipse/leshan/blob/61b5a12f861b38b416e5c9997019395968b004b7/leshan-core-cf/src/main/java/org/eclipse/leshan/core/californium/EndpointContextUtil.java#L74

@sbernard31
Copy link
Contributor Author

sbernard31 commented Mar 18, 2022

I see, yes as the get by uri is not implemented on the server side it cannot find an OSCORE context to use for protecting the request. But I see your point, basically if an outgoing request has the OSCORE option but a context cannot be found, this request should not be sent at all.

I didn't think about this but it makes sense.

My point was more that the server send a ReadRequest without using OSCORE (this is the expected behavior because I didn't implement get by uri at server side) I was expected that the device doesn't answer to it.

But maybe this behavior can not be done at californium side and so should be done at upper layer (so LWM2M in our case) 🤔
I will try to experiment a way with EndpointContext.

@rikard-sics
Copy link
Contributor

But maybe this behavior can not be done at californium side and so should be done at upper layer (so LWM2M in our case) thinking
I will try to experiment a way with EndpointContext.

One possibility is using an OSCoreResource as opposed to a normal CoapResource. In such case the server will only accept requests using OSCORE to that resource. But perhaps that behaviour is too course-grained and relying on the EndpointContext is better.

@sbernard31
Copy link
Contributor Author

One possibility is using an OSCoreResource as opposed to a normal CoapResource

This will not work with Leshan Client use case, because we create the resource once for all server and some server use OSCORE and some other not.

My last commit (48b1d60) use EndpointContext to check server identity and now the Request request failed 🎉

I just share an idea for californium API :
For leshan client we are using 1 Coap Endpoint by foreign peer.
So we are providing a static OscoreStore with only 1 oscore parameter to be sure we talk about the right server.
When using OSCORE, I would like to configure my endpoint in way that OSCORE is always used.
I mean if some try to send none OSCORE request on this endpoint just reject the request.
I guess this could be an option of oscore stack ?
Do you think this kind of API make sense ?

(I will now try to implement get by uri at server side)

@sbernard31
Copy link
Contributor Author

I Implemented LwM2mOscoreStore.getOscoreParameters() (commit 2d9f63d)

But I think returning an OscoreParameters is not the right way because we will re-derive a new context from those parameters where we rather want to reuse an existent one (the one from registration for example)

So maybe we should rather get the recipientId by URI, then call InMemoryOscoreContextDB.getContext(byte[] recipientID) ?

I will create a commit about this (would be simple than this explanation ☝️) and you let me know if this make sense.

@sbernard31
Copy link
Contributor Author

@rikard-sics, see my last commit (a788103) about :

But I think returning an OscoreParameters is not the right way because we will re-derive a new context from those parameters where we rather want to reuse an existent one (the one from registration for example)

@rikard-sics
Copy link
Contributor

rikard-sics commented Mar 19, 2022

But I think returning an OscoreParameters is not the right way because we will re-derive a new context from those parameters where we rather want to reuse an existent one (the one from registration for example)

So maybe we should rather get the recipientId by URI, then call InMemoryOscoreContextDB.getContext(byte[] recipientID) ?

Hmm, maybe I don't get 100% in what situations a new context will be re-derived rather than using the existing one. But I agree that before trying to derive a context we should check the OSCORE DB to make sure a context with a matching RID doesn't already exist there.

Edit: Thinking more about this. So this problem would be specific to getContext(String uri) as the context could exist in the DB, but not associated to the uri (yet)?

@rikard-sics
Copy link
Contributor

rikard-sics commented Mar 19, 2022

@rikard-sics, see my last commit (a788103) about :

But I think returning an OscoreParameters is not the right way because we will re-derive a new context from those parameters where we rather want to reuse an existent one (the one from registration for example)

Right, yes I believe that approach makes sense.

Here I would add the context to the DB associated to the URI. As here the URI would be the "foreign peer address".
https://github.com/eclipse/leshan/blob/a7881033b2780d29e98d0330a6a26aefd8f91489/leshan-core-cf/src/main/java/org/eclipse/leshan/core/californium/oscore/cf/InMemoryOscoreContextDB.java#L81-L82
Then this would allow the ObjectSecurityLayer to find the correct context for later outgoing requests to that peer.

@rikard-sics
Copy link
Contributor

One possibility is using an OSCoreResource as opposed to a normal CoapResource

This will not work with Leshan Client use case, because we create the resource once for all server and some server use OSCORE and some other not.

Yes, I suspected that it would be too course-grained for this use case.

My last commit (48b1d60) use EndpointContext to check server identity and now the Request request failed tada

Right, very nice.

I just share an idea for californium API : For leshan client we are using 1 Coap Endpoint by foreign peer. So we are providing a static OscoreStore with only 1 oscore parameter to be sure we talk about the right server. When using OSCORE, I would like to configure my endpoint in way that OSCORE is always used. I mean if some try to send none OSCORE request on this endpoint just reject the request. I guess this could be an option of oscore stack ? Do you think this kind of API make sense ?

(I will now try to implement get by uri at server side)

Okay I see. So instead of a resource that only accepts OSCORE requests it would be like an endpoint (or an OSCORE CoAP stack building endpoints) that would only accept incoming requests if they use OSCORE. Yes, I think that could be something to consider adding. I can think about how it fits in Californium.

Comment on lines 72 to 84
@Override
public synchronized OSCoreCtx getContext(String uri) throws OSException {

OSCoreCtx osCoreCtx = super.getContext(uri);

if (osCoreCtx == null) {
byte[] rid = store.getRecipientId(uri);
if (rid != null) {
osCoreCtx = getContext(rid);
// TODO don't know if I should add by uri here ?
// super.addContext(uri, osCoreCtx);
}
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(from @rikard-sics)

Here I would add the context to the DB associated to the URI. As here the URI would be the "foreign peer address".
Then this would allow the ObjectSecurityLayer to find the correct context for later outgoing requests to that peer.

Thinking a bit more about this :
In LWM2M the foreign peer address could change (e.g. because devices are behind NAT).
When address changes client should update its registration.

So to handle this

  1. either we need to never cache the context by uri in DB (but that means more call to registration store.
  2. Or we cache in for uri and we need to update/clean DB on registration update. (still a bit afraid by this kind of house keeping)

There is another solution and this is something we will maybe need anyway.
At LWM2M level when we send a request we can tell the "identity" of the destination. This should even be done to be sure that context does not change between the moment where user decide to send the request and the moment where we really send the request.
So when we send the request we could say the expected OSCORE foreign peer RID.
(This is what we do for DTLS see : https://github.com/eclipse/leshan/blob/leshan-2.0.0-M6/leshan-server-cf/src/main/java/org/eclipse/leshan/server/californium/request/CoapRequestBuilder.java#L304-L306)

If we do that I guess ObjectSecurityLayer can find RID in EndpointContext and so get by RID and not by URI, right ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, so you mean that the ObjectSecurityLayer would get the RID from something like the following?
endpointContext.get(OSCoreEndpointContextInfo.OSCORE_RECIPIENT_ID)

That could be an addition to Californium, so if that value is set the ObjectSecurityLayer would use the RID there to get the context, rather than the request URI.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, so you mean that the ObjectSecurityLayer would get the RID from something like the following?
endpointContext.get(OSCoreEndpointContextInfo.OSCORE_RECIPIENT_ID)

Yep

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just implemented oscore store at bs server side and this idea ☝️ would help a lot.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just implemented oscore store at bs server side and this idea point_up would help a lot.

I see, then that is something I can add to the Californium side.

@sbernard31
Copy link
Contributor Author

Not directly linked to this PR.
But what is the "cost" of deriving a new context ?

@sbernard31
Copy link
Contributor Author

sbernard31 commented Mar 21, 2022

With last commits ☝️ I removed all old static oscoreDBHandler

An other important part I would like to discuss is lifetime of context.
I mean :
When the context in all the maps in OscoreCtxDB are or should be removed ?

At DTLS side :

  • we have a limited size LRU structure to store DTLS connections.
  • when a securityInfo from Leshan Security Store is removed we try to remove corresponding DTLS connection.

We also have several discussion about having a kind of maximum lifetime for DTLS connection but this was never implemented in californium. I don't know if this kind of maximum lifetime makes also sense for oscore context ?

@rikard-sics
Copy link
Contributor

Not directly linked to this PR.
But what is the "cost" of deriving a new context ?

Let me have a look at this and get back to you.

@rikard-sics
Copy link
Contributor

rikard-sics commented Mar 22, 2022

An other important part I would like to discuss is lifetime of context.
We also have several discussion about having a kind of maximum lifetime for DTLS connection but this was never implemented in californium. I don't know if this kind of maximum lifetime makes also sense for oscore context ?

Yeah, currently there is no specific lifetime of an OSCORE context. The only limit applied is that when the sender sequence number reaches its max value, then the context must not be used further.
https://datatracker.ietf.org/doc/html/rfc8613#section-7.2.1

In the OSCORE ACE profile, if the Token associated to the context expires the context should no longer be used:
https://datatracker.ietf.org/doc/html/draft-ietf-ace-oscore-profile-19#section-6

We are also working on a new draft Key Update for OSCORE (KUDOS) that is mainly about an alternative to the OSCORE appendix B.2 procedure, but it also introduces an explicit expiration parameter for OSCORE contexts:
https://datatracker.ietf.org/doc/html/draft-ietf-core-oscore-key-update-01#section-2.2.1

When it is desirable, contexts can be removed from the DB using removeContext(OSCoreCtx ctx)*. This could be done due to memory restrictions, or if a client has deregistered or been removed by the user in the server UI. If the client wishes to register then a new context will be derived for it (plus running of Appendix B.2).

*I was recently informed that the removeContext method does not remove the context from the URI map. I will update the code in Californium to resolve this.

@rikard-sics
Copy link
Contributor

rikard-sics commented Mar 22, 2022

Not directly linked to this PR.
But what is the "cost" of deriving a new context ?

Let me have a look at this and get back to you.

Having a look at this this, the main operations taking time when deriving a new context would be running 3 times a HMAC-based Extract-and-Expand Key Derivation Function (HKDF). (For generating the Sender Key, Recipient Key and Common IV).

See deriveKey which is called in the constructor for OSCoreCtx:
https://github.com/eclipse/californium/blob/05a828efded564593f15ad042261a07380a00aa8/cf-oscore/src/main/java/org/eclipse/californium/oscore/OSCoreCtx.java#L810-L811

@sbernard31
Copy link
Contributor Author

@rikard-sics thx for you last answer 🙏

I squashed all this commit and integrated this in oscore branch (commit 7fff92d)

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

Successfully merging this pull request may close these issues.

2 participants