1 // Copyright 2024 The Chromium Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef BASE_MAC_PROCESS_REQUIREMENT_H_ 6 #define BASE_MAC_PROCESS_REQUIREMENT_H_ 7 8 #include <Security/Security.h> 9 #include <mach/mach.h> 10 11 #include <optional> 12 #include <string> 13 #include <vector> 14 15 #include "base/apple/scoped_cftyperef.h" 16 #include "base/base_export.h" 17 #include "base/containers/span.h" 18 19 namespace base::mac { 20 21 enum class ValidationCategory : unsigned int; 22 23 // Represents constraints on the code signing identity of a peer process. 24 // 25 // `ProcessRequirement` is typically used to describe which processes are 26 // permitted to establish IPC connections, and to validate that a connecting 27 // process fulfills those constraints. 28 class BASE_EXPORT ProcessRequirement { 29 public: 30 class BASE_EXPORT Builder { 31 public: 32 Builder(); 33 ~Builder(); 34 35 Builder(const Builder&) = delete; 36 Builder& operator=(const Builder&) = delete; 37 Builder(Builder&&); 38 Builder& operator=(Builder&&); 39 40 // The identifier in the signature must match `identifier`. 41 // Can be called at most once. See `IdentifierIsOneOf` if multiple 42 // identifiers can be accepted. 43 // 44 // The identifier is typically the executable name or bundle identifier of 45 // the application. 46 Builder Identifier(std::string identifier) &&; 47 48 // The identifier in the signature must match one of the values 49 // in`identifiers`. 50 // Can be called at most once. 51 // 52 // The identifier is typically the executable name or bundle identifier of 53 // the application. 54 Builder IdentifierIsOneOf(std::vector<std::string> identifiers) &&; 55 56 // Equivalent to HasSameTeamIdentifier().HasSameCertificateType() 57 Builder SignedWithSameIdentity() &&; 58 59 // The process must be signed with a certificate that uses the same 60 // team identifier as this process. 61 // Can be called at most once. 62 // 63 // Note: It is an error to call this without also limiting the certificate 64 // type via `HasSameCertificateType`, `DeveloperIdCertificateType`, etc. 65 Builder HasSameTeamIdentifier() &&; 66 67 // The process must be signed with the same type of certificate as this 68 // process. 69 // Can be called at most once. 70 Builder HasSameCertificateType() &&; 71 72 // The team identifier in the signing certificate matches `team_identifier`. 73 // Can be called at most once. 74 // 75 // Note: It is an error to call this without also limiting the certificate 76 // type via `HasSameCertificateType`, `DeveloperIdCertificateType`, etc. 77 Builder TeamIdentifier(std::string team_identifier) &&; 78 79 // The certificate used during signing is an Apple Developer ID certificate. 80 // Can be called at most once. 81 Builder DeveloperIdCertificateType() &&; 82 83 // The certificate used during signing is an Apple App Store certificate. 84 // Can be called at most once. 85 Builder AppStoreCertificateType() &&; 86 87 // The certificate used during signing is an Apple Development certificate 88 // that cannot be used for distributing applications. 89 // Can be called at most once. 90 Builder DevelopmentCertificateType() &&; 91 92 // Validate only the dynamic signature of the application without 93 // comparing it to the state of the application on disk. 94 // 95 // Note that when requesting dynamic validation it is necessary to 96 // supply the application's Info.plist data when performing 97 // code signature validation using the resulting requirement. 98 Builder CheckDynamicValidityOnly() &&; 99 100 // Consume the constraints and produce a ProcessRequirement. 101 // Returns `std::nullopt` on error. 102 std::optional<ProcessRequirement> Build() &&; 103 104 private: 105 std::vector<std::string> identifiers_; 106 std::string team_identifier_; 107 std::optional<ValidationCategory> validation_category_; 108 bool dynamic_validity_only_ = false; 109 bool failed_ = false; 110 bool has_same_team_identifier_called_ = false; 111 bool has_same_certificate_type_called_ = false; 112 }; // class Builder 113 114 // Use Builder::Build to construct a ProcessRequirement. 115 ProcessRequirement() = delete; 116 ~ProcessRequirement(); 117 118 ProcessRequirement(const ProcessRequirement&); 119 ProcessRequirement& operator=(const ProcessRequirement&); 120 ProcessRequirement(ProcessRequirement&&); 121 ProcessRequirement& operator=(ProcessRequirement&&); 122 123 // Validate the process represented by `audit_token` against this requirement. 124 // 125 // If this requirement was created with `CheckDynamicValidityOnly()` then 126 // the target process's Info.plist data must be provided in `info_plist_data`. 127 bool ValidateProcess(audit_token_t audit_token, 128 base::span<const uint8_t> info_plist_data = {}) const; 129 130 // Create a `SecRequirementRef` from the requirement. 131 // Will return `nullptr` if the requirement does not place any limits 132 // on the process, such as if `SignedWithSameIdentity()` was used 133 // from a process with an ad-hoc code signature. 134 // 135 // Prefer to use `ValidateProcess` when possible. 136 apple::ScopedCFTypeRef<SecRequirementRef> AsSecRequirement() const; 137 138 // Returns true if only the dynamic signature of the application 139 // should be validated without comparing it to the state of the 140 // application on disk. ShouldCheckDynamicValidityOnly()141 bool ShouldCheckDynamicValidityOnly() const { return dynamic_validity_only_; } 142 143 // Gather metrics to validate the reliability of ProcessRequirement. 144 // Work is performed asynchronously on a background thread. 145 static void MaybeGatherMetrics(); 146 147 static ProcessRequirement AlwaysMatchesForTesting(); 148 static ProcessRequirement NeverMatchesForTesting(); 149 150 void SetShouldCheckDynamicValidityOnlyForTesting(); 151 152 struct CSOpsSystemCallProvider { 153 virtual ~CSOpsSystemCallProvider() = default; 154 virtual int csops(pid_t pid, 155 unsigned int ops, 156 void* useraddr, 157 size_t usersize) = 0; 158 virtual bool SupportsValidationCategory() const = 0; 159 }; 160 161 // Use `csops_provider` function in place of using the default provider which 162 // uses the `csops` system call for retrieving code signing information. 163 // Pass `nullptr` to reset to the default provider. 164 static void SetCSOpsSystemCallProviderForTesting( 165 CSOpsSystemCallProvider* csops_provider); 166 167 private: 168 ProcessRequirement(std::vector<std::string> identifiers, 169 std::string team_identifier, 170 ValidationCategory validation_category, 171 bool dynamic_validity_only); 172 173 // Returns true if the code signature must be validated to enforce this 174 // requirement. 175 // This will be false for unsigned code and true for all signed code. 176 bool RequiresSignatureValidation() const; 177 178 // Do the work of gathering metrics. Called on a background thread. 179 static void GatherMetrics(); 180 181 enum ForTesting { 182 AlwaysMatches, 183 NeverMatches, 184 }; 185 186 explicit ProcessRequirement(ForTesting for_testing); 187 188 static apple::ScopedCFTypeRef<SecRequirementRef> AsSecRequirementForTesting( 189 ForTesting for_testing); 190 191 std::vector<std::string> identifiers_; 192 std::string team_identifier_; 193 std::optional<ForTesting> for_testing_; 194 ValidationCategory validation_category_; 195 bool dynamic_validity_only_ = false; 196 }; 197 198 } // namespace base::mac 199 200 #endif // BASE_MAC_PROCESS_REQUIREMENT_H_ 201