This document is related to the issue ticket is Being a co-maintainer of the ruby/openssl for the OpenSSL FIPS mode. See also "What is FIPS".
Below are the steps to debug Ruby OpenSSL binding (ruby/openssl) with OpenSSL 3 with FIPS enabled.
Build and install OpenSSL from the source with the FIPS option. See the official configuration options document for details.
--libdir=lib
: This option changes the default library directory name "lib64" in x86_64 to "lib". It's useful when you access from the Ruby OpenSSL binding. Because the mkmf#dir_config
executed by --with-openssl-dir=<path>
in the later step below expects the "lib" as a default. See the code.enable-fips
: Enabling FIPSenable-trace
: Enabling tracing option. You can trace logs in a specific category. See the example. It's helpful to debug.-O0 -g3 -ggdb3 -gdwarf-5
: debugging flags for GCC$ git clone https://github.com/openssl/openssl.git
$ cd openssl
$ git checkout openssl-3.0.8
$ ./Configure \
--prefix=${HOME}/.local/openssl-3.0.8-fips-debug \
--libdir=lib \
shared \
enable-fips \
enable-trace \
-O0 -g3 -ggdb3 -gdwarf-5
$ make -j$(nproc)
$ make install
$ LD_LIBRARY_PATH=${HOME}/.local/openssl-3.0.8-fips-debug/lib/ \
${HOME}/.local/openssl-3.0.8-fips-debug/bin/openssl version -a
OpenSSL 3.0.8 7 Feb 2023 (Library: OpenSSL 3.0.8 7 Feb 2023)
built on: Tue Apr 25 14:23:34 2023 UTC
platform: linux-x86_64
options: bn(64,64)
compiler: gcc -fPIC -pthread -m64 -Wa,--noexecstack -Wall -O3 -O0 -g3 -ggdb3 -gdwarf-5 -DOPENSSL_USE_NODELETE -DL_ENDIAN -DOPENSSL_PIC -DOPENSSL_BUILDING_OPENSSL -DNDEBUG
OPENSSLDIR: "/home/jaruga/.local/openssl-3.0.8-fips-debug/ssl"
ENGINESDIR: "/home/jaruga/.local/openssl-3.0.8-fips-debug/lib/engines-3"
MODULESDIR: "/home/jaruga/.local/openssl-3.0.8-fips-debug/lib/ossl-modules"
Seeding source: os-specific
CPUINFO: OPENSSL_ia32cap=0x7ffaf3ffffebffff:0x29c67af
The program is https://github.com/junaruga/openssl-test. You can see how to use the program and test it to check if the used OpenSSL is FIPS or not. The FIPS needs to set the "fips" provider and default_properties = fips=yes
.
Prepare a config file to run OpenSSL with FIPS.
$ cat ${HOME}/.local/openssl-3.0.8-fips-debug/ssl/openssl_fips.cnf
config_diagnostics = 1
openssl_conf = openssl_init
# Need to set the absolute path of the fipsmodule.cnf.
# https://github.com/openssl/openssl/issues/17704
.include /home/jaruga/.local/openssl-3.0.8-fips-debug/ssl/fipsmodule.cnf
#.include fipsmodule.cnf
[openssl_init]
providers = provider_sect
alg_section = algorithm_sect
[provider_sect]
fips = fips_sect
base = base_sect
[base_sect]
activate = 1
[algorithm_sect]
default_properties = fips=yes
Compile the testing program.
$ gcc \
-I /home/jaruga/.local/openssl-3.0.8-fips-debug/include \
-L /home/jaruga/.local/openssl-3.0.8-fips-debug/lib \
-lcrypto \
-o fips \
fips.c
Run the program.
$ LD_LIBRARY_PATH=${HOME}/.local/openssl-3.0.8-fips-debug/lib/ \
OPENSSL_CONF=/home/jaruga/.local/openssl-3.0.8-fips-debug/ssl/openssl_fips.cnf \
./fips
Loaded providers:
fips
base
FIPS enabled: yes
Install.
$ git clone https://github.com/ruby/openssl.git
$ cd openssl
$ bundle install --standalone
Compile with the debug flags. If your OpenSSL's library name is "lib64", you need the --with-openssl-lib=$HOME/.local/openssl-3.0.8-fips-debug/lib64
option too. The MAKEFLAGS="V=1"
is to print the compiler (gcc
) command lines if your Ruby is not configured with ./configure --enable-mkmf-verbose
option. You can also use the bundle exec rake compile -- --with-verbose
option on this purpose in the Ruby on the master branch.
$ MAKEFLAGS="V=1" \
RUBY_OPENSSL_EXTCFLAGS="-O0 -g3 -ggdb3 -gdwarf-5" \
bundle exec rake compile -- \
--enable-debug \
--with-openssl-dir=$HOME/.local/openssl-3.0.8-fips-debug
Note the bundle exec rake clean
doesn't do this.
$ rm -rf tmp
$ rm lib/openssl.so
$ LD_LIBRARY_PATH=$HOME/.local/openssl-3.0.8-fips-debug/lib/ \
bundle exec rake debug
/usr/local/ruby-3.2.1/bin/ruby -I./lib -ropenssl -ve'puts OpenSSL::OPENSSL_VERSION, OpenSSL::OPENSSL_LIBRARY_VERSION'
ruby 3.2.1 (2023-02-08 revision 31819e82c8) [x86_64-linux]
OpenSSL 3.0.8 7 Feb 2023
OpenSSL 3.0.8 7 Feb 2023
You see many failures and errors on the current master branch (037c181ddf30ed7576eba7d14b95c3742449bf63
) in the ruby/openssl.
$ LD_LIBRARY_PATH=$HOME/.local/openssl-3.0.8-fips-debug/lib/ \
OPENSSL_CONF=/home/jaruga/.local/openssl-3.0.8-fips-debug/ssl/openssl_fips.cnf \
bundle exec rake test
...
510 tests, 1943 assertions, 14 failures, 331 errors, 0 pendings, 0 omissions, 0 notifications
32.3529% passed
...
Let me explain you how to debug with the following tools with an example: reading an encriped .pem file.
Create a testing .pem file.
$ openssl genrsa -out key.pem 4096
$ ls -l key.pem
-rw-------. 1 jaruga jaruga 3272 May 2 19:40 key.pem
Run a program to read the .pem file.
$ LD_LIBRARY_PATH=$HOME/.local/openssl-3.0.8-fips-debug/lib/ \
OPENSSL_CONF=/home/jaruga/.local/openssl-3.0.8-fips-debug/ssl/openssl_fips.cnf \
ruby -I lib -e "require 'openssl'; OpenSSL::PKey.read(File.read('key.pem'))"
Make sure you set the LD_LIBRARY_PATH
in the GDB prompt to prevent overriding the system OpenSSL that is a depenency of the GDB.
$ OPENSSL_CONF=/home/jaruga/.local/openssl-3.0.8-fips-debug/ssl/openssl_fips.cnf \
gdb --args ruby -I lib -e "require 'openssl'; OpenSSL::PKey.read(File.read('key.pem'))"
(gdb) set environment LD_LIBRARY_PATH /home/jaruga/.local/openssl-3.0.8-fips-debug/lib
$ LD_LIBRARY_PATH=$HOME/.local/openssl-3.0.8-fips-debug/lib/ \
OPENSSL_CONF=/home/jaruga/.local/openssl-3.0.8-fips-debug/ssl/openssl_fips.cnf \
ltrace -ttt -f -l openssl.so -l libssl.so.3 -l libcrypto.so.3 \
ruby -I lib -e "require 'openssl'; OpenSSL::PKey.read(File.read('key.pem'))"
$ LD_LIBRARY_PATH=$HOME/.local/openssl-3.0.8-fips-debug/lib
OPENSSL_CONF=/home/jaruga/.local/openssl-3.0.8-fips-debug/ssl/openssl_fips.cnf \
strace -f \
ruby -I lib -e "require 'openssl'; OpenSSL::PKey.read(File.read('key.pem'))"
Debug with the stap
command, SystemTap.
Here is how to set up SystemTap in Fedora Linux as a reference.
Prepare the following bash script.
$ cat test.sh
#! /bin/bash
LD_LIBRARY_PATH=${HOME}/.local/openssl-3.0.8-fips-debug/lib/ \
OPENSSL_CONF=${HOME}/.local/openssl-3.0.8-fips-debug/ssl/openssl_fips.cnf \
ruby -I lib -e "require 'openssl'; OpenSSL::PKey.read(File.read('key.pem'))"
$ chmod +x test.sh
$ ./test.sh
Run the SystemTap scritpt for the Ruby OpenSSL binding library (lib/openssl.so
) below. This command only traces all the methods in the .so file.
$ stap --example para-callgraph.stp \
'process("lib/openssl.so").function("*")' \
-c "./test.sh > /dev/null"
Another example of the SystemTap script for the OpenSSL library libcrypto.so
. It takes a long time.
$ stap --example para-callgraph.stp \
'process("/home/jaruga/.local/openssl-3.0.8-fips-debug/lib/libcrypto.so.3").function("*")' \
-c "./test.sh > /dev/null"