Tuesday, January 06, 2009

Creating X.509 certificates with custom extensions


Every time when I need to do something with OpenSSL, it involves searching lot of places including the library code itself to achieve my target - This time the requirement is to generate a X509 v3 certificate which contains non-standard/custom extensions. Luckily I found convincing documents early enough.

Here the task is to generate a CA certificate with standard extensions and then to create another certificate containing custom extensions and sign it with the newly created CA. The code below achieves both of the tasks.

1. To generate the ca certificate, run the script as ./genkey.sh myca ==> which generates myca.key and myca.crt
2. To generate the authentication certificate, run the script as ./genkey.sh myca mycrt ==> which generates mycrt.key and mycrt.crt and signs it with myca.key

The script is mostly self explanatory and contains an inline openssl config file - The main points to note are:
1. Extension are to be placed separately in a named section
2. Custom extension are of the form oid=DER:<DER-Encode-Hex-Values>
3. openssl command x509 should be given the extension file name and section name

#! /bin/sh
# Filename: genkey.sh

if [ $# -lt 1 ]; then
        echo "Usage: $0 ca-name [new-cert]"
        exit -1
fi


ca="$1"
new=${ca}

if [ $# -ge 2 ]; then
        new="$2"
fi

if [ -f ${new}.key ]; then
        echo "${new} already exists: Delete ${new}.key & ${new}.crt to proceed"
        exit -1
fi


#----[ inline config file ]--------------------------------------------

ca_extensions="ca_extensions"
cert_extensions="cert_extensions"

config=.${new}.config
cat > ${config} << EOF
[ req ]
default_bits           = 2048
default_keyfile        = ${new}.key
distinguished_name     = req_distinguished_name
attributes             = req_attributes
prompt                 = no

[ req_distinguished_name ]
CN                     = ${new}
OU                     = ouTest
O                      = oTest
C                      = IN

[ req_attributes ]

[ ${ca_extensions} ]
basicConstraints=critical,CA:true
subjectKeyIdentifier=hash
keyUsage=keyCertSign,cRLSign
authorityInfoAccess=OCSP;URI:http://ocsp.test.com:8080/

[ ${cert_extensions} ]
subjectKeyIdentifier=hash
keyUsage=critical,digitalSignature,keyEncipherment
certificatePolicies=1.2.276.0.76.4.64
crlDistributionPoints=URI:ldap://ocsp.test.com:389/cn=test Komponenten Testreferenz CA01
authorityInfoAccess=OCSP;URI:http://ocsp.test.com:8080/CMOCSP/OCSP
authorityKeyIdentifier=keyid
1.3.36.8.3.3=DER:\
304DA421301F310B30090603550406130244453110300E060355\
040A130767656D6174696B302830263024302230150C13416E77\
656E64756E67736B6F6E6E656B746F72300906072A8214004C0477
extendedKeyUsage=clientAuth,serverAuth

EOF


#----[ Generate key and sign ]------------------------------------------


# 1. Generate Key & CSR
openssl req -new -nodes -config ${config} > ${new}.csr


# 2. Self sign (or) Sign with CA
if [ ${new} == ${ca} ]; then
        echo "Generating self signed CA: ${ca}.crt"
        openssl x509 -extfile ${config} -extensions ${ca_extensions} \
                -sha1 -req -signkey ${ca}.key < ${new}.csr > ${new}.crt
else
        echo "Signing ${new}.crt with ${ca}.crt"
        openssl x509 -extfile ${config} -extensions ${cert_extensions} \
                -sha1 -req -CAkey ${ca}.key -CA ${ca}.crt < ${new}.csr > ${new}.crt
fi

rm ${new}.csr
rm ${config}

No comments: