# Perl script to generate your own CA and some certificates.
# Platform Windows2000pro-sp3, tomcat 4.1.27, internet explorer 6, openssel.0.9.7b.
#
# I created this, from some articles and manuals, I found on the net.
# I copied a lot from this document:: http://217.31.71.131/howtoon-certificates.html, 
# and I plan to looke more the email with subject 'OpenSSLers for Social Responsibility?'
# by Charles B Cranston <zben@umd.edu>. 
#
# I still don't know, if the certificates works, with my setup, but I will test it in the
# days to follow.
#
# Currently I am using the same configfile (openssl.cnf), for all invocations of the openssl
# tool. But I can see in the email by CBC, that it is propably a good idea, to create
# severeal different configfiles, depending on, what kind of operation, you want
# to perform, with the openssl tool.
#
# I apologice, if you think this email is a spam mail - I am still learning pki/ssl/x509.
# If it contains a lot of errors, then I hope that everybody on the list (at least the
# new ones, like myself), will learn more, if and when somebody points out the bugs/mistakes.
#
# Best Regards
# Stefan Krabbe - 20030826
# email: dsl109249@vip.cybercity.dk
#
# Here follows the Perl script.

use strict; 

my $openssl = 'e:/openssl/out/openssl.exe';
my $debug = 0;
my $ca = 'e:/certs/ca';

#Create the demoCA, the directory in which to do the signing.
mkdir($ca);
mkdir($ca.'/demoCA');
mkdir($ca.'/demoCA/newcerts'); # dir containing new certificates)
mkdir($ca.'/demoCA/certs'); # certificates
mkdir($ca.'/demoCA/crl'); # revocation list
mkdir($ca.'/demoCA/private'); # contains the CA's private key if not given on cmd-line
system('echo 01 > '.$ca.'/demoCA/serial'); # text file which contains "01" only at first, certs serial number
system('touch '.$ca.'/demoCA/index.txt'); # empty text file at first, contains index of certs
# $ca.'/demoCA/cacert.pem' # contains the CA's certificate if not given on cmd-line

#Create a private key for the root CA, which we will name/call 'sktestca'.
mkdir('e:/certs/key');
system($openssl.' genrsa -out e:/certs/key/sktestca.key -des3 1024');

#Display contents of key
if($debug) {
  system($openssl.' rsa -noout -text -in e:/certs/key/sktestca.key');
}

#Derive the RSA public key
system($openssl.' rsa -pubout -in e:/certs/key/sktestca.key -out e:/certs/key/sktestca_public.key');

#Create a self-signed certificate for the sktestca root CA.
mkdir('e:/certs/crt');
system($openssl.' req -new -key e:/certs/key/sktestca.key -x509 -days 365 -out e:/certs/crt/sktestca.crt -config e:/certs/openssl.cnf');
#This creates an x509 self-signed certificate (signed using the sktestca.key private key), valid for 365 days, #in PEM format


#Make the above created PEM certificate available through the webserver!
#Create a DER equivalent:
system($openssl.' x509 -inform PEM -outform DER -in e:/certs/crt/sktestca.crt -out e:/certs/crt/sktestca.der');

#1) Create a private key for the server or the website. This may be application-specific, we will create a private key for stunnel and
#for apache. The server is called 'freja'.
#This creates an unencrypted key with 1024 bits key length. 
mkdir('e:/certs/server');
system($openssl.' genrsa -out e:/certs/server/freja.key 1024');

mkdir('e:/certs/httpd');
system($openssl.' genrsa -out e:/certs/httpd/freja.key  -des3 1024');
#Display contents of key using
#  system($openssl.' rsa -noout -text -in e:/certs/httpd/freja.key');

#2) Create a certificate signing request (CSR) for the server key(s).
#This is the request asking the Certificate Authorithy to sign the association "server public key - server Distinguished Name (DN)" using its private key.
#Decide what you want to have certified:
#- what public key
#- what's the DN information that should appear in the certificate?
#Notice that the certification routines will balk at having to recertify a CSR that has exactly the same DN as one already certified.
print("Creating csr's for httpd/freja.csr\n");
system($openssl.' req -new -key e:/certs/httpd/freja.key -out e:/certs/httpd/freja.csr -config e:/certs/openssl.cnf');
print("Creating csr's for server/freja.csr\n");
system($openssl.' req -new -key e:/certs/server/freja.key -out e:/certs/server/freja.csr -config e:/certs/openssl.cnf');

if($debug) {
  #To check the request's contents:
  system($openssl.' req -noout -text -in e:/certs/httpd/freja.csr');
  system($openssl.' req -noout -text -in e:/certs/server/freja.csr');
  #...the request is of course NOT encrypted in any way
  #The command needs the earlier generated server private key so that a signature proving you have the private key of the public key you want to have
  #signed can be added to the CSR. If you private key was encrypted, you are asked for the password to it.
  #The request contains the server public key + DN information to be certified and a signature, obtained using the private key associated to the public key.
  #There is also a 'challenge password' (probably for exchange betweenreq -verify -in e:/certs/httpd/freja.csr CA and certification requestor)
  #To verify the signature on a request:
  #system($openssl.' req -verify -in e:/certs/httpd/freja.csr');
  #system($openssl.' req -verify -in e:/certs/server/freja.csr');
  #This should work as follows: take the signature of the csr, decrypt it using the public key in the csr, then match the hashvalue thus obtained
  #to the hashvalue of the public key in the csr. If these match, the requestor indeed owns the private key to the public key to be signed.
  #Make your own copy /usr/share/ssl/openssl.cnf for parametrization.
  #
  #At this point, the signing request is sent to the root CA, which would probably call up the requestor to 'know your customer'.
}

#After that, the root CA will sign the request. Which is what we do now:

#3) Sign the certificate signing request yielding a valid certificatereq -verify -in e:/certs/httpd/freja.csr, using the root CA created earlier.
chdir('e:/certs/ca');
system($openssl.' ca -in e:/certs/server/freja.csr -cert e:/certs/crt/sktestca.crt -keyfile e:/certs/key/sktestca.key -days 360 -extensions v3_ca -config e:/certs/openssl.cnf');
system($openssl.' ca -in e:/certs/httpd/freja.csr  -cert e:/certs/crt/sktestca.crt -keyfile e:/certs/key/sktestca.key -days 360 -config e:/certs/openssl.cnf');
#openssl x509 -text -in e:/certs/crt/sktestca.crt

#4) Copy the freja (signed) certificate to its final destination:
system('copy e:\certs\ca\demoCA\newcerts\01.pem e:\certs\server\freja-cert.pem');
system('copy e:\certs\ca\demoCA\newcerts\02.pem e:\certs\httpd\freja-cert.pem');
#Make the files available to Apache SSL
#1) Apache has to know where it should get the server's private key from:
#SSLCertificateKeyFile e:/certs/httpd/freja.key
#
#2) Apache has to know where it should get the server's signed certificate from:
#SSLCertificateFile e:/certs/httpd/freja-cert.pem


#1) Create a private key for a client (called hydrogen) This key must NOT be encrypted (at least for stunnel 4.03):
system($openssl.' genrsa -out e:/certs/client/hydrogen.key 1024');
#2) Create a Certificate Signing Request:
system($openssl.' req -new -key e:/certs/client/hydrogen.key -out e:/certs/client/hydrogen.csr -config e:/certs/openssl.cnf');
#3) Sign the Certificate using the Stunnel Server's (freja) Key:
chdir('e:/certs/ca');
system($openssl.' ca -in e:/certs/client/hydrogen.csr -cert e:/certs/server/freja-cert.pem -keyfile e:/certs/server/freja.key -days 350 -extensions v3_ca -config e:/certs/openssl.cnf');
system('copy e:\certs\ca\demoCA\newcerts\03.pem e:\certs\client\hydrogen-cert.pem');

