Skip to content

Latest commit

 

History

History
185 lines (137 loc) · 8.17 KB

ISSUES.md

File metadata and controls

185 lines (137 loc) · 8.17 KB

Caml Crush: an OCaml PKCS#11 filtering proxy

Current ISSUES and LIMITATIONS

The following document address the current issues and limitations of the project.

Back to README.md.

Summary

Client library

Handling CK_MECHANISM structures

The following functions are designed to do their best to parse input mechanism structures:

value custom_c2ml_pkcs11_struct_ck_mechanism(struct ck_mechanism *_c1,
                                         camlidl_ctx _ctx);
void custom_sanitize_ck_mechanism(struct ck_mechanism *mech);

PKCS#11 allows vendors to define their own custom mechanism. It can be used by passing CKM_VENDOR_DEFINED as mechanism type in the structure. Vendors are free to use whatever suits their needs as mechanism parameter. Our implementation only support vendor defined mechanism that are using an unsigned char array as parameter.

Handling buffers

When designing our OCaml PKCS#11 bindings we decided not to reproduce some of the concepts of the standard.

For instance, one can call the C_Digest() function with an insufficiently large receive buffer. When this happens, the standard states that the middleware is supposed to do the following:

  • update the pointer that holds the length of the buffer
  • return the CKR_BUFFER_TOO_SMALL error code

This way the client application can use the updated counter value to allocate some more memory and call C_Digest(). The same check is performed and the result gets copied if the buffer is large enough. We can picture the C_Digest() operation as a couple of transactions that will be made.

We chose to relax this constraint on the OCaml side. Developers using those bindings do not have to care about memory allocation. Therefore when calling C_Digest() from OCaml, the value is immediately returned to the caller. A subsequent call to C_Digest() would logically result with the CKR_OPERATION_NOT_INITIALIZED error code.

This is fine until you assemble all the pieces together. Because PKCS#11 client applications that will use our PKCS#11 client library which communicate with the proxy will expect the "classic" behavior described earlier.

Therefore, we had to manage a state within the client library to keep results in memory, checking that the application is giving us a large enough buffer or returning CKR_BUFFER_TOO_SMALL when needed. The workaround uses a linked list to keep track of calls made to crypto operations and stores the result for the given slot/session_id until the client has allocated its memory and calls the function again to fetch the result.

The following functions are concerned:

  • C_Digest/C_Encrypt/C_Decrypt/C_Sign
  • C_DigestUpdate/C_EncryptUpdate/C_DecryptUpdate/C_SignUpdate
  • C_DigestFinal/C_EncryptFinal/C_DecryptFinal/C_SignFinal
  • C_DigestEncryptUpdate/C_DecryptDigestUpdate/C_SignEncryptUpdate/C_DecryptVerifyUpdate
  • C_SignRecover/C_VerifyRecover
  • C_WrapKey
  • C_GetOperationState

This is transparent to the client applications.

Handling synchronization (OCaml client library)

On the synchronization side, a global lock is implemented around the calls in order for the client library to be thread safe. The main issue is that it is not possible for multiple threads to call the OCaml runtime in a safe way. At most one thread can call the runtime. Therefore, a global mutex is used to serialize PKCS#11 calls. This works well for most of the PKCS#11 calls except the C_WaitForSlotEvent call which can block. To avoid deadlocks, when an application calls C_WaitForSlotEvent with the block flag, the library will poll for events with the non-blocking function.

This is transparent to the application.

Handling synchronization (C client library)

Although the C client library is not concerned by the synchronization issue described previously, we decided to keep the locking strategy. Therefore the C client library uses the same synchronization primitives. It make the code more readable and has no side effects. This potentially reduces performance and could be improved in future releases.

Server and filter limitations library

[PFS][] (Perfect Forward Secrecy) support

Since Caml Crush 1.0.5, we support PFS and force TLS1.2. This requires ocaml-ssl 0.4.7.

See Server SSL/TLS configuration section of the server documentation.

Client library redirection based on connection source

For now, the same PKCS#11 library (provided in the configuration file) is loaded for all the clients. One would want to load different libraries depending on the client: for instance depending on its certificate, on its IP address, and so on. This feature is planned in future releases.

Possible Denial-of-Service (DoS)

The server code has two potential issues regarding DoS.

Unhandled SSL exceptions

Exceptions that arise when using [ocamlnet][] with SSL are not properly handled. When this happens, the container instance stays in a zombie state.

This issue has been communicated to the [ocamlnet][] and fixed with a patch for the ocamlnet-3.6.6 version. Patch is available:

RPC system shutdown

The ocamlnet library used to implement the server process uses a master/slave approach. When the server receives a new connection, a child process is forked and work is assigned. In order to synchronize and send/receive orders, the server process and container communicate through a Unix socket. This socket can also be used for the administration of the server process. Therefore, if an attacker finds a vulnerability in the container process, it could use the socket to shutdown the server process.

This issue is related to the design of the Netplex library, we plan to modify the current implementation in order to separate the communication channel and the administration of the Netplex process.

Misc

Unsupported PKCS#11 features

The project lacks the following features:

  • Support for callbacks (C_OpenSession, ...)

Adding support for callback is not an impossible task, but as this is not a widely used functionnality we decided to focus on other features. We plan however to add it in a future release.

Small "fixmes"

In addition to all the things that have been detailed in the previous sections, other design choices with minor impact can be improved (and might be in future releases). Please note that these elements are not considered as critical since they do not break the PKCS#11 conformance: the proxy should work fine as is. Here is a - non exhaustive - list of small "fixmes" and other "todos" that you will find in the current code:

  • In the OCaml/C bindings, some PKCS#11 stubs use fixed length buffers allocated on the stack. This is the case for the Digest functions for instance, where a MAX_BUFF_LEN is used for the hash value buffer. Since digest values should not exceed a fixed known amount of bytes, this fixed size buffer should not break the PKCS#11 standard. However, the proper way to deal with this would be to use dynamic allocation as it is done in Encrypt or Decrypt functions for example. This is left for a future release.
  • In the RPC layer, when encoding/decoding functions fail they simply exit: we should put some sanity checks and/or repair routines there.
  • When our custom allocation functions fail, they simply exit: we should do something to avoid stopping the execution instead.

OpenBSD

  • C client cannot be compiled because the RPC "hyper" symbol is missing
  • Check support for the OCaml client.