1. Basic Web SSL Server

1.1. Generate a self signed certificate - without a Certificat Authority (CA)

$ openssl genrsa -des3 -out server.key 1024
  • Step 2: Generate a CSR

$ openssl req -new -key server.key -out server.csr
  • Step 3: Remove Passphrase from Key

$ cp server.key server.key.org
$ openssl rsa -in server.key.org -out server.key
  • Step 4: Generating a Self-Signed Certificate (without a CA)

$ openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt

1.2. Generate a self signed certificate - as your own Certificate Authority (CA)

This allows you to import the CA into your OS and simplifies the permissions.

TODO: Figure out how to import into a web-client without importing into the OS.

openssl req -x509 -newkey rsa:4096 -keyout ca_auth.key -out ca_auth.pem -days 365 -subj '/CN=localhost'
  • step 2 - import the CA_auth into your OS (as described in the various articles)

ca_auth.pem
  • step 3 - create a self-signed server cert - start with a server key

openssl genrsa -out server.key 4096
  • step 4 - *make the certificate reqest 'csr' using the server key

openssl req -new -key server.key -out server_req.csr -subj '/CN=localhost'
  • Step 5 - generate the self-signed certificate based on the request & the CA

openssl x509 -req -in server_req.csr -CA ca_auth.pem -CAkey ca_auth.key -CAcreateserial -out server.crt -days 365 -sha256

1.3. Write the SSL Server Code

Helpful Docs:

code/crystal/src/web_server/web_ssl_server.cr
# A very basic HTTPS server
require "openssl"
require "http/server"

server = HTTP::Server.new do |context|
  # get incoming request
  path = context.request.path

  # log request to stdout - for fun
  puts "HTTP request for path: #{path}"

  # build / send response
  context.response.content_type = "text/plain"
  context.response.print "Hello world, got #{path}!"
end

# configure the ssl service
tls_config = OpenSSL::SSL::Context::Server.new
tls_config.private_key = "./server.key"
tls_config.certificate_chain = "./server.crt"

# 'bind' the ssl server to the web server
server.bind_tls "localhost", 8443, tls_config
puts "Listening on http://127.0.0.1:8443"
server.listen

Run with

$ crystal code/crystal/src/web_server/web_ssl.cr

Now open your browser to (dismiss all the warnings about the self-signed cert) * https://localhost:8443 * https://localhost:8443/bill

1.4. Use the Custom TLS Web Client

code/crystal/src/web_server/web_ssl_client.cr
require "openssl"
require "http/client"

tls_client = OpenSSL::SSL::Context::Client.new
tls_client.verify_mode = OpenSSL::SSL::VerifyMode::NONE
web_client = HTTP::Client.new(host: "localhost", port: 8443, tls: tls_client)

response = web_client.get "/"
puts response.status_code
response.body.each_line{ |line| puts line }

response = web_client.get "/bill"
puts response.status_code
response.body.lines.each { |line| puts line }

Run with (after starting the ssl_server)

$ crystal code/crystal/src/web_server/web_ssl_client.cr