Introdução
Vamos aprender a gerar uma CA e com ela vamos gerar um CRT a partir de um CSR assinado com nossa CA.
Gerando uma CA
Vejamos os passos necessários para gerar uma CA.
# Crie o arquivo de configuração que vamos usar para criar a CA:
$ vim ca.conf
### Coloque o texto abaixo ###
HOME = . # Essa variável especifica o diretório atual como o diretório base (ou "home") para a execução do OpenSSL.
RANDFILE = $ENV::HOME/.rand # Essa variável especifica o caminho e o nome do arquivo usado para armazenar dados aleatórios gerados pelo OpenSSL. O $ENV::HOME representa o valor da variável de ambiente HOME, que normalmente é o diretório base do usuário. Portanto, $ENV::HOME/.rnd se refere ao arquivo .rnd localizado no diretório base do usuário. Esse arquivo é usado para armazenar informações de estado relacionadas à geração de números aleatórios, que são usados em operações criptográficas.
[ ca ]
default_ca = CA_default # The default ca section
[ CA_default ]
default_days = 365 # Define a duração padrão de certificados emitidos pela CA.
default_crl_days = 30 # Define a duração padrão antes da próxima Lista de Revogação de Certificados (CRL - Certificate Revocation List).
default_md = sha256 # Especifica o algoritmo de hash padrão usado para assinar certificados.
preserve = no # Determina se a ordem dos DNs é preservada nos certificados emitidos.
x509_extensions = ca_extensions # Especifica as extensões a serem adicionadas aos certificados emitidos pela CA.
email_in_dn = no # Define se o endereço de e-mail será incluído no Distinguished Name (DN).
copy_extensions = copy # Indica que as extensões presentes na Solicitação de Assinatura de Certificado (CSR - Certificate Signing Request) devem ser copiadas para o certificado emitido.
[ req ]
default_bits = 4096 # Especifica o tamanho padrão da chave em bits.
default_keyfile = ca_key.pem # Define o arquivo padrão para a chave da CA.
distinguished_name = ca_distinguished_name # Especifica as informações do DN para as solicitações de certificado.
x509_extensions = ca_extensions # Define os valores padrão para as informações do DN da CA.
string_mask = utf8only # Define as extensões do certificado da CA.
[ ca_distinguished_name ]
countryName = Country Name (2 letter code)
countryName_default = BR
stateOrProvinceName = State or Province Name (full name)
stateOrProvinceName_default = Sao Paulo
localityName = Locality Name (eg, city)
localityName_default = SP
organizationName = Organization Name (eg, company)
organizationName_default = Custom CA
commonName = Common Name (e.g. server FQDN or YOUR name)
commonName_default = Custom CA
[ ca_extensions ]
subjectKeyIdentifier = hash # Essa extensão define como identificar exclusivamente a chave pública do titular do certificado.
authorityKeyIdentifier = keyid:always, issuer # Essa extensão define como identificar exclusivamente a chave pública da autoridade emissora (CA) do certificado.
basicConstraints = critical, CA:true # Essa extensão especifica as restrições básicas para o certificado. No caso, o valor "critical, CA:true" indica que é uma extensão crítica e que o certificado é uma Autoridade Certificadora (CA), permitindo que seja usada para assinar outros certificados.
keyUsage = keyCertSign, cRLSign # Essa extensão especifica o uso da chave contida no certificado. O valor "keyCertSign, cRLSign" indica que a chave pode ser usada para assinar certificados (keyCertSign) e para assinar Listas de Revogação de Certificados (CRLs - Certificate Revocation Lists) (cRLSign).
# a extensão crlDistributionPoints será incluída no certificado gerado. Isso permite que os verificadores do certificado saibam onde encontrar a CRL correspondente para verificar se o certificado foi revogado.
crlDistributionPoints = URI:http://example.com/crl.pem
### Fim do texto acima ###
Crie a CA:
# Gere a chave da CA:
$ openssl genrsa -des3 -out ca.key 4096
Enter PEM pass phrase:
Verifying - Enter PEM pass phrase:
# Gere a CA:
$ openssl req -x509 -config ca.conf -key ca.key -days 365 -sha256 -nodes -out ca.pem -outform PEM
Enter pass phrase for ca.key:
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [BR]:
State or Province Name (full name) [Sao Paulo]:
Locality Name (eg, city) [SP]:
Organization Name (eg, company) [Custom CA]:
Common Name (e.g. server FQDN or YOUR name) [Custom CA]:
# É possível testar a senha com o comando abaixo (se der certo nenhum erro vai aparecer):
$ openssl rsa -noout -in ca.key
Enter pass phrase for ca.key:
# É possível ver o conteúdo da CA:
$ openssl x509 -in ca.pem -text -noout
# Podemos ainda ver o propósito do certificado:
$ openssl x509 -purpose -in ca.pem -inform PEM
Certificate purposes:
SSL client : No
SSL client CA : Yes
SSL server : No
SSL server CA : Yes
Netscape SSL server : No
Netscape SSL server CA : Yes
S/MIME signing : No
S/MIME signing CA : Yes
S/MIME encryption : No
S/MIME encryption CA : Yes
CRL signing : Yes
CRL signing CA : Yes
Any Purpose : Yes
Any Purpose CA : Yes
OCSP helper : Yes
OCSP helper CA : Yes
Time Stamp signing : No
Time Stamp signing CA : Yes
.
.
.
Gerando um CSR
Agora temos a CA e a chave dela para assinar certificados. Vamos criar um certificado para um servidor:
# Crie um arquivo para colocar os dados do certificado que vamos emitir:
$ vim cert.conf
### Começo do texto ###
HOME = .
RANDFILE = $ENV::HOME/.rnd
[ req ]
default_bits = 2048
default_keyfile = test-sysnetbr.eng.br.key.pem
distinguished_name = server_distinguished_name
req_extensions = server_req_extensions
string_mask = utf8only
default_md = sha256
[ server_distinguished_name ]
countryName = Country Name (2 letter code)
countryName_default = BR
stateOrProvinceName = State or Province Name (full name)
stateOrProvinceName_default = Sao Paulo
localityName = Locality Name (eg, city)
localityName_default = SP
organizationName = Organization Name (eg, company)
organizationName_default = SysNetBR
commonName = Common Name (e.g. server FQDN or YOUR name)
commonName_default = test-sysnetbr.eng.br
emailAddress = Email Address
emailAddress_default = test@example.com
[ server_req_extensions ]
subjectKeyIdentifier = hash
basicConstraints = CA:FALSE
keyUsage = digitalSignature, keyEncipherment
subjectAltName = @alternate_names
nsComment = "OpenSSL Generated Certificate"
[ alternate_names ]
DNS.1 = sysnetbr.eng.br
DNS.2 = test-sysnetbr.eng.br
### Fim do texto acima ###
# Agora gere o CSR com a chave:
$ openssl req -config cert.conf -newkey rsa:2048 -sha256 -nodes -out test-sysnetbr.eng.br.csr -outform PEM
# Podemos ver o conteúdo do CSR:
$ openssl req -in test-sysnetbr.eng.br.csr -noout -text
Existe outra maneira de gerar o CSR (mais uma maneira das muitas existentes), essa é até um pouco mais simples.
# Crie a chave que vamos usar para atrelar ao CSR e que servirá para o CRT:
openssl genrsa -out test-sysnetbr.eng.br.key 2048
# Agora gere o CSR:
openssl req -new -nodes -sha256 \
-key test-sysnetbr.eng.br.key \
-subj "/C=BR/ST=SP/O=SysnetBR/CN=test-sysnetbr.eng.br" \
-reqexts SAN \
-config <(cat /etc/ssl/openssl.cnf <(printf "\n[SAN]\nsubjectAltName=DNS:test-sysnetbr.eng.br")) \
-out test-sysnetbr.eng.br.csr
Gerando um CRT
Agora vamos assinar o CSR e gerar um certificado de servidor válido.
# Comece criando um arquivo para assinar os certificados:
$ vim sign.conf
### Começo do texto ###
HOME = . # Essa variável especifica o diretório atual como o diretório base (ou "home") para a execução do OpenSSL.
RANDFILE = $ENV::HOME/.rand # Essa variável especifica o caminho e o nome do arquivo usado para armazenar dados aleatórios gerados pelo OpenSSL. O $ENV::HOME representa o valor da variável de ambiente HOME, que normalmente é o diretório base do usuário. Portanto, $ENV::HOME/.rnd se refere ao arquivo .rnd localizado no diretório base do usuário. Esse arquivo é usado para armazenar informações de estado relacionadas à geração de números aleatórios, que são usados em operações criptográficas.
[ ca ]
default_ca = CA_default # The default ca section
[ CA_default ]
default_days = 365 # Define a duração padrão de certificados emitidos pela CA.
default_crl_days = 30 # Define a duração padrão antes da próxima Lista de Revogação de Certificados (CRL - Certificate Revocation List).
default_md = sha256 # Especifica o algoritmo de hash padrão usado para assinar certificados.
preserve = no # Determina se a ordem dos DNs é preservada nos certificados emitidos.
x509_extensions = ca_extensions # Especifica as extensões a serem adicionadas aos certificados emitidos pela CA.
email_in_dn = no # Define se o endereço de e-mail será incluído no Distinguished Name (DN).
copy_extensions = copy # Indica que as extensões presentes na Solicitação de Assinatura de Certificado (CSR - Certificate Signing Request) devem ser copiadas para o certificado emitido.
base_dir = .
certificate = ca.pem # The CA certifcate
private_key = ca.key # The CA private key
new_certs_dir = $base_dir # Location for new certs after signing
database = index.txt # Database index file
serial = serial.txt # The current serial number
unique_subject = no # Set to 'no' to allow creation of
# several certificates with same subject.
[ req ]
default_bits = 4096 # Especifica o tamanho padrão da chave em bits.
default_keyfile = ca_key.pem # Define o arquivo padrão para a chave da CA.
distinguished_name = ca_distinguished_name # Especifica as informações do DN para as solicitações de certificado.
x509_extensions = ca_extensions # Define os valores padrão para as informações do DN da CA.
string_mask = utf8only # Define as extensões do certificado da CA.
[ ca_distinguished_name ]
countryName = Country Name (2 letter code)
countryName_default = BR
stateOrProvinceName = State or Province Name (full name)
stateOrProvinceName_default = Sao Paulo
localityName = Locality Name (eg, city)
localityName_default = SP
organizationName = Organization Name (eg, company)
organizationName_default = Custom CA
commonName = Common Name (e.g. server FQDN or YOUR name)
commonName_default = Custom CA
[ ca_extensions ]
subjectKeyIdentifier = hash # Essa extensão define como identificar exclusivamente a chave pública do titular do certificado.
authorityKeyIdentifier = keyid:always, issuer # Essa extensão define como identificar exclusivamente a chave pública da autoridade emissora (CA) do certificado.
basicConstraints = critical, CA:true # Essa extensão especifica as restrições básicas para o certificado. No caso, o valor "critical, CA:true" indica que é uma extensão crítica e que o certificado é uma Autoridade Certificadora (CA), permitindo que seja usada para assinar outros certificados.
keyUsage = keyCertSign, cRLSign # Essa extensão especifica o uso da chave contida no certificado. O valor "keyCertSign, cRLSign" indica que a chave pode ser usada para assinar certificados (keyCertSign) e para assinar Listas de Revogação de Certificados (CRLs - Certificate Revocation Lists) (cRLSign).
# a extensão crlDistributionPoints será incluída no certificado gerado. Isso permite que os verificadores do certificado saibam onde encontrar a CRL correspondente para verificar se o certificado foi revogado.
crlDistributionPoints = URI:http://example.com/crl.pem
[ signing_policy ]
countryName = optional
stateOrProvinceName = optional
localityName = optional
organizationName = optional
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
[ signing_req ]
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer
basicConstraints = CA:FALSE
keyUsage = digitalSignature, keyEncipherment
### Fim do texto acima ###
# Crie o arquivo de index:
$ touch index.txt
# Crie também o arquivo de serial:
$ echo '01' > serial.txt
# Agora gere o CRT usando o CSR:
$ openssl ca -config sign.conf -policy signing_policy -extensions signing_req -out test-sysnetbr.eng.br.crt -infiles test-sysnetbr.eng.br.csr
Using configuration from sign.conf
Enter pass phrase for ca.key:
Check that the request matches the signature
Signature ok
The Subject's Distinguished Name is as follows
countryName :PRINTABLE:'BR'
stateOrProvinceName :ASN.1 12:'Sao Paulo'
localityName :ASN.1 12:'SP'
organizationName :ASN.1 12:'SysNetBR'
commonName :ASN.1 12:'test-sysnetbr.eng.br'
Certificate is to be certified until May 19 01:05:16 2024 GMT (365 days)
Sign the certificate? [y/n]:y
1 out of 1 certificate requests certified, commit? [y/n]y
Write out database with 1 new entries
Data Base Updated
# Agora podemos ver o domínio para qual o certificado está validando:
$ openssl s_client -showcerts -servername test-sysnetbr.eng.br -connect test-sysnetbr.eng.br:443 </dev/null 2>&- | openssl x509 -noout -ext subjectAltName
X509v3 Subject Alternative Name:
DNS:sysnetbr.eng.br, DNS:test-sysnetbr.eng.br
Fontes
https://gist.github.com/fntlnz/cf14feb5a46b2eda428e000157447309