Skip to content

Commit

Permalink
Add code to delete certificate from cert_store.
Browse files Browse the repository at this point in the history
Signed-off-by: NAshwini <[email protected]>
  • Loading branch information
NAshwini committed Nov 21, 2017
1 parent f9f53f5 commit bde9dd4
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 1 deletion.
6 changes: 6 additions & 0 deletions lib/win32/certstore.rb
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,12 @@ def add(cert_file_path)
return add
end

def delete(certificate_name)
delete_cert = cert_delete(@certstore_handler, certificate_name)
close
return delete_cert
end

private

attr_reader :certstore_handler
Expand Down
4 changes: 4 additions & 0 deletions lib/win32/certstore/mixin/crypto.rb
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,10 @@ def initialize(str = nil)
safe_attach_function :CertAddEncodedCertificateToStore, [HCERTSTORE, :DWORD, :PWSTR, :DWORD, :INT_PTR, PCCERT_CONTEXT], :BOOL

safe_attach_function :CertSerializeCertificateStoreElement, [PCCERT_CONTEXT, :DWORD, :pointer, :DWORD], :BOOL
# Duplicates a certificate context by incrementing its reference count
safe_attach_function :CertDuplicateCertificateContext, [PCCERT_CONTEXT], PCCERT_CONTEXT
# Delete certification from certification store
safe_attach_function :CertDeleteCertificateFromStore, [PCCERT_CONTEXT], :BOOL
end
end
end
Expand Down
22 changes: 22 additions & 0 deletions lib/win32/certstore/store_base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,26 @@ def cert_add(store_handler, cert_file_path)
end
end

def cert_delete(store_handler, certificate_name)
cert_name = FFI::MemoryPointer.new(2, 128)
begin
while (pCertContext = CertEnumCertificatesInStore(store_handler, pCertContext) and not pCertContext.null? ) do
if (CertGetNameStringW(pCertContext, CERT_NAME_FRIENDLY_DISPLAY_TYPE, CERT_NAME_ISSUER_FLAG, nil,cert_name, 1024) &&
cert_name.read_wstring.downcase == certificate_name.downcase)
if CertDeleteCertificateFromStore(CertDuplicateCertificateContext(pCertContext))
return "Deleted certificate #{certificate_name} successfully"
else
lookup_error
end
end
end
return "Cannot find certificate with name as `#{certificate_name}`. Please re-verify certificate Issuer name or Friendly name"
rescue Exception => e
@error = "delete: "
lookup_error
end
end

private

def lookup_error(failed_operation = nil)
Expand All @@ -73,6 +93,8 @@ def lookup_error(failed_operation = nil)
raise Chef::Exceptions::Win32APIError, "ASN1 bad tag value met. -- Is the certificate in DER format?"
when -2146881278
raise Chef::Exceptions::Win32APIError, "ASN1 unexpected end of data."
when -2147024891
raise Chef::Exceptions::Win32APIError, "System.UnauthorizedAccessException, Access denied.."
else
raise Chef::Exceptions::Win32APIError, "Unable to #{failed_operation} certificate with error: #{last_error}."
end
Expand Down
45 changes: 44 additions & 1 deletion spec/win32/unit/certstore_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,46 @@
end
end

context "When deleting valid certificate" do
let (:store_name) { "ca" }
let (:certificate_name) { 'GeoTrust Global CA' }
before(:each) do
allow_any_instance_of(certbase).to receive(:CertDeleteCertificateFromStore).and_return(true)
end
it "return message of successful deletion" do
store = certstore.open(store_name)
delete_cert = store.delete(certificate_name)
expect(delete_cert).to eq("Deleted certificate GeoTrust Global CA successfully")
end
end

context "When deleting invalid certificate" do
let (:store_name) { "my" }
let (:certificate_name) { "tmp_cert.mydomain.com" }
it "return message of `Cannot find certificate`" do
allow(certbase).to receive(:CertDeleteCertificateFromStore).and_return(false)
store = certstore.open(store_name)
delete_cert = store.delete(certificate_name)
expect(delete_cert).to eq("Cannot find certificate with name as `tmp_cert.mydomain.com`. Please re-verify certificate Issuer name or Friendly name")
end
end

context "When passing empty certificate_name to delete it" do
let (:store_name) { "my" }
let (:certificate_name) { "" }
it "return message of `Cannot find certificate`" do
allow(certbase).to receive(:CertDeleteCertificateFromStore).and_return(false)
store = certstore.open(store_name)
delete_cert = store.delete(certificate_name)
expect(delete_cert).to eq("Cannot find certificate with name as ``. Please re-verify certificate Issuer name or Friendly name")
end
end

context "When adding certificate failed with FFI::LastError" do
let (:store_name) { "root" }
let (:cert_file_path) { '.\win32\unit\assets\test.cer' }

let (:certificate_name) { 'GlobalSign' }

it "returns 'The operation was canceled by the user'" do
allow(certbase).to receive(:CertAddEncodedCertificateToStore).and_return(false)
allow(FFI::LastError).to receive(:error).and_return(1223)
Expand Down Expand Up @@ -107,6 +143,13 @@
store = certstore.open(store_name)
expect { store.add(cert_file_path) }.to raise_error("ASN1 unexpected end of data.")
end

it "return 'System.UnauthorizedAccessException, Access denied..'" do
allow(certbase).to receive(:CertDeleteCertificateFromStore).and_return(false)
allow(FFI::LastError).to receive(:error).and_return(-2147024891)
store = certstore.open(store_name)
expect { store.delete(certificate_name) }.to raise_error(Chef::Exceptions::Win32APIError)
end
end
end
end

0 comments on commit bde9dd4

Please sign in to comment.