2020#
2121import base64
2222import calendar
23- import ctypes
24- import ctypes .util
2523import os
2624import shutil
2725import struct
4341
4442import Foundation
4543import macholib .MachO
46- import objc
4744from 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-
725409class 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