From 6b7041376a5bd3df7363933c9240feccbd84e0e5 Mon Sep 17 00:00:00 2001 From: Vasu1105 Date: Wed, 27 Apr 2022 17:31:38 +0530 Subject: [PATCH] Adds class iaf_file to validate the signed profile Signed-off-by: Vasu1105 --- lib/inspec/file_provider.rb | 17 ++-- lib/inspec/iaf_file.rb | 77 +++++++++++++++++++ lib/inspec/verify_signature.rb | 62 --------------- .../inspec-sign/lib/inspec-sign/base.rb | 62 ++------------- 4 files changed, 94 insertions(+), 124 deletions(-) create mode 100644 lib/inspec/iaf_file.rb delete mode 100644 lib/inspec/verify_signature.rb diff --git a/lib/inspec/file_provider.rb b/lib/inspec/file_provider.rb index c786d2c3c..bc466f96d 100644 --- a/lib/inspec/file_provider.rb +++ b/lib/inspec/file_provider.rb @@ -2,7 +2,7 @@ require "rubygems/package" unless defined?(Gem::Package) require "pathname" unless defined?(Pathname) require "zlib" unless defined?(Zlib) require "zip" unless defined?(Zip) -require "inspec/verify_signature" +require "inspec/iaf_file" module Inspec class FileProvider @@ -15,8 +15,13 @@ module Inspec TarProvider.new(path) elsif File.exist?(path) && path.end_with?(".zip") ZipProvider.new(path) - elsif File.exist?(path) && path.end_with?(".iaf") && VerifySignature.valid(path) - IafProvider.new(path) + elsif File.exist?(path) && path.end_with?(".iaf") + iaf_file = IafFile.new(path) + if iaf_file.valid? + IafProvider.new(path) + else + raise "Artifact is invalid" + end elsif File.exist?(path) DirProvider.new(path) else @@ -230,15 +235,15 @@ module Inspec content = f.read f.close else - key = f.readline.strip! - content = f.read + f.readline.strip! + content = f.read[358..content.length] f.close end tmpfile = nil Dir.mktmpdir do |workdir| 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) end end diff --git a/lib/inspec/iaf_file.rb b/lib/inspec/iaf_file.rb new file mode 100644 index 000000000..cc8666cef --- /dev/null +++ b/lib/inspec/iaf_file.rb @@ -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 diff --git a/lib/inspec/verify_signature.rb b/lib/inspec/verify_signature.rb deleted file mode 100644 index fe34a42e6..000000000 --- a/lib/inspec/verify_signature.rb +++ /dev/null @@ -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 diff --git a/lib/plugins/inspec-sign/lib/inspec-sign/base.rb b/lib/plugins/inspec-sign/lib/inspec-sign/base.rb index 29807f801..87281cf36 100644 --- a/lib/plugins/inspec-sign/lib/inspec-sign/base.rb +++ b/lib/plugins/inspec-sign/lib/inspec-sign/base.rb @@ -6,6 +6,7 @@ require "tempfile" unless defined?(Tempfile) require "yaml" require "inspec/dist" require "inspec/utils/json_profile_summary" +require "inspec/iaf_file" module InspecPlugins module Sign @@ -59,7 +60,7 @@ module InspecPlugins # convert the signature to Base64 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| f.puts INSPEC_PROFILE_VERSION_2 f.puts "#{options["keyname"]}" @@ -73,12 +74,14 @@ module InspecPlugins end def self.profile_verify(options) - artifact = new file_to_verifiy = options["signed_profile"] 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" + else + puts "Artifact is invalid" end end @@ -116,59 +119,6 @@ module InspecPlugins outfile_name 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) profile = Inspec::Profile.for_path(root_path, opts) Inspec::Utils::JsonProfileSummary.produce_json(