mirror of
https://github.com/inspec/inspec
synced 2025-02-18 15:08:44 +00:00
Adds class iaf_file to validate the signed profile
Signed-off-by: Vasu1105 <vasundhara.jagdale@chef.io>
This commit is contained in:
parent
89aaa621d4
commit
6b7041376a
4 changed files with 94 additions and 124 deletions
|
@ -2,7 +2,7 @@ require "rubygems/package" unless defined?(Gem::Package)
|
||||||
require "pathname" unless defined?(Pathname)
|
require "pathname" unless defined?(Pathname)
|
||||||
require "zlib" unless defined?(Zlib)
|
require "zlib" unless defined?(Zlib)
|
||||||
require "zip" unless defined?(Zip)
|
require "zip" unless defined?(Zip)
|
||||||
require "inspec/verify_signature"
|
require "inspec/iaf_file"
|
||||||
|
|
||||||
module Inspec
|
module Inspec
|
||||||
class FileProvider
|
class FileProvider
|
||||||
|
@ -15,8 +15,13 @@ module Inspec
|
||||||
TarProvider.new(path)
|
TarProvider.new(path)
|
||||||
elsif File.exist?(path) && path.end_with?(".zip")
|
elsif File.exist?(path) && path.end_with?(".zip")
|
||||||
ZipProvider.new(path)
|
ZipProvider.new(path)
|
||||||
elsif File.exist?(path) && path.end_with?(".iaf") && VerifySignature.valid(path)
|
elsif File.exist?(path) && path.end_with?(".iaf")
|
||||||
IafProvider.new(path)
|
iaf_file = IafFile.new(path)
|
||||||
|
if iaf_file.valid?
|
||||||
|
IafProvider.new(path)
|
||||||
|
else
|
||||||
|
raise "Artifact is invalid"
|
||||||
|
end
|
||||||
elsif File.exist?(path)
|
elsif File.exist?(path)
|
||||||
DirProvider.new(path)
|
DirProvider.new(path)
|
||||||
else
|
else
|
||||||
|
@ -230,15 +235,15 @@ module Inspec
|
||||||
content = f.read
|
content = f.read
|
||||||
f.close
|
f.close
|
||||||
else
|
else
|
||||||
key = f.readline.strip!
|
f.readline.strip!
|
||||||
content = f.read
|
content = f.read[358..content.length]
|
||||||
f.close
|
f.close
|
||||||
end
|
end
|
||||||
|
|
||||||
tmpfile = nil
|
tmpfile = nil
|
||||||
Dir.mktmpdir do |workdir|
|
Dir.mktmpdir do |workdir|
|
||||||
tmpfile = Pathname.new(workdir).join("artifact_to_install.tar.gz")
|
tmpfile = Pathname.new(workdir).join("artifact_to_install.tar.gz")
|
||||||
File.open(tmpfile, "wb") { |fl| fl.write(content[358..content.length]) }
|
File.open(tmpfile, "wb") { |fl| fl.write(content) }
|
||||||
super(tmpfile)
|
super(tmpfile)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
77
lib/inspec/iaf_file.rb
Normal file
77
lib/inspec/iaf_file.rb
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
require "base64" unless defined?(Base64)
|
||||||
|
require "openssl" unless defined?(OpenSSL)
|
||||||
|
|
||||||
|
# TODO: Refactor this once the binary format work gets merged.
|
||||||
|
module Inspec
|
||||||
|
class IafFile
|
||||||
|
KEY_ALG = OpenSSL::PKey::RSA
|
||||||
|
INSPEC_PROFILE_VERSION_1 = "INSPEC-PROFILE-1".freeze
|
||||||
|
INSPEC_PROFILE_VERSION_2 = "INSPEC-PROFILE-2".freeze
|
||||||
|
|
||||||
|
ARTIFACT_DIGEST = OpenSSL::Digest::SHA512
|
||||||
|
ARTIFACT_DIGEST_NAME = "SHA512".freeze
|
||||||
|
|
||||||
|
VALID_PROFILE_VERSIONS = Set.new [INSPEC_PROFILE_VERSION_1, INSPEC_PROFILE_VERSION_2]
|
||||||
|
VALID_PROFILE_DIGESTS = Set.new [ARTIFACT_DIGEST_NAME]
|
||||||
|
|
||||||
|
def initialize(path)
|
||||||
|
@path = path
|
||||||
|
end
|
||||||
|
|
||||||
|
def valid?
|
||||||
|
header = []
|
||||||
|
valid = true
|
||||||
|
f = File.open(@path, "rb")
|
||||||
|
version = f.readline.strip!
|
||||||
|
if version == INSPEC_PROFILE_VERSION_1
|
||||||
|
header << version
|
||||||
|
header << f.readline.strip!
|
||||||
|
header << f.readline.strip!
|
||||||
|
|
||||||
|
file_sig = ""
|
||||||
|
# the signature is multi-line
|
||||||
|
while (line = f.readline) != "\n"
|
||||||
|
file_sig += line
|
||||||
|
end
|
||||||
|
header << file_sig.strip!
|
||||||
|
f.close
|
||||||
|
|
||||||
|
f = File.open(@path, "rb")
|
||||||
|
while f.readline != "\n" do end
|
||||||
|
content = f.read
|
||||||
|
f.close
|
||||||
|
elsif version == INSPEC_PROFILE_VERSION_2
|
||||||
|
header << version
|
||||||
|
header << f.readline.strip!
|
||||||
|
content = f.read
|
||||||
|
f.close
|
||||||
|
|
||||||
|
header.concat(content[0..356].unpack("h*").pack("H*").split("."))
|
||||||
|
content = content[358..content.length]
|
||||||
|
else
|
||||||
|
valid = false
|
||||||
|
end
|
||||||
|
|
||||||
|
unless File.exist?("#{header[1]}.pem.pub")
|
||||||
|
raise "Key not found"
|
||||||
|
end
|
||||||
|
|
||||||
|
unless valid_header?(header)
|
||||||
|
valid = false
|
||||||
|
end
|
||||||
|
|
||||||
|
verification_key = KEY_ALG.new File.read "#{header[1]}.pem.pub"
|
||||||
|
signature = Base64.decode64(header[3])
|
||||||
|
digest = ARTIFACT_DIGEST.new
|
||||||
|
unless verification_key.verify digest, signature, content
|
||||||
|
valid = false
|
||||||
|
end
|
||||||
|
|
||||||
|
valid
|
||||||
|
end
|
||||||
|
|
||||||
|
def valid_header?(header)
|
||||||
|
VALID_PROFILE_VERSIONS.member?(header[0]) && VALID_PROFILE_DIGESTS.member?(header[2])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,62 +0,0 @@
|
||||||
require "base64" unless defined?(Base64)
|
|
||||||
require "openssl" unless defined?(OpenSSL)
|
|
||||||
|
|
||||||
# TODO: Refactor this once the binary format work gets merged.
|
|
||||||
module Inspec
|
|
||||||
class VerifySignature
|
|
||||||
def self.valid(path)
|
|
||||||
# Validates the file using key authentication. Currently it look for the key file in the current working directory.
|
|
||||||
|
|
||||||
f = File.open(path, "rb")
|
|
||||||
version = f.readline.strip!
|
|
||||||
header = []
|
|
||||||
header << version
|
|
||||||
|
|
||||||
if version == "INSPEC-PROFILE-1"
|
|
||||||
header << f.readline.strip!
|
|
||||||
header << f.readline.strip!
|
|
||||||
|
|
||||||
file_sig = ""
|
|
||||||
# the signature is multi-line
|
|
||||||
while (line = f.readline) != "\n"
|
|
||||||
file_sig += line
|
|
||||||
end
|
|
||||||
header << file_sig.strip!
|
|
||||||
f.close
|
|
||||||
|
|
||||||
f = File.open(path, "rb")
|
|
||||||
while f.readline != "\n" do end
|
|
||||||
content = f.read
|
|
||||||
f.close
|
|
||||||
elsif version == "INSPEC-PROFILE-2"
|
|
||||||
header << f.readline.strip!
|
|
||||||
content = f.read
|
|
||||||
f.close
|
|
||||||
|
|
||||||
header.concat(content[0..356].unpack("h*").pack("H*").split("."))
|
|
||||||
content = content[358..content.length]
|
|
||||||
else
|
|
||||||
raise "Invalid artifact version detected."
|
|
||||||
end
|
|
||||||
|
|
||||||
unless %w{INSPEC-PROFILE-1 INSPEC-PROFILE-2}.member?(header[0]) && ["SHA512"].member?(header[2])
|
|
||||||
raise "Artifact is invalid"
|
|
||||||
end
|
|
||||||
|
|
||||||
if File.exist? "#{header[1]}.pem.pub"
|
|
||||||
verification_key = OpenSSL::PKey::RSA.new File.read "#{header[1]}.pem.pub"
|
|
||||||
else
|
|
||||||
raise "Can't find #{header[1]}.pem.pub}"
|
|
||||||
end
|
|
||||||
|
|
||||||
signature = Base64.decode64(header[3])
|
|
||||||
digest = OpenSSL::Digest.new("SHA512")
|
|
||||||
|
|
||||||
if verification_key.verify(digest, signature, content)
|
|
||||||
true
|
|
||||||
else
|
|
||||||
raise "Artifact is invalid"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -6,6 +6,7 @@ require "tempfile" unless defined?(Tempfile)
|
||||||
require "yaml"
|
require "yaml"
|
||||||
require "inspec/dist"
|
require "inspec/dist"
|
||||||
require "inspec/utils/json_profile_summary"
|
require "inspec/utils/json_profile_summary"
|
||||||
|
require "inspec/iaf_file"
|
||||||
|
|
||||||
module InspecPlugins
|
module InspecPlugins
|
||||||
module Sign
|
module Sign
|
||||||
|
@ -59,7 +60,7 @@ module InspecPlugins
|
||||||
# convert the signature to Base64
|
# convert the signature to Base64
|
||||||
signature_base64 = Base64.encode64(signature)
|
signature_base64 = Base64.encode64(signature)
|
||||||
|
|
||||||
header = "#{ARTIFACT_DIGEST_NAME}.#{signature_base64}".unpack("H*").pack("h*")+".#{content}"
|
header = "#{ARTIFACT_DIGEST_NAME}.#{signature_base64}".unpack("H*").pack("h*") + ".#{content}"
|
||||||
File.open(artifact_filename, "wb") do |f|
|
File.open(artifact_filename, "wb") do |f|
|
||||||
f.puts INSPEC_PROFILE_VERSION_2
|
f.puts INSPEC_PROFILE_VERSION_2
|
||||||
f.puts "#{options["keyname"]}"
|
f.puts "#{options["keyname"]}"
|
||||||
|
@ -73,12 +74,14 @@ module InspecPlugins
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.profile_verify(options)
|
def self.profile_verify(options)
|
||||||
artifact = new
|
|
||||||
file_to_verifiy = options["signed_profile"]
|
file_to_verifiy = options["signed_profile"]
|
||||||
puts "Verifying #{file_to_verifiy}"
|
puts "Verifying #{file_to_verifiy}"
|
||||||
|
|
||||||
artifact.verify(file_to_verifiy) do ||
|
iaf_file = Inspec::IafFile.new(file_to_verifiy)
|
||||||
|
if iaf_file.valid?
|
||||||
puts "Artifact is valid"
|
puts "Artifact is valid"
|
||||||
|
else
|
||||||
|
puts "Artifact is invalid"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -116,59 +119,6 @@ module InspecPlugins
|
||||||
outfile_name
|
outfile_name
|
||||||
end
|
end
|
||||||
|
|
||||||
def verify(file_to_verifiy, &content_block)
|
|
||||||
header = []
|
|
||||||
f = File.open(file_to_verifiy, "rb")
|
|
||||||
version = f.readline.strip!
|
|
||||||
if version == INSPEC_PROFILE_VERSION_1
|
|
||||||
header << version
|
|
||||||
header << f.readline.strip!
|
|
||||||
header << f.readline.strip!
|
|
||||||
|
|
||||||
file_sig = ""
|
|
||||||
# the signature is multi-line
|
|
||||||
while (line = f.readline) != "\n"
|
|
||||||
file_sig += line
|
|
||||||
end
|
|
||||||
header << file_sig.strip!
|
|
||||||
f.close
|
|
||||||
|
|
||||||
f = File.open(file_to_verifiy, "rb")
|
|
||||||
while f.readline != "\n" do end
|
|
||||||
content = f.read
|
|
||||||
f.close
|
|
||||||
elsif version == INSPEC_PROFILE_VERSION_2
|
|
||||||
header << version
|
|
||||||
header << f.readline.strip!
|
|
||||||
content = f.read
|
|
||||||
f.close
|
|
||||||
|
|
||||||
header.concat(content[0..356].unpack("h*").pack("H*").split("."))
|
|
||||||
content = content[358..content.length]
|
|
||||||
else
|
|
||||||
raise "Invalid artifact version detected."
|
|
||||||
end
|
|
||||||
|
|
||||||
valid_header?(header)
|
|
||||||
verification_key = KEY_ALG.new File.read "#{header[1]}.pem.pub"
|
|
||||||
signature = Base64.decode64(header[3])
|
|
||||||
digest = ARTIFACT_DIGEST.new
|
|
||||||
if verification_key.verify digest, signature, content
|
|
||||||
content_block.yield(content)
|
|
||||||
else
|
|
||||||
raise "Artifact is invalid"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def valid_header?(header)
|
|
||||||
unless File.exist? "#{header[1]}.pem.pub"
|
|
||||||
raise "Can't find #{header[1]}.pem.pub}"
|
|
||||||
end
|
|
||||||
|
|
||||||
raise "Invalid artifact version detected" unless VALID_PROFILE_VERSIONS.member?(header[0])
|
|
||||||
raise "Invalid artifact digest algorithm detected" unless VALID_PROFILE_DIGESTS.member?(header[2])
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.write_inspec_json(root_path, opts)
|
def self.write_inspec_json(root_path, opts)
|
||||||
profile = Inspec::Profile.for_path(root_path, opts)
|
profile = Inspec::Profile.for_path(root_path, opts)
|
||||||
Inspec::Utils::JsonProfileSummary.produce_json(
|
Inspec::Utils::JsonProfileSummary.produce_json(
|
||||||
|
|
Loading…
Add table
Reference in a new issue