]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_codesigning/lib/legacydevid.cpp
Security-59754.60.13.tar.gz
[apple/security.git] / OSX / libsecurity_codesigning / lib / legacydevid.cpp
1 /*
2 * Copyright (c) 2019 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
24 #include "legacydevid.h"
25 #include "SecAssessment.h"
26 #include "requirement.h"
27
28 #include <Security/SecCertificatePriv.h>
29
30 namespace Security {
31 namespace CodeSigning {
32
33 static const CFStringRef kLegacyPolicyPreferenceDomain = CFSTR("com.apple.security.syspolicy");
34 static const CFStringRef kLegacyPolicyAccountCreationCutOff = CFSTR("AccountCreationCutOffDate");
35 static const CFStringRef kLegacyPolicySecureTimestampCutOff = CFSTR("SecureTimestampCutOffDate");
36 static const CFAbsoluteTime kLegacyPolicyAccountCreationDefaultCutOff = 576374400.0; // seconds from January 1, 2001 to April 7, 2019 GMT
37 static const CFAbsoluteTime kLegacyPolicySecureTimestampDefaultCutOff = 581040000.0; // seconds from January 1, 2001 to June 1, 2019 GMT
38
39 static CFDateRef
40 copyCutOffDate(const CFStringRef key, CFAbsoluteTime defaultCutoff)
41 {
42 CFDateRef defaultDate = CFDateCreate(NULL, defaultCutoff);
43 CFDateRef outputDate = defaultDate;
44 CFDateRef prefDate = NULL;
45
46 CFTypeRef prefVal = (CFDateRef)CFPreferencesCopyValue(key,
47 kLegacyPolicyPreferenceDomain,
48 kCFPreferencesCurrentUser,
49 kCFPreferencesAnyHost);
50 if (prefVal && CFGetTypeID(prefVal) == CFDateGetTypeID()) {
51 prefDate = (CFDateRef)prefVal;
52 }
53
54 if (prefDate) {
55 CFComparisonResult res = CFDateCompare(defaultDate, prefDate, NULL);
56 if (res > 0) {
57 outputDate = prefDate;
58 }
59 }
60
61 CFRetain(outputDate);
62
63 if (prefVal) {
64 CFRelease(prefVal);
65 }
66 if (defaultDate) {
67 CFRelease(defaultDate);
68 }
69 return outputDate;
70 }
71
72 bool
73 meetsDeveloperIDLegacyAllowedPolicy(const Requirement::Context *context)
74 {
75 CFRef<CFDataRef> cd;
76 CFRef<CFErrorRef> error;
77 CFRef<CFStringRef> teamID;
78 bool meets_legacy_policy = false;
79 SecCSDigestAlgorithm hashType = kSecCodeSignatureNoHash;
80 SecCertificateRef cert = NULL;
81 CFAbsoluteTime accountCreationTime = 0.0;
82
83 if (context == NULL) {
84 meets_legacy_policy = false;
85 goto lb_exit;
86 }
87
88 // First check account creation date in certs
89 // An account creation date after the cut off must be notarized so it fails the legacy policy.
90 // No account creation date or an account creation date before the cut off requires additional checking
91 cert = context->cert(Requirement::leafCert);
92 if (SecCertificateGetDeveloperIDDate(cert, &accountCreationTime, &error.aref())) {
93 //There is an account creation date
94 CFRef<CFDateRef> accountCreationDate = CFDateCreate(NULL, accountCreationTime);
95 CFRef<CFDateRef> accountCreationCutoffDate = copyCutOffDate(kLegacyPolicyAccountCreationCutOff,
96 kLegacyPolicyAccountCreationDefaultCutOff);
97 secinfo("meetsDeveloperIDLegacyAllowedPolicy", "Account Creation Date Cutoff: %@", accountCreationCutoffDate.get());
98 secinfo("meetsDeveloperIDLegacyAllowedPolicy", "Account Creation date: %@", accountCreationDate.get());
99
100 CFComparisonResult res = CFDateCompare(accountCreationDate, accountCreationCutoffDate, NULL);
101 if (res >= 0) {
102 // The account was created on or after our cut off so it doesn't meet legacy policy
103 meets_legacy_policy = false;
104 secinfo("meetsDeveloperIDLegacyAllowedPolicy", "Account creation date %@ is after cut-off %@", accountCreationDate.get(), accountCreationCutoffDate.get());
105 goto lb_exit;
106 }
107 // Account creation date before the cut off means we fall through
108 } else {
109 CFIndex errorCode = CFErrorGetCode(error);
110 if (errorCode != errSecMissingRequiredExtension) {
111 secerror("Unexpected error checking account creation date: %ld", errorCode);
112 meets_legacy_policy = false;
113 goto lb_exit;
114 }
115 // there was no account creation date so fall through
116 }
117
118 // Next check secure time stamp
119 if (context->secureTimestamp) {
120 CFRef<CFDateRef> secureTimestampCutoffDate = copyCutOffDate(kLegacyPolicySecureTimestampCutOff,
121 kLegacyPolicySecureTimestampDefaultCutOff);
122 secinfo("meetsDeveloperIDLegacyAllowedPolicy", "Secure Timestamp Cutoff Date cutoff: %@", secureTimestampCutoffDate.get());
123 secinfo("meetsDevleoperIDLegacyAllowedPolicy", "Secure Timestamp: %@", context->secureTimestamp);
124 CFComparisonResult res = CFDateCompare(context->secureTimestamp, secureTimestampCutoffDate, NULL);
125 if (res >= 0) {
126 // Secure timestamp is on or after the cut of so it doesn't meet legacy policy
127 meets_legacy_policy = false;
128 secinfo("meetsDeveloperIDLegacyAllowedPolicy", "Secure timestamp %@ is after cut-off %@", context->secureTimestamp, secureTimestampCutoffDate.get());
129 } else {
130 // Secure timestamp is before the cut off so we meet the legacy policy
131 meets_legacy_policy = true;
132 }
133 }
134
135 if (!meets_legacy_policy) {
136 // Just check against the legacy lists, both by hash and team ID.
137 if (context->directory) {
138 cd.take(context->directory->cdhash());
139 hashType = (SecCSDigestAlgorithm)context->directory->hashType;
140 } else if (context->packageChecksum) {
141 cd = context->packageChecksum;
142 hashType = context->packageAlgorithm;
143 }
144
145 if (cd.get() == NULL) {
146 // No cdhash means we can't check the legacy lists
147 meets_legacy_policy = false;
148 goto lb_exit;
149 }
150
151 if (context->teamIdentifier) {
152 teamID.take(CFStringCreateWithCString(kCFAllocatorDefault, context->teamIdentifier, kCFStringEncodingUTF8));
153 }
154
155 secnotice("legacy_list", "checking the legacy list for %d, %@, %@", hashType, cd.get(), teamID.get());
156 #if TARGET_OS_OSX
157 if (SecAssessmentLegacyCheck(cd, hashType, teamID, &error.aref())) {
158 meets_legacy_policy = true;
159 } else {
160 meets_legacy_policy = false;
161 if (error.get() != NULL) {
162 secerror("Error checking with notarization daemon: %ld", CFErrorGetCode(error));
163 }
164 }
165 #endif
166 }
167 lb_exit:
168 secnotice("legacy_list", "meetsDeveloperIDLegacyAllowedPolicy = %d", meets_legacy_policy);
169 return meets_legacy_policy;
170 }
171
172 }
173 }