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?
I can't comment, so I will put this as a separate answer. I found a few issues with the accepted one-liner answer:
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:
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:
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
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?.
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:
Create an OpenSSL config file (example:
req.cnf
)Create the certificate referencing this config file
Example config from https://support.citrix.com/article/CTX135602
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 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:
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 iskeyCertSign
andcrlSign
(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.
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 analternate_names
section in the configuration file (you should tune this to suit your taste):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):Create a signing request (notice the lack of
-x509
option):Print a self-signed certificate:
Print a signing request:
Configuration file (passed via
-config
option)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.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.
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:
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 <<
2017 one-liner:
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.