SmartCardKerberos: Difference between revisions

From DcSharedWiki
(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 (mine is
#* 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` by value depending of your configuration.
* 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: 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 ====
==== 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-id_XX -keyform engine -extensions CA_ROOT -new -x509 -out ca.pem -text
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 ===
== 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 = "CA Racine"
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 = "CA serveur SSL"
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

  1. Software: Here programs that will be used. In parenthesises I have mentionned versions I have used.
  2. 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

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

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

MIT Kerberos documentation

### 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

MIT Kerberos documentation

###  ###
[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}