Module: Win32::Certstore::StoreBase

Includes:
ChefPowerShell::ChefPowerShellModule::PowerShellExec, Mixin::Assertions, Mixin::Crypto, Mixin::Helper, Mixin::String, Mixin::Unicode
Included in:
Win32::Certstore
Defined in:
lib/win32/certstore/store_base.rb

Constant Summary

Constants included from Mixin::Crypto

Mixin::Crypto::BLOB, Mixin::Crypto::BOOL, Mixin::Crypto::BYTE, Mixin::Crypto::CERT_CLOSE_STORE_CHECK_FLAG, Mixin::Crypto::CERT_CLOSE_STORE_FORCE_FLAG, Mixin::Crypto::CERT_COMPARE_ANY, Mixin::Crypto::CERT_COMPARE_NAME_STR_W, Mixin::Crypto::CERT_COMPARE_SHA1_HASH, Mixin::Crypto::CERT_COMPARE_SHIFT, Mixin::Crypto::CERT_FIND_ANY, Mixin::Crypto::CERT_FIND_SHA1_HASH, Mixin::Crypto::CERT_FIND_SUBJECT_STR, Mixin::Crypto::CERT_INFO_SUBJECT_FLAG, Mixin::Crypto::CERT_NAME_ATTR_TYPE, Mixin::Crypto::CERT_NAME_DISABLE_IE4_UTF8_FLAG, Mixin::Crypto::CERT_NAME_DNS_TYPE, Mixin::Crypto::CERT_NAME_EMAIL_TYPE, Mixin::Crypto::CERT_NAME_FRIENDLY_DISPLAY_TYPE, Mixin::Crypto::CERT_NAME_ISSUER_FLAG, Mixin::Crypto::CERT_NAME_RDN_TYPE, Mixin::Crypto::CERT_NAME_SEARCH_ALL_NAMES_FLAG, Mixin::Crypto::CERT_NAME_SIMPLE_DISPLAY_TYPE, Mixin::Crypto::CERT_NAME_STR_ENABLE_PUNYCODE_FLAG, Mixin::Crypto::CERT_NAME_UPN_TYPE, Mixin::Crypto::CERT_NAME_URL_TYPE, Mixin::Crypto::CERT_STORE_ADD_REPLACE_EXISTING, Mixin::Crypto::CERT_STORE_ADD_USE_EXISTING, Mixin::Crypto::CERT_STORE_PROV_SYSTEM, Mixin::Crypto::CERT_SYSTEM_STORE_CURRENT_USER, Mixin::Crypto::CERT_SYSTEM_STORE_LOCAL_MACHINE, Mixin::Crypto::CERT_SYSTEM_STORE_SERVICES, Mixin::Crypto::CERT_SYSTEM_STORE_USERS, Mixin::Crypto::CRYPT_ASN_ENCODING, Mixin::Crypto::CRYPT_NDR_ENCODING, Mixin::Crypto::DWORD, Mixin::Crypto::ENCODING_TYPE, Mixin::Crypto::HCERTSTORE, Mixin::Crypto::HCRYPTPROV_LEGACY, Mixin::Crypto::INT_PTR, Mixin::Crypto::LMSTR, Mixin::Crypto::LONG, Mixin::Crypto::LPCTSTR, Mixin::Crypto::LPFILETIME, Mixin::Crypto::LPSTR, Mixin::Crypto::LPTSTR, Mixin::Crypto::LPVOID, Mixin::Crypto::PCCERT_CONTEXT, Mixin::Crypto::PCERT_INFO, Mixin::Crypto::PCTL_USAGE, Mixin::Crypto::PCTL_VERIFY_USAGE_PARA, Mixin::Crypto::PCTL_VERIFY_USAGE_STATUS, Mixin::Crypto::PKCS_7_ASN_ENCODING, Mixin::Crypto::PKCS_7_NDR_ENCODING, Mixin::Crypto::PKCS_7_OR_X509_ASN_ENCODING, Mixin::Crypto::PWSTR, Mixin::Crypto::X509_ASN_ENCODING, Mixin::Crypto::X509_NDR_ENCODING

Instance Method Summary collapse

Methods included from Mixin::Helper

#cert_ps_cmd, #valid_duration?

Methods included from Mixin::String

#utf8_to_wide, #wide_to_utf8, #wstring

Methods included from Mixin::Assertions

#lookup_error, #validate!, #validate_certificate, #validate_certificate_obj, #validate_store, #validate_thumbprint

Methods included from FFI::Library

#safe_attach_function

Instance Method Details

#cert_add(store_handler, certificate_obj) ⇒ Object

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



43
44
45
46
47
48
49
50
51
52
53
54
55
# File 'lib/win32/certstore/store_base.rb', line 43

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) ⇒ Boolean

Adds a PFX certificate to certificate store

Parameters:

  • certstore_handler (FFI::Pointer)

    Handle of the store where certificate should be imported

  • path (String)

    Path of the certificate that should be imported

  • password (String) (defaults to: "")

    Password of the certificate

  • key_properties (Integer) (defaults to: 0)

    dwFlags used to specify properties of the pfx key, see link above

Returns:

  • (Boolean)

Raises:

  • (SystemCallError)

    when Crypt API would not be able to perform some action

See Also:



71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
# File 'lib/win32/certstore/store_base.rb', line 71

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) ⇒ Object

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.



126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
# File 'lib/win32/certstore/store_base.rb', line 126

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) ⇒ Object

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



95
96
97
98
99
100
101
102
103
# File 'lib/win32/certstore/store_base.rb', line 95

def cert_get(certificate_thumbprint)
  validate_thumbprint(certificate_thumbprint)
  thumbprint = update_thumbprint(certificate_thumbprint)
  cert_pem = get_cert_pem(thumbprint)
  return cert_pem  if cert_pem == "Certificate Not Found"
  cert_pem = format_pem(cert_pem)
  verify_certificate(cert_pem)
  build_openssl_obj(cert_pem)
end

#cert_list(store_handler) ⇒ Object

Listing certificate of open certstore and return list in json



106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
# File 'lib/win32/certstore/store_base.rb', line 106

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_lookup_by_token(search_token, store_name: @store_name, store_location: @store_location, timeout: -1)) ⇒ Object

how can I find a cert if I don’t have the thumbprint? This should be replaced by a call to CertFindCertificateInStore



179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
# File 'lib/win32/certstore/store_base.rb', line 179

def cert_lookup_by_token(search_token, store_name: @store_name, store_location: @store_location, timeout: -1)
  raise ArgumentError, "Invalid search token" if !search_token || search_token.strip.empty?

  converted_store = if store_location == CERT_SYSTEM_STORE_LOCAL_MACHINE || store_location == 131072
                      "LocalMachine"
                    else
                      "CurrentUser"
                    end
  powershell_cmd = <<~EOH
      $result = Get-ChildItem -Path Cert:\\#{converted_store}\\#{store_name} | Where-Object { $_.Subject -match "#{search_token.strip}" } | Select-Object Thumbprint
      if ([string]::IsNullOrEmpty($result)){
        return "Certificate Not Found"
      }
      return $result[0].Thumbprint
  EOH

  powershell_exec!(powershell_cmd, :powershell, timeout: timeout).result

rescue ChefPowerShell::PowerShellExceptions::PowerShellCommandFailed
  raise ArgumentError, "PowerShell threw an error retreiving the certificate. You asked for a cert with this Search Token : #{search_token}, located in this store : #{store_name}, at this location : #{store_location}"
end

#cert_search(store_handler, search_token) ⇒ Object

Search certificate from open certificate store and return list store_handler => Open certificate store handler search_token => CN, RDN or any certificate attribute

Raises:

  • (ArgumentError)


160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
# File 'lib/win32/certstore/store_base.rb', line 160

def cert_search(store_handler, search_token)
  raise ArgumentError, "Invalid search token" if !search_token || search_token.strip.empty?

  certificate_list = []
  begin
    while (pcert_context = CertEnumCertificatesInStore(store_handler, pcert_context)) && !pcert_context.null?
      cert_property = get_cert_property(pcert_context)
      if cert_property.include?(search_token)
        certificate_list << [cert_property[CERT_NAME_FRIENDLY_DISPLAY_TYPE], cert_property[CERT_NAME_RDN_TYPE]]
      end
    end
    CertFreeCertificateContext(pcert_context)
  rescue
    lookup_error
  end
  certificate_list
end

#cert_validate(certificate_thumbprint) ⇒ Object

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.



147
148
149
150
151
152
153
154
155
# File 'lib/win32/certstore/store_base.rb', line 147

def cert_validate(certificate_thumbprint)
  validate_thumbprint(certificate_thumbprint)
  thumbprint = update_thumbprint(certificate_thumbprint)
  cert_pem = get_cert_pem(thumbprint)
  return cert_pem  if cert_pem == "Certificate Not Found"
  cert_pem = format_pem(cert_pem)
  result = verify_certificate(cert_pem)
  result == false ? "Certificate Has Expired" : result
end

#close_cert_store(certstore_handler = @certstore_handler) ⇒ Object

To close and destroy pointer of open certificate store handler



202
203
204
205
# File 'lib/win32/certstore/store_base.rb', line 202

def close_cert_store(certstore_handler = @certstore_handler)
  closed = CertCloseStore(certstore_handler, CERT_CLOSE_STORE_FORCE_FLAG)
  lookup_error("close") unless closed
end