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