CreateCert


#!/bin/sh

# Creates keys and certificates for HTTPS
# in the directory where this script resides.

# This script was written by Stephan Seidl in 2012, no copyright is claimed.
# It is offered as-is, without any warranty.
# This script is in the public domain; do with it what you wish.

unset LANG LC_ALL
LC_ALL=C
export LC_ALL

# Change working directory.
dir=`dirname ${0}`
cd "${dir}" || exit 1

# Create an OpenSSL config file.
# Stolen from `/etc/ssl/openssl.cnf' on some Debian system.
txt=""
txt="${txt}HOME=.;"
txt="${txt}RANDFILE=#ENV::HOME/.rnd;"
txt="${txt}oid_section=new_oids;"
txt="${txt}[new_oids];"
txt="${txt}[ca];"
txt="${txt}default_ca=CA_default;"
txt="${txt}[CA_default];"
txt="${txt}dir=./demoCA;"
txt="${txt}certs=#dir/certs;"
txt="${txt}crl_dir=#dir/crl;"
txt="${txt}database=#dir/index.txt;"
txt="${txt}new_certs_dir=#dir/newcerts;"
txt="${txt}certificate=#dir/cacert.pem;"
txt="${txt}serial=#dir/serial;"
txt="${txt}crlnumber=#dir/crlnumber;"
txt="${txt}crl=#dir/crl.pem;"
txt="${txt}private_key=#dir/private/cakey.pem;"
txt="${txt}RANDFILE=#dir/private/.rand;"
txt="${txt}x509_extensions=usr_cert;"
txt="${txt}name_opt=ca_default;"
txt="${txt}cert_opt=ca_default;"
txt="${txt}default_days=365;"
txt="${txt}default_crl_days=30;"
txt="${txt}default_md=sha1;"
txt="${txt}preserve=no;"
txt="${txt}policy=policy_match;"
txt="${txt}[policy_match];"
txt="${txt}countryName=match;"
txt="${txt}stateOrProvinceName=match;"
txt="${txt}organizationName=match;"
txt="${txt}organizationalUnitName=optional;"
txt="${txt}commonName=supplied;"
txt="${txt}emailAddress=optional;"
txt="${txt}[policy_anything];"
txt="${txt}countryName=optional;"
txt="${txt}stateOrProvinceName=optional;"
txt="${txt}localityName=optional;"
txt="${txt}organizationName=optional;"
txt="${txt}organizationalUnitName=optional;"
txt="${txt}commonName=supplied;"
txt="${txt}emailAddress=optional;"
txt="${txt}[req];"
txt="${txt}default_bits=1024;"
txt="${txt}default_keyfile=privkey.pem;"
txt="${txt}distinguished_name=req_distinguished_name;"
txt="${txt}attributes=req_attributes;"
txt="${txt}x509_extensions=v3_ca;"
txt="${txt}string_mask=nombstr;"
txt="${txt}[req_distinguished_name];"
txt="${txt}countryName=CountryName(2lettercode);"
txt="${txt}countryName_default=AU;"
txt="${txt}countryName_min=2;"
txt="${txt}countryName_max=2;"
txt="${txt}stateOrProvinceName=StateorProvinceName(fullname);"
txt="${txt}stateOrProvinceName_default=Some-State;"
txt="${txt}localityName=LocalityName(eg,city);"
txt="${txt}0.organizationName=OrganizationName(eg,company);"
txt="${txt}0.organizationName_default=InternetWidgitsPtyLtd;"
txt="${txt}organizationalUnitName=OrganizationalUnitName(eg,section);"
txt="${txt}commonName=CommonName(eg,YOURname);"
txt="${txt}commonName_max=64;"
txt="${txt}emailAddress=EmailAddress;"
txt="${txt}emailAddress_max=64;"
txt="${txt}[req_attributes];"
txt="${txt}challengePassword=Achallengepassword;"
txt="${txt}challengePassword_min=4;"
txt="${txt}challengePassword_max=20;"
txt="${txt}unstructuredName=Anoptionalcompanyname;"
txt="${txt}[usr_cert];"
txt="${txt}basicConstraints=CA:FALSE;"
txt="${txt}nsComment=OpenSSLGeneratedCertificate;"
txt="${txt}subjectKeyIdentifier=hash;"
txt="${txt}authorityKeyIdentifier=keyid,issuer;"
txt="${txt}[v3_req];"
txt="${txt}basicConstraints=CA:FALSE;"
txt="${txt}keyUsage=nonRepudiation,digitalSignature,keyEncipherment;"
txt="${txt}[v3_ca];"
txt="${txt}subjectKeyIdentifier=hash;"
txt="${txt}authorityKeyIdentifier=keyid:always,issuer:always;"
txt="${txt}basicConstraints=CA:true;"
txt="${txt}[crl_ext];"
txt="${txt}authorityKeyIdentifier=keyid:always,issuer:always;"
txt="${txt}[proxy_cert_ext];"
txt="${txt}basicConstraints=CA:FALSE;"
txt="${txt}nsComment=OpenSSLGeneratedCertificate;"
txt="${txt}subjectKeyIdentifier=hash;"
txt="${txt}authorityKeyIdentifier=keyid,issuer:always;"
txt="${txt}proxyCertInfo=critical,language:id-ppl-anyLanguage,pathlen:3,policy:foo;"
echo "${txt}" | tr '#;' '$\012' \
  | sed 's,countryName=match,countryName=optional,' \
  | sed 's,stateOrProvinceName=match,stateOrProvinceName=optional,' \
  | sed 's,organizationName=match,organizationName=optional,' \
  | cat > openssl.cnf

# Define some server name, node name, and email address.
servername="`hostname -f`"
while :; do
  test -e /usr/sbin/nvram || break
  test -x /usr/sbin/nvram || break
  aux=`/usr/sbin/nvram get ddns_hostname`
  test -n "${aux}" && servername="${aux}" || :
  aux=`/usr/sbin/nvram get ddns_enable`
  test -n "${aux}" && aux="ddns_hostname_${aux}" || aux="ddns_hostname"
  aux=`/usr/sbin/nvram get ${aux}`
  test -n "${aux}" && servername="${aux}" || :
  break
  done
servername=`echo "${servername}" | tr '[A-Z]' '[a-z]'`
nodename=`echo "${servername}.x" | cut -f1 -d'.'`
emailaddress="Issuer@${servername}"

# Create a self signed issuer root CA with a nonencrypted private issuer key.
# Work around a 32 bit limit.
days=`date '+%s'`
days=" 2147483647 ${days} - 86400 / 2 - p "
days=`echo "${days}" | dc 2>/dev/null`
txt=""
txt="${txt}.;"
txt="${txt}.;"
txt="${txt}.;"
txt="${txt}.;"
txt="${txt}.;"
txt="${txt}${emailaddress};"
txt="${txt}.;"
txt="${txt}.;"
txt="${txt}.;"
echo "${txt}" | tr ';' '\012' \
  | openssl req -new -x509 -newkey rsa:2048 -nodes \
    -config openssl.cnf -set_serial 0 -days ${days} \
    -out icert.pem -keyout ikey.pem 2> /dev/null

# Create a V3 server certificate request and an encrypted private server key.
txt=""
txt="${txt}.;"
txt="${txt}.;"
txt="${txt}.;"
txt="${txt}.;"
txt="${txt}.;"
txt="${txt}${servername};"
txt="${txt}.;"
txt="${txt}.;"
txt="${txt}.;"
echo "${txt}" | tr ';' '\012' \
  | openssl req -new -newkey rsa:2048 -passout pass:qwert123 \
    -config openssl.cnf -reqexts v3_req \
    -out sreq.pem -keyout sekey.pem 2> /dev/null

# Decrypt the server key.
openssl rsa -passin pass:qwert123 -in sekey.pem -out skey.pem 2> /dev/null

# Prepare some infrastructure for the ca command.
rm -fr demoCA
mkdir demoCA
mkdir demoCA/newcerts
touch demoCA/index.txt
echo "01" > demoCA/serial

# Sign the server certificate request with the self signed issuer root CA.
txt=""
txt="${txt}y;"
txt="${txt}y;"
echo "${txt}" | tr ';' '\012' \
  | openssl ca \
    -config openssl.cnf -extensions usr_cert -days ${days} -notext \
    -in sreq.pem -out scert.pem -cert icert.pem -keyfile ikey.pem 2> /dev/null

# Create the PKCS#12 files that have to be imported by the browser.
openssl pkcs12 -export -nokeys \
  -name "CA-${nodename}" -caname "CA-${nodename}" -passout pass:qwert123 \
  -in icert.pem -out icert.p12
openssl pkcs12 -export -nokeys \
  -name "UC-${nodename}" -caname "UC-${nodename}" -passout pass:qwert123 \
  -in scert.pem -out scert.p12

# Copy. Pay attention, the private issuer key is given up.
cp icert.pem  cacert.pem
cp icert.p12  cacert.p12
cp scert.pem    cert.pem
cp scert.p12    cert.p12
cp  skey.pem     key.pem
cp sekey.pem privkey.pem

# Set perms.
chmod 644 cacert.pem cacert.p12 cert.pem cert.p12
chmod 640 key.pem privkey.pem

# Clean up.
rm -fr demoCA
rm openssl.cnf
rm icert.pem icert.p12 ikey.pem
rm sreq.pem scert.pem scert.p12 sekey.pem skey.pem

# Show human-readable format.
openssl x509 -in cacert.pem -text -noout
openssl x509 -in   cert.pem -text -noout


Stephan K.H. Seidl