module Sec begin attach_variable 'kSecAttrAccessible', :pointer rescue FFI::NotFoundError #Only available in 10.9 end begin attach_variable 'kSecAttrAccessControl', :pointer rescue FFI::NotFoundError #Only available in 10.10 end attach_variable 'kSecAttrAccessGroup', :pointer attach_variable 'kSecAttrKeyClass', :pointer attach_variable 'kSecAttrApplicationLabel', :pointer attach_variable 'kSecAttrIsPermanent', :pointer attach_variable 'kSecAttrApplicationTag', :pointer attach_variable 'kSecAttrKeyType', :pointer attach_variable 'kSecAttrKeySizeInBits', :pointer attach_variable 'kSecAttrEffectiveKeySize', :pointer attach_variable 'kSecAttrCanEncrypt', :pointer attach_variable 'kSecAttrCanDecrypt', :pointer attach_variable 'kSecAttrCanDerive', :pointer attach_variable 'kSecAttrCanSign', :pointer attach_variable 'kSecAttrCanVerify', :pointer attach_variable 'kSecAttrCanWrap', :pointer attach_variable 'kSecAttrCanUnwrap', :pointer enum :SecItemImportExportFlags, [:kSecItemPemArmour, 1] enum :SecExternalFormat, [:kSecFormatUnknown, 0, :kSecFormatOpenSSL, :kSecFormatSSH, :kSecFormatBSAFE, :kSecFormatRawKey, :kSecFormatWrappedPKCS8, :kSecFormatWrappedOpenSSL, :kSecFormatWrappedSSH, :kSecFormatWrappedLSH, :kSecFormatX509Cert, :kSecFormatPEMSequence, :kSecFormatPKCS7, :kSecFormatPKCS12, :kSecFormatNetscapeCertSequence, :kSecFormatSSHv2] enum :SecKeyImportExportParameters, [:kSecKeyImportOnlyOne, 1, :kSecKeySecurePassphrase, 2, :kSecKeyNoAccessControl, 4] class SecItemImportExportKeyParameters < FFI::Struct layout :version, :uint32, :flags, :SecKeyImportExportParameters, :passphrase, :pointer, :alertTitle, :pointer, :alertPrompt, :pointer, :accessRef, :pointer, :keyUsage, :pointer, :keyAttributes, :pointer end attach_function 'SecItemExport', [:pointer, :SecExternalFormat, :SecItemImportExportFlags, :pointer, :pointer], :osstatus attach_function 'SecItemImport', [:pointer, :pointer, :SecExternalFormat, :SecExternalItemType, :SecItemImportExportFlags, :pointer, :pointer, :pointer], :osstatus end module Keychain class Key < Sec::Base register_type 'SecKey' ATTR_MAP = {CF::Base.typecast(Sec::kSecAttrAccessGroup) => :access_group, CF::Base.typecast(Sec::kSecAttrKeyClass) => :key_class, CF::Base.typecast(Sec::kSecAttrLabel) => :label, CF::Base.typecast(Sec::kSecAttrApplicationLabel) => :application_label, CF::Base.typecast(Sec::kSecAttrIsPermanent) => :is_permanent, CF::Base.typecast(Sec::kSecAttrApplicationTag) => :application_tag, CF::Base.typecast(Sec::kSecAttrKeyType) => :key_type, CF::Base.typecast(Sec::kSecAttrKeySizeInBits) => :size_in_bites, CF::Base.typecast(Sec::kSecAttrEffectiveKeySize) => :effective_key_size, CF::Base.typecast(Sec::kSecAttrCanEncrypt) => :can_encrypt, CF::Base.typecast(Sec::kSecAttrCanDecrypt) => :can_decrypt, CF::Base.typecast(Sec::kSecAttrCanDerive) => :can_derive, CF::Base.typecast(Sec::kSecAttrCanSign) => :can_sign, CF::Base.typecast(Sec::kSecAttrCanVerify) => :can_verify, CF::Base.typecast(Sec::kSecAttrCanWrap) => :can_wrap, CF::Base.typecast(Sec::kSecAttrCanUnwrap) => :can_unwrap} ATTR_MAP[CF::Base.typecast(Sec::kSecAttrAccessible)] = :accessible if defined?(Sec::kSecAttrAccessible) ATTR_MAP[CF::Base.typecast(Sec::kSecAttrAccessControl)] = :access_control if defined?(Sec::kSecAttrAccessControl) INVERSE_ATTR_MAP = ATTR_MAP.invert define_attributes(ATTR_MAP) def klass Sec::Classes::KEY.to_ruby end def export(passphrase = nil, format = :kSecFormatUnknown) flags = Sec::SecItemImportExportKeyParameters.new flags[:version] = Sec::SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION flags[:passphrase] = CF::String.from_string(passphrase).to_ptr if passphrase data_ptr = FFI::MemoryPointer.new(:pointer) status = Sec.SecItemExport(self, format, :kSecItemPemArmour, flags, data_ptr) Sec.check_osstatus(status) data = CF::Data.new(data_ptr.read_pointer) result = data.to_s data.release result end end end