Gerando um certificado autoassinado com openssl que funciona no Chrome 58

52

No Chrome 58, ele não aceita mais certificados autoassinados que dependem de Common Name: https://productforums.google.com/forum/#!topic/chrome/zVo3M8CgKzQ;context-place=topicsearchin/chrome/category $ 3ACanary% 7Cortar: relevância% 7Cspell: false

Em vez disso, requer o uso Subject Alt Name. Anteriormente, segui este guia sobre como gerar um certificado autoassinado: https://devcenter.heroku.com/articles/ssl-certificate-self que funcionou muito bem porque exigi os arquivos server.crte server.keypara o que estou fazendo. Agora, preciso gerar novos certificados que incluam, no SANentanto, todas as minhas tentativas de fazê-lo não funcionaram com o Chrome 58.

Aqui está o que eu fiz:

Eu segui as etapas no artigo Heroku acima mencionado para gerar a chave. Eu então escrevi um novo arquivo de configuração do OpenSSL:

[ req ]
default_bits        = 2048
distinguished_name  = req_distinguished_name
req_extensions      = san
extensions          = san
[ req_distinguished_name ]
countryName         = US
stateOrProvinceName = Massachusetts
localityName        = Boston
organizationName    = MyCompany
[ san ]
subjectAltName      = DNS:dev.mycompany.com

Em seguida, gerou o server.crtcom o seguinte comando:

openssl req \
-new \
-key server.key \
-out server.csr \
-config config.cnf \
-sha256 \
-days 3650

Como estou em um Mac, abri o server.crtarquivo com o Keychain e o adicionei aos meus Certificados do sistema. Eu então o defino Always Trust.

Com exceção do arquivo de configuração para definir o valor da SAN, foram etapas semelhantes que usei nas versões anteriores do Chrome para gerar e confiar no certificado autoassinado.

No entanto, depois disso, ainda recebo o ERR_CERT_COMMON_NAME_INVALIDno Chrome 58.

bcardarella
fonte

Respostas:

62

Minha solução:

openssl req \
    -newkey rsa:2048 \
    -x509 \
    -nodes \
    -keyout server.key \
    -new \
    -out server.crt \
    -subj /CN=dev.mycompany.com \
    -reqexts SAN \
    -extensions SAN \
    -config <(cat /System/Library/OpenSSL/openssl.cnf \
        <(printf '[SAN]\nsubjectAltName=DNS:dev.mycompany.com')) \
    -sha256 \
    -days 3650

Status: Funciona para mim

bcardarella
fonte
2
ótimo uso do subshell. Eu acho que você pode simplificar um pouco:-config <(cat /System/Library/OpenSSL/openssl.cnf ; printf '[SAN]\nsubjectAltName=DNS:dev.mycompany.com')
jrwren
11
Eu não recebo mais o erro Nome alternativo do assunto, mas agora recebo um erro sobre o nome comum e a configuração do certificado baixado para "sempre confiar" não funciona. Alguma ideia? @bcardarella
rugbert
2
Com a atualização para o Chrome 59, o certificado mostra um erro como este: Há problemas na cadeia de certificados do site (net :: ERR_CERT_COMMON_NAME_INVALID).
precisa
11
Mudei dev.company.namepara localhoste isso funcionou para servir o site de desenvolvimento local do localhost. No macOS, também tive que adicionar o certificado ao Keychain e definir o SSL como "Sempre confie".
Daniel M.
11
Essa é de longe a solução mais simples e não requer mexer com o sslconf ou instalar uma CA.
bp.
16

No Windows, salve este script na sua pasta SSL como makeCERT.bat. Ele criará esses arquivos: example.cnf, example.crt, example.key

@echo off

REM IN YOUR SSL FOLDER, SAVE THIS FILE AS: makeCERT.bat
REM AT COMMAND LINE IN YOUR SSL FOLDER, RUN: makecert
REM IT WILL CREATE THESE FILES: example.cnf, example.crt, example.key
REM IMPORT THE .crt FILE INTO CHROME Trusted Root Certification Authorities
REM REMEMBER TO RESTART APACHE OR NGINX AFTER YOU CONFIGURE FOR THESE FILES

REM PLEASE UPDATE THE FOLLOWING VARIABLES FOR YOUR NEEDS.
SET HOSTNAME=example
SET DOT=com
SET COUNTRY=US
SET STATE=KS
SET CITY=Olathe
SET ORGANIZATION=IT
SET ORGANIZATION_UNIT=IT Department
SET EMAIL=webmaster@%HOSTNAME%.%DOT%

(
echo [req]
echo default_bits = 2048
echo prompt = no
echo default_md = sha256
echo x509_extensions = v3_req
echo distinguished_name = dn
echo:
echo [dn]
echo C = %COUNTRY%
echo ST = %STATE%
echo L = %CITY%
echo O = %ORGANIZATION%
echo OU = %ORGANIZATION_UNIT%
echo emailAddress = %EMAIL%
echo CN = %HOSTNAME%.%DOT%
echo:
echo [v3_req]
echo subjectAltName = @alt_names
echo:
echo [alt_names]
echo DNS.1 = *.%HOSTNAME%.%DOT%
echo DNS.2 = %HOSTNAME%.%DOT%
)>%HOSTNAME%.cnf

openssl req -new -x509 -newkey rsa:2048 -sha256 -nodes -keyout %HOSTNAME%.key -days 3560 -out %HOSTNAME%.crt -config %HOSTNAME%.cnf
STWilson
fonte
13

Aqui está uma solução que funciona para mim:

Criar chave e certificado CA

# openssl genrsa -out server_rootCA.key 2048
# openssl req -x509 -new -nodes -key server_rootCA.key -sha256 -days 3650 -out server_rootCA.pem

Crie server_rootCA.csr.cnf

# server_rootCA.csr.cnf
[req]
default_bits = 2048
prompt = no
default_md = sha256
distinguished_name = dn

[dn]
C=DE
ST=Berlin
L=NeuKoelln
O=Weisestrasse
OU=local_RootCA
[email protected]
CN = server.berlin

Criar arquivo de configuração v3.ext

# v3.ext
authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
subjectAltName = @alt_names

[alt_names]
DNS.1 = server.berlin

Criar chave do servidor

# openssl req -new -sha256 -nodes -out server.csr -newkey rsa:2048 -keyout server.key -config <( cat server_rootCA.csr.cnf )

Criar certificado de servidor

# openssl x509 -req -in server.csr -CA server_rootCA.pem -CAkey server_rootCA.key -CAcreateserial -out server.crt -days 3650 -sha256 -extfile v3.ext

Adicione certificado e chave ao arquivo do site Apache2, seção HTTPS (porta 443)

SSLCertificateFile    /etc/apache2/ssl/server.crt
SSLCertificateKeyFile    /etc/apache2/ssl/server.key

Copie server_rootCA.pem do servidor para sua máquina.

# scp [email protected]:~/server_rootCA.pem .

.. e adicione-o ao navegador Chromium

Chromium -> Setting -> (Advanced) Manage Certificates -> Import -> 'server_rootCA.pem'

VOCÊ ESTÁ TODO FEITO!

PS Em vez de criar um par de certificação CA e servidor funcional (conforme as instruções acima), você pode simplesmente desativar os cabeçalhos HSTS na configuração do servidor HTTP. Isso impedirá o Chromium de aplicar o HTTPS e permitirá que os usuários cliquem em "Avançado → avance para your.url (inseguro)" sem precisar obter e instalar seu certificado CA personalizado (server_rootCA.pem). Em outras palavras, ter que desativar o HSTS permitirá que seu site seja exibido publicamente por HTTP e / ou conexão HTTPS insegura (cuidado!).

Para o Apache2, adicione o seguinte ao arquivo do site, seção HTTP (porta 80)

Header unset Strict-Transport-Security
Header always set Strict-Transport-Security "max-age=0;includeSubDomains"

Testado no Debian / Apache2.4 + Debian / Chromium 59

https://ram.k0a1a.net/self-signed_https_cert_after_chrome_58

binary.koala
fonte
Seguir a rota de uma autoridade de autoridade de certificação raiz que mais tarde assina os certificados individuais é a única maneira de obter o chrome para autenticar completamente; também tem a vantagem de que eu só precisava que as pessoas instalassem um único certificado. Graças
Geoff
4
Alguém por favor pode me explicar por que todos nesta área parecem usar bashisms como em -config <( cat server_rootCA.csr.cnf )vez de apenas -config server_rootCA.csr.cnf?
César
você pode atualizar sua resposta relacionada aos cabeçalhos do apache que podem contornar o problema (não me importo que isso seja apenas para sites locais de desenvolvimento e eu gostaria de uma solução genérica sem precisar gerar novos certificados a cada vez). Você pode apontar para onde eles devem ir dentro de uma definição de host virtual. Eu tentei várias alternativas e ainda não consigo acessar os sites através do https. Obrigado
Nikos M.
12

Existem várias ótimas respostas que dão exemplos de como fazer isso funcionar, mas nenhuma que explica onde as coisas deram errado em sua tentativa. O OpenSSL pode ser bastante intuitivo algumas vezes, por isso vale a pena percorrer.

Primeiro, como um aparte, o OpenSSL usa como padrão ignorar qualquer valor de nome distinto fornecido na configuração. Se você quiser usá-los, você deve adicionar prompt = no à sua configuração. Além disso, o comando conforme escrito gera apenas uma solicitação de certificado, não um certificado em si, portanto, o -dayscomando não faz nada.

Se você gerar sua solicitação de certificado usando este comando, você forneceu e inspecionou o resultado, o Nome Alt do Assunto está presente:

$ openssl req -new -key server.key -out server.csr -config config.cnf -sha256
$ openssl req -text -noout -in server.csr
Certificate Request:
    Data:
        Version: 1 (0x0)
        Subject: C = US, ST = Massachusetts, L = Boston, O = MyCompany
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (2048 bit)
                Modulus:
                    ...
                Exponent: 65537 (0x10001)
        Attributes:
        Requested Extensions:
            X509v3 Subject Alternative Name:
                DNS:dev.mycompany.com
    Signature Algorithm: sha256WithRSAEncryption
         ...

Mas se você gerar o certificado usando o comando no link heroku e inspecionar o resultado, o Nome Alt do Assunto estará ausente:

$ openssl x509 -req -sha256 -days 365 -in server.csr -signkey server.key -out server.crt
$ openssl x509 -text -noout -in server.crt
Certificate:
    Data:
        Version: 1 (0x0)
        Serial Number:
            89:fd:75:26:43:08:04:61
    Signature Algorithm: sha256WithRSAEncryption
        Issuer: C = US, ST = Massachusetts, L = Boston, O = MyCompany
        Validity
            Not Before: Jan 21 04:27:21 2018 GMT
            Not After : Jan 21 04:27:21 2019 GMT
        Subject: C = US, ST = Massachusetts, L = Boston, O = MyCompany
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (2048 bit)
                Modulus:
                    ...
                Exponent: 65537 (0x10001)
    Signature Algorithm: sha256WithRSAEncryption
         ...

O motivo é que, por padrão, o OpenSSL não copia extensões da solicitação para o certificado. Normalmente, o certificado seria criado / assinado por uma CA com base em uma solicitação de um cliente, e algumas extensões poderiam conceder ao certificado mais poder do que a CA pretendia, caso confiassem cegamente nas extensões definidas na solicitação.

Existem maneiras de dizer ao OpenSSL para copiar as extensões, mas IMHO é mais trabalhoso do que apenas fornecer as extensões em um arquivo de configuração quando você gera o certificado.

Se você tentar usar seu arquivo de configuração existente, ele não funcionará porque a seção de nível superior está marcada [req]para que essas configurações se apliquem apenas ao comando req e não ao comando x509. Não é necessário ter um marcador de seção de nível superior; portanto, você pode simplesmente remover a primeira linha e, em seguida, funcionará bem para gerar solicitações ou certificado.

$ openssl x509 -req -sha256 -days 365 -in server.csr -signkey server.key -out server.crt -extfile config.cnf

Como alternativa, você pode usar o -x509argumento do reqcomando para gerar um certificado autoassinado em um único comando, em vez de primeiro criar uma solicitação e depois um certificado. Nesse caso, não é necessário remover a [req]linha de seção, pois essa seção é lida e usada pelo comando req.

$ openssl req -x509 -sha256 -days 365 -key server.key -out server.crt -config config.cnf

Para recapitular, aqui está o arquivo de configuração modificado usado nos comandos acima:

default_bits        = 2048
distinguished_name  = dn
x509_extensions     = san
req_extensions      = san
extensions          = san
prompt              = no
[ dn ]
countryName         = US
stateOrProvinceName = Massachusetts
localityName        = Boston
organizationName    = MyCompany
[ san ]
subjectAltName      = DNS:dev.mycompany.com
pavão
fonte
2
Esta é a única explicação que me ajudou a entender por que o certificado saiu sem uma SAN (no meu caso, eu precisava para incluir x509_extensions no arquivo de configuração)
Daniel Beardsmore
2

Minha solução é manter o principal openssl.cnfcomo está e, no final, adicionar uma nova seção, como [ cert_www.example.com ]onde www.example.com é o site para o qual desejo criar um certificado e, nele, colocar o que subjectAltNameeu precisaria (e algo mais). Obviamente, a seção pode ter o nome que você desejar.

Depois disso, eu posso executar o openssl reqcomando como antes, apenas adicionando -extensions cert_www.example.como conteúdo a ser escolhido e adiciono -subjpara adicionar diretamente todas as informações de DN.

Não se esqueça de verificar o conteúdo do certificado após sua criação e antes de seu uso, com openssl x509 -text

Patrick Mevzek
fonte
1

Script Bash com configuração criada em

Como um script de shell que deve funcionar em plataformas com bash. Assume um HOSTNAMEconjunto de env para o shell ou fornece um nome de host de sua escolha, por exemploself_signed_cert.sh test

set -e

if [ -z "$1" ]; then
  hostname="$HOSTNAME"
else
  hostname="$1"
fi

local_openssl_config="
[ req ]
prompt = no
distinguished_name = req_distinguished_name
x509_extensions = san_self_signed
[ req_distinguished_name ]
CN=$hostname
[ san_self_signed ]
subjectAltName = DNS:$hostname, DNS:localhost
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints = CA:true
keyUsage = nonRepudiation, digitalSignature, keyEncipherment, dataEncipherment, keyCertSign, cRLSign
extendedKeyUsage = serverAuth, clientAuth, timeStamping
"

openssl req \
  -newkey rsa:2048 -nodes \
  -keyout "$hostname.key.pem" \
  -x509 -sha256 -days 3650 \
  -config <(echo "$local_openssl_config") \
  -out "$hostname.cert.pem"
openssl x509 -noout -text -in "$hostname.cert.pem"

O procedimento acima injeta mais ou menos as informações mínimas necessárias sobre o openssl.

Observe que é incluído extra DNS:localhostcomo uma SAN para permitir testes via host local com mais facilidade. Remova esse bit extra do script, se você não quiser.

Crédito

A resposta de bcardarella é ótima (não é possível comentar / votar devido à insuficiência de representantes). No entanto, a resposta usa um local de arquivo de configuração openssl existente que é específico da plataforma ... portanto:

Funciona para mim

Obviamente, seria necessário simplesmente encontrar o arquivo de configuração openssl para sua própria plataforma e substituir o local correto.

Teste

Para uma maneira de testar, importe test.cert.pempara as autoridades do chrome chrome://settings/certificatese:

openssl s_server -key test.key.pem -cert test.cert.pem -accept 20443 -www &
openssl_pid=$!
google-chrome https://localhost:20443

E depois do teste

kill $openssl_pid
JPvRiel
fonte