What Are Ports and Why Forward Them? TCP/IP applications tell hosts apart via IP addresses: each computer or device on a TCP/IP
Chapter 5. Tunneling
5.1 Stunnel and OpenSSL: Concepts
5.1.1.2 How to become a small-time CA
Anybody can create their own Certificate Authority using OpenSSL on their platform of choice: it compiles and runs not only on Linux and other Unices, but also on Windows, VMS, and other operating systems. All examples in this chapter will, of course, show OpenSSL running on Linux. Also, given the importance and sensitivity of CA activities, you should be logged in as root when performing CA functions, and all CA files and directories should be owned by root and set to mode 0600 or 0700.
First, install OpenSSL as described earlier under "OpenSSL." In OpenSSL's home directory (e.g.,
/usr/local/ssl), you'll find a directory named misc/ that contains several scripts. One of them, CA, can be used to automatically set up a CA directory hierarchy complete with index files and a CA certificate (and key). Depending on which version of OpenSSL you have, CA may be provided as a shell script (CA.sh), a Perl script (CA.pl), or both.
Before you use it, however, you should tweak both it and the file openssl.cnf (located at the root of your OpenSSL home directory) to reflect your needs and environment. First, in CA.sh, edit the variables at the beginning of the script as you see fit. One noteworthy variable is DAYS, which sets the default lifetime of new certificates. I usually leave this to its default value of -days 365, but your needs may differ. One variable that I always change, however, is CA_TOP, which sets the name of new CA directory trees. By default, this is set to ./demoCA, but I prefer to name mine ./localCA or simply ./CA. The leading ./ is handy: it causes the script to create the new CA with your working directory as its root. There's nothing to stop you from making this an absolute path, though: you'll just need to change the script if you want to run it again to create another CA; otherwise, you'll copy over older CAs. (Multiple CAs can be created on the same host, each with its own directory tree.)
In openssl.cnf, there are still more variables to set, which determine default settings for your certificates (Example 5-1). These are less important — since most of them may be changed when you actually create certificates — but one in particular, default_bits, is most easily changed in openssl.cnf. This setting determines the strength of your certificate's key, which is used to sign other certificates, and in the case of SSL clients and servers (but not of CAs), to negotiate SSL session keys and authenticate SSL sessions. By default, default_bits is set to 1024. Recent advances in the factoring of large numbers have made 2048 a safer choice, though computationally expensive (but only during certificate actions such as generating, signing, and verifying signatures, and during SSL session startup — it has no effect on the speed of actual data transfers). The CA script reads openssl.cnf, so if you want your CA certificate to be stronger or weaker than 1024 bits, change openssl.cnf before running CA.pl or CA.sh (see Example 5-1).
Example 5-1. Changed lines from a sample openssl.cnf file
# these are the only important lines in this sample... dir = ./CA
default_bits = 2048
# ...changing these saves typing when generating new certificates countryName_default = ES
stateOrProvinceName_default = Andalucia localityName_default = Sevilla
0.organizationName_default = Mesòn Milwaukee organizationalUnitName_default =
commonName_default = emailAddress_default =
# I don't use unstructuredName, so I comment it out: # unstructuredName = An optional company name
Now, change your working directory to the one in which you wish to locate your CA hierarchy. Popular choices are /root and the OpenSSL home directory itself, which again is often /usr/local/ssl. From this directory, run one of the following commands:
[root ssl]# /usr/local/ssl/misc/CA.pl -newca or:
[root ssl]# /usr/local/ssl/misc/CA.sh -newca
In either case, replace /usr/local/ssl with your OpenSSL home directory if different. The script will prompt you for an existing CA certificate to use (Example 5-2); simply press Return to generate a new one. You’ll next be prompted for a passphrase for your new CA key. This passphrase is extremely important: anyone who knows this and has access to your CA key can sign certificates that are verifiably valid for your domain. Choose as long and complex a passphrase as is feasible for you. Whitespace and punctuation marks are allowed.
Example 5-2. A CA.pl session
[root@tamarin ssl]# /usr/local/ssl/misc/CA.pl -newca CA certificate filename (or enter to create)
Making CA certificate ...
Using configuration from /usr/local/ssl/openssl.cnf Generating a 2048 bit RSA private key
...++++++ ....++++++
writing new private key to './CA/private/cakey.pem' Enter PEM pass phrase: *************
Verifying password - Enter PEM pass phrase: ************* ---
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
For some fields there will be a default value, If you enter ’.’, the field will be left blank. ---
Country Name (2 letter code) [ES]:
State or Province Name (full name) [Andalucia]: Locality Name (eg, city) [Sevilla]:
Organization Name (eg, company) [Mesòn Milwaukee]: Organizational Unit Name (eg, section) [ ]:
Common Name (eg, YOUR name) [ ]:Mick’s Certificate Authority Email Address [ ]:[email protected]
By default, the CA.pl and CA.sh scripts create a CA certificate called cacert.pem in the root of the CA filesystem hierarchy (e.g., /usr/local/ssl/CA/cacert.pem) and a CA key called cakey.pem in the CA
filesystem’s private/ directory (e.g., /usr/local/ssl/CA/private/cakey.pem). The CA certificate must be copied to any host that will verify certificates signed by your CA, but make sure the CA key is never copied out of private/ and is owned and readable only by root.
Now you’re ready to create and sign your own certificates. Technically, any host running OpenSSL may generate certificates, regardless of whether it’s a CA. In practice, however, the CA is the logical place to do this, since you won’t have to worry about the integrity of certificates created elsewhere and transmitted over potentially untrustworthy bandwidth. In other words, it’s a lot easier to feel good about signing a locally generated certificate than about signing one that was emailed to the CA over the Internet.
For Stunnel use, you’ll need certificates for each host that will act as a server. If you plan to use SSL client- certificate authentication, you’ll also need a certificate for each client system. Stunnel supports two types of client-certificate authentication: you can restrict connections to clients with certificates signed by a trusted CA, or you can allow only certificates of which the server has a local copy. Either type of authentication uses the same type of client certificate.
There’s usually no difference between server certificates and client certificates. The exception is that server certificates must have unencrypted (i.e., non-password-protected) keys since they’re used by automated processes, whereas it’s often desirable to encrypt (password-protect) client certificates. If a client certificate’s key is encrypted with a strong passphrase, the risk of that key’s being copied or stolen is mitigated to a modest degree.
On the other hand, if you think the application you’ll be tunneling through Stunnel has adequate authentication controls of its own, or if the client Stunnel process will be used by an automated process, unencrypted client keys may be justified. Just remember that any time you create client certificates without passphrases, their usefulness in authenticating users is practically nil.
Before you start generating host certificates, copy the openssl.cnf file from the OpenSSL home directory to your CA directory, and optionally edit it to reflect any differences between your CA certificate and subsequent certificates (e.g., you may have set default_bits to 2048 for your CA certificate but wish to use 1024-bit certificates for server or client certificates). At the very least, I recommend you set the variable dir in this copy of openssl.cnf to the absolute path of the CA, e.g. /usr/local/ssl/CA. 5.1.1.3 Generating and signing certificates
Now let’s generate a certificate. We’ll start with a server certificate for an Stunnel server named "elfiero": 1. Change your working directory to the CA directory you created earlier — e.g., /usr/local/ssl/CA. 2. Create a new signing request (which is actually a certificate) and key with this command: 3. bash-# openssl req -nodes -new -keyout elfiero_key.pem \
-out elfiero_req.pem -days 365 -config ./openssl.cnf The -nodes flag specifies that the new certificate should be unencrypted. Automated processes will be using it, so it isn't feasible to encrypt it with a password that must be entered every time it's used. -keyout specifies what name you want the new key to be, and -out specifies a name for the new request/certificate. (The filenames passed to both -keyout and -out are both arbitrary: you can name them whatever you like.) -days specifies how many days the certificate will be valid, and it's
optional since it’s also set in openssl.cnf. Another flag you can include is -newkey rsa:[bits], where [bits] is the size of the new certificate’s RSA key — e.g., 1024 or 2048.
After you enter this command, you will be prompted to enter new values or accept default values for the certificate's "Distinguished Name" parameters (CountryName, LocalityName, etc.), as in Example 5-2. Note that each certificate's Distinguished Name must be unique: if you try to create a certificate with all the DN parameters the same as those of a previous certificate created by your CA, the action will fail with an error. Only one DN field must differ from certificate to certificate, however; the fields I tend to change are EmailAddress or Organizational Unit Name.
4. Now, sign the certificate with this command:
5. bash-# openssl ca -config ./openssl.cnf -policy policy_anything \
-out elfiero_pubcert.pem -infiles elfiero_req.pem Again, you can call the output file specified by -out anything you want. After entering this command, you'll be prompted for the CA key's passphrase, and after you enter this, you'll be presented with the new certificate's details and asked to verify your intention to sign it.
If you skipped to this procedure from Section 7.4.9 (i.e., you're creating this certificate for an SMTP server, not an Stunnel server), you're done: copy your new CA certificate, server key, and signed server certificate over to your SMTP server, and return to where you left off in Chapter 7. Otherwise, proceed to Step 4.
4. Open the new key (e.g., elfiero_key.pem) in a text editor, add a blank line to the bottom of the file, and save it.
This step isn't strictly necessary for recent versions of Stunnel, which isn't as fussy about certificate file formatting as it used to be, but I still add the blank line, since it's one less thing that can cause problems (e.g., in case the local Stunnel build is older than I thought).
5. Open the new signed certificate (e.g., elfiero_pubcert.pem) and delete everything above but not including the line ---BEGIN CERTIFICATE---. Add a blank line to the bottom of the file and save it. Again, the blank line may not be necessary, but it doesn't hurt.
6. Concatenate the key and the signed certificate into a single file, like this:
bash-# cat ./elfiero_key.pem ./elfiero_pubcert.pem > ./elfiero_cert.pem
That's it! You now have a signed public certificate you can share, named elfiero_pubcert.pem, and a combined certificate and key named elfiero_cert.pem that you can use as elfiero's Stunnel server certificate. 5.1.1.4 Client certificates
Creating certificates for Stunnel client systems, which again is optional, is no different than creating server certificates. Omit the -nodes flag in Step 2 if you wish to password-protect your client certificate's key. Unfortunately, doing so buys you little security when using Stunnel. Although you'll need to enter the correct passphrase to start an Stunnel client daemon using a password-protected certificate, after the daemon starts, any local user on your client machine can use the resulting tunnel.[1] (Authentication required by the application being tunneled, however, will still apply.)
[1] Iptables has a new match-module, owner, that can help restrict local users’ access to local
network daemons. If your Stunnel client machine’s kernel has Iptables support, you can add rules to its INPUT and OUTPUT chains that restrict access to Stunnel’s local listening port (e.g., localhost:ssync) to a specific Group ID or User ID via the Iptables options — gid-owner and — uid-owner, respectively. However, the owner module, which provides these options, is still experimental and must be enabled in a custom kernel build. This module’s name is ipt_owner.o,
"Owner Match Support (EXPERIMENTAL)" in the kernel-configuration script. Linux in a Nutshell by Siever et al (O’Reilly) includes documentation on Iptables in general and the owner match module specifically.
In other SSL client-certificate scenarios (e.g., HTTPS), you really ought to password-protect any certificate that will not be used by an automated process. In other words, when certificates will be used by human beings, especially by human beings logged on to shared systems, these should usually not be generated with OpenSSL’s -nodes flag unless you have carefully considered the security
ramifications and mitigated the risks associated with these client keys — e.g., with an application-layer authentication mechanism.
From an Stunnel server's perspective, the client certificate effectively authenticates the Stunnel client system and not the tunneled application's users per se. This is true of any server application that accepts connections involving either certificates with unprotected keys or shared client daemons.