Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
205 changes: 205 additions & 0 deletions ext/openssl/ossl.c
Original file line number Diff line number Diff line change
Expand Up @@ -1012,6 +1012,211 @@ ossl_crypto_fixed_length_secure_compare(VALUE dummy, VALUE str1, VALUE str2)
* If the server certificate is invalid or <tt>context.ca_file</tt> is not set
* when verifying peers an OpenSSL::SSL::SSLError will be raised.
*
* === Post-Quantum Cryptography
*
* Post-quantum cryptography (PQC) secures electronic information against
* attacks by quantum computers. PQC is available in \OpenSSL >= 3.5.0.
*
* Two aspects of a TLS connection can use PQC algorithms:
*
* * Key exchange - ML-KEM specifying via OpenSSL::SSL::SSLContext#groups= and
* getting via OpenSSL::SSL::SSLSocket#group.
* * Signature - ML-DSA specifying via
* OpenSSL::SSL::SSLContext#sigalgs= and getting via
* OpenSSL::SSL::SSLSocket#sigalg and OpenSSL::SSL::SSLSocket#peer_sigalg.
*
* ==== PQC Server and Client
*
* A server using an ML-KEM key exchange and ML-DSA signature (X25519MLKEM768
* is a hybrid algorithm (X25519 + ML-KEM-768), a variant of ML-KEM, ML-DSA-65
* is a variant of ML-DSA):
Comment on lines +1028 to +1032

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The example code in this section seems redundant now with the following sections.

*
* require 'socket'
*
* # ML-DSA-65 server certificate and key
* cert = OpenSSL::X509::Certificate.new(File.read('mldsa65_server_cert.pem'))
* key = OpenSSL::PKey.read(File.read('mldsa65_server_key.pem'))
*
* context = OpenSSL::SSL::SSLContext.new
* # Set the allowed TLS group with X25519MLKEM768
* context.groups = 'X25519MLKEM768'
* context.add_certificate(cert, key)
*
* tcp_server = TCPServer.new('localhost', 5000)
*
* loop do
* tcp_connection = tcp_server.accept
* ssl_connection = OpenSSL::SSL::SSLSocket.new(tcp_connection, context)
* ssl_connection.accept
*
* p ssl_connection.group # => "X25519MLKEM768"
* p ssl_connection.sigalg # => "mldsa65"
* p ssl_connection.peer_sigalg # => nil
*
* ssl_connection.close
* tcp_connection.close
* end
*
* A client connecting to the server:
*
* require 'socket'
*
* context = OpenSSL::SSL::SSLContext.new
* context.ca_file = 'mldsa65_ca_cert.pem'
* context.verify_mode = OpenSSL::SSL::VERIFY_PEER
*
* tcp_socket = TCPSocket.new('localhost', 5000)
* ssl_client = OpenSSL::SSL::SSLSocket.new(tcp_socket, context)
* ssl_client.connect
*
* p ssl_client.group # => "X25519MLKEM768"
* p ssl_client.sigalg # => nil
* p ssl_client.peer_sigalg # => "mldsa65"
*
* ssl_client.close
* tcp_socket.close
*
* ==== Multiple Key Exchanges (PQC and Classical) Server and Clients
*
* A server can be configured with both ML-KEM (PQC) and X25519 (classical) key
* exchange groups, so that it can serve both PQC-capable and classical clients.
* \OpenSSL automatically selects the appropriate key exchange group based on
* the client's capabilities.
*
* require 'socket'
*
* # ML-DSA-65 server certificate and key
* cert = OpenSSL::X509::Certificate.new(File.read('mldsa65_server_cert.pem'))
* key = OpenSSL::PKey.read(File.read('mldsa65_server_key.pem'))
*
* context = OpenSSL::SSL::SSLContext.new
* # Set the allowed TLS group with X25519MLKEM768 and X25519
* context.groups = 'X25519MLKEM768:X25519'
* context.add_certificate(cert, key)
*
* tcp_server = TCPServer.new('localhost', 5000)
*
* loop do
* tcp_connection = tcp_server.accept
* ssl_connection = OpenSSL::SSL::SSLSocket.new(tcp_connection, context)
* ssl_connection.accept
*
* p ssl_connection.group
* p ssl_connection.sigalg
* p ssl_connection.peer_sigalg
*
* ssl_connection.close
* tcp_connection.close
* end
*
* A client connecting with X25519MLKEM768 key exchange group to the server:
*
* require 'socket'
*
* context = OpenSSL::SSL::SSLContext.new
* context.groups = 'X25519MLKEM768'
* context.ca_file = 'mldsa65_ca_cert.pem'
* context.verify_mode = OpenSSL::SSL::VERIFY_PEER
*
* tcp_socket = TCPSocket.new('localhost', 5000)
* ssl_client = OpenSSL::SSL::SSLSocket.new(tcp_socket, context)
* ssl_client.connect
*
* p ssl_client.group # => "X25519MLKEM768"
*
* ssl_client.close
* tcp_socket.close
*
* A client connecting with X25519 key exchange group to the server:
*
* require 'socket'
*
* context = OpenSSL::SSL::SSLContext.new
* context.groups = 'X25519'
* context.ca_file = 'mldsa65_ca_cert.pem'
* context.verify_mode = OpenSSL::SSL::VERIFY_PEER
*
* tcp_socket = TCPSocket.new('localhost', 5000)
* ssl_client = OpenSSL::SSL::SSLSocket.new(tcp_socket, context)
* ssl_client.connect
*
* p ssl_client.group # => "X25519"
*
* ssl_client.close
* tcp_socket.close
*
* ==== Multiple Certificates (PQC and Classical) Server and Clients
*
* A server can be configured with both ML-DSA (PQC) and RSA (classical)
* certificates, so that it can serve both PQC-capable and classical clients.
* \OpenSSL automatically selects the appropriate certificate based on the
* client's capabilities.
Comment thread
junaruga marked this conversation as resolved.
Resolved
*
* require 'socket'
*
* # ML-DSA-65 server certificate and key
* mldsa_cert = OpenSSL::X509::Certificate.new(File.read('mldsa65_server_cert.pem'))
* mldsa_key = OpenSSL::PKey.read(File.read('mldsa65_server_key.pem'))
* # RSA server certificate and key
* rsa_cert = OpenSSL::X509::Certificate.new(File.read('rsa_server_cert.pem'))
* rsa_key = OpenSSL::PKey::RSA.new(File.read('rsa_server_key.pem'))
*
* context = OpenSSL::SSL::SSLContext.new
* context.add_certificate(mldsa_cert, mldsa_key)
* context.add_certificate(rsa_cert, rsa_key)
*
* tcp_server = TCPServer.new('localhost', 5000)
*
* loop do
* tcp_connection = tcp_server.accept
* ssl_connection = OpenSSL::SSL::SSLSocket.new(tcp_connection, context)
* ssl_connection.accept
*
* p ssl_connection.sigalg
* p ssl_connection.peer_sigalg
*
* ssl_connection.close
* tcp_connection.close
* end
*
* A client connecting with ML-DSA signature to the server:
*
* require 'socket'
*
* context = OpenSSL::SSL::SSLContext.new
* context.sigalgs = 'mldsa65'
* context.ca_file = 'mldsa65_ca_cert.pem'
* context.verify_mode = OpenSSL::SSL::VERIFY_PEER
*
* tcp_socket = TCPSocket.new('localhost', 5000)
* ssl_client = OpenSSL::SSL::SSLSocket.new(tcp_socket, context)
* ssl_client.connect
*
* p ssl_client.sigalg # => nil
* p ssl_client.peer_sigalg # => "mldsa65"
*
* ssl_client.close
* tcp_socket.close
*
* A client connecting with RSA signature to the server:
*
* require 'socket'
*
* context = OpenSSL::SSL::SSLContext.new
* context.sigalgs = 'rsa_pss_rsae_sha256'
* context.ca_file = 'rsa_ca_cert.pem'
* context.verify_mode = OpenSSL::SSL::VERIFY_PEER
*
* tcp_socket = TCPSocket.new('localhost', 5000)
* ssl_client = OpenSSL::SSL::SSLSocket.new(tcp_socket, context)
* ssl_client.connect
*
* p ssl_client.sigalg # => nil
* p ssl_client.peer_sigalg # => "rsa_pss_rsae_sha256"
*
* ssl_client.close
* tcp_socket.close

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we reduce some of the repetitive boilerplate and focus more on the interesting settings? Runnable examples are often useful, but I feel this goes a bit too far.

*
*/
void
Init_openssl(void)
Expand Down
9 changes: 7 additions & 2 deletions ext/openssl/ossl_ssl.c
Original file line number Diff line number Diff line change
Expand Up @@ -1120,7 +1120,11 @@ ossl_sslctx_set_ciphersuites(VALUE self, VALUE v)
* determine the set of shared signature algorithms. OpenSSL will pick the most
* appropriate one from it.
*
* See also #client_sigalgs= for the client authentication equivalent.
* See also the man page SSL_CTX_set1_sigalgs_list(3), and #client_sigalgs= for
* the client authentication equivalent.
*
* === Example
* ctx.sigalgs = "ECDSA+SHA256:RSA+SHA256"
*/
static VALUE
ossl_sslctx_set_sigalgs(VALUE self, VALUE v)
Expand Down Expand Up @@ -1148,7 +1152,8 @@ ossl_sslctx_set_sigalgs(VALUE self, VALUE v)
* For a TLS server, the list is sent to the client as part of the
* CertificateRequest message.
*
* See also #sigalgs= for the server authentication equivalent.
* See also the man page SSL_CTX_set1_client_sigalgs_list(3), and #sigalgs= for
* the server authentication equivalent.
*/
static VALUE
ossl_sslctx_set_client_sigalgs(VALUE self, VALUE v)
Expand Down
Loading