]> git.saurik.com Git - apple/security.git/blob - OSX/utilities/SecXPCHelper.m
Security-59306.41.2.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> *)safeErrorCollectionClasses
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 "NSArray",
46 "NSDictionary",
47 "NSError",
48 "NSOrderedSet",
49 "NSSet",
50 };
51
52 for (unsigned n = 0; n < sizeof(classes) / sizeof(classes[0]); n++) {
53 Class class = objc_getClass(classes[n]);
54 if (class) {
55 [errorClasses addObject:class];
56 }
57 }
58 });
59
60 return errorClasses;
61 }
62
63 + (NSSet<Class> *)safeErrorClasses
64 {
65 static NSMutableSet<Class> *errorClasses = nil;
66 static dispatch_once_t onceToken;
67 dispatch_once(&onceToken, ^{
68 errorClasses = [NSMutableSet set];
69 for (Class class in [SecXPCHelper safeErrorPrimitiveClasses]) {
70 [errorClasses addObject:class];
71 }
72 for (Class class in [SecXPCHelper safeErrorCollectionClasses]) {
73 [errorClasses addObject:class];
74 }
75 });
76
77 return errorClasses;
78 }
79
80 + (NSDictionary *)cleanDictionaryForXPC:(NSDictionary *)dict
81 {
82 if (!dict) {
83 return nil;
84 }
85
86 NSMutableDictionary *mutableDictionary = [dict mutableCopy];
87 for (id key in mutableDictionary.allKeys) {
88 id object = mutableDictionary[key];
89 mutableDictionary[key] = [SecXPCHelper cleanObjectForXPC:object];
90 }
91 return mutableDictionary;
92 }
93
94 + (id)cleanObjectForXPC:(id)object
95 {
96 if (!object) {
97 return nil;
98 }
99
100 // Check for primitive classes first, and return them as is
101 for (Class class in [SecXPCHelper safeErrorPrimitiveClasses]) {
102 if ([object isKindOfClass:class]) {
103 return object;
104 }
105 }
106
107 // Else, check for known collection classes. We only handle those collection classes we whitelist as
108 // safe, as per the result of `[SecXPCHelper safeErrorCollectionClasses]`. For each collection class,
109 // we also handle the contents uniquely, since not all collections share the same APIs.
110 for (Class class in [SecXPCHelper safeErrorCollectionClasses]) {
111 if ([object isKindOfClass:class]) {
112 if ([object isKindOfClass:[NSError class]]) {
113 NSError *errorObject = (NSError *)object;
114 return [NSError errorWithDomain:errorObject.domain code:errorObject.code userInfo:[SecXPCHelper cleanDictionaryForXPC:errorObject.userInfo]];
115 } if ([object isKindOfClass:[NSDictionary class]]) {
116 return [SecXPCHelper cleanDictionaryForXPC:(NSDictionary *)object];
117 } else if ([object isKindOfClass:[NSArray class]]) {
118 NSArray *arrayObject = (NSArray *)object;
119 NSMutableArray* cleanArray = [NSMutableArray arrayWithCapacity:arrayObject.count];
120 for (id x in arrayObject) {
121 [cleanArray addObject:[SecXPCHelper cleanObjectForXPC:x]];
122 }
123 return cleanArray;
124 } else if ([object isKindOfClass:[NSSet class]]) {
125 NSSet *setObject = (NSSet *)object;
126 NSMutableSet *cleanSet = [NSMutableSet setWithCapacity:setObject.count];
127 for (id x in setObject) {
128 [cleanSet addObject:[SecXPCHelper cleanObjectForXPC:x]];
129 }
130 return cleanSet;
131 } else if ([object isKindOfClass:[NSOrderedSet class]]) {
132 NSOrderedSet *setObject = (NSOrderedSet *)object;
133 NSMutableOrderedSet *cleanSet = [NSMutableOrderedSet orderedSetWithCapacity:setObject.count];
134 for (id x in setObject) {
135 [cleanSet addObject:[SecXPCHelper cleanObjectForXPC:x]];
136 }
137 return cleanSet;
138 }
139 }
140 }
141
142 // If all else fails, just return the object's class description
143 return NSStringFromClass([object class]);
144 }
145
146 + (NSError *)cleanseErrorForXPC:(NSError * _Nullable)error
147 {
148 if (!error) {
149 return nil;
150 }
151
152 NSDictionary<NSErrorUserInfoKey, id> *userInfo = [SecXPCHelper cleanDictionaryForXPC:error.userInfo];
153 return [NSError errorWithDomain:error.domain code:error.code userInfo:userInfo];
154 }
155
156 static NSString *kArchiveKeyError = @"error";
157
158 + (NSError *)errorFromEncodedData:(NSData *)data
159 {
160 NSKeyedUnarchiver *unarchiver = nil;
161 NSError *error = nil;
162
163 unarchiver = [[NSKeyedUnarchiver alloc] initForReadingFromData:data error:NULL];
164 if (unarchiver != nil) {
165 error = [unarchiver decodeObjectOfClass:[NSError class] forKey:kArchiveKeyError];
166 }
167
168 return error;
169 }
170
171 + (NSData *)encodedDataFromError:(NSError *)error
172 {
173 NSKeyedArchiver *archiver = nil;
174 NSData *data = nil;
175
176 archiver = [[NSKeyedArchiver alloc] initRequiringSecureCoding:YES];
177 [archiver encodeObject:error forKey:kArchiveKeyError];
178 data = archiver.encodedData;
179
180 return data;
181 }
182
183 @end