Generating TLS certs for testing is difficult. Most guides have incomprehensible commands that require security knowledge to operate.
Cloudflare open-sourced their well-trusted Golang TLS library,
cloudflare/cfssl
. It has sane defaults and is constantly updated with best practices.
We've compiled it to
WebAssembly
to generate certs in your browser.
Here are some examples of doing mTLS in various languages.
Python
Go
Ruby
Javascript
import ssl
from flask import Flask
app = Flask(__name__)
port = 443
@app.route('/')
def index():
return 'Hi!'
ctx = ssl.create_default_context(purpose=ssl.Purpose.CLIENT_AUTH)
ctx.load_verify_locations(cafile='./ca.pem')
ctx.load_cert_chain(
certfile='./server.pem',
keyfile='./server-key.pem',
)
ctx.verify_mode = ssl.CERT_REQUIRED
app.run(debug=True, ssl_context=ctx, host="0.0.0.0", port=port)
package main
import (
"crypto/tls"
"crypto/x509"
"io/ioutil"
"log"
"net/http"
)
func main() {
caCert, err := ioutil.ReadFile("./ca.pem")
if err != nil {
log.Fatalf("reading ca cert: %s", err)
}
certPool := x509.NewCertPool()
certPool.AppendCertsFromPEM(caCert)
conf := &tls.Config{
ClientCAs: certPool,
}
conf.BuildNameToCertificate()
httpServer := &http.Server{
Addr: ":443",
TLSConfig: conf,
Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
}),
}
err = httpServer.ListenAndServeTLS("./server.pem", "./server-key.pem")
if err != nil {
log.Fatalf("listen and serving: %s", err)
}
}
require 'openssl'
require 'webrick'
require 'webrick/https'
cert = OpenSSL::X509::Certificate.new File.read './server.pem'
pkey = OpenSSL::PKey::EC.new File.read './server-key.pem'
server = WEBrick::HTTPServer.new(:Port => 443,
:SSLEnable => true,
:SSLCertificate => cert,
:SSLPrivateKey => pkey,
:SSLCACertificateFile => './ca.pem')
server.mount_proc '/' do |req, res|
res.body = 'Hi!'
end
server.start
const fs = require('fs');
const https = require('https');
const port = 443;
const server = https.createServer(
{
cert: fs.readFileSync('./server.pem'),
key: fs.readFileSync('./server-key.pem'),
ca: fs.readFileSync('./ca.pem'),
},
(req, res) => {
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
res.end('Hi!\n');
}
);
server.listen(port);
import requests
resp = requests.get(
'https://server/',
cert=('./client.pem', './client-key.pem'),
verify='./ca.pem',
)
if resp.status_code != 200:
print('expected status_code 200 but got {}'.format(resp.status_code))
exit(1)
package main
import (
"crypto/tls"
"crypto/x509"
"io/ioutil"
"log"
"net/http"
)
func main() {
cert, err := tls.LoadX509KeyPair("./client.pem", "./client-key.pem")
if err != nil {
log.Fatalf("loading key pair: %s", err)
}
caCert, err := ioutil.ReadFile("./ca.pem")
if err != nil {
log.Fatalf("reading ca cert: %s", err)
}
certPool := x509.NewCertPool()
certPool.AppendCertsFromPEM(caCert)
conf := &tls.Config{
Certificates: []tls.Certificate{cert},
RootCAs: certPool,
}
client := http.Client{
Transport: &http.Transport{
TLSClientConfig: conf,
},
}
resp, err := client.Get("https://server/")
if err != nil {
log.Fatalf("sending request: %s", err)
}
if resp.StatusCode != http.StatusOK {
log.Fatalf("expected status %d but got %d", http.StatusOK, resp.StatusCode)
}
}
require 'faraday'
require 'openssl'
cert = OpenSSL::X509::Certificate.new File.read './client.pem'
pkey = OpenSSL::PKey::EC.new File.read './client-key.pem'
connection = Faraday::Connection.new 'https://server/', :ssl => {
:client_cert => cert,
:client_key => pkey,
:ca_file => './ca.pem'
}
resp = connection.get '/'
if resp.status != 200
exit 1
end
exit 0
const fs = require('fs');
const https = require('https');
https.get(
{
hostname: 'server',
port: 443,
path: '/',
method: 'GET',
cert: fs.readFileSync('./client.pem'),
key: fs.readFileSync('./client-key.pem'),
ca: fs.readFileSync('./ca.pem')
},
res => {
if (res.statusCode != 200) {
console.error(`expected status 200 but found ${res.statusCode}`);
return process.exit(1);
}
}
).on('error', error => {
console.error(error);
process.exit(1);
});
Want to add something? Find a bug? This project is open-source, please send PRs to github.com/jchorl/tlscerts. Feel free to also get in touch at info@mtls.dev.