How to generate a self-signed SSL certificate using OpenSSL? [closed]
Asked Answered
P

23

1966

I'm adding HTTPS support to an embedded Linux device. I have tried to generate a self-signed certificate with these steps:

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

This works, but I get some errors with, for example, Google Chrome:

This is probably not the site you are looking for!
The site's security certificate is not trusted!

Am I missing something? Is this the correct way to build a self-signed certificate?

Palestrina answered 16/4, 2012 at 14:14 Comment(6)
Self-signed certificates are considered insecure for the Internet. Firefox will treat the site as having an invalid certificate, while Chrome will act as if the connection was plain HTTP. More details: gerv.net/security/self-signed-certsHump
You need to import your CA certificate into your browsers and tell the browsers you trust the certificate -or- get it signed by one of the big money-for-nothing organizations that are already trusted by the browsers -or- ignore the warning and click past it. I like the last option myself.Enzymology
You should not use the "stock" OpenSSL settings like that. That's because you cannot place DNS names in the Subject Alternate Name (SAN). You need to provide a configuration file with an alternate_names section and pass it with the -config option. Also, placing a DNS name in the Common Name (CN) is deprecated (but not prohibited) by both the IETF and the CA/Browser Forums. Any DNS name in the CN must also be present in the SAN. There's no way to avoid using the SAN. See answer below.Protest
In addition to @Protest 's comment. Per may 2017 Chrome doesn't accept certs w/o (emtpy) SAN's anymore: "The certificate for this site does not contain a Subject Alternative Name extension containing a domain name or IP address."Amphioxus
These days, as long as your webserver is accessible by its FQDN on port 80 over the internet, you can use LetsEncrypt and get free full CA certs (valid for 90 days, renewal can be automated) that won't give any browser warnings/messages. www.letsencrypt.comSorehead
The Let's Encrypt site is not .com but .orgBawdry
A
3147

You can do that in one command:

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

# non-interactive and 10 years expiration
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -sha256 -days 3650 -nodes -subj "/C=XX/ST=StateName/L=CityName/O=CompanyName/OU=CompanySectionName/CN=CommonNameOrHostname"

You can also add -nodes (short for "no DES") if you don't want to protect your private key with a passphrase. Otherwise it will prompt you for "at least a 4 character" password.

The days parameter (365) you can replace with any number to affect the expiration date. It will then prompt you for things like "Country Name", but you can just hit Enter and accept the defaults.

Add -subj '/CN=localhost' to suppress questions about the contents of the certificate (replace localhost with your desired domain).

Self-signed certificates are not validated with any third party unless you import them to the browsers previously. If you need more security, you should use a certificate signed by a certificate authority (CA).

Aglow answered 16/4, 2012 at 15:4 Comment(31)
Does this support a wildcard?Subsequent
Yes, but because is a self-signed certificado, doesn't make any sense usually :)Aglow
@coder101 in the current working directory. Files key.pem and cert.pem.Aglow
For anyone who's interested, here is the documentation, if you want to verify anything yourself.Faggot
How does signing with a 3rd-party provide more security?Acquisition
@Rob - placing a DNS name (like localhost) in the CN is deprecated by both the IETF and CA/B Forums. While its deprecated, its currently not prohibited (that's coming next for the CA/B). All names go in the Subject Alternate Name. If a certificate has a DNS name in the CN, then it must also be present in the SAN. Otherwise, the certificate will fail to validate under browsers and other user agents that follow the CA/B. There's no way to avoid using the SAN.Protest
Could I use this same cert file for multiple websites on different ip addresses?Headwaiter
For anyone else using this in automation, here's all of the common parameters for the subject: -subj "/C=US/ST=Oregon/L=Portland/O=Company Name/OU=Org/CN=www.example.com"Proscription
It is not possible to specify the encryption algorithm for your key if you generate the key pair and certificate in one command. If that's a concern, then the key pair should be generated separately: openssl genrsa -aes128 -out server-key.pemGerundive
@Protest It would be awesome if you included the options to add a Subject Alternate Name (for DNS names).Totaquine
@JonathonReinhart - see the answer below. Its a bit long winded, but there's no easy way to do it with OpenSSL because you can't pass a SAN via the command line. It also provides references to the relevant standards.Protest
This answer unexpectedly includes a passphrase in the key - see Mike Ns answer below for an alternative that does not include a passphrase.Peach
@JamesMills I mean, think about it -- if a shady looking guy with "free candy" written on the side of his van invites you to come inside, you're totally going to think twice and be on guard about it -- but if someone you trust -- like really trust -- is all like, "naw man, he's legit" you're going to be all about that free candy.Dioecious
@Dioecious I think you just totally validated my point entirely :)Acquisition
@JamesMills all I saw was your question, didn't see anything else. -- To elaborate: basically it prevents impersonation attacks (i.e. man in the middle, etc.) -- More Info: en.wikipedia.org/wiki/Man-in-the-middle_attackDioecious
Remember to use -sha256 to generate SHA-256-based certificate.Dona
this will result in: received a weak ephemeral Diffie-Hellman key in Server Key Exchange handshake message. on client side.Aguilera
Good answer, except the commend that a CA-signature adds more security. The best security is to depend on a public key that you exchange in a secure way, like face to face. PKIX, CA-signatures etc. make this scalable beyond small communites, but actually introduce new attack vectors.Somatic
For anyone getting the error: Can't load ./.rnd into RNG running touch ~/.rnd helped for me. github.com/openssl/openssl/issues/7754Davison
So I went to generate a batch of 40 of these, and it took 5s. Where did it get all the entropy? gpg takes a long time to do similar thingEuphorbiaceous
where is the pem file stored in windows?Blocker
described process for win/osx here alfilatov.com/posts/how-to-create-self-signed-certificateDynamometry
@BrittonKerin from the kernel. GPG is a dinosaurAdnopoz
I upvoted this answer long time ago but now I realise this is NOT the way to generate a self-signed certificate. You are generating a certificate signed by an unknown authority. This is a different thing. A self-signed certificate you can bypass in Chrome browser, but signed by unknown authority not.Creaturely
Hi @Creaturely not sure if I follow. What do you mean exactly? Because there is no authority in a self-signed cert.. and it's always broken, but it could be good in some scenarios for testing purposes for example.Aglow
Finally I got it. This is a self-signed cert but you need to add extended key usage "Server Authentication" to make it work in Chrome: serverfault.com/questions/571910/…. Try with and without it to see the difference in Chrome.Creaturely
This results in Apache warnings: AH01906: 127.0.1.1:443:0 server certificate is a CA certificate (BasicConstraints: CA == TRUE !?)Laurence
Meanwhile, in 2022, this answer does not work anymore, just like people warned.Silvasilvain
Just curious, isn't it irrelevant which key is the public one and which one is the private one? Why does the command have separate flags for the private key and the public keyUrea
It would be more clear, if specific extensions were used for generated files.Diatomaceous
Please view the "As of 2023..." post below for an updated approach.Sorbitol
F
752

As of 2023 with OpenSSL ≥ 1.1.1, the following command serves all your needs, including Subject Alternate Name (SAN):

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

If you prefer ECC over RSA, you can specify different crypto parameters:

openssl req -x509 -newkey ec -pkeyopt ec_paramgen_curve:secp384r1 -days 3650 \
  -nodes -keyout example.com.key -out example.com.crt -subj "/CN=example.com" \
  -addext "subjectAltName=DNS:example.com,DNS:*.example.com,IP:10.0.0.1"

On old systems with OpenSSL ≤ 1.1.0, such as Debian ≤ 9 or CentOS ≤ 7, a longer version of this command needs to be used:

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

Each of the above commands creates a certificate that is

  • valid for the domain example.com (SAN),
  • also valid for the wildcard domain *.example.com (SAN),
  • also valid for the IP address 10.0.0.1 (SAN),
  • relatively strong (as of 2023) and
  • valid for 3650 days (~10 years).

The following files are generated:

  • Private key: example.com.key
  • Certificate: example.com.crt

All information is provided at the command line. There is no interactive input that annoys you. There are no config files you have to mess around with. All necessary steps are executed by a single OpenSSL invocation: from private key generation up to the self-signed certificate.


Remark #1: Crypto parameters

Since the certificate is self-signed and needs to be accepted by users manually, it doesn't make sense to use a short expiration or weak cryptography.

In the future, you might want to use more than 4096 bits for the RSA key and a hash algorithm stronger than sha256, but as of 2023 these are sane values. They are sufficiently strong while being supported by all modern browsers.

Remark #2: Parameter "-nodes"

Theoretically you could leave out the -nodes parameter (which means "no DES encryption"), in which case example.key would be encrypted with a password. However, this is almost never useful for a server installation, because you would either have to store the password on the server as well, or you'd have to enter it manually on each reboot.

Remark #3: See also

Found answered 28/12, 2016 at 17:30 Comment(29)
I tried to use the oneliner #2 (modern) on windows in mingw64, and I faced a bug with -subj parameter. ` $ openssl req -x509 -newkey rsa:4096 -sha256 -days 3650 -nodes -keyout localhost.key -out localhost.crt -subj '/CN=localhost' -addext subjectAltName=DNS:localhost,IP:127.0.0.1 Generating a RSA private key [...] writing new private key to 'localhost.key' ----- name is expected to be in the format /type0=value0/type1=value1/type2=... where characters may be escaped by \. This name is not in that format: 'C:/Program Files/Git/CN=localhost' problems making Certificate Request `Saraband
I couldn't figure out what exactly was to blame in the arg /CN=localhost expanding to C:/Program Files/Git/CN=localhost , so I just ran the whole command in plain cmd.exe and it worked just fine. Just in case someone is struggling with this one.Saraband
If -newkey rsa:4096 is omitted, OpenSSL defaults to 2048-bit RSA which sounds enough. Also I think -sha256 is the default for 1.1.1 or above.Balboa
@FranklinYu Are you sure that rsa:2048 will be enough in 10 years from now? Because that's the validity period. As explained, it doesn't make sense to use short expiration or weak crypto. Most 2048-bit RSA keys have a validity period of 1-3 years at most. Regarding OpenSSL 1.1.1, I'm still leaving sha256 in there, so it's more explicit and obvious to change if you want a stronger hash.Found
If you're using git bash on windows, like @YuriyPozniak, you will get the error he listed where /CN=localhost is being expanded to C:/Progra Files/Git/CN=localhost. If you add an extra /, then the expansion won't occur. //CN=localhostFlagstaff
@DaveFerguson Isn't the certificate then created for //CN=localhost instead of /CN=localhost? Will proper escaping help here? For example, does replacing /CN=localhost with "/CN=localhost" solve the problem in a clean way?Found
@Found I tested using quotes and doesn't work as it still does the path expansion. I also checked the certificate and the subject is correct. Alternatively, you can set an environment variable to disable path expansion (MSYS_NO_PATHCONV=1 openssl <args>). See stackoverflow.com/a/34386471. If you are using the git bash MINGW64 terminal window and you're trying to export the cert to a pfx file, you may also run into the password prompt not showing. Put winpty in front of the command. See omgdebugging.com/2019/03/18/…Flagstaff
@DaveFerguson My answer already contains a hint to MSYS_NO_PATHCONV. Is this information not prominent enough? How should it be improved?Found
@Found Apologies, no disrespect intended. It looks great, actually. I had searched for specific text strings and saw the comment by Yuriy based on the actual error text I was seeing in my terminal. Since the error wasn't listed in the answer directly, I totally missed that section of the answer and focused on the comments instead. Perhaps if you included the error message in the answer text it would help with searches? Also, the double forward slash shortcut is useful too.Flagstaff
@DaveFerguson I fully agree that the MinGW section is incomplete as it should include the error message that it solves. Would you mind providing the exact error message that you get without MSYS_NO_PATHCONV=1? Thanks!Found
@YuriyPozniak @Found @DaveFerguson et al: i encountered pretty much the same problem with the second one-liner. Solution: BOTH the -subj and -addext values need to be wrapped in " " like so: ... -subj "/CN=example.com" -addext "subjectAltName=..."Zillion
@Found Looks great! However, i'm not sure the reference to MSYS_NO_PATHCONV remains necessary with that correction. Maybe replace with notes that arguments with Windows-illegal path/file characters should be enclosed in " "?Zillion
@Zillion Feel free to make a test. I'd also be happy to remove the entire Remark #3: MinGW if the above command (i.e. the second "one-liner") works as-is on Windows.Found
I've tried above solution and it's works for me on every web browser except Firefox. After deep digging I found a solution for Windows users here: serverfault.com/questions/1002185/…Loathing
Incredible ! It works perfectly if you dont forget to replace "10.0.0.1" by your own local IP. AND restart the PC. It's boring but it's required (thanks windows or chrome) !Frith
req part looks wrong. it looks like its pointing back to itselfSeurat
@JimmyMGLim Do you care to elaborate? Which of the two commands did you try? Did they fail? Did they produce a wrong result? What do you think should be changed in the answer?Found
[req] represents the config part of the cert request. see switch.ch/pki/manage/request/csr-openssl .. as part of [req] it points to [dn] for example which that section defines the distinguished name. If you really want to define that.. you can do [req] distinguished_name = dn [dn] C = GB O = foo limited CN = foobar.example.comSeurat
As of Aug-31/2020 I can vouch this works!!! Thanks a lot! I really would like to see a reference that explains in simple terms why this is evolving at such pace. Part of me wonders if it's just because the idea of creating self signed certs is counter productive to the big tech cos. What is going to be needed in 10 or 20 years time? It's madness, and it's a testament of that the amount of activity this kind of questions on openssl generates.Smyth
should i replace example.com with my domain?Tentative
@SandrinJoy Yes. And www.example.net with your second domain, if you need.Found
If you're having trouble remove the backslashes.Grimaud
This is the only console command for SAN which works. Can give an example if we want to add SAN and Basic Contraints in console command, how do we do that? Do we add another line of -addtext?Sena
@Sena If you want to add more SAN entries, add them directly to the single subjectAltName entry, separated by comma. If you want to add more extension settings besides subjectAltName, use additional -addtext parameters. As a side note, you might want to have a look at "man openssl-req" and scroll to the end of their EXAMPLES section.Found
Does this create a self-signed certificate, or a certificate signed by an unknown authority? Is there a difference between the two?Cockcroft
@JohnGo-Soco This does create a self-signed certificate. The authority is yourself. So it is "unknown" to the browser (until you tell it to accept the certificate), but it is not "unkown" to you or your organization.Found
I entered the same command as the first one when I started up my web server it says "your connection is not private. Attackers may be trying to steal your information"Yestreen
@DavidG Yes, this is how self-signed certificates work. It is a TOFU (trust on first use) model, that is, users need to accept them on their first use. If this is an issue for you, don't use self-signed certificates, and setup Let's Encrypt on your webserver instead: letsencrypt.orgFound
@mirageglobe: the distinguished_name = req pointing back to [req] is actually a very clever trick to avoid a dummy, empty [dn] section. As he's using -subj on the command line, the section content would be ignored anyway.Descendible
P
664

Am I missing something? Is this the correct way to build a self-signed certificate?

It's easy to create a self-signed certificate. You just use the openssl req command. It can be tricky to create one that can be consumed by the largest selection of clients, like browsers and command line tools.

It's difficult because the browsers have their own set of requirements, and they are more restrictive than the IETF. The requirements used by browsers are documented at the CA/Browser Forums (see references below). The restrictions arise in two key areas: (1) trust anchors, and (2) DNS names.

Modern browsers (like the warez we're using in 2014/2015) want a certificate that chains back to a trust anchor, and they want DNS names to be presented in particular ways in the certificate. And browsers are actively moving against self-signed server certificates.

Some browsers don't exactly make it easy to import a self-signed server certificate. In fact, you can't with some browsers, like Android's browser. So the complete solution is to become your own authority.

In the absence of becoming your own authority, you have to get the DNS names right to give the certificate the greatest chance of success. But I would encourage you to become your own authority. It's easy to become your own authority, and it will sidestep all the trust issues (who better to trust than yourself?).


This is probably not the site you are looking for!
The site's security certificate is not trusted!

This is because browsers use a predefined list of trust anchors to validate server certificates. A self-signed certificate does not chain back to a trusted anchor.

The best way to avoid this is:

  1. Create your own authority (i.e., become a CA)
  2. Create a certificate signing request (CSR) for the server
  3. Sign the server's CSR with your CA key
  4. Install the server certificate on the server
  5. Install the CA certificate on the client

Step 1 - Create your own authority just means to create a self-signed certificate with CA: true and proper key usage. That means the Subject and Issuer are the same entity, CA is set to true in Basic Constraints (it should also be marked as critical), key usage is keyCertSign and crlSign (if you are using CRLs), and the Subject Key Identifier (SKI) is the same as the Authority Key Identifier (AKI).

To become your own certificate authority, see *How do you sign a certificate signing request with your certification authority? on Stack Overflow. Then, import your CA into the Trust Store used by the browser.

Steps 2 - 4 are roughly what you do now for a public facing server when you enlist the services of a CA like Startcom or CAcert. Steps 1 and 5 allows you to avoid the third-party authority, and act as your own authority (who better to trust than yourself?).

The next best way to avoid the browser warning is to trust the server's certificate. But some browsers, like Android's default browser, do not let you do it. So it will never work on the platform.

The issue of browsers (and other similar user agents) not trusting self-signed certificates is going to be a big problem in the Internet of Things (IoT). For example, what is going to happen when you connect to your thermostat or refrigerator to program it? The answer is, nothing good as far as the user experience is concerned.

The W3C's WebAppSec Working Group is starting to look at the issue. See, for example, Proposal: Marking HTTP As Non-Secure.


How to create a self-signed certificate with OpenSSL

The commands below and the configuration file create a self-signed certificate (it also shows you how to create a signing request). They differ from other answers in one respect: the DNS names used for the self signed certificate are in the Subject Alternate Name (SAN), and not the Common Name (CN).

The DNS names are placed in the SAN through the configuration file with the line subjectAltName = @alternate_names (there's no way to do it through the command line). Then there's an alternate_names section in the configuration file (you should tune this to suit your taste):

[ 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

It's important to put DNS name in the SAN and not the CN, because both the IETF and the CA/Browser Forums specify the practice. They also specify that DNS names in the CN are deprecated (but not prohibited). If you put a DNS name in the CN, then it must be included in the SAN under the CA/B policies. So you can't avoid using the Subject Alternate Name.

If you don't do put DNS names in the SAN, then the certificate will fail to validate under a browser and other user agents which follow the CA/Browser Forum guidelines.

Related: browsers follow the CA/Browser Forum policies; and not the IETF policies. That's one of the reasons a certificate created with OpenSSL (which generally follows the IETF) sometimes does not validate under a browser (browsers follow the CA/B). They are different standards, they have different issuing policies and different validation requirements.


Create a self signed certificate (notice the addition of -x509 option):

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

Create a signing request (notice the lack of -x509 option):

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

Print a self-signed certificate:

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

Print a signing request:

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

Configuration file (passed via -config option)

[ 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

You may need to do the following for Chrome. Otherwise Chrome may complain a Common Name is invalid (ERR_CERT_COMMON_NAME_INVALID). I'm not sure what the relationship is between an IP address in the SAN and a CN in this instance.

# IPv4 localhost
# IP.1       = 127.0.0.1

# IPv6 localhost
# IP.2     = ::1

There are other rules concerning the handling of DNS names in X.509/PKIX certificates. Refer to these documents for the rules:

RFC 6797 and RFC 7469 are listed, because they are more restrictive than the other RFCs and CA/B documents. RFCs 6797 and 7469 do not allow an IP address, either.

Protest answered 13/1, 2015 at 21:12 Comment(9)
Is it possible to use wildcards in the alternate_names section? Particularly sub-sub domains. I have a question referencing this answer here: serverfault.com/questions/711596/…Fronniah
However it may seem confusing for beginners the Create a self signed certificate vs. Create a signing requestCosmonautics
I've just replied to his specific question. I think doesn't make sense to add this long security description when the answer was so simpleAglow
@diegows - your answer is not complete or correct. The reason it is not correct is discussed in the long post you don't want to read :)Protest
Thanks! I found your post very helpful. FYI I was recently playing with vault and found it insisted on IP.x 127.0.0.1 rather than DNS.x 127... I didn't check if this is in the standard or not.Circumsolar
Thank you @jww. You said, "1. Create your own authority (i.e, become a CA)", then said, "5. Install the CA certificate on the client". If the root key became compromised, a malicious person could sign a cert for any domain with that key, and if they trick you into going to their website, they can now do a man-in-the-middle attack. Is there a way to create the root CA such that it can only sign intermediary CAs and not certificates? Then you can protect your intermediary CA with a name constraint.Malt
In the step "Create a self signed certificate", I get the error: unable to find 'distinguished_name' in config problems making Certificate Request 140429517596352:error:0E06D06C:configuration file routines:NCONF_get_string:no value:conf_lib.c:324:group=req name=distinguished_name. Batteries not included?Jochbed
Here's a starter file similar to this answer github.com/bencmbrook/certificate-authorityJataka
@Protest which long post? What's not complete and correct in this answer?Underpass
F
455

Here are the options described in @diegows's answer, described in more detail, from the documentation:

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

PKCS#10 certificate request and certificate generating utility.

-x509

this option outputs a self signed certificate instead of a certificate request. This is typically used to generate a test certificate or a self signed root CA.

-newkey arg

this option creates a new certificate request and a new private key. The argument takes one of several forms. rsa:nbits, where nbits is the number of bits, generates an RSA key nbits in size.

-keyout filename

this gives the filename to write the newly created private key to.

-out filename

This specifies the output filename to write to or standard output by default.

-days n

when the -x509 option is being used this specifies the number of days to certify the certificate for. The default is 30 days.

-nodes

if this option is specified then if a private key is created it will not be encrypted.

The documentation is actually more detailed than the above; I just summarized it here.

Faggot answered 13/4, 2014 at 1:48 Comment(2)
The XXX in the original command should be replaced with the 'number of days to certify the certificate for'. The default is 30 days. For example, -days XXX becomes -days 365 if you want your cert to be valid for 365 days. See the docs for more.Requital
Thanks for adding the documentation. This IBM link on creating a self-signed certificate using command which seems identical to this answerPaquito
E
184

I can't comment, so I will put this as a separate answer. I found a few issues with the accepted one-liner answer:

  • The one-liner includes a passphrase in the key.
  • The one-liner uses SHA-1 which in many browsers throws warnings in console.

Here is a simplified version that removes the passphrase, ups the security to suppress warnings and includes a suggestion in comments to pass in -subj to remove the full question list:

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

Replace 'localhost' with whatever domain you require. You will need to run the first two commands one by one as OpenSSL will prompt for a passphrase.

To combine the two into a .pem file:

cat server.crt server.key > cert.pem
Etem answered 13/8, 2015 at 9:44 Comment(11)
I needed a dev certificate for github.com/molnarg/node-http2 and this answer is just the best.Brune
To combine the certificate and the key in a single file: cat server.crt server.key >foo-cert.pem. Works with the example in openssl-1.0.2d/demos/ssl/Homeward
The cert I generated this way is still using SHA1.Lianaliane
Tks, works great to create a self signed certificate on FreeBSD 10 OpenLDAP 2.4 with TLSMinify
What about the key.pem file?Isidoro
For windows users, cat command is here => type server.crt server.key > cert.pemClaudetteclaudia
You don't need to go through all those steps. You can put everything together in a single, simple command. See: https://mcmap.net/q/35871/-how-to-generate-a-self-signed-ssl-certificate-using-openssl-closedFound
For windows file join I use copy /bCupping
when I use these firefox expectedly complains the cert is self signed but lets me advance to the requested webpage. Chrome on the other hand does not. Any ideas what I need to change?Narda
Just used this to generate a self-signed to test Firefox Mobile connected to a Mojolicious server. I had to do this cd ~/; openssl rand -writerand .rnd to suppress the rnd error message. Then put the cert into /public, downloaded running as http (since it won't connect as https) and installed. Gives the warning dialogue but connects. I actually needed this because Firefox geolocation refuses under http, Chrome is fine. So, thanks!Sadonia
@Isidoro The server.key file is the same as that afaik.Prajna
M
90

Modern browsers now throw a security error for otherwise well-formed self-signed certificates if they are missing a SAN (Subject Alternate Name). OpenSSL does not provide a command-line way to specify this, so many developers' tutorials and bookmarks are suddenly outdated.

The quickest way to get running again is a short, stand-alone conf file:

  1. Create an OpenSSL config file (example: 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. Create the certificate referencing this config file

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

Example config from https://support.citrix.com/article/CTX135602

Moneylender answered 9/5, 2017 at 2:37 Comment(10)
It worked for me after removing the last parameter -extensions 'v3_req' which was causing an error. Using OpenSSL for windows. Finally, I manage to fix this issue! Thanks.Geometry
@Kyopaxa you're right - that parameter is redundant with line 3 of the cnf file; updated.Moneylender
Yes, this is very relevant now, five years later. Most of the other answers, as stated, suddenly stopped working. The minimal config given in this answer is very useful, since it would have taken quite some time to figure it out by trial and error.Panhellenic
Solid way. Thanks. I'd suggest adding -sha256.Nemathelminth
You can now specify the SAN on the command line with -extension 'subjectAltName = DNS:dom.ain, DNS:oth.er' see github.com/openssl/openssl/pull/4986Piperpiperaceous
@AlexandreDuBreuil this is good to know. Is that in an available release or still in development?Moneylender
@Moneylender it's merged but not released yet, check the issue for infoPiperpiperaceous
Getting 'There are issues with the site's certificate chain (net::ERR_CERT_AUTHORITY_INVALID).' in ChromeVibrator
It looks like the -extension option was released about a month ago in OpenSSL 1.1.1. Ubuntu 18.10 will ship 1.1.0h so many users will still have to wait a long time.Obstinacy
Looks like this option is called -addext now.Banna
U
76

I would recommend to add the -sha256 parameter, to use the SHA-2 hash algorithm, because major browsers are considering to show "SHA-1 certificates" as not secure.

The same command line from the accepted answer - @diegows with added -sha256

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

More information in Google Security blog.

Update May 2018. As many noted in the comments that using SHA-2 does not add any security to a self-signed certificate. But I still recommend using it as a good habit of not using outdated / insecure cryptographic hash functions. Full explanation is available in Why is it fine for certificates above the end-entity certificate to be SHA-1 based?.

Unit answered 20/10, 2014 at 9:52 Comment(11)
If it's a self signed key, it's going to generate browser errors anyway, so this doesn't really matterUnthinkable
@Mark, it matters, because SHA-2 is more secureUnit
Opening the certificate in windows after renaming the cert.pem to cert.cer says the fingerprint algorithm still is Sha1, but the signature hash algorithm is sha256.Look
There is more improve on @diegows' answer, such as using "-nodes" and "-subj". But since collecting all useful parameters is more the purpose of an anwer than a comment, I summarized these in a separate answer: stackoverflow.com/a/41366949.Found
@Maris : not really more secure here, since it's self-signed !Amandine
@Amandine - sha256 makes self-signed certificates more secure. And actually self-signed certificates can be more secure (in contrast to CA managed ones, if you do not trust third parties). Rad more here: serverfault.com/questions/363707/…Unit
No @Maris. You can consider trusting your self-signed certificate through out-of-band method more secure than accepting one signed by a public CA, but in no case you will use it's signature to trust it, so in no case will the fact that this signature uses sha256 or sha1 have any weight.Amandine
"World-class encryption * zero authentication = zero security" gerv.net/security/self-signed-certsAcrodrome
Note that the signature algorithm used on a self-signed certificate is irrelevant in deciding whether it's trustworthy or not. Root CA certs are self-signed. and as of May 2018, there are still many active root CA certificates that are SHA-1 signed. Because it doesn't matter if a certificate trusts itself, nor how that certificate verifies that trust. You either trust the root/self-signed cert for who it says it is, or you don't. See security.stackexchange.com/questions/91913/…Shelly
This advice about self signed certificates not providing security completely bizarre because all root CA certs are self-signed. You trust those better than ones you signed yourself? Interesting. The reason to use SHA2 instead of SHA1 for self signed certs is that SHA1 is now considered a weak hashing algorithm. Encryption of anonymous messages is still secure, despite lacking authentication. Really depends on your application.Unscrew
NET::ERR_CERT_INVALIDBituminize
E
29

I can`t comment so I add a separate answer. I tried to create a self-signed certificate for NGINX and it was easy, but when I wanted to add it to Chrome white list I had a problem. And my solution was to create a Root certificate and signed a child certificate by it.

So step by step. Create file config_ssl_ca.cnf Notice, config file has an option basicConstraints=CA:true which means that this certificate is supposed to be root.

This is a good practice, because you create it once and can reuse.

[ 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=Market(localhost)
organizationalUnitName=roote department
commonName=market.localhost
[email protected]

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

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

Next config file for your child certificate will be call config_ssl.cnf.

[ 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=market.localhost
[email protected]

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

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

The first step - create Root key and certificate

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

The second step creates child key and file CSR - Certificate Signing Request. Because the idea is to sign the child certificate by root and get a correct certificate

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

Open Linux terminal and do this command

echo 00 > ca.srl
touch index.txt

The ca.srl text file containing the next serial number to use in hex. Mandatory. This file must be present and contain a valid serial number.

Last Step, create one more config file and call it 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 = market.localhost
organizationalUnitName = optional
commonName = supplied

You may ask, why so difficult, why we must create one more config to sign child certificate by root. The answer is simple because child certificate must have a SAN block - Subject Alternative Names. If we sign the child certificate by "openssl x509" utils, the Root certificate will delete the SAN field in child certificate. So we use "openssl ca" instead of "openssl x509" to avoid the deleting of the SAN field. We create a new config file and tell it to copy all extended fields copy_extensions = copy.

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

The program asks you 2 questions:

  1. Sign the certificate? Say "Y"
  2. 1 out of 1 certificate requests certified, commit? Say "Y"

In terminal you can see a sentence with the word "Database", it means file index.txt which you create by the command "touch". It will contain all information by all certificates you create by "openssl ca" util. To check the certificate valid use:

openssl rsa -in market.key -check

If you want to see what inside in CRT:

openssl x509 -in market.crt -text -noout

If you want to see what inside in CSR:

openssl req -in market.csr -noout -text 
Elliottellipse answered 21/1, 2020 at 7:23 Comment(5)
Although, this process looks complicated, this is exactly what we need for .dev domain, as this domain does not support self-signed certificates and Chrome and Firefox are forcing HSTS. What I did is followed this steps, which is creating CA, creating a certificate and signing it with my CA and at the end trusting my CA in the browser. Thanks.Alien
Your common name is wrong. Not firstname/lastname. its your domain cn i.e. www.yoursite.com . see ssl.com/faqs/common-nameSeurat
no problem. there are some documents which also say name (yourname) which is a bit misleading. but common name should be the actual domain. in this sense it would be (your"domain"name) they are trying to say. when running thru with interactive method of creating the certs, it does say cn=domain example. so commonname should be domainSeurat
UPD answer to resolve #39271492Elliottellipse
I gave this a try and it works. I had to do some extra steps, copy ca.crt to ca.pem, cp ca.crt ca.pem and install the ca.pem as a trusted certificate authority on centos. It works perfectly fine with curl operations now! To install the certificate authority on centos, copy the ca.pem to /etc/pki/ca-trust/source/anchors/ and execute the command update-ca-trust extract; unix.stackexchange.com/a/438698/418196Pisolite
A
24

This is the script I use on local boxes to set the SAN (subjectAltName) in self-signed certificates.

This script takes the domain name (example.com) and generates the SAN for *.example.com and example.com in the same certificate. The sections below are commented. Name the script (e.g. generate-ssl.sh) and give it executable permissions. The files will be written to the same directory as the script.

Chrome 58 an onward requires SAN to be set in self-signed certificates.

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

This script also writes an information file, so you can inspect the new certificate and verify the SAN is set properly.

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

If you are using Apache, then you can reference the above certificate in your configuration file like so:

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

Remember to restart your Apache (or Nginx, or IIS) server for the new certificate to take effect.

Anathematize answered 13/5, 2017 at 20:21 Comment(3)
Works on macOS High Siera and Chrome 58Stpeter
I'm still not sure how the CN affects the overall setup? I'm attempting to run this as localhost or 127.0.0.1:port# what would be the corresponding CN for something like this.Intuit
@Intuit I would set BASE_DOMAIN=“localhost”Anathematize
M
11

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

This also works in Chrome 57, as it provides the SAN, without having another configuration file. It was taken from an answer here.

This creates a single .pem file that contains both the private key and cert. You can move them to separate .pem files if needed.

Middlebrow answered 20/9, 2017 at 16:27 Comment(2)
For Linux users you'll need to change that path for the config. e.g. on current Ubuntu /etc/ssl/openssl.conf worksPamela
For a one-liner that doesn't require you to specify the openssl.cnf location, see: https://mcmap.net/q/35871/-how-to-generate-a-self-signed-ssl-certificate-using-openssl-closedFound
P
11

Generate a key without password and certificate for 10 years, the short way:

openssl req  -x509 -nodes -new  -keyout server.key -out server.crt -days 3650 -subj "/C=/ST=/L=/O=/OU=web/CN=www.server.com"

for the flag -subj | -subject empty values are permitted -subj "/C=/ST=/L=/O=/OU=web/CN=www.server.com", but you can sets more details as you like:

  • C - Country Name (2 letter code)
  • ST - State
  • L - Locality Name (eg, city)
  • O - Organization Name
  • OU - Organizational Unit Name
  • CN - Common Name - required!
Piecedyed answered 27/12, 2021 at 13:35 Comment(0)
S
9

openssl allows to generate self-signed certificate by a single command (-newkey instructs to generate a private key and -x509 instructs to issue a self-signed certificate instead of a signing request)::

openssl req -x509 -newkey rsa:4096 \
-keyout my.key -passout pass:123456 -out my.crt \
-days 365 \
-subj /CN=localhost/O=home/C=US/[email protected] \
-addext "subjectAltName = DNS:localhost,DNS:web.internal,email:[email protected]" \
-addext keyUsage=digitalSignature -addext extendedKeyUsage=serverAuth

You can generate a private key and construct a self-signing certificate in separate steps::

openssl genrsa -out my.key -passout pass:123456 2048

openssl req -x509 \
-key my.key -passin pass:123456 -out my.csr \
-days 3650 \
-subj /CN=localhost/O=home/C=US/[email protected] \
-addext "subjectAltName = DNS:localhost,DNS:web.internal,email:[email protected]" \
-addext keyUsage=digitalSignature -addext extendedKeyUsage=serverAuth

Review the resulting certificate::

openssl x509 -text -noout -in my.crt

Java keytool creates PKCS#12 store::

keytool -genkeypair -keystore my.p12 -alias master \
-storetype pkcs12 -keyalg RSA -keysize 2048 -validity 3650 \
-storepass 123456 \
-dname "CN=localhost,O=home,C=US" \
-ext 'san=dns:localhost,dns:web.internal,email:[email protected]'

To export the self-signed certificate::

keytool -exportcert -keystore my.p12 -file my.crt \
-alias master -rfc -storepass 123456

Review the resulting certificate::

keytool -printcert -file my.crt

certtool from GnuTLS doesn't allow passing different attributes from CLI. I don't like to mess with config files ((

Subset answered 7/11, 2020 at 22:36 Comment(1)
I cannot stress that enough!!!!!!! extendedKeyUsage = serverAuth, clientAuth is what got me the button "Proceed to localhost (unsafe)"Isar
G
8

One-liner version 2017:

CentOS:

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

Ubuntu:

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

Edit: added prepending Slash to 'subj' option for Ubuntu.

Goodson answered 28/11, 2017 at 10:11 Comment(0)
R
7

Generate keys

I am using /etc/mysql for cert storage because /etc/apparmor.d/usr.sbin.mysqld contains /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;

Add configuration

/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

On my setup, Ubuntu server logged to: /var/log/mysql/error.log

Follow up notes:

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

    MySQL might be denied read access to your certificate file if it is not in apparmors configuration. As mentioned in the previous steps^, save all our certificates as .pem files in the /etc/mysql/ directory which is approved by default by apparmor (or modify your apparmor/SELinux to allow access to wherever you stored them.)

  • SSL error: Unable to get private key

    Your MySQL server version may not support the default rsa:2048 format

    Convert generated rsa:2048 to plain rsa with:

    openssl rsa -in server-key.pem -out server-key.pem
    openssl rsa -in client-key.pem -out client-key.pem
    
  • Check if local server supports 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  |
    +---------------+----------------------------+
    
  • Verifying a connection to the database is SSL encrypted:

    Verifying connection

    When logged in to the MySQL instance, you can issue the query:

    show status like 'Ssl_cipher';
    

    If your connection is not encrypted, the result will be blank:

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

    Otherwise, it would show a non-zero length string for the cypher in use:

    mysql> show status like 'Ssl_cipher';
    +---------------+--------------------+
    | Variable_name | Value              |
    +---------------+--------------------+
    | Ssl_cipher    | DHE-RSA-AES256-SHA |
    +---------------+--------------------+
    1 row in set (0.00 sec)
    
  • Require ssl for specific user's connection ('require ssl'):

    • SSL

    Tells the server to permit only SSL-encrypted connections for the account.

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

    To connect, the client must specify the --ssl-ca option to authenticate the server certificate, and may additionally specify the --ssl-key and --ssl-cert options. If neither --ssl-ca option nor --ssl-capath option is specified, the client does not authenticate the server certificate.


Alternate link: Lengthy tutorial in Secure PHP Connections to MySQL with SSL.

Remmer answered 16/4, 2012 at 14:14 Comment(2)
-1; this is largely tangential to the question asked, and also does a bad job of making clear where its quotes are from.Hoopoe
This shows provisioning CA, Server/Client certs signed by the CA, configure them for reading by mysqld on a host with apparmor. It exemplifies a rather useless case of hosting the ca, server, and client on the same machine, and dangerously exposing that ca's authority to the mysqld process. This setup doesn't really make sense other than to test ssl configuration in a test environment. For operating an internal CA, I would recommend the gnuttls toolchain over openssl help.ubuntu.com/community/GnuTLS and having a good understanding of tls before working around the mysqld+apparmor caseRemmer
B
7

One liner FTW. I like to keep it simple. Why not use one command that contains ALL the arguments needed? This is how I like it - this creates an x509 certificate and its PEM key:

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

That single command contains all the answers you would normally provide for the certificate details. This way you can set the parameters and run the command, get your output - then go for coffee.

>> More here <<

Baggott answered 11/9, 2017 at 15:14 Comment(2)
All the arguments except for SANs... @vog's answer covers that as well (and predate this) (This has a more complete "Subject" field filled in though...) (Not a big fan of the one year expiry either)Battologize
vog's answer. Linked, because usernames are neither unique nor immutable. "vog" could change to "scoogie" at any point in time.Sweetsop
H
6

You have the general procedure correct. The syntax for the command is below.

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

However, the warnings are displayed, because the browser was not able to verify the identify by validating the certificate with a known Certificate Authority (CA).

As this is a self-signed certificate there is no CA and you can safely ignore the warning and proceed. Should you want to get a real certificate that will be recognizable by anyone on the public Internet then the procedure is below.

  1. Generate a private key
  2. Use that private key to create a CSR file
  3. Submit CSR to CA (Verisign or others, etc.)
  4. Install received cert from CA on web server
  5. Add other certs to authentication chain depending on the type cert

I have more details about this in a post at Securing the Connection: Creating a Security Certificate with OpenSSL

Helterskelter answered 2/4, 2015 at 6:15 Comment(0)
S
6

Quick command line: Minimal Version

"I want a self signed certificate, in pfx form, for www.example.com with minimal fuss":

openssl req -x509 -sha256 -days 365 -nodes -out cert.crt -keyout cert.key -subj "/CN=www.example.com"
openssl pkcs12 -export -out cert.pfx -inkey cert.key -in cert.crt
Schoenfeld answered 8/9, 2022 at 13:6 Comment(1)
-sub should be -subjChaucerian
J
5

As has been discussed in detail, self-signed certificates are not trusted for the Internet. You can add your self-signed certificate to many but not all browsers. Alternatively you can become your own certificate authority.

The primary reason one does not want to get a signed certificate from a certificate authority is cost -- Symantec charges between $995 - $1,999 per year for certificates -- just for a certificate intended for internal network, Symantec charges $399 per year. That cost is easy to justify if you are processing credit card payments or work for the profit center of a highly profitable company. It is more than many can afford for a personal project one is creating on the internet, or for a non-profit running on a minimal budget, or if one works in a cost center of an organization -- cost centers always try to do more with less.

An alternative is to use certbot (see about certbot). Certbot is an easy-to-use automatic client that fetches and deploys SSL/TLS certificates for your web server.

If you setup certbot, you can enable it to create and maintain a certificate for you issued by the Let’s Encrypt certificate authority.

I did this over the weekend for my organization. I installed the required packages for certbot on my server (Ubuntu 16.04) and then ran the command necessary to setup and enable certbot. One likely needs a DNS plugin for certbot - we are presently using DigitalOcean though may be migrating to another service soon.

Note that some of the instructions were not quite right and took a little poking and time with Google to figure out. This took a fair amount of my time the first time but now I think I could do it in minutes.

For DigitalOcean, one area I struggled was when I was prompted to input the path to your DigitalOcean credentials INI file. What the script is referring to is the Applications & API page and the Tokens/Key tab on that page. You need to have or generate a personal access token (read and write) for DigitalOcean's API -- this is a 65 character hexadecimal string. This string then needs to be put into a file on the webserver from which you are running certbot. That file can have a comment as its first line (comments start with #). The seccond line is:

dns_digitalocean_token = 0000111122223333444455556666777788889999aaaabbbbccccddddeeeeffff

Once I figured out how to set up a read+write token for DigitalOcean's API, it was pretty easy to use certbot to setup a wildcard certificate. Note that one does not have to setup a wildcard certificate, one may instead specify each domain and sub-domain that one wants the certificate to appply to. It was the wildcard certificate that required the credentials INI file that contained the personal access token from DigitalOcean.

Note that public key certificates (also known as identity certificates or SSL certificates) expire and require renewal. Thus you will need to renew your certificate on a periodic (reoccurring) basis. The certbot documentation covers renewing certificates.

My plan is to write a script to use the openssl command to get my certificate's expiration date and to trigger renewal when it is 30 days or less until it expires. I will then add this script to cron and run it once per day.

Here is the command to read your certificate's expiration date:

root@prod-host:~# /usr/bin/openssl x509 -enddate -noout -in path-to-certificate-pem-file
notAfter=May 25 19:24:12 2019 GMT
Judie answered 25/2, 2019 at 21:52 Comment(0)
I
4

After much of going around, playing with various solutions, still I faced the problem that issuing a self-signed certificate for localhost, gave me error

ERR_CERT_INVALID

When expanding the details, chrome said:

You cannot visit localhost right now because the website sent scrambled credentials...

And the only ugly way to get through is to type (directly in this screen, without seeing any cursor for the text) :

(type in the keyboard) thisisunsafe

Which let me proceed.

Until I found extendedKeyUsage = serverAuth, clientAuth

TL;DR

  1. openssl genrsa -out localhost.key 2048

  2. openssl req -key localhost.key -new -out localhost.csr

  3. (click enter on everything and just fill in the common name (CN) with localhost or your other FQDN.

  4. put the following in a file named v3.ext (edit whatever you need):

subjectKeyIdentifier   = hash
authorityKeyIdentifier = keyid:always,issuer:always
basicConstraints       = CA:TRUE
keyUsage               = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment, keyAgreement, keyCertSign
extendedKeyUsage       = serverAuth, clientAuth
subjectAltName         = DNS:localhost, DNS:localhost.localdomain
issuerAltName          = issuer:copy
  1. openssl x509 -req -in localhost.csr -signkey localhost.key -out localhost.pem -days 3650 -sha256 -extfile v3.ext

And voilà! You can visit the website, expand "Advanced" and click "Proceed to localhost (unsafe)".

Isar answered 28/2, 2022 at 11:15 Comment(3)
Maybe some smart fellow would be able to make all of this a nice one-liner...Isar
what is the v3.ext file in your last command?Baseburner
Edited the answer. look at point 4.Isar
D
2

this worked for me

openssl req -x509 -nodes -subj '/CN=localhost'  -newkey rsa:4096 -keyout ./sslcert/key.pem -out ./sslcert/cert.pem -days 365

server.js

var fs = require('fs');
var path = require('path');
var http = require('http');
var https = require('https');
var compression = require('compression');
var express = require('express');
var app = express();

app.use(compression());
app.use(express.static(__dirname + '/www'));    

app.get('/*', function(req,res) {
  res.sendFile(path.join(__dirname+'/www/index.html'));
});

// your express configuration here

var httpServer = http.createServer(app);
var credentials = {
    key: fs.readFileSync('./sslcert/key.pem', 'utf8'),
    cert: fs.readFileSync('./sslcert/cert.pem', 'utf8')
};
var httpsServer = https.createServer(credentials, app);

httpServer.listen(8080);
httpsServer.listen(8443);

console.log(`RUNNING ON  http://127.0.0.1:8080`);
console.log(`RUNNING ON  http://127.0.0.1:8443`);
Deluge answered 5/12, 2020 at 6:16 Comment(0)
F
-1

This very simple Python app that creates a self-signed certificate. Code:

from OpenSSL import crypto, SSL
from secrets import randbelow
print("Please know, if you make a mistake, you must restart the program.")
def cert_gen(
    emailAddress=input("Enter Email Address: "),
    commonName=input("Enter Common Name: "),
    countryName=input("Enter Country Name (2 characters): "),
    localityName=input("Enter Locality Name: "),
    stateOrProvinceName=input("Enter State of Province Name: "),
    organizationName=input("Enter Organization Name: "),
    organizationUnitName=input("Enter Organization Unit Name: "),
    serialNumber=randbelow(1000000),
    validityStartInSeconds=0,
    validityEndInSeconds=10*365*24*60*60,
    KEY_FILE = "private.key",
    CERT_FILE="selfsigned.crt"):
    #can look at generated file using openssl:
    #openssl x509 -inform pem -in selfsigned.crt -noout -text
    # create a key pair
    k = crypto.PKey()
    k.generate_key(crypto.TYPE_RSA, 4096)
    # create a self-signed cert
    cert = crypto.X509()
    cert.get_subject().C = countryName
    cert.get_subject().ST = stateOrProvinceName
    cert.get_subject().L = localityName
    cert.get_subject().O = organizationName
    cert.get_subject().OU = organizationUnitName
    cert.get_subject().CN = commonName
    cert.get_subject().emailAddress = emailAddress
    cert.set_serial_number(serialNumber)
    cert.gmtime_adj_notBefore(0)
    cert.gmtime_adj_notAfter(validityEndInSeconds)
    cert.set_issuer(cert.get_subject())
    cert.set_pubkey(k)
    cert.sign(k, 'sha512')
    with open(CERT_FILE, "wt") as f:
        f.write(crypto.dump_certificate(crypto.FILETYPE_PEM, cert).decode("utf-8"))
    with open(KEY_FILE, "wt") as f:
        f.write(crypto.dump_privatekey(crypto.FILETYPE_PEM, k).decode("utf-8"))
    print("GENERATED")
    input("Press enter to close program.")
cert_gen()

However, you still get the "certificate is not trusted" error. This is because of a few reasons:

  1. It is self-signed/not verified (a verified certificate would need a CA (Certificate Authority), like Let's Encrypt to be trusted on all devices).
  2. It is not trusted on your machine. (this answer shows how you can make Windows trust your certificate).
Forecourt answered 23/5, 2022 at 4:56 Comment(0)
T
-1

If you want to generate self signed certificates using open ssl - here is a script we have generated which can be used as is.

#!/bin/bash

subj='//SKIP=skip/C=IN/ST=Country/L=City/O=MyCompany/OU=Technology'
red='\033[31m'        # red
yellow='\033[33m'        # yellow
green='\033[32m'        # green
blue='\033[34m'        # Blue
purple='\033[35m'      # Purple
cyan='\033[36m'        # Cyan
white='\033[37m'       # White


gencerts(){
certname=$1
pkname=$2
alias=$3
$(openssl genrsa -out $pkname'pem.pem' 4096)
$(openssl req -new -sha256 -key $pkname'pem.pem' -out $certname'csr.csr' -subj $subj)
$(openssl x509 -req -sha256 -days 3650 -in $certname'csr.csr' -signkey $pkname'pem.pem' -out $certname'.crt')
$(openssl pkcs12 -export -out $pkname'.p12' -name $alias -inkey $pkname'pem.pem' -in $certname'.crt')
}

verify(){
pkname=$1
keytool -v -list -storetype pkcs12 -keystore $pkname'.p12'
}

echo -e "${purple}WELCOME TO KEY PAIR GENERATOR"
echo -e "${yellow} Please enter the name of the certificate required: "
read certname
echo -e "${green}Please enter the name of the Private Key p12 file required: "
read pkname
echo -e "${cyan}Please enter the ALIAS of the Private Key p12 file : "
read pkalias
echo -e "${white}Please wait while we generate your Key Pair"

gencerts $certname $pkname $pkalias
echo -e "${white}Now lets verify the private key :)"

tput bel     # Play a bell

verify $pkname
  • Do let me know if any improvements can be made to the script.
Tartan answered 28/10, 2022 at 17:17 Comment(0)
D
-4

You don't need to use openssl's bad user interface at all! Try mkcert.

$ brew install mkcert nss
[...]

$ mkcert -install
Created a new local CA 💥
The local CA is now installed in the system trust store! ⚡️
The local CA is now installed in the Firefox trust store (requires browser restart)! 🦊

$ mkcert example.com "*.example.com" example.test localhost 127.0.0.1 ::1

Created a new certificate valid for the following names 📜
 - "example.com"
 - "*.example.com"
 - "example.test"
 - "localhost"
 - "127.0.0.1"
 - "::1"

The certificate is at "./example.com+5.pem" and the key at "./example.com+5-key.pem" ✅
Defrost answered 22/8, 2022 at 17:40 Comment(3)
why the downvote?? this is the best easy solution instead of 1000line to create a local ssl cert which at the end chrome does not accept even when we put it in windows cert store! mkcert works perfectly and does everything except adding 192.168.1.100 mysite.com to C:\Windows\System32\drivers\etc\HOSTSOrgandy
Also it's worth pointing out that mkcert has over 40,000 stars on GitHub - this is a very popular tool!Defrost
Yes, I was surprised by the amount of GitHub stars. It is clear that he solves a real problem, otherwise he would not have got all these starsOrgandy

© 2022 - 2024 — McMap. All rights reserved.