eToken and openssl PKI

Introduction

This is a draft how a small PKI - in fact a single CA - could be easily implemented unsing openssl. This CA will be able to enroll server certificates, client certificates and also enroll Aladdin eToken with the keypair generated on the eToken. CRLs will be generated and pushed to the certificate distribution point.

It can and should be easily enhanced.

It was originally based on easy-rsa of openvpn but the interface was changed from the pkitool thing and multiple scripts to a single Makefile and openssl.cnf.

the Makefile

The Makefile is the central user interface for all tasks of the CA. It gives you roughly the following possibilities:

Usage:
-------------
make initca
                        Initialize CA

make gencrl [ldap=1]
                        generate CRL
                        if ldap=1 is given, the CRL will also be published in LDAP

make req ext=<extensions> name=<name>
                        generate a request

make sign csr=csr-file ext=<extensions>
                        sign a certificate request

make etoken name=<name> size=<key size> id=<Key ID> label=<Key label>
                        enroll an etoken for a user

make extensions
                        lists the available extensions

make revoke cert=crt-file
                        revoke a certificate

make listcerts
                        lists all issued certificates

make validcerts
                        lists all valid certificates

make listrevoked
                        lists all revoked certificates

make publishcert cn=<user> cert=<certificate serial>
                        publish certificate in LDAP
                        ex: make publish cert cn=koelbel cert=25

Initializing the CA

You first need to adapt the variables in the Makefile and maybe openssl.cnf to your needs.

Then you need to issue:

make initca 

which will generate your self signed CA certificate and setup the directory structure.

Enrolling server certificates

You need to enroll the certificate in two steps. First you create the request:

make req ext=server name=www.etokenonlinux.org 

The request will be stored in your data directory in the file www.etokenonlinux.org.req.

Then you sign the request. Thus you can also sign requests that were generated somewhere else:

make sign csr=www.etokenonlinux.org ext=server

Enrolling eToken

For enrolling Aladdin eToken you need to install the Aladdin pkcs11 library. Then you can enroll an eToken by typing

make etoken name=userToken size=2048 id=23 label=userKey

Certificate Distribution Points

The CRLs will be published to the certificate distribution point which can be configured in the Makefile in the variable CRL_REMOTE_DEST. It is of the format user@host-fqdn:/path. You can use this to upload it to your web server.

Downloads

openssl.cnf Makefile ldap.template

Files

openssl.cnf

   1 HOME                    = .
   2 RANDFILE                = $ENV::HOME/.rnd
   3 oid_section             = new_oids
   4 openssl_conf            = openssl_init
   5 
   6 [ new_oids ]
   7 
   8 [ openssl_init ]
   9 engines = engine_list
  10 
  11 [ engine_list ]
  12 pkcs11 = engine_pkcs11
  13 
  14 [ engine_pkcs11 ]
  15 engine_id    = pkcs11
  16 dynamic_path = /usr/lib/engines/engine_pkcs11.so
  17 MODULE_PATH  = /usr/lib/libeTPkcs11.so
  18 init         = 0
  19 
  20 
  21 ####################################################################
  22 [ ca ]
  23 default_ca      = CA_default            # The default ca section
  24 
  25 ####################################################################
  26 [ CA_default ]
  27 
  28 dir             = $ENV::KEY_DIR         # Where everything is kept
  29 certs           = $dir                  # Where the issued certs are kept
  30 crl_dir         = $dir                  # Where the issued crl are kept
  31 database        = $dir/index.txt        # database index file.
  32 new_certs_dir   = $dir                  # default place for new certs.
  33 
  34 certificate     = $dir/ca.crt           # The CA certificate
  35 serial          = $dir/serial           # The current serial number
  36 crl             = $dir/crl.pem          # The current CRL
  37 private_key     = $dir/ca.key           # The private key
  38 RANDFILE        = $dir/.rand            # private random number file
  39 
  40 x509_extensions = usr_cert              # The extentions to add to the cert
  41 
  42 # Extensions to add to a CRL. Note: Netscape communicator chokes on V2 CRLs
  43 # so this is commented out by default to leave a V1 CRL.
  44 # crl_extensions        = crl_ext
  45 
  46 default_days    = 3650                  # how long to certify for
  47 default_crl_days= 35                    # how long before next CRL
  48 default_md      = sha256                # which md to use.
  49 preserve        = no                    # keep passed DN ordering
  50 
  51 # A few difference way of specifying how similar the request should look
  52 # For type CA, the listed attributes must be the same, and the optional
  53 # and supplied fields are just that :-)
  54 policy          = policy_anything
  55 
  56 # For the CA policy
  57 [ policy_match ]
  58 countryName             = match
  59 stateOrProvinceName     = match
  60 organizationName        = match
  61 organizationalUnitName  = optional
  62 commonName              = supplied
  63 emailAddress            = optional
  64 
  65 # For the 'anything' policy
  66 # At this point in time, you must list all acceptable 'object'
  67 # types.
  68 [ policy_anything ]
  69 countryName             = optional
  70 stateOrProvinceName     = optional
  71 localityName            = optional
  72 organizationName        = optional
  73 organizationalUnitName  = optional
  74 commonName              = supplied
  75 emailAddress            = optional
  76 
  77 ####################################################################
  78 [ req ]
  79 default_bits            = $ENV::KEY_SIZE
  80 default_keyfile         = privkey.pem
  81 distinguished_name      = req_distinguished_name
  82 attributes              = req_attributes
  83 x509_extensions = v3_ca # The extentions to add to the self signed cert
  84 string_mask = nombstr
  85 
  86 # req_extensions = v3_req # The extensions to add to a certificate request
  87 
  88 [ req_distinguished_name ]
  89 countryName                     = Country Name (2 letter code)
  90 countryName_default             = $ENV::KEY_COUNTRY
  91 countryName_min                 = 2
  92 countryName_max                 = 2
  93 
  94 stateOrProvinceName             = State or Province Name (full name)
  95 stateOrProvinceName_default     = $ENV::KEY_PROVINCE
  96 
  97 localityName                    = Locality Name (eg, city)
  98 localityName_default            = $ENV::KEY_CITY
  99 
 100 0.organizationName              = Organization Name (eg, company)
 101 0.organizationName_default      = $ENV::KEY_ORG
 102 
 103 organizationalUnitName          = Organizational Unit Name (eg, section)
 104 
 105 commonName                      = Common Name (eg, your name or your server\'s hostname)
 106 commonName_max                  = 64
 107 
 108 emailAddress                    = Email Address
 109 emailAddress_default            = $ENV::KEY_EMAIL
 110 emailAddress_max                = 40
 111 
 112 organizationalUnitName_default = $ENV::KEY_OU
 113 commonName_default = $ENV::KEY_CN
 114 
 115 [ req_attributes ]
 116 challengePassword               = A challenge password
 117 challengePassword_min           = 4
 118 challengePassword_max           = 20
 119 unstructuredName                = An optional company name
 120 
 121 [ usr_cert ]
 122 basicConstraints=CA:FALSE
 123 nsComment                       = "OpenSSL Generated Certificate"
 124 subjectKeyIdentifier=hash
 125 authorityKeyIdentifier=keyid,issuer:always
 126 crlDistributionPoints = @crl_dp_policy
 127 
 128 [ server ]
 129 keyUsage = digitalSignature, keyEncipherment
 130 basicConstraints=CA:FALSE
 131 nsCertType                      = server
 132 nsComment                       = "OpenSSL Generated Server Certificate"
 133 subjectKeyIdentifier=hash
 134 authorityKeyIdentifier=keyid,issuer:always
 135 extendedKeyUsage=serverAuth
 136 crlDistributionPoints = @crl_dp_policy
 137 
 138 [ etoken ]
 139 keyUsage = nonRepudiation, digitalSignature, keyEncipherment
 140 basicConstraints=CA:FALSE
 141 subjectKeyIdentifier=hash
 142 authorityKeyIdentifier=keyid,issuer:always
 143 crlDistributionPoints = @crl_dp_policy
 144 
 145 
 146 [ user ]
 147 keyUsage = nonRepudiation, digitalSignature, keyEncipherment
 148 basicConstraints = CA:FALSE
 149 subjectKeyIdentifier=hash
 150 authorityKeyIdentifier=keyid,issuer:always
 151 crlDistributionPoints = @crl_dp_policy
 152 
 153 [ v3_ca ]
 154 subjectKeyIdentifier=hash
 155 authorityKeyIdentifier=keyid:always,issuer:always
 156 basicConstraints = CA:true
 157 # keyUsage = cRLSign, keyCertSign
 158 # nsCertType = sslCA, emailCA
 159 # subjectAltName=email:copy
 160 # issuerAltName=issuer:copy
 161 # basicConstraints= critical, DER:30:03:01:01:FF
 162 
 163 [ crl_ext ]
 164 # CRL extensions.
 165 authorityKeyIdentifier=keyid:always,issuer:always
 166 
 167 [ crl_dp_policy ]
 168 URI.1=$ENV::CDP1
 169 URI.2=$ENV::CDP2

Makefile

   1 DATA_DIR=keys
   2 CA_DIR=${DATA_DIR}
   3 CA_KEY=ca.key
   4 CA_CRT=ca.crt
   5 CA_DER=ca.der
   6 CONF=openssl.cnf
   7 DAYS=80
   8 CSR_DAYS=760
   9 
  10 CRL_DIR=${DATA_DIR}
  11 CRL_DAYS=${DAYS}
  12 CRL_PEM=crl.pem
  13 CRL_DER=crl.der
  14 CRL_REMOTE_DEST="changeme"
  15 
  16 CA=openssl ca -config ${CONF} -keyfile ${CA_DIR}/${CA_KEY}  -cert ${CA_DIR}/${CA_CRT}
  17 CA_SIGN=openssl ca -keyfile ${CA_DIR}/${CA_KEY}  -cert ${CA_DIR}/${CA_CRT}
  18 
  19 export CDP1=changeme
  20 export CDP2=changeme
  21 export KEY_CONFIG=${CONF}
  22 export KEY_DIR=${DATA_DIR}
  23 export KEY_SIZE=2048
  24 export CA_EXPIRE=3650
  25 export KEY_EXPIRE=760
  26 export KEY_COUNTRY=changeme
  27 export KEY_PROVINCE=changeme
  28 export KEY_OU=changeme
  29 export KEY_CITY=changeme
  30 export KEY_ORG=changeme
  31 export KEY_EMAIL=changeme
  32 export KEY_CN=changeme
  33 
  34 
  35 LDAP_HOST=localhost
  36 LDAP_BASE='dc=changeme, dc=local'
  37 LDAP_USER_BASE=ou=users, dc=changeme, dc=local
  38 LDAP_CA='cn=changeme-ca, ou=certificate authority, dc=changeme, dc=local'
  39 LDAP_CRL_ATTR=certificateRevocationList
  40 LDAP_CERT_ATTR=userCertificate
  41 LDAP_BIND='cn=admin,dc=changeme,dc=local'
  42 LDAP_TMP_FILE=tmpldap
  43 LDAP_TEMPLATE=ldap.template
  44 
  45 
  46 help:
  47         @echo "Usage:"
  48         @echo "-------------"
  49         @echo "make initca"
  50         @echo "                 Initialize CA"
  51         @echo
  52         @echo "make gencrl [ldap=1]"
  53         @echo "                 generate CRL"
  54         @echo "                 if ldap=1 is given, the CRL will also be published in LDAP"
  55         @echo
  56         @echo "make req ext=<extensions> name=<name>"
  57         @echo "                 generate a request"
  58         @echo
  59         @echo "make sign csr=csr-file ext=<extensions>"
  60         @echo "                 sign a certificate request"
  61         @echo 
  62         @echo "make etoken name=<name> size=<key size> id=<Key ID> label=<Key label>"
  63         @echo "                 enroll an etoken for a user"
  64         @echo
  65         @echo "make extensions"
  66         @echo "                 lists the available extensions"
  67         @echo
  68         @echo "make revoke cert=crt-file"
  69         @echo "                 revoke a certificate"
  70         @echo
  71         @echo "make listcerts"
  72         @echo "                 lists all issued certificates"
  73         @echo
  74         @echo "make validcerts"
  75         @echo "                 lists all valid certificates"
  76         @echo
  77         @echo "make listrevoked"
  78         @echo "                 lists all revoked certificates"
  79         @echo 
  80         @echo "make publishcert cn=<user> cert=<certificate serial>"
  81         @echo "                 publish certificate in LDAP"
  82         @echo "                 ex: make publish cert cn=koelbel cert=25"
  83         @echo
  84 publishcert:
  85         @echo
  86         @echo "--------------- Publish certificate in LDAP -----------------"
  87         @test $${cn:?"usage: make publishcert cn=<user> cert=<cert file>"}
  88         @test $${cert:?"usage: make publishcert cn=<user> cert=<cert file>"}
  89         @echo "building ldap file from template"
  90         # KNOW ISSUE: this will fail, if DATA_DIR has a / in it. :(
  91         sed -e s/%BASE%/'cn=$(cn), ${LDAP_USER_BASE}'/ -e s/%CERT_ATTR%/${LDAP_CERT_ATTR}/g -e s/%FILE%/'${DATA_DIR}\/$(cert).der'/ ${LDAP_TEMPLATE} > ${LDAP_TMP_FILE}
  92         @echo "running ldapmodify"
  93         openssl x509 -in ${DATA_DIR}/$(cert).pem -out ${DATA_DIR}/$(cert).der -outform DER
  94         ldapmodify -a -D ${LDAP_BIND} -x -W -f ${LDAP_TMP_FILE}  
  95 
  96 initca:
  97         @echo
  98         @echo "--------------- Initializing CA ------------------------------"
  99         openssl req -days ${CA_EXPIRE} -new -x509 -keyout ${CA_DIR}/ca.key -out ${CA_DIR}/ca.crt -config ${CONF}
 100         chmod 0600 ${CA_DIR}/ca.key
 101         touch ${DATA_DIR}/index.txt
 102         echo 01 > ${DATA_DIR}/serial
 103 listcerts:
 104         @echo
 105         @echo "--------------- Issued Certficates ------------------------------"
 106         @for cert in $$(ls ${DATA_DIR}/??.pem); do echo -n $$cert:; openssl x509 -in $$cert -text | grep -B3 Subject:; done
 107         @echo
 108 
 109 validcerts:
 110         @echo
 111         @echo "--------------- Valid Certficates ------------------------------"
 112         @for cert in $$(ls ${DATA_DIR}/??.pem); do openssl crl -in ${DATA_DIR}/${CRL_PEM} -text | grep "Serial Number: `basename $$cert .pem`" > /dev/null; if [ $$? -eq 1 ]; then echo -n $$cert:; openssl x509 -in $$cert -text | grep Subject:;fi; done
 113         @echo
 114 
 115 listrevoked:
 116         @echo
 117         @echo "--------------- Revoked Certificates ----------------------------"
 118         @openssl crl -in ${CRL_DIR}/${CRL_PEM} -text | grep -A1 "Serial Number:"
 119         @echo
 120 
 121 gencrl:
 122         @echo
 123         @echo "------------------ Generating CRL  ---------------------------------"
 124         ${CA} -gencrl -out ${CRL_DIR}/${CRL_PEM} -crldays ${CRL_DAYS}
 125         openssl crl -in ${CRL_DIR}/${CRL_PEM} -out ${CRL_DIR}/${CRL_DER} -outform DER
 126         # publish at WWW
 127         cp ${CRL_DIR}/${CRL_PEM} /var/www
 128         cp ${DATA_DIR}/index.txt /var/www
 129         scp ${CRL_DIR}/${CRL_DER} ${CRL_REMOTE_DEST}
 130         @if [ "$(ldap)" -eq 1 ]; then echo "Publish in LDAP"; sed -e s/%BASE%/${LDAP_CA}/ -e s/%CERT_ATTR%/${LDAP_CRL_ATTR}/g -e s/%FILE%/'${DATA_DIR}\/crl.der'/ ${LDAP_TEMPLATE} > ${LDAP_TMP_FILE} ; ldapmodify -a -D ${LDAP_BIND} -x -W -f ${LDAP_TMP_FILE}; fi
 131 
 132 revoke:
 133         @echo
 134         @echo "------------------ Revoking Certificate ----------------------------"
 135         @test $${cert:?"usage: make revoke cert=certificate"}
 136         ${CA} -revoke ${DATA_DIR}/$(cert).pem
 137         @$(MAKE) gencrl
 138 
 139 sign:
 140         @echo
 141         @echo "------------------ Sign Certificate Request ------------------------"
 142         @test $${csr:?"usage: make sign csr=<certificate request> ext=<extensions>"}
 143         @test $${ext:?"usage: make sign csr=<certificate request> ext=<extensions>"}
 144         ${CA_SIGN} -config ${CONF} -extensions $(ext) -days ${CSR_DAYS} -in ${DATA_DIR}/$(csr).req -out ${DATA_DIR}/$(name).pem
 145         openssl x509 -in ${DATA_DIR}/$(name).pem -out ${DATA_DIR}/$(name).der -outform DER
 146 
 147 req:
 148         @echo
 149         @echo "------------------- Generating Request -----------------------------"
 150         @test $${ext:?"usage: make req ext=<extensions> name=<name>"}
 151         @test $${name:?"usage: make req ext=<extensions> name=<name>"}
 152         openssl req -config ${CONF} -extensions $(ext) -new -out ${DATA_DIR}/${name}.req -keyout ${DATA_DIR}/${name}.key
 153         @echo
 154 
 155 
 156 extensions:
 157         @echo 
 158         @echo "------------- Available Extensions ----------------------"
 159         grep -B1 ^keyUsage ${CONF}
 160 
 161 etoken:
 162         @echo
 163         @echo "------------------- Enrolling eToken -----------------------------"
 164         @test $${size:?"usage: make etoken name=<name> size=<key size> id=<Key ID> label=<Key label>"}
 165         @test $${name:?"usage: make etoken name=<name> size=<key size> id=<Key ID> label=<Key label>"}
 166         @test $${id:?"usage: make etoken name=<name> size=<key size> id=<Key ID> label=<Key label>"}
 167         @test $${label:?"usage: make etoken name=<name> size=<key size> id=<Key ID> label=<Key label>"}
 168         @echo =============================
 169         @echo Generating Key Pair on eToken
 170         @echo RSA $(size) bit
 171         @echo =============================
 172         pkcs11-tool --module /usr/lib/libeTPkcs11.so -k --key-type rsa:$(size) -l --id $(id)  --label $(label)
 173         @echo =============================
 174         @echo Building Cert Req
 175         @echo =============================
 176         openssl req -config ${CONF} -engine pkcs11 -new -key id_$(id) -keyform engine -out ${DATA_DIR}/$(name).req -outform PEM
 177         @echo =============================
 178         @echo Signing Request
 179         @echo =============================
 180         @$(MAKE) sign csr=$(name) ext=etoken
 181         @echo =============================
 182         @echo Loading cert to the token
 183         @echo =============================
 184         pkcs11-tool --module /usr/lib/libeTPkcs11.so  -w ${DATA_DIR}/$(name).der -y cert -l --slot 0 --id $(id)  -a $(label)

None: HowTos/eToken and PKI (last edited 2011-02-02 07:57:56 by CorneliusKoelbel)