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 +4 -4
- data/lib/win32/certstore.rb +16 -5
- data/lib/win32/certstore/mixin/assertions.rb +1 -1
- data/lib/win32/certstore/mixin/crypto.rb +48 -26
- data/lib/win32/certstore/mixin/shell_out.rb +3 -2
- data/lib/win32/certstore/store_base.rb +52 -3
- data/lib/win32/certstore/version.rb +1 -1
- metadata +3 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a571cfa5aea1f77ed28c7711fe81982338d7af42a73f886cfbdfe6df3123fc91
|
4
|
+
data.tar.gz: cb36e5aba55afe58af9a7770f330f276ad7013fe86f7d51dd1d9d372b7a9a598
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 94138aaef753c7b9830e7374fc80d53ae531c85f14677f3fc72eb4234744ee7c21737b0ee8f41d530deeec0e433196ec1acacc1792468ed0849b995ee0fab754
|
7
|
+
data.tar.gz: 5710436ecefe40dc2883375d4317d333189ef0b7896b27dd3c31e0ccf1beab9d321edab6cae714b365492aec5420853a0ec8d53cb18dd006f61ecfa1e85c8a4a
|
data/lib/win32/certstore.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
150
|
-
|
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
|
-
|
156
|
-
|
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
|
-
|
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
|
-
|
184
|
+
:PublicKey, CRYPT_BIT_BLOB
|
167
185
|
end
|
168
186
|
|
169
187
|
class CERT_INFO < FFI::Struct
|
170
188
|
layout :dwVersion, DWORD,
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
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
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
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(
|
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
|
-
|
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
|
|
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.
|
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:
|
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
|
-
|
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.
|