blob: 097500d0ed1488b343cef2ed4402041ac14bda2b [file] [log] [blame] [edit]
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/mac/code_signature.h"
#include <variant>
#include "base/apple/osstatus_logging.h"
#include "base/apple/scoped_cftyperef.h"
#include "base/mac/info_plist_data.h"
#include "base/strings/string_view_util.h"
#include "base/strings/sys_string_conversions.h"
using base::apple::ScopedCFTypeRef;
namespace base::mac {
namespace {
// Return a dictionary of attributes suitable for looking up `process` with
// `SecCodeCopyGuestWithAttributes`.
ScopedCFTypeRef<CFDictionaryRef> AttributesForGuestValidation(
std::variant<audit_token_t, pid_t> process,
SignatureValidationType validation_type,
std::string_view info_plist_xml) {
ScopedCFTypeRef<CFMutableDictionaryRef> attributes(
CFDictionaryCreateMutable(nullptr, 3, &kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks));
if (audit_token_t* token = std::get_if<audit_token_t>(&process)) {
ScopedCFTypeRef<CFDataRef> audit_token_cf(CFDataCreate(
nullptr, reinterpret_cast<const UInt8*>(token), sizeof(audit_token_t)));
CFDictionarySetValue(attributes.get(), kSecGuestAttributeAudit,
audit_token_cf.get());
} else {
CHECK(std::holds_alternative<pid_t>(process));
ScopedCFTypeRef<CFNumberRef> pid_cf(
CFNumberCreate(nullptr, kCFNumberIntType, &std::get<pid_t>(process)));
CFDictionarySetValue(attributes.get(), kSecGuestAttributePid, pid_cf.get());
}
if (validation_type == SignatureValidationType::DynamicOnly) {
ScopedCFTypeRef<CFDataRef> info_plist(CFDataCreate(
nullptr, reinterpret_cast<const UInt8*>(info_plist_xml.data()),
static_cast<CFIndex>(info_plist_xml.length())));
CFDictionarySetValue(attributes.get(), kSecGuestAttributeDynamicCode,
kCFBooleanTrue);
CFDictionarySetValue(attributes.get(),
kSecGuestAttributeDynamicCodeInfoPlist,
info_plist.get());
}
return attributes;
}
OSStatus ValidateGuestWithAttributes(CFDictionaryRef attributes,
SecRequirementRef requirement) {
ScopedCFTypeRef<SecCodeRef> code;
OSStatus status = SecCodeCopyGuestWithAttributes(
nullptr, attributes, kSecCSDefaultFlags, code.InitializeInto());
if (status != errSecSuccess) {
OSSTATUS_LOG(ERROR, status) << "SecCodeCopyGuestWithAttributes";
return status;
}
return SecCodeCheckValidity(code.get(), kSecCSDefaultFlags, requirement);
}
} // namespace
OSStatus ProcessIsSignedAndFulfillsRequirement(
audit_token_t audit_token,
SecRequirementRef requirement,
SignatureValidationType validation_type,
std::string_view info_plist_xml) {
ScopedCFTypeRef<CFDictionaryRef> attributes = AttributesForGuestValidation(
audit_token, validation_type, info_plist_xml);
return ValidateGuestWithAttributes(attributes.get(), requirement);
}
OSStatus ProcessIdIsSignedAndFulfillsRequirement_DoNotUse(
pid_t pid,
SecRequirementRef requirement,
SignatureValidationType validation_type,
std::string_view info_plist_xml) {
ScopedCFTypeRef<CFDictionaryRef> attributes =
AttributesForGuestValidation(pid, validation_type, info_plist_xml);
return ValidateGuestWithAttributes(attributes.get(), requirement);
}
ScopedCFTypeRef<SecRequirementRef> RequirementFromString(
std::string_view requirement_string) {
ScopedCFTypeRef<CFStringRef> requirement_string_cf(
base::SysUTF8ToCFStringRef(requirement_string));
ScopedCFTypeRef<SecRequirementRef> requirement;
OSStatus status = SecRequirementCreateWithString(
requirement_string_cf.get(), kSecCSDefaultFlags,
requirement.InitializeInto());
if (status != errSecSuccess) {
OSSTATUS_LOG(ERROR, status)
<< "SecRequirementCreateWithString: " << requirement_string;
return base::apple::ScopedCFTypeRef<SecRequirementRef>(nullptr);
}
return requirement;
}
base::expected<ScopedCFTypeRef<SecCodeRef>, OSStatus>
DynamicCodeObjectForCurrentProcess() {
std::vector<uint8_t> info_plist_xml = OuterBundleCachedInfoPlistData();
ScopedCFTypeRef<CFDictionaryRef> attributes = AttributesForGuestValidation(
getpid(), SignatureValidationType::DynamicOnly,
base::as_string_view(info_plist_xml));
ScopedCFTypeRef<SecCodeRef> code;
OSStatus status = SecCodeCopyGuestWithAttributes(
nullptr, attributes.get(), kSecCSDefaultFlags, code.InitializeInto());
if (status != errSecSuccess) {
OSSTATUS_LOG(ERROR, status) << "SecCodeCopyGuestWithAttributes";
return base::unexpected(status);
}
return code;
}
} // namespace base::mac