2 * Copyright (c) 2020 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
23 * ca_revocation_additions.m
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>
32 #include "SecurityCommands.h"
34 NSString* secToolAppID = @"com.apple.security";
36 static int addCertFile(const char *fileName, NSMutableArray *array) {
37 SecCertificateRef certRef = NULL;
39 unsigned char *buf = NULL;
43 if (readFileSizet(fileName, &buf, &numBytes)) {
48 data = [NSData dataWithBytes:buf length:numBytes];
49 certRef = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)data);
51 certRef = SecCertificateCreateWithPEM(NULL, (__bridge CFDataRef)data);
58 [array addObject:(__bridge id)certRef];
63 CFReleaseNull(certRef);
67 static 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);
72 CFIndex errCode = CFErrorGetCode(error);
77 static int resetRevocationAdditions(bool resetCerts) {
79 CFErrorRef error = NULL;
81 NSDictionary *resetCertsDict = @{ (__bridge NSString*)kSecCARevocationAdditionsKey: @[] };
82 result = SecTrustStoreSetCARevocationAdditions(NULL, (__bridge CFDictionaryRef)resetCertsDict, &error);
85 return returnCFError(error);
90 static 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);
97 NSMutableArray *additionsForKey = nil;
98 if (currentAdditions && currentAdditions[(__bridge NSString*)key]) {
99 additionsForKey = [currentAdditions[(__bridge NSString*)key] mutableCopy];
100 [additionsForKey addObjectsFromArray:newAdditions];
102 additionsForKey = [newAdditions copy];
105 NSDictionary *newAdditionsDict = @{ (__bridge NSString*)key: additionsForKey };
106 bool result = SecTrustStoreSetCARevocationAdditions(NULL, (__bridge CFDictionaryRef)newAdditionsDict, &error);
108 return returnCFError(error);
114 int add_ca_revocation_checking(int argc, char * const *argv) {
117 bool resetCerts = false;
119 NSMutableArray *certs = [NSMutableArray array];
120 NSDictionary *plist = nil;
124 return SHOW_USAGE_MESSAGE;
127 while ((arg = getopt(argc, argv, "c:r:p:")) != -1) {
130 if (addCertFile(optarg, certs)) {
131 fprintf(stderr, "Failed to read cert file\n");
136 if (!strcmp(optarg, "all")) {
138 } else if (!strcmp(optarg, "cert")) {
141 return SHOW_USAGE_MESSAGE;
145 plist = [NSDictionary dictionaryWithContentsOfFile:[NSString stringWithCString:optarg encoding:NSUTF8StringEncoding]];
149 return SHOW_USAGE_MESSAGE;
153 /* handle reset operation */
155 return resetRevocationAdditions(resetCerts);
160 CFErrorRef error = NULL;
161 bool result = SecTrustStoreSetCARevocationAdditions(NULL, (__bridge CFDictionaryRef)plist, &error);
163 return returnCFError(error);
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];
180 status = addRevocationAdditions(kSecCARevocationAdditionsKey, valuesForCAsKey);
183 fprintf(stderr, "failed to add cert revocation additions\n");
190 static 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);
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]]) {
204 [additionsString appendFormat:@"\"%@\"",obj];
206 [additionsString appendFormat:@", \"%@\"", obj];
208 } else if ([obj isKindOfClass:[NSDictionary class]]) {
210 [additionsString appendString:@"\n\t "];
212 [additionsString appendString:@"\t "];
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"];
220 [additionsString appendString:@"\",\n"];
224 [additionsString appendString:@"]\n"];
225 CFStringPerformWithCString((__bridge CFStringRef)additionsString, ^(const char *utf8Str) {
226 fprintf(stdout, "\n%s\n", utf8Str);
232 int show_ca_revocation_checking(int argc, char * const *argv) {
234 bool allAdditions = false;
235 NSString *identifier = nil;
236 bool certAdditions = false;
239 while ((arg = getopt(argc, argv, "ai:c")) != -1) {
245 identifier = [NSString stringWithCString:optarg encoding:NSUTF8StringEncoding];
248 certAdditions = true;
252 return SHOW_USAGE_MESSAGE;
258 fprintf(stdout, "Showing revocation additions for all apps\n");
259 } else if (!identifier) {
260 identifier = secToolAppID;
264 CFStringPerformWithCString((__bridge CFStringRef)identifier, ^(const char *utf8Str) {
265 fprintf(stdout, "Showing revocation additions for %s\n", utf8Str);
269 CFErrorRef error = NULL;
270 NSDictionary *results = CFBridgingRelease(SecTrustStoreCopyCARevocationAdditions((__bridge CFStringRef)identifier, &error));
272 /* Copy failed, return error */
273 if (!results && error) {
274 return returnCFError(error);
277 /* print cert revocation additions */
280 status = printRevocationAdditions(kSecCARevocationAdditionsKey, results);
283 fprintf(stderr, "failed to print revocation additions\n");