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

rpc: Support protocol version negotiation #371

Merged
merged 2 commits into from
Jul 9, 2021

Conversation

ueno
Copy link
Member

@ueno ueno commented Jun 4, 2021

This works as follows:

  • a couple of build-time constants have been added to represent the
    minimal and maximum supported protocol versions
  • the client sends the maximum supported version upon the connection
    establishment (when C_Initialize is called for the first time for the client process)
  • the server checks the version sent from the client; if it is lower
    than the minimum supported version of the server, sends an error
  • otherwise, the server responds with either of smaller value between
    the version sent from the client or the maximum supported version of
    the server

Example:

  • the client supports versions from 1 upto 3
  • the server supports versions from 0 upto 2
  • the client sends 3 to the server upon connection establishment
  • the server responds with 2
  • version 2 is negotiated

Partially fixes #370

Signed-off-by: Daiki Ueno <ueno@gnu.org>
@coveralls
Copy link

coveralls commented Jun 4, 2021

Coverage Status

Coverage decreased (-0.01%) to 71.854% when pulling 52e0194 on ueno:wip/dueno/version-negotiation into 576bba3 on p11-glue:master.

@ueno
Copy link
Member Author

ueno commented Jun 4, 2021

It's a shame that this doesn't accompany any automated tests (because it would requires multiple versions compiled in), but it could be tested manually by running:

$ P11_KIT_DEBUG=rpc _build/p11-kit/test-transport /transport/unix/basic
...
(p11-kit:19432) rpc_C_Initialize: authenticated with protocol version 1

after modifying P11_RPC_PROTOCOL_VERSION_MAXIMUM.

@ueno ueno force-pushed the wip/dueno/version-negotiation branch 5 times, most recently from 8fc5d3e to 330db46 Compare June 4, 2021 14:44
Copy link

@ep69 ep69 left a comment

Choose a reason for hiding this comment

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

I am a bit confused to be honest, mostly because this is more like ground work if I get it correctly. Is it true that this is more like anticipating a future where protocol will have to change?

Further concerns:

  1. What should happen if client version min > server version max?
  2. What about testing? If protocol really changes in future, we need automated tests. Perhaps adding some override for strict checking of mins and maxes that can be specified at runtime?

case 0:
goto out;
case 1:
if (version != 0) {
#if P11_RPC_PROTOCOL_VERSION_MINIMUM > 0
Copy link

Choose a reason for hiding this comment

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

I don't understand this #if. Isn't 0 the current default of P11_RPC_PROTOCOL_VERSION_MINIMUM? Or does P11_RPC_PROTOCOL_VERSION_MINIMUM == 0 mean "don't bother with checking versions"?

Copy link
Member Author

Choose a reason for hiding this comment

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

This is to avoid static analyzer warning: otherwise the following if condition always holds.

@@ -642,6 +619,51 @@ rpc_transport_uninit (p11_rpc_transport *rpc)
p11_buffer_uninit (&rpc->options);
}

static CK_RV
rpc_transport_authenticate (p11_rpc_client_vtable *vtable,
Copy link

Choose a reason for hiding this comment

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

Is rpc_transport_authenticate a reasonable name? We are negotiation protocol version rather than authenticating, aren't we?

Copy link
Member Author

Choose a reason for hiding this comment

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

This is named after AUTH command in D-Bus, and actually it allows the peers to exchange Unix credentials (UID and GID), so I think it's kind of authentication :-)

Copy link

Choose a reason for hiding this comment

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

I see the analogy neither in D-Bus specification, nor in RPC. But I am no expert, I'll believe you know what you are doing.

Copy link
Member Author

Choose a reason for hiding this comment

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

In the D-Bus specification, more relevant section is Authentication Protocol, where not only SASL-based authentication but also capability negotiations like Unix FD passing are part of the protocol, though there is no version negotiation (I guess it's not needed at this level of the protocol, because usually the D-Bus interface version is maintained at the interface level). But anyway, I don't have a strong opinion on the naming of the method.

Copy link

Choose a reason for hiding this comment

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

Me neither, feel free to keep it. I was just slightly confused.

@@ -755,10 +756,17 @@ rpc_C_Initialize (CK_X_FUNCTION_LIST *self,
assert (module->vtable->connect != NULL);
ret = (module->vtable->connect) (module->vtable, reserved);

if (ret == CKR_OK) {
Copy link

Choose a reason for hiding this comment

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

Shouldn't be client further initialized to send P11_RPC_PROTOCOL_VERSION_MAXIMUM?

Copy link
Member Author

Choose a reason for hiding this comment

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

It's not possible to send data, if connect returns error.

Copy link

Choose a reason for hiding this comment

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

I might just be confused here. My concern was, the protocol description says client should tell server maximum version it supports. I don't see this logic anywhere in the code, so I'm assuming it sends 0 because of some implicit zeroing of some structure. Am I wrong?

Copy link
Member Author

Choose a reason for hiding this comment

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

It's sent in the default implementation of the authenticate method (rpc_transport_authenticate):
https://github.com/p11-glue/p11-kit/pull/371/files#diff-71598b22704d395f7e1134bcb2149f62123d7617365db84f3146cc5842115fe0R644

Copy link

Choose a reason for hiding this comment

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

Ah, then I missed it, thanks for pointing it out.

@ueno
Copy link
Member Author

ueno commented Jun 8, 2021

Yes, this is a groundwork for future changes; we've already faced situations where we realized issues cannot be fixed without breaking the current protocol: #275 and #366 are the examples.

What should happen if client version min > server version max?

Good point; if there is no overwrap, the client should close the connection.

What about testing? If protocol really changes in future, we need automated tests. Perhaps adding some override for strict checking of mins and maxes that can be specified at runtime?

Indeed, I think the server side test case could be easily extended for that, as it crafts RPC messages, but the client side needs some mechanism to exercise the scenario.

@ueno ueno force-pushed the wip/dueno/version-negotiation branch from 330db46 to 5edfec6 Compare June 10, 2021 09:26
Copy link

@ep69 ep69 left a comment

Choose a reason for hiding this comment

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

Followed up in some comments.

About the high level concerns, I still don't see the logic for the case where client_version_max < server_version_min. Also, no tests appear for the version negotiation.

Anyway, I'll mark this approved not to block you further in case I am totally wrong.

@@ -755,10 +756,17 @@ rpc_C_Initialize (CK_X_FUNCTION_LIST *self,
assert (module->vtable->connect != NULL);
ret = (module->vtable->connect) (module->vtable, reserved);

if (ret == CKR_OK) {
Copy link

Choose a reason for hiding this comment

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

I might just be confused here. My concern was, the protocol description says client should tell server maximum version it supports. I don't see this logic anywhere in the code, so I'm assuming it sends 0 because of some implicit zeroing of some structure. Am I wrong?

@@ -642,6 +619,51 @@ rpc_transport_uninit (p11_rpc_transport *rpc)
p11_buffer_uninit (&rpc->options);
}

static CK_RV
rpc_transport_authenticate (p11_rpc_client_vtable *vtable,
Copy link

Choose a reason for hiding this comment

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

I see the analogy neither in D-Bus specification, nor in RPC. But I am no expert, I'll believe you know what you are doing.

@ep69
Copy link

ep69 commented Jun 21, 2021

One more high-level thought: Let's say there is indeed a problem in future that requires a change of the protocol. Is this groundwork really all we can do at this moment? Perhaps there is something else that would help in future that could be done already (still thinking about figuring out a reasonable way to test protocol changes).

This works as follows:
- a couple of build-time constants have been added to represent the
  minimal and maximum supported protocol versions
- the client sends the maximum supported version upon connection
  establishment (when C_Initialize is called for first time from the
  client process)
- the server checks the version sent from the client; if it is lower
  than the minimum supported version of the server, sends an error
- otherwise, the server responds with either of smaller value between
  the version sent from the client and the maximum supported version of
  the server

Signed-off-by: Daiki Ueno <ueno@gnu.org>
@ueno ueno force-pushed the wip/dueno/version-negotiation branch from 5edfec6 to 52e0194 Compare July 9, 2021 05:17
@ueno
Copy link
Member Author

ueno commented Jul 9, 2021

I agree, though we probably wouldn't be able to identify what else is missing without a version bump. Let's explore in that area in the follow-up PRs.

@ueno ueno merged commit 4769c47 into p11-glue:master Jul 9, 2021
@ueno ueno added this to the 0.24.1 milestone Jan 17, 2022
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.

rpc: Interface version/capability negotiation
3 participants