# NGINX Configuration for Multiple Certificates
Date: 2025-01-06


NGINX typically supports two scenarios for configuring multiple certificates:

1. Providing multiple certificate types (e.g., RSA and ECC) for the same domain.
2. Hosting multiple domains on the same IP address, using different certificates selected based on the client-provided SNI.

* * *

### **Generating Certificates**

Use the `ssl_cert_chain_tool.sh` script to generate a set of valid certificates:

```bash
# RSA Certificates
ssl_cert_chain_tool.sh -a RSA -o a_cert -n a.example.com -u
ssl_cert_chain_tool.sh -a RSA -o b_cert -n b.example.com -u
ssl_cert_chain_tool.sh -a RSA -o c_cert -n c.example.com -u

# ECC Certificates
ssl_cert_chain_tool.sh -a ECC -o d_cert -n d.example.com -u
ssl_cert_chain_tool.sh -a ECC -o e_cert -n e.example.com -u
```

* * *

### **Support for Multiple Certificate Types**

```nginx
http {
    include mime.types;
    default_type application/octet-stream;

    sendfile on;
    keepalive_timeout 65;

    server {
        listen 0.0.0.0:443 ssl;
        ssl_protocols TLSv1.3 TLSv1.2;
        server_name a.example.com b.example.com c.example.com d.example.com e.example.com;

        ssl_prefer_server_ciphers on;

        # RSA and ECC Certificates
        ssl_certificate a_cert/server.cert.pem;
        ssl_certificate_key a_cert/server.key.pem;

        ssl_certificate e_cert/server.cert.pem;
        ssl_certificate_key e_cert/server.key.pem;

        ssl_certificate d_cert/server.cert.pem;
        ssl_certificate_key d_cert/server.key.pem;

        ssl_certificate c_cert/server.cert.pem;
        ssl_certificate_key c_cert/server.key.pem;

        ssl_certificate b_cert/server.cert.pem;
        ssl_certificate_key b_cert/server.key.pem;

        location / {
            return 200 'Multi-certificates test\n';
        }
    }
}
```

During the handshake process, the server selects the appropriate certificate based on the signature algorithm. OpenSSL handles this in the `tls_post_process_client_hello->tls_choose_sigalg` function, which processes the client hello message and selects the most suitable certificate based on the signature algorithms and the server's configuration.

#### TLS 1.2 Behavior

In TLS 1.2, cipher suites include the signature algorithm. If specified, the certificate selection prioritizes the cipher suite over the signature algorithms in the extensions field.

```bash
# TLS 1.2 Example
curl -ksv --tlsv1.2 --tls-max 1.2 --resolve a.example.com:443:127.0.0.1 https://a.example.com
```

The above command shows an ECC certificate (`d_cert`) being selected by default. Specifying a cipher suite forces the server to select an RSA certificate (`b_cert`).

```bash
curl -ksv --tlsv1.2 --tls-max 1.2 --resolve a.example.com:443:127.0.0.1 https://a.example.com --ciphers ECDHE-RSA-AES128-GCM-SHA256
```

OpenSSL and Wireshark provide further insights into the handshake process and certificate selection.

#### TLS 1.3 Behavior

In TLS 1.3, cipher suites no longer specify the signature algorithm, which is selected exclusively through the `signature_algorithms` extension.

```bash
openssl s_client -connect 127.0.0.1:443 -sigalgs "RSA-PSS+SHA256" -tls1_3
```

* * *

### **SNI-Based Certificate Selection**

NGINX allows the use of the SNI (Server Name Indication) extension to dynamically select certificates for different domains. Here’s an example using the `map` directive:

```nginx
http {
    map $ssl_server_name $cert {
        a.example.com a_cert/server.cert.pem;
        b.example.com b_cert/server.cert.pem;
        d.example.com d_cert/server.cert.pem;
        e.example.com e_cert/server.cert.pem;
        default c_cert/server.cert.pem;
    }

    map $ssl_server_name $key {
        a.example.com a_cert/server.key.pem;
        b.example.com b_cert/server.key.pem;
        d.example.com d_cert/server.key.pem;
        e.example.com e_cert/server.key.pem;
        default c_cert/server.key.pem;
    }

    server {
        listen 0.0.0.0:443 ssl;
        ssl_protocols TLSv1.3 TLSv1.2;
        server_name a.example.com b.example.com c.example.com d.example.com e.example.com;

        ssl_certificate $cert;
        ssl_certificate_key $key;

        location / {
            return 200 'Multi-certificates test\n';
        }
    }
}
```

### **Verification**

Using `curl` or `openssl`, you can validate the setup to ensure certificates are selected based on the server name.

```bash
curl -ksv --resolve a.example.com:443:127.0.0.1 https://a.example.com
curl -ksv --resolve e.example.com:443:127.0.0.1 https://e.example.com
```

### **Conclusion**

The examples above demonstrate how NGINX can be configured to handle multiple certificates effectively. For production use, it’s recommended to use server blocks rather than `map` for better performance unless dynamic certificate loading is essential.

Lastly, during research, quantum-safe cryptographic algorithms were mentioned as a new development area. This is a topic worth exploring further in the future.

