dev@emaze.net, 2001-06-28, openssl certs and stunnel (client/server auth), v1.1 [ 1 | Create a Certificate Authority (CA) ] [ ======================================= ] (you can skip this part if you want to sign your certificate-request by VeriSign or any other commercial and expensive CA.) (you can skip this part also if you already have a CA somewhere and dont want to use your own CA. Ask your admin...he probably already has a CA running somewhere). Create a CA key [do this only once]. $ cd /usr/local/ssl/misc $ ./CA.sh -newca -> demoCA/cacert.pem (public) and demoCA/private/cakey.pem (private). [ 2.1 | Create a SERVER private key and a certificate ] [ =================================================== ] (skip this part if you are not the first one who stunnels to the server (db2 in this example). If other people already tunnel to the server..then someone else already created a private server key for the server (db2)). for each SERVER (the database server by example (db2)): create a 'certificate request': $ ./CA.sh -newreq Attention: common name must be the host name (FQDN) ! -> newreq.pem (Attention, this file contains your private RSA key and the certificate! normally you would create a private key with: $ openssl genrsa -des3 -out privkey.pem 2048). -> privkey.key and then create a 'request' from the private key: $ openssl req -new -key privkey.pem -out newjustreq.pem -days 365 -> newjustreq.pem # the certificate request only, not the private key. ) [ 2.2 | Sign the just created Certificate with our CA ] [ =================================================== ] (skip this part if you also skipped 2.1. Someone else already created and signed the key/certificate for the server (db2).). Sign the 'certificate request' with your CA-key: (this means: send the newreq.pem file to a CA and let the CA admin sign your request. Attention: We also stored our _private_ RSA key in newreq.pem. If you use any other CA then your own one on the same computer create the 'certifiate request' with openssl and dont use the CA.sh example above). Now, lets sign the 'certificate request': $ ./CA.sh -sign # uses 'newreq.pem' as input file. # rename 'newjustreq.pem' to 'newreq.pem' if needed. - enter your CA pwd. -> newcert.pem Manually create the final .pem file: $ cat newreq.pem newcert.pem >server_db2.pem (or if you used openssl and generated a seperated privkey.pem file: $ cat privkey.pem newjustreq.pem newcert.pem >server_db2.pem) server_db2.pem will be installed on the server. It's signed by our (trusted) CA. Distribute the _public_ CA key (cacert.pem) to everyone who wants to verify the authenticity of the server where server_db2.pem is used. [ 3 | A simple stunnel example with server side authentification ] [ ============================================================== ] (Ok. Now we did a lot of stuff. Lets do some _testings_ if everything works fine _so far_ (we are not finished yet! just some testings!) You can skip this part if you dont like boring tests). (We do a test with _just_ server side authentification. If this is all what you want....apply this 'test' for realworld usage). We use stunnel to establish the secure and trusted/authenticated connection between two hosts: On the server side (db2): # stunnel -p ./server_db2.pem -d 998 -r 127.0.0.1:5432 (listen on port 998 and accept ssl connections. Forwards this connection to the localhost on port 5432 [where our database is listening].). On the client side: # stunnel -v2 -A //cacert.pem -c -d 127.0.0.1:5432 -r :995 (Now try to connect to 127.0.0.1 on port 5432 on the client side. The connection should be forwardet via the trusted/authenticated ssl tunnel to our database server (db2). Check /var/log/messages if something went wrong). [ ====== CONGRATS. You already finished the server-side auth part! ===== ] [ OK. We finally got stunnel working and use server side authentication. ] [ Now we extend our existing stunnel to do CLIENT side authenticatioin. ] [ This means that onlu clients with a specific certificate are allowed ] [ to connect to our database server (db2). ] [ ====================================================================== ] [ 4 | Starting with the clientside authentication stuff ] [ ===================================================== ] On the client side: Create a private clientkey: $ cd /usr/local/ssl/private $ openssl genrsa -des3 -out clientkey.pem 2048 create the certificate for the key: $ openssl req -new -x509 -key clientkey.pem -out clientcert.pem -days 365 (we use -x509 here. This means we dont create a certificate request but a self signed certificate. This is nice for client side authentication). (We can also combine these two commands into one: $ openssl req -x509 -newkey rsa:2048 -keyout clientkey.pem -out clientcert -days 365 ) You can distribute the clientcert.pem freely. Now copy the just created clientcert.pem file on the server (db2). (your should rename the clientcert.pem file to something like: _clientcert.pem to prevent collisions if other use the same name (clientcert.pem) for their client-certificates). Place the file 'clientcert.pem' into '/usr/local/ssl/certs/trusted' and execute: $ cd /usr/local/ssl/certs/trusted $ /usr/local/ssl/misc/c_hash clientcert.pem You will see a output similar to: 89f05566.0 => clientcert.pem Now create a sumbolic link to this file: $ ln -s clientcert.pem 89f05566.0 (Stunnel will use a 'hash' to lookup the filename. It wont work without this.). We have two files on the clientside now: clientcert.pem: Our public certificate for our key that we can distribute freely to everyone. clientkey.pem: Our _private_ (passphrase) protected client RSA key. We need to combine both files if we want to use them with stunnel on the client side: $ cat clientkey.pem clientcert.pem >clientkeycert.pem [ == NEARLY FINISHED. we have all the certs. lets get it running. == ] [ Lets start stunnel with full CLIENT and SERVER side authentication ] [ ================================================================== ] On the client side now execute: # stunnel -v2 -A //cacert.pem -p clientkeycert.pem -c \ -d 127.0.0.1:5432 -r :998 (cacert.pem is the public CA certificate of the CA that signed the SERVERs (db2) certificate. You should store this file somewhere on the clients harddrive. Ask the admin of the CA you used to sign your servers certificate for the 'cacert.pem' file). And on the server side now use: # stunnel -v3 -a /usr/local/ssl/certs/trusted/ -p ./server_db2.pem \ -d 998 -r 127.0.0.1:5432 (We dont need to specify the public clientcert here. We placed it into our trusted directory in '/usr/local/ssl/certs/trusted'. You can specify another directories with the -a option.). [ GENERAL CONFIGURATION ] [ ===================== ] - We used port 5432 in our example. I recommend to use a port <1024. This port should ONLY be accessable from the localhost (we use -d 127.0.0.1:port in all of our examples....but you should packetfilter this port even though). Keep in mind: ANYone has access to the tunnel (port 5432) from localhost [this means any local user and any programm running on the same host can connect to the database server (through the stunnel). Use password authentication also. - Private keys should remain private. Store them in well protected directories. We use password on any private key in our example. You can specify '-nodes' if you dont want to put a password on your private keys (dont do this!). In some versions of openssl you just dont use the -des3 option for no-password. If your want to remove the passphrase from a RSA key: $ openssl rsa -in privkey.pem -out privkey_withoutpassphrase.pem - The last pending question: If you just want to use clientside authentication (clientside authentication without server side authentication is a security risk!) you must specify a .pem file on the server side (-p server_db2.pem or the default stunnel.pem or some dummy.pem) and omit the -v2 option on the client side. Gimme feedback. dev@emaze.net, yet another developer.....