win32-certstore 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 3f88b178dce120110256036f506c0643650a851f
4
+ data.tar.gz: 26e4d3283456a4e3f4297b5d076df2e1a2f677d5
5
+ SHA512:
6
+ metadata.gz: 2768217e40d97a78ca9c0f393ac1afe154e14f833a7f549fcb7b478ffab5666a2c051df349bbceb9ce32810863d1a366760f4b397097c2a5b9ee52fb1bf7a9f4
7
+ data.tar.gz: 853495d9d5334d56b268fa34d9b3b4c9e5afa3bf913f7b817b67aec6e5c40516ff17b4060ec63da94eec7f97ffc6dc253006a6596f86d57acb88342fa2d605f2
@@ -0,0 +1,225 @@
1
+ # win32-certstore
2
+ Ruby library for accessing the certificate store on Microsoft Windows:
3
+
4
+ ## Subcommands
5
+
6
+ This library provides the following features.
7
+
8
+ ### Open certificate store
9
+
10
+ Any valid certificate store can be opened in two ways:
11
+
12
+ ```
13
+ Win32::Certstore.open("Root") do |store|
14
+ //your code should be here!
15
+ end
16
+ ```
17
+
18
+ or
19
+
20
+ ```
21
+ store = Win32::Certstore.open("Root")
22
+ ```
23
+
24
+ ### Add certificate
25
+
26
+ This method adds a new certificate to an open certificate store.
27
+
28
+ ```
29
+ Input - Certificate Object (OpenSSL::X509)
30
+ Return - True/False
31
+ ```
32
+
33
+ **Notes: The certificate must be passed as an `OpenSSL::X509` object.**
34
+
35
+ ```
36
+ raw = File.read "C:\GlobalSignRootCA.pem"
37
+ certificate_object = OpenSSL::X509::Certificate.new raw
38
+
39
+ Win32::Certstore.open('Root') do |store|
40
+ store.add(certificate_object)
41
+ end
42
+ ```
43
+
44
+ or
45
+
46
+ ```
47
+ raw = File.read "C:\GlobalSignRootCA.pem"
48
+ certificate_object = OpenSSL::X509::Certificate.new raw
49
+
50
+ store = Win32::Certstore.open('Root')
51
+ store.add(certificate_object)
52
+ store.close
53
+ ```
54
+
55
+ ### Get certificate
56
+
57
+ Gets a certificate from an open certificate store and returns it as an `OpenSSL::X509` object.
58
+
59
+ ```
60
+ Input - Certificate thumbprint
61
+ Return - Certificate Object (OpenSSL::X509)
62
+ ```
63
+
64
+ ```
65
+ Win32::Certstore.open("Root") do |store|
66
+ store.get(certificate_thumbprint)
67
+ end
68
+ ```
69
+
70
+ or
71
+
72
+ ```
73
+ store = Win32::Certstore.open("Root")
74
+ store.get(certificate_thumbprint)
75
+ store.close
76
+ ```
77
+
78
+ ### List certificates
79
+
80
+ Lists all certificates in a certificate store.
81
+
82
+ ```
83
+ Input - NA
84
+ Return - Certificate List in JSON format.
85
+ ```
86
+
87
+ ```
88
+ Win32::Certstore.open("Root") do |store|
89
+ store.list
90
+ end
91
+ ```
92
+
93
+ or
94
+
95
+ ```
96
+ store = Win32::Certstore.open("Root")
97
+ store.list
98
+ store.close
99
+ ```
100
+
101
+ ### Delete certificate
102
+
103
+ Deletes a certificate from a certificate store.
104
+
105
+ ```
106
+ Input - Certificate thumbprint
107
+ Return - True/False
108
+ ```
109
+
110
+ ```
111
+ Win32::Certstore.open("Root") do |store|
112
+ store.delete(certificate_thumbprint)
113
+ end
114
+ ```
115
+
116
+ or
117
+
118
+ ```
119
+ store = Win32::Certstore.open("Root")
120
+ store.delete(certificate_thumbprint)
121
+ store.close
122
+ ```
123
+
124
+ ### Search certificate
125
+
126
+ Searches for a certificate in an open certificate store.
127
+
128
+ ```
129
+ Input - Search Token as: Comman name, Friendly name, RDN and other attributes
130
+ Return - Matching certificate list
131
+ ```
132
+
133
+ ```
134
+ Win32::Certstore.open("Root") do |store|
135
+ store.search(search_token)
136
+ end
137
+ ```
138
+
139
+ or
140
+
141
+ ```
142
+ store = Win32::Certstore.open("Root")
143
+ store.search(search_token)
144
+ store.close
145
+ ```
146
+
147
+ ### Validate certificate
148
+
149
+ Validates a certificate in a certificate store on the basis of time validity.
150
+
151
+ ```
152
+ Input - Certificate thumbprint
153
+ Return - True/False
154
+
155
+ ```
156
+
157
+ ```
158
+ Win32::Certstore.open("Root") do |store|
159
+ store.valid?(certificate_thumbprint)
160
+ end
161
+ ```
162
+
163
+ or
164
+
165
+ ```
166
+ store = Win32::Certstore.open("Root")
167
+ store.valid?(certificate_thumbprint)
168
+ store.close
169
+ ```
170
+
171
+ ### Performing multiple operations
172
+
173
+ To perform more than one operations with single certificate store object
174
+
175
+ ```
176
+ raw = File.read "C:\GlobalSignRootCA.pem"
177
+ certificate_object = OpenSSL::X509::Certificate.new raw
178
+
179
+ Win32::Certstore.open('Root') do |store|
180
+ store.add(certificate_object)
181
+ store.list
182
+ end
183
+ ```
184
+
185
+ or
186
+
187
+ ```
188
+ raw = File.read "C:\GlobalSignRootCA.pem"
189
+ certificate_object = OpenSSL::X509::Certificate.new raw
190
+
191
+ store = Win32::Certstore.open('Root')
192
+ store.add(certificate_object)
193
+ store.list
194
+ store.close
195
+ ```
196
+
197
+ ## Requirements / setup
198
+
199
+ ### Ruby
200
+
201
+ Ruby 1.9.3+ is required.
202
+
203
+ ## CONTRIBUTING:
204
+
205
+ Please file bugs against the WIN32-CERTSTORE project at https://github.com/chef/win32-certstore/issues.
206
+
207
+ More information on the contribution process for Chef projects can be found in the [Chef Contributions document](http://docs.chef.io/community_contributions.html).
208
+
209
+ # LICENSE:
210
+
211
+ Author:: Bryan McLellan (<btm@chef.io>)
212
+ Copyright:: 2017-2018 Chef Software, Inc.
213
+ License:: Apache License, Version 2.0
214
+
215
+ Licensed under the Apache License, Version 2.0 (the "License");
216
+ you may not use this file except in compliance with the License.
217
+ You may obtain a copy of the License at
218
+
219
+ http://www.apache.org/licenses/LICENSE-2.0
220
+
221
+ Unless required by applicable law or agreed to in writing, software
222
+ distributed under the License is distributed on an "AS IS" BASIS,
223
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
224
+ See the License for the specific language governing permissions and
225
+ limitations under the License.
@@ -0,0 +1,18 @@
1
+ #
2
+ # Author:: Nimisha Sharad (<nimisha.sharad@msystechnologies.com>)
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_relative "win32/certstore"
@@ -0,0 +1,129 @@
1
+ #
2
+ # Author:: Nimisha Sharad (<nimisha.sharad@msystechnologies.com>)
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_relative "certstore/mixin/crypto"
19
+ require_relative "certstore/mixin/assertions"
20
+ require_relative "certstore/mixin/helper"
21
+ require_relative "certstore/mixin/string"
22
+ require_relative "certstore/store_base"
23
+ require_relative "certstore/version"
24
+
25
+ module Win32
26
+ class Certstore
27
+ include Win32::Certstore::Mixin::Crypto
28
+ extend Win32::Certstore::Mixin::Assertions
29
+ include Win32::Certstore::Mixin::String
30
+ include Win32::Certstore::StoreBase
31
+
32
+ attr_reader :store_name
33
+
34
+ def initialize(store_name)
35
+ @certstore_handler = open(store_name)
36
+ end
37
+
38
+ # To open given certificate store
39
+ def self.open(store_name)
40
+ validate_store(store_name)
41
+ if block_given?
42
+ yield new(store_name)
43
+ else
44
+ new(store_name)
45
+ end
46
+ end
47
+
48
+ # Adds a new certificate to an open certificate store
49
+ # @param request [Object] of certificate in OpenSSL::X509::Certificate.new format
50
+ # @return [true, false] only true or false
51
+ def add(certificate_obj)
52
+ cert_add(certstore_handler, certificate_obj)
53
+ end
54
+
55
+ # Return `OpenSSL::X509` certificate object
56
+ # @param request [thumbprint<string>] of certificate
57
+ # @return [Object] of certificates in OpenSSL::X509 format
58
+ def get(certificate_thumbprint)
59
+ cert_get(certificate_thumbprint)
60
+ end
61
+
62
+ # Returns all the certificates in a store
63
+ # @param [nil]
64
+ # @return [Array] array of certificates list
65
+ def list
66
+ cert_list(certstore_handler)
67
+ end
68
+
69
+ # Delete existing certificate from open certificate store
70
+ # @param request [thumbprint<string>] of certificate
71
+ # @return [true, false] only true or false
72
+ def delete(certificate_thumbprint)
73
+ cert_delete(certstore_handler, certificate_thumbprint)
74
+ end
75
+
76
+ # Returns all matching certificates in a store
77
+ # @param request[search_token<string>] attributes of certificates as: CN, RDN, Friendly Name and other attributes
78
+ # @return [Array] array of certificates list
79
+ def search(search_token)
80
+ cert_search(certstore_handler, search_token)
81
+ end
82
+
83
+ # Validates a certificate in a certificate store on the basis of time validity
84
+ # @param request[thumbprint<string>] of certificate
85
+ # @return [true, false] only true or false
86
+ def valid?(certificate_thumbprint)
87
+ cert_validate(certificate_thumbprint)
88
+ end
89
+
90
+ # To close and destroy pointer of open certificate store handler
91
+ def close
92
+ closed = CertCloseStore(@certstore_handler, CERT_CLOSE_STORE_FORCE_FLAG)
93
+ unless closed
94
+ last_error = FFI::LastError.error
95
+ raise SystemCallError.new("Unable to close the Certificate Store.", last_error)
96
+ end
97
+ remove_finalizer
98
+ end
99
+
100
+ private
101
+
102
+ attr_reader :certstore_handler
103
+
104
+ # To open certstore and return open certificate store pointer
105
+ def open(store_name)
106
+ certstore_handler = CertOpenSystemStoreW(nil, wstring(store_name))
107
+ unless certstore_handler
108
+ last_error = FFI::LastError.error
109
+ raise SystemCallError.new("Unable to open the Certificate Store `#{store_name}`.", last_error)
110
+ end
111
+ add_finalizer(certstore_handler)
112
+ certstore_handler
113
+ end
114
+
115
+ # Get all open certificate store handler
116
+ def add_finalizer(certstore_handler)
117
+ ObjectSpace.define_finalizer(self, self.class.finalize(certstore_handler))
118
+ end
119
+
120
+ def self.finalize(certstore_handler)
121
+ proc { puts "DESTROY OBJECT #{certstore_handler}" }
122
+ end
123
+
124
+ # To close all open certificate store at the end
125
+ def remove_finalizer
126
+ ObjectSpace.undefine_finalizer(self)
127
+ end
128
+ end
129
+ end
@@ -0,0 +1,90 @@
1
+ #
2
+ # Author:: Piyush Awasthi (<piyush.awasthi@msystechnologies.com>)
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
+ require "openssl"
18
+
19
+ module Win32
20
+ class Certstore
21
+ module Mixin
22
+ module Assertions
23
+ # Validate certificate store name
24
+ def validate_store(store_name)
25
+ unless valid_store_name.include?(store_name&.upcase)
26
+ raise ArgumentError, "Invalid Certificate Store."
27
+ end
28
+ end
29
+
30
+ # Validate certificate type
31
+ def validate_certificate(cert_file_path)
32
+ unless !cert_file_path.nil? && File.extname(cert_file_path) =~ /.cer|.crt|.pfx|.der/
33
+ raise ArgumentError, "Invalid Certificate format."
34
+ end
35
+ end
36
+
37
+ # Validate certificate Object
38
+ def validate_certificate_obj(cert_obj)
39
+ unless cert_obj.class == OpenSSL::X509::Certificate
40
+ raise ArgumentError, "Invalid Certificate object."
41
+ end
42
+ end
43
+
44
+ # Validate thumbprint
45
+ def validate_thumbprint(cert_thumbprint)
46
+ if cert_thumbprint.nil? || cert_thumbprint.strip.empty?
47
+ raise ArgumentError, "Invalid certificate thumbprint."
48
+ end
49
+ end
50
+
51
+ # Validate certificate name not nil/empty
52
+ def validate!(token)
53
+ raise ArgumentError, "Invalid search token" if !token || token.strip.empty?
54
+ end
55
+
56
+ # Common System call errors
57
+ def lookup_error(failed_operation = nil)
58
+ error_no = FFI::LastError.error
59
+ case error_no
60
+ when 1223
61
+ raise SystemCallError.new("The operation was canceled by the user", error_no)
62
+ when -2146885628
63
+ raise SystemCallError.new("Cannot find object or property", error_no)
64
+ when -2146885629
65
+ raise SystemCallError.new("An error occurred while reading or writing to a file.", error_no)
66
+ when -2146881269
67
+ raise SystemCallError.new("ASN1 bad tag value met. -- Is the certificate in DER format?", error_no)
68
+ when -2146881278
69
+ raise SystemCallError.new("ASN1 unexpected end of data.", error_no)
70
+ when -2147024891
71
+ raise SystemCallError.new("System.UnauthorizedAccessException, Access denied..", error_no)
72
+ else
73
+ raise SystemCallError.new("Unable to #{failed_operation} certificate.", error_no)
74
+ end
75
+ end
76
+
77
+ private
78
+
79
+ # These Are Valid certificate store name
80
+ # CA -> Certification authority certificates.
81
+ # MY -> A certificate store that holds certificates with associated private keys.
82
+ # ROOT -> Root certificates.
83
+ # SPC -> Software Publisher Certificate.
84
+ def valid_store_name
85
+ %w{MY CA ROOT SPC}
86
+ end
87
+ end
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,203 @@
1
+ #
2
+ # Author:: Nimisha Sharad (<nimisha.sharad@msystechnologies.com>)
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
+
19
+ require "ffi"
20
+
21
+ module Win32
22
+ class Certstore
23
+ module Mixin
24
+ module Crypto
25
+ extend FFI::Library
26
+
27
+ ffi_lib "Crypt32"
28
+ ffi_convention :stdcall
29
+
30
+ # Attempts to use FFI's attach_function method to link a native Win32
31
+ # function into the calling module. If this fails a dummy method is
32
+ # defined which when called, raises a helpful exception to the end-user.
33
+ module FFI::Library
34
+ def safe_attach_function(win32_func, *args)
35
+ attach_function(win32_func.to_sym, *args)
36
+ rescue FFI::NotFoundError
37
+ define_method(win32_func.to_sym) do |*margs|
38
+ raise NotImplementedError, "This version of Windows does not implement the Win32 function [#{win32_func}]."
39
+ end
40
+ end
41
+ end
42
+
43
+ ###############################################
44
+ # Win32 API Constants
45
+ ###############################################
46
+
47
+ CERT_CLOSE_STORE_CHECK_FLAG = 0
48
+ CERT_CLOSE_STORE_FORCE_FLAG = 1
49
+
50
+ # cert encoding flags.
51
+ CRYPT_ASN_ENCODING = 0x00000001
52
+ CRYPT_NDR_ENCODING = 0x00000002
53
+ X509_ASN_ENCODING = 0x00000001
54
+ X509_NDR_ENCODING = 0x00000002
55
+ PKCS_7_ASN_ENCODING = 0x00010000
56
+ PKCS_7_NDR_ENCODING = 0x00020000
57
+ PKCS_7_OR_X509_ASN_ENCODING = (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING)
58
+
59
+ # Certificate Display Format
60
+ CERT_NAME_EMAIL_TYPE = 1
61
+ CERT_NAME_RDN_TYPE = 2
62
+ CERT_NAME_ATTR_TYPE = 3
63
+ CERT_NAME_SIMPLE_DISPLAY_TYPE = 4
64
+ CERT_NAME_FRIENDLY_DISPLAY_TYPE = 5
65
+ CERT_NAME_DNS_TYPE = 6
66
+ CERT_NAME_URL_TYPE = 7
67
+ CERT_NAME_UPN_TYPE = 8
68
+
69
+ # Retrieve Certificates flag
70
+ CERT_FIND_SUBJECT_STR = 0x00080007
71
+ CERT_FIND_ISSUER_STR = 0x00080004
72
+
73
+ # List Certificates Flag
74
+ CERT_NAME_ISSUER_FLAG = 0x1
75
+ CERT_NAME_DISABLE_IE4_UTF8_FLAG = 0x00010000
76
+ CERT_NAME_SEARCH_ALL_NAMES_FLAG = 0x2
77
+ CERT_NAME_STR_ENABLE_PUNYCODE_FLAG = 0x00200000
78
+
79
+ # Define ffi pointer
80
+ HCERTSTORE = FFI::TypeDefs[:pointer]
81
+ HCRYPTPROV_LEGACY = FFI::TypeDefs[:pointer]
82
+ PCCERT_CONTEXT = FFI::TypeDefs[:pointer]
83
+ BYTE = FFI::TypeDefs[:pointer]
84
+ DWORD = FFI::TypeDefs[:uint32]
85
+ BLOB = FFI::TypeDefs[:ulong]
86
+ LPSTR = FFI::TypeDefs[:pointer]
87
+ LPCTSTR = FFI::TypeDefs[:pointer]
88
+ BOOL = FFI::TypeDefs[:bool]
89
+ INT_PTR = FFI::TypeDefs[:int]
90
+ LONG = FFI::TypeDefs[:long]
91
+ LPVOID = FFI::TypeDefs[:pointer]
92
+ LPTSTR = FFI::TypeDefs[:pointer]
93
+ LMSTR = FFI::TypeDefs[:pointer]
94
+ PWSTR = FFI::TypeDefs[:pointer]
95
+ LPFILETIME = FFI::TypeDefs[:pointer]
96
+ PCERT_INFO = FFI::TypeDefs[:pointer]
97
+ PCTL_USAGE = FFI::TypeDefs[:pointer]
98
+ PCTL_VERIFY_USAGE_PARA = FFI::TypeDefs[:pointer]
99
+ PCTL_VERIFY_USAGE_STATUS = FFI::TypeDefs[:pointer]
100
+
101
+ class FILETIME < FFI::Struct
102
+ layout :dwLowDateTime, DWORD,
103
+ :dwHighDateTime, DWORD
104
+ end
105
+
106
+ class CRYPT_INTEGER_BLOB < FFI::Struct
107
+ layout :cbData, DWORD, # Count, in bytes, of data
108
+ :pbData, :pointer # Pointer to data buffer
109
+ end
110
+
111
+ class CRYPT_NAME_BLOB < FFI::Struct
112
+ layout :cbData, DWORD, # Count, in bytes, of data
113
+ :pbData, :pointer # Pointer to data buffer
114
+ def initialize(str = nil)
115
+ super(nil)
116
+ if str
117
+ self[:pbData] = FFI::MemoryPointer.new(2, 128)
118
+ end
119
+ end
120
+ end
121
+
122
+ class CERT_EXTENSION < FFI::Struct
123
+ layout :pszObjId, LPTSTR,
124
+ :fCritical, BOOL,
125
+ :Value, CRYPT_INTEGER_BLOB
126
+ end
127
+
128
+ class CRYPT_BIT_BLOB < FFI::Struct
129
+ layout :cbData, DWORD,
130
+ :pbData, BYTE,
131
+ :cUnusedBits, DWORD
132
+ end
133
+
134
+ class CRYPT_ALGORITHM_IDENTIFIER < FFI::Struct
135
+ layout :pszObjId, LPSTR,
136
+ :Parameters, CRYPT_INTEGER_BLOB
137
+ end
138
+
139
+ class CERT_PUBLIC_KEY_INFO < FFI::Struct
140
+ layout :Algorithm, CRYPT_ALGORITHM_IDENTIFIER,
141
+ :PublicKey, CRYPT_BIT_BLOB
142
+ end
143
+
144
+ class CERT_INFO < FFI::Struct
145
+ layout :dwVersion, DWORD,
146
+ :SerialNumber, CRYPT_INTEGER_BLOB,
147
+ :SignatureAlgorithm, CRYPT_ALGORITHM_IDENTIFIER,
148
+ :Issuer, CRYPT_NAME_BLOB,
149
+ :NotBefore, FILETIME,
150
+ :NotAfter, FILETIME,
151
+ :Subject, CRYPT_NAME_BLOB,
152
+ :SubjectPublicKeyInfo, CERT_PUBLIC_KEY_INFO,
153
+ :IssuerUniqueId, CRYPT_BIT_BLOB,
154
+ :SubjectUniqueId, CRYPT_BIT_BLOB,
155
+ :cExtension, DWORD,
156
+ :rgExtension, CERT_EXTENSION
157
+ end
158
+
159
+ class CERT_CONTEXT < FFI::Struct
160
+ layout :dwCertEncodingType, DWORD,
161
+ :pbCertEncoded, BYTE,
162
+ :cbCertEncoded, DWORD,
163
+ :pCertInfo, CERT_INFO,
164
+ :hCertStore, HCERTSTORE
165
+ end
166
+
167
+ ###############################################################################
168
+ # Windows Function
169
+ # To know description about below windows function
170
+ # Search Ref: https://msdn.microsoft.com/en-us/library/windows/desktop/aa376560
171
+ ###############################################################################
172
+
173
+ # To opens the most common system certificate store
174
+ safe_attach_function :CertOpenSystemStoreW, [HCRYPTPROV_LEGACY, LPCTSTR], HCERTSTORE
175
+ # To close the already open certificate store
176
+ safe_attach_function :CertCloseStore, [HCERTSTORE, DWORD], BOOL
177
+ # To create encoded certificate context
178
+ safe_attach_function :CertCreateCertificateContext, [DWORD, BYTE, DWORD], PCCERT_CONTEXT
179
+ # To retrieves certificates in a certificate store
180
+ safe_attach_function :CertEnumCertificatesInStore, [HCERTSTORE, PCCERT_CONTEXT], PCCERT_CONTEXT
181
+ # To get certificate name
182
+ safe_attach_function :CertGetNameStringW, [PCCERT_CONTEXT, DWORD, DWORD, LPVOID, LPTSTR, DWORD], DWORD
183
+ # To find all of the property identifiers for the specified certificate.
184
+ safe_attach_function :CertEnumCertificateContextProperties, [PCCERT_CONTEXT, DWORD], DWORD
185
+ # Clean up
186
+ safe_attach_function :CertFreeCertificateContext, [PCCERT_CONTEXT], BOOL
187
+ # Add certificate file in certificate store.
188
+ safe_attach_function :CertAddSerializedElementToStore, [HCERTSTORE, :pointer, DWORD, DWORD, DWORD, DWORD, LMSTR, LPVOID], BOOL
189
+ # Add certification to certification store - Ref: https://msdn.microsoft.com/en-us/library/windows/desktop/aa376015(v=vs.85).aspx
190
+ safe_attach_function :CertAddEncodedCertificateToStore, [HCERTSTORE, DWORD, PWSTR, DWORD, INT_PTR, PCCERT_CONTEXT], BOOL
191
+ safe_attach_function :CertSerializeCertificateStoreElement, [PCCERT_CONTEXT, DWORD, :pointer, DWORD], BOOL
192
+ # Duplicates a certificate context by incrementing its reference count
193
+ safe_attach_function :CertDuplicateCertificateContext, [PCCERT_CONTEXT], PCCERT_CONTEXT
194
+ # Delete certification from certification store
195
+ safe_attach_function :CertDeleteCertificateFromStore, [PCCERT_CONTEXT], BOOL
196
+ # To retrieve specific certificates from certificate store
197
+ safe_attach_function :CertFindCertificateInStore, [HCERTSTORE, DWORD, DWORD, DWORD, LPVOID, PCCERT_CONTEXT], PCCERT_CONTEXT
198
+
199
+ safe_attach_function :PFXExportCertStoreEx, [HCERTSTORE, CRYPT_INTEGER_BLOB, LPCTSTR, LPVOID, DWORD], BOOL
200
+ end
201
+ end
202
+ end
203
+ end
@@ -0,0 +1,50 @@
1
+ #
2
+ # Author:: Piyush Awasthi (<piyush.awasthi@msystechnologies.com>)
3
+ # Copyright:: Copyright (c) 2018 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 'date'
19
+
20
+ module Win32
21
+ class Certstore
22
+ module Mixin
23
+ module Helper
24
+
25
+ # PSCommand to search certificate from thumbprint and convert in pem
26
+ def cert_ps_cmd(thumbprint)
27
+ <<-EOH
28
+ $content = $null
29
+ $cert = Get-ChildItem Cert:\ -Recurse | Where { $_.Thumbprint -eq '#{thumbprint}' }
30
+ if($cert -ne $null)
31
+ {
32
+ $content = @(
33
+ '-----BEGIN CERTIFICATE-----'
34
+ [System.Convert]::ToBase64String($cert.RawData, 'InsertLineBreaks')
35
+ '-----END CERTIFICATE-----'
36
+ )
37
+ }
38
+ $content
39
+ EOH
40
+ end
41
+
42
+ # validate certificate not_before and not_after date in UTC
43
+ def valid_duration?(cert_obj)
44
+ cert_obj.not_before < Time.now.utc && cert_obj.not_after > Time.now.utc
45
+ end
46
+
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,104 @@
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"
19
+
20
+ module Win32
21
+ class Certstore
22
+ module Mixin
23
+ module ShellOut
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
+ cmd
32
+ end
33
+ # Run a command under powershell with the same API as shell_out. The
34
+ # options hash is extended to take an "architecture" flag which
35
+ # can be set to :i386 or :x86_64 to force the windows architecture.
36
+ #
37
+ # @param script [String] script to run
38
+ # @param options [Hash] options hash
39
+ # @return [Mixlib::Shellout] mixlib-shellout object
40
+ def powershell_out(*command_args)
41
+ script = command_args.first
42
+ options = command_args.last.is_a?(Hash) ? command_args.last : nil
43
+
44
+ run_command_with_os_architecture(script, options)
45
+ end
46
+
47
+ # Run a command under powershell with the same API as shell_out!
48
+ # (raises exceptions on errors)
49
+ #
50
+ # @param script [String] script to run
51
+ # @param options [Hash] options hash
52
+ # @return [Mixlib::Shellout] mixlib-shellout object
53
+ def powershell_out!(*command_args)
54
+ cmd = powershell_out(*command_args)
55
+ cmd.error!
56
+ cmd
57
+ end
58
+
59
+ private
60
+
61
+ # Helper function to run shell_out and wrap it with the correct
62
+ # flags to possibly disable WOW64 redirection (which we often need
63
+ # because chef-client runs as a 32-bit app on 64-bit windows).
64
+ #
65
+ # @param script [String] script to run
66
+ # @param options [Hash] options hash
67
+ # @return [Mixlib::Shellout] mixlib-shellout object
68
+ def run_command_with_os_architecture(script, options)
69
+ options ||= {}
70
+ options = options.dup
71
+ arch = options.delete(:architecture)
72
+
73
+ shell_out_command(
74
+ build_powershell_command(script),
75
+ options
76
+ )
77
+ end
78
+
79
+ # Helper to build a powershell command around the script to run.
80
+ #
81
+ # @param script [String] script to run
82
+ # @return [String] powershell command to execute
83
+ def build_powershell_command(script)
84
+ flags = [
85
+ # Hides the copyright banner at startup.
86
+ "-NoLogo",
87
+ # Does not present an interactive prompt to the user.
88
+ "-NonInteractive",
89
+ # Does not load the Windows PowerShell profile.
90
+ "-NoProfile",
91
+ # always set the ExecutionPolicy flag
92
+ # see http://technet.microsoft.com/en-us/library/ee176961.aspx
93
+ "-ExecutionPolicy Unrestricted",
94
+ # Powershell will hang if STDIN is redirected
95
+ # http://connect.microsoft.com/PowerShell/feedback/details/572313/powershell-exe-can-hang-if-stdin-is-redirected
96
+ "-InputFormat None",
97
+ ]
98
+
99
+ "powershell.exe #{flags.join(' ')} -Command \"#{script.gsub('"', '\"')}\""
100
+ end
101
+ end
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,71 @@
1
+ #
2
+ # Author:: Jay Mundrawala(<jdm@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
+ module Win32
19
+ class Certstore
20
+ module Mixin
21
+ module String
22
+ def wstring(str)
23
+ if str.nil? || str.encoding == Encoding::UTF_16LE
24
+ str
25
+ else
26
+ utf8_to_wide(str)
27
+ end
28
+ end
29
+
30
+ def utf8_to_wide(ustring)
31
+ # ensure it is actually UTF-8
32
+ # Ruby likes to mark binary data as ASCII-8BIT
33
+ ustring = (ustring + "").force_encoding("UTF-8") if ustring.respond_to?(:force_encoding) && ustring.encoding.name != "UTF-8"
34
+
35
+ # ensure we have the double-null termination Windows Wide likes
36
+ ustring += "\000\000" if ustring.length == 0 || ustring[-1].chr != "\000"
37
+
38
+ # encode it all as UTF-16LE AKA Windows Wide Character AKA Windows Unicode
39
+ ustring = begin
40
+ if ustring.respond_to?(:encode)
41
+ ustring.encode("UTF-16LE")
42
+ else
43
+ require "iconv"
44
+ Iconv.conv("UTF-16LE", "UTF-8", ustring)
45
+ end
46
+ end
47
+ ustring
48
+ end
49
+
50
+ def wide_to_utf8(wstring)
51
+ # ensure it is actually UTF-16LE
52
+ # Ruby likes to mark binary data as ASCII-8BIT
53
+ wstring = wstring.force_encoding("UTF-16LE") if wstring.respond_to?(:force_encoding)
54
+
55
+ # encode it all as UTF-8
56
+ wstring = begin
57
+ if wstring.respond_to?(:encode)
58
+ wstring.encode("UTF-8")
59
+ else
60
+ require "iconv"
61
+ Iconv.conv("UTF-8", "UTF-16LE", wstring)
62
+ end
63
+ end
64
+ # remove trailing CRLF and NULL characters
65
+ wstring.strip!
66
+ wstring
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,50 @@
1
+ #
2
+ # Author:: John Keiser (<jkeiser@chef.io>)
3
+ # Author:: Seth Chisamore (<schisamo@chef.io>)
4
+ # Copyright:: Copyright (c) 2017 Chef Software, Inc.
5
+ # License:: Apache License, Version 2.0
6
+ #
7
+ # Licensed under the Apache License, Version 2.0 (the "License");
8
+ # you may not use this file except in compliance with the License.
9
+ # You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an "AS IS" BASIS,
15
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ # See the License for the specific language governing permissions and
17
+ # limitations under the License.
18
+
19
+ require_relative "string"
20
+
21
+ module Win32::Certstore::Mixin::Unicode
22
+ end
23
+
24
+ module FFI
25
+ class Pointer
26
+ include Win32::Certstore::Mixin::String
27
+ def read_wstring(num_wchars = nil)
28
+ if num_wchars.nil?
29
+ # Find the length of the string
30
+ length = 0
31
+ last_char = nil
32
+ while last_char != "\000\000"
33
+ length += 1
34
+ last_char = get_bytes(0, length * 2)[-2..-1]
35
+ end
36
+
37
+ num_wchars = length
38
+ end
39
+ wide_to_utf8(get_bytes(0, num_wchars * 2))
40
+ end
41
+ end
42
+ end
43
+
44
+ class String
45
+ include Win32::Certstore::Mixin::String
46
+
47
+ def to_wstring
48
+ utf8_to_wide(self)
49
+ end
50
+ end
@@ -0,0 +1,214 @@
1
+ #
2
+ # Author:: Piyush Awasthi (<piyush.awasthi@msystechnologies.com>)
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_relative "mixin/crypto"
19
+ require_relative "mixin/string"
20
+ require_relative "mixin/shell_out"
21
+ require_relative "mixin/unicode"
22
+ require "openssl"
23
+ require "json"
24
+
25
+ module Win32
26
+ class Certstore
27
+ module StoreBase
28
+ include Win32::Certstore::Mixin::Crypto
29
+ include Win32::Certstore::Mixin::Assertions
30
+ include Win32::Certstore::Mixin::String
31
+ include Win32::Certstore::Mixin::ShellOut
32
+ include Win32::Certstore::Mixin::Unicode
33
+ include Win32::Certstore::Mixin::Helper
34
+
35
+ # Adding new certification in open certificate and return boolean
36
+ # store_handler => Open certificate store handler
37
+ # certificate_obj => certificate object must be in OpenSSL::X509
38
+ def cert_add(store_handler, certificate_obj)
39
+ validate_certificate_obj(certificate_obj)
40
+ begin
41
+ cert_args = cert_add_args(store_handler, certificate_obj)
42
+ if CertAddEncodedCertificateToStore(*cert_args)
43
+ true
44
+ else
45
+ lookup_error
46
+ end
47
+ rescue Exception => e
48
+ lookup_error("add")
49
+ end
50
+ end
51
+
52
+ # Get certificate from open certificate store and return certificate object
53
+ # store_handler => Open certificate store handler
54
+ # certificate_thumbprint => thumbprint is a hash. which could be sha1 or md5.
55
+ def cert_get(certificate_thumbprint)
56
+ validate_thumbprint(certificate_thumbprint)
57
+ thumbprint = update_thumbprint(certificate_thumbprint)
58
+ cert_pem = get_cert_pem(thumbprint)
59
+ cert_pem = format_pem(cert_pem)
60
+ unless cert_pem.empty?
61
+ build_openssl_obj(cert_pem)
62
+ end
63
+ end
64
+
65
+ # Listing certificate of open certstore and return list in json
66
+ def cert_list(store_handler)
67
+ cert_name = memory_ptr
68
+ cert_list = []
69
+ begin
70
+ while (pcert_context = CertEnumCertificatesInStore(store_handler, pcert_context)) && (not pcert_context.null?) do
71
+ cert_args = cert_get_name_args(pcert_context, cert_name, CERT_NAME_FRIENDLY_DISPLAY_TYPE)
72
+ if CertGetNameStringW(*cert_args)
73
+ cert_list << cert_name.read_wstring
74
+ end
75
+ end
76
+ CertFreeCertificateContext(pcert_context)
77
+ rescue Exception => e
78
+ lookup_error("list")
79
+ end
80
+ cert_list.to_json
81
+ end
82
+
83
+ # Deleting certificate from open certificate store and return boolean
84
+ # store_handler => Open certificate store handler
85
+ # certificate_thumbprint => thumbprint is a hash. which could be sha1 or md5.
86
+ def cert_delete(store_handler, certificate_thumbprint)
87
+ validate_thumbprint(certificate_thumbprint)
88
+ cert_name = memory_ptr
89
+ thumbprint = update_thumbprint(certificate_thumbprint)
90
+ cert_pem = format_pem(get_cert_pem(thumbprint))
91
+ cert_rdn = get_rdn(build_openssl_obj(cert_pem))
92
+ cert_delete_flag = false
93
+ begin
94
+ cert_args = cert_find_args(store_handler, cert_rdn)
95
+ if (pcert_context = CertFindCertificateInStore(*cert_args) and !pcert_context.null?)
96
+ cert_delete_flag = CertDeleteCertificateFromStore(CertDuplicateCertificateContext(pcert_context)) || lookup_error
97
+ end
98
+ CertFreeCertificateContext(pcert_context)
99
+ rescue Exception => e
100
+ lookup_error("delete")
101
+ end
102
+ cert_delete_flag
103
+ end
104
+
105
+ # Verify certificate from open certificate store and return boolean or exceptions
106
+ # store_handler => Open certificate store handler
107
+ # certificate_thumbprint => thumbprint is a hash. which could be sha1 or md5.
108
+ def cert_validate(certificate_thumbprint)
109
+ validate_thumbprint(certificate_thumbprint)
110
+ thumbprint = update_thumbprint(certificate_thumbprint)
111
+ cert_pem = get_cert_pem(thumbprint)
112
+ cert_pem = format_pem(cert_pem)
113
+ verify_certificate(cert_pem)
114
+ end
115
+
116
+ # Search certificate from open certificate store and return list
117
+ # store_handler => Open certificate store handler
118
+ # search_token => CN, RDN or any certificate attribute
119
+ def cert_search(store_handler, search_token)
120
+ raise ArgumentError, "Invalid search token" if !search_token || search_token.strip.empty?
121
+ cert_rdn = memory_ptr
122
+ certificate_list =[]
123
+ counter = 0
124
+ begin
125
+ while (pcert_context = CertEnumCertificatesInStore(store_handler, pcert_context) and !pcert_context.null?)
126
+ cert_property = get_cert_property(pcert_context)
127
+ if cert_property.include?(search_token)
128
+ certificate_list << [cert_property[CERT_NAME_FRIENDLY_DISPLAY_TYPE], cert_property[CERT_NAME_RDN_TYPE]]
129
+ end
130
+ end
131
+ CertFreeCertificateContext(pcert_context)
132
+ rescue Exception => e
133
+ lookup_error
134
+ end
135
+ certificate_list
136
+ end
137
+
138
+ private
139
+
140
+ # Build arguments for CertAddEncodedCertificateToStore
141
+ def cert_add_args(store_handler, certificate_obj)
142
+ [store_handler, X509_ASN_ENCODING, der_cert(certificate_obj), certificate_obj.to_s.bytesize, 2, nil]
143
+ end
144
+
145
+ # Build arguments for CertFindCertificateInStore
146
+ def cert_find_args(store_handler, cert_rdn)
147
+ [store_handler, X509_ASN_ENCODING, 0, CERT_FIND_ISSUER_STR, cert_rdn.to_wstring, nil]
148
+ end
149
+
150
+ # Match certificate CN exist in cert_rdn
151
+ def is_cn_match?(cert_rdn, certificate_name)
152
+ cert_rdn.read_wstring.match(/(^|\W)#{certificate_name}($|\W)/i)
153
+ end
154
+
155
+ # Get Certificate all properties
156
+ def get_cert_property(pcert_context)
157
+ property_value = memory_ptr
158
+ property_list = []
159
+ property_list[0] = ""
160
+ (1..8).to_a.each do |property_type|
161
+ CertGetNameStringW(pcert_context, property_type, CERT_NAME_ISSUER_FLAG, nil, property_value, 1024)
162
+ property_list << property_value.read_wstring
163
+ end
164
+ property_list
165
+ end
166
+
167
+ # Build argument for CertGetNameStringW
168
+ def cert_get_name_args(pcert_context, cert_name, search_type)
169
+ [pcert_context, search_type, CERT_NAME_ISSUER_FLAG, nil, cert_name, 1024]
170
+ end
171
+
172
+ # Remove extra space and : from thumbprint
173
+ def update_thumbprint(certificate_thumbprint)
174
+ certificate_thumbprint.gsub(/[^A-Za-z0-9]/, '')
175
+ end
176
+
177
+ # Verify OpenSSL::X509::Certificate object
178
+ def verify_certificate(cert_pem)
179
+ return "Certificate not found" if cert_pem.empty?
180
+ valid_duration?(build_openssl_obj(cert_pem))
181
+ end
182
+
183
+ # Convert OpenSSL::X509::Certificate object in .der formate
184
+ def der_cert(cert_obj)
185
+ FFI::MemoryPointer.from_string(cert_obj.to_der)
186
+ end
187
+
188
+ # Get certificate pem
189
+ def get_cert_pem(thumbprint)
190
+ get_data = powershell_out!(cert_ps_cmd(thumbprint))
191
+ get_data.stdout
192
+ end
193
+
194
+ # To get RDN from certificate object
195
+ def get_rdn(cert_obj)
196
+ cert_obj.issuer.to_s.concat("/").scan(/=(.*?)\//).join(", ")
197
+ end
198
+
199
+ # Format pem
200
+ def format_pem(cert_pem)
201
+ cert_pem.delete("\r")
202
+ end
203
+
204
+ # Build pem to OpenSSL::X509::Certificate object
205
+ def build_openssl_obj(cert_pem)
206
+ OpenSSL::X509::Certificate.new(cert_pem)
207
+ end
208
+ # Create empty memory pointer
209
+ def memory_ptr
210
+ FFI::MemoryPointer.new(2, 256)
211
+ end
212
+ end
213
+ end
214
+ end
@@ -0,0 +1,6 @@
1
+ module Win32
2
+ class Certstore
3
+ VERSION = "0.1.0"
4
+ MAJOR, MINOR, TINY = VERSION.split(".")
5
+ end
6
+ end
metadata ADDED
@@ -0,0 +1,125 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: win32-certstore
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - nimisha
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2018-05-03 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.12'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.12'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: mixlib-shellout
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: ffi
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ description:
84
+ email:
85
+ - nimisha.sharad@msystechnologies.com
86
+ executables: []
87
+ extensions: []
88
+ extra_rdoc_files: []
89
+ files:
90
+ - README.md
91
+ - lib/win32-certstore.rb
92
+ - lib/win32/certstore.rb
93
+ - lib/win32/certstore/mixin/assertions.rb
94
+ - lib/win32/certstore/mixin/crypto.rb
95
+ - lib/win32/certstore/mixin/helper.rb
96
+ - lib/win32/certstore/mixin/shell_out.rb
97
+ - lib/win32/certstore/mixin/string.rb
98
+ - lib/win32/certstore/mixin/unicode.rb
99
+ - lib/win32/certstore/store_base.rb
100
+ - lib/win32/certstore/version.rb
101
+ homepage: https://github.com/chef/win32-certstore
102
+ licenses: []
103
+ metadata:
104
+ yard.run: yri
105
+ post_install_message:
106
+ rdoc_options: []
107
+ require_paths:
108
+ - lib
109
+ required_ruby_version: !ruby/object:Gem::Requirement
110
+ requirements:
111
+ - - ">="
112
+ - !ruby/object:Gem::Version
113
+ version: '0'
114
+ required_rubygems_version: !ruby/object:Gem::Requirement
115
+ requirements:
116
+ - - ">="
117
+ - !ruby/object:Gem::Version
118
+ version: '0'
119
+ requirements: []
120
+ rubyforge_project:
121
+ rubygems_version: 2.6.14
122
+ signing_key:
123
+ specification_version: 4
124
+ summary: Ruby library for accessing the certificate store on Windows.
125
+ test_files: []