Skip to content

Commit

Permalink
MSYS-546 - List certificates of specific certificate store
Browse files Browse the repository at this point in the history
Signed-off-by: piyushawasthi <[email protected]>
  • Loading branch information
piyushawasthi committed Aug 16, 2017
1 parent 08c0cf4 commit 24c7ca6
Show file tree
Hide file tree
Showing 17 changed files with 448 additions and 206 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ build-iPhoneSimulator/

# for a library or gem, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# Gemfile.lock
Gemfile.lock
# .ruby-version
# .ruby-gemset

Expand Down
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@ rvm:
branches:
only:
- master
before_install: gem install bundler -v 1.12.5
before_install: gem install bundler
script: bundle exec rake spec
11 changes: 7 additions & 4 deletions Gemfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
source 'https://rubygems.org'

# Specify your gem's dependencies in win32-certstore.gemspec
gemspec
source 'https://rubygems.org'

# Specify your gem's dependencies in win32-certstore.gemspec
gemspec

gem 'pry'
gem 'rb-readline'
22 changes: 5 additions & 17 deletions lib/win32-certstore.rb
Original file line number Diff line number Diff line change
@@ -1,18 +1,6 @@
#
# Author:: Nimisha Sharad (<[email protected]>)
# Copyright:: Copyright (c) 2017 Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
$LOAD_PATH.unshift File.expand_path('../../lib/win32', __FILE__)

require 'win32/certstore/certstore'
require "backend/core_ext"
require "certstore/certstore"
require "win32-certstore/version"
require 'certstore/certificate/list'
43 changes: 0 additions & 43 deletions lib/win32/api/reserved_names.rb

This file was deleted.

83 changes: 83 additions & 0 deletions lib/win32/backend/core_ext.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
#
# Author:: Nimisha Sharad (<[email protected]>)
# Copyright:: Copyright (c) 2017 Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

require 'ffi'
require 'chef'
require 'chef/win32/api'
require 'mixlib/shellout'

module Win32
module Backend
module CoreExt
extend Chef::ReservedNames::Win32::API
extend FFI::Library

ffi_lib 'Crypt32'
ffi_convention :stdcall

###############################################
# Win32 API Constants
###############################################

CERT_CLOSE_STORE_CHECK_FLAG = 0
CERT_CLOSE_STORE_FORCE_FLAG = 1

# cert encoding flags.
CRYPT_ASN_ENCODING = 0x00000001
CRYPT_NDR_ENCODING = 0x00000002
X509_ASN_ENCODING = 0x00000001
X509_NDR_ENCODING = 0x00000002
PKCS_7_ASN_ENCODING = 0x00010000
PKCS_7_NDR_ENCODING = 0x00020000
PKCS_7_OR_X509_ASN_ENCODING = (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING)

# Define ffi pointer
HCERTSTORE = FFI::TypeDefs[:pointer]
HCRYPTPROV_LEGACY = FFI::TypeDefs[:pointer]
PCCERT_CONTEXT = FFI::TypeDefs[:pointer]
BYTE = FFI::TypeDefs[:pointer]

class CERT_CONTEXT < FFI::Struct
layout :hCertStore, :HANDLE,
:dwCertEncodingType, :DWORD,
:pbCertEncoded, :PWSTR,
:cbCertEncoded, :DWORD,
:pCertInfo, :pointer
end

###############################################################################
# Windows Function
# To know description about below windows function
# Search Ref: https://msdn.microsoft.com/en-us/library/windows/desktop/aa376560
###############################################################################

# To opens the most common system certificate store
safe_attach_function :CertOpenSystemStoreW, [HCRYPTPROV_LEGACY, :LPCTSTR], HCERTSTORE
# To close the already open certificate store
safe_attach_function :CertCloseStore, [HCERTSTORE, :DWORD], :BOOL
# To retrieves certificates in a certificate store
safe_attach_function :CertEnumCertificatesInStore, [HCERTSTORE, PCCERT_CONTEXT], PCCERT_CONTEXT
# To get certificate name
safe_attach_function :CertGetNameStringW, [PCCERT_CONTEXT, :DWORD, :DWORD, :LPVOID, :LPTSTR, :DWORD], :DWORD
# To find all of the property identifiers for the specified certificate.
safe_attach_function :CertEnumCertificateContextProperties, [PCCERT_CONTEXT, :DWORD], :DWORD
# Clean up
safe_attach_function :CertFreeCertificateContext, [PCCERT_CONTEXT], :BOOL
end
end
end
44 changes: 44 additions & 0 deletions lib/win32/backend/policies.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#
# Author:: Piyush Awasthi (<[email protected]>)
# Copyright:: Copyright (c) 2017 Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

module Win32::Backend::Policies

# Validate import certificate file format
def validate_args(import_cert_params)
unless import_cert_params.each_index.select {|i| import_cert_params[i] =~ /.cer|.crt|.pfx|.der/}
raise ArgumentError, "Invalid Certificate format."
end
end

# Validate certificate store name
def validate_store(store_name)
unless valid_store_name.include?(store_name&.upcase)
raise ArgumentError, "Invalid Certificate Store Name."
end
end

private

# These Are Valid certificate store name
# CA -> Certification authority certificates.
# MY -> A certificate store that holds certificates with associated private keys.
# ROOT -> Root certificates.
# SPC -> Software Publisher Certificate.
def valid_store_name
["MY", "CA", "ROOT", "SPC"]
end
end
29 changes: 0 additions & 29 deletions lib/win32/certstore/certificate.rb

This file was deleted.

62 changes: 62 additions & 0 deletions lib/win32/certstore/certificate/list.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
#
# Author:: Piyush Awasthi (<[email protected]>)
# Copyright:: Copyright (c) 2017 Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

require 'win32/certstore/certificate/win32_base'

module Win32
class Certstore
class Certificate
class List < Certificate
include Certificate::Win32Base

def initialize(store_name)
@store_name = store_name
# TO verify Valid ceritificate store name
validate_store(@store_name)
end

def show
# Open Valid certificate store
@store_handle = open_store(@store_name)
# Get Certificate list of open certificate store
certificates_list = list_cert
# Close Open store
close_store(@store_handle)
return certificates_list
end

def list_cert
cert_name = FFI::MemoryPointer.new(2, 128)
cert_list = []
begin
while (pCertContext = CertEnumCertificatesInStore(@store_handle, pCertContext) and not pCertContext.null? ) do
if (CertGetNameStringW(pCertContext, 5, 0, nil, cert_name, 1024))
cert_list << cert_name.read_wstring
end
end
CertFreeCertificateContext(pCertContext)
rescue Exception => e
last_error = FFI::LastError.error
raise Chef::Exceptions::Win32APIError, "Unable to load certificate with error: #{last_error}."
end
cert_list.to_json
end

end
end
end
end
69 changes: 69 additions & 0 deletions lib/win32/certstore/certificate/win32_base.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
#
# Author:: Piyush Awasthi (<[email protected]>)
# Copyright:: Copyright (c) 2017 Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

require 'win32/backend/core_ext'
require 'win32/backend/policies'

module Win32
class Certstore
class Certificate
module Win32Base
include Win32::Backend::CoreExt
include Win32::Backend::Policies
include Chef::Mixin::ShellOut
include Chef::Mixin::WideString

def open_store(store_name)
certstore_handle = CertOpenSystemStoreW(nil, wstring(store_name))
unless certstore_handle
last_error = FFI::LastError.error
raise Chef::Exceptions::Win32APIError, "Unable to open the Certificate Store `#{store_name}` with error: #{last_error}."
end
certstore_handle
end

def close_store(certstore_handle)
closed = CertCloseStore(certstore_handle, CERT_CLOSE_STORE_FORCE_FLAG)
unless closed
last_error = FFI::LastError.error
raise Chef::Exceptions::Win32APIError, "Unable to close the Certificate Store with error: #{last_error}."
end
closed
end

def update_params(user_parms)
if user_parms.size > 1
path_index = user_parms.each_index.select{|i| user_parms[i] =~ /.cer|.crt|.pfx|.der/}.first
user_parms[0], user_parms[user_parms.size-1] = user_parms.find{|loc| loc != user_parms[path_index]}.delete(' '), user_parms[path_index]
else
user_parms[0], user_parms[1] = "ROOT", user_parms[0]
end
end

def get_PScommand(user_parms)
user_parms = update_params(user_parms)
if user_parms.last =~ /.pfx/
cmd = "powershell.exe -Command certutil -addstore -f -importpfx '#{user_parms.first}' '#{user_parms.last}'"
else
cmd = "powershell.exe -Command certutil -addstore -f -v '#{user_parms.first}' '#{user_parms.last}'"
end
cmd
end
end
end
end
end
Loading

0 comments on commit 24c7ca6

Please sign in to comment.