Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve OpenSSL module documentation #14410

Merged
merged 2 commits into from Apr 2, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
98 changes: 64 additions & 34 deletions src/openssl.cr
@@ -1,69 +1,99 @@
require "./openssl/lib_ssl"
require "./openssl/error"

# NOTE: To use `OpenSSL`, you must explicitly import it with `require "openssl"`
# 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](https://openssl.org)
# or [LibreSSL](https://www.libressl.org).
#
# ## OpenSSL Integration
# WARNING: This module should not be used without first reading the [Security considerations](#security-considerations).
#
# - TLS sockets need a context, potentially with keys (required for servers) and configuration.
# - TLS sockets will wrap the underlying TCP socket, and any further communication must happen through the `OpenSSL::SSL::Socket` only.
# To can create secure sockets, use either `OpenSSL::SSL::Socket::Client` for client applications, or
summer-alice marked this conversation as resolved.
Show resolved Hide resolved
# `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`.
#
# ## Usage Example
# 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
ysbaddaden marked this conversation as resolved.
Show resolved Hide resolved
# [Mozilla's recommendations](https://wiki.mozilla.org/Security/Server_Side_TLS#Intermediate_compatibility_.28recommended.29).
# 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](https://cheatsheetseries.owasp.org/cheatsheets/Transport_Layer_Security_Cheat_Sheet.html)
# to ensure the appropriate configuration for your use.
#
# Recommended ciphers can be taken from:
# - [OWASP Wiki](https://www.owasp.org/index.php/Transport_Layer_Protection_Cheat_Sheet#Rule_-_Only_Support_Strong_Cryptographic_Ciphers)
# - [Cipherli.st](https://cipherli.st/)
# - A full list is available at the [OpenSSL Docs](https://www.openssl.org/docs/man1.1.0/apps/ciphers.html#CIPHER-STRINGS)
# 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](https://github.com/crystal-lang/crystal/issues/new).
#
# Do note that:
# - Crystal does its best to provide sane configuration defaults (see [Mozilla-Intermediate](https://wiki.mozilla.org/Security/Server_Side_TLS#Intermediate_compatibility_.28default.29)).
# - Linked version of OpenSSL need to be checked for supporting specific protocols and ciphers.
# - If any configurations or choices in Crystal regarding SSL settings and security are found to be lacking or need
# improvement please [open an issue](https://github.com/crystal-lang/crystal/issues/new) and let us know.
# ## Usage Example
#
# ### Server side
#
# NOTE: For the below example to work, a key pair should be attained.
# 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 "socket"
# require "openssl"
# require "socket"
#
# def server
# # Bind new TCPSocket to port 5555
# socket = TCPServer.new(5555)
# PORT = ENV["PORT"] ||= "5555"
#
# context = OpenSSL::SSL::Context::Server.new
# context.private_key = "/path/to/private.key"
# context.certificate_chain = "/path/to/public.cert"
# # Bind new TCPServer to PORT
# socket = TCPServer.new(PORT.to_i)
#
# puts "Server is up"
# context = OpenSSL::SSL::Context::Server.new
# context.private_key = "/path/to/private.key"
# context.certificate_chain = "/path/to/public.cert"
#
# socket.accept do |client|
# puts "Got client"
# puts "Server is up. Listening on port #{PORT}."
#
# bytes = Bytes.new(20)
# socket.accept do |client|
# puts "Got client"
#
# ssl_socket = OpenSSL::SSL::Socket::Server.new(client, context)
# ssl_socket.read(bytes)
# bytes = Bytes.new(20)
#
# puts String.new(bytes)
# 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 "socket"
# require "openssl"
# require "socket"
#
# def client
# socket = TCPSocket.new("127.0.0.1", 5555)
# 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
#
# ssl_socket = OpenSSL::SSL::Socket::Client.new(socket, context)
# ssl_socket << "Testing"
# OpenSSL::SSL::Socket::Client.open(socket, context) do |ssl_socket|
# ssl_socket << "Hello from client!"
# end
# end
# ```
module OpenSSL
Expand Down
4 changes: 4 additions & 0 deletions src/openssl/cipher.cr
Expand Up @@ -3,6 +3,10 @@ require "openssl"

# A class which can be used to encrypt and decrypt data using a specified cipher.
#
# NOTE: The ciphers available to an application are determined by the linked version of the system SSL library.
# A comprehensive list of ciphers can be found in the
# [OpenSSL Cipher documentation](https://www.openssl.org/docs/man3.0/man1/openssl-ciphers.html#CIPHER-STRINGS).
#
# ```
# require "random/secure"
#
Expand Down
20 changes: 16 additions & 4 deletions src/openssl/ssl/context.cr
Expand Up @@ -294,19 +294,31 @@ abstract class OpenSSL::SSL::Context
raise OpenSSL::Error.new("SSL_CTX_use_PrivateKey_file") unless ret == 1
end

# Specify a list of TLS ciphers to use or discard.
# Specify a list of TLS ciphers to use or discard for TLSv1.2 and below.
#
# This affects only TLSv1.2 and below. See `#security_level=` for some
# sensible system configuration.
# See `#security_level=` for some sensible system configuration.
#
# This method does not impact TLSv1.3 ciphersuites. Use `#cipher_suites=`
# to configure those.
#
# NOTE: The ciphers available to an application are determined by the
# linked version of the system SSL library. A comprehensive list
# of ciphers can be found in the
# [OpenSSL Cipher documentation](https://www.openssl.org/docs/man3.0/man1/openssl-ciphers.html#CIPHER-STRINGS).
def ciphers=(ciphers : String)
ret = LibSSL.ssl_ctx_set_cipher_list(@handle, ciphers)
raise OpenSSL::Error.new("SSL_CTX_set_cipher_list") if ret == 0
ciphers
end

# Specify a list of TLS cipher suites to use or discard.
# Specify a list of TLS ciphersuites to use or discard for TLSv1.3.
#
# See `#security_level=` for some sensible system configuration.
#
# NOTE: The ciphersuites available to an application are determined by the
# linked version of the system SSL library. A comprehensive list
# of ciphersuites can be found in the
# [OpenSSL Cipher documentation](https://www.openssl.org/docs/man3.0/man1/openssl-ciphers.html#TLS-v1.3-cipher-suites).
def cipher_suites=(cipher_suites : String)
{% if LibSSL.has_method?(:ssl_ctx_set_ciphersuites) %}
ret = LibSSL.ssl_ctx_set_ciphersuites(@handle, cipher_suites)
Expand Down