Verificar uma cadeia de certificados usando o openssl

128

Estou construindo uma própria cadeia de certificados com os seguintes componentes:

Root Certificate - Intermediate Certificate - User Certificate

O Root Cert é um certificado autoassinado, o Certificado Intermediário é assinado pela Raiz e o Usuário pelo Intermediário.

Agora, quero verificar se um certificado de usuário tem sua âncora pelo certificado raiz.

Com

openssl verify -verbose -CAfile RootCert.pem Intermediate.pem

a validação está ok. Na próxima etapa, valido o certificado do usuário com

openssl verify -verbose -CAfile Intermediate.pem UserCert.pem

e a validação mostra

error 20 at 0 depth lookup:unable to get local issuer certificate

O que está errado?

Indra
fonte

Respostas:

164

Da verifydocumentação:

Se for encontrado um certificado que seja seu próprio emissor, ele será considerado a CA raiz.

Em outras palavras, a CA raiz precisa ser autoassinada para que a verificação funcione. É por isso que seu segundo comando não funcionou. Tente isso:

openssl verify -CAfile RootCert.pem -untrusted Intermediate.pem UserCert.pem

Ele verificará toda a sua cadeia em um único comando.

Priyadi
fonte
2
Estou votando positivamente nesta resposta, pois recentemente fiz isso e depois de tentar as diferentes opções listadas por man verify, descobri que o -untrustedparâmetro é o correto a ser usado ao especificar o certificado intermediário.
Anthony Geoghegan
Acho que a segunda resposta: stackoverflow.com/a/31205833/173062 é mais precisa - passa a cadeia de certificados para o parâmetro -CAfile.
precisa saber é o seguinte
2
-untrustednão verifica se a cadeia de certificados é totalmente válida. Por favor, considere passar o intermediário e o root para o comando, -CAfilecomo sugere outras perguntas.
Envek
2
Use -unfusted para Intermediate.pem se for possível que aconteça o seguinte: mail.python.org/pipermail/cryptography-dev/2016-August/…
Greg Smethells 17/17
2
Não é isso que o OP solicitou, mas, caso você queira verificar a cadeia NÃO autoassinada, use o arquivo CA do sistema / navegador em vez do seu. Por exemplo, no OS X com o openssl do homebrew use:openssl verify -CAfile /usr/local/etc/openssl/cert.pem -untrusted Intermediate.pem UserCert.pem
Greg Dubicki 22/03
50

Esse é um dos poucos trabalhos legítimos para cat:

openssl verify -verbose -CAfile <(cat Intermediate.pem RootCert.pem) UserCert.pem

Atualizar:

Como Greg Smethells aponta nos comentários, esse comando confia implicitamente no Intermediate.pem . Eu recomendo a leitura da primeira parte das referências de Greg (a segunda parte é especificamente sobre pyOpenSSL e não é relevante para esta pergunta).

Caso o post desapareça, citarei os parágrafos importantes:

Infelizmente, um certificado "intermediário", na verdade um root / autoassinado , será tratado como uma CA confiável ao usar o comando recomendado fornecido acima:

$ openssl verifica -CAfile <(cat geotrust_global_ca.pem rogue_ca.pem) fake_sometechcompany_from_rogue_ca.com.pem fake_sometechcompany_from_rogue_ca.com.pem: OK

Parece que o openssl irá parar de verificar a cadeia assim que um certificado raiz for encontrado, que também pode ser Intermediate.pem se for autoassinado. Nesse caso, RootCert.pem não é considerado. Portanto, verifique se o Intermediate.pem é proveniente de uma fonte confiável antes de confiar no comando acima.

Peter
fonte
Isso realmente verificará o certificado intermediário em relação ao certificado raiz?
Augurar
Faz. Acabei de executar novamente os comandos com uma cadeia que eu sei que está correta (ela serve para o tráfego de produção do meu empregador) e, em seguida, novamente com outro certificado raiz não relacionado. Veja a essência da transcrição .
Peter
8
AVISO: NÃO use isso se o Intermediate.pem não for confiável. Para obter mais informações, leia aqui: mail.python.org/pipermail/cryptography-dev/2016-August/…
Greg Smethells 17/17
1
Obrigado por apontar isso, Greg. Quando dei a resposta, baixei as raízes e os intermediários das páginas iniciais dos emissores, para que o pensamento não me ocorresse. Atualizei a resposta para deixar claro que o intermediário é implicitamente confiável com este comando.
Peter Peter
1
@somenickname, veja o comentário de Tony. A opção -ontrusted é preferível de qualquer maneira. Eu sugiro que você faça sua própria pergunta se quiser mais ajuda. Os comentários não são o lugar certo para depurar seu problema.
Peter
17

O problema é que openssl -verifyisso não funciona.

Como Priyadi mencionou , openssl -verifypara no primeiro certificado autoassinado, portanto, você realmente não verifica a cadeia, pois geralmente o certificado intermediário é autoassinado.

Suponho que você queira ter 101% de certeza de que os arquivos de certificado estão corretos antes de tentar instalá-los no serviço da web produtivo. Esta receita aqui executa exatamente essa verificação pré-vôo.

Observe que a resposta de Pedro está correta , no entanto, a saída de openssl -verifynão é nenhuma pista de que tudo realmente funciona depois. Sim, pode encontrar alguns problemas, mas não todos.

Aqui está um script que executa a tarefa de verificar uma cadeia de certificados antes de instalá-la no Apache. Talvez isso possa ser aprimorado com algumas das mágicas mais místicas do OpenSSL, mas eu não sou um guru do OpenSSL e os seguintes trabalhos:

#!/bin/bash
# This Works is placed under the terms of the Copyright Less License,
# see file COPYRIGHT.CLL.  USE AT OWN RISK, ABSOLUTELY NO WARRANTY. 
#
# COPYRIGHT.CLL can be found at http://permalink.de/tino/cll
# (CLL is CC0 as long as not covered by any Copyright)

OOPS() { echo "OOPS: $*" >&2; exit 23; }

PID=
kick() { [ -n "$PID" ] && kill "$PID" && sleep .2; PID=; }
trap 'kick' 0

serve()
{
kick
PID=
openssl s_server -key "$KEY" -cert "$CRT" "$@" -www &
PID=$!
sleep .5    # give it time to startup
}

check()
{
while read -r line
do
    case "$line" in
    'Verify return code: 0 (ok)')   return 0;;
    'Verify return code: '*)    return 1;;
#   *)  echo "::: $line :::";;
    esac
done < <(echo | openssl s_client -verify 8 -CApath /etc/ssl/certs/)
OOPS "Something failed, verification output not found!"
return 2
}

ARG="${1%.}"
KEY="$ARG.key"
CRT="$ARG.crt"
BND="$ARG.bundle"

for a in "$KEY" "$CRT" "$BND"
do
    [ -s "$a" ] || OOPS "missing $a"
done

serve
check && echo "!!! =========> CA-Bundle is not needed! <========"
echo
serve -CAfile "$BND"
check
ret=$?
kick

echo
case $ret in
0)  echo "EVERYTHING OK"
    echo "SSLCertificateKeyFile $KEY"
    echo "SSLCertificateFile    $CRT"
    echo "SSLCACertificateFile  $BND"
    ;;
*)  echo "!!! =========> something is wrong, verification failed! <======== ($ret)";;
esac

exit $ret

Observe que a saída posterior EVERYTHING OKé a configuração do Apache, porque as pessoas que usam NginXou haproxygeralmente também podem ler e entender isso perfeitamente;)

Existe uma GistHub Gist disso que pode ter algumas atualizações

Pré-requisitos deste script:

  • Você tem os dados raiz da CA confiáveis, /etc/ssl/certscomo de costume, por exemplo, no Ubuntu
  • Crie um diretório DIRonde você armazena 3 arquivos:
    • DIR/certificate.crt que contém o certificado
    • DIR/certificate.key que contém a chave secreta do seu serviço da web (sem senha)
    • DIR/certificate.bundleque contém o CA-Bundle. Sobre como preparar o pacote, veja abaixo.
  • Agora execute o script: ./check DIR/certificate(isso pressupõe que o script seja nomeado checkno diretório atual)
  • Há um caso muito improvável de saída do script CA-Bundle is not needed. Isso significa que você (leia /etc/ssl/certs/:) já confia no certificado de assinatura. Mas isso é altamente improvável na WWW.
  • Para este teste, a porta 4433 deve ser não utilizada em sua estação de trabalho. E melhor executar isso apenas em um ambiente seguro, pois abre a porta 4433 em breve para o público, que pode ver conexões externas em um ambiente hostil.

Como criar o certificate.bundlearquivo?

Na WWW, a cadeia de confiança geralmente se parece com isso:

  • certificado confiável de /etc/ssl/certs
  • certificados intermediários desconhecidos, possivelmente com assinatura cruzada por outra CA
  • seu certificado ( certificate.crt)

Agora, a avaliação ocorre de baixo para cima, ou seja, primeiro, seu certificado é lido, então é necessário o certificado intermediário desconhecido, talvez o certificado de assinatura cruzada e, em seguida, /etc/ssl/certs é consultado para encontrar o certificado confiável adequado.

O pacote CA deve ser formado exatamente na ordem de processamento correta, ou seja, o primeiro certificado necessário (o certificado intermediário que assina seu certificado) é o primeiro no pacote. Em seguida, é necessário o certificado de assinatura cruzada.

Normalmente, sua autoridade de certificação (a autoridade que assinou seu certificado) já fornecerá um arquivo CA-bundle adequado. Caso contrário, você precisará escolher todos os certificados intermediários necessários e cateles juntos em um único arquivo (no Unix). No Windows, você pode simplesmente abrir um editor de texto (como notepad.exe) e colar os certificados no arquivo, o primeiro necessário na parte superior e os demais.

Há outra coisa. Os arquivos precisam estar no formato PEM. Algumas autoridades de certificação emitem o formato DER (um binário). O PEM é fácil de detectar: ​​é legível em ASCII. Para informações sobre como converter algo em PEM, consulte Como converter .crt em .pem e siga a estrada de tijolos amarelos.

Exemplo:

Você tem:

  • intermediate2.crt o certificado intermediário que assinou seu certificate.crt
  • intermediate1.crt outro certificado intermediário, que chamuscava intermediate2.crt
  • crossigned.crt que é um certificado de assinatura cruzada de outra CA, que assinou intermediate1.crt
  • crossintermediate.crtque é outro intermediário da outra CA que assinou crossigned.crt(você provavelmente nunca verá uma coisa dessas)

Então o apropriado catficaria assim:

cat intermediate2.crt intermediate1.crt crossigned.crt crossintermediate.crt > certificate.bundle

E como você pode descobrir quais arquivos são necessários ou não e em qual sequência?

Bem, experimente, até que o checkinforme que está tudo bem. É como um jogo de quebra-cabeça de computador para resolver o enigma. Cada. Solteiro. Tempo. Mesmo para profissionais. Mas você vai melhorar cada vez que precisar fazer isso. Então você definitivamente não está sozinho com toda essa dor. É SSL, sabe? O SSL é provavelmente um dos piores projetos que já vi em mais de 30 anos de administração profissional de sistemas. Já se perguntou por que a criptografia não se tornou popular nos últimos 30 anos? É por isso. disse nuff.

Tino
fonte
Para o downvoter: Por favor, explique o que está errado com a minha resposta. Obrigado.
Tino
2
Eu sou um dos que rejeitam. O que desencadeou o voto negativo é o seguinte: "E como você pode descobrir quais arquivos são necessários ou não e em qual sequência? Bem, experimente, até que a verificação diga que está tudo bem". Não acho que o SSL seja um caso especial. Problemas como esse devem ter uma solução determinística.
ychaouche 19/09/16
2
@ychaouche Thanks! Como você, eu gosto de coisas desterministas. A pergunta era: "O que está errado" e como fazê-lo com o "openssl Verifique". Como estamos no stackoverflow, expliquei que, seguido de uma resposta programática (portanto determinística) sim / não. Você pode usá-lo para automatizar as verificações do novo Bundle antes de instalá-lo na produção. Isso responde totalmente à pergunta. O que você não gosta é que eu contei sobre a frustração em "Como criar um pacote adequado?". Como acho que não pode haver uma resposta determinística curta para isso, responder a isso seria offtopic no contexto aqui.
Tino
6
"Como Priyadi mencionou, o openssl -verify para no primeiro certificado autoassinado, portanto, você realmente não verifica a cadeia, pois muitas vezes o certificado intermediário é autoassinado." Obviamente, os certificados intermediários nunca são autoassinados (se fossem, seriam certificados raiz). E o ponto principal da verificação é verificar se você incluiu todos os certificados na cadeia até um certificado raiz confiável. É exatamente isso que a verificação do openssl faz. No entanto, openssl tende a ser bastante conservador com suas políticas de confiança ...
Timo
4
"frequentemente o certificado intermediário é autoassinado". Isso está errado, e confusões terminológicas como essa dificultam a compreensão de um tópico que é realmente simples quando explicado da maneira correta. Do RFC 5280: "[...] os certificados CA podem ser divididos em três classes: certificados cruzados, certificados emitidos por si mesmos e certificados autoassinados. Certificados cruzados são certificados CA nos quais o emissor e o sujeito são entidades diferentes Os certificados cruzados descrevem uma relação de confiança entre as duas CAs. [...] ".
Dr. Jan-Philip Gehrcke
8

Eu tive que fazer uma verificação de um certificado letsencrypt e fiz assim:

  1. Faça o download do certificado raiz e intermediário da cadeia de confiança letsencrypt .
  2. Emita este comando:

    $ openssl verify -CAfile letsencrypt-root-cert/isrgrootx1.pem.txt -untrusted letsencrypt-intermediate-cert/letsencryptauthorityx3.pem.txt /etc/letsencrypt/live/sitename.tld/cert.pem 
    /etc/letsencrypt/live/sitename.tld/cert.pem: OK
    
Michael
fonte
1
Bem, parece que John não gostou do que eu disse obrigado. Eu insisto no duro "Obrigado", então aqui está o texto excluído: Espero que ajude você para seus certificados de criptografia. Obrigado por Priyadi, sua solução me ajudou a encontrar este comando. Por favor, certifique-se de votar em sua solução.
Michael
5

Depois de quebrar um dia inteiro no mesmo problema, sem nenhum conhecimento prévio sobre certificados SSL, baixei o Gerenciador de Chaves do CERTivity Keystores e importei meu keystore para ele, e obtive uma visualização clara da cadeia de certificados.

Captura de tela:

insira a descrição da imagem aqui

praveen.chandran
fonte
1
Não tenta responder à pergunta que é sobre como usar openssl verify.
binki
sim, mas esse tipo de ferramenta pode fornecer a visualização necessária desse tipo de coisa, se você não entender as informações enigmáticas das ferramentas de linha de comando openssl :)
precisa saber é o seguinte
2

Se você deseja apenas verificar se o emissor de UserCert.pem é realmente Intermediate.pem faça o seguinte (o exemplo usa OpenSSL 1.1.1:):

openssl verify -no-CAfile -no-CApath -partial_chain -trusted Intermediate.pem UserCert.pem

e você receberá:

UserCert.pem: OK

ou

UserCert.pem: verification failed
Marinos An
fonte
existe algum comando equivalente openssl verify -no-CAfile -no-CApath -partial_chain -trusted Intermediate.pem UserCert.pemno Python 3.7?
Bogotá
-5

Você pode verificar facilmente uma cadeia de certificados com o openssl. A cadeia completa incluirá o certificado da CA, portanto você deve ver detalhes sobre a CA e o próprio certificado.

openssl x509 -em fullchain.pem -text -noout

jorfus
fonte
4
1) Isso é totalmente sem qualquer tipo de explicação. 2) esta é uma resposta a uma pergunta que o solicitante não fez, sem nenhum contexto.
Shadur