Skip to content
kares edited this page Jul 29, 2026 · 4 revisions

JRuby-OpenSSL (FIPS)

FIPS 140-3 variant of jruby-openssl. Ships the unmodified BC-FJA module (NIST cert) and a FIPS-aware loader, emulates the Ruby OpenSSL native library on top of BC-FIPS through JCE.

jruby-openssl variant is not itself FIPS (140-3) validated, what carries FIPS compliance is the unmodified validated cryptographic module (bundled with the gem)

gem is not a full drop-in replacement, the OpenSSL API surface is unchanged, in approved-only mode only FIPS-approved algorithms and parameters are exposed, code that reaches for a non-approved primitive raises instead of proceeding

Installation

gem install jruby-openssl-*.gem

or preferably add it to your Gemfile e.g.

gem "jruby-openssl", source: "https://gem.coop/@jossl-fips"

(J)Ruby's standard require 'openssl' than resolves to gem's loader, which:

  1. refuses to load if a non-FIPS BouncyCastle provider is already registered
  2. loads bc-fips, bcutil-fips, bcpkix-fips, bctls-fips libraries
  3. delegates OpenSSL cryptographic operations to the FIPS-variant provider

Approved-only mode

For NIST-validated operation, start the JVM with the BC-FIPS integrity self-test and approved-only mode, using the org.bouncycastle.fips.approved_only property:

JRUBY_OPTS='-J-Dorg.bouncycastle.fips.approved_only=true' ruby -ropenssl -e 'p OpenSSL.fips_mode'

Supported configuration

All the upstream jruby-openssl documentation applies here as well — the OpenSSL API and the supported configuration knobs are the same. This variant only swaps the regular Bouncy Castle backend for the FIPS-validated one, so the rest of this README covers just the FIPS-specific parts.

Specific Runtime / JVM properties

Property Default Effect
org.bouncycastle.fips.approved_only unset by default; should be true in production FIPS use BC-FIPS approved-only mode

Features unavailable under FIPS

  • Legacy ciphers e.g. OpenSSL::Cipher.new('des-cbc'), 'bf-cbc' (Blowfish), 'rc4', 'rc2-cbc', 'cast5-cbc', 'seed-cbc' are refused
  • MD5 / MD4 as digests - OpenSSL::Digest.new('MD5') and MD5-based key derivation (Cipher#pkcs5_keyivgen) are not approved
  • Legacy encrypted PEM - MD5-based DEK-Info format (older OpenSSL::PKey.read(pem, pass) keys) cannot be read or written
  • Undersized keys / parameters e.g. RSA below 2048-bit and HMAC keys shorter than 112 bits

Bundled Bouncy Castle FIPS module

This gem ships the Bouncy Castle FIPS Java API (BC-FJA) along with its companion jars:

  • bc-fips
  • bcutil-fips
  • bcpkix-fips
  • bctls-fips

These are libraries Bouncy Castle publishes, shipped byte-for-byte as released: nothing is modified, repackaged or shaded - so the FIPS 140-3 HMAC-SHA2-256 integrity self-test built into the module is kept valid.

The BC-FIPS jars are Copyright (c) The Legion of the Bouncy Castle Inc. and are licensed under the Bouncy Castle Licence - see LICENSE.bouncycastle.

Further reading:

Logging

BC (FIPS) logging

Bouncy Castle FIPS log via java.util.logging (JUL) JDK's built-in logging.

BC-JSSE (TLS implementation) is fairly chatty out of the box: it reports JDK-wide disabled-algorithm policy at first load and emits an INFO line per TLS handshake. Because JUL's default console handler prints INFO and above, these would show up on stderr in an otherwise quiet application.

By default, jruby-openssl adjusts the level on exactly those known-noisy loggers (init-time reports to SEVERE and per-handshake logs to WARNING so genuine protocol problems are still visible). This silencing is skipped when you have configured JUL yourself e.g. using a java.util.logging.config.file and can also be turned off explicitly with -Djruby.openssl.log.silence=false.

Any BC logger can then be tuned the usual JUL way, in your logging.properties:

org.bouncycastle.jsse.provider.ProvTlsClient.level = FINE

Routing jruby-openssl logging (recommended)

jruby-openssl has its own small logger facade, that defaults to the process output and is gated by setting OpenSSL.debug = true or -Djruby.openssl.debug=true. This is convenient for quick debugging but isn't wired into any logging framework.

Since the FIPS module already logs through JUL, we recommend to switch jruby-openssl logging to the JUL backend too, so both go to the same place with one configuration:

-Djruby.openssl.log.logger=jul

Messages are then emitted through java.util.logging under org.jruby.ext.openssl.* logger names and are configured like any other JUL logger:

handlers = java.util.logging.ConsoleHandler
.level = INFO

# jruby-openssl internals
org.jruby.ext.openssl.level = FINE
java.util.logging.ConsoleHandler.level = FINE

FAQ

How does the FIPS variant differ from regular jruby-openssl?

It's the same OpenSSL API, only the cryptographic backend changes. Regular jruby-openssl runs on the general-purpose Bouncy Castle (or the Java built-in) provider, this variant runs on the FIPS-validated Bouncy Castle FIPS provider.

It ships as a separate gem, from a separate source, but under the same name (jruby-openssl) so application code and require 'openssl' stay unchanged.

What is BC-FIPS and where do I get it?

BC-FIPS is Bouncy Castle's FIPS 140-3 validated cryptographic module and Java API, distinct from the regular BC provider jars. The FIPS variant of the gem bundles the bc-fips, bcutil-fips, bcpkix-fips and bctls-fips jars. Upstream releases live at downloads.bouncycastle.org/fips-java.

How is BC-FIPS different from regular BC provider?

BC-FIPS is not the regular provider, it's a separate fork (branched from regular BC around 1.58), differences:

  • BouncyCastleFipsProvider ("BC-FIPS") instead of BouncyCastleProvider ("BC").
  • No direct primitives - regular BC lets you instantiate engines/digests/signers from org.bouncycastle.crypto.*, BC-FIPS replaces those with an approved-mode factory pattern where primitives can only be reached through approved services.
  • A validated module - "FIPS 140-3 validated" means an independent NIST-accredited lab tested the exact provider under NIST's CMVP: its algorithm implementations checked against NIST's known answer tests, key-management and self-test requirements, after which NIST issued certificate #4943.
  • Divergent APIs (because of the fork and its requirement), e.g. ASN.1 and key classes differ in both names and types.

Standard (non-FIPS) jruby-openssl is built against regular BC, so it cannot simply load the FIPS jars. This variant (and especially the parent) need to be aware of the subtle API differences and potential illegal cryptographic operations and be adapted.

Which algorithms or key sizes are not available under FIPS?

In approved-only mode BC-FIPS permits only FIPS-approved algorithms and parameters, so some things (that work on regular jruby-openssl) are rejected:

  • Legacy ciphers - DES/3DES-as-DES, Blowfish, CAST5/CAST6, RC2, RC4, SEED, and CFB-1 mode
  • MD5-based key derivation e.g. Cipher#pkcs5_keyivgen (which defaults to MD5)
  • Undersized keys - RSA below 2048 bits for signing, HMAC keys shorter than 112 bits

An operation that BC-FIPS refuses surfaces as an OpenSSL error, not a silent downgrade — the point of FIPS is that non-approved crypto fails closed.

Does using this gem make my application FIPS validated?

No, jruby-openssl gem is not validated, the only validated artifact is the unmodified BC-FIPS module, responsible for all cryptographic operations. Using this gem in approved-only mode means your cryptography runs inside that validated module using approved algorithms: it does not certify your application, JVM, OS, or deployment. Overall FIPS claims remain your responsibility.

How do I obtain the FIPS variant of the gem?

Gem is not published on rubygems.org, jruby-openssl name there belongs to the non-FIPS artifact. The FIPS (open-source) variant is published to a separate source, point your Gemfile at:

source 'https://rubygems.org'

gem 'jruby-openssl', source: 'https://gem.coop/@jossl-fips' # GPL-3.0 licensed

The commercial edition is distributed through a separate source, see COMMERCIAL for access and contact details.

Either way gem name stays jruby-openssl, it's a drop-in replacement for the default gem.

Why GPL-3.0 / commercial only, not permissively licensed like jruby-openssl?

Packaging and maintaining the FIPS variant - a bundled validated module, a separate build, a second artifact, and keeping all of it in step with the parent - is a considerable amount of ongoing work on top of jruby-openssl itself.

The dual GPL-3.0 + commercial model is how we are trying to gauge whether there is enough interest to sustain that work. Open-source and internal use are already covered by GPL-3.0 (see COMMERCIAL for what does not need a commercial license).

jruby-openssl is largely maintained on volunteer time, and FIPS support adds to that on both sides of the split. A pure-Java OpenSSL is what lets JRuby ship without native dependencies; the alternative, binding to C OpenSSL, would trade that away for packaging and deployment friction. Commercial licensing is how the work of keeping the JVM route viable can be funded, and interest in it is a clear signal that it's worth the effort.

What is approved-only mode and why should I set it?

BC-FIPS can run in two states. In the default "general mode" it still exposes non-FIPS approved algorithms and parameters, so you could unknowingly use non-compliant crypto. Approved-only mode (-Dorg.bouncycastle.fips.approved_only=true) restricts the runtime to the FIPS-approved algorithm set and key sizes (the actual FIPS operational state).

This gem assumes an approved-only default, see Approved-only mode for the flag.

Why the same gem name, and how does versioning work?

For the FIPS variant to be a genuine drop-in, application code and transitive dependencies must resolve the same gem name. RubyGems identifies a gem solely by name + version + platform and neither platform nor a metadata field can act as a "variant" selector. Thus the only way to be a true drop-in is to reuse the name jruby-openssl which is why this is not published as a separate jruby-openssl-fips name, and why the gem comes from a separate source.

With the name fixed there's extra metadata to be able to distinguish the gems installed locally, there's also a versioning convention. The FIPS gem mirrors the parent release it is built from and appends a fourth segment as its own version (revision) number:

Normal (jruby-openssl) FIPS (jruby-openssl)
0.19.0 0.19.0.1, 0.19.0.2, …
0.20.0 0.20.0.1, …

The revision starts at 1 (a .0 would compare equal to the bare parent version).

Licence

This gem's customizations are (re-)licensed under GPL-3.0, see LICENSE. Commercial (non-GPL) licensing is available for organizations embedding this gem in proprietary or non-GPL products, see COMMERCIAL.


Generated content - edits made here will be overwritten.

Clone this wiki locally