|
6 | 6 | // |
7 | 7 | #include "profiles.h" |
8 | 8 | @import Foundation; |
9 | | -@import Security; |
10 | 9 |
|
11 | 10 | NSError* makeError(int code, NSString* msg) { |
12 | 11 | return [NSError errorWithDomain:@"profiles" code:code userInfo:@{NSLocalizedDescriptionKey: msg}]; |
@@ -91,87 +90,57 @@ bool addProfile(IdeviceProviderHandle* provider, NSData* profile, NSError** erro |
91 | 90 | return true; |
92 | 91 | } |
93 | 92 |
|
94 | | -typedef CFTypeRef CMSDecoderRef; |
95 | | -OSStatus CMSDecoderCreate(CMSDecoderRef * cmsDecoderOut); |
96 | | -OSStatus CMSDecoderUpdateMessage(CMSDecoderRef cmsDecoder, const void * msgBytes, size_t msgBytesLen); |
97 | | -OSStatus CMSDecoderFinalizeMessage(CMSDecoderRef cmsDecoder); |
98 | | -OSStatus CMSDecoderCopyContent(CMSDecoderRef cmsDecoder, CFDataRef * contentOut); |
99 | | -OSStatus CMSDecoderCopyAllCerts(CMSDecoderRef cmsDecoder, CFArrayRef * certsOut); |
100 | | - |
101 | | - |
102 | | -// Helper to convert OSStatus -> NSError |
103 | | -static NSError *NSErrorFromOSStatus(OSStatus status, NSString *message) { |
104 | | - if (status == errSecSuccess) return nil; |
105 | | - NSDictionary *userInfo = @{ NSLocalizedDescriptionKey: message ?: @"Security error", |
106 | | - @"OSStatus" : @(status) }; |
107 | | - return [NSError errorWithDomain:NSOSStatusErrorDomain code:status userInfo:userInfo]; |
108 | | -} |
109 | | - |
110 | | - |
111 | 93 | @implementation CMSDecoderHelper |
112 | 94 |
|
113 | 95 | + (NSData*)decodeCMSData:(NSData *)cmsData |
114 | 96 | // outCerts:(NSArray<id> * _Nullable * _Nullable)outCerts |
115 | 97 | error:(NSError * _Nullable * _Nullable)error |
116 | 98 | { |
117 | | - if (!cmsData) { |
118 | | - if (error) *error = [NSError errorWithDomain:NSCocoaErrorDomain code:NSURLErrorBadURL userInfo:@{NSLocalizedDescriptionKey: @"cmsData is nil"}]; |
| 99 | + if (!cmsData || cmsData.length == 0) { |
| 100 | + if (error) { |
| 101 | + *error = [NSError errorWithDomain:NSCocoaErrorDomain |
| 102 | + code:NSURLErrorBadURL |
| 103 | + userInfo:@{NSLocalizedDescriptionKey: @"Invalid or empty CMS payload"}]; |
| 104 | + } |
119 | 105 | return nil; |
120 | 106 | } |
121 | 107 |
|
122 | | - CMSDecoderRef decoder = NULL; |
123 | | - OSStatus status = CMSDecoderCreate(&decoder); |
124 | | - if (status != errSecSuccess || decoder == NULL) { |
125 | | - if (error) *error = NSErrorFromOSStatus(status, @"Failed to create CMS decoder"); |
126 | | - return nil; |
| 108 | + NSData *xmlStart = [@"<?xml" dataUsingEncoding:NSASCIIStringEncoding]; |
| 109 | + NSData *plistEnd = [@"</plist>" dataUsingEncoding:NSASCIIStringEncoding]; |
| 110 | + NSData *binaryMagic = [@"bplist00" dataUsingEncoding:NSASCIIStringEncoding]; |
| 111 | + |
| 112 | + if (xmlStart && plistEnd) { |
| 113 | + NSRange searchRange = NSMakeRange(0, cmsData.length); |
| 114 | + NSRange startRange = [cmsData rangeOfData:xmlStart options:0 range:searchRange]; |
| 115 | + if (startRange.location != NSNotFound) { |
| 116 | + NSUInteger remainingLength = cmsData.length - startRange.location; |
| 117 | + NSRange endSearchRange = NSMakeRange(startRange.location, remainingLength); |
| 118 | + NSRange endRange = [cmsData rangeOfData:plistEnd options:0 range:endSearchRange]; |
| 119 | + if (endRange.location != NSNotFound) { |
| 120 | + NSUInteger plistStart = startRange.location; |
| 121 | + NSUInteger plistEndIndex = NSMaxRange(endRange); |
| 122 | + if (plistEndIndex > plistStart && plistEndIndex <= cmsData.length) { |
| 123 | + NSRange plistRange = NSMakeRange(plistStart, plistEndIndex - plistStart); |
| 124 | + return [cmsData subdataWithRange:plistRange]; |
| 125 | + } |
| 126 | + } |
| 127 | + } |
127 | 128 | } |
128 | 129 |
|
129 | | - // Feed data to decoder |
130 | | - status = CMSDecoderUpdateMessage(decoder, cmsData.bytes, cmsData.length); |
131 | | - if (status != errSecSuccess) { |
132 | | - if (error) *error = NSErrorFromOSStatus(status, @"Failed to update CMS decoder with message bytes"); |
133 | | - CFRelease(decoder); |
134 | | - return nil; |
| 130 | + if (binaryMagic) { |
| 131 | + NSRange binaryRange = [cmsData rangeOfData:binaryMagic options:0 range:NSMakeRange(0, cmsData.length)]; |
| 132 | + if (binaryRange.location != NSNotFound) { |
| 133 | + NSRange plistRange = NSMakeRange(binaryRange.location, cmsData.length - binaryRange.location); |
| 134 | + return [cmsData subdataWithRange:plistRange]; |
| 135 | + } |
135 | 136 | } |
136 | 137 |
|
137 | | - // Finalize (parse) the message |
138 | | - status = CMSDecoderFinalizeMessage(decoder); |
139 | | - if (status != errSecSuccess) { |
140 | | - if (error) *error = NSErrorFromOSStatus(status, @"Failed to finalize CMS message"); |
141 | | - CFRelease(decoder); |
142 | | - return nil; |
143 | | - } |
144 | | - |
145 | | - // Extract the content (the inner payload). This may be NULL if content is detached. |
146 | | - CFDataRef contentData = NULL; |
147 | | - status = CMSDecoderCopyContent(decoder, &contentData); |
148 | | - if (status != errSecSuccess && status != errSecItemNotFound) { |
149 | | - // errSecItemNotFound could mean no content (detached signature) |
150 | | - if (error) *error = NSErrorFromOSStatus(status, @"Failed to copy CMS content"); |
151 | | - if (contentData) CFRelease(contentData); |
152 | | - CFRelease(decoder); |
153 | | - return nil; |
| 138 | + if (error) { |
| 139 | + *error = [NSError errorWithDomain:NSCocoaErrorDomain |
| 140 | + code:NSFileReadUnknownError |
| 141 | + userInfo:@{NSLocalizedDescriptionKey: @"Unable to extract plist from CMS payload"}]; |
154 | 142 | } |
155 | | - |
156 | | -// // Extract embedded certificates (if any) |
157 | | -// CFArrayRef certsArray = NULL; |
158 | | -// status = CMSDecoderCopyAllCerts(decoder, &certsArray); |
159 | | -// if (status == errSecSuccess && certsArray) { |
160 | | -// // certsArray contains SecCertificateRef items |
161 | | -// NSArray *certs = (__bridge_transfer NSArray *)certsArray; |
162 | | -// if (outCerts) *outCerts = certs; |
163 | | -// } else { |
164 | | -// // no certs or error |
165 | | -// if (status != errSecSuccess && status != errSecItemNotFound) { |
166 | | -// if (error) *error = NSErrorFromOSStatus(status, @"Failed to copy embedded certificates (if any)"); |
167 | | -// CFRelease(decoder); |
168 | | -// return NO; |
169 | | -// } |
170 | | -// if (outCerts) *outCerts = @[]; // empty |
171 | | -// } |
172 | | - |
173 | | - CFRelease(decoder); |
174 | | - return (__bridge NSData *)(contentData); |
| 143 | + return nil; |
175 | 144 | } |
176 | 145 |
|
177 | 146 | @end |
0 commit comments