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

Make the shard plugin work under FIPS by using SHA2 instead of MD5 #1175

Merged
merged 8 commits into from
May 3, 2018
60 changes: 55 additions & 5 deletions lib/ohai/plugins/shard.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,8 @@
#

Ohai.plugin(:ShardSeed) do
require "digest/md5"
depends "hostname", "dmi", "machine_id", "machinename"
depends "hostname", "dmi", "machine_id", "machinename", "fips", "hardware", "kernel"
provides "shard_seed"
optional true

def get_dmi_property(dmi, thing)
%w{system base_board chassis}.each do |section|
Expand All @@ -31,7 +29,33 @@ def get_dmi_property(dmi, thing)
end

def default_sources
[:machinename, :serial, :uuid]
case collect_os
when :linux, :darwin, :windows
[:machinename, :serial, :uuid]
else
[:machinename]
end
end

def default_digest_algorithm
if fips["kernel"]["enabled"]
# Even though it is being used safely, FIPS-mode will still blow up on
# any use of MD5 so default to SHA2 instead.
"sha256"
else
"md5"
end
end

def digest_algorithm
case Ohai.config[:plugin][:shard_seed][:digest_algorithm] || default_digest_algorithm
when "md5"
require "digest/md5"
Digest::MD5
when "sha256"
require "digest/sha2"
Digest::SHA256
end
end

# Common sources go here. Put sources that need to be different per-platform
Expand All @@ -53,7 +77,31 @@ def create_seed(&block)
yield(src)
end
end
shard_seed Digest::MD5.hexdigest(data)[0...7].to_i(16)
shard_seed digest_algorithm.hexdigest(data)[0...7].to_i(16)
end

collect_data do
create_seed do |src|
raise "No such shard_seed source: #{src}"
end
end

collect_data(:windows) do
require "wmi-lite/wmi"
wmi = WmiLite::Wmi.new

create_seed do |src|
case src
when :serial
wmi.first_of("Win32_BIOS")["SerialNumber"]
when :os_serial
kernel["os_info"]["serial_number"]
when :uuid
wmi.first_of("Win32_ComputerSystemProduct")["UUID"]
else
raise "No such shard_seed source: #{src}"
end
end
end

collect_data(:darwin) do
Expand All @@ -63,6 +111,8 @@ def create_seed(&block)
hardware["serial_number"]
when :uuid
hardware["platform_UUID"]
else
raise "No such shard_seed source: #{src}"
end
end
end
Expand Down
80 changes: 69 additions & 11 deletions spec/unit/plugins/shard_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,35 +26,93 @@
let(:serial) { "234du3m4i498xdjr2" }
let(:machine_id) { "0a1f869f457a4c8080ab19faf80af9cc" }
let(:machinename) { "somehost004" }
let(:fips) { false }
let(:os) { :linux }

subject do
plugin.run
plugin[:shard_seed]
end

before(:each) do
allow(plugin).to receive(:collect_os).and_return(:linux)
plugin["machinename"] = machinename
plugin["machine_id"] = machine_id
plugin["fqdn"] = fqdn
plugin["dmi"] = { "system" => {} }
plugin["dmi"]["system"]["uuid"] = uuid
plugin["dmi"]["system"]["serial_number"] = serial
allow(plugin).to receive(:collect_os).and_return(:linux)
plugin["fips"] = { "kernel" => { "enabled" => fips } }
allow(plugin).to receive(:collect_os).and_return(os)
end

it "should provide a shard with a default-safe set of sources" do
plugin.run
result = Digest::MD5.hexdigest(
"#{machinename}#{serial}#{uuid}"
)[0...7].to_i(16)
expect(plugin[:shard_seed]).to eq(result)
expect(subject).to eq(27767217)
end

it "should provide a shard with a configured source" do
Ohai.config[:plugin][:shard_seed][:sources] = [:fqdn]
plugin.run
result = Digest::MD5.hexdigest(fqdn)[0...7].to_i(16)
expect(plugin[:shard_seed]).to eq(result)
expect(subject).to eq(203669792)
end

it "fails on an unrecognized source" do
Ohai.config[:plugin][:shard_seed][:sources] = [:GreatGooglyMoogly]
expect { plugin.run }.to raise_error(RuntimeError)
expect { subject }.to raise_error(RuntimeError)
end

it "should provide a shard with a configured algorithm" do
Ohai.config[:plugin][:shard_seed][:digest_algorithm] = "sha256"
expect(Digest::MD5).to_not receive(:new)
expect(subject).to eq(117055036)
end

context "with Darwin OS" do
let(:os) { :darwin }
before do
plugin["hardware"] = { "serial_number" => serial, "platform_UUID" => uuid }
end

it "should provide a shard with a default-safe set of sources" do
expect(subject).to eq(27767217)
end
end

context "with Windows OS" do
let(:os) { :windows }
before do
wmi = double("WmiLite::Wmi")
allow(WmiLite::Wmi).to receive(:new).and_return(wmi)
allow(wmi).to receive(:first_of).with("Win32_BIOS").and_return("SerialNumber" => serial)
allow(wmi).to receive(:first_of).with("Win32_ComputerSystemProduct").and_return("UUID" => uuid)
plugin["kernel"] = { "os_info" => { "serial_number" => serial + "0" } }
plugin.data.delete("dmi") # To make sure we aren't using the wrong data.
end

it "should provide a shard with a default-safe set of sources" do
expect(subject).to eq(27767217)
end

it "should allow os_serial source" do
Ohai.config[:plugin][:shard_seed][:sources] = [:machinename, :os_serial, :uuid]
# Different from above.
expect(subject).to eq(178738102)
end
end

context "with a weird OS" do
let(:os) { :aix }

it "should provide a shard with a default-safe set of sources" do
# Note: this is different than the other defaults.
expect(subject).to eq(253499154)
Copy link
Collaborator

Choose a reason for hiding this comment

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

above you raise an error in the default case

Copy link
Collaborator

Choose a reason for hiding this comment

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

Oh, nevermind, only if it's not one of the default ones.

end
end

context "with FIPS mode enabled" do
let(:fips) { true }

it "should use SHA2" do
expect(Digest::MD5).to_not receive(:new)
expect(subject).to eq(117055036)
end
end
end