SmartCardKerberos: Difference between revisions
(add typographical conventions) |
(fixed links after import) |
||
(8 intermediate revisions by 2 users not shown) | |||
Line 1: | Line 1: | ||
__NOTOC__ |
|||
How to use smart card with Kerberos. |
How to use smart card with Kerberos. |
||
''Requirements'' |
''Requirements'' |
||
# Software: Here programs that will be used. In parenthesises I have mentionned versions I have used. |
# Software: Here programs that will be used. In parenthesises I have mentionned versions I have used. |
||
#* openssl (0.9.8) |
#* [OpenSSL http://www.openssl.org/] (0.9.8) |
||
#* Kerberos server with pkinit plugin (MIT 1.6) |
#* [http://web.mit.edu/Kerberos/ Kerberos server with pkinit plugin] (MIT 1.6) |
||
#* opensc (0.11.13) |
#* [OpenSC http://www.opensc-project.org/opensc] (0.11.13) |
||
#* pcscd (1.5.5) |
#* pcscd (1.5.5) |
||
# Hardware |
# Hardware |
||
#* a smart card: Feitian PKI card bought on http://www.gooze.eu/ There is a lot of documentation on this website. |
#* a smart card: Feitian PKI card bought on http://www.gooze.eu/ There is a lot of documentation on this website. |
||
#* smart card reader ( |
#* one smart card reader (mines are Gemalto PC Twin Reader and Gemalto USB Shell Token v2 for SIM card size) |
||
''External links'' |
''External links'' |
||
* [http://www.openssl.org/docs/ OpenSSL documentation] |
|||
* [http://www.opensc-project.org/opensc/wiki/QuickStart OpenSC quick start] and [http://www.opensc-project.org/engine_pkcs11/wiki/QuickStart OpenSC engine_pkcs11 quickstart] |
* [http://www.opensc-project.org/opensc/wiki/QuickStart OpenSC quick start] and [http://www.opensc-project.org/engine_pkcs11/wiki/QuickStart OpenSC engine_pkcs11 quickstart] |
||
* [http://www.hsc.fr/ressources/breves/ssl_configuration.html.fr OpenSSL configration (in french) by Franck Davy] |
* [http://www.hsc.fr/ressources/breves/ssl_configuration.html.fr OpenSSL configration (in french) by Franck Davy] |
||
* [http://mailman.mit.edu/pipermail/krbdev/2006-November/005180.html Generating cert for pkinit by Sam Hartman] |
* [http://mailman.mit.edu/pipermail/krbdev/2006-November/005180.html Generating cert for pkinit by Sam Hartman] |
||
* [http://honk.sigxcpu.org/con/PKINIT__Kerberos_v5_with_Smart_Cards.html Smart cards with Heimdal by Guido Günther] |
* [http://honk.sigxcpu.org/con/PKINIT__Kerberos_v5_with_Smart_Cards.html Smart cards with Heimdal by Guido Günther] |
||
* [http://www.ietf.org/rfc/rfc4556.txt RFC 4556 Public Key Cryptography for Initial Authentication in Kerberos (PKINIT)] |
|||
''Typographical conventions'' |
''Typographical conventions'' |
||
* in commands listed below, you must replace `XX` |
* in commands listed below, you must replace `XX` depending of your configuration |
||
* Constant width is used for `keywords` |
* Constant width is used for `keywords` |
||
Line 44: | Line 47: | ||
=== PKI structure === |
=== PKI structure === |
||
* |
* Root CA: sign servers CA and clients CA. Root CA is a self-signed certificate. (directory `./ca`) |
||
* servers CA: sign servers certificates |
* servers CA: sign servers certificates (directory `./cassl`) |
||
** A server certificate will be signed by servers CA. For example kdc certificate will be signed by servers CA. |
|||
** kdc certificate |
|||
* clients CA: sign clients certificates |
* clients CA: sign clients certificates (directory `./client`) |
||
** A client certificate will be signed by client CA. For example user certificate will be signed by clients CA. |
|||
** user certificate |
|||
`openssl.cnf` with 3 CA: |
|||
<pre><nowiki> |
|||
[ CA_root_default ] |
|||
dir = ./root_ca |
|||
certs = $dir/certs # Where the issued certs are kept |
|||
crl_dir = $dir/crl # Where the issued crl are kept |
|||
database = $dir/index.txt # database index file. |
|||
new_certs_dir = $dir/newcerts # default place for new certs. |
|||
certificate = $dir/cacert.pem # The CA certificate |
|||
serial = $dir/serial # The current serial number |
|||
crlnumber = $dir/crlnumber # the current crl number |
|||
crl = $dir/crl.pem # The current CRL |
|||
RANDFILE = $dir/private/.rand # private random number file |
|||
# Comment out the following two lines for the "traditional" |
|||
# (and highly broken) format. |
|||
name_opt = ca_default # Subject Name options |
|||
cert_opt = ca_default # Certificate field options |
|||
default_days = 365 # how long to certify for |
|||
default_crl_days = 30 # how long before next CRL |
|||
default_md = sha1 # which md to use. |
|||
preserve = no # keep passed DN ordering |
|||
policy = policy_match |
|||
[ CA_serveur_default ] |
|||
dir = ./servers_ca |
|||
certs = $dir/certs # Where the issued certs are kept |
|||
crl_dir = $dir/crl # Where the issued crl are kept |
|||
database = $dir/index.txt # database index file. |
|||
new_certs_dir = $dir/newcerts # default place for new certs. |
|||
certificate = $dir/cassl.pem # The CA certificate |
|||
serial = $dir/serial # The current serial number |
|||
crlnumber = $dir/crlnumber # the current crl number |
|||
crl = $dir/crl.pem # The current CRL |
|||
RANDFILE = $dir/private/.rand # private random number file |
|||
# Comment out the following two lines for the "traditional" |
|||
# (and highly broken) format. |
|||
name_opt = ca_default # Subject Name options |
|||
cert_opt = ca_default # Certificate field options |
|||
default_days = 365 # how long to certify for |
|||
default_crl_days = 30 # how long before next CRL |
|||
default_md = sha1 # which md to use. |
|||
preserve = no # keep passed DN ordering |
|||
policy = policy_match |
|||
[ CA_client_default ] |
|||
dir = ./clients_ca |
|||
certs = $dir/certs # Where the issued certs are kept |
|||
crl_dir = $dir/crl # Where the issued crl are kept |
|||
database = $dir/index.txt # database index file. |
|||
new_certs_dir = $dir/newcerts # default place for new certs. |
|||
certificate = $dir/client.pem # The CA certificate |
|||
serial = $dir/serial # The current serial number |
|||
crlnumber = $dir/crlnumber # the current crl number |
|||
crl = $dir/crl.pem # The current CRL |
|||
RANDFILE = $dir/private/.rand # private random number file |
|||
# Comment out the following two lines for the "traditional" |
|||
# (and highly broken) format. |
|||
name_opt = ca_default # Subject Name options |
|||
cert_opt = ca_default # Certificate field options |
|||
default_days = 365 # how long to certify for |
|||
default_crl_days = 30 # how long before next CRL |
|||
default_md = sha1 # which md to use. |
|||
preserve = no # keep passed DN ordering |
|||
policy = policy_user |
|||
[ policy_match ] |
|||
countryName = match |
|||
stateOrProvinceName = match |
|||
organizationName = match |
|||
organizationalUnitName = optional |
|||
commonName = supplied |
|||
emailAddress = optional |
|||
[ policy_user ] |
|||
countryName = match |
|||
stateOrProvinceName = match |
|||
organizationName = match |
|||
organizationalUnitName = optional |
|||
commonName = supplied |
|||
emailAddress = supplied |
|||
</nowiki></pre> |
|||
<pre><nowiki> |
|||
# create directory |
|||
mkdir -p root_ca/newcerts |
|||
touch root_ca/index.txt touch root_ca/index.txt root_ca/index.txt.attr |
|||
echo "00" > root_ca/serial |
|||
mkdir server_ca |
|||
mkdir client_ca |
|||
</nowiki></pre> |
|||
=== Create root CA === |
=== Create root CA === |
||
Line 66: | Line 164: | ||
<pre><nowiki> |
<pre><nowiki> |
||
pkcs15-tool --list-pins |
pkcs15-tool --list-pins # use 'ID' field |
||
</nowiki></pre> |
</nowiki></pre> |
||
Line 73: | Line 171: | ||
<pre><nowiki> |
<pre><nowiki> |
||
cd root_ca |
|||
openssl genrsa 2048 > id_rsa.pem |
openssl genrsa 2048 > id_rsa.pem |
||
openssl rsa -pubout < id_rsa.pem > id_rsa.pub |
openssl rsa -pubout < id_rsa.pem > id_rsa.pub |
||
Line 79: | Line 178: | ||
==== |
==== Create certificate ==== |
||
Then the root CA can be created from the RSA key: |
|||
<pre><nowiki> |
<pre><nowiki> |
||
openssl req -config openssl.cnf -engine pkcs11 -key slot_XX- |
openssl req -config openssl.cnf -engine pkcs11 -key slot_XX-id_XXX -keyform engine -extensions CA_ROOT -new -x509 -out root_ca/ca.pem -text |
||
</nowiki></pre> |
</nowiki></pre> |
||
* `id` number can be found with the following command: |
|||
<pre><nowiki> |
|||
`id` is same as value of parameter `--auth-id` and `slot` is indicated by: |
|||
pkcs11-tool --list-keys # check ID field |
|||
</nowiki></pre> |
|||
* `id` is same as value of parameter `--auth-id` and `slot` number can be found with the following command: |
|||
<pre><nowiki> |
|||
pkcs11-tool --list-slots |
|||
</nowiki></pre> |
|||
* `-key slot_XX-id_XXX -keyform engine` indicate that private key XXX is stored on smart card at slot XX |
|||
* Value of parameter `-engine` is a name of an engine defined in `openssl.cnf`: |
|||
<pre><nowiki> |
|||
[openssl_init] |
|||
engines = engine_section |
|||
[engine_section] |
|||
pkcs11 = pkcs11_section |
|||
[pkcs11_section] |
|||
engine_id = pkcs11 |
|||
dynamic_path = /usr/lib/engines/engine_pkcs11.so |
|||
MODULE_PATH = /usr/lib/opensc-pkcs11.so |
|||
init = 0 |
|||
</nowiki></pre> |
|||
* ` -extensions` refers to certificate extensions to be added to root CA certificate. Extensions are defined in `openssl.cnf`: |
|||
<pre><nowiki> |
|||
[CA_ROOT] |
|||
nsComment = "Root CA" |
|||
subjectKeyIdentifier = hash |
|||
authorityKeyIdentifier = keyid,issuer:always |
|||
basicConstraints = critical,CA:TRUE,pathlen:1 |
|||
keyUsage = keyCertSign, cRLSign |
|||
</nowiki></pre> |
|||
=== Create server CA === |
|||
Server CA will be signed by root CA. In order to create the server CA certificate you need to generate a RSA key. Store the private key in smart card. See previous paragraph. |
|||
* Create a certificate request [http://en.wikipedia.org/wiki/Certificate_signing_request CSR] from previously created RSA key: |
|||
<pre><nowiki> |
|||
# -key refers to private key of server CA, pin will be asked |
|||
openssl req -config openssl.cnf -engine pkcs11 -key slot_X-id_XX -keyform engine -new -out server_ca/ca.csr |
|||
</nowiki></pre> |
|||
* Validate certificate signing request with the private key of root CA (`-name` parameter specifies which CA is used when signing the CSR): |
|||
<pre><nowiki> |
|||
# -key refers to private key of root CA, pin will be asked |
|||
openssl ca -config openssl.cnf -engine pkcs11 -keyfile slot_X-id_XX -keyform engine -name CA_root_default -extensions CA_SERVER_SSL -out server_sa/ca.pem -infiles server_ca/ca.csr |
|||
</nowiki></pre> |
|||
* certificate extensions `CA_SERVER_SSL` is: |
|||
<pre><nowiki> |
|||
[CA_SERVER_SSL] |
|||
nsComment = "server CA SSL" |
|||
basicConstraints = critical,CA:TRUE,pathlen:0 |
|||
subjectKeyIdentifier = hash |
|||
authorityKeyIdentifier = keyid,issuer:always |
|||
issuerAltName = issuer:copy |
|||
keyUsage = keyCertSign, cRLSign |
|||
nsCertType = sslCA |
|||
</nowiki></pre> |
|||
=== Create a client CA === |
|||
Client CA will be signed by root CA. In order to create the client CA certificate you need to generate a RSA key. Store the private key in smart card. See previous paragraph. |
|||
* Create a certificate request [http://en.wikipedia.org/wiki/Certificate_signing_request CSR] from previously created RSA key: |
|||
<pre><nowiki> |
|||
# -key refers to private key of client CA, pin will be asked |
|||
openssl req -config openssl.cnf -engine pkcs11 -key slot_X-id_XX -keyform engine -new -out client/client.csr |
|||
</nowiki></pre> |
|||
* Validate certificate signing request with the private key of root CA: |
|||
<pre><nowiki> |
|||
# -key refers to private key of root CA, pin will be asked |
|||
openssl ca -config openssl.cnf -engine pkcs11 -keyfile slot_X-id_XX -keyform engine -name CA_root_default -extensions CA_CLIENT_SSL -out client/client.pem -infiles client/client.csr |
|||
</nowiki></pre> |
|||
* certificate extensions `CA_CLIENT_SSL` is: |
|||
<pre><nowiki> |
|||
[CA_CLIENT_SSL] |
|||
nsComment = "CA client SSL" |
|||
basicConstraints = critical,CA:TRUE,pathlen:0 |
|||
subjectKeyIdentifier = hash |
|||
authorityKeyIdentifier = keyid,issuer:always |
|||
issuerAltName = issuer:copy |
|||
keyUsage = keyCertSign, cRLSign |
|||
nsCertType = sslCA |
|||
</nowiki></pre> |
|||
=== Create a server certificate for Kerberos KDC === |
|||
In order to create a KDC certificate you need to generate a RSA key '''on a computer'''. `kdc` will need access to the private key, don't store it in a smart card! |
|||
<pre><nowiki> |
|||
openssl genrsa 2048 > ./cassl/id_kdc.pem |
|||
openssl rsa -pubout < ./cassl/id_kdc.pem > ./cassl/id_kdc.pub |
|||
</nowiki></pre> |
|||
Create the [http://en.wikipedia.org/wiki/Certificate_signing_request CSR] from the previously created RSA key: |
|||
<pre><nowiki> |
|||
export REALM=MYREALM.ORG |
|||
openssl req -config openssl.cnf -key ./cassl/id_kdc.pem -new -out cassl/kdcssl.csr |
|||
</nowiki></pre> |
|||
Validate certificate signing request with the private key of server CA: |
|||
<pre><nowiki> |
|||
export REALM=MYREALM.ORG |
|||
# -key refers to private key of server CA, pin will be asked |
|||
openssl ca -config openssl.cnf -engine pkcs11 -keyfile slot_X-id_XX -keyform engine -name CA_server_default -extensions KDC_CERT -out cassl/kdcssl.pem -infiles cassl/kdcssl.csr |
|||
</nowiki></pre> |
|||
* certificate extensions `KDC_CERT` are |
|||
<pre><nowiki> |
|||
[ KDC_CERT ] |
|||
nsComment = "KDC SERVER SSL" |
|||
subjectKeyIdentifier = hash |
|||
authorityKeyIdentifier = keyid,issuer:always |
|||
issuerAltName = issuer:copy |
|||
keyUsage = nonRepudiation, digitalSignature, keyEncipherment, keyAgreement |
|||
extendedKeyUsage = pkkdcekuoid |
|||
basicConstraints = critical,CA:FALSE |
|||
</nowiki></pre> |
|||
* Here the [http://en.wikipedia.org/wiki/Certificate_signing_request CSR] is signed by server CA. |
|||
* `extendedKeyUsage` follows the [http://www.ietf.org/rfc/rfc4556.txt RFC 4556 Public Key Cryptography for Initial Authentication in Kerberos (PKINIT)] |
|||
This [http://en.wikipedia.org/wiki/Object_identifier OID] need to be added to `openssl.cnf`: |
|||
<pre><nowiki> |
|||
[openssl_init] |
|||
engines = engine_section |
|||
oid_section = new_oids |
|||
[ new_oids ] |
|||
pkkdcekuoid=1.3.6.1.5.2.3.5 |
|||
</nowiki></pre> |
|||
ND: you can take a look at http://www.oid-info.com/ |
|||
=== Create a client certificate === |
|||
Client certificate will be signed by client CA. In order to create the client certificate you need to generate a RSA key. Store the private key in smart card. See previous paragraph. |
|||
* Create a certificate request [http://en.wikipedia.org/wiki/Certificate_signing_request CSR] from previously created RSA key: |
|||
<pre><nowiki> |
|||
# -key refers to private key of client certificate, pin will be asked |
|||
openssl req -config openssl.cnf -engine pkcs11 -key slot_X-id_XX -keyform engine -new -out client/pilou.csr |
|||
</nowiki></pre> |
|||
* Validate certificate signing request with the private key of client CA: |
|||
<pre><nowiki> |
|||
# -key refers to private key of client CA, pin will be asked |
|||
export REALM=MYREALM.ORG |
|||
export LOGIN=pilou |
|||
openssl ca -config openssl.cnf -engine pkcs11 -keyfile slot_X-id_XX -keyform engine -name CA_client_default -extensions CLIENT_CERT -out client/pilou.pem -infiles client/pilou.csr |
|||
</nowiki></pre> |
|||
* `-extensions CLIENT_CERT` refers to certificate extensions to be added to client certificate: |
|||
<pre><nowiki> |
|||
[CLIENT_SSL] |
|||
nsComment = "Certificat Client SSL" |
|||
subjectKeyIdentifier = hash |
|||
authorityKeyIdentifier = keyid,issuer:always |
|||
issuerAltName = issuer:copy |
|||
basicConstraints = critical,CA:FALSE |
|||
keyUsage = digitalSignature, nonRepudiation |
|||
nsCertType = client |
|||
</nowiki></pre> |
|||
* Store certificate on smart card: |
|||
<pre><nowiki> |
|||
pkcs15-init --store-certificate client/pilou.pem --auth-id XX --id XX --format pem |
|||
</nowiki></pre> |
|||
== Kerberos configuration == |
|||
=== Client configuration === |
|||
[http://web.mit.edu/Kerberos/krb5-1.7/krb5-1.7.1/doc/krb5-admin.html#pkinit%20client%20options MIT Kerberos documentation] |
|||
<pre><nowiki> |
|||
### file /etc/krb5.conf ### |
|||
[realms] |
|||
MYREALM.ORG = { |
|||
... |
|||
pkinit_anchors = FILE:/home/lilou/pki/ca/cacert.pem |
|||
pkinit_pool = FILE:/home/lilou/pki/cassl/cassl.pem |
|||
pkinit_pool = FILE:/home/lilou/pki/client/client.pem |
|||
} |
|||
</nowiki></pre> |
|||
=== KDC configuration === |
|||
[http://web.mit.edu/Kerberos/krb5-1.7/krb5-1.7.1/doc/krb5-admin.html#pkinit%20kdc.conf%20options MIT Kerberos documentation] |
|||
<pre><nowiki> |
<pre><nowiki> |
||
### ### |
|||
pkcs11-tool --list-slots |
|||
[realms] |
|||
MYREALM.ORG = { |
|||
... |
|||
pkinit_identity = FILE:/etc/krb5kdc/kdcssl.pem,/etc/krb5kdc/id_kdc.key |
|||
pkinit_anchors = FILE:/etc/krb5kdc/cacert.pem |
|||
pkinit_pool = FILE:/etc/krb5kdc/cassl.pem |
|||
pkinit_eku_checking = kpClientAuth |
|||
} |
|||
</nowiki></pre> |
</nowiki></pre> |
||
== OpenSSL configuration == |
|||
Here is my complete openssl.cnf file: |
Here is my complete openssl.cnf file: |
||
Line 126: | Line 449: | ||
crlnumber = $dir/crlnumber # the current crl number |
crlnumber = $dir/crlnumber # the current crl number |
||
crl = $dir/crl.pem # The current CRL |
crl = $dir/crl.pem # The current CRL |
||
#private_key = $dir/private/cakey.pem # The private key |
|||
RANDFILE = $dir/private/.rand # private random number file |
RANDFILE = $dir/private/.rand # private random number file |
||
# Comment out the following two lines for the "traditional" |
# Comment out the following two lines for the "traditional" |
||
Line 148: | Line 470: | ||
crlnumber = $dir/crlnumber # the current crl number |
crlnumber = $dir/crlnumber # the current crl number |
||
crl = $dir/crl.pem # The current CRL |
crl = $dir/crl.pem # The current CRL |
||
#private_key = $dir/private/cakey.pem # The private key |
|||
RANDFILE = $dir/private/.rand # private random number file |
RANDFILE = $dir/private/.rand # private random number file |
||
# Comment out the following two lines for the "traditional" |
# Comment out the following two lines for the "traditional" |
||
Line 170: | Line 491: | ||
crlnumber = $dir/crlnumber # the current crl number |
crlnumber = $dir/crlnumber # the current crl number |
||
crl = $dir/crl.pem # The current CRL |
crl = $dir/crl.pem # The current CRL |
||
#private_key = $dir/private/cakey.pem # The private key |
|||
RANDFILE = $dir/private/.rand # private random number file |
RANDFILE = $dir/private/.rand # private random number file |
||
# Comment out the following two lines for the "traditional" |
# Comment out the following two lines for the "traditional" |
||
Line 197: | Line 517: | ||
commonName = supplied |
commonName = supplied |
||
emailAddress = supplied |
emailAddress = supplied |
||
#################################################################### |
#################################################################### |
||
Line 242: | Line 561: | ||
[CA_ROOT] |
[CA_ROOT] |
||
nsComment = " |
nsComment = "Root CA" |
||
subjectKeyIdentifier = hash |
subjectKeyIdentifier = hash |
||
authorityKeyIdentifier = keyid,issuer:always |
authorityKeyIdentifier = keyid,issuer:always |
||
Line 248: | Line 567: | ||
keyUsage = keyCertSign, cRLSign |
keyUsage = keyCertSign, cRLSign |
||
[CA_SERVER_SSL] |
|||
[CA_SERVEUR_SSL] |
|||
nsComment = " |
nsComment = "server CA SSL" |
||
basicConstraints = critical,CA:TRUE,pathlen:0 |
basicConstraints = critical,CA:TRUE,pathlen:0 |
||
subjectKeyIdentifier = hash |
subjectKeyIdentifier = hash |
||
Line 257: | Line 576: | ||
nsCertType = sslCA |
nsCertType = sslCA |
||
[SERVER_SSL] |
|||
[SERVEUR_SSL] |
|||
nsComment = "Certificat Serveur SSL" |
nsComment = "Certificat Serveur SSL" |
||
subjectKeyIdentifier = hash |
subjectKeyIdentifier = hash |
Latest revision as of 06:19, 22 April 2019
How to use smart card with Kerberos.
Requirements
- Software: Here programs that will be used. In parenthesises I have mentionned versions I have used.
- [OpenSSL http://www.openssl.org/] (0.9.8)
- Kerberos server with pkinit plugin (MIT 1.6)
- [OpenSC http://www.opensc-project.org/opensc] (0.11.13)
- pcscd (1.5.5)
- Hardware
- a smart card: Feitian PKI card bought on http://www.gooze.eu/ There is a lot of documentation on this website.
- one smart card reader (mines are Gemalto PC Twin Reader and Gemalto USB Shell Token v2 for SIM card size)
External links
- OpenSSL documentation
- OpenSC quick start and OpenSC engine_pkcs11 quickstart
- OpenSSL configration (in french) by Franck Davy
- Generating cert for pkinit by Sam Hartman
- Smart cards with Heimdal by Guido Günther
- RFC 4556 Public Key Cryptography for Initial Authentication in Kerberos (PKINIT)
Typographical conventions
- in commands listed below, you must replace `XX` depending of your configuration
- Constant width is used for `keywords`
Initialize smart card
An empty smart card can be initialized with:
# pin & puk will be asked pkcs15-init --create-pkcs15 --profile pkcs15+onepin --use-default-transport-key --label "Pilou"
A not empty smart card can be erased and initialized with:
pkcs15-init -E --label "Pilou"
Create a PKI
Private keys of root CA, server CA and clients CA will be stored on a smart card.
PKI structure
- Root CA: sign servers CA and clients CA. Root CA is a self-signed certificate. (directory `./ca`)
- servers CA: sign servers certificates (directory `./cassl`)
- A server certificate will be signed by servers CA. For example kdc certificate will be signed by servers CA.
- clients CA: sign clients certificates (directory `./client`)
- A client certificate will be signed by client CA. For example user certificate will be signed by clients CA.
`openssl.cnf` with 3 CA:
[ CA_root_default ] dir = ./root_ca certs = $dir/certs # Where the issued certs are kept crl_dir = $dir/crl # Where the issued crl are kept database = $dir/index.txt # database index file. new_certs_dir = $dir/newcerts # default place for new certs. certificate = $dir/cacert.pem # The CA certificate serial = $dir/serial # The current serial number crlnumber = $dir/crlnumber # the current crl number crl = $dir/crl.pem # The current CRL RANDFILE = $dir/private/.rand # private random number file # Comment out the following two lines for the "traditional" # (and highly broken) format. name_opt = ca_default # Subject Name options cert_opt = ca_default # Certificate field options default_days = 365 # how long to certify for default_crl_days = 30 # how long before next CRL default_md = sha1 # which md to use. preserve = no # keep passed DN ordering policy = policy_match [ CA_serveur_default ] dir = ./servers_ca certs = $dir/certs # Where the issued certs are kept crl_dir = $dir/crl # Where the issued crl are kept database = $dir/index.txt # database index file. new_certs_dir = $dir/newcerts # default place for new certs. certificate = $dir/cassl.pem # The CA certificate serial = $dir/serial # The current serial number crlnumber = $dir/crlnumber # the current crl number crl = $dir/crl.pem # The current CRL RANDFILE = $dir/private/.rand # private random number file # Comment out the following two lines for the "traditional" # (and highly broken) format. name_opt = ca_default # Subject Name options cert_opt = ca_default # Certificate field options default_days = 365 # how long to certify for default_crl_days = 30 # how long before next CRL default_md = sha1 # which md to use. preserve = no # keep passed DN ordering policy = policy_match [ CA_client_default ] dir = ./clients_ca certs = $dir/certs # Where the issued certs are kept crl_dir = $dir/crl # Where the issued crl are kept database = $dir/index.txt # database index file. new_certs_dir = $dir/newcerts # default place for new certs. certificate = $dir/client.pem # The CA certificate serial = $dir/serial # The current serial number crlnumber = $dir/crlnumber # the current crl number crl = $dir/crl.pem # The current CRL RANDFILE = $dir/private/.rand # private random number file # Comment out the following two lines for the "traditional" # (and highly broken) format. name_opt = ca_default # Subject Name options cert_opt = ca_default # Certificate field options default_days = 365 # how long to certify for default_crl_days = 30 # how long before next CRL default_md = sha1 # which md to use. preserve = no # keep passed DN ordering policy = policy_user [ policy_match ] countryName = match stateOrProvinceName = match organizationName = match organizationalUnitName = optional commonName = supplied emailAddress = optional [ policy_user ] countryName = match stateOrProvinceName = match organizationName = match organizationalUnitName = optional commonName = supplied emailAddress = supplied
# create directory mkdir -p root_ca/newcerts touch root_ca/index.txt touch root_ca/index.txt root_ca/index.txt.attr echo "00" > root_ca/serial mkdir server_ca mkdir client_ca
Create root CA
Root CA is a self-signed certificate. In order to create the certificate you need to generate a RSA key. This key can be either:
- generated on the smart card
- generated on a computer and copied on the smart card
RSA generated on the smart card
# (pin will be asked) pkcs15-init --generate-key rsa/2048 --auth-id XX
Value of "--auth-id" parameter can be retreived with:
pkcs15-tool --list-pins # use 'ID' field
RSA generated on a computer and copied
cd root_ca openssl genrsa 2048 > id_rsa.pem openssl rsa -pubout < id_rsa.pem > id_rsa.pub pkcs15-init --store-private-key id_rsa.pem --auth-id XX # PIN will be asked or '--pin' can be used
Create certificate
Then the root CA can be created from the RSA key:
openssl req -config openssl.cnf -engine pkcs11 -key slot_XX-id_XXX -keyform engine -extensions CA_ROOT -new -x509 -out root_ca/ca.pem -text
- `id` number can be found with the following command:
pkcs11-tool --list-keys # check ID field
- `id` is same as value of parameter `--auth-id` and `slot` number can be found with the following command:
pkcs11-tool --list-slots
- `-key slot_XX-id_XXX -keyform engine` indicate that private key XXX is stored on smart card at slot XX
- Value of parameter `-engine` is a name of an engine defined in `openssl.cnf`:
[openssl_init] engines = engine_section [engine_section] pkcs11 = pkcs11_section [pkcs11_section] engine_id = pkcs11 dynamic_path = /usr/lib/engines/engine_pkcs11.so MODULE_PATH = /usr/lib/opensc-pkcs11.so init = 0
- ` -extensions` refers to certificate extensions to be added to root CA certificate. Extensions are defined in `openssl.cnf`:
[CA_ROOT] nsComment = "Root CA" subjectKeyIdentifier = hash authorityKeyIdentifier = keyid,issuer:always basicConstraints = critical,CA:TRUE,pathlen:1 keyUsage = keyCertSign, cRLSign
Create server CA
Server CA will be signed by root CA. In order to create the server CA certificate you need to generate a RSA key. Store the private key in smart card. See previous paragraph.
- Create a certificate request CSR from previously created RSA key:
# -key refers to private key of server CA, pin will be asked openssl req -config openssl.cnf -engine pkcs11 -key slot_X-id_XX -keyform engine -new -out server_ca/ca.csr
- Validate certificate signing request with the private key of root CA (`-name` parameter specifies which CA is used when signing the CSR):
# -key refers to private key of root CA, pin will be asked openssl ca -config openssl.cnf -engine pkcs11 -keyfile slot_X-id_XX -keyform engine -name CA_root_default -extensions CA_SERVER_SSL -out server_sa/ca.pem -infiles server_ca/ca.csr
- certificate extensions `CA_SERVER_SSL` is:
[CA_SERVER_SSL] nsComment = "server CA SSL" basicConstraints = critical,CA:TRUE,pathlen:0 subjectKeyIdentifier = hash authorityKeyIdentifier = keyid,issuer:always issuerAltName = issuer:copy keyUsage = keyCertSign, cRLSign nsCertType = sslCA
Create a client CA
Client CA will be signed by root CA. In order to create the client CA certificate you need to generate a RSA key. Store the private key in smart card. See previous paragraph.
- Create a certificate request CSR from previously created RSA key:
# -key refers to private key of client CA, pin will be asked openssl req -config openssl.cnf -engine pkcs11 -key slot_X-id_XX -keyform engine -new -out client/client.csr
- Validate certificate signing request with the private key of root CA:
# -key refers to private key of root CA, pin will be asked openssl ca -config openssl.cnf -engine pkcs11 -keyfile slot_X-id_XX -keyform engine -name CA_root_default -extensions CA_CLIENT_SSL -out client/client.pem -infiles client/client.csr
- certificate extensions `CA_CLIENT_SSL` is:
[CA_CLIENT_SSL] nsComment = "CA client SSL" basicConstraints = critical,CA:TRUE,pathlen:0 subjectKeyIdentifier = hash authorityKeyIdentifier = keyid,issuer:always issuerAltName = issuer:copy keyUsage = keyCertSign, cRLSign nsCertType = sslCA
Create a server certificate for Kerberos KDC
In order to create a KDC certificate you need to generate a RSA key on a computer. `kdc` will need access to the private key, don't store it in a smart card!
openssl genrsa 2048 > ./cassl/id_kdc.pem openssl rsa -pubout < ./cassl/id_kdc.pem > ./cassl/id_kdc.pub
Create the CSR from the previously created RSA key:
export REALM=MYREALM.ORG openssl req -config openssl.cnf -key ./cassl/id_kdc.pem -new -out cassl/kdcssl.csr
Validate certificate signing request with the private key of server CA:
export REALM=MYREALM.ORG # -key refers to private key of server CA, pin will be asked openssl ca -config openssl.cnf -engine pkcs11 -keyfile slot_X-id_XX -keyform engine -name CA_server_default -extensions KDC_CERT -out cassl/kdcssl.pem -infiles cassl/kdcssl.csr
- certificate extensions `KDC_CERT` are
[ KDC_CERT ] nsComment = "KDC SERVER SSL" subjectKeyIdentifier = hash authorityKeyIdentifier = keyid,issuer:always issuerAltName = issuer:copy keyUsage = nonRepudiation, digitalSignature, keyEncipherment, keyAgreement extendedKeyUsage = pkkdcekuoid basicConstraints = critical,CA:FALSE
- Here the CSR is signed by server CA.
- `extendedKeyUsage` follows the RFC 4556 Public Key Cryptography for Initial Authentication in Kerberos (PKINIT)
This OID need to be added to `openssl.cnf`:
[openssl_init] engines = engine_section oid_section = new_oids [ new_oids ] pkkdcekuoid=1.3.6.1.5.2.3.5
ND: you can take a look at http://www.oid-info.com/
Create a client certificate
Client certificate will be signed by client CA. In order to create the client certificate you need to generate a RSA key. Store the private key in smart card. See previous paragraph.
- Create a certificate request CSR from previously created RSA key:
# -key refers to private key of client certificate, pin will be asked openssl req -config openssl.cnf -engine pkcs11 -key slot_X-id_XX -keyform engine -new -out client/pilou.csr
- Validate certificate signing request with the private key of client CA:
# -key refers to private key of client CA, pin will be asked export REALM=MYREALM.ORG export LOGIN=pilou openssl ca -config openssl.cnf -engine pkcs11 -keyfile slot_X-id_XX -keyform engine -name CA_client_default -extensions CLIENT_CERT -out client/pilou.pem -infiles client/pilou.csr
- `-extensions CLIENT_CERT` refers to certificate extensions to be added to client certificate:
[CLIENT_SSL] nsComment = "Certificat Client SSL" subjectKeyIdentifier = hash authorityKeyIdentifier = keyid,issuer:always issuerAltName = issuer:copy basicConstraints = critical,CA:FALSE keyUsage = digitalSignature, nonRepudiation nsCertType = client
- Store certificate on smart card:
pkcs15-init --store-certificate client/pilou.pem --auth-id XX --id XX --format pem
Kerberos configuration
Client configuration
### file /etc/krb5.conf ### [realms] MYREALM.ORG = { ... pkinit_anchors = FILE:/home/lilou/pki/ca/cacert.pem pkinit_pool = FILE:/home/lilou/pki/cassl/cassl.pem pkinit_pool = FILE:/home/lilou/pki/client/client.pem }
KDC configuration
### ### [realms] MYREALM.ORG = { ... pkinit_identity = FILE:/etc/krb5kdc/kdcssl.pem,/etc/krb5kdc/id_kdc.key pkinit_anchors = FILE:/etc/krb5kdc/cacert.pem pkinit_pool = FILE:/etc/krb5kdc/cassl.pem pkinit_eku_checking = kpClientAuth }
OpenSSL configuration
Here is my complete openssl.cnf file:
# This definition stops the following lines choking if HOME isn't # defined. HOME = . RANDFILE = $ENV::HOME/.rnd openssl_conf = openssl_init [openssl_init] engines = engine_section oid_section = new_oids [ new_oids ] pkkdcekuoid=1.3.6.1.5.2.3.5 [ ca ] default_ca = CA_root_default #################################################################### [ CA_root_default ] dir = ./ca certs = $dir/certs # Where the issued certs are kept crl_dir = $dir/crl # Where the issued crl are kept database = $dir/index.txt # database index file. new_certs_dir = $dir/newcerts # default place for new certs. certificate = $dir/cacert.pem # The CA certificate serial = $dir/serial # The current serial number crlnumber = $dir/crlnumber # the current crl number crl = $dir/crl.pem # The current CRL RANDFILE = $dir/private/.rand # private random number file # Comment out the following two lines for the "traditional" # (and highly broken) format. name_opt = ca_default # Subject Name options cert_opt = ca_default # Certificate field options default_days = 365 # how long to certify for default_crl_days = 30 # how long before next CRL default_md = sha1 # which md to use. preserve = no # keep passed DN ordering policy = policy_match [ CA_serveur_default ] dir = ./cassl certs = $dir/certs # Where the issued certs are kept crl_dir = $dir/crl # Where the issued crl are kept database = $dir/index.txt # database index file. new_certs_dir = $dir/newcerts # default place for new certs. certificate = $dir/cassl.pem # The CA certificate serial = $dir/serial # The current serial number crlnumber = $dir/crlnumber # the current crl number crl = $dir/crl.pem # The current CRL RANDFILE = $dir/private/.rand # private random number file # Comment out the following two lines for the "traditional" # (and highly broken) format. name_opt = ca_default # Subject Name options cert_opt = ca_default # Certificate field options default_days = 365 # how long to certify for default_crl_days = 30 # how long before next CRL default_md = sha1 # which md to use. preserve = no # keep passed DN ordering policy = policy_match [ CA_client_default ] dir = ./client certs = $dir/certs # Where the issued certs are kept crl_dir = $dir/crl # Where the issued crl are kept database = $dir/index.txt # database index file. new_certs_dir = $dir/newcerts # default place for new certs. certificate = $dir/client.pem # The CA certificate serial = $dir/serial # The current serial number crlnumber = $dir/crlnumber # the current crl number crl = $dir/crl.pem # The current CRL RANDFILE = $dir/private/.rand # private random number file # Comment out the following two lines for the "traditional" # (and highly broken) format. name_opt = ca_default # Subject Name options cert_opt = ca_default # Certificate field options default_days = 365 # how long to certify for default_crl_days = 30 # how long before next CRL default_md = sha1 # which md to use. preserve = no # keep passed DN ordering policy = policy_user [ policy_match ] countryName = match stateOrProvinceName = match organizationName = match organizationalUnitName = optional commonName = supplied emailAddress = optional [ policy_user ] countryName = match stateOrProvinceName = match organizationName = match organizationalUnitName = optional commonName = supplied emailAddress = supplied #################################################################### [ req ] default_bits = 1024 default_keyfile = privkey.pem distinguished_name = req_distinguished_name # This sets a mask for permitted string types. There are several options. # default: PrintableString, T61String, BMPString. # pkix : PrintableString, BMPString. # utf8only: only UTF8Strings. # nombstr : PrintableString, T61String (no BMPStrings or UTF8Strings). # MASK:XXXX a literal mask value. # WARNING: current versions of Netscape crash on BMPStrings or UTF8Strings # so use this option with caution! string_mask = nombstr [ req_distinguished_name ] countryName = Country Name (2 letter code) countryName_default = FR countryName_min = 2 countryName_max = 2 stateOrProvinceName = State or Province Name (full name) stateOrProvinceName_default = Ile de France localityName = Locality Name (eg, city) localityName_default = Paris 0.organizationName = Organization Name (eg, company) 0.organizationName_default = PilouCorp organizationalUnitName = Organizational Unit Name (eg, section) commonName = Common Name (eg, YOUR name) commonName_max = 64 emailAddress = Email Address emailAddress_max = 64 [engine_section] pkcs11 = pkcs11_section [pkcs11_section] engine_id = pkcs11 dynamic_path = /usr/lib/engines/engine_pkcs11.so MODULE_PATH = /usr/lib/opensc-pkcs11.so init = 0 [CA_ROOT] nsComment = "Root CA" subjectKeyIdentifier = hash authorityKeyIdentifier = keyid,issuer:always basicConstraints = critical,CA:TRUE,pathlen:1 keyUsage = keyCertSign, cRLSign [CA_SERVER_SSL] nsComment = "server CA SSL" basicConstraints = critical,CA:TRUE,pathlen:0 subjectKeyIdentifier = hash authorityKeyIdentifier = keyid,issuer:always issuerAltName = issuer:copy keyUsage = keyCertSign, cRLSign nsCertType = sslCA [SERVER_SSL] nsComment = "Certificat Serveur SSL" subjectKeyIdentifier = hash authorityKeyIdentifier = keyid,issuer:always issuerAltName = issuer:copy basicConstraints = critical,CA:FALSE keyUsage = digitalSignature, nonRepudiation, keyEncipherment nsCertType = server extendedKeyUsage = serverAuth [CA_CLIENT_SSL] nsComment = "CA client SSL" basicConstraints = critical,CA:TRUE,pathlen:0 subjectKeyIdentifier = hash authorityKeyIdentifier = keyid,issuer:always issuerAltName = issuer:copy keyUsage = keyCertSign, cRLSign nsCertType = sslCA [CLIENT_SSL] nsComment = "Certificat Client SSL" subjectKeyIdentifier = hash authorityKeyIdentifier = keyid,issuer:always issuerAltName = issuer:copy basicConstraints = critical,CA:FALSE keyUsage = digitalSignature, nonRepudiation nsCertType = client [ KDC_CERT ] nsComment = "KDC SERVEUR SSL" subjectKeyIdentifier = hash authorityKeyIdentifier = keyid,issuer:always issuerAltName = issuer:copy keyUsage = nonRepudiation, digitalSignature, keyEncipherment, keyAgreement extendedKeyUsage = pkkdcekuoid basicConstraints = critical,CA:FALSE # Add id-pkinit-san (pkinit subjectAlternativeName) subjectAltName = otherName:1.3.6.1.5.2.2;SEQUENCE:kdc_princ_name [kdc_princ_name] realm = EXP:0,GeneralString:${ENV::REALM} principal_name = EXP:1,SEQUENCE:kdc_principal_seq [kdc_principal_seq] name_type = EXP:0,INTEGER:1 name_string = EXP:1,SEQUENCE:kdc_principals [kdc_principals] princ1 = GeneralString:krbtgt princ2 = GeneralString:${ENV::REALM} [ CLIENT_CERT ] nsComment = "KRB CLIENT SSL" subjectKeyIdentifier = hash authorityKeyIdentifier = keyid,issuer:always issuerAltName = issuer:copy keyUsage = digitalSignature, keyEncipherment, keyAgreement extendedKeyUsage = 1.3.6.1.5.2.3.4 basicConstraints = CA:FALSE subjectAltName = otherName:1.3.6.1.5.2.2;SEQUENCE:princ_name [princ_name] realm = EXP:0, GeneralString:${ENV::REALM} principal_name = EXP:1, SEQUENCE:principal_seq [principal_seq] name_type = EXP:0, INTEGER:1 name_string = EXP:1, SEQUENCE:principals [principals] princ1 = GeneralString:${ENV::CLIENT}