Skip to content
This repository was archived by the owner on Oct 5, 2019. It is now read-only.

Commit 08a0193

Browse files
authored
Merge pull request #160 from armtash/remove_cert_chain
removed deprecated signature_chain
2 parents cb9e54a + c40f3bf commit 08a0193

File tree

2 files changed

+0
-324
lines changed

2 files changed

+0
-324
lines changed

README.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,6 @@ For records representing files there are a bunch of useful keys:
154154
* `md5`: MD5 hash of the file contents.
155155
* `sha1`: SHA1 hash of the file contents.
156156
* `sha2`: SHA2 hash of the file contents.
157-
* `signature_chain`: The common names of the certs in the file's signing chain
158157

159158
For records representing downloaded files:
160159
* `xattr-wherefrom`: A list containing the source and referrer URLs for the downloaded file.

osxcollector/osxcollector.py

Lines changed: 0 additions & 323 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,6 @@
2020
#
2121
import base64
2222
import calendar
23-
import ctypes
24-
import ctypes.util
2523
import os
2624
import shutil
2725
import struct
@@ -43,7 +41,6 @@
4341

4442
import Foundation
4543
import macholib.MachO
46-
import objc
4744
from xattr import getxattr
4845

4946
__version__ = '1.9'
@@ -301,10 +298,6 @@ def _get_file_info(file_path, log_xattr=False):
301298
mtime = _datetime_to_string(datetime.fromtimestamp(os.path.getmtime(file_path)))
302299
ctime = _datetime_to_string(datetime.fromtimestamp(os.path.getctime(file_path)))
303300
md5_hash, sha1_hash, sha2_hash = _hash_file(file_path)
304-
try:
305-
signature_chain = CodeSignChecker.get_signature_chain(file_path)
306-
except CodeSignChecker.CodeSignCheckerError:
307-
signature_chain = []
308301

309302
# check for extradata
310303
try:
@@ -324,7 +317,6 @@ def _get_file_info(file_path, log_xattr=False):
324317
'file_path': file_path,
325318
'mtime': mtime,
326319
'ctime': ctime,
327-
'signature_chain': signature_chain,
328320
'extra_data_check': extra_data_check,
329321
'extra_data_found': extra_data_found,
330322
}
@@ -414,314 +406,6 @@ def _decode_error_description(error):
414406
return cfstring.encode('utf-8', 'ignore')
415407

416408

417-
class CodeSignChecker(object):
418-
419-
"""Call `CodeSignChecker.get_signature_chain` to get the signing chain for a binary.
420-
421-
This class is derived from KnockKock
422-
- https://github.com/synack/knockknock
423-
KnockKnock is licensed under a Creative Commons Attribution-NonCommercial 4.0 International License
424-
- https://github.com/synack/knockknock/blob/master/LICENSE
425-
"""
426-
427-
# Class level pointers to dynamic link libraries
428-
SEC_DLL = None
429-
OBJC_DLL = None
430-
FOUNDATION_DLL = None
431-
432-
# OS X constants
433-
errSecSuccess = 0x0
434-
kSecCSCheckAllArchitectures = 0x1
435-
kSecCSDefaultFlags = 0x0
436-
kSecCSDoNotValidateResources = 0x4
437-
kSecCSSigningInformation = 0x2
438-
kSecCSStrictValidate = 0x16
439-
# kSecCSStrictValidate | kSecCSCheckAllArchitectures
440-
kSecCSStrictValidate_kSecCSCheckAllArchitectures = 0x17
441-
# kSecCSStrictValidate | kSecCSCheckAllArchitectures | kSecCSCheckNestedCode
442-
kSecCSStrictValidate_kSecCSCheckAllArchitectures_kSecCSCheckNestedCode = 0x1f
443-
kSecCodeInfoCertificates = 'certificates'
444-
445-
class CodeSignCheckerError(Exception):
446-
pass
447-
448-
class MissingDLLError(CodeSignCheckerError):
449-
450-
"""Raised when a DLL can't be loaded."""
451-
pass
452-
453-
class CheckSignatureError(CodeSignCheckerError):
454-
455-
"""Raised when a signature can't be checked."""
456-
pass
457-
458-
class SystemCallError(CodeSignCheckerError):
459-
460-
"""Raised when a system call fails."""
461-
462-
def __init__(self, method, status):
463-
self.status = status
464-
self.method = method
465-
466-
def __str__(self):
467-
return '{0} failed with status[{1}]'.format(self.method, self.status)
468-
469-
class CFTypeWrapper(object):
470-
471-
"""A helper class which ensures CFRelease is called.
472-
473-
Attributes:
474-
val: The actual value stored in this wrapper.
475-
"""
476-
477-
def __init__(self, val):
478-
self.val = val
479-
480-
def __del__(self):
481-
CFRelease = CodeSignChecker.FOUNDATION_DLL.CFRelease
482-
CFRelease.argtypes = [ctypes.c_void_p]
483-
CFRelease(self.val)
484-
485-
@classmethod
486-
def _load_library(cls, dll_path):
487-
"""Load a DLL.
488-
489-
Args:
490-
dll_path: Fully qualified path to the DLL
491-
Returns:
492-
handle to the library
493-
Raises:
494-
MissingDLLError
495-
"""
496-
dll = ctypes.cdll.LoadLibrary(dll_path)
497-
if not dll:
498-
raise cls.MissingDLLError(message='could not load {0}'.format(dll_path))
499-
return dll
500-
501-
@classmethod
502-
def _load_framework(cls):
503-
"""Loads all DLLs required by the CodeSignChecker."""
504-
505-
if not cls.SEC_DLL:
506-
cls.SEC_DLL = cls._load_library('/System/Library/Frameworks/Security.framework/Versions/Current/Security')
507-
508-
if not cls.OBJC_DLL:
509-
cls.OBJC_DLL = cls._load_library(ctypes.util.find_library('objc'))
510-
511-
cls.OBJC_DLL.objc_getClass.restype = ctypes.c_void_p
512-
cls.OBJC_DLL.sel_registerName.restype = ctypes.c_void_p
513-
514-
if not cls.FOUNDATION_DLL:
515-
cls.FOUNDATION_DLL = cls._load_library(ctypes.util.find_library('Foundation'))
516-
517-
@classmethod
518-
def SecStaticCodeCreateWithPath(cls, file_path):
519-
"""Call Security Framework's SecStaticCodeCreateWithPath method.
520-
521-
Args:
522-
file_path: fully qualified file path
523-
Returns:
524-
A SecStaticCodeRef wrapped with a CFTypeWrapper
525-
"""
526-
527-
if isinstance(file_path, unicode):
528-
file_path = file_path.encode(encoding='utf-8', errors='ignore')
529-
530-
# file_path as NSString
531-
file_path = Foundation.NSString.stringWithUTF8String_(file_path)
532-
533-
# file_path with spaces escaped
534-
file_path = file_path.stringByAddingPercentEscapesUsingEncoding_(Foundation.NSUTF8StringEncoding).encode('utf-8')
535-
536-
# init file_path as url
537-
path = Foundation.NSURL.URLWithString_(Foundation.NSString.stringWithUTF8String_(file_path))
538-
539-
# pointer for static code
540-
static_code = ctypes.c_void_p(0)
541-
542-
# create static code from path and check
543-
result = cls.SEC_DLL.SecStaticCodeCreateWithPath(
544-
ctypes.c_void_p(objc.pyobjc_id(path)), cls.kSecCSDefaultFlags,
545-
ctypes.byref(static_code))
546-
if cls.errSecSuccess != result:
547-
raise cls.SystemCallError('SecStaticCodeCreateWithPath', result)
548-
549-
return cls.CFTypeWrapper(static_code)
550-
551-
@classmethod
552-
def SecStaticCodeCheckValidityWithErrors(cls, static_code):
553-
"""Call Security Framework's SecStaticCodeCheckValidityWithErrors method.
554-
555-
Args:
556-
static_code: A SecStaticCodeRef
557-
Raises:
558-
SystemCallError when the code is not secure
559-
"""
560-
if strict is True:
561-
# strict checking
562-
sigCheckFlags = cls.kSecCSStrictValidate_kSecCSCheckAllArchitectures_kSecCSCheckNestedCode
563-
else:
564-
# no-strict checking
565-
sigCheckFlags = cls.kSecCSDoNotValidateResources
566-
567-
result = cls.SEC_DLL.SecStaticCodeCheckValidityWithErrors(static_code, sigCheckFlags, None, None)
568-
if cls.errSecSuccess != result:
569-
raise cls.SystemCallError('SecStaticCodeCheckValidityWithErrors', result)
570-
571-
@classmethod
572-
def SecCodeCopySigningInformation(cls, static_code):
573-
"""Call Security Framework's SecCodeCopySigningInformation method.
574-
575-
Args:
576-
static_code: A SecStaticCodeRef
577-
Returns:
578-
A CFDictionaryRef wrapped with a CFTypeWrapper
579-
Raises:
580-
SystemCallError
581-
"""
582-
583-
signing_information = ctypes.c_void_p(0)
584-
585-
result = cls.SEC_DLL.SecCodeCopySigningInformation(static_code, cls.kSecCSSigningInformation, ctypes.byref(signing_information))
586-
if cls.errSecSuccess != result:
587-
raise cls.SystemCallError('SecCodeCopySigningInformation', result)
588-
589-
return cls.CFTypeWrapper(signing_information)
590-
591-
@classmethod
592-
def SecCertificateCopyCommonName(cls, certificate):
593-
"""Call Security Framework's SecCertificateCopyCommonName method.
594-
595-
Args:
596-
static_code: A SecCertificateRef
597-
Returns:
598-
An NSString
599-
Raises:
600-
SystemCallError
601-
"""
602-
603-
certificate_name = ctypes.c_char_p(0)
604-
605-
result = cls.SEC_DLL.SecCertificateCopyCommonName(ctypes.c_void_p(certificate), ctypes.byref(certificate_name))
606-
if cls.errSecSuccess != result:
607-
raise cls.SystemCallError('SecCertificateCopyCommonName', result)
608-
609-
return certificate_name
610-
611-
@classmethod
612-
def NSString_from_str(cls, str_val):
613-
"""Creates an instance of NSString.
614-
615-
Args:
616-
str_val: A Python string
617-
Returns:
618-
An NSString
619-
"""
620-
NSString = cls.OBJC_DLL.objc_getClass('NSString')
621-
cls.OBJC_DLL.objc_msgSend.restype = ctypes.c_void_p
622-
cls.OBJC_DLL.objc_msgSend.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p]
623-
624-
return cls.OBJC_DLL.objc_msgSend(NSString, cls.OBJC_DLL.sel_registerName('stringWithUTF8String:'), str_val)
625-
626-
@classmethod
627-
def str_from_NSString(cls, nsstring_val):
628-
"""Creates a Python string from an NSString.
629-
630-
Args:
631-
nsstring_val: An NSString
632-
Returns:
633-
A string
634-
"""
635-
cls.OBJC_DLL.objc_msgSend.restype = ctypes.c_char_p
636-
cls.OBJC_DLL.objc_msgSend.argtypes = [ctypes.c_void_p, ctypes.c_void_p]
637-
638-
return cls.OBJC_DLL.objc_msgSend(nsstring_val, cls.OBJC_DLL.sel_registerName('UTF8String'))
639-
640-
@classmethod
641-
def CFDictionary_objectForKey(cls, instance, key):
642-
"""Calls CFDictionary:objectForKey
643-
644-
Args:
645-
instance - A CFDictionaryRef
646-
key - A string
647-
Returns:
648-
value retrieved from the CFDictionary
649-
"""
650-
nsstring_key = cls.NSString_from_str(key)
651-
652-
cls.OBJC_DLL.objc_msgSend.restype = ctypes.c_void_p
653-
cls.OBJC_DLL.objc_msgSend.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p]
654-
655-
return cls.OBJC_DLL.objc_msgSend(instance, cls.OBJC_DLL.sel_registerName('objectForKey:'), nsstring_key)
656-
657-
@classmethod
658-
def CFArray_count(cls, instance):
659-
"""Calls CFArray:count
660-
661-
Args:
662-
instance - A CFArrayRef
663-
Returns:
664-
int
665-
"""
666-
cls.OBJC_DLL.objc_msgSend.restype = ctypes.c_uint
667-
cls.OBJC_DLL.objc_msgSend.argtypes = [ctypes.c_void_p, ctypes.c_void_p]
668-
669-
return cls.OBJC_DLL.objc_msgSend(instance, cls.OBJC_DLL.sel_registerName('count'))
670-
671-
@classmethod
672-
def CFArray_objectAtIndex(cls, instance, index):
673-
"""Calls CFArray:objectAtIndex
674-
675-
Args:
676-
instance - A CFArrayRef
677-
index - int
678-
Returns:
679-
value retrieved from the CFArray
680-
"""
681-
cls.OBJC_DLL.objc_msgSend.restype = ctypes.c_void_p
682-
cls.OBJC_DLL.objc_msgSend.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_uint]
683-
684-
return cls.OBJC_DLL.objc_msgSend(instance, cls.OBJC_DLL.sel_registerName('objectAtIndex:'), index)
685-
686-
@classmethod
687-
def get_signature_chain(cls, file_path):
688-
"""Retrieves the singing authorities for a binary.
689-
690-
Args:
691-
file_path: A string of the fully qualified file path
692-
693-
Returns:
694-
An array of signing authorities or an empty array
695-
"""
696-
signing_authorities = []
697-
698-
cls._load_framework()
699-
700-
static_code = cls.SecStaticCodeCreateWithPath(file_path)
701-
702-
try:
703-
cls.SecStaticCodeCheckValidityWithErrors(static_code.val)
704-
except cls.SystemCallError:
705-
# The binary is not signed
706-
return signing_authorities
707-
708-
cfdict_information = cls.SecCodeCopySigningInformation(static_code.val)
709-
cfarray_cert_chain = cls.CFDictionary_objectForKey(cfdict_information.val, cls.kSecCodeInfoCertificates)
710-
711-
for index in xrange(cls.CFArray_count(cfarray_cert_chain)):
712-
certificate = cls.CFArray_objectAtIndex(cfarray_cert_chain, index)
713-
714-
try:
715-
nsstring_common_name = cls.SecCertificateCopyCommonName(certificate)
716-
common_name = cls.str_from_NSString(nsstring_common_name)
717-
signing_authorities.append(common_name)
718-
except cls.SystemCallError:
719-
# If this certificate's name can't be retrieved just continue
720-
pass
721-
722-
return signing_authorities
723-
724-
725409
class DictUtils(object):
726410

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

18441528
global DEBUG_MODE
18451529
global ROOT_PATH
1846-
global strict
18471530

18481531
global firefox_ignored_sqlite_keys
18491532
global safari_ignored_sqlite_keys
@@ -1872,10 +1555,6 @@ def main():
18721555
parser.add_argument(
18731556
'-d', '--debug', action='store_true', default=False,
18741557
help='[OPTIONAL] Enable verbose output and python breakpoints.')
1875-
parser.add_argument(
1876-
'-t', '--strict', dest='strict', default=False, action='store_true',
1877-
help='[OPTIONAL] Enable strict codesign checking of applications and '
1878-
'binaries')
18791558
parser.add_argument(
18801559
'-c', '--collect-cookies', dest='collect_cookies_value',
18811560
default=False, action='store_true',
@@ -1888,8 +1567,6 @@ def main():
18881567
'local storage')
18891568
args = parser.parse_args()
18901569

1891-
strict = args.strict
1892-
18931570
DEBUG_MODE = args.debug
18941571
ROOT_PATH = args.rootpath
18951572

0 commit comments

Comments
 (0)