Secure Connection with Holographic Remoting and the OpenXR API
When using the OpenXR API, all secure connection-related API is available as part of the XR_MSFT_holographic_remoting
OpenXR extension.
Important
To learn about the Holographic Remoting OpenXR extension API, check out the specification which can be found in the Holographic Remoting samples github repository.
Remember that you need to implement custom remote and player apps if you want to enable connection security. Both of the custom apps need:
- A certificate provider and an authentication validator if the app runs as the server.
- An authentication provider and a certificate validator if the app runs as the client.
The OpenXR API is similar to the Windows Mixed Reality API described here.
However, instead of implementing interfaces, the key elements for secure connection using the XR_MSFT_holographic_remoting
OpenXR extension are the following callbacks:
xrRemotingRequestAuthenticationTokenCallbackMSFT
, generates, or retrieves the authentication token to be sent.xrRemotingValidateServerCertificateCallbackMSFT
, validates the certificate chain.xrRemotingValidateAuthenticationTokenCallbackMSFT
, validates the client authentication token.xrRemotingRequestServerCertificateCallbackMSFT
, supply the server application with the certificate to use.
Note
With Holographic Remoting it is possible that either the Player or the Remote is the server depending on your needs (For more information, see Holographic Remoting Terminology). If your custom remote or custom player application can run as client and server the app has to provide all four callbacks.
The callbacks can be provided to the remoting OpenXR runtime via xrRemotingSetSecureConnectionClientCallbacksMSFT
and xrRemotingSetSecureConnectionServerCallbacksMSFT
.
In order to do so, you can create static functions for the callbacks:
class SecureConnectionCallbacks {
public:
...
// Static callbacks
static XrResult XRAPI_CALL
RequestAuthenticationTokenStaticCallback(XrRemotingAuthenticationTokenRequestMSFT* authenticationTokenRequest) {
if (!authenticationTokenRequest->context) {
return XR_ERROR_RUNTIME_FAILURE;
}
return reinterpret_cast<SecureConnectionCallbacks*>(authenticationTokenRequest->context)
->RequestAuthenticationToken(authenticationTokenRequest);
}
static XrResult XRAPI_CALL
ValidateServerCertificateStaticCallback(XrRemotingServerCertificateValidationMSFT* serverCertificateValidation) {
if (!serverCertificateValidation->context) {
return XR_ERROR_RUNTIME_FAILURE;
}
return reinterpret_cast<SecureConnectionCallbacks*>(serverCertificateValidation->context)
->ValidateServerCertificate(serverCertificateValidation);
}
static XrResult XRAPI_CALL
ValidateAuthenticationTokenStaticCallback(XrRemotingAuthenticationTokenValidationMSFT* authenticationTokenValidation) {
if (!authenticationTokenValidation->context) {
return XR_ERROR_RUNTIME_FAILURE;
}
return reinterpret_cast<SecureConnectionCallbacks*>(authenticationTokenValidation->context)
->ValidateAuthenticationToken(authenticationTokenValidation);
}
static XrResult XRAPI_CALL
RequestServerCertificateStaticCallback(XrRemotingServerCertificateRequestMSFT* serverCertificateRequest) {
if (!serverCertificateRequest->context) {
return XR_ERROR_RUNTIME_FAILURE;
}
return reinterpret_cast<SecureConnectionCallbacks*>(serverCertificateRequest->context)
->RequestServerCertificate(serverCertificateRequest);
}
}
The static callback functions all look similar and in the example above they just call a function on the context object, which is set in xrRemotingSetSecureConnectionClientCallbacksMSFT
or xrRemotingSetSecureConnectionServerCallbacksMSFT
. The actual implementation of the callbacks is then done inside the member functions of the context object:
class SecureConnectionCallbacks {
...
private:
// The client has to provide a token and has to validate the certificate.
XrResult RequestAuthenticationToken(XrRemotingAuthenticationTokenRequestMSFT* authenticationTokenRequest) {
// To provide a token fill out the authenticationTokenRequest with your token.
}
XrResult ValidateServerCertificate(XrRemotingServerCertificateValidationMSFT* serverCertificateValidation) {
// Validate the certificate.
}
// The server has to provide a certificate and hast to validate the token.
XrResult ValidateAuthenticationToken(XrRemotingAuthenticationTokenValidationMSFT* authenticationTokenValidation) {
// Validate the token.
}
XrResult RequestServerCertificate(XrRemotingServerCertificateRequestMSFT* serverCertificateRequest) {
// To provide a certificate fill out the serverCertificateRequest with your certificate.
}
}
Now you can provide the callbacks to xrRemotingSetSecureConnectionClientCallbacksMSFT
and xrRemotingSetSecureConnectionServerCallbacksMSFT
. Additionally, the secure connection needs to be enabled via the secureConnection parameter on the XrRemotingConnectInfoMSFT
structure or the XrRemotingListenInfoMSFT
structure depending on whether you're using xrRemotingConnectMSFT
or xrRemotingListenMSFT
:
...
SecureConnectionCallbacks callbackObject;
...
if (client)
{
XrRemotingSecureConnectionClientCallbacksMSFT clientCallbacks{static_cast<XrStructureType>(XR_TYPE_REMOTING_SECURE_CONNECTION_CLIENT_CALLBACKS_MSFT);
clientCallbacks.context = &callbackObject;
clientCallbacks.requestAuthenticationTokenCallback = SecureConnectionCallbacks::RequestAuthenticationTokenStaticCallback;
clientCallbacks.validateServerCertificateCallback = SecureConnectionCallbacks::ValidateServerCertificateStaticCallback;
clientCallbacks.performSystemValidation = true;
CHECK_XRCMD(m_extensions.xrRemotingSetSecureConnectionClientCallbacksMSFT(m_instance.Get(), m_systemId, &clientCallbacks));
...
connectInfo.secureConnection = true; // Enable secure connection!
CHECK_XRCMD(m_extensions.xrRemotingConnectMSFT(m_instance.Get(), m_systemId, &connectInfo));
}
if (server)
{
XrRemotingSecureConnectionServerCallbacksMSFT serverCallbacks{static_cast<XrStructureType>(XR_TYPE_REMOTING_SECURE_CONNECTION_SERVER_CALLBACKS_MSFT);
serverCallbacks.context = &callbackObject;
serverCallbacks.requestServerCertificateCallback = SecureConnectionCallbacks::RequestServerCertificateStaticCallback;
serverCallbacks.validateAuthenticationTokenCallback = SecureConnectionCallbacks::ValidateAuthenticationTokenStaticCallback;
serverCallbacks.authenticationRealm = /*YourAuthenticationRealm*/;
CHECK_XRCMD(m_extensions.xrRemotingSetSecureConnectionServerCallbacksMSFT(m_instance.Get(), m_systemId, &serverCallbacks));
...
listenInfo.secureConnection = true; // Enable secure connection!
CHECK_XRCMD(m_extensions.xrRemotingListenMSFT(m_instance.Get(), m_systemId, &listenInfo));
}
Note
You can find a detailed example in the OpenXR sample app.