• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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