Skip to main content

Transport Layer Security

Masters and outstations may optionally use TLS which protects DNP3 communication by adding encryption and authentication. The DNP3 library uses rustls, a modern TLS library written in safe Rust. It does not depend on OpenSSL or other system libraries, but will interoperate seamlessly with other implementations.

Rustls has been reviewed by a third party and is production ready. It outperforms OpenSSL in almost every aspect and has the backing of the ISRG.

Secure Authentication?

DNP3 SAv5 (and v2) has a number of design flaws and is not widely adopted. The multi-user support in SAv5 was deprecated because it did not meet its stated design goals. SAv6 aims to reduce the complexity of SAv5, but it has not been standardized yet and there are no full implementations.

tip

We recommend using TLS to secure DNP3 and caution the industry to avoid home-grown solutions such as secure authentication.

Supported Features

  • TLS v1.2 and v1.3
  • Supported cipher suites (in descending order of preference):
    • TLS v1.3:
      • TLS_CHACHA20_POLY1305_SHA256
      • TLS_AES_256_GCM_SHA384
      • TLS_AES_128_GCM_SHA256
    • TLS v1.2:
      • TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256
      • TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
      • TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
      • TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
      • TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
      • TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
  • Supported key exchange algorithms (in descending order of preference):
    • x25519
    • secp384r1
    • secp256r1
  • Supported signature algorithms (in descending order of preference):
    • ecdsa_secp384r1_sha384
    • ecdsa_secp256r1_sha256
    • ed25519 (v1.3 only)
    • rsa_pss_sha512 (v1.3 only)
    • rsa_pss_sha384 (v1.3 only)
    • rsa_pss_sha256 (v1.3 only)
    • rsa_pkcs1_sha512
    • rsa_pkcs1_sha384
    • rsa_pkcs1_sha256
  • Client and server name validation through the Subject Alternative Name (SAN) extension or the Common Name.
  • Self-signed certificates (with a special configuration).

Configuration

TLS configuration is configured using the TlsClientConfig or TlsServerConfig structures. They are very similar and contain the following fields:

  • name:
    • The client and the server both verify that the certificate presented by the peer is valid for this name. Check out the next section for the gory details on name validation.
    • The client will advertise this name through a Server Name Indication (SNI) extension in the Client Hello.
  • peer_cert_path:
    • Path to the unencrypted PEM file containing the trusted root certificate(s) or the peer self-signed certificate.
  • local_cert_path:
    • Path to the unencrypted PEM file containing the certificate(s) to present to the peer.
  • private_key_path:
    • Path to the PEM file containing the encrypted or plaintext private key corresponding to the public key in the presented certificate.
  • password:
    • Password used to decrypt the private key file. This field should be left empty if the file is not encrypted. See the next section for more details.
  • min_tls_version:
    • Minimum TLS version to support. Setting this to Tls1_3 will force the usage of TLSv1.3.
  • certificate_mode:
    • Mode used to verify the peer certificate.

Name Validation

This section describes how name validation is performed when certificate_mode is AuthorityBased. When the mode is SelfSigned, name validation is performed indirectly since a byte-for-byte comparison occurs of the entire certificate.

A valid name has the same requirements as a DNS name. This is defined in RFC 1034 Section 3.5, updated by RFC1123 Section 2.1, with the additional exception that underscores _ are allowed. A brief (but incomplete) definition of a valid name includes:

  • One or more labels separated by a single period
  • Labels are made of alphanumeric characters [A-Za-z0-9], hyphens -, and underscores _
  • A label cannot start or end with an hyphen -
  • A label cannot be all numeric
  • A label cannot be empty
  • Maximum of 63 characters per label
  • Maximum of 253 characters total

If the SAN extension is present, the name is validated against it. The SAN may contain multiple names and each name can contain a wildcard * character. The comparison is case-insensitive.

If the SAN is absent, then the Common Name from the certificate's Subject is extracted and compared. The Common Name cannot contain a wildcard character and the comparison is case-sensitive. It is effectively compared byte-for-byte with the expected name.

tip

New certificates should always include the SAN extension. Performing name verification using the Common Name is still secure, but it is deprecated for new use cases.

Private Key Encryption

Unencrypted private keys may be stored in PKCS#1 or PKCS#8 formats:

  • ----BEGIN RSA PRIVATE KEY-----

  • -----BEGIN PRIVATE KEY-----

Encrypted private keys must be stored in PKCS#8v2 format:

  • -----BEGIN ENCRYPTED PRIVATE KEY-----

Keys encrypted in PKCS#1 format are not supported.

The following algorithms are supported when keys are encrypted in PKCS#8v2 format:

  • Key derivation functions:
    • scrypt (RFC 7914) recommended
    • PBKDF2 (RFC 8018) using one of the following HMAC:
      • HMAC-SHA224
      • HMAC-SHA256
      • HMAC-SHA384
      • HMAC-SHA512
  • Symmetric encryption:
    • AES-128-CBC
    • AES-192-CBC
    • AES-256-CBC recommended

SHA-1 based key derivation and DES/3DES symmetric encryption are not supported because they are insecure.

The OpenSSL pkcs8 command can be used to encrypt keys or convert private key formats.

tip

Encrypting private keys for use with TLS rarely addresses a meaningful threat model. Encrypting a private key and storing the password in a configuration file is equivalent to locking your doors and leaving the key under the doormat.

Certificate Mode

The certificate_mode parameter determines how the presented peer certificate is validated.

Authority-based

The default AuthorityBased mode uses the default rustls implementation to check the presented chain of certificates and verify that the root certificate of the chain is one of those provided in the peer_cert_path file. Most, if not all applications, in the power industry, will have a single root certificate.

This mode validates the chain and the end-entity certificate in accordance with RFC 5280.

Self-Signed

The SelfSigned mode validates that:

  • Only a single certificate is presented
  • It is a byte-for-byte match of the one specified in peer_cert_path
  • NotBefore and NotAfter time fields are valid for the current time
note

Name validation is performed indirectly in self-signed mode, since the byte-for-byte comparison also compares the internal name fields.

Generating Certificates

The following OpenSSL commands are provided for testing purposes only. Real systems will use some kind of specialized CA software for certificate procurement.

Full CA chain

  • Generate the root CA certificate:
openssl req -x509 -newkey rsa:4096 -keyout ./ca_key.pem -out ./ca_cert.pem -subj "/C=US/ST=Oregon/L=Bend/O=Test/CN=DO NOT USE" -nodes -days 3650
  • Generate the master CSR:
openssl req -new -newkey rsa:4096 -keyout ./master_key.pem -out ./master_csr.pem -subj "/C=US/ST=Oregon/L=Bend/O=Test/CN=DO NOT USE" -addext "subjectAltName=DNS:test.com" -nodes -days 365
  • Generate the master certificate:
openssl x509 -req -days 365 -in ./master_csr.pem -extfile <(printf "subjectAltName=DNS:test.com") -CA ./ca_cert.pem -CAkey ./ca_key.pem -set_serial 1 -out ./master_cert.pem -sha256
  • Generate the outstation CSR:
openssl req -new -newkey rsa:4096 -keyout ./outstation_key.pem -out ./outstation_csr.pem -subj "/C=US/ST=Oregon/L=Bend/O=Test/CN=DO NOT USE" -addext "subjectAltName=DNS:test.com" -nodes -days 365
  • Generate the outstation certificate:
openssl x509 -req -days 365 -in ./outstation_csr.pem -extfile <(printf "subjectAltName=DNS:test.com") -CA ./ca_cert.pem -CAkey ./ca_key.pem -set_serial 2 -out ./outstation_cert.pem -sha256

Self-signed certificate

  • Generate the master certificate:
openssl req -x509 -newkey rsa:4096 -keyout ./master_key.pem -out ./master_cert.pem -subj "/C=US/ST=Oregon/L=Bend/O=Test/CN=DO NOT USE" -addext "subjectAltName=DNS:test.com" -nodes -days 365
  • Generate the outstation certificate:
openssl req -x509 -newkey rsa:4096 -keyout ./outstation_key.pem -out ./outstation/entity2_cert.pem -subj "/C=US/ST=Oregon/L=Bend/O=Test/CN=DO NOT USE" -addext "subjectAltName=DNS:test.com" -nodes -days 365