https://github.com/FiloSottile/mkcert
It's in pure Go instead of using OpenSSL, and it works with Windows, macOS and Firefox, too.
I've added a link to your project in my README.md file.
Initially they used to come as a goodies with OpenVPN, but they are now provided as a standalone project.
There are already packaged and available in most distributions (easy-rsa package under Debian for example).
There are probably a little bit more complex to use, but it's far from horrible, and it's quite battle tested.
Also, Go's TLS library is missing some important features, like decrypting most varieties of private keys.
I use Go's TLS library, but I don't think it's necessary "better" than openssl, though it's certainly more convenient.
* /bin/bash -> /usr/bin/env bash
* You probably don't need bash anyway, so switch to /bin/sh
* errors go to stderr (>&2), not stdout
* exits because of errors should return non-zero codes. (e.g.: `exit 1`)
* Full caps variables are bad practise (might conflict with real, global env variables)
* rather than running everything as root (using sudo), I'd call sudo for the only few commands that actually require root privileges (I found none, so I suppose "security" is the only command that needs root perms).
* Indentation is mad. "exit" seems to cause preceding lines to be indented. This is code, treat it as such.
* Only split a command in two where it increases readability. Type "rm +.txt +.doc" if that's what you mean, not "rm +.txt ; rm +.doc". (Substitute + for asterisks; don't know how to avoid markdown.) The asterisks already expands to multiple filenames.
* When rm:ing files in shell scripts using "-f" is likely a good idea. Interactive aliases or unexpected permissions might trip you up otherwise.
* But removing everything in your-certs is probably a surprise for the user. You would expect the script to generate a new certificate, not erase old ones!
* Don't do an if-construct every time you mkdir something. Just do "mkdir -p" instead, that makes sure directories exist and creates them if necessary.
* The config file needs to be specified with a full path, or at least checked if it exists. If you place it in the same directory as the script, use "dirname $0" to figure out the path.
* That config file is so small you might as well store it in the script and cat << EOF it directly through sed to disk. Or even use variable substitution directly.
* If you need temporary files for some reason, it's good practice to use mktemp to allocate them which gives you uniqueness and a suitable tmp folder for free.
* That awk-construct is perhaps not obvious to everyone. Just do "for fprint in $(... | grep)" instead. Or "security .. | while read" if there are more than a handful.
* Not setting umask could potentially render key material readable to other users. Don't do this.
* Don't generate a new CA every run. Keep it around in a directory (with proper permissions) and only generate a new if not already present in the trust store.
Sometimes you may trip on applications not willing to accept a new certificate with the same serial number as an old one. If this is something you need to take into account, just store used serial numbers in the same directory as your CA keys. It should also be noted that openssl ships with a script does all this, except installing the trusted certificate in the trust store.
set -u
in all scripts. Then set +u when you need something undefined such as a case statement.And the Google 'Shell Style Guide': https://google.github.io/styleguide/shell.xml
Just in case you hadn't seen them already.
Good luck!
There are other steps involved, like adding the cert to the trust store (so you don't get invalid SSL warnings). And also changing your application code to use these certificates.
Even if you do that, you are still exposed to a serious security threat: if a bad actor gets hold of your certificate file, they can pose as a legitimate website and steal sensitive data. This security flaw is present with all other script solutions mentioned in this thread.
To overcome these issues, I have built a mac application called HTTPSLocalhost (https://httpslocalhost.com).
- It offers a user interface to add remove local https domains
- Has an inbuilt proxy so you don't need to change your application code
- Is much safer because it deletes the certificate and private keys as soon as the proxy server starts
- It creates a new certificate each time you start the app, to enhance security.
- And of course, like all good things, is free (there is a video demo on the website, the app will be ready soon).
Wanted to do a proper Show HN next week, but I guess it's the right time to bring it up :)
Thanks
Sorry, but, what? Who is using self-signed certs for public production websites?
But if an attacker has a private key that is trusted by your local trust store, they can pose a legitimate website (man in the middle) and decrypt your traffic.
The title tells me that this thread is about local https. Nothing to do with prod.
Local dev certs should go into a personal store or something that is less trusted than something like VeriSign. You shouldn't be able to mint a legit-looking Google certificates with the same private key that's only trusted via a local self-signed certificate.
Maybe I don't understand something.
I often hack together quick experiments using PHP's internal webserver. It only serves via http though, not https. Is there a way to make it serve over https?
$ php -S localhost:8080
Then, you can proxy with combination of ncat server and client: $ sudo ncat --listen --ssl localhost 443 -k --sh-exec "ncat localhost 8080"
You can also point ncat to your SSL certificate.I just tried it and it works nicely.
Thank you so much!
Write SANs. Subject Alternative Names. These aren't aliases, the "alternative" means in the sense that this is an "alternative" to writing human readable X.500 series Common Names. Unlike those human names, SANs are defined in a machine readable way, e.g. the dnsNAme SAN spells exactly DNS A-labels, the ipAddress SAN is just an IPv4 or IPv6 address written out as raw bytes, not a dotted decimal or whatever else someone thought might be fun today.
You should also write one of the SANs you choose as the Common Name in some plausible text format, but by having SANs all vaguely modern tools can just match those rather than trying to make sense of the Common Name.
In a very new OpenSSL you can actually do this from the command line sort-of sensibly. In most installs you will need to modify that configuration file instead, you're already using a configuration file so that's no big deal.
Chrome finally stopped looking at the Common Name field, and I'm hoping to fade out support in the next few versions of Go. You can already test your systems in 1.11 with GODEBUG=x509ignoreCN=1. Use SANs.
This was one of the motives to create mkcert: https://github.com/FiloSottile/mkcert
Not really... I will grant that the openssl commands are a bit non-obvious.
Step 1: Generate private key
openssl ecparam -genkey -name secp384r1 -out key.pem
Step 2: Create and sign cert
openssl req -x509 -sha512 -nodes -days 365 -key key.pem -subj "/CN=example.com" -reqexts SAN -extensions SAN -config <(cat /etc/ssl/openssl.cnf <(printf '[SAN]\nsubjectAltName=DNS:example.com,DNS:*.example.com')) -out cert.pem
It's really time to lay DES to rest.