292 lines
9.6 KiB
HTML
292 lines
9.6 KiB
HTML
<!--# set var="title" value="Elliptic Curve Certificate Authority" -->
|
|
<!--# set var="date" value="2016-03-21" -->
|
|
|
|
<!--# include file="include/top.html" -->
|
|
|
|
<p>Notes from setting up a two-level (root and intermediate) CA using EC certs, combined from two decent sets of instructions <a href="https://jamielinux.com/docs/openssl-certificate-authority/introduction.html">here</a> and <a href="https://wiki.openssl.org/index.php/Command_Line_Elliptic_Curve_Operations">here</a>. This is the CliffsNotes version; see those two docs for more detail. XXXX is used as a placeholder here; search for it and replace.</p>
|
|
|
|
<h2>Create directory structure</h2>
|
|
|
|
<pre><code>mkdir ca
|
|
cd ca
|
|
mkdir -p {root,intermediate}/{certs,crl,csr,newcerts,private}
|
|
mkdir -p {client,server}/{certs,csr,pfx,private}
|
|
touch {root,intermediate}/database
|
|
echo 1000 | tee {root,intermediate}/{serial,crlnumber}
|
|
chmod 700 {root,intermediate,client,server}/private
|
|
Create openssl.cnf
|
|
cat > openssl.cnf <<'END'
|
|
[ ca ]
|
|
default_ca = ca_intermediate
|
|
|
|
[ ca_root ]
|
|
dir = root
|
|
certs = $dir/certs
|
|
crl_dir = $dir/crl
|
|
new_certs_dir = $dir/newcerts
|
|
database = $dir/database
|
|
serial = $dir/serial
|
|
crlnumber = $dir/crlnumber
|
|
private_key = $dir/private/root.key.pem
|
|
certificate = $dir/certs/root.cert.pem
|
|
crl = $dir/crl/root.crl.pem
|
|
crl_extensions = ext_crl
|
|
default_md = sha256
|
|
name_opt = ca_default
|
|
cert_opt = ca_default
|
|
default_crl_days = 30
|
|
default_days = 3650
|
|
preserve = no
|
|
policy = policy_strict
|
|
|
|
[ ca_intermediate ]
|
|
dir = intermediate
|
|
certs = $dir/certs
|
|
crl_dir = $dir/crl
|
|
new_certs_dir = $dir/newcerts
|
|
database = $dir/database
|
|
serial = $dir/serial
|
|
crlnumber = $dir/crlnumber
|
|
private_key = $dir/private/intermediate.key.pem
|
|
certificate = $dir/certs/intermediate.cert.pem
|
|
crl = $dir/crl/intermediate.crl.pem
|
|
crl_extensions = ext_crl
|
|
default_md = sha256
|
|
name_opt = ca_default
|
|
cert_opt = ca_default
|
|
default_crl_days = 30
|
|
default_days = 375
|
|
preserve = no
|
|
policy = policy_loose
|
|
|
|
[ policy_strict ]
|
|
countryName = match
|
|
stateOrProvinceName = match
|
|
organizationName = match
|
|
organizationalUnitName = optional
|
|
commonName = supplied
|
|
emailAddress = optional
|
|
|
|
[ policy_loose ]
|
|
countryName = optional
|
|
stateOrProvinceName = optional
|
|
localityName = optional
|
|
organizationName = optional
|
|
organizationalUnitName = optional
|
|
commonName = supplied
|
|
emailAddress = optional
|
|
|
|
[ req ]
|
|
default_bits = 2048
|
|
string_mask = utf8only
|
|
default_md = sha256
|
|
distinguished_name = req_distinguished_name
|
|
|
|
[ req_distinguished_name ]
|
|
countryName = Country Name (2 letter code)
|
|
stateOrProvinceName = State or Province Name
|
|
localityName = Locality Name
|
|
0.organizationName = Organization Name
|
|
organizationalUnitName = Organizational Unit Name
|
|
commonName = Common Name
|
|
emailAddress = Email Address
|
|
|
|
[ ext_root ]
|
|
subjectKeyIdentifier = hash
|
|
authorityKeyIdentifier = keyid:always, issuer
|
|
basicConstraints = critical, CA:true
|
|
keyUsage = critical, digitalSignature, cRLSign, keyCertSign
|
|
|
|
[ ext_intermediate ]
|
|
subjectKeyIdentifier = hash
|
|
authorityKeyIdentifier = keyid:always, issuer
|
|
basicConstraints = critical, CA:true, pathlen:0
|
|
keyUsage = critical, digitalSignature, cRLSign, keyCertSign
|
|
|
|
[ ext_client ]
|
|
basicConstraints = CA:FALSE
|
|
nsCertType = client, email
|
|
nsComment = "OpenSSL Generated Client Certificate"
|
|
subjectKeyIdentifier = hash
|
|
authorityKeyIdentifier = keyid, issuer
|
|
keyUsage = critical, nonRepudiation, digitalSignature, keyEncipherment
|
|
extendedKeyUsage = clientAuth, emailProtection
|
|
|
|
[ ext_server ]
|
|
basicConstraints = CA:FALSE
|
|
nsCertType = server
|
|
nsComment = "OpenSSL Generated Server Certificate"
|
|
subjectKeyIdentifier = hash
|
|
authorityKeyIdentifier = keyid, issuer:always
|
|
keyUsage = critical, digitalSignature, keyEncipherment
|
|
extendedKeyUsage = serverAuth
|
|
|
|
[ ext_crl ]
|
|
authorityKeyIdentifier = keyid:always
|
|
|
|
[ ext_ocsp ]
|
|
basicConstraints = CA:FALSE
|
|
subjectKeyIdentifier = hash
|
|
authorityKeyIdentifier = keyid, issuer
|
|
keyUsage = critical, digitalSignature
|
|
extendedKeyUsage = critical, OCSPSigning
|
|
END
|
|
</code></pre>
|
|
|
|
<h2>Create a root key</h2>
|
|
|
|
<pre><code>openssl ecparam -name secp384r1 -genkey | openssl ec -aes-256-cbc -out root/private/root.key.pem
|
|
# Create strong root key password
|
|
chmod 400 root/private/root.key.pem
|
|
</code></pre>
|
|
|
|
<h2>Create a self-signed root cert</h2>
|
|
|
|
<pre><code>openssl req -config openssl.cnf -key root/private/root.key.pem -new -extensions ext_root -out root/certs/root.cert.pem -x509 -subj '/C=US/ST=California/O=XXXX/OU=XXXX Certificate Authority/CN=XXXX Root CA' -days 7300
|
|
# Enter root key password
|
|
chmod 444 root/certs/root.cert.pem
|
|
</code></pre>
|
|
|
|
<h2>Verify root cert</h2>
|
|
|
|
<pre><code>openssl x509 -noout -text -in root/certs/root.cert.pem
|
|
</code></pre>
|
|
|
|
<p>Check:</p>
|
|
|
|
<ul>
|
|
<li>Expiration date (20 years in future)</li>
|
|
<li>Signature algorithm (ecdsa-with-SHA256)</li>
|
|
<li>Public key size (384 bit)</li>
|
|
<li>CA:TRUE</li>
|
|
</ul>
|
|
|
|
<h2>Create an intermediate key</h2>
|
|
|
|
<pre><code>openssl ecparam -name secp384r1 -genkey | openssl ec -aes-256-cbc -out intermediate/private/intermediate.key.pem
|
|
# Create strong intermediate key password
|
|
chmod 400 intermediate/private/intermediate.key.pem
|
|
</code></pre>
|
|
|
|
<h2>Create an intermediate certificate signing request (CSR)</h2>
|
|
|
|
<pre><code>openssl req -config openssl.cnf -new -key intermediate/private/intermediate.key.pem -out intermediate/csr/intermediate.csr.pem -subj '/C=US/ST=California/O=XXXX/OU=XXXX Certificate Authority/CN=XXXX Intermediate'
|
|
# Enter intermediate key password
|
|
</code></pre>
|
|
|
|
<h2>Sign intermediate cert with root key</h2>
|
|
|
|
<pre><code>openssl ca -config openssl.cnf -name ca_root -extensions ext_intermediate -notext -in intermediate/csr/intermediate.csr.pem -out intermediate/certs/intermediate.cert.pem
|
|
# Enter root key password
|
|
chmod 444 intermediate/certs/intermediate.cert.pem
|
|
</code></pre>
|
|
|
|
<h2>Verify intermediate cert</h2>
|
|
|
|
<pre><code>openssl x509 -noout -text -in intermediate/certs/intermediate.cert.pem
|
|
openssl verify -CAfile root/certs/root.cert.pem intermediate/certs/intermediate.cert.pem
|
|
</code></pre>
|
|
|
|
<p>Check:</p>
|
|
|
|
<ul>
|
|
<li>Expiration date (10 years in future)</li>
|
|
<li>Signature algorithm (ecdsa-with-SHA256)</li>
|
|
<li>Public key size (384 bit)</li>
|
|
<li>CA:TRUE</li>
|
|
<li>OK</li>
|
|
</ul>
|
|
|
|
<h2>Create a chain certificate file</h2>
|
|
|
|
<pre><code>cat intermediate/certs/intermediate.cert.pem root/certs/root.cert.pem > intermediate/certs/chain.cert.pem
|
|
chmod 444 intermediate/certs/chain.cert.pem
|
|
</code></pre>
|
|
|
|
<h2>Create a client key</h2>
|
|
|
|
<p>You can substitute “server” for “client” for a server cert.</p>
|
|
|
|
<pre><code>openssl ecparam -name secp384r1 -genkey | openssl ec -aes-256-cbc -out client/private/test1.key.pem
|
|
# Create client key password
|
|
chmod 400 client/private/test1.key.pem
|
|
</code></pre>
|
|
|
|
<h2>Create a client certificate signing request (CSR)</h2>
|
|
|
|
<pre><code>openssl req -config openssl.cnf -new -key client/private/test1.key.pem -out client/csr/test1.csr.pem -subj '/C=US/ST=California/O=XXXX/OU=XXXX Test/CN=XXXX Test 1'
|
|
</code></pre>
|
|
|
|
<h2>Sign client cert with intermediate key</h2>
|
|
|
|
<pre><code>openssl ca -config openssl.cnf -extensions ext_client -notext -in client/csr/test1.csr.pem -out client/certs/test1.cert.pem
|
|
# Enter intermediate key password
|
|
chmod 444 client/certs/test1.cert.pem
|
|
</code></pre>
|
|
|
|
<h2>Verify client cert</h2>
|
|
|
|
<pre><code>openssl x509 -noout -text -in client/certs/test1.cert.pem
|
|
openssl verify -CAfile intermediate/certs/chain.cert.pem client/certs/test1.cert.pem
|
|
</code></pre>
|
|
|
|
<p>Check:</p>
|
|
|
|
<ul>
|
|
<li>Expiration date (1 year in future)</li>
|
|
<li>Signature algorithm (ecdsa-with-SHA256)</li>
|
|
<li>Public key size (384 bit)</li>
|
|
<li>CA:FALSE</li>
|
|
<li>OK</li>
|
|
</ul>
|
|
|
|
<h2>Create a PKCS#12 bundle for the client</h2>
|
|
|
|
<p>This is an easy(er) way to get all the necessary keys & certs to the client in one package.</p>
|
|
|
|
<pre><code>openssl pkcs12 -export -out client/pfx/test1.pfx -inkey client/private/test1.key.pem -in client/certs/test1.cert.pem -certfile intermediate/certs/chain.cert.pem
|
|
# Enter both the client key password, and a new password for the export; you'll need to give the latter to the client
|
|
</code></pre>
|
|
|
|
<h2>Generate a certificate revocation list (CRL)</h2>
|
|
|
|
<p>Initially empty. You can also do this for your root CA.</p>
|
|
|
|
<pre><code>openssl ca -config openssl.cnf -gencrl -out intermediate/crl/intermediate.crl.pem
|
|
</code></pre>
|
|
|
|
<h2>Verify certificate revocation list</h2>
|
|
|
|
<pre><code>openssl crl -in intermediate/crl/intermediate.crl.pem -noout -text
|
|
</code></pre>
|
|
|
|
<p>Check:</p>
|
|
|
|
<ul>
|
|
<li>Expiration date (30 days in future)</li>
|
|
<li>Signature algorithm (ecdsa-with-SHA256)</li>
|
|
</ul>
|
|
|
|
<h2>Revoke a certificate</h2>
|
|
|
|
<p>Only do this if you need to. Find the certificate:</p>
|
|
|
|
<pre><code>cat intermediate/database
|
|
# You'll need the hex-formatted serial number, in the third field.
|
|
# Substitute serial number for YYYY below.
|
|
</code></pre>
|
|
|
|
<p>Revoke it:</p>
|
|
|
|
<pre><code>openssl ca -config openssl.cnf -revoke intermediate/newcerts/YYYY.pem
|
|
# Enter intermediate key password
|
|
</code></pre>
|
|
|
|
<p>Generate a new CRL file:</p>
|
|
|
|
<pre><code>openssl ca -config openssl.cnf -gencrl -out intermediate/crl/intermediate.crl.pem
|
|
# Enter intermediate key password
|
|
</code></pre>
|
|
|
|
<!--# include file="include/bottom.html" -->
|