NetBurner 3.5.8
PDF Version
SSL/TLS and Certificates

Introduction

This comprehensive guide covers SSL/TLS security implementation on NetBurner embedded devices. Whether you're securing a web interface, IoT communication, or industrial control system, this guide provides practical solutions for establishing encrypted, authenticated connections.

What You'll Learn:**

  • Core SSL/TLS concepts explained clearly
  • Multiple implementation approaches from simple to advanced
  • Certificate management strategies
  • Common issues and their solutions
  • Production-ready deployment practices

Understanding SSL/TLS Fundamentals

Note: This document uses "SSL" as shorthand for SSL/TLS protocols. Modern implementations use TLS (Transport Layer Security), the successor to SSL.

The Security Problem

In a normal network connection, data travels in plain text. This creates two critical vulnerabilities:

┌────────┐ ┌────────┐
│ Client │─────────────────────────────────────>│ Server │
└────────┘ Unencrypted Data └────────┘

Vulnerability 1: Eavesdropping**

┌────────┐ ┌────────┐
│ Client │──────────┐ ┌────│ Server │
└────────┘ │ │ └────────┘
v ^
┌──────────┐ │
│ Attacker │─────────────────┘
│(Sniffing)│
└──────────┘
"I can read everything!"

Vulnerability 2: Man-in-the-Middle (MITM)**

┌────────┐ ┌────────┐
│ Client │──────────┐ ┌────│ Server │
└────────┘ │ │ └────────┘
v ^
┌──────────┐ │
│ Attacker │─────────────────┘
│ (Proxy) │
└──────────┘
"I can read AND modify everything!"

How SSL/TLS Solves These Problems

SSL/TLS provides three critical security features:

  1. Encryption: Data is scrambled so eavesdroppers see gibberish
  2. Authentication: Verify you're talking to the real server (not an attacker)
  3. Integrity: Detect if data has been tampered with

The Trust Chain: How Authentication Works

SSL/TLS uses a "chain of trust" similar to how we trust professionals:

Real-World Analogy: Trusting a Doctor

┌─────────────────┐
│ Medical School │ <── We trust the institution
└────────┬────────┘
│ issues diploma
v
┌─────────┐
│ Hospital│ <── Hospital verifies the diploma
└────┬────┘
│ employs
v
┌────────┐
│ Doctor │ <── We trust the doctor by extension
└────────┘

SSL/TLS Certificate Chain

┌──────────────────────┐
│ Root CA │ <── Trusted by browsers/clients (pre-installed)
│ (e.g., DigiCert) │
└──────────┬───────────┘
│ signs
v
┌──────────────────────┐
│ Intermediate CA │ <── Issues certificates for organizations
└──────────┬───────────┘
│ signs
v
┌──────────────────────┐
│ Server Certificate │ <── Your device's identity
│ CN: yourdevice.com │
└──────────────────────┘

Key Components of a Certificate:**

  1. Identity (Common Name/CN) - Who this certificate represents
  2. Public Key - Like an open padlock anyone can use to encrypt
  3. Signature - Cryptographic proof from a trusted CA

Public Key Cryptography Simplified

Think of it like a special mailbox:

┌─────────────────────────────────────────┐
│ Public Key = Open Padlock │
│ (Anyone can lock, share freely) │
│ │
│ ┌───────┐ │
│ │ [BOX] │ <── Locked Box │
│ │ [LCK] │ (Encrypted Data) │
│ └───────┘ │
│ │
│ Private Key = Key to Padlock │
│ (Only owner can unlock, KEEP SECRET!) │
│ │
│ ┌───────┐ │
│ │ [BOX] │ <── Unlocked Box │
│ │ [GEM] │ (Decrypted Data) │
│ └───────┘ │
└─────────────────────────────────────────┘

Critical Security Principle:**

[LOCK] The system is only as secure as the private key. If an attacker gets your private key, they can decrypt all traffic and impersonate your device.

Certificate Types at a Glance

Type Trust Level Browser Warnings Best For Cost
Self-Signed Low [!] Yes Development, testing, internal networks Free
Private CA Medium [!] Yes (until CA installed) Enterprise deployments, controlled environments Free
Public CA High [OK] No Production, public-facing devices Varies
ACME (Let's Encrypt) High [OK] No Production with public DNS Free

Quick Start Guide

For SSL Servers (Your NetBurner Device)

Option 1: Automatic (Recommended for Production)

If you have a public DNS name:**

// ACME with Let's Encrypt - Automatic trusted certificates
#include <acmeservlet.h>
void UserMain(void *pd) {
init();
// Configure ACME
AcmeConfig config;
config.domain = "mydevice.example.com";
config.email = "admin@example.com";
// Automatic certificate issuance and renewal
StartAcmeHttps(config);
printf("Secure HTTPS server running\n");
while(1) { OSTimeDly(TICKS_PER_SECOND); }
}
#define TICKS_PER_SECOND
System clock ticks per second.
Definition constants.h:49
void OSTimeDly(uint32_t to_count)
Delay the task until the specified value of the system timer ticks. The number of system ticks per se...
Definition nbrtos.h:1855
void init()
System initialization. Ideally called at the beginning of all applications, since the easiest Recover...
bool WaitForActiveNetwork(uint32_t ticks_to_wait=120 *TICKS_PER_SECOND, int interface=-1)
Wait for an active network connection on at least one interface.

If you only have local/private network:**

// Auto-generated self-signed certificate
#include <init.h>
#include <startnet.h>
void UserMain(void *pd) {
init();
// Automatically generates self-signed cert on first run
StartHttps(); // Port 443 by default
printf("HTTPS server running (self-signed)\n");
while(1) { OSTimeDly(TICKS_PER_SECOND); }
}
void StartHttps(uint16_t ssl_port, uint16_t http_port)
Start the HTTPS secure web server.

For SSL Clients (Connecting to Servers)

#include <ssl.h>
#include <nettcp.h>
// CA certificates you trust (example: Let's Encrypt root)
extern const char letsEncryptCA[];
extern const int letsEncryptCA_len;
void ConnectSecurely() {
// Initialize SSL system
// Add trusted CA certificates
SSL_AddCertToClientCaList(letsEncryptCA, letsEncryptCA_len);
// Create secure connection
int fd = connect("api.example.com", 443);
WOLFSSL* ssl = SSL_connect(fd);
if (ssl) {
SSL_write(ssl, "GET / HTTP/1.1\r\n\r\n", 18);
// ... read response ...
SSL_close(ssl);
}
}
bool SSL_AddCertToClientCaList(const unsigned char *certBuff=nullptr, uint32_t certBuffSize=0, uint16_t certBuffFormat=SSL_FILETYPE_PEM)
Attempts to add a cert to the Certificate Authority List to the client SSL context.
void SslInit()
This function initializes the SSL library.
int SSL_connect(IPADDR ip, uint16_t remotePort, uint32_t timeout, const char *commonName, bool verifyPeer=false, bool waitForNegotiation=true, const unsigned char *certBuff=nullptr, uint32_t certBuffSize=0, uint16_t certBuffFormat=SSL_FILETYPE_PEM, int intf=-1)
SSL mirror of the TCP::connect() call.
int connect(const IPADDR &ipAddress, uint16_t remotePort, uint32_t timeout)
Establish a TCP connection to a remote host.
Definition tcp.h:1547

Certificate Types and Use Cases

Decision Matrix

Need Public Access?
│
┌─────────┴─────────┐
YES NO
│ │
Have DNS name? Multiple devices?
│ │
┌─────┴─────┐ ┌─────┴─────┐
YES NO YES NO
│ │ │ │
v v v v
Use ACME Use Public Private Self-Signed
(Let's Encrypt) CA CA (Simplest)

1. Self-Signed Certificates

What It Is:** Device acts as its own Certificate Authority

Visual Flow:**

NetBurner Device
┌──────────────────────────┐
│ 1. Generate Key Pair │
│ 2. Create Certificate │
│ 3. Sign with Own Key │
│ 4. Use for Connections │
└──────────┬───────────────┘
│
v
Browser/Client
┌──────────────────────────┐
│ [!] Certificate Warning │
│ "Not Trusted" │
│ │
│ [Proceed Anyway] │
└──────────────────────────┘

When to Use:**

  • [YES] Development and testing
  • [YES] Single device, few users
  • [YES] Internal network only
  • [YES] Quick prototyping

    Limitations:**

  • [NO] Browser warnings for every user
  • [NO] Certificate must be manually installed on each client
  • [NO] No central management
  • [NO] Looks unprofessional in production

    NetBurner Implementation:**

    // Automatic - just enable HTTPS
    StartHttps(); // Self-signed cert auto-generated
    // Or manual control, in overload/nbrtos/include/predef-overload.h
    #define ENABLE_AUTOCERT_REGEN (1)
    #define AUTO_CERT_GEN_CHECK (60 * TICKS_PER_SECOND) // Both lines are required
    // Regenerates when expired (checked every minute by default)

2. Private Certificate Authority (CA)

What It Is:** You create your own CA and sign device certificates

Visual Flow:**

Step 1: Create Your CA
┌─────────────────────┐
│ Computer with │
│ OpenSSL/CreateCerts │
│ │
│ 1. Create CA Key │
│ 2. Create CA Cert │
└─────────┬───────────┘
│
v
Step 2: Sign Device Certs
┌─────────────────────┐
│ For each device: │
│ 1. Generate Key │
│ 2. Create CSR │
│ 3. Sign with CA │
└─────────┬───────────┘
│
v
Step 3: Deploy
┌──────────────────────┬──────────────────────┐
│ Install CA Cert on │ Install Device Cert │
│ All Clients │ on Each Device │
└──────────────────────┴──────────────────────┘

When to Use:**

  • [YES] Multiple devices in controlled environment
  • [YES] Corporate/enterprise deployment
  • [YES] Need certificate management
  • [YES] Air-gapped or private networks

    Advantages:**

  • [YES] One-time CA installation for all clients
  • [YES] Central control over certificate issuance
  • [YES] Can revoke compromised certificates
  • [YES] No external dependencies

    Limitations:**

  • [NO] More complex initial setup
  • [NO] Must manually manage certificate expiration
  • [NO] CA certificate must be distributed to all clients

    NetBurner Implementation:**

Use the provided scripts in \nburn\CreateCerts\\endiskip:

# Step 1: Create your CA (one time)
cd C:\nburn\CreateCerts\ECDSA
createCA.bat
# Step 2: Create device certificate
createDeviceCert.bat mydevice.example.com
# Step 3: Convert to C++ for NetBurner
compfile device.key comp_key comp_key_len key.cpp
compfile device.crt comp_cert comp_cert_len cert.cpp
// In your application
extern const unsigned char comp_cert[];
extern const int comp_cert_len;
extern const unsigned char comp_key[];
extern const int comp_key_len;
void UserMain(void *pd) {
init();
// Install certificate before starting HTTPS
SSL_InstallCertificate(comp_cert, comp_cert_len,
comp_key, comp_key_len);
while(1) { OSTimeDly(TICKS_PER_SECOND); }
}

3. Public CA Certificates

What It Is:** Purchase certificates from trusted authorities (DigiCert, GoDaddy, etc.)

Visual Flow:**

Step 1: Generate CSR
┌──────────────────────┐
│ Device/Computer │
│ 1. Create Key │
│ 2. Generate CSR │
└──────────┬───────────┘
│
v
Step 2: Submit to CA
┌──────────────────────┐
│ Certificate Authority│
│ (DigiCert, etc.) │
│ │
│ 1. Verify Domain │
│ 2. Issue Certificate │
└──────────┬───────────┘
│
v
Step 3: Install
┌──────────────────────┐
│ NetBurner Device │
│ 1. Install Cert │
│ 2. Install Chain │
└──────────────────────┘

When to Use:**

  • [YES] Public-facing production devices
  • [YES] Need universal trust (no warnings)
  • [YES] Customer/client access
  • [YES] Professional appearance required

    Advantages:**

  • [YES] No browser warnings
  • [YES] Pre-trusted by all clients
  • [YES] Professional appearance
  • [YES] Insurance/warranty often included

    Limitations:**

  • [NO] Annual costs ($50-$500+)
  • [NO] Manual renewal process
  • [NO] Requires public DNS name
  • [NO] Validation requirements

    Process:**

  1. Generate Certificate Signing Request (CSR):
    openssl genrsa -out device.key 2048
    openssl req -new -key device.key -out device.csr
    # Enter device domain name as Common Name
  2. Submit CSR to CA and complete verification
  3. Receive certificate and chain files
  4. Combine certificate with chain:
    # Create complete chain file
    cat device.crt intermediate.crt root.crt > device_chain.crt
  5. Convert and install on NetBurner (same as Private CA method)

4. ACME (Automated Certificate Management)

What It Is:** Automated certificate issuance from Let's Encrypt or BuyPass

Visual Flow:**

┌──────────────────────────────────────────────────────┐
│ NetBurner Device with ACME │
│ │
│ ┌──────────────────────────────────────────────┐ │
│ │ 1. Request Certificate from Let's Encrypt │ │
│ └─────────────────┬────────────────────────────┘ │
│ v │
│ ┌──────────────────────────────────────────────┐ │
│ │ 2. Let's Encrypt Verifies Domain Ownership │ │
│ │ (HTTP-01 Challenge) │ │
│ └─────────────────┬────────────────────────────┘ │
│ v │
│ ┌──────────────────────────────────────────────┐ │
│ │ 3. Certificate Issued & Installed │ │
│ └─────────────────┬────────────────────────────┘ │
│ v │
│ ┌──────────────────────────────────────────────┐ │
│ │ 4. Auto-Renewal Before Expiration (90 days) │ │
│ └──────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────┘
│
v
Browser/Client
┌──────────────────────┐
│ [OK] Trusted Connect │
│ No Warnings │
└──────────────────────┘

When to Use:**

  • [YES] Production devices with public DNS
  • [YES] Need automatic renewal
  • [YES] Want trusted certs without cost
  • [YES] Device accessible from internet

    Requirements:**

  • [YES] Public DNS name pointing to device
  • [YES] Device reachable on port 80 (for validation)
  • [YES] NNDK 3.5.0 or later

    Advantages:**

  • [YES] Completely automatic
  • [YES] Free trusted certificates
  • [YES] Auto-renewal every 60 days
  • [YES] No manual certificate management

    Limitations:**

  • [NO] Requires public internet access
  • [NO] Must have DNS name (no IP-only)
  • [NO] Shorter validity (90 days vs 1 year)

    NetBurner Implementation:**

#include <acmeservlet.h>
void UserMain(void *pd) {
init();
// Configure ACME settings
AcmeConfig config;
config.domain = "iot-device.example.com";
config.email = "admin@example.com";
config.acmeServer = ACME_LETSENCRYPT_PRODUCTION;
// Start HTTPS with automatic ACME management
int result = StartAcmeHttps(config);
if (result == 0) {
printf("ACME HTTPS server started successfully\n");
printf("Certificate will auto-renew before expiration\n");
} else {
printf("ACME setup failed: %d\n", result);
}
while(1) { OSTimeDly(TICKS_PER_SECOND); }
}
void EnableSystemDiagnostics()
Turn on the diagnostic reports from the config page.

Use Case Decision Table

Scenario Recommended Method Why
Development/Testing Self-Signed Fastest, simplest
Internal corporate network, 10+ devices Private CA Central management, one-time client setup
Public website/API ACME or Public CA Trusted by all browsers
Air-gapped system Private CA or Self-Signed No external dependencies
IoT fleet with DNS names ACME Automatic, scalable, free
Single device, few users Self-Signed Adequate for small scale
Requires IP address (no DNS) Self-Signed or Private CA ACME requires DNS
Critical infrastructure Public CA Professional support, insurance

Implementation Methods

Method 1: Automatic Onboard Certificate Generation

Simplest approach - certificates generated automatically on first use.**

How It Works

First Boot / Certificate Needed
│
v
┌──────────────────────────────────┐
│ Check: Certificate exists? │
└──────┬────────────────────┬──────┘
NO YES
│ │
v v
┌──────────────────┐ ┌──────────────┐
│ Generate New │ │ Use Existing │
│ Self-Signed │ │ Certificate │
│ Certificate │ └──────────────┘
└──────────┬───────┘
│
v
┌──────────────────────────────────┐
│ Store in Non-Volatile Memory │
└──────────────────────────────────┘

Basic Implementation

#include <init.h>
const char *AppName = "Secure Device";
void UserMain(void *pd) {
init();
// Certificate automatically generated on first HTTPS connection
StartHttps(); // Default port 443
printf("HTTPS Server: %s\n", AppName);
printf("Certificate auto-generated if needed\n");
while (1) {
}
}

Advanced: Auto-Regeneration

Enable automatic regeneration when certificates expire:

// In your project's overload/nbrtos/include/predef-overload.h:
#define ENABLE_AUTOCERT_REGEN (1)
#define AUTO_CERT_GEN_CHECK (60 * 20 * TICKS_PER_SECOND) // Check every 20 minutes
// Defaults if ENABLE_AUTOCERT_REGEN is left off:
// - Certificate valid for 1 year
// - Uses SECP384R1 ECC by default
Warning
Define both macros. predef.h sets AUTO_CERT_GEN_CHECK inside its own #ifdef ENABLE_AUTOCERT_REGEN block, which is evaluated before predef-overload.h is included on the last line of predef.h. Define ENABLE_AUTOCERT_REGEN alone and the build fails on an undefined AUTO_CERT_GEN_CHECK. Do not edit the SDK's predef.h to work around this. See On-board Cert Generation - Simple and Modifying System Files with Overload.

Customizing Certificate Generation

#include <ssl.h>
// Callback for custom certificate attributes
void CustomCertCallback(SslCertAttributes_t *attrs) {
// Set custom fields
attrs->country = "US";
attrs->state = "California";
attrs->locality = "San Diego";
attrs->organization = "My Company";
attrs->commonName = "mydevice.local";
// Add alternative names
attrs->altNames = "mydevice.local,192.168.1.100,#LOCAL";
// #LOCAL = automatically use mDNS .local name
}
void UserMain(void *pd) {
init();
// Register custom certificate callback
SSL_SetCertificateCallback(CustomCertCallback);
while(1) { OSTimeDly(TICKS_PER_SECOND); }
}

Method 2: ACME Automated Certificates

Production-ready trusted certificates with automatic renewal.**

Complete ACME Example

#include <init.h>
#include <acmeservlet.h>
#include <nbrtos.h>
const char *AppName = "ACME Secure Device";
void UserMain(void *pd) {
init();
// Ensure DNS is working (critical for ACME)
printf("Device IP: %s\n", GetIP().c_str());
printf("Waiting for DNS resolution...\n");
// Configure ACME
AcmeConfig config;
config.domain = "iot-device.example.com"; // Must match DNS
config.email = "admin@example.com"; // For renewal notices
config.acmeServer = ACME_LETSENCRYPT_PRODUCTION;
config.acceptTerms = true;
// Optional: Use staging server for testing
// config.acmeServer = ACME_LETSENCRYPT_STAGING;
printf("Starting ACME certificate process for: %s\n", config.domain);
int result = StartAcmeHttps(config);
if (result == 0) {
printf("[OK] ACME HTTPS server running\n");
printf("Certificate valid for 90 days\n");
printf("Auto-renewal occurs at 60 days\n");
} else {
printf("[ERR] ACME failed with error: %d\n", result);
printf("Check: DNS resolution, firewall, port 80 access\n");
}
while (1) {
// ACME renewal happens automatically in background
}
}

ACME Troubleshooting Checklist

Prerequisites Check:
[ ] Device has public IP address
[ ] DNS A record points to device IP
[ ] Port 80 open and accessible from internet
[ ] Port 443 open for final HTTPS
[ ] NTP time synchronized (critical!)
[ ] Sufficient free memory (>50KB)
Common Issues:
[X] DNS not resolving -> Check DNS propagation (nslookup)
[X] Port 80 blocked -> Check firewall rules
[X] Challenge fails -> Verify HTTP-01 accessibility
[X] Time sync error -> Enable and wait for NTP
[X] Memory allocation fail -> Check heap usage
time_t time(time_t *pt)
Gets the current system GMT time.

Method 3: Manual Certificate Installation

For private CAs or purchased certificates.**

Step-by-Step Process

Step 1: Generate Certificate Files**

Using NetBurner CreateCerts scripts:

# Navigate to CreateCerts directory
cd C:\nburn\CreateCerts\ECDSA
# Create CA (one time, if needed)
createCA.bat
# Create device certificate
createDeviceCert.bat mydevice.example.com
# Output files:
# - device.key (private key - KEEP SECRET!)
# - device.crt (certificate)
# - ca.crt (CA certificate)

Step 2: Convert to C++ Code**

# Convert key
compfile device.key comp_key comp_key_len key.cpp
# Convert certificate
compfile device.crt comp_cert comp_cert_len cert.cpp
# Optional: Convert CA for chain
compfile ca.crt comp_ca comp_ca_len ca.cpp

Step 3: Add to Project**

YourProject/
├── src/
│ ├── main.cpp
│ ├── key.cpp <- Add these
│ ├── cert.cpp <- Add these
│ └── ca.cpp <- Optional
└── makefile

Update makefile if using command line builds:

CPP_SRC += \
src/main.cpp \
src/key.cpp \
src/cert.cpp

Step 4: Install in Code**

#include <init.h>
#include <ssl.h>
// External declarations for compiled certificates
extern const unsigned char comp_cert[];
extern const int comp_cert_len;
extern const unsigned char comp_key[];
extern const int comp_key_len;
void UserMain(void *pd)
{
init();
// Install certificate BEFORE starting HTTPS
int result = SSL_InstallCertificate(
comp_cert, comp_cert_len,
comp_key, comp_key_len
);
if (result == 0) {
printf("[OK] Certificate installed successfully\n");
} else {
printf("[ERR] Certificate installation failed: %d\n", result);
}
while (1) {
}
}

Installing Certificate Chain

For trusted certificates, install the full chain:

// Combine certificate with intermediate and root CAs
extern const unsigned char comp_device_cert[];
extern const int comp_device_cert_len;
extern const unsigned char comp_chain[];
extern const int comp_chain_len;
extern const unsigned char comp_key[];
extern const int comp_key_len;
void InstallWithChain() {
// Method 1: Combined file (preferred)
SSL_InstallCertificate(comp_chain, comp_chain_len,
comp_key, comp_key_len);
// Method 2: Separate installation
SSL_InstallCertificate(comp_device_cert, comp_device_cert_len,
comp_key, comp_key_len);
SSL_AddIntermediateCert(comp_chain, comp_chain_len);
}

Method 4: SSL Client Implementation

Connecting to secure servers with certificate validation.**

Basic SSL Client

#include <ssl.h>
#include <nettcp.h>
// CA certificate for validation
extern const char trustedCA[];
extern const int trustedCA_len;
void SecureClientConnection()
{
// Initialize SSL (once at startup)
// Add trusted CA certificates
SSL_AddCertToClientCaList(trustedCA, trustedCA_len);
// Create TCP connection
int fd = connect("api.example.com", 443);
if (fd > 0) {
// Upgrade to SSL
WOLFSSL* ssl = SSL_connect(fd);
if (ssl) {
printf("[OK] Secure connection established\n");
// Send data
const char* request = "GET / HTTP/1.1\r\n"
"Host: api.example.com\r\n"
"\r\n";
SSL_write(ssl, request, strlen(request));
// Read response
char buffer[1024];
int n = SSL_read(ssl, buffer, sizeof(buffer)-1);
if (n > 0) {
buffer[n] = '\0';
printf("Response: %s\n", buffer);
}
SSL_close(ssl);
} else {
printf("[ERR] SSL handshake failed\n");
}
close(fd);
}
}
int close(int fd)
Close the specified file descriptor and free the associated resources.

Advanced: Certificate Verification

#include <ssl.h>
// Custom verification callback
int VerifyCertCallback(int preverify_ok, WOLFSSL_X509_STORE_CTX* store) {
if (!preverify_ok) {
// Get error details
int err = X509_STORE_CTX_get_error(store);
int depth = X509_STORE_CTX_get_error_depth(store);
printf("Certificate verification failed at depth %d\n", depth);
printf("Error: %s\n", X509_verify_cert_error_string(err));
// Decide whether to accept anyway
// return 1; // Accept despite error (insecure!)
return 0; // Reject connection (secure)
}
return 1; // Accept
}
void SetupSecureClient() {
// Add CA certificates
SSL_AddCertToClientCaList(trustedCA, trustedCA_len);
// Set verification callback
SSL_SetVerifyCallback(VerifyCertCallback);
// Set verification mode
SSL_SetVerifyMode(SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT);
}

Loading CAs from Storage

#include <effs_fat.h>
#include <ssl.h>
void LoadCAsFromSD() {
F_FILE* f = f_open("ca-bundle.crt", "r");
if (f) {
// Get file size
f_seek(f, 0, SEEK_END);
long size = f_tell(f);
f_seek(f, 0, SEEK_SET);
// Read CA bundle
char* certs = new char[size + 1];
f_read(certs, 1, size, f);
certs[size] = '\0';
f_close(f);
// Add to trusted list
delete[] certs;
printf("[OK] Loaded CA certificates from SD\n");
}
}
#define f_read(buf, size, size_st, filehandle)
Read data from the current position in a file.
Definition api_f.h:526
#define f_seek(filehandle, offset, whence)
Move the stream position of an open file.
Definition api_f.h:550
#define f_close(filehandle)
Closes an opened file.
Definition api_f.h:487
#define f_open(filename, mode)
Opens a file in the file system.
Definition api_f.h:512

Troubleshooting

Common Browser Warning Messages

1. "Your Connection is Not Private"

┌────────────────────────────────────────┐
│ [!] Your connection is not private │
│ │
│ Attackers might be trying to steal │
│ your information... │
│ │
│ NET::ERR_CERT_AUTHORITY_INVALID │
└────────────────────────────────────────┘

Cause:** Certificate not signed by trusted CA

Solutions:**

  • [OK] Use ACME for automatic trusted certificates
  • [OK] Install your CA certificate on client devices
  • [OK] Purchase certificate from public CA
  • [!] For testing only: Click "Advanced" -> "Proceed (unsafe)"

2. "Certificate Name Mismatch"

┌────────────────────────────────────────┐
│ [!] Certificate doesn't match │
│ │
│ Certificate: device.example.com │
│ Accessing: 192.168.1.100 │
│ │
│ NET::ERR_CERT_COMMON_NAME_INVALID │
└────────────────────────────────────────┘

Cause:** Certificate issued for different name/IP

Solutions:**

  • [OK] Access device using correct hostname
  • [OK] Add Subject Alternative Names (SANs) to certificate
  • [OK] Use wildcard certificate (*.example.com)
  • [OK] Generate new certificate with correct CN/SAN

Example with multiple names:

void CertCallback(SslCertAttributes_t *attrs) {
attrs->commonName = "device.example.com";
attrs->altNames = "device.example.com,"
"device.local,"
"192.168.1.100,"
"10.0.0.50";
}

3. "Certificate Expired"

┌────────────────────────────────────────┐
│ [!] This certificate has expired │
│ │
│ Valid Until: Jan 15, 2025 │
│ Today: Feb 20, 2025 │
│ │
│ NET::ERR_CERT_DATE_INVALID │
└────────────────────────────────────────┘

Cause:** Certificate past expiration date

Solutions:**

  • [OK] Use ACME for automatic renewal
  • [OK] Enable auto-regeneration for self-signed certs
  • [OK] Set calendar reminders for manual renewal
  • [OK] Check device clock is synchronized (NTP)

4. "Certificate Not Yet Valid"

Cause:** Device clock incorrect or certificate future-dated

Solutions:**

#include <ntpclient.h>
void UserMain(void *pd) {
init();
// Synchronize time BEFORE SSL operations
SetNTPServer("pool.ntp.org");
EnableNTP();
// Wait for time sync
while (!NTPTimeSet()) {
}
printf("[OK] Time synchronized\n");
StartHttps(); // Now SSL will work
while(1) { OSTimeDly(TICKS_PER_SECOND); }
}

SSL Handshake Failures

Debugging Connection Issues

#include <ssl.h>
void DebugSSLConnection(const char* host, int port) {
printf("\n=== SSL Debug Info ===\n");
// 1. Test TCP connectivity
printf("Testing TCP connection to %s:%d...\n", host, port);
int fd = connect(host, port);
if (fd < 0) {
printf("[ERR] TCP connection failed\n");
return;
}
printf("[OK] TCP connected\n");
// 2. Enable SSL debugging
wolfSSL_Debugging_ON();
// 3. Attempt SSL handshake
printf("Attempting SSL handshake...\n");
WOLFSSL* ssl = SSL_connect(fd);
if (ssl) {
printf("[OK] SSL handshake successful\n");
// Get connection details
WOLFSSL_CIPHER* cipher = SSL_get_current_cipher(ssl);
printf("Cipher: %s\n", SSL_CIPHER_get_name(cipher));
printf("Protocol: %s\n", SSL_get_version(ssl));
SSL_close(ssl);
} else {
printf("[ERR] SSL handshake failed\n");
int err = SSL_get_error(ssl, -1);
printf("Error code: %d\n", err);
}
close(fd);
wolfSSL_Debugging_OFF();
}

Decrypting a Packet Capture (TLS Key Logging)

Every TLS 1.3 handshake after the ServerHello is encrypted, including the Certificate, CertificateRequest and CertificateVerify messages, and including alerts. A capture of a failing TLS connection therefore shows a ClientHello, an opaque blob, and a connection that dies. The session secrets are what make the capture readable.

Warning: for testing only.** Key logging works in release builds as well as debug builds. Anyone who can read the console can decrypt every TLS session the device makes. Never ship a product with key logging enabled.

To turn it on for one project, define NB_TLS_KEYLOG in the project copy of user_settings-overload.h:

// <project root>/overload/libraries/include/crypto/platform/user_settings-overload.h
#define NB_TLS_KEYLOG

Clean the build once after you add the file, so that the crypto library is rebuilt. See "Changing wolfSSL Settings for One Project" below. To turn it on for every project instead, uncomment // #define NB_TLS_KEYLOG in the user_settings.h file for your platform, under libraries/include/crypto/platform/.

No application code is needed. The library registers the callbacks when each TLS socket is created, so client sockets, the HTTPS server and mail are all covered, on TLS 1.2 and TLS 1.3 alike. Each session secret is printed to the console as one NSS key log line:

CLIENT_HANDSHAKE_TRAFFIC_SECRET <client random> <secret>
SERVER_HANDSHAKE_TRAFFIC_SECRET <client random> <secret>
CLIENT_TRAFFIC_SECRET_0 <client random> <secret>
SERVER_TRAFFIC_SECRET_0 <client random> <secret>

Collect the lines, save them to a file, and point Wireshark at it: Preferences, Protocols, TLS, "(Pre)-Master-Secret log filename". From the command line:

tshark -r tls.pcap -o "tls.keylog_file:/abs/path/keys.log" -Y "tls.handshake.type"

Two functions support this, both declared in crypto/ssl.h:

  • SSL_KeyLogEnabled() reports whether the library was built with key logging. An application cannot test the define itself, because application objects are not compiled with WOLFSSL_USER_SETTINGS.
  • SSL_KeyLogWrite() writes one line and is weak, so an application can send the lines to a TCP socket or flash instead of the console. Pass the line through unchanged.

Do not define SHOW_SECRETS or WOLFSSL_SSLKEYLOGFILE. Those are wolfSSL options that write to a file, and NetBurner platforms set NO_FILESYSTEM. A build with WOLFSSL_SSLKEYLOGFILE stops with an error that names NB_TLS_KEYLOG.

The board caches TLS sessions, so a second connection to the same server resumes and its handshake carries no Certificate message. Reboot between captures when you need a full handshake.

See TLS Key Logging for the whole capture and decrypt procedure.

Changing wolfSSL Settings for One Project

The wolfSSL settings for each platform are in libraries/include/crypto/platform/<PLATFORM>/user_settings.h. Editing that file changes every project. To change a setting for one project only, create this file in the project:

<project root>/overload/libraries/include/crypto/platform/user_settings-overload.h

Put in only the lines you want to change. Every platform user_settings.h includes user_settings-overload.h after all of its own settings, so your lines win. The SDK ships the file empty.

To Write
Turn on an option that is off #define WOLFSSL_SP_4096
Turn off an option that is on #undef HAVE_AESCCM
Change a value #undef WOLFSSL_TLS_SRAM_KB, then #define WOLFSSL_TLS_SRAM_KB 64
Select a switch #define CRYPTO_PROFILE_AESGCM

A switch is a NetBurner macro that changes several wolfSSL settings at once. Every switch takes effect in user_settings_switches.h, which user_settings.h includes after your file, so a switch works from your file too:

Switch Effect
CRYPTO_PROFILE_AESGCM TLS 1.3 only. Turns off TLS 1.2, DH, DES3, ChaCha20-Poly1305, Curve25519 and Ed25519.
CRYPTO_PROFILE_CHACHA TLS 1.3 only. Turns off TLS 1.2, DH and DES3.
CRYPTO_PROFILE_MINIMAL Turns off the same options as CRYPTO_PROFILE_AESGCM.
NB_TLS_KEYLOG Prints TLS session secrets to the console. For testing only.
SSL_CUSTOM_MALLOC Selects the memory region for the TLS allocator. Defined in predef.h.
ENABLE_ECC384, ENABLE_ECC521 Turn the P-384 and P-521 curves on or off. Defined in predef.h.

Define at most one crypto profile. The build stops with an error if you define more. A profile turns off its options even if your file defines one of them again.

SSL_TLS_1_3_SUPPORT also changes wolfSSL settings, but system code outside the crypto library reads it too. Change it in predef-overload.h, not in user_settings-overload.h. See Modifying System Files with Overload.

The first time you add the file, clean the build so that the crypto library is rebuilt. On the command line, run make clean, then make. In NBEclipse, select "Clean NetBurner System Library" under the project's "Build Targets", then rebuild. After that, edits to the file rebuild the right objects. NBEclipse also needs the project folder overload/libraries/include in both the C and the C++ compiler include paths, above the $(NNDK_ROOT)/ entries. The TLS Key Logging example ships the file, and an nbeclipse-rules.json that adds the include paths on import.

Common Error Codes

Error Meaning Solution
-188 ASN parse error Certificate format invalid
-173 Bad certificate Corrupted or wrong cert format
-155 No CA match Add appropriate CA to trust list
-313 Cipher suite mismatch Update wolfSSL or adjust cipher list
-101 Connection reset Network issue or server rejected

Certificate Verification Issues

Verification Flowchart

SSL Handshake Started
│
v
┌────────────────────┐
│ Verify Certificate │
└────────┬───────────┘
v
┌─────────┐
│ Trusted │ YES ┌─────────────────┐
│ CA? ├──────>│ Check Validity │
└────┬────┘ └────────┬────────┘
│ NO │
v v
┌────────┐ ┌──────────┐
│ Reject │ │ Check CN │
└────────┘ └─────┬────┘
v
┌─────────┐
│ Matches │ YES ┌─────────┐
│ Host? ├──────>│ Success │
└────┬────┘ └─────────┘
│ NO
v
┌────────┐
│ Reject │
└────────┘

Bypass Verification (Development Only!)

// [!] WARNING: This is insecure! Only for development!
void InsecureClientSetup() {
// Disable certificate verification
SSL_SetVerifyMode(SSL_VERIFY_NONE);
printf("[!] Certificate verification DISABLED\n");
printf("[!] Use only for development/testing\n");
}
// For production, always verify:
void SecureClientSetup() {
SSL_AddCertToClientCaList(trustedCA, trustedCA_len);
SSL_SetVerifyMode(SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT);
}

Memory and Resource Issues

Memory Requirements

Typical SSL Memory Usage:

Component Size
SSL Context ~8-12 KB
Certificate Chain 2-8 KB
Per Connection 40-60 KB
Crypto Operations 10-20 KB

Minimum Recommended: 128 KB free heap Comfortable: 256 KB+ free heap

Checking Memory

#include <system.h>
void CheckMemoryForSSL() {
uint32_t freeHeap = FreeRTOSMemRemaining();
uint32_t minFree = FreeRTOSMemMinEver();
printf("\n=== Memory Status ===\n");
printf("Current Free: %lu KB\n", freeHeap / 1024);
printf("Minimum Ever: %lu KB\n", minFree / 1024);
if (freeHeap < 128 * 1024) {
printf("[!] WARNING: Low memory for SSL\n");
printf(" Consider: Reducing buffer sizes\n");
printf(" Limiting connections\n");
printf(" Using lighter ciphers\n");
} else {
printf("[OK] Sufficient memory for SSL\n");
}
}

Performance Optimization

Cipher Suite Selection

#include <ssl.h>
// Faster but less secure (use only if needed)
const char* fastCiphers =
"ECDHE-ECDSA-AES128-GCM-SHA256:"
"ECDHE-RSA-AES128-GCM-SHA256";
// Balanced (recommended)
const char* balancedCiphers =
"ECDHE-ECDSA-AES256-GCM-SHA384:"
"ECDHE-ECDSA-AES128-GCM-SHA256:"
"ECDHE-RSA-AES256-GCM-SHA384";
// Maximum security (slower)
const char* secureCiphers =
"ECDHE-ECDSA-CHACHA20-POLY1305:"
"ECDHE-ECDSA-AES256-GCM-SHA384";
void ConfigureCiphers() {
SSL_SetCipherList(balancedCiphers);
printf("Cipher list configured\n");
}

Connection Reuse

// Reuse SSL context for multiple connections
WOLFSSL_CTX* ctx = nullptr;
void InitSSLContext() {
if (!ctx) {
ctx = wolfSSL_CTX_new(wolfTLSv1_2_client_method());
SSL_AddCertToClientCaList(trustedCA, trustedCA_len);
}
}
WOLFSSL* CreateConnection(const char* host, int port) {
InitSSLContext(); // Only runs once
int fd = connect(host, port);
if (fd < 0) return nullptr;
WOLFSSL* ssl = wolfSSL_new(ctx);
wolfSSL_set_fd(ssl, fd);
if (wolfSSL_connect(ssl) != SSL_SUCCESS) {
wolfSSL_free(ssl);
close(fd);
return nullptr;
}
return ssl;
}

Best Practices

Security Principles

1. Private Key Protection

┌─────────────────────────────────────────┐
│ Private Key Security Hierarchy │
├─────────────────────────────────────────┤
│ │
│ Most Secure: │
│ ├─ Hardware Security Module (HSM) │
│ ├─ Secure Enclave / TPM │
│ └─ Encrypted Storage │
│ │
│ Moderate: │
│ ├─ Compiled into firmware │
│ ├─ Flash storage with permissions │
│ └─ Protected file system │
│ │
│ Least Secure: │
│ ├─ Plain text on SD card │
│ ├─ Unprotected flash │
│ └─ Debug accessible memory │
│ │
└─────────────────────────────────────────┘

Best Practices:**

  • [YES] Never store private keys in version control
  • [YES] Use different keys for dev/test/production
  • [YES] Rotate keys periodically
  • [YES] Monitor for unauthorized access
  • [NO] Don't log private keys
  • [NO] Don't transmit private keys unencrypted
  • [NO] Don't reuse keys across devices (except CA)

2. Certificate Validation

// [X] BAD: Accepting any certificate
SSL_SetVerifyMode(SSL_VERIFY_NONE);
// [OK] GOOD: Proper validation
SSL_SetVerifyMode(SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT);
SSL_AddCertToClientCaList(trustedCA, trustedCA_len);
// [OK] BETTER: With custom verification
int VerifyCallback(int preverify, WOLFSSL_X509_STORE_CTX* store) {
// Additional checks: expiration, revocation, etc.
return preverify && CustomSecurityChecks(store);
}
SSL_SetVerifyCallback(VerifyCallback);

3. Protocol and Cipher Configuration

// [X] BAD: Allowing old protocols
SSL_SetMinVersion(SSL_3_0); // SSL is broken!
// [OK] GOOD: Modern protocols only
SSL_SetMinVersion(TLS_1_2);
// [OK] BETTER: Latest protocols
SSL_SetMinVersion(TLS_1_3);
// Configure strong cipher suites
const char* strongCiphers =
"TLS_AES_256_GCM_SHA384:" // TLS 1.3
"TLS_CHACHA20_POLY1305_SHA256:" // TLS 1.3
"ECDHE-ECDSA-AES256-GCM-SHA384:" // TLS 1.2
"ECDHE-RSA-AES256-GCM-SHA384"; // TLS 1.2
SSL_SetCipherList(strongCiphers);

Production Checklist

Pre-Deployment

[ ] Security Review:
[ ] All private keys properly protected
[ ] Certificate chain complete and valid
[ ] Strong cipher suites configured
[ ] Old protocols disabled (SSL, TLS 1.0/1.1)
[ ] Certificate validation enabled for clients
[ ] Certificate Management:
[ ] Expiration dates documented
[ ] Renewal process established
[ ] Contact information current
[ ] Backup certificates available
[ ] Monitoring Setup:
[ ] Certificate expiration alerts
[ ] Connection failure logging
[ ] Performance metrics
[ ] Security event logging
[ ] Testing Complete:
[ ] Browser compatibility verified
[ ] Client application tested
[ ] Load testing performed
[ ] Failover scenarios tested
[ ] Documentation:
[ ] Certificate inventory maintained
[ ] Configuration documented
[ ] Recovery procedures written
[ ] Contact list updated

Post-Deployment Monitoring

#include <ssl.h>
// Monitor SSL health
void MonitorSSLStatus() {
uint32_t activeConnections = SSL_GetActiveConnections();
uint32_t failedHandshakes = SSL_GetFailedHandshakes();
uint32_t certificateErrors = SSL_GetCertErrors();
printf("\n=== SSL Status ===\n");
printf("Active Connections: %lu\n", activeConnections);
printf("Failed Handshakes: %lu\n", failedHandshakes);
printf("Certificate Errors: %lu\n", certificateErrors);
// Check certificate expiration
uint32_t daysUntilExpiry = SSL_GetCertDaysRemaining();
if (daysUntilExpiry < 30) {
printf("[!] Certificate expires in %lu days!\n", daysUntilExpiry);
// Trigger renewal process
}
// Alert if too many failures
if (failedHandshakes > 100) {
printf("[!] High handshake failure rate!\n");
// Send alert to administrator
}
}

Development Workflow

Recommended Development Cycle

┌─────────────────────────────────────────┐
│ Development Stages │
├─────────────────────────────────────────┤
│ │
│ 1. Development (Local Network) │
│ └─> Self-Signed Certificates │
│ - Fast iteration │
│ - No external dependencies │
│ │
│ 2. Integration Testing │
│ └─> Private CA Certificates │
│ - Test certificate chains │
│ - Verify validation logic │
│ │
│ 3. Staging (Pre-Production) │
│ └─> ACME Staging Certs │
│ - Test automation │
│ - Verify renewal process │
│ │
│ 4. Production │
│ └─> ACME Production or Public CA │
│ - Trusted by all clients │
│ - Automatic renewal │
│ │
└─────────────────────────────────────────┘

Configuration Management

// Use preprocessor for environment-specific config
#ifdef DEVELOPMENT
// Development: Self-signed, relaxed validation
#define SSL_MODE SSL_SELF_SIGNED
#define VERIFY_MODE SSL_VERIFY_NONE
#define DEBUG_SSL 1
#elif defined(STAGING)
// Staging: Test ACME, strict validation
#define SSL_MODE SSL_ACME_STAGING
#define VERIFY_MODE SSL_VERIFY_PEER
#define DEBUG_SSL 1
#elif defined(PRODUCTION)
// Production: Full security, monitoring
#define SSL_MODE SSL_ACME_PRODUCTION
#define VERIFY_MODE SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT
#define DEBUG_SSL 0
#define ENABLE_SSL_MONITORING 1
#endif
void ConfigureSSL() {
#if SSL_MODE == SSL_SELF_SIGNED
StartHttps(); // Auto-generated cert
#elif SSL_MODE == SSL_ACME_STAGING
AcmeConfig config;
config.acmeServer = ACME_LETSENCRYPT_STAGING;
StartAcmeHttps(config);
#elif SSL_MODE == SSL_ACME_PRODUCTION
AcmeConfig config;
config.acmeServer = ACME_LETSENCRYPT_PRODUCTION;
StartAcmeHttps(config);
#endif
SSL_SetVerifyMode(VERIFY_MODE);
#if DEBUG_SSL
wolfSSL_Debugging_ON();
#endif
}

Common Pitfalls to Avoid

1. Time Synchronization

// [X] BAD: Starting SSL before time sync
void UserMain(void *pd) {
init();
StartHttps(); // Certificates may appear expired!
EnableNTP(); // Too late!
}
// [OK] GOOD: Ensure time is synced first
void UserMain(void *pd) {
init();
EnableNTP();
SetNTPServer("pool.ntp.org");
// Wait for time sync
uint32_t timeout = 0;
while (!NTPTimeSet() && timeout++ < 30) {
}
if (NTPTimeSet()) {
printf("[OK] Time synchronized\n");
StartHttps(); // Now safe
} else {
printf("[!] Time sync failed, SSL may have issues\n");
}
}

2. Certificate Chain Issues

// [X] BAD: Installing only device certificate
SSL_InstallCertificate(device_cert, device_cert_len,
device_key, device_key_len);
// Clients may not trust the certificate!
// [OK] GOOD: Installing complete chain
// Combine: device cert + intermediate CA + root CA
SSL_InstallCertificate(full_chain, full_chain_len,
device_key, device_key_len);

3. Resource Leaks

// [X] BAD: Not cleaning up
void MakeRequest() {
WOLFSSL* ssl = SSL_connect(fd);
SSL_write(ssl, data, len);
// Forgot SSL_close() and close(fd)!
}
// [OK] GOOD: Proper cleanup
void MakeRequest() {
int fd = connect(host, port);
if (fd < 0) return;
WOLFSSL* ssl = SSL_connect(fd);
if (ssl) {
SSL_write(ssl, data, len);
SSL_close(ssl); // Free SSL resources
}
close(fd); // Close socket
}

4. Hardcoded Credentials

// [X] VERY BAD: Hardcoded in source
#define CA_KEY "-----BEGIN PRIVATE KEY-----\nMIIE..."
#define DEVICE_PASSWORD "admin123"
// [OK] BETTER: Compiled externally
extern const char comp_key[];
extern const int comp_key_len;
// [OK] BEST: Retrieved from secure storage
void LoadCredentials() {
// Read from encrypted flash, secure element, etc.
ReadSecureKey(keyBuffer, sizeof(keyBuffer));
}

Additional Resources

NetBurner Examples

Located in your NNDK installation:

C:\nburn\examples\SSL\
+-- acmeservlet\ <- ACME automation
+-- SslOnboardCertGeneration\ <- Auto-generated certs
| +-- Simple\
| +-- Advanced\
| +-- CompiledCa\
+-- SslClientVerifyPeerBasic\ <- Client validation
+-- SslClientVerifyPeerEffs\ <- Loading CAs from storage
+-- CreateCerts\ <- Certificate generation scripts
+-- ECDSA\
+-- RSA\

Documentation and References

Official Documentation

Educational Resources

Books:**

Wikipedia Articles

Tools and Utilities

Certificate Management

  • OpenSSL: Included in NNDK at \Nburn\gcc\msys\1.0\bin\openssl.exe
  • NetBurner CreateCerts: Scripts in \nburn\CreateCerts\\endiskip
  • compfile: NetBurner utility to convert files to C++ arrays

Testing and Debugging

# Test SSL/TLS connection
openssl s_client -connect device.example.com:443 -showcerts
# Check certificate details
openssl x509 -in device.crt -text -noout
# Verify private key
openssl rsa -in device.key -check
# Test certificate chain
openssl verify -CAfile ca.crt device.crt

Online Testing

Quick Reference

Essential SSL Functions

// Server Setup
StartHttps(); // Auto-generated cert
StartAcmeHttps(config); // ACME automation
SSL_InstallCertificate(cert, key); // Manual install
// Client Setup
SslInit(); // Initialize SSL
SSL_AddCertToClientCaList(ca); // Add trusted CA
SSL_connect(fd); // Secure connection
SSL_SetVerifyMode(mode); // Verification level
// Certificate Management
SSL_CreateNewSelfSignedCert(); // Generate cert
SSL_GetCertDaysRemaining(); // Check expiration
SSL_SetCertificateCallback(fn); // Custom attributes
// Data Transfer
SSL_write(ssl, data, len); // Send data
SSL_read(ssl, buffer, size); // Receive data
SSL_close(ssl); // Close connection
// Debugging
wolfSSL_Debugging_ON(); // Enable debug logs
SSL_get_error(ssl, ret); // Get error code
CertGenReturnCode SSL_CreateNewSelfSignedCert(CertGenData &pGenData)
Generates a new self-signed certificate that will be stored on the device.

Configuration Constants

// Verification Modes
SSL_VERIFY_NONE // No validation (insecure!)
SSL_VERIFY_PEER // Validate peer
SSL_VERIFY_FAIL_IF_NO_PEER_CERT // Require peer cert
// Protocol Versions
SSL_3_0 // Deprecated
TLS_1_0 // Deprecated
TLS_1_1 // Deprecated
TLS_1_2 // Minimum recommended
TLS_1_3 // Latest
// ACME Servers
ACME_LETSENCRYPT_STAGING // Testing
ACME_LETSENCRYPT_PRODUCTION // Production
ACME_BUYPASS_PRODUCTION // Alternative CA
// Certificate Types
SSL_FILETYPE_PEM // Text format
SSL_FILETYPE_DER // Binary format

Recommended Approach for Most Users:**

  1. Development: Use auto-generated self-signed certificates
  2. Testing: Set up private CA for realistic testing
  3. Production: Deploy ACME if possible, otherwise use public CA

    Key Takeaways:**

  • [LOCK] Private keys are your most sensitive security asset
  • [SYNC] ACME automation eliminates manual certificate management
  • [TIME] Time synchronization is critical for SSL/TLS
  • [LINK] Complete certificate chains prevent trust issues
  • [STAT] Monitor certificate expiration and connection health