8000 removed deprecated signature_chain by armtash · Pull Request #160 · Yelp/osxcollector · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content
This repository was archived by the owner on Oct 5, 2019. It is now read-only.

removed deprecated signature_chain #160

Merged
merged 1 commit into from
May 10, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,6 @@ For records representing files there are a bunch of useful keys:
* `md5`: MD5 hash of the file contents.
* `sha1`: SHA1 hash of the file contents.
* `sha2`: SHA2 hash of the file contents.
* `signature_chain`: The common names of the certs in the file's signing chain

For records representing downloaded files:
* `xattr-wherefrom`: A list containing the source and referrer URLs for the downloaded file.
Expand Down
323 changes: 0 additions & 323 deletions osxcollector/osxcollector.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@
#
import base64
import calendar
import ctypes
import ctypes.util
import os
import shutil
import struct
Expand All @@ -43,7 +41,6 @@

import Foundation
import macholib.MachO
import objc
from xattr import getxattr

__version__ = '1.9'
Expand Down Expand Up @@ -301,10 +298,6 @@ def _get_file_info(file_path, log_xattr=False):
mtime = _datetime_to_string(datetime.fromtimestamp(os.path.getmtime(file_path)))
ctime = _datetime_to_string(datetime.fromtimestamp(os.path.getctime(file_path)))
md5_hash, sha1_hash, sha2_hash = _hash_file(file_path)
try:
signature_chain = CodeSignChecker.get_signature_chain(file_path)
except CodeSignChecker.CodeSignCheckerError:
signature_chain = []

# check for extradata
try:
Expand All @@ -324,7 +317,6 @@ def _get_file_info(file_path, log_xattr=False):
'file_path': file_path,
'mtime': mtime,
'ctime': ctime,
'signature_chain': signature_chain,
'extra_data_check': extra_data_check,
'extra_data_found': extra_data_found,
}
Expand Down Expand Up @@ -414,314 +406,6 @@ def _decode_error_description(error):
return cfstring.encode('utf-8', 'ignore')


class CodeSignChecker(object):

"""Call `CodeSignChecker.get_signature_chain` to get the signing chain for a binary.

This class is derived from KnockKock
- https://github.com/synack/knockknock
KnockKnock is licensed under a Creative Commons Attribution-NonCommercial 4.0 International License
- https://github.com/synack/knockknock/blob/master/LICENSE
"""

# Class level pointers to dynamic link libraries
SEC_DLL = None
OBJC_DLL = None
FOUNDATION_DLL = None

# OS X constants
errSecSuccess = 0x0
kSecCSCheckAllArchitectures = 0x1
kSecCSDefaultFlags = 0x0
kSecCSDoNotValidateResources = 0x4
kSecCSSigningInformation = 0x2
kSecCSStrictValidate = 0x16
# kSecCSStrictValidate | kSecCSCheckAllArchitectures
kSecCSStrictValidate_kSecCSCheckAllArchitectures = 0x17
# kSecCSStrictValidate | kSecCSCheckAllArchitectures | kSecCSCheckNestedCode
kSecCSStrictValidate_kSecCSCheckAllArchitectures_kSecCSCheckNestedCode = 0x1f
kSecCodeInfoCertificates = 'certificates'

class CodeSignCheckerError(Exception):
pass

class MissingDLLError(CodeSignCheckerError):

"""Raised when a DLL can't be loaded."""
pass

class CheckSignatureError(CodeSignCheckerError):

"""Raised when a signature can't be checked."""
pass

class SystemCallError(CodeSignCheckerError):

"""Raised when a system call fails."""

def __init__(self, method, status):
self.status = status
self.method = method

def __str__(self):
return '{0} failed with status[{1}]'.format(self.method, self.status)

class CFTypeWrapper(object):

"""A helper class which ensures CFRelease is called.

Attributes:
val: The actual value stored in this wrapper.
"""

def __init__(self, val):
self.val = val

def __del__(self):
CFRelease = CodeSignChecker.FOUNDATION_DLL.CFRelease
CFRelease.argtypes = [ctypes.c_void_p]
CFRelease(self.val)

@classmethod
def _load_library(cls, dll_path):
"""Load a DLL.

Args:
dll_path: Fully qualified path to the DLL
Returns:
handle to the library
Raises:
MissingDLLError
"""
dll = ctypes.cdll.LoadLibrary(dll_path)
if not dll:
raise cls.MissingDLLError(message='could not load {0}'.format(dll_path))
return dll

@classmethod
def _load_framework(cls):
"""Loads all DLLs required by the CodeSignChecker."""

if not cls.SEC_DLL:
cls.SEC_DLL = cls._load_library('/System/Library/Frameworks/Security.framework/Versions/Current/Security')

if not cls.OBJC_DLL:
cls.OBJC_DLL = cls._load_library(ctypes.util.find_library('objc'))

cls.OBJC_DLL.objc_getClass.restype = ctypes.c_void_p
cls.OBJC_DLL.sel_registerName.restype = ctypes.c_void_p

if not cls.FOUNDATION_DLL:
cls.FOUNDATION_DLL = cls._load_library(ctypes.util.find_library('Foundation'))

@classmethod
def SecStaticCodeCreateWithPath(cls, file_path):
"""Call Security Framework's SecStaticCodeCreateWithPath method.

Args:
file_path: fully qualified file path
Returns:
A SecStaticCodeRef wrapped with a CFTypeWrapper
"""

if isinstance(file_path, unicode):
file_path = file_path.encode(encoding='utf-8', errors='ignore')

# file_path as NSString
file_path = Foundation.NSString.stringWithUTF8String_(file_path)

# file_path with spaces escaped
file_path = file_path.stringByAddingPercentEscapesUsingEncoding_(Foundation.NSUTF8StringEncoding).encode('utf-8')

# init file_path as url
path = Foundation.NSURL.URLWithString_(Foundation.NSString.stringWithUTF8String_(file_path))

# pointer for static code
static_code = ctypes.c_void_p(0)

# create static code from path and check
result = cls.SEC_DLL.SecStaticCodeCreateWithPath(
ctypes.c_void_p(objc.pyobjc_id(path)), cls.kSecCSDefaultFlags,
ctypes.byref(static_code))
if cls.errSecSuccess != result:
raise cls.SystemCallError('SecStaticCodeCreateWithPath', result)

return cls.CFTypeWrapper(static_code)

@classmethod
def SecStaticCodeCheckValidityWithErrors(cls, static_code):
"""Call Security Framework's SecStaticCodeCheckValidityWithErrors method.

Args:
static_code: A SecStaticCodeRef
Raises:
SystemCallError when the code is not secure
"""
if strict is True:
# strict checking
sigCheckFlags = cls.kSecCSStrictValidate_kSecCSCheckAllArchitectures_kSecCSCheckNestedCode
else:
# no-strict checking
sigCheckFlags = cls.kSecCSDoNotValidateResources

result = cls.SEC_DLL.SecStaticCodeCheckValidityWithErrors(static_code, sigCheckFlags, None, None)
if cls.errSecSuccess != result:
raise cls.SystemCallError('SecStaticCodeCheckValidityWithErrors', result)

@classmethod
def SecCodeCopySigningInformation(cls, static_code):
"""Call Security Framework's SecCodeCopySigningInformation method.

Args:
static_code: A SecStaticCodeRef
Returns:
A CFDictionaryRef wrapped with a CFTypeWrapper
Raises:
SystemCallError
"""

signing_information = ctypes.c_void_p(0)

result = cls.SEC_DLL.SecCodeCopySigningInformation(static_code, cls.kSecCSSigningInformation, ctypes.byref(signing_information))
if cls.errSecSuccess != result:
raise cls.SystemCallError('SecCodeCopySigningInformation', result)

return cls.CFTypeWrapper(signing_information)

@classmethod
def SecCertificateCopyCommonName(cls, certificate):
"""Call Security Framework's SecCertificateCopyCommonName method.

Args:
static_code: A SecCertificateRef
Returns:
An NSString
Raises:
SystemCallError
"""

certificate_name = ctypes.c_char_p(0)

result = cls.SEC_DLL.SecCertificateCopyCommonName(ctypes.c_void_p(certificate), ctypes.byref(certificate_name))
if cls.errSecSuccess != result:
raise cls.SystemCallError('SecCertificateCopyCommonName', result)

return certificate_name

@classmethod
def NSString_from_str(cls, str_val):
"""Creates an instance of NSString.

Args:
str_val: A Python string
Returns:
An NSString
"""
NSString = cls.OBJC_DLL.objc_getClass('NSString')
cls.OBJC_DLL.objc_msgSend.restype = ctypes.c_void_p
cls.OBJC_DLL.objc_msgSend.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p]

return cls.OBJC_DLL.objc_msgSend(NSString, cls.OBJC_DLL.sel_registerName('stringWithUTF8String:'), str_val)

@classmethod
def str_from_NSString(cls, nsstring_val):
"""Creates a Python string from an NSString.

Args:
nsstring_val: An NSString
Returns:
A string
"""
cls.OBJC_DLL.objc_msgSend.restype = ctypes.c_char_p
cls.OBJC_DLL.objc_msgSend.argtypes = [ctypes.c_void_p, ctypes.c_void_p]

return cls.OBJC_DLL.objc_msgSend(nsstring_val, cls.OBJC_DLL.sel_registerName('UTF8String'))

@classmethod
def CFDictionary_objectForKey(cls, instance, key):
"""Calls CFDictionary:objectForKey

Args:
instance - A CFDictionaryRef
key - A string
Returns:
value retrieved from the CFDictionary
"""
nsstring_key = cls.NSString_from_str(key)

cls.OBJC_DLL.objc_msgSend.restype = ctypes.c_void_p
cls.OBJC_DLL.objc_msgSend.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p]

return cls.OBJC_DLL.objc_msgSend(instance, cls.OBJC_DLL.sel_registerName('objectForKey:'), nsstring_key)

@classmethod
def CFArray_count(cls, instance):
"""Calls CFArray:count

Args:
instance - A CFArrayRef
Returns:
int
"""
cls.OBJC_DLL.objc_msgSend.restype = ctypes.c_uint
cls.OBJC_DLL.objc_msgSend.argtypes = [ctypes.c_void_p, ctypes.c_void_p]

return cls.OBJC_DLL.objc_msgSend(instance, cls.OBJC_DLL.sel_registerName('count'))

@classmethod
def CFArray_objectAtIndex(cls, instance, index):
"""Calls CFArray:objectAtIndex

Args:
instance - A CFArrayRef
index - int
Returns:
value retrieved from the CFArray
"""
cls.OBJC_DLL.objc_msgSend.restype = ctypes.c_void_p
cls.OBJC_DLL.objc_msgSend.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_uint]

return cls.OBJC_DLL.objc_msgSend(instance, cls.OBJC_DLL.sel_registerName('objectAtIndex:'), index)

@classmethod
def get_signature_chain(cls, file_path):
"""Retrieves the singing authorities for a binary.

Args:
file_path: A string of the fully qualified file path

Returns:
An array of signing authorities or an empty array
"""
signing_authorities = []

cls._load_framework()

static_code = cls.SecStaticCodeCreateWithPath(file_path)

try:
cls.SecStaticCodeCheckValidityWithErrors(static_code.val)
except cls.SystemCallError:
# The binary is not signed
return signing_authorities

cfdict_information = cls.SecCodeCopySigningInformation(static_code.val)
cfarray_cert_chain = cls.CFDictionary_objectForKey(cfdict_information.val, cls.kSecCodeInfoCertificates)

for index in xrange(cls.CFArray_count(cfarray_cert_chain)):
certificate = cls.CFArray_objectAtIndex(cfarray_cert_chain, index)

try:
nsstring_common_name = cls.SecCertificateCopyCommonName(certificate)
common_name = cls.str_from_NSString(nsstring_common_name)
signing_authorities.append(common_name)
except cls.SystemCallError:
# If this certificate's name can't be retrieved just continue
pass

return signing_authorities


class DictUtils(object):

"""A set of method for manipulating dictionaries."""
Expand Down Expand Up @@ -1843,7 +1527,6 @@ def main():

global DEBUG_MODE
global ROOT_PATH
global strict

global firefox_ignored_sqlite_keys
global safari_ignored_sqlite_keys
Expand Down Expand Up @@ -1872,10 +1555,6 @@ def main():
parser.add_argument(
'-d', '--debug', action='store_true', default=False,
help='[OPTIONAL] Enable verbose output and python breakpoints.')
parser.add_argument(
'-t', '--strict', dest='strict', default=False, action='store_true',
help='[OPTIONAL] Enable strict codesign checking of applications and '
'binaries')
parser.add_argument(
'-c', '--collect-cookies', dest='collect_cookies_value',
default=False, action='store_true',
Expand All @@ -1888,8 +1567,6 @@ def main():
'local storage')
args = parser.parse_args()

strict = args.strict

DEBUG_MODE = args.debug
ROOT_PATH = args.rootpath

Expand Down
0