EnclaveClient

public class EnclaveClient implements Closeable

Represents a client of an enclave. EnclaveClient manages the encryption of requests that need to be sent to an enclave (sendMail), and using an EnclaveTransport, transports encrypted mail to the host for delivery to the enclave. It also provides a polling mechanism with pollMail for retrieving any asychronous responses from the enclave.

Creating a new client instance requires providing an EnclaveConstraint object. This acts as an identity of the enclave and is used to check that the client is communicating with the intended one. A private encryption key is also required. There is an constructor overload which creates a random new one for you, or you can use Curve25519PrivateKey.random to create a new random one yourself.

After creating a new client, users will need to call start and provide an EnclaveTransport for communicating with the host. Which implemenation of EnclaveTransport is used will depend on the network transport between the client and host. If the host is using the conclave-web-host server then users can use com.r3.conclave.client.web.WebEnclaveTransport for the transport.

Sending and receiving Mail

After starting the client is able to send mail to the enclave using sendMail. EnclaveClient will encrypt the body and optional envelope with the private encryption key and then pass the encrypted bytes onto the provided EnclaveTransport to deliver it to the host. sendMail can optionally return back a decrypted EnclaveMail which is the synchronous response from the enclave, if it produced one.

For receiving asychronous responses, i.e. those which the enclave produces for the client but which are produced due to other clients, pollMail will return the next asynchronous response if one is available.

Thread safety

EnclaveClient is not thread-safe. sendMail and pollMail must be called from the same thread. If the client wants to poll for asychronous mail in a background thread then that same thread must also be used for sending mail. A simple way to achieve this is to use a single-threaded ScheduledExecutorService. The following (incomplete) code sample shows how this might be done.

    ScheduledExecutorService singleThreadWorker = Executors.newSingleThreadScheduledExecutor();
BlockingQueue<EnclaveMail> receivedMail = new LinkedBlockingQueue<>();

private ScheduledFuture<?> pollingTask;

void start() throws InvalidEnclaveException, IOException {
enclaveClient.start(enclaveTransport);
pollingTask = singleThreadWorker.scheduleAtFixedRate(() -> {
try {
EnclaveMail mail = enclaveClient.pollMail();
if (mail != null) {
receivedMail.add(mail);
}
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}, 0, 5, TimeUnit.SECONDS); // Poll every 5 seconds
}

Future<EnclaveMail> sendMail(byte[] body) {
return singleThreadWorker.submit(() -> enclaveClient.sendMail(body));
}

void close() throws IOException {
if (pollTask != null)
pollingTask.cancel(true);
enclaveClient.close();
}

Enclave rollback

One key security feature EnclaveClient provides is detection of rollback attacks by the host on the enclave. This type of attack is where the host restarts the enclave but in an older state. The enclave itself is unable to detect this but it can leverage its clients so that they may detect it. However not all clients may detect the rollback, but at least some will.

Detection is enabled by default in EnclaveClient. However it's only detected when the client next receives mail which is why sendMail and pollMail can throw EnclaveRollbackException. What action needs to be taken depends on the client's security policy but it may include contacting other clients (if any are known) or maybe even the enclave host if there is genuine foul play and they can be brought to account. It's also important to note a rollback can arise from a genuine mistake if the host accidently restarted the enclave from an old state.

The client can continue to be used to send and receive mail after an EnclaveRollbackException is thrown. However the state of the client and the state of the enclave are probably now out of sync and further communication with the enclave may be unsafe. If rollback attacks are not a concern at all then detection for it can be turned off completely by overriding ignoreEnclaveRollback to return true. The same security caveats apply.

Restarts

EnclaveClient is designed to handle both enclave and client restarts. If the enclave restarts then its encryption key changes but EnclaveClient will automatically switch to the new encryption key when it detects this. Notifications for restarts can be enabled by overriding onEnclaveRestarted. This might be needed if the enclave is non-persistent and the client needs to re-submit their data. It could also be used as an indication of a rollback attack.

To support client restarts the state of EnclaveClient must be persisted and then restored. Failing to do this will prevent the client from sending or receive mail due to spurious errors. To this end, save can be used to serialize the state of the client which can be restored using the EnclaveClient constructor that takes in a byte array. This is provided solely as a convenience and the state of the client can be persisted any other way. See the save documentation for more details.

PostOffice

EnclaveClient is an extension to PostOffice and provides features it cannot support. If these features are not needed and you simply need to send a one-off mail, for example, then use EnclaveInstanceInfo.createPostOffice to create a post office for encrypting requests and decrypting any responses.

See also

Constructors

EnclaveClient
Link copied to clipboard
EnclaveClient EnclaveClient(EnclaveConstraint enclaveConstraint)

Creates a new client with a new random private key.

EnclaveClient
Link copied to clipboard
EnclaveClient EnclaveClient(PrivateKey clientPrivateKey, EnclaveConstraint enclaveConstraint)

Creates a new client with an existing private key.

EnclaveClient
Link copied to clipboard
EnclaveClient EnclaveClient(byte[] savedClient)

Creates a new client from the serialized state of a previous one that used save.

Types

Companion
Link copied to clipboard
public class Companion

Methods

close
Link copied to clipboard
void close()

Closes the client and disconnects it from the enclave transport. This is a no-op if the client is already closed.

getClientConnection
Link copied to clipboard

Returns this client's EnclaveTransport.ClientConnection instance with the enclave transport.

getClientPrivateKey
Link copied to clipboard
PrivateKey getClientPrivateKey()

Returns the private key that is used to encrypt mail to send to the enclave.

getClientPublicKey
Link copied to clipboard
PublicKey getClientPublicKey()

Returns the corresponding public key of clientPrivateKey. This will be what the enclave sees as the authenticated sender of mail it receives from this client.

getEnclaveConstraint
Link copied to clipboard
EnclaveConstraint getEnclaveConstraint()

The constraints the enclave must satisfy before this client will communicate with it.

getEnclaveInstanceInfo
Link copied to clipboard
EnclaveInstanceInfo getEnclaveInstanceInfo()

Returns the most recent EnclaveInstanceInfo downloaded from the host via the transport.

getLastSeenStateId
Link copied to clipboard
byte[] getLastSeenStateId()

Returns the last seen state ID from the enclave. The state ID is tracked to detect attempts to roll back the state of the enclave by the host.

Access to this value is typically only needed to persist it if a custom serialisation scheme is used (i.e. not save). Make sure to restore this value on the new client object to ensure it can continue communicating with the enclave.

getPostOffices
Link copied to clipboard
Set<PostOfficegetPostOffices()

Returns the set of PostOffices that have been used to send mail.

The returned Set is a copy. Adding or removing from it does not affect the client.

getTransport
Link copied to clipboard
EnclaveTransport getTransport()

Returns the EnclaveTransport used to communicate with the host.

ignoreEnclaveRollback
Link copied to clipboard
boolean ignoreEnclaveRollback()

Determines whether the client should continue processing mail it's getting from host if it detects the enclave's state has been rolled back.

A rollback is a type of attack the host can do on an enclave to make it think it is dealing with up-to-date data when in fact it's been given old out-of-date data. Due to the nature of enclaves they have no way of detecting this themeselves and so must rely on their clients to detect for them.

The default implementation returns false which means the client will not process the mail and sendMail and pollMail will throw an EnclaveRollbackException. Override this method if you wish to change this. You can connect this method to a UI, for example, if the decision needs to be made by the user.

onEnclaveRestarted
Link copied to clipboard
void onEnclaveRestarted()

Called when the client detects the enclave has been restarted. Override this method to get notification of any restarts. The default implementation does nothing.

Note, it's not necessary that all restarts will be detected. Plus, sendMail is required before a restart can be detected.

pollMail
Link copied to clipboard
EnclaveMail pollMail()

Polls the host for the next asynchronous mail response from the enclave, if there is one, and returns it decrypted. Otherwise returns null.

postOffice
Link copied to clipboard
PostOffice postOffice(String topic)

Returns the PostOffice instance for the given topic, creating a new one if one doesn't already exist.

save
Link copied to clipboard
byte[] save()

Serializes the state of the client to a byte array so that it can be safely persisted and restored if the client is restarted. Use EnclaveClient.restoreState to materialise the state again. As the private key is also serialized it's vitally important the bytes are persisted securely or are encrypted.

It is recommended that state be saved after every sendMail and pollMail call.

This method is just a convenience and you may use your own serialization scheme to persist the enclave's state. To ensure the client can continue communicating with the enclave if the client is restarted it's important the following is preserved:

sendMail
Link copied to clipboard
EnclaveMail sendMail(byte[] body)

Encrypt and send a mail message with the given body to the host using the transport for delivery to the enclave. The mail will have a topic of "default" and an empty envelope.

This method will block until the enclave has processed the mail successfully. If the enclave synchronously responds back with mail then they will be decrypted and returned back here. Any responses the enclave produces asychronously after the mail has been produced will be returned by pollMail.

If the enclave throws an exception during the processing of the request mail then this method will throw an EnclaveException. The message from the original enclave exception may or may not be present. In particular, if the enclave is running in release mode then the message will never be present. This is to prevent any potential secrets from being leaked.

EnclaveMail sendMail(String topic, byte[] body, byte[] envelope)

Encrypt and send a mail message with the given body to the host using the transport for delivery to the enclave. It will have the given topic and envelope.

This method will block until the enclave has processed the mail successfully. If the enclave synchronously responds back with mail then it will be decrypted and returned back here. Any responses the enclave produces asychronously after the mail has been produced need to be polled for using pollMail.

If the enclave threw an exception during the processing of the request mail then this method will throw an EnclaveException. The message from the original enclave exception may or may not be present. In particular, if the enclave is running in release mode then the message will never be present. This is to prevent any potential secrets from being leaked.

setEnclaveConstraint
Link copied to clipboard
void setEnclaveConstraint(EnclaveConstraint enclaveConstraint)

The constraints the enclave must satisfy before this client will communicate with it.

setLastSeenStateId
Link copied to clipboard
void setLastSeenStateId(byte[] lastSeenStateId)

Returns the last seen state ID from the enclave. The state ID is tracked to detect attempts to roll back the state of the enclave by the host.

Access to this value is typically only needed to persist it if a custom serialisation scheme is used (i.e. not save). Make sure to restore this value on the new client object to ensure it can continue communicating with the enclave.

start
Link copied to clipboard
void start(EnclaveTransport transport)

Starts the client with the given EnclaveTransport.

Properties

clientConnection
Link copied to clipboard
private EnclaveTransport.ClientConnection clientConnection

Returns this client's EnclaveTransport.ClientConnection instance with the enclave transport.

clientPrivateKey
Link copied to clipboard
private PrivateKey clientPrivateKey

Returns the private key that is used to encrypt mail to send to the enclave.

clientPublicKey
Link copied to clipboard
private PublicKey clientPublicKey

Returns the corresponding public key of clientPrivateKey. This will be what the enclave sees as the authenticated sender of mail it receives from this client.

enclaveConstraint
Link copied to clipboard
private EnclaveConstraint enclaveConstraint

The constraints the enclave must satisfy before this client will communicate with it.

enclaveInstanceInfo
Link copied to clipboard
private EnclaveInstanceInfo enclaveInstanceInfo

Returns the most recent EnclaveInstanceInfo downloaded from the host via the transport.

lastSeenStateId
Link copied to clipboard
private byte[] lastSeenStateId

Returns the last seen state ID from the enclave. The state ID is tracked to detect attempts to roll back the state of the enclave by the host.

Access to this value is typically only needed to persist it if a custom serialisation scheme is used (i.e. not save). Make sure to restore this value on the new client object to ensure it can continue communicating with the enclave.

postOffices
Link copied to clipboard
private Set<PostOfficepostOffices

Returns the set of PostOffices that have been used to send mail.

The returned Set is a copy. Adding or removing from it does not affect the client.

transport
Link copied to clipboard
private EnclaveTransport transport

Returns the EnclaveTransport used to communicate with the host.