module OpenSSL

Overview

The OpenSSL module allows for access to Secure Sockets Layer (SSL) and Transport Layer Security (TLS) encryption, as well as classes for encrypting data, decrypting data, and computing hashes. It uses the SSL library provided by the operating system, which may be either OpenSSL or LibreSSL.

WARNING This module should not be used without first reading the Security considerations.

To create secure sockets, use either OpenSSL::SSL::Socket::Client for client applications, or OpenSSL::SSL::Socket::Server for servers. These classes use a default context, but you can provide your own by supplying an OpenSSL::SSL::Context. For more control, consider subclassing OpenSSL::SSL::Socket.

Hashing algorithms are provided by classes such as Digest::SHA256 and Digest::MD5. If you need a different option, you can initialize one using the name of the digest with OpenSSL::Digest. A Hash-based Message Authentication Code (HMAC) can be computed using HMAC and specifying a digest Algorithm.

The OpenSSL::Cipher class can be used for encrypting and decrypting data.

NOTE To use OpenSSL, you must explicitly import it using the require "openssl" statement.

Security Considerations

Crystal aims to provide reasonable configuration defaults in accordance with Mozilla's recommendations. However, these defaults may not be suitable for your application. It is recommended that you refer to the Open Worldwide Application Security Project (OWASP) cheat sheet on implementing transport layer protection to ensure the appropriate configuration for your use.

If you come across any shortcomings or spots for improvement in Crystal's configuration options, please don't hesitate to let us know by opening an issue.

Usage Example

Server side

An SSL server is created with a TCPServer and a SSL::Context. You can then use the SSL server like an ordinary TCP server.

NOTE For the below example to work, a certificate and private key should be attained.

require "openssl"
require "socket"

PORT = ENV["PORT"] ||= "5555"

# Bind new TCPServer to PORT
socket = TCPServer.new(PORT.to_i)

context = OpenSSL::SSL::Context::Server.new
context.private_key = "/path/to/private.key"
context.certificate_chain = "/path/to/public.cert"

puts "Server is up. Listening on port #{PORT}."

socket.accept do |client|
  puts "Got client"

  bytes = Bytes.new(20)

  OpenSSL::SSL::Socket::Server.open(client, context) do |ssl_socket|
    ssl_socket.read(bytes)
  end

  puts "Client said: #{String.new(bytes)}"
end

socket.close
puts "Server has stopped."

Client side

An SSL client is created with a TCPSocket and a SSL::Context. Unlike a SSL server, a client does not require a certificate or private key.

NOTE By default, closing an SSL::Socket does not close the underlying socket. You need to set SSL::Socket#sync_close= to true if you want this behaviour.

require "openssl"
require "socket"

PORT = ENV["PORT"] ||= "5555"

# Bind TCPSocket to PORT and open a connection
TCPSocket.open("127.0.0.1", PORT) do |socket|
  context = OpenSSL::SSL::Context::Client.new

  OpenSSL::SSL::Socket::Client.open(socket, context) do |ssl_socket|
    ssl_socket << "Hello from client!"
  end
end

Defined in:

openssl_ext/bio.cr
openssl_ext/pkey.cr
openssl_ext/rsa.cr