win32-certstore 0.6.2 → 0.6.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e832ae077e8be7cd039393f84b74062e58dd331b1317cdcc2a1bb1f13109f176
4
- data.tar.gz: 453bd4ad7e2d6a92d3935b0a4df4f241636b657256a39f1ac35bc81d2d34030b
3
+ metadata.gz: 5a55969ab67094eb7c246c946a77807c596afb12d76fd4eef07d48076ffa43b7
4
+ data.tar.gz: 711f553c79a83a4edb8ed2b572ca4ddac1478658b910d57fdb097d2323b4985f
5
5
  SHA512:
6
- metadata.gz: a3254affc58f8eb862a585b78cc5c5451c61db3398ef1de59ffcb6580755f5e24338c2a1caf16e89e46db4e8ee7c9f431a1c4372768cb7ff08bd76265d1b53da
7
- data.tar.gz: bab7b27e4c0c6d780556a6410836283f6de31c64d559fb1b331b679c3d671b68673b6313f53560916e0a5c89f83fff658fd3335f965cfa3024b5066860393b3b
6
+ metadata.gz: 79af95ff03edc99c69c77cb2b333258929afda17bd3c7068cfc08f3fac65619d4723e2b0042f6f1b77fd6b34f0c2136d0136931275dc1514f2e5e78252a05d79
7
+ data.tar.gz: c8d84f2111d7ff052bacf7c3384552a519a17c9f49feec1e11e924115708c6838b2d034a3c9ecefafddf0ca08b3a0d1a0a4ef10b9863811abb684d92bb52c743
@@ -37,13 +37,13 @@ module Win32
37
37
  # Validate certificate Object
38
38
  def validate_certificate_obj(cert_obj)
39
39
  unless cert_obj.class == OpenSSL::X509::Certificate
40
- raise ArgumentError, "Invalid Certificate object."
40
+ raise ArgumentError, "Invalid Certificate object. This is not a properly formatted x509 object"
41
41
  end
42
42
  end
43
43
 
44
44
  # Validate thumbprint
45
45
  def validate_thumbprint(cert_thumbprint)
46
- if cert_thumbprint.nil? || cert_thumbprint.strip.empty?
46
+ if cert_thumbprint.nil? || cert_thumbprint.empty? || cert_thumbprint.strip.empty?
47
47
  raise ArgumentError, "Invalid certificate thumbprint."
48
48
  end
49
49
  end
@@ -82,7 +82,7 @@ module Win32
82
82
  # ROOT -> Root certificates.
83
83
  # SPC -> Software Publisher Certificate.
84
84
  def valid_store_name
85
- %w{MY CA ROOT AUTHROOT DISALLOWED SPC TRUST TRUSTEDPEOPLE TRUSTEDPUBLISHER CLIENTAUTHISSUER TRUSTEDDEVICES SMARTCARDROOT WEBHOSTING REMOTE\ DESKTOP}
85
+ ["MY", "CA", "ROOT", "AUTHROOT", "DISALLOWED", "SPC", "TRUST", "TRUSTEDPEOPLE", "TRUSTEDPUBLISHER", "CLIENTAUTHISSUER", "TRUSTEDDEVICES", "SMARTCARDROOT", "WEBHOSTING", "REMOTE DESKTOP"]
86
86
  end
87
87
  end
88
88
  end
@@ -22,17 +22,20 @@ module Win32
22
22
  module Mixin
23
23
  module Helper
24
24
  def cert_ps_cmd(thumbprint, store_location: "LocalMachine", store_name: "My")
25
+ # the PowerShell block below uses a "Here-String" - it is explicitly formatted against the left margin.
25
26
  <<-EOH
26
- $cert = Get-ChildItem Cert:\\#{store_location}\\#{store_name} -Recurse | Where { $_.Thumbprint -eq "#{thumbprint}" }
27
+ $cert = Get-ChildItem Cert:\\#{store_location}\\#{store_name} -Recurse | Where-Object { $_.Thumbprint -eq "#{thumbprint}" }
27
28
 
29
+ $certdata = [System.Convert]::ToBase64String($cert.RawData, 'InsertLineBreaks')
28
30
  $content = $null
29
31
  if($null -ne $cert)
30
32
  {
31
- $content = @(
32
- '-----BEGIN CERTIFICATE-----'
33
- [System.Convert]::ToBase64String($cert.RawData, 'InsertLineBreaks')
34
- '-----END CERTIFICATE-----'
35
- )
33
+ $content =
34
+ @"
35
+ -----BEGIN CERTIFICATE-----
36
+ $($certdata)
37
+ -----END CERTIFICATE-----
38
+ "@
36
39
  }
37
40
  $content
38
41
  EOH
@@ -17,20 +17,25 @@
17
17
 
18
18
  require_relative "mixin/crypto"
19
19
  require_relative "mixin/string"
20
- require_relative "mixin/shell_exec"
21
20
  require_relative "mixin/unicode"
22
21
  require "openssl" unless defined?(OpenSSL)
23
22
  require "json" unless defined?(JSON)
24
23
 
24
+ begin
25
+ require "chef-powershell"
26
+ rescue LoadError
27
+ puts "Not loading powershell_exec during testing"
28
+ end
29
+
25
30
  module Win32
26
31
  class Certstore
27
32
  module StoreBase
28
33
  include Win32::Certstore::Mixin::Crypto
29
34
  include Win32::Certstore::Mixin::Assertions
30
35
  include Win32::Certstore::Mixin::String
31
- include Win32::Certstore::Mixin::ShellExec
32
36
  include Win32::Certstore::Mixin::Unicode
33
37
  include Win32::Certstore::Mixin::Helper
38
+ include ChefPowerShell::ChefPowerShellModule::PowerShellExec
34
39
 
35
40
  # Adding new certification in open certificate and return boolean
36
41
  # store_handler => Open certificate store handler
@@ -87,18 +92,13 @@ module Win32
87
92
 
88
93
  # Get certificate from open certificate store and return certificate object
89
94
  # certificate_thumbprint => thumbprint is a hash. which could be sha1 or md5.
90
- def cert_get(certificate_thumbprint, store_name:, store_location:)
95
+ def cert_get(certificate_thumbprint)
91
96
  validate_thumbprint(certificate_thumbprint)
92
97
  thumbprint = update_thumbprint(certificate_thumbprint)
93
- cert_pem = get_cert_pem(thumbprint, store_name: store_name, store_location: store_location)
98
+ cert_pem = get_cert_pem(thumbprint)
94
99
  cert_pem = format_pem(cert_pem)
95
- if cert_pem.empty?
96
- raise ArgumentError, "Unable to retrieve the certificate"
97
- end
98
-
99
- unless cert_pem.empty?
100
- build_openssl_obj(cert_pem)
101
- end
100
+ verify_certificate(cert_pem)
101
+ build_openssl_obj(cert_pem)
102
102
  end
103
103
 
104
104
  # Listing certificate of open certstore and return list in json
@@ -125,6 +125,7 @@ module Win32
125
125
  def cert_delete(store_handler, certificate_thumbprint)
126
126
  validate_thumbprint(certificate_thumbprint)
127
127
  thumbprint = update_thumbprint(certificate_thumbprint)
128
+
128
129
  cert_delete_flag = false
129
130
  begin
130
131
  cert_args = cert_find_args(store_handler, thumbprint)
@@ -142,10 +143,11 @@ module Win32
142
143
  # Verify certificate from open certificate store and return boolean or exceptions
143
144
  # store_handler => Open certificate store handler
144
145
  # certificate_thumbprint => thumbprint is a hash. which could be sha1 or md5.
145
- def cert_validate(certificate_thumbprint, store_location:, store_name:)
146
+ def cert_validate(certificate_thumbprint)
146
147
  validate_thumbprint(certificate_thumbprint)
147
148
  thumbprint = update_thumbprint(certificate_thumbprint)
148
- cert_pem = get_cert_pem(thumbprint, store_name: store_name, store_location: store_location)
149
+
150
+ cert_pem = get_cert_pem(thumbprint)
149
151
  cert_pem = format_pem(cert_pem)
150
152
  verify_certificate(cert_pem)
151
153
  end
@@ -171,6 +173,26 @@ module Win32
171
173
  certificate_list
172
174
  end
173
175
 
176
+ # how can I find a cert if I don't have the thumbprint? This should be replaced by a call to CertFindCertificateInStore
177
+ def cert_lookup_by_token(search_token, store_name: @store_name, store_location: @store_location, timeout: -1)
178
+ raise ArgumentError, "Invalid search token" if !search_token || search_token.strip.empty?
179
+
180
+ converted_store = if store_location == CERT_SYSTEM_STORE_LOCAL_MACHINE || store_location == 131072
181
+ "LocalMachine"
182
+ else
183
+ "CurrentUser"
184
+ end
185
+ powershell_cmd = <<~EOH
186
+ $result = Get-ChildItem -Path Cert:\\#{converted_store}\\#{store_name} | Where-Object { $_.Subject -match "#{search_token.strip}" } | Select-Object Thumbprint
187
+ return $result[0].Thumbprint
188
+ EOH
189
+
190
+ powershell_exec!(powershell_cmd, :powershell, timeout: timeout).result
191
+
192
+ rescue ChefPowerShell::PowerShellExceptions::PowerShellCommandFailed
193
+ raise ArgumentError, "Certificate not found while looking for certificate : #{search_token} in store : #{store_name} at this location : #{store_location}"
194
+ end
195
+
174
196
  # To close and destroy pointer of open certificate store handler
175
197
  def close_cert_store(certstore_handler = @certstore_handler)
176
198
  closed = CertCloseStore(certstore_handler, CERT_CLOSE_STORE_FORCE_FLAG)
@@ -194,6 +216,11 @@ module Win32
194
216
  [certstore_handler, cert_context, CERT_STORE_ADD_REPLACE_EXISTING, nil]
195
217
  end
196
218
 
219
+ # Remove extra space and : from thumbprint
220
+ def update_thumbprint(certificate_thumbprint)
221
+ certificate_thumbprint.gsub(/[^A-Za-z0-9]/, "")
222
+ end
223
+
197
224
  # Match certificate CN exist in cert_rdn
198
225
  def is_cn_match?(cert_rdn, certificate_name)
199
226
  cert_rdn.read_wstring.match(/(^|\W)#{certificate_name}($|\W)/i)
@@ -216,14 +243,9 @@ module Win32
216
243
  [pcert_context, search_type, CERT_NAME_ISSUER_FLAG, nil, cert_name, 1024]
217
244
  end
218
245
 
219
- # Remove extra space and : from thumbprint
220
- def update_thumbprint(certificate_thumbprint)
221
- certificate_thumbprint.gsub(/[^A-Za-z0-9]/, "")
222
- end
223
-
224
246
  # Verify OpenSSL::X509::Certificate object
225
247
  def verify_certificate(cert_pem)
226
- return "Certificate not found" if cert_pem.empty?
248
+ raise ArgumentError, "Certificate not found" if cert_pem.empty?
227
249
 
228
250
  valid_duration?(build_openssl_obj(cert_pem))
229
251
  end
@@ -233,15 +255,17 @@ module Win32
233
255
  FFI::MemoryPointer.from_string(cert_obj.to_der)
234
256
  end
235
257
 
236
- # Get certificate pem
237
- def get_cert_pem(thumbprint, store_name:, store_location:)
238
- converted_store = if store_location == CERT_SYSTEM_STORE_LOCAL_MACHINE
258
+ # Get certificate pem.
259
+ def get_cert_pem(thumbprint, store_name: @store_name, store_location: @store_location, timeout: -1)
260
+ converted_store = if store_location == CERT_SYSTEM_STORE_LOCAL_MACHINE || store_location == 131072
239
261
  "LocalMachine"
240
262
  else
241
263
  "CurrentUser"
242
264
  end
243
- get_data = powershell_exec!(cert_ps_cmd(thumbprint, store_location: converted_store, store_name: store_name))
244
- get_data.stdout
265
+ get_data = powershell_exec!(cert_ps_cmd(thumbprint, store_location: converted_store, store_name: store_name), :powershell, timeout: timeout)
266
+ get_data.result
267
+ rescue ChefPowerShell::PowerShellExceptions::PowerShellCommandFailed
268
+ raise ArgumentError, "PowerShell threw an error retreiving the certificate. You asked for a cert with this thumbprint : #{thumbprint}, located in this store : #{store_name}, at this location : #{store_location}"
245
269
  end
246
270
 
247
271
  # Format pem
@@ -1,6 +1,6 @@
1
1
  module Win32
2
2
  class Certstore
3
- VERSION = "0.6.2".freeze
3
+ VERSION = "0.6.10".freeze
4
4
  MAJOR, MINOR, TINY = VERSION.split(".")
5
5
  end
6
6
  end
@@ -29,23 +29,23 @@ module Win32
29
29
  include Win32::Certstore::Mixin::String
30
30
  include Win32::Certstore::StoreBase
31
31
 
32
- attr_accessor :store_name
32
+ attr_accessor :store_name, :store_location
33
33
 
34
34
  # Initializes a new instance of a certificate store.
35
35
  # takes 2 parameters - the store name (My, Root, etc) and the location (CurrentUser or LocalMachine), it defaults to LocalMachine for backwards compatibility
36
- def initialize(store_name, store_location: CERT_SYSTEM_STORE_LOCAL_MACHINE)
36
+ def initialize(store_name, store_location)
37
37
  @store_name = store_name
38
38
  @store_location = store_location
39
- @certstore_handler = open(store_name, store_location: store_location)
39
+ @certstore_handler = open(store_name, store_location)
40
40
  end
41
41
 
42
42
  # To open given certificate store
43
43
  def self.open(store_name, store_location: CERT_SYSTEM_STORE_LOCAL_MACHINE)
44
44
  validate_store(store_name)
45
45
  if block_given?
46
- yield new(store_name, store_location: store_location)
46
+ yield new(store_name, store_location)
47
47
  else
48
- new(store_name, store_location: store_location)
48
+ new(store_name, store_location)
49
49
  end
50
50
  end
51
51
 
@@ -74,8 +74,19 @@ module Win32
74
74
  # Return `OpenSSL::X509` certificate object
75
75
  # @param request [thumbprint<string>] of certificate
76
76
  # @return [Object] of certificates in OpenSSL::X509 format
77
- def get(certificate_thumbprint, store_name: @store_name, store_location: @store_location)
78
- cert_get(certificate_thumbprint, store_name: store_name, store_location: store_location)
77
+ def get(certificate_thumbprint)
78
+ cert_get(certificate_thumbprint)
79
+ end
80
+
81
+ # Return `OpenSSL::X509` certificate object if present otherwise raise a "Certificate not found!" error
82
+ # @param request [thumbprint<string>] of certificate
83
+ # @return [Object] of certificates in OpenSSL::X509 format
84
+ def get!(certificate_thumbprint)
85
+ cert_pem = cert_get(certificate_thumbprint)
86
+
87
+ raise ArgumentError, "Unable to retrieve the certificate" if cert_pem.empty?
88
+
89
+ cert_pem
79
90
  end
80
91
 
81
92
  # Returns all the certificates in a store
@@ -99,11 +110,21 @@ module Win32
99
110
  cert_search(certstore_handler, search_token)
100
111
  end
101
112
 
113
+ def get_thumbprint(search_token)
114
+ cert_lookup_by_token(search_token)
115
+ end
116
+
102
117
  # Validates a certificate in a certificate store on the basis of time validity
103
118
  # @param request[thumbprint<string>] of certificate
104
119
  # @return [true, false] only true or false
105
- def valid?(certificate_thumbprint, store_location: "", store_name: "")
106
- cert_validate(certificate_thumbprint, store_location: store_location, store_name: store_name)
120
+ def valid?(certificate_thumbprint)
121
+ cert_validate(certificate_thumbprint).yield_self do |x|
122
+ if x.is_a?(TrueClass) || x.is_a?(FalseClass)
123
+ x
124
+ else
125
+ false
126
+ end
127
+ end
107
128
  end
108
129
 
109
130
  # To close and destroy pointer of open certificate store handler
@@ -122,7 +143,7 @@ module Win32
122
143
 
123
144
  # To open certstore and return open certificate store pointer
124
145
 
125
- def open(store_name, store_location: CERT_SYSTEM_STORE_LOCAL_MACHINE)
146
+ def open(store_name, store_location)
126
147
  certstore_handler = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, nil, store_location, wstring(store_name))
127
148
  unless certstore_handler
128
149
  last_error = FFI::LastError.error
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: win32-certstore
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.2
4
+ version: 0.6.10
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chef Software
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-04-15 00:00:00.000000000 Z
11
+ date: 2022-02-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -39,7 +39,7 @@ dependencies:
39
39
  - !ruby/object:Gem::Version
40
40
  version: '3.0'
41
41
  - !ruby/object:Gem::Dependency
42
- name: mixlib-shellout
42
+ name: ffi
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - ">="
@@ -53,19 +53,19 @@ dependencies:
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
55
  - !ruby/object:Gem::Dependency
56
- name: ffi
56
+ name: chef-powershell
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - ">="
60
60
  - !ruby/object:Gem::Version
61
- version: '0'
61
+ version: 1.0.12
62
62
  type: :runtime
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - ">="
67
67
  - !ruby/object:Gem::Version
68
- version: '0'
68
+ version: 1.0.12
69
69
  description:
70
70
  email:
71
71
  - oss@chef.io
@@ -79,7 +79,6 @@ files:
79
79
  - lib/win32/certstore/mixin/assertions.rb
80
80
  - lib/win32/certstore/mixin/crypto.rb
81
81
  - lib/win32/certstore/mixin/helper.rb
82
- - lib/win32/certstore/mixin/shell_exec.rb
83
82
  - lib/win32/certstore/mixin/string.rb
84
83
  - lib/win32/certstore/mixin/unicode.rb
85
84
  - lib/win32/certstore/store_base.rb
@@ -1,105 +0,0 @@
1
- #
2
- # Author:: Daniel DeLeo (<dan@chef.io>)
3
- # Copyright:: Copyright (c) 2017 Chef Software, Inc.
4
- # License:: Apache License, Version 2.0
5
- #
6
- # Licensed under the Apache License, Version 2.0 (the "License");
7
- # you may not use this file except in compliance with the License.
8
- # You may obtain a copy of the License at
9
- #
10
- # http://www.apache.org/licenses/LICENSE-2.0
11
- #
12
- # Unless required by applicable law or agreed to in writing, software
13
- # distributed under the License is distributed on an "AS IS" BASIS,
14
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
- # See the License for the specific language governing permissions and
16
- # limitations under the License.
17
-
18
- require "mixlib/shellout" unless defined?(Mixlib::ShellOut)
19
-
20
- module Win32
21
- class Certstore
22
- module Mixin
23
- module ShellExec
24
- def shell_out_command(*command_args)
25
- cmd = Mixlib::ShellOut.new(*command_args)
26
- cmd.live_stream
27
- cmd.run_command
28
- if cmd.error!
29
- raise Mixlib::ShellOut::ShellCommandFailed, cmd.error!
30
- end
31
-
32
- cmd
33
- end
34
-
35
- # Run a command under powershell with the same API as shell_out. The
36
- # options hash is extended to take an "architecture" flag which
37
- # can be set to :i386 or :x86_64 to force the windows architecture.
38
- #
39
- # @param script [String] script to run
40
- # @param options [Hash] options hash
41
- # @return [Mixlib::Shellout] mixlib-shellout object
42
- def powershell_exec(*command_args)
43
- script = command_args.first
44
- options = command_args.last.is_a?(Hash) ? command_args.last : nil
45
-
46
- run_command_with_os_architecture(script, options)
47
- end
48
-
49
- # Run a command under powershell with the same API as shell_out!
50
- # (raises exceptions on errors)
51
- #
52
- # @param script [String] script to run
53
- # @param options [Hash] options hash
54
- # @return [Mixlib::Shellout] mixlib-shellout object
55
- def powershell_exec!(*command_args)
56
- cmd = powershell_exec(*command_args)
57
- cmd.error!
58
- cmd
59
- end
60
-
61
- private
62
-
63
- # Helper function to run shell_out and wrap it with the correct
64
- # flags to possibly disable WOW64 redirection (which we often need
65
- # because chef-client runs as a 32-bit app on 64-bit windows).
66
- #
67
- # @param script [String] script to run
68
- # @param options [Hash] options hash
69
- # @return [Mixlib::Shellout] mixlib-shellout object
70
- def run_command_with_os_architecture(script, options)
71
- options ||= {}
72
- options = options.dup
73
-
74
- shell_out_command(
75
- build_powershell_command(script),
76
- options
77
- )
78
- end
79
-
80
- # Helper to build a powershell command around the script to run.
81
- #
82
- # @param script [String] script to run
83
- # @return [String] powershell command to execute
84
- def build_powershell_command(script)
85
- flags = [
86
- # Hides the copyright banner at startup.
87
- "-NoLogo",
88
- # Does not present an interactive prompt to the user.
89
- "-NonInteractive",
90
- # Does not load the Windows PowerShell profile.
91
- "-NoProfile",
92
- # always set the ExecutionPolicy flag
93
- # see http://technet.microsoft.com/en-us/library/ee176961.aspx
94
- "-ExecutionPolicy Unrestricted",
95
- # Powershell will hang if STDIN is redirected
96
- # http://connect.microsoft.com/PowerShell/feedback/details/572313/powershell-exe-can-hang-if-stdin-is-redirected
97
- "-InputFormat None",
98
- ]
99
-
100
- "powershell.exe #{flags.join(" ")} -Command \"#{script.gsub('"', '\"')}\""
101
- end
102
- end
103
- end
104
- end
105
- end