@@ -75,6 +75,11 @@ @interface MOLCodesignChecker ()
7575
7676// Cached on-disk binary file descriptor
7777@property int binaryFileDescriptor;
78+
79+ // Active-slice hint; values <= 0 mean no hint (CPU_TYPE_ANY is -1; ivar zero-default
80+ // from non-fd init paths also fails the > 0 gate in -initWithSecStaticCodeRef:error:).
81+ @property cpu_type_t cpuTypeHint;
82+ @property cpu_subtype_t cpuSubtypeHint;
7883@end
7984
8085@implementation MOLCodesignChecker
@@ -98,6 +103,12 @@ - (instancetype)initWithSecStaticCodeRef:(SecStaticCodeRef)codeRef error:(NSErro
98103 }
99104 });
100105
106+ // hintActiveForFat is YES when the caller passed a real arch hint and we're
107+ // looking at a fat binary. In that mode the per-slice dict is the authority
108+ // for _signingInformation/_certificates; the whole-binary fallback below is
109+ // suppressed regardless of whether a matching slice was found.
110+ BOOL hintActiveForFat = NO ;
111+
101112 // For static code checks perform additional checks across all slices
102113 if (CFGetTypeID (codeRef) == SecStaticCodeGetTypeID ()) {
103114 // Ensure signing is consistent for all architectures.
@@ -106,6 +117,26 @@ - (instancetype)initWithSecStaticCodeRef:(SecStaticCodeRef)codeRef error:(NSErro
106117 NSArray * infos = [self universalSigningInformationForBinaryPath: _binaryPath
107118 fileDescriptor: _binaryFileDescriptor];
108119 if (infos) _universalSigningInformation = infos;
120+
121+ // When the caller provided an active-slice hint and this is a fat binary,
122+ // populate _signingInformation/_certificates from the matching slice.
123+ // The cross-slice consistency check below still runs and still surfaces
124+ // its error informationally; the per-arch identity is already locked in
125+ // via the active-slice extraction. If no slice matches the hint (e.g. a
126+ // PowerPC hint against an i386/x86_64 binary), _signingInformation stays
127+ // nil and hintActiveForFat suppresses the whole-binary fallback below so
128+ // callers see an empty identity for the mismatched arch request.
129+ hintActiveForFat = (_cpuTypeHint > 0 && _universalSigningInformation.count > 0 );
130+ if (hintActiveForFat) {
131+ NSDictionary * sliceDict = [self perSliceDictForCpuType: _cpuTypeHint
132+ cpuSubtype: _cpuSubtypeHint];
133+ if (sliceDict.count > 0 ) {
134+ _signingInformation = sliceDict;
135+ NSArray * certs = sliceDict[(__bridge id )kSecCodeInfoCertificates ];
136+ _certificates = [MOLCertificate certificatesFromArray: certs];
137+ }
138+ }
139+
109140 if (infos && ![self allSigningInformationMatches: infos]) {
110141 status = errSecCSSignatureInvalid;
111142 scopedError = ScopedCFError::BridgeRetain ([self
@@ -114,9 +145,14 @@ - (instancetype)initWithSecStaticCodeRef:(SecStaticCodeRef)codeRef error:(NSErro
114145 }
115146 }
116147
117- // Do not set _signingInformation or _certificates for universal binaries with signing issues.
148+ // Do not set _signingInformation or _certificates for universal binaries with
149+ // signing issues EXCEPT when the cputype hint already populated them from the
150+ // active slice (above). Also suppress when hint mode is active but no slice
151+ // matched — callers asked for a specific arch and should not receive the
152+ // whole-binary aggregate identity.
118153 NSError * err = scopedError.BridgeRelease <NSError *>();
119- if (!([err.domain isEqualToString: kMOLCodesignCheckerErrorDomain ] &&
154+ if (!_signingInformation && !hintActiveForFat &&
155+ !([err.domain isEqualToString: kMOLCodesignCheckerErrorDomain ] &&
120156 status == errSecCSSignatureInvalid)) {
121157 // Get CFDictionary of signing information for binary
122158 CFDictionaryRef signingDict = NULL ;
@@ -154,6 +190,18 @@ - (instancetype)initWithBinaryPath:(NSString*)binaryPath {
154190- (instancetype )initWithBinaryPath : (NSString *)binaryPath
155191 fileDescriptor : (int )fileDescriptor
156192 error : (NSError **)error {
193+ return [self initWithBinaryPath: binaryPath
194+ fileDescriptor: fileDescriptor
195+ cpuType: CPU_TYPE_ANY
196+ cpuSubtype: CPU_SUBTYPE_ANY
197+ error: error];
198+ }
199+
200+ - (instancetype )initWithBinaryPath : (NSString *)binaryPath
201+ fileDescriptor : (int )fileDescriptor
202+ cpuType : (cpu_type_t )cpuType
203+ cpuSubtype : (cpu_subtype_t )cpuSubtype
204+ error : (NSError **)error {
157205 OSStatus status = errSecSuccess;
158206 SecStaticCodeRef codeRef = NULL ;
159207
@@ -177,6 +225,8 @@ - (instancetype)initWithBinaryPath:(NSString*)binaryPath
177225
178226 _binaryPath = binaryPath;
179227 _binaryFileDescriptor = (fileDescriptor != -1 ) ? fileDescriptor : -1 ;
228+ _cpuTypeHint = cpuType;
229+ _cpuSubtypeHint = cpuSubtype;
180230
181231 self = [self initWithSecStaticCodeRef: codeRef error: error];
182232 if (codeRef) CFRelease (codeRef); // it was retained above
@@ -415,6 +465,11 @@ - (NSError*)errorWithCode:(OSStatus)code {
415465 return [self errorWithCode: code description: nil ];
416466}
417467
468+ // Reports whether every slice of a universal binary shares the same signing
469+ // identity (cert chain, or "-" for ad-hoc). Callers that care about per-arch
470+ // identity should use the cputype-aware initializer instead; this check is
471+ // retained as an informational signal that surfaces `errSecCSSignatureInvalid`
472+ // in MOL's error domain for cross-slice inconsistencies.
418473- (BOOL )allSigningInformationMatches : (NSArray *)signingInformation {
419474 NSMutableSet * chains = [NSMutableSet set ];
420475 for (NSDictionary * arch in signingInformation) {
@@ -460,6 +515,17 @@ - (NSArray*)universalSigningInformationForBinaryPath:(NSString*)path fileDescrip
460515 return infos.count ? infos : nil ;
461516}
462517
518+ - (NSDictionary *)perSliceDictForCpuType : (cpu_type_t )cpuType cpuSubtype : (cpu_subtype_t )cpuSubtype {
519+ const char * nameRaw = macho_arch_name_for_cpu_type (cpuType, cpuSubtype);
520+ NSString * archName =
521+ nameRaw ? @(nameRaw) : [NSString stringWithFormat: @" %i :%i " , cpuType, cpuSubtype];
522+ for (NSDictionary * arch in _universalSigningInformation) {
523+ NSDictionary * dict = arch[archName];
524+ if (dict) return dict;
525+ }
526+ return nil ;
527+ }
528+
463529- (NSString *)architectureString : (struct fat_arch *)fatArch bigEndian : (BOOL )bigEndian {
464530 cpu_type_t cpu = bigEndian ? OSSwapBigToHostInt (fatArch->cputype ) : fatArch->cputype ;
465531 cpu_subtype_t cpuSub = bigEndian ? OSSwapBigToHostInt (fatArch->cpusubtype ) : fatArch->cpusubtype ;
0 commit comments