Skip to content

Commit

Permalink
MSYS-547 Added feature to verify certificate from certificate store
Browse files Browse the repository at this point in the history
Signed-off-by: piyushawasthi <[email protected]>
  • Loading branch information
piyushawasthi committed Mar 23, 2018
1 parent dbe159a commit 43995fc
Show file tree
Hide file tree
Showing 4 changed files with 111 additions and 1 deletion.
5 changes: 5 additions & 0 deletions lib/win32/certstore.rb
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,11 @@ def search(certificate_name)
cert_search(certstore_handler, certificate_name)
end

# Validate certificate from open certificate store and return boolean
def verify(certificate_name)
cert_verify(certstore_handler, certificate_name)
end

# To close and destroy pointer of open certificate store handler
def close
closed = CertCloseStore(@certstore_handler, CERT_CLOSE_STORE_FORCE_FLAG)
Expand Down
7 changes: 7 additions & 0 deletions lib/win32/certstore/mixin/helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.

require 'date'

module Win32
class Certstore
module Mixin
Expand All @@ -35,6 +37,11 @@ def cert_ps_cmd(thumbprint)
}
$content"
end

# validate certificate not_before and not_after date in UTC
def valid_duration(cert_obj)
cert_obj.not_before < Time.now.utc && cert_obj.not_after > Time.now.utc
end
end
end
end
Expand Down
17 changes: 17 additions & 0 deletions lib/win32/certstore/store_base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,17 @@ def cert_delete(store_handler, certificate_thumbprint)
end
end

# Verify certificate from open certificate store and return boolean or exceptions
# store_handler => Open certificate store handler
# certificate_thumbprint => thumbprint is a hash. which could be sha1 or md5.
def cert_verify(store_handler, certificate_thumbprint)
validate_thumbprint(certificate_thumbprint)
thumbprint = update_thumbprint(certificate_thumbprint)
cert_pem = get_cert_pem(thumbprint)
cert_pem = format_pem(cert_pem)
verify_certificate(cert_pem)
end

private

# Build arguments for CertAddEncodedCertificateToStore
Expand All @@ -116,6 +127,12 @@ def update_thumbprint(certificate_thumbprint)
certificate_thumbprint.gsub(/[^A-Za-z0-9]/, '')
end

# Verify OpenSSL::X509::Certificate object
def verify_certificate(cert_pem)
return "Certificate not found" if cert_pem.empty?
valid_duration(build_openssl_obj(cert_pem))
end

# Convert OpenSSL::X509::Certificate object in .der formate
def der_cert(cert_obj)
FFI::MemoryPointer.from_string(cert_obj.to_der)
Expand Down
83 changes: 82 additions & 1 deletion spec/win32/unit/certstore_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,6 @@
expect(cert_obj.not_after.to_s).to eql("2028-01-28 12:00:00 UTC")
end
end

end

describe "Perform more than one operations with single certstore object" do
Expand All @@ -208,6 +207,88 @@
end
end

describe "#cert_verify" do
context "When passing empty certificate store name" do
let (:store_name) { "" }
it "raises ArgumentError" do
expect { certstore.open(store_name) }.to raise_error("Invalid Certificate Store.")
end
end

context "When passing empty thumbprint" do
let (:store_name) { "root" }
let (:thumbprint) { " " }
it "raises ArgumentError" do
store = certstore.open(store_name)
expect { store.verify(thumbprint) }.to raise_error("Invalid certificate thumbprint.")
end
end

context "When passing thumbprint is nil" do
let (:store_name) { "root" }
let (:thumbprint) { nil }
it "raises ArgumentError" do
store = certstore.open(store_name)
expect { store.verify(thumbprint) }.to raise_error("Invalid certificate thumbprint.")
end
end

context "When passing invalid thumbprint" do
let (:store_name) { "root" }
let (:thumbprint) { "b1bc968bd4f49d622aa89a81f2150152a41d829c" }
before(:each) do
allow_any_instance_of(certbase).to receive(:get_cert_pem).and_return([])
end
it "returns Certificate not found" do
store = certstore.open(store_name)
cert_obj = store.verify(thumbprint)
expect(cert_obj).to eql("Certificate not found")
end
end

context "When passing valid thumbprint" do
let (:store_name) { "root" }
let (:thumbprint) { "b1bc968bd4f49d622aa89a81f2150152a41d829909c" }
let (:cert_pem) { File.read('.\spec\win32\unit\assets\GlobalSignRootCA.pem') }
before(:each) do
allow_any_instance_of(certbase).to receive(:get_cert_pem).and_return([cert_pem])
end
it "returns OpenSSL::X509::Certificate Object" do
store = certstore.open(store_name)
cert_obj = store.verify(thumbprint)
expect(cert_obj).to eql(true)
end
end

context "When passing valid thumbprint with spaces" do
let (:store_name) { "root" }
let (:thumbprint) { "b1 bc 96 8b d4 f4 9d 62 2a a8 9a 81 f2 15 01 52 a4 1d 82 9c" }
let (:cert_pem) { File.read('.\spec\win32\unit\assets\GlobalSignRootCA.pem') }
before(:each) do
allow_any_instance_of(certbase).to receive(:get_cert_pem).and_return([cert_pem])
end
it "returns OpenSSL::X509::Certificate Object" do
store = certstore.open(store_name)
cert_obj = store.verify(thumbprint)
expect(cert_obj).to eql(true)
end
end

context "When passing valid thumbprint with :" do
let (:store_name) { "root" }
let (:thumbprint) { "b1:bc:96:8b:d4:f4:9d:62:2a:a8:9a:81:f2:15:01:52:a4:1d:82:9c" }
let (:cert_pem) { File.read('.\spec\win32\unit\assets\GlobalSignRootCA.pem') }
before(:each) do
allow_any_instance_of(certbase).to receive(:get_cert_pem).and_return([cert_pem])
end
it "returns OpenSSL::X509::Certificate Object" do
store = certstore.open(store_name)
cert_obj = store.verify(thumbprint)
expect(cert_obj).to eql(true)
end
end
end

describe "#Failed with FFI::LastError" do
context "While adding or deleting or retrieving certificate" do
let (:store_name) { "root" }
Expand Down

0 comments on commit 43995fc

Please sign in to comment.