parallaxsecond / parsec

Platform AbstRaction for SECurity service
https://parsec.community/
Apache License 2.0
465 stars 66 forks source link

Investigate PKCS#11 front-end compatibility layer for Parsec #291

Open paulhowardarm opened 3 years ago

paulhowardarm commented 3 years ago

Summary

There are a number of existing systems that use PKCS#11 as their interface of choice for calling out to hardware security functions - it is a well-established interface with a lot of industry adoption. If Parsec could be accessed and driven through this interface, it would allow those systems to gain the benefits of the Parsec platform abstraction without having to code to any Parsec-specific front-end API or client library. Existing PKCS#11 client code would automatically "just work" with Parsec. Hence it would be a useful ecosystem enabler.

This request is to investigate and define the required work.

Design Considerations

A non-exhaustive list of design considerations for this investigation:

Definition of Done

This is a ticket for investigation, so the expected end result would be a more detailed specification and scope for the work, perhaps with a breakdown into individual issues for concrete engineering items. Part of the DoD should also be a specification (perhaps as a PR against parsec-book) for the subset of PKCS#11 standard that would be implemented - this should aim to resolve some of the questions about slot modelling noted above. A good first target would be to enable PKCS#11-compatible access to the Parsec features that exist at time of writing (November 2020) for the provisioning of asymmetric keys, sign/verify and asymmetric crypto primitives.

ionut-arm commented 3 years ago

Does it make sense to model the Parsec service in terms of its providers, and perhaps have a slot per provider? What about slot PINs?

My vote would be to have a slot per provider and an empty PIN for each one (i.e. we just reject the call in the frontend if any PIN is supplied), it seems like a reasonable mapping.

What if the back-end is also PKCS#11 and has multiple slots? Should we try to reflect the back-end slots into front-end slots?

Unless we want to implement some PKCS11-specific operations to support this, I don't think it's do-able. There are a lot of complications that I can think of, it'd be better to discuss this one separately if we think it might be useful, but overall we'd have to use the current operations in a hacky way to achieve this (hacky including in the provider, not just in the frontend...).

hug-dev commented 3 years ago

Concerning the bridge from the C PKCS11 API to the Rust Parsec Client one, I think we can do:

I think the main type to convert is PKCS11 CK_MECHANISM to rust-pkcs11 Mechanism to psa-crypto Algorithm. Maybe for the key types as well but that's easier. Note that this also depends of the linked PR to be merged somewhere.

My vote would be to have a slot per provider and an empty PIN for each one (i.e. we just reject the call in the frontend if any PIN is supplied), it seems like a reasonable mapping.

Agreed as well, the problem remaining is how we map a provider to a specific slot ID. I propose that they can be listed, starting from 0 in a prioritised list (same order than what ListProviders returns) and that we can convert the ProviderInfo structure into a CK_SLOT_INFO one to give more information if needed when C_GetSlotInfo is called.

ionut-arm commented 3 years ago

Agreed as well, the problem remaining is how we map a provider to a specific slot ID. I propose that they can be listed, starting from 0 in a prioritised list (same order than what ListProviders returns) and that we can convert the ProviderInfo structure into a CK_SLOT_INFO one to give more information if needed when C_GetSlotInfo is called.

Alternatively, we can use the provider UUID - it's essentially an 128-bit, base64 encoded number, so we can just take the lowest X bits and hope they don't collide.

ionut-arm commented 3 years ago

We started investigating this topic a bit and found a few other questions and ideas to throw around.

  1. What version of the API should we expose? How do we decide? The work we put in for the pkcs11 crate was on the 2.40 version of the spec, but there's a version 3 out.
  2. How do we handle sessions? Presumably we can be stateful in the library and keep track of requests made per session (such as opening objects).
  3. We'll need to define a clear set of primitives that we need to implement and figure out if we can "partially" implement them (e.g. if we can support some type of keys for one operation, but not others).

We can start from the C headers of PKCS11 and build out the interface or use something like this and call our library from the methods we implement.

hug-dev commented 3 years ago

I have also had a look at the specs and can think of the following:

Finally, we will have to think about security, PIN handling and authentication. As stated by the spec:

It is also possible for a token to have concurrent sessions with more than one application.

I think that it should be possible to access the same keys from multiple application in PKCS11. That would imply that the PKCS11 front end has a fixed, direct authentication name. That might lead to several problems.

All of these comments are for a general, compliant PKCS11 library. We could make simplifications if we put constraints on the use-case.

areiter commented 2 years ago

Does this ticket represent the current state of the PKCS11 frontend discussion? (or did I miss something?)

paulhowardarm commented 2 years ago

Hi @areiter - this ticket accurately reflects the current status. There was some initial discussion and investigation, but recently the focus of the project has shifted more towards natively integrating Parsec rather than using a common shim. This issue is still open because I don't think we completely rule out the possibility of a shim. But at this point my personal view is that a shim would more likely get created if there is a use case that specifically requires it, rather than as a strategic compatibility exercise. The philosophy behind Parsec is to avoid shims wherever possible, and instead to create attractive and ergonomic API surfaces in a variety of programming languages. We would like developers to embrace Parsec as a new and updated developer experience, and we are very keen to engage with engineers and partners who are willing to join us in that quest. I would be very keen to hear more about your possible use case with Parsec and/or PKCS#11.

areiter commented 2 years ago

Hi @paulhowardarm, thanks for your quick response, and thanks for all your effort!

Let me just give you a short overview: My system at hand is a multi tenant environment (not necessarily human users, let's call them apps), running on a single device. The system is already existing and many apps are already out there - using mainly pkcs#11 interface to perform different cryptographic operations but e.g. directly talk to the hardware --> Currently no abstraction layer is available. Apps can be completely custom binaries, but typically are a composition of existing tools, libraries,... When it comes to cryptographic operations most of these tools already support PKCS#11.

I'm now looking into different possibilities of how a "security abstraction layer" could look like, but also need to provide an easy migration path for existing components, without the need to rewrite all the existing components. For my use case it would also be a viable option to provide multiple interfaces.

paulhowardarm commented 2 years ago

Thanks @areiter - this sounds extremely interesting.

The PKCS#11 front-end shim work hasn't progressed in any material way as mentioned above, but there is plenty of room in the project for community contribution, if this is something that you would consider. As you might gather from the discussion above, there would be quite a lot of detail to resolve to create a general-purpose PKCS#11 front end. But perhaps that's not what you need? A narrow and highly-specialised subset could be considered instead, and either contributed into the broader Parsec project, or just kept as a separate component maintained elsewhere for your own use. But I think you would need to look at contributing that as part of your brownfield scenarios, because as I mentioned we are highly focused at the moment on creating client library experiences that are compelling in their own right, so there isn't any plan right now to deliver this feature.

For your greenfield use cases, where the client language is C or C++, you certainly can use the PSA Crypto API as way to call Parsec. Parsec doesn't have a C client library as such, but you can use Mbed TLS and link in a component known as the Parsec Secure Element Driver, see: https://github.com/parallaxsecond/parsec-se-driver

This method allows you to make C calls to PSA Crypto, and have those calls routed through to the Parsec service/daemon. For some minimal example of that, take a look at the CI tests for the SE driver here: https://github.com/parallaxsecond/parsec-se-driver/tree/main/ci/c-tests

If you would like to engage with the project team in order to discuss your requirements in more detail, feel free to join our public Slack channel or come to one of our regular open project meetings. Details for all of these can be found in our community repo: https://github.com/parallaxsecond/community

I hope that you will be able to find Parsec useful in your systems.