-
Notifications
You must be signed in to change notification settings - Fork 167
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
Implement FIPS functions, adding OpenSSL FIPS mode case on CI. #608
Conversation
I created a repository of testing OpenSSL APIs as a proof of concept. You can check the OpenSSL fips_mode_get and fips_mode_set APIs. |
@@ -112,3 +135,10 @@ jobs: | |||
- name: test | |||
run: rake test TESTOPTS="-v --no-show-detail-immediately" OSSL_MDEBUG=1 | |||
timeout-minutes: 5 | |||
if: ${{ !matrix.fips_enabled }} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This condition is a temporary workaround. If you remove the if
, you can reproduce the issue #603 on the fips mode case on CI.
assert OpenSSL.fips_mode == false, ".fips_mode returns false on FIPS mode disabled" | ||
end; | ||
end | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't this test cases be enabled permanently, also outside of CI?
Or shouldn't there rather be one test case, which will compare the expected result based on the env variables?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right now I don't find a good way to check if the OpenSSL is running on the FIPS mode enabled or disabled. Because the OpenSSL.fips_mode
itself is a logic to check if the OpenSSL is running on the FIPS mode enabled or disabled.
Perhaps, one possible way to check the FIPS mode or not with the OpenSSL 3 is, to add a source code of the command fips_enabled
just to return the exit status 0 or 1 using the EVP_default_properties_is_fips_enabled(NULL)
such as (the example in my proof of concept repository), build it and use in the testing process. The code can be below. A challenge of this way is when OpenSSL is not set up properly for the FIPS mode unintentionally, the EVP_default_properties_is_fips_enabled(NULL)
returns 0
(disabled), and the test is skipped unintentionally. Perhaps with keeping the current tests, and in addition, we can add the new test with the command fips_enabled
.
fips_enabled.c
#include <stdio.h>
#include <openssl/evp.h>
int main(int argc, char *argv[])
{
int status = EXIT_SUCCESS;
int fips_enabled = 0;
fips_enabled = EVP_default_properties_is_fips_enabled(NULL);
status = fips_enabled ? EXIT_SUCCESS : EXIT_FAILURE;
exit(status);
}
If you guys like this way, I can add the source code to this repository and can add new tests. But I would like that it is in another PR. Because the current tests running on CI can test the new implementation on the CI.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The FIPS mode is enabled in CI, so it is in know state. Or are you afraid that somebody who would by a chance run the test suite on their FIPS enabled system would differ from default expectation? I don't think this is very likely scenario.
IOW I believe it is safe to assume that by default, FIPS is disabled and the OpenSSL.fips_mode == false
condition is true.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The FIPS mode is enabled in CI, so it is in know state. Or are you afraid that somebody who would by a chance run the test suite on their FIPS enabled system would differ from default expectation? I don't think this is very likely scenario.
Yes. Maybe in my understanding, that is the case I am afraid of. I noticed that OpenSSL.fips_mode
returns false
on FIPS enabled system on OpenSSL 3, then I opened the issue ticket. Let's say that I want to notice by seeing the failure of the unit test when the OpenSSL.fips_mode
will unintentionally return false
on FIPS enabled system on OpenSSL "4".
IOW I believe it is safe to assume that by default, FIPS is disabled and the OpenSSL.fips_mode == false condition is true.
I still cannot imagine how do you want to change the condition. Could you share your suggestion for the change with the result of the git diff
or diff -u <original_file> <new_file>
for the test/openssl/test_fips.rb
by doing checkout the branch used for this PR in my forked repository? How can the change look like?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My another suggestion is below, removing the ENV["CI"]
from the condition. It can test the assert OpenSSL.fips_mode == false
on local environment outside CI.
$ git diff
diff --git a/test/openssl/test_fips.rb b/test/openssl/test_fips.rb
index dc92bde..e12f1d2 100644
--- a/test/openssl/test_fips.rb
+++ b/test/openssl/test_fips.rb
@@ -5,22 +5,25 @@ if defined?(OpenSSL)
class OpenSSL::TestFIPS < OpenSSL::TestCase
def test_fips_mode_get_is_true_on_fips_mode_enabled
- unless ENV["CI"] && ENV["TEST_RUBY_OPENSSL_FIPS_ENABLED"]
+ unless ENV["TEST_RUBY_OPENSSL_FIPS_ENABLED"]
omit "Only for on FIPS mode environment on CI"
end
assert_separately([{ "OSSL_MDEBUG" => nil }, "-ropenssl"], <<~"end;")
- assert OpenSSL.fips_mode == true, ".fips_mode returns true on FIPS mode enabled"
+ assert OpenSSL.fips_mode == true, ".fips_mode should return true on FIPS mode enabled"
end;
end
def test_fips_mode_get_is_false_on_fips_mode_disabled
- unless ENV["CI"] && !ENV["TEST_RUBY_OPENSSL_FIPS_ENABLED"]
+ if ENV["TEST_RUBY_OPENSSL_FIPS_ENABLED"]
omit "Only for non-FIPS mode environment on CI"
end
assert_separately([{ "OSSL_MDEBUG" => nil }, "-ropenssl"], <<~"end;")
- assert OpenSSL.fips_mode == false, ".fips_mode returns false on FIPS mode disabled"
+ message = ".fips_mode should return false on FIPS mode disabled. " \
+ "If you run the test on FIPS mode, please set " \
+ "TEST_RUBY_OPENSSL_FIPS_ENABLED=true"
+ assert OpenSSL.fips_mode == false, message
end;
end
@@ -35,10 +38,10 @@ class OpenSSL::TestFIPS < OpenSSL::TestCase
assert_separately([{ "OSSL_MDEBUG" => nil }, "-ropenssl"], <<~"end;")
begin
OpenSSL.fips_mode = true
- assert OpenSSL.fips_mode == true, ".fips_mode returns true when .fips_mode=true"
+ assert OpenSSL.fips_mode == true, ".fips_mode should return true when .fips_mode=true"
OpenSSL.fips_mode = false
- assert OpenSSL.fips_mode == false, ".fips_mode returns false when .fips_mode=false"
+ assert OpenSSL.fips_mode == false, ".fips_mode should return false when .fips_mode=false"
rescue OpenSSL::OpenSSLError
pend "Could not set FIPS mode (OpenSSL::OpenSSLError: \#$!); skipping"
end
9acb9b5
to
00fb72f
Compare
I rebased the 2nd commit on this PR. I was able to implement Note that the When I run the The steps I confirmed are below. Install OpenSSL without FIPS option.
Run the
|
def test_fips_mode_get | ||
return unless OpenSSL::OPENSSL_FIPS | ||
def test_fips_mode_get_with_fips_mode_set | ||
omit('OpenSSL is not FIPS-capable') unless OpenSSL::OPENSSL_FIPS |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that I used the message OpenSSL is not FIPS-capable
, because the word "OpenSSL" in the message is used as a meaning of the SSL Library in this context including LibreSSL cases, as well as the "openssl" in this repository name "OpenSSL for Ruby". The word "FIPS-capable" comes from the OpenSSL::OPENSSL_FIPS
's comment: "Boolean indicating whether OpenSSL is FIPS-capable or not".
I see the following error message in the ext/openssl/ossl.c
. So, another candidate of the message is "OpenSSL does not support FIPS mode" to align with the error message.
ossl_raise(eOSSLError, "This version of OpenSSL does not support FIPS mode");
test/openssl/test_fips.rb
Outdated
end | ||
|
||
assert_separately([{ "OSSL_MDEBUG" => nil }, "-ropenssl"], <<~"end;") | ||
assert OpenSSL.fips_mode == true, ".fips_mode returns true on FIPS mode enabled" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't the assert message negated? Shouldn't the assert failure report ".fips_mode returns false on FIPS mode enabled"
instead, because the message is actually displayed when OpenSSL.fips_mode != true
if I am not mistaken.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A good point! The message was partly copied from the exisintg test test_fips_mode_get_with_fips_mode_set
. I think we should replace the "returns" with "should return"?
The change is like this. Ignore the line OpenSSL.fips_mode = false # debug
to print the error message in the debugging purpose.
$ git diff
diff --git a/test/openssl/test_fips.rb b/test/openssl/test_fips.rb
index dc92bde..93243dc 100644
--- a/test/openssl/test_fips.rb
+++ b/test/openssl/test_fips.rb
@@ -10,7 +10,9 @@ class OpenSSL::TestFIPS < OpenSSL::TestCase
end
assert_separately([{ "OSSL_MDEBUG" => nil }, "-ropenssl"], <<~"end;")
- assert OpenSSL.fips_mode == true, ".fips_mode returns true on FIPS mode enabled"
+ OpenSSL.fips_mode = false # debug
+
+ assert OpenSSL.fips_mode == true, ".fips_mode should return true on FIPS mode enabled"
end;
end
@@ -20,7 +22,7 @@ class OpenSSL::TestFIPS < OpenSSL::TestCase
end
assert_separately([{ "OSSL_MDEBUG" => nil }, "-ropenssl"], <<~"end;")
- assert OpenSSL.fips_mode == false, ".fips_mode returns false on FIPS mode disabled"
+ assert OpenSSL.fips_mode == false, ".fips_mode should return false on FIPS mode disabled"
end;
end
@@ -35,10 +37,10 @@ class OpenSSL::TestFIPS < OpenSSL::TestCase
assert_separately([{ "OSSL_MDEBUG" => nil }, "-ropenssl"], <<~"end;")
begin
OpenSSL.fips_mode = true
- assert OpenSSL.fips_mode == true, ".fips_mode returns true when .fips_mode=true"
+ assert OpenSSL.fips_mode == true, ".fips_mode should return true when .fips_mode=true"
OpenSSL.fips_mode = false
- assert OpenSSL.fips_mode == false, ".fips_mode returns false when .fips_mode=false"
+ assert OpenSSL.fips_mode == false, ".fips_mode should return false when .fips_mode=false"
rescue OpenSSL::OpenSSLError
pend "Could not set FIPS mode (OpenSSL::OpenSSLError: \#$!); skipping"
end
Then the result is below. Does this make sense for you?
$ CI=true TEST_RUBY_OPENSSL_FIPS_ENABLED=true LD_LIBRARY_PATH=/home/jaruga/.local/openssl-3.0.8-fips/lib/ OPENSSL_CONF=/home/jaruga/.local/openssl-3.0.8-fips/ssl/openssl_fips.cnf bundle exec ruby test/openssl/test_fips.rb
Loaded suite test/openssl/test_fips
Started
O
==================================================================================================
Omission: Only for non-FIPS mode environment on CI [test_fips_mode_get_is_false_on_fips_mode_disabled(OpenSSL::TestFIPS)]
test/openssl/test_fips.rb:21:in `test_fips_mode_get_is_false_on_fips_mode_disabled'
==================================================================================================
F
==================================================================================================
Failure: test_fips_mode_get_is_true_on_fips_mode_enabled(OpenSSL::TestFIPS):
.fips_mode should return true on FIPS mode enabled.
<false> is not true.
/home/jaruga/var/git/ruby/openssl/test/lib/core_assertions.rb:490:in `assert'
test/openssl/test_fips.rb:15:in `<main>'
test/openssl/test_fips.rb:12:in `test_fips_mode_get_is_true_on_fips_mode_enabled'
9: omit "Only for on FIPS mode environment on CI"
10: end
11:
=> 12: assert_separately([{ "OSSL_MDEBUG" => nil }, "-ropenssl"], <<~"end;")
13: OpenSSL.fips_mode = false # debug
14:
15: assert OpenSSL.fips_mode == true, ".fips_mode should return true on FIPS mode enabled"
==================================================================================================
..
Finished in 0.470415204 seconds.
--------------------------------------------------------------------------------------------------
4 tests, 8 assertions, 1 failures, 0 errors, 0 pendings, 1 omissions, 0 notifications
66.6667% passed
--------------------------------------------------------------------------------------------------
8.50 tests/s, 17.01 assertions/s
I rebased adding the 3rd commit that fixes issues in the review. If it is ok, I will do squash the 3rd commit with the 2nd commit. |
aed2e77
to
c21ddfa
Compare
I squashed the 3rd commit with the 2nd commit, updating the commit message. |
Hello, @rhenium, can you review this PR? Perhaps, can I merge this PR by myself? |
test/openssl/fixtures/ssl/openssl_fips.cnf.tmpl: I referred to the following document for the openssl config file for FIPS mode. <https://www.openssl.org/docs/manmaster/man7/fips_module.html> - Making all applications use the FIPS module by default It seems that the `.include` syntax only requires the absolute path. So, the placeholder OPENSSL_DIR in the template file is replaced with the actual OpenSSL directory. .github/workflows/test.yml: The `TEST_RUBY_OPENSSL_FIPS_ENABLED` environment variable is set in the FIPS mode CI case. It can be used in the unit tests.
This commit is to implement the `OpenSSL::OPENSSL_FIPS`, `ossl_fips_mode_get` and `ossl_fips_mode_set` to pass the test `test/openssl/test_fips.rb`. It seems that the `OPENSSL_FIPS` macro is not used on the FIPS mode case any more, and some FIPS related APIs also were removed in OpenSSL 3. See the document <https://github.com/openssl/openssl/blob/master/doc/man7/migration_guide.pod#removed-fips_mode-and-fips_mode_set> the section OPENSSL 3.0 > Main Changes from OpenSSL 1.1.1 > Other notable deprecations and changes - Removed FIPS_mode() and FIPS_mode_set() . The `OpenSSL::OPENSSL_FIPS` returns always true in OpenSSL 3 because the used functions `EVP_default_properties_enable_fips` and `EVP_default_properties_is_fips_enabled` works with the OpenSSL installed without FIPS option. The `TEST_RUBY_OPENSSL_FIPS_ENABLED` is set on the FIPS mode case on the CI. Because I want to test that the `OpenSSL.fips_mode` returns the `true` or 'false' surely in the CI. You can test the FIPS mode case by setting `TEST_RUBY_OPENSSL_FIPS_ENABLED` on local too. Right now I don't find a better way to get the status of the FIPS mode enabled or disabled for this purpose. I am afraid of the possibility that the FIPS test case is unintentionally skipped. I also replaced the ambiguous "returns" with "should return" in the tests.
According to this Ruby ticket where I didn't see any disagreements, I will start to work as a co-maintainer of the ruby/openssl for FIPS mode. |
This PR includes the 2 commits below.
The 1st commit is to add the latest stable OpenSSL version 3.0.8 FIPS mode to the CI. I was able to create the FIPS mode environment. That means you can create the environment in your local environment too!
The 2nd commit fixes the issue #605 related to the
OpenSSL.fips_mode
(fips_mode_get
). The commit can be also a minimal fix to test the FIPS mode created by the 1st commit.CI: Add OpenSSL FIPS mode case.
I referred to the following documents.
I prepared the OpenSSL config file to enable the FIPS mode:
test/openssl/fixtures/ssl/openssl_fips.cnf.tmpl
that was introduced in the document above.As a reference, if you want to change the default OpenSSL config file (
OPENSSL_INSTALL_DIR/ssl/openssl.cnf
) to enable the FIPS mode, the difference is below for the OpenSSL 3.0.8 config file.Fix the fips_mode_get on OpenSSL 3.
The commit only fixes
OpenSSL.fips_mode
(fips_mode_get
). I think this can be a good start to fixing other issues for OpenSSL 3 FIPS mode in other PRs. The use of theTEST_RUBY_OPENSSL_FIPS_ENABLED
is not the best way. However, I don't know a better way than that right now.The test
test_fips_mode_get
previously passed unintentionally because theOpenSSL::OPENSSL_FIPS
returnsfalse
in the FIPS mode-enabled environment. So, I added the pending message.What do you think? Review, please. Thanks.