]> git.saurik.com Git - apple/security.git/blob - OSX/utilities/SecXPCHelper.m
Security-59754.80.3.tar.gz
[apple/security.git] / OSX / utilities / SecXPCHelper.m
1 //
2 // SecXPCHelper.m
3 // Security
4 //
5
6 #import <Foundation/Foundation.h>
7 #import <objc/objc-class.h>
8 #import "SecXPCHelper.h"
9
10 @implementation SecXPCHelper : NSObject
11
12 + (NSSet<Class> *)safeErrorPrimitiveClasses
13 {
14 static NSMutableSet<Class> *errorClasses = nil;
15 static dispatch_once_t onceToken;
16 dispatch_once(&onceToken, ^{
17 errorClasses = [NSMutableSet set];
18 char *classes[] = {
19 "NSData",
20 "NSDate",
21 "NSNull",
22 "NSNumber",
23 "NSString",
24 "NSURL",
25 };
26
27 for (unsigned n = 0; n < sizeof(classes) / sizeof(classes[0]); n++) {
28 Class class = objc_getClass(classes[n]);
29 if (class) {
30 [errorClasses addObject:class];
31 }
32 }
33 });
34
35 return errorClasses;
36 }
37
38 + (NSSet<Class> *)safeCKErrorPrimitiveClasses
39 {
40 static NSMutableSet<Class> *errorClasses = nil;
41 static dispatch_once_t onceToken;
42 dispatch_once(&onceToken, ^{
43 errorClasses = [NSMutableSet set];
44 char *classes[] = {
45 "CKArchivedAnchoredPackage",
46 "CKAsset",
47 "CKPackage",
48 "CKRecordID",
49 "CKReference",
50 "CLLocation",
51 };
52
53 for (unsigned n = 0; n < sizeof(classes) / sizeof(classes[0]); n++) {
54 Class class = objc_getClass(classes[n]);
55 if (class) {
56 [errorClasses addObject:class];
57 }
58 }
59 });
60
61 return errorClasses;
62 }
63
64 + (NSSet<Class> *)safeErrorCollectionClasses
65 {
66 static NSMutableSet<Class> *errorClasses = nil;
67 static dispatch_once_t onceToken;
68 dispatch_once(&onceToken, ^{
69 errorClasses = [NSMutableSet set];
70 char *classes[] = {
71 "NSArray",
72 "NSDictionary",
73 "NSError",
74 "NSOrderedSet",
75 "NSSet",
76 "NSURLError",
77 };
78
79 for (unsigned n = 0; n < sizeof(classes) / sizeof(classes[0]); n++) {
80 Class class = objc_getClass(classes[n]);
81 if (class) {
82 [errorClasses addObject:class];
83 }
84 }
85 });
86
87 return errorClasses;
88 }
89
90 + (NSSet<Class> *)safeErrorClasses
91 {
92 static NSMutableSet<Class> *errorClasses = nil;
93 static dispatch_once_t onceToken;
94 dispatch_once(&onceToken, ^{
95 errorClasses = [NSMutableSet set];
96 for (Class class in [SecXPCHelper safeErrorPrimitiveClasses]) {
97 [errorClasses addObject:class];
98 }
99 for (Class class in [SecXPCHelper safeCKErrorPrimitiveClasses]) {
100 [errorClasses addObject:class];
101 }
102 for (Class class in [SecXPCHelper safeErrorCollectionClasses]) {
103 [errorClasses addObject:class];
104 }
105 });
106
107 return errorClasses;
108 }
109
110 + (NSDictionary *)cleanDictionaryForXPC:(NSDictionary *)dict
111 {
112 if (!dict) {
113 return nil;
114 }
115
116 NSMutableDictionary *mutableDictionary = [dict mutableCopy];
117 for (id key in mutableDictionary.allKeys) {
118 id object = mutableDictionary[key];
119 mutableDictionary[key] = [SecXPCHelper cleanObjectForXPC:object];
120 }
121 return mutableDictionary;
122 }
123
124 + (id)cleanObjectForXPC:(id)object
125 {
126 if (!object) {
127 return nil;
128 }
129
130 // Check for primitive classes first, and return them as is
131 for (Class class in [SecXPCHelper safeErrorPrimitiveClasses]) {
132 if ([object isKindOfClass:class]) {
133 return object;
134 }
135 }
136
137 // Else, check for known collection classes. We only handle those collection classes we whitelist as
138 // safe, as per the result of `[SecXPCHelper safeErrorCollectionClasses]`. For each collection class,
139 // we also handle the contents uniquely, since not all collections share the same APIs.
140 for (Class class in [SecXPCHelper safeErrorCollectionClasses]) {
141 if ([object isKindOfClass:class]) {
142 if ([object isKindOfClass:[NSError class]]) {
143 NSError *errorObject = (NSError *)object;
144 return [NSError errorWithDomain:errorObject.domain code:errorObject.code userInfo:[SecXPCHelper cleanDictionaryForXPC:errorObject.userInfo]];
145 } if ([object isKindOfClass:[NSDictionary class]]) {
146 return [SecXPCHelper cleanDictionaryForXPC:(NSDictionary *)object];
147 } else if ([object isKindOfClass:[NSArray class]]) {
148 NSArray *arrayObject = (NSArray *)object;
149 NSMutableArray* cleanArray = [NSMutableArray arrayWithCapacity:arrayObject.count];
150 for (id x in arrayObject) {
151 [cleanArray addObject:[SecXPCHelper cleanObjectForXPC:x]];
152 }
153 return cleanArray;
154 } else if ([object isKindOfClass:[NSSet class]]) {
155 NSSet *setObject = (NSSet *)object;
156 NSMutableSet *cleanSet = [NSMutableSet setWithCapacity:setObject.count];
157 for (id x in setObject) {
158 [cleanSet addObject:[SecXPCHelper cleanObjectForXPC:x]];
159 }
160 return cleanSet;
161 } else if ([object isKindOfClass:[NSOrderedSet class]]) {
162 NSOrderedSet *setObject = (NSOrderedSet *)object;
163 NSMutableOrderedSet *cleanSet = [NSMutableOrderedSet orderedSetWithCapacity:setObject.count];
164 for (id x in setObject) {
165 [cleanSet addObject:[SecXPCHelper cleanObjectForXPC:x]];
166 }
167 return cleanSet;
168 }
169 }
170 }
171
172 // If all else fails, just return the object's class description
173 return NSStringFromClass([object class]);
174 }
175
176 + (NSError * _Nullable)cleanseErrorForXPC:(NSError * _Nullable)error
177 {
178 if (!error) {
179 return nil;
180 }
181
182 NSDictionary<NSErrorUserInfoKey, id> *userInfo = [SecXPCHelper cleanDictionaryForXPC:error.userInfo];
183 return [NSError errorWithDomain:error.domain code:error.code userInfo:userInfo];
184 }
185
186 static NSString *kArchiveKeyError = @"error";
187
188 + (NSError * _Nullable)errorFromEncodedData:(NSData *)data
189 {
190 NSKeyedUnarchiver *unarchiver = nil;
191 NSError *error = nil;
192
193 unarchiver = [[NSKeyedUnarchiver alloc] initForReadingFromData:data error:NULL];
194 if (unarchiver != nil) {
195 error = [unarchiver decodeObjectOfClass:[NSError class] forKey:kArchiveKeyError];
196 }
197
198 return error;
199 }
200
201 + (NSData *)encodedDataFromError:(NSError *)error
202 {
203 NSKeyedArchiver *archiver = nil;
204 NSData *data = nil;
205
206 archiver = [[NSKeyedArchiver alloc] initRequiringSecureCoding:YES];
207 [archiver encodeObject:error forKey:kArchiveKeyError];
208 data = archiver.encodedData;
209
210 return data;
211 }
212
213 @end