• 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 #include "base/mac/code_signature.h"
6 
7 #include "base/apple/osstatus_logging.h"
8 #include "base/apple/scoped_cftyperef.h"
9 #include "base/mac/info_plist_data.h"
10 #include "base/strings/sys_string_conversions.h"
11 #include "third_party/abseil-cpp/absl/types/variant.h"
12 
13 using base::apple::ScopedCFTypeRef;
14 
15 namespace base::mac {
16 
17 namespace {
18 
19 // Return a dictionary of attributes suitable for looking up `process` with
20 // `SecCodeCopyGuestWithAttributes`.
AttributesForGuestValidation(absl::variant<audit_token_t,pid_t> process,SignatureValidationType validation_type,std::string_view info_plist_xml)21 ScopedCFTypeRef<CFDictionaryRef> AttributesForGuestValidation(
22     absl::variant<audit_token_t, pid_t> process,
23     SignatureValidationType validation_type,
24     std::string_view info_plist_xml) {
25   ScopedCFTypeRef<CFMutableDictionaryRef> attributes(
26       CFDictionaryCreateMutable(nullptr, 3, &kCFTypeDictionaryKeyCallBacks,
27                                 &kCFTypeDictionaryValueCallBacks));
28 
29   if (audit_token_t* token = absl::get_if<audit_token_t>(&process)) {
30     ScopedCFTypeRef<CFDataRef> audit_token_cf(CFDataCreate(
31         nullptr, reinterpret_cast<const UInt8*>(token), sizeof(audit_token_t)));
32     CFDictionarySetValue(attributes.get(), kSecGuestAttributeAudit,
33                          audit_token_cf.get());
34   } else {
35     CHECK(absl::holds_alternative<pid_t>(process));
36     ScopedCFTypeRef<CFNumberRef> pid_cf(
37         CFNumberCreate(nullptr, kCFNumberIntType, &absl::get<pid_t>(process)));
38     CFDictionarySetValue(attributes.get(), kSecGuestAttributePid, pid_cf.get());
39   }
40 
41   if (validation_type == SignatureValidationType::DynamicOnly) {
42     ScopedCFTypeRef<CFDataRef> info_plist(CFDataCreate(
43         nullptr, reinterpret_cast<const UInt8*>(info_plist_xml.data()),
44         static_cast<CFIndex>(info_plist_xml.length())));
45 
46     CFDictionarySetValue(attributes.get(), kSecGuestAttributeDynamicCode,
47                          kCFBooleanTrue);
48     CFDictionarySetValue(attributes.get(),
49                          kSecGuestAttributeDynamicCodeInfoPlist,
50                          info_plist.get());
51   }
52 
53   return attributes;
54 }
55 
ValidateGuestWithAttributes(CFDictionaryRef attributes,SecRequirementRef requirement)56 OSStatus ValidateGuestWithAttributes(CFDictionaryRef attributes,
57                                      SecRequirementRef requirement) {
58   ScopedCFTypeRef<SecCodeRef> code;
59   OSStatus status = SecCodeCopyGuestWithAttributes(
60       nullptr, attributes, kSecCSDefaultFlags, code.InitializeInto());
61   if (status != errSecSuccess) {
62     OSSTATUS_LOG(ERROR, status) << "SecCodeCopyGuestWithAttributes";
63     return status;
64   }
65   return SecCodeCheckValidity(code.get(), kSecCSDefaultFlags, requirement);
66 }
67 
68 }  // namespace
69 
ProcessIsSignedAndFulfillsRequirement(audit_token_t audit_token,SecRequirementRef requirement,SignatureValidationType validation_type,std::string_view info_plist_xml)70 OSStatus ProcessIsSignedAndFulfillsRequirement(
71     audit_token_t audit_token,
72     SecRequirementRef requirement,
73     SignatureValidationType validation_type,
74     std::string_view info_plist_xml) {
75   ScopedCFTypeRef<CFDictionaryRef> attributes = AttributesForGuestValidation(
76       audit_token, validation_type, info_plist_xml);
77   return ValidateGuestWithAttributes(attributes.get(), requirement);
78 }
79 
ProcessIdIsSignedAndFulfillsRequirement_DoNotUse(pid_t pid,SecRequirementRef requirement,SignatureValidationType validation_type,std::string_view info_plist_xml)80 OSStatus ProcessIdIsSignedAndFulfillsRequirement_DoNotUse(
81     pid_t pid,
82     SecRequirementRef requirement,
83     SignatureValidationType validation_type,
84     std::string_view info_plist_xml) {
85   ScopedCFTypeRef<CFDictionaryRef> attributes =
86       AttributesForGuestValidation(pid, validation_type, info_plist_xml);
87   return ValidateGuestWithAttributes(attributes.get(), requirement);
88 }
89 
RequirementFromString(std::string_view requirement_string)90 ScopedCFTypeRef<SecRequirementRef> RequirementFromString(
91     std::string_view requirement_string) {
92   ScopedCFTypeRef<CFStringRef> requirement_string_cf(
93       base::SysUTF8ToCFStringRef(requirement_string));
94   ScopedCFTypeRef<SecRequirementRef> requirement;
95   OSStatus status = SecRequirementCreateWithString(
96       requirement_string_cf.get(), kSecCSDefaultFlags,
97       requirement.InitializeInto());
98   if (status != errSecSuccess) {
99     OSSTATUS_LOG(ERROR, status)
100         << "SecRequirementCreateWithString: " << requirement_string;
101     return base::apple::ScopedCFTypeRef<SecRequirementRef>(nullptr);
102   }
103 
104   return requirement;
105 }
106 
107 base::expected<ScopedCFTypeRef<SecCodeRef>, OSStatus>
DynamicCodeObjectForCurrentProcess()108 DynamicCodeObjectForCurrentProcess() {
109   std::vector<uint8_t> info_plist_xml = OuterBundleCachedInfoPlistData();
110   ScopedCFTypeRef<CFDictionaryRef> attributes = AttributesForGuestValidation(
111       getpid(), SignatureValidationType::DynamicOnly,
112       base::as_string_view(info_plist_xml));
113 
114   ScopedCFTypeRef<SecCodeRef> code;
115   OSStatus status = SecCodeCopyGuestWithAttributes(
116       nullptr, attributes.get(), kSecCSDefaultFlags, code.InitializeInto());
117   if (status != errSecSuccess) {
118     OSSTATUS_LOG(ERROR, status) << "SecCodeCopyGuestWithAttributes";
119     return base::unexpected(status);
120   }
121 
122   return code;
123 }
124 
125 }  // namespace base::mac
126