Cómo crear un certificado autofirmado con OpenSSL

1294

Estoy agregando soporte HTTPS a un dispositivo Linux incorporado. He intentado generar un certificado autofirmado con estos pasos:

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

Esto funciona, pero obtengo algunos errores con, por ejemplo, Google Chrome:

¡Probablemente este no sea el sitio que estás buscando!
Certificado de seguridad del sitio no es de confianza!

¿Me estoy perdiendo de algo? ¿Es esta la forma correcta de crear un certificado autofirmado?

michelemarcon
fuente
40
Los certificados autofirmados se consideran inseguros para Internet. Firefox tratará el sitio como si tuviera un certificado no válido, mientras que Chrome actuará como si la conexión fuera HTTP simple. Más detalles: gerv.net/security/self-signed-certs
user1202136
34
Debe importar su certificado de CA en sus navegadores y decirles a los navegadores que confía en el certificado -o- conseguir que lo firme una de las grandes organizaciones de dinero por nada en las que los navegadores ya confían -o- ignore la advertencia y haga clic pasado Me gusta la última opción yo mismo.
trojanfoe
12
No debe utilizar la configuración de OpenSSL "stock" de esa manera. Esto se debe a que no puede colocar nombres DNS en el Nombre alternativo del sujeto (SAN). Debe proporcionar un archivo de configuración con una alternate_namessección y pasarlo con la -configopción. Además, colocar un nombre DNS en el nombre común (CN) está en desuso (pero no está prohibido) tanto por el IETF como por los foros de CA / navegador. Cualquier nombre DNS en el CN ​​también debe estar presente en la SAN. No hay forma de evitar usar la SAN. Ver la respuesta a continuación.
jww
55
Además del comentario de @jww. En mayo de 2017, Chrome ya no acepta certificados sin SAN (emtpy): "El certificado para este sitio no contiene una extensión de Nombre alternativo del sujeto que contenga un nombre de dominio o una dirección IP".
GerardJP
66
En estos días, siempre y cuando su FQDN pueda acceder a su servidor web en el puerto 80 a través de Internet, puede usar LetsEncrypt y obtener certificados de CA completos gratuitos (válidos durante 90 días, la renovación puede automatizarse) que no darán advertencias al navegador / mensajes www.letsencrypt.com
barny

Respuestas:

2131

Puedes hacerlo con un solo comando:

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

También puede agregar -nodes(abreviatura no DES) si no desea proteger su clave privada con una frase de contraseña. De lo contrario, le pedirá una contraseña de "al menos 4 caracteres".

El daysparámetro (365) puede reemplazarse con cualquier número para afectar la fecha de vencimiento. Luego le pedirá cosas como "Nombre del país", pero puede presionar Entery aceptar los valores predeterminados.

Agregue -subj '/CN=localhost'para suprimir preguntas sobre el contenido del certificado (reemplace localhostcon el dominio deseado).

Los certificados autofirmados no se validan con ningún tercero a menos que los importe previamente a los navegadores. Si necesita más seguridad, debe usar un certificado firmado por una autoridad de certificación (CA).

Diego Woitasen
fuente
8
Para cualquiera que esté interesado, aquí está la documentación , si desea verificar algo usted mismo.
17
¿Cómo proporciona más seguridad la firma con un tercero?
James Mills
201
Para cualquier otra persona que use esto en la automatización, aquí están todos los parámetros comunes para el tema:-subj "/C=US/ST=Oregon/L=Portland/O=Company Name/OU=Org/CN=www.example.com"
Alex S
17
@JamesMills Quiero decir, piénsalo, si un chico de aspecto sombrío con "dulces gratis" escrito en el costado de su camioneta te invita a entrar, lo pensarás dos veces y estarás en guardia al respecto, pero si alguien en quien confías, como realmente confías, es como "no, hombre, él es legítimo", vas a ser todo acerca de ese dulce gratis.
BrainSlugs83
73
Recuerde usar -sha256para generar un certificado basado en SHA-256.
Gea-Suan Lin
536

¿Me estoy perdiendo de algo? ¿Es esta la forma correcta de crear un certificado autofirmado?

Es fácil crear un certificado autofirmado. Solo usa el openssl reqcomando. Puede ser complicado crear uno que pueda ser consumido por la mayor selección de clientes, como navegadores y herramientas de línea de comandos.

Es difícil porque los navegadores tienen sus propios requisitos y son más restrictivos que el IETF . Los requisitos utilizados por los navegadores están documentados en los foros de CA / Navegador (ver referencias a continuación). Las restricciones surgen en dos áreas clave: (1) anclas de confianza y (2) nombres DNS.

Los navegadores modernos (como el warez que estamos usando en 2014/2015) quieren un certificado que se encadene a un ancla de confianza, y quieren que los nombres DNS se presenten de manera particular en el certificado. Y los navegadores se mueven activamente contra certificados de servidor autofirmados.

Algunos navegadores no facilitan la importación de un certificado de servidor autofirmado. De hecho, no puedes con algunos navegadores, como el navegador de Android. Entonces, la solución completa es convertirse en su propia autoridad.

En ausencia de convertirse en su propia autoridad, debe obtener los nombres DNS correctos para dar al certificado la mayor posibilidad de éxito. Pero te animo a que te conviertas en tu propia autoridad. Es fácil convertirse en su propia autoridad, y evitará todos los problemas de confianza (¿en quién mejor confiar que usted?).


¡Probablemente este no sea el sitio que estás buscando!
Certificado de seguridad del sitio no es de confianza!

Esto se debe a que los navegadores usan una lista predefinida de anclas de confianza para validar los certificados del servidor. Un certificado autofirmado no se encadena a un ancla de confianza.

La mejor manera de evitar esto es:

  1. Cree su propia autoridad (es decir, conviértase en CA )
  2. Crear una solicitud de firma de certificado (CSR) para el servidor
  3. Firme el CSR del servidor con su clave CA
  4. Instale el certificado del servidor en el servidor
  5. Instale el certificado de CA en el cliente

Paso 1: crear su propia autoridad solo significa crear un certificado autofirmado con CA: trueun uso adecuado de la clave. Eso significa que el Sujeto y el Emisor son la misma entidad, CA se establece en verdadero en Restricciones básicas (también debe marcarse como crítico), el uso de la clave es keyCertSigny crlSign(si está utilizando CRL), y el Identificador de clave del sujeto (SKI) es lo mismo que el Identificador de clave de autoridad (AKI).

Para convertirse en su propia autoridad de certificación, consulte * ¿Cómo firma una solicitud de firma de certificado con su autoridad de certificación? en desbordamiento de pila. Luego, importe su CA al Trust Store que utiliza el navegador.

Los pasos 2 a 4 son más o menos lo que hace ahora para un servidor público cuando contrata los servicios de una CA como Startcom o CAcert . Los pasos 1 y 5 le permiten evitar la autoridad de un tercero y actuar como su propia autoridad (¿en quién es mejor confiar que usted mismo?).

La siguiente mejor manera de evitar la advertencia del navegador es confiar en el certificado del servidor. Pero algunos navegadores, como el navegador predeterminado de Android, no te permiten hacerlo. Por lo tanto, nunca funcionará en la plataforma.

El problema de los navegadores (y otros agentes de usuario similares) que no confían en los certificados autofirmados será un gran problema en Internet de las cosas (IoT). Por ejemplo, ¿qué sucederá cuando se conecte a su termostato o refrigerador para programarlo? La respuesta es, nada bueno en lo que respecta a la experiencia del usuario.

El Grupo de trabajo WebAppSec del W3C está comenzando a analizar el problema. Consulte, por ejemplo, Propuesta: Marcar HTTP como no seguro .


Cómo crear un certificado autofirmado con OpenSSL

Los comandos a continuación y el archivo de configuración crean un certificado autofirmado (también le muestra cómo crear una solicitud de firma). Se diferencian de otras respuestas en un aspecto: los nombres DNS utilizados para el certificado autofirmado están en el Nombre alternativo del sujeto (SAN) y no en el Nombre común (CN) .

Los nombres DNS se colocan en la SAN a través del archivo de configuración con la línea subjectAltName = @alternate_names(no hay forma de hacerlo a través de la línea de comando). Luego hay una alternate_namessección en el archivo de configuración (debe ajustar esto a su gusto):

[ 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

Es importante poner el nombre DNS en la SAN y no en la CN, porque tanto el IETF como los foros CA / Browser especifican la práctica. También especifican que los nombres DNS en el CN ​​están en desuso (pero no están prohibidos). Si coloca un nombre DNS en la CN, debe incluirse en la SAN según las políticas de CA / B. Por lo tanto, no puede evitar usar el Nombre alternativo del sujeto.

Si no coloca nombres DNS en la SAN, el certificado no se validará bajo un navegador y otros agentes de usuario que sigan las pautas de CA / Browser Forum.

Relacionado: los navegadores siguen las políticas de CA / Browser Forum; y no las políticas de IETF. Esa es una de las razones por las que un certificado creado con OpenSSL (que generalmente sigue al IETF) a veces no se valida bajo un navegador (los navegadores siguen la CA / B). Son estándares diferentes, tienen diferentes políticas de emisión y diferentes requisitos de validación.


Cree un certificado autofirmado (observe la adición de la -x509opción):

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

Cree una solicitud de firma (observe la falta de -x509opción):

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 un certificado autofirmado :

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

Imprima una solicitud de firma :

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

Archivo de configuración (aprobado mediante -configopción)

[ 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

Es posible que deba hacer lo siguiente para Chrome. De lo contrario, Chrome puede quejarse de que un Nombre común no es válido ( ERR_CERT_COMMON_NAME_INVALID) . No estoy seguro de cuál es la relación entre una dirección IP en la SAN y un CN en este caso.

# IPv4 localhost
# IP.1       = 127.0.0.1

# IPv6 localhost
# IP.2     = ::1

Existen otras reglas sobre el manejo de nombres DNS en los certificados X.509 / PKIX. Consulte estos documentos para conocer las reglas:

RFC 6797 y RFC 7469 se enumeran, porque son más restrictivos que los otros RFC y documentos CA / B. Las RFC 6797 y 7469 tampoco permiten una dirección IP.

jww
fuente
44
¿Es posible usar comodines en la alternate_namessección? Particularmente subdominios sub-sub. Tengo una pregunta hace referencia a esta respuesta aquí: serverfault.com/questions/711596/...
LeonardChallis
3
Acabo de responder a su pregunta específica. Creo que no tiene sentido agregar esta larga descripción de seguridad cuando la respuesta fue tan simple
Diego Woitasen
14
@diegows: su respuesta no es completa ni correcta. La razón por la que no es correcta se discute en la larga publicación que no desea leer :)
jww
1
¡Gracias! Tu publicación me pareció muy útil. FYI Estaba jugando recientemente con Vault y descubrí que insistía en IP.x 127.0.0.1 en lugar de DNS.x 127 ... No verifiqué si esto está en el estándar o no.
Chomeh
44
Gracias @jww. Usted dijo: "1. Cree su propia autoridad (es decir, conviértase en CA)" , luego dijo: "5. Instale el certificado de CA en el cliente" . Si la clave raíz se ve comprometida, una persona malintencionada podría firmar un certificado para cualquier dominio con esa clave, y si te engañan para que vayas a su sitio web, ahora pueden hacer un ataque man-in-the-middle. ¿Hay alguna manera de crear la CA raíz de modo que solo pueda firmar CA intermedias y no certificados? Entonces puede proteger su CA intermediaria con una restricción de nombre.
Robin Zimmermann
408

Estas son las opciones descritas en la respuesta de @ diegows , descritas con más detalle, de la documentación :

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

Solicitud de certificado PKCS # 10 y utilidad de generación de certificados.

-x509

Esta opción genera un certificado autofirmado en lugar de una solicitud de certificado. Esto normalmente se usa para generar un certificado de prueba o una CA raíz autofirmada.

-newkey arg

Esta opción crea una nueva solicitud de certificado y una nueva clave privada. El argumento toma una de varias formas. rsa: nbits , donde nbits es el número de bits, genera una clave RSA nbits de tamaño.

-keyout filename

esto proporciona el nombre de archivo para escribir la clave privada recién creada.

-out filename

Esto especifica el nombre de archivo de salida para escribir o la salida estándar de forma predeterminada.

-days n

cuando se usa la opción -x509, esto especifica el número de días para certificar el certificado. El valor predeterminado es de 30 días.

-nodes

Si se especifica esta opción, si se crea una clave privada, no se cifrará.

La documentación es en realidad más detallada que la anterior; Lo acabo de resumir aquí.

Peter Mortensen
fuente
3
El XXXcomando original debe reemplazarse por el "número de días para certificar el certificado". El valor predeterminado es de 30 días. Por ejemplo, se -days XXXconvierte -days 365si desea que su certificado sea válido durante 365 días. Ver los documentos para más .
Nathan Jones
Gracias por agregar la documentación. Este enlace de IBM sobre la creación de un certificado autofirmado utilizando un comando que parece idéntico a esta respuesta
The Red Pea
314

A partir de 2020, el siguiente comando satisface todas sus necesidades, incluida 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"

En OpenSSL ≥ 1.1.1, esto se puede acortar a:

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"

Crea un certificado que es

  • válido para los dominios example.comy example.net(SAN),
  • también válido para la dirección IP 10.0.0.1(SAN),
  • relativamente fuerte (a partir de 2020) y
  • válido por 3650días (~ 10 años).

Crea los siguientes archivos:

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

Toda la información se proporciona en la línea de comando. No hay entrada interactiva que te moleste. No hay archivos de configuración con los que deba meterse. Todos los pasos necesarios se ejecutan mediante una sola invocación de OpenSSL : desde la generación de clave privada hasta el certificado autofirmado.

Observación # 1: parámetros criptográficos

Dado que el certificado está autofirmado y los usuarios deben aceptarlo manualmente, no tiene sentido usar una caducidad breve o una criptografía débil.

En el futuro, es posible que desee utilizar más de 4096bits para la clave RSA y un algoritmo hash más fuerte que sha256, pero a partir de 2020, estos son valores razonables. Son lo suficientemente fuertes mientras son compatibles con todos los navegadores modernos.

Observación # 2: Parámetro " -nodes"

Teóricamente, podría omitir el -nodesparámetro (que significa "sin cifrado DES"), en cuyo caso example.keyse cifraría con una contraseña. Sin embargo, esto casi nunca es útil para la instalación de un servidor, ya que también tendría que almacenar la contraseña en el servidor, o tendría que ingresarla manualmente en cada reinicio.

Observación # 3: Ver también

vog
fuente
1
No pude averiguar qué era exactamente la culpa en el argumento arg / CN = localhost expandiéndose a C: / Archivos de programa / Git / CN = localhost, así que ejecuté todo el comando en cmd.exe y funcionó bien. Por si acaso alguien está luchando con este.
Yuriy Pozniak el
1
@FranklinYu ¿Estás seguro de que rsa: 2048 será suficiente en 10 años a partir de ahora? Porque ese es el período de validez. Como se explicó, no tiene sentido usar una caducidad corta o una criptografía débil. La mayoría de las claves RSA de 2048 bits tienen un período de validez de 1-3 años como máximo. Con respecto a OpenSSL 1.1.1, todavía estoy dejando sha256 allí, por lo que es más explícito y obvio cambiar si quieres un hash más fuerte.
vog
1
@DaveFerguson ¿No se crea el certificado en //CN=localhostlugar de /CN=localhost? ¿Ayudará el escape adecuado aquí? Por ejemplo, ¿reemplazar /CN=localhostcon "/CN=localhost"resolver el problema de una manera limpia?
vog
44
1000 + 1s para crear un "one-liner" que utiliza la nueva SAN requerida sin tener que crear un archivo de configuración de largo aliento con mucha repetitiva. ¡Bien hecho!
Joshua Pinter
1
@ Precaución ¡Gracias! Acabo de editar esto en la respuesta. ¿La respuesta ahora es correcta para Windows / MinGW?
vog
143

No puedo comentar, así que pondré esto como una respuesta separada. Encontré algunos problemas con la respuesta de una línea aceptada:

  • El one-liner incluye una frase de contraseña en la clave.
  • El one-liner utiliza SHA-1 que en muchos navegadores arroja advertencias en la consola.

Aquí hay una versión simplificada que elimina la frase de contraseña, aumenta la seguridad para suprimir las advertencias e incluye una sugerencia en los comentarios para pasar en -subj para eliminar la lista de preguntas 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

Reemplace 'localhost' con cualquier dominio que necesite. Deberá ejecutar los dos primeros comandos uno por uno, ya que OpenSSL solicitará una frase de contraseña.

Para combinar los dos en un archivo .pem:

cat server.crt server.key > cert.pem
Mike N
fuente
66
Necesitaba un certificado de desarrollo para github.com/molnarg/node-http2 y esta respuesta es la mejor.
Capaj
1
Para combinar el certificado y la clave en un solo archivo: cat server.crt server.key >foo-cert.pem. Funciona con el ejemplo enopenssl-1.0.2d/demos/ssl/
18446744073709551615
El certificado que generé de esta manera todavía usa SHA1.
user169771
1
Tks, funciona muy bien para crear un certificado autofirmado FreeBSD 10 OpenLDAP 2.4conTLS
Thiago Pereira
2
¿Qué pasa con el archivo key.pem?
quikchange
72

Los navegadores modernos ahora arrojan un error de seguridad para los certificados autofirmados de otro modo bien formados si les falta una SAN (Nombre alternativo del sujeto). OpenSSL no proporciona una forma de línea de comandos para especificar esto , por lo que muchos tutoriales y marcadores de desarrolladores quedan desactualizados de repente.

La forma más rápida de volver a ejecutar es un archivo de configuración corto e independiente:

  1. Crear un archivo de configuración de OpenSSL (ejemplo: 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. Cree el certificado haciendo referencia a este archivo de configuración

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

Ejemplo de configuración de https://support.citrix.com/article/CTX135602

rymo
fuente
1
Funcionó para mí después de eliminar el último parámetro -extensions 'v3_req' que estaba causando un error. Usando OpenSSL para Windows. ¡Finalmente, me las arreglo para solucionar este problema! Gracias.
CGodo
1
@Kyopaxa tiene razón: ese parámetro es redundante con la línea 3 del archivo cnf; actualizado.
rymo
2
Manera sólida. Gracias. Sugeriría agregar -sha256.
cherouvim
55
Ahora puede especificar la SAN en la línea de comando con -extension 'subjectAltName = DNS:dom.ain, DNS:oth.er'ver github.com/openssl/openssl/pull/4986
Alexandre DuBreuil el
2
Parece que esta opción se llama -addextahora.
Alexandr Zarubkin
67

Recomendaría agregar el parámetro -sha256 , para usar el algoritmo hash SHA-2, porque los principales navegadores están considerando mostrar "certificados SHA-1" como no seguros.

La misma línea de comando de la respuesta aceptada - @diegows con agregado -sha256

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

Más información en el blog de Google Security .

Actualización de mayo de 2018. Como muchos señalaron en los comentarios, el uso de SHA-2 no agrega ninguna seguridad a un certificado autofirmado. Pero todavía recomiendo usarlo como un buen hábito de no usar funciones hash criptográficas obsoletas / inseguras. La explicación completa está disponible en ¿Por qué está bien que los certificados por encima del certificado de entidad final estén basados ​​en SHA-1? .

Maris B.
fuente
1
Si se trata de una clave autofirmada, generará errores del navegador de todos modos, por lo que esto realmente no importa
Mark
30
@ Mark, es importante, porque SHA-2 es más seguro
Maris B.
1
Al abrir el certificado en Windows después de renombrar cert.pem a cert.cer dice que el algoritmo de huellas digitales sigue siendo Sha1, pero el algoritmo de hash de firma es sha256.
pecado el
2
"Cifrado de clase mundial * autenticación cero = seguridad cero" gerv.net/security/self-signed-certs
x-yuri
44
Tenga en cuenta que el algoritmo de firma utilizado en un certificado autofirmado es irrelevante para decidir si es confiable o no. Los certificados raíz de CA son autofirmados. y a partir de mayo de 2018, todavía hay muchos certificados de CA raíz activos que están firmados con SHA-1. Porque no importa si un certificado confía en sí mismo, ni cómo ese certificado verifica esa confianza. Usted confía en el certificado raíz / autofirmado de quién dice que es, o no lo hace. Ver security.stackexchange.com/questions/91913/…
Andrew Henle
20

Este es el script que uso en cuadros locales para configurar el SAN (subjectAltName) en certificados autofirmados.

Este script toma el nombre de dominio (example.com) y genera la SAN para * .example.com y example.com en el mismo certificado. Las secciones a continuación están comentadas. Asigne un nombre al script (p generate-ssl.sh. Ej. ) Y dele permisos de ejecución. Los archivos se escribirán en el mismo directorio que el script.

Chrome 58 en adelante requiere que SAN se configure en certificados autofirmados.

#!/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"

Este script también escribe un archivo de información, por lo que puede inspeccionar el nuevo certificado y verificar que la SAN esté configurada correctamente.

                ...
                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:
     ...

Si está utilizando Apache, puede hacer referencia al certificado anterior en su archivo de configuración de la siguiente manera:

<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>

Recuerde reiniciar su servidor Apache (o Nginx, o IIS) para que el nuevo certificado surta efecto.

Drakes
fuente
Funciona en macOS High Siera y Chrome 58
Saqib Omer el
¿Todavía no estoy seguro de cómo afecta el CN ​​a la configuración general? Estoy intentando ejecutar esto como localhosto 127.0.0.1:port#lo que sería el correspondiente CNpara algo como esto.
DJ2
@ DJ2 Establecería 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

Esto también funciona en Chrome 57, ya que proporciona la SAN, sin tener otro archivo de configuración. Fue tomado de una respuesta aquí .

Esto crea un único archivo .pem que contiene la clave privada y el certificado. Puede moverlos para separar archivos .pem si es necesario.

joemillervi
fuente
2
Para los usuarios de Linux, deberá cambiar esa ruta para la configuración. por ejemplo, en las /etc/ssl/openssl.confobras actuales de Ubuntu
declinación del
Para una línea que no requiera que especifique la ubicación de openssl.cnf, consulte: stackoverflow.com/a/41366949/19163
vog
7

No puedo comentar, así que agrego una respuesta por separado. Traté de crear un certificado autofirmado para NGINX y fue fácil, pero cuando quise agregarlo a la lista blanca de Chrome tuve un problema. Y mi solución fue crear un certificado raíz y firmar un certificado hijo con él.

Entonces paso a paso. Crear archivo config_ssl_ca.cnf Aviso, el archivo de configuración tiene una opción basicConstraints = CA: verdadero, lo que significa que se supone que este certificado es root.

Esta es una buena práctica, porque la crea una vez y puede reutilizarla.

[ 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

Siguiente archivo de configuración para su certificado hijo.

[ 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

El primer paso: crear una clave raíz y un certificado

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

El segundo paso crea la clave secundaria y el archivo CSR - Solicitud de firma de certificado. Porque la idea es firmar el certificado secundario por root y obtener un certificado correcto

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

Abra la terminal de Linux y haga este comando echo 0

echo 1 > ca.srl
touch index.txt

El archivo de texto ca.srl que contiene el siguiente número de serie para usar en hexadecimal. Obligatorio. Este archivo debe estar presente y contener un número de serie válido.

Último paso, cree un archivo de configuración más y llámelo 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

Puede preguntar, por qué es tan difícil, por qué debemos crear una configuración más para firmar el certificado secundario por root. La respuesta es simple porque el certificado secundario debe tener un bloque SAN: nombres alternativos de sujeto. Si firmamos el certificado secundario con las utilidades "openssl x509", el certificado raíz eliminará el campo SAN en el certificado secundario. Entonces usamos "openssl ca" en lugar de "openssl x509" para evitar la eliminación del campo SAN. Creamos un nuevo archivo de configuración y le pedimos que copie todos los campos extendidos copy_extensions = copy .

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

El programa te hace 2 preguntas: 1. ¿Firmas el certificado? Diga "Y" 2. 1 de 1 solicitudes de certificado certificadas, ¿se comprometen? Di "Y"

En la terminal puede ver una oración con la palabra "Base de datos", significa el archivo index.txt que crea con el comando "touch". Contendrá toda la información de todos los certificados que cree mediante la utilidad "openssl ca". Para verificar el uso válido del certificado:

openssl rsa -in market.key -check

Si quieres ver qué hay en CRT:

openssl x509 -in market.crt -text -noout

Si quieres ver qué hay en CSR:

openssl req -in market.csr -noout -text 
mrkiril
fuente
2
Aunque este proceso parece complicado, esto es exactamente lo que necesitamos para el dominio .dev, ya que este dominio no admite certificados autofirmados y Chrome y Firefox están forzando HSTS. Lo que hice fue seguir estos pasos, que es crear CA, crear un certificado y firmarlo con mi CA y al final confiar en mi CA en el navegador. Gracias.
bajicdusko
1
Usted señor, es una maldita leyenda. ¡Mi homelab te lo agradece!
antsyawn
6

Tienes el procedimiento general correcto. La sintaxis para el comando está abajo.

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

Sin embargo, se muestran las advertencias porque el navegador no pudo verificar la identificación al validar el certificado con una Autoridad de certificación (CA) conocida.

Como se trata de un certificado autofirmado, no hay CA y puede ignorar la advertencia y continuar. Si desea obtener un certificado real que pueda ser reconocido por cualquier persona en Internet público, el procedimiento se encuentra a continuación.

  1. Generar una clave privada
  2. Use esa clave privada para crear un archivo CSR
  3. Enviar CSR a CA (Verisign u otros, etc.)
  4. Instale el certificado recibido de CA en el servidor web
  5. Agregue otros certificados a la cadena de autenticación según el tipo de certificado

Tengo más detalles sobre esto en una publicación en Asegurar la conexión: Crear un certificado de seguridad con OpenSSL

nneko
fuente
6

Un forro FTW. Me gusta que sea simple. ¿Por qué no usar un comando que contiene TODOS los argumentos necesarios? Así es como me gusta: esto crea un certificado x509 y su clave 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]"

Ese comando único contiene todas las respuestas que normalmente proporcionaría para los detalles del certificado. De esta manera, puede establecer los parámetros y ejecutar el comando, obtener su salida y luego ir a tomar un café.

>> Más aquí <<

OkezieE
fuente
1
Todos los argumentos, excepto las SAN ... la respuesta de @ vog cubre eso también (y es anterior a esto) (Esto tiene un campo "Asunto" más completo, aunque ...) (Tampoco es un gran admirador del vencimiento de un año)
Gert van den Berg
6

One-liner versión 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"))

Editar: se agregó la barra diagonal previa a la opción 'subj' para Ubuntu.

usuario327843
fuente
3

Generar claves

Estoy usando /etc/mysqlpara el almacenamiento de certificados porque /etc/apparmor.d/usr.sbin.mysqldcontiene /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;

Agregar configuración

/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

En mi configuración, el servidor Ubuntu inició sesión en: /var/log/mysql/error.log

Notas de seguimiento:

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

    MySQL podría ser denegado el acceso de lectura a su archivo de certificado si no está en la configuración de los dispositivos . Como se mencionó en los pasos anteriores ^, guarde todos nuestros certificados como .pemarchivos en el/etc/mysql/ directorio que apparmor aprueba por defecto (o modifique su apparmor / SELinux para permitir el acceso a donde sea que los haya almacenado).

  • SSL error: Unable to get private key

    Es posible que la versión de su servidor MySQL no sea compatible con el rsa:2048formato predeterminado

    Convertir generado rsa:2048a simple rsacon:

    openssl rsa -in server-key.pem -out server-key.pem
    openssl rsa -in client-key.pem -out client-key.pem
    
  • Compruebe si el servidor local admite 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  |
    +---------------+----------------------------+
    
  • Verificar que una conexión a la base de datos esté encriptada SSL :

    Verificando conexión

    Cuando inicie sesión en la instancia de MySQL, puede emitir la consulta:

    show status like 'Ssl_cipher';
    

    Si su conexión no está encriptada, el resultado estará en blanco:

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

    De lo contrario, mostraría una cadena de longitud distinta de cero para el cifrado en uso:

    mysql> show status like 'Ssl_cipher';
    +---------------+--------------------+
    | Variable_name | Value              |
    +---------------+--------------------+
    | Ssl_cipher    | DHE-RSA-AES256-SHA |
    +---------------+--------------------+
    1 row in set (0.00 sec)
    
  • Requerir ssl para la conexión de un usuario específico ('require ssl'):

    • SSL

    Le dice al servidor que permita solo conexiones cifradas con SSL para la cuenta.

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

    Para conectarse, el cliente debe especificar la opción --ssl-ca para autenticar el certificado del servidor, y además puede especificar las opciones --ssl-key y --ssl-cert. Si no se especifica la opción --ssl-ca ni la opción --ssl-capath, el cliente no autentica el certificado del servidor.


Enlace alternativo: Tutorial extenso en conexiones PHP seguras a MySQL con SSL .

ThorSummoner
fuente
-1; Esto es en gran medida tangencial a la pregunta formulada, y también hace un mal trabajo al dejar en claro de dónde provienen sus citas.
Mark Amery
Esto muestra aprovisionamiento de CA, certificados de servidor / cliente firmados por la CA, configúrelos para que mysqld los lea en un host con apparmor. Ejemplifica un caso bastante inútil de alojar el ca, el servidor y el cliente en la misma máquina, y exponer peligrosamente la autoridad de ese ca al proceso mysqld. Esta configuración realmente no tiene más sentido que probar la configuración de SSL en un entorno de prueba. Para operar una CA interna, recomendaría la cadena de herramientas gnuttls sobre openssl help.ubuntu.com/community/GnuTLS y tener una buena comprensión de tls antes de trabajar en el caso de mysqld + apparmor
ThorSummoner
3

Como se ha discutido en detalle, los certificados autofirmados no son confiables para Internet . Puede agregar su certificado autofirmado a muchos pero no a todos los navegadores . Alternativamente, puede convertirse en su propia autoridad de certificación .

La razón principal por la que uno no desea obtener un certificado firmado de una autoridad de certificación es el costo: Symantec cobra entre $ 995 y $ 1,999 por año por los certificados, solo por un certificado destinado a la red interna, Symantec cobra $ 399 por año . Ese costo es fácil de justificar si está procesando pagos con tarjeta de crédito o trabaja para el centro de ganancias de una empresa altamente rentable. Es más de lo que muchos pueden permitirse para un proyecto personal que uno está creando en Internet, o para una organización sin fines de lucro con un presupuesto mínimo, o si uno trabaja en el centro de costos de una organización, los centros de costos siempre intentan hacer más con menos.

Una alternativa es usar certbot (ver sobre certbot ). Certbot es un cliente automático fácil de usar que busca e implementa certificados SSL / TLS para su servidor web.

Si configura certbot, puede habilitarlo para crear y mantener un certificado emitido por la autoridad de certificación Let's Encrypt .

Hice esto durante el fin de semana para mi organización. Instalé los paquetes necesarios para certbot en mi servidor (Ubuntu 16.04) y luego ejecuté el comando necesario para configurar y habilitar certbot. Es probable que se necesite un complemento de DNS para certbot: actualmente estamos utilizando DigitalOcean, aunque es posible que pronto estemos migrando a otro servicio.

Tenga en cuenta que algunas de las instrucciones no fueron del todo correctas y se tomó un poco de tiempo y Google para darse cuenta. La primera vez me costó bastante tiempo, pero ahora creo que podría hacerlo en minutos.

Para DigitalOcean, un área que tuve dificultades fue cuando se me solicitó ingresar la ruta a su archivo INI de credenciales de DigitalOcean. A lo que se refiere el script es a la página Aplicaciones y API y a la pestaña Tokens / Key en esa página. Debe tener o generar un token de acceso personal (lectura y escritura) para la API de DigitalOcean; esta es una cadena hexadecimal de 65 caracteres. Esta cadena debe colocarse en un archivo en el servidor web desde el que está ejecutando certbot. Ese archivo puede tener un comentario como su primera línea (los comentarios comienzan con #). La segunda línea es:

dns_digitalocean_token = 0000111122223333444455556666777788889999aaaabbbbccccddddeeeeffff

Una vez que descubrí cómo configurar un token de lectura + escritura para la API de DigitalOcean, fue bastante fácil usar certbot para configurar un certificado comodín . Tenga en cuenta que no es necesario configurar un certificado comodín, sino que puede especificar cada dominio y subdominio en el que desea que se aplique el certificado. Era el certificado comodín que requería el archivo INI de credenciales que contenía el token de acceso personal de DigitalOcean.

Tenga en cuenta que los certificados de clave pública (también conocidos como certificados de identidad o certificados SSL) caducan y requieren renovación. Por lo tanto, deberá renovar su certificado de forma periódica (recurrente). La documentación de certbot cubre la renovación de certificados .

Mi plan es escribir un script para usar el comando openssl para obtener la fecha de vencimiento de mi certificado y activar la renovación cuando faltan 30 días para que caduque. Luego agregaré este script a cron y lo ejecutaré una vez al día.

Aquí está el comando para leer la fecha de vencimiento de su 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
fuente