eToken and openssl PKI
- modified: 06.10.2008
author: CorneliusKoelbel
<cornelius.koelbel AT lsexperts DOT de>
- used eToken: eTokenPro 64K 4.2B
- used RTE: 4.55 deb
- used software: pkcs11-tool (OpenSC 0.11.3), openssl 0.9.8e
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)
