PKI OpenSSL (pt 3)

Certificados de servidor e de cliente

Agora que temos a nossa IntermediateCA configurada correctamente, podemos começar a utilizá-la para emitir certificados.
Notas prévias:

  • Deve-se usar metade dos bits usados na CA
  • O CN do servidor deve ser o FQDN
  • Um certificado servidor precisa de ter o mesmo FQDN repetido na informação SAN
  • O CN dos clientes pode ser qualquer coisa, não é importante.
  • Devem ser assinados com a IntermediateCA
  • Normalmente têm a duração de um ano (365) e o máximo, desde Julho de 2019, é 824 dias (+1)
  • Comando OpenSSL para certificado servidor: -extensions server_cert
  • Comando OpenSSL para certificado cliente: -extensions usr_cert
  • Só é possível copiar a informação SAN do CSR para o certificado se for colocada a opção copy_extensions = copy ou = all na secção [ca_default] do intermediate/openssl.conf; caso contrário, a informação SAN tem de ser reinserida quando se usa o comando x509 para assinar o CSR, de modo a que chegue ao certificado assinado.
  • Vamos utilizar 4 servidores:
    • offline: tem a RootCA
    • server: tem o CRLDistribution da RootCA, a IntermediateCA e os seus certificados, e o OCSP Responder da IntermediateCA
    • www: vai ter um servidor HTML certificado pela IntermediateCA
    • cliente: vai aceder ao site que está em www

Exemplo de certificado servidor: o servidor da PKI

Começar por criar uma chave; neste caso deve-se omitir o -aes256 ou a opção -passout para não criar uma palavra-passe.
Se existir uma palavra-passe, será necessário introduzi-la sempre que o processo do webserver seja iniciado…

1
2
inter="/root/ca/inter-ca"
openssl genrsa -out $inter/private/server.tjs.lan.key.pem 4096

Generating RSA private key, 4096 bit long modulus (2 primes)
...............................................................................................................++++
........................................................++++
e is 65537 (0x010001)

1
chmod 400 $inter/private/server.tjs.lan.key.pem

Criar informação SAN

É especialmente útil quando o FQDN é fictício (por exemplo, não há DNS e precisamos de certificar o IP), mas tornou-se obrigatório porque agora os certificados de Web Server têm de ter o FQDN numa entrada SAN, e tê-lo só no CN já não é suficiente…
Para o fazer, temos de criar um ficheiro .CNF extra, contendo apenas essa informação (que será diferente para cada servidor)

1
2
mkdir $inter/san
cat > $inter/san/server.tjs.lan-san.cnf
[req]
distinguished_name = req_distinguished_name
req_extensions = req_ext
prompt = no

[req_distinguished_name]
C   = PT
ST  = Lisboa
L   = Lisboa
O   = Tiago Joao Silva
OU  = TJS
CN  = server.tjs.lan
[req_ext]
subjectAltName = @alt_names

[alt_names]
IP.1 = 192.168.1.70
DNS.1 = server.tjs.lan 
DNS.2 = dns.tjs.lan
DNS.3 = chat.tjs.lan
DNS.4 = mail.tjs.lan

Criar o CSR

1
2
3
4
openssl req -config $inter/openssl.cnf \
    -key $inter/private/server.tjs.lan.key.pem \
	-config $inter/san/server.tjs.lan-san.cnf \
    -new -sha512 -out $inter/csr/server.tjs.lan.csr.pem

Confirmar que o CSR tem a informação SAN:

1
2
openssl req -noout -text -in $inter/csr/server.tjs.lan.csr.pem | \
grep -A 1 "Subject Alternative Name"

    X509v3 Subject Alternative Name:
        IP Address:192.168.1.70, DNS:server.tjs.lan, DNS:dns.tjs.lan, DNS:chat.tjs.lan, DNS:mail.tjs.lan

Assinar o CSR

Atenção que desde Julho de 2019 o tempo máximo de um certificado Server é 824 dias (+hoje) e os browsers mais recentes rejeitam certificados com mais tempo…

Caso não exista copy\_extensions = copy ou = all no inter-ca/openssl.cnf, será preciso reinserir a informação SAN com as opções -extensions req_ext e -extfile aaa-san.cnf

1
2
3
4
5
6
7
openssl ca -config $inter/openssl.cnf \
    -extensions server_cert -days 823 -notext -md sha512 \
	-extensions req_ext \
	-extfile $inter/san/server.tjs.lan-san.cnf \
	-passin file:$inter/private/inter-ca.key.pass \
    -in $inter/csr/server.tjs.lan.csr.pem \
    -out $inter/certs/server.tjs.lan.cert.pem

Caso exista copy\_extensions = copy ou = all no inter-ca/openssl.cnf, é mais simples:

1
2
3
4
5
openssl ca -config $inter/openssl.cnf \
    -extensions server_cert -days 823 -notext -md sha512 \
	-passin file:$inter/private/inter-ca.key.pass \
    -in $inter/csr/server.tjs.lan.csr.pem \
    -out $inter/certs/server.tjs.lan.cert.pem

Using configuration from /root/ca/inter-ca/openssl.cnf
Check that the request matches the signature
Signature ok
Certificate Details:
        Serial Number: 4100 (0x1004)
        Validity
            Not Before: Aug 22 23:54:31 2021 GMT
            Not After : Nov 23 23:54:31 2023 GMT
        Subject:
            countryName               = PT
            stateOrProvinceName       = Lisboa
            localityName              = Lisboa
            organizationName          = Tiago Joao Silva
            organizationalUnitName    = TJS
            commonName                = server.tjs.lan
        X509v3 extensions:
            X509v3 Basic Constraints:
                CA:FALSE
            Netscape Cert Type:
                SSL Server
            Netscape Comment:
                OpenSSL Generated Server Certificate
            X509v3 Subject Key Identifier:
                94:00:E3:58:4F:BA:20:85:F7:9C:DC:47:3C:68:A1:46:8B:78:10:AF
            X509v3 Authority Key Identifier:
                keyid:E3:75:25:D7:74:08:0B:23:F0:AF:E4:EC:D0:D4:52:CB:5A:3A:10:2E
                DirName:/C=PT/ST=Lisboa/L=Lisboa/O=TiagoJoaoSilva/OU=TJS/CN=ca-tjs-1/emailAddress=bofh@tjs.lan
                serial:10:03

            X509v3 Key Usage: critical
                Digital Signature, Key Encipherment
            X509v3 Extended Key Usage:
                TLS Web Server Authentication
            Authority Information Access:
                OCSP - URI:http://ocsp.tjs.lan:7888

Certificate is to be certified until Nov 23 23:54:31 2023 GMT (823 days)
Sign the certificate? [y/n]:Y

1 out of 1 certificate requests certified, commit? [y/n]Y
Write out database with 1 new entries
Data Base Updated

1
chmod 444 $inter/certs/server.tjs.lan.cert.pem

Verificar a ChainOfTrust com o certificado CA-CHAIN

1
2
openssl verify -CAfile $inter/certs/inter-ca_chain.cert.pem \
	$inter/certs/server.tjs.lan.cert.pem 

/root/ca/inter-ca/certs/server.tjs.lan.cert.pem: OK

Criar um certificado Chain/Bundle para o servidor

Concatenamos o certificado do servidor com o certificado CA-CHAIN:

1
2
cat $inter/certs/{server.tjs.lan.cert.pem,inter-ca_chain.cert.pem} > \
	$inter/certs/server.tjs.lan.cert_chain.pem

Testes da CA

Configurar um webserver

Precisamos de criar um certificado novo para o webserver. O IP será 192.168.1.77 e o hostname será www

1
2
3
4
inter="/root/ca/inter-ca"
openssl genrsa -out $inter/private/www.tjs.lan.key.pem 4096
chmod 400 $inter/private/www.tjs.lan.key.pem
cat > $inter/san/www.tjs.lan-san.cnf
[req]
distinguished_name = req_distinguished_name
req_extensions = req_ext
prompt = no

[req_distinguished_name]
C   = PT
ST  = Lisboa
L   = Lisboa
O   = Tiago Joao Silva
OU  = TJS
CN  = www.tjs.lan
[req_ext]
subjectAltName = @alt_names

[alt_names]
IP.1 = 192.168.1.77
DNS.1 = www.tjs.lan 
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
openssl req -config $inter/openssl.cnf \
    -key $inter/private/www.tjs.lan.key.pem \
	-config $inter/san/www.tjs.lan-san.cnf \
    -new -sha512 -out $inter/csr/www.tjs.lan.csr.pem
openssl ca -config $inter/openssl.cnf \
    -extensions server_cert -days 823 -notext -md sha512 \
	-passin file:$inter/private/inter-ca.key.pass \
    -in $inter/csr/www.tjs.lan.csr.pem \
    -out $inter/certs/www.tjs.lan.cert.pem
chmod 444 $inter/certs/www.tjs.lan.cert.pem
cat $inter/certs/{www.tjs.lan.cert.pem,inter-ca_chain.cert.pem} > \
	$inter/certs/www.tjs.lan.cert_chain.pem
chmod 444 $inter/certs/www.tjs.lan.cert_chain.pem

Para testar, instalamos um novo sistema Debian 11 sem GUI.
Editamos a configuração da interface desejada (enp0s3 é a interface primária no VirtualBox; no VMware é ens33)

1
vim /etc/network/interfaces
iface enp0s3 inet static
address 192.168.1.77/24
gateway 192.168.1.1
1
hostnamectl set-hostname www.tjs.lan

Editar o ficheiro /etc/hosts; na segunda linha, mudar para:

127.0.1.1	www.tjs.lan		www

Verificar:

1
for opt in {s,d,f}; do hostname -$opt ; done


www
tjs.lan
www.tjs.lan


Instalamos o servidor Nginx

1
apt install nginx -y

Verificamos se serve a página definida por defeito

1
wget localhost:80 -O-
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br>/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

Trazer o certificado CHAIN do servidor para o webserver e colocá-lo num caminho que não seja afectado por updates nos certificados, como uma pasta local-certs em /etc/ssl/

1
2
3
mkdir /etc/ssl/local-certs
cp www.tjs.lan.cert_chain.pem /etc/ssl/local-certs/
chmod 444 /etc/ssl/local-certs/www.tjs.lan.cert_chain.pem

Trazer também a chave privada associada ao certificado do webserver e colocá-la em /etc/ssl/private/

1
2
cp www.tjs.lan.key.pem /etc/ssl/private/
chmod 400 /etc/ssl/private/www.tjs.lan.key.pem

Mudamos a configuração do Nginx para redirecionar automaticamente pedidos feitos à porta 80 (HTTP) para a porta 443 (HTTPS), e configuramos o certificado e a chave do webserver

1
2
cp /etc/nginx/sites-available/default{,.orig}
vim /etc/nginx/sites-available/default

A partir da linha 21:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
server {
	# redirect all HTTP to HTTPS
    listen 		80;
    listen 		[::]:80;
    server_name	www.tjs.lan;
    return 301 	https://www.tjs.lan$request_uri;
}

server {
    listen              	443 ssl;
    listen              	[::]:443 ssl;
    server_name         	www.tjs.lan;
    ssl_certificate     	/etc/ssl/local-certs/www.tjs.lan.cert_chain.pem;
    ssl_certificate_key 	/etc/ssl/private/www.tjs.lan.key.pem;

Note-se que não se fechou a chaveta do site SSL, porque a configuração default continua por mais umas linhas e fecha mais abaixo.

1
2
systemctl restart nginx
wget localhost:80 -O-


--2021-08-24 21:45:45--  http://localhost/
Resolving localhost (localhost)... ::1, 127.0.0.1
Connecting to localhost (localhost)|::1|:80... connected.
HTTP request sent, awaiting response... 301 Moved Permanently
Location: https://www.tjs.lan/ [following]
--2021-08-24 21:45:45--  https://www.tjs.lan/
Resolving www.tjs.lan (www.tjs.lan)... 127.0.1.1
Connecting to www.tjs.lan (www.tjs.lan)|127.0.1.1|:443... connected.
ERROR: The certificate of ‘www.tjs.lan’ is not trusted.
ERROR: The certificate of ‘www.tjs.lan’ doesn't have a known issuer.


A redirecção está a acontecer, mas o wget local a www.tjs.lan não confia no certificado do servidor porque não conhece o certificado da RootCA.

Abrimos as portas 80 e 443 da firewall

1
2
ufw allow 80
ufw allow 443

Testar o webserver

Configuramos um cliente gráfico (por exemplo, um Debian 11 com MATE).

Resolução de nomes

Como não temos um servidor DNS com a zona tjs.lan nem com todos estes sistemas configurados, vamos adicionar o seguinte ao /etc/hosts dos três sistemas (server, www e cliente)

# printf "\
#tjs.lan\n\
192.168.1.70	server.tjs.lan      server\n\
192.168.1.70	ocsp.tjs.lan	    ocsp\n\
192.168.1.77	www.tjs.lan         www \n" \
    >> /etc/hosts

Instalar o certificado Root no cliente final

Importamos o certificado da RootCA para a home do utilizador actual do cliente.
Abrimos o Firefox, Preferences, Privacy and Security, View Certificates…
Ou (about:preferences#privacy)


Import…

Escolhemos o certificado da RootCA, Open

Trust this CA to identify websites
Trust this CA to identify email users (opcional)
OK

Clicando em View, podemos ver detalhes do certificado

Temos a Authority importada, OK

Testar o site

Abrimos http://www.tjs.lan (pode ser necessário dizer ao Firefox que queremos mesmo ir para esse endereço), e temos uma ligação SSL protegida com o nosso certificado:

Configurar OCSP Stapling

Fonte: https://www.digitalocean.com/community/tutorials/how-to-configure-ocsp-stapling-on-apache-and-nginx
Trazemos para o webserver o certificado da RootCA

1
cp ca.cert.pem /etc/ssl/local-certs/

Adicionamos as linhas seguintes ao site activo no Nginx (estávamos a usar /etc/nginx/sites-available/default), por baixo de ssl_certificate_key:

1
2
3
ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /etc/ssl/local-certs/ca.cert.pem;

Testar

A partir do cliente, testar o processo de OCSP Stapling com o comando seguinte, não esquecendo de indicar o certificado da CA (que deixámos na homefolder do utilizador quando o importamos para dentro do Firefox); se o apagou, é necessário trazê-lo de novo para o cliente para que possa ser usado agora:

1
echo QUIT | sudo openssl s_client -connect www.tjs.lan:443 -CAfile ~/ca.cert.pem -status

CONNECTED(00000003)
depth=2 C = PT, ST = Lisboa, L = Lisboa, O = TiagoJoaoSilva, OU = TJS, CN = ca-tjs-1, emailAddress = bofh@tjs.lan
verify return:1
depth=1 C = PT, ST = Lisboa, O = TiagoJoaoSilva, OU = TJS, CN = inter-ca-tjs-2, emailAddress = bofh@tjs.lan
verify return:1
depth=0 C = PT, ST = Lisboa, L = Lisboa, O = Tiago Joao Silva, OU = TJS, CN = www.tjs.lan
verify return:1
OCSP response: 
======================================
OCSP Response Data:
    OCSP Response Status: successful (0x0)
    Response Type: Basic OCSP Response
    Version: 1 (0x0)
    Responder Id: C = PT, ST = Lisboa, L = Lisboa, O = Tiago Joao Silva, OU = TJS, CN = ocsp.tjs.lan
    Produced At: Aug 24 22:18:56 2021 GMT
    Responses:
    Certificate ID:
      Hash Algorithm: sha1
      Issuer Name Hash: AE59C598DC56A005EA5239AE471093B7924F5018
      Issuer Key Hash: E37525D774080B23F0AFE4ECD0D452CB5A3A102E
      Serial Number: 1007
    Cert Status: good
    This Update: Aug 24 22:18:56 2021 GMT
[…]
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number: 4099 (0x1003)
        Signature Algorithm: sha512WithRSAEncryption
        Issuer: C=PT, ST=Lisboa, O=TiagoJoaoSilva, OU=TJS, CN=inter-ca-tjs-2/emailAddress=bofh@tjs.lan
        Validity
            Not Before: Aug 22 22:53:56 2021 GMT
            Not After : Nov 23 22:53:56 2023 GMT
        Subject: C=PT, ST=Lisboa, L=Lisboa, O=Tiago Joao Silva, OU=TJS, CN=ocsp.tjs.lan
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                RSA Public-Key: (4096 bit)
[…]
---
Certificate chain
 0 s:C = PT, ST = Lisboa, L = Lisboa, O = Tiago Joao Silva, OU = TJS, CN = www.tjs.lan
   i:C = PT, ST = Lisboa, O = TiagoJoaoSilva, OU = TJS, CN = inter-ca-tjs-2, emailAddress = bofh@tjs.lan
 1 s:C = PT, ST = Lisboa, O = TiagoJoaoSilva, OU = TJS, CN = inter-ca-tjs-2, emailAddress = bofh@tjs.lan
   i:C = PT, ST = Lisboa, L = Lisboa, O = TiagoJoaoSilva, OU = TJS, CN = ca-tjs-1, emailAddress = bofh@tjs.lan
 2 s:C = PT, ST = Lisboa, L = Lisboa, O = TiagoJoaoSilva, OU = TJS, CN = ca-tjs-1, emailAddress = bofh@tjs.lan
   i:C = PT, ST = Lisboa, L = Lisboa, O = TiagoJoaoSilva, OU = TJS, CN = ca-tjs-1, emailAddress = bofh@tjs.lan
---
Server certificate
-----BEGIN CERTIFICATE-----
[…]
subject=C = PT, ST = Lisboa, L = Lisboa, O = Tiago Joao Silva, OU = TJS, CN = www.tjs.lan

issuer=C = PT, ST = Lisboa, O = TiagoJoaoSilva, OU = TJS, CN = inter-ca-tjs-2, emailAddress = bofh@tjs.lan

---
No client certificate CA names sent
Peer signing digest: SHA256
Peer signature type: RSA-PSS
Server Temp Key: X25519, 253 bits
---
SSL handshake has read 11091 bytes and written 392 bytes
Verification: OK
---
New, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384
Server public key is 4096 bit
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
Early data was not sent
Verify return code: 0 (ok)
---
---
Post-Handshake New Session Ticket arrived:
SSL-Session:
    Protocol  : TLSv1.3
    Cipher    : TLS_AES_256_GCM_SHA384
    Session-ID: 18DD0A571D36D69EC35D46FBC8F28711DDEED91000F1F595897B061640DD86E9
    Session-ID-ctx: 
    Resumption PSK: 2B54CFDFF0170EDC5F77AE462A18AAA4DC7CC3CED7B21E2F6B97454A0AB65725AE63DDA084379C793DADF63983606283
    PSK identity: None
    PSK identity hint: None
    SRP username: None
    TLS session ticket lifetime hint: 300 (seconds)
    TLS session ticket:
    0000 - 28 c6 3d 71 b3 5c 60 1f-a8 7d 5f f7 26 3c cd f5   (.=q.\`..}_.&<..
    0010 - 07 ca 09 c9 4f 92 45 7a-28 a0 ff bc 1e 5a d2 19   ....O.Ez(....Z..
    0020 - 1f 19 d4 47 06 20 45 5e-f5 68 90 74 c1 66 e8 5b   ...G. E^.h.t.f.[
    0030 - 9d aa eb 47 36 2e 6f e0-4b d3 05 a3 5c cf 29 c0   ...G6.o.K...\.).
    0040 - 15 b6 f2 07 1b d5 49 df-33 f9 3b 9d 86 5a 43 dc   ......I.3.;..ZC.
    0050 - 5e 82 3b 8b 67 0a 57 99-ac 1b cc e0 e7 99 fc ef   ^.;.g.W.........
    0060 - a9 b5 72 c2 3b 2d b2 88-10 0c 1c 9f 0b 32 60 b1   ..r.;-.......2`.
    0070 - 5b 1b d4 07 7b b5 39 69-ba 70 84 bd fd ac 22 75   [...{.9i.p...."u
    0080 - bd 34 12 66 33 55 0c c4-2e 7f 7b 40 f0 28 ab eb   .4.f3U....{@.(..
    0090 - 68 58 5f e6 30 b8 5e 36-3f b9 0b ec 99 7f 0a 23   hX_.0.^6?......#
    00a0 - fa 2e a6 43 c1 22 a3 42-d5 a5 ba 81 9f 08 16 e1   ...C.".B........
    00b0 - 11 22 1a d7 e9 d0 30 eb-84 30 b4 66 b8 b0 55 26   ."....0..0.f..U&
    00c0 - 20 de ce 79 d2 4a 16 ef-5b 7c 0f d1 20 76 8d 7c    ..y.J..[|.. v.|
    00d0 - 23 46 3b ba 52 41 32 8e-d9 1e 00 40 cf 99 fb 19   #F;.RA2....@....
    00e0 - 11 57 3b 15 6e 11 2b 69-3b 66 b8 0d 25 7b 01 4c   .W;.n.+i;f..%{.L

    Start Time: 1629850720
    Timeout   : 7200 (sec)
    Verify return code: 0 (ok)
    Extended master secret: no
    Max Early Data: 0
---
read R BLOCK
---
Post-Handshake New Session Ticket arrived:
SSL-Session:
    Protocol  : TLSv1.3
    Cipher    : TLS_AES_256_GCM_SHA384
    Session-ID: 94D2D4E6AF0537B7954B0598F85D0CB83DD0867A723BEBB3DB2049DAE5732D14
    Session-ID-ctx: 
    Resumption PSK: 2450AA5D903DCB94D409C7DB761892864AA712372CB373022321247D83178F6BB520E6B43D0D0154E92766CC16806391
    PSK identity: None
    PSK identity hint: None
    SRP username: None
    TLS session ticket lifetime hint: 300 (seconds)
    TLS session ticket:
    0000 - 28 c6 3d 71 b3 5c 60 1f-a8 7d 5f f7 26 3c cd f5   (.=q.\`..}_.&<..
    0010 - 2e 43 d1 89 25 84 e5 dd-91 82 37 ad b9 95 13 3d   .C..%.....7....=
    0020 - de b5 14 d6 16 f3 d0 24-e0 b9 14 c2 87 b8 ce ed   .......$........
    0030 - a9 0e cd 1f 9e 3a 8a fe-b8 a2 14 e4 5d 1d e9 5b   .....:......]..[
    0040 - e4 18 22 e7 c5 61 de fc-9b 02 66 72 1f fb 89 b4   .."..a....fr....
    0050 - c5 00 4d d9 0d 15 49 e3-6c 4f 9e ad 99 ea 10 fb   ..M...I.lO......
    0060 - f6 b8 83 9f 29 59 59 c6-69 b3 35 cb 1f 19 3a ff   ....)YY.i.5...:.
    0070 - c2 53 af db 84 e0 07 6e-fc 26 59 b7 9c 1b 79 f1   .S.....n.&Y...y.
    0080 - 14 77 9d bb d4 c6 3c 90-39 9f 94 dc f8 ab 51 df   .w....<.9.....Q.
    0090 - 52 59 cc 13 47 ac 68 11-7c 24 c9 d9 54 3d 0b 88   RY..G.h.|$..T=..
    00a0 - bd 19 47 f1 e7 57 d4 6f-ad 61 71 68 6e e4 37 2c   ..G..W.o.aqhn.7,
    00b0 - c5 ac 45 b1 a1 1a ab 38-c0 2d 51 39 86 2f b7 fb   ..E....8.-Q9./..
    00c0 - 5b 4d 57 b8 19 94 da 6c-45 7d 24 23 b6 08 10 6a   [MW....lE}$#...j
    00d0 - 76 10 31 1a 91 c2 98 80-bb 49 07 88 65 df ea 24   v.1......I..e..$

    Start Time: 1629850720
    Timeout   : 7200 (sec)
    Verify return code: 0 (ok)
    Extended master secret: no
    Max Early Data: 0
---
read R BLOCK

Revogação com OSCP Responder

O Stapling costuma ter uma validade de 7 dias, em que o server guarda a resposta e já não contacta de novo o OCSP para obter a confirmação da validade do certificado, enviando directamente a resposta anterior ao cliente.
Isto significa que se revogarmos o certificado agora, só daqui a 7 dias é que o cliente recusará o certificado do webserver.
A não ser, claro, que o webserver seja reiniciado para perder a memória da resposta OCSP…
Vamos revogar o certificado do webserver:

1
2
3
4
5
6
stamp=$(date +%F_%T)
mv /root/ca/inter-ca/certs/www.tjs.lan.cert.pem{,-revoked_$stamp}
openssl ca -config /root/ca/inter-ca/openssl.cnf \
	-passin file:/root/ca/inter-ca/private/inter-ca.key.pass \
    -revoke /root/ca/inter-ca/certs/www.tjs.lan.cert.pem-revoked_$stamp \
	-crl_reason superseded

Using configuration from /root/ca/inter-ca/openssl.cnf
Revoking Certificate 1007.
Data Base Updated

Reiniciamos o serviço do ocsp, para que este fique actualizado com o novo CRL

1
systemctl restart ocsp-responder_inter-ca.service

Reiniciamos o serviço do nginx em www, para perder a cache do OCSP Stapling

1
systemctl restart nginx
1
echo QUIT | sudo openssl s_client -connect www.tjs.lan:443 -CAfile ~/ca.cert.pem -status

CONNECTED(00000003)
depth=2 C = PT, ST = Lisboa, L = Lisboa, O = TiagoJoaoSilva, OU = TJS, CN = ca-tjs-1, emailAddress = bofh@tjs.lan
verify return:1
depth=1 C = PT, ST = Lisboa, O = TiagoJoaoSilva, OU = TJS, CN = inter-ca-tjs-2, emailAddress = bofh@tjs.lan
verify return:1
depth=0 C = PT, ST = Lisboa, L = Lisboa, O = Tiago Joao Silva, OU = TJS, CN = www.tjs.lan
verify return:1
OCSP response: no response sent

Confirmar que os clientes vêem o certificado como revogado

E quando tentamos aceder a www.tjs.lan pelo Firefox, somos informados que o certificado foi revogado:

Criar um novo certificado para substituir o revogado

Caso esteja a seguir o tutorial por ordem, é melhor emitir um certificado novo para www.tjs.lan antes de prosseguir.

Não esquecer que uma vez que a chave não foi comprometida nem a informação do servidor www mudou, o seu CSR continua válido, e por isso só é necessário repetir os passos da assinatura do CSR em diante. Caso a chave privada tivesse sido comprometida, seria necessário emitir um novo certificado para www a partir do zero.

Depois é preciso fazê-lo chegar ao local adequado em www.tjs.lan, reiniciar o nginx, e testar de novo o acesso ao webserver no cliente:

Revogar a IntermediateCA

Para revogarmos a IntermediateCA (vamos supor que alguém deixou a chave privada da IntermediateCA num repositório público do GitHub), temos de nos deslocar à RootCA, que está offline, e seguir os passos descritos na secção correspondente:

1
2
3
4
5
6
stamp=$(date +%F_%T)
mv /root/ca/inter-ca/certs/inter-ca.cert.pem{,-revoked_$stamp}
openssl ca -config /root/ca/openssl.cnf \
	-passin file:/root/ca/private/ca.key.pass \
    -revoke /root/ca/inter-ca/certs/inter-ca.cert.pem-revoked_$stamp \
	-crl_reason keyCompromise

Using configuration from /root/ca/openssl.cnf
Revoking Certificate 1003.
Data Base Updated

A seguir actualizamos o CRL e convertêmo-lo para DER, seguindo os passos da secção correspondente:

1
2
3
4
5
6
openssl ca -config /root/ca/openssl.cnf -gencrl \
	-passin file:/root/ca/private/ca.key.pass \
	-keyfile /root/ca/private/ca.key.pem -cert /root/ca/certs/ca.cert.pem \
	-out /root/ca/crl/ca.crl.pem
openssl crl -inform PEM -in /root/ca/crl/ca.crl.pem \
	-outform DER -out /root/ca/crl/root-ca.crl

Podemos ver que o CRL alterado tem uma entrada nova:

1
openssl crl -inform DER -text -noout -in /root/ca/crl/root-ca.crl

Certificate Revocation List (CRL):
        Version 2 (0x1)
        Signature Algorithm: sha512WithRSAEncryption
        Issuer: C = PT, ST = Lisboa, L = Lisboa, O = TiagoJoaoSilva, OU = TJS, CN = ca-tjs-1, emailAddress = bofh@tjs.lan
        Last Update: Aug 25 20:50:52 2021 GMT
        Next Update: Sep 14 20:50:52 2022 GMT
        CRL extensions:
            X509v3 Authority Key Identifier:
                keyid:01:F2:CC:54:E0:F2:58:AC:E2:14:8E:2B:DB:6D:B6:FF:5C:25:41:A0

            X509v3 CRL Number:
                4098
Revoked Certificates:
    Serial Number: 1001
        Revocation Date: Aug 13 22:11:25 2021 GMT
        CRL entry extensions:
            X509v3 CRL Reason Code:
                Unspecified
    Serial Number: 1002
        Revocation Date: Aug 13 23:41:51 2021 GMT
        CRL entry extensions:
            X509v3 CRL Reason Code:
                Superseded
    Serial Number: 1003
        Revocation Date: Aug 25 20:45:54 2021 GMT
        CRL entry extensions:
            X509v3 CRL Reason Code:
                Key Compromise

Trazer o CRL actualizado do offline para online

Usando um meio seguro que não quebre o airgapping do sistema da RootCA, levamos este ficheiro DER ao servidor que aloja a distribuição do CRL da RootCA:

1
2
cp root-ca.crl /var/www/crl
systemctl restart lighttpd.service

Para eliminar a cache do OCSP Stapling, também é necessário reiniciar o webserver se queremos que a revogação seja imediatamente reconhecida em vez de esperarmos 7 dias:

1
systemctl restart nginx.service

Testar a revogação da IntermediateCA

Em browsers modernos (falha)

O site continua a ser reconhecido como seguro no Firefox, porque aparentemente os browsers não se dão ao trabalho de verificar a cadeia inteira de certificados (nem mesmo por OCSP), confiando apenas na lista interna de RootCAs e em CRLs internos distribuídos com as actualizações.
A única excepção é o velhinho Internet Explorer, paz à sua alma, que vamos testar já a seguir.
https://news.netcraft.com/archives/2013/05/13/how-certificate-revocation-doesnt-work-in-practice.html
E não consigo encontrar um comando openssl verify que me consiga indicar que a cadeia do certificado www.tjs.lan.cert_chain.pem está quebrada pela revogação da IntermediateCA
(https://stackoverflow.com/questions/25482199/verify-a-certificate-chain-using-openssl-verify)
O uso de PKI em browsers parece que utiliza muitos atalhos…

Em Internet Explorer

Para testar com Internet Explorer, precisamos de um cliente Windows, por isso provisionei uma VM Windows 7.

Importar o certificado da RootCA

Trazer o certificado da RootCA para o cliente Windows e salvar como ca.cert.cer)

.CER é a extensão típica do Windows para ficheiros PEM (Base64)

Win+R, certmgr.msc
Seleccionar Trusted Root Certification Authorities/Certificates
All Tasks > Import…

Escolher o certificado (Browse…)

Confirmar que queremos instalar em Trusted Root

Yes

E está instalado

Ficheiro hosts

Agora precisamos de colocar a mesma informação no ficheiro hosts para resolver a falta de DNS.
Abrir o Notepad com permissões de administrador (clique direito em cima do Notepad, Run as administrator)

Abrir o ficheiro %SystemRoot%\System32\drivers\etc\hosts
Colar:

#tjs.lan
192.168.1.70		server.tjs.lan 	server
192.168.1.70		ocsp.tjs.lan	ocsp
192.168.1.77		www.tjs.lan 	www

Salvar o ficheiro e sair do Notepad.

Abrir o site no IE

Agora podemos testar se o IE reconhece que a Inter-CA que assinou o certificado do nosso site foi revogada:
E o resultado é sim, o Internet Explorer consulta e respeita uma PKI interna a uma empresa, em vez de se limitar àquilo que já sabe sobre a PKI pública utilizada na Internet.