1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125

base / mac / code_signature.cc [blame]

// 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 "base/apple/osstatus_logging.h"
#include "base/apple/scoped_cftyperef.h"
#include "base/mac/info_plist_data.h"
#include "base/strings/sys_string_conversions.h"
#include "third_party/abseil-cpp/absl/types/variant.h"

using base::apple::ScopedCFTypeRef;

namespace base::mac {

namespace {

// Return a dictionary of attributes suitable for looking up `process` with
// `SecCodeCopyGuestWithAttributes`.
ScopedCFTypeRef<CFDictionaryRef> AttributesForGuestValidation(
    absl::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 = absl::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(absl::holds_alternative<pid_t>(process));
    ScopedCFTypeRef<CFNumberRef> pid_cf(
        CFNumberCreate(nullptr, kCFNumberIntType, &absl::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