🔐 Certificados Digitais na Prática — CA Interna + Apache2 com TLS

Criado por André Albuquerque em Linux 11/03/2026
Compartilhar

🔐 Certificados Digitais na Prática — CA Interna + Apache2 com TLS

Público: Analistas de segurança em formação  |  Produzido por: Base TI
Tags: 🏷️ #pki #tls #openssl #apache2 #certificados #x509 #blueteam 


Neste lab você vai construir do zero uma PKI interna completa: criar uma CA Root no Debian 13, gerar um certificado com SAN no Kali Linux, configurar o Apache2 com TLS hardened e instalar a cadeia de confiança no sistema e nos browsers. Ao final, o cadeado 🔒 aparece sem avisos — provado via openssl s_client.


📚 1. Conceitos Fundamentais

Uma Autoridade Certificadora (CA) é uma entidade confiável responsável por emitir, assinar e revogar certificados digitais X.509. Ela é a raiz da confiança (Root of Trust) em uma infraestrutura de PKI (Public Key Infrastructure).

Root CA
└── Intermediate CA (opcional)
└── Certificado Final (servidor, cliente, e-mail)

Componentes de um Certificado X.509 v3

CampoDescriçãoExemplo
SubjectIdentidade do donoCN=securecorp.local, O=SecureCorp
IssuerQuem assinouCN=SecureCorp Root CA
ValidityPeríodo de validadeNot Before / Not After
Public KeyChave pública do donoRSA 2048/4096 bits
SignatureAssinatura digital da CASHA-256 with RSA
SANSubject Alternative NamesDNS:securecorp.local, IP:192.168.56.20
ExtensionsUsos permitidosTLS Web Server Authentication

Fluxo de Emissão de Certificado

[Cliente]                          [CA]
| |
|-- 1. Gera par de chaves ------>|
| (chave privada fica local) |
| |
|-- 2. Cria CSR (pedido) ------->|
| (contém chave pública + SAN) |
| |
|<-- 3. CA assina e devolve -----|
| (certificado .crt) |
| |
|-- 4. Instala no servidor |

🏛️ 2. Analogias do Mundo Real

🏛️ A CA é o Cartório de Notas: Você não pode assinar um contrato qualquer e esperar que todos confiem. Você vai a um cartório que valida sua identidade, autentica sua assinatura e emite um documento com fé pública. A CA faz exatamente isso no mundo digital.

✈️ O Passaporte — Chain of Trust: O agente de imigração não te conhece, mas confia no seu passaporte porque confia no governo brasileiro que o emitiu. Ele não precisa te conhecer — conhece a autoridade que assinou. Browsers funcionam igual: confiam no site porque confiam na CA.

🔒 O Cadeado Assimétrico: Eu te dou o cadeado aberto (chave pública). Você coloca sua mensagem dentro e fecha. Só eu, com minha chave privada, consigo abrir. A chave privada nunca sai da sua máquina.

Conceito PKIAnalogia no Mundo Real
CA (Certificate Authority)Cartório / Receita Federal
CSRFormulário de pedido de certidão
Certificado X.509RG / CPF / Certidão autenticada
Chave PrivadaSenha do cofre — nunca sai da sua posse
Chave PúblicaNúmero do CPF — todos podem ver
Chain of TrustTabelião → Cartório → CNJ

🖧 3. Topologia do Lab

┌──────────────────────────────────────────────────────────────┐
│ Rede Interna — VMware / VirtualBox │
│ Host-Only ou NAT Network │
│ │
│ ┌───────────────────────┐ ┌───────────────────────┐ │
│ │ Debian 13 │ │ Kali Linux │ │
│ │ 192.168.56.10 │◄─────►│ 192.168.56.20 │ │
│ │ │ SCP │ │ │
│ │ [CA Root] │ │ [Cliente + Apache2] │ │
│ │ - openssl │ │ - openssl │ │
│ │ - /root/CA/ │ │ - apache2 + ssl │ │
│ └───────────────────────┘ └───────────────────────┘ │
│ │
│ SSH/SCP para transferência de arquivos │
└──────────────────────────────────────────────────────────────┘
MáquinaIPPapel
Debian 13192.168.56.10Certificate Authority (CA Root)
Kali Linux192.168.56.20Cliente + Servidor Web (Apache2)

⚙️ 4. Pré-requisitos

No Debian 13:

apt update && apt install -y openssl openssh-server
systemctl start ssh

No Kali Linux:

apt update && apt install -y openssl openssh-client apache2

Verificar conectividade (do Kali → Debian):

ping -c 3 192.168.56.10
ssh root@192.168.56.10 "echo 'Conectado com sucesso!'"

🖥️ Parte 1 — Debian 13: Construindo a CA Raiz

Passo 1 — Criar estrutura de diretórios:

mkdir -p /root/CA/{certs,crl,newcerts,private,requests}
chmod 700 /root/CA/private
cd /root/CA

echo 1000 > serial
touch index.txt
echo 1000 > crlnumber

Passo 2 — Criar o arquivo openssl.cnf:

cat > /root/CA/openssl.cnf << 'EOF'
[ ca ]
default_ca = CA_default

[ CA_default ]
dir = /root/CA
certs = $dir/certs
crl_dir = $dir/crl
new_certs_dir = $dir/newcerts
database = $dir/index.txt
serial = $dir/serial
RANDFILE = $dir/private/.rand
private_key = $dir/private/ca.key
certificate = $dir/certs/ca.crt
default_days = 365
default_crl_days = 30
default_md = sha256
preserve = no
policy = policy_strict

[ policy_strict ]
countryName = match
stateOrProvinceName = match
organizationName = match
organizationalUnitName = optional
commonName = supplied
emailAddress = optional

[ req ]
default_bits = 4096
distinguished_name = req_distinguished_name
string_mask = utf8only
default_md = sha256
x509_extensions = v3_ca

[ req_distinguished_name ]
countryName = Country Name (2 letter code)
stateOrProvinceName = State or Province Name
localityName = Locality Name
organizationName = Organization Name
organizationalUnitName = Organizational Unit Name
commonName = Common Name

[ v3_ca ]
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints = critical, CA:true
keyUsage = critical, digitalSignature, cRLSign, keyCertSign

[ v3_server ]
basicConstraints = CA:FALSE
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer
keyUsage = critical, digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth

[ v3_client ]
basicConstraints = CA:FALSE
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer
keyUsage = critical, digitalSignature, keyEncipherment
extendedKeyUsage = clientAuth
EOF

Passo 3 — Gerar chave privada da CA (RSA 4096):

🔴 NUNCA perca essa senha! Sem ela, a CA não consegue assinar novos certificados. Jamais armazene a chave privada da CA em locais acessíveis pela rede.

openssl genrsa -aes256 -out /root/CA/private/ca.key 4096
chmod 400 /root/CA/private/ca.key

Passo 4 — Gerar certificado autoassinado da CA Root (10 anos):

openssl req -config /root/CA/openssl.cnf \
-key /root/CA/private/ca.key \
-new -x509 \
-days 3650 \
-extensions v3_ca \
-out /root/CA/certs/ca.crt \
-subj "/C=BR/ST=SP/L=SaoPaulo/O=SecureCorp/OU=PKI/CN=SecureCorp Root CA"

# Verificar o certificado gerado
openssl x509 -noout -text -in /root/CA/certs/ca.crt | \
grep -E "Subject:|Issuer:|Not After|CA:true"

Saída esperada: Subject e Issuer idênticos (autoassinado) + CA:TRUE nas extensions + validade de 10 anos.


💀 Parte 2 — Kali Linux: Gerando o CSR com SAN

⚠️ Ponto crítico para browsers modernos: Chrome, Firefox e Edge exigem o campo SAN (Subject Alternative Name). Sem ele, o browser exibe aviso de segurança mesmo com CA confiável instalada. Sempre inclua o SAN!

Passo 1 — Criar diretório e arquivo de configuração com SAN:

mkdir -p ~/pki-web && cd ~/pki-web

cat > san.cnf << 'EOF'
[req]
default_bits = 2048
prompt = no
default_md = sha256
distinguished_name = dn
req_extensions = req_ext

[dn]
C = BR
ST = SP
L = SaoPaulo
O = SecureCorp
OU = WebServices
CN = securecorp.local

[req_ext]
subjectAltName = @alt_names

[alt_names]
DNS.1 = securecorp.local
DNS.2 = www.securecorp.local
IP.1 = 192.168.56.20
EOF

Passo 2 — Gerar chave privada e CSR:

# Chave privada sem senha — Apache precisa ler automaticamente no boot
openssl genrsa -out web.key 2048
chmod 400 web.key

# Gerar CSR incluindo os SANs definidos em san.cnf
openssl req -new -key web.key -out web.csr -config san.cnf

# Inspecionar o CSR — mostre para a turma!
openssl req -noout -text -in web.csr | grep -A5 "Subject Alternative"

Passo 3 — Enviar CSR para a CA (Debian):

scp web.csr root@192.168.56.10:/root/CA/requests/web.csr

🖥️ Parte 3 — Debian 13: Assinando o Certificado Web

Passo 1 — Criar arquivo de extensões SAN para a assinatura:

cat > /tmp/san_ext.cnf << 'EOF'
subjectAltName = DNS:securecorp.local, DNS:www.securecorp.local, IP:192.168.56.20
keyUsage = critical, digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth
basicConstraints = CA:FALSE
EOF

Passo 2 — Assinar o certificado com a CA:

cd /root/CA

openssl x509 -req \
-in requests/web.csr \
-CA certs/ca.crt \
-CAkey private/ca.key \
-CAcreateserial \
-out certs/web.crt \
-days 365 \
-sha256 \
-extfile /tmp/san_ext.cnf

# Verificar SAN no certificado emitido
openssl x509 -noout -text -in certs/web.crt | grep -A4 "Subject Alternative"

# Verificar cadeia de confiança
openssl verify -CAfile certs/ca.crt certs/web.crt

Esperado: web.crt: OK

Passo 3 — Devolver certificados ao Kali:

scp certs/web.crt root@192.168.56.20:/root/pki-web/web.crt
scp certs/ca.crt root@192.168.56.20:/root/pki-web/ca.crt

💀 Parte 4 — Kali: Instalando o Apache2

Passo 1 — Habilitar módulos SSL:

a2enmod ssl rewrite headers
systemctl restart apache2
systemctl enable apache2

Passo 2 — Organizar os certificados:

mkdir -p /etc/apache2/ssl

cp ~/pki-web/web.crt /etc/apache2/ssl/securecorp.crt
cp ~/pki-web/web.key /etc/apache2/ssl/securecorp.key
cp ~/pki-web/ca.crt /etc/apache2/ssl/securecorp-ca.crt

chmod 400 /etc/apache2/ssl/securecorp.key # Chave privada: só root lê
chmod 644 /etc/apache2/ssl/securecorp.crt
chmod 644 /etc/apache2/ssl/securecorp-ca.crt

ls -la /etc/apache2/ssl/

🌐 Parte 5 — Página HTML da SecureCorp

💡 Para o instrutor: A página completa com design cyberpunk dark está disponível no material de apoio como securecorp-index.html. Copie direto para /var/www/securecorp/index.html.

mkdir -p /var/www/securecorp

cat > /var/www/securecorp/index.html << 'HTMLEOF'




SecureCorp — Cyber Defense Platform




SecureCorp


Cyber Defense Platform



🔒 CONEXÃO TLS VERIFICADA



Certificado emitido por: SecureCorp Root CA

Algoritmo: SHA-256 with RSA Encryption






HTMLEOF

chown -R www-data:www-data /var/www/securecorp
chmod -R 755 /var/www/securecorp

💀 Parte 6 — Configurando Virtual Host SSL

Passo 1 — Criar o Virtual Host:

cat > /etc/apache2/sites-available/securecorp-ssl.conf << 'EOF'
# ── Redirecionar HTTP → HTTPS ──────────────────────────

ServerName securecorp.local
ServerAlias www.securecorp.local
Redirect permanent / https://securecorp.local/


# ── HTTPS com TLS hardened ─────────────────────────────

ServerName securecorp.local
ServerAlias www.securecorp.local
DocumentRoot /var/www/securecorp

SSLEngine on
SSLCertificateFile /etc/apache2/ssl/securecorp.crt
SSLCertificateKeyFile /etc/apache2/ssl/securecorp.key
SSLCACertificateFile /etc/apache2/ssl/securecorp-ca.crt

# Desabilitar protocolos antigos
SSLProtocol all -SSLv3 -TLSv1 -TLSv1.1
SSLCipherSuite ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384
SSLHonorCipherOrder off
SSLSessionTickets off

# Security Headers
Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains"
Header always set X-Frame-Options "DENY"
Header always set X-Content-Type-Options "nosniff"
Header always set Referrer-Policy "no-referrer"

ErrorLog ${APACHE_LOG_DIR}/securecorp_error.log
CustomLog ${APACHE_LOG_DIR}/securecorp_access.log combined


AllowOverride All
Require all granted


EOF

Passo 2 — Ativar e testar:

a2ensite securecorp-ssl.conf
a2dissite 000-default.conf

# ⚠️ SEMPRE testar antes de reiniciar!
apache2ctl configtest
# ✅ Esperado: Syntax OK

systemctl restart apache2
ss -tlnp | grep :443

Passo 3 — Resolver DNS local:

echo "192.168.56.20   securecorp.local www.securecorp.local" >> /etc/hosts
grep securecorp /etc/hosts

🔑 Parte 7 — Instalando a CA como Confiável

No sistema (curl, wget, Python, etc.):

cp /etc/apache2/ssl/securecorp-ca.crt \
/usr/local/share/ca-certificates/securecorp-ca.crt

update-ca-certificates
# ✅ Esperado: 1 added, 0 removed; done.

curl https://securecorp.local
# ✅ HTML da página sem erros SSL

No Firefox (manualmente):

  • Menu (☰) → Configurações → Privacidade e Segurança
  • Certificados → Ver Certificados → aba AutoridadesImportar
  • Selecione: /etc/apache2/ssl/securecorp-ca.crt
  • Marque ✅ "Confiar nessa CA para identificar sites" → OK

✅ Acesse https://securecorp.local — o cadeado 🔒 deve aparecer sem nenhum aviso!

No Chrome/Chromium (via NSS):

apt install -y libnss3-tools
mkdir -p ~/.pki/nssdb
certutil -d ~/.pki/nssdb -N --empty-password 2>/dev/null || true

certutil -d ~/.pki/nssdb \
-A -n "SecureCorp Root CA" \
-t "CT,," \
-i /etc/apache2/ssl/securecorp-ca.crt

certutil -d ~/.pki/nssdb -L | grep SecureCorp
# ✅ Esperado: SecureCorp Root CA CT,,

🔎 Parte 8 — Verificação e Demonstração

Comandos de verificação TLS:

# Ver certificado ao vivo
openssl s_client -connect securecorp.local:443 \
-CAfile /etc/apache2/ssl/securecorp-ca.crt

# Subject, Issuer e datas de validade
echo | openssl s_client -connect securecorp.local:443 2>/dev/null \
| openssl x509 -noout -subject -issuer -dates

# Cadeia completa de certificados
echo | openssl s_client -connect securecorp.local:443 -showcerts 2>/dev/null \
| grep -E "s:|i:"

# Subject Alternative Names
echo | openssl s_client -connect securecorp.local:443 2>/dev/null \
| openssl x509 -noout -text | grep -A3 "Subject Alternative"

# Versão TLS e cipher suite negociados
openssl s_client -connect securecorp.local:443 2>/dev/null \
| grep -E "Protocol|Cipher"

Roteiro de demonstração (5 min):

  • Passo 1: Sem CA instalada → mostre NET::ERR_CERT_AUTHORITY_INVALID. Pergunta: "Por que o browser desconfia?"
  • Passo 2: Instale a CA no Firefox → recarregue → mostre o 🔒 verde. Clique: "A conexão é segura" → "Ver Certificado"
  • Passo 3: Destaque: Emitido para securecorp.local, por SecureCorp Root CA, SAN com DNS e IP
  • Passo 4: Terminal → openssl s_client → mostre Verify return code: 0 (ok)

Teste de regressão (o que NÃO deve funcionar):

# Simular ataque MITM com CA falsa
openssl req -x509 -newkey rsa:2048 -keyout /tmp/fake.key \
-out /tmp/fake-ca.crt -days 1 -nodes -subj "/CN=FakeCA"

openssl verify -CAfile /tmp/fake-ca.crt /etc/apache2/ssl/securecorp.crt
# ❌ Esperado: verification failed

curl --cacert /tmp/fake-ca.crt https://securecorp.local
# ❌ Esperado: SSL certificate problem: unable to get local issuer certificate

# Verificar security headers
curl -I https://securecorp.local | grep -E "Strict|X-Frame|X-Content"
# ✅ HSTS + X-Frame-Options + X-Content-Type-Options

💡 Lição-chave: "A confiança vem da CA, não do certificado em si. Trocar a CA = browser rejeita."


🎯 Exercício Prático com Solução

🎯 Cenário — Operação SecureCorp: Você foi contratado para implementar a PKI interna. O Debian 13 é a CA. O Kali é o servidor web do portal interno. Implemente a cadeia completa e prove que a conexão é válida e confiável.

Checklist do aluno:

  • ⬜ Criar CA Root no Debian 13 com estrutura correta
  • ⬜ Gerar CSR com SAN no Kali para securecorp.local
  • ⬜ Assinar o certificado na CA e devolver ao Kali
  • ⬜ Subir Apache2 com a página da SecureCorp em HTTPS
  • ⬜ Instalar a CA no Firefox e demonstrar o cadeado verde
  • ⬜ Provar a cadeia via openssl verify e openssl s_client

Solução — Validação Rápida:

# No Debian: CA OK?
openssl x509 -noout -text -in /root/CA/certs/ca.crt \
| grep -E "CA:true|Subject:|Not After"

# No Kali: cadeia OK?
openssl verify -CAfile ~/pki-web/ca.crt /etc/apache2/ssl/securecorp.crt
# ✅ securecorp.crt: OK

# No Kali: Apache OK?
curl -sv https://securecorp.local 2>&1 | grep -E "SSL|issuer|subject|verify"

# No Kali: TLS e cipher?
echo | openssl s_client -connect securecorp.local:443 2>/dev/null \
| grep -E "Protocol|Cipher|Verify"
# ✅ Protocol : TLSv1.3
# ✅ Verify return code: 0 (ok)

✅ Checklist de Avaliação

CritérioPtsComo verificar
CA criada com estrutura correta em /root/CA/10ls /root/CA/
Certificado CA tem CA:TRUE10openssl x509 -text
CSR contém SAN (DNS + IP)15openssl req -text
Certificado assinado com SHA-25610openssl x509 -text
openssl verify retorna OK15openssl verify -CAfile ca.crt web.crt
Apache2 ouvindo na porta 44315ss -tlnp | grep :443
Redirecionamento HTTP→HTTPS ativo5curl -I http://securecorp.local
CA instalada como confiável no sistema10update-ca-certificates
Browser exibe cadeado sem avisos10Inspeção visual no Firefox
Total100

📎 Referências


🗒️ Notas

Dúvidas frequentes:

  • "Por que a chave privada não vai para a CA?"
    A CA nunca precisa da sua chave privada. O CSR já contém a chave pública. A CA usa a chave privada dela para assinar. Isso é a base da criptografia assimétrica.
  • "Qual a diferença entre .crt, .pem e .cer?"
    Mesma coisa, nomes diferentes por convenção. .pem é Base64 com header -----BEGIN-----, .der é binário. O OpenSSL usa PEM por padrão.
  • "Por que não usar Let's Encrypt para o lab?"
    Let's Encrypt valida domínios públicos via HTTP/DNS challenge. Domínios .local e IPs privados não são alcançáveis — daí a necessidade de CA própria.
  • "O que é OCSP?"
    Online Certificate Status Protocol — permite verificar em tempo real se um certificado foi revogado, sem baixar a CRL inteira. Mais eficiente em larga escala.

📌 Atenção no lab: Se o SCP falhar, use cat + copiar/colar como alternativa. Em VMs com NAT, ajuste os IPs conforme o seu ambiente. O Chrome pode exigir reinicialização após importar a CA no NSS. O /etc/hosts é obrigatório — sem ele o DNS local não resolve.


Material produzido por Base TI para o programa Hackers do Bem · 2025

Compartilhar

Compartilhar este post com outros