1
0
Fork 0
mirror of https://github.com/rest-client/rest-client.git synced 2022-11-09 13:49:40 -05:00

Adapt Windows root cert store code from puppet.

This commit is contained in:
Andy Brody 2014-03-30 17:41:51 -07:00
parent e30ecc8929
commit 1d0f0d9fa3
4 changed files with 121 additions and 0 deletions

View file

@ -2,6 +2,8 @@ source "https://rubygems.org"
gemspec
gem 'ffi', '~> 1.9', :platforms => [:mswin, :mingw]
group :test do
gem 'rake'
end

View file

@ -18,6 +18,7 @@ require File.dirname(__FILE__) + '/restclient/raw_response'
require File.dirname(__FILE__) + '/restclient/resource'
require File.dirname(__FILE__) + '/restclient/payload'
require File.dirname(__FILE__) + '/restclient/net_http_ext'
require File.dirname(__FILE__) + '/restclient/windows'
# This module's static methods are the entry point for using the REST client.
#

13
lib/restclient/windows.rb Normal file
View file

@ -0,0 +1,13 @@
module RestClient
module Windows
def self.windows?
# Ruby only sets File::ALT_SEPARATOR on Windows, and the Ruby standard
# library uses that to test what platform it's on.
!!File::ALT_SEPARATOR
end
end
end
if RestClient::Windows.windows?
require_relative './windows/root_certs'
end

View file

@ -0,0 +1,105 @@
require 'openssl'
require 'ffi'
# Adapted from Puppet, Copyright (c) Puppet Labs Inc,
# licensed under the Apache License, Version 2.0.
#
# https://github.com/puppetlabs/puppet/blob/bbe30e0a/lib/puppet/util/windows/root_certs.rb
# Represents a collection of trusted root certificates.
#
# @api public
class RestClient::Windows::RootCerts
include Enumerable
extend FFI::Library
typedef :ulong, :dword
typedef :uintptr_t, :handle
def initialize(roots)
@roots = roots
end
# Enumerates each root certificate.
# @yieldparam cert [OpenSSL::X509::Certificate] each root certificate
# @api public
def each
@roots.each {|cert| yield cert}
end
# Returns a new instance.
# @return [Puppet::Util::Windows::RootCerts] object constructed from current root certificates
def self.instance
new(self.load_certs)
end
# Returns an array of root certificates.
#
# @return [Array<[OpenSSL::X509::Certificate]>] an array of root certificates
# @api private
def self.load_certs
certs = []
# This is based on a patch submitted to openssl:
# http://www.mail-archive.com/openssl-dev@openssl.org/msg26958.html
ptr = FFI::Pointer::NULL
store = CertOpenSystemStoreA(nil, "ROOT")
begin
while (ptr = CertEnumCertificatesInStore(store, ptr)) and not ptr.null?
context = CERT_CONTEXT.new(ptr)
cert_buf = context[:pbCertEncoded].read_bytes(context[:cbCertEncoded])
begin
certs << OpenSSL::X509::Certificate.new(cert_buf)
rescue => detail
Puppet.warning("Failed to import root certificate: #{detail.inspect}")
end
end
ensure
CertCloseStore(store, 0)
end
certs
end
private
# typedef ULONG_PTR HCRYPTPROV_LEGACY;
# typedef void *HCERTSTORE;
class CERT_CONTEXT < FFI::Struct
layout(
:dwCertEncodingType, :dword,
:pbCertEncoded, :pointer,
:cbCertEncoded, :dword,
:pCertInfo, :pointer,
:hCertStore, :handle
)
end
# HCERTSTORE
# WINAPI
# CertOpenSystemStoreA(
# __in_opt HCRYPTPROV_LEGACY hProv,
# __in LPCSTR szSubsystemProtocol
# );
ffi_lib :crypt32
attach_function :CertOpenSystemStoreA, [:pointer, :string], :handle
# PCCERT_CONTEXT
# WINAPI
# CertEnumCertificatesInStore(
# __in HCERTSTORE hCertStore,
# __in_opt PCCERT_CONTEXT pPrevCertContext
# );
ffi_lib :crypt32
attach_function :CertEnumCertificatesInStore, [:handle, :pointer], :pointer
# BOOL
# WINAPI
# CertCloseStore(
# __in_opt HCERTSTORE hCertStore,
# __in DWORD dwFlags
# );
ffi_lib :crypt32
attach_function :CertCloseStore, [:handle, :dword], :bool
end