win32-certstore 0.1.0

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.
@@ -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: []