无法在红宝石中创建有效的CRYPT_HASH_BLOB



我正在使用Ruby中的Crypto API来查找Windows证书,使用指纹。为此,我正在使用需要CRYPT_HASH_BLOB结构的CertFindCertificateInStore函数。

我正在使用FFI::MemoryPointer来处理指针。尝试了各种方法来创建此结构,但似乎都没有工作。

有人可以看看并为我提供建议吗?

以下是供参考的完整代码:

    require "ffi"
    module LibC
      extend FFI::Library
      ffi_lib FFI::Library::LIBC
      # memory allocators
      attach_function :malloc, [:size_t], :pointer
      attach_function :calloc, [:size_t], :pointer
      attach_function :free, [:pointer], :void
    end
    module Crypto
      extend LibC
      extend FFI::Library
      ffi_lib "Crypt32"
      HCERTSTORE               = FFI::TypeDefs[:pointer]
      HCRYPTPROV_LEGACY        = FFI::TypeDefs[:pointer]
      PCCERT_CONTEXT           = FFI::TypeDefs[:pointer]
      DWORD                    = FFI::TypeDefs[:uint32]
      BLOB                     = FFI::TypeDefs[:ulong]
      LPCTSTR                  = FFI::TypeDefs[:pointer]
      BOOL                     = FFI::TypeDefs[:bool]
      LPVOID                   = FFI::TypeDefs[:pointer]
      class CRYPT_HASH_BLOB < FFI::Struct
        layout :cbData, DWORD, # Count, in bytes, of data
               :pbData, :pointer # Pointer to data buffer
        def initialize(str)
          super(nil)
          if str
            # Method 1: Simply using thumbprint string
            buffer1 = LibC.malloc str.size
            buffer1.write_string str
            self[:pbData] = buffer1
            self[:cbData] = str.size
            # Converting thumbpring string into a byte array
            # arr = [str].pack('H*').unpack('C*')
            # Method 2: Using Byte Array  with LibC
            # buffer2 = LibC.malloc(arr.first.size * arr.size) # Create the pointer to the array
            # buffer2.write_array_of_uint32 arr                # Fill the memory location with data
            # self[:pbData] = buffer2
            # self[:cbData] = arr.size
            # # Method 3: Using Byte Array with FFI::MemoryPointer
            # buffer3 = FFI::MemoryPointer.new :uint32, arr.size # Create the pointer to the array
            # buffer3.put_array_of_uint32 0, arr                 # Fill the memory location with data
            # self[:pbData] = buffer3
            # self[:cbData] = arr.size
          end
        end
      end
      attach_function :CertOpenStore, [DWORD, DWORD, HCRYPTPROV_LEGACY, DWORD, LPCTSTR], HCERTSTORE
      attach_function :CertCloseStore, [HCERTSTORE, DWORD], BOOL
      attach_function :CertFindCertificateInStore, [HCERTSTORE, DWORD, DWORD, DWORD, LPVOID, PCCERT_CONTEXT], PCCERT_CONTEXT
      attach_function :CertFreeCertificateContext, [PCCERT_CONTEXT], BOOL
    =begin
      PCCERT_CONTEXT CertFindCertificateInStore(
        HCERTSTORE     hCertStore,
        DWORD          dwCertEncodingType,
        DWORD          dwFindFlags,
        DWORD          dwFindType,
        const void     *pvFindPara,
        PCCERT_CONTEXT pPrevCertContext
      );
    =end
    end
    class CertificateHandler
      include Crypto
      CERT_STORE_PROV_SYSTEM = 10
      CERT_SYSTEM_STORE_LOCAL_MACHINE = 0x00020000
      X509_ASN_ENCODING = 0x00000001
      PKCS_7_ASN_ENCODING = 0x00010000
      ENCODING_TYPE = X509_ASN_ENCODING | PKCS_7_ASN_ENCODING
      CERT_CLOSE_STORE_FORCE_FLAG = 1
      CERT_COMPARE_SHA1_HASH = 1
      CERT_COMPARE_SHIFT = 16
      CERT_FIND_SHA1_HASH = CERT_COMPARE_SHA1_HASH << CERT_COMPARE_SHIFT
      def self.finalize(certstore_handler)
        proc { certstore_handler.to_s }
      end
      def add_finalizer(certstore_handler)
        ObjectSpace.define_finalizer(self, self.class.finalize(certstore_handler))
      end
      def remove_finalizer
        ObjectSpace.undefine_finalizer(self)
      end
      def utf8_to_wide(ustring)
        # ensure it is actually UTF-8
        # Ruby likes to mark binary data as ASCII-8BIT
        ustring = (ustring + "").force_encoding("UTF-8") if ustring.respond_to?(:force_encoding) && ustring.encoding.name != "UTF-8"
        # ensure we have the double-null termination Windows Wide likes
        ustring += "0000" if ustring.length == 0 || ustring[-1].chr != "00"
        # encode it all as UTF-16LE AKA Windows Wide Character AKA Windows Unicode
        ustring = ustring.encode("UTF-16LE") if ustring.respond_to?(:encode)
        ustring
      end
      def cert_find_by_thumbprint(thumbprint = nil)
        store_name = "Root"
        thumbprint ||= "1D F4 AB B6 13 F2 12 27 1C 04 F8 52 9D DE 38 E4 B7 24 2E 6C" # Assume this is a valid thumbprint in Root
        thumbprint.gsub!(/[^A-Za-z0-9]/, "") # Discard WhiteSpaces
        certstore_handler = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, nil,
          CERT_SYSTEM_STORE_LOCAL_MACHINE, utf8_to_wide(store_name))
        add_finalizer(certstore_handler)
        pcert_context = CertFindCertificateInStore(certstore_handler, ENCODING_TYPE, 0, CERT_FIND_SHA1_HASH, CRYPT_HASH_BLOB.new(thumbprint), nil)
        puts "Certificate Found = #{!pcert_context.null?}" # It should be true
        CertFreeCertificateContext(pcert_context)
        closed = CertCloseStore(@certstore_handler, CERT_CLOSE_STORE_FORCE_FLAG)
        remove_finalizer
      end
    end
    CertificateHandler.new.cert_find_by_thumbprint

我根本不熟悉Ruby,但我可以做一些假设。如果我错了,请纠正我。

正在将源指纹(SHA1 值)转换为八位字节之间没有空格的字符串:

thumbprint ||= "1D F4 AB B6 13 F2 12 27 1C 04 F8 52 9D DE 38 E4 B7 24 2E 6C" # Assume this is a valid thumbprint in Root
thumbprint.gsub!(/[^A-Za-z0-9]/, "") # Discard WhiteSpaces

这将产生如下结果:1DF4ABB613F212271C04F8529DDE38E4B7242E6C然后将此字符串传递到此行中的构造函数CRYPT_HASH_BLOB

pcert_context = CertFindCertificateInStore(certstore_handler, ENCODING_TYPE, 0, CERT_FIND_SHA1_HASH, CRYPT_HASH_BLOB.new(thumbprint), nil)

CRYPT_HASH_BLOB.initialize(str)中,您将 utf8 字符串解压缩为字节数组。第一种方法不正确,因为您将输入字符串视为原始字符数组。相反,它是一个十六进制编码的字节数组,因此必须涉及arr = [str].pack('H*').unpack('C*')行。至少,谷歌建议这条线将一系列八位字节转换为相应的字节数组。因此,方法 3 很好,除了您必须分配 *byte* 数组(不是整数数组)并写入字符而不是整数。正确的构造函数代码应如下所示:

def initialize(str)
    super(nil)
    if str
        # Converting thumbpring string into a byte array
        arr = [str].pack('H*').unpack('C*')
        # Method 3: Using Byte Array with FFI::MemoryPointer
        buffer3 = FFI::MemoryPointer.new(:char, arr.size) # Create the pointer to the array
        buffer3.write_array_of_char(arr) # Fill the memory location with data
        self[:pbData] = buffer3
        self[:cbData] = arr.size
    end
end

我相信,这将完成这项工作。

相关内容

  • 没有找到相关文章

最新更新