Come creare un certificato autofirmato con OpenSSL


1294

Sto aggiungendo il supporto HTTPS a un dispositivo Linux incorporato. Ho provato a generare un certificato autofirmato con questi passaggi:

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

Funziona, ma ottengo alcuni errori con, ad esempio, Google Chrome:

Questo probabilmente non è il sito che stai cercando!
Il certificato di sicurezza del sito non è attendibile!

Mi sto perdendo qualcosa? È questo il modo corretto di costruire un certificato autofirmato?


40
I certificati autofirmati sono considerati non sicuri per Internet. Firefox tratterà il sito con un certificato non valido, mentre Chrome agirà come se la connessione fosse semplice HTTP. Maggiori dettagli: gerv.net/security/self-signed-certs
user1202136

34
Devi importare il tuo certificato CA nei tuoi browser e dire ai browser che ti fidi del certificato -oppure- farti firmare da una delle grandi organizzazioni che non si fidano del browser -o-- oppure ignorare l'avviso e fare clic incollalo. Mi piace l'ultima opzione me stesso.
trojanfoe,

12
Non utilizzare le impostazioni OpenSSL "stock" in questo modo. Questo perché non è possibile posizionare i nomi DNS nel soggetto Nome alternativo (SAN). Devi fornire un file di configurazione con una alternate_namessezione e passarlo con l' -configopzione. Inoltre, l'immissione di un nome DNS nel nome comune (CN) è deprecata (ma non proibita) da entrambi i forum IETF e CA / Browser. Qualsiasi nome DNS nella CN deve essere presente anche nella SAN. Non c'è modo di evitare l'uso della SAN. Vedi la risposta sotto.
JWW

5
Oltre al commento di @jww. A maggio 2017 Chrome non accetta più certificati SAN (emtpy) SAN: "Il certificato per questo sito non contiene un'estensione di nome alternativo soggetto contenente un nome di dominio o un indirizzo IP".
GerardJP,

6
In questi giorni, purché il tuo server web sia accessibile dal suo nome di dominio completo sulla porta 80 su Internet, puoi usare LetsEncrypt e ottenere certificati CA completi gratuiti (validi per 90 giorni, il rinnovo può essere automatizzato) che non fornirà alcun avviso del browser / messaggi. www.letsencrypt.com
barny

Risposte:


2131

Puoi farlo in un solo comando:

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

Puoi anche aggiungere -nodes(abbreviazione no DES) se non vuoi proteggere la tua chiave privata con una passphrase. Altrimenti ti chiederà la password "almeno 4 caratteri".

Il daysparametro (365) è possibile sostituire con qualsiasi numero per influire sulla data di scadenza. Ti chiederà quindi cose come "Nome Paese", ma puoi semplicemente selezionare Entere accettare le impostazioni predefinite.

Aggiungi -subj '/CN=localhost'per eliminare le domande sul contenuto del certificato (sostituisci localhostcon il dominio desiderato).

I certificati autofirmati non vengono convalidati con terze parti a meno che non vengano importati in precedenza nei browser. Se è necessaria maggiore sicurezza, è necessario utilizzare un certificato firmato da un'autorità di certificazione (CA).


8
Per chiunque sia interessato, ecco la documentazione , se si desidera verificare qualcosa da soli.

17
In che modo la firma con terze parti fornisce maggiore sicurezza?
James Mills,

201
Per chiunque lo usi in automazione, ecco tutti i parametri comuni per l'argomento: -subj "/C=US/ST=Oregon/L=Portland/O=Company Name/OU=Org/CN=www.example.com"
Alex S

17
@JamesMills Voglio dire, pensaci - se un ragazzo dall'aspetto ombroso con "caramelle gratis" scritto sul lato del suo furgone ti invita ad entrare, ci penserai due volte e ti starai attento - ma se qualcuno di cui ti fidi - come la vera fiducia - è tutto come "naw man, lui è legittimo" sarai tutto per quella caramella gratis.
BrainSlugs83,

73
Ricordarsi di utilizzare -sha256per generare un certificato basato su SHA-256.
Gea-Suan Lin,

536

Mi sto perdendo qualcosa? È questo il modo corretto di costruire un certificato autofirmato?

È facile creare un certificato autofirmato. Basta usare il openssl reqcomando. Può essere complicato crearne uno che può essere utilizzato dalla più grande selezione di client, come browser e strumenti da riga di comando.

È difficile perché i browser hanno i propri requisiti e sono più restrittivi di IETF . I requisiti utilizzati dai browser sono documentati nei forum CA / Browser (vedere i riferimenti di seguito). Le restrizioni sorgono in due aree chiave: (1) trust anchor e (2) nomi DNS.

I browser moderni (come il warez che stiamo usando nel 2014/2015) vogliono un certificato che ritorni su un ancoraggio sicuro e vogliono che i nomi DNS vengano presentati in modo particolare nel certificato. E i browser si stanno attivamente spostando rispetto ai certificati server autofirmati.

Alcuni browser non semplificano esattamente l'importazione di un certificato server autofirmato. In effetti, non è possibile con alcuni browser, come il browser Android. Quindi la soluzione completa è diventare la tua autorità.

In assenza di diventare la tua autorità, devi ottenere i nomi DNS giusti per dare al certificato le maggiori possibilità di successo. Ma ti incoraggio a diventare la tua autorità. È facile diventare la tua autorità e eluderà tutti i problemi di fiducia (di chi è meglio fidarsi di te stesso?).


Questo probabilmente non è il sito che stai cercando!
Il certificato di sicurezza del sito non è attendibile!

Questo perché i browser utilizzano un elenco predefinito di ancoraggi sicuri per convalidare i certificati del server. Un certificato autofirmato non si ricollega a un ancoraggio attendibile.

Il modo migliore per evitarlo è:

  1. Crea la tua autorità (ad esempio, diventa una CA. )
  2. Creare una richiesta di firma del certificato (CSR) per il server
  3. Firma il CSR del server con la tua chiave CA.
  4. Installa il certificato del server sul server
  5. Installa il certificato CA sul client

Passaggio 1: creare la propria autorità significa solo creare un certificato autofirmato con un CA: truecorretto utilizzo della chiave. Ciò significa che il Soggetto e l' Emittente sono la stessa entità, la CA è impostata su true nei Vincoli di base (deve anche essere contrassegnata come critica), l'utilizzo della chiave è keyCertSigne crlSign(se si utilizzano CRL) e l' identificatore chiave dell'oggetto (SKI) è lo stesso del dell'identificatore chiave autorità (AKI).

Per diventare la propria autorità di certificazione, vedere * Come si firma una richiesta di firma del certificato con la propria autorità di certificazione?su Stack Overflow. Quindi, importa la tua CA nel Trust Store utilizzato dal browser.

I passaggi 2 - 4 sono all'incirca quelli che fai ora per un server pubblico quando aggiungi i servizi di una CA come Startcom o CAcert . I passaggi 1 e 5 ti consentono di evitare l'autorità di terze parti e di agire come la tua autorità (di chi è meglio fidarsi di te stesso?).

Il prossimo modo migliore per evitare l'avviso del browser è fidarsi del certificato del server. Ma alcuni browser, come il browser predefinito di Android, non ti consentono di farlo. Quindi non funzionerà mai sulla piattaforma.

Il problema dei browser (e altri agenti utente simili) no fidano dei certificati autofirmati sarà un grosso problema nell'Internet of Things (IoT). Ad esempio, cosa accadrà quando ci si collega al termostato o al frigorifero per programmarlo? La risposta è: nulla di buono per quanto riguarda l'esperienza dell'utente.

Il gruppo di lavoro WebAppSec del W3C sta iniziando a esaminare il problema. Vedere, ad esempio, Proposta: contrassegnare HTTP come non sicuro .


Come creare un certificato autofirmato con OpenSSL

I comandi seguenti e il file di configurazione creano un certificato autofirmato (mostra anche come creare una richiesta di firma). Differiscono dalle altre risposte per un aspetto: i nomi DNS utilizzati per il certificato autofirmato si trovano nel soggetto Nome alternativo (SAN) e non nel nome comune (CN) .

I nomi DNS vengono inseriti nella SAN attraverso il file di configurazione con la linea subjectAltName = @alternate_names(non c'è modo di farlo attraverso la riga di comando). Quindi c'è una alternate_namessezione nel file di configurazione (dovresti regolarla secondo i tuoi gusti):

[ 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 inserire il nome DNS nella SAN e non nella CN, poiché sia IETF che i forum CA / Browser specificano la pratica. Inoltre, specificano che i nomi DNS nella CN sono obsoleti (ma non vietati). Se si inserisce un nome DNS nella CN, deve essere incluso nella SAN in base ai criteri CA / B. Quindi non puoi evitare di usare il Nome alternativo soggetto.

Se non si inseriscono nomi DNS nella SAN, il certificato non verrà convalidato in un browser e altri agenti utente che seguono le linee guida CA / Forum Forum.

Correlati: i browser seguono le politiche CA / Browser Forum; e non le politiche IETF. Questo è uno dei motivi per cui un certificato creato con OpenSSL (che generalmente segue la IETF) a volte non viene convalidato da un browser (i browser seguono la CA / B). Sono standard diversi, hanno politiche di emissione e requisiti di convalida diversi.


Crea un certificato autofirmato (nota l'aggiunta -x509dell'opzione):

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

Crea una richiesta di firma (nota la mancanza di -x509opzione):

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

Stampa un certificato autofirmato :

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

Stampa una richiesta di firma :

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

File di configurazione (passato tramite -configopzione)

[ 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        = test@example.com

# 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

Potrebbe essere necessario eseguire le seguenti operazioni per Chrome. Altrimenti Chrome potrebbe lamentare un nome comune non valido ( ERR_CERT_COMMON_NAME_INVALID) . Non sono sicuro di quale sia la relazione tra un indirizzo IP nella SAN e una CN in questo caso.

# IPv4 localhost
# IP.1       = 127.0.0.1

# IPv6 localhost
# IP.2     = ::1

Esistono altre regole relative alla gestione dei nomi DNS nei certificati X.509 / PKIX. Fare riferimento a questi documenti per le regole:

Sono elencati RFC 6797 e RFC 7469, poiché sono più restrittivi rispetto agli altri documenti RFC e CA / B. Le RFC 6797 e 7469 non consentono neanche un indirizzo IP.


4
È possibile utilizzare i caratteri jolly nella alternate_namessezione? Soprattutto sottodomini. Ho una domanda che fa riferimento a questa risposta qui: serverfault.com/questions/711596/…
LeonardChallis

3
Ho appena risposto alla sua domanda specifica. Penso che non abbia senso aggiungere questa lunga descrizione della sicurezza quando la risposta era così semplice
Diego Woitasen,

14
@diegows - la tua risposta non è completa o corretta. La ragione per cui non è corretta è discussa nel lungo post che non vuoi leggere :)
jww

1
Grazie! Ho trovato il tuo post molto utile. Cordiali saluti Recentemente stavo giocando con Vault e ho scoperto che insisteva su IP.x 127.0.0.1 piuttosto che su DNS.x 127 ... Non ho controllato se questo è standard o no.
Chomeh,

4
Grazie @jww. Hai detto, "1. Crea la tua autorità (ad esempio, diventa una CA)" , poi hai detto "5. Installa il certificato CA sul client" . Se la chiave di root venisse compromessa, una persona malintenzionata potrebbe firmare un certificato per qualsiasi dominio con quella chiave e se ti inducono ad accedere al loro sito Web, ora possono eseguire un attacco man-in-the-middle. Esiste un modo per creare la CA principale in modo tale che possa firmare solo CA intermedie e non certificati? Quindi è possibile proteggere la propria CA intermedia con un vincolo di nome.
Robin Zimmermann,

408

Ecco le opzioni descritte nella risposta di @ diegows , descritte più dettagliatamente dalla documentazione :

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

Richiesta di certificato PKCS # 10 e utilità per la generazione di certificati.

-x509

questa opzione genera un certificato autofirmato anziché una richiesta di certificato. In genere viene utilizzato per generare un certificato di prova o una CA radice autofirmata.

-newkey arg

questa opzione crea una nuova richiesta di certificato e una nuova chiave privata. L'argomento assume una delle diverse forme. rsa: nbits , dove nbits è il numero di bit, genera una chiave RSA di dimensioni nbit .

-keyout filename

questo dà il nome del file in cui scrivere la chiave privata appena creata.

-out filename

Questo specifica il nome del file di output su cui scrivere o lo standard output per impostazione predefinita.

-days n

quando viene utilizzata l'opzione -x509 , questo specifica il numero di giorni per cui certificare il certificato. L'impostazione predefinita è 30 giorni.

-nodes

se questa opzione è specificata, se viene creata una chiave privata non verrà crittografata.

La documentazione è in realtà più dettagliata di quanto sopra; L'ho appena sintetizzato qui.


3
Il XXXcomando originale deve essere sostituito con il "numero di giorni per cui certificare il certificato". L'impostazione predefinita è 30 giorni. Ad esempio, -days XXXdiventa -days 365se si desidera che il certificato sia valido per 365 giorni. Vedi i documenti per di più .
Nathan Jones,

Grazie per aver aggiunto la documentazione. Questo link IBM sulla creazione di un certificato autofirmato utilizzando un comando che sembra identico a questa risposta
The Red Pea

314

A partire dal 2020, il seguente comando soddisfa tutte le tue esigenze, inclusa la 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"

In OpenSSL ≥ 1.1.1, questo può essere abbreviato in:

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 certificato che lo è

  • valido per i domini example.come example.net(SAN),
  • valido anche per l'indirizzo IP 10.0.0.1(SAN),
  • relativamente forte (dal 2020) e
  • valido per 3650 giorni (~ 10 anni).

Crea i seguenti file:

  • Chiave privata: example.key
  • Certificato: example.crt

Tutte le informazioni sono fornite dalla riga di comando. Non ci sono input interattivi che ti danno fastidio. Non ci sono file di configurazione con cui devi scherzare. Tutti i passaggi necessari vengono eseguiti da un'unica chiamata OpenSSL : dalla generazione della chiave privata fino al certificato autofirmato.

Nota n. 1: parametri crittografici

Poiché il certificato è autofirmato e deve essere accettato manualmente dagli utenti, non ha senso utilizzare una scadenza breve o una crittografia debole.

In futuro, potresti voler usare più di 4096bit per la chiave RSA e un algoritmo di hash più forte di sha256, ma a partire dal 2020 questi sono valori sani. Sono sufficientemente potenti pur essendo supportati da tutti i browser moderni.

Nota n. 2: parametro " -nodes"

Teoricamente potresti tralasciare il -nodesparametro (che significa "nessuna crittografia DES"), nel qual caso example.keyverrebbe crittografato con una password. Tuttavia, questo non è quasi mai utile per l'installazione di un server, perché dovresti o memorizzare anche la password sul server, o dovresti inserirla manualmente ad ogni riavvio.

Nota n. 3: vedi anche


1
Non riuscivo a capire quale fosse esattamente la colpa nell'arg / CN = localhost che si espandeva in C: / Program Files / Git / CN = localhost, quindi ho appena eseguito l'intero comando in semplice cmd.exe e ha funzionato bene. Nel caso in cui qualcuno stia lottando con questo.
Yuriy Pozniak,

1
@FranklinYu Sei sicuro che rsa: 2048 sarà sufficiente tra 10 anni? Perché quello è il periodo di validità. Come spiegato, non ha senso usare una scadenza breve o una crittografia debole. La maggior parte delle chiavi RSA a 2048 bit ha un periodo di validità di 1-3 anni al massimo. Per quanto riguarda OpenSSL 1.1.1, sto ancora lasciando sha256 lì, quindi è più esplicito e ovvio cambiare se si desidera un hash più forte.
Vog

1
@DaveFerguson Non è stato quindi creato il certificato //CN=localhostanziché /CN=localhost? La fuga corretta aiuterà qui? Ad esempio, la sostituzione /CN=localhostcon "/CN=localhost"risolve il problema in modo pulito?
Vog

4
1000 + 1s per la creazione di un "one-liner" che utilizza la nuova SAN richiesta senza dover creare un file di configurazione prolisso con molta piastra di caldaia. Molto bene!
Joshua Pinter,

1
@cautionbug Grazie! Ho appena modificato questo nella risposta. La risposta ora è corretta per Windows / MinGW?
vog

143

Non posso commentare, quindi inserirò questo come una risposta separata. Ho riscontrato alcuni problemi con la risposta accettata in una sola riga:

  • Il one-liner include una passphrase nella chiave.
  • Il one-liner utilizza SHA-1 che in molti browser genera avvisi nella console.

Ecco una versione semplificata che rimuove la passphrase, aumenta la sicurezza per sopprimere gli avvisi e include un suggerimento nei commenti da passare in -subj per rimuovere l'elenco completo delle domande:

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

Sostituisci "localhost" con qualunque dominio tu richieda. Dovrai eseguire i primi due comandi uno alla volta poiché OpenSSL richiederà una passphrase.

Per combinare i due in un file .pem:

cat server.crt server.key > cert.pem

6
Avevo bisogno di un certificato di sviluppo per github.com/molnarg/node-http2 e questa risposta è la migliore.
Capaj,

1
Per combinare il certificato e la chiave in un unico file: cat server.crt server.key >foo-cert.pem. Funziona con l'esempio inopenssl-1.0.2d/demos/ssl/
18446744073709551615

Il certificato che ho generato in questo modo sta ancora usando SHA1.
user169771

1
Tks, funziona benissimo per creare un certificato autofirmato FreeBSD 10 OpenLDAP 2.4conTLS
Thiago Pereira,

2
Che dire del file key.pem?
quikchange

72

I browser moderni ora generano un errore di sicurezza per i certificati autofirmati altrimenti ben formati se mancano di una SAN (soggetto nome alternativo). OpenSSL non fornisce un modo da riga di comando per specificare questo , quindi molti tutorial e segnalibri degli sviluppatori sono improvvisamente obsoleti.

Il modo più rapido per riavviare è un file di configurazione autonomo breve:

  1. Creare un file di configurazione OpenSSL (esempio: 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. Creare il certificato che fa riferimento a questo file di configurazione

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

Esempio di configurazione da https://support.citrix.com/article/CTX135602


1
Ha funzionato per me dopo aver rimosso l'ultimo parametro -extensions 'v3_req' che stava causando un errore. Utilizzando OpenSSL per Windows. Finalmente riesco a risolvere questo problema! Grazie.
CGodo

1
@Kyopaxa hai ragione: quel parametro è ridondante con la riga 3 del file cnf; aggiornato.
Rymo,

2
Modo solido. Grazie. Suggerirei di aggiungere -sha256.
Cherouvim,

5
Ora puoi specificare la SAN dalla riga di comando con -extension 'subjectAltName = DNS:dom.ain, DNS:oth.er'vedi github.com/openssl/openssl/pull/4986
Alexandre DuBreuil,

2
Sembra che questa opzione sia chiamata -addextora.
Alexandr Zarubkin,

67

Vorrei raccomandare di aggiungere il parametro -sha256 , per utilizzare l'algoritmo di hash SHA-2, perché i principali browser stanno considerando di mostrare "certificati SHA-1" come non sicuri.

La stessa riga di comando dalla risposta accettata - @diegows con l'aggiunta di -sha256

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

Maggiori informazioni nel blog sulla sicurezza di Google .

Aggiornamento maggio 2018. Come molti hanno notato nei commenti che l'uso di SHA-2 non aggiunge alcuna sicurezza a un certificato autofirmato. Ma consiglio comunque di usarlo come una buona abitudine di non usare funzioni hash crittografiche obsolete / insicure. La spiegazione completa è disponibile in Perché è corretto che i certificati superiori al certificato dell'entità finale siano basati su SHA-1? .


1
Se è una chiave autofirmata, genererà comunque errori del browser, quindi questo non ha molta importanza
Mark

30
@Mark, importa, perché SHA-2 è più sicuro
Maris B.

1
L'apertura del certificato in Windows dopo aver rinominato cert.pem in cert.cer dice che l'algoritmo dell'impronta digitale è ancora Sha1, ma l'algoritmo hash della firma è sha256.
peccato il

2
"Crittografia di classe mondiale * autenticazione zero = zero sicurezza" gerv.net/security/self-signed-certs
x-yuri

4
Si noti che l'algoritmo di firma utilizzato su un certificato autofirmato è irrilevante nel decidere se sia affidabile o meno. I certificati CA principali sono autofirmati. e a partire da maggio 2018, ci sono ancora molti certificati CA radice attivi che sono firmati SHA-1. Perché non importa se un certificato si fida di se stesso, né in che modo quel certificato verifica tale affidabilità. O ti fidi del certificato root / autofirmato per chi dice che sia, oppure no. Vedi security.stackexchange.com/questions/91913/…
Andrew Henle

20

Questo è lo script che uso sulle caselle locali per impostare la SAN (subjectAltName) nei certificati autofirmati.

Questo script prende il nome di dominio (esempio.com) e genera la SAN per * .example.com ed esempio.com nello stesso certificato. Le sezioni seguenti sono commentate. Denominare lo script (ad es. generate-ssl.sh) E dargli le autorizzazioni eseguibili. I file verranno scritti nella stessa directory dello script.

Chrome 58 in poi richiede che SAN sia impostato in certificati autofirmati.

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

Questo script scrive anche un file di informazioni, quindi è possibile ispezionare il nuovo certificato e verificare che la SAN sia impostata correttamente.

                ...
                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 stai usando Apache, puoi fare riferimento al certificato sopra nel tuo file di configurazione in questo modo:

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

Ricordare di riavviare il server Apache (o Nginx o IIS) per rendere effettivo il nuovo certificato.


Funziona su macOS High Siera e Chrome 58
Saqib Omer il

Non sono ancora sicuro di come la CN influenzi la configurazione generale? Sto tentando di eseguire questo come localhosto 127.0.0.1:port#quale sarebbe il corrispondente CNper qualcosa di simile.
DJ2

@ DJ2 Vorrei impostare BASE_DOMAIN = "localhost"
Drakes

9

One-liner 2017:

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

Questo funziona anche in Chrome 57, in quanto fornisce la SAN, senza avere un altro file di configurazione. È stato preso da una risposta qui .

Questo crea un singolo file .pem che contiene sia la chiave privata che cert. Se necessario, puoi spostarli in file .pem separati.


2
Per gli utenti Linux dovrai cambiare quel percorso per la configurazione. ad es. sulle attuali /etc/ssl/openssl.confopere di Ubuntu
declinazione

Per una battuta che non richiede di specificare la posizione openssl.cnf, vedi: stackoverflow.com/a/41366949/19163
VOG

7

Non posso commentare, quindi aggiungo una risposta separata. Ho provato a creare un certificato autofirmato per NGINX ed è stato facile, ma quando volevo aggiungerlo alla lista bianca di Chrome ho avuto un problema. E la mia soluzione era quella di creare un certificato radice e firmare un certificato figlio da esso.

Quindi passo dopo passo. Crea file config_ssl_ca.cnf Nota, il file config ha un'opzione basicConstraints = CA: true che significa che questo certificato dovrebbe essere root.

Questa è una buona pratica, perché la crei una volta e puoi riutilizzarla.

[ 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
emailAddress=root_email@root.localhost

[ 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

File di configurazione successivo per il certificato figlio.

[ 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
emailAddress=email@market.localhost

[ 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

Il primo passo: crea la chiave e il certificato di root

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

Il secondo passaggio crea CSR chiave file e file - Richiesta firma certificato. Perché l'idea è quella di firmare il certificato figlio da root e ottenere un certificato corretto

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

Apri il terminale Linux ed esegui questo comando echo 0

echo 1 > ca.srl
touch index.txt

Il ca.srl file di testo contenente il numero seriale successivo da utilizzare in esadecimale. Obbligatorio. Questo file deve essere presente e contenere un numero seriale valido.

Ultimo passaggio, crea un altro file di configurazione e chiamalo 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

Potresti chiedere, perché è così difficile, perché dobbiamo creare un'altra configurazione per firmare il certificato figlio dalla radice. La risposta è semplice perché il certificato figlio deve avere un blocco SAN - Nomi alternativi soggetto. Se firmiamo il certificato figlio con "openssl x509" utils, il certificato radice eliminerà il campo SAN nel certificato figlio. Quindi usiamo "openssl ca" invece di "openssl x509" per evitare la cancellazione del campo SAN. Creiamo un nuovo file di configurazione e gli diciamo di copiare tutti i campi estesi copy_extensions = copy .

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

Il programma ti pone 2 domande: 1. Firmare il certificato? Pronuncia "Y" 2. 1 su 1 richieste di certificato certificate, impegno? Dì "Y"

Nel terminale puoi vedere una frase con la parola "Database", significa file index.txt che crei con il comando "touch". Conterrà tutte le informazioni di tutti i certificati creati da "openssl ca" util. Per verificare la validità del certificato utilizzare:

openssl rsa -in market.key -check

Se vuoi vedere cosa c'è dentro in CRT:

openssl x509 -in market.crt -text -noout

Se vuoi vedere cosa c'è dentro CSR:

openssl req -in market.csr -noout -text 

2
Anche se questo processo sembra complicato, questo è esattamente ciò di cui abbiamo bisogno per il dominio .dev, poiché questo dominio non supporta i certificati autofirmati e Chrome e Firefox stanno forzando HSTS. Quello che ho fatto è stato seguire questa procedura, che sta creando CA, creando un certificato e firmandolo con la mia CA e alla fine fidandomi della mia CA nel browser. Grazie.
bajicdusko,

1
Signore, siete una dannata leggenda. Il mio homelab ti ringrazia!
Antsyawn,

6

La procedura generale è corretta. La sintassi per il comando è di seguito.

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

Tuttavia, vengono visualizzati gli avvisi, poiché il browser non è stato in grado di verificare l'identificazione convalidando il certificato con un'autorità di certificazione nota (CA).

Poiché si tratta di un certificato autofirmato, non esiste alcuna CA e puoi tranquillamente ignorare l'avviso e procedere. Se desideri ottenere un vero certificato che sarà riconoscibile da chiunque su Internet pubblico, la procedura è di seguito.

  1. Genera una chiave privata
  2. Utilizzare quella chiave privata per creare un file CSR
  3. Invia CSR a CA (Verisign o altri, ecc.)
  4. Installa il certificato ricevuto dalla CA sul server web
  5. Aggiungi altri certificati alla catena di autenticazione in base al tipo di certificato

Ho maggiori dettagli a riguardo in un post su Protezione della connessione: creazione di un certificato di sicurezza con OpenSSL


6

Una fodera FTW. Mi piace mantenerlo semplice. Perché non usare un comando che contiene TUTTI gli argomenti necessari? Ecco come mi piace: crea un certificato x509 e la sua chiave 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/emailAddress=someEmail@gmail.com"

Quel singolo comando contiene tutte le risposte che normalmente forniresti per i dettagli del certificato. In questo modo puoi impostare i parametri ed eseguire il comando, ottenere il tuo output - quindi andare per un caffè.

>> Più qui <<


1
Tutti gli argomenti ad eccezione di SAN ... La risposta di @ vog copre anche questo (e lo precede) (Questo ha un campo "Oggetto" più completo compilato però ...) (Neanche un grande fan della scadenza di un anno)
Gert van den Berg,

6

Versione 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"))

Modifica: aggiunta l'aggiunta di Slash all'opzione 'subj' per Ubuntu.


3

Genera chiavi

Sto usando /etc/mysqlper la memorizzazione di certificati perché /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;

Aggiungi configurazione

/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

Nella mia configurazione, il server Ubuntu ha effettuato l'accesso a: /var/log/mysql/error.log

Note di follow-up:

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

    A MySQL potrebbe essere negato l'accesso in lettura al file del certificato se non si trova nella configurazione di apparmors . Come accennato nei passaggi precedenti ^, salva tutti i nostri certificati come .pemfile nella /etc/mysql/directory che è approvata di default da apparmor (o modifica il tuo apparmor / SELinux per consentire l'accesso ovunque tu li abbia memorizzati).

  • SSL error: Unable to get private key

    La versione del tuo server MySQL potrebbe non supportare il rsa:2048formato predefinito

    Converti generato rsa:2048in piano rsacon:

    openssl rsa -in server-key.pem -out server-key.pem
    openssl rsa -in client-key.pem -out client-key.pem
    
  • Verifica se il server locale supporta 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  |
    +---------------+----------------------------+
    
  • La verifica di una connessione al database è crittografata SSL :

    Verifica connessione

    Una volta effettuato l'accesso all'istanza di MySQL, è possibile inviare la query:

    show status like 'Ssl_cipher';
    

    Se la tua connessione non è crittografata, il risultato sarà vuoto:

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

    Altrimenti, mostrerebbe una stringa di lunghezza diversa da zero per il codice in uso:

    mysql> show status like 'Ssl_cipher';
    +---------------+--------------------+
    | Variable_name | Value              |
    +---------------+--------------------+
    | Ssl_cipher    | DHE-RSA-AES256-SHA |
    +---------------+--------------------+
    1 row in set (0.00 sec)
    
  • Richiedi SSL per la connessione di un utente specifico ("richiede SSL"):

    • SSL

    Indica al server di consentire solo connessioni crittografate SSL per l'account.

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

    Per connettersi, il client deve specificare l'opzione --ssl-ca per autenticare il certificato del server e può inoltre specificare le opzioni --ssl-key e --ssl-cert. Se non viene specificata né l'opzione --ssl-ca né l'opzione --ssl-capath, il client non autentica il certificato del server.


Link alternativo: tutorial lungo in Secure PHP Connections a MySQL con SSL .


-1; questo è in gran parte tangenziale alla domanda posta e fa anche un brutto lavoro nel chiarire da dove provengono le sue citazioni.
Mark Amery,

Ciò mostra CA di provisioning, certificati Server / Client firmati dalla CA, configurarli per la lettura di mysqld su un host con apparmor. È un esempio del caso piuttosto inutile di ospitare ca, server e client sulla stessa macchina e di esporre pericolosamente l'autorità di tale ca al processo mysqld. Questa configurazione non ha molto senso se non quella di testare la configurazione SSL in un ambiente di test. Per il funzionamento di una CA interna, consiglierei la toolchain di gnuttls su openssl help.ubuntu.com/community/GnuTLS e avere una buona conoscenza di tls prima di aggirare il caso mysqld + apparmor
ThorSummoner

3

Come è stato discusso in dettaglio, i certificati autofirmati non sono affidabili per Internet . Puoi aggiungere il tuo certificato autofirmato a molti ma non a tutti i browser . In alternativa puoi diventare la tua autorità di certificazione .

Il motivo principale per cui non si desidera ottenere un certificato firmato da un'autorità di certificazione è il costo - Symantec addebita tra $ 995 - $ 1,999 all'anno per i certificati - solo per un certificato destinato alla rete interna, Symantec addebita $ 399 all'anno . Tale costo è facile da giustificare se si stanno elaborando pagamenti con carta di credito o si lavora per il centro di profitto di un'azienda altamente redditizia. È più di quello che molti possono permettersi per un progetto personale che si sta creando su Internet, o per un'attività senza scopo di lucro con un budget minimo o se si lavora in un centro di costo di un'organizzazione - i centri di costo cercano sempre di fare di più con meno.

Un'alternativa è usare certbot (vedi su certbot ). Certbot è un client automatico di facile utilizzo che recupera e distribuisce certificati SSL / TLS per il tuo server web.

Se si configura certbot, è possibile abilitarlo per creare e gestire un certificato emesso dall'autorità di certificazione Let's Encrypt .

L'ho fatto durante il fine settimana per la mia organizzazione. Ho installato i pacchetti richiesti per certbot sul mio server (Ubuntu 16.04) e quindi ho eseguito il comando necessario per configurare e abilitare certbot. Uno probabilmente ha bisogno di un plug-in DNS per certbot: attualmente stiamo usando DigitalOcean anche se potrebbe presto migrare verso un altro servizio.

Nota che alcune delle istruzioni non erano del tutto giuste e ci sono voluti un po 'di frugate e tempo con Google per capire. La prima volta ci è voluto un bel po 'del mio tempo, ma ora penso di poterlo fare in pochi minuti.

Per DigitalOcean, un'area in cui mi sono trovata in difficoltà è stata quando mi è stato chiesto di inserire il percorso del file INI delle credenziali DigitalOcean. Ciò a cui si riferisce lo script è la pagina Applicazioni e API e la scheda Token / Chiave su quella pagina. È necessario disporre o generare un token di accesso personale (lettura e scrittura) per l'API di DigitalOcean: si tratta di una stringa esadecimale di 65 caratteri. Questa stringa deve quindi essere inserita in un file sul server Web da cui si sta eseguendo certbot. Quel file può avere un commento come prima riga (i commenti iniziano con #). La seconda riga è:

dns_digitalocean_token = 0000111122223333444455556666777788889999aaaabbbbccccddddeeeeffff

Una volta capito come impostare un token read + write per l'API di DigitalOcean, è stato abbastanza facile usare certbot per impostare un certificato jolly . Si noti che non è necessario impostare un certificato con caratteri jolly, è possibile invece specificare ciascun dominio e sottodominio a cui si desidera applicare il certificato. Era il certificato jolly che richiedeva il file INI delle credenziali che conteneva il token di accesso personale da DigitalOcean.

Si noti che i certificati a chiave pubblica (noti anche come certificati di identità o certificati SSL) scadono e richiedono il rinnovo. Pertanto sarà necessario rinnovare il certificato su base periodica (ricorrente). La documentazione di certbot riguarda il rinnovo dei certificati .

Il mio piano è quello di scrivere uno script per utilizzare il comando openssl per ottenere la data di scadenza del mio certificato e per attivare il rinnovo quando mancano 30 giorni alla scadenza. Aggiungerò quindi questo script a cron ed eseguirlo una volta al giorno.

Ecco il comando per leggere la data di scadenza del certificato:

root@prod-host:~# /usr/bin/openssl x509 -enddate -noout -in path-to-certificate-pem-file
notAfter=May 25 19:24:12 2019 GMT
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.