win32-certstore 0.2.2 → 0.4.1

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: fdfde36cb468d1ce15e0d5fd317783347f07c96f0282519b56b86b424d89e92e
4
- data.tar.gz: a4ce61aafb784b12bf5e7ee28958221c4318500d78ec2ac23f3d700e7528d466
3
+ metadata.gz: a571cfa5aea1f77ed28c7711fe81982338d7af42a73f886cfbdfe6df3123fc91
4
+ data.tar.gz: cb36e5aba55afe58af9a7770f330f276ad7013fe86f7d51dd1d9d372b7a9a598
5
5
  SHA512:
6
- metadata.gz: 3f1ff03dc3ac803b951179683c48bdef81ea481f12c0a1838e9d236085e4451d2698a3f488da855bbc44bdbf037d6fdc753113309ef0838b2b61fab425cc8040
7
- data.tar.gz: 61ac2a5b3f1cbceb606822c07dfdfec2b5b76e1ba91820f4f7571c094f16c10ffeba292e9772abf3938eba537951426d8c8ef8f09ddcf5b1bc74cbf0367435ce
6
+ metadata.gz: 94138aaef753c7b9830e7374fc80d53ae531c85f14677f3fc72eb4234744ee7c21737b0ee8f41d530deeec0e433196ec1acacc1792468ed0849b995ee0fab754
7
+ data.tar.gz: 5710436ecefe40dc2883375d4317d333189ef0b7896b27dd3c31e0ccf1beab9d321edab6cae714b365492aec5420853a0ec8d53cb18dd006f61ecfa1e85c8a4a
@@ -53,6 +53,21 @@ module Win32
53
53
  cert_add(certstore_handler, certificate_obj)
54
54
  end
55
55
 
56
+ # Adds a PFX certificate to certificate store
57
+ #
58
+ # @note Unlike other certificates, PFX can be password protected and may contain a private key.
59
+ # Therefore we need a different approach to import them.
60
+ #
61
+ # @param path [String] Path of the certificate that should be imported
62
+ # @param password [String] Password of the certificate if it is protected
63
+ # @param key_properties [Integer] dwFlags used to specify properties of the pfx key, see certstore/store_base.rb cert_add_pfx function
64
+ #
65
+ # @return [Boolean]
66
+ #
67
+ def add_pfx(path, password, key_properties = 0)
68
+ cert_add_pfx(certstore_handler, path, password, key_properties)
69
+ end
70
+
56
71
  # Return `OpenSSL::X509` certificate object
57
72
  # @param request [thumbprint<string>] of certificate
58
73
  # @return [Object] of certificates in OpenSSL::X509 format
@@ -90,11 +105,7 @@ module Win32
90
105
 
91
106
  # To close and destroy pointer of open certificate store handler
92
107
  def close
93
- closed = CertCloseStore(@certstore_handler, CERT_CLOSE_STORE_FORCE_FLAG)
94
- unless closed
95
- last_error = FFI::LastError.error
96
- raise SystemCallError.new("Unable to close the Certificate Store.", last_error)
97
- end
108
+ close_cert_store
98
109
  remove_finalizer
99
110
  end
100
111
 
@@ -14,7 +14,7 @@
14
14
  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
15
  # See the License for the specific language governing permissions and
16
16
  # limitations under the License.
17
- require "openssl"
17
+ require "openssl" unless defined?(OpenSSL)
18
18
 
19
19
  module Win32
20
20
  class Certstore
@@ -16,7 +16,7 @@
16
16
  # limitations under the License.
17
17
  #
18
18
 
19
- require "ffi"
19
+ require "ffi" unless defined?(FFI)
20
20
 
21
21
  module Win32
22
22
  class Certstore
@@ -68,12 +68,17 @@ module Win32
68
68
  CERT_NAME_UPN_TYPE = 8
69
69
 
70
70
  # Retrieve Certificates flag
71
+ CERT_COMPARE_ANY = 0
71
72
  CERT_COMPARE_SHA1_HASH = 1
72
73
  CERT_INFO_SUBJECT_FLAG = 7
73
74
  CERT_COMPARE_NAME_STR_W = 8
74
75
  CERT_COMPARE_SHIFT = 16
75
76
  CERT_FIND_SHA1_HASH = CERT_COMPARE_SHA1_HASH << CERT_COMPARE_SHIFT
76
77
  CERT_FIND_SUBJECT_STR = CERT_COMPARE_NAME_STR_W << CERT_COMPARE_SHIFT | CERT_INFO_SUBJECT_FLAG
78
+ CERT_FIND_ANY = CERT_COMPARE_ANY << CERT_COMPARE_SHIFT
79
+
80
+ CERT_STORE_ADD_USE_EXISTING = 2
81
+ CERT_STORE_ADD_REPLACE_EXISTING = 3
77
82
 
78
83
  # List Certificates Flag
79
84
  CERT_NAME_ISSUER_FLAG = 0x1
@@ -108,17 +113,17 @@ module Win32
108
113
 
109
114
  class FILETIME < FFI::Struct
110
115
  layout :dwLowDateTime, DWORD,
111
- :dwHighDateTime, DWORD
116
+ :dwHighDateTime, DWORD
112
117
  end
113
118
 
114
119
  class CRYPT_INTEGER_BLOB < FFI::Struct
115
120
  layout :cbData, DWORD, # Count, in bytes, of data
116
- :pbData, :pointer # Pointer to data buffer
121
+ :pbData, :pointer # Pointer to data buffer
117
122
  end
118
123
 
119
124
  class CRYPT_NAME_BLOB < FFI::Struct
120
125
  layout :cbData, DWORD, # Count, in bytes, of data
121
- :pbData, :pointer # Pointer to data buffer
126
+ :pbData, :pointer # Pointer to data buffer
122
127
  def initialize(str = nil)
123
128
  super(nil)
124
129
  if str
@@ -129,7 +134,7 @@ module Win32
129
134
 
130
135
  class CRYPT_HASH_BLOB < FFI::Struct
131
136
  layout :cbData, DWORD, # Count, in bytes, of data
132
- :pbData, :pointer # Pointer to data buffer
137
+ :pbData, :pointer # Pointer to data buffer
133
138
 
134
139
  def initialize(str = nil)
135
140
  super(nil)
@@ -144,49 +149,62 @@ module Win32
144
149
  end
145
150
  end
146
151
 
152
+ class CRYPT_DATA_BLOB < FFI::Struct
153
+ layout :cbData, DWORD, # Count, in bytes, of data
154
+ :pbData, :pointer # Pointer to data buffer
155
+
156
+ def initialize(str = nil)
157
+ super(nil)
158
+ if str
159
+ self[:pbData] = FFI::MemoryPointer.from_string(str)
160
+ self[:cbData] = str.size
161
+ end
162
+ end
163
+ end
164
+
147
165
  class CERT_EXTENSION < FFI::Struct
148
166
  layout :pszObjId, LPTSTR,
149
- :fCritical, BOOL,
150
- :Value, CRYPT_INTEGER_BLOB
167
+ :fCritical, BOOL,
168
+ :Value, CRYPT_INTEGER_BLOB
151
169
  end
152
170
 
153
171
  class CRYPT_BIT_BLOB < FFI::Struct
154
172
  layout :cbData, DWORD,
155
- :pbData, BYTE,
156
- :cUnusedBits, DWORD
173
+ :pbData, BYTE,
174
+ :cUnusedBits, DWORD
157
175
  end
158
176
 
159
177
  class CRYPT_ALGORITHM_IDENTIFIER < FFI::Struct
160
178
  layout :pszObjId, LPSTR,
161
- :Parameters, CRYPT_INTEGER_BLOB
179
+ :Parameters, CRYPT_INTEGER_BLOB
162
180
  end
163
181
 
164
182
  class CERT_PUBLIC_KEY_INFO < FFI::Struct
165
183
  layout :Algorithm, CRYPT_ALGORITHM_IDENTIFIER,
166
- :PublicKey, CRYPT_BIT_BLOB
184
+ :PublicKey, CRYPT_BIT_BLOB
167
185
  end
168
186
 
169
187
  class CERT_INFO < FFI::Struct
170
188
  layout :dwVersion, DWORD,
171
- :SerialNumber, CRYPT_INTEGER_BLOB,
172
- :SignatureAlgorithm, CRYPT_ALGORITHM_IDENTIFIER,
173
- :Issuer, CRYPT_NAME_BLOB,
174
- :NotBefore, FILETIME,
175
- :NotAfter, FILETIME,
176
- :Subject, CRYPT_NAME_BLOB,
177
- :SubjectPublicKeyInfo, CERT_PUBLIC_KEY_INFO,
178
- :IssuerUniqueId, CRYPT_BIT_BLOB,
179
- :SubjectUniqueId, CRYPT_BIT_BLOB,
180
- :cExtension, DWORD,
181
- :rgExtension, CERT_EXTENSION
189
+ :SerialNumber, CRYPT_INTEGER_BLOB,
190
+ :SignatureAlgorithm, CRYPT_ALGORITHM_IDENTIFIER,
191
+ :Issuer, CRYPT_NAME_BLOB,
192
+ :NotBefore, FILETIME,
193
+ :NotAfter, FILETIME,
194
+ :Subject, CRYPT_NAME_BLOB,
195
+ :SubjectPublicKeyInfo, CERT_PUBLIC_KEY_INFO,
196
+ :IssuerUniqueId, CRYPT_BIT_BLOB,
197
+ :SubjectUniqueId, CRYPT_BIT_BLOB,
198
+ :cExtension, DWORD,
199
+ :rgExtension, CERT_EXTENSION
182
200
  end
183
201
 
184
202
  class CERT_CONTEXT < FFI::Struct
185
203
  layout :dwCertEncodingType, DWORD,
186
- :pbCertEncoded, BYTE,
187
- :cbCertEncoded, DWORD,
188
- :pCertInfo, CERT_INFO,
189
- :hCertStore, HCERTSTORE
204
+ :pbCertEncoded, BYTE,
205
+ :cbCertEncoded, DWORD,
206
+ :pCertInfo, CERT_INFO,
207
+ :hCertStore, HCERTSTORE
190
208
  end
191
209
 
192
210
  ###############################################################################
@@ -224,6 +242,10 @@ module Win32
224
242
  safe_attach_function :CertFindCertificateInStore, [HCERTSTORE, DWORD, DWORD, DWORD, LPVOID, PCCERT_CONTEXT], PCCERT_CONTEXT
225
243
 
226
244
  safe_attach_function :PFXExportCertStoreEx, [HCERTSTORE, CRYPT_INTEGER_BLOB, LPCTSTR, LPVOID, DWORD], BOOL
245
+
246
+ # Fetches store handler of a PFX certificate
247
+ attach_function :PFXImportCertStore, [CRYPT_DATA_BLOB, LPCTSTR, DWORD], HCERTSTORE
248
+ attach_function :CertAddCertificateContextToStore, [HCERTSTORE, PCCERT_CONTEXT, DWORD, PCCERT_CONTEXT], BOOL
227
249
  end
228
250
  end
229
251
  end
@@ -15,7 +15,7 @@
15
15
  # See the License for the specific language governing permissions and
16
16
  # limitations under the License.
17
17
 
18
- require "mixlib/shellout"
18
+ require "mixlib/shellout" unless defined?(Mixlib::ShellOut)
19
19
 
20
20
  module Win32
21
21
  class Certstore
@@ -28,6 +28,7 @@ module Win32
28
28
  if cmd.error!
29
29
  raise Mixlib::ShellOut::ShellCommandFailed, cmd.error!
30
30
  end
31
+
31
32
  cmd
32
33
  end
33
34
 
@@ -96,7 +97,7 @@ module Win32
96
97
  "-InputFormat None",
97
98
  ]
98
99
 
99
- "powershell.exe #{flags.join(' ')} -Command \"#{script.gsub('"', '\"')}\""
100
+ "powershell.exe #{flags.join(" ")} -Command \"#{script.gsub('"', '\"')}\""
100
101
  end
101
102
  end
102
103
  end
@@ -19,8 +19,8 @@ require_relative "mixin/crypto"
19
19
  require_relative "mixin/string"
20
20
  require_relative "mixin/shell_out"
21
21
  require_relative "mixin/unicode"
22
- require "openssl"
23
- require "json"
22
+ require "openssl" unless defined?(OpenSSL)
23
+ require "json" unless defined?(JSON)
24
24
 
25
25
  module Win32
26
26
  class Certstore
@@ -49,6 +49,42 @@ module Win32
49
49
  end
50
50
  end
51
51
 
52
+ # Adds a PFX certificate to certificate store
53
+ #
54
+ # @see https://docs.microsoft.com/en-us/windows/desktop/api/wincrypt/nf-wincrypt-pfximportcertstore PFXImportCertStore function
55
+ # @see https://docs.microsoft.com/en-us/windows/desktop/api/wincrypt/nf-wincrypt-certaddcertificatecontexttostore CertAddCertificateContextToStore
56
+ #
57
+ # @param certstore_handler [FFI::Pointer] Handle of the store where certificate should be imported
58
+ # @param path [String] Path of the certificate that should be imported
59
+ # @param password [String] Password of the certificate
60
+ # @param key_properties [Integer] dwFlags used to specify properties of the pfx key, see link above
61
+ #
62
+ # @return [Boolean]
63
+ #
64
+ # @raise [SystemCallError] when Crypt API would not be able to perform some action
65
+ #
66
+ def cert_add_pfx(certstore_handler, path, password = "", key_properties = 0)
67
+ cert_added = false
68
+ # Imports a PFX BLOB and returns the handle of a store
69
+ pfx_cert_store = PFXImportCertStore(CRYPT_DATA_BLOB.new(File.binread(path)), wstring(password), key_properties)
70
+ raise if pfx_cert_store.null?
71
+
72
+ # Find all the certificate contexts in certificate store and add them ino the store
73
+ while (cert_context = CertEnumCertificatesInStore(pfx_cert_store, cert_context)) && (not cert_context.null?)
74
+ # Add certificate context to the certificate store
75
+ args = add_certcontxt_args(certstore_handler, cert_context)
76
+ cert_added = CertAddCertificateContextToStore(*args)
77
+ raise unless cert_added
78
+ end
79
+ cert_added
80
+ rescue
81
+ lookup_error("Add a PFX")
82
+ ensure
83
+ if pfx_cert_store && !pfx_cert_store.null?
84
+ close_cert_store(pfx_cert_store)
85
+ end
86
+ end
87
+
52
88
  # Get certificate from open certificate store and return certificate object
53
89
  # certificate_thumbprint => thumbprint is a hash. which could be sha1 or md5.
54
90
  def cert_get(certificate_thumbprint)
@@ -89,7 +125,7 @@ module Win32
89
125
  begin
90
126
  cert_args = cert_find_args(store_handler, thumbprint)
91
127
  pcert_context = CertFindCertificateInStore(*cert_args)
92
- if !pcert_context.null?
128
+ unless pcert_context.null?
93
129
  cert_delete_flag = CertDeleteCertificateFromStore(CertDuplicateCertificateContext(pcert_context)) || lookup_error
94
130
  end
95
131
  CertFreeCertificateContext(pcert_context)
@@ -115,6 +151,7 @@ module Win32
115
151
  # search_token => CN, RDN or any certificate attribute
116
152
  def cert_search(store_handler, search_token)
117
153
  raise ArgumentError, "Invalid search token" if !search_token || search_token.strip.empty?
154
+
118
155
  certificate_list = []
119
156
  begin
120
157
  while (pcert_context = CertEnumCertificatesInStore(store_handler, pcert_context)) && !pcert_context.null?
@@ -130,6 +167,12 @@ module Win32
130
167
  certificate_list
131
168
  end
132
169
 
170
+ # To close and destroy pointer of open certificate store handler
171
+ def close_cert_store(certstore_handler = @certstore_handler)
172
+ closed = CertCloseStore(certstore_handler, CERT_CLOSE_STORE_FORCE_FLAG)
173
+ lookup_error("close") unless closed
174
+ end
175
+
133
176
  private
134
177
 
135
178
  # Build arguments for CertAddEncodedCertificateToStore
@@ -142,6 +185,11 @@ module Win32
142
185
  [store_handler, ENCODING_TYPE, 0, CERT_FIND_SHA1_HASH, CRYPT_HASH_BLOB.new(thumbprint), nil]
143
186
  end
144
187
 
188
+ # Build arguments for CertAddCertificateContextToStore
189
+ def add_certcontxt_args(certstore_handler, cert_context)
190
+ [certstore_handler, cert_context, CERT_STORE_ADD_REPLACE_EXISTING, nil]
191
+ end
192
+
145
193
  # Match certificate CN exist in cert_rdn
146
194
  def is_cn_match?(cert_rdn, certificate_name)
147
195
  cert_rdn.read_wstring.match(/(^|\W)#{certificate_name}($|\W)/i)
@@ -172,6 +220,7 @@ module Win32
172
220
  # Verify OpenSSL::X509::Certificate object
173
221
  def verify_certificate(cert_pem)
174
222
  return "Certificate not found" if cert_pem.empty?
223
+
175
224
  valid_duration?(build_openssl_obj(cert_pem))
176
225
  end
177
226
 
@@ -1,6 +1,6 @@
1
1
  module Win32
2
2
  class Certstore
3
- VERSION = "0.2.2".freeze
3
+ VERSION = "0.4.1".freeze
4
4
  MAJOR, MINOR, TINY = VERSION.split(".")
5
5
  end
6
6
  end
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.2.2
4
+ version: 0.4.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chef Software
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-01-16 00:00:00.000000000 Z
11
+ date: 2020-08-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -104,8 +104,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
104
104
  - !ruby/object:Gem::Version
105
105
  version: '0'
106
106
  requirements: []
107
- rubyforge_project:
108
- rubygems_version: 2.7.6
107
+ rubygems_version: 3.0.3
109
108
  signing_key:
110
109
  specification_version: 4
111
110
  summary: Ruby library for accessing the certificate store on Windows.