Como criar um certificado autoassinado com OpenSSL

1294

Estou adicionando suporte HTTPS a um dispositivo Linux incorporado. Eu tentei gerar um certificado autoassinado com estas etapas:

openssl req -new > cert.csr
openssl rsa -in privkey.pem -out key.pem
openssl x509 -in cert.csr -out cert.pem -req -signkey key.pem -days 1001
cat key.pem>>cert.pem

Isso funciona, mas eu recebo alguns erros com, por exemplo, o Google Chrome:

Este provavelmente não é o site que você está procurando!
O certificado de segurança do site não é confiável!

Estou esquecendo de algo? Essa é a maneira correta de criar um certificado autoassinado?

michelemarcon
fonte
40
Os certificados autoassinados são considerados inseguros para a Internet. O Firefox tratará o site como tendo um certificado inválido, enquanto o Chrome agirá como se a conexão fosse HTTP simples. Mais detalhes: gerv.net/security/self-signed-certs
user1202136
34
Você precisa importar o certificado da CA para os navegadores e informar aos navegadores em que confia no certificado - ou - assiná-lo por uma das organizações mais lucrativas que já são confiáveis ​​pelos navegadores - ou - ignore o aviso e clique em passado. Eu gosto da última opção.
trojanfoe
12
Você não deve usar as configurações OpenSSL "padrão" dessa maneira. Isso ocorre porque você não pode colocar nomes DNS na SAN (Nome Alternativo do Assunto). Você precisa fornecer um arquivo de configuração com uma alternate_namesseção e passá-lo com a -configopção Além disso, a colocação de um nome DNS no Nome Comum (CN) é preterida (mas não proibida) pelos IETF e pelos Fóruns da CA / Navegador. Qualquer nome DNS na CN também deve estar presente na SAN. Não há como evitar o uso da SAN. Veja a resposta abaixo.
JWW
5
Além do comentário de @jww. Em maio de 2017, o Chrome não aceita mais certificados de SAN sem (emtpy): "O certificado deste site não contém uma extensão de Nome alternativo do assunto que contém um nome de domínio ou endereço IP".
GerardJP
6
Hoje em dia, desde que seu servidor da Web esteja acessível pelo FQDN na porta 80 pela Internet, você pode usar o LetsEncrypt e obter certificados completos gratuitos da CA (válidos por 90 dias, a renovação pode ser automatizada) que não emitirá nenhum aviso ao navegador / mensagens. www.letsencrypt.com
barny

Respostas:

2130

Você pode fazer isso em um comando:

openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365

Você também pode adicionar -nodes(abreviação de no DES) se não quiser proteger sua chave privada com uma senha. Caso contrário, ele solicitará a senha "pelo menos 4 caracteres".

O daysparâmetro (365) pode ser substituído por qualquer número para afetar a data de validade. Em seguida, será solicitado itens como "Nome do país", mas você pode simplesmente clicar Entere aceitar os padrões.

Adicione -subj '/CN=localhost'para suprimir perguntas sobre o conteúdo do certificado (substitua localhostpelo domínio desejado).

Os certificados autoassinados não são validados com terceiros, a menos que você os importe para os navegadores anteriormente. Se você precisar de mais segurança, use um certificado assinado por uma autoridade de certificação (CA).

Diego Woitasen
fonte
8
Para quem estiver interessado, aqui está a documentação , se você quiser verificar alguma coisa.
17
Como a assinatura com terceiros fornece mais segurança?
11138 James Mills
201
Para qualquer outra pessoa usando este em automação, aqui está todos os parâmetros comuns para o assunto:-subj "/C=US/ST=Oregon/L=Portland/O=Company Name/OU=Org/CN=www.example.com"
Alex S
17
@JamesMills, quero dizer, pense nisso - se um cara sombrio com "bala de graça" escrito ao lado de sua van o convidar a entrar, você vai pensar duas vezes e ficar alerta - mas se alguém em quem você confia - como realmente confia - é como "naw homem, ele é legítimo", você vai ser tudo sobre esse doce grátis.
BrainSlugs83
73
Lembre-se de usar -sha256para gerar o certificado baseado em SHA-256.
Gea-Suan Lin
535

Estou esquecendo de algo? Essa é a maneira correta de criar um certificado autoassinado?

É fácil criar um certificado autoassinado. Você acabou de usar o openssl reqcomando Pode ser complicado criar um que possa ser consumido pela maior seleção de clientes, como navegadores e ferramentas de linha de comando.

É difícil porque os navegadores têm seu próprio conjunto de requisitos e são mais restritivos que o IETF . Os requisitos usados ​​pelos navegadores estão documentados nos fóruns da CA / navegador (consulte as referências abaixo). As restrições surgem em duas áreas principais: (1) âncoras confiáveis ​​e (2) nomes DNS.

Os navegadores modernos (como o warez que estamos usando em 2014/2015) desejam um certificado que seja vinculado a uma âncora de confiança e desejam que os nomes DNS sejam apresentados de maneiras específicas no certificado. E os navegadores estão se movendo ativamente contra certificados de servidor autoassinado.

Alguns navegadores não facilitam exatamente a importação de um certificado de servidor autoassinado. Na verdade, você não pode usar alguns navegadores, como o Android. Portanto, a solução completa é se tornar sua própria autoridade.

Na ausência de se tornar sua própria autoridade, é necessário acertar os nomes DNS para dar ao certificado a maior chance de sucesso. Mas eu encorajaria você a se tornar sua própria autoridade. É fácil tornar-se sua própria autoridade e contornar todos os problemas de confiança (em quem é melhor confiar do que você?).


Este provavelmente não é o site que você está procurando!
O certificado de segurança do site não é confiável!

Isso ocorre porque os navegadores usam uma lista predefinida de âncoras confiáveis ​​para validar certificados de servidor. Um certificado autoassinado não volta para uma âncora confiável.

A melhor maneira de evitar isso é:

  1. Crie sua própria autoridade (ex .: torne-se uma autoridade de certificação )
  2. Crie uma solicitação de assinatura de certificado (CSR) para o servidor
  3. Assine o CSR do servidor com sua chave CA
  4. Instale o certificado do servidor no servidor
  5. Instale o certificado da CA no cliente

Etapa 1 - Crie sua própria autoridade significa apenas criar um certificado autoassinado com CA: trueo uso adequado da chave. Isso significa que o Assunto e o emissor são a mesma entidade, a CA é configurada como verdadeira em Restrições básicas (também deve ser marcada como crítica), o uso da chave é keyCertSigne crlSign(se você estiver usando CRLs) e o Identificador de chave do sujeito (SKI) é o mesmo que o AKI ( Authority Key Identifier ).

Para se tornar sua própria autoridade de certificação, consulte * Como você assina uma solicitação de assinatura de certificado com sua autoridade de certificação? no estouro de pilha. Em seguida, importe sua CA para o Trust Store usado pelo navegador.

As etapas 2 a 4 são basicamente o que você faz agora para um servidor público ao recrutar os serviços de uma CA como a Startcom ou CAcert . As etapas 1 e 5 permitem evitar a autoridade de terceiros e agir como sua própria autoridade (em quem é melhor confiar do que você?).

A próxima melhor maneira de evitar o aviso do navegador é confiar no certificado do servidor. Mas alguns navegadores, como o navegador padrão do Android, não permitem isso. Portanto, nunca funcionará na plataforma.

A questão de navegadores (e outros agentes de usuário semelhantes) não confiarem em certificados autoassinados será um grande problema na Internet das Coisas (IoT). Por exemplo, o que acontecerá quando você se conectar ao termostato ou à geladeira para programá-lo? A resposta é: nada de bom no que diz respeito à experiência do usuário.

O grupo de trabalho WebAppSec do W3C está começando a analisar o problema. Consulte, por exemplo, Proposta: Marcando HTTP como Não Seguro .


Como criar um certificado autoassinado com OpenSSL

Os comandos abaixo e o arquivo de configuração criam um certificado autoassinado (também mostra como criar uma solicitação de assinatura). Eles diferem de outras respostas em um aspecto: os nomes DNS usados ​​para o certificado autoassinado estão no Nome Alternativo do Assunto (SAN) e não no Nome Comum (CN) .

Os nomes DNS são colocados na SAN através do arquivo de configuração com a linha subjectAltName = @alternate_names(não há como fazê-lo através da linha de comando). Depois, há uma alternate_namesseção no arquivo de configuração (você deve ajustar isso de acordo com o seu gosto):

[ alternate_names ]

DNS.1       = example.com
DNS.2       = www.example.com
DNS.3       = mail.example.com
DNS.4       = ftp.example.com

# Add these if you need them. But usually you don't want them or
#   need them in production. You may need them for development.
# DNS.5       = localhost
# DNS.6       = localhost.localdomain
# IP.1        = 127.0.0.1
# IP.2        = ::1

É importante colocar o nome DNS na SAN e não o CN, porque ambos o IETF eo CA / Fórum do navegador especificar a prática. Eles também especificam que os nomes DNS na CN são preteridos (mas não proibidos). Se você colocar um nome DNS no CN, ele deverá ser incluído na SAN nas políticas da CA / B. Portanto, você não pode evitar o uso do Nome alternativo do assunto.

Se você não colocar nomes DNS na SAN, o certificado falhará na validação em um navegador e outros agentes de usuário que sigam as diretrizes do CA / Forum do navegador.

Relacionado: os navegadores seguem as políticas do CA / Browser Forum; e não as políticas da IETF. Essa é uma das razões pelas quais um certificado criado com o OpenSSL (que geralmente segue o IETF) às vezes não é validado em um navegador (os navegadores seguem o CA / B). São padrões diferentes, têm políticas de emissão diferentes e requisitos de validação diferentes.


Crie um certificado autoassinado (observe a adição da -x509opção):

openssl req -config example-com.conf -new -x509 -sha256 -newkey rsa:2048 -nodes \
    -keyout example-com.key.pem -days 365 -out example-com.cert.pem

Crie uma solicitação de assinatura (observe a falta de -x509opção):

openssl req -config example-com.conf -new -sha256 -newkey rsa:2048 -nodes \
    -keyout example-com.key.pem -days 365 -out example-com.req.pem

Imprima um certificado autoassinado :

openssl x509 -in example-com.cert.pem -text -noout

Imprima uma solicitação de assinatura :

openssl req -in example-com.req.pem -text -noout

Arquivo de configuração (passado via -configopção)

[ req ]
default_bits        = 2048
default_keyfile     = server-key.pem
distinguished_name  = subject
req_extensions      = req_ext
x509_extensions     = x509_ext
string_mask         = utf8only

# The Subject DN can be formed using X501 or RFC 4514 (see RFC 4519 for a description).
#   Its sort of a mashup. For example, RFC 4514 does not provide emailAddress.
[ subject ]
countryName         = Country Name (2 letter code)
countryName_default     = US

stateOrProvinceName     = State or Province Name (full name)
stateOrProvinceName_default = NY

localityName            = Locality Name (eg, city)
localityName_default        = New York

organizationName         = Organization Name (eg, company)
organizationName_default    = Example, LLC

# Use a friendly name here because it's presented to the user. The server's DNS
#   names are placed in Subject Alternate Names. Plus, DNS names here is deprecated
#   by both IETF and CA/Browser Forums. If you place a DNS name here, then you
#   must include the DNS name in the SAN too (otherwise, Chrome and others that
#   strictly follow the CA/Browser Baseline Requirements will fail).
commonName          = Common Name (e.g. server FQDN or YOUR name)
commonName_default      = Example Company

emailAddress            = Email Address
emailAddress_default        = [email protected]

# Section x509_ext is used when generating a self-signed certificate. I.e., openssl req -x509 ...
[ x509_ext ]

subjectKeyIdentifier        = hash
authorityKeyIdentifier    = keyid,issuer

# You only need digitalSignature below. *If* you don't allow
#   RSA Key transport (i.e., you use ephemeral cipher suites), then
#   omit keyEncipherment because that's key transport.
basicConstraints        = CA:FALSE
keyUsage            = digitalSignature, keyEncipherment
subjectAltName          = @alternate_names
nsComment           = "OpenSSL Generated Certificate"

# RFC 5280, Section 4.2.1.12 makes EKU optional
#   CA/Browser Baseline Requirements, Appendix (B)(3)(G) makes me confused
#   In either case, you probably only need serverAuth.
# extendedKeyUsage    = serverAuth, clientAuth

# Section req_ext is used when generating a certificate signing request. I.e., openssl req ...
[ req_ext ]

subjectKeyIdentifier        = hash

basicConstraints        = CA:FALSE
keyUsage            = digitalSignature, keyEncipherment
subjectAltName          = @alternate_names
nsComment           = "OpenSSL Generated Certificate"

# RFC 5280, Section 4.2.1.12 makes EKU optional
#   CA/Browser Baseline Requirements, Appendix (B)(3)(G) makes me confused
#   In either case, you probably only need serverAuth.
# extendedKeyUsage    = serverAuth, clientAuth

[ alternate_names ]

DNS.1       = example.com
DNS.2       = www.example.com
DNS.3       = mail.example.com
DNS.4       = ftp.example.com

# Add these if you need them. But usually you don't want them or
#   need them in production. You may need them for development.
# DNS.5       = localhost
# DNS.6       = localhost.localdomain
# DNS.7       = 127.0.0.1

# IPv6 localhost
# DNS.8     = ::1

Pode ser necessário fazer o seguinte no Chrome. Caso contrário, o Chrome poderá reclamar que um Nome Comum é inválido ( ERR_CERT_COMMON_NAME_INVALID) . Não tenho certeza de qual é a relação entre um endereço IP na SAN e uma CN nessa instância.

# IPv4 localhost
# IP.1       = 127.0.0.1

# IPv6 localhost
# IP.2     = ::1

Existem outras regras relacionadas ao tratamento de nomes DNS nos certificados X.509 / PKIX. Refira estes documentos para as regras:

As RFC 6797 e RFC 7469 são listadas, porque são mais restritivas que os outros RFCs e documentos CA / B. Os RFCs 6797 e 7469 também não permitem um endereço IP.

jww
fonte
4
É possível usar curingas na alternate_namesseção? Particularmente sub-sub domínios. Eu tenho uma pergunta referenciando esta resposta aqui: serverfault.com/questions/711596/...
LeonardChallis
3
Acabei de responder à sua pergunta específica. Eu acho que não faz sentido para adicionar esta descrição longa de segurança quando a resposta era tão simples
Diego Woitasen
14
@diegows - sua resposta não está completa ou correta. A razão não é correto é discutido no longo post você não quiser ler :)
JWW
1
Obrigado! Achei sua postagem muito útil. Para sua informação, eu estava jogando recentemente com o Vault e achei que ele insistia no IP.x 127.0.0.1 em vez do DNS.x 127 ... Não verifiquei se isso está no padrão ou não.
Chomeh
4
Obrigado @jww. Você disse: "1. Crie sua própria autoridade (ou seja, torne-se uma CA)" e , em seguida, disse: "5. Instale o certificado da CA no cliente" . Se a chave raiz for comprometida, uma pessoa mal-intencionada poderá assinar um certificado para qualquer domínio com essa chave e, se ela o induzir a acessar o site deles, poderá agora fazer um ataque intermediário. Existe uma maneira de criar a CA raiz, de forma que ela possa assinar apenas CAs intermediárias e não certificados? Em seguida, você pode proteger sua CA intermediária com uma restrição de nome.
Robin Zimmermann
408

Aqui estão as opções descritas na resposta do @ diegows , descritas em mais detalhes, na documentação :

openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days XXX
req

Pedido de certificado PKCS # 10 e utilitário de geração de certificado.

-x509

essa opção gera um certificado autoassinado em vez de uma solicitação de certificado. Isso geralmente é usado para gerar um certificado de teste ou uma CA raiz autoassinada.

-newkey arg

essa opção cria uma nova solicitação de certificado e uma nova chave privada. O argumento assume uma das várias formas. rsa: nbits , onde nbits é o número de bits, gera uma chave RSA nbits em tamanho.

-keyout filename

isso fornece o nome do arquivo para o qual escrever a chave privada recém-criada.

-out filename

Isso especifica o nome do arquivo de saída para gravação ou saída padrão por padrão.

-days n

quando a opção -x509 está sendo usada, isso especifica o número de dias para a certificação do certificado. O padrão é 30 dias.

-nodes

se essa opção for especificada, se uma chave privada for criada, ela não será criptografada.

A documentação é realmente mais detalhada que a anterior; Acabei de resumir aqui.

Peter Mortensen
fonte
3
O XXXcomando original deve ser substituído pelo 'número de dias para certificação do certificado'. O padrão é 30 dias. Por exemplo, -days XXXtorna- -days 365se se você deseja que seu certificado seja válido por 365 dias. Veja os documentos para mais .
Nathan Jones
Obrigado por adicionar a documentação. Este link IBM na criação de um certificado auto-assinado usando comando que parece idêntica a esta resposta
The Red Pea
314

A partir de 2020, o comando a seguir atende a todas as suas necessidades, incluindo SAN:

openssl req -x509 -newkey rsa:4096 -sha256 -days 3650 -nodes \
  -keyout example.key -out example.crt -extensions san -config \
  <(echo "[req]"; 
    echo distinguished_name=req; 
    echo "[san]"; 
    echo subjectAltName=DNS:example.com,DNS:example.net,IP:10.0.0.1
    ) \
  -subj "/CN=example.com"

No OpenSSL ≥ 1.1.1, isso pode ser reduzido para:

openssl req -x509 -newkey rsa:4096 -sha256 -days 3650 -nodes \
  -keyout example.key -out example.crt -subj "/CN=example.com" \
  -addext "subjectAltName=DNS:example.com,DNS:example.net,IP:10.0.0.1"

Ele cria um certificado que é

  • válido para os domínios example.come example.net(SAN),
  • também válido para o endereço IP 10.0.0.1(SAN),
  • relativamente forte (a partir de 2020) e
  • válido por 3650dias (~ 10 anos).

Ele cria os seguintes arquivos:

  • Chave privada: example.key
  • Certificado: example.crt

Todas as informações são fornecidas na linha de comando. Não há entrada interativa que o irrite. Não há arquivos de configuração com os quais você precise mexer. Todas as etapas necessárias são executadas por uma única chamada OpenSSL : da geração da chave privada até o certificado autoassinado.

Observação 1: parâmetros de criptografia

Como o certificado é autoassinado e precisa ser aceito pelos usuários manualmente, não faz sentido usar uma expiração curta ou criptografia fraca.

No futuro, convém usar mais de 4096bits para a chave RSA e um algoritmo de hash mais forte que sha256, mas, a partir de 2020, esses são valores sãos. Eles são suficientemente fortes enquanto são suportados por todos os navegadores modernos.

Observação 2: Parâmetro " -nodes"

Teoricamente, você poderia deixar de fora o -nodesparâmetro (que significa "sem criptografia DES"), caso em que example.keyseria criptografado com uma senha. No entanto, isso quase nunca é útil para uma instalação do servidor, porque você também precisará armazenar a senha no servidor ou inseri-la manualmente em cada reinicialização.

Observação 3: Veja também

vog
fonte
1
Eu não conseguia descobrir o que exatamente era o culpado no arg / CN = localhost, expandindo para C: / Arquivos de Programas / Git / CN = localhost, então apenas executei o comando inteiro no cmd.exe simples e funcionou perfeitamente. Apenas no caso de alguém estar lutando com este.
Yuriy Pozniak
1
@FranklinYu Você tem certeza de que a RSA: 2048 será suficiente daqui a 10 anos? Porque esse é o período de validade. Como explicado, não faz sentido usar expiração curta ou criptografia fraca. A maioria das chaves RSA de 2048 bits tem um período de validade de 1 a 3 anos, no máximo. Com relação ao OpenSSL 1.1.1, ainda estou deixando o sha256 lá, então é mais explícito e óbvio mudar se você quiser um hash mais forte.
vog
1
@DaveFerguson O certificado não foi criado para e //CN=localhostnão /CN=localhost? A fuga adequada ajudará aqui? Por exemplo, a substituição /CN=localhostpor "/CN=localhost"resolve o problema de maneira limpa?
vog
4
1000 + 1s para criar um "one-liner" que usa a nova SAN necessária sem precisar criar um arquivo de configuração prolongado com muito clichê. Bem feito!
Joshua Pinter
1
@cautionbug Thanks! Acabei de editar isso na resposta. A resposta agora está correta para Windows / MinGW?
vog 17/02
143

Não posso comentar, por isso vou colocar isso como uma resposta separada. Encontrei alguns problemas com a resposta de uma linha aceita:

  • O one-liner inclui uma senha na chave.
  • O one-liner usa SHA-1, que em muitos navegadores lança avisos no console.

Aqui está uma versão simplificada que remove a frase secreta, aumenta a segurança para suprimir avisos e inclui uma sugestão nos comentários para passar em -subj para remover a lista de perguntas completa:

openssl genrsa -out server.key 2048
openssl rsa -in server.key -out server.key
openssl req -sha256 -new -key server.key -out server.csr -subj '/CN=localhost'
openssl x509 -req -sha256 -days 365 -in server.csr -signkey server.key -out server.crt

Substitua 'localhost' pelo domínio que você precisar. Você precisará executar os dois primeiros comandos, um por um, pois o OpenSSL solicitará uma senha.

Para combinar os dois em um arquivo .pem:

cat server.crt server.key > cert.pem
Mike N
fonte
6
Eu precisava de um certificado de desenvolvedor para github.com/molnarg/node-http2 e esta resposta é a melhor.
Capaj
1
Para combinar o certificado ea chave em um único arquivo: cat server.crt server.key >foo-cert.pem. Trabalha com o exemplo emopenssl-1.0.2d/demos/ssl/
18446744073709551615
O certificado que eu gerei dessa maneira ainda está usando SHA1.
User169771
1
Tks, funciona muito bem para criar um certificado auto-assinado em FreeBSD 10 OpenLDAP 2.4comTLS
Thiago Pereira
2
E o arquivo key.pem?
QuikChange
72

Os navegadores modernos agora lançam um erro de segurança para certificados autoassinados, de outra forma bem formados, se houver uma SAN (Nome Alternativo do Assunto). O OpenSSL não fornece uma maneira da linha de comando para especificar isso , de modo que muitos tutoriais e indicadores de desenvolvedores estão subitamente desatualizados.

A maneira mais rápida de executar novamente é um arquivo conf curto e independente:

  1. Crie um arquivo OpenSSL config (exemplo: req.cnf)

    [req]
    distinguished_name = req_distinguished_name
    x509_extensions = v3_req
    prompt = no
    [req_distinguished_name]
    C = US
    ST = VA
    L = SomeCity
    O = MyCompany
    OU = MyDivision
    CN = www.company.com
    [v3_req]
    keyUsage = critical, digitalSignature, keyAgreement
    extendedKeyUsage = serverAuth
    subjectAltName = @alt_names
    [alt_names]
    DNS.1 = www.company.com
    DNS.2 = company.com
    DNS.3 = company.net
    
  2. Crie o certificado referenciando este arquivo de configuração

    openssl req -x509 -nodes -days 730 -newkey rsa:2048 \
     -keyout cert.key -out cert.pem -config req.cnf -sha256
    

Exemplo de configuração de https://support.citrix.com/article/CTX135602

rymo
fonte
1
Funcionou para mim depois de remover o último parâmetro -extensions 'v3_req', que estava causando um erro. Usando o OpenSSL para Windows. Finalmente, eu consigo corrigir esse problema! Obrigado.
CGodo
1
@ Kyopaxa, você está certo - esse parâmetro é redundante com a linha 3 do arquivo cnf; Atualizada.
RYMO
2
Maneira sólida. Obrigado. Eu sugiro adicionar -sha256.
27417 cherouvim
5
Agora você pode especificar a SAN na linha de comando com -extension 'subjectAltName = DNS:dom.ain, DNS:oth.er'see github.com/openssl/openssl/pull/4986
Alexandre Dubreuil
2
Parece que esta opção é chamada -addextagora.
Alexandr Zarubkin
67

Eu recomendaria adicionar o parâmetro -sha256 , para usar o algoritmo de hash SHA-2, porque os principais navegadores estão considerando mostrar "certificados SHA-1" como não seguros.

A mesma linha de comando da resposta aceita - @diegows with -sha256 adicionado

openssl req -x509 -sha256 -newkey rsa: 2048 -keyout key.pem -out cert.pem -days XXX

Mais informações no blog do Google Security .

Atualização em maio de 2018. Como muitos observaram nos comentários, o uso do SHA-2 não adiciona nenhuma segurança a um certificado autoassinado. Mas eu ainda recomendo usá-lo como um bom hábito de não usar funções hash criptográficas desatualizadas / inseguras. A explicação completa está disponível em Por que é bom que os certificados acima do certificado da entidade final sejam baseados em SHA-1? .

Maris B.
fonte
1
Se for uma chave autoassinada, irá gerar erros no navegador de qualquer maneira, portanto isso realmente não importa #
Mark #
30
@ Marcos, é importante, porque SHA-2 é mais seguro
Maris B.
1
A abertura do certificado no Windows após renomear o cert.pem para cert.cer diz que o algoritmo de impressão digital ainda é Sha1, mas o algoritmo de hash de assinatura é sha256.
pecou
2
"Criptografia de classe mundial * autenticação zero = segurança zero" gerv.net/security/self-signed-certs
x-yuri
4
Observe que o algoritmo de assinatura usado em um certificado autoassinado é irrelevante para decidir se é confiável ou não. Certificados de CA raiz são autoassinados. e em maio de 2018, ainda existem muitos certificados de CA raiz ativos assinados pelo SHA-1. Porque não importa se um certificado confia em si mesmo, nem como esse certificado verifica essa confiança. Você confia no certificado raiz / autoassinado para quem ele diz que é ou não. Consulte security.stackexchange.com/questions/91913/…
Andrew Henle
20

Este é o script que eu uso nas caixas locais para definir a SAN (subjectAltName) em certificados autoassinados.

Esse script pega o nome de domínio (exemplo.com) e gera a SAN para * .exemplo.com e exemplo.com no mesmo certificado. As seções abaixo estão comentadas. Nomeie o script (por exemplo generate-ssl.sh) e dê a ele permissões executáveis. Os arquivos serão gravados no mesmo diretório que o script.

O Chrome 58 em diante exige que a SAN seja definida em certificados autoassinados.

#!/usr/bin/env bash

# Set the TLD domain we want to use
BASE_DOMAIN="example.com"

# Days for the cert to live
DAYS=1095

# A blank passphrase
PASSPHRASE=""

# Generated configuration file
CONFIG_FILE="config.txt"

cat > $CONFIG_FILE <<-EOF
[req]
default_bits = 2048
prompt = no
default_md = sha256
x509_extensions = v3_req
distinguished_name = dn

[dn]
C = CA
ST = BC
L = Vancouver
O = Example Corp
OU = Testing Domain
emailAddress = webmaster@$BASE_DOMAIN
CN = $BASE_DOMAIN

[v3_req]
subjectAltName = @alt_names

[alt_names]
DNS.1 = *.$BASE_DOMAIN
DNS.2 = $BASE_DOMAIN
EOF

# The file name can be anything
FILE_NAME="$BASE_DOMAIN"

# Remove previous keys
echo "Removing existing certs like $FILE_NAME.*"
chmod 770 $FILE_NAME.*
rm $FILE_NAME.*

echo "Generating certs for $BASE_DOMAIN"

# Generate our Private Key, CSR and Certificate
# Use SHA-2 as SHA-1 is unsupported from Jan 1, 2017

openssl req -new -x509 -newkey rsa:2048 -sha256 -nodes -keyout "$FILE_NAME.key" -days $DAYS -out "$FILE_NAME.crt" -passin pass:$PASSPHRASE -config "$CONFIG_FILE"

# OPTIONAL - write an info to see the details of the generated crt
openssl x509 -noout -fingerprint -text < "$FILE_NAME.crt" > "$FILE_NAME.info"

# Protect the key
chmod 400 "$FILE_NAME.key"

Esse script também grava um arquivo de informações, para que você possa inspecionar o novo certificado e verificar se a SAN está configurada corretamente.

                ...
                28:dd:b8:1e:34:b5:b1:44:1a:60:6d:e3:3c:5a:c4:
                da:3d
            Exponent: 65537 (0x10001)
    X509v3 extensions:
        X509v3 Subject Alternative Name: 
            DNS:*.example.com, DNS:example.com
Signature Algorithm: sha256WithRSAEncryption
     3b:35:5a:d6:9e:92:4f:fc:f4:f4:87:78:cd:c7:8d:cd:8c:cc:
     ...

Se você estiver usando o Apache, poderá fazer referência ao certificado acima no seu arquivo de configuração da seguinte maneira:

<VirtualHost _default_:443>
    ServerName example.com
    ServerAlias www.example.com
    DocumentRoot /var/www/htdocs

    SSLEngine on
    SSLCertificateFile path/to/your/example.com.crt
    SSLCertificateKeyFile path/to/your/example.com.key
</VirtualHost>

Lembre-se de reiniciar o servidor Apache (ou Nginx ou IIS) para que o novo certificado entre em vigor.

Drakes
fonte
Funciona no macOS High Siera e Chrome 58
Saqib Omer
Ainda não tenho certeza de como a CN afeta a configuração geral? Estou tentando executar isso como localhostou o 127.0.0.1:port#que seria o correspondente CNpara algo assim.
DJ2
@ DJ2 eu definiria BASE_DOMAIN = “localhost”
Drakes
9

2017 one-liner:

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

Isso também funciona no Chrome 57, pois fornece a SAN, sem ter outro arquivo de configuração. Foi retirado de uma resposta aqui .

Isso cria um único arquivo .pem que contém a chave privada e o certificado. Você pode movê-los para separar arquivos .pem, se necessário.

joemillervi
fonte
2
Para usuários do Linux, você precisará alterar esse caminho para a configuração. por exemplo, nas /etc/ssl/openssl.confobras atuais do Ubuntu
declinação
Para uma linha única que não exige que você especifique o local openssl.cnf, consulte: stackoverflow.com/a/41366949/19163
vog
7

Não posso comentar, então adiciono uma resposta separada. Tentei criar um certificado autoassinado para o NGINX e foi fácil, mas quando quis adicioná-lo à lista branca do Chrome, tive um problema. E minha solução foi criar um certificado raiz e assinar um certificado filho por ele.

Então passo a passo. Criar arquivo config_ssl_ca.cnf Observe que o arquivo de configuração possui uma opção basicConstraints = CA: true, o que significa que esse certificado deve ser root.

Essa é uma boa prática, porque você a cria uma vez e pode reutilizá-la.

[ req ]
default_bits = 2048

prompt = no
distinguished_name=req_distinguished_name
req_extensions = v3_req

[ req_distinguished_name ]
countryName=UA
stateOrProvinceName=root region
localityName=root city
organizationName=root organisation
organizationalUnitName=roote department
commonName=root
[email protected]

[ alternate_names ]
DNS.1        = market.localhost
DNS.2        = www.market.localhost
DNS.3        = mail.market.localhost
DNS.4        = ftp.market.localhost

[ v3_req ]
keyUsage=digitalSignature
basicConstraints=CA:true
subjectKeyIdentifier = hash
subjectAltName = @alternate_names

Próximo arquivo de configuração para o seu certificado filho.

[ req ]
default_bits = 2048

prompt = no
distinguished_name=req_distinguished_name
req_extensions = v3_req

[ req_distinguished_name ]
countryName=UA
stateOrProvinceName=Kyiv region
localityName=Kyiv
organizationName=market place
organizationalUnitName=market place department
commonName=FirstName LastName
[email protected]

[ alternate_names ]
DNS.1        = market.localhost
DNS.2        = www.market.localhost
DNS.3        = mail.market.localhost
DNS.4        = ftp.market.localhost

[ v3_req ]
keyUsage=digitalSignature
basicConstraints=CA:false
subjectAltName = @alternate_names
subjectKeyIdentifier = hash

A primeira etapa - criar chave e certificado raiz

openssl genrsa -out ca.key 2048
openssl req -new -x509 -key ca.key -out ca.crt -days 365 -config config_ssl_ca.cnf

A segunda etapa cria a chave filha e o arquivo CSR - Certificate Signing Request. Como a idéia é assinar o certificado filho pela raiz e obter um certificado correto

openssl genrsa -out market.key 2048
openssl req -new -sha256 -key market.key -config config_ssl.cnf -out market.csr

Abra o terminal Linux e execute este comando eco 0

echo 1 > ca.srl
touch index.txt

O arquivo de texto ca.srl contendo o próximo número de série a ser usado em hexadecimal. Obrigatório. Este arquivo deve estar presente e conter um número de série válido.

Última etapa, crie mais um arquivo de configuração e chame-o de config_ca.cnf

# we use 'ca' as the default section because we're usign the ca command
[ ca ]
default_ca = my_ca

[ my_ca ]
#  a text file containing the next serial number to use in hex. Mandatory.
#  This file must be present and contain a valid serial number.
serial = ./ca.srl

# the text database file to use. Mandatory. This file must be present though
# initially it will be empty.
database = ./index.txt

# specifies the directory where new certificates will be placed. Mandatory.
new_certs_dir = ./

# the file containing the CA certificate. Mandatory
certificate = ./ca.crt

# the file contaning the CA private key. Mandatory
private_key = ./ca.key

# the message digest algorithm. Remember to not use MD5
default_md = sha256

# for how many days will the signed certificate be valid
default_days = 365

# a section with a set of variables corresponding to DN fields
policy = my_policy

# MOST IMPORTANT PART OF THIS CONFIG
copy_extensions = copy

[ my_policy ]
# if the value is "match" then the field value must match the same field in the
# CA certificate. If the value is "supplied" then it must be present.
# Optional means it may be present. Any fields not mentioned are silently
# deleted.
countryName = match
stateOrProvinceName = supplied
organizationName = supplied
commonName = supplied
organizationalUnitName = optional
commonName = supplied

Você pode perguntar, por que tão difícil, por que precisamos criar mais uma configuração para assinar o certificado filho pela raiz. A resposta é simples porque o certificado filho deve ter um bloco SAN - Nomes Alternativos para o Assunto. Se assinarmos o certificado filho pelos utilitários "openssl x509", o certificado raiz excluirá o campo SAN no certificado filho. Portanto, usamos "openssl ca" em vez de "openssl x509" para evitar a exclusão do campo SAN. Nós criamos um novo arquivo de configuração e dizemos para copiar todos os campos estendidos copy_extensions = copy .

openssl ca -config config_ca.cnf -out market.crt -in market.csr

O programa faz duas perguntas: 1. Assine o certificado? Diga "Y" 2. 1 de 1 solicitações de certificado certificadas, confirma? Diga "Y"

No terminal você pode ver uma frase com a palavra "Banco de Dados", significa o arquivo index.txt que você cria com o comando "touch". Ele conterá todas as informações de todos os certificados que você criar pelo utilitário "openssl ca". Para verificar o certificado válido, use:

openssl rsa -in market.key -check

Se você quiser ver o que há dentro do CRT:

openssl x509 -in market.crt -text -noout

Se você quiser ver o que há no CSR:

openssl req -in market.csr -noout -text 
Mrkiril
fonte
2
Embora esse processo pareça complicado, é exatamente isso que precisamos para o domínio .dev, pois esse domínio não suporta certificados autoassinados e o Chrome e o Firefox estão forçando o HSTS. O que fiz foi seguir estas etapas, que estão criando a CA, criando um certificado e assinando-o com a minha CA e, no final, confiando na minha CA no navegador. Obrigado.
bajicdusko 17/04
1
Você senhor, é uma lenda maldita. Meu homelab obrigado!
antsyawn
6

Você tem o procedimento geral correto. A sintaxe para o comando está abaixo.

openssl req -new -key {private key file} -out {output file}

No entanto, os avisos são exibidos, porque o navegador não conseguiu verificar a identificação validando o certificado com uma CA (Autoridade de Certificação) conhecida.

Como este é um certificado autoassinado, não há CA e você pode ignorar com segurança o aviso e prosseguir. Se você deseja obter um certificado real que possa ser reconhecido por qualquer pessoa na Internet pública, o procedimento está abaixo.

  1. Gere uma chave privada
  2. Use essa chave privada para criar um arquivo CSR
  3. Enviar CSR para a CA (Verisign ou outros, etc.)
  4. Instalar o certificado recebido da CA no servidor web
  5. Adicione outros certificados à cadeia de autenticação, dependendo do tipo cert

Tenho mais detalhes sobre isso em uma postagem em Protegendo a conexão: Criando um certificado de segurança com o OpenSSL

nneko
fonte
6

Um forro FTW. Eu gosto de simplificar. Por que não usar um comando que contenha TODOS os argumentos necessários? É assim que eu gosto - isso cria um certificado x509 e sua chave PEM:

openssl req -x509 \
 -nodes -days 365 -newkey rsa:4096 \
 -keyout self.key.pem \
 -out self-x509.crt \
 -subj "/C=US/ST=WA/L=Seattle/CN=example.com/[email protected]"

Esse comando único contém todas as respostas que você normalmente forneceria para os detalhes do certificado. Dessa forma, você pode definir os parâmetros e executar o comando, obter sua saída e depois tomar um café.

>> Mais aqui <<

OkezieE
fonte
1
Todos os argumentos, exceto as respostas da SAN ... @ vog, também abrangem isso (e são anteriores a isso) (esse campo "Assunto" mais completo foi preenchido ...) (também não é um grande fã do prazo de um ano)
Gert van den Berg
6

Versão one-liner 2017:

CentOS:

openssl req -x509 -nodes -sha256 -newkey rsa:2048 \
-keyout localhost.key -out localhost.crt \
-days 3650 \
-subj "CN=localhost" \
-reqexts SAN -extensions SAN \
-config <(cat /etc/pki/tls/openssl.cnf <(printf "\n[SAN]\nsubjectAltName=IP:127.0.0.1,DNS:localhost"))

Ubuntu:

openssl req -x509 -nodes -sha256 -newkey rsa:2048 \
-keyout localhost.key -out localhost.crt \
-days 3650 \
-subj "/CN=localhost" \
-reqexts SAN -extensions SAN \
-config <(cat /etc/ssl/openssl.cnf <(printf "\n[SAN]\nsubjectAltName=IP:127.0.0.1,DNS:localhost"))

Edit: adicionada a adição de Slash à opção 'subj' do Ubuntu.

user327843
fonte
3

Gerar chaves

Estou usando /etc/mysqlpara armazenamento de certificados porque /etc/apparmor.d/usr.sbin.mysqldcontém /etc/mysql/*.pem r.

sudo su -
cd /etc/mysql
openssl genrsa -out ca-key.pem 2048;
openssl req -new -x509 -nodes -days 1000 -key ca-key.pem -out ca-cert.pem;
openssl req -newkey rsa:2048 -days 1000 -nodes -keyout server-key.pem -out server-req.pem;
openssl x509 -req -in server-req.pem -days 1000 -CA ca-cert.pem -CAkey ca-key.pem -set_serial 01 -out server-cert.pem;
openssl req -newkey rsa:2048 -days 1000 -nodes -keyout client-key.pem -out client-req.pem;
openssl x509 -req -in client-req.pem -days 1000 -CA ca-cert.pem -CAkey ca-key.pem -set_serial 01 -out client-cert.pem;

Adicionar configuração

/etc/mysql/my.cnf

[client]
ssl-ca=/etc/mysql/ca-cert.pem
ssl-cert=/etc/mysql/client-cert.pem
ssl-key=/etc/mysql/client-key.pem

[mysqld]
ssl-ca=/etc/mysql/ca-cert.pem
ssl-cert=/etc/mysql/server-cert.pem
ssl-key=/etc/mysql/server-key.pem

Na minha configuração, o servidor Ubuntu logou em: /var/log/mysql/error.log

Notas de acompanhamento:

  • SSL error: Unable to get certificate from '...'

    Pode ser negado ao MySQL acesso de leitura ao seu arquivo de certificado se ele não estiver na configuração de aparentes . Como mencionado nas etapas anteriores ^, salve todos os nossos certificados como .pemarquivos no /etc/mysql/diretório que é aprovado por padrão pelo apparmor (ou modifique seu apparmor / SELinux para permitir acesso a onde você os armazenou.)

  • SSL error: Unable to get private key

    Sua versão do servidor MySQL pode não suportar o rsa:2048formato padrão

    Converter gerado rsa:2048em comum rsacom:

    openssl rsa -in server-key.pem -out server-key.pem
    openssl rsa -in client-key.pem -out client-key.pem
    
  • Verifique se o servidor local suporta SSL :

    mysql -u root -p
    mysql> show variables like "%ssl%";
    +---------------+----------------------------+
    | Variable_name | Value                      |
    +---------------+----------------------------+
    | have_openssl  | YES                        |
    | have_ssl      | YES                        |
    | ssl_ca        | /etc/mysql/ca-cert.pem     |
    | ssl_capath    |                            |
    | ssl_cert      | /etc/mysql/server-cert.pem |
    | ssl_cipher    |                            |
    | ssl_key       | /etc/mysql/server-key.pem  |
    +---------------+----------------------------+
    
  • A verificação de uma conexão com o banco de dados é criptografada em SSL :

    Verificando conexão

    Quando conectado à instância do MySQL, você pode emitir a consulta:

    show status like 'Ssl_cipher';
    

    Se sua conexão não estiver criptografada, o resultado ficará em branco:

    mysql> show status like 'Ssl_cipher';
    +---------------+-------+
    | Variable_name | Value |
    +---------------+-------+
    | Ssl_cipher    |       |
    +---------------+-------+
    1 row in set (0.00 sec)
    

    Caso contrário, ele mostraria uma cadeia de comprimento diferente de zero para o código em uso:

    mysql> show status like 'Ssl_cipher';
    +---------------+--------------------+
    | Variable_name | Value              |
    +---------------+--------------------+
    | Ssl_cipher    | DHE-RSA-AES256-SHA |
    +---------------+--------------------+
    1 row in set (0.00 sec)
    
  • Exigir ssl para conexão de usuário específico ('require ssl'):

    • SSL

    Diz ao servidor para permitir apenas conexões criptografadas em SSL para a conta.

    GRANT ALL PRIVILEGES ON test.* TO 'root'@'localhost'
      REQUIRE SSL;
    

    Para conectar-se, o cliente deve especificar a opção --ssl-ca para autenticar o certificado do servidor e também pode especificar as opções --ssl-key e --ssl-cert. Se nenhuma opção --ssl-ca nem --ssl-capath for especificada, o cliente não autenticará o certificado do servidor.


Link alternativo: tutorial longo em Secure PHP Connections to MySQL with SSL .

ThorSummoner
fonte
-1; isso é em grande parte tangencial à pergunta e também faz um péssimo trabalho de esclarecer de onde são suas citações.
Mark Amery
Isso mostra CA de provisionamento, certificados de Servidor / Cliente assinados pela CA, configurá-los para leitura pelo mysqld em um host com apparmor. Ele exemplifica um caso bastante inútil de hospedar o ca, servidor e cliente na mesma máquina e expor perigosamente a autoridade desse ca ao processo mysqld. Essa configuração realmente não faz sentido além de testar a configuração do SSL em um ambiente de teste. Para operar uma CA interna, eu recomendaria as gnuttls conjunto de ferramentas sobre OpenSSL help.ubuntu.com/community/GnuTLS e ter uma boa compreensão do TLS antes de trabalhar em todo o mysqld + apparmor caso
ThorSummoner
3

Como foi discutido em detalhes, os certificados autoassinados não são confiáveis ​​para a Internet . Você pode adicionar seu certificado autoassinado a muitos, mas não a todos os navegadores . Como alternativa, você pode se tornar sua própria autoridade de certificação .

A principal razão pela qual não se deseja obter um certificado assinado de uma autoridade de certificação é o custo - a Symantec cobra entre US $ 995 e US $ 1.999 por ano pelos certificados - apenas para um certificado destinado à rede interna, a Symantec cobra US $ 399 por ano . Esse custo é fácil de justificar se você estiver processando pagamentos com cartão de crédito ou trabalhando para o centro de lucro de uma empresa altamente lucrativa. É mais do que muitos podem pagar por um projeto pessoal que você está criando na Internet, ou por uma organização sem fins lucrativos, com um orçamento mínimo, ou se trabalha no centro de custos de uma organização - os centros de custo sempre tentam fazer mais com menos.

Uma alternativa é usar o certbot (consulte sobre o certbot ). O Certbot é um cliente automático fácil de usar que busca e implanta certificados SSL / TLS para o seu servidor web.

Se você configurar o certbot, poderá habilitá-lo para criar e manter um certificado emitido pela autoridade de certificação Let's Encrypt .

Fiz isso no fim de semana para a minha organização. Instalei os pacotes necessários para o certbot no meu servidor (Ubuntu 16.04) e, em seguida, executei o comando necessário para configurar e ativar o certbot. Provavelmente, é necessário um plug-in DNS para o certbot - atualmente estamos usando o DigitalOcean, embora possamos estar migrando para outro serviço em breve.

Observe que algumas das instruções não estavam certas e demoraram um pouco para descobrir o Google. Isso levou uma boa quantidade de tempo da primeira vez, mas agora acho que posso fazê-lo em minutos.

Para o DigitalOcean, uma área em que lutei foi quando fui solicitado a inserir o caminho para o arquivo INI das credenciais do DigitalOcean. O que o script está se referindo é a página Aplicativos e API e a guia Tokens / Chave nessa página. Você precisa ter ou gerar um token de acesso pessoal (leitura e gravação) para a API do DigitalOcean - essa é uma sequência hexadecimal de 65 caracteres. Essa sequência precisa ser colocada em um arquivo no servidor da web do qual você está executando o certbot. Esse arquivo pode ter um comentário como primeira linha (os comentários começam com #). A linha seccond é:

dns_digitalocean_token = 0000111122223333444455556666777788889999aaaabbbbccccddddeeeeffff

Depois que eu descobri como configurar um token de leitura + gravação para a API do DigitalOcean, era muito fácil usar o certbot para configurar um certificado curinga . Observe que não é necessário configurar um certificado curinga, pode-se especificar cada domínio e subdomínio ao qual deseja que o certificado seja aplicado. Era o certificado curinga que exigia o arquivo INI de credenciais que continha o token de acesso pessoal do DigitalOcean.

Observe que os certificados de chave pública (também conhecidos como certificados de identidade ou certificados SSL) expiram e exigem renovação. Portanto, você precisará renovar seu certificado periodicamente (de forma recorrente). A documentação do certbot abrange a renovação de certificados .

Meu plano é escrever um script para usar o comando openssl para obter a data de validade do meu certificado e acionar a renovação quando tiver 30 dias ou menos até que expire. Vou adicionar esse script ao cron e executá-lo uma vez por dia.

Aqui está o comando para ler a data de validade do seu certificado:

root@prod-host:~# /usr/bin/openssl x509 -enddate -noout -in path-to-certificate-pem-file
notAfter=May 25 19:24:12 2019 GMT
Peter Jirak Eldritch
fonte