This is an old revision of the document!
This HOWTO takes you through all the steps needed to create:
It then shows you how to distribute these, and install them in FreshTomato NVRAM. The setup was done on an r2025.3 build, but should work fine on releases r2023 and later.
The steps involved in creating the Local Certificate Authority, Certificates and Signing Request can be run only on Linux. If your main computing device isn't running Linux, it is recommended that you create a Live, bootable Linux USB flash drive on which to perform these tasks. This media should be configured with persistent storage. The FreshTomato team may attempt to find ways to allow all these tasks to be done directly in FreshTomato.
Each step is preceded above it by an explanation of what it does. If you just want to create the configuration without reading what each step does, simply download the script at the bottom of this page, and run it.
Thanks to Tomato forum user “ikunat33” for writing the original text.
Before this was written, the author fell victim to a suspected Man-in-the-Middle attack. He had a device that only connected if WPA was disabled. In order to test that device, he enabled open WiFi. However, a distraction caused him to leave the open WiFi enabled. He failed to notice what happened in time to prevent problems. The author later realized the attacker would likely not have gained access to his router if he'd used SSL certificates and set up HTTPS. This led him to use SSL.
The author also decided to switch to the WPA2 Enterprise protocol, which requires a Radius server with value pairs with EAP-TLS. As well, the author uses MySQL and Cacti for monitoring a family member's blood sugar. All these technologies can incorporate SSL certificates to improve network security and thus mitigate, or even stop MTM attacks. Even more so when using MTLS.
The author soon realized that having his own Certificate Authority (CA) would allow him to install the single root CA cert in his browser, and in doing so, the browser would recognize any site using one of the CA signed certs as trusted.
In the context of this tutorial, and the requirements of this setup, the CA is passive and doesn't directly interact with anything.
To be authenticated, certificates don't need an active connection to the issuing CA. Your browser, however, does need to authenticate the certificate on the site you are trying to access. This is done by either:
In this case, the Intermediate CA certificate (the certificate of our CA) will be imported to our browser. Having the Intermediate CA certificate in our browser will allow us to access any website using a certificate signed by the intermediate CA, without having to export it from the site, verify it, and import it into our browser.
In cases when a CA is signing certificates for many different users/sites, you can also set up the CA to use Certificate Revocation Lists. However, revocation lists must be manually distributed and installed to the browsers or other applications that need them.
One alternative is to use Online Certificate Status Protocol, in which certificates distributed by the CA include an OCSP server address. When an application accesses a site whose certificate has an OCSP address, the application sends a request to that address for the status of that certificate. If the certificate was revoked, the application won't access the site. This is discussed more thoroughly in Jamie Nguyen's “OpenSSL Certificate Authority”.
Begin by opening a terminal window, about two inches wide and vertical. Move it to one side of the screen. Right click its window title and choose “always on top”.
Run an interactive login shell with root privileges allowing you to run multiple commands in a row as root:
sudo -i
Make the tree command run repeatedly at regular intervals, and display in colour:
watch tree -C /root/
Open a second terminal window, and position it so you can see both terminal windows clearly (as well as this HOWTO).
Open an interactive root login shell to provide root privileges for more than one typed command:
sudo -i
Change to the /root directory:
cd /root
Now, create a directory structure for the CA (including the 5 directory names separated by commas):
mkdir -p ca/{certs,crl,newcerts,private,csr}
Change permission on the “private” directory so only you, not your group or others have access:
chmod 700 ca/private
Create the “index.txt” file that OpenSSL will use as the Certificate Database:
touch ca/index.txt
Run the echo command to output the text “1000”, use the “>” operator to redirect the output into file: “/ca/serial”:
echo 1000 > ca/serial
Change to the “/root/ca” directory:
cd /root/ca
Run the nano text editor and make it open the “openssl.cnf” file:
nano /root/ca/openssl.cnf
Generate the root Authority 4096-bit RSA Private Key, encrypt it with a passphrase using AES256 encryption and output it to file: “/private/ca.key.pem”:
openssl genrsa -aes256 -out private/ca.key.pem 4096
Change permissions on the “ca.key.pem” file to read only, not your group and not others:
chmod 400 private/ca.key.pem
W A R N I N G: when prompted during creation of a signing request, enter a CN matching the hostname of the system on which the the cert will be used.
Run the cert request utility using config. file: “/root/ca/openssl.cnf”, and the key in “/ca/key.pem” to create a new x509 certificate valid for 20 years. Encrypt it with an SHA256 password, use v3_ca extensions defined in openssl.cfg and name the certificate in “certs/ca.cert.pem”:
openssl req -config /root/ca/openssl.cnf -key private/ca.key.pem -new -x509 -days 7300 -sha256 -extensions v3_ca -out certs/ca.cert.pem
Change permissions on the “ca.cert.pem” file to read-only, and make it readable by everyone. Any browser with it installed will recognize valid certificates signed by the CA key as trusted:
chmod 444 certs/ca.cert.pem
Display the certificate text on the screen so you can inspect it for errors:
openssl x509 -noout -text -in certs/ca.cert.pem
Create a directory named: “intermediate”, and inside it, subdirectories named: “certs”, “crl”, “newcerts”, “private”, “csr” and “client keys”:
mkdir -p intermediate/{certs,crl,newcerts,private,csr,client_keys}
Change directories to “intermediate”:
cd intermediate
Set full permissions on the “private” directory for the user only:
chmod 700 private
Create a file: “index.txt” which will serve as the CA database. This plain text file records every certificate the CA has issued, including its status, expiration date, revocation date if applicable, serial number, and certificate subject. Each line corresponds to one certificate and helps the CA keep track of certificates it has issued and their current status:
touch index.txt
Generate the word “1000” and redirect the output to the “serial” file:
echo 1000 > serial
Print the words “1000” to the file: “crlnumber”:
echo 1000 > crlnumber
Run the nano editor and open the “openssl.cnf” file:
nano /root/ca/intermediate/openssl.cnf
After the file opens, you must copy the contents of the “IntermediateCA.openssl.cnf” file on this wiki page and paste it into the “openssl.cnf” file and save it.
Generate a new RSA private key, 4096 bits long and encrypted with AES-256, and output it to file: “private/intermediate.key.pem”:
openssl genrsa -aes256 \-out private/intermediate.key.pem 4096
Change the permissions on the “intermediate.key.pem” file to read for the user and no access for groups or others:
chmod 400 private/intermediate.key.pem
Create a certifcate signing request for the intermediate CA, using settings in the “openssl.cnf” file, generate an SHA256 hash of the key so the CA signing the certificate can verify the integrity of the received key, and save the request to the: “csr” directory of the root CA:
openssl req -config /root/ca/intermediate/openssl.cnf \ -new -sha256 -key private/intermediate.key.pem \ -out /root/ca/csr/intermediate.csr.pem
\\ \\ \\
Change to the: “/root/ca” directory:
cd /root/ca
Run the configure routine on the “opensslf.cnf” configuration file, telling openssl to act as the CA. Prevent readable data being displayed on the screen. Tell openssh to encrypt with SHA256. Use the certificate signing request created in the previous step above and return the signed certificate to the intermediate CA certs folder:
openssl ca -config /root/ca/openssl.cnf -extensions v3_intermediate_ca -days 3650 -notext -md sha256 -in csr/intermediate.csr.pem -out intermediate/certs/intermediate.cert.pem
Change to the “intermediate” directory:
cd intermediate
Change permissions on the: “intermediate.cert.pem” file to read-only for the owner, group and others:
chmod 444 certs/intermediate.cert.pem
Run the OpenSSL tool to generate an X.509 certificate, using file: “/certs/intermediate.cert.pem” for input. Prevent output of the encoded version of the certificate, so no raw cert data is printed. Display the certificate in human-readable format:
openssl x509 -noout -text -in certs/intermediate.cert.pem
Perform a verification using the “ca.cert.pem” file to check the chain of trust and ensure ensure everything is correct:
openssl verify -CAfile /root/ca/certs/ca.cert.pem certs/intermediate.cert.pem
Use the concatenate command to combine the root and intermediate certificates, in ascending order of trust, into one file:
cat certs/intermediate.cert.pem /root/ca/certs/ca.cert.pem > certs/ca-chain.cert.pem
Change permissions on the “chain.cert.pem” file to read-only for the user, group and others:
chmod 444 certs/ca-chain.cert.pem
CONSTRUCTION
OF THE
CERTIFICATE AUTHORTY
IS NOW COMPLETE
Change to the “/root/ca/intermediate” directory:
cd /root/ca/intermediate
Run the openssl tool and, using Prime256v1 elliptical curve cryptography, generate a private key. Output the private key to file: “/client_keys/FT.key.pem”. (EC cryptography is a good compromise between high security and key length-important for FreshTomato:
openssl ecparam -out client_keys/FT.key.pem -name prime256v1 -genkey
(Modify these commands to match your own openssl.cnf files on your CA).
Run the OpenSSL cert signing request function. Using the private key in file “FT.key.pem”, sign the new certificate signing request with the SHA256 algorithm. Save the output in file: “/csr/FT.cert.csr.pem”. Use the following subject Distinguished Name settings for the signing request:
Add an X.509 extension to the CSR to specify Subject Alternative Names (SANs). This will define additional identities for the certificate:
openssl req -key client_keys/FT.key.pem -new -sha256 -out csr/FT.cert.csr.pem -subj “/C=FI/ST=Ohio/L=Timbucktwo/O=Section 8/OU=Section 8 IT/CN=FT_Router_Sane” -addext “subjectAltName=IP:192.168.1.1,DNS:sane,DNS:sane.nuts”
Now, verify your certificate signing request has all the correct information. (If not, repeat the process):
openssl req -noout -text -in csr/FT.cert.csr.pem
Run the OpenSSL CA utility and sign the CSR in file: “/csr/Ft/cert.csr.pem”, using settings in the CA setup file: “openssl.cnf” and applying the certificate extensions in: “server_cert”. Set the validity period of the cert to 375 days and include only a PEM version cert (no ASCII version) in the output file. Use SHA-256 as the hash algorithm during signing. Output the result to the newly-signed certificate to file: “/newcerts/Ft.cert.pem”. Exit the script/terminal session.
openssl ca -config openssl.cnf -extensions server_cert -days 375 -notext -md sha256 -in csr/FT.cert.csr.pem -out newcerts/FT.cert.pem exit
(This is done with root credentials because the certificates must be installed in FreshTomato. Using root access helps avoid unsecured steps in between).
Change to the: “/root” directory:
cd /root
Generate a public and private SSH key pair using the Ed25519 hashing algorithm. Add a comment containing a default email address to the key:
ssh-keygen -t ed25519 -C “your_email@example.com”
Display the contents of the public SSH key file: “/root/.ssh/id_ed25519.pub”:
cat /root/.ssh/id_ed25519.pub
(The contents should look similar to: “ssh-ed25519 AAA….Oo your_email@example.com” copy the whole thing)
Now, connect to the router's web interface and go to the Admin Access menu. In the SSH Server section, paste the output copied from the previous step in the “Authorized keys” section).
Uncheck:
Now, check:
Finally, click “Start Now” to restart the SSH server.
Using the secure copy command (and legacy protocol), copy the: “FT.key.pem” file and the: ““FT.cert.pem” file from the Intermediate CA to the root user FreshTomato home directory (whose default name is assumed to be: “FT”)
scp -O /root/ca/intermediate/client_keys/FT.key.pem /root/ca/intermediate/newcerts/FT.cert.pem root@FT
Run the SSH command to connect via SSH to the root account on the host router named: “FT”:
ssh root@FT
Rename the file: “FT.key.pem” file to: “key.pem”:
mv FT.key.pem key.pem
Rename the file: “FT.key.pem” to cert.pem:
mv FT.cert.pem cert.pem
Concatenate the contents of the “key.pem” and “cert.pem” files and write the combined content into new file: ”/etc/server.pem“:
cat key.pem cert.pem > /etc/server.pem
Copy the ”./cert.pem“ file to the ”/etc“ directory:
cp ./cert.pem /etc/cert.pem
Copy the ”./key.pem“ file to the ”/etc“ directory:
cp ./key.pem /etc/key.pem
Run the stream text editor tool and make it open the “cert.pem” file in place, overwriting any changes and cutting off content after the words: “END CERTIFICATE”:
sed -i ”/END CERTIFICATE/q“ /etc/cert.pem
Run the tar command and compress the “cert.pem” and “key.pem files into the ”/tmp/cert.tar” file, preserving all /path/ information)
/bin/tar -C / -cf /tmp/cert.tar etc/cert.pem etc/key.pem
Run the gzip archive tool to further compress the “cert.tar” file (making it into a “tar.gzip” file):
/bin/gzip -f /tmp/cert.tar
Encode the “/tmp/cert.tar.gz” tarball archive of SSL certificate files, encode it in base64 using OpenSSL, remove any newline characters from the encoded string, and then set this base64-encoded string as the value of the “https_crt_file” variable in NVRAM.
nvram set https_crt_file=“$(/usr/sbin/openssl enc -base64 < /tmp/cert.tar.gz | tr -d '\n')”
Commit all the changes to NVRAM:
nvram commit
Finally, restart the HTTP daemon:
service httpd restart
The “intermediate.cert.pem” file is now ready to be imported into your browser. The author uses Brave, in which you can import the file via “Trusted certificates”, (not “Intermediate certificates”).
The process is now complete. Now, you should be able to access your FreshTomato web interface using the custom certificates you created with your own CA. If something isn't working, review all steps and double-check that they were properly completed.
Download the two configuration files needed to create the Custom Certificate Authority here:
The OpenSSL ccparam subcommand doesn't directly support adding a password to a key. However, it can be piped back through OpenSSL to give it an extra layer of protection. For example, typing:
openssl ecparam -genkey -name prime256v1 | openssl ec -aes256 -out yourkey.pem
Since r2025.3, FreshTomato doesn't require the CN to match the Hostname. The following steps will allow you test your setup to verify this. However, please note that testing this could cause FreshTomato to overwrite your custom cert. If it does happens, just upload your certificate again and SSH will still function fine.