Gerenciamento de uma CA e de chaves publicas e privadas

Nesta seção, você encontrará detalhes desde como Criar uma CA privada, os Procedimentos usados por uma entidade certificadora.

Gerando uma chave RSA de 2048 bits

Siga o procedimento abaixo para gerar uma chave privada 2048. Caso deseje gerar uma chave mais forte, substitua 2048 por um número maior (como 3072, 4096):

openssl genrsa -des3 -out chave_privada.pem 2048

Gerando uma chave PKCS8 de 2048 bits

Para gerar um certificado PKCS8, siga o seguinte procedimento:

openssl genrsa 2048 | openssl pkcs8 -topk8 -out servidor.key

OBS: Note que certificados PKCs8 iniciam com -----BEGIN ENCRYPTED PRIVATE KEY-----.

Exportando a chave RSA publica para arquivo

Siga o procedimento abaixo para exporta a chave RSA pública para arquivo:

openssl rsa -in chave_privada.pem -outform PEM -pubout -out chave_publica.pem openssl rsa -in chave_privada.pem -outform PEM -pubout > chave_publica.pem

É importante SEMPRE especificar o parametro -pubout, pois o padrão é exportar a chave privada. Tenha certeza de incluílo!

Próximo passo, abra o chave_publica.pem e tenha certeza que ele começa com

-----BEGIN PUBLIC KEY-----

. Este é como o formato de arquivo de chaves pública se parece.

Desta forma, caso deseje exportar uma chave privada, remova o -pubout:

openssl rsa -in chave_privada.pem -out private_unencrypted.pem -outform PEM

Com o comando acima, a chave gerada iniciará com a strings:

-----BEGIN RSA PRIVATE KEY-----

As chaves geradas são encodificadas em base64 em formato texto plano. Caso selecione uma senha para a chave privada, o arquivo será encriptado com sua senha. Caso perca a senha o par de chave se tornará inútil.

Protegendo a chave privada

Dependendo do nível de proteção de dados que deseja proteger, é importante manter a chave privada em um backup e segura. A chave pública pode ser distribuida e embutida em aplicações web, como PHP, Ruby e outros scripts.

Para relizar o backup de uma chave privada, veja as tecnicas em “Exportando a chave RSA publica para arquivo”

Requisitos para gerenciar uma CA

Basicamente, uma entidade que funciona como CA, precisa obedecer os seguintes requisitos abaixo para permitir o gerencimaento de forma segura dos certificados gerados:

  1. Você deve publicar o certificado root da CA, assim ele poderá ser instalado em larga escala pelos aplicativos

  2. Você deve publicar o arquivo CRL

  3. Você deve publicar detalhes do certificado, fornecendo seu número serial

  4. Você deverá prover um formulário digital para os usuários enviarem requisições de certificados

É claro que um sistema que gerenciam uma CA possuem diversas camadas de segurança, passando por diversos checks para emissão, registro de acesso e armazenamento por longos períodos (pelo menos igual o equivalente ao tempo de emissão do seu maior certificado), qual canal foi solicitada a emissão, e o certificado emitido apenas após as validações de consistencias adequadas. Validação de certificados de identidade deve ser feita criteriosamente por mais de uma pessoa devidamente habilitadas para operação segura dos procedimentos e um conjunto de automações que gerenciam os ítens acima (como anúncio de CRL na web).

Criando uma CA privada

Vamos seguir passo a passo, com o procedimento para criação de uma CA privada, desde a chave, CSR até a geração do certificado. Começaremos pela geração da chave privada da CA. Execute o seguinte comando:

openssl req -new -newkey rsa:2048 -nodes -out ca/ca.csr -keyout ca/ca.key -sha256

Onde:

  • 2048 - É o tamanho da chave, quanto maior, mais segurança e mais lento nas operações de criptografia e descriptografia de dados. Valores recomendados: 2048, 3072, 4096.

  • -out [arquivo] - Especifica o arquivo de saída que armazenará o arquivo CSR. Este será usado para geração do certificado final, assinado pela entidade certificadora.

  • -keyout [arquivo] - Especifica o arquivo de saída que armazenará a chave privada gerada pelo openssl

  • -sha256 - Algoritmo usado para assinatura do certificado.

Criando um certificado de CA

Para gerar um certificado baseado na chave de CA privada:

openssl x509 -signkey ca/ca.key -days 10000 -req -in ca/ca.csr -out ca/ca.crt -sha256

Onde:

  • signkey - Chave da CA criada no passo anterior, usada para gerar o certificado privado da CA.

  • days - Especifica a validade do certificado da CA (em dias). Após este período, o certificado se tornará Inválido!.

  • -in arquivo_CSR - Especifica o caminho para o arquivo CSR gerado no passo anterior, para criação do certificado da CA.

  • -out arquivo_crt - Especifica o arquivo de Certificado que será gerado ao final do procedimento.

Assinando um arquivo CRT

Assumindo que você é uma CA e alguém te envia um arquivo CRT para validação e assinatura, siga o seguinte procedimento para assinar o Certificado, e devolver ao usuário, para que ele consiga utilizar o certificado de forma válida:

openssl x509 -req -days 768 -in csr.csr -CA ca/ca.crt -CAkey ca/ca.key -out cert-assinado.crt -set_serial 01 -sha256

Onde:

  • -in [arquivo] - Especifica o arquivo CSR enviado pelo cliente que será assinado.

  • -CAkey [arquivo] - Especifica o arquivo chave da CA que você criou anteriormente.

  • -out [arquivo] - Arquivo que será gerado e deverá ser enviado para o cliente para que ele conclua o procedimento de geração do certificado assinado por uma CA.

  • -CA [arquivo] - Especifica o certificado da CA que deverá usar para assinar o CSR.

Após executado o comando, o arquivo assinado especificado pela opção -out, deverá ser enviado ao cliente para que ele possa utilizar o certificado em sua aplicação.

Renovando um Certificado

Caso vocẽ seja uma CA (ou esteja admnistrando uma CA auto-assinada), os seguintes procedimentos precisam ser executados para criar um novo certificado:

  1. O usuário precisa enviar o antigo arquivo CSR ou criar um novo CSR baseado na antiga chave criptográfica privada.

  2. O certificado antigo precisa ser revogado antes do novo CSR enviado precisa ser assinado. Para localizar o certificado antigo, olhe no arquivo index.txt e procure pelo campo DN (Distinguished Name), que corresponde a requisição. Obtenha o número serial correspondente àquele certificado (campo Serial Number).

    No arquivo index.txt é normal encontrar os seguintes campos (e seus respectivos significados):

    • R - Certificados Revogadas

    • V - Certificados Válidos

    • E - Certificados Expirados

  3. Se desejar assinar a requisição manualmente, execute o comando: openssl ca -config /etc/openssl.cnf -out novo_certificado.pem \ -infiles newreq.pem -startdate [now] -enddate [previous enddate+365days]

    Note que este certificado utiliza a data de inicio now significando que ele permanece válido já no momento da geração. Algumas CAs colocam a validade para algumas horas antes para evitar possíveis problemas com o horário de máquinas que estão recebendo o certificado. Note que a validade do certificado é definida pela expiração anterior + 365 dias.

Agora basta enviar o novo_certificado.pem assinado para o cliente para que ele possa fazer a instalação no sistema alvo.

Revogando um Certificado

Para revogar um certificado, de o comando: openssl ca -revoke certificado.pem

O banco de dados é atualizado e o certificado marcado como revogado. Você precisará gerar o novo banco de dados CRL:

openssl ca -gencrl -config /etc/openssl.cnf -out crl/revogados-ca.crl

Nota: O arquivo CRL atualizado deverá ser sempre disponibilizado em seu website para os clientes.

Os parâmetros adiiconais aceitos durante a revogação do certificado são crldays / crlhours e crlexts. Os primeiro dos parametros indicam quando o próximo CRL será atualizado e e o último usará a sessão crl_exts no openssl.cnf para produzir um CRL v2 ao invés do CRL v1.

Segue um exemplo de revogação de certificado indicando atualização do CRL em 7 dias:

openssl ca -gencrl -config /etc/openssl.cnf -crldays 7 -crlexts crl_ext \
-out crl/sopac-ca.crl

Revogando uma CA

Como a CA é criada sendo um certificado auto-assinado (issuer é igual ao subject), ela NÃO pode ser revogada. Ninguém pode emitir um certificado de revogação que seriam autoritativos em cima daquela CA, pois representa o topo na cadeia de validação de segurança.

Entretanto, existe um consenso para evita que uma CA comprometida cause dados em toda a estrutura da árvore do topo para baixo, que consiste em remover a CA comprometida dos navegadores e banco de dados de sistemas operacionais, sem envolve rum CRL, pois devido a crescente risco de tal comprometimento, os navegadores mais modernos atualizam essa lista de CAs confiáveis automaticamente.

Isto pode ser feito também no Windows e MacOS que também possuem uma lista de certificados desautorizados, e esta lista é verificada antes da lista confiável do sistema operacional. Com isso até mesmo certificados de CA adicionadas na cadeia de confiança podem ser 'marcados' como não confiáveis.

Gerando um par de chaves RSA a partir da chave privada

execute o seguinte comando para gera o par de chaves e salvar no arquivo chave_privada.pem:

openssl genpkey -algorithm RSA -out chave_privada.pem -pkeyopt rsa_keygen_bits:2048

Após executar este procedimento, não se esqueça de remover a permissão de leitura de outros usuários com chmod go-r chave_privada.pem.

Extraindo a chave pública a partir da chave privada do certificado

Caso tenha a chave privada, e por alguma razão necessite gerar novamente a chave pública a partir deste certificado, execute o seguinte procedimento para obter o arquivo:

openssl rsa -pubout -in private_key.pem -out public_key.pem

Como mencionado anteriormente, a Chave Pública pode ser distribuida sem qualquer procupação.

Extraindo elementos texto do certificado

Siga o procediment abaixo para visualizar em formato humano, os detalhes de um certificado:

openssl rsa -text -in private_key.pem

O conteúdo do certificado será exibido para a saída padrão.

Gerando uma chave Pública

Para gerar uma chave pública em formato PEM, utilize o seguinte comando abaixo, subsituindo certificado.pem pelo nome do seu certificado privado gerado anteriormente:

openssl rsa -in certificado.pem -out chave_publica.pem -outform PEM -pubout Será gerado um arquivo chave_publica.pem, contendo o certificado público.

Gerando arquivo binário contendo números aleatórios

Alguns sistemas como o WireGuard, requerem um arquivo de números aleatórios gerado para permitir a criação de certificados. Este arquivo pode ser gerado com o comando abaixo:

openssl rand -base64 128 -out key.bin

Note que foi criada uma chave 128 bits, e será encodada usando base64.

Automatizando preenchimento de dados de certificado

Você deve ter notado que sempre que gera um certificado são requeridos dados como Cidade, País, Estado, Email, CN, etc. Esse preenchimento pode ser feito automaticamente via linha de comando, com isso seus scripts poderão operar totalmente em modo não interativo (sem intervenção humana), facilitando a adição deles em um ciclo DevOps.

Para isso, precisamos apenas informar o parametro -subj para o OpenSSL, usando a construção Chave=Valor, como abaixo:

openssl ... -subj "/C=BR/ST=ES/L=Vitoria/O=GuiaFoca/OU=Departamento de Seguranca/CN=guiafoca.org"

Como deve ter observado acima, mais de um parâmetro pode ser especificado separando os mesmos por uma /.

Usando SNI nos domínios

Mais de um nome de domínio pode ser adicionado as extesões SSl usando o subjectAltnames, com isso, o certificado será vaálido para o subject e também para os nomes DNS adicionais especificados nesse campo. Por exemplo:

openssl req -new -sha256 \
    -key guiafoca.key \
    -subj "/C=BR/ST=ES/O=Guia Foca/CN=guiafoca.org" \
    -reqexts SAN \
    -config <(cat /etc/ssl/openssl.cnf \
        <(printf "\n[SAN]\nsubjectAltName=DNS:www.guiafoca.org,DNS:www2.guiafoca.org")) \
    -out dominio.csr

Após isso, o certificdo gerado também passará a atender corretamente os dominios: guiafoca.org, www.guiafoca.org e www2.guiafoca.org.

Encriptando arquivos grandes

Devido a forma que o algoritmo RSA trabalha, não é possível encriptar arquivos muito grandes. Por padrão, o arquivo encriptado não pode ser maior que (n - 11) (onde n é o tamanho da chave). O uso mais efetivo da criptografia RSA é para encriptar uma senha gerada aleatóriamente, e então encriptar o arquivo grande usando uma criptografia simétrica.

Caso tentar encriptar um arquivo maior que o tamanho acima, o comando de encriptação finalizará com erro.

Especificando níveis de validação no Apache

Nesta seção, mostraremos como altera o nível de validação do servidor web Apache para ou relaxar ou ser rigoroso sobre a validação da cadeia de segurança de certificados. Faremos uso das opções SSLVerifyClient e SSLVerifyDepth como na configuração abaixo:

SSLVerifyClient optional
SSLVerifyDepth 1
SSLOptions +StdEnvVars

SSLVerifyClient - Permite enviar o certificado de cliente de forma opcional e dizemos que devemos verificar a CA que assinou o certificado de cliente, mas não o parent da CA (SSLVerifyDepth 1). Também que devemos passar as variáveis de ambiente SSL para o servidor (StdEnvVars).

Enviando um certificado SSL de cliente para testes

Agora que fizemos a configuração do Apache para validação de certificado de cliente (permitindo a conexão apenas para quem possuir o certificado assinado), podemos fazer o teste enviando o certificando via curl:

curl --cert guiafoca/all.crt --key guiafoca/all.key --cacert guiafoca/ca.crt https://guiafoca.org

Provavelmente você receberá um erro de CA desconhecida (“unknown ca”):

curl: (35) error:14094418:SSL routines:SSL3_READ_BYTES:tlsv1 alert unknown ca

Para corrigir isto, precisaremos dizer ao Apache sobre a CA do GuiaFoca. Fazemos isso adicionando a seguinte linha ao nosso VirtualHost:

SSLCACertificateFile /caminho/para/o/ca.crt

Agora, se fizemos uma nova requisição, veremos os dados do servidor novamente, mas dessa vez deverão existir valores que iniciam com SSL_CLIENT_. Para tornar o envio do certificado obrigatório, edite o VirtualHost e altere:

SSLVerifyClient optional

para

SSLVerifyClient require 

E reinicie o Apache. Agora, se enviar uma nova requisição via curl após fazer a verificação, e não enviar o certificado do cliente, você obterá o seguinte erro:

curl: (35) error:14094410:SSL routines:SSL3_READ_BYTES:sslv3 alert handshake failure

Verificando uma identidade

Após o procedimento de validação de chave de cliente funcional, nós podemos nos aprofundar na verificação da identidade de usuário. Existem duas formas de fazer isso:

A primeira, é verificar o número serial do certificado do usuário. Este será o mesmo durante a validade do certificado. Caso o certificado for substituido por um novo, o número serial mudará. Esta é a opção mais segura:

if ($_SERVER['SSL_CLIENT_M_SERIAL'] !== 'ABACABBF0CA') {
  echo "Você não deveria estar conectando aqui";
  exit;
}

Este código só rodará se o certificado do cliente for assinado por uma CA que você confia, mas não é o certificado que está esperando. Se não for uma CA que confie, então o comando falhará com uma falha na negociação.

A outra opção para verificar a identidade é usar o SSL_CLIENT_S_DN_Email. Um endereço de e-mail pode ser usado em múltiplos ceritifcados, assim você não poderá ter certeza que quem está confiando é a pessoal que deu o certificado client. No entanto, como você precisa confiar na CA que assinou o certificado antes, é aceitável e isto não será um risco tão grande como poderia ser:

if ($_SERVER['SSL_CLIENT_S_DN_Email'] !== '[gleydson@guiafoca.org]') {
  echo "Você não deveria estar aqui";
  exit;
}

Com essas duas opções, poderá ser escolhido identificar e autorizar o acesso de pessoas pessoas baseadas no número serial do certificado ou pelo endereço de e-mail.