]> git.saurik.com Git - apple/security.git/blame - SecurityTool/sharedTool/ca_revocation_additions.m
Security-59754.80.3.tar.gz
[apple/security.git] / SecurityTool / sharedTool / ca_revocation_additions.m
CommitLineData
d64be36e
A
1/*
2 * Copyright (c) 2020 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 *
23 * ca_revocation_additions.m
24 */
25
26#import <Foundation/Foundation.h>
27#include <Security/SecTrustSettingsPriv.h>
28#include <Security/SecCertificatePriv.h>
29#include <utilities/fileIo.h>
30#include <utilities/SecCFWrappers.h>
31
32#include "SecurityCommands.h"
33
34NSString* secToolAppID = @"com.apple.security";
35
36static int addCertFile(const char *fileName, NSMutableArray *array) {
37 SecCertificateRef certRef = NULL;
38 NSData *data = NULL;
39 unsigned char *buf = NULL;
40 size_t numBytes;
41 int rtn = 0;
42
43 if (readFileSizet(fileName, &buf, &numBytes)) {
44 rtn = -1;
45 goto errOut;
46 }
47
48 data = [NSData dataWithBytes:buf length:numBytes];
49 certRef = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)data);
50 if (!certRef) {
51 certRef = SecCertificateCreateWithPEM(NULL, (__bridge CFDataRef)data);
52 if (!certRef) {
53 rtn = -1;
54 goto errOut;
55 }
56 }
57
58 [array addObject:(__bridge id)certRef];
59
60errOut:
61 /* Cleanup */
62 free(buf);
63 CFReleaseNull(certRef);
64 return rtn;
65}
66
67static int returnCFError(CFErrorRef CF_CONSUMED error) {
68 CFStringRef errorString = CFErrorCopyDescription(error);
69 CFStringPerformWithCString(errorString, ^(const char *utf8Str) {
70 fprintf(stderr, "Failed to copy CA revocation additions: %s\n", utf8Str);
71 });
72 CFIndex errCode = CFErrorGetCode(error);
73 CFReleaseNull(error);
74 return (int)errCode;
75}
76
77static int resetRevocationAdditions(bool resetCerts) {
78 bool result = false;
79 CFErrorRef error = NULL;
80 if (resetCerts) {
81 NSDictionary *resetCertsDict = @{ (__bridge NSString*)kSecCARevocationAdditionsKey: @[] };
82 result = SecTrustStoreSetCARevocationAdditions(NULL, (__bridge CFDictionaryRef)resetCertsDict, &error);
83 }
84 if (!result) {
85 return returnCFError(error);
86 }
87 return 0;
88}
89
90static int addRevocationAdditions(CFStringRef key, NSArray *newAdditions) {
91 CFErrorRef error = NULL;
92 NSDictionary *currentAdditions = CFBridgingRelease(SecTrustStoreCopyCARevocationAdditions((__bridge CFStringRef)secToolAppID, &error));
93 if (!currentAdditions && error) {
94 return returnCFError(error);
95 }
96
97 NSMutableArray *additionsForKey = nil;
98 if (currentAdditions && currentAdditions[(__bridge NSString*)key]) {
99 additionsForKey = [currentAdditions[(__bridge NSString*)key] mutableCopy];
100 [additionsForKey addObjectsFromArray:newAdditions];
101 } else {
102 additionsForKey = [newAdditions copy];
103 }
104
105 NSDictionary *newAdditionsDict = @{ (__bridge NSString*)key: additionsForKey };
106 bool result = SecTrustStoreSetCARevocationAdditions(NULL, (__bridge CFDictionaryRef)newAdditionsDict, &error);
107 if (!result) {
108 return returnCFError(error);
109 }
110
111 return 0;
112}
113
114int add_ca_revocation_checking(int argc, char * const *argv) {
115 int arg;
116
117 bool resetCerts = false;
118
119 NSMutableArray *certs = [NSMutableArray array];
120 NSDictionary *plist = nil;
121
122 /* parse args */
123 if (argc == 1) {
124 return SHOW_USAGE_MESSAGE;
125 }
126
127 while ((arg = getopt(argc, argv, "c:r:p:")) != -1) {
128 switch(arg) {
129 case 'c':
130 if (addCertFile(optarg, certs)) {
131 fprintf(stderr, "Failed to read cert file\n");
132 return 1;
133 }
134 break;
135 case 'r':
136 if (!strcmp(optarg, "all")) {
137 resetCerts = true;
138 } else if (!strcmp(optarg, "cert")) {
139 resetCerts = true;
140 } else {
141 return SHOW_USAGE_MESSAGE;
142 }
143 break;
144 case 'p':
145 plist = [NSDictionary dictionaryWithContentsOfFile:[NSString stringWithCString:optarg encoding:NSUTF8StringEncoding]];
146 break;
147 case '?':
148 default:
149 return SHOW_USAGE_MESSAGE;
150 }
151 }
152
153 /* handle reset operation */
154 if (resetCerts) {
155 return resetRevocationAdditions(resetCerts);
156 }
157
158 /* set plist */
159 if (plist) {
160 CFErrorRef error = NULL;
161 bool result = SecTrustStoreSetCARevocationAdditions(NULL, (__bridge CFDictionaryRef)plist, &error);
162 if (!result) {
163 return returnCFError(error);
164 } else {
165 return 0;
166 }
167 }
168
169 /* add certs */
170 int status = 0;
171 if ([certs count]) {
172 NSMutableArray<NSDictionary *>*valuesForCAsKey = [NSMutableArray arrayWithCapacity:[certs count]];
173 [certs enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
174 SecCertificateRef cert = (__bridge SecCertificateRef)obj;
175 NSData* hash = CFBridgingRelease(SecCertificateCopySubjectPublicKeyInfoSHA256Digest(cert));
176 NSDictionary *value = @{ (__bridge NSString*)kSecCARevocationHashAlgorithmKey:@"sha256",
177 (__bridge NSString*)kSecCARevocationSPKIHashKey:hash };
178 [valuesForCAsKey addObject:value];
179 }];
180 status = addRevocationAdditions(kSecCARevocationAdditionsKey, valuesForCAsKey);
181 }
182 if (status != 0) {
183 fprintf(stderr, "failed to add cert revocation additions\n");
184 return status;
185 }
186
187 return 0;
188}
189
190static int printRevocationAdditions(CFStringRef key, NSDictionary *allAdditions) {
191 if (!allAdditions || !allAdditions[(__bridge NSString*)key] ||
192 [allAdditions[(__bridge NSString*)key] count] == 0) {
193 CFStringPerformWithCString(key, ^(const char *utf8Str) {
194 fprintf(stdout, "No revocation additions for %s\n", utf8Str);
195 });
196 return 0;
197 }
198
199 NSArray *additionsForKey = allAdditions[(__bridge NSString*)key];
200 NSMutableString *additionsString = [NSMutableString stringWithFormat:@"\t%@ : [",key];
201 [additionsForKey enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
202 if ([obj isKindOfClass:[NSString class]]) {
203 if (idx == 0) {
204 [additionsString appendFormat:@"\"%@\"",obj];
205 } else {
206 [additionsString appendFormat:@", \"%@\"", obj];
207 }
208 } else if ([obj isKindOfClass:[NSDictionary class]]) {
209 if (idx == 0) {
210 [additionsString appendString:@"\n\t "];
211 } else {
212 [additionsString appendString:@"\t "];
213 }
214 [additionsString appendFormat:@"\"%@:", obj[(__bridge NSString*)kSecCARevocationHashAlgorithmKey]];
215 NSString *hashHex = CFBridgingRelease(CFDataCopyHexString((__bridge CFDataRef)obj[(__bridge NSString*)kSecCARevocationSPKIHashKey]));
216 [additionsString appendString:hashHex];
217 if ([additionsForKey count] == idx + 1) { // last entry
218 [additionsString appendString:@"\"\n"];
219 } else {
220 [additionsString appendString:@"\",\n"];
221 }
222 }
223 }];
224 [additionsString appendString:@"]\n"];
225 CFStringPerformWithCString((__bridge CFStringRef)additionsString, ^(const char *utf8Str) {
226 fprintf(stdout, "\n%s\n", utf8Str);
227 });
228
229 return 0;
230}
231
232int show_ca_revocation_checking(int argc, char * const *argv) {
233 int arg;
234 bool allAdditions = false;
235 NSString *identifier = nil;
236 bool certAdditions = false;
237
238 /* parse args */
239 while ((arg = getopt(argc, argv, "ai:c")) != -1) {
240 switch(arg) {
241 case 'a':
242 allAdditions = true;
243 break;
244 case 'i':
245 identifier = [NSString stringWithCString:optarg encoding:NSUTF8StringEncoding];
246 break;
247 case 'c':
248 certAdditions = true;
249 break;
250 case '?':
251 default:
252 return SHOW_USAGE_MESSAGE;
253 }
254 }
255
256 if (allAdditions) {
257 identifier = nil;
258 fprintf(stdout, "Showing revocation additions for all apps\n");
259 } else if (!identifier) {
260 identifier = secToolAppID;
261 }
262
263 if (identifier) {
264 CFStringPerformWithCString((__bridge CFStringRef)identifier, ^(const char *utf8Str) {
265 fprintf(stdout, "Showing revocation additions for %s\n", utf8Str);
266 });
267 }
268
269 CFErrorRef error = NULL;
270 NSDictionary *results = CFBridgingRelease(SecTrustStoreCopyCARevocationAdditions((__bridge CFStringRef)identifier, &error));
271
272 /* Copy failed, return error */
273 if (!results && error) {
274 return returnCFError(error);
275 }
276
277 /* print cert revocation additions */
278 int status = 0;
279 if (certAdditions) {
280 status = printRevocationAdditions(kSecCARevocationAdditionsKey, results);
281 }
282 if (status != 0) {
283 fprintf(stderr, "failed to print revocation additions\n");
284 return status;
285 }
286
287
288 return 0;
289}