OpenSSL PKI (parte 2) - IntermediateCA
Criar uma IntermediateCA
Mais uma vez, a(s) IntermediateCA(s) devem estar alojadas num sistema separado (server) daquele que aloja a RootCA, e o sistema da RootCA (root) deve estar airgapped e desligado da corrente.
No sistema online não me parece má ideia manter as CAs secundárias debaixo de /root/ca
, o que permite colocar o certificado da RootCA no mesmo caminho (/root/ca/certs/ca.cert.pem
). No entanto, esta é a única informação da RootCA que é necessário trazer para o host da(s) CA(s) secundária(s); é debatível se vale a pena trazer o CRL da RootCA em formato PEM e colocá-lo em /root/ca/crl/ca.crl.pem
, a não ser que este sistema online seja o mesmo que esteja a ser usado para distribuir o CRL da RootCA (como visto anteriormente).
|
|
Criamos a árvore de pastas completa para suportar a operação da IntermediateCA:
|
|
Criamos o ficheiro de configuração da Inter-CA:
|
|
Num mundo ideal, haveria várias sub-CAs, nomeadas pelo uso a que se destinariam (geralmente com conjuntos de extensões diferentes para cada utilização):
- tls-ca: certificados para servidores e clientes
- vpn-ca: certificados para VPNs
- mime-ca: certificados para email
- code-ca: certificados para code signing
- net-ca: certificados para activos de rede
A configuração dessas extensões está fora do âmbito deste documento. Mas cada uma delas teria a sua árvore de pastas e a sua cópia doopenssl.cnf
, ao qual eu daria um nome mais específico em cada caso.
Na realidade, parece que quase ninguém se dá a este trabalho; geralmente existe uma CA separada para VPNs externas, se a empresa assinar software existe uma CA para code-signing, e depois uma única CA para todos os sistemas internos.
Para que não seja preciso criar ficheiros de configuração separados para cada certificado re-especificando todas as funcionalidades que são comuns à InterCA, acrescentamos o seguinte a /root/ca/inter-ca/openssl.cnf
:
[ CA_default ]
(…)
# copy extensions missing from the CSR to the final certificate
copy_extensions = copy
De notar que como esta IntermediateCA é mais dinâmica que a RootCA, a vigência dos CRLs não deve ser maior do que 30 dias; aconselho que se configure uma tarefa periódica que refresque o CRL a cada 29 dias.
default_crl_days = 30
Criamos uma nova palavra-passe complexa para a InterCA:
|
|
Criamos a chave da InterCA indicando a palavra-passe complexa:
|
|
Generating RSA private key, 8192 bit long modulus (2 primes) ......................................................................................................................................................................................................+++ .....................................................................................................................................................................................................+++ e is 65537 (0x010001)
|
|
Criamos o Certificate Signing Request para assinarmos com a CA (note-se que fica nos CSRs da RootCA):
|
|
You are about to be asked to enter information that will be incorporated into your certificate request. What you are about to enter is what is called a Distinguished Name or a DN. There are quite a few fields but you can leave some blank For some fields there will be a default value, If you enter '.', the field will be left blank. ----- Country Name (2 letter code) [PT]: State or Province Name [Lisboa]: Locality Name [Lisboa]: Organization Name [TiagoJoaoSilva]: Organizational Unit Name [TJS]: Common Name []:**inter-ca-tjs-2** Email Address [bofh@tjs.lan]
Assinar o CSR com a RootCA
Voltamos ao sistema offline da RootCA e criamos a árvore de pastas necessária.
Como apenas vai suportar a criação das InterCAs e não a sua operação, é muito mais simples:
|
|
Trazemos do sistema online o CSR da IntermediateCA, que colocamos no mesmo local onde estava no sistema online (a pasta de CSRs da RootCA):
|
|
Para que a informação CDL e/ou AIA da RootCA seja passada à IntermediateCA, acrescentamos esta directiva à secção [ CA_default ]
de /root/ca/openssl.cnf
# copy extensions missing from the CSR to the final certificate
copy_extensions = copy
Agora assinamos o CSR; note-se que vamos indicar que a extensão a usar do /root/ca/openssl.cnf
é a [ v3_intermediate_ca ]
!
|
|
Using configuration from /root/ca/openssl.cnf Check that the request matches the signature Signature ok Certificate Details: Serial Number: 4099 (0x1003) Validity Not Before: Aug 13 23:44:07 2021 GMT Not After : Aug 11 23:44:07 2031 GMT Subject: countryName = PT stateOrProvinceName = Lisboa organizationName = TiagoJoaoSilva organizationalUnitName = TJS commonName = inter-ca-tjs-2 emailAddress = bofh@tjs.lan X509v3 extensions: X509v3 Subject Key Identifier: E3:75:25:D7:74:08:0B:23:F0:AF:E4:EC:D0:D4:52:CB:5A:3A:10:2E 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 Basic Constraints: critical CA:TRUE, pathlen:0 X509v3 Key Usage: critical Digital Signature, Certificate Sign, CRL Sign X509v3 CRL Distribution Points: Full Name: URI:http://server.tjs.lan:7788/root-ca.crl Certificate is to be certified until Aug 11 23:44:07 2031 GMT (3650 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
Verificamos a emissão:
|
|
/root/ca/inter-ca/certs/inter-ca.cert.pem: OK
Criamos um certificado para a cadeia de autoridade com um certificado Chain (também chamado Bundle), concatenando os certificados por ordem ascendente - o último será a RootCA ou o mais próximo.
|
|
Activar a IntermediateCA no sistema online
Uma vez que deixamos no sistema online tudo aquilo que a IntermediateCA necessita para funcionar, só temos de trazer (de forma segura) os certificados assinados pela RootCA para o local adequado; não encontrei nenhuma fonte que indicasse que se deveria deixar os certificados da própria IntermediateCA em /root/ca/certs
, por isso vamos deixá-los em /root/ca/inter-ca/certs
|
|
Revogação de certificados da IntermediateCA
Como o número de certificados a emitir (ou a revogar) pela IntermediateCA será muito maior, é vantajoso que se utilize o método de verificação de revogação por OCSP Responder, também chamado AIA devido à directiva que o configura (AuthorityInfoAccess).
Configuração do CNF com o endereço do OCSP Responder
Começamos por colocar no /root/ca/inter-ca/openssl.cnf
a seguinte directiva nas secções [server_cert]
e [usr_cert]
authorityInfoAccess = OCSP;URI:http://ocsp.tjs.lan:7888
Criar o certificado
Geramos uma chave:
|
|
Generating RSA private key, 4096 bit long modulus (2 primes) ...............................++++ ................................................++++ e is 65537 (0x010001)
Precisamos de inserir no CSR Informação SAN (Subject Alternative Name) específica para o OCSP:
|
|
[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 = ocsp.tjs.lan
[req_ext]
subjectAltName = @alt_names
[alt_names]
IP.1 = 192.168.1.70
DNS.1 = ocsp.tjs.lan
Criamos o CSR:
|
|
Confirmar que o CSR tem a informação SAN:
|
|
X509v3 Subject Alternative Name: IP Address:192.168.20.170, DNS:ocsp.tjs.lan
Assinar o CSR com
-extensions ocsp
:
|
|
Using configuration from /root/ca/inter-ca/openssl.cnf Check that the request matches the signature Signature ok Certificate Details: Serial Number: 4099 (0x1003) Validity Not Before: Aug 22 22:53:56 2021 GMT Not After : Nov 23 22:53:56 2023 GMT Subject: countryName = PT stateOrProvinceName = Lisboa localityName = Lisboa organizationName = Tiago Joao Silva organizationalUnitName = TJS commonName = ocsp.tjs.lan X509v3 extensions: X509v3 Basic Constraints: CA:FALSE X509v3 Subject Key Identifier: BD:A6:EE:6D:0F:73:0E:47:DC:26:9A:A8:B0:40:18:55:DB:35:6B:5A 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 X509v3 Key Usage: critical Digital Signature X509v3 Extended Key Usage: critical OCSP Signing Certificate is to be certified until Nov 23 22:53:56 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
Confirmar que o certificado tem a extensão OCSP:
|
|
X509v3 extensions: X509v3 Basic Constraints: CA:FALSE X509v3 Subject Key Identifier: BD:A6:EE:6D:0F:73:0E:47:DC:26:9A:A8:B0:40:18:55:DB:35:6B:5A 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 -- X509v3 Key Usage: critical Digital Signature X509v3 Extended Key Usage: critical OCSP Signing
|
|
Criar um OCSP Responder no OpenSSL (não usar em produção)
Para testar, vamos activar o Responder temporariamente:
- vamos usar a porta 7888, uma das que já vimos que está livre (ver a Parte 1 para detalhes)
- usando a opção
-nrequest 1
, vai fechar depois de receber um único pedido - e vamos gravar um log.
|
|
ocsp: waiting for OCSP client connections...
Abrir a porta na firewall se esta estiver activa
|
|
Fazer uma pergunta ao Responder (usando o certificado emitido para o OCSP, ou outro):
|
|
[…] Response verify OK /root/ca/inter-ca/certs/ocsp.tjs.lan.cert.pem: good This Update: Aug 22 23:06:21 2021 GMT [1]+ Done openssl ocsp -index /root/ca/inter-ca/index.txt -port 7888 -text -CA /root/ca/inter-ca/certs/inter-ca_chain.cert.pem -rkey /root/ca/inter-ca/private/ocsp.tjs.lan.key.pem -rsigner /root/ca/inter-ca/certs/ocsp.tjs.lan.cert.pem -out /root/ca/inter-ca/ocsp-log.txt -crl_check_all -nrequest 1
Verificamos o que aconteceu na comunicação com o OCSP:
|
|
OCSP Request Data: Version: 1 (0x0) Requestor List: Certificate ID: Hash Algorithm: sha1 Issuer Name Hash: AE59C598DC56A005EA5239AE471093B7924F5018 Issuer Key Hash: E37525D774080B23F0AFE4ECD0D452CB5A3A102E Serial Number: 1003 Request Extensions: OCSP Nonce: 04104CA2F5C63FA8F6A8D89256935DB37177 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 22 23:06:21 2021 GMT Responses: Certificate ID: Hash Algorithm: sha1 Issuer Name Hash: AE59C598DC56A005EA5239AE471093B7924F5018 Issuer Key Hash: E37525D774080B23F0AFE4ECD0D452CB5A3A102E Serial Number: 1003 Cert Status: good This Update: Aug 22 23:06:21 2021 GMT Response Extensions: OCSP Nonce: 04104CA2F5C63FA8F6A8D89256935DB37177 Signature Algorithm: sha256WithRSAEncryption
Configurar o OCSP Responder como um serviço permanente
Se o sistema usar o init systemd, criamos um Service Unit (outros inits usarão os seus mecanismos)
|
|
[Unit]
Description = OCSP responder using OpenSSL (for CA inter-ca)
After = network.target
[Service]
ExecStart = /usr/bin/openssl ocsp \
-index /root/ca/inter-ca/index.txt \
-port 7888 \
-rkey /root/ca/inter-ca/private/ocsp.tjs.lan.key.pem \
-rsigner /root/ca/inter-ca/certs/ocsp.tjs.lan.cert.pem \
-CA /root/ca/inter-ca/certs/inter-ca_chain.cert.pem \
-text -crl_check_all\
-out /root/ca/inter-ca/ocsp-log.txt
[Install]
WantedBy = multi-user.target
|
|
Testar o serviço:
|
|
● ocsp-responder_inter-ca.service - OCSP responder using OpenSSL (for CA inter-ca) Loaded: loaded (/etc/systemd/system/ocsp-responder_inter-ca.service; disabled; vendor preset: enabled) Active: active (running) since Mon 2021-08-23 00:21:27 WEST; 22s ago […] Aug 23 00:21:27 debian systemd[1]: Started OCSP responder using OpenSSL (for CA inter-ca). Aug 23 00:21:27 debian openssl[2585]: ocsp: waiting for OCSP client connections...
Fazer um pedido ao serviço:
|
|
Confirmar que a resposta é idêntica à que deu no teste feito anteriormente. Depois deixar o serviço como permanente:
|
|
Outras CAs
Caso esta não seja a única IntermediateCA, outras se poderiam configurar seguindo exactamente o mesmo método, bastando mudar a porta de escuta (até à 7899/TCP há mais 10 portas disponíveis).
No entanto, não é recomendado usar o OpenSSL como um OCSP Responder, porque a implementação é mínima e pouco robusta.