module Win32::Certstore::StoreBase

Public Instance Methods

cert_add(store_handler, certificate_obj) click to toggle source

Adding new certification in open certificate and return boolean store_handler => Open certificate store handler certificate_obj => certificate object must be in OpenSSL::X509

# File lib/win32/certstore/store_base.rb, line 38
def cert_add(store_handler, certificate_obj)
  validate_certificate_obj(certificate_obj)
  begin
    cert_args = cert_add_args(store_handler, certificate_obj)
    if CertAddEncodedCertificateToStore(*cert_args)
      true
    else
      lookup_error
    end
  rescue
    lookup_error("add")
  end
end
cert_add_pfx(certstore_handler, path, password = "", key_properties = 0) click to toggle source

Adds a PFX certificate to certificate store

@see docs.microsoft.com/en-us/windows/desktop/api/wincrypt/nf-wincrypt-pfximportcertstore PFXImportCertStore function @see docs.microsoft.com/en-us/windows/desktop/api/wincrypt/nf-wincrypt-certaddcertificatecontexttostore CertAddCertificateContextToStore

@param certstore_handler [FFI::Pointer] Handle of the store where certificate should be imported @param path [String] Path of the certificate that should be imported @param password [String] Password of the certificate @param key_properties [Integer] dwFlags used to specify properties of the pfx key, see link above

@return [Boolean]

@raise [SystemCallError] when Crypt API would not be able to perform some action

# File lib/win32/certstore/store_base.rb, line 66
def cert_add_pfx(certstore_handler, path, password = "", key_properties = 0)
  cert_added = false
  # Imports a PFX BLOB and returns the handle of a store
  pfx_cert_store = PFXImportCertStore(CRYPT_DATA_BLOB.new(File.binread(path)), wstring(password), key_properties)
  raise if pfx_cert_store.null?

  # Find all the certificate contexts in certificate store and add them ino the store
  while (cert_context = CertEnumCertificatesInStore(pfx_cert_store, cert_context)) && (not cert_context.null?)
    # Add certificate context to the certificate store
    args = add_certcontxt_args(certstore_handler, cert_context)
    cert_added = CertAddCertificateContextToStore(*args)
    raise unless cert_added
  end
  cert_added
rescue
  lookup_error("Add a PFX")
ensure
  if pfx_cert_store && !pfx_cert_store.null?
    close_cert_store(pfx_cert_store)
  end
end
cert_delete(store_handler, certificate_thumbprint) click to toggle source

Deleting certificate from open certificate store and return boolean store_handler => Open certificate store handler certificate_thumbprint => thumbprint is a hash. which could be sha1 or md5.

# File lib/win32/certstore/store_base.rb, line 125
def cert_delete(store_handler, certificate_thumbprint)
  validate_thumbprint(certificate_thumbprint)
  thumbprint = update_thumbprint(certificate_thumbprint)
  cert_delete_flag = false
  begin
    cert_args = cert_find_args(store_handler, thumbprint)
    pcert_context = CertFindCertificateInStore(*cert_args)
    unless pcert_context.null?
      cert_delete_flag = CertDeleteCertificateFromStore(CertDuplicateCertificateContext(pcert_context)) || lookup_error
    end
    CertFreeCertificateContext(pcert_context)
  rescue
    lookup_error("delete")
  end
  cert_delete_flag
end
cert_get(certificate_thumbprint, store_name:, store_location:) click to toggle source

Get certificate from open certificate store and return certificate object certificate_thumbprint => thumbprint is a hash. which could be sha1 or md5.

# File lib/win32/certstore/store_base.rb, line 90
def cert_get(certificate_thumbprint, store_name:, store_location:)
  validate_thumbprint(certificate_thumbprint)
  thumbprint = update_thumbprint(certificate_thumbprint)
  cert_pem = get_cert_pem(thumbprint, store_name: store_name, store_location: store_location)
  cert_pem = format_pem(cert_pem)
  if cert_pem.empty?
    raise ArgumentError, "Unable to retrieve the certificate"
  end

  unless cert_pem.empty?
    build_openssl_obj(cert_pem)
  end
end
cert_list(store_handler) click to toggle source

Listing certificate of open certstore and return list in json

# File lib/win32/certstore/store_base.rb, line 105
def cert_list(store_handler)
  cert_name = memory_ptr
  cert_list = []
  begin
    while (pcert_context = CertEnumCertificatesInStore(store_handler, pcert_context)) && (not pcert_context.null?)
      cert_args = cert_get_name_args(pcert_context, cert_name, CERT_NAME_FRIENDLY_DISPLAY_TYPE)
      if CertGetNameStringW(*cert_args)
        cert_list << cert_name.read_wstring
      end
    end
    CertFreeCertificateContext(pcert_context)
  rescue
    lookup_error("list")
  end
  cert_list.to_json
end
cert_validate(certificate_thumbprint, store_location:, store_name:) click to toggle source

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.

# File lib/win32/certstore/store_base.rb, line 145
def cert_validate(certificate_thumbprint, store_location:, store_name:)
  validate_thumbprint(certificate_thumbprint)
  thumbprint = update_thumbprint(certificate_thumbprint)
  cert_pem = get_cert_pem(thumbprint, store_name: store_name, store_location: store_location)
  cert_pem = format_pem(cert_pem)
  verify_certificate(cert_pem)
end
close_cert_store(certstore_handler = @certstore_handler) click to toggle source

To close and destroy pointer of open certificate store handler

# File lib/win32/certstore/store_base.rb, line 175
def close_cert_store(certstore_handler = @certstore_handler)
  closed = CertCloseStore(certstore_handler, CERT_CLOSE_STORE_FORCE_FLAG)
  lookup_error("close") unless closed
end

Private Instance Methods

add_certcontxt_args(certstore_handler, cert_context) click to toggle source

Build arguments for CertAddCertificateContextToStore

# File lib/win32/certstore/store_base.rb, line 193
def add_certcontxt_args(certstore_handler, cert_context)
  [certstore_handler, cert_context, CERT_STORE_ADD_REPLACE_EXISTING, nil]
end
build_openssl_obj(cert_pem) click to toggle source

Build pem to OpenSSL::X509::Certificate object

# File lib/win32/certstore/store_base.rb, line 253
def build_openssl_obj(cert_pem)
  OpenSSL::X509::Certificate.new(cert_pem)
end
cert_add_args(store_handler, certificate_obj) click to toggle source

Build arguments for CertAddEncodedCertificateToStore

# File lib/win32/certstore/store_base.rb, line 183
def cert_add_args(store_handler, certificate_obj)
  [store_handler, X509_ASN_ENCODING, der_cert(certificate_obj), certificate_obj.to_s.bytesize, 2, nil]
end
cert_find_args(store_handler, thumbprint) click to toggle source

Build arguments for CertFindCertificateInStore

# File lib/win32/certstore/store_base.rb, line 188
def cert_find_args(store_handler, thumbprint)
  [store_handler, ENCODING_TYPE, 0, CERT_FIND_SHA1_HASH, CRYPT_HASH_BLOB.new(thumbprint), nil]
end
cert_get_name_args(pcert_context, cert_name, search_type) click to toggle source

Build argument for CertGetNameStringW

# File lib/win32/certstore/store_base.rb, line 215
def cert_get_name_args(pcert_context, cert_name, search_type)
  [pcert_context, search_type, CERT_NAME_ISSUER_FLAG, nil, cert_name, 1024]
end
der_cert(cert_obj) click to toggle source

Convert OpenSSL::X509::Certificate object in .der formate

# File lib/win32/certstore/store_base.rb, line 232
def der_cert(cert_obj)
  FFI::MemoryPointer.from_string(cert_obj.to_der)
end
format_pem(cert_pem) click to toggle source

Format pem

# File lib/win32/certstore/store_base.rb, line 248
def format_pem(cert_pem)
  cert_pem.delete("\r")
end
get_cert_pem(thumbprint, store_name:, store_location:) click to toggle source

Get certificate pem

# File lib/win32/certstore/store_base.rb, line 237
def get_cert_pem(thumbprint, store_name:, store_location:)
  converted_store = if store_location == CERT_SYSTEM_STORE_LOCAL_MACHINE
                      "LocalMachine"
                    else
                      "CurrentUser"
                    end
  get_data = powershell_exec!(cert_ps_cmd(thumbprint, store_location: converted_store, store_name: store_name))
  get_data.stdout
end
get_cert_property(pcert_context) click to toggle source

Get Certificate all properties

# File lib/win32/certstore/store_base.rb, line 203
def get_cert_property(pcert_context)
  property_value = memory_ptr
  property_list = []
  property_list[0] = ""
  (1..8).to_a.each do |property_type|
    CertGetNameStringW(pcert_context, property_type, CERT_NAME_ISSUER_FLAG, nil, property_value, 1024)
    property_list << property_value.read_wstring
  end
  property_list
end
is_cn_match?(cert_rdn, certificate_name) click to toggle source

Match certificate CN exist in cert_rdn

# File lib/win32/certstore/store_base.rb, line 198
def is_cn_match?(cert_rdn, certificate_name)
  cert_rdn.read_wstring.match(/(^|\W)#{certificate_name}($|\W)/i)
end
memory_ptr() click to toggle source

Create empty memory pointer

# File lib/win32/certstore/store_base.rb, line 258
def memory_ptr
  FFI::MemoryPointer.new(2, 256)
end
update_thumbprint(certificate_thumbprint) click to toggle source

Remove extra space and : from thumbprint

# File lib/win32/certstore/store_base.rb, line 220
def update_thumbprint(certificate_thumbprint)
  certificate_thumbprint.gsub(/[^A-Za-z0-9]/, "")
end
verify_certificate(cert_pem) click to toggle source

Verify OpenSSL::X509::Certificate object

# File lib/win32/certstore/store_base.rb, line 225
def verify_certificate(cert_pem)
  return "Certificate not found" if cert_pem.empty?

  valid_duration?(build_openssl_obj(cert_pem))
end