Skip to content

Update the APIs used in the transport secure documentation #785

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

Merged
merged 5 commits into from
Oct 10, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 8 additions & 6 deletions transport/samples/secureclientbehaviour.cs.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,19 @@ Sample code for `SecureClient`:
using UnityEngine;
using Unity.Networking.Transport;
using Unity.Networking.Transport.TLS;

public class SecureClientBehaviour : MonoBehaviour
{
public NetworkDriver m_Driver;
public NetworkConnection m_Connection;
public bool m_Done;
private NetworkSettings settings = new NetworkSettings();

void Start ()
{
settings.WithSecureClientParameters(
serverName: ref SecureParameters.ServerCommonName,
caCertificate: ref SecureParameters.MyGameClientCA // Use the content of myGameClientCA.pem
);
var settings = new NetworkSettings();
settings.WithSecureClientParameters(
serverName: SecureParameters.ServerCommonName,
caCertificate: SecureParameters.MyGameClientCA);
m_Driver = NetworkDriver.Create(settings);
m_Connection = default(NetworkConnection);

Expand Down Expand Up @@ -74,4 +75,5 @@ public class SecureClientBehaviour : MonoBehaviour
}
}
}
}
}
```
31 changes: 15 additions & 16 deletions transport/samples/secureparameters.cs.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,27 +6,26 @@ title: SecureParameters sample
Sample code for `SecureParameters`:

```csharp
using Unity.Collections;
public static class SecureParameters
{
public static FixedString32Bytes ServerCommonName = new FixedString32Bytes("localserver"); // Use the common name you used to define the server certificate.
{
// Use the common name you used to create the server certificate.
public static readonly string ServerCommonName = "localserver";

public static FixedString4096Bytes MyGameClientCA = new FixedString4096Bytes(
@"-----BEGIN CERTIFICATE-----
*** REPLACE BY YOUR OWN CA Certificate ***
-----END CERTIFICATE-----");
public static readonly string MyGameClientCA =
@"-----BEGIN CERTIFICATE-----
*** REPLACE WITH YOUR OWN CA CERTIFICATE ***
-----END CERTIFICATE-----";

#if UNITY_SERVER
public static FixedString4096Bytes MyGameServerCertificate = new FixedString4096Bytes(
@"-----BEGIN CERTIFICATE-----
*** REPLACE BY YOUR OWN Server Certificate ***
-----END CERTIFICATE-----");
public static readonly string MyGameServerCertificate =
@"-----BEGIN CERTIFICATE-----
*** REPLACE WITH YOUR OWN SERVER CERTIFICATE ***
-----END CERTIFICATE-----";

public static FixedString4096Bytes MyGameServerPrivate = new FixedString4096Bytes(
@"-----BEGIN RSA PRIVATE KEY-----
*** REPLACE BY YOUR OWN Private Key ***
-----END RSA PRIVATE KEY-----");
public static readonly string MyGameServerPrivateKey =
@"-----BEGIN RSA PRIVATE KEY-----
*** REPLACE WITH YOUR OWN SERVER PRIVATE KEY ***
-----END RSA PRIVATE KEY-----";
#endif
}

```
9 changes: 5 additions & 4 deletions transport/samples/secureserverbehaviour.cs.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@ title: SecureServerBehaviour sample
---

Sample code for `SecureServerBehaviour`:
```cs

```csharp
using UnityEngine;
using UnityEngine.Assertions;
using Unity.Collections;
using Unity.Networking.Transport;
using Unity.Networking.Transport.TLS;

public class SecureServerBehaviour : MonoBehaviour
{
public NetworkDriver m_Driver;
Expand All @@ -19,9 +21,8 @@ public class SecureServerBehaviour : MonoBehaviour
{
var settings = new NetworkSettings();
settings.WithSecureServerParameters(
certificate: ref SecureParameters.MyGameServerCertificate, // The content of the `myGameServerCertificate.pem`
privateKey: ref SecureParameters.MyGameServerPrivate // The content of `myGameServerPrivate.pem`
);
certificate: SecureParameters.MyGameServerCertificate,
privateKey: SecureParameters.MyGameServerPrivateKey);
m_Driver = NetworkDriver.Create(settings);
var endpoint = NetworkEndPoint.AnyIpv4;
endpoint.Port = 9001;
Expand Down
185 changes: 96 additions & 89 deletions transport/workflow-client-server-secure.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,148 +2,155 @@
id: secure-connection
title: Create secure client and server
---
The unity transport protocol can be configure to encrypt the connection between the server and the client while ensuring the server's/client's authenticity.
This secure connection relies on UnityTLS and is available with the following editor versions:
`2020.3 (2020.3.34 minimum and above), 2021.3 (2021.3.1f1 minimum and above) and 2022.1 (2022.1.0b16 minimum and above)`

You can configure the Unity Transport package to encrypt the server-client connection while ensuring the authenticity of both the server and the client.

Secure connections are available with Editor versions 2020.3 (starting at 2020.3.34), 2021.3, and 2022.1 and above.

Copy link
Contributor

Choose a reason for hiding this comment

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

You can configure the Unity Transport package to encrypt the server-client connection while ensuring the authenticity of both the server and the client.

Secure connections are available with Editor versions 2020.3 (starting at 2020.3.34), 2021.3, and 2022.1 and above.

## Server authentication

:::warning Warning
Be sure private keys are not included in your code base or client builds.
This example uses hardcoded certificates to illustrate the process better. However, in an actual deployment, you should keep the server certificates separate from the client builds. You can do this by keeping the server certificates on a separate assembly or by loading the server certificates from a file on the server.
:::
Copy link
Contributor

Choose a reason for hiding this comment

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

This example uses hardcoded certificates to illustrate the process better. However, in an actual deployment, you should keep the server certificates separate from the client builds. You can do this by keeping the server certificates on a separate assembly or by loading the server certificates from a file on the server.


### High level authentication process
In this configuration, the server will provide a certificate to the client (`certificate`) containing the server host name.
The client will compare the server hostname to the one it knows (`serverName`) and will then validate the provided certificate against its own root certificate (`caCertificate`) confirming the server identity.

In this configuration, the server provides a certificate to the client (`certificate`) to prove its identity. The client uses its own root certificate (`caCertificate`) to validate the certificate from the server.

Copy link
Contributor

Choose a reason for hiding this comment

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

In this configuration, the server provides a certificate to the client (certificate) to prove its identity. The client validates the certificate against its own root certificate (caCertificate) to validate its identity.

I'm not sure this reads correctly. In the second sentence, it's unclear whether the client is using the certificate to validate its own or the server's identity.

Maybe this is more correct?

In this configuration, the server provides a certificate to the client (certificate) to prove its identity. The client uses its own root certificate (caCertificate) to validate the certificate from the server.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, your suggestion is correct and much clearer. Thanks!

:::note
Root certificate is also sometimes referred as CA Certificate.
Root certificates are also sometimes referred to as CA certificates.
:::

Once its identity confirmed, the server will then use the private key (`privateKey`) to establish the secure communication.
After confirming its identity, the server uses the private key (`privateKey`) to establish a secure communication channel.

Copy link
Contributor

Choose a reason for hiding this comment

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

After confirming its identity, the server uses the private key (privateKey) to establish a secure communication channel.

### Requirements
To use the client server secure workflow, you need a `valid certificate` and the `root certificate` it has been generated from. You also need the `private key` that has been used to create the certificate.
If you don't have these, they can be generated using OpenSSL. The procedure is detailed hereafter.

You need the following before you can use the client-server secure workflow:

- A valid certificate
- The root certificate used to sign the certificate
- The private key used to create the certificate

You can use OpenSSL to generate these if you don't have them. The procedure is detailed hereafter.

Copy link
Contributor

Choose a reason for hiding this comment

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

You need the following before you can use the client-server secure workflow:

  • A valid certificate
  • The root certificate used to sign the certificate
  • The private key used to create the certificate

You can use OpenSSL to generate these if you don't have them. The procedure is detailed hereafter.

### Generating the required keys and certificates with OpenSSL

It is assumed that you have [OpenSSL](https://www.openssl.org/) installed on your machine.

#### Generate the Certification Authority root certificate.
First thing first is to generate a private key. We will use it later on to generate the Certification Authority root certificate.
#### Generate the root certificate

First, generate a root private key. You will need it later to generate the root certificate.

Copy link
Contributor

Choose a reason for hiding this comment

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

First, generate a root private key. You will need it later to generate the root certificate.

I changed "we" to "you" because it's poor practice to switch between perspectives. The Unity Style guide recommends using second-person ("you").

Although, I'm not too worried about many of these comments because the same type of corrections should be applied throughout the entire documentation set.

```shell
openssl genrsa -out clientPrivateKeyForRootCA.pem 2048
```
Now that you have a private key, you can now generate the root certificate.

Now that you have a root private key, you can generate the root certificate.

Copy link
Contributor

Choose a reason for hiding this comment

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

Now that you have a root private key, you can generate the root certificate.

```shell
openssl req -x509 -new -nodes -key clientPrivateKeyForRootCA.pem -sha256 -days 1095 -out myGameClientCA.pem
```
You will be prompted to answer several questions. Most of the answers are not that important within the present context.
It is however useful to use a `common name` that makes sense for you to identify this certificate amongst others.
Ideally, you would want to use your domain name if you have one.

You will be prompted to answer several questions. Most of the answers are not that important within the present context. It is, however, useful to use a common name that makes sense for you to identify this certificate amongst others. Ideally, you would want to use your domain name if you have one.

Copy link
Contributor

Choose a reason for hiding this comment

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

It is, however, useful to use a common name that makes sense for you to identify this certificate amongst others. Ideally, you would want to use your domain name if you have one.

#### Generate the root-signed certificate to use with the server

Now, create a private key for the server.

Copy link
Contributor

Choose a reason for hiding this comment

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

Create a private key for the server.

Or

Now, create a private key for the server.

#### Generate the CA-signed certificate to use with the server
Create now a private key for the server.
```shell
openssl genrsa -out myGameServerPrivate.pem 2048
openssl genrsa -out myGameServerPrivateKey.pem 2048
```
From this private key, you can generate a certificate signing request.

You can use this private key to generate a certificate signing request.

Copy link
Contributor

Choose a reason for hiding this comment

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

You can use this private key to generate a certificate signing request.

```shell
openssl req -new -key myGameServerPrivate.pem -out myGameServerCertificateSigningRequest.pem
openssl req -new -key myGameServerPrivateKey.pem -out myGameServerCertificateSigningRequest.pem
```
You'll be prompted with the same questions as for generating the root certificate.
The answers are no more important, except for the `common name` : use the host name of your server if you have one. This common name
will appear in the generated certificate and will be compare by the Client against the common name it received as parameter (`serverName`).

Finally, using the different files generated, we can create the certificate file the server will use to authenticate itself :
You'll be prompted with the same questions you answered when generating the root certificate. The answers are no more important (except for the common name: it is recommended to use the server's hostname).

Finally, you can create the certificate file the server will use to authenticate itself using the generated files:

Copy link
Contributor

Choose a reason for hiding this comment

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

You'll be prompted with the same questions you answered when generating the root certificate. The answers are no more important (except for the common name: it is recommended to use the server's hostname).

Finally, you can create the certificate file the server will use to authenticate itself using the generated files:

```shell
openssl.exe x509 -req -in myGameServerCertificateSigningRequest.pem -CA myGameClientCA.pem -CAkey clientPrivateKeyForRootCA.pem -CAcreateserial -out myGameServerCertificate.pem -days 365 -sha256
```
You should have now generated a total of five files. Out of these, only three will be used later on :
* The content of the `myGameClientCA.pem` file, will be used client side as the `caCertificate` parameter.
* On the server end, `myGameServerPrivate.pem` file content will be used for the `privateKey` parameter.
* `myGameServerCertificate.pem` will be used by the `certificate` parameter on the server end.

### Boiler Plate file holding the secure parameters
Create a `SecureParameters.cs` script file to hold your certificates and the private key. Place it in the same folder as the minimal server and minimal client scripts.
Add the following dependencies:
```cs
using Unity.Collections;
using Unity.Networking.Transport.TLS;
```
Then declare the secureParameters class and the boilerplate code that will hold your secure information:
```cs

You should have now generated a total of five files. You only need to use the following three: `myGameClientCA.pem`, `myGameServerCertificate.pem`, and `myGameServerPrivateKey.pem`.

- On the client side, you need the content of the `myGameClientCA.pem` for the `caCertificate` parameter.
- On the server end, you need the contents of `myGameServerCertificate.pem` for the `certificate` parameter.
- On the server end, you need the contents of `myGameServerPrivateKey.pem` for the `privateKey` parameter.

### Boilerplate file holding the secure parameters

Create a `SecureParameters.cs` script file to hold your certificates and the private key. Place it in the same folder as the minimal server and minimal client scripts. Then, declare the `SecureParameters` static class and the boilerplate code that will hold your secure information:

Copy link
Contributor

Choose a reason for hiding this comment

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

You should have now generated a total of five files. You only need to use the following three: myGameClientCA.pem, myGameServerCertificate.pem, and myGameServerPrivateKey.pem.

  • On the client side, you need the content of the myGameClientCA.pem for the caCertificate parameter.
  • On the server end, you need the contents of myGameServerCertificate.pem for the certificate parameter.
  • On the server end, you need the contents of myGameServerPrivateKey.pem for the privateKey parameter.

Boilerplate file holding the secure parameters

Create a SecureParameters.cs script file to hold your certificates and the private key. Place it in the same folder as the minimal server and minimal client scripts. Then, declare the SecureParameters static class and the boilerplate code that will hold your secure information:

```csharp
public static class SecureParameters
{
public static FixedString32Bytes ServerCommonName = new FixedString32Bytes("server_certificate_host_name"); // Use the common name you used to define the server certificate.
public static FixedString4096Bytes MyGameClientCA = new FixedString4096Bytes(
// Use the common name you used to create the server certificate.
public static readonly string ServerCommonName = "localserver";

public static readonly string MyGameClientCA =
@"-----BEGIN CERTIFICATE-----
*** Contents of myGameClientCA.pem ***
-----END CERTIFICATE-----";

public static readonly string MyGameServerCertificate =
@"-----BEGIN CERTIFICATE-----
***
-----END CERTIFICATE-----"); // This should contain the content of myGameClientCA.pem

public static FixedString4096Bytes MyGameServerCertificate = new FixedString4096Bytes(
@"-----BEGIN CERTIFICATE-----
***
-----END CERTIFICATE-----");; // This should contain the content of myGameServerCertificate.pem

public static FixedString4096Bytes MyGameServerPrivate = new FixedString4096Bytes(
@"-----BEGIN RSA PRIVATE KEY-----
***
-----END RSA PRIVATE KEY-----"); // This should contain the content of myGameServerPrivate.pem
*** Contents of myGameServerCertificate.pem ***
-----END CERTIFICATE-----";

public static readonly string MyGameServerPrivateKey =
@"-----BEGIN RSA PRIVATE KEY-----
*** Contents of myGameServerPrivateKey.pem ***
-----END RSA PRIVATE KEY-----";
}
```

### Creating the Secure Server
### Creating the secure server

Starting from the minimal server sample code, create a `NetworkSettings` object in the `Start` method and configure it as follows:

Starting from the minimal server sample code, create a `NetworkSettings` object.
```csharp
void Start ()
{
var settings = new NetworkSettings();
settings.WithSecureServerParameters(
certificate: SecureParameters.MyGameServerCertificate,
privateKey: SecureParameters.myGameServerPrivateKey);

```cs
private NetworkSettings settings = new NetworkSettings();
// ...
}
```

Within the `start()` method, configure this `NetworkSettings` as following:
```cs
void Start ()
{
settings.WithSecureServerParameters(
certificate: ref SecureParameters.MyGameServerCertificate, // The content of the `myGameServerCertificate.pem`
privateKey: ref SecureParameters.MyGameServerPrivate // The content of `myGameServerPrivate.pem`
);
```
Call create method of the network driver but this time, integrate the `NetworkSettings` object.
```cs
When creating the `NetworkDriver`, pass in this `NetworkSettings` object:

```csharp
m_Driver = NetworkDriver.Create(settings);
```
That's it for the server !

### Creating a Secure Client
That's it for the server!

The secure client is very similar to the secure server. Starting from the minimal client sample code, create `NetworkSettings` object.
```cs
private NetworkSettings settings = new NetworkSettings();
```
### Creating a secure client

The difference between client and server lies with the parameters that will be provided to the NetworkSettings object.
Within the `start()` method, configure this `NetworkSettings` object as following :
```cs
The secure client is very similar to the secure server. The only difference is in how the `NetworkSettings` object is configured.

```csharp
void Start ()
{
settings.WithSecureClientParameters(
serverName: ref SecureParameters.ServerCommonName,
caCertificate: ref SecureParameters.MyGameClientCA, // Use the content of myGameClientCA.pem
);
{
var settings = new NetworkSettings();
settings.WithSecureServerParameters(
serverName: SecureParameters.ServerCommonName,
caCertificate: SecureParameters.MyGameClientCA);
m_Driver = NetworkDriver.Create(settings);

// ...
}
```
Finally, call the `create` method of the network driver but this time, integrate the `NetworkSettings` object.
```cs
m_Driver = NetworkDriver.Create(settings);
```
and that's it !
You should now have a secure connection between the server and its clients.

You should now have a secure connection between the server and its clients!

:::note
If you create clients for multiple platform, it is important for all of these to use the same Root Certificate if they communicate with the same server.
If you create clients for multiple platforms, it is important for all clients to continue using the same root certificate if they communicate with the same server.
:::
Copy link
Contributor

Choose a reason for hiding this comment

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

If you create clients for multiple platforms, it is important for all clients to continue using the same root certificate if they communicate with the same server.