require 'chef' require 'mixlib/shellout' require 'ffi' require "chef/win32/api" require 'openssl' module Cert extend Chef::ReservedNames::Win32::API extend FFI::Library ffi_lib 'Crypt32' ############################################### # 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) # Certificate Display Format CERT_NAME_EMAIL_TYPE = 1 CERT_NAME_RDN_TYPE = 2 CERT_NAME_ATTR_TYPE = 3 CERT_NAME_SIMPLE_DISPLAY_TYPE = 4 CERT_NAME_FRIENDLY_DISPLAY_TYPE = 5 CERT_NAME_DNS_TYPE = 6 CERT_NAME_URL_TYPE = 7 CERT_NAME_UPN_TYPE = 8 # Retrieve Certificates flag CERT_FIND_SUBJECT_STR = 0x00080007 CERT_FIND_ISSUER_STR = 0x00080004 # List Certificates Flag CERT_NAME_ISSUER_FLAG = 0x1 CERT_NAME_DISABLE_IE4_UTF8_FLAG = 0x00010000 CERT_NAME_SEARCH_ALL_NAMES_FLAG = 0x2 CERT_NAME_STR_ENABLE_PUNYCODE_FLAG = 0x00200000 # Define ffi pointer HCERTSTORE = FFI::TypeDefs[:pointer] HCRYPTPROV_LEGACY = FFI::TypeDefs[:pointer] PCCERT_CONTEXT = FFI::TypeDefs[:pointer] BYTE = FFI::TypeDefs[:pointer] DWORD = FFI::TypeDefs[:uint32] BLOB = FFI::TypeDefs[:ulong] LPSTR = FFI::TypeDefs[:pointer] LPCTSTR = FFI::TypeDefs[:pointer] BOOL = FFI::TypeDefs[:bool] INT_PTR = FFI::TypeDefs[:int] LONG = FFI::TypeDefs[:long] LPVOID = FFI::TypeDefs[:pointer] LPTSTR = FFI::TypeDefs[:pointer] LMSTR = FFI::TypeDefs[:pointer] PWSTR = FFI::TypeDefs[:pointer] PCERT_INFO = FFI::TypeDefs[:pointer] class FILETIME < FFI::Struct layout :dwLowDateTime, DWORD, :dwHighDateTime, DWORD end class CRYPT_INTEGER_BLOB < FFI::Struct layout :cbData, DWORD, # Count, in bytes, of data :pbData, :pointer # Pointer to data buffer end class CERT_EXTENSION < FFI::Struct layout :pszObjId, LPTSTR, :fCritical, BOOL, :Value, CRYPT_INTEGER_BLOB end class CRYPT_BIT_BLOB < FFI::Struct layout :cbData, DWORD, :pbData, BYTE, :cUnusedBits, DWORD end class CRYPT_ALGORITHM_IDENTIFIER < FFI::Struct layout :pszObjId, LPSTR, :Parameters, CRYPT_INTEGER_BLOB end class CERT_PUBLIC_KEY_INFO < FFI::Struct layout :Algorithm, CRYPT_ALGORITHM_IDENTIFIER, :PublicKey, CRYPT_BIT_BLOB end class CERT_INFO < FFI::Struct layout :dwVersion, DWORD, :SerialNumber, CRYPT_INTEGER_BLOB, :SignatureAlgorithm, CRYPT_ALGORITHM_IDENTIFIER, :Issuer, CRYPT_INTEGER_BLOB, :NotBefore, FILETIME, :NotAfter, FILETIME, :Subject, CRYPT_INTEGER_BLOB, :SubjectPublicKeyInfo, CERT_PUBLIC_KEY_INFO, :IssuerUniqueId, CRYPT_BIT_BLOB, :SubjectUniqueId, CRYPT_BIT_BLOB, :cExtension, DWORD, :rgExtension, CERT_EXTENSION 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 retrieve specific certificates from certificate store safe_attach_function :CertFindCertificateInStore, [HCERTSTORE, DWORD, DWORD, DWORD, LPVOID, PCCERT_CONTEXT], PCCERT_CONTEXT # The CertVerifyTimeValidity function verifies the time validity of a certificate safe_attach_function :CertVerifyTimeValidity, [FILETIME, PCERT_INFO], LONG end ################################################## include Chef::Mixin::WideString include Cert store_handler = CertOpenSystemStoreW(nil, wstring("Root")) # Expired certificate_name = "Microsoft Authenticode(tm) Root Authority" # Valid certificate_name = "AddTrust External CA Root" if ( !certificate_name.empty? && pCertContext = CertFindCertificateInStore(store_handler, X509_ASN_ENCODING, 0, CERT_FIND_ISSUER_STR, certificate_name.to_wstring, nil) and not pCertContext.null? ) pTargetCertInfo = CERT_INFO.new(pCertContext) case CertVerifyTimeValidity(nil, pTargetCertInfo) when -1 puts "Certificate is not valid yet." when 1 puts "Certificate is expired." when 0 puts "Certificate's time is valid." else puts "Certificate time validity not matched." end end CertCloseStore(store_handler, CERT_CLOSE_STORE_FORCE_FLAG)